From d6b55749e6dd1c679e3fec4e7b6802159b8d786f Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 6 Jun 2022 17:01:59 +0200 Subject: [PATCH 001/715] tests/fuzzers/bls12381: fix blst deserializing (#25036) * tests/fuzzers/bls12381: fix blst deserializing * tests/fuzzers/bls12381: fix blst deserializing --- tests/fuzzers/bls12381/bls12381_fuzz.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/fuzzers/bls12381/bls12381_fuzz.go b/tests/fuzzers/bls12381/bls12381_fuzz.go index c511c6501132..8f5761cf5c5a 100644 --- a/tests/fuzzers/bls12381/bls12381_fuzz.go +++ b/tests/fuzzers/bls12381/bls12381_fuzz.go @@ -29,6 +29,7 @@ import ( gnark "github.com/consensys/gnark-crypto/ecc/bls12-381" "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/crypto/bls12381" blst "github.com/supranational/blst/bindings/go" ) @@ -70,7 +71,9 @@ func FuzzCrossPairing(data []byte) int { blst.PairingRawAggregate(ctx, blG2, blG1) blstResult := blst.PairingAsFp12(ctx) if !(bytes.Equal(blstResult.ToBendian(), bls12381.NewGT().ToBytes(kResult))) { - panic("pairing mismatch blst / geth ") + fmt.Printf("geth: %v\n", common.Bytes2Hex(bls12381.NewGT().ToBytes(kResult))) + fmt.Printf("blst: %v\n", common.Bytes2Hex(blstResult.ToBendian())) + panic("pairing mismatch blst / geth") } return 1 @@ -227,10 +230,8 @@ func getG1Points(input io.Reader) (*bls12381.PointG1, *gnark.G1Affine, *blst.P1A } // marshal gnark point -> blst point - var p1 *blst.P1Affine - var scalar *blst.Scalar - scalar.Deserialize(s.Bytes()) - p1.From(scalar) + scalar := new(blst.Scalar).FromBEndian(common.LeftPadBytes(s.Bytes(), 32)) + p1 := new(blst.P1Affine).From(scalar) if !bytes.Equal(p1.Serialize(), cpBytes) { panic("bytes(blst.G1) != bytes(geth.G1)") } @@ -262,10 +263,9 @@ func getG2Points(input io.Reader) (*bls12381.PointG2, *gnark.G2Affine, *blst.P2A } // marshal gnark point -> blst point - var p2 *blst.P2Affine - var scalar *blst.Scalar - scalar.Deserialize(s.Bytes()) - p2.From(scalar) + // Left pad the scalar to 32 bytes + scalar := new(blst.Scalar).FromBEndian(common.LeftPadBytes(s.Bytes(), 32)) + p2 := new(blst.P2Affine).From(scalar) if !bytes.Equal(p2.Serialize(), cpBytes) { panic("bytes(blst.G2) != bytes(geth.G2)") } From c375ee91e99cd9c072f2fe9b535c5cb780b5f8a0 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 6 Jun 2022 17:09:39 +0200 Subject: [PATCH 002/715] cmd/geth, core/state/snapshot: rework journal loading, implement account-check (#24765) * cmd/geth, core/state/snapshot: rework journal loading, implement account-check * core/state/snapshot, cmd/geth: polish code (#37) * core/state/snapshot: minor nits * core/state/snapshot: simplify error logic * cmd/geth: go format Co-authored-by: rjl493456442 --- cmd/geth/snapshot.go | 44 +++++ core/state/snapshot/generate_test.go | 2 +- core/state/snapshot/journal.go | 185 ++++++++++-------- core/state/snapshot/{dangling.go => utils.go} | 125 ++++++------ 4 files changed, 205 insertions(+), 151 deletions(-) rename core/state/snapshot/{dangling.go => utils.go} (55%) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 9ffc5918cc74..b46c8013ca9f 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -101,6 +101,18 @@ In other words, this command does the snapshot to trie conversion. Description: ` geth snapshot check-dangling-storage traverses the snap storage data, and verifies that all snapshot storage data has a corresponding account. +`, + }, + { + Name: "inspect-account", + Usage: "Check all snapshot layers for the a specific account", + ArgsUsage: "
", + Action: utils.MigrateFlags(checkAccount), + Category: "MISCELLANEOUS COMMANDS", + Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), + Description: ` +geth snapshot inspect-account
checks all snapshot layers and prints out +information about the specified address. `, }, { @@ -535,3 +547,35 @@ func dumpState(ctx *cli.Context) error { "elapsed", common.PrettyDuration(time.Since(start))) return nil } + +// checkAccount iterates the snap data layers, and looks up the given account +// across all layers. +func checkAccount(ctx *cli.Context) error { + if ctx.NArg() != 1 { + return errors.New("need arg") + } + var ( + hash common.Hash + addr common.Address + ) + switch len(ctx.Args()[0]) { + case 40, 42: + addr = common.HexToAddress(ctx.Args()[0]) + hash = crypto.Keccak256Hash(addr.Bytes()) + case 64, 66: + hash = common.HexToHash(ctx.Args()[0]) + default: + return errors.New("malformed address or hash") + } + stack, _ := makeConfigNode(ctx) + defer stack.Close() + chaindb := utils.MakeChainDatabase(ctx, stack, true) + defer chaindb.Close() + start := time.Now() + log.Info("Checking difflayer journal", "address", addr, "hash", hash) + if err := snapshot.CheckJournalAccount(chaindb, hash); err != nil { + return err + } + log.Info("Checked the snapshot journalled storage", "time", common.PrettyDuration(time.Since(start))) + return nil +} diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 94caed08ad7a..40a234dcb766 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -171,7 +171,7 @@ func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) { t.Fatalf("snaproot: %#x != trieroot #%x", snapRoot, trieRoot) } if err := CheckDanglingStorage(snap.diskdb); err != nil { - t.Fatalf("Detected dangling storages %v", err) + t.Fatalf("Detected dangling storages: %v", err) } } diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index 6836a574090c..80cd4eeee42a 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -108,44 +108,15 @@ func loadAndParseJournal(db ethdb.KeyValueStore, base *diskLayer) (snapshot, jou // So if there is no journal, or the journal is invalid(e.g. the journal // is not matched with disk layer; or the it's the legacy-format journal, // etc.), we just discard all diffs and try to recover them later. - journal := rawdb.ReadSnapshotJournal(db) - if len(journal) == 0 { - log.Warn("Loaded snapshot journal", "diskroot", base.root, "diffs", "missing") - return base, generator, nil - } - r := rlp.NewStream(bytes.NewReader(journal), 0) - - // Firstly, resolve the first element as the journal version - version, err := r.Uint() + var current snapshot = base + err := iterateJournal(db, func(parent common.Hash, root common.Hash, destructSet map[common.Hash]struct{}, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte) error { + current = newDiffLayer(current, root, destructSet, accountData, storageData) + return nil + }) if err != nil { - log.Warn("Failed to resolve the journal version", "error", err) return base, generator, nil } - if version != journalVersion { - log.Warn("Discarded the snapshot journal with wrong version", "required", journalVersion, "got", version) - return base, generator, nil - } - // Secondly, resolve the disk layer root, ensure it's continuous - // with disk layer. Note now we can ensure it's the snapshot journal - // correct version, so we expect everything can be resolved properly. - var root common.Hash - if err := r.Decode(&root); err != nil { - return nil, journalGenerator{}, errors.New("missing disk layer root") - } - // The diff journal is not matched with disk, discard them. - // It can happen that Geth crashes without persisting the latest - // diff journal. - if !bytes.Equal(root.Bytes(), base.root.Bytes()) { - log.Warn("Loaded snapshot journal", "diskroot", base.root, "diffs", "unmatched") - return base, generator, nil - } - // Load all the snapshot diffs from the journal - snapshot, err := loadDiffLayer(base, r) - if err != nil { - return nil, journalGenerator{}, err - } - log.Debug("Loaded snapshot journal", "diskroot", base.root, "diffhead", snapshot.Root()) - return snapshot, generator, nil + return current, generator, nil } // loadSnapshot loads a pre-existing state snapshot backed by a key-value store. @@ -218,57 +189,6 @@ func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, return snapshot, false, nil } -// loadDiffLayer reads the next sections of a snapshot journal, reconstructing a new -// diff and verifying that it can be linked to the requested parent. -func loadDiffLayer(parent snapshot, r *rlp.Stream) (snapshot, error) { - // Read the next diff journal entry - var root common.Hash - if err := r.Decode(&root); err != nil { - // The first read may fail with EOF, marking the end of the journal - if err == io.EOF { - return parent, nil - } - return nil, fmt.Errorf("load diff root: %v", err) - } - var destructs []journalDestruct - if err := r.Decode(&destructs); err != nil { - return nil, fmt.Errorf("load diff destructs: %v", err) - } - destructSet := make(map[common.Hash]struct{}) - for _, entry := range destructs { - destructSet[entry.Hash] = struct{}{} - } - var accounts []journalAccount - if err := r.Decode(&accounts); err != nil { - return nil, fmt.Errorf("load diff accounts: %v", err) - } - accountData := make(map[common.Hash][]byte) - for _, entry := range accounts { - if len(entry.Blob) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that - accountData[entry.Hash] = entry.Blob - } else { - accountData[entry.Hash] = nil - } - } - var storage []journalStorage - if err := r.Decode(&storage); err != nil { - return nil, fmt.Errorf("load diff storage: %v", err) - } - storageData := make(map[common.Hash]map[common.Hash][]byte) - for _, entry := range storage { - slots := make(map[common.Hash][]byte) - for i, key := range entry.Keys { - if len(entry.Vals[i]) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that - slots[key] = entry.Vals[i] - } else { - slots[key] = nil - } - } - storageData[entry.Hash] = slots - } - return loadDiffLayer(newDiffLayer(parent, root, destructSet, accountData, storageData), r) -} - // Journal terminates any in-progress snapshot generation, also implicitly pushing // the progress into the database. func (dl *diskLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) { @@ -345,3 +265,96 @@ func (dl *diffLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) { log.Debug("Journalled diff layer", "root", dl.root, "parent", dl.parent.Root()) return base, nil } + +// journalCallback is a function which is invoked by iterateJournal, every +// time a difflayer is loaded from disk. +type journalCallback = func(parent common.Hash, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error + +// iterateJournal iterates through the journalled difflayers, loading them from +// the database, and invoking the callback for each loaded layer. +// The order is incremental; starting with the bottom-most difflayer, going towards +// the most recent layer. +// This method returns error either if there was some error reading from disk, +// OR if the callback returns an error when invoked. +func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error { + journal := rawdb.ReadSnapshotJournal(db) + if len(journal) == 0 { + log.Warn("Loaded snapshot journal", "diffs", "missing") + return nil + } + r := rlp.NewStream(bytes.NewReader(journal), 0) + // Firstly, resolve the first element as the journal version + version, err := r.Uint() + if err != nil { + log.Warn("Failed to resolve the journal version", "error", err) + return errors.New("failed to resolve journal version") + } + if version != journalVersion { + log.Warn("Discarded the snapshot journal with wrong version", "required", journalVersion, "got", version) + return errors.New("wrong journal version") + } + // Secondly, resolve the disk layer root, ensure it's continuous + // with disk layer. Note now we can ensure it's the snapshot journal + // correct version, so we expect everything can be resolved properly. + var parent common.Hash + if err := r.Decode(&parent); err != nil { + return errors.New("missing disk layer root") + } + if baseRoot := rawdb.ReadSnapshotRoot(db); baseRoot != parent { + log.Warn("Loaded snapshot journal", "diskroot", baseRoot, "diffs", "unmatched") + return fmt.Errorf("mismatched disk and diff layers") + } + for { + var ( + root common.Hash + destructs []journalDestruct + accounts []journalAccount + storage []journalStorage + destructSet = make(map[common.Hash]struct{}) + accountData = make(map[common.Hash][]byte) + storageData = make(map[common.Hash]map[common.Hash][]byte) + ) + // Read the next diff journal entry + if err := r.Decode(&root); err != nil { + // The first read may fail with EOF, marking the end of the journal + if errors.Is(err, io.EOF) { + return nil + } + return fmt.Errorf("load diff root: %v", err) + } + if err := r.Decode(&destructs); err != nil { + return fmt.Errorf("load diff destructs: %v", err) + } + if err := r.Decode(&accounts); err != nil { + return fmt.Errorf("load diff accounts: %v", err) + } + if err := r.Decode(&storage); err != nil { + return fmt.Errorf("load diff storage: %v", err) + } + for _, entry := range destructs { + destructSet[entry.Hash] = struct{}{} + } + for _, entry := range accounts { + if len(entry.Blob) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that + accountData[entry.Hash] = entry.Blob + } else { + accountData[entry.Hash] = nil + } + } + for _, entry := range storage { + slots := make(map[common.Hash][]byte) + for i, key := range entry.Keys { + if len(entry.Vals[i]) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that + slots[key] = entry.Vals[i] + } else { + slots[key] = nil + } + } + storageData[entry.Hash] = slots + } + if err := callback(parent, root, destructSet, accountData, storageData); err != nil { + return err + } + parent = root + } +} diff --git a/core/state/snapshot/dangling.go b/core/state/snapshot/utils.go similarity index 55% rename from core/state/snapshot/dangling.go rename to core/state/snapshot/utils.go index ca73da793f7a..fa1f216e6826 100644 --- a/core/state/snapshot/dangling.go +++ b/core/state/snapshot/utils.go @@ -18,9 +18,7 @@ package snapshot import ( "bytes" - "errors" "fmt" - "io" "time" "github.com/ethereum/go-ethereum/common" @@ -34,7 +32,7 @@ import ( // storage also has corresponding account data. func CheckDanglingStorage(chaindb ethdb.KeyValueStore) error { if err := checkDanglingDiskStorage(chaindb); err != nil { - return err + log.Error("Database check error", "err", err) } return checkDanglingMemStorage(chaindb) } @@ -75,81 +73,80 @@ func checkDanglingDiskStorage(chaindb ethdb.KeyValueStore) error { // checkDanglingMemStorage checks if there is any 'dangling' storage in the journalled // snapshot difflayers. func checkDanglingMemStorage(db ethdb.KeyValueStore) error { - var ( - start = time.Now() - journal = rawdb.ReadSnapshotJournal(db) - ) - if len(journal) == 0 { - log.Warn("Loaded snapshot journal", "diffs", "missing") + start := time.Now() + log.Info("Checking dangling journalled storage") + err := iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { + for accHash := range storage { + if _, ok := accounts[accHash]; !ok { + log.Error("Dangling storage - missing account", "account", fmt.Sprintf("%#x", accHash), "root", root) + } + } return nil - } - r := rlp.NewStream(bytes.NewReader(journal), 0) - // Firstly, resolve the first element as the journal version - version, err := r.Uint() + }) if err != nil { - log.Warn("Failed to resolve the journal version", "error", err) - return nil - } - if version != journalVersion { - log.Warn("Discarded the snapshot journal with wrong version", "required", journalVersion, "got", version) - return nil - } - // Secondly, resolve the disk layer root, ensure it's continuous - // with disk layer. Note now we can ensure it's the snapshot journal - // correct version, so we expect everything can be resolved properly. - var root common.Hash - if err := r.Decode(&root); err != nil { - return errors.New("missing disk layer root") - } - // The diff journal is not matched with disk, discard them. - // It can happen that Geth crashes without persisting the latest - // diff journal. - // Load all the snapshot diffs from the journal - if err := checkDanglingJournalStorage(r); err != nil { + log.Info("Failed to resolve snapshot journal", "err", err) return err } log.Info("Verified the snapshot journalled storage", "time", common.PrettyDuration(time.Since(start))) return nil } -// loadDiffLayer reads the next sections of a snapshot journal, reconstructing a new -// diff and verifying that it can be linked to the requested parent. -func checkDanglingJournalStorage(r *rlp.Stream) error { - for { - // Read the next diff journal entry - var root common.Hash - if err := r.Decode(&root); err != nil { - // The first read may fail with EOF, marking the end of the journal - if err == io.EOF { - return nil - } - return fmt.Errorf("load diff root: %v", err) +// CheckJournalAccount shows information about an account, from the disk layer and +// up through the diff layers. +func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error { + // Look up the disk layer first + baseRoot := rawdb.ReadSnapshotRoot(db) + fmt.Printf("Disklayer: Root: %x\n", baseRoot) + if data := rawdb.ReadAccountSnapshot(db, hash); data != nil { + account := new(Account) + if err := rlp.DecodeBytes(data, account); err != nil { + panic(err) } - var destructs []journalDestruct - if err := r.Decode(&destructs); err != nil { - return fmt.Errorf("load diff destructs: %v", err) + fmt.Printf("\taccount.nonce: %d\n", account.Nonce) + fmt.Printf("\taccount.balance: %x\n", account.Balance) + fmt.Printf("\taccount.root: %x\n", account.Root) + fmt.Printf("\taccount.codehash: %x\n", account.CodeHash) + } + // Check storage + { + it := rawdb.NewKeyLengthIterator(db.NewIterator(append(rawdb.SnapshotStoragePrefix, hash.Bytes()...), nil), 1+2*common.HashLength) + fmt.Printf("\tStorage:\n") + for it.Next() { + slot := it.Key()[33:] + fmt.Printf("\t\t%x: %x\n", slot, it.Value()) } - var accounts []journalAccount - if err := r.Decode(&accounts); err != nil { - return fmt.Errorf("load diff accounts: %v", err) + it.Release() + } + var depth = 0 + + return iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { + _, a := accounts[hash] + _, b := destructs[hash] + _, c := storage[hash] + depth++ + if !a && !b && !c { + return nil } - accountData := make(map[common.Hash][]byte) - for _, entry := range accounts { - if len(entry.Blob) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that - accountData[entry.Hash] = entry.Blob - } else { - accountData[entry.Hash] = nil + fmt.Printf("Disklayer+%d: Root: %x, parent %x\n", depth, root, pRoot) + if data, ok := accounts[hash]; ok { + account := new(Account) + if err := rlp.DecodeBytes(data, account); err != nil { + panic(err) } + fmt.Printf("\taccount.nonce: %d\n", account.Nonce) + fmt.Printf("\taccount.balance: %x\n", account.Balance) + fmt.Printf("\taccount.root: %x\n", account.Root) + fmt.Printf("\taccount.codehash: %x\n", account.CodeHash) } - var storage []journalStorage - if err := r.Decode(&storage); err != nil { - return fmt.Errorf("load diff storage: %v", err) + if _, ok := destructs[hash]; ok { + fmt.Printf("\t Destructed!") } - for _, entry := range storage { - if _, ok := accountData[entry.Hash]; !ok { - log.Error("Dangling storage - missing account", "account", fmt.Sprintf("%#x", entry.Hash), "root", root) - return fmt.Errorf("dangling journal snapshot storage account %#x", entry.Hash) + if data, ok := storage[hash]; ok { + fmt.Printf("\tStorage\n") + for k, v := range data { + fmt.Printf("\t\t%x: %x\n", k, v) } } - } + return nil + }) } From 22defa5af7a388cf3f8443f4d86067670ece6a90 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 6 Jun 2022 23:14:55 +0800 Subject: [PATCH 003/715] all: introduce trie owner notion (#24750) * cmd, core/state, light, trie, eth: add trie owner notion * all: refactor * tests: fix goimports * core/state/snapshot: fix ineffasigns Co-authored-by: Martin Holst Swende --- cmd/geth/dbcmd.go | 2 +- cmd/geth/snapshot.go | 8 +- core/blockchain.go | 2 +- core/state/database.go | 4 +- core/state/pruner/pruner.go | 4 +- core/state/snapshot/conversion.go | 8 +- core/state/snapshot/generate.go | 18 +- core/state/snapshot/generate_test.go | 458 ++++++++---------- core/state/state_object.go | 6 +- core/state/statedb.go | 21 +- core/state/sync_test.go | 6 +- core/state/trie_prefetcher.go | 88 ++-- core/state/trie_prefetcher_test.go | 36 +- core/types/hashing_test.go | 12 +- eth/api.go | 4 +- eth/protocols/snap/handler.go | 10 +- eth/protocols/snap/sync.go | 10 +- eth/protocols/snap/sync_test.go | 50 +- les/downloader/downloader_test.go | 2 +- les/handler_test.go | 8 +- les/server_handler.go | 4 +- light/odr_test.go | 2 +- light/postprocess.go | 13 +- light/trie.go | 12 +- tests/fuzzers/les/les-fuzzer.go | 4 +- tests/fuzzers/rangeproof/rangeproof-fuzzer.go | 2 +- tests/fuzzers/stacktrie/trie_fuzzer.go | 3 +- tests/fuzzers/trie/trie-fuzzer.go | 6 +- trie/errors.go | 13 +- trie/iterator_test.go | 18 +- trie/proof_test.go | 20 +- trie/secure_trie.go | 4 +- trie/secure_trie_test.go | 4 +- trie/stacktrie.go | 47 +- trie/stacktrie_test.go | 14 +- trie/sync_test.go | 10 +- trie/trie.go | 60 ++- trie/trie_test.go | 58 +-- trie/util_test.go | 7 +- trie/utils.go | 38 +- 40 files changed, 563 insertions(+), 533 deletions(-) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index c4fe9251f9b8..d996d46f9ac1 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -519,7 +519,7 @@ func dbDumpTrie(ctx *cli.Context) error { return err } } - theTrie, err := trie.New(stRoot, trie.NewDatabase(db)) + theTrie, err := trie.New(common.Hash{}, stRoot, trie.NewDatabase(db)) if err != nil { return err } diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index b46c8013ca9f..e8c2d0f24188 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -278,7 +278,7 @@ func traverseState(ctx *cli.Context) error { log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64()) } triedb := trie.NewDatabase(chaindb) - t, err := trie.NewSecure(root, triedb) + t, err := trie.NewSecure(common.Hash{}, root, triedb) if err != nil { log.Error("Failed to open trie", "root", root, "err", err) return err @@ -299,7 +299,7 @@ func traverseState(ctx *cli.Context) error { return err } if acc.Root != emptyRoot { - storageTrie, err := trie.NewSecure(acc.Root, triedb) + storageTrie, err := trie.NewSecure(common.BytesToHash(accIter.Key), acc.Root, triedb) if err != nil { log.Error("Failed to open storage trie", "root", acc.Root, "err", err) return err @@ -367,7 +367,7 @@ func traverseRawState(ctx *cli.Context) error { log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64()) } triedb := trie.NewDatabase(chaindb) - t, err := trie.NewSecure(root, triedb) + t, err := trie.NewSecure(common.Hash{}, root, triedb) if err != nil { log.Error("Failed to open trie", "root", root, "err", err) return err @@ -413,7 +413,7 @@ func traverseRawState(ctx *cli.Context) error { return errors.New("invalid account") } if acc.Root != emptyRoot { - storageTrie, err := trie.NewSecure(acc.Root, triedb) + storageTrie, err := trie.NewSecure(common.BytesToHash(accIter.LeafKey()), acc.Root, triedb) if err != nil { log.Error("Failed to open storage trie", "root", acc.Root, "err", err) return errors.New("missing storage trie") diff --git a/core/blockchain.go b/core/blockchain.go index b8de2d484456..3b677aca6ca6 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -674,7 +674,7 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error { if block == nil { return fmt.Errorf("non existent block [%x..]", hash[:4]) } - if _, err := trie.NewSecure(block.Root(), bc.stateCache.TrieDB()); err != nil { + if _, err := trie.NewSecure(common.Hash{}, block.Root(), bc.stateCache.TrieDB()); err != nil { return err } diff --git a/core/state/database.go b/core/state/database.go index bbcd2358e5b8..ce5d8d731715 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -133,7 +133,7 @@ type cachingDB struct { // OpenTrie opens the main account trie at a specific root hash. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { - tr, err := trie.NewSecure(root, db.db) + tr, err := trie.NewSecure(common.Hash{}, root, db.db) if err != nil { return nil, err } @@ -142,7 +142,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { // OpenStorageTrie opens the storage trie of an account. func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) { - tr, err := trie.NewSecure(root, db.db) + tr, err := trie.NewSecure(addrHash, root, db.db) if err != nil { return nil, err } diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index a121839bd099..2f4b068d88f3 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -410,7 +410,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { if genesis == nil { return errors.New("missing genesis block") } - t, err := trie.NewSecure(genesis.Root(), trie.NewDatabase(db)) + t, err := trie.NewSecure(common.Hash{}, genesis.Root(), trie.NewDatabase(db)) if err != nil { return err } @@ -430,7 +430,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { return err } if acc.Root != emptyRoot { - storageTrie, err := trie.NewSecure(acc.Root, trie.NewDatabase(db)) + storageTrie, err := trie.NewSecure(common.BytesToHash(accIter.LeafKey()), acc.Root, trie.NewDatabase(db)) if err != nil { return err } diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index f70cbf1e686b..0f3934cb423b 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -43,7 +43,7 @@ type trieKV struct { type ( // trieGeneratorFn is the interface of trie generation which can // be implemented by different trie algorithm. - trieGeneratorFn func(db ethdb.KeyValueWriter, in chan (trieKV), out chan (common.Hash)) + trieGeneratorFn func(db ethdb.KeyValueWriter, owner common.Hash, in chan (trieKV), out chan (common.Hash)) // leafCallbackFn is the callback invoked at the leaves of the trie, // returns the subtrie root with the specified subtrie identifier. @@ -253,7 +253,7 @@ func generateTrieRoot(db ethdb.KeyValueWriter, it Iterator, account common.Hash, wg.Add(1) go func() { defer wg.Done() - generatorFn(db, in, out) + generatorFn(db, account, in, out) }() // Spin up a go-routine for progress logging if report && stats != nil { @@ -360,8 +360,8 @@ func generateTrieRoot(db ethdb.KeyValueWriter, it Iterator, account common.Hash, return stop(nil) } -func stackTrieGenerate(db ethdb.KeyValueWriter, in chan trieKV, out chan common.Hash) { - t := trie.NewStackTrie(db) +func stackTrieGenerate(db ethdb.KeyValueWriter, owner common.Hash, in chan trieKV, out chan common.Hash) { + t := trie.NewStackTrieWithOwner(db, owner) for leaf := range in { t.TryUpdate(leaf.key[:], leaf.value) } diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 769989aec21c..36055856e1c7 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -166,7 +166,7 @@ func (result *proofResult) forEach(callback func(key []byte, val []byte) error) // // The proof result will be returned if the range proving is finished, otherwise // the error will be returned to abort the entire procedure. -func (dl *diskLayer) proveRange(ctx *generatorContext, root common.Hash, prefix []byte, kind string, origin []byte, max int, valueConvertFn func([]byte) ([]byte, error)) (*proofResult, error) { +func (dl *diskLayer) proveRange(ctx *generatorContext, owner common.Hash, root common.Hash, prefix []byte, kind string, origin []byte, max int, valueConvertFn func([]byte) ([]byte, error)) (*proofResult, error) { var ( keys [][]byte vals [][]byte @@ -234,7 +234,7 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, root common.Hash, prefix // The snap state is exhausted, pass the entire key/val set for verification if origin == nil && !diskMore { - stackTr := trie.NewStackTrie(nil) + stackTr := trie.NewStackTrieWithOwner(nil, owner) for i, key := range keys { stackTr.TryUpdate(key, vals[i]) } @@ -248,7 +248,7 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, root common.Hash, prefix return &proofResult{keys: keys, vals: vals}, nil } // Snap state is chunked, generate edge proofs for verification. - tr, err := trie.New(root, dl.triedb) + tr, err := trie.New(owner, root, dl.triedb) if err != nil { ctx.stats.Log("Trie missing, state snapshotting paused", dl.root, dl.genMarker) return nil, errMissingTrie @@ -313,9 +313,9 @@ type onStateCallback func(key []byte, val []byte, write bool, delete bool) error // generateRange generates the state segment with particular prefix. Generation can // either verify the correctness of existing state through range-proof and skip // generation, or iterate trie to regenerate state on demand. -func (dl *diskLayer) generateRange(ctx *generatorContext, root common.Hash, prefix []byte, kind string, origin []byte, max int, onState onStateCallback, valueConvertFn func([]byte) ([]byte, error)) (bool, []byte, error) { +func (dl *diskLayer) generateRange(ctx *generatorContext, owner common.Hash, root common.Hash, prefix []byte, kind string, origin []byte, max int, onState onStateCallback, valueConvertFn func([]byte) ([]byte, error)) (bool, []byte, error) { // Use range prover to check the validity of the flat state in the range - result, err := dl.proveRange(ctx, root, prefix, kind, origin, max, valueConvertFn) + result, err := dl.proveRange(ctx, owner, root, prefix, kind, origin, max, valueConvertFn) if err != nil { return false, nil, err } @@ -363,7 +363,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, root common.Hash, pref if len(result.keys) > 0 { snapNodeCache = memorydb.New() snapTrieDb := trie.NewDatabase(snapNodeCache) - snapTrie, _ := trie.New(common.Hash{}, snapTrieDb) + snapTrie, _ := trie.New(owner, common.Hash{}, snapTrieDb) for i, key := range result.keys { snapTrie.Update(key, result.vals[i]) } @@ -374,7 +374,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, root common.Hash, pref // if it's already opened with some nodes resolved. tr := result.tr if tr == nil { - tr, err = trie.New(root, dl.triedb) + tr, err = trie.New(owner, root, dl.triedb) if err != nil { ctx.stats.Log("Trie missing, state snapshotting paused", dl.root, dl.genMarker) return false, nil, errMissingTrie @@ -537,7 +537,7 @@ func generateStorages(ctx *generatorContext, dl *diskLayer, account common.Hash, // Loop for re-generating the missing storage slots. var origin = common.CopyBytes(storeMarker) for { - exhausted, last, err := dl.generateRange(ctx, storageRoot, append(rawdb.SnapshotStoragePrefix, account.Bytes()...), snapStorage, origin, storageCheckRange, onStorage, nil) + exhausted, last, err := dl.generateRange(ctx, account, storageRoot, append(rawdb.SnapshotStoragePrefix, account.Bytes()...), snapStorage, origin, storageCheckRange, onStorage, nil) if err != nil { return err // The procedure it aborted, either by external signal or internal error. } @@ -637,7 +637,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er } origin := common.CopyBytes(accMarker) for { - exhausted, last, err := dl.generateRange(ctx, dl.root, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, FullAccountRLP) + exhausted, last, err := dl.generateRange(ctx, common.Hash{}, dl.root, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, FullAccountRLP) if err != nil { return err // The procedure it aborted, either by external signal or internal error. } diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 40a234dcb766..fe81993e9d2f 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -26,47 +26,40 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "golang.org/x/crypto/sha3" ) +func hashData(input []byte) common.Hash { + var hasher = sha3.NewLegacyKeccak256() + var hash common.Hash + hasher.Reset() + hasher.Write(input) + hasher.Sum(hash[:0]) + return hash +} + // Tests that snapshot generation from an empty database. func TestGeneration(t *testing.T) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - var ( - diskdb = memorydb.New() - triedb = trie.NewDatabase(diskdb) - ) - stTrie, _ := trie.NewSecure(common.Hash{}, triedb) - stTrie.Update([]byte("key-1"), []byte("val-1")) // 0x1314700b81afc49f94db3623ef1df38f3ed18b73a1b7ea2f6c095118cf6118a0 - stTrie.Update([]byte("key-2"), []byte("val-2")) // 0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371 - stTrie.Update([]byte("key-3"), []byte("val-3")) // 0x51c71a47af0695957647fb68766d0becee77e953df17c29b3c2f25436f055c78 - stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 - - accTrie, _ := trie.NewSecure(common.Hash{}, triedb) - acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} - val, _ := rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + var helper = newHelper() + stRoot := helper.makeStorageTrie(common.Hash{}, common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false) - acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} - val, _ = rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) - acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} - val, _ = rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 - root, _, _ := accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd - triedb.Commit(root, false, nil) + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + root, snap := helper.CommitAndGenerate() if have, want := root, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"); have != want { t.Fatalf("have %#x want %#x", have, want) } - snap := generateSnapshot(diskdb, triedb, 16, root) select { case <-snap.genPending: // Snapshot generation succeeded @@ -75,63 +68,34 @@ func TestGeneration(t *testing.T) { t.Errorf("Snapshot generation failed") } checkSnapRoot(t, snap, root) + // Signal abortion to the generator and wait for it to tear down stop := make(chan *generatorStats) snap.genAbort <- stop <-stop } -func hashData(input []byte) common.Hash { - var hasher = sha3.NewLegacyKeccak256() - var hash common.Hash - hasher.Reset() - hasher.Write(input) - hasher.Sum(hash[:0]) - return hash -} - // Tests that snapshot generation with existent flat state. func TestGenerateExistentState(t *testing.T) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - var ( - diskdb = memorydb.New() - triedb = trie.NewDatabase(diskdb) - ) - stTrie, _ := trie.NewSecure(common.Hash{}, triedb) - stTrie.Update([]byte("key-1"), []byte("val-1")) // 0x1314700b81afc49f94db3623ef1df38f3ed18b73a1b7ea2f6c095118cf6118a0 - stTrie.Update([]byte("key-2"), []byte("val-2")) // 0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371 - stTrie.Update([]byte("key-3"), []byte("val-3")) // 0x51c71a47af0695957647fb68766d0becee77e953df17c29b3c2f25436f055c78 - stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 - - accTrie, _ := trie.NewSecure(common.Hash{}, triedb) - acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} - val, _ := rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e - rawdb.WriteAccountSnapshot(diskdb, hashData([]byte("acc-1")), val) - rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-1")), hashData([]byte("key-1")), []byte("val-1")) - rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-1")), hashData([]byte("key-2")), []byte("val-2")) - rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-1")), hashData([]byte("key-3")), []byte("val-3")) - - acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} - val, _ = rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 - diskdb.Put(hashData([]byte("acc-2")).Bytes(), val) - rawdb.WriteAccountSnapshot(diskdb, hashData([]byte("acc-2")), val) - - acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} - val, _ = rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 - rawdb.WriteAccountSnapshot(diskdb, hashData([]byte("acc-3")), val) - rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-3")), hashData([]byte("key-1")), []byte("val-1")) - rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-3")), hashData([]byte("key-2")), []byte("val-2")) - rawdb.WriteStorageSnapshot(diskdb, hashData([]byte("acc-3")), hashData([]byte("key-3")), []byte("val-3")) - - root, _, _ := accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd - triedb.Commit(root, false, nil) - - snap := generateSnapshot(diskdb, triedb, 16, root) + var helper = newHelper() + + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addSnapAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) + + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) + helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) + + stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) + + root, snap := helper.CommitAndGenerate() select { case <-snap.genPending: // Snapshot generation succeeded @@ -140,6 +104,7 @@ func TestGenerateExistentState(t *testing.T) { t.Errorf("Snapshot generation failed") } checkSnapRoot(t, snap, root) + // Signal abortion to the generator and wait for it to tear down stop := make(chan *generatorStats) snap.genAbort <- stop @@ -163,7 +128,6 @@ func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) { } return hash, nil }, newGenerateStats(), true) - if err != nil { t.Fatal(err) } @@ -176,15 +140,15 @@ func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) { } type testHelper struct { - diskdb *memorydb.Database + diskdb ethdb.Database triedb *trie.Database accTrie *trie.SecureTrie } func newHelper() *testHelper { - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := trie.NewDatabase(diskdb) - accTrie, _ := trie.NewSecure(common.Hash{}, triedb) + accTrie, _ := trie.NewSecure(common.Hash{}, common.Hash{}, triedb) return &testHelper{ diskdb: diskdb, triedb: triedb, @@ -215,18 +179,28 @@ func (t *testHelper) addSnapStorage(accKey string, keys []string, vals []string) } } -func (t *testHelper) makeStorageTrie(keys []string, vals []string) []byte { - stTrie, _ := trie.NewSecure(common.Hash{}, t.triedb) +func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string, vals []string, commit bool) []byte { + stTrie, _ := trie.NewSecure(owner, common.Hash{}, t.triedb) for i, k := range keys { stTrie.Update([]byte(k), []byte(vals[i])) } - root, _, _ := stTrie.Commit(nil) + var root common.Hash + if !commit { + root = stTrie.Hash() + } else { + root, _, _ = stTrie.Commit(nil) + } return root.Bytes() } -func (t *testHelper) Generate() (common.Hash, *diskLayer) { +func (t *testHelper) Commit() common.Hash { root, _, _ := t.accTrie.Commit(nil) t.triedb.Commit(root, false, nil) + return root +} + +func (t *testHelper) CommitAndGenerate() (common.Hash, *diskLayer) { + root := t.Commit() snap := generateSnapshot(t.diskdb, t.triedb, 16, root) return root, snap } @@ -249,26 +223,29 @@ func (t *testHelper) Generate() (common.Hash, *diskLayer) { // - extra slots in the end func TestGenerateExistentStateWithWrongStorage(t *testing.T) { helper := newHelper() - stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) // Account one, empty root but non-empty database helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) // Account two, non empty root but empty database + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // Miss slots { // Account three, non empty root but misses slots in the beginning + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"}) // Account four, non empty root but misses slots in the middle + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"}) // Account five, non empty root but misses slots in the end + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-5")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-5", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"}) } @@ -276,18 +253,22 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { // Wrong storage slots { // Account six, non empty root but wrong slots in the beginning + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"}) // Account seven, non empty root but wrong slots in the middle + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-7")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-7", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"}) // Account eight, non empty root but wrong slots in the end + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-8")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-8", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"}) // Account 9, non empty root but rotated slots + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-9")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-9", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"}) } @@ -295,19 +276,22 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { // Extra storage slots { // Account 10, non empty root but extra slots in the beginning + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-10")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-10", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"}) // Account 11, non empty root but extra slots in the middle + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-11")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-11", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"}) // Account 12, non empty root but extra slots in the end + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-12")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-12", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"}) } - root, snap := helper.Generate() + root, snap := helper.CommitAndGenerate() t.Logf("Root: %#x\n", root) // Root = 0x8746cce9fd9c658b2cfd639878ed6584b7a2b3e73bb40f607fcfa156002429a0 select { @@ -331,7 +315,12 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { // - extra accounts func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { helper := newHelper() - stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) + + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // Trie accounts [acc-1, acc-2, acc-3, acc-4, acc-6] // Extra accounts [acc-0, acc-5, acc-7] @@ -359,7 +348,7 @@ func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { helper.addSnapAccount("acc-7", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyRoot.Bytes()}) // after the end } - root, snap := helper.Generate() + root, snap := helper.CommitAndGenerate() t.Logf("Root: %#x\n", root) // Root = 0x825891472281463511e7ebcc7f109e4f9200c20fa384754e11fd605cd98464e8 select { @@ -383,29 +372,19 @@ func TestGenerateCorruptAccountTrie(t *testing.T) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // without any storage slots to keep the test smaller. - var ( - diskdb = memorydb.New() - triedb = trie.NewDatabase(diskdb) - ) - tr, _ := trie.NewSecure(common.Hash{}, triedb) - acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} - val, _ := rlp.EncodeToBytes(acc) - tr.Update([]byte("acc-1"), val) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 + helper := newHelper() - acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} - val, _ = rlp.EncodeToBytes(acc) - tr.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 - acc = &Account{Balance: big.NewInt(3), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} - val, _ = rlp.EncodeToBytes(acc) - tr.Update([]byte("acc-3"), val) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 - tr.Commit(nil) // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 + root, _, _ := helper.accTrie.Commit(nil) // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 // Delete an account trie leaf and ensure the generator chokes - triedb.Commit(common.HexToHash("0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978"), false, nil) - diskdb.Delete(common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7").Bytes()) + helper.triedb.Commit(root, false, nil) + helper.diskdb.Delete(common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7").Bytes()) - snap := generateSnapshot(diskdb, triedb, 16, common.HexToHash("0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978")) + snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) select { case <-snap.genPending: // Snapshot generation succeeded @@ -427,45 +406,30 @@ func TestGenerateMissingStorageTrie(t *testing.T) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - var ( - diskdb = memorydb.New() - triedb = trie.NewDatabase(diskdb) - ) - stTrie, _ := trie.NewSecure(common.Hash{}, triedb) - stTrie.Update([]byte("key-1"), []byte("val-1")) // 0x1314700b81afc49f94db3623ef1df38f3ed18b73a1b7ea2f6c095118cf6118a0 - stTrie.Update([]byte("key-2"), []byte("val-2")) // 0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371 - stTrie.Update([]byte("key-3"), []byte("val-3")) // 0x51c71a47af0695957647fb68766d0becee77e953df17c29b3c2f25436f055c78 - stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 - - accTrie, _ := trie.NewSecure(common.Hash{}, triedb) - acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} - val, _ := rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e - - acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} - val, _ = rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + helper := newHelper() - acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} - val, _ = rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 - accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 + root, _, _ := helper.accTrie.Commit(nil) // We can only corrupt the disk database, so flush the tries out - triedb.Reference( - common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), + helper.triedb.Reference( + common.BytesToHash(stRoot), common.HexToHash("0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e"), ) - triedb.Reference( - common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), + helper.triedb.Reference( + common.BytesToHash(stRoot), common.HexToHash("0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2"), ) - triedb.Commit(common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"), false, nil) + helper.triedb.Commit(root, false, nil) // Delete a storage trie root and ensure the generator chokes - diskdb.Delete(common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67").Bytes()) + helper.diskdb.Delete(stRoot) - snap := generateSnapshot(diskdb, triedb, 16, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd")) + snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) select { case <-snap.genPending: // Snapshot generation succeeded @@ -486,45 +450,31 @@ func TestGenerateCorruptStorageTrie(t *testing.T) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - var ( - diskdb = memorydb.New() - triedb = trie.NewDatabase(diskdb) - ) - stTrie, _ := trie.NewSecure(common.Hash{}, triedb) - stTrie.Update([]byte("key-1"), []byte("val-1")) // 0x1314700b81afc49f94db3623ef1df38f3ed18b73a1b7ea2f6c095118cf6118a0 - stTrie.Update([]byte("key-2"), []byte("val-2")) // 0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371 - stTrie.Update([]byte("key-3"), []byte("val-3")) // 0x51c71a47af0695957647fb68766d0becee77e953df17c29b3c2f25436f055c78 - stTrie.Commit(nil) // Root: 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 - - accTrie, _ := trie.NewSecure(common.Hash{}, triedb) - acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} - val, _ := rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper := newHelper() - acc = &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} - val, _ = rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-2"), val) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 - acc = &Account{Balance: big.NewInt(3), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} - val, _ = rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-3"), val) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 - accTrie.Commit(nil) // Root: 0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd + root, _, _ := helper.accTrie.Commit(nil) // We can only corrupt the disk database, so flush the tries out - triedb.Reference( - common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), + helper.triedb.Reference( + common.BytesToHash(stRoot), common.HexToHash("0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e"), ) - triedb.Reference( - common.HexToHash("0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67"), + helper.triedb.Reference( + common.BytesToHash(stRoot), common.HexToHash("0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2"), ) - triedb.Commit(common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd"), false, nil) + helper.triedb.Commit(root, false, nil) // Delete a storage trie leaf and ensure the generator chokes - diskdb.Delete(common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371").Bytes()) + helper.diskdb.Delete(common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371").Bytes()) - snap := generateSnapshot(diskdb, triedb, 16, common.HexToHash("0xe3712f1a226f3782caca78ca770ccc19ee000552813a9f59d479f8611db9b1fd")) + snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) select { case <-snap.genPending: // Snapshot generation succeeded @@ -539,56 +489,51 @@ func TestGenerateCorruptStorageTrie(t *testing.T) { <-stop } -func getStorageTrie(n int, triedb *trie.Database) *trie.SecureTrie { - stTrie, _ := trie.NewSecure(common.Hash{}, triedb) - for i := 0; i < n; i++ { - k := fmt.Sprintf("key-%d", i) - v := fmt.Sprintf("val-%d", i) - stTrie.Update([]byte(k), []byte(v)) - } - stTrie.Commit(nil) - return stTrie -} - // Tests that snapshot generation when an extra account with storage exists in the snap state. func TestGenerateWithExtraAccounts(t *testing.T) { - var ( - diskdb = memorydb.New() - triedb = trie.NewDatabase(diskdb) - stTrie = getStorageTrie(5, triedb) - ) - accTrie, _ := trie.NewSecure(common.Hash{}, triedb) - { // Account one in the trie - acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} + helper := newHelper() + { + // Account one in the trie + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), + []string{"key-1", "key-2", "key-3", "key-4", "key-5"}, + []string{"val-1", "val-2", "val-3", "val-4", "val-5"}, + true, + ) + acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()} val, _ := rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + // Identical in the snap key := hashData([]byte("acc-1")) - rawdb.WriteAccountSnapshot(diskdb, key, val) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("key-1")), []byte("val-1")) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("key-2")), []byte("val-2")) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("key-3")), []byte("val-3")) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("key-4")), []byte("val-4")) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("key-5")), []byte("val-5")) - } - { // Account two exists only in the snapshot - acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} + rawdb.WriteAccountSnapshot(helper.triedb.DiskDB(), key, val) + rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("key-1")), []byte("val-1")) + rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("key-2")), []byte("val-2")) + rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("key-3")), []byte("val-3")) + rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("key-4")), []byte("val-4")) + rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("key-5")), []byte("val-5")) + } + { + // Account two exists only in the snapshot + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-2")), + []string{"key-1", "key-2", "key-3", "key-4", "key-5"}, + []string{"val-1", "val-2", "val-3", "val-4", "val-5"}, + true, + ) + acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()} val, _ := rlp.EncodeToBytes(acc) key := hashData([]byte("acc-2")) - rawdb.WriteAccountSnapshot(diskdb, key, val) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("b-key-1")), []byte("b-val-1")) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("b-key-2")), []byte("b-val-2")) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("b-key-3")), []byte("b-val-3")) - } - root, _, _ := accTrie.Commit(nil) - t.Logf("root: %x", root) - triedb.Commit(root, false, nil) + rawdb.WriteAccountSnapshot(helper.triedb.DiskDB(), key, val) + rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("b-key-1")), []byte("b-val-1")) + rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("b-key-2")), []byte("b-val-2")) + rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("b-key-3")), []byte("b-val-3")) + } + root := helper.Commit() + // To verify the test: If we now inspect the snap db, there should exist extraneous storage items - if data := rawdb.ReadStorageSnapshot(diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data == nil { + if data := rawdb.ReadStorageSnapshot(helper.triedb.DiskDB(), hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data == nil { t.Fatalf("expected snap storage to exist") } - - snap := generateSnapshot(diskdb, triedb, 16, root) + snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) select { case <-snap.genPending: // Snapshot generation succeeded @@ -597,12 +542,13 @@ func TestGenerateWithExtraAccounts(t *testing.T) { t.Errorf("Snapshot generation failed") } checkSnapRoot(t, snap, root) + // Signal abortion to the generator and wait for it to tear down stop := make(chan *generatorStats) snap.genAbort <- stop <-stop // If we now inspect the snap db, there should exist no extraneous storage items - if data := rawdb.ReadStorageSnapshot(diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil { + if data := rawdb.ReadStorageSnapshot(helper.triedb.DiskDB(), hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil { t.Fatalf("expected slot to be removed, got %v", string(data)) } } @@ -616,37 +562,36 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) { if false { enableLogging() } - var ( - diskdb = memorydb.New() - triedb = trie.NewDatabase(diskdb) - stTrie = getStorageTrie(3, triedb) - ) - accTrie, _ := trie.NewSecure(common.Hash{}, triedb) - { // Account one in the trie - acc := &Account{Balance: big.NewInt(1), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} + helper := newHelper() + { + // Account one in the trie + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), + []string{"key-1", "key-2", "key-3"}, + []string{"val-1", "val-2", "val-3"}, + true, + ) + acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()} val, _ := rlp.EncodeToBytes(acc) - accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + // Identical in the snap key := hashData([]byte("acc-1")) - rawdb.WriteAccountSnapshot(diskdb, key, val) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("key-1")), []byte("val-1")) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("key-2")), []byte("val-2")) - rawdb.WriteStorageSnapshot(diskdb, key, hashData([]byte("key-3")), []byte("val-3")) + rawdb.WriteAccountSnapshot(helper.diskdb, key, val) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-1")), []byte("val-1")) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-2")), []byte("val-2")) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-3")), []byte("val-3")) } - { // 100 accounts exist only in snapshot + { + // 100 accounts exist only in snapshot for i := 0; i < 1000; i++ { //acc := &Account{Balance: big.NewInt(int64(i)), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} acc := &Account{Balance: big.NewInt(int64(i)), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} val, _ := rlp.EncodeToBytes(acc) key := hashData([]byte(fmt.Sprintf("acc-%d", i))) - rawdb.WriteAccountSnapshot(diskdb, key, val) + rawdb.WriteAccountSnapshot(helper.diskdb, key, val) } } - root, _, _ := accTrie.Commit(nil) - t.Logf("root: %x", root) - triedb.Commit(root, false, nil) - - snap := generateSnapshot(diskdb, triedb, 16, root) + root, snap := helper.CommitAndGenerate() select { case <-snap.genPending: // Snapshot generation succeeded @@ -675,31 +620,22 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) { if false { enableLogging() } - var ( - diskdb = memorydb.New() - triedb = trie.NewDatabase(diskdb) - ) - accTrie, _ := trie.New(common.Hash{}, triedb) + helper := newHelper() { acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} val, _ := rlp.EncodeToBytes(acc) - accTrie.Update(common.HexToHash("0x03").Bytes(), val) - accTrie.Update(common.HexToHash("0x07").Bytes(), val) - - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x01"), val) - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x02"), val) - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x03"), val) - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x04"), val) - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x05"), val) - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x06"), val) - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x07"), val) - } - - root, _, _ := accTrie.Commit(nil) - t.Logf("root: %x", root) - triedb.Commit(root, false, nil) - - snap := generateSnapshot(diskdb, triedb, 16, root) + helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val) + helper.accTrie.Update(common.HexToHash("0x07").Bytes(), val) + + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x01"), val) + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x02"), val) + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x03"), val) + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x04"), val) + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x05"), val) + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x06"), val) + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x07"), val) + } + root, snap := helper.CommitAndGenerate() select { case <-snap.genPending: // Snapshot generation succeeded @@ -721,29 +657,20 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) { if false { enableLogging() } - var ( - diskdb = memorydb.New() - triedb = trie.NewDatabase(diskdb) - ) - accTrie, _ := trie.New(common.Hash{}, triedb) + helper := newHelper() { acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} val, _ := rlp.EncodeToBytes(acc) - accTrie.Update(common.HexToHash("0x03").Bytes(), val) + helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val) junk := make([]byte, 100) copy(junk, []byte{0xde, 0xad}) - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x02"), junk) - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x03"), junk) - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x04"), junk) - rawdb.WriteAccountSnapshot(diskdb, common.HexToHash("0x05"), junk) + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x02"), junk) + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x03"), junk) + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x04"), junk) + rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x05"), junk) } - - root, _, _ := accTrie.Commit(nil) - t.Logf("root: %x", root) - triedb.Commit(root, false, nil) - - snap := generateSnapshot(diskdb, triedb, 16, root) + root, snap := helper.CommitAndGenerate() select { case <-snap.genPending: // Snapshot generation succeeded @@ -757,7 +684,7 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) { snap.genAbort <- stop <-stop // If we now inspect the snap db, there should exist no extraneous storage items - if data := rawdb.ReadStorageSnapshot(diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil { + if data := rawdb.ReadStorageSnapshot(helper.diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil { t.Fatalf("expected slot to be removed, got %v", string(data)) } } @@ -767,13 +694,13 @@ func TestGenerateFromEmptySnap(t *testing.T) { accountCheckRange = 10 storageCheckRange = 20 helper := newHelper() - stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) // Add 1K accounts to the trie for i := 0; i < 400; i++ { + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte(fmt.Sprintf("acc-%d", i))), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount(fmt.Sprintf("acc-%d", i), &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) } - root, snap := helper.Generate() + root, snap := helper.CommitAndGenerate() t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4 select { @@ -802,12 +729,12 @@ func TestGenerateWithIncompleteStorage(t *testing.T) { helper := newHelper() stKeys := []string{"1", "2", "3", "4", "5", "6", "7", "8"} stVals := []string{"v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"} - stRoot := helper.makeStorageTrie(stKeys, stVals) // We add 8 accounts, each one is missing exactly one of the storage slots. This means // we don't have to order the keys and figure out exactly which hash-key winds up // on the sensitive spots at the boundaries for i := 0; i < 8; i++ { accKey := fmt.Sprintf("acc-%d", i) + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte(accKey)), stKeys, stVals, true) helper.addAccount(accKey, &Account{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: emptyCode.Bytes()}) var moddedKeys []string var moddedVals []string @@ -819,8 +746,7 @@ func TestGenerateWithIncompleteStorage(t *testing.T) { } helper.addSnapStorage(accKey, moddedKeys, moddedVals) } - - root, snap := helper.Generate() + root, snap := helper.CommitAndGenerate() t.Logf("Root: %#x\n", root) // Root: 0xca73f6f05ba4ca3024ef340ef3dfca8fdabc1b677ff13f5a9571fd49c16e67ff select { @@ -899,7 +825,7 @@ func populateDangling(disk ethdb.KeyValueStore) { // This test will populate some dangling storages to see if they can be cleaned up. func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { var helper = newHelper() - stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) + stRoot := helper.makeStorageTrie(common.Hash{}, common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) @@ -910,7 +836,7 @@ func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { populateDangling(helper.diskdb) - root, snap := helper.Generate() + root, snap := helper.CommitAndGenerate() select { case <-snap.genPending: // Snapshot generation succeeded @@ -932,7 +858,7 @@ func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { // This test will populate some dangling storages to see if they can be cleaned up. func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) { var helper = newHelper() - stRoot := helper.makeStorageTrie([]string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) + stRoot := helper.makeStorageTrie(common.Hash{}, common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) @@ -940,7 +866,7 @@ func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) { populateDangling(helper.diskdb) - root, snap := helper.Generate() + root, snap := helper.CommitAndGenerate() select { case <-snap.genPending: // Snapshot generation succeeded diff --git a/core/state/state_object.go b/core/state/state_object.go index bcb6dca4f56b..1ffb7eb40228 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -154,7 +154,7 @@ func (s *stateObject) getTrie(db Database) Trie { if s.data.Root != emptyRoot && s.db.prefetcher != nil { // When the miner is creating the pending state, there is no // prefetcher - s.trie = s.db.prefetcher.trie(s.data.Root) + s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root) } if s.trie == nil { var err error @@ -295,7 +295,7 @@ func (s *stateObject) finalise(prefetch bool) { } } if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != emptyRoot { - s.db.prefetcher.prefetch(s.data.Root, slotsToPrefetch) + s.db.prefetcher.prefetch(s.addrHash, s.data.Root, slotsToPrefetch) } if len(s.dirtyStorage) > 0 { s.dirtyStorage = make(Storage) @@ -352,7 +352,7 @@ func (s *stateObject) updateTrie(db Database) Trie { usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure } if s.db.prefetcher != nil { - s.db.prefetcher.used(s.data.Root, usedStorage) + s.db.prefetcher.used(s.addrHash, s.data.Root, usedStorage) } if len(s.pendingStorage) > 0 { s.pendingStorage = make(Storage) diff --git a/core/state/statedb.go b/core/state/statedb.go index 1d31cf470be0..a36d65fce791 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -62,11 +62,14 @@ func (n *proofList) Delete(key []byte) error { // * Contracts // * Accounts type StateDB struct { - db Database - prefetcher *triePrefetcher - originalRoot common.Hash // The pre-state root, before any changes were made - trie Trie - hasher crypto.KeccakState + db Database + prefetcher *triePrefetcher + trie Trie + hasher crypto.KeccakState + + // originalRoot is the pre-state root, before any changes were made. + // It will be updated when the Commit is called. + originalRoot common.Hash snaps *snapshot.Tree snap snapshot.Snapshot @@ -648,6 +651,7 @@ func (s *StateDB) Copy() *StateDB { state := &StateDB{ db: s.db, trie: s.db.CopyTrie(s.trie), + originalRoot: s.originalRoot, stateObjects: make(map[common.Address]*stateObject, len(s.journal.dirties)), stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)), stateObjectsDirty: make(map[common.Address]struct{}, len(s.journal.dirties)), @@ -810,7 +814,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure } if s.prefetcher != nil && len(addressesToPrefetch) > 0 { - s.prefetcher.prefetch(s.originalRoot, addressesToPrefetch) + s.prefetcher.prefetch(common.Hash{}, s.originalRoot, addressesToPrefetch) } // Invalidate journal because reverting across transactions is not allowed. s.clearJournalAndRefund() @@ -851,7 +855,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // _untouched_. We can check with the prefetcher, if it can give us a trie // which has the same root, but also has some content loaded into it. if prefetcher != nil { - if trie := prefetcher.trie(s.originalRoot); trie != nil { + if trie := prefetcher.trie(common.Hash{}, s.originalRoot); trie != nil { s.trie = trie } } @@ -867,7 +871,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { usedAddrs = append(usedAddrs, common.CopyBytes(addr[:])) // Copy needed for closure } if prefetcher != nil { - prefetcher.used(s.originalRoot, usedAddrs) + prefetcher.used(common.Hash{}, s.originalRoot, usedAddrs) } if len(s.stateObjectsPending) > 0 { s.stateObjectsPending = make(map[common.Address]struct{}) @@ -980,6 +984,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { } s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil } + s.originalRoot = root return root, err } diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 007590c76d9c..83c5aa2df7a8 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -104,7 +104,7 @@ func checkTrieConsistency(db ethdb.Database, root common.Hash) error { if v, _ := db.Get(root[:]); v == nil { return nil // Consider a non existent state consistent. } - trie, err := trie.New(root, trie.NewDatabase(db)) + trie, err := trie.New(common.Hash{}, root, trie.NewDatabase(db)) if err != nil { return err } @@ -166,7 +166,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { if commit { srcDb.TrieDB().Commit(srcRoot, false, nil) } - srcTrie, _ := trie.New(srcRoot, srcDb.TrieDB()) + srcTrie, _ := trie.New(common.Hash{}, srcRoot, srcDb.TrieDB()) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() @@ -207,7 +207,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { if err := rlp.DecodeBytes(srcTrie.Get(path[0]), &acc); err != nil { t.Fatalf("failed to decode account on path %x: %v", path, err) } - stTrie, err := trie.New(acc.Root, srcDb.TrieDB()) + stTrie, err := trie.New(common.BytesToHash(path[0]), acc.Root, srcDb.TrieDB()) if err != nil { t.Fatalf("failed to retriev storage trie for path %x: %v", path, err) } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 25c3730e3f7a..4c817b1bc6fb 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -25,7 +25,7 @@ import ( ) var ( - // triePrefetchMetricsPrefix is the prefix under which to publis the metrics. + // triePrefetchMetricsPrefix is the prefix under which to publish the metrics. triePrefetchMetricsPrefix = "trie/prefetch/" ) @@ -35,10 +35,10 @@ var ( // // Note, the prefetcher's API is not thread safe. type triePrefetcher struct { - db Database // Database to fetch trie nodes through - root common.Hash // Root hash of theaccount trie for metrics - fetches map[common.Hash]Trie // Partially or fully fetcher tries - fetchers map[common.Hash]*subfetcher // Subfetchers for each trie + db Database // Database to fetch trie nodes through + root common.Hash // Root hash of the account trie for metrics + fetches map[string]Trie // Partially or fully fetcher tries + fetchers map[string]*subfetcher // Subfetchers for each trie deliveryMissMeter metrics.Meter accountLoadMeter metrics.Meter @@ -51,13 +51,12 @@ type triePrefetcher struct { storageWasteMeter metrics.Meter } -// newTriePrefetcher func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePrefetcher { prefix := triePrefetchMetricsPrefix + namespace p := &triePrefetcher{ db: db, root: root, - fetchers: make(map[common.Hash]*subfetcher), // Active prefetchers use the fetchers map + fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil), accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil), @@ -112,7 +111,7 @@ func (p *triePrefetcher) copy() *triePrefetcher { copy := &triePrefetcher{ db: p.db, root: p.root, - fetches: make(map[common.Hash]Trie), // Active prefetchers use the fetches map + fetches: make(map[string]Trie), // Active prefetchers use the fetches map deliveryMissMeter: p.deliveryMissMeter, accountLoadMeter: p.accountLoadMeter, @@ -132,33 +131,35 @@ func (p *triePrefetcher) copy() *triePrefetcher { return copy } // Otherwise we're copying an active fetcher, retrieve the current states - for root, fetcher := range p.fetchers { - copy.fetches[root] = fetcher.peek() + for id, fetcher := range p.fetchers { + copy.fetches[id] = fetcher.peek() } return copy } // prefetch schedules a batch of trie items to prefetch. -func (p *triePrefetcher) prefetch(root common.Hash, keys [][]byte) { +func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, keys [][]byte) { // If the prefetcher is an inactive one, bail out if p.fetches != nil { return } // Active fetcher, schedule the retrievals - fetcher := p.fetchers[root] + id := p.trieID(owner, root) + fetcher := p.fetchers[id] if fetcher == nil { - fetcher = newSubfetcher(p.db, root) - p.fetchers[root] = fetcher + fetcher = newSubfetcher(p.db, owner, root) + p.fetchers[id] = fetcher } fetcher.schedule(keys) } // trie returns the trie matching the root hash, or nil if the prefetcher doesn't // have it. -func (p *triePrefetcher) trie(root common.Hash) Trie { +func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie { // If the prefetcher is inactive, return from existing deep copies + id := p.trieID(owner, root) if p.fetches != nil { - trie := p.fetches[root] + trie := p.fetches[id] if trie == nil { p.deliveryMissMeter.Mark(1) return nil @@ -166,7 +167,7 @@ func (p *triePrefetcher) trie(root common.Hash) Trie { return p.db.CopyTrie(trie) } // Otherwise the prefetcher is active, bail if no trie was prefetched for this root - fetcher := p.fetchers[root] + fetcher := p.fetchers[id] if fetcher == nil { p.deliveryMissMeter.Mark(1) return nil @@ -185,20 +186,26 @@ func (p *triePrefetcher) trie(root common.Hash) Trie { // used marks a batch of state items used to allow creating statistics as to // how useful or wasteful the prefetcher is. -func (p *triePrefetcher) used(root common.Hash, used [][]byte) { - if fetcher := p.fetchers[root]; fetcher != nil { +func (p *triePrefetcher) used(owner common.Hash, root common.Hash, used [][]byte) { + if fetcher := p.fetchers[p.trieID(owner, root)]; fetcher != nil { fetcher.used = used } } +// trieID returns an unique trie identifier consists the trie owner and root hash. +func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string { + return string(append(owner.Bytes(), root.Bytes()...)) +} + // subfetcher is a trie fetcher goroutine responsible for pulling entries for a // single trie. It is spawned when a new root is encountered and lives until the // main prefetcher is paused and either all requested items are processed or if // the trie being worked on is retrieved from the prefetcher. type subfetcher struct { - db Database // Database to load trie nodes through - root common.Hash // Root hash of the trie to prefetch - trie Trie // Trie being populated with nodes + db Database // Database to load trie nodes through + owner common.Hash // Owner of the trie, usually account hash + root common.Hash // Root hash of the trie to prefetch + trie Trie // Trie being populated with nodes tasks [][]byte // Items queued up for retrieval lock sync.Mutex // Lock protecting the task queue @@ -215,15 +222,16 @@ type subfetcher struct { // newSubfetcher creates a goroutine to prefetch state items belonging to a // particular root hash. -func newSubfetcher(db Database, root common.Hash) *subfetcher { +func newSubfetcher(db Database, owner common.Hash, root common.Hash) *subfetcher { sf := &subfetcher{ - db: db, - root: root, - wake: make(chan struct{}, 1), - stop: make(chan struct{}), - term: make(chan struct{}), - copy: make(chan chan Trie), - seen: make(map[string]struct{}), + db: db, + owner: owner, + root: root, + wake: make(chan struct{}, 1), + stop: make(chan struct{}), + term: make(chan struct{}), + copy: make(chan chan Trie), + seen: make(map[string]struct{}), } go sf.loop() return sf @@ -279,13 +287,21 @@ func (sf *subfetcher) loop() { defer close(sf.term) // Start by opening the trie and stop processing if it fails - trie, err := sf.db.OpenTrie(sf.root) - if err != nil { - log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) - return + if sf.owner == (common.Hash{}) { + trie, err := sf.db.OpenTrie(sf.root) + if err != nil { + log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) + return + } + sf.trie = trie + } else { + trie, err := sf.db.OpenStorageTrie(sf.owner, sf.root) + if err != nil { + log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) + return + } + sf.trie = trie } - sf.trie = trie - // Trie opened successfully, keep prefetching items for { select { diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index 35dc7a2c0da4..cb0b67d7ea79 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -47,20 +47,20 @@ func TestCopyAndClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(db.originalRoot, [][]byte{skey.Bytes()}) - prefetcher.prefetch(db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) time.Sleep(1 * time.Second) - a := prefetcher.trie(db.originalRoot) - prefetcher.prefetch(db.originalRoot, [][]byte{skey.Bytes()}) - b := prefetcher.trie(db.originalRoot) + a := prefetcher.trie(common.Hash{}, db.originalRoot) + prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + b := prefetcher.trie(common.Hash{}, db.originalRoot) cpy := prefetcher.copy() - cpy.prefetch(db.originalRoot, [][]byte{skey.Bytes()}) - cpy.prefetch(db.originalRoot, [][]byte{skey.Bytes()}) - c := cpy.trie(db.originalRoot) + cpy.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + cpy.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + c := cpy.trie(common.Hash{}, db.originalRoot) prefetcher.close() cpy2 := cpy.copy() - cpy2.prefetch(db.originalRoot, [][]byte{skey.Bytes()}) - d := cpy2.trie(db.originalRoot) + cpy2.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + d := cpy2.trie(common.Hash{}, db.originalRoot) cpy.close() cpy2.close() if a.Hash() != b.Hash() || a.Hash() != c.Hash() || a.Hash() != d.Hash() { @@ -72,10 +72,10 @@ func TestUseAfterClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(db.originalRoot, [][]byte{skey.Bytes()}) - a := prefetcher.trie(db.originalRoot) + prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + a := prefetcher.trie(common.Hash{}, db.originalRoot) prefetcher.close() - b := prefetcher.trie(db.originalRoot) + b := prefetcher.trie(common.Hash{}, db.originalRoot) if a == nil { t.Fatal("Prefetching before close should not return nil") } @@ -88,13 +88,13 @@ func TestCopyClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) cpy := prefetcher.copy() - a := prefetcher.trie(db.originalRoot) - b := cpy.trie(db.originalRoot) + a := prefetcher.trie(common.Hash{}, db.originalRoot) + b := cpy.trie(common.Hash{}, db.originalRoot) prefetcher.close() - c := prefetcher.trie(db.originalRoot) - d := cpy.trie(db.originalRoot) + c := prefetcher.trie(common.Hash{}, db.originalRoot) + d := cpy.trie(common.Hash{}, db.originalRoot) if a == nil { t.Fatal("Prefetching before close should not return nil") } diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index de71ee41a47d..44726c9cbb9f 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -39,8 +39,7 @@ func TestDeriveSha(t *testing.T) { t.Fatal(err) } for len(txs) < 1000 { - tr, _ := trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase())) - exp := types.DeriveSha(txs, tr) + exp := types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) got := types.DeriveSha(txs, trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp) @@ -87,8 +86,7 @@ func BenchmarkDeriveSha200(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - tr, _ := trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase())) - exp = types.DeriveSha(txs, tr) + exp = types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) } }) @@ -109,8 +107,7 @@ func TestFuzzDeriveSha(t *testing.T) { rndSeed := mrand.Int() for i := 0; i < 10; i++ { seed := rndSeed + i - tr, _ := trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase())) - exp := types.DeriveSha(newDummy(i), tr) + exp := types.DeriveSha(newDummy(i), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { printList(newDummy(seed)) @@ -138,8 +135,7 @@ func TestDerivableList(t *testing.T) { }, } for i, tc := range tcs[1:] { - tr, _ := trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase())) - exp := types.DeriveSha(flatList(tc), tr) + exp := types.DeriveSha(flatList(tc), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) got := types.DeriveSha(flatList(tc), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { t.Fatalf("case %d: got %x exp %x", i, got, exp) diff --git a/eth/api.go b/eth/api.go index ef69acb76eb4..b2260a32ade1 100644 --- a/eth/api.go +++ b/eth/api.go @@ -529,11 +529,11 @@ func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Bloc } triedb := api.eth.BlockChain().StateCache().TrieDB() - oldTrie, err := trie.NewSecure(startBlock.Root(), triedb) + oldTrie, err := trie.NewSecure(common.Hash{}, startBlock.Root(), triedb) if err != nil { return nil, err } - newTrie, err := trie.NewSecure(endBlock.Root(), triedb) + newTrie, err := trie.NewSecure(common.Hash{}, endBlock.Root(), triedb) if err != nil { return nil, err } diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 23638ef88884..7ecf041e9a54 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -285,7 +285,7 @@ func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePac req.Bytes = softResponseLimit } // Retrieve the requested state and bail out if non existent - tr, err := trie.New(req.Root, chain.StateCache().TrieDB()) + tr, err := trie.New(common.Hash{}, req.Root, chain.StateCache().TrieDB()) if err != nil { return nil, nil } @@ -415,7 +415,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP if origin != (common.Hash{}) || (abort && len(storage) > 0) { // Request started at a non-zero hash or was capped prematurely, add // the endpoint Merkle proofs - accTrie, err := trie.New(req.Root, chain.StateCache().TrieDB()) + accTrie, err := trie.New(common.Hash{}, req.Root, chain.StateCache().TrieDB()) if err != nil { return nil, nil } @@ -423,7 +423,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP if err := rlp.DecodeBytes(accTrie.Get(account[:]), &acc); err != nil { return nil, nil } - stTrie, err := trie.New(acc.Root, chain.StateCache().TrieDB()) + stTrie, err := trie.New(account, acc.Root, chain.StateCache().TrieDB()) if err != nil { return nil, nil } @@ -489,7 +489,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s // Make sure we have the state associated with the request triedb := chain.StateCache().TrieDB() - accTrie, err := trie.NewSecure(req.Root, triedb) + accTrie, err := trie.NewSecure(common.Hash{}, req.Root, triedb) if err != nil { // We don't have the requested state available, bail out return nil, nil @@ -531,7 +531,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s if err != nil || account == nil { break } - stTrie, err := trie.NewSecure(common.BytesToHash(account.Root), triedb) + stTrie, err := trie.NewSecure(common.BytesToHash(pathset[0]), common.BytesToHash(account.Root), triedb) loads++ // always account database reads, even for failures if err != nil { break diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 415253c839be..76072eb06c40 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -712,7 +712,7 @@ func (s *Syncer) loadSyncStatus() { } task.genTrie = trie.NewStackTrie(task.genBatch) - for _, subtasks := range task.SubTasks { + for accountHash, subtasks := range task.SubTasks { for _, subtask := range subtasks { subtask.genBatch = ethdb.HookedBatch{ Batch: s.db.NewBatch(), @@ -720,7 +720,7 @@ func (s *Syncer) loadSyncStatus() { s.storageBytes += common.StorageSize(len(key) + len(value)) }, } - subtask.genTrie = trie.NewStackTrie(subtask.genBatch) + subtask.genTrie = trie.NewStackTrieWithOwner(subtask.genBatch, accountHash) } } } @@ -1971,7 +1971,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { Last: r.End(), root: acc.Root, genBatch: batch, - genTrie: trie.NewStackTrie(batch), + genTrie: trie.NewStackTrieWithOwner(batch, account), }) for r.Next() { batch := ethdb.HookedBatch{ @@ -1985,7 +1985,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { Last: r.End(), root: acc.Root, genBatch: batch, - genTrie: trie.NewStackTrie(batch), + genTrie: trie.NewStackTrieWithOwner(batch, account), }) } for _, task := range tasks { @@ -2030,7 +2030,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { slots += len(res.hashes[i]) if i < len(res.hashes)-1 || res.subTask == nil { - tr := trie.NewStackTrie(batch) + tr := trie.NewStackTrieWithOwner(batch, account) for j := 0; j < len(res.hashes[i]); j++ { tr.Update(res.hashes[i][j][:], res.slots[i][j]) } diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index e727544fa450..5eab6dd844e6 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1349,7 +1349,7 @@ func getCodeByHash(hash common.Hash) []byte { // makeAccountTrieNoStorage spits out a trie, along with the leafs func makeAccountTrieNoStorage(n int) (*trie.Trie, entrySlice) { db := trie.NewDatabase(rawdb.NewMemoryDatabase()) - accTrie, _ := trie.New(common.Hash{}, db) + accTrie := trie.NewEmpty(db) var entries entrySlice for i := uint64(1); i <= uint64(n); i++ { value, _ := rlp.EncodeToBytes(&types.StateAccount{ @@ -1376,8 +1376,8 @@ func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) { entries entrySlice boundaries []common.Hash - db = trie.NewDatabase(rawdb.NewMemoryDatabase()) - trie, _ = trie.New(common.Hash{}, db) + db = trie.NewDatabase(rawdb.NewMemoryDatabase()) + trie = trie.NewEmpty(db) ) // Initialize boundaries var next common.Hash @@ -1429,7 +1429,7 @@ func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) { func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) (*trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) - accTrie, _ = trie.New(common.Hash{}, db) + accTrie = trie.NewEmpty(db) entries entrySlice storageTries = make(map[common.Hash]*trie.Trie) storageEntries = make(map[common.Hash]entrySlice) @@ -1442,7 +1442,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) codehash = getCodeHash(i) } // Create a storage trie - stTrie, stEntries := makeStorageTrieWithSeed(uint64(slots), i, db) + stTrie, stEntries := makeStorageTrieWithSeed(common.BytesToHash(key), uint64(slots), i, db) stRoot := stTrie.Hash() stTrie.Commit(nil) value, _ := rlp.EncodeToBytes(&types.StateAccount{ @@ -1468,23 +1468,11 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) - accTrie, _ = trie.New(common.Hash{}, db) + accTrie = trie.NewEmpty(db) entries entrySlice storageTries = make(map[common.Hash]*trie.Trie) storageEntries = make(map[common.Hash]entrySlice) ) - // Make a storage trie which we reuse for the whole lot - var ( - stTrie *trie.Trie - stEntries entrySlice - ) - if boundary { - stTrie, stEntries = makeBoundaryStorageTrie(slots, db) - } else { - stTrie, stEntries = makeStorageTrieWithSeed(uint64(slots), 0, db) - } - stRoot := stTrie.Hash() - // Create n accounts in the trie for i := uint64(1); i <= uint64(accounts); i++ { key := key32(i) @@ -1492,6 +1480,19 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie if code { codehash = getCodeHash(i) } + // Make a storage trie + var ( + stTrie *trie.Trie + stEntries entrySlice + ) + if boundary { + stTrie, stEntries = makeBoundaryStorageTrie(common.BytesToHash(key), slots, db) + } else { + stTrie, stEntries = makeStorageTrieWithSeed(common.BytesToHash(key), uint64(slots), 0, db) + } + stRoot := stTrie.Hash() + stTrie.Commit(nil) + value, _ := rlp.EncodeToBytes(&types.StateAccount{ Nonce: i, Balance: big.NewInt(int64(i)), @@ -1506,7 +1507,6 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie storageEntries[common.BytesToHash(key)] = stEntries } sort.Sort(entries) - stTrie.Commit(nil) accTrie.Commit(nil) return accTrie, entries, storageTries, storageEntries } @@ -1514,8 +1514,8 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie // makeStorageTrieWithSeed fills a storage trie with n items, returning the // not-yet-committed trie and the sorted entries. The seeds can be used to ensure // that tries are unique. -func makeStorageTrieWithSeed(n, seed uint64, db *trie.Database) (*trie.Trie, entrySlice) { - trie, _ := trie.New(common.Hash{}, db) +func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (*trie.Trie, entrySlice) { + trie, _ := trie.New(owner, common.Hash{}, db) var entries entrySlice for i := uint64(1); i <= n; i++ { // store 'x' at slot 'x' @@ -1537,11 +1537,11 @@ func makeStorageTrieWithSeed(n, seed uint64, db *trie.Database) (*trie.Trie, ent // makeBoundaryStorageTrie constructs a storage trie. Instead of filling // storage slots normally, this function will fill a few slots which have // boundary hash. -func makeBoundaryStorageTrie(n int, db *trie.Database) (*trie.Trie, entrySlice) { +func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (*trie.Trie, entrySlice) { var ( entries entrySlice boundaries []common.Hash - trie, _ = trie.New(common.Hash{}, db) + trie, _ = trie.New(owner, common.Hash{}, db) ) // Initialize boundaries var next common.Hash @@ -1588,7 +1588,7 @@ func makeBoundaryStorageTrie(n int, db *trie.Database) (*trie.Trie, entrySlice) func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { t.Helper() triedb := trie.NewDatabase(db) - accTrie, err := trie.New(root, triedb) + accTrie, err := trie.New(common.Hash{}, root, triedb) if err != nil { t.Fatal(err) } @@ -1606,7 +1606,7 @@ func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { } accounts++ if acc.Root != emptyRoot { - storeTrie, err := trie.NewSecure(acc.Root, triedb) + storeTrie, err := trie.NewSecure(common.BytesToHash(accIt.Key), acc.Root, triedb) if err != nil { t.Fatal(err) } diff --git a/les/downloader/downloader_test.go b/les/downloader/downloader_test.go index f6510eb41237..b4b12b1b2957 100644 --- a/les/downloader/downloader_test.go +++ b/les/downloader/downloader_test.go @@ -229,7 +229,7 @@ func (dl *downloadTester) CurrentFastBlock() *types.Block { func (dl *downloadTester) FastSyncCommitHead(hash common.Hash) error { // For now only check that the state trie is correct if block := dl.GetBlockByHash(hash); block != nil { - _, err := trie.NewSecure(block.Root(), trie.NewDatabase(dl.stateDb)) + _, err := trie.NewSecure(common.Hash{}, block.Root(), trie.NewDatabase(dl.stateDb)) return err } return fmt.Errorf("non existent block: %x", hash[:4]) diff --git a/les/handler_test.go b/les/handler_test.go index aba45764b306..56d7d55b5a5f 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -405,7 +405,7 @@ func testGetProofs(t *testing.T, protocol int) { accounts := []common.Address{bankAddr, userAddr1, userAddr2, signerAddr, {}} for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ { header := bc.GetHeaderByNumber(i) - trie, _ := trie.New(header.Root, trie.NewDatabase(server.db)) + trie, _ := trie.New(common.Hash{}, header.Root, trie.NewDatabase(server.db)) for _, acc := range accounts { req := ProofReq{ @@ -456,7 +456,7 @@ func testGetStaleProof(t *testing.T, protocol int) { var expected []rlp.RawValue if wantOK { proofsV2 := light.NewNodeSet() - t, _ := trie.New(header.Root, trie.NewDatabase(server.db)) + t, _ := trie.New(common.Hash{}, header.Root, trie.NewDatabase(server.db)) t.Prove(account, 0, proofsV2) expected = proofsV2.NodeList() } @@ -512,7 +512,7 @@ func testGetCHTProofs(t *testing.T, protocol int) { AuxData: [][]byte{rlp}, } root := light.GetChtRoot(server.db, 0, bc.GetHeaderByNumber(config.ChtSize-1).Hash()) - trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(server.db, light.ChtTablePrefix))) + trie, _ := trie.New(common.Hash{}, root, trie.NewDatabase(rawdb.NewTable(server.db, light.ChtTablePrefix))) trie.Prove(key, 0, &proofsV2.Proofs) // Assemble the requests for the different protocols requestsV2 := []HelperTrieReq{{ @@ -577,7 +577,7 @@ func testGetBloombitsProofs(t *testing.T, protocol int) { var proofs HelperTrieResps root := light.GetBloomTrieRoot(server.db, 0, bc.GetHeaderByNumber(config.BloomTrieSize-1).Hash()) - trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(server.db, light.BloomTrieTablePrefix))) + trie, _ := trie.New(common.Hash{}, root, trie.NewDatabase(rawdb.NewTable(server.db, light.BloomTrieTablePrefix))) trie.Prove(key, 0, &proofs.Proofs) // Send the proof request and verify the response diff --git a/les/server_handler.go b/les/server_handler.go index ef1af844c26b..a199a34a7254 100644 --- a/les/server_handler.go +++ b/les/server_handler.go @@ -359,7 +359,7 @@ func (h *serverHandler) AddTxsSync() bool { // getAccount retrieves an account from the state based on root. func getAccount(triedb *trie.Database, root, hash common.Hash) (types.StateAccount, error) { - trie, err := trie.New(root, triedb) + trie, err := trie.New(common.Hash{}, root, triedb) if err != nil { return types.StateAccount{}, err } @@ -391,7 +391,7 @@ func (h *serverHandler) GetHelperTrie(typ uint, index uint64) *trie.Trie { if root == (common.Hash{}) { return nil } - trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(h.chainDb, prefix))) + trie, _ := trie.New(common.Hash{}, root, trie.NewDatabase(rawdb.NewTable(h.chainDb, prefix))) return trie } diff --git a/light/odr_test.go b/light/odr_test.go index fdf657a82ec5..ec109f61f2bf 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -82,7 +82,7 @@ func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error { req.Receipts = rawdb.ReadRawReceipts(odr.sdb, req.Hash, *number) } case *TrieRequest: - t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb)) + t, _ := trie.New(common.BytesToHash(req.Id.AccKey), req.Id.Root, trie.NewDatabase(odr.sdb)) nodes := NewNodeSet() t.Prove(req.Key, 0, nodes) req.Proof = nodes diff --git a/light/postprocess.go b/light/postprocess.go index ce38d091e891..c09b00e71c81 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -187,12 +187,12 @@ func (c *ChtIndexerBackend) Reset(ctx context.Context, section uint64, lastSecti root = GetChtRoot(c.diskdb, section-1, lastSectionHead) } var err error - c.trie, err = trie.New(root, c.triedb) + c.trie, err = trie.New(common.Hash{}, root, c.triedb) if err != nil && c.odr != nil { err = c.fetchMissingNodes(ctx, section, root) if err == nil { - c.trie, err = trie.New(root, c.triedb) + c.trie, err = trie.New(common.Hash{}, root, c.triedb) } } c.section = section @@ -253,9 +253,8 @@ func (c *ChtIndexerBackend) Commit() error { return nil } -// PruneSections implements core.ChainIndexerBackend which deletes all -// chain data(except hash<->number mappings) older than the specified -// threshold. +// Prune implements core.ChainIndexerBackend which deletes all chain data +// (except hash<->number mappings) older than the specified threshold. func (c *ChtIndexerBackend) Prune(threshold uint64) error { // Short circuit if the light pruning is disabled. if c.disablePruning { @@ -404,11 +403,11 @@ func (b *BloomTrieIndexerBackend) Reset(ctx context.Context, section uint64, las root = GetBloomTrieRoot(b.diskdb, section-1, lastSectionHead) } var err error - b.trie, err = trie.New(root, b.triedb) + b.trie, err = trie.New(common.Hash{}, root, b.triedb) if err != nil && b.odr != nil { err = b.fetchMissingNodes(ctx, section, root) if err == nil { - b.trie, err = trie.New(root, b.triedb) + b.trie, err = trie.New(common.Hash{}, root, b.triedb) } } b.section = section diff --git a/light/trie.go b/light/trie.go index 4ab6f4ace075..931ba30cb40a 100644 --- a/light/trie.go +++ b/light/trie.go @@ -169,7 +169,11 @@ func (t *odrTrie) do(key []byte, fn func() error) error { for { var err error if t.trie == nil { - t.trie, err = trie.New(t.id.Root, trie.NewDatabase(t.db.backend.Database())) + var owner common.Hash + if len(t.id.AccKey) > 0 { + owner = common.BytesToHash(t.id.AccKey) + } + t.trie, err = trie.New(owner, t.id.Root, trie.NewDatabase(t.db.backend.Database())) } if err == nil { err = fn() @@ -195,7 +199,11 @@ func newNodeIterator(t *odrTrie, startkey []byte) trie.NodeIterator { // Open the actual non-ODR trie if that hasn't happened yet. if t.trie == nil { it.do(func() error { - t, err := trie.New(t.id.Root, trie.NewDatabase(t.db.backend.Database())) + var owner common.Hash + if len(t.id.AccKey) > 0 { + owner = common.BytesToHash(t.id.AccKey) + } + t, err := trie.New(owner, t.id.Root, trie.NewDatabase(t.db.backend.Database())) if err == nil { it.t.trie = t } diff --git a/tests/fuzzers/les/les-fuzzer.go b/tests/fuzzers/les/les-fuzzer.go index 3e1017187345..677702208871 100644 --- a/tests/fuzzers/les/les-fuzzer.go +++ b/tests/fuzzers/les/les-fuzzer.go @@ -88,8 +88,8 @@ func makechain() (bc *core.BlockChain, addrHashes, txHashes []common.Hash) { } func makeTries() (chtTrie *trie.Trie, bloomTrie *trie.Trie, chtKeys, bloomKeys [][]byte) { - chtTrie, _ = trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase())) - bloomTrie, _ = trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase())) + chtTrie = trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())) + bloomTrie = trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < testChainLen; i++ { // The element in CHT is -> key := make([]byte, 8) diff --git a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go index 18717e70d001..229dea95b1c4 100644 --- a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go +++ b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go @@ -62,7 +62,7 @@ func (f *fuzzer) readInt() uint64 { } func (f *fuzzer) randomTrie(n int) (*trie.Trie, map[string]*kv) { - trie, _ := trie.New(common.Hash{}, trie.NewDatabase(rawdb.NewMemoryDatabase())) + trie := trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())) vals := make(map[string]*kv) size := f.readInt() // Fill it with some fluff diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 9ed8bcbc51d5..772c776436f7 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -25,7 +25,6 @@ import ( "io" "sort" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" "golang.org/x/crypto/sha3" @@ -144,7 +143,7 @@ func (f *fuzzer) fuzz() int { var ( spongeA = &spongeDb{sponge: sha3.NewLegacyKeccak256()} dbA = trie.NewDatabase(spongeA) - trieA, _ = trie.New(common.Hash{}, dbA) + trieA = trie.NewEmpty(dbA) spongeB = &spongeDb{sponge: sha3.NewLegacyKeccak256()} trieB = trie.NewStackTrie(spongeB) vals kvs diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index e993af47cf20..2301721c9311 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -144,7 +144,7 @@ func runRandTest(rt randTest) error { triedb := trie.NewDatabase(memorydb.New()) - tr, _ := trie.New(common.Hash{}, triedb) + tr := trie.NewEmpty(triedb) values := make(map[string]string) // tracks content of the trie for i, step := range rt { @@ -170,13 +170,13 @@ func runRandTest(rt randTest) error { if err != nil { return err } - newtr, err := trie.New(hash, triedb) + newtr, err := trie.New(common.Hash{}, hash, triedb) if err != nil { return err } tr = newtr case opItercheckhash: - checktr, _ := trie.New(common.Hash{}, triedb) + checktr := trie.NewEmpty(triedb) it := trie.NewIterator(tr.NodeIterator(nil)) for it.Next() { checktr.Update(it.Key, it.Value) diff --git a/trie/errors.go b/trie/errors.go index 567b80078c06..afe344bed269 100644 --- a/trie/errors.go +++ b/trie/errors.go @@ -26,10 +26,21 @@ import ( // in the case where a trie node is not present in the local database. It contains // information necessary for retrieving the missing node. type MissingNodeError struct { + Owner common.Hash // owner of the trie if it's 2-layered trie NodeHash common.Hash // hash of the missing node Path []byte // hex-encoded path to the missing node + err error // concrete error for missing trie node +} + +// Unwrap returns the concrete error for missing trie node which +// allows us for further analysis outside. +func (err *MissingNodeError) Unwrap() error { + return err.err } func (err *MissingNodeError) Error() string { - return fmt.Sprintf("missing trie node %x (path %x)", err.NodeHash, err.Path) + if err.Owner == (common.Hash{}) { + return fmt.Sprintf("missing trie node %x (path %x) %v", err.NodeHash, err.Path, err.err) + } + return fmt.Sprintf("missing trie node %x (owner %x) (path %x) %v", err.NodeHash, err.Owner, err.Path, err.err) } diff --git a/trie/iterator_test.go b/trie/iterator_test.go index ea8a46bb4301..e3e6d0e3a8fa 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -297,7 +297,7 @@ func TestUnionIterator(t *testing.T) { } func TestIteratorNoDups(t *testing.T) { - tr, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + tr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range testdata1 { tr.Update([]byte(val.k), []byte(val.v)) } @@ -312,7 +312,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { diskdb := memorydb.New() triedb := NewDatabase(diskdb) - tr, _ := New(common.Hash{}, triedb) + tr := NewEmpty(triedb) for _, val := range testdata1 { tr.Update([]byte(val.k), []byte(val.v)) } @@ -337,7 +337,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { } for i := 0; i < 20; i++ { // Create trie that will load all nodes from DB. - tr, _ := New(tr.Hash(), triedb) + tr, _ := New(common.Hash{}, tr.Hash(), triedb) // Remove a random node from the database. It can't be the root node // because that one is already loaded. @@ -403,7 +403,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { diskdb := memorydb.New() triedb := NewDatabase(diskdb) - ctr, _ := New(common.Hash{}, triedb) + ctr := NewEmpty(triedb) for _, val := range testdata1 { ctr.Update([]byte(val.k), []byte(val.v)) } @@ -425,7 +425,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { } // Create a new iterator that seeks to "bars". Seeking can't proceed because // the node is missing. - tr, _ := New(root, triedb) + tr, _ := New(common.Hash{}, root, triedb) it := tr.NodeIterator([]byte("bars")) missing, ok := it.Error().(*MissingNodeError) if !ok { @@ -513,7 +513,7 @@ func makeLargeTestTrie() (*Database, *SecureTrie, *loggingDb) { // Create an empty trie logDb := &loggingDb{0, memorydb.New()} triedb := NewDatabase(logDb) - trie, _ := NewSecure(common.Hash{}, triedb) + trie, _ := NewSecure(common.Hash{}, common.Hash{}, triedb) // Fill it with some arbitrary data for i := 0; i < 10000; i++ { @@ -546,9 +546,9 @@ func TestNodeIteratorLargeTrie(t *testing.T) { func TestIteratorNodeBlob(t *testing.T) { var ( - db = memorydb.New() - triedb = NewDatabase(db) - trie, _ = New(common.Hash{}, triedb) + db = memorydb.New() + triedb = NewDatabase(db) + trie = NewEmpty(triedb) ) vals := []struct{ k, v string }{ {"do", "verb"}, diff --git a/trie/proof_test.go b/trie/proof_test.go index cdf5cf605098..8db035256e32 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -80,7 +80,7 @@ func TestProof(t *testing.T) { } func TestOneElementProof(t *testing.T) { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) updateString(trie, "k", "v") for i, prover := range makeProvers(trie) { proof := prover([]byte("k")) @@ -131,7 +131,7 @@ func TestBadProof(t *testing.T) { // Tests that missing keys can also be proven. The test explicitly uses a single // entry trie and checks for missing keys both before and after the single entry. func TestMissingKeyProof(t *testing.T) { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) updateString(trie, "k", "v") for i, key := range []string{"a", "j", "l", "z"} { @@ -387,7 +387,7 @@ func TestOneElementRangeProof(t *testing.T) { } // Test the mini trie with only a single element. - tinyTrie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + tinyTrie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) entry := &kv{randBytes(32), randBytes(20), false} tinyTrie.Update(entry.k, entry.v) @@ -459,7 +459,7 @@ func TestAllElementsProof(t *testing.T) { // TestSingleSideRangeProof tests the range starts from zero. func TestSingleSideRangeProof(t *testing.T) { for i := 0; i < 64; i++ { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) var entries entrySlice for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} @@ -494,7 +494,7 @@ func TestSingleSideRangeProof(t *testing.T) { // TestReverseSingleSideRangeProof tests the range ends with 0xffff...fff. func TestReverseSingleSideRangeProof(t *testing.T) { for i := 0; i < 64; i++ { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) var entries entrySlice for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} @@ -601,7 +601,7 @@ func TestBadRangeProof(t *testing.T) { // TestGappedRangeProof focuses on the small trie with embedded nodes. // If the gapped node is embedded in the trie, it should be detected too. func TestGappedRangeProof(t *testing.T) { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) var entries []*kv // Sorted entries for i := byte(0); i < 10; i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} @@ -675,7 +675,7 @@ func TestSameSideProofs(t *testing.T) { } func TestHasRightElement(t *testing.T) { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) var entries entrySlice for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} @@ -1028,7 +1028,7 @@ func benchmarkVerifyRangeNoProof(b *testing.B, size int) { } func randomTrie(n int) (*Trie, map[string]*kv) { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := make(map[string]*kv) for i := byte(0); i < 100; i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} @@ -1053,7 +1053,7 @@ func randBytes(n int) []byte { } func nonRandomTrie(n int) (*Trie, map[string]*kv) { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := make(map[string]*kv) max := uint64(0xffffffffffffffff) for i := uint64(0); i < uint64(n); i++ { @@ -1078,7 +1078,7 @@ func TestRangeProofKeysWithSharedPrefix(t *testing.T) { common.Hex2Bytes("02"), common.Hex2Bytes("03"), } - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i, key := range keys { trie.Update(key, vals[i]) } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 248b93544d2f..6a5cc89c9ffd 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -53,11 +53,11 @@ type SecureTrie struct { // Loaded nodes are kept around until their 'cache generation' expires. // A new cache generation is created by each call to Commit. // cachelimit sets the number of past cache generations to keep. -func NewSecure(root common.Hash, db *Database) (*SecureTrie, error) { +func NewSecure(owner common.Hash, root common.Hash, db *Database) (*SecureTrie, error) { if db == nil { panic("trie.NewSecure called without a database") } - trie, err := New(root, db) + trie, err := New(owner, root, db) if err != nil { return nil, err } diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index a3ece84b5712..beea5845ad0d 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -28,7 +28,7 @@ import ( ) func newEmptySecure() *SecureTrie { - trie, _ := NewSecure(common.Hash{}, NewDatabase(memorydb.New())) + trie, _ := NewSecure(common.Hash{}, common.Hash{}, NewDatabase(memorydb.New())) return trie } @@ -36,7 +36,7 @@ func newEmptySecure() *SecureTrie { func makeTestSecureTrie() (*Database, *SecureTrie, map[string][]byte) { // Create an empty trie triedb := NewDatabase(memorydb.New()) - trie, _ := NewSecure(common.Hash{}, triedb) + trie, _ := NewSecure(common.Hash{}, common.Hash{}, triedb) // Fill it with some arbitrary data content := make(map[string][]byte) diff --git a/trie/stacktrie.go b/trie/stacktrie.go index b38bb01b0fb3..a22fa0dd6797 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -38,9 +38,10 @@ var stPool = sync.Pool{ }, } -func stackTrieFromPool(db ethdb.KeyValueWriter) *StackTrie { +func stackTrieFromPool(db ethdb.KeyValueWriter, owner common.Hash) *StackTrie { st := stPool.Get().(*StackTrie) st.db = db + st.owner = owner return st } @@ -53,6 +54,7 @@ func returnToPool(st *StackTrie) { // in order. Once it determines that a subtree will no longer be inserted // into, it will hash it and free up the memory it uses. type StackTrie struct { + owner common.Hash // the owner of the trie nodeType uint8 // node type (as in branch, ext, leaf) val []byte // value contained by this node if it's a leaf key []byte // key chunk covered by this (leaf|ext) node @@ -68,6 +70,16 @@ func NewStackTrie(db ethdb.KeyValueWriter) *StackTrie { } } +// NewStackTrieWithOwner allocates and initializes an empty trie, but with +// the additional owner field. +func NewStackTrieWithOwner(db ethdb.KeyValueWriter, owner common.Hash) *StackTrie { + return &StackTrie{ + owner: owner, + nodeType: emptyNode, + db: db, + } +} + // NewFromBinary initialises a serialized stacktrie with the given db. func NewFromBinary(data []byte, db ethdb.KeyValueWriter) (*StackTrie, error) { var st StackTrie @@ -88,10 +100,12 @@ func (st *StackTrie) MarshalBinary() (data []byte, err error) { w = bufio.NewWriter(&b) ) if err := gob.NewEncoder(w).Encode(struct { - Nodetype uint8 + Owner common.Hash + NodeType uint8 Val []byte Key []byte }{ + st.owner, st.nodeType, st.val, st.key, @@ -122,12 +136,14 @@ func (st *StackTrie) UnmarshalBinary(data []byte) error { func (st *StackTrie) unmarshalBinary(r io.Reader) error { var dec struct { - Nodetype uint8 + Owner common.Hash + NodeType uint8 Val []byte Key []byte } gob.NewDecoder(r).Decode(&dec) - st.nodeType = dec.Nodetype + st.owner = dec.Owner + st.nodeType = dec.NodeType st.val = dec.Val st.key = dec.Key @@ -154,16 +170,16 @@ func (st *StackTrie) setDb(db ethdb.KeyValueWriter) { } } -func newLeaf(key, val []byte, db ethdb.KeyValueWriter) *StackTrie { - st := stackTrieFromPool(db) +func newLeaf(owner common.Hash, key, val []byte, db ethdb.KeyValueWriter) *StackTrie { + st := stackTrieFromPool(db, owner) st.nodeType = leafNode st.key = append(st.key, key...) st.val = val return st } -func newExt(key []byte, child *StackTrie, db ethdb.KeyValueWriter) *StackTrie { - st := stackTrieFromPool(db) +func newExt(owner common.Hash, key []byte, child *StackTrie, db ethdb.KeyValueWriter) *StackTrie { + st := stackTrieFromPool(db, owner) st.nodeType = extNode st.key = append(st.key, key...) st.children[0] = child @@ -196,6 +212,7 @@ func (st *StackTrie) Update(key, value []byte) { } func (st *StackTrie) Reset() { + st.owner = common.Hash{} st.db = nil st.key = st.key[:0] st.val = nil @@ -236,7 +253,7 @@ func (st *StackTrie) insert(key, value []byte) { // Add new child if st.children[idx] == nil { - st.children[idx] = newLeaf(key[1:], value, st.db) + st.children[idx] = newLeaf(st.owner, key[1:], value, st.db) } else { st.children[idx].insert(key[1:], value) } @@ -262,7 +279,7 @@ func (st *StackTrie) insert(key, value []byte) { // node directly. var n *StackTrie if diffidx < len(st.key)-1 { - n = newExt(st.key[diffidx+1:], st.children[0], st.db) + n = newExt(st.owner, st.key[diffidx+1:], st.children[0], st.db) } else { // Break on the last byte, no need to insert // an extension node: reuse the current node @@ -282,12 +299,12 @@ func (st *StackTrie) insert(key, value []byte) { // the common prefix is at least one byte // long, insert a new intermediate branch // node. - st.children[0] = stackTrieFromPool(st.db) + st.children[0] = stackTrieFromPool(st.db, st.owner) st.children[0].nodeType = branchNode p = st.children[0] } // Create a leaf for the inserted part - o := newLeaf(key[diffidx+1:], value, st.db) + o := newLeaf(st.owner, key[diffidx+1:], value, st.db) // Insert both child leaves where they belong: origIdx := st.key[diffidx] @@ -323,7 +340,7 @@ func (st *StackTrie) insert(key, value []byte) { // Convert current node into an ext, // and insert a child branch node. st.nodeType = extNode - st.children[0] = NewStackTrie(st.db) + st.children[0] = NewStackTrieWithOwner(st.db, st.owner) st.children[0].nodeType = branchNode p = st.children[0] } @@ -332,11 +349,11 @@ func (st *StackTrie) insert(key, value []byte) { // value and another containing the new value. The child leaf // is hashed directly in order to free up some memory. origIdx := st.key[diffidx] - p.children[origIdx] = newLeaf(st.key[diffidx+1:], st.val, st.db) + p.children[origIdx] = newLeaf(st.owner, st.key[diffidx+1:], st.val, st.db) p.children[origIdx].hash() newIdx := key[diffidx] - p.children[newIdx] = newLeaf(key[diffidx+1:], value, st.db) + p.children[newIdx] = newLeaf(st.owner, key[diffidx+1:], value, st.db) // Finally, cut off the key part that has been passed // over to the children. diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index e57df60369bf..f24c749716e5 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -188,7 +188,7 @@ func TestStackTrieInsertAndHash(t *testing.T) { func TestSizeBug(t *testing.T) { st := NewStackTrie(nil) - nt, _ := New(common.Hash{}, NewDatabase(memorydb.New())) + nt := NewEmpty(NewDatabase(memorydb.New())) leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") @@ -203,7 +203,7 @@ func TestSizeBug(t *testing.T) { func TestEmptyBug(t *testing.T) { st := NewStackTrie(nil) - nt, _ := New(common.Hash{}, NewDatabase(memorydb.New())) + nt := NewEmpty(NewDatabase(memorydb.New())) //leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") //value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") @@ -229,7 +229,7 @@ func TestEmptyBug(t *testing.T) { func TestValLength56(t *testing.T) { st := NewStackTrie(nil) - nt, _ := New(common.Hash{}, NewDatabase(memorydb.New())) + nt := NewEmpty(NewDatabase(memorydb.New())) //leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") //value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") @@ -254,7 +254,8 @@ func TestValLength56(t *testing.T) { // which causes a lot of node-within-node. This case was found via fuzzing. func TestUpdateSmallNodes(t *testing.T) { st := NewStackTrie(nil) - nt, _ := New(common.Hash{}, NewDatabase(memorydb.New())) + nt := NewEmpty(NewDatabase(memorydb.New())) + kvs := []struct { K string V string @@ -282,7 +283,8 @@ func TestUpdateSmallNodes(t *testing.T) { func TestUpdateVariableKeys(t *testing.T) { t.SkipNow() st := NewStackTrie(nil) - nt, _ := New(common.Hash{}, NewDatabase(memorydb.New())) + nt := NewEmpty(NewDatabase(memorydb.New())) + kvs := []struct { K string V string @@ -352,7 +354,7 @@ func TestStacktrieNotModifyValues(t *testing.T) { func TestStacktrieSerialization(t *testing.T) { var ( st = NewStackTrie(nil) - nt, _ = New(common.Hash{}, NewDatabase(memorydb.New())) + nt = NewEmpty(NewDatabase(memorydb.New())) keyB = big.NewInt(1) keyDelta = big.NewInt(1) vals [][]byte diff --git a/trie/sync_test.go b/trie/sync_test.go index 970730b67187..4c2c50d7a159 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -29,7 +29,7 @@ import ( func makeTestTrie() (*Database, *SecureTrie, map[string][]byte) { // Create an empty trie triedb := NewDatabase(memorydb.New()) - trie, _ := NewSecure(common.Hash{}, triedb) + trie, _ := NewSecure(common.Hash{}, common.Hash{}, triedb) // Fill it with some arbitrary data content := make(map[string][]byte) @@ -60,7 +60,7 @@ func makeTestTrie() (*Database, *SecureTrie, map[string][]byte) { // content map. func checkTrieContents(t *testing.T, db *Database, root []byte, content map[string][]byte) { // Check root availability and trie contents - trie, err := NewSecure(common.BytesToHash(root), db) + trie, err := NewSecure(common.Hash{}, common.BytesToHash(root), db) if err != nil { t.Fatalf("failed to create trie at %x: %v", root, err) } @@ -77,7 +77,7 @@ func checkTrieContents(t *testing.T, db *Database, root []byte, content map[stri // checkTrieConsistency checks that all nodes in a trie are indeed present. func checkTrieConsistency(db *Database, root common.Hash) error { // Create and iterate a trie rooted in a subnode - trie, err := NewSecure(root, db) + trie, err := NewSecure(common.Hash{}, root, db) if err != nil { return nil // Consider a non existent state consistent } @@ -91,8 +91,8 @@ func checkTrieConsistency(db *Database, root common.Hash) error { func TestEmptySync(t *testing.T) { dbA := NewDatabase(memorydb.New()) dbB := NewDatabase(memorydb.New()) - emptyA, _ := New(common.Hash{}, dbA) - emptyB, _ := New(emptyRoot, dbB) + emptyA := NewEmpty(dbA) + emptyB, _ := New(common.Hash{}, emptyRoot, dbB) for i, trie := range []*Trie{emptyA, emptyB} { sync := NewSync(trie.Hash(), memorydb.New(), nil) diff --git a/trie/trie.go b/trie/trie.go index fe7d6dc17e79..0c81cb2c3901 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -61,8 +61,9 @@ type LeafCallback func(paths [][]byte, hexpath []byte, leaf []byte, parent commo // // Trie is not safe for concurrent use. type Trie struct { - db *Database - root node + db *Database + root node + owner common.Hash // Keep track of the number leaves which have been inserted since the last // hashing operation. This number will not directly map to the number of @@ -84,23 +85,47 @@ func (t *Trie) Copy() *Trie { return &Trie{ db: t.db, root: t.root, + owner: t.owner, unhashed: t.unhashed, tracer: t.tracer.copy(), } } -// New creates a trie with an existing root node from db. +// New creates a trie with an existing root node from db and an assigned +// owner for storage proximity. // // If root is the zero hash or the sha3 hash of an empty string, the // trie is initially empty and does not require a database. Otherwise, // New will panic if db is nil and returns a MissingNodeError if root does // not exist in the database. Accessing the trie loads nodes from db on demand. -func New(root common.Hash, db *Database) (*Trie, error) { +func New(owner common.Hash, root common.Hash, db *Database) (*Trie, error) { + return newTrie(owner, root, db) +} + +// NewEmpty is a shortcut to create empty tree. It's mostly used in tests. +func NewEmpty(db *Database) *Trie { + tr, _ := newTrie(common.Hash{}, common.Hash{}, db) + return tr +} + +// newWithRootNode initializes the trie with the given root node. +// It's only used by range prover. +func newWithRootNode(root node) *Trie { + return &Trie{ + root: root, + //tracer: newTracer(), + db: NewDatabase(rawdb.NewMemoryDatabase()), + } +} + +// newTrie is the internal function used to construct the trie with given parameters. +func newTrie(owner common.Hash, root common.Hash, db *Database) (*Trie, error) { if db == nil { panic("trie.New called without a database") } trie := &Trie{ - db: db, + db: db, + owner: owner, //tracer: newTracer(), } if root != (common.Hash{}) && root != emptyRoot { @@ -113,16 +138,6 @@ func New(root common.Hash, db *Database) (*Trie, error) { return trie, nil } -// newWithRootNode initializes the trie with the given root node. -// It's only used by range prover. -func newWithRootNode(root node) *Trie { - return &Trie{ - root: root, - //tracer: newTracer(), - db: NewDatabase(rawdb.NewMemoryDatabase()), - } -} - // NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at // the key after the given start key. func (t *Trie) NodeIterator(start []byte) NodeIterator { @@ -562,7 +577,7 @@ func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) { if node := t.db.node(hash); node != nil { return node, nil } - return nil, &MissingNodeError{NodeHash: hash, Path: prefix} + return nil, &MissingNodeError{Owner: t.owner, NodeHash: hash, Path: prefix} } func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) { @@ -571,7 +586,7 @@ func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) { if len(blob) != 0 { return blob, nil } - return nil, &MissingNodeError{NodeHash: hash, Path: prefix} + return nil, &MissingNodeError{Owner: t.owner, NodeHash: hash, Path: prefix} } // Hash returns the root hash of the trie. It does not write to the @@ -602,7 +617,10 @@ func (t *Trie) Commit(onleaf LeafCallback) (common.Hash, int, error) { // Do a quick check if we really need to commit, before we spin // up goroutines. This can happen e.g. if we load a trie for reading storage // values, but don't write to it. - if _, dirty := t.root.cache(); !dirty { + if hashedNode, dirty := t.root.cache(); !dirty { + // Replace the root node with the origin hash in order to + // ensure all resolved nodes are dropped after the commit. + t.root = hashedNode return rootHash, 0, nil } var wg sync.WaitGroup @@ -647,6 +665,12 @@ func (t *Trie) hashRoot() (node, node, error) { // Reset drops the referenced root node and cleans all internal state. func (t *Trie) Reset() { t.root = nil + t.owner = common.Hash{} t.unhashed = 0 t.tracer.reset() } + +// Owner returns the associated trie owner. +func (t *Trie) Owner() common.Hash { + return t.owner +} diff --git a/trie/trie_test.go b/trie/trie_test.go index f994e31af40e..ab65965b4972 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -48,12 +48,12 @@ func init() { // Used for testing func newEmpty() *Trie { - trie, _ := New(common.Hash{}, NewDatabase(memorydb.New())) + trie := NewEmpty(NewDatabase(memorydb.New())) return trie } func TestEmptyTrie(t *testing.T) { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) res := trie.Hash() exp := emptyRoot if res != exp { @@ -62,7 +62,7 @@ func TestEmptyTrie(t *testing.T) { } func TestNull(t *testing.T) { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) key := make([]byte, 32) value := []byte("test") trie.Update(key, value) @@ -72,7 +72,7 @@ func TestNull(t *testing.T) { } func TestMissingRoot(t *testing.T) { - trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(memorydb.New())) + trie, err := New(common.Hash{}, common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(memorydb.New())) if trie != nil { t.Error("New returned non-nil trie for invalid root") } @@ -88,7 +88,7 @@ func testMissingNode(t *testing.T, memonly bool) { diskdb := memorydb.New() triedb := NewDatabase(diskdb) - trie, _ := New(common.Hash{}, triedb) + trie := NewEmpty(triedb) updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") root, _, _ := trie.Commit(nil) @@ -96,27 +96,27 @@ func testMissingNode(t *testing.T, memonly bool) { triedb.Commit(root, true, nil) } - trie, _ = New(root, triedb) + trie, _ = New(common.Hash{}, root, triedb) _, err := trie.TryGet([]byte("120000")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(root, triedb) + trie, _ = New(common.Hash{}, root, triedb) _, err = trie.TryGet([]byte("120099")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(root, triedb) + trie, _ = New(common.Hash{}, root, triedb) _, err = trie.TryGet([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(root, triedb) + trie, _ = New(common.Hash{}, root, triedb) err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(root, triedb) + trie, _ = New(common.Hash{}, root, triedb) err = trie.TryDelete([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -129,27 +129,27 @@ func testMissingNode(t *testing.T, memonly bool) { diskdb.Delete(hash[:]) } - trie, _ = New(root, triedb) + trie, _ = New(common.Hash{}, root, triedb) _, err = trie.TryGet([]byte("120000")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - trie, _ = New(root, triedb) + trie, _ = New(common.Hash{}, root, triedb) _, err = trie.TryGet([]byte("120099")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - trie, _ = New(root, triedb) + trie, _ = New(common.Hash{}, root, triedb) _, err = trie.TryGet([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(root, triedb) + trie, _ = New(common.Hash{}, root, triedb) err = trie.TryUpdate([]byte("120099"), []byte("zxcv")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - trie, _ = New(root, triedb) + trie, _ = New(common.Hash{}, root, triedb) err = trie.TryDelete([]byte("123456")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) @@ -277,7 +277,7 @@ func TestReplication(t *testing.T) { } // create a new trie on top of the database and check that lookups work. - trie2, err := New(exp, trie.db) + trie2, err := New(common.Hash{}, exp, trie.db) if err != nil { t.Fatalf("can't recreate trie at %x: %v", exp, err) } @@ -410,10 +410,10 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value { func runRandTest(rt randTest) bool { var ( - triedb = NewDatabase(memorydb.New()) - tr, _ = New(common.Hash{}, triedb) - values = make(map[string]string) // tracks content of the trie - origTrie, _ = New(common.Hash{}, triedb) + triedb = NewDatabase(memorydb.New()) + tr = NewEmpty(triedb) + values = make(map[string]string) // tracks content of the trie + origTrie = NewEmpty(triedb) ) tr.tracer = newTracer() @@ -445,7 +445,7 @@ func runRandTest(rt randTest) bool { rt[i].err = err return false } - newtr, err := New(hash, triedb) + newtr, err := New(common.Hash{}, hash, triedb) if err != nil { rt[i].err = err return false @@ -455,7 +455,7 @@ func runRandTest(rt randTest) bool { origTrie = tr.Copy() case opItercheckhash: - checktr, _ := New(common.Hash{}, triedb) + checktr := NewEmpty(triedb) it := NewIterator(tr.NodeIterator(nil)) for it.Next() { checktr.Update(it.Key, it.Value) @@ -542,10 +542,10 @@ func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) } const benchElemCount = 20000 func benchGet(b *testing.B, commit bool) { - trie, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) if commit { tmpdb := tempDB(b) - trie, _ = New(common.Hash{}, tmpdb) + trie = NewEmpty(tmpdb) } k := make([]byte, 32) for i := 0; i < benchElemCount; i++ { @@ -664,7 +664,7 @@ func TestTinyTrie(t *testing.T) { if exp, root := common.HexToHash("0608c1d1dc3905fa22204c7a0e43644831c3b6d3def0f274be623a948197e64a"), trie.Hash(); exp != root { t.Errorf("3: got %x, exp %x", root, exp) } - checktr, _ := New(common.Hash{}, trie.db) + checktr := NewEmpty(trie.db) it := NewIterator(trie.NodeIterator(nil)) for it.Next() { checktr.Update(it.Key, it.Value) @@ -790,7 +790,7 @@ func TestCommitSequence(t *testing.T) { // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} db := NewDatabase(s) - trie, _ := New(common.Hash{}, db) + trie := NewEmpty(db) // Another sponge is used to check the callback-sequence callbackSponge := sha3.NewLegacyKeccak256() // Fill the trie with elements @@ -832,7 +832,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} db := NewDatabase(s) - trie, _ := New(common.Hash{}, db) + trie := NewEmpty(db) // Another sponge is used to check the callback-sequence callbackSponge := sha3.NewLegacyKeccak256() // Fill the trie with elements @@ -871,7 +871,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"} db := NewDatabase(s) - trie, _ := New(common.Hash{}, db) + trie := NewEmpty(db) // Another sponge is used for the stacktrie commits stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} stTrie := NewStackTrie(stackTrieSponge) @@ -927,7 +927,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { func TestCommitSequenceSmallRoot(t *testing.T) { s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"} db := NewDatabase(s) - trie, _ := New(common.Hash{}, db) + trie := NewEmpty(db) // Another sponge is used for the stacktrie commits stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} stTrie := NewStackTrie(stackTrieSponge) diff --git a/trie/util_test.go b/trie/util_test.go index fadb0553b529..589eca62423a 100644 --- a/trie/util_test.go +++ b/trie/util_test.go @@ -19,14 +19,12 @@ package trie import ( "testing" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" ) // Tests if the trie diffs are tracked correctly. func TestTrieTracer(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - trie, _ := New(common.Hash{}, db) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) trie.tracer = newTracer() // Insert a batch of entries, all the nodes should be marked as inserted @@ -93,8 +91,7 @@ func TestTrieTracer(t *testing.T) { } func TestTrieTracerNoop(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - trie, _ := New(common.Hash{}, db) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) trie.tracer = newTracer() // Insert a batch of entries, all the nodes should be marked as inserted diff --git a/trie/utils.go b/trie/utils.go index 5f9e3ba58ecc..fe7f6e52f9eb 100644 --- a/trie/utils.go +++ b/trie/utils.go @@ -29,24 +29,39 @@ package trie // 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 reverse-diffs in the future. +// // Note tracer is not thread-safe, callers should be responsible for handling // the concurrency issues by themselves. type tracer struct { insert map[string]struct{} delete map[string]struct{} + origin map[string][]byte } -// newTracer initializes trie node diff tracer. +// newTracer initializes the tracer for capturing trie changes. func newTracer() *tracer { return &tracer{ insert: make(map[string]struct{}), delete: make(map[string]struct{}), + origin: make(map[string][]byte), + } +} + +// 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(key []byte, val []byte) { + // Tracer isn't used right now, remove this check later. + if t == nil { + return } + t.origin[string(key)] = 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. +// 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 the "untouched". func (t *tracer) onInsert(key []byte) { // Tracer isn't used right now, remove this check later. if t == nil { @@ -100,6 +115,15 @@ func (t *tracer) deleteList() [][]byte { return ret } +// getPrev returns the cached original value of the specified node. +func (t *tracer) getPrev(key []byte) []byte { + // Don't panic on uninitialized tracer, it's possible in testing. + if t == nil { + return nil + } + return t.origin[string(key)] +} + // reset clears the content tracked by tracer. func (t *tracer) reset() { // Tracer isn't used right now, remove this check later. @@ -108,6 +132,7 @@ func (t *tracer) reset() { } t.insert = make(map[string]struct{}) t.delete = make(map[string]struct{}) + t.origin = make(map[string][]byte) } // copy returns a deep copied tracer instance. @@ -119,6 +144,7 @@ func (t *tracer) copy() *tracer { var ( insert = make(map[string]struct{}) delete = make(map[string]struct{}) + origin = make(map[string][]byte) ) for key := range t.insert { insert[key] = struct{}{} @@ -126,8 +152,12 @@ func (t *tracer) copy() *tracer { for key := range t.delete { delete[key] = struct{}{} } + for key, val := range t.origin { + origin[key] = val + } return &tracer{ insert: insert, delete: delete, + origin: origin, } } From 10da98072c21b36d225e9da81713b5803fb03518 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 6 Jun 2022 17:33:05 +0200 Subject: [PATCH 004/715] eth/api: use `hexutil.Bytes` for account range method (#25024) eth/api: use hexutil.Bytes for range at methods --- eth/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/api.go b/eth/api.go index b2260a32ade1..1892746602cf 100644 --- a/eth/api.go +++ b/eth/api.go @@ -361,7 +361,7 @@ func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, const AccountRangeMaxResults = 256 // AccountRange enumerates all accounts in the given block and start point in paging request -func (api *PublicDebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start []byte, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) { +func (api *PublicDebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) { var stateDb *state.StateDB var err error From 096daa9a7d4f64a5f01fdecb9b11a5d4d33f877e Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Tue, 7 Jun 2022 00:55:16 +0900 Subject: [PATCH 005/715] eth/tracers: fix typo in 4byte_tracer_legacy.js (#25020) indentifier -> identifier --- eth/tracers/js/internal/tracers/4byte_tracer_legacy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/tracers/js/internal/tracers/4byte_tracer_legacy.js b/eth/tracers/js/internal/tracers/4byte_tracer_legacy.js index 462b4ad4cb55..e4714b8bfb76 100644 --- a/eth/tracers/js/internal/tracers/4byte_tracer_legacy.js +++ b/eth/tracers/js/internal/tracers/4byte_tracer_legacy.js @@ -46,7 +46,7 @@ return false; }, - // store save the given indentifier and datasize. + // store save the given identifier and datasize. store: function(id, size){ var key = "" + toHex(id) + "-" + size; this.ids[key] = this.ids[key] + 1 || 1; From 6b3e6cb2ab0b4fe2d23c3f64642c1a8284121af2 Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Tue, 7 Jun 2022 02:02:04 -0400 Subject: [PATCH 006/715] trie: move locking into trieDB insert method (#25030) Move locking into trieDB insert function --- trie/committer.go | 4 ---- trie/database.go | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/trie/committer.go b/trie/committer.go index 9a7bf48d977f..9b7ecbf5fcce 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -193,9 +193,7 @@ func (c *committer) store(n node, db *Database) node { } else if db != nil { // No leaf-callback used, but there's still a database. Do serial // insertion - db.lock.Lock() db.insert(common.BytesToHash(hash), size, n) - db.lock.Unlock() } return hash } @@ -209,9 +207,7 @@ func (c *committer) commitLoop(db *Database) { n = item.node ) // We are pooling the trie nodes into an intermediate memory cache - db.lock.Lock() db.insert(hash, size, n) - db.lock.Unlock() if c.onleaf != nil { switch n := n.(type) { diff --git a/trie/database.go b/trie/database.go index d71abeee476a..4167031a584c 100644 --- a/trie/database.go +++ b/trie/database.go @@ -310,6 +310,9 @@ func (db *Database) DiskDB() ethdb.KeyValueStore { // All nodes inserted by this function will be reference tracked // and in theory should only used for **trie nodes** insertion. func (db *Database) insert(hash common.Hash, size int, node node) { + db.lock.Lock() + defer db.lock.Unlock() + // If the node's already cached, skip if _, ok := db.dirties[hash]; ok { return From 7e9514b8c3a4bd637ed0389336b6ce2bf53ee3da Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 7 Jun 2022 08:11:01 +0200 Subject: [PATCH 007/715] params: update ropsten terminal total difficulty block (#25018) --- params/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/config.go b/params/config.go index 0f8b8a7cb417..2732e96468d8 100644 --- a/params/config.go +++ b/params/config.go @@ -114,7 +114,7 @@ var ( MuirGlacierBlock: big.NewInt(7_117_117), BerlinBlock: big.NewInt(9_812_189), LondonBlock: big.NewInt(10_499_401), - TerminalTotalDifficulty: new(big.Int).SetBytes([]byte{0x15, 0x2D, 0x02, 0xC7, 0xE1, 0x4A, 0xF6, 0x80, 0x00, 0x00}), // 100_000_000_000_000_000_000_000 + TerminalTotalDifficulty: new(big.Int).SetUint64(50000000000000000), Ethash: new(EthashConfig), } From d9566e39bd1b05325cfa08c832488f0e04feacd3 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 7 Jun 2022 08:31:19 +0200 Subject: [PATCH 008/715] eth/filters: fix getLogs for pending block (#24949) * eth/filters: fix pending for getLogs * add pending method to test backend * fix block range validation --- accounts/abi/bind/backends/simulated.go | 25 +++++++++----- eth/filters/filter.go | 46 ++++++++++++++++++++----- eth/filters/filter_system_test.go | 4 +++ internal/ethapi/backend.go | 1 + 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index ac696f446be6..f5780c4a32c2 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -63,9 +63,10 @@ type SimulatedBackend struct { database ethdb.Database // In memory database to store our testing data blockchain *core.BlockChain // Ethereum blockchain to handle the consensus - mu sync.Mutex - pendingBlock *types.Block // Currently pending block that will be imported on request - pendingState *state.StateDB // Currently pending state that will be the active on request + mu sync.Mutex + pendingBlock *types.Block // Currently pending block that will be imported on request + pendingState *state.StateDB // Currently pending state that will be the active on request + pendingReceipts types.Receipts // Currently receipts for the pending block events *filters.EventSystem // Event system for filtering log events live @@ -84,8 +85,8 @@ func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.Genesis database: database, blockchain: blockchain, config: genesis.Config, - events: filters.NewEventSystem(&filterBackend{database, blockchain}, false), } + backend.events = filters.NewEventSystem(&filterBackend{database, blockchain, backend}, false) backend.rollback(blockchain.CurrentBlock()) return backend } @@ -662,7 +663,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa return fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce) } // Include tx in chain - blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { + blocks, receipts := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { for _, tx := range b.pendingBlock.Transactions() { block.AddTxWithChain(b.blockchain, tx) } @@ -672,6 +673,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa b.pendingBlock = blocks[0] b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil) + b.pendingReceipts = receipts[0] return nil } @@ -683,7 +685,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter var filter *filters.Filter if query.BlockHash != nil { // Block filter requested, construct a single-shot filter - filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics) + filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain, b}, *query.BlockHash, query.Addresses, query.Topics) } else { // Initialize unset filter boundaries to run from genesis to chain head from := int64(0) @@ -695,7 +697,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter to = query.ToBlock.Int64() } // Construct the range filter - filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics) + filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain, b}, from, to, query.Addresses, query.Topics) } // Run the filter and return all the logs logs, err := filter.Logs(ctx) @@ -816,8 +818,9 @@ func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList } // filterBackend implements filters.Backend to support filtering for logs without // taking bloom-bits acceleration structures into account. type filterBackend struct { - db ethdb.Database - bc *core.BlockChain + db ethdb.Database + bc *core.BlockChain + backend *SimulatedBackend } func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db } @@ -834,6 +837,10 @@ func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*t return fb.bc.GetHeaderByHash(hash), nil } +func (fb *filterBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { + return fb.backend.pendingBlock, fb.backend.pendingReceipts +} + func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { number := rawdb.ReadHeaderNumber(fb.db, hash) if number == nil { diff --git a/eth/filters/filter.go b/eth/filters/filter.go index f64e84abb86c..9ff7ab7f55e1 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -36,6 +36,7 @@ type Backend interface { HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) + PendingBlockAndReceipts() (*types.Block, types.Receipts) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription @@ -128,26 +129,35 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { } return f.blockLogs(ctx, header) } + // Short-cut if all we care about is pending logs + if f.begin == rpc.PendingBlockNumber.Int64() { + if f.end != rpc.PendingBlockNumber.Int64() { + return nil, errors.New("invalid block range") + } + return f.pendingLogs() + } // Figure out the limits of the filter range header, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) if header == nil { return nil, nil } - head := header.Number.Uint64() - - if f.begin == -1 { + var ( + head = header.Number.Uint64() + end = uint64(f.end) + pending = f.end == rpc.PendingBlockNumber.Int64() + ) + if f.begin == rpc.LatestBlockNumber.Int64() { f.begin = int64(head) } - end := uint64(f.end) - if f.end == -1 { + if f.end == rpc.LatestBlockNumber.Int64() || f.end == rpc.PendingBlockNumber.Int64() { end = head } // Gather all indexed logs, and finish with non indexed ones var ( - logs []*types.Log - err error + logs []*types.Log + err error + size, sections = f.backend.BloomStatus() ) - size, sections := f.backend.BloomStatus() if indexed := sections * size; indexed > uint64(f.begin) { if indexed > end { logs, err = f.indexedLogs(ctx, end) @@ -160,6 +170,13 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { } rest, err := f.unindexedLogs(ctx, end) logs = append(logs, rest...) + if pending { + pendingLogs, err := f.pendingLogs() + if err != nil { + return nil, err + } + logs = append(logs, pendingLogs...) + } return logs, err } @@ -272,6 +289,19 @@ func (f *Filter) checkMatches(ctx context.Context, header *types.Header) (logs [ return nil, nil } +// pendingLogs returns the logs matching the filter criteria within the pending block. +func (f *Filter) pendingLogs() ([]*types.Log, error) { + block, receipts := f.backend.PendingBlockAndReceipts() + if bloomFilter(block.Bloom(), f.addresses, f.topics) { + var unfiltered []*types.Log + for _, r := range receipts { + unfiltered = append(unfiltered, r.Logs...) + } + return filterLogs(unfiltered, nil, nil, f.addresses, f.topics), nil + } + return nil, nil +} + func includes(addresses []common.Address, a common.Address) bool { for _, addr := range addresses { if addr == a { diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 8d145d960432..82d626ef127e 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -106,6 +106,10 @@ func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types return logs, nil } +func (b *testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { + return nil, nil +} + func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { return b.txFeed.Subscribe(ch) } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index bc60fb2a64f6..c11d842df7d5 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -65,6 +65,7 @@ type Backend interface { BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) + PendingBlockAndReceipts() (*types.Block, types.Receipts) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetTd(ctx context.Context, hash common.Hash) *big.Int GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) From 84b327244d1a4bf256633210fe01045c2c46f9f0 Mon Sep 17 00:00:00 2001 From: lwh Date: Tue, 7 Jun 2022 14:38:54 +0800 Subject: [PATCH 009/715] accounts/abi/bind: fix duplicate field names in the generated go struct (#24924) * accounts/abi/bind: fix duplicate field names in the generated go struct #24627 * accounts, cmd/abigen: resolve name conflicts * ci lint, accounts/abi: remove unused function overloadedArgName Co-authored-by: Gary Rong --- accounts/abi/abi.go | 23 +++------------- accounts/abi/bind/bind.go | 25 +++++++++++++++--- accounts/abi/bind/bind_test.go | 48 ++++++++++++++++++++++++++++++++++ accounts/abi/error.go | 6 +++-- accounts/abi/event.go | 7 +++-- accounts/abi/type.go | 24 +++++------------ accounts/abi/utils.go | 41 +++++++++++++++++++++++++++++ cmd/abigen/main.go | 6 ++++- 8 files changed, 136 insertions(+), 44 deletions(-) create mode 100644 accounts/abi/utils.go diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index cd2f4d7978bd..ed5b6e92ef9c 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -164,7 +164,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { case "constructor": abi.Constructor = NewMethod("", "", Constructor, field.StateMutability, field.Constant, field.Payable, field.Inputs, nil) case "function": - name := overloadedName(field.Name, func(s string) bool { _, ok := abi.Methods[s]; return ok }) + name := ResolveNameConflict(field.Name, func(s string) bool { _, ok := abi.Methods[s]; return ok }) abi.Methods[name] = NewMethod(name, field.Name, Function, field.StateMutability, field.Constant, field.Payable, field.Inputs, field.Outputs) case "fallback": // New introduced function type in v0.6.0, check more detail @@ -184,9 +184,11 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { } abi.Receive = NewMethod("", "", Receive, field.StateMutability, field.Constant, field.Payable, nil, nil) case "event": - name := overloadedName(field.Name, func(s string) bool { _, ok := abi.Events[s]; return ok }) + name := ResolveNameConflict(field.Name, func(s string) bool { _, ok := abi.Events[s]; return ok }) abi.Events[name] = NewEvent(name, field.Name, field.Anonymous, field.Inputs) case "error": + // Errors cannot be overloaded or overridden but are inherited, + // no need to resolve the name conflict here. abi.Errors[field.Name] = NewError(field.Name, field.Inputs) default: return fmt.Errorf("abi: could not recognize type %v of field %v", field.Type, field.Name) @@ -251,20 +253,3 @@ func UnpackRevert(data []byte) (string, error) { } return unpacked[0].(string), nil } - -// overloadedName returns the next available name for a given thing. -// Needed since solidity allows for overloading. -// -// e.g. if the abi contains Methods send, send1 -// overloadedName would return send2 for input send. -// -// overloadedName works for methods, events and errors. -func overloadedName(rawName string, isAvail func(string) bool) string { - name := rawName - ok := isAvail(name) - for idx := 0; ok; idx++ { - name = fmt.Sprintf("%s%d", rawName, idx) - ok = isAvail(name) - } - return name -} diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index 2bd8b6dde07f..a938e7dfcd85 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -99,6 +99,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] // Normalize the method for capital cases and non-anonymous inputs/outputs normalized := original normalizedName := methodNormalizer[lang](alias(aliases, original.Name)) + // Ensure there is no duplicated identifier var identifiers = callIdentifiers if !original.IsConstant() { @@ -108,6 +109,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName) } identifiers[normalizedName] = true + normalized.Name = normalizedName normalized.Inputs = make([]abi.Argument, len(original.Inputs)) copy(normalized.Inputs, original.Inputs) @@ -152,12 +154,22 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] eventIdentifiers[normalizedName] = true normalized.Name = normalizedName + used := make(map[string]bool) normalized.Inputs = make([]abi.Argument, len(original.Inputs)) copy(normalized.Inputs, original.Inputs) for j, input := range normalized.Inputs { if input.Name == "" { normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) } + // Event is a bit special, we need to define event struct in binding, + // ensure there is no camel-case-style name conflict. + for index := 0; ; index++ { + if !used[capitalise(normalized.Inputs[j].Name)] { + used[capitalise(normalized.Inputs[j].Name)] = true + break + } + normalized.Inputs[j].Name = fmt.Sprintf("%s%d", normalized.Inputs[j].Name, index) + } if hasStruct(input.Type) { bindStructType[lang](input.Type, structs) } @@ -432,15 +444,22 @@ func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { if s, exist := structs[id]; exist { return s.Name } - var fields []*tmplField + var ( + names = make(map[string]bool) + fields []*tmplField + ) for i, elem := range kind.TupleElems { - field := bindStructTypeGo(*elem, structs) - fields = append(fields, &tmplField{Type: field, Name: capitalise(kind.TupleRawNames[i]), SolKind: *elem}) + name := capitalise(kind.TupleRawNames[i]) + name = abi.ResolveNameConflict(name, func(s string) bool { return names[s] }) + names[name] = true + fields = append(fields, &tmplField{Type: bindStructTypeGo(*elem, structs), Name: name, SolKind: *elem}) } name := kind.TupleRawName if name == "" { name = fmt.Sprintf("Struct%d", len(structs)) } + name = capitalise(name) + structs[id] = &tmplStruct{ Name: name, Fields: fields, diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 87e8187f09ca..b71d85ee6085 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -1948,6 +1948,54 @@ var bindTests = []struct { } sim.Commit() + if _, err = bind.WaitDeployed(nil, sim, tx); err != nil { + t.Logf("Deployment tx: %+v", tx) + t.Errorf("bind.WaitDeployed(nil, %T, ) got err %v; want nil err", sim, err) + } + `, + }, + { + name: `NameConflict`, + contract: ` + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.4.22 <0.9.0; + contract oracle { + struct request { + bytes data; + bytes _data; + } + event log (int msg, int _msg); + function addRequest(request memory req) public pure {} + function getRequest() pure public returns (request memory) { + return request("", ""); + } + } + `, + bytecode: []string{`0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033`}, + abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`}, + imports: ` + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/ethconfig" + `, + tester: ` + var ( + key, _ = crypto.GenerateKey() + user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) + sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil) + ) + defer sim.Close() + + _, tx, _, err := DeployNameConflict(user, sim) + if err != nil { + t.Fatalf("DeployNameConflict() got err %v; want nil err", err) + } + sim.Commit() + if _, err = bind.WaitDeployed(nil, sim, tx); err != nil { t.Logf("Deployment tx: %+v", tx) t.Errorf("bind.WaitDeployed(nil, %T, ) got err %v; want nil err", sim, err) diff --git a/accounts/abi/error.go b/accounts/abi/error.go index e564c10c2f84..f53c996def14 100644 --- a/accounts/abi/error.go +++ b/accounts/abi/error.go @@ -30,11 +30,13 @@ type Error struct { Name string Inputs Arguments str string + // Sig contains the string signature according to the ABI spec. - // e.g. event foo(uint32 a, int b) = "foo(uint32,int256)" + // e.g. error foo(uint32 a, int b) = "foo(uint32,int256)" // Please note that "int" is substitute for its canonical representation "int256" Sig string - // ID returns the canonical representation of the event's signature used by the + + // ID returns the canonical representation of the error's signature used by the // abi definition to identify event names and types. ID common.Hash } diff --git a/accounts/abi/event.go b/accounts/abi/event.go index b238a36d7cea..f9457b86afeb 100644 --- a/accounts/abi/event.go +++ b/accounts/abi/event.go @@ -29,24 +29,27 @@ import ( // don't get the signature canonical representation as the first LOG topic. type Event struct { // Name is the event name used for internal representation. It's derived from - // the raw name and a suffix will be added in the case of a event overload. + // the raw name and a suffix will be added in the case of event overloading. // // e.g. // These are two events that have the same name: // * foo(int,int) // * foo(uint,uint) - // The event name of the first one wll be resolved as foo while the second one + // The event name of the first one will be resolved as foo while the second one // will be resolved as foo0. Name string + // RawName is the raw event name parsed from ABI. RawName string Anonymous bool Inputs Arguments str string + // Sig contains the string signature according to the ABI spec. // e.g. event foo(uint32 a, int b) = "foo(uint32,int256)" // Please note that "int" is substitute for its canonical representation "int256" Sig string + // ID returns the canonical representation of the event's signature used by the // abi definition to identify event names and types. ID common.Hash diff --git a/accounts/abi/type.go b/accounts/abi/type.go index fd75f586a99d..008b665b1aee 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -163,22 +163,26 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty elems []*Type names []string expression string // canonical parameter expression + used = make(map[string]bool) ) expression += "(" - overloadedNames := make(map[string]string) for idx, c := range components { cType, err := NewType(c.Type, c.InternalType, c.Components) if err != nil { return Type{}, err } - fieldName, err := overloadedArgName(c.Name, overloadedNames) + name := ToCamelCase(c.Name) + if name == "" { + return Type{}, errors.New("abi: purely anonymous or underscored field is not supported") + } + fieldName := ResolveNameConflict(name, func(s string) bool { return used[s] }) if err != nil { return Type{}, err } + used[fieldName] = true if !isValidFieldName(fieldName) { return Type{}, fmt.Errorf("field %d has invalid name", idx) } - overloadedNames[fieldName] = fieldName fields = append(fields, reflect.StructField{ Name: fieldName, // reflect.StructOf will panic for any exported field. Type: cType.GetType(), @@ -255,20 +259,6 @@ func (t Type) GetType() reflect.Type { } } -func overloadedArgName(rawName string, names map[string]string) (string, error) { - fieldName := ToCamelCase(rawName) - if fieldName == "" { - return "", errors.New("abi: purely anonymous or underscored field is not supported") - } - // Handle overloaded fieldNames - _, ok := names[fieldName] - for idx := 0; ok; idx++ { - fieldName = fmt.Sprintf("%s%d", ToCamelCase(rawName), idx) - _, ok = names[fieldName] - } - return fieldName, nil -} - // String implements Stringer. func (t Type) String() (out string) { return t.stringKind diff --git a/accounts/abi/utils.go b/accounts/abi/utils.go new file mode 100644 index 000000000000..e24df5b7003d --- /dev/null +++ b/accounts/abi/utils.go @@ -0,0 +1,41 @@ +// Copyright 2022 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 abi + +import "fmt" + +// ResolveNameConflict returns the next available name for a given thing. +// This helper can be used for lots of purposes: +// +// - In solidity function overloading is supported, this function can fix +// the name conflicts of overloaded functions. +// - In golang binding generation, the parameter(in function, event, error, +// and struct definition) name will be converted to camelcase style which +// may eventually lead to name conflicts. +// +// Name conflicts are mostly resolved by adding number suffix. +// e.g. if the abi contains Methods send, send1 +// ResolveNameConflict would return send2 for input send. +func ResolveNameConflict(rawName string, used func(string) bool) string { + name := rawName + ok := used(name) + for idx := 0; ok; idx++ { + name = fmt.Sprintf("%s%d", rawName, idx) + ok = used(name) + } + return name +} diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 7a321e18b6b5..5a93f2a92294 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -198,7 +198,11 @@ func abigen(c *cli.Context) error { nameParts := strings.Split(name, ":") types = append(types, nameParts[len(nameParts)-1]) - libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] + // Derive the library placeholder which is a 34 character prefix of the + // hex encoding of the keccak256 hash of the fully qualified library name. + // Note that the fully qualified library name is the path of its source + // file and the library name separated by ":". + libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] // the first 2 chars are 0x libs[libPattern] = nameParts[len(nameParts)-1] } } From 5e8fa1da70c0636bd3f29f2eb2a371ef4fc306ad Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 7 Jun 2022 09:06:34 +0200 Subject: [PATCH 010/715] tests/fuzzers/bls12381: fix blst pairing (#25037) * tests/fuzzers/bls12381: fix blst pairing * tests/fuzzers/bls12381: only build on gofuzz * tests/fuzzers/bls12381: remove unused code * tests/fuzzers/bls12381: remove unused code --- tests/fuzzers/bls12381/bls12381_fuzz.go | 35 ++++++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/tests/fuzzers/bls12381/bls12381_fuzz.go b/tests/fuzzers/bls12381/bls12381_fuzz.go index 8f5761cf5c5a..a5b4b9e79856 100644 --- a/tests/fuzzers/bls12381/bls12381_fuzz.go +++ b/tests/fuzzers/bls12381/bls12381_fuzz.go @@ -65,20 +65,41 @@ func FuzzCrossPairing(data []byte) int { panic("pairing mismatch gnark / geth ") } - var b []byte - ctx := blst.PairingCtx(false, b) // compute pairing using blst - blst.PairingRawAggregate(ctx, blG2, blG1) - blstResult := blst.PairingAsFp12(ctx) - if !(bytes.Equal(blstResult.ToBendian(), bls12381.NewGT().ToBytes(kResult))) { - fmt.Printf("geth: %v\n", common.Bytes2Hex(bls12381.NewGT().ToBytes(kResult))) - fmt.Printf("blst: %v\n", common.Bytes2Hex(blstResult.ToBendian())) + blstResult := blst.Fp12MillerLoop(blG2, blG1) + blstResult.FinalExp() + res := massageBLST(blstResult.ToBendian()) + if !(bytes.Equal(res, bls12381.NewGT().ToBytes(kResult))) { panic("pairing mismatch blst / geth") } return 1 } +func massageBLST(in []byte) []byte { + out := make([]byte, len(in)) + len := 12 * 48 + // 1 + copy(out[0:], in[len-1*48:len]) + copy(out[1*48:], in[len-2*48:len-1*48]) + // 2 + copy(out[6*48:], in[len-3*48:len-2*48]) + copy(out[7*48:], in[len-4*48:len-3*48]) + // 3 + copy(out[2*48:], in[len-5*48:len-4*48]) + copy(out[3*48:], in[len-6*48:len-5*48]) + // 4 + copy(out[8*48:], in[len-7*48:len-6*48]) + copy(out[9*48:], in[len-8*48:len-7*48]) + // 5 + copy(out[4*48:], in[len-9*48:len-8*48]) + copy(out[5*48:], in[len-10*48:len-9*48]) + // 6 + copy(out[10*48:], in[len-11*48:len-10*48]) + copy(out[11*48:], in[len-12*48:len-11*48]) + return out +} + func FuzzCrossG1Add(data []byte) int { input := bytes.NewReader(data) From 403624a4a17bf99b74e50343024a07fe54c53fa7 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 7 Jun 2022 12:15:22 +0200 Subject: [PATCH 011/715] p2p/discover: fix panicky test (#25038) --- p2p/discover/v4_udp_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index e36912f010ae..977fa85a06c6 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -284,6 +284,7 @@ func TestUDPv4_findnode(t *testing.T) { test.waitPacketOut(func(p *v4wire.Neighbors, to *net.UDPAddr, hash []byte) { if len(p.Nodes) != len(want) { t.Errorf("wrong number of results: got %d, want %d", len(p.Nodes), bucketSize) + return } for i, n := range p.Nodes { if n.ID.ID() != want[i].ID() { From 450f5da7e1ea95a6cf898a5d00a328c03a7fbfff Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Tue, 7 Jun 2022 19:46:27 +0900 Subject: [PATCH 012/715] accounts: increase parseURL test coverage (#25033) accounts/url: add test logic what check null string to parseURL() --- accounts/url_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/accounts/url_test.go b/accounts/url_test.go index bd6f35fa2a0e..239aa06d227b 100644 --- a/accounts/url_test.go +++ b/accounts/url_test.go @@ -32,9 +32,10 @@ func TestURLParsing(t *testing.T) { t.Errorf("expected: %v, got: %v", "ethereum.org", url.Path) } - _, err = parseURL("ethereum.org") - if err == nil { - t.Error("expected err, got: nil") + for _, u := range []string{"ethereum.org", ""} { + if _, err = parseURL(u); err == nil { + t.Errorf("input %v, expected err, got: nil", u) + } } } From 41e75480df2a70265e9e364f100f9962e2972ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 7 Jun 2022 13:49:07 +0300 Subject: [PATCH 013/715] eth, les, params: log chain config a bit saner (#24904) Previously on Geth startup we just logged the chain config is a semi-json-y format. Whilst that worked while we had a handful of hard-forks defined, currently it's kind of unwieldy. This PR converts that original data dump and converts it into a user friendly - alas multiline - log output. --- core/forkid/forkid_test.go | 2 +- eth/backend.go | 9 +++- les/client.go | 9 +++- params/config.go | 100 ++++++++++++++++++++++++++----------- tests/init.go | 2 +- 5 files changed, 89 insertions(+), 33 deletions(-) diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index b0ee59b9eb7b..42adc0019d02 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -31,7 +31,7 @@ import ( // the correct fork ID. func TestCreation(t *testing.T) { mergeConfig := *params.MainnetChainConfig - mergeConfig.MergeForkBlock = big.NewInt(15000000) + mergeConfig.MergeNetsplitBlock = big.NewInt(15000000) type testcase struct { head uint64 want ID diff --git a/eth/backend.go b/eth/backend.go index 8e70723b5b16..b7b670c9dbf5 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -22,6 +22,7 @@ import ( "fmt" "math/big" "runtime" + "strings" "sync" "sync/atomic" "time" @@ -140,7 +141,13 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { return nil, genesisErr } - log.Info("Initialised chain configuration", "config", chainConfig) + log.Info("") + log.Info(strings.Repeat("-", 153)) + for _, line := range strings.Split(chainConfig.String(), "\n") { + log.Info(line) + } + log.Info(strings.Repeat("-", 153)) + log.Info("") if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil { log.Error("Failed to recover state", "error", err) diff --git a/les/client.go b/les/client.go index c3acbc2e4bf8..6eae73cf1631 100644 --- a/les/client.go +++ b/les/client.go @@ -19,6 +19,7 @@ package les import ( "fmt" + "strings" "time" "github.com/ethereum/go-ethereum/accounts" @@ -96,7 +97,13 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { return nil, genesisErr } - log.Info("Initialised chain configuration", "config", chainConfig) + log.Info("") + log.Info(strings.Repeat("-", 153)) + for _, line := range strings.Split(chainConfig.String(), "\n") { + log.Info(line) + } + log.Info(strings.Repeat("-", 153)) + log.Info("") peers := newServerPeerSet() merger := consensus.NewMerger(chainDb) diff --git a/params/config.go b/params/config.go index 2732e96468d8..c4a9ae981266 100644 --- a/params/config.go +++ b/params/config.go @@ -272,6 +272,15 @@ var ( TestRules = TestChainConfig.Rules(new(big.Int), false) ) +// NetworkNames are user friendly names to use in the chain spec banner. +var NetworkNames = map[string]string{ + MainnetChainConfig.ChainID.String(): "mainnet", + RopstenChainConfig.ChainID.String(): "ropsten", + RinkebyChainConfig.ChainID.String(): "rinkeby", + GoerliChainConfig.ChainID.String(): "goerli", + SepoliaChainConfig.ChainID.String(): "sepolia", +} + // TrustedCheckpoint represents a set of post-processed trie roots (CHT and // BloomTrie) associated with the appropriate section index and head hash. It is // used to start light syncing from this checkpoint and avoid downloading the @@ -348,7 +357,7 @@ type ChainConfig struct { BerlinBlock *big.Int `json:"berlinBlock,omitempty"` // Berlin switch block (nil = no fork, 0 = already on berlin) LondonBlock *big.Int `json:"londonBlock,omitempty"` // London switch block (nil = no fork, 0 = already on london) ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated) - MergeForkBlock *big.Int `json:"mergeForkBlock,omitempty"` // EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in merge proceedings) + MergeNetsplitBlock *big.Int `json:"mergeNetsplitBlock,omitempty"` // Virtual fork after The Merge to use as a network splitter // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. @@ -380,35 +389,68 @@ func (c *CliqueConfig) String() string { // String implements the fmt.Stringer interface. func (c *ChainConfig) String() string { - var engine interface{} + var banner string + + // Create some basinc network config output + network := NetworkNames[c.ChainID.String()] + if network == "" { + network = "unknown" + } + banner += fmt.Sprintf("Chain ID: %v (%s)\n", c.ChainID, network) switch { case c.Ethash != nil: - engine = c.Ethash + if c.TerminalTotalDifficulty == nil { + banner += "Consensus: Ethash (proof-of-work)\n" + } else { + banner += "Consensus: Beacon (proof-of-stake), merged from Ethash (proof-of-work)\n" + } case c.Clique != nil: - engine = c.Clique + if c.TerminalTotalDifficulty == nil { + banner += "Consensus: Clique (proof-of-authority)\n" + } else { + banner += "Consensus: Beacon (proof-of-stake), merged from Clique (proof-of-authority)\n" + } default: - engine = "unknown" - } - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, MergeFork: %v, Terminal TD: %v, Engine: %v}", - c.ChainID, - c.HomesteadBlock, - c.DAOForkBlock, - c.DAOForkSupport, - c.EIP150Block, - c.EIP155Block, - c.EIP158Block, - c.ByzantiumBlock, - c.ConstantinopleBlock, - c.PetersburgBlock, - c.IstanbulBlock, - c.MuirGlacierBlock, - c.BerlinBlock, - c.LondonBlock, - c.ArrowGlacierBlock, - c.MergeForkBlock, - c.TerminalTotalDifficulty, - engine, - ) + banner += "Consensus: unknown\n" + } + banner += "\n" + + // Create a list of forks with a short description of them. Forks that only + // makes sense for mainnet should be optional at printing to avoid bloating + // the output for testnets and private networks. + banner += "Pre-Merge hard forks:\n" + banner += fmt.Sprintf(" - Homestead: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/homestead.md)\n", c.HomesteadBlock) + if c.DAOForkBlock != nil { + banner += fmt.Sprintf(" - DAO Fork: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/dao-fork.md)\n", c.DAOForkBlock) + } + banner += fmt.Sprintf(" - Tangerine Whistle (EIP 150): %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/tangerine-whistle.md)\n", c.EIP150Block) + banner += fmt.Sprintf(" - Spurious Dragon/1 (EIP 155): %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md)\n", c.EIP155Block) + banner += fmt.Sprintf(" - Spurious Dragon/2 (EIP 158): %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md)\n", c.EIP155Block) + banner += fmt.Sprintf(" - Byzantium: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/byzantium.md)\n", c.ByzantiumBlock) + banner += fmt.Sprintf(" - Constantinople: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/constantinople.md)\n", c.ConstantinopleBlock) + banner += fmt.Sprintf(" - Petersburg: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/petersburg.md)\n", c.PetersburgBlock) + banner += fmt.Sprintf(" - Istanbul: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/istanbul.md)\n", c.IstanbulBlock) + if c.MuirGlacierBlock != nil { + banner += fmt.Sprintf(" - Muir Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/muir-glacier.md)\n", c.MuirGlacierBlock) + } + banner += fmt.Sprintf(" - Berlin: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/berlin.md)\n", c.BerlinBlock) + banner += fmt.Sprintf(" - London: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/london.md)\n", c.LondonBlock) + if c.ArrowGlacierBlock != nil { + banner += fmt.Sprintf(" - Arrow Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/arrow-glacier.md)\n", c.ArrowGlacierBlock) + } + banner += "\n" + + // Add a special section for the merge as it's non-obvious + if c.TerminalTotalDifficulty == nil { + banner += "Merge not configured!\n" + banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)" + } else { + banner += "Merge configured:\n" + banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)\n" + banner += fmt.Sprintf(" - Total terminal difficulty: %v\n", c.TerminalTotalDifficulty) + banner += fmt.Sprintf(" - Merge netsplit block: %-8v", c.MergeNetsplitBlock) + } + return banner } // IsHomestead returns whether num is either equal to the homestead block or greater. @@ -527,7 +569,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "berlinBlock", block: c.BerlinBlock}, {name: "londonBlock", block: c.LondonBlock}, {name: "arrowGlacierBlock", block: c.ArrowGlacierBlock, optional: true}, - {name: "mergeStartBlock", block: c.MergeForkBlock, optional: true}, + {name: "mergeNetsplitBlock", block: c.MergeNetsplitBlock, optional: true}, } { if lastFork.name != "" { // Next one must be higher number @@ -600,8 +642,8 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.ArrowGlacierBlock, newcfg.ArrowGlacierBlock, head) { return newCompatError("Arrow Glacier fork block", c.ArrowGlacierBlock, newcfg.ArrowGlacierBlock) } - if isForkIncompatible(c.MergeForkBlock, newcfg.MergeForkBlock, head) { - return newCompatError("Merge Start fork block", c.MergeForkBlock, newcfg.MergeForkBlock) + if isForkIncompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, head) { + return newCompatError("Merge netsplit fork block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock) } return nil } diff --git a/tests/init.go b/tests/init.go index 52277e841642..acf3790bf7ce 100644 --- a/tests/init.go +++ b/tests/init.go @@ -211,7 +211,7 @@ var Forks = map[string]*params.ChainConfig{ BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0), - MergeForkBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0), }, } From 138f0d74943a054b5c8bb6943e9041404defdf6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Anda=20Estensen?= Date: Tue, 7 Jun 2022 17:27:21 +0200 Subject: [PATCH 014/715] p2p: use errors.Is for error comparison (#24882) Co-authored-by: Felix Lange --- p2p/discover/lookup.go | 3 ++- p2p/discover/v4_udp.go | 4 ++-- p2p/discover/v5_udp.go | 4 ++-- p2p/discover/v5wire/encoding.go | 2 +- p2p/dnsdisc/client.go | 5 +++-- p2p/enr/entries.go | 12 ++++++++++-- p2p/peer.go | 2 +- p2p/peer_error.go | 2 +- p2p/simulations/http.go | 3 ++- 9 files changed, 24 insertions(+), 13 deletions(-) diff --git a/p2p/discover/lookup.go b/p2p/discover/lookup.go index 9ab4a71ce7b4..b8d97b44e1cc 100644 --- a/p2p/discover/lookup.go +++ b/p2p/discover/lookup.go @@ -18,6 +18,7 @@ package discover import ( "context" + "errors" "time" "github.com/ethereum/go-ethereum/p2p/enode" @@ -141,7 +142,7 @@ func (it *lookup) slowdown() { func (it *lookup) query(n *node, reply chan<- []*node) { fails := it.tab.db.FindFails(n.ID(), n.IP()) r, err := it.queryfunc(n) - if err == errClosed { + if errors.Is(err, errClosed) { // Avoid recording failures on shutdown. reply <- nil return diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 334716aebed0..a3e1549075b3 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -328,7 +328,7 @@ func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubke // enough nodes the reply matcher will time out waiting for the second reply, but // there's no need for an error in that case. err := <-rm.errc - if err == errTimeout && rm.reply != nil { + if errors.Is(err, errTimeout) && rm.reply != nil { err = nil } return nodes, err @@ -526,7 +526,7 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { continue } else if err != nil { // Shut down the loop for permament errors. - if err != io.EOF { + if !errors.Is(err, io.EOF) { t.log.Debug("UDP read error", "err", err) } return diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index dc63382fc901..22fab7243501 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -305,7 +305,7 @@ func (t *UDPv5) lookupWorker(destNode *node, target enode.ID) ([]*node, error) { ) var r []*enode.Node r, err = t.findnode(unwrapNode(destNode), dists) - if err == errClosed { + if errors.Is(err, errClosed) { return nil, err } for _, n := range r { @@ -623,7 +623,7 @@ func (t *UDPv5) readLoop() { continue } else if err != nil { // Shut down the loop for permament errors. - if err != io.EOF { + if !errors.Is(err, io.EOF) { t.log.Debug("UDP read error", "err", err) } return diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index 7d17281ef969..8dc64de6dfd6 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -596,7 +596,7 @@ func (c *Codec) decodeMessage(fromAddr string, head *Header, headerData, msgData // Try decrypting the message. key := c.sc.readKey(auth.SrcID, fromAddr) msg, err := c.decryptMessage(msgData, head.Nonce[:], headerData, key) - if err == errMessageDecrypt { + if errors.Is(err, errMessageDecrypt) { // It didn't work. Start the handshake since this is an ordinary message packet. return &Unknown{Nonce: head.Nonce}, nil } diff --git a/p2p/dnsdisc/client.go b/p2p/dnsdisc/client.go index 93868b39a8d4..3f914d6e9416 100644 --- a/p2p/dnsdisc/client.go +++ b/p2p/dnsdisc/client.go @@ -19,6 +19,7 @@ package dnsdisc import ( "bytes" "context" + "errors" "fmt" "math/rand" "net" @@ -204,7 +205,7 @@ func (c *Client) doResolveEntry(ctx context.Context, domain, hash string) (entry } for _, txt := range txts { e, err := parseEntry(txt, c.cfg.ValidSchemes) - if err == errUnknownEntry { + if errors.Is(err, errUnknownEntry) { continue } if !bytes.HasPrefix(crypto.Keccak256([]byte(txt)), wantHash) { @@ -281,7 +282,7 @@ func (it *randomIterator) nextNode() *enode.Node { } n, err := ct.syncRandom(it.ctx) if err != nil { - if err == it.ctx.Err() { + if errors.Is(err, it.ctx.Err()) { return nil // context canceled. } it.c.cfg.Logger.Debug("Error in DNS random node sync", "tree", ct.loc.domain, "err", err) diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go index f2118401afb8..a8b0a3839bda 100644 --- a/p2p/enr/entries.go +++ b/p2p/enr/entries.go @@ -17,6 +17,7 @@ package enr import ( + "errors" "fmt" "io" "net" @@ -180,9 +181,16 @@ func (err *KeyError) Error() string { return fmt.Sprintf("ENR key %q: %v", err.Key, err.Err) } +func (err *KeyError) Unwrap() error { + return err.Err +} + // IsNotFound reports whether the given error means that a key/value pair is // missing from a record. func IsNotFound(err error) bool { - kerr, ok := err.(*KeyError) - return ok && kerr.Err == errNotFound + var ke *KeyError + if errors.As(err, &ke) { + return ke.Err == errNotFound + } + return false } diff --git a/p2p/peer.go b/p2p/peer.go index 257027a5b74d..469a1b797416 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -416,7 +416,7 @@ func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) if err == nil { p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) err = errProtocolReturned - } else if err != io.EOF { + } else if !errors.Is(err, io.EOF) { p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) } p.protoErr <- err diff --git a/p2p/peer_error.go b/p2p/peer_error.go index 3028685041fe..ebc59de251a8 100644 --- a/p2p/peer_error.go +++ b/p2p/peer_error.go @@ -103,7 +103,7 @@ func discReasonForError(err error) DiscReason { if reason, ok := err.(DiscReason); ok { return reason } - if err == errProtocolReturned { + if errors.Is(err, errProtocolReturned) { return DiscQuitting } peerError, ok := err.(*peerError) diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go index 341ff8718b7d..66cdc13109d1 100644 --- a/p2p/simulations/http.go +++ b/p2p/simulations/http.go @@ -21,6 +21,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "html" "io" @@ -559,7 +560,7 @@ func (s *Server) CreateNode(w http.ResponseWriter, req *http.Request) { config := &adapters.NodeConfig{} err := json.NewDecoder(req.Body).Decode(config) - if err != nil && err != io.EOF { + if err != nil && !errors.Is(err, io.EOF) { http.Error(w, err.Error(), http.StatusBadRequest) return } From 106a162b7ca59d3660478cdeb6ca3ef473e21e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 8 Jun 2022 16:24:33 +0300 Subject: [PATCH 015/715] rpc: swap out timer metrics to histograms --- rpc/handler.go | 2 +- rpc/metrics.go | 25 ++++++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/rpc/handler.go b/rpc/handler.go index e8d1887c7d23..cd95a067f3e2 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -346,7 +346,7 @@ func (h *handler) handleCall(cp *callProc, msg *jsonrpcMessage) *jsonrpcMessage successfulRequestGauge.Inc(1) } rpcServingTimer.UpdateSince(start) - newRPCServingTimer(msg.Method, answer.Error == nil).UpdateSince(start) + updateServeTimeHistogram(msg.Method, answer.Error == nil, time.Since(start)) } return answer } diff --git a/rpc/metrics.go b/rpc/metrics.go index 4f166ad1cc07..b1f1284535e2 100644 --- a/rpc/metrics.go +++ b/rpc/metrics.go @@ -18,6 +18,7 @@ package rpc import ( "fmt" + "time" "github.com/ethereum/go-ethereum/metrics" ) @@ -26,14 +27,24 @@ var ( rpcRequestGauge = metrics.NewRegisteredGauge("rpc/requests", nil) successfulRequestGauge = metrics.NewRegisteredGauge("rpc/success", nil) failedRequestGauge = metrics.NewRegisteredGauge("rpc/failure", nil) - rpcServingTimer = metrics.NewRegisteredTimer("rpc/duration/all", nil) + + // serveTimeHistName is the prefix of the per-request serving time histograms. + serveTimeHistName = "rpc/duration" + + rpcServingTimer = metrics.NewRegisteredTimer("rpc/duration/all", nil) ) -func newRPCServingTimer(method string, valid bool) metrics.Timer { - flag := "success" - if !valid { - flag = "failure" +// updateServeTimeHistogram tracks the serving time of a remote RPC call. +func updateServeTimeHistogram(method string, success bool, elapsed time.Duration) { + note := "success" + if !success { + note = "failure" + } + h := fmt.Sprintf("%s/%s/%s", serveTimeHistName, method, note) + sampler := func() metrics.Sample { + return metrics.ResettingSample( + metrics.NewExpDecaySample(1028, 0.015), + ) } - m := fmt.Sprintf("rpc/duration/%s/%s", method, flag) - return metrics.GetOrRegisterTimer(m, nil) + metrics.GetOrRegisterHistogramLazy(h, nil, sampler).Update(elapsed.Microseconds()) } From b60a08d2fde030a9212b9a4b43eaacc450ed5b3e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 8 Jun 2022 15:36:25 +0200 Subject: [PATCH 016/715] eth/catalyst: remove unauthenticated 'engine' api (#24997) Removes engine from any unauthenticated RPC service. --- eth/catalyst/api.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 4ed5093d831c..166931e38134 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -47,13 +47,6 @@ func Register(stack *node.Node, backend *eth.Ethereum) error { Public: true, Authenticated: true, }, - { - Namespace: "engine", - Version: "1.0", - Service: NewConsensusAPI(backend), - Public: true, - Authenticated: false, - }, }) return nil } From 61602964459bc222725e4a818cd2cf311e94aa48 Mon Sep 17 00:00:00 2001 From: Rajaram Gaunker Date: Wed, 8 Jun 2022 09:31:43 -0700 Subject: [PATCH 017/715] core/types: remove unused field 'td' in Block (#25010) --- core/types/block.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index 8386c4c440e8..589a34cef6b5 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -172,10 +172,6 @@ type Block struct { hash atomic.Value size atomic.Value - // Td is used by package core to store the total difficulty - // of the chain up to and including the block. - td *big.Int - // These fields are used by package eth to track // inter-peer block relay. ReceivedAt time.Time @@ -197,7 +193,7 @@ type extblock struct { // are ignored and set to values derived from the given txs, uncles // and receipts. func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher TrieHasher) *Block { - b := &Block{header: CopyHeader(header), td: new(big.Int)} + b := &Block{header: CopyHeader(header)} // TODO: panic if len(txs) != len(receipts) if len(txs) == 0 { From f5037185aa6ebea0f7e6765b2439a3c8a066e85e Mon Sep 17 00:00:00 2001 From: henridf Date: Wed, 8 Jun 2022 18:32:07 +0200 Subject: [PATCH 018/715] core/types: improve LogForStorage and ReceiptForStorage comments (#25032) Co-authored-by: Felix Lange --- core/types/log.go | 4 ++-- core/types/receipt.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/types/log.go b/core/types/log.go index ee323ba86804..eb30957b1278 100644 --- a/core/types/log.go +++ b/core/types/log.go @@ -98,8 +98,8 @@ func (l *Log) DecodeRLP(s *rlp.Stream) error { return err } -// LogForStorage is a wrapper around a Log that flattens and parses the entire content of -// a log including non-consensus fields. +// LogForStorage is a wrapper around a Log that handles +// backward compatibility with prior storage formats. type LogForStorage Log // EncodeRLP implements rlp.Encoder. diff --git a/core/types/receipt.go b/core/types/receipt.go index a913cd0e83be..bdf48451473c 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -267,8 +267,8 @@ func (r *Receipt) Size() common.StorageSize { return size } -// ReceiptForStorage is a wrapper around a Receipt that flattens and parses the -// entire content of a receipt, as opposed to only the consensus fields originally. +// ReceiptForStorage is a wrapper around a Receipt with RLP serialization +// that omits the Bloom field and deserialization that re-computes it. type ReceiptForStorage Receipt // EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt From 594e32166269eed4f5cb8270bba99fa234a41606 Mon Sep 17 00:00:00 2001 From: int88 <106391185+int88@users.noreply.github.com> Date: Thu, 9 Jun 2022 00:40:37 +0800 Subject: [PATCH 019/715] core/evm: fix error in comment (#25040) Co-authored-by: Martin Holst Swende --- core/evm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/evm.go b/core/evm.go index 21e2639a5f63..e929da25eaee 100644 --- a/core/evm.go +++ b/core/evm.go @@ -31,7 +31,7 @@ type ChainContext interface { // Engine retrieves the chain's consensus engine. Engine() consensus.Engine - // GetHeader returns the hash corresponding to their hash. + // GetHeader returns the header corresponding to the hash/number argument pair. GetHeader(common.Hash, uint64) *types.Header } From 3f5b5ec3e55afcc81895d85e0022e3755189d172 Mon Sep 17 00:00:00 2001 From: Luozhu <70309026+LuozhuZhang@users.noreply.github.com> Date: Fri, 10 Jun 2022 16:57:32 +0800 Subject: [PATCH 020/715] internal/ethapi: fix typo in comment (#25056) typo error: keccack256 -> keccak256 --- internal/ethapi/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 7c422e642d70..5eb307a1f215 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -505,7 +505,7 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args Transactio } // Sign calculates an Ethereum ECDSA signature for: -// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message)) +// keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)) // // Note, the produced signature conforms to the secp256k1 curve R, S and V values, // where the V value will be 27 or 28 for legacy reasons. @@ -1741,7 +1741,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, input } // Sign calculates an ECDSA signature for: -// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message). +// keccak256("\x19Ethereum Signed Message:\n" + len(message) + message). // // Note, the produced signature conforms to the secp256k1 curve R, S and V values, // where the V value will be 27 or 28 for legacy reasons. From eb948962704397bb861fd4c0591b5056456edd4d Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Fri, 10 Jun 2022 16:47:06 +0100 Subject: [PATCH 021/715] Chore: Minimal gramatical errors (signleton -> singleton) (#25057) core: fix typos --- core/blockchain_test.go | 2 +- core/bloombits/matcher_test.go | 4 ++-- core/state/pruner/bloom.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 28d3ccd9269b..0cfb2f1c63dd 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -503,7 +503,7 @@ func TestReorgShortBlocks(t *testing.T) { testReorgShort(t, true) } func testReorgShort(t *testing.T, full bool) { // Create a long easy chain vs. a short heavy one. Due to difficulty adjustment // we need a fairly long chain of blocks with different difficulties for a short - // one to become heavyer than a long one. The 96 is an empirical value. + // one to become heavier than a long one. The 96 is an empirical value. easy := make([]int64, 96) for i := 0; i < len(easy); i++ { easy[i] = 60 diff --git a/core/bloombits/matcher_test.go b/core/bloombits/matcher_test.go index 923579221f51..93d4632b8587 100644 --- a/core/bloombits/matcher_test.go +++ b/core/bloombits/matcher_test.go @@ -124,13 +124,13 @@ func makeRandomIndexes(lengths []int, max int) [][]bloomIndexes { // testMatcherDiffBatches runs the given matches test in single-delivery and also // in batches delivery mode, verifying that all kinds of deliveries are handled -// correctly withn. +// correctly within. func testMatcherDiffBatches(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, intermittent bool, retrievals uint32) { singleton := testMatcher(t, filter, start, blocks, intermittent, retrievals, 1) batched := testMatcher(t, filter, start, blocks, intermittent, retrievals, 16) if singleton != batched { - t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, %v in signleton vs. %v in batched mode", filter, blocks, intermittent, singleton, batched) + t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, %v in singleton vs. %v in batched mode", filter, blocks, intermittent, singleton, batched) } } diff --git a/core/state/pruner/bloom.go b/core/state/pruner/bloom.go index 29bc4e7314ef..72315db720f1 100644 --- a/core/state/pruner/bloom.go +++ b/core/state/pruner/bloom.go @@ -39,7 +39,7 @@ func (f stateBloomHasher) BlockSize() int { panic("not implem func (f stateBloomHasher) Size() int { return 8 } func (f stateBloomHasher) Sum64() uint64 { return binary.BigEndian.Uint64(f) } -// stateBloom is a bloom filter used during the state convesion(snapshot->state). +// stateBloom is a bloom filter used during the state conversion(snapshot->state). // The keys of all generated entries will be recorded here so that in the pruning // stage the entries belong to the specific version can be avoided for deletion. // @@ -100,7 +100,7 @@ func (bloom *stateBloom) Commit(filename, tempname string) error { } f.Close() - // Move the teporary file into it's final location + // Move the temporary file into it's final location return os.Rename(tempname, filename) } From a907d7e81aaeea15d80b2d3209ad8e08e3bf49e0 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 13 Jun 2022 16:24:45 +0200 Subject: [PATCH 022/715] all: more linters (#24783) This enables the following linters - typecheck - unused - staticcheck - bidichk - durationcheck - exportloopref - gosec WIth a few exceptions. - We use a deprecated protobuf in trezor. I didn't want to mess with that, since I cannot meaningfully test any changes there. - The deprecated TypeMux is used in a few places still, so the warning for it is silenced for now. - Using string type in context.WithValue is apparently wrong, one should use a custom type, to prevent collisions between different places in the hierarchy of callers. That should be fixed at some point, but may require some attention. - The warnings for using weak random generator are squashed, since we use a lot of random without need for cryptographic guarantees. --- .golangci.yml | 51 ++++++++++---- accounts/abi/abi_test.go | 4 +- accounts/abi/bind/backends/simulated_test.go | 3 +- accounts/external/backend.go | 4 -- accounts/keystore/account_cache_test.go | 2 +- accounts/keystore/passphrase_test.go | 2 +- cmd/devp2p/internal/ethtest/snap.go | 4 ++ cmd/devp2p/internal/v5test/framework.go | 8 +-- cmd/geth/accountcmd.go | 7 +- cmd/geth/les_test.go | 35 --------- cmd/puppeth/ssh.go | 6 +- cmd/puppeth/wizard.go | 4 +- cmd/utils/diskusage.go | 1 + core/blockchain_sethead_test.go | 1 + core/blockchain_snapshot_test.go | 51 +------------- core/blockchain_test.go | 2 + core/rawdb/freezer_test.go | 2 +- core/rawdb/freezer_utils_test.go | 2 +- core/state/snapshot/journal.go | 2 +- core/tx_pool.go | 4 -- core/vm/contracts.go | 2 - core/vm/instructions_test.go | 42 +++++------ core/vm/runtime/runtime_test.go | 20 ------ crypto/blake2b/blake2b.go | 2 + crypto/blake2b/blake2b_generic.go | 1 + crypto/blake2b/blake2b_test.go | 8 --- crypto/bn256/cloudflare/gfp_decl.go | 2 +- eth/discovery.go | 63 ----------------- eth/downloader/downloader.go | 1 - eth/filters/api.go | 1 + eth/filters/bench_test.go | 8 +-- eth/filters/filter_system_test.go | 1 - eth/peer.go | 3 +- eth/protocols/snap/sort_test.go | 3 +- eth/protocols/snap/sync.go | 2 +- eth/protocols/snap/sync_test.go | 2 +- eth/tracers/tracers_test.go | 15 ---- go.mod | 2 +- graphql/graphql_test.go | 2 +- internal/build/gotool.go | 2 +- internal/debug/flags.go | 2 +- les/downloader/statesync.go | 6 +- les/fetcher_test.go | 4 +- les/flowcontrol/manager.go | 7 +- les/odr_test.go | 4 +- les/peer.go | 74 -------------------- les/ulc_test.go | 25 +++---- les/vflux/client/serverpool_test.go | 1 - les/vflux/server/clientpool.go | 1 - light/lightchain.go | 16 ----- metrics/influxdb/influxdb.go | 8 +-- metrics/influxdb/influxdbv2.go | 8 +-- miner/stress/beacon/main.go | 2 +- miner/worker_test.go | 1 - node/config_test.go | 5 +- node/utils_test.go | 2 - p2p/nat/natupnp.go | 2 +- p2p/server.go | 2 +- p2p/simulations/http.go | 1 + rlp/rlpgen/main.go | 2 +- rpc/client_test.go | 2 +- tests/fuzzers/difficulty/difficulty-fuzz.go | 1 - tests/init_test.go | 1 + tests/rlp_test_util.go | 2 +- tests/state_test.go | 1 + trie/proof.go | 18 ++--- trie/utils.go | 4 ++ 67 files changed, 156 insertions(+), 423 deletions(-) delete mode 100644 eth/discovery.go diff --git a/.golangci.yml b/.golangci.yml index 4950b98c21ba..b4aa0a01d779 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,10 +19,24 @@ linters: - govet - ineffassign - misspell - # - staticcheck - unconvert - # - unused - varcheck + - typecheck + - unused + - staticcheck + - bidichk + - durationcheck + - exportloopref + - gosec + + #- structcheck # lots of false positives + #- errcheck #lot of false positives + # - contextcheck + # - errchkjson # lots of false positives + # - errorlint # this check crashes + # - exhaustive # silly check + # - makezero # false positives + # - nilerr # several intentional linters-settings: gofmt: @@ -30,21 +44,28 @@ linters-settings: goconst: min-len: 3 # minimum length of string constant min-occurrences: 6 # minimum number of occurrences + gosec: + excludes: + - G404 # Use of weak random number generator - lots of FP + - G107 # Potential http request -- those are intentional + - G306 # G306: Expect WriteFile permissions to be 0600 or less issues: exclude-rules: - - path: crypto/blake2b/ - linters: - - deadcode - - path: crypto/bn256/cloudflare - linters: - - deadcode - - path: p2p/discv5/ - linters: - - deadcode - - path: core/vm/instructions_test.go - linters: - - goconst - - path: cmd/faucet/ + - path: crypto/bn256/cloudflare/optate.go linters: - deadcode + - staticcheck + - path: internal/build/pgp.go + text: 'SA1019: package golang.org/x/crypto/openpgp is deprecated' + - path: core/vm/contracts.go + text: 'SA1019: package golang.org/x/crypto/ripemd160 is deprecated' + - path: accounts/usbwallet/trezor.go + text: 'SA1019: package github.com/golang/protobuf/proto is deprecated' + - path: accounts/usbwallet/trezor/ + text: 'SA1019: package github.com/golang/protobuf/proto is deprecated' + exclude: + - 'SA1019: event.TypeMux is deprecated: use Feed' + - 'SA1019: strings.Title is deprecated' + - 'SA1029: should not use built-in type string as key for value' + - 'G306: Expect WriteFile permissions to be 0600 or less' \ No newline at end of file diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index cc8dfc61c389..cd9433ca7f73 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -1038,9 +1038,7 @@ func TestABI_EventById(t *testing.T) { } if event == nil { t.Errorf("We should find a event for topic %s, test #%d", topicID.Hex(), testnum) - } - - if event.ID != topicID { + } else if event.ID != topicID { t.Errorf("Event id %s does not match topic %s, test #%d", event.ID.Hex(), topicID.Hex(), testnum) } diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index 8a0cbe335778..2287055ebdfb 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -655,8 +655,7 @@ func TestHeaderByNumber(t *testing.T) { } if latestBlockHeader == nil { t.Errorf("received a nil block header") - } - if latestBlockHeader.Number.Uint64() != uint64(0) { + } else if latestBlockHeader.Number.Uint64() != uint64(0) { t.Errorf("expected block header number 0, instead got %v", latestBlockHeader.Number.Uint64()) } diff --git a/accounts/external/backend.go b/accounts/external/backend.go index e3f754eafcc4..d403b7e562d4 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -152,10 +152,6 @@ func (api *ExternalSigner) SelfDerive(bases []accounts.DerivationPath, chain eth log.Error("operation SelfDerive not supported on external signers") } -func (api *ExternalSigner) signHash(account accounts.Account, hash []byte) ([]byte, error) { - return []byte{}, fmt.Errorf("operation not supported on external signers") -} - // SignData signs keccak256(data). The mimetype parameter describes the type of data being signed func (api *ExternalSigner) SignData(account accounts.Account, mimeType string, data []byte) ([]byte, error) { var res hexutil.Bytes diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index fda0e5667c2a..bdcd81182512 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -383,7 +383,7 @@ func TestUpdatedKeyfileContents(t *testing.T) { time.Sleep(1000 * time.Millisecond) // Now replace file contents with crap - if err := os.WriteFile(file, []byte("foo"), 0644); err != nil { + if err := os.WriteFile(file, []byte("foo"), 0600); err != nil { t.Fatal(err) return } diff --git a/accounts/keystore/passphrase_test.go b/accounts/keystore/passphrase_test.go index b94fce8edcae..1356b317806d 100644 --- a/accounts/keystore/passphrase_test.go +++ b/accounts/keystore/passphrase_test.go @@ -52,7 +52,7 @@ func TestKeyEncryptDecrypt(t *testing.T) { t.Errorf("test %d: key address mismatch: have %x, want %x", i, key.Address, address) } // Recrypt with a new password and start over - password += "new data appended" + password += "new data appended" // nolint: gosec if keyjson, err = EncryptKey(key, password, veryLightScryptN, veryLightScryptP); err != nil { t.Errorf("test %d: failed to recrypt key %v", i, err) } diff --git a/cmd/devp2p/internal/ethtest/snap.go b/cmd/devp2p/internal/ethtest/snap.go index 2bfd29c75abf..9c3e88f9cb66 100644 --- a/cmd/devp2p/internal/ethtest/snap.go +++ b/cmd/devp2p/internal/ethtest/snap.go @@ -104,6 +104,7 @@ func (s *Suite) TestSnapGetAccountRange(t *utesting.T) { // Max bytes: 0. Expect to deliver one account. {0, root, zero, ffHash, 1, firstKey, firstKey}, } { + tc := tc if err := s.snapGetAccountRange(t, &tc); err != nil { t.Errorf("test %d \n root: %x\n range: %#x - %#x\n bytes: %d\nfailed: %v", i, tc.root, tc.origin, tc.limit, tc.nBytes, err) } @@ -194,6 +195,7 @@ func (s *Suite) TestSnapGetStorageRanges(t *utesting.T) { expSlots: 2, }, } { + tc := tc if err := s.snapGetStorageRanges(t, &tc); err != nil { t.Errorf("test %d \n root: %x\n range: %#x - %#x\n bytes: %d\n #accounts: %d\nfailed: %v", i, tc.root, tc.origin, tc.limit, tc.nBytes, len(tc.accounts), err) @@ -291,6 +293,7 @@ func (s *Suite) TestSnapGetByteCodes(t *utesting.T) { expHashes: 4, }, } { + tc := tc if err := s.snapGetByteCodes(t, &tc); err != nil { t.Errorf("test %d \n bytes: %d\n #hashes: %d\nfailed: %v", i, tc.nBytes, len(tc.hashes), err) } @@ -436,6 +439,7 @@ func (s *Suite) TestSnapTrieNodes(t *utesting.T) { }, }, } { + tc := tc if err := s.snapGetTrieNodes(t, &tc); err != nil { t.Errorf("test %d \n #hashes %x\n root: %#x\n bytes: %d\nfailed: %v", i, len(tc.expHashes), tc.root, tc.nBytes, err) } diff --git a/cmd/devp2p/internal/v5test/framework.go b/cmd/devp2p/internal/v5test/framework.go index 9eac37520f7b..6ccbbd075bf0 100644 --- a/cmd/devp2p/internal/v5test/framework.go +++ b/cmd/devp2p/internal/v5test/framework.go @@ -60,11 +60,9 @@ type conn struct { remoteAddr *net.UDPAddr listeners []net.PacketConn - log logger - codec *v5wire.Codec - lastRequest v5wire.Packet - lastChallenge *v5wire.Whoareyou - idCounter uint32 + log logger + codec *v5wire.Codec + idCounter uint32 } type logger interface { diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go index 0b7d58e8888c..f065b6eeab14 100644 --- a/cmd/geth/accountcmd.go +++ b/cmd/geth/accountcmd.go @@ -239,14 +239,15 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr } fmt.Println("Testing your password against all of them...") var match *accounts.Account - for _, a := range err.Matches { - if err := ks.Unlock(a, auth); err == nil { - match = &a + for i, a := range err.Matches { + if e := ks.Unlock(a, auth); e == nil { + match = &err.Matches[i] break } } if match == nil { utils.Fatalf("None of the listed files could be unlocked.") + return accounts.Account{} } fmt.Printf("Your password unlocked %s\n", match.URL) fmt.Println("In order to avoid this warning, you need to remove the following duplicate key files:") diff --git a/cmd/geth/les_test.go b/cmd/geth/les_test.go index 73cc23e6674f..56ed874cd64a 100644 --- a/cmd/geth/les_test.go +++ b/cmd/geth/les_test.go @@ -81,41 +81,6 @@ func (g *gethrpc) getNodeInfo() *p2p.NodeInfo { return g.nodeInfo } -func (g *gethrpc) waitSynced() { - // Check if it's synced now - var result interface{} - g.callRPC(&result, "eth_syncing") - syncing, ok := result.(bool) - if ok && !syncing { - g.geth.Logf("%v already synced", g.name) - return - } - - // Actually wait, subscribe to the event - ch := make(chan interface{}) - sub, err := g.rpc.Subscribe(context.Background(), "eth", ch, "syncing") - if err != nil { - g.geth.Fatalf("%v syncing: %v", g.name, err) - } - defer sub.Unsubscribe() - timeout := time.After(4 * time.Second) - select { - case ev := <-ch: - g.geth.Log("'syncing' event", ev) - syncing, ok := ev.(bool) - if ok && !syncing { - break - } - g.geth.Log("Other 'syncing' event", ev) - case err := <-sub.Err(): - g.geth.Fatalf("%v notification: %v", g.name, err) - break - case <-timeout: - g.geth.Fatalf("%v timeout syncing", g.name) - break - } -} - // ipcEndpoint resolves an IPC endpoint based on a configured value, taking into // account the set data folders as well as the designated platform we're currently // running on. diff --git a/cmd/puppeth/ssh.go b/cmd/puppeth/ssh.go index 95a36f327236..0c23ab556228 100644 --- a/cmd/puppeth/ssh.go +++ b/cmd/puppeth/ssh.go @@ -30,7 +30,7 @@ import ( "github.com/ethereum/go-ethereum/log" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" ) // sshClient is a small wrapper around Go's SSH client with a few utility methods @@ -101,7 +101,7 @@ func dial(server string, pubkey []byte) (*sshClient, error) { key, err := ssh.ParsePrivateKey(buf) if err != nil { fmt.Printf("What's the decryption password for %s? (won't be echoed)\n>", path) - blob, err := terminal.ReadPassword(int(os.Stdin.Fd())) + blob, err := term.ReadPassword(int(os.Stdin.Fd())) fmt.Println() if err != nil { log.Warn("Couldn't read password", "err", err) @@ -118,7 +118,7 @@ func dial(server string, pubkey []byte) (*sshClient, error) { } auths = append(auths, ssh.PasswordCallback(func() (string, error) { fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", username, server) - blob, err := terminal.ReadPassword(int(os.Stdin.Fd())) + blob, err := term.ReadPassword(int(os.Stdin.Fd())) fmt.Println() return string(blob), err diff --git a/cmd/puppeth/wizard.go b/cmd/puppeth/wizard.go index f7aafd4dd90a..6e5ca41d68fa 100644 --- a/cmd/puppeth/wizard.go +++ b/cmd/puppeth/wizard.go @@ -34,7 +34,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/log" "github.com/peterh/liner" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" ) // config contains all the configurations needed by puppeth that should be saved @@ -228,7 +228,7 @@ func (w *wizard) readDefaultFloat(def float64) float64 { // line and returns it. The input will not be echoed. func (w *wizard) readPassword() string { fmt.Printf("> ") - text, err := terminal.ReadPassword(int(os.Stdin.Fd())) + text, err := term.ReadPassword(int(os.Stdin.Fd())) if err != nil { log.Crit("Failed to read password", "err", err) } diff --git a/cmd/utils/diskusage.go b/cmd/utils/diskusage.go index 14cd5cd0bef8..0e88f9194430 100644 --- a/cmd/utils/diskusage.go +++ b/cmd/utils/diskusage.go @@ -33,6 +33,7 @@ func getFreeDiskSpace(path string) (uint64, error) { // Available blocks * size per block = available space in bytes var bavail = stat.Bavail + // nolint:staticcheck if stat.Bavail < 0 { // FreeBSD can have a negative number of blocks available // because of the grace limit. diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index 970e0306308d..d8103b5b5c50 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -51,6 +51,7 @@ type rewindTest struct { expHeadBlock uint64 // Block number of the expected head full block } +//nolint:unused func (tt *rewindTest) dump(crash bool) string { buffer := new(strings.Builder) diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index dfa8ed65ec6d..189eee59a009 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -150,6 +150,7 @@ func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks [ } } +//nolint:unused func (basic *snapshotTestBasic) dump() string { buffer := new(strings.Builder) @@ -341,54 +342,6 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) { snaptest.verify(t, newchain, blocks) } -// restartCrashSnapshotTest is the test type used to test this scenario: -// - have a complete snapshot -// - restart chain -// - insert more blocks with enabling the snapshot -// - commit the snapshot -// - crash -// - restart again -type restartCrashSnapshotTest struct { - snapshotTestBasic - newBlocks int -} - -func (snaptest *restartCrashSnapshotTest) test(t *testing.T) { - // It's hard to follow the test case, visualize the input - // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) - // fmt.Println(tt.dump()) - chain, blocks := snaptest.prepare(t) - - // Firstly, stop the chain properly, with all snapshot journal - // and state committed. - chain.Stop() - - newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) - if err != nil { - t.Fatalf("Failed to recreate chain: %v", err) - } - newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {}) - newchain.InsertChain(newBlocks) - - // Commit the entire snapshot into the disk if requested. Note only - // (a) snapshot root and (b) snapshot generator will be committed, - // the diff journal is not. - newchain.Snapshots().Cap(newBlocks[len(newBlocks)-1].Root(), 0) - - // Simulate the blockchain crash - // Don't call chain.Stop here, so that no snapshot - // journal and latest state will be committed - - // Restart the chain after the crash - newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) - if err != nil { - t.Fatalf("Failed to recreate chain: %v", err) - } - defer newchain.Stop() - - snaptest.verify(t, newchain, blocks) -} - // wipeCrashSnapshotTest is the test type used to test this scenario: // - have a complete snapshot // - restart, insert more blocks without enabling the snapshot @@ -431,7 +384,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { SnapshotLimit: 256, SnapshotWait: false, // Don't wait rebuild } - newchain, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + _, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 0cfb2f1c63dd..9144b3d9a660 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2576,6 +2576,7 @@ func TestTransactionIndices(t *testing.T) { t.Fatalf("failed to create temp freezer db: %v", err) } gspec.MustCommit(ancientDb) + l := l chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatalf("failed to create tester chain: %v", err) @@ -2601,6 +2602,7 @@ func TestTransactionIndices(t *testing.T) { limit = []uint64{0, 64 /* drop stale */, 32 /* shorten history */, 64 /* extend history */, 0 /* restore all */} tails := []uint64{0, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */, 69 /* 132 - 64 + 1 */, 0} for i, l := range limit { + l := l chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatalf("failed to create tester chain: %v", err) diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index c28d35ef387d..630911ec867c 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -277,7 +277,7 @@ func TestFreezerReadonlyValidate(t *testing.T) { // Re-openening as readonly should fail when validating // table lengths. - f, err = NewFreezer(dir, "", true, 2049, tables) + _, err = NewFreezer(dir, "", true, 2049, tables) if err == nil { t.Fatal("readonly freezer should fail with differing table lengths") } diff --git a/core/rawdb/freezer_utils_test.go b/core/rawdb/freezer_utils_test.go index cc300cb614fa..829cbfb4f332 100644 --- a/core/rawdb/freezer_utils_test.go +++ b/core/rawdb/freezer_utils_test.go @@ -43,7 +43,7 @@ func TestCopyFrom(t *testing.T) { {"foo", "bar", 8, true}, } for _, c := range cases { - os.WriteFile(c.src, content, 0644) + os.WriteFile(c.src, content, 0600) if err := copyFrom(c.src, c.dest, c.offset, func(f *os.File) error { if !c.writePrefix { diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index 80cd4eeee42a..9a22f2737306 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -284,7 +284,7 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error { } r := rlp.NewStream(bytes.NewReader(journal), 0) // Firstly, resolve the first element as the journal version - version, err := r.Uint() + version, err := r.Uint64() if err != nil { log.Warn("Failed to resolve the journal version", "error", err) return errors.New("failed to resolve journal version") diff --git a/core/tx_pool.go b/core/tx_pool.go index 81a726bae4ab..2f21fd09fa07 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -1603,10 +1603,6 @@ func (as *accountSet) contains(addr common.Address) bool { return exist } -func (as *accountSet) empty() bool { - return len(as.accounts) == 0 -} - // containsTx checks if the sender of a given tx is within the set. If the sender // cannot be derived, this method returns false. func (as *accountSet) containsTx(tx *types.Transaction) bool { diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 79f1a3611680..1b832b638695 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -29,8 +29,6 @@ import ( "github.com/ethereum/go-ethereum/crypto/bls12381" "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/params" - - //lint:ignore SA1019 Needed for precompile "golang.org/x/crypto/ripemd160" ) diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index f0fa4811ca7b..fb0fcc1da49d 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -229,32 +229,32 @@ func TestAddMod(t *testing.T) { } } -// getResult is a convenience function to generate the expected values -func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase { - var ( - env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) - stack = newstack() - pc = uint64(0) - interpreter = env.interpreter - ) - result := make([]TwoOperandTestcase, len(args)) - for i, param := range args { - x := new(uint256.Int).SetBytes(common.Hex2Bytes(param.x)) - y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y)) - stack.push(x) - stack.push(y) - opFn(&pc, interpreter, &ScopeContext{nil, stack, nil}) - actual := stack.pop() - result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)} - } - return result -} - // utility function to fill the json-file with testcases // Enable this test to generate the 'testcases_xx.json' files func TestWriteExpectedValues(t *testing.T) { t.Skip("Enable this test to create json test cases.") + // getResult is a convenience function to generate the expected values + getResult := func(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase { + var ( + env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) + stack = newstack() + pc = uint64(0) + interpreter = env.interpreter + ) + result := make([]TwoOperandTestcase, len(args)) + for i, param := range args { + x := new(uint256.Int).SetBytes(common.Hex2Bytes(param.x)) + y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y)) + stack.push(x) + stack.push(y) + opFn(&pc, interpreter, &ScopeContext{nil, stack, nil}) + actual := stack.pop() + result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)} + } + return result + } + for name, method := range twoOpMethods { data, err := json.Marshal(getResult(commonParams, method)) if err != nil { diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index fcaa10f1c62c..ca4e64843695 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -22,7 +22,6 @@ import ( "os" "strings" "testing" - "time" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -326,25 +325,6 @@ func TestBlockhash(t *testing.T) { } } -type stepCounter struct { - inner *logger.JSONLogger - steps int -} - -func (s *stepCounter) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { -} - -func (s *stepCounter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { -} - -func (s *stepCounter) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {} - -func (s *stepCounter) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - s.steps++ - // Enable this for more output - //s.inner.CaptureState(env, pc, op, gas, cost, memory, stack, rStack, contract, depth, err) -} - // benchmarkNonModifyingCode benchmarks code, but if the code modifies the // state, this should not be used, since it does not reset the state between runs. func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode string, b *testing.B) { diff --git a/crypto/blake2b/blake2b.go b/crypto/blake2b/blake2b.go index 5da50cab6f00..7ecaab813999 100644 --- a/crypto/blake2b/blake2b.go +++ b/crypto/blake2b/blake2b.go @@ -302,6 +302,7 @@ func appendUint64(b []byte, x uint64) []byte { return append(b, a[:]...) } +//nolint:unused,deadcode func appendUint32(b []byte, x uint32) []byte { var a [4]byte binary.BigEndian.PutUint32(a[:], x) @@ -313,6 +314,7 @@ func consumeUint64(b []byte) ([]byte, uint64) { return b[8:], x } +//nolint:unused,deadcode func consumeUint32(b []byte) ([]byte, uint32) { x := binary.BigEndian.Uint32(b) return b[4:], x diff --git a/crypto/blake2b/blake2b_generic.go b/crypto/blake2b/blake2b_generic.go index 35c40cc924f8..61e678fdf576 100644 --- a/crypto/blake2b/blake2b_generic.go +++ b/crypto/blake2b/blake2b_generic.go @@ -25,6 +25,7 @@ var precomputed = [10][16]byte{ {10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0}, } +// nolint:unused,deadcode func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { var m [16]uint64 c0, c1 := c[0], c[1] diff --git a/crypto/blake2b/blake2b_test.go b/crypto/blake2b/blake2b_test.go index 9e7297da160f..9d24444a27b7 100644 --- a/crypto/blake2b/blake2b_test.go +++ b/crypto/blake2b/blake2b_test.go @@ -14,14 +14,6 @@ import ( "testing" ) -func fromHex(s string) []byte { - b, err := hex.DecodeString(s) - if err != nil { - panic(err) - } - return b -} - func TestHashes(t *testing.T) { defer func(sse4, avx, avx2 bool) { useSSE4, useAVX, useAVX2 = sse4, avx, avx2 diff --git a/crypto/bn256/cloudflare/gfp_decl.go b/crypto/bn256/cloudflare/gfp_decl.go index ec4018e88a0c..cf7f5654239f 100644 --- a/crypto/bn256/cloudflare/gfp_decl.go +++ b/crypto/bn256/cloudflare/gfp_decl.go @@ -10,7 +10,7 @@ import ( "golang.org/x/sys/cpu" ) -//nolint:varcheck +//nolint:varcheck,unused,deadcode var hasBMI2 = cpu.X86.HasBMI2 // go:noescape diff --git a/eth/discovery.go b/eth/discovery.go deleted file mode 100644 index f7c85b4c5d3b..000000000000 --- a/eth/discovery.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2020 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 eth - -import ( - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/forkid" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/rlp" -) - -// ethEntry is the "eth" ENR entry which advertises eth protocol -// on the discovery network. -type ethEntry struct { - ForkID forkid.ID // Fork identifier per EIP-2124 - - // Ignore additional fields (for forward compatibility). - Rest []rlp.RawValue `rlp:"tail"` -} - -// ENRKey implements enr.Entry. -func (e ethEntry) ENRKey() string { - return "eth" -} - -// startEthEntryUpdate starts the ENR updater loop. -func (eth *Ethereum) startEthEntryUpdate(ln *enode.LocalNode) { - var newHead = make(chan core.ChainHeadEvent, 10) - sub := eth.blockchain.SubscribeChainHeadEvent(newHead) - - go func() { - defer sub.Unsubscribe() - for { - select { - case <-newHead: - ln.Set(eth.currentEthEntry()) - case <-sub.Err(): - // Would be nice to sync with eth.Stop, but there is no - // good way to do that. - return - } - } - }() -} - -func (eth *Ethereum) currentEthEntry() *ethEntry { - return ðEntry{ForkID: forkid.NewID(eth.blockchain.Config(), eth.blockchain.Genesis().Hash(), - eth.blockchain.CurrentHeader().Number.Uint64())} -} diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index c836fdd4b8cf..1dcacba3a267 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -131,7 +131,6 @@ type Downloader struct { pivotHeader *types.Header // Pivot block header to dynamically push the syncing state root pivotLock sync.RWMutex // Lock protecting pivot header reads from updates - snapSync bool // Whether to run state sync over the snap protocol SnapSyncer *snap.Syncer // TODO(karalabe): make private! hack for now stateSyncStart chan *stateSync diff --git a/eth/filters/api.go b/eth/filters/api.go index 7196e90f9eb7..41b3222bcaab 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -257,6 +257,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc select { case logs := <-matchedLogs: for _, log := range logs { + log := log notifier.Notify(rpcSub.ID, &log) } case <-rpcSub.Err(): // client send an unsubscribe request diff --git a/eth/filters/bench_test.go b/eth/filters/bench_test.go index 9632f4195f4c..694d73735028 100644 --- a/eth/filters/bench_test.go +++ b/eth/filters/bench_test.go @@ -93,9 +93,9 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) { var header *types.Header for i := sectionIdx * sectionSize; i < (sectionIdx+1)*sectionSize; i++ { hash := rawdb.ReadCanonicalHash(db, i) - header = rawdb.ReadHeader(db, hash, i) - if header == nil { + if header = rawdb.ReadHeader(db, hash, i); header == nil { b.Fatalf("Error creating bloomBits data") + return } bc.AddBloom(uint(i-sectionIdx*sectionSize), header.Bloom) } @@ -144,9 +144,9 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) { db.Close() } -var bloomBitsPrefix = []byte("bloomBits-") - +//nolint:unused func clearBloomBits(db ethdb.Database) { + var bloomBitsPrefix = []byte("bloomBits-") fmt.Println("Clearing bloombits data...") it := db.NewIterator(bloomBitsPrefix, nil) for it.Next() { diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 82d626ef127e..629e05416053 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -44,7 +44,6 @@ var ( ) type testBackend struct { - mux *event.TypeMux db ethdb.Database sections uint64 txFeed event.Feed diff --git a/eth/peer.go b/eth/peer.go index 024a6e619371..55e5f0046206 100644 --- a/eth/peer.go +++ b/eth/peer.go @@ -34,8 +34,7 @@ type ethPeerInfo struct { // ethPeer is a wrapper around eth.Peer to maintain a few extra metadata. type ethPeer struct { *eth.Peer - snapExt *snapPeer // Satellite `snap` connection - snapWait chan struct{} // Notification channel for snap connections + snapExt *snapPeer // Satellite `snap` connection } // info gathers and returns some `eth` protocol metadata known about a peer. diff --git a/eth/protocols/snap/sort_test.go b/eth/protocols/snap/sort_test.go index c625be09ea54..49730c886e7f 100644 --- a/eth/protocols/snap/sort_test.go +++ b/eth/protocols/snap/sort_test.go @@ -67,10 +67,9 @@ func TestRequestSorting(t *testing.T) { "0x01234567890123456789012345678901012345678901234567890123456789010", "0x01234567890123456789012345678901012345678901234567890123456789011", } { - sp, tnps, hash := f(x) + sp, _, hash := f(x) hashes = append(hashes, hash) paths = append(paths, sp) - pathsets = append(pathsets, tnps) } _, paths, pathsets = sortByAccountPath(hashes, paths) { diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 76072eb06c40..d68e728ff211 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -2781,7 +2781,7 @@ func (s *Syncer) onHealState(paths [][]byte, value []byte) error { if len(paths) == 1 { var account types.StateAccount if err := rlp.DecodeBytes(value, &account); err != nil { - return nil + return nil // Returning the error here would drop the remote peer } blob := snapshot.SlimAccountRLP(account.Nonce, account.Balance, account.Root, account.CodeHash) rawdb.WriteAccountSnapshot(s.stateWriter, common.BytesToHash(paths[0]), blob) diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 5eab6dd844e6..85e4dc5e4f83 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1661,7 +1661,7 @@ func TestSyncAccountPerformance(t *testing.T) { // Doing so would bring this number down to zero in this artificial testcase, // but only add extra IO for no reason in practice. if have, want := src.nTrienodeRequests, 1; have != want { - fmt.Printf(src.Stats()) + fmt.Print(src.Stats()) t.Errorf("trie node heal requests wrong, want %d, have %d", want, have) } } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index ce9289dd756b..12e01abae403 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -21,7 +21,6 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" @@ -32,20 +31,6 @@ import ( "github.com/ethereum/go-ethereum/tests" ) -// callTrace is the result of a callTracer run. -type callTrace struct { - Type string `json:"type"` - From common.Address `json:"from"` - To common.Address `json:"to"` - Input hexutil.Bytes `json:"input"` - Output hexutil.Bytes `json:"output"` - Gas *hexutil.Uint64 `json:"gas,omitempty"` - GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"` - Value *hexutil.Big `json:"value,omitempty"` - Error string `json:"error,omitempty"` - Calls []callTrace `json:"calls,omitempty"` -} - func BenchmarkTransactionTrace(b *testing.B) { key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") from := crypto.PubkeyToAddress(key.PublicKey) diff --git a/go.mod b/go.mod index fc944282f2d7..f9af9abe0052 100644 --- a/go.mod +++ b/go.mod @@ -59,6 +59,7 @@ require ( golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 golang.org/x/text v0.3.7 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 @@ -95,7 +96,6 @@ require ( github.com/tklauser/numcpus v0.2.2 // indirect golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect - golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/protobuf v1.23.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 2768026b5197..4b7f7bf96021 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -45,10 +45,10 @@ func TestBuildSchema(t *testing.T) { conf := node.DefaultConfig conf.DataDir = ddir stack, err := node.New(&conf) - defer stack.Close() if err != nil { t.Fatalf("could not create new node: %v", err) } + defer stack.Close() // Make sure the schema can be parsed and matched up to the object model. if err := newHandler(stack, nil, []string{}, []string{}); err != nil { t.Errorf("Could not construct GraphQL handler: %v", err) diff --git a/internal/build/gotool.go b/internal/build/gotool.go index e644b5f69526..08c8b2ef05fe 100644 --- a/internal/build/gotool.go +++ b/internal/build/gotool.go @@ -85,7 +85,7 @@ func (g *GoToolchain) goTool(command string, args ...string) *exec.Cmd { if g.Root == "" { g.Root = runtime.GOROOT() } - tool := exec.Command(filepath.Join(g.Root, "bin", "go"), command) + tool := exec.Command(filepath.Join(g.Root, "bin", "go"), command) // nolint: gosec tool.Args = append(tool.Args, args...) tool.Env = append(tool.Env, "GOROOT="+g.Root) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 3aa990adfb3a..d1bd31abeed6 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -20,7 +20,7 @@ import ( "fmt" "io" "net/http" - _ "net/http/pprof" + _ "net/http/pprof" // nolint: gosec "os" "runtime" diff --git a/les/downloader/statesync.go b/les/downloader/statesync.go index 2b3278822996..fd24c5150b3c 100644 --- a/les/downloader/statesync.go +++ b/les/downloader/statesync.go @@ -608,7 +608,7 @@ func (s *stateSync) updateStats(written, duplicate, unexpected int, duration tim if written > 0 || duplicate > 0 || unexpected > 0 { log.Info("Imported new state entries", "count", written, "elapsed", common.PrettyDuration(duration), "processed", s.d.syncStatsState.processed, "pending", s.d.syncStatsState.pending, "trieretry", len(s.trieTasks), "coderetry", len(s.codeTasks), "duplicate", s.d.syncStatsState.duplicate, "unexpected", s.d.syncStatsState.unexpected) } - if written > 0 { - //rawdb.WriteFastTrieProgress(s.d.stateDB, s.d.syncStatsState.processed) - } + //if written > 0 { + //rawdb.WriteFastTrieProgress(s.d.stateDB, s.d.syncStatsState.processed) + //} } diff --git a/les/fetcher_test.go b/les/fetcher_test.go index 28db3b8913ac..6a17e73757a5 100644 --- a/les/fetcher_test.go +++ b/les/fetcher_test.go @@ -160,7 +160,6 @@ func testTrustedAnnouncement(t *testing.T, protocol int) { nodes []*enode.Node ids []string cpeers []*clientPeer - speers []*serverPeer config = light.TestServerIndexerConfig waitIndexers = func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { @@ -213,12 +212,11 @@ func testTrustedAnnouncement(t *testing.T, protocol int) { // Connect all server instances. for i := 0; i < len(servers); i++ { - sp, cp, err := connect(servers[i].handler, nodes[i].ID(), c.handler, protocol, true) + _, cp, err := connect(servers[i].handler, nodes[i].ID(), c.handler, protocol, true) if err != nil { t.Fatalf("connect server and client failed, err %s", err) } cpeers = append(cpeers, cp) - speers = append(speers, sp) } newHead := make(chan *types.Header, 1) c.handler.fetcher.newHeadHook = func(header *types.Header) { newHead <- header } diff --git a/les/flowcontrol/manager.go b/les/flowcontrol/manager.go index c9e681c1440a..4ffbee58f0d0 100644 --- a/les/flowcontrol/manager.go +++ b/les/flowcontrol/manager.go @@ -58,10 +58,9 @@ var ( // corrigated buffer value and usually allows a higher remaining buffer value // to be returned with each reply. type ClientManager struct { - clock mclock.Clock - lock sync.Mutex - enabledCh chan struct{} - stop chan chan struct{} + clock mclock.Clock + lock sync.Mutex + stop chan chan struct{} curve PieceWiseLinear sumRecharge, totalRecharge, totalConnected uint64 diff --git a/les/odr_test.go b/les/odr_test.go index ad77abf5b9b2..24b8e2ae3111 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -392,12 +392,10 @@ func testGetTxStatusFromUnindexedPeers(t *testing.T, protocol int) { for _, testspec := range testspecs { // Create a bunch of server peers with different tx history var ( - serverPeers []*testPeer - closeFns []func() + closeFns []func() ) for i := 0; i < testspec.peers; i++ { peer, closePeer, _ := client.newRawPeer(t, fmt.Sprintf("server-%d", i), protocol, testspec.txLookups[i]) - serverPeers = append(serverPeers, peer) closeFns = append(closeFns, closePeer) // Create a one-time routine for serving message diff --git a/les/peer.go b/les/peer.go index 499429739d23..deda052a3b14 100644 --- a/les/peer.go +++ b/les/peer.go @@ -995,40 +995,6 @@ func (p *clientPeer) sendLastAnnounce() { } } -// freezeClient temporarily puts the client in a frozen state which means all -// unprocessed and subsequent requests are dropped. Unfreezing happens automatically -// after a short time if the client's buffer value is at least in the slightly positive -// region. The client is also notified about being frozen/unfrozen with a Stop/Resume -// message. -func (p *clientPeer) freezeClient() { - if p.version < lpv3 { - // if Stop/Resume is not supported then just drop the peer after setting - // its frozen status permanently - atomic.StoreUint32(&p.frozen, 1) - p.Peer.Disconnect(p2p.DiscUselessPeer) - return - } - if atomic.SwapUint32(&p.frozen, 1) == 0 { - go func() { - p.sendStop() - time.Sleep(freezeTimeBase + time.Duration(rand.Int63n(int64(freezeTimeRandom)))) - for { - bufValue, bufLimit := p.fcClient.BufferStatus() - if bufLimit == 0 { - return - } - if bufValue <= bufLimit/8 { - time.Sleep(freezeCheckPeriod) - } else { - atomic.StoreUint32(&p.frozen, 0) - p.sendResume(bufValue) - break - } - } - }() - } -} - // Handshake executes the les protocol handshake, negotiating version number, // network IDs, difficulties, head and genesis blocks. func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis common.Hash, forkID forkid.ID, forkFilter forkid.Filter, server *LesServer) error { @@ -1157,19 +1123,6 @@ func (ps *serverPeerSet) subscribe(sub serverPeerSubscriber) { } } -// unSubscribe removes the specified service from the subscriber pool. -func (ps *serverPeerSet) unSubscribe(sub serverPeerSubscriber) { - ps.lock.Lock() - defer ps.lock.Unlock() - - for i, s := range ps.subscribers { - if s == sub { - ps.subscribers = append(ps.subscribers[:i], ps.subscribers[i+1:]...) - return - } - } -} - // register adds a new server peer into the set, or returns an error if the // peer is already known. func (ps *serverPeerSet) register(peer *serverPeer) error { @@ -1236,25 +1189,6 @@ func (ps *serverPeerSet) len() int { return len(ps.peers) } -// bestPeer retrieves the known peer with the currently highest total difficulty. -// If the peerset is "client peer set", then nothing meaningful will return. The -// reason is client peer never send back their latest status to server. -func (ps *serverPeerSet) bestPeer() *serverPeer { - ps.lock.RLock() - defer ps.lock.RUnlock() - - var ( - bestPeer *serverPeer - bestTd *big.Int - ) - for _, p := range ps.peers { - if td := p.Td(); bestTd == nil || td.Cmp(bestTd) > 0 { - bestPeer, bestTd = p, td - } - } - return bestPeer -} - // allServerPeers returns all server peers in a list. func (ps *serverPeerSet) allPeers() []*serverPeer { ps.lock.RLock() @@ -1348,14 +1282,6 @@ func (ps *clientPeerSet) peer(id enode.ID) *clientPeer { return ps.peers[id] } -// len returns if the current number of peers in the set. -func (ps *clientPeerSet) len() int { - ps.lock.RLock() - defer ps.lock.RUnlock() - - return len(ps.peers) -} - // setSignerKey sets the signer key for signed announcements. Should be called before // starting the protocol handler. func (ps *clientPeerSet) setSignerKey(privateKey *ecdsa.PrivateKey) { diff --git a/les/ulc_test.go b/les/ulc_test.go index a4df0795b46d..9a29a24cee55 100644 --- a/les/ulc_test.go +++ b/les/ulc_test.go @@ -35,6 +35,19 @@ func TestULCAnnounceThresholdLes3(t *testing.T) { testULCAnnounceThreshold(t, 3) func testULCAnnounceThreshold(t *testing.T, protocol int) { // todo figure out why it takes fetcher so longer to fetcher the announced header. t.Skip("Sometimes it can failed") + + // newTestLightPeer creates node with light sync mode + newTestLightPeer := func(t *testing.T, protocol int, ulcServers []string, ulcFraction int) (*testClient, func()) { + netconfig := testnetConfig{ + protocol: protocol, + ulcServers: ulcServers, + ulcFraction: ulcFraction, + nopruning: true, + } + _, c, teardown := newClientServerEnv(t, netconfig) + return c, teardown + } + var cases = []struct { height []int threshold int @@ -148,15 +161,3 @@ func newTestServerPeer(t *testing.T, blocks int, protocol int, indexFn indexerCa n := enode.NewV4(&key.PublicKey, net.ParseIP("127.0.0.1"), 35000, 35000) return s, n, teardown } - -// newTestLightPeer creates node with light sync mode -func newTestLightPeer(t *testing.T, protocol int, ulcServers []string, ulcFraction int) (*testClient, func()) { - netconfig := testnetConfig{ - protocol: protocol, - ulcServers: ulcServers, - ulcFraction: ulcFraction, - nopruning: true, - } - _, c, teardown := newClientServerEnv(t, netconfig) - return c, teardown -} diff --git a/les/vflux/client/serverpool_test.go b/les/vflux/client/serverpool_test.go index c7d0245ef21d..9f83c5f7f2c0 100644 --- a/les/vflux/client/serverpool_test.go +++ b/les/vflux/client/serverpool_test.go @@ -55,7 +55,6 @@ type ServerPoolTest struct { clock *mclock.Simulated quit chan chan struct{} preNeg, preNegFail bool - vt *ValueTracker sp *ServerPool spi enode.Iterator input enode.Iterator diff --git a/les/vflux/server/clientpool.go b/les/vflux/server/clientpool.go index e90469bb1c9a..734d74f453c9 100644 --- a/les/vflux/server/clientpool.go +++ b/les/vflux/server/clientpool.go @@ -61,7 +61,6 @@ type ClientPool struct { setup *serverSetup clock mclock.Clock - closed bool ns *nodestate.NodeStateMachine synced func() bool diff --git a/light/lightchain.go b/light/lightchain.go index fa0dc71c9599..2a8e3672145a 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -355,22 +355,6 @@ func (lc *LightChain) Rollback(chain []common.Hash) { } } -// postChainEvents iterates over the events generated by a chain insertion and -// posts them into the event feed. -func (lc *LightChain) postChainEvents(events []interface{}) { - for _, event := range events { - switch ev := event.(type) { - case core.ChainEvent: - if lc.CurrentHeader().Hash() == ev.Hash { - lc.chainHeadFeed.Send(core.ChainHeadEvent{Block: ev.Block}) - } - lc.chainFeed.Send(ev) - case core.ChainSideEvent: - lc.chainSideFeed.Send(ev) - } - } -} - func (lc *LightChain) InsertHeader(header *types.Header) error { // Verify the header first before obtaining the lock headers := []*types.Header{header} diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go index dac9e824775a..e99717aeebf9 100644 --- a/metrics/influxdb/influxdb.go +++ b/metrics/influxdb/influxdb.go @@ -98,16 +98,16 @@ func (r *reporter) makeClient() (err error) { } func (r *reporter) run() { - intervalTicker := time.Tick(r.interval) - pingTicker := time.Tick(time.Second * 5) + intervalTicker := time.NewTicker(r.interval) + pingTicker := time.NewTicker(time.Second * 5) for { select { - case <-intervalTicker: + case <-intervalTicker.C: if err := r.send(); err != nil { log.Warn("Unable to send to InfluxDB", "err", err) } - case <-pingTicker: + case <-pingTicker.C: _, _, err := r.client.Ping() if err != nil { log.Warn("Got error while sending a ping to InfluxDB, trying to recreate client", "err", err) diff --git a/metrics/influxdb/influxdbv2.go b/metrics/influxdb/influxdbv2.go index 00901f52c9f4..31f956481dae 100644 --- a/metrics/influxdb/influxdbv2.go +++ b/metrics/influxdb/influxdbv2.go @@ -67,14 +67,14 @@ func InfluxDBV2WithTags(r metrics.Registry, d time.Duration, endpoint string, to } func (r *v2Reporter) run() { - intervalTicker := time.Tick(r.interval) - pingTicker := time.Tick(time.Second * 5) + intervalTicker := time.NewTicker(r.interval) + pingTicker := time.NewTicker(time.Second * 5) for { select { - case <-intervalTicker: + case <-intervalTicker.C: r.send() - case <-pingTicker: + case <-pingTicker.C: _, err := r.client.Health(context.Background()) if err != nil { log.Warn("Got error from influxdb client health check", "err", err.Error()) diff --git a/miner/stress/beacon/main.go b/miner/stress/beacon/main.go index 3f751049b89e..439bcc5d10bd 100644 --- a/miner/stress/beacon/main.go +++ b/miner/stress/beacon/main.go @@ -316,7 +316,7 @@ func (mgr *nodeManager) run() { nodes := mgr.getNodes(eth2MiningNode) nodes = append(nodes, mgr.getNodes(eth2NormalNode)...) nodes = append(nodes, mgr.getNodes(eth2LightClient)...) - for _, node := range append(nodes) { + for _, node := range nodes { fcState := beacon.ForkchoiceStateV1{ HeadBlockHash: oldest.Hash(), SafeBlockHash: common.Hash{}, diff --git a/miner/worker_test.go b/miner/worker_test.go index 55361349bcca..bda0fd4899b0 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -113,7 +113,6 @@ type testWorkerBackend struct { db ethdb.Database txPool *core.TxPool chain *core.BlockChain - testTxFeed event.Feed genesis *core.Genesis uncleBlock *types.Block } diff --git a/node/config_test.go b/node/config_test.go index d9f812ec4cb2..62b2fbbd16a3 100644 --- a/node/config_test.go +++ b/node/config_test.go @@ -63,12 +63,9 @@ func TestDatadirCreation(t *testing.T) { }() dir = filepath.Join(file.Name(), "invalid/path") - node, err = New(&Config{DataDir: dir}) + _, err = New(&Config{DataDir: dir}) if err == nil { t.Fatalf("protocol stack created with an invalid datadir") - if err := node.Close(); err != nil { - t.Fatalf("failed to close node: %v", err) - } } } diff --git a/node/utils_test.go b/node/utils_test.go index b7474bb70618..1974e2e17cdd 100644 --- a/node/utils_test.go +++ b/node/utils_test.go @@ -47,8 +47,6 @@ type InstrumentedService struct { startHook func() stopHook func() - - protocols []p2p.Protocol } func (s *InstrumentedService) Start() error { diff --git a/p2p/nat/natupnp.go b/p2p/nat/natupnp.go index 1f5d71466450..a8de00e978b9 100644 --- a/p2p/nat/natupnp.go +++ b/p2p/nat/natupnp.go @@ -79,7 +79,7 @@ func (n *upnp) ExternalIP() (addr net.IP, err error) { func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, lifetime time.Duration) error { ip, err := n.internalAddress() if err != nil { - return nil + return nil // TODO: Shouldn't we return the error? } protocol = strings.ToUpper(protocol) lifetimeS := uint32(lifetime / time.Second) diff --git a/p2p/server.go b/p2p/server.go index 138975e54bf5..898201f8f7fc 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -126,7 +126,7 @@ type Config struct { // Protocols should contain the protocols supported // by the server. Matching protocols are launched for // each peer. - Protocols []Protocol `toml:"-"` + Protocols []Protocol `toml:"-" json:"-"` // If ListenAddr is set to a non-nil address, the server // will listen for incoming connections. diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go index 66cdc13109d1..a344a8d5cbbe 100644 --- a/p2p/simulations/http.go +++ b/p2p/simulations/http.go @@ -442,6 +442,7 @@ func (s *Server) StreamNetworkEvents(w http.ResponseWriter, req *http.Request) { } } for _, conn := range snap.Conns { + conn := conn event := NewEvent(&conn) if err := writeEvent(event); err != nil { writeErr(err) diff --git a/rlp/rlpgen/main.go b/rlp/rlpgen/main.go index 6258fdb47a56..17d7e64e0842 100644 --- a/rlp/rlpgen/main.go +++ b/rlp/rlpgen/main.go @@ -51,7 +51,7 @@ func main() { } if *output == "-" { os.Stdout.Write(code) - } else if err := os.WriteFile(*output, code, 0644); err != nil { + } else if err := os.WriteFile(*output, code, 0600); err != nil { fatal(err) } } diff --git a/rpc/client_test.go b/rpc/client_test.go index fa6010bb199c..04c847d0d626 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -615,10 +615,10 @@ func TestClientReconnect(t *testing.T) { // Start a server and corresponding client. s1, l1 := startServer("127.0.0.1:0") client, err := DialContext(ctx, "ws://"+l1.Addr().String()) - defer client.Close() if err != nil { t.Fatal("can't dial", err) } + defer client.Close() // Perform a call. This should work because the server is up. var resp echoResult diff --git a/tests/fuzzers/difficulty/difficulty-fuzz.go b/tests/fuzzers/difficulty/difficulty-fuzz.go index 58936fcd80b1..2112abac1afa 100644 --- a/tests/fuzzers/difficulty/difficulty-fuzz.go +++ b/tests/fuzzers/difficulty/difficulty-fuzz.go @@ -30,7 +30,6 @@ import ( type fuzzer struct { input io.Reader exhausted bool - debugging bool } func (f *fuzzer) read(size int) []byte { diff --git a/tests/init_test.go b/tests/init_test.go index 218634966d83..4ef5aaf7378f 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -116,6 +116,7 @@ func (tm *testMatcher) skipLoad(pattern string) { } // fails adds an expected failure for tests matching the pattern. +//nolint:unused func (tm *testMatcher) fails(pattern string, reason string) { if reason == "" { panic("empty fail reason") diff --git a/tests/rlp_test_util.go b/tests/rlp_test_util.go index 9069ec55a15d..15acb3a244f7 100644 --- a/tests/rlp_test_util.go +++ b/tests/rlp_test_util.go @@ -124,7 +124,7 @@ func translateJSON(v interface{}) interface{} { func checkDecodeFromJSON(s *rlp.Stream, exp interface{}) error { switch exp := exp.(type) { case uint64: - i, err := s.Uint() + i, err := s.Uint64() if err != nil { return addStack("Uint", exp, err) } diff --git a/tests/state_test.go b/tests/state_test.go index d2c92b211cd1..93d8a1210626 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -174,6 +174,7 @@ func runBenchmarkFile(b *testing.B, path string) { return } for _, t := range m { + t := t runBenchmark(b, &t) } } diff --git a/trie/proof.go b/trie/proof.go index f42dcc761bee..9bf9107562fa 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -367,11 +367,12 @@ func unset(parent node, child node, key []byte, pos int, removeLeft bool) error // branch. The parent must be a fullnode. fn := parent.(*fullNode) fn.Children[key[pos-1]] = nil - } else { - // The key of fork shortnode is greater than the - // path(it doesn't belong to the range), keep - // it with the cached hash available. } + //else { + // The key of fork shortnode is greater than the + // path(it doesn't belong to the range), keep + // it with the cached hash available. + //} } else { if bytes.Compare(cld.Key, key[pos:]) > 0 { // The key of fork shortnode is greater than the @@ -379,11 +380,12 @@ func unset(parent node, child node, key []byte, pos int, removeLeft bool) error // branch. The parent must be a fullnode. fn := parent.(*fullNode) fn.Children[key[pos-1]] = nil - } else { - // The key of fork shortnode is less than the - // path(it doesn't belong to the range), keep - // it with the cached hash available. } + //else { + // The key of fork shortnode is less than the + // path(it doesn't belong to the range), keep + // it with the cached hash available. + //} } return nil } diff --git a/trie/utils.go b/trie/utils.go index fe7f6e52f9eb..7e26915041ef 100644 --- a/trie/utils.go +++ b/trie/utils.go @@ -50,6 +50,7 @@ func newTracer() *tracer { } } +/* // 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(key []byte, val []byte) { @@ -59,6 +60,7 @@ func (t *tracer) onRead(key []byte, val []byte) { } t.origin[string(key)] = 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 the "untouched". @@ -115,6 +117,7 @@ func (t *tracer) deleteList() [][]byte { return ret } +/* // getPrev returns the cached original value of the specified node. func (t *tracer) getPrev(key []byte) []byte { // Don't panic on uninitialized tracer, it's possible in testing. @@ -123,6 +126,7 @@ func (t *tracer) getPrev(key []byte) []byte { } return t.origin[string(key)] } +*/ // reset clears the content tracked by tracer. func (t *tracer) reset() { From f74bb3a3bff901e3179e8e335a4aeca04a18cf50 Mon Sep 17 00:00:00 2001 From: Ivan Aracki Date: Tue, 14 Jun 2022 10:24:29 +0200 Subject: [PATCH 023/715] cmd/utils: update --ropsten description (#25078) --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 0b28cd09f141..5908a55e099d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -150,7 +150,7 @@ var ( } RopstenFlag = cli.BoolFlag{ Name: "ropsten", - Usage: "Ropsten network: pre-configured proof-of-work test network", + Usage: "Ropsten network: pre-configured proof-of-stake test network", } RinkebyFlag = cli.BoolFlag{ Name: "rinkeby", From 1cf58c7b8113187c8f7e491b3f7ddbbb3bdd426f Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 14 Jun 2022 12:59:05 +0200 Subject: [PATCH 024/715] readme,eth: remove references to eth.wiki (#25086) --- README.md | 6 +++--- eth/filters/api.go | 14 -------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 0987200d3b9a..c6d758afc093 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ directory. | `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://docs.soliditylang.org/en/develop/abi-spec.html) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://geth.ethereum.org/docs/dapp/native-bindings) page for details. | | `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | | `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug run`). | -| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://eth.wiki/en/fundamentals/rlp)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | +| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | | `puppeth` | a CLI wizard that aids in creating a new Ethereum network. | ## Running `geth` @@ -188,7 +188,7 @@ accessible from the outside. As a developer, sooner rather than later you'll want to start interacting with `geth` and the Ethereum network via your own programs and not manually through the console. To aid -this, `geth` has built-in support for a JSON-RPC based APIs ([standard APIs](https://eth.wiki/json-rpc/API) +this, `geth` has built-in support for a JSON-RPC based APIs ([standard APIs](https://ethereum.github.io/execution-apis/api-documentation/) and [`geth` specific APIs](https://geth.ethereum.org/docs/rpc/server)). These can be exposed via HTTP, WebSockets and IPC (UNIX sockets on UNIX based platforms, and named pipes on Windows). @@ -297,7 +297,7 @@ $ bootnode --genkey=boot.key $ bootnode --nodekey=boot.key ``` -With the bootnode online, it will display an [`enode` URL](https://eth.wiki/en/fundamentals/enode-url-format) +With the bootnode online, it will display an [`enode` URL](https://ethereum.org/en/developers/docs/networking-layer/network-addresses/#enode) that other nodes can use to connect to it and exchange peer information. Make sure to replace the displayed IP address information (most probably `[::]`) with your externally accessible IP to get the actual `enode` URL. diff --git a/eth/filters/api.go b/eth/filters/api.go index 41b3222bcaab..ce2b0cb0b87d 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -101,8 +101,6 @@ func (api *PublicFilterAPI) timeoutLoop(timeout time.Duration) { // // It is part of the filter package because this filter can be used through the // `eth_getFilterChanges` polling method that is also used for log filters. -// -// https://eth.wiki/json-rpc/API#eth_newpendingtransactionfilter func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID { var ( pendingTxs = make(chan []common.Hash) @@ -171,8 +169,6 @@ func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Su // NewBlockFilter creates a filter that fetches blocks that are imported into the chain. // It is part of the filter package since polling goes with eth_getFilterChanges. -// -// https://eth.wiki/json-rpc/API#eth_newblockfilter func (api *PublicFilterAPI) NewBlockFilter() rpc.ID { var ( headers = make(chan *types.Header) @@ -288,8 +284,6 @@ type FilterCriteria ethereum.FilterQuery // again but with the removed property set to true. // // In case "fromBlock" > "toBlock" an error is returned. -// -// https://eth.wiki/json-rpc/API#eth_newfilter func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { logs := make(chan []*types.Log) logsSub, err := api.events.SubscribeLogs(ethereum.FilterQuery(crit), logs) @@ -323,8 +317,6 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { } // GetLogs returns logs matching the given argument that are stored within the state. -// -// https://eth.wiki/json-rpc/API#eth_getlogs func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) { var filter *Filter if crit.BlockHash != nil { @@ -352,8 +344,6 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([ } // UninstallFilter removes the filter with the given filter id. -// -// https://eth.wiki/json-rpc/API#eth_uninstallfilter func (api *PublicFilterAPI) UninstallFilter(id rpc.ID) bool { api.filtersMu.Lock() f, found := api.filters[id] @@ -370,8 +360,6 @@ func (api *PublicFilterAPI) UninstallFilter(id rpc.ID) bool { // GetFilterLogs returns the logs for the filter with the given id. // If the filter could not be found an empty array of logs is returned. -// -// https://eth.wiki/json-rpc/API#eth_getfilterlogs func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Log, error) { api.filtersMu.Lock() f, found := api.filters[id] @@ -411,8 +399,6 @@ func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*ty // // For pending transaction and block filters the result is []common.Hash. // (pending)Log filters return []Log. -// -// https://eth.wiki/json-rpc/API#eth_getfilterchanges func (api *PublicFilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { api.filtersMu.Lock() defer api.filtersMu.Unlock() From 6ad620d642039452c1cd7733547ec46b02114d6a Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 14 Jun 2022 19:47:11 +0800 Subject: [PATCH 025/715] cmd/ethkey: use accounts.TextHash (#25069) --- cmd/ethkey/message.go | 5 +++-- cmd/ethkey/utils.go | 13 ------------- signer/core/signed_data.go | 8 ++++---- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/cmd/ethkey/message.go b/cmd/ethkey/message.go index 1a58eeb536fa..8d253783ceb1 100644 --- a/cmd/ethkey/message.go +++ b/cmd/ethkey/message.go @@ -21,6 +21,7 @@ import ( "fmt" "os" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" @@ -68,7 +69,7 @@ To sign a message contained in a file, use the --msgfile flag. utils.Fatalf("Error decrypting key: %v", err) } - signature, err := crypto.Sign(signHash(message), key.PrivateKey) + signature, err := crypto.Sign(accounts.TextHash(message), key.PrivateKey) if err != nil { utils.Fatalf("Failed to sign message: %v", err) } @@ -113,7 +114,7 @@ It is possible to refer to a file containing the message.`, utils.Fatalf("Signature encoding is not hexadecimal: %v", err) } - recoveredPubkey, err := crypto.SigToPub(signHash(message), signature) + recoveredPubkey, err := crypto.SigToPub(accounts.TextHash(message), signature) if err != nil || recoveredPubkey == nil { utils.Fatalf("Signature verification failed: %v", err) } diff --git a/cmd/ethkey/utils.go b/cmd/ethkey/utils.go index b81e70913b5b..ed492272e33f 100644 --- a/cmd/ethkey/utils.go +++ b/cmd/ethkey/utils.go @@ -23,7 +23,6 @@ import ( "strings" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/crypto" "gopkg.in/urfave/cli.v1" ) @@ -46,18 +45,6 @@ func getPassphrase(ctx *cli.Context, confirmation bool) string { return utils.GetPassPhrase("", confirmation) } -// signHash is a helper function that calculates a hash for the given message -// that can be safely used to calculate a signature from. -// -// The hash is calculated as -// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). -// -// This gives context to the signed message and prevents signing of transactions. -func signHash(data []byte) []byte { - msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data) - return crypto.Keccak256([]byte(msg)) -} - // mustPrintJSON prints the JSON encoding of the given object and // exits the program with an error message when the marshaling fails. func mustPrintJSON(jsonObject interface{}) { diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go index 9bf47be799d8..48559bd98cf7 100644 --- a/signer/core/signed_data.go +++ b/signer/core/signed_data.go @@ -169,7 +169,7 @@ func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType req = &SignDataRequest{ContentType: mediaType, Rawdata: cliqueRlp, Messages: messages, Hash: sighash} default: // also case TextPlain.Mime: // Calculates an Ethereum ECDSA signature for: - // hash = keccak256("\x19${byteVersion}Ethereum Signed Message:\n${message length}${message}") + // hash = keccak256("\x19Ethereum Signed Message:\n${message length}${message}") // We expect it to be a string if stringData, ok := data.(string); !ok { return nil, useEthereumV, fmt.Errorf("input for text/plain must be an hex-encoded string") @@ -194,7 +194,7 @@ func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType return req, useEthereumV, nil } -// SignTextWithValidator signs the given message which can be further recovered +// SignTextValidator signs the given message which can be further recovered // with the given validator. // hash = keccak256("\x19\x00"${address}${data}). func SignTextValidator(validatorData apitypes.ValidatorData) (hexutil.Bytes, string) { @@ -271,11 +271,11 @@ func (api *SignerAPI) EcRecover(ctx context.Context, data hexutil.Bytes, sig hex // // Note, this function is compatible with eth_sign and personal_sign. As such it recovers // the address of: - // hash = keccak256("\x19${byteVersion}Ethereum Signed Message:\n${message length}${message}") + // hash = keccak256("\x19Ethereum Signed Message:\n${message length}${message}") // addr = ecrecover(hash, signature) // // Note, the signature must conform to the secp256k1 curve R, S and V values, where - // the V value must be be 27 or 28 for legacy reasons. + // the V value must be 27 or 28 for legacy reasons. // // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover if len(sig) != 65 { From 8cfd1214b7fd7118a22520b5ecdcdfe4d6158d6f Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 14 Jun 2022 14:08:43 +0200 Subject: [PATCH 026/715] common: improve pretty duration regex (#25073) * common: improve pretty duration regex * common: improve pretty duration regex --- common/format.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/format.go b/common/format.go index 6fc21af71923..7af41f52d540 100644 --- a/common/format.go +++ b/common/format.go @@ -27,12 +27,12 @@ import ( // the unnecessary precision off from the formatted textual representation. type PrettyDuration time.Duration -var prettyDurationRe = regexp.MustCompile(`\.[0-9]+`) +var prettyDurationRe = regexp.MustCompile(`\.[0-9]{4,}`) // String implements the Stringer interface, allowing pretty printing of duration // values rounded to three decimals. func (d PrettyDuration) String() string { - label := fmt.Sprintf("%v", time.Duration(d)) + label := time.Duration(d).String() if match := prettyDurationRe.FindString(label); len(match) > 4 { label = strings.Replace(label, match, match[:4], 1) } From bc013bc42ee1b15e5c74a8b634679ae054662071 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Tue, 14 Jun 2022 14:09:48 +0200 Subject: [PATCH 027/715] all: prefer `new(big.Int)` over `big.NewInt(0)` (#25087) minor performance improvement: `big.NewInt(0).Xxx` -> `new(big.Int).Xxx` --- accounts/abi/unpack.go | 10 ++++------ accounts/abi/unpack_test.go | 2 +- cmd/devp2p/internal/ethtest/chain.go | 4 ++-- cmd/evm/internal/t8ntool/execution.go | 2 +- consensus/ethash/consensus_test.go | 2 +- core/blockchain_test.go | 6 +++--- internal/ethapi/api.go | 2 +- rlp/decode_test.go | 2 +- rlp/encode_test.go | 6 +++--- signer/core/api_test.go | 2 +- signer/fourbyte/validation_test.go | 4 ++-- signer/rules/rules_test.go | 4 ++-- 12 files changed, 22 insertions(+), 24 deletions(-) diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index 43cd6c64575c..28c5c82bb3d5 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -255,7 +255,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) { // lengthPrefixPointsTo interprets a 32 byte slice as an offset and then determines which indices to look to decode the type. func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) { - bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32]) + bigOffsetEnd := new(big.Int).SetBytes(output[index : index+32]) bigOffsetEnd.Add(bigOffsetEnd, common.Big32) outputLength := big.NewInt(int64(len(output))) @@ -268,11 +268,9 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err } offsetEnd := int(bigOffsetEnd.Uint64()) - lengthBig := big.NewInt(0).SetBytes(output[offsetEnd-32 : offsetEnd]) + lengthBig := new(big.Int).SetBytes(output[offsetEnd-32 : offsetEnd]) - totalSize := big.NewInt(0) - totalSize.Add(totalSize, bigOffsetEnd) - totalSize.Add(totalSize, lengthBig) + totalSize := new(big.Int).Add(bigOffsetEnd, lengthBig) if totalSize.BitLen() > 63 { return 0, 0, fmt.Errorf("abi: length larger than int64: %v", totalSize) } @@ -287,7 +285,7 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err // tuplePointsTo resolves the location reference for dynamic tuple. func tuplePointsTo(index int, output []byte) (start int, err error) { - offset := big.NewInt(0).SetBytes(output[index : index+32]) + offset := new(big.Int).SetBytes(output[index : index+32]) outputLen := big.NewInt(int64(len(output))) if offset.Cmp(outputLen) > 0 { diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index bf40c301b5f7..ae3565c71e29 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -424,7 +424,7 @@ func TestMultiReturnWithStringArray(t *testing.T) { } buff := new(bytes.Buffer) buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000005c1b78ea0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000001a055690d9db80000000000000000000000000000ab1257528b3782fb40d7ed5f72e624b744dffb2f00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001048656c6c6f2c20457468657265756d2100000000000000000000000000000000")) - temp, _ := big.NewInt(0).SetString("30000000000000000000", 10) + temp, _ := new(big.Int).SetString("30000000000000000000", 10) ret1, ret1Exp := new([3]*big.Int), [3]*big.Int{big.NewInt(1545304298), big.NewInt(6), temp} ret2, ret2Exp := new(common.Address), common.HexToAddress("ab1257528b3782fb40d7ed5f72e624b744dffb2f") ret3, ret3Exp := new([2]string), [2]string{"Ethereum", "Hello, Ethereum!"} diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index c1d696b40728..0a17252a3503 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -47,7 +47,7 @@ func (c *Chain) Len() int { // TD calculates the total difficulty of the chain at the // chain head. func (c *Chain) TD() *big.Int { - sum := big.NewInt(0) + sum := new(big.Int) for _, block := range c.blocks[:c.Len()] { sum.Add(sum, block.Difficulty()) } @@ -57,7 +57,7 @@ func (c *Chain) TD() *big.Int { // TotalDifficultyAt calculates the total difficulty of the chain // at the given block height. func (c *Chain) TotalDifficultyAt(height int) *big.Int { - sum := big.NewInt(0) + sum := new(big.Int) if height >= c.Len() { return sum } diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 83a0025344a4..241b57f55ea9 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -241,7 +241,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, minerReward.Add(minerReward, perOmmer) // Add (8-delta)/8 reward := big.NewInt(8) - reward.Sub(reward, big.NewInt(0).SetUint64(ommer.Delta)) + reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) reward.Mul(reward, blockReward) reward.Div(reward, big.NewInt(8)) statedb.AddBalance(ommer.Address, reward) diff --git a/consensus/ethash/consensus_test.go b/consensus/ethash/consensus_test.go index bca424af30e3..db997d737e62 100644 --- a/consensus/ethash/consensus_test.go +++ b/consensus/ethash/consensus_test.go @@ -103,7 +103,7 @@ func TestDifficultyCalculators(t *testing.T) { for i := 0; i < 5000; i++ { // 1 to 300 seconds diff var timeDelta = uint64(1 + rand.Uint32()%3000) - diffBig := big.NewInt(0).SetBytes(randSlice(2, 10)) + diffBig := new(big.Int).SetBytes(randSlice(2, 10)) if diffBig.Cmp(params.MinimumDifficulty) < 0 { diffBig.Set(params.MinimumDifficulty) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 9144b3d9a660..c1e1d6371e0d 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2764,7 +2764,7 @@ func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) { numBlocks = 1 ) recipientFn := func(nonce uint64) common.Address { - return common.BigToAddress(big.NewInt(0).SetUint64(1337 + nonce)) + return common.BigToAddress(new(big.Int).SetUint64(1337 + nonce)) } dataFn := func(nonce uint64) []byte { return nil @@ -2781,7 +2781,7 @@ func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) { b.ResetTimer() recipientFn := func(nonce uint64) common.Address { - return common.BigToAddress(big.NewInt(0).SetUint64(1337)) + return common.BigToAddress(new(big.Int).SetUint64(1337)) } dataFn := func(nonce uint64) []byte { return nil @@ -2798,7 +2798,7 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { b.ResetTimer() recipientFn := func(nonce uint64) common.Address { - return common.BigToAddress(big.NewInt(0).SetUint64(0xc0de)) + return common.BigToAddress(new(big.Int).SetUint64(0xc0de)) } dataFn := func(nonce uint64) []byte { return nil diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 5eb307a1f215..4aa37a8dc4c3 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1268,7 +1268,7 @@ type RPCTransaction struct { // newRPCTransaction returns a transaction that will serialize to the RPC // representation, with the given location metadata set (if available). func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { - signer := types.MakeSigner(config, big.NewInt(0).SetUint64(blockNumber)) + signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber)) from, _ := types.Sender(signer, tx) v, r, s := tx.RawSignatureValues() result := &RPCTransaction{ diff --git a/rlp/decode_test.go b/rlp/decode_test.go index 46aa68cea3d7..e0d33dc43ee9 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -452,7 +452,7 @@ type ignoredField struct { var ( veryBigInt = new(big.Int).Add( - big.NewInt(0).Lsh(big.NewInt(0xFFFFFFFFFFFFFF), 16), + new(big.Int).Lsh(big.NewInt(0xFFFFFFFFFFFFFF), 16), big.NewInt(0xFFFF), ) veryVeryBigInt = new(big.Int).Exp(veryBigInt, big.NewInt(8), nil) diff --git a/rlp/encode_test.go b/rlp/encode_test.go index 78392906b557..58ddc0d120f0 100644 --- a/rlp/encode_test.go +++ b/rlp/encode_test.go @@ -119,15 +119,15 @@ var encTests = []encTest{ {val: big.NewInt(0xFFFFFFFFFFFF), output: "86FFFFFFFFFFFF"}, {val: big.NewInt(0xFFFFFFFFFFFFFF), output: "87FFFFFFFFFFFFFF"}, { - val: big.NewInt(0).SetBytes(unhex("102030405060708090A0B0C0D0E0F2")), + val: new(big.Int).SetBytes(unhex("102030405060708090A0B0C0D0E0F2")), output: "8F102030405060708090A0B0C0D0E0F2", }, { - val: big.NewInt(0).SetBytes(unhex("0100020003000400050006000700080009000A000B000C000D000E01")), + val: new(big.Int).SetBytes(unhex("0100020003000400050006000700080009000A000B000C000D000E01")), output: "9C0100020003000400050006000700080009000A000B000C000D000E01", }, { - val: big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000")), + val: new(big.Int).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000")), output: "A1010000000000000000000000000000000000000000000000000000000000000000", }, { diff --git a/signer/core/api_test.go b/signer/core/api_test.go index ddc2b82eac69..821af663fa81 100644 --- a/signer/core/api_test.go +++ b/signer/core/api_test.go @@ -62,7 +62,7 @@ func (ui *headlessUi) ApproveTx(request *core.SignTxRequest) (core.SignTxRespons case "M": // modify // The headless UI always modifies the transaction old := big.Int(request.Transaction.Value) - newVal := big.NewInt(0).Add(&old, big.NewInt(1)) + newVal := new(big.Int).Add(&old, big.NewInt(1)) request.Transaction.Value = hexutil.Big(*newVal) return core.SignTxResponse{request.Transaction, true}, nil default: diff --git a/signer/fourbyte/validation_test.go b/signer/fourbyte/validation_test.go index c3085696f432..2e6d9f2d9bb7 100644 --- a/signer/fourbyte/validation_test.go +++ b/signer/fourbyte/validation_test.go @@ -29,11 +29,11 @@ func mixAddr(a string) (*common.MixedcaseAddress, error) { return common.NewMixedcaseAddressFromString(a) } func toHexBig(h string) hexutil.Big { - b := big.NewInt(0).SetBytes(common.FromHex(h)) + b := new(big.Int).SetBytes(common.FromHex(h)) return hexutil.Big(*b) } func toHexUint(h string) hexutil.Uint64 { - b := big.NewInt(0).SetBytes(common.FromHex(h)) + b := new(big.Int).SetBytes(common.FromHex(h)) return hexutil.Uint64(b.Uint64()) } func dummyTxArgs(t txtestcase) *apitypes.SendTxArgs { diff --git a/signer/rules/rules_test.go b/signer/rules/rules_test.go index 0ab246eeaf7e..af4ed2d7e132 100644 --- a/signer/rules/rules_test.go +++ b/signer/rules/rules_test.go @@ -449,7 +449,7 @@ func dummyTx(value hexutil.Big) *core.SignTxRequest { } func dummyTxWithV(value uint64) *core.SignTxRequest { - v := big.NewInt(0).SetUint64(value) + v := new(big.Int).SetUint64(value) h := hexutil.Big(*v) return dummyTx(h) } @@ -469,7 +469,7 @@ func TestLimitWindow(t *testing.T) { return } // 0.3 ether: 429D069189E0000 wei - v := big.NewInt(0).SetBytes(common.Hex2Bytes("0429D069189E0000")) + v := new(big.Int).SetBytes(common.Hex2Bytes("0429D069189E0000")) h := hexutil.Big(*v) // The first three should succeed for i := 0; i < 3; i++ { From 3273ad1a587ef0707d865074ec84e75e152bd016 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Wed, 15 Jun 2022 09:29:23 +0200 Subject: [PATCH 028/715] eth: add missing period at end of sentences (#25058) eth: add missing periods on end of comments --- eth/api.go | 12 ++++++------ eth/downloader/api.go | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/eth/api.go b/eth/api.go index 1892746602cf..818df89c07c9 100644 --- a/eth/api.go +++ b/eth/api.go @@ -52,17 +52,17 @@ func NewPublicEthereumAPI(e *Ethereum) *PublicEthereumAPI { return &PublicEthereumAPI{e} } -// Etherbase is the address that mining rewards will be send to +// Etherbase is the address that mining rewards will be send to. func (api *PublicEthereumAPI) Etherbase() (common.Address, error) { return api.e.Etherbase() } -// Coinbase is the address that mining rewards will be send to (alias for Etherbase) +// Coinbase is the address that mining rewards will be send to (alias for Etherbase). func (api *PublicEthereumAPI) Coinbase() (common.Address, error) { return api.Etherbase() } -// Hashrate returns the POW hashrate +// Hashrate returns the POW hashrate. func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 { return hexutil.Uint64(api.e.Miner().Hashrate()) } @@ -136,7 +136,7 @@ func (api *PrivateMinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool { return true } -// SetEtherbase sets the etherbase of the miner +// SetEtherbase sets the etherbase of the miner. func (api *PrivateMinerAPI) SetEtherbase(etherbase common.Address) bool { api.e.SetEtherbase(etherbase) return true @@ -160,7 +160,7 @@ func NewPrivateAdminAPI(eth *Ethereum) *PrivateAdminAPI { } // ExportChain exports the current blockchain into a local file, -// or a range of blocks if first and last are non-nil +// or a range of blocks if first and last are non-nil. func (api *PrivateAdminAPI) ExportChain(file string, first *uint64, last *uint64) (bool, error) { if first == nil && last != nil { return false, errors.New("last cannot be specified without first") @@ -328,7 +328,7 @@ type BadBlockArgs struct { } // GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network -// and returns them as a JSON list of block-hashes +// and returns them as a JSON list of block hashes. func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) { var ( err error diff --git a/eth/downloader/api.go b/eth/downloader/api.go index 2024d23deade..645912286d57 100644 --- a/eth/downloader/api.go +++ b/eth/downloader/api.go @@ -159,7 +159,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. func (api *PublicDownloaderAPI) SubscribeSyncStatus(status chan interface{}) *SyncStatusSubscription { api.installSyncSubscription <- status return &SyncStatusSubscription{api: api, c: status} From 30602163d5d8321fbc68afdcbbaf2362b2641bde Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 15 Jun 2022 18:56:47 +0800 Subject: [PATCH 029/715] eth: introduce eth67 protocol (#24093) The new protocol version removes support for GetNodeData. See https://eips.ethereum.org/EIPS/eip-4938 for more information. Co-authored-by: Felix Lange Co-authored-by: Martin Holst Swende --- eth/downloader/downloader_test.go | 73 ++++++++++++++++++++++++++++++- eth/protocols/eth/handler.go | 21 +++++++-- eth/protocols/eth/protocol.go | 5 ++- eth/sync_test.go | 1 + les/downloader/peer.go | 8 ++-- 5 files changed, 97 insertions(+), 11 deletions(-) diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index a5db037a456c..5e77d3272d63 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -437,6 +437,9 @@ func assertOwnChain(t *testing.T, tester *downloadTester, length int) { func TestCanonicalSynchronisation66Full(t *testing.T) { testCanonSync(t, eth.ETH66, FullSync) } func TestCanonicalSynchronisation66Snap(t *testing.T) { testCanonSync(t, eth.ETH66, SnapSync) } func TestCanonicalSynchronisation66Light(t *testing.T) { testCanonSync(t, eth.ETH66, LightSync) } +func TestCanonicalSynchronisation67Full(t *testing.T) { testCanonSync(t, eth.ETH67, FullSync) } +func TestCanonicalSynchronisation67Snap(t *testing.T) { testCanonSync(t, eth.ETH67, SnapSync) } +func TestCanonicalSynchronisation67Light(t *testing.T) { testCanonSync(t, eth.ETH67, LightSync) } func testCanonSync(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -457,6 +460,8 @@ func testCanonSync(t *testing.T, protocol uint, mode SyncMode) { // until the cached blocks are retrieved. func TestThrottling66Full(t *testing.T) { testThrottling(t, eth.ETH66, FullSync) } func TestThrottling66Snap(t *testing.T) { testThrottling(t, eth.ETH66, SnapSync) } +func TestThrottling67Full(t *testing.T) { testThrottling(t, eth.ETH67, FullSync) } +func TestThrottling67Snap(t *testing.T) { testThrottling(t, eth.ETH67, SnapSync) } func testThrottling(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -537,6 +542,9 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { func TestForkedSync66Full(t *testing.T) { testForkedSync(t, eth.ETH66, FullSync) } func TestForkedSync66Snap(t *testing.T) { testForkedSync(t, eth.ETH66, SnapSync) } func TestForkedSync66Light(t *testing.T) { testForkedSync(t, eth.ETH66, LightSync) } +func TestForkedSync67Full(t *testing.T) { testForkedSync(t, eth.ETH67, FullSync) } +func TestForkedSync67Snap(t *testing.T) { testForkedSync(t, eth.ETH67, SnapSync) } +func TestForkedSync67Light(t *testing.T) { testForkedSync(t, eth.ETH67, LightSync) } func testForkedSync(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -564,6 +572,9 @@ func testForkedSync(t *testing.T, protocol uint, mode SyncMode) { func TestHeavyForkedSync66Full(t *testing.T) { testHeavyForkedSync(t, eth.ETH66, FullSync) } func TestHeavyForkedSync66Snap(t *testing.T) { testHeavyForkedSync(t, eth.ETH66, SnapSync) } func TestHeavyForkedSync66Light(t *testing.T) { testHeavyForkedSync(t, eth.ETH66, LightSync) } +func TestHeavyForkedSync67Full(t *testing.T) { testHeavyForkedSync(t, eth.ETH67, FullSync) } +func TestHeavyForkedSync67Snap(t *testing.T) { testHeavyForkedSync(t, eth.ETH67, SnapSync) } +func TestHeavyForkedSync67Light(t *testing.T) { testHeavyForkedSync(t, eth.ETH67, LightSync) } func testHeavyForkedSync(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -593,6 +604,9 @@ func testHeavyForkedSync(t *testing.T, protocol uint, mode SyncMode) { func TestBoundedForkedSync66Full(t *testing.T) { testBoundedForkedSync(t, eth.ETH66, FullSync) } func TestBoundedForkedSync66Snap(t *testing.T) { testBoundedForkedSync(t, eth.ETH66, SnapSync) } func TestBoundedForkedSync66Light(t *testing.T) { testBoundedForkedSync(t, eth.ETH66, LightSync) } +func TestBoundedForkedSync67Full(t *testing.T) { testBoundedForkedSync(t, eth.ETH67, FullSync) } +func TestBoundedForkedSync67Snap(t *testing.T) { testBoundedForkedSync(t, eth.ETH67, SnapSync) } +func TestBoundedForkedSync67Light(t *testing.T) { testBoundedForkedSync(t, eth.ETH67, LightSync) } func testBoundedForkedSync(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -627,6 +641,15 @@ func TestBoundedHeavyForkedSync66Snap(t *testing.T) { func TestBoundedHeavyForkedSync66Light(t *testing.T) { testBoundedHeavyForkedSync(t, eth.ETH66, LightSync) } +func TestBoundedHeavyForkedSync67Full(t *testing.T) { + testBoundedHeavyForkedSync(t, eth.ETH67, FullSync) +} +func TestBoundedHeavyForkedSync67Snap(t *testing.T) { + testBoundedHeavyForkedSync(t, eth.ETH67, SnapSync) +} +func TestBoundedHeavyForkedSync67Light(t *testing.T) { + testBoundedHeavyForkedSync(t, eth.ETH67, LightSync) +} func testBoundedHeavyForkedSync(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -654,6 +677,9 @@ func testBoundedHeavyForkedSync(t *testing.T, protocol uint, mode SyncMode) { func TestCancel66Full(t *testing.T) { testCancel(t, eth.ETH66, FullSync) } func TestCancel66Snap(t *testing.T) { testCancel(t, eth.ETH66, SnapSync) } func TestCancel66Light(t *testing.T) { testCancel(t, eth.ETH66, LightSync) } +func TestCancel67Full(t *testing.T) { testCancel(t, eth.ETH67, FullSync) } +func TestCancel67Snap(t *testing.T) { testCancel(t, eth.ETH67, SnapSync) } +func TestCancel67Light(t *testing.T) { testCancel(t, eth.ETH67, LightSync) } func testCancel(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -681,6 +707,9 @@ func testCancel(t *testing.T, protocol uint, mode SyncMode) { func TestMultiSynchronisation66Full(t *testing.T) { testMultiSynchronisation(t, eth.ETH66, FullSync) } func TestMultiSynchronisation66Snap(t *testing.T) { testMultiSynchronisation(t, eth.ETH66, SnapSync) } func TestMultiSynchronisation66Light(t *testing.T) { testMultiSynchronisation(t, eth.ETH66, LightSync) } +func TestMultiSynchronisation67Full(t *testing.T) { testMultiSynchronisation(t, eth.ETH67, FullSync) } +func TestMultiSynchronisation67Snap(t *testing.T) { testMultiSynchronisation(t, eth.ETH67, SnapSync) } +func TestMultiSynchronisation67Light(t *testing.T) { testMultiSynchronisation(t, eth.ETH67, LightSync) } func testMultiSynchronisation(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -705,6 +734,9 @@ func testMultiSynchronisation(t *testing.T, protocol uint, mode SyncMode) { func TestMultiProtoSynchronisation66Full(t *testing.T) { testMultiProtoSync(t, eth.ETH66, FullSync) } func TestMultiProtoSynchronisation66Snap(t *testing.T) { testMultiProtoSync(t, eth.ETH66, SnapSync) } func TestMultiProtoSynchronisation66Light(t *testing.T) { testMultiProtoSync(t, eth.ETH66, LightSync) } +func TestMultiProtoSynchronisation67Full(t *testing.T) { testMultiProtoSync(t, eth.ETH67, FullSync) } +func TestMultiProtoSynchronisation67Snap(t *testing.T) { testMultiProtoSync(t, eth.ETH67, SnapSync) } +func TestMultiProtoSynchronisation67Light(t *testing.T) { testMultiProtoSync(t, eth.ETH67, LightSync) } func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -715,7 +747,7 @@ func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) { // Create peers of every type tester.newPeer("peer 66", eth.ETH66, chain.blocks[1:]) - //tester.newPeer("peer 65", eth.ETH67, chain.blocks[1:) + tester.newPeer("peer 67", eth.ETH67, chain.blocks[1:]) // Synchronise with the requested peer and make sure all blocks were retrieved if err := tester.sync(fmt.Sprintf("peer %d", protocol), nil, mode); err != nil { @@ -724,7 +756,7 @@ func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) { assertOwnChain(t, tester, len(chain.blocks)) // Check that no peers have been dropped off - for _, version := range []int{66} { + for _, version := range []int{66, 67} { peer := fmt.Sprintf("peer %d", version) if _, ok := tester.peers[peer]; !ok { t.Errorf("%s dropped", peer) @@ -737,6 +769,9 @@ func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) { func TestEmptyShortCircuit66Full(t *testing.T) { testEmptyShortCircuit(t, eth.ETH66, FullSync) } func TestEmptyShortCircuit66Snap(t *testing.T) { testEmptyShortCircuit(t, eth.ETH66, SnapSync) } func TestEmptyShortCircuit66Light(t *testing.T) { testEmptyShortCircuit(t, eth.ETH66, LightSync) } +func TestEmptyShortCircuit67Full(t *testing.T) { testEmptyShortCircuit(t, eth.ETH67, FullSync) } +func TestEmptyShortCircuit67Snap(t *testing.T) { testEmptyShortCircuit(t, eth.ETH67, SnapSync) } +func TestEmptyShortCircuit67Light(t *testing.T) { testEmptyShortCircuit(t, eth.ETH67, LightSync) } func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -785,6 +820,9 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { func TestMissingHeaderAttack66Full(t *testing.T) { testMissingHeaderAttack(t, eth.ETH66, FullSync) } func TestMissingHeaderAttack66Snap(t *testing.T) { testMissingHeaderAttack(t, eth.ETH66, SnapSync) } func TestMissingHeaderAttack66Light(t *testing.T) { testMissingHeaderAttack(t, eth.ETH66, LightSync) } +func TestMissingHeaderAttack67Full(t *testing.T) { testMissingHeaderAttack(t, eth.ETH67, FullSync) } +func TestMissingHeaderAttack67Snap(t *testing.T) { testMissingHeaderAttack(t, eth.ETH67, SnapSync) } +func TestMissingHeaderAttack67Light(t *testing.T) { testMissingHeaderAttack(t, eth.ETH67, LightSync) } func testMissingHeaderAttack(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -811,6 +849,9 @@ func testMissingHeaderAttack(t *testing.T, protocol uint, mode SyncMode) { func TestShiftedHeaderAttack66Full(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH66, FullSync) } func TestShiftedHeaderAttack66Snap(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH66, SnapSync) } func TestShiftedHeaderAttack66Light(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH66, LightSync) } +func TestShiftedHeaderAttack67Full(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH67, FullSync) } +func TestShiftedHeaderAttack67Snap(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH67, SnapSync) } +func TestShiftedHeaderAttack67Light(t *testing.T) { testShiftedHeaderAttack(t, eth.ETH67, LightSync) } func testShiftedHeaderAttack(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -837,6 +878,7 @@ func testShiftedHeaderAttack(t *testing.T, protocol uint, mode SyncMode) { // for various failure scenarios. Afterwards a full sync is attempted to make // sure no state was corrupted. func TestInvalidHeaderRollback66Snap(t *testing.T) { testInvalidHeaderRollback(t, eth.ETH66, SnapSync) } +func TestInvalidHeaderRollback67Snap(t *testing.T) { testInvalidHeaderRollback(t, eth.ETH67, SnapSync) } func testInvalidHeaderRollback(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -923,6 +965,15 @@ func TestHighTDStarvationAttack66Snap(t *testing.T) { func TestHighTDStarvationAttack66Light(t *testing.T) { testHighTDStarvationAttack(t, eth.ETH66, LightSync) } +func TestHighTDStarvationAttack67Full(t *testing.T) { + testHighTDStarvationAttack(t, eth.ETH67, FullSync) +} +func TestHighTDStarvationAttack67Snap(t *testing.T) { + testHighTDStarvationAttack(t, eth.ETH67, SnapSync) +} +func TestHighTDStarvationAttack67Light(t *testing.T) { + testHighTDStarvationAttack(t, eth.ETH67, LightSync) +} func testHighTDStarvationAttack(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -937,6 +988,7 @@ func testHighTDStarvationAttack(t *testing.T, protocol uint, mode SyncMode) { // Tests that misbehaving peers are disconnected, whilst behaving ones are not. func TestBlockHeaderAttackerDropping66(t *testing.T) { testBlockHeaderAttackerDropping(t, eth.ETH66) } +func TestBlockHeaderAttackerDropping67(t *testing.T) { testBlockHeaderAttackerDropping(t, eth.ETH67) } func testBlockHeaderAttackerDropping(t *testing.T, protocol uint) { // Define the disconnection requirement for individual hash fetch errors @@ -987,6 +1039,9 @@ func testBlockHeaderAttackerDropping(t *testing.T, protocol uint) { func TestSyncProgress66Full(t *testing.T) { testSyncProgress(t, eth.ETH66, FullSync) } func TestSyncProgress66Snap(t *testing.T) { testSyncProgress(t, eth.ETH66, SnapSync) } func TestSyncProgress66Light(t *testing.T) { testSyncProgress(t, eth.ETH66, LightSync) } +func TestSyncProgress67Full(t *testing.T) { testSyncProgress(t, eth.ETH67, FullSync) } +func TestSyncProgress67Snap(t *testing.T) { testSyncProgress(t, eth.ETH67, SnapSync) } +func TestSyncProgress67Light(t *testing.T) { testSyncProgress(t, eth.ETH67, LightSync) } func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -1064,6 +1119,9 @@ func checkProgress(t *testing.T, d *Downloader, stage string, want ethereum.Sync func TestForkedSyncProgress66Full(t *testing.T) { testForkedSyncProgress(t, eth.ETH66, FullSync) } func TestForkedSyncProgress66Snap(t *testing.T) { testForkedSyncProgress(t, eth.ETH66, SnapSync) } func TestForkedSyncProgress66Light(t *testing.T) { testForkedSyncProgress(t, eth.ETH66, LightSync) } +func TestForkedSyncProgress67Full(t *testing.T) { testForkedSyncProgress(t, eth.ETH67, FullSync) } +func TestForkedSyncProgress67Snap(t *testing.T) { testForkedSyncProgress(t, eth.ETH67, SnapSync) } +func TestForkedSyncProgress67Light(t *testing.T) { testForkedSyncProgress(t, eth.ETH67, LightSync) } func testForkedSyncProgress(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -1135,6 +1193,9 @@ func testForkedSyncProgress(t *testing.T, protocol uint, mode SyncMode) { func TestFailedSyncProgress66Full(t *testing.T) { testFailedSyncProgress(t, eth.ETH66, FullSync) } func TestFailedSyncProgress66Snap(t *testing.T) { testFailedSyncProgress(t, eth.ETH66, SnapSync) } func TestFailedSyncProgress66Light(t *testing.T) { testFailedSyncProgress(t, eth.ETH66, LightSync) } +func TestFailedSyncProgress67Full(t *testing.T) { testFailedSyncProgress(t, eth.ETH67, FullSync) } +func TestFailedSyncProgress67Snap(t *testing.T) { testFailedSyncProgress(t, eth.ETH67, SnapSync) } +func TestFailedSyncProgress67Light(t *testing.T) { testFailedSyncProgress(t, eth.ETH67, LightSync) } func testFailedSyncProgress(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -1201,6 +1262,9 @@ func testFailedSyncProgress(t *testing.T, protocol uint, mode SyncMode) { func TestFakedSyncProgress66Full(t *testing.T) { testFakedSyncProgress(t, eth.ETH66, FullSync) } func TestFakedSyncProgress66Snap(t *testing.T) { testFakedSyncProgress(t, eth.ETH66, SnapSync) } func TestFakedSyncProgress66Light(t *testing.T) { testFakedSyncProgress(t, eth.ETH66, LightSync) } +func TestFakedSyncProgress67Full(t *testing.T) { testFakedSyncProgress(t, eth.ETH67, FullSync) } +func TestFakedSyncProgress67Snap(t *testing.T) { testFakedSyncProgress(t, eth.ETH67, SnapSync) } +func TestFakedSyncProgress67Light(t *testing.T) { testFakedSyncProgress(t, eth.ETH67, LightSync) } func testFakedSyncProgress(t *testing.T, protocol uint, mode SyncMode) { tester := newTester(t) @@ -1347,6 +1411,11 @@ func TestCheckpointEnforcement66Snap(t *testing.T) { testCheckpointEnforcement(t func TestCheckpointEnforcement66Light(t *testing.T) { testCheckpointEnforcement(t, eth.ETH66, LightSync) } +func TestCheckpointEnforcement67Full(t *testing.T) { testCheckpointEnforcement(t, eth.ETH67, FullSync) } +func TestCheckpointEnforcement67Snap(t *testing.T) { testCheckpointEnforcement(t, eth.ETH67, SnapSync) } +func TestCheckpointEnforcement67Light(t *testing.T) { + testCheckpointEnforcement(t, eth.ETH67, LightSync) +} func testCheckpointEnforcement(t *testing.T, protocol uint, mode SyncMode) { // Create a new tester with a particular hard coded checkpoint block diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 81d45d8b8fcf..3a0b21c30bdb 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -181,6 +181,21 @@ var eth66 = map[uint64]msgHandler{ PooledTransactionsMsg: handlePooledTransactions66, } +var eth67 = map[uint64]msgHandler{ + NewBlockHashesMsg: handleNewBlockhashes, + NewBlockMsg: handleNewBlock, + TransactionsMsg: handleTransactions, + NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes, + GetBlockHeadersMsg: handleGetBlockHeaders66, + BlockHeadersMsg: handleBlockHeaders66, + GetBlockBodiesMsg: handleGetBlockBodies66, + BlockBodiesMsg: handleBlockBodies66, + GetReceiptsMsg: handleGetReceipts66, + ReceiptsMsg: handleReceipts66, + GetPooledTransactionsMsg: handleGetPooledTransactions66, + PooledTransactionsMsg: handlePooledTransactions66, +} + // handleMessage is invoked whenever an inbound message is received from a remote // peer. The remote connection is torn down upon returning any error. func handleMessage(backend Backend, peer *Peer) error { @@ -195,9 +210,9 @@ func handleMessage(backend Backend, peer *Peer) error { defer msg.Discard() var handlers = eth66 - //if peer.Version() >= ETH67 { // Left in as a sample when new protocol is added - // handlers = eth67 - //} + if peer.Version() >= ETH67 { + handlers = eth67 + } // Track the amount of time it takes to serve the request and run the handler if metrics.Enabled { diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index 24b65f01dd96..f6fac4278080 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -31,6 +31,7 @@ import ( // Constants to match up protocol versions and messages const ( ETH66 = 66 + ETH67 = 67 ) // ProtocolName is the official short name of the `eth` protocol used during @@ -39,11 +40,11 @@ const ProtocolName = "eth" // ProtocolVersions are the supported versions of the `eth` protocol (first // is primary). -var ProtocolVersions = []uint{ETH66} +var ProtocolVersions = []uint{ETH67, ETH66} // protocolLengths are the number of implemented message corresponding to // different protocol versions. -var protocolLengths = map[uint]uint64{ETH66: 17} +var protocolLengths = map[uint]uint64{ETH67: 17, ETH66: 17} // maxMessageSize is the maximum cap on the size of a protocol message. const maxMessageSize = 10 * 1024 * 1024 diff --git a/eth/sync_test.go b/eth/sync_test.go index 929a2a9d181c..0b9f9e1bbaaf 100644 --- a/eth/sync_test.go +++ b/eth/sync_test.go @@ -30,6 +30,7 @@ import ( // Tests that snap sync is disabled after a successful sync cycle. func TestSnapSyncDisabling66(t *testing.T) { testSnapSyncDisabling(t, eth.ETH66, snap.SNAP1) } +func TestSnapSyncDisabling67(t *testing.T) { testSnapSyncDisabling(t, eth.ETH67, snap.SNAP1) } // Tests that snap sync gets disabled as soon as a real block is successfully // imported into the blockchain. diff --git a/les/downloader/peer.go b/les/downloader/peer.go index 863294832971..5a92e9cf9b87 100644 --- a/les/downloader/peer.go +++ b/les/downloader/peer.go @@ -413,7 +413,7 @@ func (ps *peerSet) HeaderIdlePeers() ([]*peerConnection, int) { throughput := func(p *peerConnection) int { return p.rates.Capacity(eth.BlockHeadersMsg, time.Second) } - return ps.idlePeers(eth.ETH66, eth.ETH66, idle, throughput) + return ps.idlePeers(eth.ETH66, eth.ETH67, idle, throughput) } // BodyIdlePeers retrieves a flat list of all the currently body-idle peers within @@ -425,7 +425,7 @@ func (ps *peerSet) BodyIdlePeers() ([]*peerConnection, int) { throughput := func(p *peerConnection) int { return p.rates.Capacity(eth.BlockBodiesMsg, time.Second) } - return ps.idlePeers(eth.ETH66, eth.ETH66, idle, throughput) + return ps.idlePeers(eth.ETH66, eth.ETH67, idle, throughput) } // ReceiptIdlePeers retrieves a flat list of all the currently receipt-idle peers @@ -437,7 +437,7 @@ func (ps *peerSet) ReceiptIdlePeers() ([]*peerConnection, int) { throughput := func(p *peerConnection) int { return p.rates.Capacity(eth.ReceiptsMsg, time.Second) } - return ps.idlePeers(eth.ETH66, eth.ETH66, idle, throughput) + return ps.idlePeers(eth.ETH66, eth.ETH67, idle, throughput) } // NodeDataIdlePeers retrieves a flat list of all the currently node-data-idle @@ -449,7 +449,7 @@ func (ps *peerSet) NodeDataIdlePeers() ([]*peerConnection, int) { throughput := func(p *peerConnection) int { return p.rates.Capacity(eth.NodeDataMsg, time.Second) } - return ps.idlePeers(eth.ETH66, eth.ETH66, idle, throughput) + return ps.idlePeers(eth.ETH66, eth.ETH67, idle, throughput) } // idlePeers retrieves a flat list of all currently idle peers satisfying the From d8f963811df6ef97c76c9b4f433bf0bc936051e2 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 15 Jun 2022 13:10:38 +0200 Subject: [PATCH 030/715] cmd, params: implement Gray Glacier hard-fork (EIP-5133) (#25088) * cmd/geth, params: implement Gray Glacier (EIP-5133) * cmd/evm: add gray glacier tests * params: nitpicks * params: fixes --- cmd/evm/internal/t8ntool/flags.go | 2 +- cmd/evm/t8n_test.go | 8 ++++++++ cmd/evm/testdata/19/exp_grayglacier.json | 12 ++++++++++++ cmd/evm/testdata/19/readme.md | 6 +++--- cmd/geth/config.go | 4 ++-- cmd/geth/main.go | 2 +- cmd/utils/flags.go | 6 +++--- consensus/ethash/consensus.go | 7 +++++++ core/forkid/forkid_test.go | 20 ++++++++++++-------- core/genesis.go | 10 +++++----- eth/backend.go | 2 +- eth/ethconfig/config.go | 4 ++-- eth/ethconfig/gen_config.go | 10 +++++----- eth/gasprice/gasprice_test.go | 1 + les/client.go | 2 +- params/config.go | 20 +++++++++++++++++--- tests/difficulty_test.go | 3 +++ tests/init.go | 16 ++++++++++++++++ 18 files changed, 100 insertions(+), 35 deletions(-) create mode 100644 cmd/evm/testdata/19/exp_grayglacier.json diff --git a/cmd/evm/internal/t8ntool/flags.go b/cmd/evm/internal/t8ntool/flags.go index de666f115123..12a7002c69ed 100644 --- a/cmd/evm/internal/t8ntool/flags.go +++ b/cmd/evm/internal/t8ntool/flags.go @@ -152,7 +152,7 @@ var ( "\n\tSyntax (+ExtraEip)", strings.Join(tests.AvailableForks(), "\n\t "), strings.Join(vm.ActivateableEips(), ", ")), - Value: "ArrowGlacier", + Value: "GrayGlacier", } VerbosityFlag = cli.IntFlag{ Name: "verbosity", diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 92c01398ba36..805eea90c45e 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -211,6 +211,14 @@ func TestT8n(t *testing.T) { output: t8nOutput{result: true}, expOut: "exp_arrowglacier.json", }, + { // Difficulty calculation on gray glacier + base: "./testdata/19", + input: t8nInput{ + "alloc.json", "txs.json", "env.json", "GrayGlacier", "", + }, + output: t8nOutput{result: true}, + expOut: "exp_grayglacier.json", + }, { // Sign unprotected (pre-EIP155) transaction base: "./testdata/23", input: t8nInput{ diff --git a/cmd/evm/testdata/19/exp_grayglacier.json b/cmd/evm/testdata/19/exp_grayglacier.json new file mode 100644 index 000000000000..95a3cb1685cf --- /dev/null +++ b/cmd/evm/testdata/19/exp_grayglacier.json @@ -0,0 +1,12 @@ +{ + "result": { + "stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc", + "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [], + "currentDifficulty": "0x2000000004000", + "gasUsed": "0x0" + } +} \ No newline at end of file diff --git a/cmd/evm/testdata/19/readme.md b/cmd/evm/testdata/19/readme.md index 5fae183f4886..095d4525d4fe 100644 --- a/cmd/evm/testdata/19/readme.md +++ b/cmd/evm/testdata/19/readme.md @@ -1,9 +1,9 @@ ## Difficulty calculation This test shows how the `evm t8n` can be used to calculate the (ethash) difficulty, if none is provided by the caller, -this time on `ArrowGlacier` (Eip 4345). +this time on `GrayGlacier` (Eip 5133). -Calculating it (with an empty set of txs) using `ArrowGlacier` rules (and no provided unclehash for the parent block): +Calculating it (with an empty set of txs) using `GrayGlacier` rules (and no provided unclehash for the parent block): ``` -[user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.json --output.result=stdout --state.fork=ArrowGlacier +[user@work evm]$ ./evm t8n --input.alloc=./testdata/19/alloc.json --input.txs=./testdata/19/txs.json --input.env=./testdata/19/env.json --output.result=stdout --state.fork=GrayGlacier ``` \ No newline at end of file diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 6d2bb2bcb622..bd321da9a3d3 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -156,8 +156,8 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // makeFullNode loads geth configuration and creates the Ethereum backend. func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { stack, cfg := makeConfigNode(ctx) - if ctx.GlobalIsSet(utils.OverrideArrowGlacierFlag.Name) { - cfg.Eth.OverrideArrowGlacier = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideArrowGlacierFlag.Name)) + if ctx.GlobalIsSet(utils.OverrideGrayGlacierFlag.Name) { + cfg.Eth.OverrideGrayGlacier = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideGrayGlacierFlag.Name)) } if ctx.GlobalIsSet(utils.OverrideTerminalTotalDifficulty.Name) { cfg.Eth.OverrideTerminalTotalDifficulty = utils.GlobalBig(ctx, utils.OverrideTerminalTotalDifficulty.Name) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 1e2770ae808e..76d6427fabdf 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -69,7 +69,7 @@ var ( utils.NoUSBFlag, utils.USBFlag, utils.SmartCardDaemonPathFlag, - utils.OverrideArrowGlacierFlag, + utils.OverrideGrayGlacierFlag, utils.OverrideTerminalTotalDifficulty, utils.EthashCacheDirFlag, utils.EthashCachesInMemoryFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5908a55e099d..907e3ce91677 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -257,9 +257,9 @@ var ( Usage: "Megabytes of memory allocated to bloom-filter for pruning", Value: 2048, } - OverrideArrowGlacierFlag = cli.Uint64Flag{ - Name: "override.arrowglacier", - Usage: "Manually specify Arrow Glacier fork-block, overriding the bundled setting", + OverrideGrayGlacierFlag = cli.Uint64Flag{ + Name: "override.grayglacier", + Usage: "Manually specify Gray Glacier fork-block, overriding the bundled setting", } OverrideTerminalTotalDifficulty = BigFlag{ Name: "override.terminaltotaldifficulty", diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 6a93fead29db..1c38b80ea59b 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -45,6 +45,11 @@ var ( maxUncles = 2 // Maximum number of uncles allowed in a single block allowedFutureBlockTimeSeconds = int64(15) // Max seconds from current time allowed for blocks, before they're considered future blocks + // calcDifficultyEip5133 is the difficulty adjustment algorithm as specified by EIP 5133. + // It offsets the bomb a total of 11.4M blocks. + // Specification EIP-5133: https://eips.ethereum.org/EIPS/eip-5133 + calcDifficultyEip5133 = makeDifficultyCalculator(big.NewInt(11_400_000)) + // calcDifficultyEip4345 is the difficulty adjustment algorithm as specified by EIP 4345. // It offsets the bomb a total of 10.7M blocks. // Specification EIP-4345: https://eips.ethereum.org/EIPS/eip-4345 @@ -334,6 +339,8 @@ func (ethash *Ethash) CalcDifficulty(chain consensus.ChainHeaderReader, time uin func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int { next := new(big.Int).Add(parent.Number, big1) switch { + case config.IsGrayGlacier(next): + return calcDifficultyEip5133(time, parent) case config.IsArrowGlacier(next): return calcDifficultyEip4345(time, parent) case config.IsLondon(next): diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index 42adc0019d02..ca698c47171d 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -31,7 +31,7 @@ import ( // the correct fork ID. func TestCreation(t *testing.T) { mergeConfig := *params.MainnetChainConfig - mergeConfig.MergeNetsplitBlock = big.NewInt(15000000) + mergeConfig.MergeNetsplitBlock = big.NewInt(18000000) type testcase struct { head uint64 want ID @@ -68,8 +68,10 @@ func TestCreation(t *testing.T) { {12964999, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block {12965000, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block {13772999, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block - {13773000, ID{Hash: checksumToBytes(0x20c327fc), Next: 0}}, // First Arrow Glacier block - {20000000, ID{Hash: checksumToBytes(0x20c327fc), Next: 0}}, // Future Arrow Glacier block + {13773000, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block + {15049999, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block + {15050000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}}, // First Gray Glacier block + {20000000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}}, // Future Gray Glacier block }, }, // Ropsten test cases @@ -163,9 +165,11 @@ func TestCreation(t *testing.T) { {12964999, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block {12965000, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block {13772999, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block - {13773000, ID{Hash: checksumToBytes(0x20c327fc), Next: 15000000}}, // First Arrow Glacier block - {15000000, ID{Hash: checksumToBytes(0xe3abe201), Next: 0}}, // First Merge Start block - {20000000, ID{Hash: checksumToBytes(0xe3abe201), Next: 0}}, // Future Merge Start block + {13773000, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block + {15049999, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block + {15050000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 18000000}}, // First Gray Glacier block + {18000000, ID{Hash: checksumToBytes(0x4fb8a872), Next: 0}}, // First Merge Start block + {20000000, ID{Hash: checksumToBytes(0x4fb8a872), Next: 0}}, // Future Merge Start block }, }, } @@ -242,11 +246,11 @@ func TestValidation(t *testing.T) { // Local is mainnet Petersburg, remote is Rinkeby Petersburg. {7987396, ID{Hash: checksumToBytes(0xafec6b27), Next: 0}, ErrLocalIncompatibleOrStale}, - // Local is mainnet Arrow Glacier, far in the future. Remote announces Gopherium (non existing fork) + // Local is mainnet Gray Glacier, far in the future. Remote announces Gopherium (non existing fork) // at some future block 88888888, for itself, but past block for local. Local is incompatible. // // This case detects non-upgraded nodes with majority hash power (typical Ropsten mess). - {88888888, ID{Hash: checksumToBytes(0x20c327fc), Next: 88888888}, ErrLocalIncompatibleOrStale}, + {88888888, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 88888888}, ErrLocalIncompatibleOrStale}, // Local is mainnet Byzantium. Remote is also in Byzantium, but announces Gopherium (non existing // fork) at block 7279999, before Petersburg. Local is incompatible. diff --git a/core/genesis.go b/core/genesis.go index 64ee99c5443d..aa7d704ea2c7 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -233,7 +233,7 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig return SetupGenesisBlockWithOverride(db, genesis, nil, nil) } -func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, overrideArrowGlacier, overrideTerminalTotalDifficulty *big.Int) (*params.ChainConfig, common.Hash, error) { +func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, overrideGrayGlacier, overrideTerminalTotalDifficulty *big.Int) (*params.ChainConfig, common.Hash, error) { if genesis != nil && genesis.Config == nil { return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig } @@ -279,8 +279,8 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override } // Get the existing chain configuration. newcfg := genesis.configOrDefault(stored) - if overrideArrowGlacier != nil { - newcfg.ArrowGlacierBlock = overrideArrowGlacier + if overrideGrayGlacier != nil { + newcfg.GrayGlacierBlock = overrideGrayGlacier } if overrideTerminalTotalDifficulty != nil { newcfg.TerminalTotalDifficulty = overrideTerminalTotalDifficulty @@ -301,8 +301,8 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override // apply the overrides. if genesis == nil && stored != params.MainnetGenesisHash { newcfg = storedcfg - if overrideArrowGlacier != nil { - newcfg.ArrowGlacierBlock = overrideArrowGlacier + if overrideGrayGlacier != nil { + newcfg.GrayGlacierBlock = overrideGrayGlacier } if overrideTerminalTotalDifficulty != nil { newcfg.TerminalTotalDifficulty = overrideTerminalTotalDifficulty diff --git a/eth/backend.go b/eth/backend.go index b7b670c9dbf5..e080181864f1 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -137,7 +137,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideArrowGlacier, config.OverrideTerminalTotalDifficulty) + chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideGrayGlacier, config.OverrideTerminalTotalDifficulty) if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { return nil, genesisErr } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index ca29aad8f080..f9496359528b 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -205,8 +205,8 @@ type Config struct { // CheckpointOracle is the configuration for checkpoint oracle. CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - // Arrow Glacier block override (TODO: remove after the fork) - OverrideArrowGlacier *big.Int `toml:",omitempty"` + // Gray Glacier block override (TODO: remove after the fork) + OverrideGrayGlacier *big.Int `toml:",omitempty"` // OverrideTerminalTotalDifficulty (TODO: remove after the fork) OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 0f43c36ad447..e714dd97ab19 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -59,7 +59,7 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCTxFeeCap float64 Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - OverrideArrowGlacier *big.Int `toml:",omitempty"` + OverrideGrayGlacier *big.Int `toml:",omitempty"` OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` } var enc Config @@ -104,7 +104,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCTxFeeCap = c.RPCTxFeeCap enc.Checkpoint = c.Checkpoint enc.CheckpointOracle = c.CheckpointOracle - enc.OverrideArrowGlacier = c.OverrideArrowGlacier + enc.OverrideGrayGlacier = c.OverrideGrayGlacier enc.OverrideTerminalTotalDifficulty = c.OverrideTerminalTotalDifficulty return &enc, nil } @@ -153,7 +153,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCTxFeeCap *float64 Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - OverrideArrowGlacier *big.Int `toml:",omitempty"` + OverrideGrayGlacier *big.Int `toml:",omitempty"` OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` } var dec Config @@ -283,8 +283,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.CheckpointOracle != nil { c.CheckpointOracle = dec.CheckpointOracle } - if dec.OverrideArrowGlacier != nil { - c.OverrideArrowGlacier = dec.OverrideArrowGlacier + if dec.OverrideGrayGlacier != nil { + c.OverrideGrayGlacier = dec.OverrideGrayGlacier } if dec.OverrideTerminalTotalDifficulty != nil { c.OverrideTerminalTotalDifficulty = dec.OverrideTerminalTotalDifficulty diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index c0d3c6b6038e..95a908fc1e9c 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -108,6 +108,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke ) config.LondonBlock = londonBlock config.ArrowGlacierBlock = londonBlock + config.GrayGlacierBlock = londonBlock engine := ethash.NewFaker() db := rawdb.NewMemoryDatabase() genesis, err := gspec.Commit(db) diff --git a/les/client.go b/les/client.go index 6eae73cf1631..b38a0aae74d3 100644 --- a/les/client.go +++ b/les/client.go @@ -93,7 +93,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { if err != nil { return nil, err } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideArrowGlacier, config.OverrideTerminalTotalDifficulty) + chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideGrayGlacier, config.OverrideTerminalTotalDifficulty) if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { return nil, genesisErr } diff --git a/params/config.go b/params/config.go index c4a9ae981266..44b575a876c7 100644 --- a/params/config.go +++ b/params/config.go @@ -73,6 +73,7 @@ var ( BerlinBlock: big.NewInt(12_244_000), LondonBlock: big.NewInt(12_965_000), ArrowGlacierBlock: big.NewInt(13_773_000), + GrayGlacierBlock: big.NewInt(15_050_000), Ethash: new(EthashConfig), } @@ -259,16 +260,16 @@ var ( // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil} + AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil} // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} + AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil} TestRules = TestChainConfig.Rules(new(big.Int), false) ) @@ -357,6 +358,7 @@ type ChainConfig struct { BerlinBlock *big.Int `json:"berlinBlock,omitempty"` // Berlin switch block (nil = no fork, 0 = already on berlin) LondonBlock *big.Int `json:"londonBlock,omitempty"` // London switch block (nil = no fork, 0 = already on london) ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated) + GrayGlacierBlock *big.Int `json:"grayGlacierBlock,omitempty"` // Eip-5133 (bomb delay) switch block (nil = no fork, 0 = already activated) MergeNetsplitBlock *big.Int `json:"mergeNetsplitBlock,omitempty"` // Virtual fork after The Merge to use as a network splitter // TerminalTotalDifficulty is the amount of total difficulty reached by @@ -438,6 +440,9 @@ func (c *ChainConfig) String() string { if c.ArrowGlacierBlock != nil { banner += fmt.Sprintf(" - Arrow Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/arrow-glacier.md)\n", c.ArrowGlacierBlock) } + if c.GrayGlacierBlock != nil { + banner += fmt.Sprintf(" - Gray Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md)\n", c.GrayGlacierBlock) + } banner += "\n" // Add a special section for the merge as it's non-obvious @@ -520,6 +525,11 @@ func (c *ChainConfig) IsArrowGlacier(num *big.Int) bool { return isForked(c.ArrowGlacierBlock, num) } +// IsGrayGlacier returns whether num is either equal to the Gray Glacier (EIP-5133) fork block or greater. +func (c *ChainConfig) IsGrayGlacier(num *big.Int) bool { + return isForked(c.GrayGlacierBlock, num) +} + // IsTerminalPoWBlock returns whether the given block is the last block of PoW stage. func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool { if c.TerminalTotalDifficulty == nil { @@ -569,6 +579,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "berlinBlock", block: c.BerlinBlock}, {name: "londonBlock", block: c.LondonBlock}, {name: "arrowGlacierBlock", block: c.ArrowGlacierBlock, optional: true}, + {name: "grayGlacierBlock", block: c.GrayGlacierBlock, optional: true}, {name: "mergeNetsplitBlock", block: c.MergeNetsplitBlock, optional: true}, } { if lastFork.name != "" { @@ -642,6 +653,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.ArrowGlacierBlock, newcfg.ArrowGlacierBlock, head) { return newCompatError("Arrow Glacier fork block", c.ArrowGlacierBlock, newcfg.ArrowGlacierBlock) } + if isForkIncompatible(c.GrayGlacierBlock, newcfg.GrayGlacierBlock, head) { + return newCompatError("Gray Glacier fork block", c.GrayGlacierBlock, newcfg.GrayGlacierBlock) + } if isForkIncompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, head) { return newCompatError("Merge netsplit fork block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock) } diff --git a/tests/difficulty_test.go b/tests/difficulty_test.go index 192dff12cc97..8239850b7617 100644 --- a/tests/difficulty_test.go +++ b/tests/difficulty_test.go @@ -79,6 +79,9 @@ func TestDifficulty(t *testing.T) { dt.config("EIP4345", params.ChainConfig{ ArrowGlacierBlock: big.NewInt(0), }) + dt.config("EIP5133", params.ChainConfig{ + GrayGlacierBlock: big.NewInt(0), + }) dt.config("difficulty.json", mainnetChainConfig) dt.walk(t, difficultyTestDir, func(t *testing.T, name string, test *DifficultyTest) { diff --git a/tests/init.go b/tests/init.go index acf3790bf7ce..87ffc65a677c 100644 --- a/tests/init.go +++ b/tests/init.go @@ -197,6 +197,22 @@ var Forks = map[string]*params.ChainConfig{ LondonBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0), }, + "GrayGlacier": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + GrayGlacierBlock: big.NewInt(0), + }, "Merged": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), From d78d302f3d4a1a41eebf17c2cad297271e90b9d6 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 15 Jun 2022 14:35:53 +0200 Subject: [PATCH 031/715] node: add info message when JWT secret is loaded (#25095) Co-authored-by: Felix Lange --- node/node.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/node/node.go b/node/node.go index 7c540306db2b..0a2b9eb83692 100644 --- a/node/node.go +++ b/node/node.go @@ -20,6 +20,7 @@ import ( crand "crypto/rand" "errors" "fmt" + "hash/crc32" "net/http" "os" "path/filepath" @@ -352,10 +353,10 @@ func (n *Node) obtainJWTSecret(cliParam string) ([]byte, error) { fileName = n.ResolvePath(datadirJWTKey) } // try reading from file - log.Debug("Reading JWT secret", "path", fileName) if data, err := os.ReadFile(fileName); err == nil { jwtSecret := common.FromHex(strings.TrimSpace(string(data))) if len(jwtSecret) == 32 { + log.Info("Loaded JWT secret file", "path", fileName, "crc32", fmt.Sprintf("%#x", crc32.ChecksumIEEE(jwtSecret))) return jwtSecret, nil } log.Error("Invalid JWT secret", "path", fileName, "length", len(jwtSecret)) From 23bee16208718975f9b9e012949b8d4ee1223108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 15 Jun 2022 15:35:32 +0300 Subject: [PATCH 032/715] params: release Geth v1.10.19 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 8c8b6295a8f0..18e5e593a0d5 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 19 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 10 // Minor version component of the current release + VersionPatch = 19 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 67454df08b512ea33aa4c246ee405cf4b418ec35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 15 Jun 2022 15:56:01 +0300 Subject: [PATCH 033/715] params: begin v1.10.20 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 18e5e593a0d5..c013fd015c20 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 19 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 10 // Minor version component of the current release + VersionPatch = 20 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From ba99e192152733e191ada0cff76369b19dbf5f6f Mon Sep 17 00:00:00 2001 From: Kosuke Taniguchi <73885532+TaniguchiKosuke@users.noreply.github.com> Date: Fri, 17 Jun 2022 00:08:25 +0900 Subject: [PATCH 034/715] internal/ethapi: add comment explaining return of nil instead of error (#25097) Co-authored-by: Felix Lange --- internal/ethapi/api.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4aa37a8dc4c3..24d9b58567b9 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1581,6 +1581,8 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) if err != nil { + // When the transaction doesn't exist, the RPC method should return JSON null + // as per specification. return nil, nil } receipts, err := s.b.GetReceipts(ctx, blockHash) From 01e5e9c2c3fa1cf7a9747148dca22d59ff9839b6 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 17 Jun 2022 00:44:30 +0200 Subject: [PATCH 035/715] tests/fuzzers/rlp: avoid very large input (#25109) The oss-fuzz engine crashes due to stack overflow decoding a large nested structure into a interface{}. This PR limits the size of the input data, so should avoid such crashes. --- tests/fuzzers/rlp/rlp_fuzzer.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/fuzzers/rlp/rlp_fuzzer.go b/tests/fuzzers/rlp/rlp_fuzzer.go index 18b36287b53c..ac02e1651d44 100644 --- a/tests/fuzzers/rlp/rlp_fuzzer.go +++ b/tests/fuzzers/rlp/rlp_fuzzer.go @@ -40,6 +40,9 @@ func Fuzz(input []byte) int { if len(input) == 0 { return 0 } + if len(input) > 500*1024 { + return 0 + } var i int { From 21129ec83848c0db455ab0492e9075d51f68f8b6 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 20 Jun 2022 10:10:25 +0200 Subject: [PATCH 036/715] node: make jwt tests less time-dependent (#25120) --- node/rpcstack_test.go | 107 ++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 31 deletions(-) diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index 229a5b5e53ba..58a02234025a 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -319,55 +319,100 @@ func TestJWT(t *testing.T) { wsUrl := fmt.Sprintf("ws://%v", srv.listenAddr()) htUrl := fmt.Sprintf("http://%v", srv.listenAddr()) - expOk := []string{ - fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), - fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + 4})), - fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() - 4})), - fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{ - "iat": time.Now().Unix(), - "exp": time.Now().Unix() + 2, - })), - fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{ - "iat": time.Now().Unix(), - "bar": "baz", - })), + expOk := []func() string{ + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + 4})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() - 4})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{ + "iat": time.Now().Unix(), + "exp": time.Now().Unix() + 2, + })) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{ + "iat": time.Now().Unix(), + "bar": "baz", + })) + }, } - for i, token := range expOk { + for i, tokenFn := range expOk { + token := tokenFn() if err := wsRequest(t, wsUrl, "Authorization", token); err != nil { t.Errorf("test %d-ws, token '%v': expected ok, got %v", i, token, err) } + token = tokenFn() if resp := rpcRequest(t, htUrl, "Authorization", token); resp.StatusCode != 200 { t.Errorf("test %d-http, token '%v': expected ok, got %v", i, token, resp.StatusCode) } } - expFail := []string{ + + expFail := []func() string{ // future - fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + 6})), + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + 6})) + }, // stale - fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() - 6})), + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() - 6})) + }, // wrong algo - fmt.Sprintf("Bearer %v", issueToken(secret, jwt.SigningMethodHS512, testClaim{"iat": time.Now().Unix() + 4})), + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, jwt.SigningMethodHS512, testClaim{"iat": time.Now().Unix() + 4})) + }, // expired - fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix(), "exp": time.Now().Unix()})), + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix(), "exp": time.Now().Unix()})) + }, // missing mandatory iat - fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{})), - // wrong secret - fmt.Sprintf("Bearer %v", issueToken([]byte("wrong"), nil, testClaim{"iat": time.Now().Unix()})), - fmt.Sprintf("Bearer %v", issueToken([]byte{}, nil, testClaim{"iat": time.Now().Unix()})), - fmt.Sprintf("Bearer %v", issueToken(nil, nil, testClaim{"iat": time.Now().Unix()})), + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{})) + }, + // wrong secret + func() string { + return fmt.Sprintf("Bearer %v", issueToken([]byte("wrong"), nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken([]byte{}, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(nil, nil, testClaim{"iat": time.Now().Unix()})) + }, // Various malformed syntax - fmt.Sprintf("%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), - fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), - fmt.Sprintf("bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), - fmt.Sprintf("Bearer: %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), - fmt.Sprintf("Bearer:%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), - fmt.Sprintf("Bearer\t%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), - fmt.Sprintf("Bearer \t%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})), + func() string { + return fmt.Sprintf("%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer: %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer:%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer\t%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer \t%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, } - for i, token := range expFail { + for i, tokenFn := range expFail { + token := tokenFn() if err := wsRequest(t, wsUrl, "Authorization", token); err == nil { t.Errorf("tc %d-ws, token '%v': expected not to allow, got ok", i, token) } + token = tokenFn() if resp := rpcRequest(t, htUrl, "Authorization", token); resp.StatusCode != 403 { t.Errorf("tc %d-http, token '%v': expected not to allow, got %v", i, token, resp.StatusCode) } From c776029c6cb8934f4b114d71c3f10b44b09dd50f Mon Sep 17 00:00:00 2001 From: Zachinquarantine Date: Mon, 20 Jun 2022 04:20:32 -0400 Subject: [PATCH 037/715] cmd/faucet: more verbose message about private posts (#25129) * cmd/faucet: Add error message for private posts Fixes #22631 * grammar --- cmd/faucet/faucet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index bcb837062f6f..d958ab972039 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -860,7 +860,7 @@ func authFacebook(url string) (string, string, common.Address, error) { address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body))) if address == (common.Address{}) { //lint:ignore ST1005 This error is to be displayed in the browser - return "", "", common.Address{}, errors.New("No Ethereum address found to fund") + return "", "", common.Address{}, errors.New("No Ethereum address found to fund. Please check the post URL and verify that it can be viewed publicly.") } var avatar string if parts = regexp.MustCompile(`src="([^"]+fbcdn\.net[^"]+)"`).FindStringSubmatch(string(body)); len(parts) == 2 { From d39f0cce71e7a18e2f0591a12591bcc14adc845e Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 20 Jun 2022 10:38:46 +0200 Subject: [PATCH 038/715] internal/ethapi: remove SignAndSendTransaction (#25111) --- internal/ethapi/api.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 24d9b58567b9..69ddfa8cc364 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -557,12 +557,6 @@ func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Byt return crypto.PubkeyToAddress(*rpk), nil } -// SignAndSendTransaction was renamed to SendTransaction. This method is deprecated -// and will be removed in the future. It primary goal is to give clients time to update. -func (s *PrivateAccountAPI) SignAndSendTransaction(ctx context.Context, args TransactionArgs, passwd string) (common.Hash, error) { - return s.SendTransaction(ctx, args, passwd) -} - // InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key. func (s *PrivateAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) { wallet, err := s.am.Wallet(url) From ad15050c7fbedd0f05a49e81400de18c2cc2c284 Mon Sep 17 00:00:00 2001 From: Zachinquarantine Date: Mon, 20 Jun 2022 04:40:06 -0400 Subject: [PATCH 039/715] cmd/faucet: add sepolia network support (#25128) cmd/faucet: Add Sepolia network support to faucet --- cmd/faucet/README.md | 3 ++- cmd/faucet/faucet.go | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cmd/faucet/README.md b/cmd/faucet/README.md index f27e94aa9e72..c31676b0dac1 100644 --- a/cmd/faucet/README.md +++ b/cmd/faucet/README.md @@ -10,9 +10,10 @@ The `faucet` is a single binary app (everything included) with all configuration First thing's first, the `faucet` needs to connect to an Ethereum network, for which it needs the necessary genesis and network infos. Each of the following flags must be set: -- `-genesis` is a path to a file containin the network `genesis.json`. or using: +- `-genesis` is a path to a file containing the network `genesis.json`. or using: - `-goerli` with the faucet with Görli network config - `-rinkeby` with the faucet with Rinkeby network config + - `-sepolia` with the faucet with Sepolia network config - `-network` is the devp2p network id used during connection - `-bootnodes` is a list of `enode://` ids to join the network through diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index d958ab972039..6c8796076c07 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -86,6 +86,7 @@ var ( goerliFlag = flag.Bool("goerli", false, "Initializes the faucet with Görli network config") rinkebyFlag = flag.Bool("rinkeby", false, "Initializes the faucet with Rinkeby network config") + sepoliaFlag = flag.Bool("sepolia", false, "Initializes the faucet with Sepolia network config") ) var ( @@ -143,7 +144,7 @@ func main() { log.Crit("Failed to render the faucet template", "err", err) } // Load and parse the genesis block requested by the user - genesis, err := getGenesis(*genesisFlag, *goerliFlag, *rinkebyFlag) + genesis, err := getGenesis(*genesisFlag, *goerliFlag, *rinkebyFlag, *sepoliaFlag) if err != nil { log.Crit("Failed to parse genesis config", "err", err) } @@ -882,7 +883,7 @@ func authNoAuth(url string) (string, string, common.Address, error) { } // getGenesis returns a genesis based on input args -func getGenesis(genesisFlag string, goerliFlag bool, rinkebyFlag bool) (*core.Genesis, error) { +func getGenesis(genesisFlag string, goerliFlag bool, rinkebyFlag bool, sepoliaFlag bool) (*core.Genesis, error) { switch { case genesisFlag != "": var genesis core.Genesis @@ -892,6 +893,8 @@ func getGenesis(genesisFlag string, goerliFlag bool, rinkebyFlag bool) (*core.Ge return core.DefaultGoerliGenesisBlock(), nil case rinkebyFlag: return core.DefaultRinkebyGenesisBlock(), nil + case sepoliaFlag: + return core.DefaultSepoliaGenesisBlock(), nil default: return nil, fmt.Errorf("no genesis flag provided") } From 241dd27300664c4102134a951a6361051079252c Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Tue, 21 Jun 2022 05:00:37 -0400 Subject: [PATCH 040/715] trie: fix size accounting in cleaner (#25007) Decrease children size instead of dirties size when marking dirties as cleaned up in trie cleaner --- trie/database.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trie/database.go b/trie/database.go index 4167031a584c..2df2e859d7b4 100644 --- a/trie/database.go +++ b/trie/database.go @@ -812,7 +812,7 @@ func (c *cleaner) Put(key []byte, rlp []byte) error { delete(c.db.dirties, hash) c.db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) if node.children != nil { - c.db.dirtiesSize -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) + c.db.childrenSize -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) } // Move the flushed node into the clean cache to prevent insta-reloads if c.db.cleans != nil { From 10dc5dce0871bf8c24bac41b04e47c3b9ad2b93e Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 21 Jun 2022 11:05:43 +0200 Subject: [PATCH 041/715] all: remove concept of public/private API definitions (#25053) * internal/ethapi: rename PublicEthereumAPI to EthereumAPI * eth: rename PublicEthereumAPI to EthereumAPI * internal/ethapi: rename PublicTxPoolAPI to TxPoolAPI * internal/ethapi: rename PublicAccountAPI to EthereumAccountAPI * internal/ethapi: rename PrivateAccountAPI to PersonalAccountAPI * internal/ethapi: rename PublicBlockChainAPI to BlockChainAPI * internal/ethapi: rename PublicTransactionPoolAPI to TransactionAPI * internal/ethapi: rename PublicDebugAPI to DebugAPI * internal/ethapi: move PrivateDebugAPI methods to DebugAPI * internal/ethapi: rename PublicNetAPI to NetAPI * les: rename PrivateLightServerAPI to LightServerAPI * les: rename PrivateLightAPI to LightAPI * les: rename PrivateDebugAPI to DebugAPI * les: rename PublicDownloaderAPI to DownloaderAPI * eth,les: rename PublicFilterAPI to FilterAPI * eth: rename PublicMinerAPI to MinerAPI * eth: rename PublicDownloaderAPI to DownloaderAPI * eth: move PrivateMinerAPI methods to MinerAPI * eth: rename PrivateAdminAPI to AdminAPI * eth: rename PublicDebugAPI to DebugAPI * eth: move PrivateDebugAPI methods to DebugAPI * node: rename publicAdminAPI to adminAPI * node: move privateAdminAPI methods to adminAPI * node: rename publicWeb3API to web3API * eth,internal/ethapi: sync comments with previous renamings --- eth/api.go | 115 ++++++-------- eth/backend.go | 27 ++-- eth/downloader/api.go | 22 +-- eth/filters/api.go | 32 ++-- eth/filters/filter_system_test.go | 16 +- internal/ethapi/api.go | 249 ++++++++++++++---------------- internal/ethapi/backend.go | 18 +-- internal/ethapi/dbapi.go | 6 +- les/api.go | 58 +++---- les/client.go | 10 +- les/downloader/api.go | 22 +-- les/server.go | 6 +- node/api.go | 56 +++---- node/api_test.go | 30 ++-- 14 files changed, 301 insertions(+), 366 deletions(-) diff --git a/eth/api.go b/eth/api.go index 818df89c07c9..b5053095a234 100644 --- a/eth/api.go +++ b/eth/api.go @@ -41,57 +41,44 @@ import ( "github.com/ethereum/go-ethereum/trie" ) -// PublicEthereumAPI provides an API to access Ethereum full node-related -// information. -type PublicEthereumAPI struct { +// EthereumAPI provides an API to access Ethereum full node-related information. +type EthereumAPI struct { e *Ethereum } -// NewPublicEthereumAPI creates a new Ethereum protocol API for full nodes. -func NewPublicEthereumAPI(e *Ethereum) *PublicEthereumAPI { - return &PublicEthereumAPI{e} +// NewEthereumAPI creates a new Ethereum protocol API for full nodes. +func NewEthereumAPI(e *Ethereum) *EthereumAPI { + return &EthereumAPI{e} } // Etherbase is the address that mining rewards will be send to. -func (api *PublicEthereumAPI) Etherbase() (common.Address, error) { +func (api *EthereumAPI) Etherbase() (common.Address, error) { return api.e.Etherbase() } // Coinbase is the address that mining rewards will be send to (alias for Etherbase). -func (api *PublicEthereumAPI) Coinbase() (common.Address, error) { +func (api *EthereumAPI) Coinbase() (common.Address, error) { return api.Etherbase() } // Hashrate returns the POW hashrate. -func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 { +func (api *EthereumAPI) Hashrate() hexutil.Uint64 { return hexutil.Uint64(api.e.Miner().Hashrate()) } -// PublicMinerAPI provides an API to control the miner. -// It offers only methods that operate on data that pose no security risk when it is publicly accessible. -type PublicMinerAPI struct { - e *Ethereum -} - -// NewPublicMinerAPI create a new PublicMinerAPI instance. -func NewPublicMinerAPI(e *Ethereum) *PublicMinerAPI { - return &PublicMinerAPI{e} -} - // Mining returns an indication if this node is currently mining. -func (api *PublicMinerAPI) Mining() bool { +func (api *EthereumAPI) Mining() bool { return api.e.IsMining() } -// PrivateMinerAPI provides private RPC methods to control the miner. -// These methods can be abused by external users and must be considered insecure for use by untrusted users. -type PrivateMinerAPI struct { +// MinerAPI provides an API to control the miner. +type MinerAPI struct { e *Ethereum } -// NewPrivateMinerAPI create a new RPC service which controls the miner of this node. -func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI { - return &PrivateMinerAPI{e: e} +// NewMinerAPI create a new MinerAPI instance. +func NewMinerAPI(e *Ethereum) *MinerAPI { + return &MinerAPI{e} } // Start starts the miner with the given number of threads. If threads is nil, @@ -99,7 +86,7 @@ func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI { // usable by this process. If mining is already running, this method adjust the // number of threads allowed to use and updates the minimum price required by the // transaction pool. -func (api *PrivateMinerAPI) Start(threads *int) error { +func (api *MinerAPI) Start(threads *int) error { if threads == nil { return api.e.StartMining(runtime.NumCPU()) } @@ -108,12 +95,12 @@ func (api *PrivateMinerAPI) Start(threads *int) error { // Stop terminates the miner, both at the consensus engine level as well as at // the block creation level. -func (api *PrivateMinerAPI) Stop() { +func (api *MinerAPI) Stop() { api.e.StopMining() } // SetExtra sets the extra data string that is included when this miner mines a block. -func (api *PrivateMinerAPI) SetExtra(extra string) (bool, error) { +func (api *MinerAPI) SetExtra(extra string) (bool, error) { if err := api.e.Miner().SetExtra([]byte(extra)); err != nil { return false, err } @@ -121,7 +108,7 @@ func (api *PrivateMinerAPI) SetExtra(extra string) (bool, error) { } // SetGasPrice sets the minimum accepted gas price for the miner. -func (api *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { +func (api *MinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { api.e.lock.Lock() api.e.gasPrice = (*big.Int)(&gasPrice) api.e.lock.Unlock() @@ -131,37 +118,36 @@ func (api *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { } // SetGasLimit sets the gaslimit to target towards during mining. -func (api *PrivateMinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool { +func (api *MinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool { api.e.Miner().SetGasCeil(uint64(gasLimit)) return true } // SetEtherbase sets the etherbase of the miner. -func (api *PrivateMinerAPI) SetEtherbase(etherbase common.Address) bool { +func (api *MinerAPI) SetEtherbase(etherbase common.Address) bool { api.e.SetEtherbase(etherbase) return true } // SetRecommitInterval updates the interval for miner sealing work recommitting. -func (api *PrivateMinerAPI) SetRecommitInterval(interval int) { +func (api *MinerAPI) SetRecommitInterval(interval int) { api.e.Miner().SetRecommitInterval(time.Duration(interval) * time.Millisecond) } -// PrivateAdminAPI is the collection of Ethereum full node-related APIs -// exposed over the private admin endpoint. -type PrivateAdminAPI struct { +// AdminAPI is the collection of Ethereum full node related APIs for node +// administration. +type AdminAPI struct { eth *Ethereum } -// NewPrivateAdminAPI creates a new API definition for the full node private -// admin methods of the Ethereum service. -func NewPrivateAdminAPI(eth *Ethereum) *PrivateAdminAPI { - return &PrivateAdminAPI{eth: eth} +// NewAdminAPI creates a new instance of AdminAPI. +func NewAdminAPI(eth *Ethereum) *AdminAPI { + return &AdminAPI{eth: eth} } // ExportChain exports the current blockchain into a local file, // or a range of blocks if first and last are non-nil. -func (api *PrivateAdminAPI) ExportChain(file string, first *uint64, last *uint64) (bool, error) { +func (api *AdminAPI) ExportChain(file string, first *uint64, last *uint64) (bool, error) { if first == nil && last != nil { return false, errors.New("last cannot be specified without first") } @@ -209,7 +195,7 @@ func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { } // ImportChain imports a blockchain from a local file. -func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { +func (api *AdminAPI) ImportChain(file string) (bool, error) { // Make sure the can access the file to import in, err := os.Open(file) if err != nil { @@ -257,20 +243,19 @@ func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { return true, nil } -// PublicDebugAPI is the collection of Ethereum full node APIs exposed -// over the public debugging endpoint. -type PublicDebugAPI struct { +// DebugAPI is the collection of Ethereum full node APIs for debugging the +// protocol. +type DebugAPI struct { eth *Ethereum } -// NewPublicDebugAPI creates a new API definition for the full node- -// related public debug methods of the Ethereum service. -func NewPublicDebugAPI(eth *Ethereum) *PublicDebugAPI { - return &PublicDebugAPI{eth: eth} +// NewDebugAPI creates a new DebugAPI instance. +func NewDebugAPI(eth *Ethereum) *DebugAPI { + return &DebugAPI{eth: eth} } // DumpBlock retrieves the entire state of the database at a given block. -func (api *PublicDebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) { +func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) { opts := &state.DumpConfig{ OnlyWithAddresses: true, Max: AccountRangeMaxResults, // Sanity limit over RPC @@ -300,20 +285,8 @@ func (api *PublicDebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error return stateDb.RawDump(opts), nil } -// PrivateDebugAPI is the collection of Ethereum full node APIs exposed over -// the private debugging endpoint. -type PrivateDebugAPI struct { - eth *Ethereum -} - -// NewPrivateDebugAPI creates a new API definition for the full node-related -// private debug methods of the Ethereum service. -func NewPrivateDebugAPI(eth *Ethereum) *PrivateDebugAPI { - return &PrivateDebugAPI{eth: eth} -} - // Preimage is a debug API function that returns the preimage for a sha3 hash, if known. -func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { +func (api *DebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { if preimage := rawdb.ReadPreimage(api.eth.ChainDb(), hash); preimage != nil { return preimage, nil } @@ -329,7 +302,7 @@ type BadBlockArgs struct { // GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network // and returns them as a JSON list of block hashes. -func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) { +func (api *DebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) { var ( err error blocks = rawdb.ReadAllBadBlocks(api.eth.chainDb) @@ -361,7 +334,7 @@ func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, const AccountRangeMaxResults = 256 // AccountRange enumerates all accounts in the given block and start point in paging request -func (api *PublicDebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) { +func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) { var stateDb *state.StateDB var err error @@ -428,7 +401,7 @@ type storageEntry struct { } // StorageRangeAt returns the storage at the given block height and transaction index. -func (api *PrivateDebugAPI) StorageRangeAt(blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { +func (api *DebugAPI) StorageRangeAt(blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { // Retrieve the block block := api.eth.blockchain.GetBlockByHash(blockHash) if block == nil { @@ -473,7 +446,7 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeRes // code hash, or storage hash. // // With one parameter, returns the list of accounts modified in the specified block. -func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) { +func (api *DebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) { var startBlock, endBlock *types.Block startBlock = api.eth.blockchain.GetBlockByNumber(startNum) @@ -501,7 +474,7 @@ func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum // code hash, or storage hash. // // With one parameter, returns the list of accounts modified in the specified block. -func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) { +func (api *DebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) { var startBlock, endBlock *types.Block startBlock = api.eth.blockchain.GetBlockByHash(startHash) if startBlock == nil { @@ -523,7 +496,7 @@ func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash common.Hash, end return api.getModifiedAccounts(startBlock, endBlock) } -func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) { +func (api *DebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) { if startBlock.Number().Uint64() >= endBlock.Number().Uint64() { return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64()) } @@ -556,7 +529,7 @@ func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Bloc // of the next block. // The (from, to) parameters are the sequence of blocks to search, which can go // either forwards or backwards -func (api *PrivateDebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error) { +func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error) { db := api.eth.ChainDb() var pivot uint64 if p := rawdb.ReadLastPivotNumber(db); p != nil { diff --git a/eth/backend.go b/eth/backend.go index e080181864f1..f34aaba369cc 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -94,7 +94,7 @@ type Ethereum struct { etherbase common.Address networkID uint64 - netRPCService *ethapi.PublicNetAPI + netRPCService *ethapi.NetAPI p2pServer *p2p.Server @@ -266,7 +266,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } // Start the RPC service - eth.netRPCService = ethapi.NewPublicNetAPI(eth.p2pServer, config.NetworkId) + eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, config.NetworkId) // Register the backend on the node stack.RegisterAPIs(eth.APIs()) @@ -309,41 +309,32 @@ func (s *Ethereum) APIs() []rpc.API { { Namespace: "eth", Version: "1.0", - Service: NewPublicEthereumAPI(s), + Service: NewEthereumAPI(s), Public: true, }, { - Namespace: "eth", + Namespace: "miner", Version: "1.0", - Service: NewPublicMinerAPI(s), + Service: NewMinerAPI(s), Public: true, }, { Namespace: "eth", Version: "1.0", - Service: downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux), + Service: downloader.NewDownloaderAPI(s.handler.downloader, s.eventMux), Public: true, - }, { - Namespace: "miner", - Version: "1.0", - Service: NewPrivateMinerAPI(s), - Public: false, }, { Namespace: "eth", Version: "1.0", - Service: filters.NewPublicFilterAPI(s.APIBackend, false, 5*time.Minute), + Service: filters.NewFilterAPI(s.APIBackend, false, 5*time.Minute), Public: true, }, { Namespace: "admin", Version: "1.0", - Service: NewPrivateAdminAPI(s), + Service: NewAdminAPI(s), }, { Namespace: "debug", Version: "1.0", - Service: NewPublicDebugAPI(s), + Service: NewDebugAPI(s), Public: true, - }, { - Namespace: "debug", - Version: "1.0", - Service: NewPrivateDebugAPI(s), }, { Namespace: "net", Version: "1.0", diff --git a/eth/downloader/api.go b/eth/downloader/api.go index 645912286d57..b36dd6386500 100644 --- a/eth/downloader/api.go +++ b/eth/downloader/api.go @@ -25,21 +25,21 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -// PublicDownloaderAPI provides an API which gives information about the current synchronisation status. +// DownloaderAPI provides an API which gives information about the current synchronisation status. // It offers only methods that operates on data that can be available to anyone without security risks. -type PublicDownloaderAPI struct { +type DownloaderAPI struct { d *Downloader mux *event.TypeMux installSyncSubscription chan chan interface{} uninstallSyncSubscription chan *uninstallSyncSubscriptionRequest } -// NewPublicDownloaderAPI create a new PublicDownloaderAPI. The API has an internal event loop that +// NewDownloaderAPI create a new DownloaderAPI. The API has an internal event loop that // listens for events from the downloader through the global event mux. In case it receives one of // these events it broadcasts it to all syncing subscriptions that are installed through the // installSyncSubscription channel. -func NewPublicDownloaderAPI(d *Downloader, m *event.TypeMux) *PublicDownloaderAPI { - api := &PublicDownloaderAPI{ +func NewDownloaderAPI(d *Downloader, m *event.TypeMux) *DownloaderAPI { + api := &DownloaderAPI{ d: d, mux: m, installSyncSubscription: make(chan chan interface{}), @@ -53,7 +53,7 @@ func NewPublicDownloaderAPI(d *Downloader, m *event.TypeMux) *PublicDownloaderAP // eventLoop runs a loop until the event mux closes. It will install and uninstall new // sync subscriptions and broadcasts sync status updates to the installed sync subscriptions. -func (api *PublicDownloaderAPI) eventLoop() { +func (api *DownloaderAPI) eventLoop() { var ( sub = api.mux.Subscribe(StartEvent{}, DoneEvent{}, FailedEvent{}) syncSubscriptions = make(map[chan interface{}]struct{}) @@ -90,7 +90,7 @@ func (api *PublicDownloaderAPI) eventLoop() { } // Syncing provides information when this nodes starts synchronising with the Ethereum network and when it's finished. -func (api *PublicDownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error) { +func (api *DownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported @@ -133,9 +133,9 @@ type uninstallSyncSubscriptionRequest struct { // SyncStatusSubscription represents a syncing subscription. type SyncStatusSubscription struct { - api *PublicDownloaderAPI // register subscription in event loop of this api instance - c chan interface{} // channel where events are broadcasted to - unsubOnce sync.Once // make sure unsubscribe logic is executed once + api *DownloaderAPI // register subscription in event loop of this api instance + c chan interface{} // channel where events are broadcasted to + unsubOnce sync.Once // make sure unsubscribe logic is executed once } // Unsubscribe uninstalls the subscription from the DownloadAPI event loop. @@ -160,7 +160,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. -func (api *PublicDownloaderAPI) SubscribeSyncStatus(status chan interface{}) *SyncStatusSubscription { +func (api *DownloaderAPI) SubscribeSyncStatus(status chan interface{}) *SyncStatusSubscription { api.installSyncSubscription <- status return &SyncStatusSubscription{api: api, c: status} } diff --git a/eth/filters/api.go b/eth/filters/api.go index ce2b0cb0b87d..6463a189b061 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -43,9 +43,9 @@ type filter struct { s *Subscription // associated subscription in event system } -// PublicFilterAPI offers support to create and manage filters. This will allow external clients to retrieve various +// FilterAPI offers support to create and manage filters. This will allow external clients to retrieve various // information related to the Ethereum protocol such als blocks, transactions and logs. -type PublicFilterAPI struct { +type FilterAPI struct { backend Backend events *EventSystem filtersMu sync.Mutex @@ -53,9 +53,9 @@ type PublicFilterAPI struct { timeout time.Duration } -// NewPublicFilterAPI returns a new PublicFilterAPI instance. -func NewPublicFilterAPI(backend Backend, lightMode bool, timeout time.Duration) *PublicFilterAPI { - api := &PublicFilterAPI{ +// NewFilterAPI returns a new FilterAPI instance. +func NewFilterAPI(backend Backend, lightMode bool, timeout time.Duration) *FilterAPI { + api := &FilterAPI{ backend: backend, events: NewEventSystem(backend, lightMode), filters: make(map[rpc.ID]*filter), @@ -68,7 +68,7 @@ func NewPublicFilterAPI(backend Backend, lightMode bool, timeout time.Duration) // timeoutLoop runs at the interval set by 'timeout' and deletes filters // that have not been recently used. It is started when the API is created. -func (api *PublicFilterAPI) timeoutLoop(timeout time.Duration) { +func (api *FilterAPI) timeoutLoop(timeout time.Duration) { var toUninstall []*Subscription ticker := time.NewTicker(timeout) defer ticker.Stop() @@ -101,7 +101,7 @@ func (api *PublicFilterAPI) timeoutLoop(timeout time.Duration) { // // It is part of the filter package because this filter can be used through the // `eth_getFilterChanges` polling method that is also used for log filters. -func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID { +func (api *FilterAPI) NewPendingTransactionFilter() rpc.ID { var ( pendingTxs = make(chan []common.Hash) pendingTxSub = api.events.SubscribePendingTxs(pendingTxs) @@ -134,7 +134,7 @@ func (api *PublicFilterAPI) NewPendingTransactionFilter() rpc.ID { // NewPendingTransactions creates a subscription that is triggered each time a transaction // enters the transaction pool and was signed from one of the transactions this nodes manages. -func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Subscription, error) { +func (api *FilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported @@ -169,7 +169,7 @@ func (api *PublicFilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Su // NewBlockFilter creates a filter that fetches blocks that are imported into the chain. // It is part of the filter package since polling goes with eth_getFilterChanges. -func (api *PublicFilterAPI) NewBlockFilter() rpc.ID { +func (api *FilterAPI) NewBlockFilter() rpc.ID { var ( headers = make(chan *types.Header) headerSub = api.events.SubscribeNewHeads(headers) @@ -201,7 +201,7 @@ func (api *PublicFilterAPI) NewBlockFilter() rpc.ID { } // NewHeads send a notification each time a new (header) block is appended to the chain. -func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, error) { +func (api *FilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported @@ -231,7 +231,7 @@ func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, er } // Logs creates a subscription that fires for all new log that match the given filter criteria. -func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subscription, error) { +func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported @@ -284,7 +284,7 @@ type FilterCriteria ethereum.FilterQuery // again but with the removed property set to true. // // In case "fromBlock" > "toBlock" an error is returned. -func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { +func (api *FilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { logs := make(chan []*types.Log) logsSub, err := api.events.SubscribeLogs(ethereum.FilterQuery(crit), logs) if err != nil { @@ -317,7 +317,7 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { } // GetLogs returns logs matching the given argument that are stored within the state. -func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) { +func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) { var filter *Filter if crit.BlockHash != nil { // Block filter requested, construct a single-shot filter @@ -344,7 +344,7 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([ } // UninstallFilter removes the filter with the given filter id. -func (api *PublicFilterAPI) UninstallFilter(id rpc.ID) bool { +func (api *FilterAPI) UninstallFilter(id rpc.ID) bool { api.filtersMu.Lock() f, found := api.filters[id] if found { @@ -360,7 +360,7 @@ func (api *PublicFilterAPI) UninstallFilter(id rpc.ID) bool { // GetFilterLogs returns the logs for the filter with the given id. // If the filter could not be found an empty array of logs is returned. -func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Log, error) { +func (api *FilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Log, error) { api.filtersMu.Lock() f, found := api.filters[id] api.filtersMu.Unlock() @@ -399,7 +399,7 @@ func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*ty // // For pending transaction and block filters the result is []common.Hash. // (pending)Log filters return []Log. -func (api *PublicFilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { +func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { api.filtersMu.Lock() defer api.filtersMu.Unlock() diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 629e05416053..c7fc4331b222 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -171,7 +171,7 @@ func TestBlockSubscription(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewFilterAPI(backend, false, deadline) genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) chain, _ = core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {}) chainEvents = []core.ChainEvent{} @@ -223,7 +223,7 @@ func TestPendingTxFilter(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewFilterAPI(backend, false, deadline) transactions = []*types.Transaction{ types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), @@ -278,7 +278,7 @@ func TestLogFilterCreation(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewFilterAPI(backend, false, deadline) testCases = []struct { crit FilterCriteria @@ -325,7 +325,7 @@ func TestInvalidLogFilterCreation(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewFilterAPI(backend, false, deadline) ) // different situations where log filter creation should fail. @@ -347,7 +347,7 @@ func TestInvalidGetLogsRequest(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewFilterAPI(backend, false, deadline) blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") ) @@ -372,7 +372,7 @@ func TestLogFilter(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewFilterAPI(backend, false, deadline) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") @@ -486,7 +486,7 @@ func TestPendingLogsSubscription(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, deadline) + api = NewFilterAPI(backend, false, deadline) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") @@ -670,7 +670,7 @@ func TestPendingTxFilterDeadlock(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() backend = &testBackend{db: db} - api = NewPublicFilterAPI(backend, false, timeout) + api = NewFilterAPI(backend, false, timeout) done = make(chan struct{}) ) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 69ddfa8cc364..7f12fdb95232 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -48,19 +48,18 @@ import ( "github.com/tyler-smith/go-bip39" ) -// PublicEthereumAPI provides an API to access Ethereum related information. -// It offers only methods that operate on public data that is freely available to anyone. -type PublicEthereumAPI struct { +// EthereumAPI provides an API to access Ethereum related information. +type EthereumAPI struct { b Backend } -// NewPublicEthereumAPI creates a new Ethereum protocol API. -func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI { - return &PublicEthereumAPI{b} +// NewEthereumAPI creates a new Ethereum protocol API. +func NewEthereumAPI(b Backend) *EthereumAPI { + return &EthereumAPI{b} } // GasPrice returns a suggestion for a gas price for legacy transactions. -func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) { +func (s *EthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) { tipcap, err := s.b.SuggestGasTipCap(ctx) if err != nil { return nil, err @@ -72,7 +71,7 @@ func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) } // MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions. -func (s *PublicEthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { +func (s *EthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { tipcap, err := s.b.SuggestGasTipCap(ctx) if err != nil { return nil, err @@ -87,7 +86,7 @@ type feeHistoryResult struct { GasUsedRatio []float64 `json:"gasUsedRatio"` } -func (s *PublicEthereumAPI) FeeHistory(ctx context.Context, blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { +func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, int(blockCount), lastBlock, rewardPercentiles) if err != nil { return nil, err @@ -121,7 +120,7 @@ func (s *PublicEthereumAPI) FeeHistory(ctx context.Context, blockCount rpc.Decim // - highestBlock: block number of the highest block header this node has received from peers // - pulledStates: number of state entries processed until now // - knownStates: number of known state entries that still need to be pulled -func (s *PublicEthereumAPI) Syncing() (interface{}, error) { +func (s *EthereumAPI) Syncing() (interface{}, error) { progress := s.b.SyncProgress() // Return not syncing if the synchronisation already completed @@ -148,18 +147,18 @@ func (s *PublicEthereumAPI) Syncing() (interface{}, error) { }, nil } -// PublicTxPoolAPI offers and API for the transaction pool. It only operates on data that is non confidential. -type PublicTxPoolAPI struct { +// TxPoolAPI offers and API for the transaction pool. It only operates on data that is non confidential. +type TxPoolAPI struct { b Backend } -// NewPublicTxPoolAPI creates a new tx pool service that gives information about the transaction pool. -func NewPublicTxPoolAPI(b Backend) *PublicTxPoolAPI { - return &PublicTxPoolAPI{b} +// NewTxPoolAPI creates a new tx pool service that gives information about the transaction pool. +func NewTxPoolAPI(b Backend) *TxPoolAPI { + return &TxPoolAPI{b} } // Content returns the transactions contained within the transaction pool. -func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { +func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { content := map[string]map[string]map[string]*RPCTransaction{ "pending": make(map[string]map[string]*RPCTransaction), "queued": make(map[string]map[string]*RPCTransaction), @@ -186,7 +185,7 @@ func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*RPCTransac } // ContentFrom returns the transactions contained within the transaction pool. -func (s *PublicTxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCTransaction { +func (s *TxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCTransaction { content := make(map[string]map[string]*RPCTransaction, 2) pending, queue := s.b.TxPoolContentFrom(addr) curHeader := s.b.CurrentHeader() @@ -209,7 +208,7 @@ func (s *PublicTxPoolAPI) ContentFrom(addr common.Address) map[string]map[string } // Status returns the number of pending and queued transaction in the pool. -func (s *PublicTxPoolAPI) Status() map[string]hexutil.Uint { +func (s *TxPoolAPI) Status() map[string]hexutil.Uint { pending, queue := s.b.Stats() return map[string]hexutil.Uint{ "pending": hexutil.Uint(pending), @@ -219,7 +218,7 @@ func (s *PublicTxPoolAPI) Status() map[string]hexutil.Uint { // Inspect retrieves the content of the transaction pool and flattens it into an // easily inspectable list. -func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string { +func (s *TxPoolAPI) Inspect() map[string]map[string]map[string]string { content := map[string]map[string]map[string]string{ "pending": make(map[string]map[string]string), "queued": make(map[string]map[string]string), @@ -252,34 +251,34 @@ func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string { return content } -// PublicAccountAPI provides an API to access accounts managed by this node. +// EthereumAccountAPI provides an API to access accounts managed by this node. // It offers only methods that can retrieve accounts. -type PublicAccountAPI struct { +type EthereumAccountAPI struct { am *accounts.Manager } -// NewPublicAccountAPI creates a new PublicAccountAPI. -func NewPublicAccountAPI(am *accounts.Manager) *PublicAccountAPI { - return &PublicAccountAPI{am: am} +// NewEthereumAccountAPI creates a new EthereumAccountAPI. +func NewEthereumAccountAPI(am *accounts.Manager) *EthereumAccountAPI { + return &EthereumAccountAPI{am: am} } -// Accounts returns the collection of accounts this node manages -func (s *PublicAccountAPI) Accounts() []common.Address { +// Accounts returns the collection of accounts this node manages. +func (s *EthereumAccountAPI) Accounts() []common.Address { return s.am.Accounts() } -// PrivateAccountAPI provides an API to access accounts managed by this node. +// PersonalAccountAPI provides an API to access accounts managed by this node. // It offers methods to create, (un)lock en list accounts. Some methods accept // passwords and are therefore considered private by default. -type PrivateAccountAPI struct { +type PersonalAccountAPI struct { am *accounts.Manager nonceLock *AddrLocker b Backend } -// NewPrivateAccountAPI create a new PrivateAccountAPI. -func NewPrivateAccountAPI(b Backend, nonceLock *AddrLocker) *PrivateAccountAPI { - return &PrivateAccountAPI{ +// NewPersonalAccountAPI create a new PersonalAccountAPI. +func NewPersonalAccountAPI(b Backend, nonceLock *AddrLocker) *PersonalAccountAPI { + return &PersonalAccountAPI{ am: b.AccountManager(), nonceLock: nonceLock, b: b, @@ -287,7 +286,7 @@ func NewPrivateAccountAPI(b Backend, nonceLock *AddrLocker) *PrivateAccountAPI { } // ListAccounts will return a list of addresses for accounts this node manages. -func (s *PrivateAccountAPI) ListAccounts() []common.Address { +func (s *PersonalAccountAPI) ListAccounts() []common.Address { return s.am.Accounts() } @@ -301,7 +300,7 @@ type rawWallet struct { } // ListWallets will return a list of wallets this node manages. -func (s *PrivateAccountAPI) ListWallets() []rawWallet { +func (s *PersonalAccountAPI) ListWallets() []rawWallet { wallets := make([]rawWallet, 0) // return [] instead of nil if empty for _, wallet := range s.am.Wallets() { status, failure := wallet.Status() @@ -323,7 +322,7 @@ func (s *PrivateAccountAPI) ListWallets() []rawWallet { // connection and attempting to authenticate via the provided passphrase. Note, // the method may return an extra challenge requiring a second open (e.g. the // Trezor PIN matrix challenge). -func (s *PrivateAccountAPI) OpenWallet(url string, passphrase *string) error { +func (s *PersonalAccountAPI) OpenWallet(url string, passphrase *string) error { wallet, err := s.am.Wallet(url) if err != nil { return err @@ -337,7 +336,7 @@ func (s *PrivateAccountAPI) OpenWallet(url string, passphrase *string) error { // DeriveAccount requests a HD wallet to derive a new account, optionally pinning // it for later reuse. -func (s *PrivateAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { +func (s *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { wallet, err := s.am.Wallet(url) if err != nil { return accounts.Account{}, err @@ -353,7 +352,7 @@ func (s *PrivateAccountAPI) DeriveAccount(url string, path string, pin *bool) (a } // NewAccount will create a new account and returns the address for the new account. -func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) { +func (s *PersonalAccountAPI) NewAccount(password string) (common.Address, error) { ks, err := fetchKeystore(s.am) if err != nil { return common.Address{}, err @@ -378,7 +377,7 @@ func fetchKeystore(am *accounts.Manager) (*keystore.KeyStore, error) { // ImportRawKey stores the given hex encoded ECDSA key into the key directory, // encrypting it with the passphrase. -func (s *PrivateAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) { +func (s *PersonalAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) { key, err := crypto.HexToECDSA(privkey) if err != nil { return common.Address{}, err @@ -394,7 +393,7 @@ func (s *PrivateAccountAPI) ImportRawKey(privkey string, password string) (commo // UnlockAccount will unlock the account associated with the given address with // the given password for duration seconds. If duration is nil it will use a // default of 300 seconds. It returns an indication if the account was unlocked. -func (s *PrivateAccountAPI) UnlockAccount(ctx context.Context, addr common.Address, password string, duration *uint64) (bool, error) { +func (s *PersonalAccountAPI) UnlockAccount(ctx context.Context, addr common.Address, password string, duration *uint64) (bool, error) { // When the API is exposed by external RPC(http, ws etc), unless the user // explicitly specifies to allow the insecure account unlocking, otherwise // it is disabled. @@ -423,7 +422,7 @@ func (s *PrivateAccountAPI) UnlockAccount(ctx context.Context, addr common.Addre } // LockAccount will lock the account associated with the given address when it's unlocked. -func (s *PrivateAccountAPI) LockAccount(addr common.Address) bool { +func (s *PersonalAccountAPI) LockAccount(addr common.Address) bool { if ks, err := fetchKeystore(s.am); err == nil { return ks.Lock(addr) == nil } @@ -433,7 +432,7 @@ func (s *PrivateAccountAPI) LockAccount(addr common.Address) bool { // signTransaction sets defaults and signs the given transaction // NOTE: the caller needs to ensure that the nonceLock is held, if applicable, // and release it after the transaction has been submitted to the tx pool -func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args *TransactionArgs, passwd string) (*types.Transaction, error) { +func (s *PersonalAccountAPI) signTransaction(ctx context.Context, args *TransactionArgs, passwd string) (*types.Transaction, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: args.from()} wallet, err := s.am.Find(account) @@ -453,7 +452,7 @@ func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args *Transacti // SendTransaction will create a transaction from the given arguments and // tries to sign it with the key associated with args.From. If the given // passwd isn't able to decrypt the key it fails. -func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args TransactionArgs, passwd string) (common.Hash, error) { +func (s *PersonalAccountAPI) SendTransaction(ctx context.Context, args TransactionArgs, passwd string) (common.Hash, error) { if args.Nonce == nil { // Hold the addresse's mutex around signing to prevent concurrent assignment of // the same nonce to multiple accounts. @@ -472,7 +471,7 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args Transactio // tries to sign it with the key associated with args.From. If the given passwd isn't // able to decrypt the key it fails. The transaction is returned in RLP-form, not broadcast // to other nodes -func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args TransactionArgs, passwd string) (*SignTransactionResult, error) { +func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args TransactionArgs, passwd string) (*SignTransactionResult, error) { // No need to obtain the noncelock mutex, since we won't be sending this // tx into the transaction pool, but right back to the user if args.From == nil { @@ -513,7 +512,7 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args Transactio // The key used to calculate the signature is decrypted with the given password. // // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign -func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) { +func (s *PersonalAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: addr} @@ -541,7 +540,7 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr c // the V value must be 27 or 28 for legacy reasons. // // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover -func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) { +func (s *PersonalAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) { if len(sig) != crypto.SignatureLength { return common.Address{}, fmt.Errorf("signature must be %d bytes long", crypto.SignatureLength) } @@ -558,7 +557,7 @@ func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Byt } // InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key. -func (s *PrivateAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) { +func (s *PersonalAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) { wallet, err := s.am.Wallet(url) if err != nil { return "", err @@ -585,7 +584,7 @@ func (s *PrivateAccountAPI) InitializeWallet(ctx context.Context, url string) (s } // Unpair deletes a pairing between wallet and geth. -func (s *PrivateAccountAPI) Unpair(ctx context.Context, url string, pin string) error { +func (s *PersonalAccountAPI) Unpair(ctx context.Context, url string, pin string) error { wallet, err := s.am.Wallet(url) if err != nil { return err @@ -599,19 +598,18 @@ func (s *PrivateAccountAPI) Unpair(ctx context.Context, url string, pin string) } } -// PublicBlockChainAPI provides an API to access the Ethereum blockchain. -// It offers only methods that operate on public data that is freely available to anyone. -type PublicBlockChainAPI struct { +// BlockChainAPI provides an API to access Ethereum blockchain data. +type BlockChainAPI struct { b Backend } -// NewPublicBlockChainAPI creates a new Ethereum blockchain API. -func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI { - return &PublicBlockChainAPI{b} +// NewBlockChainAPI creates a new Ethereum blockchain API. +func NewBlockChainAPI(b Backend) *BlockChainAPI { + return &BlockChainAPI{b} } -// ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config. -func (api *PublicBlockChainAPI) ChainId() (*hexutil.Big, error) { +// ChainId is the EIP-155 replay-protection chain id for the current Ethereum chain config. +func (api *BlockChainAPI) ChainId() (*hexutil.Big, error) { // if current block is at or past the EIP-155 replay-protection fork block, return chainID from config if config := api.b.ChainConfig(); config.IsEIP155(api.b.CurrentBlock().Number()) { return (*hexutil.Big)(config.ChainID), nil @@ -620,7 +618,7 @@ func (api *PublicBlockChainAPI) ChainId() (*hexutil.Big, error) { } // BlockNumber returns the block number of the chain head. -func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 { +func (s *BlockChainAPI) BlockNumber() hexutil.Uint64 { header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available return hexutil.Uint64(header.Number.Uint64()) } @@ -628,7 +626,7 @@ func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 { // GetBalance returns the amount of wei for the given address in the state of the // given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta // block numbers are also allowed. -func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { +func (s *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err @@ -654,7 +652,7 @@ type StorageResult struct { } // GetProof returns the Merkle-proof for a given account and optionally some storage keys. -func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) { +func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) { state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err @@ -706,7 +704,7 @@ func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Addre // GetHeaderByNumber returns the requested canonical block header. // * When blockNr is -1 the chain head is returned. // * When blockNr is -2 the pending chain head is returned. -func (s *PublicBlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) { +func (s *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) { header, err := s.b.HeaderByNumber(ctx, number) if header != nil && err == nil { response := s.rpcMarshalHeader(ctx, header) @@ -722,7 +720,7 @@ func (s *PublicBlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc. } // GetHeaderByHash returns the requested header by hash. -func (s *PublicBlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} { +func (s *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} { header, _ := s.b.HeaderByHash(ctx, hash) if header != nil { return s.rpcMarshalHeader(ctx, header) @@ -735,7 +733,7 @@ func (s *PublicBlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.H // * When blockNr is -2 the pending chain head is returned. // * When fullTx is true all transactions in the block are returned, otherwise // only the transaction hash is returned. -func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { +func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { block, err := s.b.BlockByNumber(ctx, number) if block != nil && err == nil { response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) @@ -752,7 +750,7 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B // GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full // detail, otherwise only the transaction hash is returned. -func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { +func (s *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { block, err := s.b.BlockByHash(ctx, hash) if block != nil { return s.rpcMarshalBlock(ctx, block, true, fullTx) @@ -761,7 +759,7 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Ha } // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. -func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { +func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { block, err := s.b.BlockByNumber(ctx, blockNr) if block != nil { uncles := block.Uncles() @@ -776,7 +774,7 @@ func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, } // GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. -func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { +func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { block, err := s.b.BlockByHash(ctx, blockHash) if block != nil { uncles := block.Uncles() @@ -791,7 +789,7 @@ func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, b } // GetUncleCountByBlockNumber returns number of uncles in the block for the given block number -func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { +func (s *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { n := hexutil.Uint(len(block.Uncles())) return &n @@ -800,7 +798,7 @@ func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, bl } // GetUncleCountByBlockHash returns number of uncles in the block for the given block hash -func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { +func (s *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { n := hexutil.Uint(len(block.Uncles())) return &n @@ -809,7 +807,7 @@ func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, bloc } // GetCode returns the code stored at the given address in the state for the given block number. -func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { +func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err @@ -821,7 +819,7 @@ func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Addres // GetStorageAt returns the storage from the state at the given address, key and // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block // numbers are also allowed. -func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { +func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err @@ -1008,7 +1006,7 @@ func (e *revertError) ErrorData() interface{} { // // Note, this function doesn't make and changes in the state/blockchain and is // useful to execute and retrieve values. -func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) { +func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) { result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap()) if err != nil { return nil, err @@ -1142,7 +1140,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr // EstimateGas returns an estimate of the amount of gas needed to execute the // given transaction against the current pending block. -func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) { +func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) { bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash @@ -1216,16 +1214,16 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param } // rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires -// a `PublicBlockchainAPI`. -func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} { +// a `BlockchainAPI`. +func (s *BlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} { fields := RPCMarshalHeader(header) fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, header.Hash())) return fields } // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires -// a `PublicBlockchainAPI`. -func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { +// a `BlockchainAPI`. +func (s *BlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { fields, err := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig()) if err != nil { return nil, err @@ -1358,7 +1356,7 @@ type accessListResult struct { // CreateAccessList creates a EIP-2930 type AccessList for the given transaction. // Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state. -func (s *PublicBlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) { +func (s *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) { bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash @@ -1447,23 +1445,23 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH } } -// PublicTransactionPoolAPI exposes methods for the RPC interface -type PublicTransactionPoolAPI struct { +// TransactionAPI exposes methods for reading and creating transaction data. +type TransactionAPI struct { b Backend nonceLock *AddrLocker signer types.Signer } -// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. -func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI { +// NewTransactionAPI creates a new RPC service with methods for interacting with transactions. +func NewTransactionAPI(b Backend, nonceLock *AddrLocker) *TransactionAPI { // The signer used by the API should always be the 'latest' known one because we expect // signers to be backwards-compatible with old transactions. signer := types.LatestSigner(b.ChainConfig()) - return &PublicTransactionPoolAPI{b, nonceLock, signer} + return &TransactionAPI{b, nonceLock, signer} } // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. -func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { +func (s *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { n := hexutil.Uint(len(block.Transactions())) return &n @@ -1472,7 +1470,7 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context. } // GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. -func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { +func (s *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { n := hexutil.Uint(len(block.Transactions())) return &n @@ -1481,7 +1479,7 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Co } // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. -func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { +func (s *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) } @@ -1489,7 +1487,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx conte } // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. -func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { +func (s *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) } @@ -1497,7 +1495,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context } // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. -func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { +func (s *TransactionAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { return newRPCRawTransactionFromBlockIndex(block, uint64(index)) } @@ -1505,7 +1503,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx co } // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. -func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { +func (s *TransactionAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { return newRPCRawTransactionFromBlockIndex(block, uint64(index)) } @@ -1513,7 +1511,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx cont } // GetTransactionCount returns the number of transactions the given address has sent for the given block number -func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { +func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { // Ask transaction pool for the nonce which includes pending transactions if blockNr, ok := blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber { nonce, err := s.b.GetPoolNonce(ctx, address) @@ -1532,7 +1530,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr } // GetTransactionByHash returns the transaction for the given hash -func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { +func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { // Try to return an already finalized transaction tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) if err != nil { @@ -1555,7 +1553,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, has } // GetRawTransactionByHash returns the bytes of the transaction for the given hash. -func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { +func (s *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { // Retrieve a finalized transaction, or a pooled otherwise tx, _, _, _, err := s.b.GetTransaction(ctx, hash) if err != nil { @@ -1572,7 +1570,7 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, } // GetTransactionReceipt returns the transaction receipt for the given transaction hash. -func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { +func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) if err != nil { // When the transaction doesn't exist, the RPC method should return JSON null @@ -1635,7 +1633,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha } // sign is a helper function that signs a transaction with the private key of the given address. -func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { +func (s *TransactionAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: addr} @@ -1679,7 +1677,7 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c // SendTransaction creates a transaction for the given argument, sign it and submit it to the // transaction pool. -func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args TransactionArgs) (common.Hash, error) { +func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionArgs) (common.Hash, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: args.from()} @@ -1712,7 +1710,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Tra // FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields) // on a given unsigned transaction, and returns it to the caller for further // processing (signing + broadcast). -func (s *PublicTransactionPoolAPI) FillTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { +func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { // Set some sanity defaults and terminate on failure if err := args.setDefaults(ctx, s.b); err != nil { return nil, err @@ -1728,7 +1726,7 @@ func (s *PublicTransactionPoolAPI) FillTransaction(ctx context.Context, args Tra // SendRawTransaction will add the signed transaction to the transaction pool. // The sender is responsible for signing the transaction and using the correct nonce. -func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) { +func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) { tx := new(types.Transaction) if err := tx.UnmarshalBinary(input); err != nil { return common.Hash{}, err @@ -1745,7 +1743,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, input // The account associated with addr must be unlocked. // // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign -func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { +func (s *TransactionAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: addr} @@ -1770,7 +1768,7 @@ type SignTransactionResult struct { // SignTransaction will sign the given transaction with the from account. // The node needs to have the private key of the account corresponding with // the given from address and it needs to be unlocked. -func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { +func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { if args.Gas == nil { return nil, fmt.Errorf("gas not specified") } @@ -1801,7 +1799,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Tra // PendingTransactions returns the transactions that are in the transaction pool // and have a from address that is one of the accounts this node manages. -func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) { +func (s *TransactionAPI) PendingTransactions() ([]*RPCTransaction, error) { pending, err := s.b.GetPoolTransactions() if err != nil { return nil, err @@ -1825,7 +1823,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err // Resend accepts an existing transaction and a new gas price and limit. It will remove // the given transaction from the pool and reinsert it with the new gas price and limit. -func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) { +func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) { if sendArgs.Nonce == nil { return common.Hash{}, fmt.Errorf("missing transaction nonce in transaction spec") } @@ -1875,20 +1873,19 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs Transact return common.Hash{}, fmt.Errorf("transaction %#x not found", matchTx.Hash()) } -// PublicDebugAPI is the collection of Ethereum APIs exposed over the public -// debugging endpoint. -type PublicDebugAPI struct { +// DebugAPI is the collection of Ethereum APIs exposed over the debugging +// namespace. +type DebugAPI struct { b Backend } -// NewPublicDebugAPI creates a new API definition for the public debug methods -// of the Ethereum service. -func NewPublicDebugAPI(b Backend) *PublicDebugAPI { - return &PublicDebugAPI{b: b} +// NewDebugAPI creates a new instance of DebugAPI. +func NewDebugAPI(b Backend) *DebugAPI { + return &DebugAPI{b: b} } // GetHeaderRlp retrieves the RLP encoded for of a single header. -func (api *PublicDebugAPI) GetHeaderRlp(ctx context.Context, number uint64) (hexutil.Bytes, error) { +func (api *DebugAPI) GetHeaderRlp(ctx context.Context, number uint64) (hexutil.Bytes, error) { header, _ := api.b.HeaderByNumber(ctx, rpc.BlockNumber(number)) if header == nil { return nil, fmt.Errorf("header #%d not found", number) @@ -1897,7 +1894,7 @@ func (api *PublicDebugAPI) GetHeaderRlp(ctx context.Context, number uint64) (hex } // GetBlockRlp retrieves the RLP encoded for of a single block. -func (api *PublicDebugAPI) GetBlockRlp(ctx context.Context, number uint64) (hexutil.Bytes, error) { +func (api *DebugAPI) GetBlockRlp(ctx context.Context, number uint64) (hexutil.Bytes, error) { block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) if block == nil { return nil, fmt.Errorf("block #%d not found", number) @@ -1906,7 +1903,7 @@ func (api *PublicDebugAPI) GetBlockRlp(ctx context.Context, number uint64) (hexu } // GetRawReceipts retrieves the binary-encoded raw receipts of a single block. -func (api *PublicDebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]hexutil.Bytes, error) { +func (api *DebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]hexutil.Bytes, error) { var hash common.Hash if h, ok := blockNrOrHash.Hash(); ok { hash = h @@ -1933,7 +1930,7 @@ func (api *PublicDebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc } // PrintBlock retrieves a block and returns its pretty printed form. -func (api *PublicDebugAPI) PrintBlock(ctx context.Context, number uint64) (string, error) { +func (api *DebugAPI) PrintBlock(ctx context.Context, number uint64) (string, error) { block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) if block == nil { return "", fmt.Errorf("block #%d not found", number) @@ -1942,7 +1939,7 @@ func (api *PublicDebugAPI) PrintBlock(ctx context.Context, number uint64) (strin } // SeedHash retrieves the seed hash of a block. -func (api *PublicDebugAPI) SeedHash(ctx context.Context, number uint64) (string, error) { +func (api *DebugAPI) SeedHash(ctx context.Context, number uint64) (string, error) { block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) if block == nil { return "", fmt.Errorf("block #%d not found", number) @@ -1950,20 +1947,8 @@ func (api *PublicDebugAPI) SeedHash(ctx context.Context, number uint64) (string, return fmt.Sprintf("0x%x", ethash.SeedHash(number)), nil } -// PrivateDebugAPI is the collection of Ethereum APIs exposed over the private -// debugging endpoint. -type PrivateDebugAPI struct { - b Backend -} - -// NewPrivateDebugAPI creates a new API definition for the private debug methods -// of the Ethereum service. -func NewPrivateDebugAPI(b Backend) *PrivateDebugAPI { - return &PrivateDebugAPI{b: b} -} - // ChaindbProperty returns leveldb properties of the key-value database. -func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) { +func (api *DebugAPI) ChaindbProperty(property string) (string, error) { if property == "" { property = "leveldb.stats" } else if !strings.HasPrefix(property, "leveldb.") { @@ -1974,7 +1959,7 @@ func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) { // ChaindbCompact flattens the entire key-value database into a single level, // removing all unused slots and merging all keys. -func (api *PrivateDebugAPI) ChaindbCompact() error { +func (api *DebugAPI) ChaindbCompact() error { for b := byte(0); b < 255; b++ { log.Info("Compacting chain database", "range", fmt.Sprintf("0x%0.2X-0x%0.2X", b, b+1)) if err := api.b.ChainDb().Compact([]byte{b}, []byte{b + 1}); err != nil { @@ -1986,33 +1971,33 @@ func (api *PrivateDebugAPI) ChaindbCompact() error { } // SetHead rewinds the head of the blockchain to a previous block. -func (api *PrivateDebugAPI) SetHead(number hexutil.Uint64) { +func (api *DebugAPI) SetHead(number hexutil.Uint64) { api.b.SetHead(uint64(number)) } -// PublicNetAPI offers network related RPC methods -type PublicNetAPI struct { +// NetAPI offers network related RPC methods +type NetAPI struct { net *p2p.Server networkVersion uint64 } -// NewPublicNetAPI creates a new net API instance. -func NewPublicNetAPI(net *p2p.Server, networkVersion uint64) *PublicNetAPI { - return &PublicNetAPI{net, networkVersion} +// NewNetAPI creates a new net API instance. +func NewNetAPI(net *p2p.Server, networkVersion uint64) *NetAPI { + return &NetAPI{net, networkVersion} } // Listening returns an indication if the node is listening for network connections. -func (s *PublicNetAPI) Listening() bool { +func (s *NetAPI) Listening() bool { return true // always listening } // PeerCount returns the number of connected peers -func (s *PublicNetAPI) PeerCount() hexutil.Uint { +func (s *NetAPI) PeerCount() hexutil.Uint { return hexutil.Uint(s.net.PeerCount()) } // Version returns the current ethereum protocol version. -func (s *PublicNetAPI) Version() string { +func (s *NetAPI) Version() string { return fmt.Sprintf("%d", s.networkVersion) } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index c11d842df7d5..98006d957eb8 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -102,41 +102,37 @@ func GetAPIs(apiBackend Backend) []rpc.API { { Namespace: "eth", Version: "1.0", - Service: NewPublicEthereumAPI(apiBackend), + Service: NewEthereumAPI(apiBackend), Public: true, }, { Namespace: "eth", Version: "1.0", - Service: NewPublicBlockChainAPI(apiBackend), + Service: NewBlockChainAPI(apiBackend), Public: true, }, { Namespace: "eth", Version: "1.0", - Service: NewPublicTransactionPoolAPI(apiBackend, nonceLock), + Service: NewTransactionAPI(apiBackend, nonceLock), Public: true, }, { Namespace: "txpool", Version: "1.0", - Service: NewPublicTxPoolAPI(apiBackend), + Service: NewTxPoolAPI(apiBackend), Public: true, }, { Namespace: "debug", Version: "1.0", - Service: NewPublicDebugAPI(apiBackend), + Service: NewDebugAPI(apiBackend), Public: true, - }, { - Namespace: "debug", - Version: "1.0", - Service: NewPrivateDebugAPI(apiBackend), }, { Namespace: "eth", Version: "1.0", - Service: NewPublicAccountAPI(apiBackend.AccountManager()), + Service: NewEthereumAccountAPI(apiBackend.AccountManager()), Public: true, }, { Namespace: "personal", Version: "1.0", - Service: NewPrivateAccountAPI(apiBackend, nonceLock), + Service: NewPersonalAccountAPI(apiBackend, nonceLock), Public: false, }, } diff --git a/internal/ethapi/dbapi.go b/internal/ethapi/dbapi.go index 33dca29d3c66..33fda936dcd0 100644 --- a/internal/ethapi/dbapi.go +++ b/internal/ethapi/dbapi.go @@ -22,7 +22,7 @@ import ( ) // DbGet returns the raw value of a key stored in the database. -func (api *PrivateDebugAPI) DbGet(key string) (hexutil.Bytes, error) { +func (api *DebugAPI) DbGet(key string) (hexutil.Bytes, error) { blob, err := common.ParseHexOrString(key) if err != nil { return nil, err @@ -32,12 +32,12 @@ func (api *PrivateDebugAPI) DbGet(key string) (hexutil.Bytes, error) { // DbAncient retrieves an ancient binary blob from the append-only immutable files. // It is a mapping to the `AncientReaderOp.Ancient` method -func (api *PrivateDebugAPI) DbAncient(kind string, number uint64) (hexutil.Bytes, error) { +func (api *DebugAPI) DbAncient(kind string, number uint64) (hexutil.Bytes, error) { return api.b.ChainDb().Ancient(kind, number) } // DbAncients returns the ancient item numbers in the ancient store. // It is a mapping to the `AncientReaderOp.Ancients` method -func (api *PrivateDebugAPI) DbAncients() (uint64, error) { +func (api *DebugAPI) DbAncients() (uint64, error) { return api.b.ChainDb().Ancients() } diff --git a/les/api.go b/les/api.go index 782bb31ef29a..dc8639381777 100644 --- a/les/api.go +++ b/les/api.go @@ -33,15 +33,15 @@ var ( errUnknownBenchmarkType = errors.New("unknown benchmark type") ) -// PrivateLightServerAPI provides an API to access the LES light server. -type PrivateLightServerAPI struct { +// LightServerAPI provides an API to access the LES light server. +type LightServerAPI struct { server *LesServer defaultPosFactors, defaultNegFactors vfs.PriceFactors } -// NewPrivateLightServerAPI creates a new LES light server API. -func NewPrivateLightServerAPI(server *LesServer) *PrivateLightServerAPI { - return &PrivateLightServerAPI{ +// NewLightServerAPI creates a new LES light server API. +func NewLightServerAPI(server *LesServer) *LightServerAPI { + return &LightServerAPI{ server: server, defaultPosFactors: defaultPosFactors, defaultNegFactors: defaultNegFactors, @@ -61,7 +61,7 @@ func parseNode(node string) (enode.ID, error) { } // ServerInfo returns global server parameters -func (api *PrivateLightServerAPI) ServerInfo() map[string]interface{} { +func (api *LightServerAPI) ServerInfo() map[string]interface{} { res := make(map[string]interface{}) res["minimumCapacity"] = api.server.minCapacity res["maximumCapacity"] = api.server.maxCapacity @@ -72,7 +72,7 @@ func (api *PrivateLightServerAPI) ServerInfo() map[string]interface{} { } // ClientInfo returns information about clients listed in the ids list or matching the given tags -func (api *PrivateLightServerAPI) ClientInfo(nodes []string) map[enode.ID]map[string]interface{} { +func (api *LightServerAPI) ClientInfo(nodes []string) map[enode.ID]map[string]interface{} { var ids []enode.ID for _, node := range nodes { if id, err := parseNode(node); err == nil { @@ -102,7 +102,7 @@ func (api *PrivateLightServerAPI) ClientInfo(nodes []string) map[enode.ID]map[st // If maxCount limit is applied but there are more potential results then the ID // of the next potential result is included in the map with an empty structure // assigned to it. -func (api *PrivateLightServerAPI) PriorityClientInfo(start, stop enode.ID, maxCount int) map[enode.ID]map[string]interface{} { +func (api *LightServerAPI) PriorityClientInfo(start, stop enode.ID, maxCount int) map[enode.ID]map[string]interface{} { res := make(map[enode.ID]map[string]interface{}) ids := api.server.clientPool.GetPosBalanceIDs(start, stop, maxCount+1) if len(ids) > maxCount { @@ -122,7 +122,7 @@ func (api *PrivateLightServerAPI) PriorityClientInfo(start, stop enode.ID, maxCo } // clientInfo creates a client info data structure -func (api *PrivateLightServerAPI) clientInfo(peer *clientPeer, balance vfs.ReadOnlyBalance) map[string]interface{} { +func (api *LightServerAPI) clientInfo(peer *clientPeer, balance vfs.ReadOnlyBalance) map[string]interface{} { info := make(map[string]interface{}) pb, nb := balance.GetBalance() info["isConnected"] = peer != nil @@ -140,7 +140,7 @@ func (api *PrivateLightServerAPI) clientInfo(peer *clientPeer, balance vfs.ReadO // setParams either sets the given parameters for a single connected client (if specified) // or the default parameters applicable to clients connected in the future -func (api *PrivateLightServerAPI) setParams(params map[string]interface{}, client *clientPeer, posFactors, negFactors *vfs.PriceFactors) (updateFactors bool, err error) { +func (api *LightServerAPI) setParams(params map[string]interface{}, client *clientPeer, posFactors, negFactors *vfs.PriceFactors) (updateFactors bool, err error) { defParams := client == nil for name, value := range params { errValue := func() error { @@ -191,7 +191,7 @@ func (api *PrivateLightServerAPI) setParams(params map[string]interface{}, clien // SetClientParams sets client parameters for all clients listed in the ids list // or all connected clients if the list is empty -func (api *PrivateLightServerAPI) SetClientParams(nodes []string, params map[string]interface{}) error { +func (api *LightServerAPI) SetClientParams(nodes []string, params map[string]interface{}) error { var err error for _, node := range nodes { var id enode.ID @@ -215,7 +215,7 @@ func (api *PrivateLightServerAPI) SetClientParams(nodes []string, params map[str } // SetDefaultParams sets the default parameters applicable to clients connected in the future -func (api *PrivateLightServerAPI) SetDefaultParams(params map[string]interface{}) error { +func (api *LightServerAPI) SetDefaultParams(params map[string]interface{}) error { update, err := api.setParams(params, nil, &api.defaultPosFactors, &api.defaultNegFactors) if update { api.server.clientPool.SetDefaultFactors(api.defaultPosFactors, api.defaultNegFactors) @@ -227,7 +227,7 @@ func (api *PrivateLightServerAPI) SetDefaultParams(params map[string]interface{} // So that already connected client won't be kicked out very soon and we can ensure all // connected clients can have enough time to request or sync some data. // When the input parameter `bias` < 0 (illegal), return error. -func (api *PrivateLightServerAPI) SetConnectedBias(bias time.Duration) error { +func (api *LightServerAPI) SetConnectedBias(bias time.Duration) error { if bias < time.Duration(0) { return fmt.Errorf("bias illegal: %v less than 0", bias) } @@ -237,7 +237,7 @@ func (api *PrivateLightServerAPI) SetConnectedBias(bias time.Duration) error { // AddBalance adds the given amount to the balance of a client if possible and returns // the balance before and after the operation -func (api *PrivateLightServerAPI) AddBalance(node string, amount int64) (balance [2]uint64, err error) { +func (api *LightServerAPI) AddBalance(node string, amount int64) (balance [2]uint64, err error) { var id enode.ID if id, err = parseNode(node); err != nil { return @@ -254,7 +254,7 @@ func (api *PrivateLightServerAPI) AddBalance(node string, amount int64) (balance // // Note: measurement time is adjusted for each pass depending on the previous ones. // Therefore a controlled total measurement time is achievable in multiple passes. -func (api *PrivateLightServerAPI) Benchmark(setups []map[string]interface{}, passCount, length int) ([]map[string]interface{}, error) { +func (api *LightServerAPI) Benchmark(setups []map[string]interface{}, passCount, length int) ([]map[string]interface{}, error) { benchmarks := make([]requestBenchmark, len(setups)) for i, setup := range setups { if t, ok := setup["type"].(string); ok { @@ -324,20 +324,20 @@ func (api *PrivateLightServerAPI) Benchmark(setups []map[string]interface{}, pas return result, nil } -// PrivateDebugAPI provides an API to debug LES light server functionality. -type PrivateDebugAPI struct { +// DebugAPI provides an API to debug LES light server functionality. +type DebugAPI struct { server *LesServer } -// NewPrivateDebugAPI creates a new LES light server debug API. -func NewPrivateDebugAPI(server *LesServer) *PrivateDebugAPI { - return &PrivateDebugAPI{ +// NewDebugAPI creates a new LES light server debug API. +func NewDebugAPI(server *LesServer) *DebugAPI { + return &DebugAPI{ server: server, } } // FreezeClient forces a temporary client freeze which normally happens when the server is overloaded -func (api *PrivateDebugAPI) FreezeClient(node string) error { +func (api *DebugAPI) FreezeClient(node string) error { var ( id enode.ID err error @@ -353,14 +353,14 @@ func (api *PrivateDebugAPI) FreezeClient(node string) error { } } -// PrivateLightAPI provides an API to access the LES light server or light client. -type PrivateLightAPI struct { +// LightAPI provides an API to access the LES light server or light client. +type LightAPI struct { backend *lesCommons } -// NewPrivateLightAPI creates a new LES service API. -func NewPrivateLightAPI(backend *lesCommons) *PrivateLightAPI { - return &PrivateLightAPI{backend: backend} +// NewLightAPI creates a new LES service API. +func NewLightAPI(backend *lesCommons) *LightAPI { + return &LightAPI{backend: backend} } // LatestCheckpoint returns the latest local checkpoint package. @@ -370,7 +370,7 @@ func NewPrivateLightAPI(backend *lesCommons) *PrivateLightAPI { // result[1], 32 bytes hex encoded latest section head hash // result[2], 32 bytes hex encoded latest section canonical hash trie root hash // result[3], 32 bytes hex encoded latest section bloom trie root hash -func (api *PrivateLightAPI) LatestCheckpoint() ([4]string, error) { +func (api *LightAPI) LatestCheckpoint() ([4]string, error) { var res [4]string cp := api.backend.latestLocalCheckpoint() if cp.Empty() { @@ -387,7 +387,7 @@ func (api *PrivateLightAPI) LatestCheckpoint() ([4]string, error) { // result[0], 32 bytes hex encoded latest section head hash // result[1], 32 bytes hex encoded latest section canonical hash trie root hash // result[2], 32 bytes hex encoded latest section bloom trie root hash -func (api *PrivateLightAPI) GetCheckpoint(index uint64) ([3]string, error) { +func (api *LightAPI) GetCheckpoint(index uint64) ([3]string, error) { var res [3]string cp := api.backend.localCheckpoint(index) if cp.Empty() { @@ -398,7 +398,7 @@ func (api *PrivateLightAPI) GetCheckpoint(index uint64) ([3]string, error) { } // GetCheckpointContractAddress returns the contract contract address in hex format. -func (api *PrivateLightAPI) GetCheckpointContractAddress() (string, error) { +func (api *LightAPI) GetCheckpointContractAddress() (string, error) { if api.backend.oracle == nil { return "", errNotActivated } diff --git a/les/client.go b/les/client.go index b38a0aae74d3..fa5de5450acb 100644 --- a/les/client.go +++ b/les/client.go @@ -74,7 +74,7 @@ type LightEthereum struct { eventMux *event.TypeMux engine consensus.Engine accountManager *accounts.Manager - netRPCService *ethapi.PublicNetAPI + netRPCService *ethapi.NetAPI p2pServer *p2p.Server p2pConfig *p2p.Config @@ -189,7 +189,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { leth.blockchain.DisableCheckFreq() } - leth.netRPCService = ethapi.NewPublicNetAPI(leth.p2pServer, leth.config.NetworkId) + leth.netRPCService = ethapi.NewNetAPI(leth.p2pServer, leth.config.NetworkId) // Register the backend on the node stack.RegisterAPIs(leth.APIs()) @@ -300,12 +300,12 @@ func (s *LightEthereum) APIs() []rpc.API { }, { Namespace: "eth", Version: "1.0", - Service: downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux), + Service: downloader.NewDownloaderAPI(s.handler.downloader, s.eventMux), Public: true, }, { Namespace: "eth", Version: "1.0", - Service: filters.NewPublicFilterAPI(s.ApiBackend, true, 5*time.Minute), + Service: filters.NewFilterAPI(s.ApiBackend, true, 5*time.Minute), Public: true, }, { Namespace: "net", @@ -315,7 +315,7 @@ func (s *LightEthereum) APIs() []rpc.API { }, { Namespace: "les", Version: "1.0", - Service: NewPrivateLightAPI(&s.lesCommons), + Service: NewLightAPI(&s.lesCommons), Public: false, }, { Namespace: "vflux", diff --git a/les/downloader/api.go b/les/downloader/api.go index 2024d23deade..b1a81b6b76d3 100644 --- a/les/downloader/api.go +++ b/les/downloader/api.go @@ -25,21 +25,21 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -// PublicDownloaderAPI provides an API which gives information about the current synchronisation status. +// DownloaderAPI provides an API which gives information about the current synchronisation status. // It offers only methods that operates on data that can be available to anyone without security risks. -type PublicDownloaderAPI struct { +type DownloaderAPI struct { d *Downloader mux *event.TypeMux installSyncSubscription chan chan interface{} uninstallSyncSubscription chan *uninstallSyncSubscriptionRequest } -// NewPublicDownloaderAPI create a new PublicDownloaderAPI. The API has an internal event loop that +// NewDownloaderAPI create a new PublicDownloaderAPI. The API has an internal event loop that // listens for events from the downloader through the global event mux. In case it receives one of // these events it broadcasts it to all syncing subscriptions that are installed through the // installSyncSubscription channel. -func NewPublicDownloaderAPI(d *Downloader, m *event.TypeMux) *PublicDownloaderAPI { - api := &PublicDownloaderAPI{ +func NewDownloaderAPI(d *Downloader, m *event.TypeMux) *DownloaderAPI { + api := &DownloaderAPI{ d: d, mux: m, installSyncSubscription: make(chan chan interface{}), @@ -53,7 +53,7 @@ func NewPublicDownloaderAPI(d *Downloader, m *event.TypeMux) *PublicDownloaderAP // eventLoop runs a loop until the event mux closes. It will install and uninstall new // sync subscriptions and broadcasts sync status updates to the installed sync subscriptions. -func (api *PublicDownloaderAPI) eventLoop() { +func (api *DownloaderAPI) eventLoop() { var ( sub = api.mux.Subscribe(StartEvent{}, DoneEvent{}, FailedEvent{}) syncSubscriptions = make(map[chan interface{}]struct{}) @@ -90,7 +90,7 @@ func (api *PublicDownloaderAPI) eventLoop() { } // Syncing provides information when this nodes starts synchronising with the Ethereum network and when it's finished. -func (api *PublicDownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error) { +func (api *DownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported @@ -133,9 +133,9 @@ type uninstallSyncSubscriptionRequest struct { // SyncStatusSubscription represents a syncing subscription. type SyncStatusSubscription struct { - api *PublicDownloaderAPI // register subscription in event loop of this api instance - c chan interface{} // channel where events are broadcasted to - unsubOnce sync.Once // make sure unsubscribe logic is executed once + api *DownloaderAPI // register subscription in event loop of this api instance + c chan interface{} // channel where events are broadcasted to + unsubOnce sync.Once // make sure unsubscribe logic is executed once } // Unsubscribe uninstalls the subscription from the DownloadAPI event loop. @@ -160,7 +160,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 -func (api *PublicDownloaderAPI) SubscribeSyncStatus(status chan interface{}) *SyncStatusSubscription { +func (api *DownloaderAPI) SubscribeSyncStatus(status chan interface{}) *SyncStatusSubscription { api.installSyncSubscription <- status return &SyncStatusSubscription{api: api, c: status} } diff --git a/les/server.go b/les/server.go index c135e65f2dc4..436dff2bf64f 100644 --- a/les/server.go +++ b/les/server.go @@ -160,19 +160,19 @@ func (s *LesServer) APIs() []rpc.API { { Namespace: "les", Version: "1.0", - Service: NewPrivateLightAPI(&s.lesCommons), + Service: NewLightAPI(&s.lesCommons), Public: false, }, { Namespace: "les", Version: "1.0", - Service: NewPrivateLightServerAPI(s), + Service: NewLightServerAPI(s), Public: false, }, { Namespace: "debug", Version: "1.0", - Service: NewPrivateDebugAPI(s), + Service: NewDebugAPI(s), Public: false, }, } diff --git a/node/api.go b/node/api.go index 1b32399f635c..8d0dadc9e241 100644 --- a/node/api.go +++ b/node/api.go @@ -36,11 +36,7 @@ func (n *Node) apis() []rpc.API { { Namespace: "admin", Version: "1.0", - Service: &privateAdminAPI{n}, - }, { - Namespace: "admin", - Version: "1.0", - Service: &publicAdminAPI{n}, + Service: &adminAPI{n}, Public: true, }, { Namespace: "debug", @@ -49,21 +45,21 @@ func (n *Node) apis() []rpc.API { }, { Namespace: "web3", Version: "1.0", - Service: &publicWeb3API{n}, + Service: &web3API{n}, Public: true, }, } } -// privateAdminAPI is the collection of administrative API methods exposed only -// over a secure RPC channel. -type privateAdminAPI struct { +// adminAPI is the collection of administrative API methods exposed over +// both secure and unsecure RPC channels. +type adminAPI struct { node *Node // Node interfaced by this API } // AddPeer requests connecting to a remote node, and also maintaining the new // connection at all times, even reconnecting if it is lost. -func (api *privateAdminAPI) AddPeer(url string) (bool, error) { +func (api *adminAPI) AddPeer(url string) (bool, error) { // Make sure the server is running, fail otherwise server := api.node.Server() if server == nil { @@ -79,7 +75,7 @@ func (api *privateAdminAPI) AddPeer(url string) (bool, error) { } // RemovePeer disconnects from a remote node if the connection exists -func (api *privateAdminAPI) RemovePeer(url string) (bool, error) { +func (api *adminAPI) RemovePeer(url string) (bool, error) { // Make sure the server is running, fail otherwise server := api.node.Server() if server == nil { @@ -95,7 +91,7 @@ func (api *privateAdminAPI) RemovePeer(url string) (bool, error) { } // AddTrustedPeer allows a remote node to always connect, even if slots are full -func (api *privateAdminAPI) AddTrustedPeer(url string) (bool, error) { +func (api *adminAPI) AddTrustedPeer(url string) (bool, error) { // Make sure the server is running, fail otherwise server := api.node.Server() if server == nil { @@ -111,7 +107,7 @@ func (api *privateAdminAPI) AddTrustedPeer(url string) (bool, error) { // RemoveTrustedPeer removes a remote node from the trusted peer set, but it // does not disconnect it automatically. -func (api *privateAdminAPI) RemoveTrustedPeer(url string) (bool, error) { +func (api *adminAPI) RemoveTrustedPeer(url string) (bool, error) { // Make sure the server is running, fail otherwise server := api.node.Server() if server == nil { @@ -127,7 +123,7 @@ func (api *privateAdminAPI) RemoveTrustedPeer(url string) (bool, error) { // PeerEvents creates an RPC subscription which receives peer events from the // node's p2p.Server -func (api *privateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) { +func (api *adminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) { // Make sure the server is running, fail otherwise server := api.node.Server() if server == nil { @@ -164,7 +160,7 @@ func (api *privateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, } // StartHTTP starts the HTTP RPC API server. -func (api *privateAdminAPI) StartHTTP(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { +func (api *adminAPI) StartHTTP(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { api.node.lock.Lock() defer api.node.lock.Unlock() @@ -219,26 +215,26 @@ func (api *privateAdminAPI) StartHTTP(host *string, port *int, cors *string, api // StartRPC starts the HTTP RPC API server. // Deprecated: use StartHTTP instead. -func (api *privateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { +func (api *adminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { log.Warn("Deprecation warning", "method", "admin.StartRPC", "use-instead", "admin.StartHTTP") return api.StartHTTP(host, port, cors, apis, vhosts) } // StopHTTP shuts down the HTTP server. -func (api *privateAdminAPI) StopHTTP() (bool, error) { +func (api *adminAPI) StopHTTP() (bool, error) { api.node.http.stop() return true, nil } // StopRPC shuts down the HTTP server. // Deprecated: use StopHTTP instead. -func (api *privateAdminAPI) StopRPC() (bool, error) { +func (api *adminAPI) StopRPC() (bool, error) { log.Warn("Deprecation warning", "method", "admin.StopRPC", "use-instead", "admin.StopHTTP") return api.StopHTTP() } // StartWS starts the websocket RPC API server. -func (api *privateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { +func (api *adminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { api.node.lock.Lock() defer api.node.lock.Unlock() @@ -290,21 +286,15 @@ func (api *privateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str } // StopWS terminates all WebSocket servers. -func (api *privateAdminAPI) StopWS() (bool, error) { +func (api *adminAPI) StopWS() (bool, error) { api.node.http.stopWS() api.node.ws.stop() return true, nil } -// publicAdminAPI is the collection of administrative API methods exposed over -// both secure and unsecure RPC channels. -type publicAdminAPI struct { - node *Node // Node interfaced by this API -} - // Peers retrieves all the information we know about each individual peer at the // protocol granularity. -func (api *publicAdminAPI) Peers() ([]*p2p.PeerInfo, error) { +func (api *adminAPI) Peers() ([]*p2p.PeerInfo, error) { server := api.node.Server() if server == nil { return nil, ErrNodeStopped @@ -314,7 +304,7 @@ func (api *publicAdminAPI) Peers() ([]*p2p.PeerInfo, error) { // NodeInfo retrieves all the information we know about the host node at the // protocol granularity. -func (api *publicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) { +func (api *adminAPI) NodeInfo() (*p2p.NodeInfo, error) { server := api.node.Server() if server == nil { return nil, ErrNodeStopped @@ -323,22 +313,22 @@ func (api *publicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) { } // Datadir retrieves the current data directory the node is using. -func (api *publicAdminAPI) Datadir() string { +func (api *adminAPI) Datadir() string { return api.node.DataDir() } -// publicWeb3API offers helper utils -type publicWeb3API struct { +// web3API offers helper utils +type web3API struct { stack *Node } // ClientVersion returns the node name -func (s *publicWeb3API) ClientVersion() string { +func (s *web3API) ClientVersion() string { return s.stack.Server().Name } // Sha3 applies the ethereum sha3 implementation on the input. // It assumes the input is hex encoded. -func (s *publicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes { +func (s *web3API) Sha3(input hexutil.Bytes) hexutil.Bytes { return crypto.Keccak256(input) } diff --git a/node/api_test.go b/node/api_test.go index 9549adf9c254..d76cb943e4ee 100644 --- a/node/api_test.go +++ b/node/api_test.go @@ -35,7 +35,7 @@ func TestStartRPC(t *testing.T) { type test struct { name string cfg Config - fn func(*testing.T, *Node, *privateAdminAPI) + fn func(*testing.T, *Node, *adminAPI) // Checks. These run after the node is configured and all API calls have been made. wantReachable bool // whether the HTTP server should be reachable at all @@ -48,7 +48,7 @@ func TestStartRPC(t *testing.T) { { name: "all off", cfg: Config{}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { }, wantReachable: false, wantHandlers: false, @@ -58,7 +58,7 @@ func TestStartRPC(t *testing.T) { { name: "rpc enabled through config", cfg: Config{HTTPHost: "127.0.0.1"}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { }, wantReachable: true, wantHandlers: true, @@ -68,7 +68,7 @@ func TestStartRPC(t *testing.T) { { name: "rpc enabled through API", cfg: Config{}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { _, err := api.StartHTTP(sp("127.0.0.1"), ip(0), nil, nil, nil) assert.NoError(t, err) }, @@ -80,7 +80,7 @@ func TestStartRPC(t *testing.T) { { name: "rpc start again after failure", cfg: Config{}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { // Listen on a random port. listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { @@ -108,7 +108,7 @@ func TestStartRPC(t *testing.T) { { name: "rpc stopped through API", cfg: Config{HTTPHost: "127.0.0.1"}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { _, err := api.StopHTTP() assert.NoError(t, err) }, @@ -120,7 +120,7 @@ func TestStartRPC(t *testing.T) { { name: "rpc stopped twice", cfg: Config{HTTPHost: "127.0.0.1"}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { _, err := api.StopHTTP() assert.NoError(t, err) @@ -143,7 +143,7 @@ func TestStartRPC(t *testing.T) { { name: "ws enabled through API", cfg: Config{}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { _, err := api.StartWS(sp("127.0.0.1"), ip(0), nil, nil) assert.NoError(t, err) }, @@ -155,7 +155,7 @@ func TestStartRPC(t *testing.T) { { name: "ws stopped through API", cfg: Config{WSHost: "127.0.0.1"}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { _, err := api.StopWS() assert.NoError(t, err) }, @@ -167,7 +167,7 @@ func TestStartRPC(t *testing.T) { { name: "ws stopped twice", cfg: Config{WSHost: "127.0.0.1"}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { _, err := api.StopWS() assert.NoError(t, err) @@ -182,7 +182,7 @@ func TestStartRPC(t *testing.T) { { name: "ws enabled after RPC", cfg: Config{HTTPHost: "127.0.0.1"}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { wsport := n.http.port _, err := api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil) assert.NoError(t, err) @@ -195,7 +195,7 @@ func TestStartRPC(t *testing.T) { { name: "ws enabled after RPC then stopped", cfg: Config{HTTPHost: "127.0.0.1"}, - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { wsport := n.http.port _, err := api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil) assert.NoError(t, err) @@ -210,7 +210,7 @@ func TestStartRPC(t *testing.T) { }, { name: "rpc stopped with ws enabled", - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { _, err := api.StartHTTP(sp("127.0.0.1"), ip(0), nil, nil, nil) assert.NoError(t, err) @@ -228,7 +228,7 @@ func TestStartRPC(t *testing.T) { }, { name: "rpc enabled after ws", - fn: func(t *testing.T, n *Node, api *privateAdminAPI) { + fn: func(t *testing.T, n *Node, api *adminAPI) { _, err := api.StartWS(sp("127.0.0.1"), ip(0), nil, nil) assert.NoError(t, err) @@ -271,7 +271,7 @@ func TestStartRPC(t *testing.T) { // Run the API call hook. if test.fn != nil { - test.fn(t, stack, &privateAdminAPI{stack}) + test.fn(t, stack, &adminAPI{stack}) } // Check if the HTTP endpoints are available. From f20a56926551ae91a349498f9ce97c8ee373d6bb Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 21 Jun 2022 11:16:05 +0200 Subject: [PATCH 042/715] cmd/geth: drop geth js command (#25000) * cmd/geth: drop js command * cmd: simplify ipc path determination for attach * Add deprecation warning for js * rm testdata for exec * fix account unlock test cases * Update cmd/geth/consolecmd.go Co-authored-by: Martin Holst Swende * fix Co-authored-by: Martin Holst Swende --- cmd/geth/accountcmd_test.go | 16 ++++--- cmd/geth/consolecmd.go | 90 +++++++------------------------------ cmd/utils/flags.go | 4 +- console/console.go | 5 --- console/console_test.go | 13 ------ console/testdata/exec.js | 1 - 6 files changed, 30 insertions(+), 99 deletions(-) delete mode 100644 console/testdata/exec.js diff --git a/cmd/geth/accountcmd_test.go b/cmd/geth/accountcmd_test.go index 0c22e8c9bf57..bbde27c3785a 100644 --- a/cmd/geth/accountcmd_test.go +++ b/cmd/geth/accountcmd_test.go @@ -180,11 +180,12 @@ Fatal: could not decrypt key with given password func TestUnlockFlag(t *testing.T) { geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), - "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "js", "testdata/empty.js") + "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "console", "--exec", "loadScript('testdata/empty.js')") geth.Expect(` Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 !! Unsupported terminal, password will be echoed. Password: {{.InputLine "foobar"}} +undefined `) geth.ExpectExit() @@ -201,7 +202,7 @@ Password: {{.InputLine "foobar"}} func TestUnlockFlagWrongPassword(t *testing.T) { geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), - "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "js", "testdata/empty.js") + "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "console", "--exec", "loadScript('testdata/empty.js')") defer geth.ExpectExit() geth.Expect(` @@ -219,7 +220,7 @@ Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could // https://github.com/ethereum/go-ethereum/issues/1785 func TestUnlockFlagMultiIndex(t *testing.T) { geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), - "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--unlock", "0,2", "js", "testdata/empty.js") + "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--unlock", "0,2", "console", "--exec", "loadScript('testdata/empty.js')") geth.Expect(` Unlocking account 0 | Attempt 1/3 @@ -227,6 +228,7 @@ Unlocking account 0 | Attempt 1/3 Password: {{.InputLine "foobar"}} Unlocking account 2 | Attempt 1/3 Password: {{.InputLine "foobar"}} +undefined `) geth.ExpectExit() @@ -244,8 +246,11 @@ Password: {{.InputLine "foobar"}} func TestUnlockFlagPasswordFile(t *testing.T) { geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), - "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--password", "testdata/passwords.txt", "--unlock", "0,2", "js", "testdata/empty.js") + "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--password", "testdata/passwords.txt", "--unlock", "0,2", "console", "--exec", "loadScript('testdata/empty.js')") + geth.Expect(` +undefined +`) geth.ExpectExit() wantMessages := []string{ @@ -275,7 +280,7 @@ func TestUnlockFlagAmbiguous(t *testing.T) { geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t), "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--keystore", store, "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", - "js", "testdata/empty.js") + "console", "--exec", "loadScript('testdata/empty.js')") defer geth.ExpectExit() // Helper for the expect template, returns absolute keystore path. @@ -294,6 +299,7 @@ Testing your password against all of them... Your password unlocked keystore://{{keypath "1"}} In order to avoid this warning, you need to remove the following duplicate key files: keystore://{{keypath "2"}} +undefined `) geth.ExpectExit() diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index 5167f8536a27..4f538f96e3f5 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -18,11 +18,9 @@ package main import ( "fmt" - "path/filepath" "strings" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" @@ -61,7 +59,7 @@ This command allows to open a console on a running geth node.`, javascriptCommand = cli.Command{ Action: utils.MigrateFlags(ephemeralConsole), Name: "js", - Usage: "Execute the specified JavaScript files", + Usage: "(DEPRECATED) Execute the specified JavaScript files", ArgsUsage: " [jsfile...]", Flags: utils.GroupFlags(nodeFlags, consoleFlags), Category: "CONSOLE COMMANDS", @@ -121,31 +119,9 @@ func localConsole(ctx *cli.Context) error { func remoteConsole(ctx *cli.Context) error { endpoint := ctx.Args().First() if endpoint == "" { - path := node.DefaultDataDir() - if ctx.GlobalIsSet(utils.DataDirFlag.Name) { - path = ctx.GlobalString(utils.DataDirFlag.Name) - } - if path != "" { - if ctx.GlobalBool(utils.RopstenFlag.Name) { - // Maintain compatibility with older Geth configurations storing the - // Ropsten database in `testnet` instead of `ropsten`. - legacyPath := filepath.Join(path, "testnet") - if common.FileExist(legacyPath) { - path = legacyPath - } else { - path = filepath.Join(path, "ropsten") - } - } else if ctx.GlobalBool(utils.RinkebyFlag.Name) { - path = filepath.Join(path, "rinkeby") - } else if ctx.GlobalBool(utils.GoerliFlag.Name) { - path = filepath.Join(path, "goerli") - } else if ctx.GlobalBool(utils.SepoliaFlag.Name) { - path = filepath.Join(path, "sepolia") - } else if ctx.GlobalBool(utils.KilnFlag.Name) { - path = filepath.Join(path, "kiln") - } - } - endpoint = fmt.Sprintf("%s/geth.ipc", path) + cfg := defaultNodeConfig() + utils.SetDataDir(ctx, &cfg) + endpoint = cfg.IPCEndpoint() } client, err := dialRPC(endpoint) if err != nil { @@ -174,6 +150,19 @@ func remoteConsole(ctx *cli.Context) error { return nil } +// ephemeralConsole starts a new geth node, attaches an ephemeral JavaScript +// console to it, executes each of the files specified as arguments and tears +// everything down. +func ephemeralConsole(ctx *cli.Context) error { + var b strings.Builder + for _, file := range ctx.Args() { + b.Write([]byte(fmt.Sprintf("loadScript('%s');", file))) + } + utils.Fatalf(`The "js" command is deprecated. Please use the following instead: +geth --exec "%s" console`, b.String()) + return nil +} + // dialRPC returns a RPC client which connects to the given endpoint. // The check for empty endpoint implements the defaulting logic // for "geth attach" with no argument. @@ -187,48 +176,3 @@ func dialRPC(endpoint string) (*rpc.Client, error) { } return rpc.Dial(endpoint) } - -// ephemeralConsole starts a new geth node, attaches an ephemeral JavaScript -// console to it, executes each of the files specified as arguments and tears -// everything down. -func ephemeralConsole(ctx *cli.Context) error { - // Create and start the node based on the CLI flags - stack, backend := makeFullNode(ctx) - startNode(ctx, stack, backend, false) - defer stack.Close() - - // Attach to the newly started node and start the JavaScript console - client, err := stack.Attach() - if err != nil { - return fmt.Errorf("Failed to attach to the inproc geth: %v", err) - } - config := console.Config{ - DataDir: utils.MakeDataDir(ctx), - DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), - Client: client, - Preload: utils.MakeConsolePreloads(ctx), - } - - console, err := console.New(config) - if err != nil { - return fmt.Errorf("Failed to start the JavaScript console: %v", err) - } - defer console.Stop(false) - - // Interrupt the JS interpreter when node is stopped. - go func() { - stack.Wait() - console.Stop(false) - }() - - // Evaluate each of the specified JavaScript files. - for _, file := range ctx.Args() { - if err = console.Execute(file); err != nil { - return fmt.Errorf("Failed to execute %s: %v", file, err) - } - } - - // The main script is now done, but keep running timers/callbacks. - console.Stop(true) - return nil -} diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 907e3ce91677..e8911330ae24 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1315,7 +1315,7 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { setGraphQL(ctx, cfg) setWS(ctx, cfg) setNodeUserIdent(ctx, cfg) - setDataDir(ctx, cfg) + SetDataDir(ctx, cfg) setSmartCard(ctx, cfg) if ctx.GlobalIsSet(JWTSecretFlag.Name) { @@ -1366,7 +1366,7 @@ func setSmartCard(ctx *cli.Context, cfg *node.Config) { cfg.SmartCardDaemonPath = path } -func setDataDir(ctx *cli.Context, cfg *node.Config) { +func SetDataDir(ctx *cli.Context, cfg *node.Config) { switch { case ctx.GlobalIsSet(DataDirFlag.Name): cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) diff --git a/console/console.go b/console/console.go index 2f61c1d7a4cf..c8f6c9cfeec5 100644 --- a/console/console.go +++ b/console/console.go @@ -540,11 +540,6 @@ func countIndents(input string) int { return indents } -// Execute runs the JavaScript file specified as the argument. -func (c *Console) Execute(path string) error { - return c.jsre.Exec(path) -} - // Stop cleans up the console and terminates the runtime environment. func (c *Console) Stop(graceful bool) error { c.stopOnce.Do(func() { diff --git a/console/console_test.go b/console/console_test.go index 04ba91d1576a..35341fcba0b5 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -234,19 +234,6 @@ func TestPreload(t *testing.T) { } } -// Tests that JavaScript scripts can be executes from the configured asset path. -func TestExecute(t *testing.T) { - tester := newTester(t, nil) - defer tester.Close(t) - - tester.console.Execute("exec.js") - - tester.console.Evaluate("execed") - if output := tester.output.String(); !strings.Contains(output, "some-executed-string") { - t.Fatalf("execed variable missing: have %s, want %s", output, "some-executed-string") - } -} - // Tests that the JavaScript objects returned by statement executions are properly // pretty printed instead of just displaying "[object]". func TestPrettyPrint(t *testing.T) { diff --git a/console/testdata/exec.js b/console/testdata/exec.js deleted file mode 100644 index 59e34d7c4033..000000000000 --- a/console/testdata/exec.js +++ /dev/null @@ -1 +0,0 @@ -var execed = "some-executed-string"; From f49e29833084d65cae0d2eba71e5788e6d9996c0 Mon Sep 17 00:00:00 2001 From: Zachinquarantine Date: Tue, 21 Jun 2022 05:59:02 -0400 Subject: [PATCH 043/715] README,rpc: remove mention of "shh" RPC API (#25137) --- README.md | 2 +- rpc/subscription_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c6d758afc093..b20eb5b748b4 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ HTTP based JSON-RPC API options: * `--ws.api` API's offered over the WS-RPC interface (default: `eth,net,web3`) * `--ws.origins` Origins from which to accept websockets requests * `--ipcdisable` Disable the IPC-RPC server - * `--ipcapi` API's offered over the IPC-RPC interface (default: `admin,debug,eth,miner,net,personal,shh,txpool,web3`) + * `--ipcapi` API's offered over the IPC-RPC interface (default: `admin,debug,eth,miner,net,personal,txpool,web3`) * `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it) You'll need to use your own programming environments' capabilities (libraries, tools, etc) to diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index 54a053dba805..a920205c001f 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -48,7 +48,7 @@ func TestNewID(t *testing.T) { func TestSubscriptions(t *testing.T) { var ( - namespaces = []string{"eth", "shh", "bzz"} + namespaces = []string{"eth", "bzz"} service = ¬ificationTestService{} subCount = len(namespaces) notificationCount = 3 From 7c7cd410d178df851bd86528e5acc29e5e70eafd Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 22 Jun 2022 19:59:55 +0800 Subject: [PATCH 044/715] eth, miner: retrieve mining state from live database (#25139) * miner: retrieve mining state from live database * eth/catalyst: ignore stale fcu events from cl --- eth/catalyst/api.go | 18 +++++++++++------- miner/miner.go | 1 - miner/worker.go | 10 ---------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 166931e38134..0c8f0c3610ab 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -140,16 +140,26 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa return beacon.ForkChoiceResponse{PayloadStatus: beacon.INVALID_TERMINAL_BLOCK, PayloadID: nil}, nil } } - + valid := func(id *beacon.PayloadID) beacon.ForkChoiceResponse { + return beacon.ForkChoiceResponse{ + PayloadStatus: beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &update.HeadBlockHash}, + PayloadID: id, + } + } if rawdb.ReadCanonicalHash(api.eth.ChainDb(), block.NumberU64()) != update.HeadBlockHash { // Block is not canonical, set head. if latestValid, err := api.eth.BlockChain().SetCanonical(block); err != nil { return beacon.ForkChoiceResponse{PayloadStatus: beacon.PayloadStatusV1{Status: beacon.INVALID, LatestValidHash: &latestValid}}, err } + } else if api.eth.BlockChain().CurrentBlock().Hash() == update.HeadBlockHash { + // If the specified head matches with our local head, do nothing and keep + // generating the payload. It's a special corner case that a few slots are + // missing and we are requested to generate the payload in slot. } else { // If the head block is already in our canonical chain, the beacon client is // probably resyncing. Ignore the update. log.Info("Ignoring beacon update to old head", "number", block.NumberU64(), "hash", update.HeadBlockHash, "age", common.PrettyAge(time.Unix(int64(block.Time()), 0)), "have", api.eth.BlockChain().CurrentBlock().NumberU64()) + return valid(nil), nil } api.eth.SetSynced() @@ -183,12 +193,6 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain")) } } - valid := func(id *beacon.PayloadID) beacon.ForkChoiceResponse { - return beacon.ForkChoiceResponse{ - PayloadStatus: beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &update.HeadBlockHash}, - PayloadID: id, - } - } // If payload generation was requested, create a new block to be potentially // sealed by the beacon client. The payload will be requested later, and we // might replace it arbitrarily many times in between. diff --git a/miner/miner.go b/miner/miner.go index 16c3bf19d263..1e9607a76ad9 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -40,7 +40,6 @@ import ( type Backend interface { BlockChain() *core.BlockChain TxPool() *core.TxPool - StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) } // Config is the configuration parameters of mining. diff --git a/miner/worker.go b/miner/worker.go index ae1b61d42411..93fb6288bb45 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -756,16 +756,6 @@ func (w *worker) makeEnv(parent *types.Block, header *types.Header, coinbase com // Retrieve the parent state to execute on top and start a prefetcher for // the miner to speed block sealing up a bit. state, err := w.chain.StateAt(parent.Root()) - if err != nil { - // Note since the sealing block can be created upon the arbitrary parent - // block, but the state of parent block may already be pruned, so the necessary - // state recovery is needed here in the future. - // - // The maximum acceptable reorg depth can be limited by the finalised block - // somehow. TODO(rjl493456442) fix the hard-coded number here later. - state, err = w.eth.StateAtBlock(parent, 1024, nil, false, false) - log.Warn("Recovered mining state", "root", parent.Root(), "err", err) - } if err != nil { return nil, err } From 68420e1aa58fdd68b578f9ceaaa06cd55b857fce Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Wed, 22 Jun 2022 16:51:45 -0400 Subject: [PATCH 045/715] core: fix typo in txpool (#25149) Fix typo in txPool truncateQueue comment --- core/tx_pool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index 2f21fd09fa07..1c25442dd9c5 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -1459,7 +1459,7 @@ func (pool *TxPool) truncatePending() { pendingRateLimitMeter.Mark(int64(pendingBeforeCap - pending)) } -// truncateQueue drops the oldes transactions in the queue if the pool is above the global queue limit. +// truncateQueue drops the oldest transactions in the queue if the pool is above the global queue limit. func (pool *TxPool) truncateQueue() { queued := uint64(0) for _, list := range pool.queue { From 0f044f3433a529889b921e398a1ec92b3bb305f6 Mon Sep 17 00:00:00 2001 From: ucwong Date: Thu, 23 Jun 2022 16:35:27 +0800 Subject: [PATCH 046/715] go.mod: upgrade to latest goleveldb (#25067) Co-authored-by: Felix Lange --- go.mod | 18 ++++++++--------- go.sum | 62 +++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index f9af9abe0052..a2d66c3daccd 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/go-stack/stack v1.8.0 github.com/golang-jwt/jwt/v4 v4.3.0 - github.com/golang/protobuf v1.4.3 + github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.4 github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa github.com/google/uuid v1.2.0 @@ -51,15 +51,15 @@ require ( github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.7.2 github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 - github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 - golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 golang.org/x/text v0.3.7 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 @@ -95,9 +95,9 @@ require ( github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect - golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - google.golang.org/protobuf v1.23.0 // indirect + golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect + golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect + google.golang.org/protobuf v1.26.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 8d28443f6c61..01f49e8dedf8 100644 --- a/go.sum +++ b/go.sum @@ -124,8 +124,9 @@ github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlK github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgxrzK5E1fW7RQGeDwE8F/ZZnUYc= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= @@ -152,6 +153,7 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -174,8 +176,9 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= @@ -189,14 +192,16 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -223,6 +228,7 @@ github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= github.com/influxdata/influxdb v1.8.3 h1:WEypI1BQFTT4teLM+1qkEcvUi0dAvopAI/ir0vAiBg8= @@ -311,19 +317,24 @@ github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hz github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= @@ -382,12 +393,13 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= +github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= @@ -470,17 +482,19 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -520,11 +534,10 @@ golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -532,11 +545,15 @@ golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -578,14 +595,16 @@ golang.org/x/tools v0.0.0-20191126055441-b0650ceb63d9/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= @@ -628,8 +647,10 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -652,8 +673,9 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 6135c688b854fdbf741e56630328349ad3d26b42 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Thu, 23 Jun 2022 18:11:47 +0200 Subject: [PATCH 047/715] eth/tracers: optimize goja buffer conversion (#25156) This changes the []byte <-> Uint8Array conversion to use an ArrayBuffer, avoiding inefficient copying of the slice data in Goja. Co-authored-by: Felix Lange --- eth/tracers/js/goja.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index f0c78c084bd9..f54c8010494f 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -55,11 +55,7 @@ type fromBufFn = func(vm *goja.Runtime, buf goja.Value, allowString bool) ([]byt func toBuf(vm *goja.Runtime, bufType goja.Value, val []byte) (goja.Value, error) { // bufType is usually Uint8Array. This is equivalent to `new Uint8Array(val)` in JS. - res, err := vm.New(bufType, vm.ToValue(val)) - if err != nil { - return nil, err - } - return vm.ToValue(res), nil + return vm.New(bufType, vm.ToValue(vm.NewArrayBuffer(val))) } func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString bool) ([]byte, error) { @@ -70,6 +66,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b break } return common.FromHex(obj.String()), nil + case "Array": var b []byte if err := vm.ExportTo(buf, &b); err != nil { @@ -81,10 +78,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b if !obj.Get("constructor").SameAs(bufType) { break } - var b []byte - if err := vm.ExportTo(buf, &b); err != nil { - return nil, err - } + b := obj.Get("buffer").Export().(goja.ArrayBuffer).Bytes() return b, nil } return nil, fmt.Errorf("invalid buffer type") @@ -765,7 +759,7 @@ func (co *contractObj) GetValue() goja.Value { } func (co *contractObj) GetInput() goja.Value { - input := co.contract.Input + input := common.CopyBytes(co.contract.Input) res, err := co.toBuf(co.vm, input) if err != nil { co.vm.Interrupt(err) From e620fa3980b9e76a3479aada9239054f594cfc1a Mon Sep 17 00:00:00 2001 From: int88 <106391185+int88@users.noreply.github.com> Date: Fri, 24 Jun 2022 20:28:01 +0800 Subject: [PATCH 048/715] eth: fix typo (#25161) --- eth/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/handler.go b/eth/handler.go index 54efe18d64a1..43d03924defa 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -296,7 +296,7 @@ func newHandler(config *handlerConfig) (*handler, error) { } // runEthPeer registers an eth peer into the joint eth/snap peerset, adds it to -// various subsistems and starts handling messages. +// various subsystems and starts handling messages. func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { // If the peer has a `snap` extension, wait for it to connect so we can have // a uniform initialization/teardown mechanism From 647c6f2db636ddc272093e00d56006e6da63f0e2 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Fri, 24 Jun 2022 18:03:13 +0200 Subject: [PATCH 049/715] internal/ethapi: always return chain id (#25166) The error was introduced in PR #21686, but there is no good reason to enforce sync in this method, and it causes issues with EL/CL integration. --- internal/ethapi/api.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 7f12fdb95232..c4bf86a40bd2 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -609,12 +609,8 @@ func NewBlockChainAPI(b Backend) *BlockChainAPI { } // ChainId is the EIP-155 replay-protection chain id for the current Ethereum chain config. -func (api *BlockChainAPI) ChainId() (*hexutil.Big, error) { - // if current block is at or past the EIP-155 replay-protection fork block, return chainID from config - if config := api.b.ChainConfig(); config.IsEIP155(api.b.CurrentBlock().Number()) { - return (*hexutil.Big)(config.ChainID), nil - } - return nil, fmt.Errorf("chain not synced beyond EIP-155 replay-protection fork block") +func (api *BlockChainAPI) ChainId() *hexutil.Big { + return (*hexutil.Big)(api.b.ChainConfig().ChainID) } // BlockNumber returns the block number of the chain head. From c7f485d9e5b9ffe125d59495da3a13e1f66a24c9 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Sat, 25 Jun 2022 21:34:21 +0200 Subject: [PATCH 050/715] internal/ethapi: add note about eth_chainId compatibility with EIP-695 (#25168) Co-authored-by: Felix Lange --- internal/ethapi/api.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index c4bf86a40bd2..b05c9a08d379 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -609,6 +609,11 @@ func NewBlockChainAPI(b Backend) *BlockChainAPI { } // ChainId is the EIP-155 replay-protection chain id for the current Ethereum chain config. +// +// Note, this method does not conform to EIP-695 because the configured chain ID is always +// returned, regardless of the current head block. We used to return an error when the chain +// wasn't synced up to a block where EIP-155 is enabled, but this behavior caused issues +// in CL clients. func (api *BlockChainAPI) ChainId() *hexutil.Big { return (*hexutil.Big)(api.b.ChainConfig().ChainID) } From 119f9556869f829a9a2b4c12b5cd49b1a7d50d38 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 27 Jun 2022 12:33:13 +0200 Subject: [PATCH 051/715] all: remove `public` field from `rpc.API` (#25059) all: remove public field from rpc.API --- cmd/clef/main.go | 3 +-- consensus/clique/clique.go | 1 - consensus/ethash/ethash.go | 2 -- eth/backend.go | 6 ------ eth/catalyst/api.go | 1 - eth/tracers/api.go | 1 - internal/ethapi/backend.go | 7 ------- les/catalyst/api.go | 1 - les/client.go | 6 ------ les/server.go | 3 --- node/api.go | 2 -- node/rpcstack.go | 8 ++++---- node/utils_test.go | 2 -- rpc/types.go | 2 +- 14 files changed, 6 insertions(+), 39 deletions(-) diff --git a/cmd/clef/main.go b/cmd/clef/main.go index b1ffa38ffefa..1a18cd16aafb 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -647,7 +647,6 @@ func signer(c *cli.Context) error { rpcAPI := []rpc.API{ { Namespace: "account", - Public: true, Service: api, Version: "1.0"}, } @@ -656,7 +655,7 @@ func signer(c *cli.Context) error { cors := utils.SplitAndTrim(c.GlobalString(utils.HTTPCORSDomainFlag.Name)) srv := rpc.NewServer() - err := node.RegisterApis(rpcAPI, []string{"account"}, srv, false) + err := node.RegisterApis(rpcAPI, []string{"account"}, srv) if err != nil { utils.Fatalf("Could not register API: %w", err) } diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 950300f03486..f229d042652d 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -699,7 +699,6 @@ func (c *Clique) APIs(chain consensus.ChainHeaderReader) []rpc.API { Namespace: "clique", Version: "1.0", Service: &API{chain: chain, clique: c}, - Public: false, }} } diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index c196ad062170..902949202250 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -680,13 +680,11 @@ func (ethash *Ethash) APIs(chain consensus.ChainHeaderReader) []rpc.API { Namespace: "eth", Version: "1.0", Service: &API{ethash}, - Public: true, }, { Namespace: "ethash", Version: "1.0", Service: &API{ethash}, - Public: true, }, } } diff --git a/eth/backend.go b/eth/backend.go index f34aaba369cc..b4bea088f5fc 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -310,22 +310,18 @@ func (s *Ethereum) APIs() []rpc.API { Namespace: "eth", Version: "1.0", Service: NewEthereumAPI(s), - Public: true, }, { Namespace: "miner", Version: "1.0", Service: NewMinerAPI(s), - Public: true, }, { Namespace: "eth", Version: "1.0", Service: downloader.NewDownloaderAPI(s.handler.downloader, s.eventMux), - Public: true, }, { Namespace: "eth", Version: "1.0", Service: filters.NewFilterAPI(s.APIBackend, false, 5*time.Minute), - Public: true, }, { Namespace: "admin", Version: "1.0", @@ -334,12 +330,10 @@ func (s *Ethereum) APIs() []rpc.API { Namespace: "debug", Version: "1.0", Service: NewDebugAPI(s), - Public: true, }, { Namespace: "net", Version: "1.0", Service: s.netRPCService, - Public: true, }, }...) } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 0c8f0c3610ab..acc9c0e66ecb 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -44,7 +44,6 @@ func Register(stack *node.Node, backend *eth.Ethereum) error { Namespace: "engine", Version: "1.0", Service: NewConsensusAPI(backend), - Public: true, Authenticated: true, }, }) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 13b89885138e..b0f30567f025 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -920,7 +920,6 @@ func APIs(backend Backend) []rpc.API { Namespace: "debug", Version: "1.0", Service: NewAPI(backend), - Public: false, }, } } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 98006d957eb8..5119be859d49 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -103,37 +103,30 @@ func GetAPIs(apiBackend Backend) []rpc.API { Namespace: "eth", Version: "1.0", Service: NewEthereumAPI(apiBackend), - Public: true, }, { Namespace: "eth", Version: "1.0", Service: NewBlockChainAPI(apiBackend), - Public: true, }, { Namespace: "eth", Version: "1.0", Service: NewTransactionAPI(apiBackend, nonceLock), - Public: true, }, { Namespace: "txpool", Version: "1.0", Service: NewTxPoolAPI(apiBackend), - Public: true, }, { Namespace: "debug", Version: "1.0", Service: NewDebugAPI(apiBackend), - Public: true, }, { Namespace: "eth", Version: "1.0", Service: NewEthereumAccountAPI(apiBackend.AccountManager()), - Public: true, }, { Namespace: "personal", Version: "1.0", Service: NewPersonalAccountAPI(apiBackend, nonceLock), - Public: false, }, } } diff --git a/les/catalyst/api.go b/les/catalyst/api.go index de09acdb0213..12d21061354d 100644 --- a/les/catalyst/api.go +++ b/les/catalyst/api.go @@ -37,7 +37,6 @@ func Register(stack *node.Node, backend *les.LightEthereum) error { Namespace: "engine", Version: "1.0", Service: NewConsensusAPI(backend), - Public: true, Authenticated: true, }, }) diff --git a/les/client.go b/les/client.go index fa5de5450acb..97a333ab9b43 100644 --- a/les/client.go +++ b/les/client.go @@ -296,32 +296,26 @@ func (s *LightEthereum) APIs() []rpc.API { Namespace: "eth", Version: "1.0", Service: &LightDummyAPI{}, - Public: true, }, { Namespace: "eth", Version: "1.0", Service: downloader.NewDownloaderAPI(s.handler.downloader, s.eventMux), - Public: true, }, { Namespace: "eth", Version: "1.0", Service: filters.NewFilterAPI(s.ApiBackend, true, 5*time.Minute), - Public: true, }, { Namespace: "net", Version: "1.0", Service: s.netRPCService, - Public: true, }, { Namespace: "les", Version: "1.0", Service: NewLightAPI(&s.lesCommons), - Public: false, }, { Namespace: "vflux", Version: "1.0", Service: s.serverPool.API(), - Public: false, }, }...) } diff --git a/les/server.go b/les/server.go index 436dff2bf64f..894fc138367f 100644 --- a/les/server.go +++ b/les/server.go @@ -161,19 +161,16 @@ func (s *LesServer) APIs() []rpc.API { Namespace: "les", Version: "1.0", Service: NewLightAPI(&s.lesCommons), - Public: false, }, { Namespace: "les", Version: "1.0", Service: NewLightServerAPI(s), - Public: false, }, { Namespace: "debug", Version: "1.0", Service: NewDebugAPI(s), - Public: false, }, } } diff --git a/node/api.go b/node/api.go index 8d0dadc9e241..b395a345ca74 100644 --- a/node/api.go +++ b/node/api.go @@ -37,7 +37,6 @@ func (n *Node) apis() []rpc.API { Namespace: "admin", Version: "1.0", Service: &adminAPI{n}, - Public: true, }, { Namespace: "debug", Version: "1.0", @@ -46,7 +45,6 @@ func (n *Node) apis() []rpc.API { Namespace: "web3", Version: "1.0", Service: &web3API{n}, - Public: true, }, } } diff --git a/node/rpcstack.go b/node/rpcstack.go index 0d2be9008a41..09692c0a0b19 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -281,7 +281,7 @@ func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error { // Create RPC server and handler. srv := rpc.NewServer() - if err := RegisterApis(apis, config.Modules, srv, false); err != nil { + if err := RegisterApis(apis, config.Modules, srv); err != nil { return err } h.httpConfig = config @@ -312,7 +312,7 @@ func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error { } // Create RPC server and handler. srv := rpc.NewServer() - if err := RegisterApis(apis, config.Modules, srv, false); err != nil { + if err := RegisterApis(apis, config.Modules, srv); err != nil { return err } h.wsConfig = config @@ -528,7 +528,7 @@ func (is *ipcServer) stop() error { // RegisterApis checks the given modules' availability, generates an allowlist based on the allowed modules, // and then registers all of the APIs exposed by the services. -func RegisterApis(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll bool) error { +func RegisterApis(apis []rpc.API, modules []string, srv *rpc.Server) error { if bad, available := checkModuleAvailability(modules, apis); len(bad) > 0 { log.Error("Unavailable modules in HTTP API list", "unavailable", bad, "available", available) } @@ -539,7 +539,7 @@ func RegisterApis(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll b } // Register all the APIs exposed by the services for _, api := range apis { - if exposeAll || allowList[api.Namespace] || (len(allowList) == 0 && api.Public) { + if allowList[api.Namespace] || len(allowList) == 0 { if err := srv.RegisterName(api.Namespace, api.Service); err != nil { return err } diff --git a/node/utils_test.go b/node/utils_test.go index 1974e2e17cdd..31dbe911ba81 100644 --- a/node/utils_test.go +++ b/node/utils_test.go @@ -100,12 +100,10 @@ func (f *FullService) APIs() []rpc.API { { Namespace: "debug", Version: "1.0", - Public: true, }, { Namespace: "net", Version: "1.0", - Public: true, }, } } diff --git a/rpc/types.go b/rpc/types.go index f4d05be48cd4..a0d742f49142 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -33,7 +33,7 @@ type API struct { Namespace string // namespace under which the rpc methods of Service are exposed Version string // api version for DApp's Service interface{} // receiver instance which holds the methods - Public bool // indication if the methods must be considered safe for public use + Public bool // deprecated - this field is no longer used, but retained for compatibility Authenticated bool // whether the api should only be available behind authentication. } From 0c6f81f8888d1045faa29de292f37d9bbfb6b4ff Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Wed, 15 Jun 2022 10:39:07 +0200 Subject: [PATCH 052/715] all: remove version field from rpc.API --- cmd/clef/main.go | 2 +- consensus/clique/clique.go | 1 - consensus/ethash/ethash.go | 2 -- eth/backend.go | 7 ------- eth/catalyst/api.go | 1 - eth/tracers/api.go | 1 - internal/ethapi/backend.go | 7 ------- les/catalyst/api.go | 1 - les/client.go | 6 ------ les/server.go | 3 --- node/api.go | 3 --- node/utils_test.go | 3 --- p2p/simulations/adapters/exec.go | 1 - rpc/types.go | 2 +- 14 files changed, 2 insertions(+), 38 deletions(-) diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 1a18cd16aafb..850d2b82dba1 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -648,7 +648,7 @@ func signer(c *cli.Context) error { { Namespace: "account", Service: api, - Version: "1.0"}, + }, } if c.GlobalBool(utils.HTTPEnabledFlag.Name) { vhosts := utils.SplitAndTrim(c.GlobalString(utils.HTTPVirtualHostsFlag.Name)) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index f229d042652d..dcdfb20c6387 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -697,7 +697,6 @@ func (c *Clique) Close() error { func (c *Clique) APIs(chain consensus.ChainHeaderReader) []rpc.API { return []rpc.API{{ Namespace: "clique", - Version: "1.0", Service: &API{chain: chain, clique: c}, }} } diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 902949202250..0efb3590f089 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -678,12 +678,10 @@ func (ethash *Ethash) APIs(chain consensus.ChainHeaderReader) []rpc.API { return []rpc.API{ { Namespace: "eth", - Version: "1.0", Service: &API{ethash}, }, { Namespace: "ethash", - Version: "1.0", Service: &API{ethash}, }, } diff --git a/eth/backend.go b/eth/backend.go index b4bea088f5fc..b16ce4b54fa0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -308,31 +308,24 @@ func (s *Ethereum) APIs() []rpc.API { return append(apis, []rpc.API{ { Namespace: "eth", - Version: "1.0", Service: NewEthereumAPI(s), }, { Namespace: "miner", - Version: "1.0", Service: NewMinerAPI(s), }, { Namespace: "eth", - Version: "1.0", Service: downloader.NewDownloaderAPI(s.handler.downloader, s.eventMux), }, { Namespace: "eth", - Version: "1.0", Service: filters.NewFilterAPI(s.APIBackend, false, 5*time.Minute), }, { Namespace: "admin", - Version: "1.0", Service: NewAdminAPI(s), }, { Namespace: "debug", - Version: "1.0", Service: NewDebugAPI(s), }, { Namespace: "net", - Version: "1.0", Service: s.netRPCService, }, }...) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index acc9c0e66ecb..552d5d1d8171 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -42,7 +42,6 @@ func Register(stack *node.Node, backend *eth.Ethereum) error { stack.RegisterAPIs([]rpc.API{ { Namespace: "engine", - Version: "1.0", Service: NewConsensusAPI(backend), Authenticated: true, }, diff --git a/eth/tracers/api.go b/eth/tracers/api.go index b0f30567f025..4041b1770777 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -918,7 +918,6 @@ func APIs(backend Backend) []rpc.API { return []rpc.API{ { Namespace: "debug", - Version: "1.0", Service: NewAPI(backend), }, } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 5119be859d49..d13547f234a3 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -101,31 +101,24 @@ func GetAPIs(apiBackend Backend) []rpc.API { return []rpc.API{ { Namespace: "eth", - Version: "1.0", Service: NewEthereumAPI(apiBackend), }, { Namespace: "eth", - Version: "1.0", Service: NewBlockChainAPI(apiBackend), }, { Namespace: "eth", - Version: "1.0", Service: NewTransactionAPI(apiBackend, nonceLock), }, { Namespace: "txpool", - Version: "1.0", Service: NewTxPoolAPI(apiBackend), }, { Namespace: "debug", - Version: "1.0", Service: NewDebugAPI(apiBackend), }, { Namespace: "eth", - Version: "1.0", Service: NewEthereumAccountAPI(apiBackend.AccountManager()), }, { Namespace: "personal", - Version: "1.0", Service: NewPersonalAccountAPI(apiBackend, nonceLock), }, } diff --git a/les/catalyst/api.go b/les/catalyst/api.go index 12d21061354d..9c2d17c79b1a 100644 --- a/les/catalyst/api.go +++ b/les/catalyst/api.go @@ -35,7 +35,6 @@ func Register(stack *node.Node, backend *les.LightEthereum) error { stack.RegisterAPIs([]rpc.API{ { Namespace: "engine", - Version: "1.0", Service: NewConsensusAPI(backend), Authenticated: true, }, diff --git a/les/client.go b/les/client.go index 97a333ab9b43..44eaffec2373 100644 --- a/les/client.go +++ b/les/client.go @@ -294,27 +294,21 @@ func (s *LightEthereum) APIs() []rpc.API { return append(apis, []rpc.API{ { Namespace: "eth", - Version: "1.0", Service: &LightDummyAPI{}, }, { Namespace: "eth", - Version: "1.0", Service: downloader.NewDownloaderAPI(s.handler.downloader, s.eventMux), }, { Namespace: "eth", - Version: "1.0", Service: filters.NewFilterAPI(s.ApiBackend, true, 5*time.Minute), }, { Namespace: "net", - Version: "1.0", Service: s.netRPCService, }, { Namespace: "les", - Version: "1.0", Service: NewLightAPI(&s.lesCommons), }, { Namespace: "vflux", - Version: "1.0", Service: s.serverPool.API(), }, }...) diff --git a/les/server.go b/les/server.go index 894fc138367f..df453b4819a2 100644 --- a/les/server.go +++ b/les/server.go @@ -159,17 +159,14 @@ func (s *LesServer) APIs() []rpc.API { return []rpc.API{ { Namespace: "les", - Version: "1.0", Service: NewLightAPI(&s.lesCommons), }, { Namespace: "les", - Version: "1.0", Service: NewLightServerAPI(s), }, { Namespace: "debug", - Version: "1.0", Service: NewDebugAPI(s), }, } diff --git a/node/api.go b/node/api.go index b395a345ca74..67953a812e9d 100644 --- a/node/api.go +++ b/node/api.go @@ -35,15 +35,12 @@ func (n *Node) apis() []rpc.API { return []rpc.API{ { Namespace: "admin", - Version: "1.0", Service: &adminAPI{n}, }, { Namespace: "debug", - Version: "1.0", Service: debug.Handler, }, { Namespace: "web3", - Version: "1.0", Service: &web3API{n}, }, } diff --git a/node/utils_test.go b/node/utils_test.go index 31dbe911ba81..681f3a8b285c 100644 --- a/node/utils_test.go +++ b/node/utils_test.go @@ -95,15 +95,12 @@ func (f *FullService) APIs() []rpc.API { return []rpc.API{ { Namespace: "admin", - Version: "1.0", }, { Namespace: "debug", - Version: "1.0", }, { Namespace: "net", - Version: "1.0", }, } } diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go index 35ccdfb06882..7bfa8aab6d10 100644 --- a/p2p/simulations/adapters/exec.go +++ b/p2p/simulations/adapters/exec.go @@ -501,7 +501,6 @@ func startExecNodeStack() (*node.Node, error) { // Add the snapshot API. stack.RegisterAPIs([]rpc.API{{ Namespace: "simulation", - Version: "1.0", Service: SnapshotAPI{services}, }}) diff --git a/rpc/types.go b/rpc/types.go index a0d742f49142..369e950aa162 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -31,7 +31,7 @@ import ( // API describes the set of methods offered over the RPC interface type API struct { Namespace string // namespace under which the rpc methods of Service are exposed - Version string // api version for DApp's + Version string // deprecated - this field is no longer used, but retained for compatibility Service interface{} // receiver instance which holds the methods Public bool // deprecated - this field is no longer used, but retained for compatibility Authenticated bool // whether the api should only be available behind authentication. From 52ed3570c483693fdd6667add7e3050520ad3ba2 Mon Sep 17 00:00:00 2001 From: "willian.eth" Date: Mon, 27 Jun 2022 18:22:36 +0200 Subject: [PATCH 053/715] cmd: migrate to urfave/cli/v2 (#24751) This change updates our urfave/cli dependency to the v2 branch of the library. There are some Go API changes in cli v2: - Flag values can now be accessed using the methods ctx.Bool, ctx.Int, ctx.String, ... regardless of whether the flag is 'local' or 'global'. - v2 has built-in support for flag categories. Our home-grown category system is removed and the categories of flags are assigned as part of the flag definition. For users, there is only one observable difference with cli v2: flags must now strictly appear before regular arguments. For example, the following command is now invalid: geth account import mykey.json --password file.txt Instead, the command must be invoked as follows: geth account import --password file.txt mykey.json --- build/ci.go | 15 +- .../ethereum/completions/bash_autocomplete | 21 + .../deb/ethereum/completions/zsh_autocomplete | 20 + cmd/abigen/main.go | 59 +- cmd/checkpoint-admin/common.go | 8 +- cmd/checkpoint-admin/exec.go | 20 +- cmd/checkpoint-admin/main.go | 27 +- cmd/checkpoint-admin/status.go | 9 +- cmd/clef/main.go | 212 +- cmd/devp2p/discv4cmd.go | 36 +- cmd/devp2p/discv5cmd.go | 16 +- cmd/devp2p/dns_cloudflare.go | 12 +- cmd/devp2p/dns_route53.go | 22 +- cmd/devp2p/dnscmd.go | 24 +- cmd/devp2p/enrcmd.go | 8 +- cmd/devp2p/keycmd.go | 16 +- cmd/devp2p/main.go | 24 +- cmd/devp2p/nodesetcmd.go | 10 +- cmd/devp2p/rlpxcmd.go | 16 +- cmd/devp2p/runtest.go | 12 +- cmd/ethkey/changepassword.go | 6 +- cmd/ethkey/generate.go | 8 +- cmd/ethkey/inspect.go | 6 +- cmd/ethkey/main.go | 9 +- cmd/ethkey/message.go | 14 +- cmd/ethkey/utils.go | 2 +- cmd/evm/compiler.go | 6 +- cmd/evm/disasm.go | 8 +- cmd/evm/internal/t8ntool/block.go | 2 +- cmd/evm/internal/t8ntool/flags.go | 54 +- cmd/evm/internal/t8ntool/transaction.go | 2 +- cmd/evm/internal/t8ntool/transition.go | 2 +- cmd/evm/internal/t8ntool/utils.go | 2 +- cmd/evm/main.go | 69 +- cmd/evm/runner.go | 63 +- cmd/evm/staterunner.go | 26 +- cmd/geth/accountcmd.go | 45 +- cmd/geth/accountcmd_test.go | 43 +- cmd/geth/chaincmd.go | 55 +- cmd/geth/config.go | 89 +- cmd/geth/consolecmd.go | 33 +- cmd/geth/dbcmd.go | 64 +- cmd/geth/les_test.go | 2 +- cmd/geth/main.go | 63 +- cmd/geth/misccmd.go | 37 +- cmd/geth/snapshot.go | 44 +- cmd/geth/usage.go | 301 --- cmd/geth/version_check.go | 2 +- cmd/p2psim/main.go | 93 +- cmd/puppeth/puppeth.go | 6 +- cmd/utils/cmd.go | 10 +- cmd/utils/customflags.go | 211 -- cmd/utils/flags.go | 2115 +++++++++-------- cmd/utils/flags_legacy.go | 25 +- go.mod | 5 +- go.sum | 11 +- internal/debug/flags.go | 153 +- internal/flags/categories.go | 43 + internal/flags/flags.go | 340 +++ .../flags/flags_test.go | 16 +- internal/flags/helpers.go | 251 +- 61 files changed, 2478 insertions(+), 2445 deletions(-) create mode 100644 build/deb/ethereum/completions/bash_autocomplete create mode 100644 build/deb/ethereum/completions/zsh_autocomplete delete mode 100644 cmd/geth/usage.go delete mode 100644 cmd/utils/customflags.go create mode 100644 internal/flags/categories.go create mode 100644 internal/flags/flags.go rename cmd/utils/customflags_test.go => internal/flags/flags_test.go (61%) diff --git a/build/ci.go b/build/ci.go index 4129168be53a..9de62edb2b4b 100644 --- a/build/ci.go +++ b/build/ci.go @@ -132,12 +132,12 @@ var ( // Note: the following Ubuntu releases have been officially deprecated on Launchpad: // wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy, hirsuite debDistroGoBoots = map[string]string{ - "trusty": "golang-1.11", // EOL: 04/2024 - "xenial": "golang-go", // EOL: 04/2026 - "bionic": "golang-go", // EOL: 04/2028 - "focal": "golang-go", // EOL: 04/2030 - "impish": "golang-go", // EOL: 07/2022 - "jammy": "golang-go", // EOL: 04/2032 + "trusty": "golang-1.11", // EOL: 04/2024 + "xenial": "golang-go", // EOL: 04/2026 + "bionic": "golang-go", // EOL: 04/2028 + "focal": "golang-go", // EOL: 04/2030 + "impish": "golang-go", // EOL: 07/2022 + "jammy": "golang-go", // EOL: 04/2032 //"kinetic": "golang-go", // EOL: 07/2023 } @@ -224,6 +224,9 @@ func doInstall(cmdline []string) { gobuild.Args = append(gobuild.Args, "-p", "1") } + // Disable CLI markdown doc generation in release builds. + gobuild.Args = append(gobuild.Args, "-tags", "urfave_cli_no_docs") + // We use -trimpath to avoid leaking local paths into the built executables. gobuild.Args = append(gobuild.Args, "-trimpath") diff --git a/build/deb/ethereum/completions/bash_autocomplete b/build/deb/ethereum/completions/bash_autocomplete new file mode 100644 index 000000000000..f0f624183bd0 --- /dev/null +++ b/build/deb/ethereum/completions/bash_autocomplete @@ -0,0 +1,21 @@ +#! /bin/bash + +: ${PROG:=$(basename ${BASH_SOURCE})} + +_cli_bash_autocomplete() { + if [[ "${COMP_WORDS[0]}" != "source" ]]; then + local cur opts base + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + if [[ "$cur" == "-"* ]]; then + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion ) + else + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion ) + fi + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi +} + +complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete $PROG +unset PROG diff --git a/build/deb/ethereum/completions/zsh_autocomplete b/build/deb/ethereum/completions/zsh_autocomplete new file mode 100644 index 000000000000..b519666f809c --- /dev/null +++ b/build/deb/ethereum/completions/zsh_autocomplete @@ -0,0 +1,20 @@ +#compdef $PROG + +_cli_zsh_autocomplete() { + local -a opts + local cur + cur=${words[-1]} + if [[ "$cur" == "-"* ]]; then + opts=("${(@f)$(${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}") + else + opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-bash-completion)}") + fi + + if [[ "${opts[1]}" != "" ]]; then + _describe 'values' opts + else + _files + fi +} + +compdef _cli_zsh_autocomplete $PROG diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 5a93f2a92294..56ebfa9e9bb9 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -30,7 +30,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( @@ -39,42 +39,44 @@ var ( gitDate = "" app *cli.App +) +var ( // Flags needed by abigen - abiFlag = cli.StringFlag{ + abiFlag = &cli.StringFlag{ Name: "abi", Usage: "Path to the Ethereum contract ABI json to bind, - for STDIN", } - binFlag = cli.StringFlag{ + binFlag = &cli.StringFlag{ Name: "bin", Usage: "Path to the Ethereum contract bytecode (generate deploy method)", } - typeFlag = cli.StringFlag{ + typeFlag = &cli.StringFlag{ Name: "type", Usage: "Struct name for the binding (default = package name)", } - jsonFlag = cli.StringFlag{ + jsonFlag = &cli.StringFlag{ Name: "combined-json", Usage: "Path to the combined-json file generated by compiler, - for STDIN", } - excFlag = cli.StringFlag{ + excFlag = &cli.StringFlag{ Name: "exc", Usage: "Comma separated types to exclude from binding", } - pkgFlag = cli.StringFlag{ + pkgFlag = &cli.StringFlag{ Name: "pkg", Usage: "Package name to generate the binding into", } - outFlag = cli.StringFlag{ + outFlag = &cli.StringFlag{ Name: "out", Usage: "Output file for the generated binding (default = stdout)", } - langFlag = cli.StringFlag{ + langFlag = &cli.StringFlag{ Name: "lang", Usage: "Destination language for the bindings (go, java, objc)", Value: "go", } - aliasFlag = cli.StringFlag{ + aliasFlag = &cli.StringFlag{ Name: "alias", Usage: "Comma separated aliases for function and event renaming, e.g. original1=alias1, original2=alias2", } @@ -82,6 +84,7 @@ var ( func init() { app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") + app.Name = "abigen" app.Flags = []cli.Flag{ abiFlag, binFlag, @@ -93,17 +96,17 @@ func init() { langFlag, aliasFlag, } - app.Action = utils.MigrateFlags(abigen) - cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate + app.Action = abigen } func abigen(c *cli.Context) error { utils.CheckExclusive(c, abiFlag, jsonFlag) // Only one source can be selected. - if c.GlobalString(pkgFlag.Name) == "" { + + if c.String(pkgFlag.Name) == "" { utils.Fatalf("No destination package specified (--pkg)") } var lang bind.Lang - switch c.GlobalString(langFlag.Name) { + switch c.String(langFlag.Name) { case "go": lang = bind.LangGo case "java": @@ -112,7 +115,7 @@ func abigen(c *cli.Context) error { lang = bind.LangObjC utils.Fatalf("Objc binding generation is uncompleted") default: - utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.GlobalString(langFlag.Name)) + utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.String(langFlag.Name)) } // If the entire solidity code was specified, build and bind based on that var ( @@ -123,13 +126,13 @@ func abigen(c *cli.Context) error { libs = make(map[string]string) aliases = make(map[string]string) ) - if c.GlobalString(abiFlag.Name) != "" { + if c.String(abiFlag.Name) != "" { // Load up the ABI, optional bytecode and type name from the parameters var ( abi []byte err error ) - input := c.GlobalString(abiFlag.Name) + input := c.String(abiFlag.Name) if input == "-" { abi, err = io.ReadAll(os.Stdin) } else { @@ -141,7 +144,7 @@ func abigen(c *cli.Context) error { abis = append(abis, string(abi)) var bin []byte - if binFile := c.GlobalString(binFlag.Name); binFile != "" { + if binFile := c.String(binFlag.Name); binFile != "" { if bin, err = os.ReadFile(binFile); err != nil { utils.Fatalf("Failed to read input bytecode: %v", err) } @@ -151,22 +154,22 @@ func abigen(c *cli.Context) error { } bins = append(bins, string(bin)) - kind := c.GlobalString(typeFlag.Name) + kind := c.String(typeFlag.Name) if kind == "" { - kind = c.GlobalString(pkgFlag.Name) + kind = c.String(pkgFlag.Name) } types = append(types, kind) } else { // Generate the list of types to exclude from binding exclude := make(map[string]bool) - for _, kind := range strings.Split(c.GlobalString(excFlag.Name), ",") { + for _, kind := range strings.Split(c.String(excFlag.Name), ",") { exclude[strings.ToLower(kind)] = true } var contracts map[string]*compiler.Contract - if c.GlobalIsSet(jsonFlag.Name) { + if c.IsSet(jsonFlag.Name) { var ( - input = c.GlobalString(jsonFlag.Name) + input = c.String(jsonFlag.Name) jsonOutput []byte err error ) @@ -207,28 +210,28 @@ func abigen(c *cli.Context) error { } } // Extract all aliases from the flags - if c.GlobalIsSet(aliasFlag.Name) { + if c.IsSet(aliasFlag.Name) { // We support multi-versions for aliasing // e.g. // foo=bar,foo2=bar2 // foo:bar,foo2:bar2 re := regexp.MustCompile(`(?:(\w+)[:=](\w+))`) - submatches := re.FindAllStringSubmatch(c.GlobalString(aliasFlag.Name), -1) + submatches := re.FindAllStringSubmatch(c.String(aliasFlag.Name), -1) for _, match := range submatches { aliases[match[1]] = match[2] } } // Generate the contract binding - code, err := bind.Bind(types, abis, bins, sigs, c.GlobalString(pkgFlag.Name), lang, libs, aliases) + code, err := bind.Bind(types, abis, bins, sigs, c.String(pkgFlag.Name), lang, libs, aliases) if err != nil { utils.Fatalf("Failed to generate ABI binding: %v", err) } // Either flush it out to a file or display on the standard output - if !c.GlobalIsSet(outFlag.Name) { + if !c.IsSet(outFlag.Name) { fmt.Printf("%s\n", code) return nil } - if err := os.WriteFile(c.GlobalString(outFlag.Name), []byte(code), 0600); err != nil { + if err := os.WriteFile(c.String(outFlag.Name), []byte(code), 0600); err != nil { utils.Fatalf("Failed to write ABI binding: %v", err) } return nil diff --git a/cmd/checkpoint-admin/common.go b/cmd/checkpoint-admin/common.go index 05a45dfbf997..f86ac24f06c1 100644 --- a/cmd/checkpoint-admin/common.go +++ b/cmd/checkpoint-admin/common.go @@ -28,12 +28,12 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) // newClient creates a client with specified remote URL. func newClient(ctx *cli.Context) *ethclient.Client { - client, err := ethclient.Dial(ctx.GlobalString(nodeURLFlag.Name)) + client, err := ethclient.Dial(ctx.String(nodeURLFlag.Name)) if err != nil { utils.Fatalf("Failed to connect to Ethereum node: %v", err) } @@ -64,9 +64,9 @@ func getContractAddr(client *rpc.Client) common.Address { func getCheckpoint(ctx *cli.Context, client *rpc.Client) *params.TrustedCheckpoint { var checkpoint *params.TrustedCheckpoint - if ctx.GlobalIsSet(indexFlag.Name) { + if ctx.IsSet(indexFlag.Name) { var result [3]string - index := uint64(ctx.GlobalInt64(indexFlag.Name)) + index := uint64(ctx.Int64(indexFlag.Name)) if err := client.Call(&result, "les_getCheckpoint", index); err != nil { utils.Fatalf("Failed to get local checkpoint %v, please ensure the les API is exposed", err) } diff --git a/cmd/checkpoint-admin/exec.go b/cmd/checkpoint-admin/exec.go index 352a96d9e6f0..cb67d0306d43 100644 --- a/cmd/checkpoint-admin/exec.go +++ b/cmd/checkpoint-admin/exec.go @@ -36,10 +36,10 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -var commandDeploy = cli.Command{ +var commandDeploy = &cli.Command{ Name: "deploy", Usage: "Deploy a new checkpoint oracle contract", Flags: []cli.Flag{ @@ -49,10 +49,10 @@ var commandDeploy = cli.Command{ signersFlag, thresholdFlag, }, - Action: utils.MigrateFlags(deploy), + Action: deploy, } -var commandSign = cli.Command{ +var commandSign = &cli.Command{ Name: "sign", Usage: "Sign the checkpoint with the specified key", Flags: []cli.Flag{ @@ -63,10 +63,10 @@ var commandSign = cli.Command{ hashFlag, oracleFlag, }, - Action: utils.MigrateFlags(sign), + Action: sign, } -var commandPublish = cli.Command{ +var commandPublish = &cli.Command{ Name: "publish", Usage: "Publish a checkpoint into the oracle", Flags: []cli.Flag{ @@ -76,7 +76,7 @@ var commandPublish = cli.Command{ indexFlag, signaturesFlag, }, - Action: utils.MigrateFlags(publish), + Action: publish, } // deploy deploys the checkpoint registrar contract. @@ -132,7 +132,7 @@ func sign(ctx *cli.Context) error { node *rpc.Client oracle *checkpointoracle.CheckpointOracle ) - if !ctx.GlobalIsSet(nodeURLFlag.Name) { + if !ctx.IsSet(nodeURLFlag.Name) { // Offline mode signing offline = true if !ctx.IsSet(hashFlag.Name) { @@ -151,7 +151,7 @@ func sign(ctx *cli.Context) error { address = common.HexToAddress(ctx.String(oracleFlag.Name)) } else { // Interactive mode signing, retrieve the data from the remote node - node = newRPCClient(ctx.GlobalString(nodeURLFlag.Name)) + node = newRPCClient(ctx.String(nodeURLFlag.Name)) checkpoint := getCheckpoint(ctx, node) chash, cindex, address = checkpoint.Hash(), checkpoint.SectionIndex, getContractAddr(node) @@ -265,7 +265,7 @@ func publish(ctx *cli.Context) error { } // Retrieve the checkpoint we want to sign to sort the signatures var ( - client = newRPCClient(ctx.GlobalString(nodeURLFlag.Name)) + client = newRPCClient(ctx.String(nodeURLFlag.Name)) addr, oracle = newContract(client) checkpoint = getCheckpoint(ctx, client) sighash = sighash(checkpoint.SectionIndex, addr, checkpoint.Hash()) diff --git a/cmd/checkpoint-admin/main.go b/cmd/checkpoint-admin/main.go index 0fb553214778..0604ccaad622 100644 --- a/cmd/checkpoint-admin/main.go +++ b/cmd/checkpoint-admin/main.go @@ -25,20 +25,20 @@ import ( "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( // Git SHA1 commit hash of the release (set via linker flags) gitCommit = "" gitDate = "" -) -var app *cli.App + app *cli.App +) func init() { app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") - app.Commands = []cli.Command{ + app.Commands = []*cli.Command{ commandStatus, commandDeploy, commandSign, @@ -48,46 +48,45 @@ func init() { oracleFlag, nodeURLFlag, } - cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate } // Commonly used command line flags. var ( - indexFlag = cli.Int64Flag{ + indexFlag = &cli.Int64Flag{ Name: "index", Usage: "Checkpoint index (query latest from remote node if not specified)", } - hashFlag = cli.StringFlag{ + hashFlag = &cli.StringFlag{ Name: "hash", Usage: "Checkpoint hash (query latest from remote node if not specified)", } - oracleFlag = cli.StringFlag{ + oracleFlag = &cli.StringFlag{ Name: "oracle", Usage: "Checkpoint oracle address (query from remote node if not specified)", } - thresholdFlag = cli.Int64Flag{ + thresholdFlag = &cli.Int64Flag{ Name: "threshold", Usage: "Minimal number of signatures required to approve a checkpoint", } - nodeURLFlag = cli.StringFlag{ + nodeURLFlag = &cli.StringFlag{ Name: "rpc", Value: "http://localhost:8545", Usage: "The rpc endpoint of a local or remote geth node", } - clefURLFlag = cli.StringFlag{ + clefURLFlag = &cli.StringFlag{ Name: "clef", Value: "http://localhost:8550", Usage: "The rpc endpoint of clef", } - signerFlag = cli.StringFlag{ + signerFlag = &cli.StringFlag{ Name: "signer", Usage: "Signer address for clef signing", } - signersFlag = cli.StringFlag{ + signersFlag = &cli.StringFlag{ Name: "signers", Usage: "Comma separated accounts of trusted checkpoint signers", } - signaturesFlag = cli.StringFlag{ + signaturesFlag = &cli.StringFlag{ Name: "signatures", Usage: "Comma separated checkpoint signatures to submit", } diff --git a/cmd/checkpoint-admin/status.go b/cmd/checkpoint-admin/status.go index f613501eb35d..bec97aed12bd 100644 --- a/cmd/checkpoint-admin/status.go +++ b/cmd/checkpoint-admin/status.go @@ -19,24 +19,23 @@ package main import ( "fmt" - "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -var commandStatus = cli.Command{ +var commandStatus = &cli.Command{ Name: "status", Usage: "Fetches the signers and checkpoint status of the oracle contract", Flags: []cli.Flag{ nodeURLFlag, }, - Action: utils.MigrateFlags(status), + Action: status, } // status fetches the admin list of specified registrar contract. func status(ctx *cli.Context) error { // Create a wrapper around the checkpoint oracle contract - addr, oracle := newContract(newRPCClient(ctx.GlobalString(nodeURLFlag.Name))) + addr, oracle := newContract(newRPCClient(ctx.String(nodeURLFlag.Name))) fmt.Printf("Oracle => %s\n", addr.Hex()) fmt.Println() diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 1a18cd16aafb..7a3413811f80 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -30,7 +30,6 @@ import ( "os/signal" "path/filepath" "runtime" - "sort" "strings" "time" @@ -55,7 +54,7 @@ import ( "github.com/ethereum/go-ethereum/signer/storage" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) const legalWarning = ` @@ -73,70 +72,70 @@ PURPOSE. See the GNU General Public License for more details. ` var ( - logLevelFlag = cli.IntFlag{ + logLevelFlag = &cli.IntFlag{ Name: "loglevel", Value: 4, Usage: "log level to emit to the screen", } - advancedMode = cli.BoolFlag{ + advancedMode = &cli.BoolFlag{ Name: "advanced", Usage: "If enabled, issues warnings instead of rejections for suspicious requests. Default off", } - acceptFlag = cli.BoolFlag{ + acceptFlag = &cli.BoolFlag{ Name: "suppress-bootwarn", Usage: "If set, does not show the warning during boot", } - keystoreFlag = cli.StringFlag{ + keystoreFlag = &cli.StringFlag{ Name: "keystore", Value: filepath.Join(node.DefaultDataDir(), "keystore"), Usage: "Directory for the keystore", } - configdirFlag = cli.StringFlag{ + configdirFlag = &cli.StringFlag{ Name: "configdir", Value: DefaultConfigDir(), Usage: "Directory for Clef configuration", } - chainIdFlag = cli.Int64Flag{ + chainIdFlag = &cli.Int64Flag{ Name: "chainid", Value: params.MainnetChainConfig.ChainID.Int64(), Usage: "Chain id to use for signing (1=mainnet, 3=Ropsten, 4=Rinkeby, 5=Goerli)", } - rpcPortFlag = cli.IntFlag{ - Name: "http.port", - Usage: "HTTP-RPC server listening port", - Value: node.DefaultHTTPPort + 5, + rpcPortFlag = &cli.IntFlag{ + Name: "http.port", + Usage: "HTTP-RPC server listening port", + Value: node.DefaultHTTPPort + 5, + Category: flags.APICategory, } - signerSecretFlag = cli.StringFlag{ + signerSecretFlag = &cli.StringFlag{ Name: "signersecret", Usage: "A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash", } - customDBFlag = cli.StringFlag{ + customDBFlag = &cli.StringFlag{ Name: "4bytedb-custom", Usage: "File used for writing new 4byte-identifiers submitted via API", Value: "./4byte-custom.json", } - auditLogFlag = cli.StringFlag{ + auditLogFlag = &cli.StringFlag{ Name: "auditlog", Usage: "File used to emit audit logs. Set to \"\" to disable", Value: "audit.log", } - ruleFlag = cli.StringFlag{ + ruleFlag = &cli.StringFlag{ Name: "rules", Usage: "Path to the rule file to auto-authorize requests with", } - stdiouiFlag = cli.BoolFlag{ + stdiouiFlag = &cli.BoolFlag{ Name: "stdio-ui", Usage: "Use STDIN/STDOUT as a channel for an external UI. " + "This means that an STDIN/STDOUT is used for RPC-communication with a e.g. a graphical user " + "interface, and can be used when Clef is started by an external process.", } - testFlag = cli.BoolFlag{ + testFlag = &cli.BoolFlag{ Name: "stdio-ui-test", Usage: "Mechanism to test interface between Clef and UI. Requires 'stdio-ui'.", } - app = cli.NewApp() - initCommand = cli.Command{ - Action: utils.MigrateFlags(initializeSecrets), + initCommand = &cli.Command{ + Action: initializeSecrets, Name: "init", Usage: "Initialize the signer, generate secret storage", ArgsUsage: "", @@ -148,8 +147,8 @@ var ( The init command generates a master seed which Clef can use to store credentials and data needed for the rule-engine to work.`, } - attestCommand = cli.Command{ - Action: utils.MigrateFlags(attestFile), + attestCommand = &cli.Command{ + Action: attestFile, Name: "attest", Usage: "Attest that a js-file is to be used", ArgsUsage: "", @@ -165,8 +164,8 @@ incoming requests. Whenever you make an edit to the rule file, you need to use attestation to tell Clef that the file is 'safe' to execute.`, } - setCredentialCommand = cli.Command{ - Action: utils.MigrateFlags(setCredential), + setCredentialCommand = &cli.Command{ + Action: setCredential, Name: "setpw", Usage: "Store a credential for a keystore file", ArgsUsage: "
", @@ -178,8 +177,8 @@ Clef that the file is 'safe' to execute.`, Description: ` The setpw command stores a password for a given address (keyfile). `} - delCredentialCommand = cli.Command{ - Action: utils.MigrateFlags(removeCredential), + delCredentialCommand = &cli.Command{ + Action: removeCredential, Name: "delpw", Usage: "Remove a credential for a keystore file", ArgsUsage: "
", @@ -191,8 +190,8 @@ The setpw command stores a password for a given address (keyfile). Description: ` The delpw command removes a password for a given address (keyfile). `} - newAccountCommand = cli.Command{ - Action: utils.MigrateFlags(newAccount), + newAccountCommand = &cli.Command{ + Action: newAccount, Name: "newaccount", Usage: "Create a new account", ArgsUsage: "", @@ -207,7 +206,7 @@ The newaccount command creates a new keystore-backed account. It is a convenienc which can be used in lieu of an external UI.`, } - gendocCommand = cli.Command{ + gendocCommand = &cli.Command{ Action: GenDoc, Name: "gendoc", Usage: "Generate documentation about json-rpc format", @@ -216,39 +215,16 @@ The gendoc generates example structures of the json-rpc communication types. `} ) -// AppHelpFlagGroups is the application flags, grouped by functionality. -var AppHelpFlagGroups = []flags.FlagGroup{ - { - Name: "FLAGS", - Flags: []cli.Flag{ - logLevelFlag, - keystoreFlag, - configdirFlag, - chainIdFlag, - utils.LightKDFFlag, - utils.NoUSBFlag, - utils.SmartCardDaemonPathFlag, - utils.HTTPListenAddrFlag, - utils.HTTPVirtualHostsFlag, - utils.IPCDisabledFlag, - utils.IPCPathFlag, - utils.HTTPEnabledFlag, - rpcPortFlag, - signerSecretFlag, - customDBFlag, - auditLogFlag, - ruleFlag, - stdiouiFlag, - testFlag, - advancedMode, - acceptFlag, - }, - }, -} +var ( + // Git SHA1 commit hash of the release (set via linker flags) + gitCommit = "" + gitDate = "" + + app = flags.NewApp(gitCommit, gitDate, "Manage Ethereum account operations") +) func init() { app.Name = "Clef" - app.Usage = "Manage Ethereum account operations" app.Flags = []cli.Flag{ logLevelFlag, keystoreFlag, @@ -273,46 +249,12 @@ func init() { acceptFlag, } app.Action = signer - app.Commands = []cli.Command{initCommand, + app.Commands = []*cli.Command{initCommand, attestCommand, setCredentialCommand, delCredentialCommand, newAccountCommand, - gendocCommand} - cli.CommandHelpTemplate = flags.CommandHelpTemplate - // Override the default app help template - cli.AppHelpTemplate = flags.ClefAppHelpTemplate - - // Override the default app help printer, but only for the global app help - originalHelpPrinter := cli.HelpPrinter - cli.HelpPrinter = func(w io.Writer, tmpl string, data interface{}) { - if tmpl == flags.ClefAppHelpTemplate { - // Render out custom usage screen - originalHelpPrinter(w, tmpl, flags.HelpData{App: data, FlagGroups: AppHelpFlagGroups}) - } else if tmpl == flags.CommandHelpTemplate { - // Iterate over all command specific flags and categorize them - categorized := make(map[string][]cli.Flag) - for _, flag := range data.(cli.Command).Flags { - if _, ok := categorized[flag.String()]; !ok { - categorized[flags.FlagCategory(flag, AppHelpFlagGroups)] = append(categorized[flags.FlagCategory(flag, AppHelpFlagGroups)], flag) - } - } - - // sort to get a stable ordering - sorted := make([]flags.FlagGroup, 0, len(categorized)) - for cat, flgs := range categorized { - sorted = append(sorted, flags.FlagGroup{Name: cat, Flags: flgs}) - } - sort.Sort(flags.ByCategory(sorted)) - - // add sorted array to data and render with default printer - originalHelpPrinter(w, tmpl, map[string]interface{}{ - "cmd": data, - "categorizedFlags": sorted, - }) - } else { - originalHelpPrinter(w, tmpl, data) - } + gendocCommand, } } @@ -329,7 +271,7 @@ func initializeSecrets(c *cli.Context) error { return err } // Ensure the master key does not yet exist, we're not willing to overwrite - configDir := c.GlobalString(configdirFlag.Name) + configDir := c.String(configdirFlag.Name) if err := os.Mkdir(configDir, 0700); err != nil && !os.IsExist(err) { return err } @@ -347,7 +289,7 @@ func initializeSecrets(c *cli.Context) error { return fmt.Errorf("failed to read enough random") } n, p := keystore.StandardScryptN, keystore.StandardScryptP - if c.GlobalBool(utils.LightKDFFlag.Name) { + if c.Bool(utils.LightKDFFlag.Name) { n, p = keystore.LightScryptN, keystore.LightScryptP } text := "The master seed of clef will be locked with a password.\nPlease specify a password. Do not forget this password!" @@ -390,8 +332,9 @@ You should treat 'masterseed.json' with utmost secrecy and make a backup of it! `) return nil } + func attestFile(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { + if ctx.NArg() < 1 { utils.Fatalf("This command requires an argument.") } if err := initialize(ctx); err != nil { @@ -402,7 +345,7 @@ func attestFile(ctx *cli.Context) error { if err != nil { utils.Fatalf(err.Error()) } - configDir := ctx.GlobalString(configdirFlag.Name) + configDir := ctx.String(configdirFlag.Name) vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10])) confKey := crypto.Keccak256([]byte("config"), stretchedKey) @@ -415,7 +358,7 @@ func attestFile(ctx *cli.Context) error { } func setCredential(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { + if ctx.NArg() < 1 { utils.Fatalf("This command requires an address to be passed as an argument") } if err := initialize(ctx); err != nil { @@ -433,7 +376,7 @@ func setCredential(ctx *cli.Context) error { if err != nil { utils.Fatalf(err.Error()) } - configDir := ctx.GlobalString(configdirFlag.Name) + configDir := ctx.String(configdirFlag.Name) vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10])) pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey) @@ -445,7 +388,7 @@ func setCredential(ctx *cli.Context) error { } func removeCredential(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { + if ctx.NArg() < 1 { utils.Fatalf("This command requires an address to be passed as an argument") } if err := initialize(ctx); err != nil { @@ -461,7 +404,7 @@ func removeCredential(ctx *cli.Context) error { if err != nil { utils.Fatalf(err.Error()) } - configDir := ctx.GlobalString(configdirFlag.Name) + configDir := ctx.String(configdirFlag.Name) vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10])) pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey) @@ -481,8 +424,8 @@ func newAccount(c *cli.Context) error { var ( ui = core.NewCommandlineUI() pwStorage storage.Storage = &storage.NoStorage{} - ksLoc = c.GlobalString(keystoreFlag.Name) - lightKdf = c.GlobalBool(utils.LightKDFFlag.Name) + ksLoc = c.String(keystoreFlag.Name) + lightKdf = c.Bool(utils.LightKDFFlag.Name) ) log.Info("Starting clef", "keystore", ksLoc, "light-kdf", lightKdf) am := core.StartClefAccountManager(ksLoc, true, lightKdf, "") @@ -500,13 +443,13 @@ func newAccount(c *cli.Context) error { func initialize(c *cli.Context) error { // Set up the logger to print everything logOutput := os.Stdout - if c.GlobalBool(stdiouiFlag.Name) { + if c.Bool(stdiouiFlag.Name) { logOutput = os.Stderr // If using the stdioui, we can't do the 'confirm'-flow - if !c.GlobalBool(acceptFlag.Name) { + if !c.Bool(acceptFlag.Name) { fmt.Fprint(logOutput, legalWarning) } - } else if !c.GlobalBool(acceptFlag.Name) { + } else if !c.Bool(acceptFlag.Name) { if !confirm(legalWarning) { return fmt.Errorf("aborted by user") } @@ -545,8 +488,8 @@ func ipcEndpoint(ipcPath, datadir string) string { func signer(c *cli.Context) error { // If we have some unrecognized command, bail out - if args := c.Args(); len(args) > 0 { - return fmt.Errorf("invalid command: %q", args[0]) + if c.NArg() > 0 { + return fmt.Errorf("invalid command: %q", c.Args().First()) } if err := initialize(c); err != nil { return err @@ -554,7 +497,7 @@ func signer(c *cli.Context) error { var ( ui core.UIClientAPI ) - if c.GlobalBool(stdiouiFlag.Name) { + if c.Bool(stdiouiFlag.Name) { log.Info("Using stdin/stdout as UI-channel") ui = core.NewStdIOUI() } else { @@ -562,7 +505,7 @@ func signer(c *cli.Context) error { ui = core.NewCommandlineUI() } // 4bytedb data - fourByteLocal := c.GlobalString(customDBFlag.Name) + fourByteLocal := c.String(customDBFlag.Name) db, err := fourbyte.NewWithFile(fourByteLocal) if err != nil { utils.Fatalf(err.Error()) @@ -574,7 +517,7 @@ func signer(c *cli.Context) error { api core.ExternalAPI pwStorage storage.Storage = &storage.NoStorage{} ) - configDir := c.GlobalString(configdirFlag.Name) + configDir := c.String(configdirFlag.Name) if stretchedKey, err := readMasterKey(c, ui); err != nil { log.Warn("Failed to open master, rules disabled", "err", err) } else { @@ -591,7 +534,7 @@ func signer(c *cli.Context) error { configStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "config.json"), confkey) // Do we have a rule-file? - if ruleFile := c.GlobalString(ruleFlag.Name); ruleFile != "" { + if ruleFile := c.String(ruleFlag.Name); ruleFile != "" { ruleJS, err := os.ReadFile(ruleFile) if err != nil { log.Warn("Could not load rules, disabling", "file", ruleFile, "err", err) @@ -615,12 +558,12 @@ func signer(c *cli.Context) error { } } var ( - chainId = c.GlobalInt64(chainIdFlag.Name) - ksLoc = c.GlobalString(keystoreFlag.Name) - lightKdf = c.GlobalBool(utils.LightKDFFlag.Name) - advanced = c.GlobalBool(advancedMode.Name) - nousb = c.GlobalBool(utils.NoUSBFlag.Name) - scpath = c.GlobalString(utils.SmartCardDaemonPathFlag.Name) + chainId = c.Int64(chainIdFlag.Name) + ksLoc = c.String(keystoreFlag.Name) + lightKdf = c.Bool(utils.LightKDFFlag.Name) + advanced = c.Bool(advancedMode.Name) + nousb = c.Bool(utils.NoUSBFlag.Name) + scpath = c.String(utils.SmartCardDaemonPathFlag.Name) ) log.Info("Starting signer", "chainid", chainId, "keystore", ksLoc, "light-kdf", lightKdf, "advanced", advanced) @@ -632,7 +575,7 @@ func signer(c *cli.Context) error { ui.RegisterUIServer(core.NewUIServerAPI(apiImpl)) api = apiImpl // Audit logging - if logfile := c.GlobalString(auditLogFlag.Name); logfile != "" { + if logfile := c.String(auditLogFlag.Name); logfile != "" { api, err = core.NewAuditLogger(logfile, api) if err != nil { utils.Fatalf(err.Error()) @@ -650,9 +593,9 @@ func signer(c *cli.Context) error { Service: api, Version: "1.0"}, } - if c.GlobalBool(utils.HTTPEnabledFlag.Name) { - vhosts := utils.SplitAndTrim(c.GlobalString(utils.HTTPVirtualHostsFlag.Name)) - cors := utils.SplitAndTrim(c.GlobalString(utils.HTTPCORSDomainFlag.Name)) + if c.Bool(utils.HTTPEnabledFlag.Name) { + vhosts := utils.SplitAndTrim(c.String(utils.HTTPVirtualHostsFlag.Name)) + cors := utils.SplitAndTrim(c.String(utils.HTTPCORSDomainFlag.Name)) srv := rpc.NewServer() err := node.RegisterApis(rpcAPI, []string{"account"}, srv) @@ -665,7 +608,7 @@ func signer(c *cli.Context) error { port := c.Int(rpcPortFlag.Name) // start http server - httpEndpoint := fmt.Sprintf("%s:%d", c.GlobalString(utils.HTTPListenAddrFlag.Name), port) + httpEndpoint := fmt.Sprintf("%s:%d", c.String(utils.HTTPListenAddrFlag.Name), port) httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler) if err != nil { utils.Fatalf("Could not start RPC api: %v", err) @@ -679,8 +622,8 @@ func signer(c *cli.Context) error { log.Info("HTTP endpoint closed", "url", extapiURL) }() } - if !c.GlobalBool(utils.IPCDisabledFlag.Name) { - givenPath := c.GlobalString(utils.IPCPathFlag.Name) + if !c.Bool(utils.IPCDisabledFlag.Name) { + givenPath := c.String(utils.IPCPathFlag.Name) ipcapiURL = ipcEndpoint(filepath.Join(givenPath, "clef.ipc"), configDir) listener, _, err := rpc.StartIPCEndpoint(ipcapiURL, rpcAPI) if err != nil { @@ -693,7 +636,7 @@ func signer(c *cli.Context) error { }() } - if c.GlobalBool(testFlag.Name) { + if c.Bool(testFlag.Name) { log.Info("Performing UI test") go testExternalUI(apiImpl) } @@ -719,7 +662,7 @@ func signer(c *cli.Context) error { // persistence requirements. func DefaultConfigDir() string { // Try to place the data folder in the user's home dir - home := utils.HomeDir() + home := flags.HomeDir() if home != "" { if runtime.GOOS == "darwin" { return filepath.Join(home, "Library", "Signer") @@ -739,10 +682,10 @@ func DefaultConfigDir() string { func readMasterKey(ctx *cli.Context, ui core.UIClientAPI) ([]byte, error) { var ( file string - configDir = ctx.GlobalString(configdirFlag.Name) + configDir = ctx.String(configdirFlag.Name) ) - if ctx.GlobalIsSet(signerSecretFlag.Name) { - file = ctx.GlobalString(signerSecretFlag.Name) + if ctx.IsSet(signerSecretFlag.Name) { + file = ctx.String(signerSecretFlag.Name) } else { file = filepath.Join(configDir, "masterseed.json") } @@ -995,7 +938,7 @@ func decryptSeed(keyjson []byte, auth string) ([]byte, error) { } // GenDoc outputs examples of all structures used in json-rpc communication -func GenDoc(ctx *cli.Context) { +func GenDoc(ctx *cli.Context) error { var ( a = common.HexToAddress("0xdeadbeef000000000000000000000000deadbeef") @@ -1145,4 +1088,5 @@ These data types are defined in the channel between clef and the UI`) for _, elem := range output { fmt.Println(elem) } + return nil } diff --git a/cmd/devp2p/discv4cmd.go b/cmd/devp2p/discv4cmd.go index 3b6dc09a1cc8..892a02b6591e 100644 --- a/cmd/devp2p/discv4cmd.go +++ b/cmd/devp2p/discv4cmd.go @@ -28,14 +28,14 @@ import ( "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - discv4Command = cli.Command{ + discv4Command = &cli.Command{ Name: "discv4", Usage: "Node Discovery v4 tools", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ discv4PingCommand, discv4RequestRecordCommand, discv4ResolveCommand, @@ -44,39 +44,39 @@ var ( discv4TestCommand, }, } - discv4PingCommand = cli.Command{ + discv4PingCommand = &cli.Command{ Name: "ping", Usage: "Sends ping to a node", Action: discv4Ping, ArgsUsage: "", } - discv4RequestRecordCommand = cli.Command{ + discv4RequestRecordCommand = &cli.Command{ Name: "requestenr", Usage: "Requests a node record using EIP-868 enrRequest", Action: discv4RequestRecord, ArgsUsage: "", } - discv4ResolveCommand = cli.Command{ + discv4ResolveCommand = &cli.Command{ Name: "resolve", Usage: "Finds a node in the DHT", Action: discv4Resolve, ArgsUsage: "", Flags: []cli.Flag{bootnodesFlag}, } - discv4ResolveJSONCommand = cli.Command{ + discv4ResolveJSONCommand = &cli.Command{ Name: "resolve-json", Usage: "Re-resolves nodes in a nodes.json file", Action: discv4ResolveJSON, Flags: []cli.Flag{bootnodesFlag}, ArgsUsage: "", } - discv4CrawlCommand = cli.Command{ + discv4CrawlCommand = &cli.Command{ Name: "crawl", Usage: "Updates a nodes.json file with random nodes found in the DHT", Action: discv4Crawl, Flags: []cli.Flag{bootnodesFlag, crawlTimeoutFlag}, } - discv4TestCommand = cli.Command{ + discv4TestCommand = &cli.Command{ Name: "test", Usage: "Runs tests against a node", Action: discv4Test, @@ -91,31 +91,31 @@ var ( ) var ( - bootnodesFlag = cli.StringFlag{ + bootnodesFlag = &cli.StringFlag{ Name: "bootnodes", Usage: "Comma separated nodes used for bootstrapping", } - nodekeyFlag = cli.StringFlag{ + nodekeyFlag = &cli.StringFlag{ Name: "nodekey", Usage: "Hex-encoded node key", } - nodedbFlag = cli.StringFlag{ + nodedbFlag = &cli.StringFlag{ Name: "nodedb", Usage: "Nodes database location", } - listenAddrFlag = cli.StringFlag{ + listenAddrFlag = &cli.StringFlag{ Name: "addr", Usage: "Listening address", } - crawlTimeoutFlag = cli.DurationFlag{ + crawlTimeoutFlag = &cli.DurationFlag{ Name: "timeout", Usage: "Time limit for the crawl.", Value: 30 * time.Minute, } - remoteEnodeFlag = cli.StringFlag{ - Name: "remote", - Usage: "Enode of the remote node under test", - EnvVar: "REMOTE_ENODE", + remoteEnodeFlag = &cli.StringFlag{ + Name: "remote", + Usage: "Enode of the remote node under test", + EnvVars: []string{"REMOTE_ENODE"}, } ) diff --git a/cmd/devp2p/discv5cmd.go b/cmd/devp2p/discv5cmd.go index 873d41e7030c..298196034b58 100644 --- a/cmd/devp2p/discv5cmd.go +++ b/cmd/devp2p/discv5cmd.go @@ -23,14 +23,14 @@ import ( "github.com/ethereum/go-ethereum/cmd/devp2p/internal/v5test" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/p2p/discover" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - discv5Command = cli.Command{ + discv5Command = &cli.Command{ Name: "discv5", Usage: "Node Discovery v5 tools", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ discv5PingCommand, discv5ResolveCommand, discv5CrawlCommand, @@ -38,24 +38,24 @@ var ( discv5ListenCommand, }, } - discv5PingCommand = cli.Command{ + discv5PingCommand = &cli.Command{ Name: "ping", Usage: "Sends ping to a node", Action: discv5Ping, } - discv5ResolveCommand = cli.Command{ + discv5ResolveCommand = &cli.Command{ Name: "resolve", Usage: "Finds a node in the DHT", Action: discv5Resolve, Flags: []cli.Flag{bootnodesFlag}, } - discv5CrawlCommand = cli.Command{ + discv5CrawlCommand = &cli.Command{ Name: "crawl", Usage: "Updates a nodes.json file with random nodes found in the DHT", Action: discv5Crawl, Flags: []cli.Flag{bootnodesFlag, crawlTimeoutFlag}, } - discv5TestCommand = cli.Command{ + discv5TestCommand = &cli.Command{ Name: "test", Usage: "Runs protocol tests against a node", Action: discv5Test, @@ -66,7 +66,7 @@ var ( testListen2Flag, }, } - discv5ListenCommand = cli.Command{ + discv5ListenCommand = &cli.Command{ Name: "listen", Usage: "Runs a node", Action: discv5Listen, diff --git a/cmd/devp2p/dns_cloudflare.go b/cmd/devp2p/dns_cloudflare.go index d67aaea1a7fb..73ecc13bc32d 100644 --- a/cmd/devp2p/dns_cloudflare.go +++ b/cmd/devp2p/dns_cloudflare.go @@ -24,16 +24,16 @@ import ( "github.com/cloudflare/cloudflare-go" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/dnsdisc" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - cloudflareTokenFlag = cli.StringFlag{ - Name: "token", - Usage: "CloudFlare API token", - EnvVar: "CLOUDFLARE_API_TOKEN", + cloudflareTokenFlag = &cli.StringFlag{ + Name: "token", + Usage: "CloudFlare API token", + EnvVars: []string{"CLOUDFLARE_API_TOKEN"}, } - cloudflareZoneIDFlag = cli.StringFlag{ + cloudflareZoneIDFlag = &cli.StringFlag{ Name: "zoneid", Usage: "CloudFlare Zone ID (optional)", } diff --git a/cmd/devp2p/dns_route53.go b/cmd/devp2p/dns_route53.go index 1d4f975dda0b..4aab0856ff90 100644 --- a/cmd/devp2p/dns_route53.go +++ b/cmd/devp2p/dns_route53.go @@ -32,7 +32,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/route53/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/dnsdisc" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) const ( @@ -45,21 +45,21 @@ const ( ) var ( - route53AccessKeyFlag = cli.StringFlag{ - Name: "access-key-id", - Usage: "AWS Access Key ID", - EnvVar: "AWS_ACCESS_KEY_ID", + route53AccessKeyFlag = &cli.StringFlag{ + Name: "access-key-id", + Usage: "AWS Access Key ID", + EnvVars: []string{"AWS_ACCESS_KEY_ID"}, } - route53AccessSecretFlag = cli.StringFlag{ - Name: "access-key-secret", - Usage: "AWS Access Key Secret", - EnvVar: "AWS_SECRET_ACCESS_KEY", + route53AccessSecretFlag = &cli.StringFlag{ + Name: "access-key-secret", + Usage: "AWS Access Key Secret", + EnvVars: []string{"AWS_SECRET_ACCESS_KEY"}, } - route53ZoneIDFlag = cli.StringFlag{ + route53ZoneIDFlag = &cli.StringFlag{ Name: "zone-id", Usage: "Route53 Zone ID", } - route53RegionFlag = cli.StringFlag{ + route53RegionFlag = &cli.StringFlag{ Name: "aws-region", Usage: "AWS Region", Value: "eu-central-1", diff --git a/cmd/devp2p/dnscmd.go b/cmd/devp2p/dnscmd.go index 21138efdc5cc..58eb6e8db1c1 100644 --- a/cmd/devp2p/dnscmd.go +++ b/cmd/devp2p/dnscmd.go @@ -29,14 +29,14 @@ import ( "github.com/ethereum/go-ethereum/console/prompt" "github.com/ethereum/go-ethereum/p2p/dnsdisc" "github.com/ethereum/go-ethereum/p2p/enode" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - dnsCommand = cli.Command{ + dnsCommand = &cli.Command{ Name: "dns", Usage: "DNS Discovery Commands", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ dnsSyncCommand, dnsSignCommand, dnsTXTCommand, @@ -45,34 +45,34 @@ var ( dnsRoute53NukeCommand, }, } - dnsSyncCommand = cli.Command{ + dnsSyncCommand = &cli.Command{ Name: "sync", Usage: "Download a DNS discovery tree", ArgsUsage: " [ ]", Action: dnsSync, Flags: []cli.Flag{dnsTimeoutFlag}, } - dnsSignCommand = cli.Command{ + dnsSignCommand = &cli.Command{ Name: "sign", Usage: "Sign a DNS discovery tree", ArgsUsage: " ", Action: dnsSign, Flags: []cli.Flag{dnsDomainFlag, dnsSeqFlag}, } - dnsTXTCommand = cli.Command{ + dnsTXTCommand = &cli.Command{ Name: "to-txt", Usage: "Create a DNS TXT records for a discovery tree", ArgsUsage: " ", Action: dnsToTXT, } - dnsCloudflareCommand = cli.Command{ + dnsCloudflareCommand = &cli.Command{ Name: "to-cloudflare", Usage: "Deploy DNS TXT records to CloudFlare", ArgsUsage: "", Action: dnsToCloudflare, Flags: []cli.Flag{cloudflareTokenFlag, cloudflareZoneIDFlag}, } - dnsRoute53Command = cli.Command{ + dnsRoute53Command = &cli.Command{ Name: "to-route53", Usage: "Deploy DNS TXT records to Amazon Route53", ArgsUsage: "", @@ -84,7 +84,7 @@ var ( route53RegionFlag, }, } - dnsRoute53NukeCommand = cli.Command{ + dnsRoute53NukeCommand = &cli.Command{ Name: "nuke-route53", Usage: "Deletes DNS TXT records of a subdomain on Amazon Route53", ArgsUsage: "", @@ -99,15 +99,15 @@ var ( ) var ( - dnsTimeoutFlag = cli.DurationFlag{ + dnsTimeoutFlag = &cli.DurationFlag{ Name: "timeout", Usage: "Timeout for DNS lookups", } - dnsDomainFlag = cli.StringFlag{ + dnsDomainFlag = &cli.StringFlag{ Name: "domain", Usage: "Domain name of the tree", } - dnsSeqFlag = cli.UintFlag{ + dnsSeqFlag = &cli.UintFlag{ Name: "seq", Usage: "New sequence number of the tree", } diff --git a/cmd/devp2p/enrcmd.go b/cmd/devp2p/enrcmd.go index 2a8f9d508fbe..211043710358 100644 --- a/cmd/devp2p/enrcmd.go +++ b/cmd/devp2p/enrcmd.go @@ -30,12 +30,12 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rlp" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -var fileFlag = cli.StringFlag{Name: "file"} +var fileFlag = &cli.StringFlag{Name: "file"} -var enrdumpCommand = cli.Command{ +var enrdumpCommand = &cli.Command{ Name: "enrdump", Usage: "Pretty-prints node records", Action: enrdump, @@ -62,7 +62,7 @@ func enrdump(ctx *cli.Context) error { } source = string(b) } else if ctx.NArg() == 1 { - source = ctx.Args()[0] + source = ctx.Args().First() } else { return fmt.Errorf("need record as argument") } diff --git a/cmd/devp2p/keycmd.go b/cmd/devp2p/keycmd.go index 869b8c2a44f0..e824abe653e2 100644 --- a/cmd/devp2p/keycmd.go +++ b/cmd/devp2p/keycmd.go @@ -22,25 +22,25 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - keyCommand = cli.Command{ + keyCommand = &cli.Command{ Name: "key", Usage: "Operations on node keys", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ keyGenerateCommand, keyToNodeCommand, }, } - keyGenerateCommand = cli.Command{ + keyGenerateCommand = &cli.Command{ Name: "generate", Usage: "Generates node key files", ArgsUsage: "keyfile", Action: genkey, } - keyToNodeCommand = cli.Command{ + keyToNodeCommand = &cli.Command{ Name: "to-enode", Usage: "Creates an enode URL from a node key file", ArgsUsage: "keyfile", @@ -50,17 +50,17 @@ var ( ) var ( - hostFlag = cli.StringFlag{ + hostFlag = &cli.StringFlag{ Name: "ip", Usage: "IP address of the node", Value: "127.0.0.1", } - tcpPortFlag = cli.IntFlag{ + tcpPortFlag = &cli.IntFlag{ Name: "tcp", Usage: "TCP port of the node", Value: 30303, } - udpPortFlag = cli.IntFlag{ + udpPortFlag = &cli.IntFlag{ Name: "udp", Usage: "UDP port of the node", Value: 30303, diff --git a/cmd/devp2p/main.go b/cmd/devp2p/main.go index 4a4e905a424e..51b9fdb76119 100644 --- a/cmd/devp2p/main.go +++ b/cmd/devp2p/main.go @@ -20,12 +20,12 @@ import ( "fmt" "os" "path/filepath" - "sort" "github.com/ethereum/go-ethereum/internal/debug" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( @@ -45,6 +45,7 @@ func init() { // Set up the CLI app. app.Flags = append(app.Flags, debug.Flags...) app.Before = func(ctx *cli.Context) error { + flags.MigrateGlobalFlags(ctx) return debug.Setup(ctx) } app.After = func(ctx *cli.Context) error { @@ -56,7 +57,7 @@ func init() { os.Exit(1) } // Add subcommands. - app.Commands = []cli.Command{ + app.Commands = []*cli.Command{ enrdumpCommand, keyCommand, discv4Command, @@ -73,10 +74,17 @@ func main() { // commandHasFlag returns true if the current command supports the given flag. func commandHasFlag(ctx *cli.Context, flag cli.Flag) bool { - flags := ctx.FlagNames() - sort.Strings(flags) - i := sort.SearchStrings(flags, flag.GetName()) - return i != len(flags) && flags[i] == flag.GetName() + names := flag.Names() + set := make(map[string]struct{}, len(names)) + for _, name := range names { + set[name] = struct{}{} + } + for _, fn := range ctx.FlagNames() { + if _, ok := set[fn]; ok { + return true + } + } + return false } // getNodeArg handles the common case of a single node descriptor argument. @@ -84,7 +92,7 @@ func getNodeArg(ctx *cli.Context) *enode.Node { if ctx.NArg() < 1 { exit("missing node as command-line argument") } - n, err := parseNode(ctx.Args()[0]) + n, err := parseNode(ctx.Args().First()) if err != nil { exit(err) } diff --git a/cmd/devp2p/nodesetcmd.go b/cmd/devp2p/nodesetcmd.go index d65d6314c8e1..f6b629278ecd 100644 --- a/cmd/devp2p/nodesetcmd.go +++ b/cmd/devp2p/nodesetcmd.go @@ -29,25 +29,25 @@ import ( "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - nodesetCommand = cli.Command{ + nodesetCommand = &cli.Command{ Name: "nodeset", Usage: "Node set tools", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ nodesetInfoCommand, nodesetFilterCommand, }, } - nodesetInfoCommand = cli.Command{ + nodesetInfoCommand = &cli.Command{ Name: "info", Usage: "Shows statistics about a node set", Action: nodesetInfo, ArgsUsage: "", } - nodesetFilterCommand = cli.Command{ + nodesetFilterCommand = &cli.Command{ Name: "filter", Usage: "Filters a node set", Action: nodesetFilter, diff --git a/cmd/devp2p/rlpxcmd.go b/cmd/devp2p/rlpxcmd.go index 6557a239da77..07978e4f8861 100644 --- a/cmd/devp2p/rlpxcmd.go +++ b/cmd/devp2p/rlpxcmd.go @@ -26,25 +26,25 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/rlpx" "github.com/ethereum/go-ethereum/rlp" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - rlpxCommand = cli.Command{ + rlpxCommand = &cli.Command{ Name: "rlpx", Usage: "RLPx Commands", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ rlpxPingCommand, rlpxEthTestCommand, rlpxSnapTestCommand, }, } - rlpxPingCommand = cli.Command{ + rlpxPingCommand = &cli.Command{ Name: "ping", Usage: "ping ", Action: rlpxPing, } - rlpxEthTestCommand = cli.Command{ + rlpxEthTestCommand = &cli.Command{ Name: "eth-test", Usage: "Runs tests against a node", ArgsUsage: " ", @@ -54,7 +54,7 @@ var ( testTAPFlag, }, } - rlpxSnapTestCommand = cli.Command{ + rlpxSnapTestCommand = &cli.Command{ Name: "snap-test", Usage: "Runs tests against a node", ArgsUsage: " ", @@ -106,7 +106,7 @@ func rlpxEthTest(ctx *cli.Context) error { if ctx.NArg() < 3 { exit("missing path to chain.rlp as command-line argument") } - suite, err := ethtest.NewSuite(getNodeArg(ctx), ctx.Args()[1], ctx.Args()[2]) + suite, err := ethtest.NewSuite(getNodeArg(ctx), ctx.Args().Get(1), ctx.Args().Get(2)) if err != nil { exit(err) } @@ -123,7 +123,7 @@ func rlpxSnapTest(ctx *cli.Context) error { if ctx.NArg() < 3 { exit("missing path to chain.rlp as command-line argument") } - suite, err := ethtest.NewSuite(getNodeArg(ctx), ctx.Args()[1], ctx.Args()[2]) + suite, err := ethtest.NewSuite(getNodeArg(ctx), ctx.Args().Get(1), ctx.Args().Get(2)) if err != nil { exit(err) } diff --git a/cmd/devp2p/runtest.go b/cmd/devp2p/runtest.go index 4168f8555bfb..f72aa91119c5 100644 --- a/cmd/devp2p/runtest.go +++ b/cmd/devp2p/runtest.go @@ -22,25 +22,25 @@ import ( "github.com/ethereum/go-ethereum/cmd/devp2p/internal/v4test" "github.com/ethereum/go-ethereum/internal/utesting" "github.com/ethereum/go-ethereum/log" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - testPatternFlag = cli.StringFlag{ + testPatternFlag = &cli.StringFlag{ Name: "run", Usage: "Pattern of test suite(s) to run", } - testTAPFlag = cli.BoolFlag{ + testTAPFlag = &cli.BoolFlag{ Name: "tap", Usage: "Output TAP", } // These two are specific to the discovery tests. - testListen1Flag = cli.StringFlag{ + testListen1Flag = &cli.StringFlag{ Name: "listen1", Usage: "IP address of the first tester", Value: v4test.Listen1, } - testListen2Flag = cli.StringFlag{ + testListen2Flag = &cli.StringFlag{ Name: "listen2", Usage: "IP address of the second tester", Value: v4test.Listen2, @@ -53,7 +53,7 @@ func runTests(ctx *cli.Context, tests []utesting.Test) error { tests = utesting.MatchTests(tests, ctx.String(testPatternFlag.Name)) } // Disable logging unless explicitly enabled. - if !ctx.GlobalIsSet("verbosity") && !ctx.GlobalIsSet("vmodule") { + if !ctx.IsSet("verbosity") && !ctx.IsSet("vmodule") { log.Root().SetHandler(log.DiscardHandler()) } // Run the tests. diff --git a/cmd/ethkey/changepassword.go b/cmd/ethkey/changepassword.go index bd8745f6db87..4298e2b83407 100644 --- a/cmd/ethkey/changepassword.go +++ b/cmd/ethkey/changepassword.go @@ -23,15 +23,15 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/cmd/utils" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -var newPassphraseFlag = cli.StringFlag{ +var newPassphraseFlag = &cli.StringFlag{ Name: "newpasswordfile", Usage: "the file that contains the new password for the keyfile", } -var commandChangePassphrase = cli.Command{ +var commandChangePassphrase = &cli.Command{ Name: "changepassword", Usage: "change the password on a keyfile", ArgsUsage: "", diff --git a/cmd/ethkey/generate.go b/cmd/ethkey/generate.go index 1b70b130bcd5..60d8b3c7795b 100644 --- a/cmd/ethkey/generate.go +++ b/cmd/ethkey/generate.go @@ -26,7 +26,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/crypto" "github.com/google/uuid" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) type outputGenerate struct { @@ -35,17 +35,17 @@ type outputGenerate struct { } var ( - privateKeyFlag = cli.StringFlag{ + privateKeyFlag = &cli.StringFlag{ Name: "privatekey", Usage: "file containing a raw private key to encrypt", } - lightKDFFlag = cli.BoolFlag{ + lightKDFFlag = &cli.BoolFlag{ Name: "lightkdf", Usage: "use less secure scrypt parameters", } ) -var commandGenerate = cli.Command{ +var commandGenerate = &cli.Command{ Name: "generate", Usage: "generate new keyfile", ArgsUsage: "[ ]", diff --git a/cmd/ethkey/inspect.go b/cmd/ethkey/inspect.go index efcaecd389d3..29b1c13e859b 100644 --- a/cmd/ethkey/inspect.go +++ b/cmd/ethkey/inspect.go @@ -24,7 +24,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/crypto" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) type outputInspect struct { @@ -34,13 +34,13 @@ type outputInspect struct { } var ( - privateFlag = cli.BoolFlag{ + privateFlag = &cli.BoolFlag{ Name: "private", Usage: "include the private key in the output", } ) -var commandInspect = cli.Command{ +var commandInspect = &cli.Command{ Name: "inspect", Usage: "inspect a keyfile", ArgsUsage: "", diff --git a/cmd/ethkey/main.go b/cmd/ethkey/main.go index 6db39174c461..2b21f3cd70a4 100644 --- a/cmd/ethkey/main.go +++ b/cmd/ethkey/main.go @@ -21,7 +21,7 @@ import ( "os" "github.com/ethereum/go-ethereum/internal/flags" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) const ( @@ -36,23 +36,22 @@ var app *cli.App func init() { app = flags.NewApp(gitCommit, gitDate, "an Ethereum key manager") - app.Commands = []cli.Command{ + app.Commands = []*cli.Command{ commandGenerate, commandInspect, commandChangePassphrase, commandSignMessage, commandVerifyMessage, } - cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate } // Commonly used command line flags. var ( - passphraseFlag = cli.StringFlag{ + passphraseFlag = &cli.StringFlag{ Name: "passwordfile", Usage: "the file that contains the password for the keyfile", } - jsonFlag = cli.BoolFlag{ + jsonFlag = &cli.BoolFlag{ Name: "json", Usage: "output JSON instead of human-readable format", } diff --git a/cmd/ethkey/message.go b/cmd/ethkey/message.go index 8d253783ceb1..6b8dec03cd67 100644 --- a/cmd/ethkey/message.go +++ b/cmd/ethkey/message.go @@ -26,19 +26,19 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) type outputSign struct { Signature string } -var msgfileFlag = cli.StringFlag{ +var msgfileFlag = &cli.StringFlag{ Name: "msgfile", Usage: "file containing the message to sign/verify", } -var commandSignMessage = cli.Command{ +var commandSignMessage = &cli.Command{ Name: "signmessage", Usage: "sign a message", ArgsUsage: " ", @@ -89,7 +89,7 @@ type outputVerify struct { RecoveredPublicKey string } -var commandVerifyMessage = cli.Command{ +var commandVerifyMessage = &cli.Command{ Name: "verifymessage", Usage: "verify the signature of a signed message", ArgsUsage: "
", @@ -144,7 +144,7 @@ It is possible to refer to a file containing the message.`, func getMessage(ctx *cli.Context, msgarg int) []byte { if file := ctx.String(msgfileFlag.Name); file != "" { - if len(ctx.Args()) > msgarg { + if ctx.NArg() > msgarg { utils.Fatalf("Can't use --msgfile and message argument at the same time.") } msg, err := os.ReadFile(file) @@ -152,9 +152,9 @@ func getMessage(ctx *cli.Context, msgarg int) []byte { utils.Fatalf("Can't read message file: %v", err) } return msg - } else if len(ctx.Args()) == msgarg+1 { + } else if ctx.NArg() == msgarg+1 { return []byte(ctx.Args().Get(msgarg)) } - utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, len(ctx.Args())) + utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, ctx.NArg()) return nil } diff --git a/cmd/ethkey/utils.go b/cmd/ethkey/utils.go index ed492272e33f..2821145089ec 100644 --- a/cmd/ethkey/utils.go +++ b/cmd/ethkey/utils.go @@ -23,7 +23,7 @@ import ( "strings" "github.com/ethereum/go-ethereum/cmd/utils" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) // getPassphrase obtains a passphrase given by the user. It first checks the diff --git a/cmd/evm/compiler.go b/cmd/evm/compiler.go index 880f995f057c..699d434bb0e1 100644 --- a/cmd/evm/compiler.go +++ b/cmd/evm/compiler.go @@ -23,10 +23,10 @@ import ( "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -var compileCommand = cli.Command{ +var compileCommand = &cli.Command{ Action: compileCmd, Name: "compile", Usage: "compiles easm source to evm binary", @@ -34,7 +34,7 @@ var compileCommand = cli.Command{ } func compileCmd(ctx *cli.Context) error { - debug := ctx.GlobalBool(DebugFlag.Name) + debug := ctx.Bool(DebugFlag.Name) if len(ctx.Args().First()) == 0 { return errors.New("filename required") diff --git a/cmd/evm/disasm.go b/cmd/evm/disasm.go index 918b01376791..a6a16fd13b77 100644 --- a/cmd/evm/disasm.go +++ b/cmd/evm/disasm.go @@ -23,10 +23,10 @@ import ( "strings" "github.com/ethereum/go-ethereum/core/asm" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -var disasmCommand = cli.Command{ +var disasmCommand = &cli.Command{ Action: disasmCmd, Name: "disasm", Usage: "disassembles evm binary", @@ -43,8 +43,8 @@ func disasmCmd(ctx *cli.Context) error { return err } in = string(input) - case ctx.GlobalIsSet(InputFlag.Name): - in = ctx.GlobalString(InputFlag.Name) + case ctx.IsSet(InputFlag.Name): + in = ctx.String(InputFlag.Name) default: return errors.New("missing filename or --input value") } diff --git a/cmd/evm/internal/t8ntool/block.go b/cmd/evm/internal/t8ntool/block.go index 9839afd5f488..4a070b6c71b5 100644 --- a/cmd/evm/internal/t8ntool/block.go +++ b/cmd/evm/internal/t8ntool/block.go @@ -33,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) //go:generate go run github.com/fjl/gencodec -type header -field-override headerMarshaling -out gen_header.go diff --git a/cmd/evm/internal/t8ntool/flags.go b/cmd/evm/internal/t8ntool/flags.go index 12a7002c69ed..626220315e19 100644 --- a/cmd/evm/internal/t8ntool/flags.go +++ b/cmd/evm/internal/t8ntool/flags.go @@ -22,45 +22,47 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/tests" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - TraceFlag = cli.BoolFlag{ + TraceFlag = &cli.BoolFlag{ Name: "trace", Usage: "Output full trace logs to files .jsonl", } - TraceDisableMemoryFlag = cli.BoolTFlag{ + TraceDisableMemoryFlag = &cli.BoolFlag{ Name: "trace.nomemory", + Value: true, Usage: "Disable full memory dump in traces (deprecated)", } - TraceEnableMemoryFlag = cli.BoolFlag{ + TraceEnableMemoryFlag = &cli.BoolFlag{ Name: "trace.memory", Usage: "Enable full memory dump in traces", } - TraceDisableStackFlag = cli.BoolFlag{ + TraceDisableStackFlag = &cli.BoolFlag{ Name: "trace.nostack", Usage: "Disable stack output in traces", } - TraceDisableReturnDataFlag = cli.BoolTFlag{ + TraceDisableReturnDataFlag = &cli.BoolFlag{ Name: "trace.noreturndata", + Value: true, Usage: "Disable return data output in traces (deprecated)", } - TraceEnableReturnDataFlag = cli.BoolFlag{ + TraceEnableReturnDataFlag = &cli.BoolFlag{ Name: "trace.returndata", Usage: "Enable return data output in traces", } - OutputBasedir = cli.StringFlag{ + OutputBasedir = &cli.StringFlag{ Name: "output.basedir", Usage: "Specifies where output files are placed. Will be created if it does not exist.", Value: "", } - OutputBodyFlag = cli.StringFlag{ + OutputBodyFlag = &cli.StringFlag{ Name: "output.body", Usage: "If set, the RLP of the transactions (block body) will be written to this file.", Value: "", } - OutputAllocFlag = cli.StringFlag{ + OutputAllocFlag = &cli.StringFlag{ Name: "output.alloc", Usage: "Determines where to put the `alloc` of the post-state.\n" + "\t`stdout` - into the stdout output\n" + @@ -68,7 +70,7 @@ var ( "\t - into the file ", Value: "alloc.json", } - OutputResultFlag = cli.StringFlag{ + OutputResultFlag = &cli.StringFlag{ Name: "output.result", Usage: "Determines where to put the `result` (stateroot, txroot etc) of the post-state.\n" + "\t`stdout` - into the stdout output\n" + @@ -76,7 +78,7 @@ var ( "\t - into the file ", Value: "result.json", } - OutputBlockFlag = cli.StringFlag{ + OutputBlockFlag = &cli.StringFlag{ Name: "output.block", Usage: "Determines where to put the `block` after building.\n" + "\t`stdout` - into the stdout output\n" + @@ -84,65 +86,65 @@ var ( "\t - into the file ", Value: "block.json", } - InputAllocFlag = cli.StringFlag{ + InputAllocFlag = &cli.StringFlag{ Name: "input.alloc", Usage: "`stdin` or file name of where to find the prestate alloc to use.", Value: "alloc.json", } - InputEnvFlag = cli.StringFlag{ + InputEnvFlag = &cli.StringFlag{ Name: "input.env", Usage: "`stdin` or file name of where to find the prestate env to use.", Value: "env.json", } - InputTxsFlag = cli.StringFlag{ + InputTxsFlag = &cli.StringFlag{ Name: "input.txs", Usage: "`stdin` or file name of where to find the transactions to apply. " + "If the file extension is '.rlp', then the data is interpreted as an RLP list of signed transactions." + "The '.rlp' format is identical to the output.body format.", Value: "txs.json", } - InputHeaderFlag = cli.StringFlag{ + InputHeaderFlag = &cli.StringFlag{ Name: "input.header", Usage: "`stdin` or file name of where to find the block header to use.", Value: "header.json", } - InputOmmersFlag = cli.StringFlag{ + InputOmmersFlag = &cli.StringFlag{ Name: "input.ommers", Usage: "`stdin` or file name of where to find the list of ommer header RLPs to use.", } - InputTxsRlpFlag = cli.StringFlag{ + InputTxsRlpFlag = &cli.StringFlag{ Name: "input.txs", Usage: "`stdin` or file name of where to find the transactions list in RLP form.", Value: "txs.rlp", } - SealCliqueFlag = cli.StringFlag{ + SealCliqueFlag = &cli.StringFlag{ Name: "seal.clique", Usage: "Seal block with Clique. `stdin` or file name of where to find the Clique sealing data.", } - SealEthashFlag = cli.BoolFlag{ + SealEthashFlag = &cli.BoolFlag{ Name: "seal.ethash", Usage: "Seal block with ethash.", } - SealEthashDirFlag = cli.StringFlag{ + SealEthashDirFlag = &cli.StringFlag{ Name: "seal.ethash.dir", Usage: "Path to ethash DAG. If none exists, a new DAG will be generated.", } - SealEthashModeFlag = cli.StringFlag{ + SealEthashModeFlag = &cli.StringFlag{ Name: "seal.ethash.mode", Usage: "Defines the type and amount of PoW verification an ethash engine makes.", Value: "normal", } - RewardFlag = cli.Int64Flag{ + RewardFlag = &cli.Int64Flag{ Name: "state.reward", Usage: "Mining reward. Set to -1 to disable", Value: 0, } - ChainIDFlag = cli.Int64Flag{ + ChainIDFlag = &cli.Int64Flag{ Name: "state.chainid", Usage: "ChainID to use", Value: 1, } - ForknameFlag = cli.StringFlag{ + ForknameFlag = &cli.StringFlag{ Name: "state.fork", Usage: fmt.Sprintf("Name of ruleset to use."+ "\n\tAvailable forknames:"+ @@ -154,7 +156,7 @@ var ( strings.Join(vm.ActivateableEips(), ", ")), Value: "GrayGlacier", } - VerbosityFlag = cli.IntFlag{ + VerbosityFlag = &cli.IntFlag{ Name: "verbosity", Usage: "sets the verbosity level", Value: 3, diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 6f1c964ada02..3409c0a3bf01 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -32,7 +32,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) type result struct { diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index b254baa99582..73a28e91c097 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -38,7 +38,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) const ( diff --git a/cmd/evm/internal/t8ntool/utils.go b/cmd/evm/internal/t8ntool/utils.go index 1c54f09bf417..8ec38c7618de 100644 --- a/cmd/evm/internal/t8ntool/utils.go +++ b/cmd/evm/internal/t8ntool/utils.go @@ -21,7 +21,7 @@ import ( "fmt" "os" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) // readFile reads the json-data in the provided path and marshals into dest. diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 2f404d48e903..994b6436ad94 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -23,115 +23,118 @@ import ( "os" "github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool" - "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/internal/flags" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -var gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags) -var gitDate = "" - var ( + gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags) + gitDate = "" + app = flags.NewApp(gitCommit, gitDate, "the evm command line interface") +) - DebugFlag = cli.BoolFlag{ +var ( + DebugFlag = &cli.BoolFlag{ Name: "debug", Usage: "output full trace logs", } - MemProfileFlag = cli.StringFlag{ + MemProfileFlag = &cli.StringFlag{ Name: "memprofile", Usage: "creates a memory profile at the given path", } - CPUProfileFlag = cli.StringFlag{ + CPUProfileFlag = &cli.StringFlag{ Name: "cpuprofile", Usage: "creates a CPU profile at the given path", } - StatDumpFlag = cli.BoolFlag{ + StatDumpFlag = &cli.BoolFlag{ Name: "statdump", Usage: "displays stack and heap memory information", } - CodeFlag = cli.StringFlag{ + CodeFlag = &cli.StringFlag{ Name: "code", Usage: "EVM code", } - CodeFileFlag = cli.StringFlag{ + CodeFileFlag = &cli.StringFlag{ Name: "codefile", Usage: "File containing EVM code. If '-' is specified, code is read from stdin ", } - GasFlag = cli.Uint64Flag{ + GasFlag = &cli.Uint64Flag{ Name: "gas", Usage: "gas limit for the evm", Value: 10000000000, } - PriceFlag = utils.BigFlag{ + PriceFlag = &flags.BigFlag{ Name: "price", Usage: "price set for the evm", Value: new(big.Int), } - ValueFlag = utils.BigFlag{ + ValueFlag = &flags.BigFlag{ Name: "value", Usage: "value set for the evm", Value: new(big.Int), } - DumpFlag = cli.BoolFlag{ + DumpFlag = &cli.BoolFlag{ Name: "dump", Usage: "dumps the state after the run", } - InputFlag = cli.StringFlag{ + InputFlag = &cli.StringFlag{ Name: "input", Usage: "input for the EVM", } - InputFileFlag = cli.StringFlag{ + InputFileFlag = &cli.StringFlag{ Name: "inputfile", Usage: "file containing input for the EVM", } - VerbosityFlag = cli.IntFlag{ + VerbosityFlag = &cli.IntFlag{ Name: "verbosity", Usage: "sets the verbosity level", } - BenchFlag = cli.BoolFlag{ + BenchFlag = &cli.BoolFlag{ Name: "bench", Usage: "benchmark the execution", } - CreateFlag = cli.BoolFlag{ + CreateFlag = &cli.BoolFlag{ Name: "create", Usage: "indicates the action should be create rather than call", } - GenesisFlag = cli.StringFlag{ + GenesisFlag = &cli.StringFlag{ Name: "prestate", Usage: "JSON file with prestate (genesis) config", } - MachineFlag = cli.BoolFlag{ + MachineFlag = &cli.BoolFlag{ Name: "json", Usage: "output trace logs in machine readable format (json)", } - SenderFlag = cli.StringFlag{ + SenderFlag = &cli.StringFlag{ Name: "sender", Usage: "The transaction origin", } - ReceiverFlag = cli.StringFlag{ + ReceiverFlag = &cli.StringFlag{ Name: "receiver", Usage: "The transaction receiver (execution context)", } - DisableMemoryFlag = cli.BoolTFlag{ + DisableMemoryFlag = &cli.BoolFlag{ Name: "nomemory", + Value: true, Usage: "disable memory output", } - DisableStackFlag = cli.BoolFlag{ + DisableStackFlag = &cli.BoolFlag{ Name: "nostack", Usage: "disable stack output", } - DisableStorageFlag = cli.BoolFlag{ + DisableStorageFlag = &cli.BoolFlag{ Name: "nostorage", Usage: "disable storage output", } - DisableReturnDataFlag = cli.BoolTFlag{ + DisableReturnDataFlag = &cli.BoolFlag{ Name: "noreturndata", + Value: true, Usage: "enable return data output", } ) -var stateTransitionCommand = cli.Command{ +var stateTransitionCommand = &cli.Command{ Name: "transition", Aliases: []string{"t8n"}, Usage: "executes a full state transition", @@ -156,7 +159,8 @@ var stateTransitionCommand = cli.Command{ t8ntool.VerbosityFlag, }, } -var transactionCommand = cli.Command{ + +var transactionCommand = &cli.Command{ Name: "transaction", Aliases: []string{"t9n"}, Usage: "performs transaction validation", @@ -169,7 +173,7 @@ var transactionCommand = cli.Command{ }, } -var blockBuilderCommand = cli.Command{ +var blockBuilderCommand = &cli.Command{ Name: "block-builder", Aliases: []string{"b11r"}, Usage: "builds a block", @@ -214,7 +218,7 @@ func init() { DisableStorageFlag, DisableReturnDataFlag, } - app.Commands = []cli.Command{ + app.Commands = []*cli.Command{ compileCommand, disasmCommand, runCommand, @@ -223,7 +227,6 @@ func init() { transactionCommand, blockBuilderCommand, } - cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate } func main() { diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 5680c07a40ee..756d762b5348 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -37,12 +37,13 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/runtime" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -var runCommand = cli.Command{ +var runCommand = &cli.Command{ Action: runCmd, Name: "run", Usage: "run arbitrary evm binary", @@ -106,14 +107,14 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) (output []by func runCmd(ctx *cli.Context) error { glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) - glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) + glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) log.Root().SetHandler(glogger) logconfig := &logger.Config{ - EnableMemory: !ctx.GlobalBool(DisableMemoryFlag.Name), - DisableStack: ctx.GlobalBool(DisableStackFlag.Name), - DisableStorage: ctx.GlobalBool(DisableStorageFlag.Name), - EnableReturnData: !ctx.GlobalBool(DisableReturnDataFlag.Name), - Debug: ctx.GlobalBool(DebugFlag.Name), + EnableMemory: !ctx.Bool(DisableMemoryFlag.Name), + DisableStack: ctx.Bool(DisableStackFlag.Name), + DisableStorage: ctx.Bool(DisableStorageFlag.Name), + EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), + Debug: ctx.Bool(DebugFlag.Name), } var ( @@ -125,16 +126,16 @@ func runCmd(ctx *cli.Context) error { receiver = common.BytesToAddress([]byte("receiver")) genesisConfig *core.Genesis ) - if ctx.GlobalBool(MachineFlag.Name) { + if ctx.Bool(MachineFlag.Name) { tracer = logger.NewJSONLogger(logconfig, os.Stdout) - } else if ctx.GlobalBool(DebugFlag.Name) { + } else if ctx.Bool(DebugFlag.Name) { debugLogger = logger.NewStructLogger(logconfig) tracer = debugLogger } else { debugLogger = logger.NewStructLogger(logconfig) } - if ctx.GlobalString(GenesisFlag.Name) != "" { - gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) + if ctx.String(GenesisFlag.Name) != "" { + gen := readGenesis(ctx.String(GenesisFlag.Name)) genesisConfig = gen db := rawdb.NewMemoryDatabase() genesis := gen.ToBlock(db) @@ -144,18 +145,18 @@ func runCmd(ctx *cli.Context) error { statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) genesisConfig = new(core.Genesis) } - if ctx.GlobalString(SenderFlag.Name) != "" { - sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) + if ctx.String(SenderFlag.Name) != "" { + sender = common.HexToAddress(ctx.String(SenderFlag.Name)) } statedb.CreateAccount(sender) - if ctx.GlobalString(ReceiverFlag.Name) != "" { - receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name)) + if ctx.String(ReceiverFlag.Name) != "" { + receiver = common.HexToAddress(ctx.String(ReceiverFlag.Name)) } var code []byte - codeFileFlag := ctx.GlobalString(CodeFileFlag.Name) - codeFlag := ctx.GlobalString(CodeFlag.Name) + codeFileFlag := ctx.String(CodeFileFlag.Name) + codeFlag := ctx.String(CodeFlag.Name) // The '--code' or '--codefile' flag overrides code in state if codeFileFlag != "" || codeFlag != "" { @@ -197,7 +198,7 @@ func runCmd(ctx *cli.Context) error { } code = common.Hex2Bytes(bin) } - initialGas := ctx.GlobalUint64(GasFlag.Name) + initialGas := ctx.Uint64(GasFlag.Name) if genesisConfig.GasLimit != 0 { initialGas = genesisConfig.GasLimit } @@ -205,19 +206,19 @@ func runCmd(ctx *cli.Context) error { Origin: sender, State: statedb, GasLimit: initialGas, - GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), - Value: utils.GlobalBig(ctx, ValueFlag.Name), + GasPrice: flags.GlobalBig(ctx, PriceFlag.Name), + Value: flags.GlobalBig(ctx, ValueFlag.Name), Difficulty: genesisConfig.Difficulty, Time: new(big.Int).SetUint64(genesisConfig.Timestamp), Coinbase: genesisConfig.Coinbase, BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), EVMConfig: vm.Config{ Tracer: tracer, - Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), + Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name), }, } - if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" { + if cpuProfilePath := ctx.String(CPUProfileFlag.Name); cpuProfilePath != "" { f, err := os.Create(cpuProfilePath) if err != nil { fmt.Println("could not create CPU profile: ", err) @@ -237,14 +238,14 @@ func runCmd(ctx *cli.Context) error { } var hexInput []byte - if inputFileFlag := ctx.GlobalString(InputFileFlag.Name); inputFileFlag != "" { + if inputFileFlag := ctx.String(InputFileFlag.Name); inputFileFlag != "" { var err error if hexInput, err = os.ReadFile(inputFileFlag); err != nil { fmt.Printf("could not load input from file: %v\n", err) os.Exit(1) } } else { - hexInput = []byte(ctx.GlobalString(InputFlag.Name)) + hexInput = []byte(ctx.String(InputFlag.Name)) } hexInput = bytes.TrimSpace(hexInput) if len(hexInput)%2 != 0 { @@ -254,7 +255,7 @@ func runCmd(ctx *cli.Context) error { input := common.FromHex(string(hexInput)) var execFunc func() ([]byte, uint64, error) - if ctx.GlobalBool(CreateFlag.Name) { + if ctx.Bool(CreateFlag.Name) { input = append(code, input...) execFunc = func() ([]byte, uint64, error) { output, _, gasLeft, err := runtime.Create(input, &runtimeConfig) @@ -269,16 +270,16 @@ func runCmd(ctx *cli.Context) error { } } - bench := ctx.GlobalBool(BenchFlag.Name) + bench := ctx.Bool(BenchFlag.Name) output, leftOverGas, stats, err := timedExec(bench, execFunc) - if ctx.GlobalBool(DumpFlag.Name) { + if ctx.Bool(DumpFlag.Name) { statedb.Commit(true) statedb.IntermediateRoot(true) fmt.Println(string(statedb.Dump(nil))) } - if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" { + if memProfilePath := ctx.String(MemProfileFlag.Name); memProfilePath != "" { f, err := os.Create(memProfilePath) if err != nil { fmt.Println("could not create memory profile: ", err) @@ -291,7 +292,7 @@ func runCmd(ctx *cli.Context) error { f.Close() } - if ctx.GlobalBool(DebugFlag.Name) { + if ctx.Bool(DebugFlag.Name) { if debugLogger != nil { fmt.Fprintln(os.Stderr, "#### TRACE ####") logger.WriteTrace(os.Stderr, debugLogger.StructLogs()) @@ -300,7 +301,7 @@ func runCmd(ctx *cli.Context) error { logger.WriteLogs(os.Stderr, statedb.Logs()) } - if bench || ctx.GlobalBool(StatDumpFlag.Name) { + if bench || ctx.Bool(StatDumpFlag.Name) { fmt.Fprintf(os.Stderr, `EVM gas used: %d execution time: %v allocations: %d diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index fcdac33eedfb..36f4e19b0bea 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -28,10 +28,10 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/tests" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -var stateTestCommand = cli.Command{ +var stateTestCommand = &cli.Command{ Action: stateTestCmd, Name: "statetest", Usage: "executes the given state tests", @@ -54,25 +54,25 @@ func stateTestCmd(ctx *cli.Context) error { } // Configure the go-ethereum logger glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) - glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) + glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) log.Root().SetHandler(glogger) // Configure the EVM logger config := &logger.Config{ - EnableMemory: !ctx.GlobalBool(DisableMemoryFlag.Name), - DisableStack: ctx.GlobalBool(DisableStackFlag.Name), - DisableStorage: ctx.GlobalBool(DisableStorageFlag.Name), - EnableReturnData: !ctx.GlobalBool(DisableReturnDataFlag.Name), + EnableMemory: !ctx.Bool(DisableMemoryFlag.Name), + DisableStack: ctx.Bool(DisableStackFlag.Name), + DisableStorage: ctx.Bool(DisableStorageFlag.Name), + EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), } var ( tracer vm.EVMLogger debugger *logger.StructLogger ) switch { - case ctx.GlobalBool(MachineFlag.Name): + case ctx.Bool(MachineFlag.Name): tracer = logger.NewJSONLogger(config, os.Stderr) - case ctx.GlobalBool(DebugFlag.Name): + case ctx.Bool(DebugFlag.Name): debugger = logger.NewStructLogger(config) tracer = debugger @@ -91,7 +91,7 @@ func stateTestCmd(ctx *cli.Context) error { // Iterate over all the tests, run them and aggregate the results cfg := vm.Config{ Tracer: tracer, - Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), + Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name), } results := make([]StatetestResult, 0, len(tests)) for key, test := range tests { @@ -100,13 +100,13 @@ func stateTestCmd(ctx *cli.Context) error { result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true} _, s, err := test.Run(st, cfg, false) // print state root for evmlab tracing - if ctx.GlobalBool(MachineFlag.Name) && s != nil { + if ctx.Bool(MachineFlag.Name) && s != nil { fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", s.IntermediateRoot(false)) } if err != nil { // Test failed, mark as so and dump any state to aid debugging result.Pass, result.Error = false, err.Error() - if ctx.GlobalBool(DumpFlag.Name) && s != nil { + if ctx.Bool(DumpFlag.Name) && s != nil { dump := s.RawDump(nil) result.State = &dump } @@ -115,7 +115,7 @@ func stateTestCmd(ctx *cli.Context) error { results = append(results, *result) // Print any structured logs collected - if ctx.GlobalBool(DebugFlag.Name) { + if ctx.Bool(DebugFlag.Name) { if debugger != nil { fmt.Fprintln(os.Stderr, "#### TRACE ####") logger.WriteTrace(os.Stderr, debugger.StructLogs()) diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go index f065b6eeab14..5158b7606cde 100644 --- a/cmd/geth/accountcmd.go +++ b/cmd/geth/accountcmd.go @@ -25,29 +25,27 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - walletCommand = cli.Command{ + walletCommand = &cli.Command{ Name: "wallet", Usage: "Manage Ethereum presale wallets", ArgsUsage: "", - Category: "ACCOUNT COMMANDS", Description: ` geth wallet import /path/to/my/presale.wallet will prompt for your password and imports your ether presale account. It can be used non-interactively with the --password option taking a passwordfile as argument containing the wallet password in plaintext.`, - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "import", Usage: "Import Ethereum presale wallet", ArgsUsage: "", - Action: utils.MigrateFlags(importWallet), - Category: "ACCOUNT COMMANDS", + Action: importWallet, Flags: []cli.Flag{ utils.DataDirFlag, utils.KeyStoreDirFlag, @@ -64,10 +62,9 @@ passwordfile as argument containing the wallet password in plaintext.`, }, } - accountCommand = cli.Command{ - Name: "account", - Usage: "Manage accounts", - Category: "ACCOUNT COMMANDS", + accountCommand = &cli.Command{ + Name: "account", + Usage: "Manage accounts", Description: ` Manage accounts, list all existing accounts, import a private key into a new @@ -88,11 +85,11 @@ It is safe to transfer the entire directory or the individual keys therein between ethereum nodes by simply copying. Make sure you backup your keys regularly.`, - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "list", Usage: "Print summary of existing accounts", - Action: utils.MigrateFlags(accountList), + Action: accountList, Flags: []cli.Flag{ utils.DataDirFlag, utils.KeyStoreDirFlag, @@ -103,7 +100,7 @@ Print a short summary of all accounts`, { Name: "new", Usage: "Create a new account", - Action: utils.MigrateFlags(accountCreate), + Action: accountCreate, Flags: []cli.Flag{ utils.DataDirFlag, utils.KeyStoreDirFlag, @@ -128,7 +125,7 @@ password to file or expose in any other way. { Name: "update", Usage: "Update an existing account", - Action: utils.MigrateFlags(accountUpdate), + Action: accountUpdate, ArgsUsage: "
", Flags: []cli.Flag{ utils.DataDirFlag, @@ -157,7 +154,7 @@ changing your password is only possible interactively. { Name: "import", Usage: "Import a private key into a new account", - Action: utils.MigrateFlags(accountImport), + Action: accountImport, Flags: []cli.Flag{ utils.DataDirFlag, utils.KeyStoreDirFlag, @@ -263,7 +260,7 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr func accountCreate(ctx *cli.Context) error { cfg := gethConfig{Node: defaultNodeConfig()} // Load config file. - if file := ctx.GlobalString(configFileFlag.Name); file != "" { + if file := ctx.String(configFileFlag.Name); file != "" { if err := loadConfig(file, &cfg); err != nil { utils.Fatalf("%v", err) } @@ -300,13 +297,13 @@ func accountCreate(ctx *cli.Context) error { // accountUpdate transitions an account from a previous format to the current // one, also providing the possibility to change the pass-phrase. func accountUpdate(ctx *cli.Context) error { - if len(ctx.Args()) == 0 { + if ctx.Args().Len() == 0 { utils.Fatalf("No accounts specified to update") } stack, _ := makeConfigNode(ctx) ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) - for _, addr := range ctx.Args() { + for _, addr := range ctx.Args().Slice() { account, oldPassword := unlockAccount(ks, addr, 0, nil) newPassword := utils.GetPassPhraseWithList("Please give a new password. Do not forget this password.", true, 0, nil) if err := ks.Update(account, oldPassword, newPassword); err != nil { @@ -317,10 +314,10 @@ func accountUpdate(ctx *cli.Context) error { } func importWallet(ctx *cli.Context) error { - keyfile := ctx.Args().First() - if len(keyfile) == 0 { - utils.Fatalf("keyfile must be given as argument") + if ctx.Args().Len() != 1 { + utils.Fatalf("keyfile must be given as the only argument") } + keyfile := ctx.Args().First() keyJSON, err := os.ReadFile(keyfile) if err != nil { utils.Fatalf("Could not read wallet file: %v", err) @@ -339,10 +336,10 @@ func importWallet(ctx *cli.Context) error { } func accountImport(ctx *cli.Context) error { - keyfile := ctx.Args().First() - if len(keyfile) == 0 { - utils.Fatalf("keyfile must be given as argument") + if ctx.Args().Len() != 1 { + utils.Fatalf("keyfile must be given as the only argument") } + keyfile := ctx.Args().First() key, err := crypto.LoadECDSA(keyfile) if err != nil { utils.Fatalf("Failed to load the private key: %v", err) diff --git a/cmd/geth/accountcmd_test.go b/cmd/geth/accountcmd_test.go index bbde27c3785a..84b9c33c24cf 100644 --- a/cmd/geth/accountcmd_test.go +++ b/cmd/geth/accountcmd_test.go @@ -49,20 +49,27 @@ func TestAccountListEmpty(t *testing.T) { func TestAccountList(t *testing.T) { datadir := tmpDatadirWithKeystore(t) - geth := runGeth(t, "account", "list", "--datadir", datadir) - defer geth.ExpectExit() + var want = ` +Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 +Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa +Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz +` if runtime.GOOS == "windows" { - geth.Expect(` + want = ` Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}\keystore\UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}\keystore\aaa Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\keystore\zzz -`) - } else { - geth.Expect(` -Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 -Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa -Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz -`) +` + } + { + geth := runGeth(t, "account", "list", "--datadir", datadir) + geth.Expect(want) + geth.ExpectExit() + } + { + geth := runGeth(t, "--datadir", datadir, "account", "list") + geth.Expect(want) + geth.ExpectExit() } } @@ -110,6 +117,20 @@ func TestAccountImport(t *testing.T) { } } +func TestAccountHelp(t *testing.T) { + geth := runGeth(t, "account", "-h") + geth.WaitExit() + if have, want := geth.ExitStatus(), 0; have != want { + t.Errorf("exit error, have %d want %d", have, want) + } + + geth = runGeth(t, "account", "import", "-h") + geth.WaitExit() + if have, want := geth.ExitStatus(), 0; have != want { + t.Errorf("exit error, have %d want %d", have, want) + } +} + func importAccountWithExpect(t *testing.T, key string, expected string) { dir := t.TempDir() keyfile := filepath.Join(dir, "key.prv") @@ -120,7 +141,7 @@ func importAccountWithExpect(t *testing.T, key string, expected string) { if err := os.WriteFile(passwordFile, []byte("foobar"), 0600); err != nil { t.Error(err) } - geth := runGeth(t, "--lightkdf", "account", "import", keyfile, "-password", passwordFile) + geth := runGeth(t, "--lightkdf", "account", "import", "-password", passwordFile, keyfile) defer geth.ExpectExit() geth.Expect(expected) } diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 6e19edeb46eb..6914e1aa2da9 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -38,17 +38,16 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - initCommand = cli.Command{ - Action: utils.MigrateFlags(initGenesis), + initCommand = &cli.Command{ + Action: initGenesis, Name: "init", Usage: "Bootstrap and initialize a new genesis block", ArgsUsage: "", Flags: utils.DatabasePathFlags, - Category: "BLOCKCHAIN COMMANDS", Description: ` The init command initializes a new genesis block and definition for the network. This is a destructive action and changes the network in which you will be @@ -56,18 +55,17 @@ participating. It expects the genesis file as argument.`, } - dumpGenesisCommand = cli.Command{ - Action: utils.MigrateFlags(dumpGenesis), + dumpGenesisCommand = &cli.Command{ + Action: dumpGenesis, Name: "dumpgenesis", Usage: "Dumps genesis block JSON configuration to stdout", ArgsUsage: "", Flags: utils.NetworkFlags, - Category: "BLOCKCHAIN COMMANDS", Description: ` The dumpgenesis command dumps the genesis block configuration in JSON format to stdout.`, } - importCommand = cli.Command{ - Action: utils.MigrateFlags(importChain), + importCommand = &cli.Command{ + Action: importChain, Name: "import", Usage: "Import a blockchain file", ArgsUsage: " ( ... ) ", @@ -94,7 +92,6 @@ The dumpgenesis command dumps the genesis block configuration in JSON format to utils.MetricsInfluxDBOrganizationFlag, utils.TxLookupLimitFlag, }, utils.DatabasePathFlags...), - Category: "BLOCKCHAIN COMMANDS", Description: ` The import command imports blocks from an RLP-encoded form. The form can be one file with several RLP-encoded blocks, or several files can be used. @@ -102,8 +99,8 @@ with several RLP-encoded blocks, or several files can be used. If only one file is used, import error will result in failure. If several files are used, processing will proceed even if an individual RLP-file import failure occurs.`, } - exportCommand = cli.Command{ - Action: utils.MigrateFlags(exportChain), + exportCommand = &cli.Command{ + Action: exportChain, Name: "export", Usage: "Export blockchain into file", ArgsUsage: " [ ]", @@ -111,7 +108,6 @@ processing will proceed even if an individual RLP-file import failure occurs.`, utils.CacheFlag, utils.SyncModeFlag, }, utils.DatabasePathFlags...), - Category: "BLOCKCHAIN COMMANDS", Description: ` Requires a first argument of the file to write to. Optional second and third arguments control the first and @@ -119,8 +115,8 @@ last block to write. In this mode, the file will be appended if already existing. If the file ends with .gz, the output will be gzipped.`, } - importPreimagesCommand = cli.Command{ - Action: utils.MigrateFlags(importPreimages), + importPreimagesCommand = &cli.Command{ + Action: importPreimages, Name: "import-preimages", Usage: "Import the preimage database from an RLP stream", ArgsUsage: "", @@ -128,14 +124,13 @@ be gzipped.`, utils.CacheFlag, utils.SyncModeFlag, }, utils.DatabasePathFlags...), - Category: "BLOCKCHAIN COMMANDS", Description: ` The import-preimages command imports hash preimages from an RLP encoded stream. It's deprecated, please use "geth db import" instead. `, } - exportPreimagesCommand = cli.Command{ - Action: utils.MigrateFlags(exportPreimages), + exportPreimagesCommand = &cli.Command{ + Action: exportPreimages, Name: "export-preimages", Usage: "Export the preimage database into an RLP stream", ArgsUsage: "", @@ -143,14 +138,13 @@ It's deprecated, please use "geth db import" instead. utils.CacheFlag, utils.SyncModeFlag, }, utils.DatabasePathFlags...), - Category: "BLOCKCHAIN COMMANDS", Description: ` The export-preimages command exports hash preimages to an RLP encoded stream. It's deprecated, please use "geth db export" instead. `, } - dumpCommand = cli.Command{ - Action: utils.MigrateFlags(dump), + dumpCommand = &cli.Command{ + Action: dump, Name: "dump", Usage: "Dump a specific block from storage", ArgsUsage: "[? | ]", @@ -163,7 +157,6 @@ It's deprecated, please use "geth db export" instead. utils.StartKeyFlag, utils.DumpLimitFlag, }, utils.DatabasePathFlags...), - Category: "BLOCKCHAIN COMMANDS", Description: ` This command dumps out the state for a given block (or latest, if none provided). `, @@ -192,7 +185,7 @@ func initGenesis(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() for _, name := range []string{"chaindata", "lightchaindata"} { - chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.GlobalString(utils.AncientFlag.Name), "", false) + chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.String(utils.AncientFlag.Name), "", false) if err != nil { utils.Fatalf("Failed to open database: %v", err) } @@ -219,7 +212,7 @@ func dumpGenesis(ctx *cli.Context) error { } func importChain(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { + if ctx.Args().Len() < 1 { utils.Fatalf("This command requires an argument.") } // Start metrics export if enabled @@ -253,13 +246,13 @@ func importChain(ctx *cli.Context) error { var importErr error - if len(ctx.Args()) == 1 { + if ctx.Args().Len() == 1 { if err := utils.ImportChain(chain, ctx.Args().First()); err != nil { importErr = err log.Error("Import error", "err", err) } } else { - for _, arg := range ctx.Args() { + for _, arg := range ctx.Args().Slice() { if err := utils.ImportChain(chain, arg); err != nil { importErr = err log.Error("Import error", "file", arg, "err", err) @@ -281,7 +274,7 @@ func importChain(ctx *cli.Context) error { fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000) fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs)) - if ctx.GlobalBool(utils.NoCompactionFlag.Name) { + if ctx.Bool(utils.NoCompactionFlag.Name) { return nil } @@ -298,7 +291,7 @@ func importChain(ctx *cli.Context) error { } func exportChain(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { + if ctx.Args().Len() < 1 { utils.Fatalf("This command requires an argument.") } @@ -310,7 +303,7 @@ func exportChain(ctx *cli.Context) error { var err error fp := ctx.Args().First() - if len(ctx.Args()) < 3 { + if ctx.Args().Len() < 3 { err = utils.ExportChain(chain, fp) } else { // This can be improved to allow for numbers larger than 9223372036854775807 @@ -337,7 +330,7 @@ func exportChain(ctx *cli.Context) error { // importPreimages imports preimage data from the specified file. func importPreimages(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { + if ctx.Args().Len() < 1 { utils.Fatalf("This command requires an argument.") } @@ -356,7 +349,7 @@ func importPreimages(ctx *cli.Context) error { // exportPreimages dumps the preimage data to specified json file in streaming way. func exportPreimages(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { + if ctx.Args().Len() < 1 { utils.Fatalf("This command requires an argument.") } stack, _ := makeConfigNode(ctx) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index bd321da9a3d3..a415aeabd2e9 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -25,7 +25,7 @@ import ( "reflect" "unicode" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" "github.com/ethereum/go-ethereum/accounts/external" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" @@ -43,19 +44,19 @@ import ( ) var ( - dumpConfigCommand = cli.Command{ - Action: utils.MigrateFlags(dumpConfig), + dumpConfigCommand = &cli.Command{ + Action: dumpConfig, Name: "dumpconfig", Usage: "Show configuration values", ArgsUsage: "", Flags: utils.GroupFlags(nodeFlags, rpcFlags), - Category: "MISCELLANEOUS COMMANDS", Description: `The dumpconfig command shows configuration values.`, } - configFileFlag = cli.StringFlag{ - Name: "config", - Usage: "TOML configuration file", + configFileFlag = &cli.StringFlag{ + Name: "config", + Usage: "TOML configuration file", + Category: flags.EthCategory, } ) @@ -127,7 +128,7 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { } // Load config file. - if file := ctx.GlobalString(configFileFlag.Name); file != "" { + if file := ctx.String(configFileFlag.Name); file != "" { if err := loadConfig(file, &cfg); err != nil { utils.Fatalf("%v", err) } @@ -145,8 +146,8 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { } utils.SetEthConfig(ctx, stack, &cfg.Eth) - if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) { - cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name) + if ctx.IsSet(utils.EthStatsURLFlag.Name) { + cfg.Ethstats.URL = ctx.String(utils.EthStatsURLFlag.Name) } applyMetricConfig(ctx, &cfg) @@ -156,15 +157,15 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // makeFullNode loads geth configuration and creates the Ethereum backend. func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { stack, cfg := makeConfigNode(ctx) - if ctx.GlobalIsSet(utils.OverrideGrayGlacierFlag.Name) { - cfg.Eth.OverrideGrayGlacier = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideGrayGlacierFlag.Name)) + if ctx.IsSet(utils.OverrideGrayGlacierFlag.Name) { + cfg.Eth.OverrideGrayGlacier = new(big.Int).SetUint64(ctx.Uint64(utils.OverrideGrayGlacierFlag.Name)) } - if ctx.GlobalIsSet(utils.OverrideTerminalTotalDifficulty.Name) { - cfg.Eth.OverrideTerminalTotalDifficulty = utils.GlobalBig(ctx, utils.OverrideTerminalTotalDifficulty.Name) + if ctx.IsSet(utils.OverrideTerminalTotalDifficulty.Name) { + cfg.Eth.OverrideTerminalTotalDifficulty = flags.GlobalBig(ctx, utils.OverrideTerminalTotalDifficulty.Name) } backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Warn users to migrate if they have a legacy freezer format. - if eth != nil && !ctx.GlobalIsSet(utils.IgnoreLegacyReceiptsFlag.Name) { + if eth != nil && !ctx.IsSet(utils.IgnoreLegacyReceiptsFlag.Name) { firstIdx := uint64(0) // Hack to speed up check for mainnet because we know // the first non-empty block. @@ -182,7 +183,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { } // Configure GraphQL if requested - if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) { + if ctx.IsSet(utils.GraphQLEnabledFlag.Name) { utils.RegisterGraphQLService(stack, backend, cfg.Node) } // Add the Ethereum Stats daemon if requested. @@ -222,47 +223,47 @@ func dumpConfig(ctx *cli.Context) error { } func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) { - if ctx.GlobalIsSet(utils.MetricsEnabledFlag.Name) { - cfg.Metrics.Enabled = ctx.GlobalBool(utils.MetricsEnabledFlag.Name) + if ctx.IsSet(utils.MetricsEnabledFlag.Name) { + cfg.Metrics.Enabled = ctx.Bool(utils.MetricsEnabledFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsEnabledExpensiveFlag.Name) { - cfg.Metrics.EnabledExpensive = ctx.GlobalBool(utils.MetricsEnabledExpensiveFlag.Name) + if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) { + cfg.Metrics.EnabledExpensive = ctx.Bool(utils.MetricsEnabledExpensiveFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsHTTPFlag.Name) { - cfg.Metrics.HTTP = ctx.GlobalString(utils.MetricsHTTPFlag.Name) + if ctx.IsSet(utils.MetricsHTTPFlag.Name) { + cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsPortFlag.Name) { - cfg.Metrics.Port = ctx.GlobalInt(utils.MetricsPortFlag.Name) + if ctx.IsSet(utils.MetricsPortFlag.Name) { + cfg.Metrics.Port = ctx.Int(utils.MetricsPortFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsEnableInfluxDBFlag.Name) { - cfg.Metrics.EnableInfluxDB = ctx.GlobalBool(utils.MetricsEnableInfluxDBFlag.Name) + if ctx.IsSet(utils.MetricsEnableInfluxDBFlag.Name) { + cfg.Metrics.EnableInfluxDB = ctx.Bool(utils.MetricsEnableInfluxDBFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsInfluxDBEndpointFlag.Name) { - cfg.Metrics.InfluxDBEndpoint = ctx.GlobalString(utils.MetricsInfluxDBEndpointFlag.Name) + if ctx.IsSet(utils.MetricsInfluxDBEndpointFlag.Name) { + cfg.Metrics.InfluxDBEndpoint = ctx.String(utils.MetricsInfluxDBEndpointFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsInfluxDBDatabaseFlag.Name) { - cfg.Metrics.InfluxDBDatabase = ctx.GlobalString(utils.MetricsInfluxDBDatabaseFlag.Name) + if ctx.IsSet(utils.MetricsInfluxDBDatabaseFlag.Name) { + cfg.Metrics.InfluxDBDatabase = ctx.String(utils.MetricsInfluxDBDatabaseFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsInfluxDBUsernameFlag.Name) { - cfg.Metrics.InfluxDBUsername = ctx.GlobalString(utils.MetricsInfluxDBUsernameFlag.Name) + if ctx.IsSet(utils.MetricsInfluxDBUsernameFlag.Name) { + cfg.Metrics.InfluxDBUsername = ctx.String(utils.MetricsInfluxDBUsernameFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsInfluxDBPasswordFlag.Name) { - cfg.Metrics.InfluxDBPassword = ctx.GlobalString(utils.MetricsInfluxDBPasswordFlag.Name) + if ctx.IsSet(utils.MetricsInfluxDBPasswordFlag.Name) { + cfg.Metrics.InfluxDBPassword = ctx.String(utils.MetricsInfluxDBPasswordFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsInfluxDBTagsFlag.Name) { - cfg.Metrics.InfluxDBTags = ctx.GlobalString(utils.MetricsInfluxDBTagsFlag.Name) + if ctx.IsSet(utils.MetricsInfluxDBTagsFlag.Name) { + cfg.Metrics.InfluxDBTags = ctx.String(utils.MetricsInfluxDBTagsFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsEnableInfluxDBV2Flag.Name) { - cfg.Metrics.EnableInfluxDBV2 = ctx.GlobalBool(utils.MetricsEnableInfluxDBV2Flag.Name) + if ctx.IsSet(utils.MetricsEnableInfluxDBV2Flag.Name) { + cfg.Metrics.EnableInfluxDBV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name) } - if ctx.GlobalIsSet(utils.MetricsInfluxDBTokenFlag.Name) { - cfg.Metrics.InfluxDBToken = ctx.GlobalString(utils.MetricsInfluxDBTokenFlag.Name) + if ctx.IsSet(utils.MetricsInfluxDBTokenFlag.Name) { + cfg.Metrics.InfluxDBToken = ctx.String(utils.MetricsInfluxDBTokenFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsInfluxDBBucketFlag.Name) { - cfg.Metrics.InfluxDBBucket = ctx.GlobalString(utils.MetricsInfluxDBBucketFlag.Name) + if ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name) { + cfg.Metrics.InfluxDBBucket = ctx.String(utils.MetricsInfluxDBBucketFlag.Name) } - if ctx.GlobalIsSet(utils.MetricsInfluxDBOrganizationFlag.Name) { - cfg.Metrics.InfluxDBOrganization = ctx.GlobalString(utils.MetricsInfluxDBOrganizationFlag.Name) + if ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) { + cfg.Metrics.InfluxDBOrganization = ctx.String(utils.MetricsInfluxDBOrganizationFlag.Name) } } diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index 4f538f96e3f5..a62b6a6ad592 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -24,31 +24,29 @@ import ( "github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag} - consoleCommand = cli.Command{ - Action: utils.MigrateFlags(localConsole), - Name: "console", - Usage: "Start an interactive JavaScript environment", - Flags: utils.GroupFlags(nodeFlags, rpcFlags, consoleFlags), - Category: "CONSOLE COMMANDS", + consoleCommand = &cli.Command{ + Action: localConsole, + Name: "console", + Usage: "Start an interactive JavaScript environment", + Flags: utils.GroupFlags(nodeFlags, rpcFlags, consoleFlags), Description: ` The Geth console is an interactive shell for the JavaScript runtime environment which exposes a node admin interface as well as the Ðapp JavaScript API. See https://geth.ethereum.org/docs/interface/javascript-console.`, } - attachCommand = cli.Command{ - Action: utils.MigrateFlags(remoteConsole), + attachCommand = &cli.Command{ + Action: remoteConsole, Name: "attach", Usage: "Start an interactive JavaScript environment (connect to node)", ArgsUsage: "[endpoint]", Flags: utils.GroupFlags([]cli.Flag{utils.DataDirFlag}, consoleFlags), - Category: "CONSOLE COMMANDS", Description: ` The Geth console is an interactive shell for the JavaScript runtime environment which exposes a node admin interface as well as the Ðapp JavaScript API. @@ -56,13 +54,12 @@ See https://geth.ethereum.org/docs/interface/javascript-console. This command allows to open a console on a running geth node.`, } - javascriptCommand = cli.Command{ - Action: utils.MigrateFlags(ephemeralConsole), + javascriptCommand = &cli.Command{ + Action: ephemeralConsole, Name: "js", Usage: "(DEPRECATED) Execute the specified JavaScript files", ArgsUsage: " [jsfile...]", Flags: utils.GroupFlags(nodeFlags, consoleFlags), - Category: "CONSOLE COMMANDS", Description: ` The JavaScript VM exposes a node admin interface as well as the Ðapp JavaScript API. See https://geth.ethereum.org/docs/interface/javascript-console`, @@ -85,7 +82,7 @@ func localConsole(ctx *cli.Context) error { } config := console.Config{ DataDir: utils.MakeDataDir(ctx), - DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), + DocRoot: ctx.String(utils.JSpathFlag.Name), Client: client, Preload: utils.MakeConsolePreloads(ctx), } @@ -96,7 +93,7 @@ func localConsole(ctx *cli.Context) error { defer console.Stop(false) // If only a short execution was requested, evaluate and return. - if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { + if script := ctx.String(utils.ExecFlag.Name); script != "" { console.Evaluate(script) return nil } @@ -129,7 +126,7 @@ func remoteConsole(ctx *cli.Context) error { } config := console.Config{ DataDir: utils.MakeDataDir(ctx), - DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), + DocRoot: ctx.String(utils.JSpathFlag.Name), Client: client, Preload: utils.MakeConsolePreloads(ctx), } @@ -139,7 +136,7 @@ func remoteConsole(ctx *cli.Context) error { } defer console.Stop(false) - if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { + if script := ctx.String(utils.ExecFlag.Name); script != "" { console.Evaluate(script) return nil } @@ -155,7 +152,7 @@ func remoteConsole(ctx *cli.Context) error { // everything down. func ephemeralConsole(ctx *cli.Context) error { var b strings.Builder - for _, file := range ctx.Args() { + for _, file := range ctx.Args().Slice() { b.Write([]byte(fmt.Sprintf("loadScript('%s');", file))) } utils.Fatalf(`The "js" command is deprecated. Please use the following instead: diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index d996d46f9ac1..be994def34d7 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -40,26 +40,24 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie" "github.com/olekukonko/tablewriter" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - removedbCommand = cli.Command{ - Action: utils.MigrateFlags(removeDB), + removedbCommand = &cli.Command{ + Action: removeDB, Name: "removedb", Usage: "Remove blockchain and state databases", ArgsUsage: "", Flags: utils.DatabasePathFlags, - Category: "DATABASE COMMANDS", Description: ` Remove blockchain and state databases`, } - dbCommand = cli.Command{ + dbCommand = &cli.Command{ Name: "db", Usage: "Low level database operations", ArgsUsage: "", - Category: "DATABASE COMMANDS", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ dbInspectCmd, dbStatCmd, dbCompactCmd, @@ -75,8 +73,8 @@ Remove blockchain and state databases`, dbCheckStateContentCmd, }, } - dbInspectCmd = cli.Command{ - Action: utils.MigrateFlags(inspect), + dbInspectCmd = &cli.Command{ + Action: inspect, Name: "inspect", ArgsUsage: " ", Flags: utils.GroupFlags([]cli.Flag{ @@ -85,8 +83,8 @@ Remove blockchain and state databases`, Usage: "Inspect the storage size for each type of data in the database", Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`, } - dbCheckStateContentCmd = cli.Command{ - Action: utils.MigrateFlags(checkStateContent), + dbCheckStateContentCmd = &cli.Command{ + Action: checkStateContent, Name: "check-state-content", ArgsUsage: "", Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), @@ -95,16 +93,16 @@ Remove blockchain and state databases`, For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates a data corruption.`, } - dbStatCmd = cli.Command{ - Action: utils.MigrateFlags(dbStats), + dbStatCmd = &cli.Command{ + Action: dbStats, Name: "stats", Usage: "Print leveldb statistics", Flags: utils.GroupFlags([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), } - dbCompactCmd = cli.Command{ - Action: utils.MigrateFlags(dbCompact), + dbCompactCmd = &cli.Command{ + Action: dbCompact, Name: "compact", Usage: "Compact leveldb database. WARNING: May take a very long time", Flags: utils.GroupFlags([]cli.Flag{ @@ -116,8 +114,8 @@ a data corruption.`, WARNING: This operation may take a very long time to finish, and may cause database corruption if it is aborted during execution'!`, } - dbGetCmd = cli.Command{ - Action: utils.MigrateFlags(dbGet), + dbGetCmd = &cli.Command{ + Action: dbGet, Name: "get", Usage: "Show the value of a database key", ArgsUsage: "", @@ -126,8 +124,8 @@ corruption if it is aborted during execution'!`, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "This command looks up the specified database key from the database.", } - dbDeleteCmd = cli.Command{ - Action: utils.MigrateFlags(dbDelete), + dbDeleteCmd = &cli.Command{ + Action: dbDelete, Name: "delete", Usage: "Delete a database key (WARNING: may corrupt your database)", ArgsUsage: "", @@ -137,8 +135,8 @@ corruption if it is aborted during execution'!`, Description: `This command deletes the specified database key from the database. WARNING: This is a low-level operation which may cause database corruption!`, } - dbPutCmd = cli.Command{ - Action: utils.MigrateFlags(dbPut), + dbPutCmd = &cli.Command{ + Action: dbPut, Name: "put", Usage: "Set the value of a database key (WARNING: may corrupt your database)", ArgsUsage: " ", @@ -148,8 +146,8 @@ WARNING: This is a low-level operation which may cause database corruption!`, Description: `This command sets a given database key to the given value. WARNING: This is a low-level operation which may cause database corruption!`, } - dbGetSlotsCmd = cli.Command{ - Action: utils.MigrateFlags(dbDumpTrie), + dbGetSlotsCmd = &cli.Command{ + Action: dbDumpTrie, Name: "dumptrie", Usage: "Show the storage key/values of a given storage trie", ArgsUsage: " ", @@ -158,8 +156,8 @@ WARNING: This is a low-level operation which may cause database corruption!`, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "This command looks up the specified database key from the database.", } - dbDumpFreezerIndex = cli.Command{ - Action: utils.MigrateFlags(freezerInspect), + dbDumpFreezerIndex = &cli.Command{ + Action: freezerInspect, Name: "freezer-index", Usage: "Dump out the index of a given freezer type", ArgsUsage: " ", @@ -168,8 +166,8 @@ WARNING: This is a low-level operation which may cause database corruption!`, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "This command displays information about the freezer index.", } - dbImportCmd = cli.Command{ - Action: utils.MigrateFlags(importLDBdata), + dbImportCmd = &cli.Command{ + Action: importLDBdata, Name: "import", Usage: "Imports leveldb-data from an exported RLP dump.", ArgsUsage: " has .gz suffix, gzip compression will be used.", ArgsUsage: " ", @@ -188,8 +186,8 @@ WARNING: This is a low-level operation which may cause database corruption!`, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.", } - dbMetadataCmd = cli.Command{ - Action: utils.MigrateFlags(showMetaData), + dbMetadataCmd = &cli.Command{ + Action: showMetaData, Name: "metadata", Usage: "Shows metadata about the chain status.", Flags: utils.GroupFlags([]cli.Flag{ @@ -197,8 +195,8 @@ WARNING: This is a low-level operation which may cause database corruption!`, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "Shows metadata about the chain status.", } - dbMigrateFreezerCmd = cli.Command{ - Action: utils.MigrateFlags(freezerMigrate), + dbMigrateFreezerCmd = &cli.Command{ + Action: freezerMigrate, Name: "freezer-migrate", Usage: "Migrate legacy parts of the freezer. (WARNING: may take a long time)", ArgsUsage: "", diff --git a/cmd/geth/les_test.go b/cmd/geth/les_test.go index 56ed874cd64a..d86f41054dd8 100644 --- a/cmd/geth/les_test.go +++ b/cmd/geth/les_test.go @@ -144,7 +144,7 @@ func initGeth(t *testing.T) string { func startLightServer(t *testing.T) *gethrpc { datadir := initGeth(t) t.Logf("Importing keys to geth") - runGeth(t, "--datadir", datadir, "--password", "./testdata/password.txt", "account", "import", "./testdata/key.prv", "--lightkdf").WaitExit() + runGeth(t, "account", "import", "--datadir", datadir, "--password", "./testdata/password.txt", "--lightkdf", "./testdata/key.prv").WaitExit() account := "0x02f0d131f1f97aef08aec6e3291b957d9efe7105" server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--mine", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1", "--verbosity=4") return server diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 76d6427fabdf..1ae7116eda79 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -44,7 +44,7 @@ import ( _ "github.com/ethereum/go-ethereum/eth/tracers/js" _ "github.com/ethereum/go-ethereum/eth/tracers/native" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) const ( @@ -208,7 +208,7 @@ func init() { app.Action = geth app.HideVersion = true // we have a command to print the version app.Copyright = "Copyright 2013-2022 The go-ethereum Authors" - app.Commands = []cli.Command{ + app.Commands = []*cli.Command{ // See chaincmd.go: initCommand, importCommand, @@ -242,13 +242,16 @@ func init() { } sort.Sort(cli.CommandsByName(app.Commands)) - app.Flags = utils.GroupFlags(nodeFlags, + app.Flags = utils.GroupFlags( + nodeFlags, rpcFlags, consoleFlags, debug.Flags, - metricsFlags) + metricsFlags, + ) app.Before = func(ctx *cli.Context) error { + flags.MigrateGlobalFlags(ctx) return debug.Setup(ctx) } app.After = func(ctx *cli.Context) error { @@ -270,22 +273,22 @@ func main() { func prepare(ctx *cli.Context) { // If we're running a known preset, log it for convenience. switch { - case ctx.GlobalIsSet(utils.RopstenFlag.Name): + case ctx.IsSet(utils.RopstenFlag.Name): log.Info("Starting Geth on Ropsten testnet...") - case ctx.GlobalIsSet(utils.RinkebyFlag.Name): + case ctx.IsSet(utils.RinkebyFlag.Name): log.Info("Starting Geth on Rinkeby testnet...") - case ctx.GlobalIsSet(utils.GoerliFlag.Name): + case ctx.IsSet(utils.GoerliFlag.Name): log.Info("Starting Geth on Görli testnet...") - case ctx.GlobalIsSet(utils.SepoliaFlag.Name): + case ctx.IsSet(utils.SepoliaFlag.Name): log.Info("Starting Geth on Sepolia testnet...") - case ctx.GlobalIsSet(utils.KilnFlag.Name): + case ctx.IsSet(utils.KilnFlag.Name): log.Info("Starting Geth on Kiln testnet...") - case ctx.GlobalIsSet(utils.DeveloperFlag.Name): + case ctx.IsSet(utils.DeveloperFlag.Name): log.Info("Starting Geth in ephemeral dev mode...") log.Warn(`You are running Geth in --dev mode. Please note the following: @@ -303,27 +306,27 @@ func prepare(ctx *cli.Context) { to 0, and discovery is disabled. `) - case !ctx.GlobalIsSet(utils.NetworkIdFlag.Name): + case !ctx.IsSet(utils.NetworkIdFlag.Name): log.Info("Starting Geth on Ethereum mainnet...") } // If we're a full node on mainnet without --cache specified, bump default cache allowance - if ctx.GlobalString(utils.SyncModeFlag.Name) != "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) && !ctx.GlobalIsSet(utils.NetworkIdFlag.Name) { + if ctx.String(utils.SyncModeFlag.Name) != "light" && !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) { // Make sure we're not on any supported preconfigured testnet either - if !ctx.GlobalIsSet(utils.RopstenFlag.Name) && - !ctx.GlobalIsSet(utils.SepoliaFlag.Name) && - !ctx.GlobalIsSet(utils.RinkebyFlag.Name) && - !ctx.GlobalIsSet(utils.GoerliFlag.Name) && - !ctx.GlobalIsSet(utils.KilnFlag.Name) && - !ctx.GlobalIsSet(utils.DeveloperFlag.Name) { + if !ctx.IsSet(utils.RopstenFlag.Name) && + !ctx.IsSet(utils.SepoliaFlag.Name) && + !ctx.IsSet(utils.RinkebyFlag.Name) && + !ctx.IsSet(utils.GoerliFlag.Name) && + !ctx.IsSet(utils.KilnFlag.Name) && + !ctx.IsSet(utils.DeveloperFlag.Name) { // Nope, we're really on mainnet. Bump that cache up! - log.Info("Bumping default cache on mainnet", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 4096) - ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(4096)) + log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096) + ctx.Set(utils.CacheFlag.Name, strconv.Itoa(4096)) } } // If we're running a light client on any network, drop the cache to some meaningfully low amount - if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) { - log.Info("Dropping default light client cache", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 128) - ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(128)) + if ctx.String(utils.SyncModeFlag.Name) == "light" && !ctx.IsSet(utils.CacheFlag.Name) { + log.Info("Dropping default light client cache", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 128) + ctx.Set(utils.CacheFlag.Name, strconv.Itoa(128)) } // Start metrics export if enabled @@ -337,7 +340,7 @@ func prepare(ctx *cli.Context) { // It creates a default node based on the command line arguments and runs it in // blocking mode, waiting for it to be shut down. func geth(ctx *cli.Context) error { - if args := ctx.Args(); len(args) > 0 { + if args := ctx.Args().Slice(); len(args) > 0 { return fmt.Errorf("invalid command: %q", args[0]) } @@ -408,7 +411,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon // Spawn a standalone goroutine for status synchronization monitoring, // close the node when synchronization is complete if user required. - if ctx.GlobalBool(utils.ExitWhenSyncedFlag.Name) { + if ctx.Bool(utils.ExitWhenSyncedFlag.Name) { go func() { sub := stack.EventMux().Subscribe(downloader.DoneEvent{}) defer sub.Unsubscribe() @@ -431,9 +434,9 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon } // Start auxiliary services if enabled - if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) { + if ctx.Bool(utils.MiningEnabledFlag.Name) || ctx.Bool(utils.DeveloperFlag.Name) { // Mining only makes sense if a full Ethereum node is running - if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { + if ctx.String(utils.SyncModeFlag.Name) == "light" { utils.Fatalf("Light clients do not support mining") } ethBackend, ok := backend.(*eth.EthAPIBackend) @@ -441,10 +444,10 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon utils.Fatalf("Ethereum service not running") } // Set the gas price to the limits from the CLI and start mining - gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) + gasprice := flags.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) ethBackend.TxPool().SetGasPrice(gasprice) // start mining - threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name) + threads := ctx.Int(utils.MinerThreadsFlag.Name) if err := ethBackend.StartMining(threads); err != nil { utils.Fatalf("Failed to start mining: %v", err) } @@ -454,7 +457,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon // unlockAccounts unlocks any account specifically requested. func unlockAccounts(ctx *cli.Context, stack *node.Node) { var unlocks []string - inputs := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") + inputs := strings.Split(ctx.String(utils.UnlockedAccountFlag.Name), ",") for _, input := range inputs { if trimmed := strings.TrimSpace(input); trimmed != "" { unlocks = append(unlocks, trimmed) diff --git a/cmd/geth/misccmd.go b/cmd/geth/misccmd.go index b347d31d97e1..cc5feea9fbc9 100644 --- a/cmd/geth/misccmd.go +++ b/cmd/geth/misccmd.go @@ -26,28 +26,27 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/params" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var ( - VersionCheckUrlFlag = cli.StringFlag{ + VersionCheckUrlFlag = &cli.StringFlag{ Name: "check.url", Usage: "URL to use when checking vulnerabilities", Value: "https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json", } - VersionCheckVersionFlag = cli.StringFlag{ + VersionCheckVersionFlag = &cli.StringFlag{ Name: "check.version", Usage: "Version to check", Value: fmt.Sprintf("Geth/v%v/%v-%v/%v", params.VersionWithCommit(gitCommit, gitDate), runtime.GOOS, runtime.GOARCH, runtime.Version()), } - makecacheCommand = cli.Command{ - Action: utils.MigrateFlags(makecache), + makecacheCommand = &cli.Command{ + Action: makecache, Name: "makecache", Usage: "Generate ethash verification cache (for testing)", ArgsUsage: " ", - Category: "MISCELLANEOUS COMMANDS", Description: ` The makecache command generates an ethash cache in . @@ -55,12 +54,11 @@ This command exists to support the system testing project. Regular users do not need to execute it. `, } - makedagCommand = cli.Command{ - Action: utils.MigrateFlags(makedag), + makedagCommand = &cli.Command{ + Action: makedag, Name: "makedag", Usage: "Generate ethash mining DAG (for testing)", ArgsUsage: " ", - Category: "MISCELLANEOUS COMMANDS", Description: ` The makedag command generates an ethash DAG in . @@ -68,43 +66,40 @@ This command exists to support the system testing project. Regular users do not need to execute it. `, } - versionCommand = cli.Command{ - Action: utils.MigrateFlags(version), + versionCommand = &cli.Command{ + Action: version, Name: "version", Usage: "Print version numbers", ArgsUsage: " ", - Category: "MISCELLANEOUS COMMANDS", Description: ` The output of this command is supposed to be machine-readable. `, } - versionCheckCommand = cli.Command{ - Action: utils.MigrateFlags(versionCheck), + versionCheckCommand = &cli.Command{ + Action: versionCheck, Flags: []cli.Flag{ VersionCheckUrlFlag, VersionCheckVersionFlag, }, Name: "version-check", - Usage: "Checks (online) whether the current version suffers from any known security vulnerabilities", + Usage: "Checks (online) for known Geth security vulnerabilities", ArgsUsage: "", - Category: "MISCELLANEOUS COMMANDS", Description: ` The version-check command fetches vulnerability-information from https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json, and displays information about any security vulnerabilities that affect the currently executing version. `, } - licenseCommand = cli.Command{ - Action: utils.MigrateFlags(license), + licenseCommand = &cli.Command{ + Action: license, Name: "license", Usage: "Display license information", ArgsUsage: " ", - Category: "MISCELLANEOUS COMMANDS", } ) // makecache generates an ethash verification cache into the provided folder. func makecache(ctx *cli.Context) error { - args := ctx.Args() + args := ctx.Args().Slice() if len(args) != 2 { utils.Fatalf(`Usage: geth makecache `) } @@ -119,7 +114,7 @@ func makecache(ctx *cli.Context) error { // makedag generates an ethash mining DAG into the provided folder. func makedag(ctx *cli.Context) error { - args := ctx.Args() + args := ctx.Args().Slice() if len(args) != 2 { utils.Fatalf(`Usage: geth makedag `) } diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index e8c2d0f24188..82206b58b8ea 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -34,7 +34,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - cli "gopkg.in/urfave/cli.v1" + cli "github.com/urfave/cli/v2" ) var ( @@ -46,18 +46,16 @@ var ( ) var ( - snapshotCommand = cli.Command{ + snapshotCommand = &cli.Command{ Name: "snapshot", Usage: "A set of commands based on the snapshot", - Category: "MISCELLANEOUS COMMANDS", Description: "", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "prune-state", Usage: "Prune stale ethereum state data based on the snapshot", ArgsUsage: "", - Action: utils.MigrateFlags(pruneState), - Category: "MISCELLANEOUS COMMANDS", + Action: pruneState, Flags: utils.GroupFlags([]cli.Flag{ utils.CacheTrieJournalFlag, utils.BloomFilterSizeFlag, @@ -81,8 +79,7 @@ the trie clean cache with default directory will be deleted. Name: "verify-state", Usage: "Recalculate state hash based on the snapshot for verification", ArgsUsage: "", - Action: utils.MigrateFlags(verifyState), - Category: "MISCELLANEOUS COMMANDS", + Action: verifyState, Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot verify-state @@ -95,8 +92,7 @@ In other words, this command does the snapshot to trie conversion. Name: "check-dangling-storage", Usage: "Check that there is no 'dangling' snap storage", ArgsUsage: "", - Action: utils.MigrateFlags(checkDanglingStorage), - Category: "MISCELLANEOUS COMMANDS", + Action: checkDanglingStorage, Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot check-dangling-storage traverses the snap storage @@ -107,8 +103,7 @@ data, and verifies that all snapshot storage data has a corresponding account. Name: "inspect-account", Usage: "Check all snapshot layers for the a specific account", ArgsUsage: "
", - Action: utils.MigrateFlags(checkAccount), - Category: "MISCELLANEOUS COMMANDS", + Action: checkAccount, Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot inspect-account
checks all snapshot layers and prints out @@ -119,8 +114,7 @@ information about the specified address. Name: "traverse-state", Usage: "Traverse the state with given root hash and perform quick verification", ArgsUsage: "", - Action: utils.MigrateFlags(traverseState), - Category: "MISCELLANEOUS COMMANDS", + Action: traverseState, Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot traverse-state @@ -135,8 +129,7 @@ It's also usable without snapshot enabled. Name: "traverse-rawstate", Usage: "Traverse the state with given root hash and perform detailed verification", ArgsUsage: "", - Action: utils.MigrateFlags(traverseRawState), - Category: "MISCELLANEOUS COMMANDS", + Action: traverseRawState, Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot traverse-rawstate @@ -152,8 +145,7 @@ It's also usable without snapshot enabled. Name: "dump", Usage: "Dump a specific block from storage (same as 'geth dump' but using snapshots)", ArgsUsage: "[? | ]", - Action: utils.MigrateFlags(dumpState), - Category: "MISCELLANEOUS COMMANDS", + Action: dumpState, Flags: utils.GroupFlags([]cli.Flag{ utils.ExcludeCodeFlag, utils.ExcludeStorageFlag, @@ -177,7 +169,7 @@ func pruneState(ctx *cli.Context) error { defer stack.Close() chaindb := utils.MakeChainDatabase(ctx, stack, false) - pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.GlobalUint64(utils.BloomFilterSizeFlag.Name)) + pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.Uint64(utils.BloomFilterSizeFlag.Name)) if err != nil { log.Error("Failed to open snapshot tree", "err", err) return err @@ -188,7 +180,7 @@ func pruneState(ctx *cli.Context) error { } var targetRoot common.Hash if ctx.NArg() == 1 { - targetRoot, err = parseRoot(ctx.Args()[0]) + targetRoot, err = parseRoot(ctx.Args().First()) if err != nil { log.Error("Failed to resolve state root", "err", err) return err @@ -222,7 +214,7 @@ func verifyState(ctx *cli.Context) error { } var root = headBlock.Root() if ctx.NArg() == 1 { - root, err = parseRoot(ctx.Args()[0]) + root, err = parseRoot(ctx.Args().First()) if err != nil { log.Error("Failed to resolve state root", "err", err) return err @@ -267,7 +259,7 @@ func traverseState(ctx *cli.Context) error { err error ) if ctx.NArg() == 1 { - root, err = parseRoot(ctx.Args()[0]) + root, err = parseRoot(ctx.Args().First()) if err != nil { log.Error("Failed to resolve state root", "err", err) return err @@ -356,7 +348,7 @@ func traverseRawState(ctx *cli.Context) error { err error ) if ctx.NArg() == 1 { - root, err = parseRoot(ctx.Args()[0]) + root, err = parseRoot(ctx.Args().First()) if err != nil { log.Error("Failed to resolve state root", "err", err) return err @@ -558,12 +550,12 @@ func checkAccount(ctx *cli.Context) error { hash common.Hash addr common.Address ) - switch len(ctx.Args()[0]) { + switch arg := ctx.Args().First(); len(arg) { case 40, 42: - addr = common.HexToAddress(ctx.Args()[0]) + addr = common.HexToAddress(arg) hash = crypto.Keccak256Hash(addr.Bytes()) case 64, 66: - hash = common.HexToHash(ctx.Args()[0]) + hash = common.HexToHash(arg) default: return errors.New("malformed address or hash") } diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go deleted file mode 100644 index 56a3d053d640..000000000000 --- a/cmd/geth/usage.go +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// Contains the geth command usage template and generator. - -package main - -import ( - "io" - "sort" - - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/internal/debug" - "github.com/ethereum/go-ethereum/internal/flags" - "gopkg.in/urfave/cli.v1" -) - -// AppHelpFlagGroups is the application flags, grouped by functionality. -var AppHelpFlagGroups = []flags.FlagGroup{ - { - Name: "ETHEREUM", - Flags: utils.GroupFlags([]cli.Flag{ - configFileFlag, - utils.MinFreeDiskSpaceFlag, - utils.KeyStoreDirFlag, - utils.USBFlag, - utils.SmartCardDaemonPathFlag, - utils.NetworkIdFlag, - utils.SyncModeFlag, - utils.ExitWhenSyncedFlag, - utils.GCModeFlag, - utils.TxLookupLimitFlag, - utils.EthStatsURLFlag, - utils.IdentityFlag, - utils.LightKDFFlag, - utils.EthRequiredBlocksFlag, - }, utils.NetworkFlags, utils.DatabasePathFlags), - }, - { - Name: "LIGHT CLIENT", - Flags: []cli.Flag{ - utils.LightServeFlag, - utils.LightIngressFlag, - utils.LightEgressFlag, - utils.LightMaxPeersFlag, - utils.UltraLightServersFlag, - utils.UltraLightFractionFlag, - utils.UltraLightOnlyAnnounceFlag, - utils.LightNoPruneFlag, - utils.LightNoSyncServeFlag, - }, - }, - { - Name: "DEVELOPER CHAIN", - Flags: []cli.Flag{ - utils.DeveloperFlag, - utils.DeveloperPeriodFlag, - utils.DeveloperGasLimitFlag, - }, - }, - { - Name: "ETHASH", - Flags: []cli.Flag{ - utils.EthashCacheDirFlag, - utils.EthashCachesInMemoryFlag, - utils.EthashCachesOnDiskFlag, - utils.EthashCachesLockMmapFlag, - utils.EthashDatasetDirFlag, - utils.EthashDatasetsInMemoryFlag, - utils.EthashDatasetsOnDiskFlag, - utils.EthashDatasetsLockMmapFlag, - }, - }, - { - Name: "TRANSACTION POOL", - Flags: []cli.Flag{ - utils.TxPoolLocalsFlag, - utils.TxPoolNoLocalsFlag, - utils.TxPoolJournalFlag, - utils.TxPoolRejournalFlag, - utils.TxPoolPriceLimitFlag, - utils.TxPoolPriceBumpFlag, - utils.TxPoolAccountSlotsFlag, - utils.TxPoolGlobalSlotsFlag, - utils.TxPoolAccountQueueFlag, - utils.TxPoolGlobalQueueFlag, - utils.TxPoolLifetimeFlag, - }, - }, - { - Name: "PERFORMANCE TUNING", - Flags: []cli.Flag{ - utils.CacheFlag, - utils.CacheDatabaseFlag, - utils.CacheTrieFlag, - utils.CacheTrieJournalFlag, - utils.CacheTrieRejournalFlag, - utils.CacheGCFlag, - utils.CacheSnapshotFlag, - utils.CacheNoPrefetchFlag, - utils.CachePreimagesFlag, - utils.FDLimitFlag, - }, - }, - { - Name: "ACCOUNT", - Flags: []cli.Flag{ - utils.UnlockedAccountFlag, - utils.PasswordFileFlag, - utils.ExternalSignerFlag, - utils.InsecureUnlockAllowedFlag, - }, - }, - { - Name: "API AND CONSOLE", - Flags: []cli.Flag{ - utils.IPCDisabledFlag, - utils.IPCPathFlag, - utils.HTTPEnabledFlag, - utils.HTTPListenAddrFlag, - utils.HTTPPortFlag, - utils.HTTPApiFlag, - utils.HTTPPathPrefixFlag, - utils.HTTPCORSDomainFlag, - utils.HTTPVirtualHostsFlag, - utils.WSEnabledFlag, - utils.WSListenAddrFlag, - utils.WSPortFlag, - utils.WSApiFlag, - utils.WSPathPrefixFlag, - utils.WSAllowedOriginsFlag, - utils.JWTSecretFlag, - utils.AuthListenFlag, - utils.AuthPortFlag, - utils.AuthVirtualHostsFlag, - utils.GraphQLEnabledFlag, - utils.GraphQLCORSDomainFlag, - utils.GraphQLVirtualHostsFlag, - utils.RPCGlobalGasCapFlag, - utils.RPCGlobalEVMTimeoutFlag, - utils.RPCGlobalTxFeeCapFlag, - utils.AllowUnprotectedTxs, - utils.JSpathFlag, - utils.ExecFlag, - utils.PreloadJSFlag, - }, - }, - { - Name: "NETWORKING", - Flags: []cli.Flag{ - utils.BootnodesFlag, - utils.DNSDiscoveryFlag, - utils.ListenPortFlag, - utils.MaxPeersFlag, - utils.MaxPendingPeersFlag, - utils.NATFlag, - utils.NoDiscoverFlag, - utils.DiscoveryV5Flag, - utils.NetrestrictFlag, - utils.NodeKeyFileFlag, - utils.NodeKeyHexFlag, - }, - }, - { - Name: "MINER", - Flags: []cli.Flag{ - utils.MiningEnabledFlag, - utils.MinerThreadsFlag, - utils.MinerNotifyFlag, - utils.MinerNotifyFullFlag, - utils.MinerGasPriceFlag, - utils.MinerGasLimitFlag, - utils.MinerEtherbaseFlag, - utils.MinerExtraDataFlag, - utils.MinerRecommitIntervalFlag, - utils.MinerNoVerifyFlag, - }, - }, - { - Name: "GAS PRICE ORACLE", - Flags: []cli.Flag{ - utils.GpoBlocksFlag, - utils.GpoPercentileFlag, - utils.GpoMaxGasPriceFlag, - utils.GpoIgnoreGasPriceFlag, - }, - }, - { - Name: "VIRTUAL MACHINE", - Flags: []cli.Flag{ - utils.VMEnableDebugFlag, - }, - }, - { - Name: "LOGGING AND DEBUGGING", - Flags: append([]cli.Flag{ - utils.FakePoWFlag, - utils.NoCompactionFlag, - }, debug.Flags...), - }, - { - Name: "METRICS AND STATS", - Flags: metricsFlags, - }, - { - Name: "ALIASED (deprecated)", - Flags: []cli.Flag{ - utils.NoUSBFlag, - utils.LegacyWhitelistFlag, - }, - }, - { - Name: "MISC", - Flags: []cli.Flag{ - utils.SnapshotFlag, - utils.BloomFilterSizeFlag, - utils.IgnoreLegacyReceiptsFlag, - cli.HelpFlag, - }, - }, -} - -func init() { - // Override the default app help template - cli.AppHelpTemplate = flags.AppHelpTemplate - - // Override the default app help printer, but only for the global app help - originalHelpPrinter := cli.HelpPrinter - cli.HelpPrinter = func(w io.Writer, tmpl string, data interface{}) { - if tmpl == flags.AppHelpTemplate { - // Iterate over all the flags and add any uncategorized ones - categorized := make(map[string]struct{}) - for _, group := range AppHelpFlagGroups { - for _, flag := range group.Flags { - categorized[flag.String()] = struct{}{} - } - } - deprecated := make(map[string]struct{}) - for _, flag := range utils.DeprecatedFlags { - deprecated[flag.String()] = struct{}{} - } - // Only add uncategorized flags if they are not deprecated - var uncategorized []cli.Flag - for _, flag := range data.(*cli.App).Flags { - if _, ok := categorized[flag.String()]; !ok { - if _, ok := deprecated[flag.String()]; !ok { - uncategorized = append(uncategorized, flag) - } - } - } - if len(uncategorized) > 0 { - // Append all ungategorized options to the misc group - miscs := len(AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags) - AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags = append(AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags, uncategorized...) - - // Make sure they are removed afterwards - defer func() { - AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags = AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags[:miscs] - }() - } - // Render out custom usage screen - originalHelpPrinter(w, tmpl, flags.HelpData{App: data, FlagGroups: AppHelpFlagGroups}) - } else if tmpl == flags.CommandHelpTemplate { - // Iterate over all command specific flags and categorize them - categorized := make(map[string][]cli.Flag) - for _, flag := range data.(cli.Command).Flags { - if _, ok := categorized[flag.String()]; !ok { - categorized[flags.FlagCategory(flag, AppHelpFlagGroups)] = append(categorized[flags.FlagCategory(flag, AppHelpFlagGroups)], flag) - } - } - - // sort to get a stable ordering - sorted := make([]flags.FlagGroup, 0, len(categorized)) - for cat, flgs := range categorized { - sorted = append(sorted, flags.FlagGroup{Name: cat, Flags: flgs}) - } - sort.Sort(flags.ByCategory(sorted)) - - // add sorted array to data and render with default printer - originalHelpPrinter(w, tmpl, map[string]interface{}{ - "cmd": data, - "categorizedFlags": sorted, - }) - } else { - originalHelpPrinter(w, tmpl, data) - } - } -} diff --git a/cmd/geth/version_check.go b/cmd/geth/version_check.go index 6eaedf373437..237556788eb9 100644 --- a/cmd/geth/version_check.go +++ b/cmd/geth/version_check.go @@ -28,7 +28,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/jedisct1/go-minisign" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var gethPubKeys []string = []string{ diff --git a/cmd/p2psim/main.go b/cmd/p2psim/main.go index eaa457200a43..4edb0a9ab43d 100644 --- a/cmd/p2psim/main.go +++ b/cmd/p2psim/main.go @@ -46,71 +46,77 @@ import ( "text/tabwriter" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/simulations" "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/rpc" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var client *simulations.Client var ( // global command flags - apiFlag = cli.StringFlag{ - Name: "api", - Value: "http://localhost:8888", - Usage: "simulation API URL", - EnvVar: "P2PSIM_API_URL", + apiFlag = &cli.StringFlag{ + Name: "api", + Value: "http://localhost:8888", + Usage: "simulation API URL", + EnvVars: []string{"P2PSIM_API_URL"}, } // events subcommand flags - currentFlag = cli.BoolFlag{ + currentFlag = &cli.BoolFlag{ Name: "current", Usage: "get existing nodes and conns first", } - filterFlag = cli.StringFlag{ + filterFlag = &cli.StringFlag{ Name: "filter", Value: "", Usage: "message filter", } // node create subcommand flags - nameFlag = cli.StringFlag{ + nameFlag = &cli.StringFlag{ Name: "name", Value: "", Usage: "node name", } - servicesFlag = cli.StringFlag{ + servicesFlag = &cli.StringFlag{ Name: "services", Value: "", Usage: "node services (comma separated)", } - keyFlag = cli.StringFlag{ + keyFlag = &cli.StringFlag{ Name: "key", Value: "", Usage: "node private key (hex encoded)", } // node rpc subcommand flags - subscribeFlag = cli.BoolFlag{ + subscribeFlag = &cli.BoolFlag{ Name: "subscribe", Usage: "method is a subscription", } ) +var ( + // Git information set by linker when building with ci.go. + gitCommit string + gitDate string +) + func main() { - app := cli.NewApp() - app.Usage = "devp2p simulation command-line client" + app := flags.NewApp(gitCommit, gitDate, "devp2p simulation command-line client") app.Flags = []cli.Flag{ apiFlag, } app.Before = func(ctx *cli.Context) error { - client = simulations.NewClient(ctx.GlobalString(apiFlag.Name)) + client = simulations.NewClient(ctx.String(apiFlag.Name)) return nil } - app.Commands = []cli.Command{ + app.Commands = []*cli.Command{ { Name: "show", Usage: "show network information", @@ -139,7 +145,7 @@ func main() { Name: "node", Usage: "manage simulation nodes", Action: listNodes, - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "list", Usage: "list nodes", @@ -204,7 +210,7 @@ func main() { } func showNetwork(ctx *cli.Context) error { - if len(ctx.Args()) != 0 { + if ctx.NArg() != 0 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } network, err := client.GetNetwork() @@ -219,7 +225,7 @@ func showNetwork(ctx *cli.Context) error { } func streamNetwork(ctx *cli.Context) error { - if len(ctx.Args()) != 0 { + if ctx.NArg() != 0 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } events := make(chan *simulations.Event) @@ -245,7 +251,7 @@ func streamNetwork(ctx *cli.Context) error { } func createSnapshot(ctx *cli.Context) error { - if len(ctx.Args()) != 0 { + if ctx.NArg() != 0 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } snap, err := client.CreateSnapshot() @@ -256,7 +262,7 @@ func createSnapshot(ctx *cli.Context) error { } func loadSnapshot(ctx *cli.Context) error { - if len(ctx.Args()) != 0 { + if ctx.NArg() != 0 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } snap := &simulations.Snapshot{} @@ -267,7 +273,7 @@ func loadSnapshot(ctx *cli.Context) error { } func listNodes(ctx *cli.Context) error { - if len(ctx.Args()) != 0 { + if ctx.NArg() != 0 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } nodes, err := client.GetNodes() @@ -292,7 +298,7 @@ func protocolList(node *p2p.NodeInfo) []string { } func createNode(ctx *cli.Context) error { - if len(ctx.Args()) != 0 { + if ctx.NArg() != 0 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } config := adapters.RandomNodeConfig() @@ -317,11 +323,10 @@ func createNode(ctx *cli.Context) error { } func showNode(ctx *cli.Context) error { - args := ctx.Args() - if len(args) != 1 { + if ctx.NArg() != 1 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } - nodeName := args[0] + nodeName := ctx.Args().First() node, err := client.GetNode(nodeName) if err != nil { return err @@ -342,11 +347,10 @@ func showNode(ctx *cli.Context) error { } func startNode(ctx *cli.Context) error { - args := ctx.Args() - if len(args) != 1 { + if ctx.NArg() != 1 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } - nodeName := args[0] + nodeName := ctx.Args().First() if err := client.StartNode(nodeName); err != nil { return err } @@ -355,11 +359,10 @@ func startNode(ctx *cli.Context) error { } func stopNode(ctx *cli.Context) error { - args := ctx.Args() - if len(args) != 1 { + if ctx.NArg() != 1 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } - nodeName := args[0] + nodeName := ctx.Args().First() if err := client.StopNode(nodeName); err != nil { return err } @@ -368,12 +371,12 @@ func stopNode(ctx *cli.Context) error { } func connectNode(ctx *cli.Context) error { - args := ctx.Args() - if len(args) != 2 { + if ctx.NArg() != 2 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } - nodeName := args[0] - peerName := args[1] + args := ctx.Args() + nodeName := args.Get(0) + peerName := args.Get(1) if err := client.ConnectNode(nodeName, peerName); err != nil { return err } @@ -383,11 +386,11 @@ func connectNode(ctx *cli.Context) error { func disconnectNode(ctx *cli.Context) error { args := ctx.Args() - if len(args) != 2 { + if args.Len() != 2 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } - nodeName := args[0] - peerName := args[1] + nodeName := args.Get(0) + peerName := args.Get(1) if err := client.DisconnectNode(nodeName, peerName); err != nil { return err } @@ -397,21 +400,21 @@ func disconnectNode(ctx *cli.Context) error { func rpcNode(ctx *cli.Context) error { args := ctx.Args() - if len(args) < 2 { + if args.Len() < 2 { return cli.ShowCommandHelp(ctx, ctx.Command.Name) } - nodeName := args[0] - method := args[1] + nodeName := args.Get(0) + method := args.Get(1) rpcClient, err := client.RPCClient(context.Background(), nodeName) if err != nil { return err } if ctx.Bool(subscribeFlag.Name) { - return rpcSubscribe(rpcClient, ctx.App.Writer, method, args[3:]...) + return rpcSubscribe(rpcClient, ctx.App.Writer, method, args.Slice()[3:]...) } var result interface{} - params := make([]interface{}, len(args[3:])) - for i, v := range args[3:] { + params := make([]interface{}, len(args.Slice()[3:])) + for i, v := range args.Slice()[3:] { params[i] = v } if err := rpcClient.Call(&result, method, params...); err != nil { diff --git a/cmd/puppeth/puppeth.go b/cmd/puppeth/puppeth.go index c3de5f936024..415542b60cc9 100644 --- a/cmd/puppeth/puppeth.go +++ b/cmd/puppeth/puppeth.go @@ -24,7 +24,7 @@ import ( "time" "github.com/ethereum/go-ethereum/log" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) // main is just a boring entry point to set up the CLI app. @@ -33,11 +33,11 @@ func main() { app.Name = "puppeth" app.Usage = "assemble and maintain private Ethereum networks" app.Flags = []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "network", Usage: "name of the network to administer (no spaces or hyphens, please)", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "loglevel", Value: 3, Usage: "log level to emit to the screen", diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 47ad3b22c8dd..90f009041477 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -41,7 +41,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rlp" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) const ( @@ -78,10 +78,10 @@ func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) { defer signal.Stop(sigc) minFreeDiskSpace := 2 * ethconfig.Defaults.TrieDirtyCache // Default 2 * 256Mb - if ctx.GlobalIsSet(MinFreeDiskSpaceFlag.Name) { - minFreeDiskSpace = ctx.GlobalInt(MinFreeDiskSpaceFlag.Name) - } else if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { - minFreeDiskSpace = 2 * ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 + if ctx.IsSet(MinFreeDiskSpaceFlag.Name) { + minFreeDiskSpace = ctx.Int(MinFreeDiskSpaceFlag.Name) + } else if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) { + minFreeDiskSpace = 2 * ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 } if minFreeDiskSpace > 0 { go monitorFreeDiskSpace(sigc, stack.InstanceDir(), uint64(minFreeDiskSpace)*1024*1024) diff --git a/cmd/utils/customflags.go b/cmd/utils/customflags.go deleted file mode 100644 index e5be085a5db7..000000000000 --- a/cmd/utils/customflags.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package utils - -import ( - "encoding" - "errors" - "flag" - "math/big" - "os" - "os/user" - "path" - "strings" - - "github.com/ethereum/go-ethereum/common/math" - "gopkg.in/urfave/cli.v1" -) - -// Custom type which is registered in the flags library which cli uses for -// argument parsing. This allows us to expand Value to an absolute path when -// the argument is parsed -type DirectoryString string - -func (s *DirectoryString) String() string { - return string(*s) -} - -func (s *DirectoryString) Set(value string) error { - *s = DirectoryString(expandPath(value)) - return nil -} - -// Custom cli.Flag type which expand the received string to an absolute path. -// e.g. ~/.ethereum -> /home/username/.ethereum -type DirectoryFlag struct { - Name string - Value DirectoryString - Usage string - EnvVar string -} - -func (f DirectoryFlag) String() string { - return cli.FlagStringer(f) -} - -// called by cli library, grabs variable from environment (if in env) -// and adds variable to flag set for parsing. -func (f DirectoryFlag) Apply(set *flag.FlagSet) { - eachName(f.Name, func(name string) { - set.Var(&f.Value, f.Name, f.Usage) - }) -} - -func (f DirectoryFlag) GetName() string { - return f.Name -} - -func (f *DirectoryFlag) Set(value string) { - f.Value.Set(value) -} - -func eachName(longName string, fn func(string)) { - parts := strings.Split(longName, ",") - for _, name := range parts { - name = strings.Trim(name, " ") - fn(name) - } -} - -type TextMarshaler interface { - encoding.TextMarshaler - encoding.TextUnmarshaler -} - -// textMarshalerVal turns a TextMarshaler into a flag.Value -type textMarshalerVal struct { - v TextMarshaler -} - -func (v textMarshalerVal) String() string { - if v.v == nil { - return "" - } - text, _ := v.v.MarshalText() - return string(text) -} - -func (v textMarshalerVal) Set(s string) error { - return v.v.UnmarshalText([]byte(s)) -} - -// TextMarshalerFlag wraps a TextMarshaler value. -type TextMarshalerFlag struct { - Name string - Value TextMarshaler - Usage string - EnvVar string -} - -func (f TextMarshalerFlag) GetName() string { - return f.Name -} - -func (f TextMarshalerFlag) String() string { - return cli.FlagStringer(f) -} - -func (f TextMarshalerFlag) Apply(set *flag.FlagSet) { - eachName(f.Name, func(name string) { - set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage) - }) -} - -// GlobalTextMarshaler returns the value of a TextMarshalerFlag from the global flag set. -func GlobalTextMarshaler(ctx *cli.Context, name string) TextMarshaler { - val := ctx.GlobalGeneric(name) - if val == nil { - return nil - } - return val.(textMarshalerVal).v -} - -// BigFlag is a command line flag that accepts 256 bit big integers in decimal or -// hexadecimal syntax. -type BigFlag struct { - Name string - Value *big.Int - Usage string - EnvVar string -} - -// bigValue turns *big.Int into a flag.Value -type bigValue big.Int - -func (b *bigValue) String() string { - if b == nil { - return "" - } - return (*big.Int)(b).String() -} - -func (b *bigValue) Set(s string) error { - intVal, ok := math.ParseBig256(s) - if !ok { - return errors.New("invalid integer syntax") - } - *b = (bigValue)(*intVal) - return nil -} - -func (f BigFlag) GetName() string { - return f.Name -} - -func (f BigFlag) String() string { - return cli.FlagStringer(f) -} - -func (f BigFlag) Apply(set *flag.FlagSet) { - eachName(f.Name, func(name string) { - f.Value = new(big.Int) - set.Var((*bigValue)(f.Value), f.Name, f.Usage) - }) -} - -// GlobalBig returns the value of a BigFlag from the global flag set. -func GlobalBig(ctx *cli.Context, name string) *big.Int { - val := ctx.GlobalGeneric(name) - if val == nil { - return nil - } - return (*big.Int)(val.(*bigValue)) -} - -// Expands a file path -// 1. replace tilde with users home dir -// 2. expands embedded environment variables -// 3. cleans the path, e.g. /a/b/../c -> /a/c -// Note, it has limitations, e.g. ~someuser/tmp will not be expanded -func expandPath(p string) string { - if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { - if home := HomeDir(); home != "" { - p = home + p[1:] - } - } - return path.Clean(os.ExpandEnv(p)) -} - -func HomeDir() string { - if home := os.Getenv("HOME"); home != "" { - return home - } - if usr, err := user.Current(); err == nil { - return usr.HomeDir - } - return "" -} diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index e8911330ae24..5cebaba43ecf 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -20,7 +20,6 @@ package utils import ( "crypto/ecdsa" "fmt" - "io" "math" "math/big" "os" @@ -28,8 +27,6 @@ import ( godebug "runtime/debug" "strconv" "strings" - "text/tabwriter" - "text/template" "time" "github.com/ethereum/go-ethereum/accounts" @@ -69,37 +66,9 @@ import ( "github.com/ethereum/go-ethereum/params" pcsclite "github.com/gballet/go-libpcsclite" gopsutil "github.com/shirou/gopsutil/mem" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -func init() { - cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] - -VERSION: - {{.Version}} - -COMMANDS: - {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} - {{end}}{{if .Flags}} -GLOBAL OPTIONS: - {{range .Flags}}{{.}} - {{end}}{{end}} -` - cli.CommandHelpTemplate = flags.CommandHelpTemplate - cli.HelpPrinter = printHelp -} - -func printHelp(out io.Writer, templ string, data interface{}) { - funcMap := template.FuncMap{"join": strings.Join} - t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) - w := tabwriter.NewWriter(out, 38, 8, 2, ' ', 0) - err := t.Execute(w, data) - if err != nil { - panic(err) - } - w.Flush() -} - // These are all the command line flags we support. // If you add to this list, please remember to include the // flag in the appropriate command definition. @@ -109,725 +78,891 @@ func printHelp(out io.Writer, templ string, data interface{}) { var ( // General settings - DataDirFlag = DirectoryFlag{ - Name: "datadir", - Usage: "Data directory for the databases and keystore", - Value: DirectoryString(node.DefaultDataDir()), - } - RemoteDBFlag = cli.StringFlag{ - Name: "remotedb", - Usage: "URL for remote database", - } - AncientFlag = DirectoryFlag{ - Name: "datadir.ancient", - Usage: "Data directory for ancient chain segments (default = inside chaindata)", - } - MinFreeDiskSpaceFlag = DirectoryFlag{ - Name: "datadir.minfreedisk", - Usage: "Minimum free disk space in MB, once reached triggers auto shut down (default = --cache.gc converted to MB, 0 = disabled)", - } - KeyStoreDirFlag = DirectoryFlag{ - Name: "keystore", - Usage: "Directory for the keystore (default = inside the datadir)", - } - USBFlag = cli.BoolFlag{ - Name: "usb", - Usage: "Enable monitoring and management of USB hardware wallets", - } - SmartCardDaemonPathFlag = cli.StringFlag{ - Name: "pcscdpath", - Usage: "Path to the smartcard daemon (pcscd) socket file", - Value: pcsclite.PCSCDSockName, - } - NetworkIdFlag = cli.Uint64Flag{ - Name: "networkid", - Usage: "Explicitly set network id (integer)(For testnets: use --ropsten, --rinkeby, --goerli instead)", - Value: ethconfig.Defaults.NetworkId, - } - MainnetFlag = cli.BoolFlag{ - Name: "mainnet", - Usage: "Ethereum mainnet", - } - RopstenFlag = cli.BoolFlag{ - Name: "ropsten", - Usage: "Ropsten network: pre-configured proof-of-stake test network", - } - RinkebyFlag = cli.BoolFlag{ - Name: "rinkeby", - Usage: "Rinkeby network: pre-configured proof-of-authority test network", - } - GoerliFlag = cli.BoolFlag{ - Name: "goerli", - Usage: "Görli network: pre-configured proof-of-authority test network", - } - SepoliaFlag = cli.BoolFlag{ - Name: "sepolia", - Usage: "Sepolia network: pre-configured proof-of-work test network", - } - KilnFlag = cli.BoolFlag{ - Name: "kiln", - Usage: "Kiln network: pre-configured proof-of-work to proof-of-stake test network", - } - DeveloperFlag = cli.BoolFlag{ - Name: "dev", - Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled", - } - DeveloperPeriodFlag = cli.IntFlag{ - Name: "dev.period", - Usage: "Block period to use in developer mode (0 = mine only if transaction pending)", - } - DeveloperGasLimitFlag = cli.Uint64Flag{ - Name: "dev.gaslimit", - Usage: "Initial block gas limit", - Value: 11500000, - } - IdentityFlag = cli.StringFlag{ - Name: "identity", - Usage: "Custom node name", - } - DocRootFlag = DirectoryFlag{ - Name: "docroot", - Usage: "Document Root for HTTPClient file scheme", - Value: DirectoryString(HomeDir()), - } - ExitWhenSyncedFlag = cli.BoolFlag{ - Name: "exitwhensynced", - Usage: "Exits after block synchronisation completes", - } - IterativeOutputFlag = cli.BoolTFlag{ + DataDirFlag = &flags.DirectoryFlag{ + Name: "datadir", + Usage: "Data directory for the databases and keystore", + Value: flags.DirectoryString(node.DefaultDataDir()), + Category: flags.EthCategory, + } + RemoteDBFlag = &cli.StringFlag{ + Name: "remotedb", + Usage: "URL for remote database", + Category: flags.LoggingCategory, + } + AncientFlag = &flags.DirectoryFlag{ + Name: "datadir.ancient", + Usage: "Data directory for ancient chain segments (default = inside chaindata)", + Category: flags.EthCategory, + } + MinFreeDiskSpaceFlag = &flags.DirectoryFlag{ + Name: "datadir.minfreedisk", + Usage: "Minimum free disk space in MB, once reached triggers auto shut down (default = --cache.gc converted to MB, 0 = disabled)", + Category: flags.EthCategory, + } + KeyStoreDirFlag = &flags.DirectoryFlag{ + Name: "keystore", + Usage: "Directory for the keystore (default = inside the datadir)", + Category: flags.AccountCategory, + } + USBFlag = &cli.BoolFlag{ + Name: "usb", + Usage: "Enable monitoring and management of USB hardware wallets", + Category: flags.AccountCategory, + } + SmartCardDaemonPathFlag = &cli.StringFlag{ + Name: "pcscdpath", + Usage: "Path to the smartcard daemon (pcscd) socket file", + Value: pcsclite.PCSCDSockName, + Category: flags.AccountCategory, + } + NetworkIdFlag = &cli.Uint64Flag{ + Name: "networkid", + Usage: "Explicitly set network id (integer)(For testnets: use --ropsten, --rinkeby, --goerli instead)", + Value: ethconfig.Defaults.NetworkId, + Category: flags.EthCategory, + } + MainnetFlag = &cli.BoolFlag{ + Name: "mainnet", + Usage: "Ethereum mainnet", + Category: flags.EthCategory, + } + RopstenFlag = &cli.BoolFlag{ + Name: "ropsten", + Usage: "Ropsten network: pre-configured proof-of-stake test network", + Category: flags.EthCategory, + } + RinkebyFlag = &cli.BoolFlag{ + Name: "rinkeby", + Usage: "Rinkeby network: pre-configured proof-of-authority test network", + Category: flags.EthCategory, + } + GoerliFlag = &cli.BoolFlag{ + Name: "goerli", + Usage: "Görli network: pre-configured proof-of-authority test network", + Category: flags.EthCategory, + } + SepoliaFlag = &cli.BoolFlag{ + Name: "sepolia", + Usage: "Sepolia network: pre-configured proof-of-work test network", + Category: flags.EthCategory, + } + KilnFlag = &cli.BoolFlag{ + Name: "kiln", + Usage: "Kiln network: pre-configured proof-of-work to proof-of-stake test network", + Category: flags.EthCategory, + } + + // Dev mode + DeveloperFlag = &cli.BoolFlag{ + Name: "dev", + Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled", + Category: flags.DevCategory, + } + DeveloperPeriodFlag = &cli.IntFlag{ + Name: "dev.period", + Usage: "Block period to use in developer mode (0 = mine only if transaction pending)", + Category: flags.DevCategory, + } + DeveloperGasLimitFlag = &cli.Uint64Flag{ + Name: "dev.gaslimit", + Usage: "Initial block gas limit", + Value: 11500000, + Category: flags.DevCategory, + } + + IdentityFlag = &cli.StringFlag{ + Name: "identity", + Usage: "Custom node name", + Category: flags.NetworkingCategory, + } + DocRootFlag = &flags.DirectoryFlag{ + Name: "docroot", + Usage: "Document Root for HTTPClient file scheme", + Value: flags.DirectoryString(flags.HomeDir()), + Category: flags.APICategory, + } + ExitWhenSyncedFlag = &cli.BoolFlag{ + Name: "exitwhensynced", + Usage: "Exits after block synchronisation completes", + Category: flags.EthCategory, + } + + // Dump command options. + IterativeOutputFlag = &cli.BoolFlag{ Name: "iterative", Usage: "Print streaming JSON iteratively, delimited by newlines", + Value: true, } - ExcludeStorageFlag = cli.BoolFlag{ + ExcludeStorageFlag = &cli.BoolFlag{ Name: "nostorage", Usage: "Exclude storage entries (save db lookups)", } - IncludeIncompletesFlag = cli.BoolFlag{ + IncludeIncompletesFlag = &cli.BoolFlag{ Name: "incompletes", Usage: "Include accounts for which we don't have the address (missing preimage)", } - ExcludeCodeFlag = cli.BoolFlag{ + ExcludeCodeFlag = &cli.BoolFlag{ Name: "nocode", Usage: "Exclude contract code (save db lookups)", } - StartKeyFlag = cli.StringFlag{ + StartKeyFlag = &cli.StringFlag{ Name: "start", Usage: "Start position. Either a hash or address", Value: "0x0000000000000000000000000000000000000000000000000000000000000000", } - DumpLimitFlag = cli.Uint64Flag{ + DumpLimitFlag = &cli.Uint64Flag{ Name: "limit", Usage: "Max number of elements (0 = no limit)", Value: 0, } + defaultSyncMode = ethconfig.Defaults.SyncMode - SyncModeFlag = TextMarshalerFlag{ - Name: "syncmode", - Usage: `Blockchain sync mode ("snap", "full" or "light")`, - Value: &defaultSyncMode, - } - GCModeFlag = cli.StringFlag{ - Name: "gcmode", - Usage: `Blockchain garbage collection mode ("full", "archive")`, - Value: "full", - } - SnapshotFlag = cli.BoolTFlag{ - Name: "snapshot", - Usage: `Enables snapshot-database mode (default = enable)`, - } - TxLookupLimitFlag = cli.Uint64Flag{ - Name: "txlookuplimit", - Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)", - Value: ethconfig.Defaults.TxLookupLimit, - } - LightKDFFlag = cli.BoolFlag{ - Name: "lightkdf", - Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", - } - EthRequiredBlocksFlag = cli.StringFlag{ - Name: "eth.requiredblocks", - Usage: "Comma separated block number-to-hash mappings to require for peering (=)", - } - LegacyWhitelistFlag = cli.StringFlag{ - Name: "whitelist", - Usage: "Comma separated block number-to-hash mappings to enforce (=) (deprecated in favor of --eth.requiredblocks)", - } - BloomFilterSizeFlag = cli.Uint64Flag{ - Name: "bloomfilter.size", - Usage: "Megabytes of memory allocated to bloom-filter for pruning", - Value: 2048, - } - OverrideGrayGlacierFlag = cli.Uint64Flag{ - Name: "override.grayglacier", - Usage: "Manually specify Gray Glacier fork-block, overriding the bundled setting", - } - OverrideTerminalTotalDifficulty = BigFlag{ - Name: "override.terminaltotaldifficulty", - Usage: "Manually specify TerminalTotalDifficulty, overriding the bundled setting", + SyncModeFlag = &flags.TextMarshalerFlag{ + Name: "syncmode", + Usage: `Blockchain sync mode ("snap", "full" or "light")`, + Value: &defaultSyncMode, + Category: flags.EthCategory, + } + GCModeFlag = &cli.StringFlag{ + Name: "gcmode", + Usage: `Blockchain garbage collection mode ("full", "archive")`, + Value: "full", + Category: flags.EthCategory, + } + SnapshotFlag = &cli.BoolFlag{ + Name: "snapshot", + Usage: `Enables snapshot-database mode (default = enable)`, + Value: true, + Category: flags.EthCategory, + } + TxLookupLimitFlag = &cli.Uint64Flag{ + Name: "txlookuplimit", + Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)", + Value: ethconfig.Defaults.TxLookupLimit, + Category: flags.EthCategory, + } + LightKDFFlag = &cli.BoolFlag{ + Name: "lightkdf", + Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", + Category: flags.AccountCategory, + } + EthRequiredBlocksFlag = &cli.StringFlag{ + Name: "eth.requiredblocks", + Usage: "Comma separated block number-to-hash mappings to require for peering (=)", + Category: flags.EthCategory, + } + LegacyWhitelistFlag = &cli.StringFlag{ + Name: "whitelist", + Usage: "Comma separated block number-to-hash mappings to enforce (=) (deprecated in favor of --eth.requiredblocks)", + Category: flags.DeprecatedCategory, + } + BloomFilterSizeFlag = &cli.Uint64Flag{ + Name: "bloomfilter.size", + Usage: "Megabytes of memory allocated to bloom-filter for pruning", + Value: 2048, + Category: flags.EthCategory, + } + OverrideGrayGlacierFlag = &cli.Uint64Flag{ + Name: "override.grayglacier", + Usage: "Manually specify Gray Glacier fork-block, overriding the bundled setting", + Category: flags.EthCategory, + } + OverrideTerminalTotalDifficulty = &flags.BigFlag{ + Name: "override.terminaltotaldifficulty", + Usage: "Manually specify TerminalTotalDifficulty, overriding the bundled setting", + Category: flags.EthCategory, } + // Light server and client settings - LightServeFlag = cli.IntFlag{ - Name: "light.serve", - Usage: "Maximum percentage of time allowed for serving LES requests (multi-threaded processing allows values over 100)", - Value: ethconfig.Defaults.LightServ, - } - LightIngressFlag = cli.IntFlag{ - Name: "light.ingress", - Usage: "Incoming bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)", - Value: ethconfig.Defaults.LightIngress, - } - LightEgressFlag = cli.IntFlag{ - Name: "light.egress", - Usage: "Outgoing bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)", - Value: ethconfig.Defaults.LightEgress, - } - LightMaxPeersFlag = cli.IntFlag{ - Name: "light.maxpeers", - Usage: "Maximum number of light clients to serve, or light servers to attach to", - Value: ethconfig.Defaults.LightPeers, - } - UltraLightServersFlag = cli.StringFlag{ - Name: "ulc.servers", - Usage: "List of trusted ultra-light servers", - Value: strings.Join(ethconfig.Defaults.UltraLightServers, ","), - } - UltraLightFractionFlag = cli.IntFlag{ - Name: "ulc.fraction", - Usage: "Minimum % of trusted ultra-light servers required to announce a new head", - Value: ethconfig.Defaults.UltraLightFraction, - } - UltraLightOnlyAnnounceFlag = cli.BoolFlag{ - Name: "ulc.onlyannounce", - Usage: "Ultra light server sends announcements only", - } - LightNoPruneFlag = cli.BoolFlag{ - Name: "light.nopruning", - Usage: "Disable ancient light chain data pruning", - } - LightNoSyncServeFlag = cli.BoolFlag{ - Name: "light.nosyncserve", - Usage: "Enables serving light clients before syncing", + LightServeFlag = &cli.IntFlag{ + Name: "light.serve", + Usage: "Maximum percentage of time allowed for serving LES requests (multi-threaded processing allows values over 100)", + Value: ethconfig.Defaults.LightServ, + Category: flags.LightCategory, + } + LightIngressFlag = &cli.IntFlag{ + Name: "light.ingress", + Usage: "Incoming bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)", + Value: ethconfig.Defaults.LightIngress, + Category: flags.LightCategory, + } + LightEgressFlag = &cli.IntFlag{ + Name: "light.egress", + Usage: "Outgoing bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)", + Value: ethconfig.Defaults.LightEgress, + Category: flags.LightCategory, + } + LightMaxPeersFlag = &cli.IntFlag{ + Name: "light.maxpeers", + Usage: "Maximum number of light clients to serve, or light servers to attach to", + Value: ethconfig.Defaults.LightPeers, + Category: flags.LightCategory, + } + UltraLightServersFlag = &cli.StringFlag{ + Name: "ulc.servers", + Usage: "List of trusted ultra-light servers", + Value: strings.Join(ethconfig.Defaults.UltraLightServers, ","), + Category: flags.LightCategory, + } + UltraLightFractionFlag = &cli.IntFlag{ + Name: "ulc.fraction", + Usage: "Minimum % of trusted ultra-light servers required to announce a new head", + Value: ethconfig.Defaults.UltraLightFraction, + Category: flags.LightCategory, + } + UltraLightOnlyAnnounceFlag = &cli.BoolFlag{ + Name: "ulc.onlyannounce", + Usage: "Ultra light server sends announcements only", + Category: flags.LightCategory, + } + LightNoPruneFlag = &cli.BoolFlag{ + Name: "light.nopruning", + Usage: "Disable ancient light chain data pruning", + Category: flags.LightCategory, + } + LightNoSyncServeFlag = &cli.BoolFlag{ + Name: "light.nosyncserve", + Usage: "Enables serving light clients before syncing", + Category: flags.LightCategory, } + // Ethash settings - EthashCacheDirFlag = DirectoryFlag{ - Name: "ethash.cachedir", - Usage: "Directory to store the ethash verification caches (default = inside the datadir)", - } - EthashCachesInMemoryFlag = cli.IntFlag{ - Name: "ethash.cachesinmem", - Usage: "Number of recent ethash caches to keep in memory (16MB each)", - Value: ethconfig.Defaults.Ethash.CachesInMem, - } - EthashCachesOnDiskFlag = cli.IntFlag{ - Name: "ethash.cachesondisk", - Usage: "Number of recent ethash caches to keep on disk (16MB each)", - Value: ethconfig.Defaults.Ethash.CachesOnDisk, - } - EthashCachesLockMmapFlag = cli.BoolFlag{ - Name: "ethash.cacheslockmmap", - Usage: "Lock memory maps of recent ethash caches", - } - EthashDatasetDirFlag = DirectoryFlag{ - Name: "ethash.dagdir", - Usage: "Directory to store the ethash mining DAGs", - Value: DirectoryString(ethconfig.Defaults.Ethash.DatasetDir), - } - EthashDatasetsInMemoryFlag = cli.IntFlag{ - Name: "ethash.dagsinmem", - Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)", - Value: ethconfig.Defaults.Ethash.DatasetsInMem, - } - EthashDatasetsOnDiskFlag = cli.IntFlag{ - Name: "ethash.dagsondisk", - Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)", - Value: ethconfig.Defaults.Ethash.DatasetsOnDisk, - } - EthashDatasetsLockMmapFlag = cli.BoolFlag{ - Name: "ethash.dagslockmmap", - Usage: "Lock memory maps for recent ethash mining DAGs", + EthashCacheDirFlag = &flags.DirectoryFlag{ + Name: "ethash.cachedir", + Usage: "Directory to store the ethash verification caches (default = inside the datadir)", + Category: flags.EthashCategory, + } + EthashCachesInMemoryFlag = &cli.IntFlag{ + Name: "ethash.cachesinmem", + Usage: "Number of recent ethash caches to keep in memory (16MB each)", + Value: ethconfig.Defaults.Ethash.CachesInMem, + Category: flags.EthashCategory, + } + EthashCachesOnDiskFlag = &cli.IntFlag{ + Name: "ethash.cachesondisk", + Usage: "Number of recent ethash caches to keep on disk (16MB each)", + Value: ethconfig.Defaults.Ethash.CachesOnDisk, + Category: flags.EthashCategory, + } + EthashCachesLockMmapFlag = &cli.BoolFlag{ + Name: "ethash.cacheslockmmap", + Usage: "Lock memory maps of recent ethash caches", + Category: flags.EthashCategory, + } + EthashDatasetDirFlag = &flags.DirectoryFlag{ + Name: "ethash.dagdir", + Usage: "Directory to store the ethash mining DAGs", + Value: flags.DirectoryString(ethconfig.Defaults.Ethash.DatasetDir), + Category: flags.EthashCategory, + } + EthashDatasetsInMemoryFlag = &cli.IntFlag{ + Name: "ethash.dagsinmem", + Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)", + Value: ethconfig.Defaults.Ethash.DatasetsInMem, + Category: flags.EthashCategory, + } + EthashDatasetsOnDiskFlag = &cli.IntFlag{ + Name: "ethash.dagsondisk", + Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)", + Value: ethconfig.Defaults.Ethash.DatasetsOnDisk, + Category: flags.EthashCategory, + } + EthashDatasetsLockMmapFlag = &cli.BoolFlag{ + Name: "ethash.dagslockmmap", + Usage: "Lock memory maps for recent ethash mining DAGs", + Category: flags.EthashCategory, } + // Transaction pool settings - TxPoolLocalsFlag = cli.StringFlag{ - Name: "txpool.locals", - Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)", - } - TxPoolNoLocalsFlag = cli.BoolFlag{ - Name: "txpool.nolocals", - Usage: "Disables price exemptions for locally submitted transactions", - } - TxPoolJournalFlag = cli.StringFlag{ - Name: "txpool.journal", - Usage: "Disk journal for local transaction to survive node restarts", - Value: core.DefaultTxPoolConfig.Journal, - } - TxPoolRejournalFlag = cli.DurationFlag{ - Name: "txpool.rejournal", - Usage: "Time interval to regenerate the local transaction journal", - Value: core.DefaultTxPoolConfig.Rejournal, - } - TxPoolPriceLimitFlag = cli.Uint64Flag{ - Name: "txpool.pricelimit", - Usage: "Minimum gas price limit to enforce for acceptance into the pool", - Value: ethconfig.Defaults.TxPool.PriceLimit, - } - TxPoolPriceBumpFlag = cli.Uint64Flag{ - Name: "txpool.pricebump", - Usage: "Price bump percentage to replace an already existing transaction", - Value: ethconfig.Defaults.TxPool.PriceBump, - } - TxPoolAccountSlotsFlag = cli.Uint64Flag{ - Name: "txpool.accountslots", - Usage: "Minimum number of executable transaction slots guaranteed per account", - Value: ethconfig.Defaults.TxPool.AccountSlots, - } - TxPoolGlobalSlotsFlag = cli.Uint64Flag{ - Name: "txpool.globalslots", - Usage: "Maximum number of executable transaction slots for all accounts", - Value: ethconfig.Defaults.TxPool.GlobalSlots, - } - TxPoolAccountQueueFlag = cli.Uint64Flag{ - Name: "txpool.accountqueue", - Usage: "Maximum number of non-executable transaction slots permitted per account", - Value: ethconfig.Defaults.TxPool.AccountQueue, - } - TxPoolGlobalQueueFlag = cli.Uint64Flag{ - Name: "txpool.globalqueue", - Usage: "Maximum number of non-executable transaction slots for all accounts", - Value: ethconfig.Defaults.TxPool.GlobalQueue, - } - TxPoolLifetimeFlag = cli.DurationFlag{ - Name: "txpool.lifetime", - Usage: "Maximum amount of time non-executable transaction are queued", - Value: ethconfig.Defaults.TxPool.Lifetime, + TxPoolLocalsFlag = &cli.StringFlag{ + Name: "txpool.locals", + Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)", + Category: flags.TxPoolCategory, + } + TxPoolNoLocalsFlag = &cli.BoolFlag{ + Name: "txpool.nolocals", + Usage: "Disables price exemptions for locally submitted transactions", + Category: flags.TxPoolCategory, + } + TxPoolJournalFlag = &cli.StringFlag{ + Name: "txpool.journal", + Usage: "Disk journal for local transaction to survive node restarts", + Value: core.DefaultTxPoolConfig.Journal, + Category: flags.TxPoolCategory, + } + TxPoolRejournalFlag = &cli.DurationFlag{ + Name: "txpool.rejournal", + Usage: "Time interval to regenerate the local transaction journal", + Value: core.DefaultTxPoolConfig.Rejournal, + Category: flags.TxPoolCategory, + } + TxPoolPriceLimitFlag = &cli.Uint64Flag{ + Name: "txpool.pricelimit", + Usage: "Minimum gas price limit to enforce for acceptance into the pool", + Value: ethconfig.Defaults.TxPool.PriceLimit, + Category: flags.TxPoolCategory, + } + TxPoolPriceBumpFlag = &cli.Uint64Flag{ + Name: "txpool.pricebump", + Usage: "Price bump percentage to replace an already existing transaction", + Value: ethconfig.Defaults.TxPool.PriceBump, + Category: flags.TxPoolCategory, + } + TxPoolAccountSlotsFlag = &cli.Uint64Flag{ + Name: "txpool.accountslots", + Usage: "Minimum number of executable transaction slots guaranteed per account", + Value: ethconfig.Defaults.TxPool.AccountSlots, + Category: flags.TxPoolCategory, + } + TxPoolGlobalSlotsFlag = &cli.Uint64Flag{ + Name: "txpool.globalslots", + Usage: "Maximum number of executable transaction slots for all accounts", + Value: ethconfig.Defaults.TxPool.GlobalSlots, + Category: flags.TxPoolCategory, + } + TxPoolAccountQueueFlag = &cli.Uint64Flag{ + Name: "txpool.accountqueue", + Usage: "Maximum number of non-executable transaction slots permitted per account", + Value: ethconfig.Defaults.TxPool.AccountQueue, + Category: flags.TxPoolCategory, + } + TxPoolGlobalQueueFlag = &cli.Uint64Flag{ + Name: "txpool.globalqueue", + Usage: "Maximum number of non-executable transaction slots for all accounts", + Value: ethconfig.Defaults.TxPool.GlobalQueue, + Category: flags.TxPoolCategory, + } + TxPoolLifetimeFlag = &cli.DurationFlag{ + Name: "txpool.lifetime", + Usage: "Maximum amount of time non-executable transaction are queued", + Value: ethconfig.Defaults.TxPool.Lifetime, + Category: flags.TxPoolCategory, } + // Performance tuning settings - CacheFlag = cli.IntFlag{ - Name: "cache", - Usage: "Megabytes of memory allocated to internal caching (default = 4096 mainnet full node, 128 light mode)", - Value: 1024, - } - CacheDatabaseFlag = cli.IntFlag{ - Name: "cache.database", - Usage: "Percentage of cache memory allowance to use for database io", - Value: 50, - } - CacheTrieFlag = cli.IntFlag{ - Name: "cache.trie", - Usage: "Percentage of cache memory allowance to use for trie caching (default = 15% full mode, 30% archive mode)", - Value: 15, - } - CacheTrieJournalFlag = cli.StringFlag{ - Name: "cache.trie.journal", - Usage: "Disk journal directory for trie cache to survive node restarts", - Value: ethconfig.Defaults.TrieCleanCacheJournal, - } - CacheTrieRejournalFlag = cli.DurationFlag{ - Name: "cache.trie.rejournal", - Usage: "Time interval to regenerate the trie cache journal", - Value: ethconfig.Defaults.TrieCleanCacheRejournal, - } - CacheGCFlag = cli.IntFlag{ - Name: "cache.gc", - Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)", - Value: 25, - } - CacheSnapshotFlag = cli.IntFlag{ - Name: "cache.snapshot", - Usage: "Percentage of cache memory allowance to use for snapshot caching (default = 10% full mode, 20% archive mode)", - Value: 10, - } - CacheNoPrefetchFlag = cli.BoolFlag{ - Name: "cache.noprefetch", - Usage: "Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data)", - } - CachePreimagesFlag = cli.BoolFlag{ - Name: "cache.preimages", - Usage: "Enable recording the SHA3/keccak preimages of trie keys", - } - FDLimitFlag = cli.IntFlag{ - Name: "fdlimit", - Usage: "Raise the open file descriptor resource limit (default = system fd limit)", + CacheFlag = &cli.IntFlag{ + Name: "cache", + Usage: "Megabytes of memory allocated to internal caching (default = 4096 mainnet full node, 128 light mode)", + Value: 1024, + Category: flags.PerfCategory, + } + CacheDatabaseFlag = &cli.IntFlag{ + Name: "cache.database", + Usage: "Percentage of cache memory allowance to use for database io", + Value: 50, + Category: flags.PerfCategory, + } + CacheTrieFlag = &cli.IntFlag{ + Name: "cache.trie", + Usage: "Percentage of cache memory allowance to use for trie caching (default = 15% full mode, 30% archive mode)", + Value: 15, + Category: flags.PerfCategory, + } + CacheTrieJournalFlag = &cli.StringFlag{ + Name: "cache.trie.journal", + Usage: "Disk journal directory for trie cache to survive node restarts", + Value: ethconfig.Defaults.TrieCleanCacheJournal, + Category: flags.PerfCategory, + } + CacheTrieRejournalFlag = &cli.DurationFlag{ + Name: "cache.trie.rejournal", + Usage: "Time interval to regenerate the trie cache journal", + Value: ethconfig.Defaults.TrieCleanCacheRejournal, + Category: flags.PerfCategory, + } + CacheGCFlag = &cli.IntFlag{ + Name: "cache.gc", + Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)", + Value: 25, + Category: flags.PerfCategory, + } + CacheSnapshotFlag = &cli.IntFlag{ + Name: "cache.snapshot", + Usage: "Percentage of cache memory allowance to use for snapshot caching (default = 10% full mode, 20% archive mode)", + Value: 10, + Category: flags.PerfCategory, + } + CacheNoPrefetchFlag = &cli.BoolFlag{ + Name: "cache.noprefetch", + Usage: "Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data)", + Category: flags.PerfCategory, + } + CachePreimagesFlag = &cli.BoolFlag{ + Name: "cache.preimages", + Usage: "Enable recording the SHA3/keccak preimages of trie keys", + Category: flags.PerfCategory, + } + FDLimitFlag = &cli.IntFlag{ + Name: "fdlimit", + Usage: "Raise the open file descriptor resource limit (default = system fd limit)", + Category: flags.PerfCategory, } + // Miner settings - MiningEnabledFlag = cli.BoolFlag{ - Name: "mine", - Usage: "Enable mining", - } - MinerThreadsFlag = cli.IntFlag{ - Name: "miner.threads", - Usage: "Number of CPU threads to use for mining", - Value: 0, - } - MinerNotifyFlag = cli.StringFlag{ - Name: "miner.notify", - Usage: "Comma separated HTTP URL list to notify of new work packages", - } - MinerNotifyFullFlag = cli.BoolFlag{ - Name: "miner.notify.full", - Usage: "Notify with pending block headers instead of work packages", - } - MinerGasLimitFlag = cli.Uint64Flag{ - Name: "miner.gaslimit", - Usage: "Target gas ceiling for mined blocks", - Value: ethconfig.Defaults.Miner.GasCeil, - } - MinerGasPriceFlag = BigFlag{ - Name: "miner.gasprice", - Usage: "Minimum gas price for mining a transaction", - Value: ethconfig.Defaults.Miner.GasPrice, - } - MinerEtherbaseFlag = cli.StringFlag{ - Name: "miner.etherbase", - Usage: "Public address for block mining rewards (default = first account)", - Value: "0", - } - MinerExtraDataFlag = cli.StringFlag{ - Name: "miner.extradata", - Usage: "Block extra data set by the miner (default = client version)", - } - MinerRecommitIntervalFlag = cli.DurationFlag{ - Name: "miner.recommit", - Usage: "Time interval to recreate the block being mined", - Value: ethconfig.Defaults.Miner.Recommit, - } - MinerNoVerifyFlag = cli.BoolFlag{ - Name: "miner.noverify", - Usage: "Disable remote sealing verification", + MiningEnabledFlag = &cli.BoolFlag{ + Name: "mine", + Usage: "Enable mining", + Category: flags.MinerCategory, + } + MinerThreadsFlag = &cli.IntFlag{ + Name: "miner.threads", + Usage: "Number of CPU threads to use for mining", + Value: 0, + Category: flags.MinerCategory, + } + MinerNotifyFlag = &cli.StringFlag{ + Name: "miner.notify", + Usage: "Comma separated HTTP URL list to notify of new work packages", + Category: flags.MinerCategory, + } + MinerNotifyFullFlag = &cli.BoolFlag{ + Name: "miner.notify.full", + Usage: "Notify with pending block headers instead of work packages", + Category: flags.MinerCategory, + } + MinerGasLimitFlag = &cli.Uint64Flag{ + Name: "miner.gaslimit", + Usage: "Target gas ceiling for mined blocks", + Value: ethconfig.Defaults.Miner.GasCeil, + Category: flags.MinerCategory, + } + MinerGasPriceFlag = &flags.BigFlag{ + Name: "miner.gasprice", + Usage: "Minimum gas price for mining a transaction", + Value: ethconfig.Defaults.Miner.GasPrice, + Category: flags.MinerCategory, + } + MinerEtherbaseFlag = &cli.StringFlag{ + Name: "miner.etherbase", + Usage: "Public address for block mining rewards (default = first account)", + Value: "0", + Category: flags.MinerCategory, + } + MinerExtraDataFlag = &cli.StringFlag{ + Name: "miner.extradata", + Usage: "Block extra data set by the miner (default = client version)", + Category: flags.MinerCategory, + } + MinerRecommitIntervalFlag = &cli.DurationFlag{ + Name: "miner.recommit", + Usage: "Time interval to recreate the block being mined", + Value: ethconfig.Defaults.Miner.Recommit, + Category: flags.MinerCategory, + } + MinerNoVerifyFlag = &cli.BoolFlag{ + Name: "miner.noverify", + Usage: "Disable remote sealing verification", + Category: flags.MinerCategory, } + // Account settings - UnlockedAccountFlag = cli.StringFlag{ - Name: "unlock", - Usage: "Comma separated list of accounts to unlock", - Value: "", - } - PasswordFileFlag = cli.StringFlag{ - Name: "password", - Usage: "Password file to use for non-interactive password input", - Value: "", - } - ExternalSignerFlag = cli.StringFlag{ - Name: "signer", - Usage: "External signer (url or path to ipc file)", - Value: "", - } - VMEnableDebugFlag = cli.BoolFlag{ - Name: "vmdebug", - Usage: "Record information useful for VM and contract debugging", - } - InsecureUnlockAllowedFlag = cli.BoolFlag{ - Name: "allow-insecure-unlock", - Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http", - } - RPCGlobalGasCapFlag = cli.Uint64Flag{ - Name: "rpc.gascap", - Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)", - Value: ethconfig.Defaults.RPCGasCap, - } - RPCGlobalEVMTimeoutFlag = cli.DurationFlag{ - Name: "rpc.evmtimeout", - Usage: "Sets a timeout used for eth_call (0=infinite)", - Value: ethconfig.Defaults.RPCEVMTimeout, - } - RPCGlobalTxFeeCapFlag = cli.Float64Flag{ - Name: "rpc.txfeecap", - Usage: "Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)", - Value: ethconfig.Defaults.RPCTxFeeCap, + UnlockedAccountFlag = &cli.StringFlag{ + Name: "unlock", + Usage: "Comma separated list of accounts to unlock", + Value: "", + Category: flags.AccountCategory, + } + PasswordFileFlag = &cli.PathFlag{ + Name: "password", + Usage: "Password file to use for non-interactive password input", + TakesFile: true, + Category: flags.AccountCategory, + } + ExternalSignerFlag = &cli.StringFlag{ + Name: "signer", + Usage: "External signer (url or path to ipc file)", + Value: "", + Category: flags.AccountCategory, + } + InsecureUnlockAllowedFlag = &cli.BoolFlag{ + Name: "allow-insecure-unlock", + Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http", + Category: flags.AccountCategory, + } + + // EVM settings + VMEnableDebugFlag = &cli.BoolFlag{ + Name: "vmdebug", + Usage: "Record information useful for VM and contract debugging", + Category: flags.VMCategory, + } + + // API options. + RPCGlobalGasCapFlag = &cli.Uint64Flag{ + Name: "rpc.gascap", + Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)", + Value: ethconfig.Defaults.RPCGasCap, + Category: flags.APICategory, + } + RPCGlobalEVMTimeoutFlag = &cli.DurationFlag{ + Name: "rpc.evmtimeout", + Usage: "Sets a timeout used for eth_call (0=infinite)", + Value: ethconfig.Defaults.RPCEVMTimeout, + Category: flags.APICategory, + } + RPCGlobalTxFeeCapFlag = &cli.Float64Flag{ + Name: "rpc.txfeecap", + Usage: "Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)", + Value: ethconfig.Defaults.RPCTxFeeCap, + Category: flags.APICategory, } // Authenticated RPC HTTP settings - AuthListenFlag = cli.StringFlag{ - Name: "authrpc.addr", - Usage: "Listening address for authenticated APIs", - Value: node.DefaultConfig.AuthAddr, - } - AuthPortFlag = cli.IntFlag{ - Name: "authrpc.port", - Usage: "Listening port for authenticated APIs", - Value: node.DefaultConfig.AuthPort, - } - AuthVirtualHostsFlag = cli.StringFlag{ - Name: "authrpc.vhosts", - Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", - Value: strings.Join(node.DefaultConfig.AuthVirtualHosts, ","), - } - JWTSecretFlag = cli.StringFlag{ - Name: "authrpc.jwtsecret", - Usage: "Path to a JWT secret to use for authenticated RPC endpoints", + AuthListenFlag = &cli.StringFlag{ + Name: "authrpc.addr", + Usage: "Listening address for authenticated APIs", + Value: node.DefaultConfig.AuthAddr, + Category: flags.APICategory, + } + AuthPortFlag = &cli.IntFlag{ + Name: "authrpc.port", + Usage: "Listening port for authenticated APIs", + Value: node.DefaultConfig.AuthPort, + Category: flags.APICategory, + } + AuthVirtualHostsFlag = &cli.StringFlag{ + Name: "authrpc.vhosts", + Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", + Value: strings.Join(node.DefaultConfig.AuthVirtualHosts, ","), + Category: flags.APICategory, + } + JWTSecretFlag = &cli.StringFlag{ + Name: "authrpc.jwtsecret", + Usage: "Path to a JWT secret to use for authenticated RPC endpoints", + Category: flags.APICategory, } + // Logging and debug settings - EthStatsURLFlag = cli.StringFlag{ - Name: "ethstats", - Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", + EthStatsURLFlag = &cli.StringFlag{ + Name: "ethstats", + Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", + Category: flags.MetricsCategory, } - FakePoWFlag = cli.BoolFlag{ - Name: "fakepow", - Usage: "Disables proof-of-work verification", + FakePoWFlag = &cli.BoolFlag{ + Name: "fakepow", + Usage: "Disables proof-of-work verification", + Category: flags.LoggingCategory, } - NoCompactionFlag = cli.BoolFlag{ - Name: "nocompaction", - Usage: "Disables db compaction after import", + NoCompactionFlag = &cli.BoolFlag{ + Name: "nocompaction", + Usage: "Disables db compaction after import", + Category: flags.LoggingCategory, } - IgnoreLegacyReceiptsFlag = cli.BoolFlag{ - Name: "ignore-legacy-receipts", - Usage: "Geth will start up even if there are legacy receipts in freezer", + + IgnoreLegacyReceiptsFlag = &cli.BoolFlag{ + Name: "ignore-legacy-receipts", + Usage: "Geth will start up even if there are legacy receipts in freezer", + Category: flags.MiscCategory, } + // RPC settings - IPCDisabledFlag = cli.BoolFlag{ - Name: "ipcdisable", - Usage: "Disable the IPC-RPC server", - } - IPCPathFlag = DirectoryFlag{ - Name: "ipcpath", - Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", - } - HTTPEnabledFlag = cli.BoolFlag{ - Name: "http", - Usage: "Enable the HTTP-RPC server", - } - HTTPListenAddrFlag = cli.StringFlag{ - Name: "http.addr", - Usage: "HTTP-RPC server listening interface", - Value: node.DefaultHTTPHost, - } - HTTPPortFlag = cli.IntFlag{ - Name: "http.port", - Usage: "HTTP-RPC server listening port", - Value: node.DefaultHTTPPort, - } - HTTPCORSDomainFlag = cli.StringFlag{ - Name: "http.corsdomain", - Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", - Value: "", - } - HTTPVirtualHostsFlag = cli.StringFlag{ - Name: "http.vhosts", - Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", - Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","), - } - HTTPApiFlag = cli.StringFlag{ - Name: "http.api", - Usage: "API's offered over the HTTP-RPC interface", - Value: "", - } - HTTPPathPrefixFlag = cli.StringFlag{ - Name: "http.rpcprefix", - Usage: "HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", - Value: "", - } - GraphQLEnabledFlag = cli.BoolFlag{ - Name: "graphql", - Usage: "Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.", - } - GraphQLCORSDomainFlag = cli.StringFlag{ - Name: "graphql.corsdomain", - Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", - Value: "", - } - GraphQLVirtualHostsFlag = cli.StringFlag{ - Name: "graphql.vhosts", - Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", - Value: strings.Join(node.DefaultConfig.GraphQLVirtualHosts, ","), - } - WSEnabledFlag = cli.BoolFlag{ - Name: "ws", - Usage: "Enable the WS-RPC server", - } - WSListenAddrFlag = cli.StringFlag{ - Name: "ws.addr", - Usage: "WS-RPC server listening interface", - Value: node.DefaultWSHost, - } - WSPortFlag = cli.IntFlag{ - Name: "ws.port", - Usage: "WS-RPC server listening port", - Value: node.DefaultWSPort, - } - WSApiFlag = cli.StringFlag{ - Name: "ws.api", - Usage: "API's offered over the WS-RPC interface", - Value: "", - } - WSAllowedOriginsFlag = cli.StringFlag{ - Name: "ws.origins", - Usage: "Origins from which to accept websockets requests", - Value: "", - } - WSPathPrefixFlag = cli.StringFlag{ - Name: "ws.rpcprefix", - Usage: "HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", - Value: "", - } - ExecFlag = cli.StringFlag{ - Name: "exec", - Usage: "Execute JavaScript statement", - } - PreloadJSFlag = cli.StringFlag{ - Name: "preload", - Usage: "Comma separated list of JavaScript files to preload into the console", - } - AllowUnprotectedTxs = cli.BoolFlag{ - Name: "rpc.allow-unprotected-txs", - Usage: "Allow for unprotected (non EIP155 signed) transactions to be submitted via RPC", + IPCDisabledFlag = &cli.BoolFlag{ + Name: "ipcdisable", + Usage: "Disable the IPC-RPC server", + Category: flags.APICategory, + } + IPCPathFlag = &flags.DirectoryFlag{ + Name: "ipcpath", + Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", + Category: flags.APICategory, + } + HTTPEnabledFlag = &cli.BoolFlag{ + Name: "http", + Usage: "Enable the HTTP-RPC server", + Category: flags.APICategory, + } + HTTPListenAddrFlag = &cli.StringFlag{ + Name: "http.addr", + Usage: "HTTP-RPC server listening interface", + Value: node.DefaultHTTPHost, + Category: flags.APICategory, + } + HTTPPortFlag = &cli.IntFlag{ + Name: "http.port", + Usage: "HTTP-RPC server listening port", + Value: node.DefaultHTTPPort, + Category: flags.APICategory, + } + HTTPCORSDomainFlag = &cli.StringFlag{ + Name: "http.corsdomain", + Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", + Value: "", + Category: flags.APICategory, + } + HTTPVirtualHostsFlag = &cli.StringFlag{ + Name: "http.vhosts", + Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", + Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","), + Category: flags.APICategory, + } + HTTPApiFlag = &cli.StringFlag{ + Name: "http.api", + Usage: "API's offered over the HTTP-RPC interface", + Value: "", + Category: flags.APICategory, + } + HTTPPathPrefixFlag = &cli.StringFlag{ + Name: "http.rpcprefix", + Usage: "HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", + Value: "", + Category: flags.APICategory, + } + GraphQLEnabledFlag = &cli.BoolFlag{ + Name: "graphql", + Usage: "Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.", + Category: flags.APICategory, + } + GraphQLCORSDomainFlag = &cli.StringFlag{ + Name: "graphql.corsdomain", + Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", + Value: "", + Category: flags.APICategory, + } + GraphQLVirtualHostsFlag = &cli.StringFlag{ + Name: "graphql.vhosts", + Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", + Value: strings.Join(node.DefaultConfig.GraphQLVirtualHosts, ","), + Category: flags.APICategory, + } + WSEnabledFlag = &cli.BoolFlag{ + Name: "ws", + Usage: "Enable the WS-RPC server", + Category: flags.APICategory, + } + WSListenAddrFlag = &cli.StringFlag{ + Name: "ws.addr", + Usage: "WS-RPC server listening interface", + Value: node.DefaultWSHost, + Category: flags.APICategory, + } + WSPortFlag = &cli.IntFlag{ + Name: "ws.port", + Usage: "WS-RPC server listening port", + Value: node.DefaultWSPort, + Category: flags.APICategory, + } + WSApiFlag = &cli.StringFlag{ + Name: "ws.api", + Usage: "API's offered over the WS-RPC interface", + Value: "", + Category: flags.APICategory, + } + WSAllowedOriginsFlag = &cli.StringFlag{ + Name: "ws.origins", + Usage: "Origins from which to accept websockets requests", + Value: "", + Category: flags.APICategory, + } + WSPathPrefixFlag = &cli.StringFlag{ + Name: "ws.rpcprefix", + Usage: "HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", + Value: "", + Category: flags.APICategory, + } + ExecFlag = &cli.StringFlag{ + Name: "exec", + Usage: "Execute JavaScript statement", + Category: flags.APICategory, + } + PreloadJSFlag = &cli.StringFlag{ + Name: "preload", + Usage: "Comma separated list of JavaScript files to preload into the console", + Category: flags.APICategory, + } + AllowUnprotectedTxs = &cli.BoolFlag{ + Name: "rpc.allow-unprotected-txs", + Usage: "Allow for unprotected (non EIP155 signed) transactions to be submitted via RPC", + Category: flags.APICategory, } // Network Settings - MaxPeersFlag = cli.IntFlag{ - Name: "maxpeers", - Usage: "Maximum number of network peers (network disabled if set to 0)", - Value: node.DefaultConfig.P2P.MaxPeers, - } - MaxPendingPeersFlag = cli.IntFlag{ - Name: "maxpendpeers", - Usage: "Maximum number of pending connection attempts (defaults used if set to 0)", - Value: node.DefaultConfig.P2P.MaxPendingPeers, - } - ListenPortFlag = cli.IntFlag{ - Name: "port", - Usage: "Network listening port", - Value: 30303, - } - BootnodesFlag = cli.StringFlag{ - Name: "bootnodes", - Usage: "Comma separated enode URLs for P2P discovery bootstrap", - Value: "", - } - NodeKeyFileFlag = cli.StringFlag{ - Name: "nodekey", - Usage: "P2P node key file", - } - NodeKeyHexFlag = cli.StringFlag{ - Name: "nodekeyhex", - Usage: "P2P node key as hex (for testing)", - } - NATFlag = cli.StringFlag{ - Name: "nat", - Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:)", - Value: "any", - } - NoDiscoverFlag = cli.BoolFlag{ - Name: "nodiscover", - Usage: "Disables the peer discovery mechanism (manual peer addition)", - } - DiscoveryV5Flag = cli.BoolFlag{ - Name: "v5disc", - Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", - } - NetrestrictFlag = cli.StringFlag{ - Name: "netrestrict", - Usage: "Restricts network communication to the given IP networks (CIDR masks)", - } - DNSDiscoveryFlag = cli.StringFlag{ - Name: "discovery.dns", - Usage: "Sets DNS discovery entry points (use \"\" to disable DNS)", - } - - // ATM the url is left to the user and deployment to - JSpathFlag = DirectoryFlag{ - Name: "jspath", - Usage: "JavaScript root path for `loadScript`", - Value: DirectoryString("."), + MaxPeersFlag = &cli.IntFlag{ + Name: "maxpeers", + Usage: "Maximum number of network peers (network disabled if set to 0)", + Value: node.DefaultConfig.P2P.MaxPeers, + Category: flags.NetworkingCategory, + } + MaxPendingPeersFlag = &cli.IntFlag{ + Name: "maxpendpeers", + Usage: "Maximum number of pending connection attempts (defaults used if set to 0)", + Value: node.DefaultConfig.P2P.MaxPendingPeers, + Category: flags.NetworkingCategory, + } + ListenPortFlag = &cli.IntFlag{ + Name: "port", + Usage: "Network listening port", + Value: 30303, + Category: flags.NetworkingCategory, + } + BootnodesFlag = &cli.StringFlag{ + Name: "bootnodes", + Usage: "Comma separated enode URLs for P2P discovery bootstrap", + Value: "", + Category: flags.NetworkingCategory, + } + NodeKeyFileFlag = &cli.StringFlag{ + Name: "nodekey", + Usage: "P2P node key file", + Category: flags.NetworkingCategory, + } + NodeKeyHexFlag = &cli.StringFlag{ + Name: "nodekeyhex", + Usage: "P2P node key as hex (for testing)", + Category: flags.NetworkingCategory, + } + NATFlag = &cli.StringFlag{ + Name: "nat", + Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:)", + Value: "any", + Category: flags.NetworkingCategory, + } + NoDiscoverFlag = &cli.BoolFlag{ + Name: "nodiscover", + Usage: "Disables the peer discovery mechanism (manual peer addition)", + Category: flags.NetworkingCategory, + } + DiscoveryV5Flag = &cli.BoolFlag{ + Name: "v5disc", + Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", + Category: flags.NetworkingCategory, + } + NetrestrictFlag = &cli.StringFlag{ + Name: "netrestrict", + Usage: "Restricts network communication to the given IP networks (CIDR masks)", + Category: flags.NetworkingCategory, + } + DNSDiscoveryFlag = &cli.StringFlag{ + Name: "discovery.dns", + Usage: "Sets DNS discovery entry points (use \"\" to disable DNS)", + Category: flags.NetworkingCategory, + } + + // Console + JSpathFlag = &flags.DirectoryFlag{ + Name: "jspath", + Usage: "JavaScript root path for `loadScript`", + Value: flags.DirectoryString("."), + Category: flags.APICategory, } // Gas price oracle settings - GpoBlocksFlag = cli.IntFlag{ - Name: "gpo.blocks", - Usage: "Number of recent blocks to check for gas prices", - Value: ethconfig.Defaults.GPO.Blocks, - } - GpoPercentileFlag = cli.IntFlag{ - Name: "gpo.percentile", - Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices", - Value: ethconfig.Defaults.GPO.Percentile, - } - GpoMaxGasPriceFlag = cli.Int64Flag{ - Name: "gpo.maxprice", - Usage: "Maximum transaction priority fee (or gasprice before London fork) to be recommended by gpo", - Value: ethconfig.Defaults.GPO.MaxPrice.Int64(), - } - GpoIgnoreGasPriceFlag = cli.Int64Flag{ - Name: "gpo.ignoreprice", - Usage: "Gas price below which gpo will ignore transactions", - Value: ethconfig.Defaults.GPO.IgnorePrice.Int64(), + GpoBlocksFlag = &cli.IntFlag{ + Name: "gpo.blocks", + Usage: "Number of recent blocks to check for gas prices", + Value: ethconfig.Defaults.GPO.Blocks, + Category: flags.GasPriceCategory, + } + GpoPercentileFlag = &cli.IntFlag{ + Name: "gpo.percentile", + Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices", + Value: ethconfig.Defaults.GPO.Percentile, + Category: flags.GasPriceCategory, + } + GpoMaxGasPriceFlag = &cli.Int64Flag{ + Name: "gpo.maxprice", + Usage: "Maximum transaction priority fee (or gasprice before London fork) to be recommended by gpo", + Value: ethconfig.Defaults.GPO.MaxPrice.Int64(), + Category: flags.GasPriceCategory, + } + GpoIgnoreGasPriceFlag = &cli.Int64Flag{ + Name: "gpo.ignoreprice", + Usage: "Gas price below which gpo will ignore transactions", + Value: ethconfig.Defaults.GPO.IgnorePrice.Int64(), + Category: flags.GasPriceCategory, } // Metrics flags - MetricsEnabledFlag = cli.BoolFlag{ - Name: "metrics", - Usage: "Enable metrics collection and reporting", + MetricsEnabledFlag = &cli.BoolFlag{ + Name: "metrics", + Usage: "Enable metrics collection and reporting", + Category: flags.MetricsCategory, } - MetricsEnabledExpensiveFlag = cli.BoolFlag{ - Name: "metrics.expensive", - Usage: "Enable expensive metrics collection and reporting", + MetricsEnabledExpensiveFlag = &cli.BoolFlag{ + Name: "metrics.expensive", + Usage: "Enable expensive metrics collection and reporting", + Category: flags.MetricsCategory, } // MetricsHTTPFlag defines the endpoint for a stand-alone metrics HTTP endpoint. // Since the pprof service enables sensitive/vulnerable behavior, this allows a user // to enable a public-OK metrics endpoint without having to worry about ALSO exposing // other profiling behavior or information. - MetricsHTTPFlag = cli.StringFlag{ - Name: "metrics.addr", - Usage: "Enable stand-alone metrics HTTP server listening interface", - Value: metrics.DefaultConfig.HTTP, - } - MetricsPortFlag = cli.IntFlag{ - Name: "metrics.port", - Usage: "Metrics HTTP server listening port", - Value: metrics.DefaultConfig.Port, - } - MetricsEnableInfluxDBFlag = cli.BoolFlag{ - Name: "metrics.influxdb", - Usage: "Enable metrics export/push to an external InfluxDB database", - } - MetricsInfluxDBEndpointFlag = cli.StringFlag{ - Name: "metrics.influxdb.endpoint", - Usage: "InfluxDB API endpoint to report metrics to", - Value: metrics.DefaultConfig.InfluxDBEndpoint, - } - MetricsInfluxDBDatabaseFlag = cli.StringFlag{ - Name: "metrics.influxdb.database", - Usage: "InfluxDB database name to push reported metrics to", - Value: metrics.DefaultConfig.InfluxDBDatabase, - } - MetricsInfluxDBUsernameFlag = cli.StringFlag{ - Name: "metrics.influxdb.username", - Usage: "Username to authorize access to the database", - Value: metrics.DefaultConfig.InfluxDBUsername, - } - MetricsInfluxDBPasswordFlag = cli.StringFlag{ - Name: "metrics.influxdb.password", - Usage: "Password to authorize access to the database", - Value: metrics.DefaultConfig.InfluxDBPassword, + MetricsHTTPFlag = &cli.StringFlag{ + Name: "metrics.addr", + Usage: "Enable stand-alone metrics HTTP server listening interface", + Value: metrics.DefaultConfig.HTTP, + Category: flags.MetricsCategory, + } + MetricsPortFlag = &cli.IntFlag{ + Name: "metrics.port", + Usage: "Metrics HTTP server listening port", + Value: metrics.DefaultConfig.Port, + Category: flags.MetricsCategory, + } + MetricsEnableInfluxDBFlag = &cli.BoolFlag{ + Name: "metrics.influxdb", + Usage: "Enable metrics export/push to an external InfluxDB database", + Category: flags.MetricsCategory, + } + MetricsInfluxDBEndpointFlag = &cli.StringFlag{ + Name: "metrics.influxdb.endpoint", + Usage: "InfluxDB API endpoint to report metrics to", + Value: metrics.DefaultConfig.InfluxDBEndpoint, + Category: flags.MetricsCategory, + } + MetricsInfluxDBDatabaseFlag = &cli.StringFlag{ + Name: "metrics.influxdb.database", + Usage: "InfluxDB database name to push reported metrics to", + Value: metrics.DefaultConfig.InfluxDBDatabase, + Category: flags.MetricsCategory, + } + MetricsInfluxDBUsernameFlag = &cli.StringFlag{ + Name: "metrics.influxdb.username", + Usage: "Username to authorize access to the database", + Value: metrics.DefaultConfig.InfluxDBUsername, + Category: flags.MetricsCategory, + } + MetricsInfluxDBPasswordFlag = &cli.StringFlag{ + Name: "metrics.influxdb.password", + Usage: "Password to authorize access to the database", + Value: metrics.DefaultConfig.InfluxDBPassword, + Category: flags.MetricsCategory, } // Tags are part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. // For example `host` tag could be used so that we can group all nodes and average a measurement // across all of them, but also so that we can select a specific node and inspect its measurements. // https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key - MetricsInfluxDBTagsFlag = cli.StringFlag{ - Name: "metrics.influxdb.tags", - Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements", - Value: metrics.DefaultConfig.InfluxDBTags, + MetricsInfluxDBTagsFlag = &cli.StringFlag{ + Name: "metrics.influxdb.tags", + Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements", + Value: metrics.DefaultConfig.InfluxDBTags, + Category: flags.MetricsCategory, } - MetricsEnableInfluxDBV2Flag = cli.BoolFlag{ - Name: "metrics.influxdbv2", - Usage: "Enable metrics export/push to an external InfluxDB v2 database", + MetricsEnableInfluxDBV2Flag = &cli.BoolFlag{ + Name: "metrics.influxdbv2", + Usage: "Enable metrics export/push to an external InfluxDB v2 database", + Category: flags.MetricsCategory, } - MetricsInfluxDBTokenFlag = cli.StringFlag{ - Name: "metrics.influxdb.token", - Usage: "Token to authorize access to the database (v2 only)", - Value: metrics.DefaultConfig.InfluxDBToken, + MetricsInfluxDBTokenFlag = &cli.StringFlag{ + Name: "metrics.influxdb.token", + Usage: "Token to authorize access to the database (v2 only)", + Value: metrics.DefaultConfig.InfluxDBToken, + Category: flags.MetricsCategory, } - MetricsInfluxDBBucketFlag = cli.StringFlag{ - Name: "metrics.influxdb.bucket", - Usage: "InfluxDB bucket name to push reported metrics to (v2 only)", - Value: metrics.DefaultConfig.InfluxDBBucket, + MetricsInfluxDBBucketFlag = &cli.StringFlag{ + Name: "metrics.influxdb.bucket", + Usage: "InfluxDB bucket name to push reported metrics to (v2 only)", + Value: metrics.DefaultConfig.InfluxDBBucket, + Category: flags.MetricsCategory, } - MetricsInfluxDBOrganizationFlag = cli.StringFlag{ - Name: "metrics.influxdb.organization", - Usage: "InfluxDB organization name (v2 only)", - Value: metrics.DefaultConfig.InfluxDBOrganization, + MetricsInfluxDBOrganizationFlag = &cli.StringFlag{ + Name: "metrics.influxdb.organization", + Usage: "InfluxDB organization name (v2 only)", + Value: metrics.DefaultConfig.InfluxDBOrganization, + Category: flags.MetricsCategory, } ) @@ -866,22 +1001,22 @@ func GroupFlags(groups ...[]cli.Flag) []cli.Flag { // if none (or the empty string) is specified. If the node is starting a testnet, // then a subdirectory of the specified datadir will be used. func MakeDataDir(ctx *cli.Context) string { - if path := ctx.GlobalString(DataDirFlag.Name); path != "" { - if ctx.GlobalBool(RopstenFlag.Name) { + if path := ctx.String(DataDirFlag.Name); path != "" { + if ctx.Bool(RopstenFlag.Name) { // Maintain compatibility with older Geth configurations storing the // Ropsten database in `testnet` instead of `ropsten`. return filepath.Join(path, "ropsten") } - if ctx.GlobalBool(RinkebyFlag.Name) { + if ctx.Bool(RinkebyFlag.Name) { return filepath.Join(path, "rinkeby") } - if ctx.GlobalBool(GoerliFlag.Name) { + if ctx.Bool(GoerliFlag.Name) { return filepath.Join(path, "goerli") } - if ctx.GlobalBool(SepoliaFlag.Name) { + if ctx.Bool(SepoliaFlag.Name) { return filepath.Join(path, "sepolia") } - if ctx.GlobalBool(KilnFlag.Name) { + if ctx.Bool(KilnFlag.Name) { return filepath.Join(path, "kiln") } return path @@ -895,8 +1030,8 @@ func MakeDataDir(ctx *cli.Context) string { // method returns nil and an emphemeral key is to be generated. func setNodeKey(ctx *cli.Context, cfg *p2p.Config) { var ( - hex = ctx.GlobalString(NodeKeyHexFlag.Name) - file = ctx.GlobalString(NodeKeyFileFlag.Name) + hex = ctx.String(NodeKeyHexFlag.Name) + file = ctx.String(NodeKeyFileFlag.Name) key *ecdsa.PrivateKey err error ) @@ -918,7 +1053,7 @@ func setNodeKey(ctx *cli.Context, cfg *p2p.Config) { // setNodeUserIdent creates the user identifier from CLI flags. func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) { - if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 { + if identity := ctx.String(IdentityFlag.Name); len(identity) > 0 { cfg.UserIdent = identity } } @@ -928,17 +1063,17 @@ func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) { func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { urls := params.MainnetBootnodes switch { - case ctx.GlobalIsSet(BootnodesFlag.Name): - urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name)) - case ctx.GlobalBool(RopstenFlag.Name): + case ctx.IsSet(BootnodesFlag.Name): + urls = SplitAndTrim(ctx.String(BootnodesFlag.Name)) + case ctx.Bool(RopstenFlag.Name): urls = params.RopstenBootnodes - case ctx.GlobalBool(SepoliaFlag.Name): + case ctx.Bool(SepoliaFlag.Name): urls = params.SepoliaBootnodes - case ctx.GlobalBool(RinkebyFlag.Name): + case ctx.Bool(RinkebyFlag.Name): urls = params.RinkebyBootnodes - case ctx.GlobalBool(GoerliFlag.Name): + case ctx.Bool(GoerliFlag.Name): urls = params.GoerliBootnodes - case ctx.GlobalBool(KilnFlag.Name): + case ctx.Bool(KilnFlag.Name): urls = params.KilnBootnodes case cfg.BootstrapNodes != nil: return // already set, don't apply defaults. @@ -962,8 +1097,8 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { urls := params.V5Bootnodes switch { - case ctx.GlobalIsSet(BootnodesFlag.Name): - urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name)) + case ctx.IsSet(BootnodesFlag.Name): + urls = SplitAndTrim(ctx.String(BootnodesFlag.Name)) case cfg.BootstrapNodesV5 != nil: return // already set, don't apply defaults. } @@ -984,15 +1119,15 @@ func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { // setListenAddress creates a TCP listening address string from set command // line flags. func setListenAddress(ctx *cli.Context, cfg *p2p.Config) { - if ctx.GlobalIsSet(ListenPortFlag.Name) { - cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)) + if ctx.IsSet(ListenPortFlag.Name) { + cfg.ListenAddr = fmt.Sprintf(":%d", ctx.Int(ListenPortFlag.Name)) } } // setNAT creates a port mapper from command line flags. func setNAT(ctx *cli.Context, cfg *p2p.Config) { - if ctx.GlobalIsSet(NATFlag.Name) { - natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) + if ctx.IsSet(NATFlag.Name) { + natif, err := nat.Parse(ctx.String(NATFlag.Name)) if err != nil { Fatalf("Option %s: %v", NATFlag.Name, err) } @@ -1015,83 +1150,83 @@ func SplitAndTrim(input string) (ret []string) { // setHTTP creates the HTTP RPC listener interface string from the set // command line flags, returning empty if the HTTP endpoint is disabled. func setHTTP(ctx *cli.Context, cfg *node.Config) { - if ctx.GlobalBool(HTTPEnabledFlag.Name) && cfg.HTTPHost == "" { + if ctx.Bool(HTTPEnabledFlag.Name) && cfg.HTTPHost == "" { cfg.HTTPHost = "127.0.0.1" - if ctx.GlobalIsSet(HTTPListenAddrFlag.Name) { - cfg.HTTPHost = ctx.GlobalString(HTTPListenAddrFlag.Name) + if ctx.IsSet(HTTPListenAddrFlag.Name) { + cfg.HTTPHost = ctx.String(HTTPListenAddrFlag.Name) } } - if ctx.GlobalIsSet(HTTPPortFlag.Name) { - cfg.HTTPPort = ctx.GlobalInt(HTTPPortFlag.Name) + if ctx.IsSet(HTTPPortFlag.Name) { + cfg.HTTPPort = ctx.Int(HTTPPortFlag.Name) } - if ctx.GlobalIsSet(AuthListenFlag.Name) { - cfg.AuthAddr = ctx.GlobalString(AuthListenFlag.Name) + if ctx.IsSet(AuthListenFlag.Name) { + cfg.AuthAddr = ctx.String(AuthListenFlag.Name) } - if ctx.GlobalIsSet(AuthPortFlag.Name) { - cfg.AuthPort = ctx.GlobalInt(AuthPortFlag.Name) + if ctx.IsSet(AuthPortFlag.Name) { + cfg.AuthPort = ctx.Int(AuthPortFlag.Name) } - if ctx.GlobalIsSet(AuthVirtualHostsFlag.Name) { - cfg.AuthVirtualHosts = SplitAndTrim(ctx.GlobalString(AuthVirtualHostsFlag.Name)) + if ctx.IsSet(AuthVirtualHostsFlag.Name) { + cfg.AuthVirtualHosts = SplitAndTrim(ctx.String(AuthVirtualHostsFlag.Name)) } - if ctx.GlobalIsSet(HTTPCORSDomainFlag.Name) { - cfg.HTTPCors = SplitAndTrim(ctx.GlobalString(HTTPCORSDomainFlag.Name)) + if ctx.IsSet(HTTPCORSDomainFlag.Name) { + cfg.HTTPCors = SplitAndTrim(ctx.String(HTTPCORSDomainFlag.Name)) } - if ctx.GlobalIsSet(HTTPApiFlag.Name) { - cfg.HTTPModules = SplitAndTrim(ctx.GlobalString(HTTPApiFlag.Name)) + if ctx.IsSet(HTTPApiFlag.Name) { + cfg.HTTPModules = SplitAndTrim(ctx.String(HTTPApiFlag.Name)) } - if ctx.GlobalIsSet(HTTPVirtualHostsFlag.Name) { - cfg.HTTPVirtualHosts = SplitAndTrim(ctx.GlobalString(HTTPVirtualHostsFlag.Name)) + if ctx.IsSet(HTTPVirtualHostsFlag.Name) { + cfg.HTTPVirtualHosts = SplitAndTrim(ctx.String(HTTPVirtualHostsFlag.Name)) } - if ctx.GlobalIsSet(HTTPPathPrefixFlag.Name) { - cfg.HTTPPathPrefix = ctx.GlobalString(HTTPPathPrefixFlag.Name) + if ctx.IsSet(HTTPPathPrefixFlag.Name) { + cfg.HTTPPathPrefix = ctx.String(HTTPPathPrefixFlag.Name) } - if ctx.GlobalIsSet(AllowUnprotectedTxs.Name) { - cfg.AllowUnprotectedTxs = ctx.GlobalBool(AllowUnprotectedTxs.Name) + if ctx.IsSet(AllowUnprotectedTxs.Name) { + cfg.AllowUnprotectedTxs = ctx.Bool(AllowUnprotectedTxs.Name) } } // setGraphQL creates the GraphQL listener interface string from the set // command line flags, returning empty if the GraphQL endpoint is disabled. func setGraphQL(ctx *cli.Context, cfg *node.Config) { - if ctx.GlobalIsSet(GraphQLCORSDomainFlag.Name) { - cfg.GraphQLCors = SplitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name)) + if ctx.IsSet(GraphQLCORSDomainFlag.Name) { + cfg.GraphQLCors = SplitAndTrim(ctx.String(GraphQLCORSDomainFlag.Name)) } - if ctx.GlobalIsSet(GraphQLVirtualHostsFlag.Name) { - cfg.GraphQLVirtualHosts = SplitAndTrim(ctx.GlobalString(GraphQLVirtualHostsFlag.Name)) + if ctx.IsSet(GraphQLVirtualHostsFlag.Name) { + cfg.GraphQLVirtualHosts = SplitAndTrim(ctx.String(GraphQLVirtualHostsFlag.Name)) } } // setWS creates the WebSocket RPC listener interface string from the set // command line flags, returning empty if the HTTP endpoint is disabled. func setWS(ctx *cli.Context, cfg *node.Config) { - if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" { + if ctx.Bool(WSEnabledFlag.Name) && cfg.WSHost == "" { cfg.WSHost = "127.0.0.1" - if ctx.GlobalIsSet(WSListenAddrFlag.Name) { - cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name) + if ctx.IsSet(WSListenAddrFlag.Name) { + cfg.WSHost = ctx.String(WSListenAddrFlag.Name) } } - if ctx.GlobalIsSet(WSPortFlag.Name) { - cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name) + if ctx.IsSet(WSPortFlag.Name) { + cfg.WSPort = ctx.Int(WSPortFlag.Name) } - if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) { - cfg.WSOrigins = SplitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name)) + if ctx.IsSet(WSAllowedOriginsFlag.Name) { + cfg.WSOrigins = SplitAndTrim(ctx.String(WSAllowedOriginsFlag.Name)) } - if ctx.GlobalIsSet(WSApiFlag.Name) { - cfg.WSModules = SplitAndTrim(ctx.GlobalString(WSApiFlag.Name)) + if ctx.IsSet(WSApiFlag.Name) { + cfg.WSModules = SplitAndTrim(ctx.String(WSApiFlag.Name)) } - if ctx.GlobalIsSet(WSPathPrefixFlag.Name) { - cfg.WSPathPrefix = ctx.GlobalString(WSPathPrefixFlag.Name) + if ctx.IsSet(WSPathPrefixFlag.Name) { + cfg.WSPathPrefix = ctx.String(WSPathPrefixFlag.Name) } } @@ -1100,45 +1235,45 @@ func setWS(ctx *cli.Context, cfg *node.Config) { func setIPC(ctx *cli.Context, cfg *node.Config) { CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag) switch { - case ctx.GlobalBool(IPCDisabledFlag.Name): + case ctx.Bool(IPCDisabledFlag.Name): cfg.IPCPath = "" - case ctx.GlobalIsSet(IPCPathFlag.Name): - cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name) + case ctx.IsSet(IPCPathFlag.Name): + cfg.IPCPath = ctx.String(IPCPathFlag.Name) } } // setLes configures the les server and ultra light client settings from the command line flags. func setLes(ctx *cli.Context, cfg *ethconfig.Config) { - if ctx.GlobalIsSet(LightServeFlag.Name) { - cfg.LightServ = ctx.GlobalInt(LightServeFlag.Name) + if ctx.IsSet(LightServeFlag.Name) { + cfg.LightServ = ctx.Int(LightServeFlag.Name) } - if ctx.GlobalIsSet(LightIngressFlag.Name) { - cfg.LightIngress = ctx.GlobalInt(LightIngressFlag.Name) + if ctx.IsSet(LightIngressFlag.Name) { + cfg.LightIngress = ctx.Int(LightIngressFlag.Name) } - if ctx.GlobalIsSet(LightEgressFlag.Name) { - cfg.LightEgress = ctx.GlobalInt(LightEgressFlag.Name) + if ctx.IsSet(LightEgressFlag.Name) { + cfg.LightEgress = ctx.Int(LightEgressFlag.Name) } - if ctx.GlobalIsSet(LightMaxPeersFlag.Name) { - cfg.LightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name) + if ctx.IsSet(LightMaxPeersFlag.Name) { + cfg.LightPeers = ctx.Int(LightMaxPeersFlag.Name) } - if ctx.GlobalIsSet(UltraLightServersFlag.Name) { - cfg.UltraLightServers = strings.Split(ctx.GlobalString(UltraLightServersFlag.Name), ",") + if ctx.IsSet(UltraLightServersFlag.Name) { + cfg.UltraLightServers = strings.Split(ctx.String(UltraLightServersFlag.Name), ",") } - if ctx.GlobalIsSet(UltraLightFractionFlag.Name) { - cfg.UltraLightFraction = ctx.GlobalInt(UltraLightFractionFlag.Name) + if ctx.IsSet(UltraLightFractionFlag.Name) { + cfg.UltraLightFraction = ctx.Int(UltraLightFractionFlag.Name) } if cfg.UltraLightFraction <= 0 && cfg.UltraLightFraction > 100 { log.Error("Ultra light fraction is invalid", "had", cfg.UltraLightFraction, "updated", ethconfig.Defaults.UltraLightFraction) cfg.UltraLightFraction = ethconfig.Defaults.UltraLightFraction } - if ctx.GlobalIsSet(UltraLightOnlyAnnounceFlag.Name) { - cfg.UltraLightOnlyAnnounce = ctx.GlobalBool(UltraLightOnlyAnnounceFlag.Name) + if ctx.IsSet(UltraLightOnlyAnnounceFlag.Name) { + cfg.UltraLightOnlyAnnounce = ctx.Bool(UltraLightOnlyAnnounceFlag.Name) } - if ctx.GlobalIsSet(LightNoPruneFlag.Name) { - cfg.LightNoPrune = ctx.GlobalBool(LightNoPruneFlag.Name) + if ctx.IsSet(LightNoPruneFlag.Name) { + cfg.LightNoPrune = ctx.Bool(LightNoPruneFlag.Name) } - if ctx.GlobalIsSet(LightNoSyncServeFlag.Name) { - cfg.LightNoSyncServe = ctx.GlobalBool(LightNoSyncServeFlag.Name) + if ctx.IsSet(LightNoSyncServeFlag.Name) { + cfg.LightNoSyncServe = ctx.Bool(LightNoSyncServeFlag.Name) } } @@ -1199,8 +1334,8 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *ethconfig.Config) { // Extract the current etherbase var etherbase string - if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) { - etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name) + if ctx.IsSet(MinerEtherbaseFlag.Name) { + etherbase = ctx.String(MinerEtherbaseFlag.Name) } // Convert the etherbase into an address and configure it if etherbase != "" { @@ -1218,7 +1353,7 @@ func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *ethconfig.Config // MakePasswordList reads password lines from the file specified by the global --password flag. func MakePasswordList(ctx *cli.Context) []string { - path := ctx.GlobalString(PasswordFileFlag.Name) + path := ctx.Path(PasswordFileFlag.Name) if path == "" { return nil } @@ -1241,25 +1376,25 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { setBootstrapNodes(ctx, cfg) setBootstrapNodesV5(ctx, cfg) - lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light" - lightServer := (ctx.GlobalInt(LightServeFlag.Name) != 0) + lightClient := ctx.String(SyncModeFlag.Name) == "light" + lightServer := (ctx.Int(LightServeFlag.Name) != 0) - lightPeers := ctx.GlobalInt(LightMaxPeersFlag.Name) - if lightClient && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) { + lightPeers := ctx.Int(LightMaxPeersFlag.Name) + if lightClient && !ctx.IsSet(LightMaxPeersFlag.Name) { // dynamic default - for clients we use 1/10th of the default for servers lightPeers /= 10 } - if ctx.GlobalIsSet(MaxPeersFlag.Name) { - cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name) - if lightServer && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) { + if ctx.IsSet(MaxPeersFlag.Name) { + cfg.MaxPeers = ctx.Int(MaxPeersFlag.Name) + if lightServer && !ctx.IsSet(LightMaxPeersFlag.Name) { cfg.MaxPeers += lightPeers } } else { if lightServer { cfg.MaxPeers += lightPeers } - if lightClient && ctx.GlobalIsSet(LightMaxPeersFlag.Name) && cfg.MaxPeers < lightPeers { + if lightClient && ctx.IsSet(LightMaxPeersFlag.Name) && cfg.MaxPeers < lightPeers { cfg.MaxPeers = lightPeers } } @@ -1272,24 +1407,24 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { } log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers) - if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) { - cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name) + if ctx.IsSet(MaxPendingPeersFlag.Name) { + cfg.MaxPendingPeers = ctx.Int(MaxPendingPeersFlag.Name) } - if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient { + if ctx.IsSet(NoDiscoverFlag.Name) || lightClient { cfg.NoDiscovery = true } // if we're running a light client or server, force enable the v5 peer discovery // unless it is explicitly disabled with --nodiscover note that explicitly specifying // --v5disc overrides --nodiscover, in which case the later only disables v4 discovery - forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name) - if ctx.GlobalIsSet(DiscoveryV5Flag.Name) { - cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name) + forceV5Discovery := (lightClient || lightServer) && !ctx.Bool(NoDiscoverFlag.Name) + if ctx.IsSet(DiscoveryV5Flag.Name) { + cfg.DiscoveryV5 = ctx.Bool(DiscoveryV5Flag.Name) } else if forceV5Discovery { cfg.DiscoveryV5 = true } - if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" { + if netrestrict := ctx.String(NetrestrictFlag.Name); netrestrict != "" { list, err := netutil.ParseNetlist(netrestrict) if err != nil { Fatalf("Option %q: %v", NetrestrictFlag.Name, err) @@ -1297,7 +1432,7 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { cfg.NetRestrict = list } - if ctx.GlobalBool(DeveloperFlag.Name) { + if ctx.Bool(DeveloperFlag.Name) { // --dev mode can't use p2p networking. cfg.MaxPeers = 0 cfg.ListenAddr = "" @@ -1318,37 +1453,37 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { SetDataDir(ctx, cfg) setSmartCard(ctx, cfg) - if ctx.GlobalIsSet(JWTSecretFlag.Name) { - cfg.JWTSecret = ctx.GlobalString(JWTSecretFlag.Name) + if ctx.IsSet(JWTSecretFlag.Name) { + cfg.JWTSecret = ctx.String(JWTSecretFlag.Name) } - if ctx.GlobalIsSet(ExternalSignerFlag.Name) { - cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name) + if ctx.IsSet(ExternalSignerFlag.Name) { + cfg.ExternalSigner = ctx.String(ExternalSignerFlag.Name) } - if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { - cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name) + if ctx.IsSet(KeyStoreDirFlag.Name) { + cfg.KeyStoreDir = ctx.String(KeyStoreDirFlag.Name) } - if ctx.GlobalIsSet(DeveloperFlag.Name) { + if ctx.IsSet(DeveloperFlag.Name) { cfg.UseLightweightKDF = true } - if ctx.GlobalIsSet(LightKDFFlag.Name) { - cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name) + if ctx.IsSet(LightKDFFlag.Name) { + cfg.UseLightweightKDF = ctx.Bool(LightKDFFlag.Name) } - if ctx.GlobalIsSet(NoUSBFlag.Name) || cfg.NoUSB { + if ctx.IsSet(NoUSBFlag.Name) || cfg.NoUSB { log.Warn("Option nousb is deprecated and USB is deactivated by default. Use --usb to enable") } - if ctx.GlobalIsSet(USBFlag.Name) { - cfg.USB = ctx.GlobalBool(USBFlag.Name) + if ctx.IsSet(USBFlag.Name) { + cfg.USB = ctx.Bool(USBFlag.Name) } - if ctx.GlobalIsSet(InsecureUnlockAllowedFlag.Name) { - cfg.InsecureUnlockAllowed = ctx.GlobalBool(InsecureUnlockAllowedFlag.Name) + if ctx.IsSet(InsecureUnlockAllowedFlag.Name) { + cfg.InsecureUnlockAllowed = ctx.Bool(InsecureUnlockAllowedFlag.Name) } } func setSmartCard(ctx *cli.Context, cfg *node.Config) { // Skip enabling smartcards if no path is set - path := ctx.GlobalString(SmartCardDaemonPathFlag.Name) + path := ctx.String(SmartCardDaemonPathFlag.Name) if path == "" { return } @@ -1368,11 +1503,11 @@ func setSmartCard(ctx *cli.Context, cfg *node.Config) { func SetDataDir(ctx *cli.Context, cfg *node.Config) { switch { - case ctx.GlobalIsSet(DataDirFlag.Name): - cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) - case ctx.GlobalBool(DeveloperFlag.Name): + case ctx.IsSet(DataDirFlag.Name): + cfg.DataDir = ctx.String(DataDirFlag.Name) + case ctx.Bool(DeveloperFlag.Name): cfg.DataDir = "" // unless explicitly requested, use memory databases - case ctx.GlobalBool(RopstenFlag.Name) && cfg.DataDir == node.DefaultDataDir(): + case ctx.Bool(RopstenFlag.Name) && cfg.DataDir == node.DefaultDataDir(): // Maintain compatibility with older Geth configurations storing the // Ropsten database in `testnet` instead of `ropsten`. legacyPath := filepath.Join(node.DefaultDataDir(), "testnet") @@ -1384,13 +1519,13 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) { } cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten") - case ctx.GlobalBool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir(): + case ctx.Bool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir(): cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") - case ctx.GlobalBool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir(): + case ctx.Bool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir(): cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli") - case ctx.GlobalBool(SepoliaFlag.Name) && cfg.DataDir == node.DefaultDataDir(): + case ctx.Bool(SepoliaFlag.Name) && cfg.DataDir == node.DefaultDataDir(): cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia") - case ctx.GlobalBool(KilnFlag.Name) && cfg.DataDir == node.DefaultDataDir(): + case ctx.Bool(KilnFlag.Name) && cfg.DataDir == node.DefaultDataDir(): cfg.DataDir = filepath.Join(node.DefaultDataDir(), "kiln") } } @@ -1401,23 +1536,23 @@ func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) { if light { *cfg = ethconfig.LightClientGPO } - if ctx.GlobalIsSet(GpoBlocksFlag.Name) { - cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name) + if ctx.IsSet(GpoBlocksFlag.Name) { + cfg.Blocks = ctx.Int(GpoBlocksFlag.Name) } - if ctx.GlobalIsSet(GpoPercentileFlag.Name) { - cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name) + if ctx.IsSet(GpoPercentileFlag.Name) { + cfg.Percentile = ctx.Int(GpoPercentileFlag.Name) } - if ctx.GlobalIsSet(GpoMaxGasPriceFlag.Name) { - cfg.MaxPrice = big.NewInt(ctx.GlobalInt64(GpoMaxGasPriceFlag.Name)) + if ctx.IsSet(GpoMaxGasPriceFlag.Name) { + cfg.MaxPrice = big.NewInt(ctx.Int64(GpoMaxGasPriceFlag.Name)) } - if ctx.GlobalIsSet(GpoIgnoreGasPriceFlag.Name) { - cfg.IgnorePrice = big.NewInt(ctx.GlobalInt64(GpoIgnoreGasPriceFlag.Name)) + if ctx.IsSet(GpoIgnoreGasPriceFlag.Name) { + cfg.IgnorePrice = big.NewInt(ctx.Int64(GpoIgnoreGasPriceFlag.Name)) } } func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { - if ctx.GlobalIsSet(TxPoolLocalsFlag.Name) { - locals := strings.Split(ctx.GlobalString(TxPoolLocalsFlag.Name), ",") + if ctx.IsSet(TxPoolLocalsFlag.Name) { + locals := strings.Split(ctx.String(TxPoolLocalsFlag.Name), ",") for _, account := range locals { if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) { Fatalf("Invalid account in --txpool.locals: %s", trimmed) @@ -1426,96 +1561,96 @@ func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { } } } - if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { - cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) + if ctx.IsSet(TxPoolNoLocalsFlag.Name) { + cfg.NoLocals = ctx.Bool(TxPoolNoLocalsFlag.Name) } - if ctx.GlobalIsSet(TxPoolJournalFlag.Name) { - cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name) + if ctx.IsSet(TxPoolJournalFlag.Name) { + cfg.Journal = ctx.String(TxPoolJournalFlag.Name) } - if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) { - cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name) + if ctx.IsSet(TxPoolRejournalFlag.Name) { + cfg.Rejournal = ctx.Duration(TxPoolRejournalFlag.Name) } - if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) { - cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name) + if ctx.IsSet(TxPoolPriceLimitFlag.Name) { + cfg.PriceLimit = ctx.Uint64(TxPoolPriceLimitFlag.Name) } - if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) { - cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name) + if ctx.IsSet(TxPoolPriceBumpFlag.Name) { + cfg.PriceBump = ctx.Uint64(TxPoolPriceBumpFlag.Name) } - if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) { - cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name) + if ctx.IsSet(TxPoolAccountSlotsFlag.Name) { + cfg.AccountSlots = ctx.Uint64(TxPoolAccountSlotsFlag.Name) } - if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) { - cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name) + if ctx.IsSet(TxPoolGlobalSlotsFlag.Name) { + cfg.GlobalSlots = ctx.Uint64(TxPoolGlobalSlotsFlag.Name) } - if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) { - cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name) + if ctx.IsSet(TxPoolAccountQueueFlag.Name) { + cfg.AccountQueue = ctx.Uint64(TxPoolAccountQueueFlag.Name) } - if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) { - cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name) + if ctx.IsSet(TxPoolGlobalQueueFlag.Name) { + cfg.GlobalQueue = ctx.Uint64(TxPoolGlobalQueueFlag.Name) } - if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) { - cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name) + if ctx.IsSet(TxPoolLifetimeFlag.Name) { + cfg.Lifetime = ctx.Duration(TxPoolLifetimeFlag.Name) } } func setEthash(ctx *cli.Context, cfg *ethconfig.Config) { - if ctx.GlobalIsSet(EthashCacheDirFlag.Name) { - cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name) + if ctx.IsSet(EthashCacheDirFlag.Name) { + cfg.Ethash.CacheDir = ctx.String(EthashCacheDirFlag.Name) } - if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) { - cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name) + if ctx.IsSet(EthashDatasetDirFlag.Name) { + cfg.Ethash.DatasetDir = ctx.String(EthashDatasetDirFlag.Name) } - if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) { - cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name) + if ctx.IsSet(EthashCachesInMemoryFlag.Name) { + cfg.Ethash.CachesInMem = ctx.Int(EthashCachesInMemoryFlag.Name) } - if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) { - cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name) + if ctx.IsSet(EthashCachesOnDiskFlag.Name) { + cfg.Ethash.CachesOnDisk = ctx.Int(EthashCachesOnDiskFlag.Name) } - if ctx.GlobalIsSet(EthashCachesLockMmapFlag.Name) { - cfg.Ethash.CachesLockMmap = ctx.GlobalBool(EthashCachesLockMmapFlag.Name) + if ctx.IsSet(EthashCachesLockMmapFlag.Name) { + cfg.Ethash.CachesLockMmap = ctx.Bool(EthashCachesLockMmapFlag.Name) } - if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) { - cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name) + if ctx.IsSet(EthashDatasetsInMemoryFlag.Name) { + cfg.Ethash.DatasetsInMem = ctx.Int(EthashDatasetsInMemoryFlag.Name) } - if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) { - cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name) + if ctx.IsSet(EthashDatasetsOnDiskFlag.Name) { + cfg.Ethash.DatasetsOnDisk = ctx.Int(EthashDatasetsOnDiskFlag.Name) } - if ctx.GlobalIsSet(EthashDatasetsLockMmapFlag.Name) { - cfg.Ethash.DatasetsLockMmap = ctx.GlobalBool(EthashDatasetsLockMmapFlag.Name) + if ctx.IsSet(EthashDatasetsLockMmapFlag.Name) { + cfg.Ethash.DatasetsLockMmap = ctx.Bool(EthashDatasetsLockMmapFlag.Name) } } func setMiner(ctx *cli.Context, cfg *miner.Config) { - if ctx.GlobalIsSet(MinerNotifyFlag.Name) { - cfg.Notify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",") + if ctx.IsSet(MinerNotifyFlag.Name) { + cfg.Notify = strings.Split(ctx.String(MinerNotifyFlag.Name), ",") } - cfg.NotifyFull = ctx.GlobalBool(MinerNotifyFullFlag.Name) - if ctx.GlobalIsSet(MinerExtraDataFlag.Name) { - cfg.ExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name)) + cfg.NotifyFull = ctx.Bool(MinerNotifyFullFlag.Name) + if ctx.IsSet(MinerExtraDataFlag.Name) { + cfg.ExtraData = []byte(ctx.String(MinerExtraDataFlag.Name)) } - if ctx.GlobalIsSet(MinerGasLimitFlag.Name) { - cfg.GasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name) + if ctx.IsSet(MinerGasLimitFlag.Name) { + cfg.GasCeil = ctx.Uint64(MinerGasLimitFlag.Name) } - if ctx.GlobalIsSet(MinerGasPriceFlag.Name) { - cfg.GasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name) + if ctx.IsSet(MinerGasPriceFlag.Name) { + cfg.GasPrice = flags.GlobalBig(ctx, MinerGasPriceFlag.Name) } - if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) { - cfg.Recommit = ctx.GlobalDuration(MinerRecommitIntervalFlag.Name) + if ctx.IsSet(MinerRecommitIntervalFlag.Name) { + cfg.Recommit = ctx.Duration(MinerRecommitIntervalFlag.Name) } - if ctx.GlobalIsSet(MinerNoVerifyFlag.Name) { - cfg.Noverify = ctx.GlobalBool(MinerNoVerifyFlag.Name) + if ctx.IsSet(MinerNoVerifyFlag.Name) { + cfg.Noverify = ctx.Bool(MinerNoVerifyFlag.Name) } - if ctx.GlobalIsSet(LegacyMinerGasTargetFlag.Name) { + if ctx.IsSet(LegacyMinerGasTargetFlag.Name) { log.Warn("The generic --miner.gastarget flag is deprecated and will be removed in the future!") } } func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) { - requiredBlocks := ctx.GlobalString(EthRequiredBlocksFlag.Name) + requiredBlocks := ctx.String(EthRequiredBlocksFlag.Name) if requiredBlocks == "" { - if ctx.GlobalIsSet(LegacyWhitelistFlag.Name) { + if ctx.IsSet(LegacyWhitelistFlag.Name) { log.Warn("The flag --whitelist is deprecated and will be removed, please use --eth.requiredblocks") - requiredBlocks = ctx.GlobalString(LegacyWhitelistFlag.Name) + requiredBlocks = ctx.String(LegacyWhitelistFlag.Name) } else { return } @@ -1550,13 +1685,13 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) { panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i])) } // Check if next arg extends current and expand its name if so - name := flag.GetName() + name := flag.Names()[0] if i+1 < len(args) { switch option := args[i+1].(type) { case string: // Extended flag check, make sure value set doesn't conflict with passed in option - if ctx.GlobalString(flag.GetName()) == option { + if ctx.String(flag.Names()[0]) == option { name += "=" + option set = append(set, "--"+name) } @@ -1570,7 +1705,7 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) { } } // Mark the flag if it's set - if ctx.GlobalIsSet(flag.GetName()) { + if ctx.IsSet(flag.Names()[0]) { set = append(set, "--"+name) } } @@ -1585,11 +1720,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, SepoliaFlag, KilnFlag) CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light") CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer - if ctx.GlobalString(GCModeFlag.Name) == "archive" && ctx.GlobalUint64(TxLookupLimitFlag.Name) != 0 { - ctx.GlobalSet(TxLookupLimitFlag.Name, "0") + if ctx.String(GCModeFlag.Name) == "archive" && ctx.Uint64(TxLookupLimitFlag.Name) != 0 { + ctx.Set(TxLookupLimitFlag.Name, "0") log.Warn("Disable transaction unindexing for archive node") } - if ctx.GlobalIsSet(LightServeFlag.Name) && ctx.GlobalUint64(TxLookupLimitFlag.Name) != 0 { + if ctx.IsSet(LightServeFlag.Name) && ctx.Uint64(TxLookupLimitFlag.Name) != 0 { log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited") } var ks *keystore.KeyStore @@ -1597,7 +1732,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { ks = keystores[0].(*keystore.KeyStore) } setEtherbase(ctx, ks, cfg) - setGPO(ctx, &cfg.GPO, ctx.GlobalString(SyncModeFlag.Name) == "light") + setGPO(ctx, &cfg.GPO, ctx.String(SyncModeFlag.Name) == "light") setTxPool(ctx, &cfg.TxPool) setEthash(ctx, cfg) setMiner(ctx, &cfg.Miner) @@ -1612,66 +1747,66 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { mem.Total = 2 * 1024 * 1024 * 1024 } allowance := int(mem.Total / 1024 / 1024 / 3) - if cache := ctx.GlobalInt(CacheFlag.Name); cache > allowance { + if cache := ctx.Int(CacheFlag.Name); cache > allowance { log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance) - ctx.GlobalSet(CacheFlag.Name, strconv.Itoa(allowance)) + ctx.Set(CacheFlag.Name, strconv.Itoa(allowance)) } } // Ensure Go's GC ignores the database cache for trigger percentage - cache := ctx.GlobalInt(CacheFlag.Name) + cache := ctx.Int(CacheFlag.Name) gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024))) log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc)) godebug.SetGCPercent(int(gogc)) - if ctx.GlobalIsSet(SyncModeFlag.Name) { - cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) + if ctx.IsSet(SyncModeFlag.Name) { + cfg.SyncMode = *flags.GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) } - if ctx.GlobalIsSet(NetworkIdFlag.Name) { - cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) + if ctx.IsSet(NetworkIdFlag.Name) { + cfg.NetworkId = ctx.Uint64(NetworkIdFlag.Name) } - if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { - cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 + if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheDatabaseFlag.Name) { + cfg.DatabaseCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheDatabaseFlag.Name) / 100 } - cfg.DatabaseHandles = MakeDatabaseHandles(ctx.GlobalInt(FDLimitFlag.Name)) - if ctx.GlobalIsSet(AncientFlag.Name) { - cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name) + cfg.DatabaseHandles = MakeDatabaseHandles(ctx.Int(FDLimitFlag.Name)) + if ctx.IsSet(AncientFlag.Name) { + cfg.DatabaseFreezer = ctx.String(AncientFlag.Name) } - if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { + if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } - if ctx.GlobalIsSet(GCModeFlag.Name) { - cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive" + if ctx.IsSet(GCModeFlag.Name) { + cfg.NoPruning = ctx.String(GCModeFlag.Name) == "archive" } - if ctx.GlobalIsSet(CacheNoPrefetchFlag.Name) { - cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name) + if ctx.IsSet(CacheNoPrefetchFlag.Name) { + cfg.NoPrefetch = ctx.Bool(CacheNoPrefetchFlag.Name) } // Read the value from the flag no matter if it's set or not. - cfg.Preimages = ctx.GlobalBool(CachePreimagesFlag.Name) + cfg.Preimages = ctx.Bool(CachePreimagesFlag.Name) if cfg.NoPruning && !cfg.Preimages { cfg.Preimages = true log.Info("Enabling recording of key preimages since archive mode is used") } - if ctx.GlobalIsSet(TxLookupLimitFlag.Name) { - cfg.TxLookupLimit = ctx.GlobalUint64(TxLookupLimitFlag.Name) + if ctx.IsSet(TxLookupLimitFlag.Name) { + cfg.TxLookupLimit = ctx.Uint64(TxLookupLimitFlag.Name) } - if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { - cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 + if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) { + cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 } - if ctx.GlobalIsSet(CacheTrieJournalFlag.Name) { - cfg.TrieCleanCacheJournal = ctx.GlobalString(CacheTrieJournalFlag.Name) + if ctx.IsSet(CacheTrieJournalFlag.Name) { + cfg.TrieCleanCacheJournal = ctx.String(CacheTrieJournalFlag.Name) } - if ctx.GlobalIsSet(CacheTrieRejournalFlag.Name) { - cfg.TrieCleanCacheRejournal = ctx.GlobalDuration(CacheTrieRejournalFlag.Name) + if ctx.IsSet(CacheTrieRejournalFlag.Name) { + cfg.TrieCleanCacheRejournal = ctx.Duration(CacheTrieRejournalFlag.Name) } - if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { - cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 + if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) { + cfg.TrieDirtyCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 } - if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) { - cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100 + if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheSnapshotFlag.Name) { + cfg.SnapshotCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheSnapshotFlag.Name) / 100 } - if !ctx.GlobalBool(SnapshotFlag.Name) { + if !ctx.Bool(SnapshotFlag.Name) { // If snap-sync is requested, this flag is also required if cfg.SyncMode == downloader.SnapSync { log.Info("Snap sync requested, enabling --snapshot") @@ -1680,32 +1815,32 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.SnapshotCache = 0 // Disabled } } - if ctx.GlobalIsSet(DocRootFlag.Name) { - cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name) + if ctx.IsSet(DocRootFlag.Name) { + cfg.DocRoot = ctx.String(DocRootFlag.Name) } - if ctx.GlobalIsSet(VMEnableDebugFlag.Name) { + if ctx.IsSet(VMEnableDebugFlag.Name) { // TODO(fjl): force-enable this in --dev mode - cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name) + cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name) } - if ctx.GlobalIsSet(RPCGlobalGasCapFlag.Name) { - cfg.RPCGasCap = ctx.GlobalUint64(RPCGlobalGasCapFlag.Name) + if ctx.IsSet(RPCGlobalGasCapFlag.Name) { + cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name) } if cfg.RPCGasCap != 0 { log.Info("Set global gas cap", "cap", cfg.RPCGasCap) } else { log.Info("Global gas cap disabled") } - if ctx.GlobalIsSet(RPCGlobalEVMTimeoutFlag.Name) { - cfg.RPCEVMTimeout = ctx.GlobalDuration(RPCGlobalEVMTimeoutFlag.Name) + if ctx.IsSet(RPCGlobalEVMTimeoutFlag.Name) { + cfg.RPCEVMTimeout = ctx.Duration(RPCGlobalEVMTimeoutFlag.Name) } - if ctx.GlobalIsSet(RPCGlobalTxFeeCapFlag.Name) { - cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCapFlag.Name) + if ctx.IsSet(RPCGlobalTxFeeCapFlag.Name) { + cfg.RPCTxFeeCap = ctx.Float64(RPCGlobalTxFeeCapFlag.Name) } - if ctx.GlobalIsSet(NoDiscoverFlag.Name) { + if ctx.IsSet(NoDiscoverFlag.Name) { cfg.EthDiscoveryURLs, cfg.SnapDiscoveryURLs = []string{}, []string{} - } else if ctx.GlobalIsSet(DNSDiscoveryFlag.Name) { - urls := ctx.GlobalString(DNSDiscoveryFlag.Name) + } else if ctx.IsSet(DNSDiscoveryFlag.Name) { + urls := ctx.String(DNSDiscoveryFlag.Name) if urls == "" { cfg.EthDiscoveryURLs = []string{} } else { @@ -1714,25 +1849,25 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { } // Override any default configs for hard coded networks. switch { - case ctx.GlobalBool(MainnetFlag.Name): - if !ctx.GlobalIsSet(NetworkIdFlag.Name) { + case ctx.Bool(MainnetFlag.Name): + if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 1 } cfg.Genesis = core.DefaultGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash) - case ctx.GlobalBool(RopstenFlag.Name): - if !ctx.GlobalIsSet(NetworkIdFlag.Name) { + case ctx.Bool(RopstenFlag.Name): + if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 3 } cfg.Genesis = core.DefaultRopstenGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.RopstenGenesisHash) - case ctx.GlobalBool(SepoliaFlag.Name): - if !ctx.GlobalIsSet(NetworkIdFlag.Name) { + case ctx.Bool(SepoliaFlag.Name): + if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 11155111 } cfg.Genesis = core.DefaultSepoliaGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash) - case ctx.GlobalBool(RinkebyFlag.Name): + case ctx.Bool(RinkebyFlag.Name): log.Warn("") log.Warn("--------------------------------------------------------------------------------") log.Warn("Please note, Rinkeby has been deprecated. It will still work for the time being,") @@ -1743,25 +1878,25 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { log.Warn("--------------------------------------------------------------------------------") log.Warn("") - if !ctx.GlobalIsSet(NetworkIdFlag.Name) { + if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 4 } cfg.Genesis = core.DefaultRinkebyGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.RinkebyGenesisHash) - case ctx.GlobalBool(GoerliFlag.Name): - if !ctx.GlobalIsSet(NetworkIdFlag.Name) { + case ctx.Bool(GoerliFlag.Name): + if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 5 } cfg.Genesis = core.DefaultGoerliGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash) - case ctx.GlobalBool(KilnFlag.Name): - if !ctx.GlobalIsSet(NetworkIdFlag.Name) { + case ctx.Bool(KilnFlag.Name): + if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 1337802 } cfg.Genesis = core.DefaultKilnGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.KilnGenesisHash) - case ctx.GlobalBool(DeveloperFlag.Name): - if !ctx.GlobalIsSet(NetworkIdFlag.Name) { + case ctx.Bool(DeveloperFlag.Name): + if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 1337 } cfg.SyncMode = downloader.FullSync @@ -1794,8 +1929,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { log.Info("Using developer account", "address", developer.Address) // Create a new developer genesis block or reuse existing one - cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), ctx.GlobalUint64(DeveloperGasLimitFlag.Name), developer.Address) - if ctx.GlobalIsSet(DataDirFlag.Name) { + cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.Int(DeveloperPeriodFlag.Name)), ctx.Uint64(DeveloperGasLimitFlag.Name), developer.Address) + if ctx.IsSet(DataDirFlag.Name) { // If datadir doesn't exist we need to open db in write-mode // so leveldb can create files. readonly := true @@ -1810,7 +1945,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { } chaindb.Close() } - if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) { + if !ctx.IsSet(MinerGasPriceFlag.Name) { cfg.Miner.GasPrice = big.NewInt(1) } default: @@ -1892,19 +2027,19 @@ func SetupMetrics(ctx *cli.Context) { log.Info("Enabling metrics collection") var ( - enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name) - enableExportV2 = ctx.GlobalBool(MetricsEnableInfluxDBV2Flag.Name) + enableExport = ctx.Bool(MetricsEnableInfluxDBFlag.Name) + enableExportV2 = ctx.Bool(MetricsEnableInfluxDBV2Flag.Name) ) if enableExport || enableExportV2 { CheckExclusive(ctx, MetricsEnableInfluxDBFlag, MetricsEnableInfluxDBV2Flag) - v1FlagIsSet := ctx.GlobalIsSet(MetricsInfluxDBUsernameFlag.Name) || - ctx.GlobalIsSet(MetricsInfluxDBPasswordFlag.Name) + v1FlagIsSet := ctx.IsSet(MetricsInfluxDBUsernameFlag.Name) || + ctx.IsSet(MetricsInfluxDBPasswordFlag.Name) - v2FlagIsSet := ctx.GlobalIsSet(MetricsInfluxDBTokenFlag.Name) || - ctx.GlobalIsSet(MetricsInfluxDBOrganizationFlag.Name) || - ctx.GlobalIsSet(MetricsInfluxDBBucketFlag.Name) + v2FlagIsSet := ctx.IsSet(MetricsInfluxDBTokenFlag.Name) || + ctx.IsSet(MetricsInfluxDBOrganizationFlag.Name) || + ctx.IsSet(MetricsInfluxDBBucketFlag.Name) if enableExport && v2FlagIsSet { Fatalf("Flags --influxdb.metrics.organization, --influxdb.metrics.token, --influxdb.metrics.bucket are only available for influxdb-v2") @@ -1914,32 +2049,32 @@ func SetupMetrics(ctx *cli.Context) { } var ( - endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) - database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) - username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) - password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name) - - token = ctx.GlobalString(MetricsInfluxDBTokenFlag.Name) - bucket = ctx.GlobalString(MetricsInfluxDBBucketFlag.Name) - organization = ctx.GlobalString(MetricsInfluxDBOrganizationFlag.Name) + endpoint = ctx.String(MetricsInfluxDBEndpointFlag.Name) + database = ctx.String(MetricsInfluxDBDatabaseFlag.Name) + username = ctx.String(MetricsInfluxDBUsernameFlag.Name) + password = ctx.String(MetricsInfluxDBPasswordFlag.Name) + + token = ctx.String(MetricsInfluxDBTokenFlag.Name) + bucket = ctx.String(MetricsInfluxDBBucketFlag.Name) + organization = ctx.String(MetricsInfluxDBOrganizationFlag.Name) ) if enableExport { - tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) + tagsMap := SplitTagsFlag(ctx.String(MetricsInfluxDBTagsFlag.Name)) log.Info("Enabling metrics export to InfluxDB") go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap) } else if enableExportV2 { - tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) + tagsMap := SplitTagsFlag(ctx.String(MetricsInfluxDBTagsFlag.Name)) log.Info("Enabling metrics export to InfluxDB (v2)") go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, token, bucket, organization, "geth.", tagsMap) } - if ctx.GlobalIsSet(MetricsHTTPFlag.Name) { - address := fmt.Sprintf("%s:%d", ctx.GlobalString(MetricsHTTPFlag.Name), ctx.GlobalInt(MetricsPortFlag.Name)) + if ctx.IsSet(MetricsHTTPFlag.Name) { + address := fmt.Sprintf("%s:%d", ctx.String(MetricsHTTPFlag.Name), ctx.Int(MetricsPortFlag.Name)) log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address) exp.Setup(address) } @@ -1966,20 +2101,20 @@ func SplitTagsFlag(tagsFlag string) map[string]string { // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.Database { var ( - cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 - handles = MakeDatabaseHandles(ctx.GlobalInt(FDLimitFlag.Name)) + cache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheDatabaseFlag.Name) / 100 + handles = MakeDatabaseHandles(ctx.Int(FDLimitFlag.Name)) err error chainDb ethdb.Database ) switch { - case ctx.GlobalIsSet(RemoteDBFlag.Name): - log.Info("Using remote db", "url", ctx.GlobalString(RemoteDBFlag.Name)) - chainDb, err = remotedb.New(ctx.GlobalString(RemoteDBFlag.Name)) - case ctx.GlobalString(SyncModeFlag.Name) == "light": + case ctx.IsSet(RemoteDBFlag.Name): + log.Info("Using remote db", "url", ctx.String(RemoteDBFlag.Name)) + chainDb, err = remotedb.New(ctx.String(RemoteDBFlag.Name)) + case ctx.String(SyncModeFlag.Name) == "light": chainDb, err = stack.OpenDatabase("lightchaindata", cache, handles, "", readonly) default: - chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly) + chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "", readonly) } if err != nil { Fatalf("Could not open database: %v", err) @@ -1990,19 +2125,19 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. func MakeGenesis(ctx *cli.Context) *core.Genesis { var genesis *core.Genesis switch { - case ctx.GlobalBool(MainnetFlag.Name): + case ctx.Bool(MainnetFlag.Name): genesis = core.DefaultGenesisBlock() - case ctx.GlobalBool(RopstenFlag.Name): + case ctx.Bool(RopstenFlag.Name): genesis = core.DefaultRopstenGenesisBlock() - case ctx.GlobalBool(SepoliaFlag.Name): + case ctx.Bool(SepoliaFlag.Name): genesis = core.DefaultSepoliaGenesisBlock() - case ctx.GlobalBool(RinkebyFlag.Name): + case ctx.Bool(RinkebyFlag.Name): genesis = core.DefaultRinkebyGenesisBlock() - case ctx.GlobalBool(GoerliFlag.Name): + case ctx.Bool(GoerliFlag.Name): genesis = core.DefaultGoerliGenesisBlock() - case ctx.GlobalBool(KilnFlag.Name): + case ctx.Bool(KilnFlag.Name): genesis = core.DefaultKilnGenesisBlock() - case ctx.GlobalBool(DeveloperFlag.Name): + case ctx.Bool(DeveloperFlag.Name): Fatalf("Developer chains are ephemeral") } return genesis @@ -2019,36 +2154,36 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai var engine consensus.Engine ethashConf := ethconfig.Defaults.Ethash - if ctx.GlobalBool(FakePoWFlag.Name) { + if ctx.Bool(FakePoWFlag.Name) { ethashConf.PowMode = ethash.ModeFake } engine = ethconfig.CreateConsensusEngine(stack, config, ðashConf, nil, false, chainDb) - if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { + if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } cache := &core.CacheConfig{ TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, - TrieCleanNoPrefetch: ctx.GlobalBool(CacheNoPrefetchFlag.Name), + TrieCleanNoPrefetch: ctx.Bool(CacheNoPrefetchFlag.Name), TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache, - TrieDirtyDisabled: ctx.GlobalString(GCModeFlag.Name) == "archive", + TrieDirtyDisabled: ctx.String(GCModeFlag.Name) == "archive", TrieTimeLimit: ethconfig.Defaults.TrieTimeout, SnapshotLimit: ethconfig.Defaults.SnapshotCache, - Preimages: ctx.GlobalBool(CachePreimagesFlag.Name), + Preimages: ctx.Bool(CachePreimagesFlag.Name), } if cache.TrieDirtyDisabled && !cache.Preimages { cache.Preimages = true log.Info("Enabling recording of key preimages since archive mode is used") } - if !ctx.GlobalBool(SnapshotFlag.Name) { + if !ctx.Bool(SnapshotFlag.Name) { cache.SnapshotLimit = 0 // Disabled } - if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { - cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 + if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) { + cache.TrieCleanLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 } - if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { - cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 + if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) { + cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 } - vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} + vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)} // TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only. // Disable transaction indexing/unindexing by default. @@ -2063,38 +2198,14 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai // scripts to preload before starting. func MakeConsolePreloads(ctx *cli.Context) []string { // Skip preloading if there's nothing to preload - if ctx.GlobalString(PreloadJSFlag.Name) == "" { + if ctx.String(PreloadJSFlag.Name) == "" { return nil } // Otherwise resolve absolute paths and return them var preloads []string - for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { + for _, file := range strings.Split(ctx.String(PreloadJSFlag.Name), ",") { preloads = append(preloads, strings.TrimSpace(file)) } return preloads } - -// MigrateFlags sets the global flag from a local flag when it's set. -// This is a temporary function used for migrating old command/flags to the -// new format. -// -// e.g. geth account new --keystore /tmp/mykeystore --lightkdf -// -// is equivalent after calling this method with: -// -// geth --keystore /tmp/mykeystore --lightkdf account new -// -// This allows the use of the existing configuration functionality. -// When all flags are migrated this function can be removed and the existing -// configuration functionality must be changed that is uses local flags -func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error { - return func(ctx *cli.Context) error { - for _, name := range ctx.FlagNames() { - if ctx.IsSet(name) { - ctx.GlobalSet(name, ctx.String(name)) - } - } - return action(ctx) - } -} diff --git a/cmd/utils/flags_legacy.go b/cmd/utils/flags_legacy.go index a0f64f609b77..651c69bd0492 100644 --- a/cmd/utils/flags_legacy.go +++ b/cmd/utils/flags_legacy.go @@ -20,15 +20,15 @@ import ( "fmt" "github.com/ethereum/go-ethereum/eth/ethconfig" - "gopkg.in/urfave/cli.v1" + "github.com/ethereum/go-ethereum/internal/flags" + "github.com/urfave/cli/v2" ) -var ShowDeprecated = cli.Command{ +var ShowDeprecated = &cli.Command{ Action: showDeprecated, Name: "show-deprecated-flags", Usage: "Show flags that have been deprecated", ArgsUsage: " ", - Category: "MISCELLANEOUS COMMANDS", Description: "Show flags that have been deprecated and will soon be removed", } @@ -39,20 +39,22 @@ var DeprecatedFlags = []cli.Flag{ var ( // (Deprecated May 2020, shown in aliased flags section) - NoUSBFlag = cli.BoolFlag{ - Name: "nousb", - Usage: "Disables monitoring for and managing USB hardware wallets (deprecated)", + NoUSBFlag = &cli.BoolFlag{ + Name: "nousb", + Usage: "Disables monitoring for and managing USB hardware wallets (deprecated)", + Category: flags.DeprecatedCategory, } // (Deprecated July 2021, shown in aliased flags section) - LegacyMinerGasTargetFlag = cli.Uint64Flag{ - Name: "miner.gastarget", - Usage: "Target gas floor for mined blocks (deprecated)", - Value: ethconfig.Defaults.Miner.GasFloor, + LegacyMinerGasTargetFlag = &cli.Uint64Flag{ + Name: "miner.gastarget", + Usage: "Target gas floor for mined blocks (deprecated)", + Value: ethconfig.Defaults.Miner.GasFloor, + Category: flags.DeprecatedCategory, } ) // showDeprecated displays deprecated flags that will be soon removed from the codebase. -func showDeprecated(*cli.Context) { +func showDeprecated(*cli.Context) error { fmt.Println("--------------------------------------------------------------------") fmt.Println("The following flags are deprecated and will be removed in the future!") fmt.Println("--------------------------------------------------------------------") @@ -61,4 +63,5 @@ func showDeprecated(*cli.Context) { fmt.Println(flag.String()) } fmt.Println() + return nil } diff --git a/go.mod b/go.mod index a2d66c3daccd..e669cff88448 100644 --- a/go.mod +++ b/go.mod @@ -55,6 +55,7 @@ require ( github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef + github.com/urfave/cli/v2 v2.10.2 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c @@ -64,7 +65,6 @@ require ( golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce - gopkg.in/urfave/cli.v1 v1.20.0 ) require ( @@ -77,6 +77,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect github.com/aws/smithy-go v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect @@ -92,8 +93,10 @@ require ( github.com/opentracing/opentracing-go v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect diff --git a/go.sum b/go.sum index 01f49e8dedf8..933c6a06bfb4 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,7 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -83,6 +84,8 @@ github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/ github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f h1:C43yEtQ6NIf4ftFXD/V55gnGFgPbMQobd//YlnLjUJ8= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= @@ -371,6 +374,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -408,11 +413,15 @@ github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZF github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y= +github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -662,8 +671,6 @@ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/debug/flags.go b/internal/debug/flags.go index d1bd31abeed6..2082d60df51c 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -24,71 +24,84 @@ import ( "os" "runtime" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics/exp" "github.com/fjl/memsize/memsizeui" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) var Memsize memsizeui.Handler var ( - verbosityFlag = cli.IntFlag{ - Name: "verbosity", - Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail", - Value: 3, - } - vmoduleFlag = cli.StringFlag{ - Name: "vmodule", - Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)", - Value: "", - } - logjsonFlag = cli.BoolFlag{ - Name: "log.json", - Usage: "Format logs with JSON", - } - backtraceAtFlag = cli.StringFlag{ - Name: "log.backtrace", - Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", - Value: "", - } - debugFlag = cli.BoolFlag{ - Name: "log.debug", - Usage: "Prepends log messages with call-site location (file and line number)", - } - pprofFlag = cli.BoolFlag{ - Name: "pprof", - Usage: "Enable the pprof HTTP server", - } - pprofPortFlag = cli.IntFlag{ - Name: "pprof.port", - Usage: "pprof HTTP server listening port", - Value: 6060, - } - pprofAddrFlag = cli.StringFlag{ - Name: "pprof.addr", - Usage: "pprof HTTP server listening interface", - Value: "127.0.0.1", - } - memprofilerateFlag = cli.IntFlag{ - Name: "pprof.memprofilerate", - Usage: "Turn on memory profiling with the given rate", - Value: runtime.MemProfileRate, - } - blockprofilerateFlag = cli.IntFlag{ - Name: "pprof.blockprofilerate", - Usage: "Turn on block profiling with the given rate", - } - cpuprofileFlag = cli.StringFlag{ - Name: "pprof.cpuprofile", - Usage: "Write CPU profile to the given file", - } - traceFlag = cli.StringFlag{ - Name: "trace", - Usage: "Write execution trace to the given file", + verbosityFlag = &cli.IntFlag{ + Name: "verbosity", + Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail", + Value: 3, + Category: flags.LoggingCategory, + } + vmoduleFlag = &cli.StringFlag{ + Name: "vmodule", + Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)", + Value: "", + Category: flags.LoggingCategory, + } + logjsonFlag = &cli.BoolFlag{ + Name: "log.json", + Usage: "Format logs with JSON", + Category: flags.LoggingCategory, + } + backtraceAtFlag = &cli.StringFlag{ + Name: "log.backtrace", + Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", + Value: "", + Category: flags.LoggingCategory, + } + debugFlag = &cli.BoolFlag{ + Name: "log.debug", + Usage: "Prepends log messages with call-site location (file and line number)", + Category: flags.LoggingCategory, + } + pprofFlag = &cli.BoolFlag{ + Name: "pprof", + Usage: "Enable the pprof HTTP server", + Category: flags.LoggingCategory, + } + pprofPortFlag = &cli.IntFlag{ + Name: "pprof.port", + Usage: "pprof HTTP server listening port", + Value: 6060, + Category: flags.LoggingCategory, + } + pprofAddrFlag = &cli.StringFlag{ + Name: "pprof.addr", + Usage: "pprof HTTP server listening interface", + Value: "127.0.0.1", + Category: flags.LoggingCategory, + } + memprofilerateFlag = &cli.IntFlag{ + Name: "pprof.memprofilerate", + Usage: "Turn on memory profiling with the given rate", + Value: runtime.MemProfileRate, + Category: flags.LoggingCategory, + } + blockprofilerateFlag = &cli.IntFlag{ + Name: "pprof.blockprofilerate", + Usage: "Turn on block profiling with the given rate", + Category: flags.LoggingCategory, + } + cpuprofileFlag = &cli.StringFlag{ + Name: "pprof.cpuprofile", + Usage: "Write CPU profile to the given file", + Category: flags.LoggingCategory, + } + traceFlag = &cli.StringFlag{ + Name: "trace", + Usage: "Write execution trace to the given file", + Category: flags.LoggingCategory, } ) @@ -121,7 +134,7 @@ func init() { func Setup(ctx *cli.Context) error { var ostream log.Handler output := io.Writer(os.Stderr) - if ctx.GlobalBool(logjsonFlag.Name) { + if ctx.Bool(logjsonFlag.Name) { ostream = log.StreamHandler(output, log.JSONFormat()) } else { usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" @@ -133,53 +146,53 @@ func Setup(ctx *cli.Context) error { glogger.SetHandler(ostream) // logging - verbosity := ctx.GlobalInt(verbosityFlag.Name) + verbosity := ctx.Int(verbosityFlag.Name) glogger.Verbosity(log.Lvl(verbosity)) - vmodule := ctx.GlobalString(vmoduleFlag.Name) + vmodule := ctx.String(vmoduleFlag.Name) glogger.Vmodule(vmodule) - debug := ctx.GlobalBool(debugFlag.Name) - if ctx.GlobalIsSet(debugFlag.Name) { - debug = ctx.GlobalBool(debugFlag.Name) + debug := ctx.Bool(debugFlag.Name) + if ctx.IsSet(debugFlag.Name) { + debug = ctx.Bool(debugFlag.Name) } log.PrintOrigins(debug) - backtrace := ctx.GlobalString(backtraceAtFlag.Name) + backtrace := ctx.String(backtraceAtFlag.Name) glogger.BacktraceAt(backtrace) log.Root().SetHandler(glogger) // profiling, tracing runtime.MemProfileRate = memprofilerateFlag.Value - if ctx.GlobalIsSet(memprofilerateFlag.Name) { - runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) + if ctx.IsSet(memprofilerateFlag.Name) { + runtime.MemProfileRate = ctx.Int(memprofilerateFlag.Name) } - blockProfileRate := ctx.GlobalInt(blockprofilerateFlag.Name) + blockProfileRate := ctx.Int(blockprofilerateFlag.Name) Handler.SetBlockProfileRate(blockProfileRate) - if traceFile := ctx.GlobalString(traceFlag.Name); traceFile != "" { + if traceFile := ctx.String(traceFlag.Name); traceFile != "" { if err := Handler.StartGoTrace(traceFile); err != nil { return err } } - if cpuFile := ctx.GlobalString(cpuprofileFlag.Name); cpuFile != "" { + if cpuFile := ctx.String(cpuprofileFlag.Name); cpuFile != "" { if err := Handler.StartCPUProfile(cpuFile); err != nil { return err } } // pprof server - if ctx.GlobalBool(pprofFlag.Name) { - listenHost := ctx.GlobalString(pprofAddrFlag.Name) + if ctx.Bool(pprofFlag.Name) { + listenHost := ctx.String(pprofAddrFlag.Name) - port := ctx.GlobalInt(pprofPortFlag.Name) + port := ctx.Int(pprofPortFlag.Name) address := fmt.Sprintf("%s:%d", listenHost, port) // This context value ("metrics.addr") represents the utils.MetricsHTTPFlag.Name. // It cannot be imported because it will cause a cyclical dependency. - StartPProf(address, !ctx.GlobalIsSet("metrics.addr")) + StartPProf(address, !ctx.IsSet("metrics.addr")) } return nil } diff --git a/internal/flags/categories.go b/internal/flags/categories.go new file mode 100644 index 000000000000..c2db6c6c1d25 --- /dev/null +++ b/internal/flags/categories.go @@ -0,0 +1,43 @@ +// Copyright 2022 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 flags + +import "github.com/urfave/cli/v2" + +const ( + EthCategory = "ETHEREUM" + LightCategory = "LIGHT CLIENT" + DevCategory = "DEVELOPER CHAIN" + EthashCategory = "ETHASH" + TxPoolCategory = "TRANSACTION POOL" + PerfCategory = "PERFORMANCE TUNING" + AccountCategory = "ACCOUNT" + APICategory = "API AND CONSOLE" + NetworkingCategory = "NETWORKING" + MinerCategory = "MINER" + GasPriceCategory = "GAS PRICE ORACLE" + VMCategory = "VIRTUAL MACHINE" + LoggingCategory = "LOGGING AND DEBUGGING" + MetricsCategory = "METRICS AND STATS" + MiscCategory = "MISC" + DeprecatedCategory = "ALIASED (deprecated)" +) + +func init() { + cli.HelpFlag.(*cli.BoolFlag).Category = MiscCategory + cli.VersionFlag.(*cli.BoolFlag).Category = MiscCategory +} diff --git a/internal/flags/flags.go b/internal/flags/flags.go new file mode 100644 index 000000000000..0ae2c6a512ef --- /dev/null +++ b/internal/flags/flags.go @@ -0,0 +1,340 @@ +// Copyright 2015 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 flags + +import ( + "encoding" + "errors" + "flag" + "math/big" + "os" + "os/user" + "path" + "strings" + + "github.com/ethereum/go-ethereum/common/math" + "github.com/urfave/cli/v2" +) + +// DirectoryString is custom type which is registered in the flags library which cli uses for +// argument parsing. This allows us to expand Value to an absolute path when +// the argument is parsed +type DirectoryString string + +func (s *DirectoryString) String() string { + return string(*s) +} + +func (s *DirectoryString) Set(value string) error { + *s = DirectoryString(expandPath(value)) + return nil +} + +var ( + _ cli.Flag = (*DirectoryFlag)(nil) + _ cli.RequiredFlag = (*DirectoryFlag)(nil) + _ cli.VisibleFlag = (*DirectoryFlag)(nil) + _ cli.DocGenerationFlag = (*DirectoryFlag)(nil) + _ cli.CategorizableFlag = (*DirectoryFlag)(nil) +) + +// DirectoryFlag is custom cli.Flag type which expand the received string to an absolute path. +// e.g. ~/.ethereum -> /home/username/.ethereum +type DirectoryFlag struct { + Name string + + Category string + DefaultText string + Usage string + + Required bool + Hidden bool + HasBeenSet bool + + Value DirectoryString + + Aliases []string +} + +// For cli.Flag: + +func (f *DirectoryFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) } +func (f *DirectoryFlag) IsSet() bool { return f.HasBeenSet } +func (f *DirectoryFlag) String() string { return cli.FlagStringer(f) } + +// Apply called by cli library, grabs variable from environment (if in env) +// and adds variable to flag set for parsing. +func (f *DirectoryFlag) Apply(set *flag.FlagSet) error { + eachName(f, func(name string) { + set.Var(&f.Value, f.Name, f.Usage) + }) + return nil +} + +// For cli.RequiredFlag: + +func (f *DirectoryFlag) IsRequired() bool { return f.Required } + +// For cli.VisibleFlag: + +func (f *DirectoryFlag) IsVisible() bool { return !f.Hidden } + +// For cli.CategorizableFlag: + +func (f *DirectoryFlag) GetCategory() string { return f.Category } + +// For cli.DocGenerationFlag: + +func (f *DirectoryFlag) TakesValue() bool { return true } +func (f *DirectoryFlag) GetUsage() string { return f.Usage } +func (f *DirectoryFlag) GetValue() string { return f.Value.String() } +func (f *DirectoryFlag) GetEnvVars() []string { return nil } // env not supported + +func (f *DirectoryFlag) GetDefaultText() string { + if f.DefaultText != "" { + return f.DefaultText + } + return f.GetValue() +} + +type TextMarshaler interface { + encoding.TextMarshaler + encoding.TextUnmarshaler +} + +// textMarshalerVal turns a TextMarshaler into a flag.Value +type textMarshalerVal struct { + v TextMarshaler +} + +func (v textMarshalerVal) String() string { + if v.v == nil { + return "" + } + text, _ := v.v.MarshalText() + return string(text) +} + +func (v textMarshalerVal) Set(s string) error { + return v.v.UnmarshalText([]byte(s)) +} + +var ( + _ cli.Flag = (*TextMarshalerFlag)(nil) + _ cli.RequiredFlag = (*TextMarshalerFlag)(nil) + _ cli.VisibleFlag = (*TextMarshalerFlag)(nil) + _ cli.DocGenerationFlag = (*TextMarshalerFlag)(nil) + _ cli.CategorizableFlag = (*TextMarshalerFlag)(nil) +) + +// TextMarshalerFlag wraps a TextMarshaler value. +type TextMarshalerFlag struct { + Name string + + Category string + DefaultText string + Usage string + + Required bool + Hidden bool + HasBeenSet bool + + Value TextMarshaler + + Aliases []string +} + +// For cli.Flag: + +func (f *TextMarshalerFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) } +func (f *TextMarshalerFlag) IsSet() bool { return f.HasBeenSet } +func (f *TextMarshalerFlag) String() string { return cli.FlagStringer(f) } + +func (f *TextMarshalerFlag) Apply(set *flag.FlagSet) error { + eachName(f, func(name string) { + set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage) + }) + return nil +} + +// For cli.RequiredFlag: + +func (f *TextMarshalerFlag) IsRequired() bool { return f.Required } + +// For cli.VisibleFlag: + +func (f *TextMarshalerFlag) IsVisible() bool { return !f.Hidden } + +// For cli.CategorizableFlag: + +func (f *TextMarshalerFlag) GetCategory() string { return f.Category } + +// For cli.DocGenerationFlag: + +func (f *TextMarshalerFlag) TakesValue() bool { return true } +func (f *TextMarshalerFlag) GetUsage() string { return f.Usage } +func (f *TextMarshalerFlag) GetEnvVars() []string { return nil } // env not supported + +func (f *TextMarshalerFlag) GetValue() string { + t, err := f.Value.MarshalText() + if err != nil { + return "(ERR: " + err.Error() + ")" + } + return string(t) +} + +func (f *TextMarshalerFlag) GetDefaultText() string { + if f.DefaultText != "" { + return f.DefaultText + } + return f.GetValue() +} + +// GlobalTextMarshaler returns the value of a TextMarshalerFlag from the global flag set. +func GlobalTextMarshaler(ctx *cli.Context, name string) TextMarshaler { + val := ctx.Generic(name) + if val == nil { + return nil + } + return val.(textMarshalerVal).v +} + +var ( + _ cli.Flag = (*BigFlag)(nil) + _ cli.RequiredFlag = (*BigFlag)(nil) + _ cli.VisibleFlag = (*BigFlag)(nil) + _ cli.DocGenerationFlag = (*BigFlag)(nil) + _ cli.CategorizableFlag = (*BigFlag)(nil) +) + +// BigFlag is a command line flag that accepts 256 bit big integers in decimal or +// hexadecimal syntax. +type BigFlag struct { + Name string + + Category string + DefaultText string + Usage string + + Required bool + Hidden bool + HasBeenSet bool + + Value *big.Int + + Aliases []string +} + +// For cli.Flag: + +func (f *BigFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) } +func (f *BigFlag) IsSet() bool { return f.HasBeenSet } +func (f *BigFlag) String() string { return cli.FlagStringer(f) } + +func (f *BigFlag) Apply(set *flag.FlagSet) error { + eachName(f, func(name string) { + f.Value = new(big.Int) + set.Var((*bigValue)(f.Value), f.Name, f.Usage) + }) + + return nil +} + +// For cli.RequiredFlag: + +func (f *BigFlag) IsRequired() bool { return f.Required } + +// For cli.VisibleFlag: + +func (f *BigFlag) IsVisible() bool { return !f.Hidden } + +// For cli.CategorizableFlag: + +func (f *BigFlag) GetCategory() string { return f.Category } + +// For cli.DocGenerationFlag: + +func (f *BigFlag) TakesValue() bool { return true } +func (f *BigFlag) GetUsage() string { return f.Usage } +func (f *BigFlag) GetValue() string { return f.Value.String() } +func (f *BigFlag) GetEnvVars() []string { return nil } // env not supported + +func (f *BigFlag) GetDefaultText() string { + if f.DefaultText != "" { + return f.DefaultText + } + return f.GetValue() +} + +// bigValue turns *big.Int into a flag.Value +type bigValue big.Int + +func (b *bigValue) String() string { + if b == nil { + return "" + } + return (*big.Int)(b).String() +} + +func (b *bigValue) Set(s string) error { + intVal, ok := math.ParseBig256(s) + if !ok { + return errors.New("invalid integer syntax") + } + *b = (bigValue)(*intVal) + return nil +} + +// GlobalBig returns the value of a BigFlag from the global flag set. +func GlobalBig(ctx *cli.Context, name string) *big.Int { + val := ctx.Generic(name) + if val == nil { + return nil + } + return (*big.Int)(val.(*bigValue)) +} + +// Expands a file path +// 1. replace tilde with users home dir +// 2. expands embedded environment variables +// 3. cleans the path, e.g. /a/b/../c -> /a/c +// Note, it has limitations, e.g. ~someuser/tmp will not be expanded +func expandPath(p string) string { + if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { + if home := HomeDir(); home != "" { + p = home + p[1:] + } + } + return path.Clean(os.ExpandEnv(p)) +} + +func HomeDir() string { + if home := os.Getenv("HOME"); home != "" { + return home + } + if usr, err := user.Current(); err == nil { + return usr.HomeDir + } + return "" +} + +func eachName(f cli.Flag, fn func(string)) { + for _, name := range f.Names() { + name = strings.Trim(name, " ") + fn(name) + } +} diff --git a/cmd/utils/customflags_test.go b/internal/flags/flags_test.go similarity index 61% rename from cmd/utils/customflags_test.go rename to internal/flags/flags_test.go index de39ca36a116..a0d4af7ca360 100644 --- a/cmd/utils/customflags_test.go +++ b/internal/flags/flags_test.go @@ -1,20 +1,20 @@ // Copyright 2015 The go-ethereum Authors -// This file is part of go-ethereum. +// This file is part of the go-ethereum library. // -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by +// 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. // -// go-ethereum is distributed in the hope that it will be useful, +// 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 General Public License for more details. +// GNU Lesser General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . -package utils +package flags import ( "os" diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index 1fc6409c6550..d0ad9c4cef4a 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -17,137 +17,160 @@ package flags import ( - "os" - "path/filepath" + "fmt" + "strings" "github.com/ethereum/go-ethereum/params" - "gopkg.in/urfave/cli.v1" + "github.com/urfave/cli/v2" ) -var ( - CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} {{.cmd.ArgsUsage}} -{{if .cmd.Description}}{{.cmd.Description}} -{{end}}{{if .cmd.Subcommands}} -SUBCOMMANDS: - {{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} - {{end}}{{end}}{{if .categorizedFlags}} -{{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS: -{{range $categorized.Flags}}{{"\t"}}{{.}} -{{end}} -{{end}}{{end}}` - - OriginCommandHelpTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} {{.ArgsUsage}} -{{if .Description}}{{.Description}} -{{end}}{{if .Subcommands}} -SUBCOMMANDS: - {{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} - {{end}}{{end}}{{if .Flags}} -OPTIONS: -{{range $.Flags}} {{.}} -{{end}} -{{end}}` - - // AppHelpTemplate is the test template for the default, global app help topic. - AppHelpTemplate = `NAME: - {{.App.Name}} - {{.App.Usage}} - - Copyright 2013-2022 The go-ethereum Authors - -USAGE: - {{.App.HelpName}} [options]{{if .App.Commands}} [command] [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}} - {{if .App.Version}} -VERSION: - {{.App.Version}} - {{end}}{{if len .App.Authors}} -AUTHOR(S): - {{range .App.Authors}}{{ . }}{{end}} - {{end}}{{if .App.Commands}} -COMMANDS: - {{range .App.Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} - {{end}}{{end}}{{if .FlagGroups}} -{{range .FlagGroups}}{{.Name}} OPTIONS: - {{range .Flags}}{{.}} - {{end}} -{{end}}{{end}}{{if .App.Copyright }} -COPYRIGHT: - {{.App.Copyright}} - {{end}} -` - // ClefAppHelpTemplate is the template for the default, global app help topic. - ClefAppHelpTemplate = `NAME: - {{.App.Name}} - {{.App.Usage}} - - Copyright 2013-2022 The go-ethereum Authors - -USAGE: - {{.App.HelpName}} [options]{{if .App.Commands}} command [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}} - {{if .App.Version}} -COMMANDS: - {{range .App.Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} - {{end}}{{end}}{{if .FlagGroups}} -{{range .FlagGroups}}{{.Name}} OPTIONS: - {{range .Flags}}{{.}} - {{end}} -{{end}}{{end}}{{if .App.Copyright }} -COPYRIGHT: - {{.App.Copyright}} - {{end}} -` -) +// NewApp creates an app with sane defaults. +func NewApp(gitCommit, gitDate, usage string) *cli.App { + app := cli.NewApp() + app.EnableBashCompletion = true + app.Version = params.VersionWithCommit(gitCommit, gitDate) + app.Usage = usage + app.Copyright = "Copyright 2013-2022 The go-ethereum Authors" + app.Before = func(ctx *cli.Context) error { + MigrateGlobalFlags(ctx) + return nil + } + return app +} + +var migrationApplied = map[*cli.Command]struct{}{} + +// MigrateGlobalFlags makes all global flag values available in the +// context. This should be called as early as possible in app.Before. +// +// Example: +// +// geth account new --keystore /tmp/mykeystore --lightkdf +// +// is equivalent after calling this method with: +// +// geth --keystore /tmp/mykeystore --lightkdf account new +// +// i.e. in the subcommand Action function of 'account new', ctx.Bool("lightkdf) +// will return true even if --lightkdf is set as a global option. +// +// This function may become unnecessary when https://github.com/urfave/cli/pull/1245 is merged. +func MigrateGlobalFlags(ctx *cli.Context) { + var iterate func(cs []*cli.Command, fn func(*cli.Command)) + iterate = func(cs []*cli.Command, fn func(*cli.Command)) { + for _, cmd := range cs { + if _, ok := migrationApplied[cmd]; ok { + continue + } + migrationApplied[cmd] = struct{}{} + fn(cmd) + iterate(cmd.Subcommands, fn) + } + } + + // This iterates over all commands and wraps their action function. + iterate(ctx.App.Commands, func(cmd *cli.Command) { + action := cmd.Action + cmd.Action = func(ctx *cli.Context) error { + doMigrateFlags(ctx) + return action(ctx) + } + }) +} -// HelpData is a one shot struct to pass to the usage template -type HelpData struct { - App interface{} - FlagGroups []FlagGroup +func doMigrateFlags(ctx *cli.Context) { + for _, name := range ctx.FlagNames() { + for _, parent := range ctx.Lineage()[1:] { + if parent.IsSet(name) { + ctx.Set(name, parent.String(name)) + break + } + } + } } -// FlagGroup is a collection of flags belonging to a single topic. -type FlagGroup struct { - Name string - Flags []cli.Flag +func init() { + cli.FlagStringer = FlagString } -// ByCategory sorts an array of FlagGroup by Name in the order -// defined in AppHelpFlagGroups. -type ByCategory []FlagGroup +// FlagString prints a single flag in help. +func FlagString(f cli.Flag) string { + df, ok := f.(cli.DocGenerationFlag) + if !ok { + return "" + } -func (a ByCategory) Len() int { return len(a) } -func (a ByCategory) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a ByCategory) Less(i, j int) bool { - iCat, jCat := a[i].Name, a[j].Name - iIdx, jIdx := len(a), len(a) // ensure non categorized flags come last + needsPlaceholder := df.TakesValue() + placeholder := "" + if needsPlaceholder { + placeholder = "value" + } - for i, group := range a { - if iCat == group.Name { - iIdx = i - } - if jCat == group.Name { - jIdx = i - } + namesText := pad(cli.FlagNamePrefixer(df.Names(), placeholder), 30) + + defaultValueString := "" + if s := df.GetDefaultText(); s != "" { + defaultValueString = " (default: " + s + ")" + } + + usage := strings.TrimSpace(df.GetUsage()) + envHint := strings.TrimSpace(cli.FlagEnvHinter(df.GetEnvVars(), "")) + if len(envHint) > 0 { + usage += " " + envHint + } + + usage = wordWrap(usage, 80) + usage = indent(usage, 10) + + return fmt.Sprintf("\n %s%s\n%s", namesText, defaultValueString, usage) +} + +func pad(s string, length int) string { + if len(s) < length { + s += strings.Repeat(" ", length-len(s)) } + return s +} - return iIdx < jIdx +func indent(s string, nspace int) string { + ind := strings.Repeat(" ", nspace) + return ind + strings.ReplaceAll(s, "\n", "\n"+ind) } -func FlagCategory(flag cli.Flag, flagGroups []FlagGroup) string { - for _, category := range flagGroups { - for _, flg := range category.Flags { - if flg.GetName() == flag.GetName() { - return category.Name +func wordWrap(s string, width int) string { + var ( + output strings.Builder + lineLength = 0 + ) + + for { + sp := strings.IndexByte(s, ' ') + var word string + if sp == -1 { + word = s + } else { + word = s[:sp] + } + wlen := len(word) + over := lineLength+wlen >= width + if over { + output.WriteByte('\n') + lineLength = 0 + } else { + if lineLength != 0 { + output.WriteByte(' ') + lineLength++ } } + + output.WriteString(word) + lineLength += wlen + + if sp == -1 { + break + } + s = s[wlen+1:] } - return "MISC" -} -// NewApp creates an app with sane defaults. -func NewApp(gitCommit, gitDate, usage string) *cli.App { - app := cli.NewApp() - app.EnableBashCompletion = true - app.Name = filepath.Base(os.Args[0]) - app.Author = "" - app.Email = "" - app.Version = params.VersionWithCommit(gitCommit, gitDate) - app.Usage = usage - return app + return output.String() } From 1438e7c3249a746069bd18be184c1aab5f9214f6 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 28 Jun 2022 14:48:13 +0200 Subject: [PATCH 054/715] params: set TTD for sepolia testnet (#25179) --- params/config.go | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/params/config.go b/params/config.go index 44b575a876c7..26c5123e7129 100644 --- a/params/config.go +++ b/params/config.go @@ -142,21 +142,22 @@ var ( // SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network. SepoliaChainConfig = &ChainConfig{ - ChainID: big.NewInt(11155111), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - MuirGlacierBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - Ethash: new(EthashConfig), + ChainID: big.NewInt(11155111), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(17_000_000_000_000_000), + Ethash: new(EthashConfig), } // SepoliaTrustedCheckpoint contains the light client trusted checkpoint for the Sepolia test network. From 9a5c1000c73c39e036973f4dfa828acc707e6d7c Mon Sep 17 00:00:00 2001 From: zeim839 <50573884+zeim839@users.noreply.github.com> Date: Tue, 28 Jun 2022 11:25:47 -0400 Subject: [PATCH 055/715] cmd/geth, p2p: add support for custom discovery UDP port (#24979) This adds a new flag to set the discovery port to be different from the TCP listener port. Co-authored-by: Felix Lange --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 13 +++++++++++-- p2p/server.go | 14 +++++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 1ae7116eda79..b0a849a3ba6a 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -119,6 +119,7 @@ var ( utils.CachePreimagesFlag, utils.FDLimitFlag, utils.ListenPortFlag, + utils.DiscoveryPortFlag, utils.MaxPeersFlag, utils.MaxPendingPeersFlag, utils.MiningEnabledFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5cebaba43ecf..ce116b574643 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -835,6 +835,12 @@ var ( Usage: "Sets DNS discovery entry points (use \"\" to disable DNS)", Category: flags.NetworkingCategory, } + DiscoveryPortFlag = &cli.IntFlag{ + Name: "discovery.port", + Usage: "Use a custom UDP port for P2P discovery", + Value: 30303, + Category: flags.NetworkingCategory, + } // Console JSpathFlag = &flags.DirectoryFlag{ @@ -1116,12 +1122,15 @@ func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { } } -// setListenAddress creates a TCP listening address string from set command -// line flags. +// setListenAddress creates TCP/UDP listening address strings from set command +// line flags func setListenAddress(ctx *cli.Context, cfg *p2p.Config) { if ctx.IsSet(ListenPortFlag.Name) { cfg.ListenAddr = fmt.Sprintf(":%d", ctx.Int(ListenPortFlag.Name)) } + if ctx.IsSet(DiscoveryPortFlag.Name) { + cfg.DiscAddr = fmt.Sprintf(":%d", ctx.Int(DiscoveryPortFlag.Name)) + } } // setNAT creates a port mapper from command line flags. diff --git a/p2p/server.go b/p2p/server.go index 898201f8f7fc..19f7935ffcae 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -136,6 +136,10 @@ type Config struct { // the server is started. ListenAddr string + // If DiscAddr is set to a non-nil value, the server will use ListenAddr + // for TCP and DiscAddr for the UDP discovery protocol. + DiscAddr string + // If set to a non-nil value, the given NAT port mapper // is used to make the listening port available to the // Internet. @@ -549,7 +553,15 @@ func (srv *Server) setupDiscovery() error { return nil } - addr, err := net.ResolveUDPAddr("udp", srv.ListenAddr) + listenAddr := srv.ListenAddr + + // Use an alternate listening address for UDP if + // a custom discovery address is configured. + if srv.DiscAddr != "" { + listenAddr = srv.DiscAddr + } + + addr, err := net.ResolveUDPAddr("udp", listenAddr) if err != nil { return err } From d1890aa402007c570dfa74fd93acb64b52adc1bb Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Wed, 29 Jun 2022 10:54:57 +0200 Subject: [PATCH 056/715] fix: linter warning (#25192) --- common/fdlimit/fdlimit_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/fdlimit/fdlimit_test.go b/common/fdlimit/fdlimit_test.go index 21362b8463a3..9fd5e9fc3cbd 100644 --- a/common/fdlimit/fdlimit_test.go +++ b/common/fdlimit/fdlimit_test.go @@ -17,7 +17,6 @@ package fdlimit import ( - "fmt" "testing" ) @@ -30,7 +29,7 @@ func TestFileDescriptorLimits(t *testing.T) { t.Fatal(err) } if hardlimit < target { - t.Skip(fmt.Sprintf("system limit is less than desired test target: %d < %d", hardlimit, target)) + t.Skipf("system limit is less than desired test target: %d < %d", hardlimit, target) } if limit, err := Current(); err != nil || limit <= 0 { From 3f712e74477c63a9c63699e89cbd5158eb50b017 Mon Sep 17 00:00:00 2001 From: Ruohui Wang Date: Wed, 29 Jun 2022 04:47:33 -0500 Subject: [PATCH 057/715] core/rawdb: fix typo in comment (#25191) --- core/rawdb/database.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 2b870d16d44f..3fbee41dad3c 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -208,7 +208,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace st // are contiguous, otherwise we might end up with a non-functional freezer. if kvhash, _ := db.Get(headerHashKey(frozen)); len(kvhash) == 0 { // Subsequent header after the freezer limit is missing from the database. - // Reject startup is the database has a more recent head. + // Reject startup if the database has a more recent head. if *ReadHeaderNumber(db, ReadHeadHeaderHash(db)) > frozen-1 { return nil, fmt.Errorf("gap (#%d) in the chain between ancients and leveldb", frozen) } From 300f6121adc1e820acba495f7bf57f48163e8c2a Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Wed, 29 Jun 2022 05:54:42 -0400 Subject: [PATCH 058/715] core/rawdb: simplify TestDiskSeek to use memorydb (#25182) --- core/state/snapshot/disklayer_test.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/core/state/snapshot/disklayer_test.go b/core/state/snapshot/disklayer_test.go index b078951c72aa..f95b79851598 100644 --- a/core/state/snapshot/disklayer_test.go +++ b/core/state/snapshot/disklayer_test.go @@ -23,7 +23,6 @@ import ( "github.com/VictoriaMetrics/fastcache" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/ethdb/leveldb" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/rlp" ) @@ -515,11 +514,7 @@ func TestDiskMidAccountPartialMerge(t *testing.T) { // TestDiskSeek tests that seek-operations work on the disk layer func TestDiskSeek(t *testing.T) { // Create some accounts in the disk layer - diskdb, err := leveldb.New(t.TempDir(), 256, 0, "", false) - if err != nil { - t.Fatal(err) - } - db := rawdb.NewDatabase(diskdb) + db := rawdb.NewMemoryDatabase() defer db.Close() // Fill even keys [0,2,4...] From 9ecf8a97a93d75bd12004df158358aa2f10877bc Mon Sep 17 00:00:00 2001 From: Andre Patta Date: Wed, 29 Jun 2022 06:57:12 -0300 Subject: [PATCH 059/715] cmd/utils: fix applying bootstrap nodes from config file (#25174) --- cmd/utils/flags.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ce116b574643..47637a9dd255 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1081,8 +1081,11 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { urls = params.GoerliBootnodes case ctx.Bool(KilnFlag.Name): urls = params.KilnBootnodes - case cfg.BootstrapNodes != nil: - return // already set, don't apply defaults. + } + + // don't apply defaults if BootstrapNodes is already set + if cfg.BootstrapNodes != nil { + return } cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls)) From 3e693e1ef6e2da69847a30a14808b327aa07060e Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Wed, 29 Jun 2022 11:58:59 +0200 Subject: [PATCH 060/715] internal/ethapi: return chain id for EIP-155 legacy txs (#25155) --- internal/ethapi/api.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b05c9a08d379..b45c1f123f58 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1284,6 +1284,11 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber result.TransactionIndex = (*hexutil.Uint64)(&index) } switch tx.Type() { + case types.LegacyTxType: + // if a legacy transaction has an EIP-155 chain id, include it explicitly + if id := tx.ChainId(); id.Sign() == 0 { + result.ChainID = (*hexutil.Big)(id) + } case types.AccessListTxType: al := tx.AccessList() result.Accesses = &al From c2070f8d15141f5fa71221a41be011e8f8b1648f Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Wed, 29 Jun 2022 19:13:00 +0900 Subject: [PATCH 061/715] common: increase StorageSize test coverage (#25188) --- common/size_test.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/common/size_test.go b/common/size_test.go index 0938d483c4bb..28f053d39f5d 100644 --- a/common/size_test.go +++ b/common/size_test.go @@ -25,6 +25,8 @@ func TestStorageSizeString(t *testing.T) { size StorageSize str string }{ + {2839274474874, "2.58 TiB"}, + {2458492810, "2.29 GiB"}, {2381273, "2.27 MiB"}, {2192, "2.14 KiB"}, {12, "12.00 B"}, @@ -36,3 +38,22 @@ func TestStorageSizeString(t *testing.T) { } } } + +func TestStorageSizeTerminalString(t *testing.T) { + tests := []struct { + size StorageSize + str string + }{ + {2839274474874, "2.58TiB"}, + {2458492810, "2.29GiB"}, + {2381273, "2.27MiB"}, + {2192, "2.14KiB"}, + {12, "12.00B"}, + } + + for _, test := range tests { + if test.size.TerminalString() != test.str { + t.Errorf("%f: got %q, want %q", float64(test.size), test.size.TerminalString(), test.str) + } + } +} From d12b1a91cd9423f83bf77dbe363164797549ff15 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 29 Jun 2022 14:13:19 +0200 Subject: [PATCH 062/715] consensus/beacon: check that only the latest pow block is valid ttd block (#25187) * consensus/beacon: check that only the latest pow block is valid ttd block * consensus/beacon: move verification to async function * consensus/beacon: fix verifyTerminalPoWBlock, add test cases * consensus/beacon: cosmetic changes * consensus/beacon: apply karalabe's fixes --- consensus/beacon/consensus.go | 40 ++++++++- consensus/beacon/consensus_test.go | 137 +++++++++++++++++++++++++++++ consensus/errors.go | 4 + core/block_validator_test.go | 3 +- 4 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 consensus/beacon/consensus_test.go diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 1fd7deb872fb..e090a03990f6 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -112,10 +112,12 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ break } } + // All the headers have passed the transition point, use new rules. if len(preHeaders) == 0 { return beacon.verifyHeaders(chain, headers, nil) } + // The transition point exists in the middle, separate the headers // into two batches and apply different verification rules for them. var ( @@ -130,6 +132,14 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders, preSeals) newDone, newResult = beacon.verifyHeaders(chain, postHeaders, preHeaders[len(preHeaders)-1]) ) + // Verify that pre-merge headers don't overflow the TTD + if index, err := verifyTerminalPoWBlock(chain, preHeaders); err != nil { + // Mark all subsequent pow headers with the error. + for i := index; i < len(preHeaders); i++ { + errors[i], done[i] = err, true + } + } + // Collect the results for { for ; done[out]; out++ { results <- errors[out] @@ -139,7 +149,9 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ } select { case err := <-oldResult: - errors[old], done[old] = err, true + if !done[old] { // skip TTD-verified failures + errors[old], done[old] = err, true + } old++ case err := <-newResult: errors[new], done[new] = err, true @@ -154,6 +166,32 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ return abort, results } +// verifyTerminalPoWBlock verifies that the preHeaders confirm to the specification +// wrt. their total difficulty. +// It expects: +// - preHeaders to be at least 1 element +// - the parent of the header element to be stored in the chain correctly +// - the preHeaders to have a set difficulty +// - the last element to be the terminal block +func verifyTerminalPoWBlock(chain consensus.ChainHeaderReader, preHeaders []*types.Header) (int, error) { + td := chain.GetTd(preHeaders[0].ParentHash, preHeaders[0].Number.Uint64()-1) + if td == nil { + return 0, consensus.ErrUnknownAncestor + } + // Check that all blocks before the last one are below the TTD + for i, head := range preHeaders { + if td.Cmp(chain.Config().TerminalTotalDifficulty) >= 0 { + return i, consensus.ErrInvalidTerminalBlock + } + td.Add(td, head.Difficulty) + } + // Check that the last block is the terminal block + if td.Cmp(chain.Config().TerminalTotalDifficulty) < 0 { + return len(preHeaders) - 1, consensus.ErrInvalidTerminalBlock + } + return 0, nil +} + // VerifyUncles verifies that the given block's uncles conform to the consensus // rules of the Ethereum consensus engine. func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { diff --git a/consensus/beacon/consensus_test.go b/consensus/beacon/consensus_test.go new file mode 100644 index 000000000000..09c0b27c4256 --- /dev/null +++ b/consensus/beacon/consensus_test.go @@ -0,0 +1,137 @@ +package beacon + +import ( + "fmt" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" +) + +type mockChain struct { + config *params.ChainConfig + tds map[uint64]*big.Int +} + +func newMockChain() *mockChain { + return &mockChain{ + config: new(params.ChainConfig), + tds: make(map[uint64]*big.Int), + } +} + +func (m *mockChain) Config() *params.ChainConfig { + return m.config +} + +func (m *mockChain) CurrentHeader() *types.Header { panic("not implemented") } + +func (m *mockChain) GetHeader(hash common.Hash, number uint64) *types.Header { + panic("not implemented") +} + +func (m *mockChain) GetHeaderByNumber(number uint64) *types.Header { panic("not implemented") } + +func (m *mockChain) GetHeaderByHash(hash common.Hash) *types.Header { panic("not implemented") } + +func (m *mockChain) GetTd(hash common.Hash, number uint64) *big.Int { + num, ok := m.tds[number] + if ok { + return new(big.Int).Set(num) + } + return nil +} + +func TestVerifyTerminalBlock(t *testing.T) { + chain := newMockChain() + chain.tds[0] = big.NewInt(10) + chain.config.TerminalTotalDifficulty = big.NewInt(50) + + tests := []struct { + preHeaders []*types.Header + ttd *big.Int + err error + index int + }{ + // valid ttd + { + preHeaders: []*types.Header{ + {Number: big.NewInt(1), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(2), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(3), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(4), Difficulty: big.NewInt(10)}, + }, + ttd: big.NewInt(50), + }, + // last block doesn't reach ttd + { + preHeaders: []*types.Header{ + {Number: big.NewInt(1), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(2), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(3), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(4), Difficulty: big.NewInt(9)}, + }, + ttd: big.NewInt(50), + err: consensus.ErrInvalidTerminalBlock, + index: 3, + }, + // two blocks reach ttd + { + preHeaders: []*types.Header{ + {Number: big.NewInt(1), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(2), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(3), Difficulty: big.NewInt(20)}, + {Number: big.NewInt(4), Difficulty: big.NewInt(10)}, + }, + ttd: big.NewInt(50), + err: consensus.ErrInvalidTerminalBlock, + index: 3, + }, + // three blocks reach ttd + { + preHeaders: []*types.Header{ + {Number: big.NewInt(1), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(2), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(3), Difficulty: big.NewInt(20)}, + {Number: big.NewInt(4), Difficulty: big.NewInt(10)}, + {Number: big.NewInt(4), Difficulty: big.NewInt(10)}, + }, + ttd: big.NewInt(50), + err: consensus.ErrInvalidTerminalBlock, + index: 3, + }, + // parent reached ttd + { + preHeaders: []*types.Header{ + {Number: big.NewInt(1), Difficulty: big.NewInt(10)}, + }, + ttd: big.NewInt(9), + err: consensus.ErrInvalidTerminalBlock, + index: 0, + }, + // unknown parent + { + preHeaders: []*types.Header{ + {Number: big.NewInt(4), Difficulty: big.NewInt(10)}, + }, + ttd: big.NewInt(9), + err: consensus.ErrUnknownAncestor, + index: 0, + }, + } + + for i, test := range tests { + fmt.Printf("Test: %v\n", i) + chain.config.TerminalTotalDifficulty = test.ttd + index, err := verifyTerminalPoWBlock(chain, test.preHeaders) + if err != test.err { + t.Fatalf("Invalid error encountered, expected %v got %v", test.err, err) + } + if index != test.index { + t.Fatalf("Invalid index, expected %v got %v", test.index, index) + } + } +} diff --git a/consensus/errors.go b/consensus/errors.go index ac5242fb54c5..d508b6580f55 100644 --- a/consensus/errors.go +++ b/consensus/errors.go @@ -34,4 +34,8 @@ var ( // ErrInvalidNumber is returned if a block's number doesn't equal its parent's // plus one. ErrInvalidNumber = errors.New("invalid block number") + + // ErrInvalidTerminalBlock is returned if a block is invalid wrt. the terminal + // total difficulty. + ErrInvalidTerminalBlock = errors.New("invalid terminal block") ) diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 0f183ba52778..8dee8d576070 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -107,7 +107,8 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { Alloc: map[common.Address]GenesisAccount{ addr: {Balance: big.NewInt(1)}, }, - BaseFee: big.NewInt(params.InitialBaseFee), + BaseFee: big.NewInt(params.InitialBaseFee), + Difficulty: new(big.Int), } copy(genspec.ExtraData[32:], addr[:]) genesis := genspec.MustCommit(testdb) From ea0bf085472180af43be11f94523459fbfd7ebbc Mon Sep 17 00:00:00 2001 From: "willian.eth" Date: Wed, 29 Jun 2022 19:41:39 +0200 Subject: [PATCH 063/715] build: fix auto-completion scripts and include them in .deb package (#25195) Co-authored-by: Felix Lange --- build/deb/ethereum/completions/bash_autocomplete | 9 ++------- build/deb/ethereum/completions/zsh_autocomplete | 6 ++---- build/deb/ethereum/deb.install | 4 ++++ 3 files changed, 8 insertions(+), 11 deletions(-) mode change 100644 => 100755 build/deb/ethereum/completions/bash_autocomplete diff --git a/build/deb/ethereum/completions/bash_autocomplete b/build/deb/ethereum/completions/bash_autocomplete old mode 100644 new mode 100755 index f0f624183bd0..a78952793efb --- a/build/deb/ethereum/completions/bash_autocomplete +++ b/build/deb/ethereum/completions/bash_autocomplete @@ -1,8 +1,4 @@ -#! /bin/bash - -: ${PROG:=$(basename ${BASH_SOURCE})} - -_cli_bash_autocomplete() { +_geth_bash_autocomplete() { if [[ "${COMP_WORDS[0]}" != "source" ]]; then local cur opts base COMPREPLY=() @@ -17,5 +13,4 @@ _cli_bash_autocomplete() { fi } -complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete $PROG -unset PROG +complete -o bashdefault -o default -o nospace -F _geth_bash_autocomplete geth diff --git a/build/deb/ethereum/completions/zsh_autocomplete b/build/deb/ethereum/completions/zsh_autocomplete index b519666f809c..119794c532bd 100644 --- a/build/deb/ethereum/completions/zsh_autocomplete +++ b/build/deb/ethereum/completions/zsh_autocomplete @@ -1,6 +1,4 @@ -#compdef $PROG - -_cli_zsh_autocomplete() { +_geth_zsh_autocomplete() { local -a opts local cur cur=${words[-1]} @@ -17,4 +15,4 @@ _cli_zsh_autocomplete() { fi } -compdef _cli_zsh_autocomplete $PROG +compdef _geth_zsh_autocomplete geth diff --git a/build/deb/ethereum/deb.install b/build/deb/ethereum/deb.install index e7666ce5fb6b..019bd0f4bb3f 100644 --- a/build/deb/ethereum/deb.install +++ b/build/deb/ethereum/deb.install @@ -1 +1,5 @@ build/bin/{{.BinaryName}} usr/bin +{{- if eq .BinaryName "geth" }} +build/deb/ethereum/completions/bash_autocomplete etc/bash_completion.d/geth +build/deb/ethereum/completions/zsh_autocomplete usr/share/zsh/vendor-completions/_geth +{{end -}} From 63b2d49b5b993a6370185bf843c221e7db9b21b0 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 29 Jun 2022 20:49:04 +0200 Subject: [PATCH 064/715] build: upgrade to golangci-lint v1.46.2 (#25202) This upgrade is required to fix lint issues with urfave/cli/v2, which uses generics when built with Go 1.18 --- .golangci.yml | 3 ++- build/checksums.txt | 62 +++++++++++++++------------------------------ build/ci.go | 2 +- 3 files changed, 24 insertions(+), 43 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b4aa0a01d779..b889c770dff6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -67,5 +67,6 @@ issues: exclude: - 'SA1019: event.TypeMux is deprecated: use Feed' - 'SA1019: strings.Title is deprecated' + - 'SA1019: strings.Title has been deprecated since Go 1.18 and an alternative has been available since Go 1.0: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead.' - 'SA1029: should not use built-in type string as key for value' - - 'G306: Expect WriteFile permissions to be 0600 or less' \ No newline at end of file + - 'G306: Expect WriteFile permissions to be 0600 or less' diff --git a/build/checksums.txt b/build/checksums.txt index 4d6176ecbe59..f97e30770f82 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -15,44 +15,24 @@ b3b815f47ababac13810fc6021eb73d65478e0b2db4b09d348eefad9581a2334 go1.18.1.linux c30bc3f1f7314a953fe208bd9cd5e24bd9403392a6c556ced3677f9f70f71fe1 go1.18.1.windows-amd64.zip 2c4a8265030eac37f906634f5c13c22c3d0ea725f2488e1bca005c6b981653d7 go1.18.1.windows-arm64.zip -03c181fc1bb29ea3e73cbb23399c43b081063833a7cf7554b94e5a98308df53e golangci-lint-1.45.2-linux-riscv64.deb -08a50bbbf451ede6d5354179eb3e14a5634e156dfa92cb9a2606f855a637e35b golangci-lint-1.45.2-linux-ppc64le.rpm -0d12f6ec1296b5a70e392aa88cd2295cceef266165eb7028e675f455515dd1c9 golangci-lint-1.45.2-linux-armv7.deb -10f2846e2e50e4ea8ae426ee62dcd2227b23adddd8e991aa3c065927ac948735 golangci-lint-1.45.2-linux-ppc64le.deb -1463049b744871168095e3e8f687247d6040eeb895955b869889ea151e0603ab golangci-lint-1.45.2-linux-arm64.tar.gz -15720f9c4c6f9324af695f081dc189adc7751b255759e78d7b2df1d7e9192533 golangci-lint-1.45.2-linux-amd64.deb -166d922e4d3cfe3d47786c590154a9c8ea689dff0aa92b73d2f5fc74fc570c29 golangci-lint-1.45.2-linux-arm64.rpm -1a3754c69f7cc19ab89cbdcc2550da4cf9abb3120383c6b3bd440c1ec22da2e6 golangci-lint-1.45.2-freebsd-386.tar.gz -1dec0aa46d4f0d241863b573f70129bdf1de9c595cf51172a840a588a4cd9fc5 golangci-lint-1.45.2-windows-amd64.zip -3198453806517c1ad988229f5e758ef850e671203f46d6905509df5bdf4dc24b golangci-lint-1.45.2-freebsd-armv7.tar.gz -46a3cd1749d7b98adc2dc01510ddbe21abe42689c8a53fb0e81662713629f215 golangci-lint-1.45.2-linux-386.deb -4e28bfb593d464b9e160f2acd5b71993836a183270bf8299b78ad31f7a168c0d golangci-lint-1.45.2-linux-arm64.deb -5157a58c8f9ab85c33af2e46f0d7c57a3b1e8953b81d61130e292e09f545cfab golangci-lint-1.45.2-linux-mips64le.tar.gz -518cd027644129fbf8ec4f02bd6f9ad7278aae826f92b63c80d4d0819ddde49a golangci-lint-1.45.2-linux-armv6.rpm -595ad6c6dade4c064351bc309f411703e457f8ffbb7a1806b3d8ee713333427f golangci-lint-1.45.2-linux-amd64.tar.gz -6994d6c80f0730751090986184a3481b4be2e6b6e84416238a2b857910045a4f golangci-lint-1.45.2-windows-arm64.zip -6c81652fc340118811b487f713c441fc6f527800bf5fd11b8929d08124efa015 golangci-lint-1.45.2-linux-armv7.tar.gz -726cb045559b7518bafdd3459de70a0647c087eb1b4634627a4b2e95b1258580 golangci-lint-1.45.2-freebsd-amd64.tar.gz -77df3774cdfda49b956d4a0e676da9a9b883f496ee37293c530770fef6b1d24e golangci-lint-1.45.2-linux-mips64.deb -7a9840f279a7d5d405bb434e101c2290964b3729630ac2add29280b962b7b9a5 golangci-lint-1.45.2-windows-armv6.zip -7d4bf9a5d80ec467aaaf66e78dbdcab567bbc6ba8151334c714eee58766aae32 golangci-lint-1.45.2-windows-armv7.zip -7e5f8821d39bb11d273b0841b34355f56bd5a45a2d5179f0d09e614e0efc0482 golangci-lint-1.45.2-linux-s390x.rpm -828de1bde796b23d8656b17a8885fbd879ef612795d62d1e4618126b419728b5 golangci-lint-1.45.2-linux-mips64.rpm -879a52107a797678a03c175cc7cf441411a14a01f66dc87f70bdfa304a4129a6 golangci-lint-1.45.2-windows-386.zip -87b6c7e3a3769f7d9abeb3bb82119b3c91e3c975300f6834fdeef8b2e37c98ff golangci-lint-1.45.2-linux-amd64.rpm -8b605c6d686c8af53ecc4ef39544541eeb1644d34cc10f9ffc5087808210c4ff golangci-lint-1.45.2-linux-s390x.deb -9427dbf51d0ac6f73a0f992838bd40c817470cc5bf6c8e2e2bea6fac46d7af6e golangci-lint-1.45.2-linux-ppc64le.tar.gz -995e509e895ca6a64ffc7395ac884d5961bdec98423cb896b17f345a9b4a19cf golangci-lint-1.45.2-darwin-amd64.tar.gz -a3f36278f2ea5516341e9071a2df6e65df272be80230b5406a12b72c6d425bee golangci-lint-1.45.2-linux-armv7.rpm -a5e12c50c23e87ac1deffc872f92ae85427b1198604969399805ae47cfe43f08 golangci-lint-1.45.2-linux-riscv64.tar.gz -aa8fa1be0729dbc2fbc4e01e82027097613eee74bd686ebef20f860b01fff8b3 golangci-lint-1.45.2-freebsd-armv6.tar.gz -c2b9669decc1b638cf2ee9060571af4e255f6dfcbb225c293e3a7ee4bb2c7217 golangci-lint-1.45.2-darwin-arm64.tar.gz -dfa8bdaf0387aec1cd5c1aa8857f67b2bbdfc2e42efce540c8fb9bbe3e8af302 golangci-lint-1.45.2-linux-armv6.tar.gz -eb8b8539dd017eee5c131ea9b875893ab2cebeeca41e8c6624907fb02224d643 golangci-lint-1.45.2-linux-386.rpm -ed6c7e17a857f30d715c5302fa250d95936936b277024bffea201187a257d7a7 golangci-lint-1.45.2-linux-armv6.deb -ef4d0154ace4001f01b288baeb118176242efb4fd163e178763e3213b77ef30b golangci-lint-1.45.2-linux-mips64le.deb -ef7002a2229f5ff5ba201a715fcf877664ea88decbe58e69d163293913024955 golangci-lint-1.45.2-linux-s390x.tar.gz -f13ecbd09228632e6bbe91a8324bd675c406eed22eb6d2c1e8192eed9ec4f914 golangci-lint-1.45.2-linux-386.tar.gz -f4cd9cfb09252f51699407277512263cae8409b665dd764f55a34738d0e89edc golangci-lint-1.45.2-linux-riscv64.rpm -fb1945dc59d37c9d14bf0a4aea11ea8651fa0e1d582ea80c4c44d0a536c08893 golangci-lint-1.45.2-linux-mips64.tar.gz -fe542c22738010f453c735a3c410decfd3784d1bd394b395c298ee298fc4c606 golangci-lint-1.45.2-linux-mips64le.rpm +658078aaaf7608693f37c4cf1380b2af418ab8b2d23fdb33e7e2d4339328590e golangci-lint-1.46.2-darwin-amd64.tar.gz +81f9b4afd62ec5e612ef8bc3b1d612a88b56ff289874831845cdad394427385f golangci-lint-1.46.2-darwin-arm64.tar.gz +943486e703e62ec55ecd90caeb22bcd39f8cc3962a93eec18c06b7bae12cb46f golangci-lint-1.46.2-freebsd-386.tar.gz +a75dd9ba7e08e8315c411697171db5375c0f6a1ece9e6fbeb9e9a4386822e17d golangci-lint-1.46.2-freebsd-amd64.tar.gz +83eedca1af72e8be055a1235177eb1b33524fbf08bec5730df2e6c3efade2b23 golangci-lint-1.46.2-freebsd-armv6.tar.gz +513d276c490de6f82baa01f9346d8d78b385f2ae97608f42f05d1f0f1314cd54 golangci-lint-1.46.2-freebsd-armv7.tar.gz +461a60016d516c69d406dc3e2d4957b722dbe684b7085dfac4802d0f84409e27 golangci-lint-1.46.2-linux-386.tar.gz +242cd4f2d6ac0556e315192e8555784d13da5d1874e51304711570769c4f2b9b golangci-lint-1.46.2-linux-amd64.tar.gz +ff5448ada2b3982581984d64b0dec614dba0a3ea4cab2d6a343c77927fc89f7e golangci-lint-1.46.2-linux-arm64.tar.gz +177f5210ef04aee282bfbc6ec519d36af5fb7d2b2c8d3f4ea5e59fdba71b0a27 golangci-lint-1.46.2-linux-armv6.tar.gz +10dd512a36ee978a1009edbca3ba3af410f0fda8df4d85f0e4793a24213870cc golangci-lint-1.46.2-linux-armv7.tar.gz +67779fa517c688c9db1090c3c456117d95c6b92979c623fe8cce8fb84251f21e golangci-lint-1.46.2-linux-mips64.tar.gz +c085f0f57bdccbb2c902a41b72ce210a3dfff16ca856789374745ab52004b6ee golangci-lint-1.46.2-linux-mips64le.tar.gz +abecef6421499248e58ed75d2938bc12b4b1f98b057f25060680b77bb51a881e golangci-lint-1.46.2-linux-ppc64le.tar.gz +134843a8f5c5c182c11979ea75f5866945d54757b2a04f3e5e04a0cf4fbf3a39 golangci-lint-1.46.2-linux-riscv64.tar.gz +9fe21a9476567aafe7a2e1a926b9641a39f920d4c0ea8eda9d968bc6136337f9 golangci-lint-1.46.2-linux-s390x.tar.gz +b48a421ec12a43f8fc8f977b9cf7d4a1ea1c4b97f803a238de7d3ce4ab23a84b golangci-lint-1.46.2-windows-386.zip +604acc1378a566abb0eac799362f3a37b7fcb5fa2268aeb2d5d954c829367301 golangci-lint-1.46.2-windows-amd64.zip +927def10db073da9687594072e6a3d9c891f67fa897105a2cfd715e018e7386c golangci-lint-1.46.2-windows-arm64.zip +729b76ed1d8b4e2612e38772b211503cb940e00a137bbaace1aa066f7c943737 golangci-lint-1.46.2-windows-armv6.zip +ea27c86d91e0b245ecbcfbf6cdb4ac0522d4bc6dca56bba02ea1bc77ad2917ac golangci-lint-1.46.2-windows-armv7.zip diff --git a/build/ci.go b/build/ci.go index 9de62edb2b4b..4b6f94c07d29 100644 --- a/build/ci.go +++ b/build/ci.go @@ -336,7 +336,7 @@ func doLint(cmdline []string) { // downloadLinter downloads and unpacks golangci-lint. func downloadLinter(cachedir string) string { - const version = "1.45.2" + const version = "1.46.2" csdb := build.MustLoadChecksums("build/checksums.txt") arch := runtime.GOARCH From 75ebeb7fe0afd0e32ec919a9b4b6167840f5afca Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 29 Jun 2022 23:19:30 +0200 Subject: [PATCH 065/715] build/deb: fix auto-completion install paths (#25204) --- .../deb/ethereum/completions/{bash_autocomplete => bash/geth} | 0 .../deb/ethereum/completions/{zsh_autocomplete => zsh/_geth} | 0 build/deb/ethereum/deb.install | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename build/deb/ethereum/completions/{bash_autocomplete => bash/geth} (100%) rename build/deb/ethereum/completions/{zsh_autocomplete => zsh/_geth} (100%) diff --git a/build/deb/ethereum/completions/bash_autocomplete b/build/deb/ethereum/completions/bash/geth similarity index 100% rename from build/deb/ethereum/completions/bash_autocomplete rename to build/deb/ethereum/completions/bash/geth diff --git a/build/deb/ethereum/completions/zsh_autocomplete b/build/deb/ethereum/completions/zsh/_geth similarity index 100% rename from build/deb/ethereum/completions/zsh_autocomplete rename to build/deb/ethereum/completions/zsh/_geth diff --git a/build/deb/ethereum/deb.install b/build/deb/ethereum/deb.install index 019bd0f4bb3f..5a624594b06c 100644 --- a/build/deb/ethereum/deb.install +++ b/build/deb/ethereum/deb.install @@ -1,5 +1,5 @@ build/bin/{{.BinaryName}} usr/bin {{- if eq .BinaryName "geth" }} -build/deb/ethereum/completions/bash_autocomplete etc/bash_completion.d/geth -build/deb/ethereum/completions/zsh_autocomplete usr/share/zsh/vendor-completions/_geth +build/deb/ethereum/completions/bash/geth etc/bash_completion.d +build/deb/ethereum/completions/zsh/_geth usr/share/zsh/vendor-completions {{end -}} From 8f2416a89a3def6ec2c749d5afafbf2c9a18e3c8 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 30 Jun 2022 00:27:43 +0200 Subject: [PATCH 066/715] params: go-ethereum v1.10.20 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index c013fd015c20..ea5d34fd27eb 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 20 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 10 // Minor version component of the current release + VersionPatch = 20 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 5e252282c0e5f9aeed43b3271ec98d4e63a24a88 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 30 Jun 2022 00:30:39 +0200 Subject: [PATCH 067/715] params: begin v1.10.21 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index ea5d34fd27eb..188b31d58b79 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 20 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 10 // Minor version component of the current release + VersionPatch = 21 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From a1cb7282b010a52e8c60e08debd9c4d9c64d5c35 Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Thu, 30 Jun 2022 13:24:04 +0900 Subject: [PATCH 068/715] common/prque: fix typo --- common/prque/lazyqueue.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/prque/lazyqueue.go b/common/prque/lazyqueue.go index 37c2f3bd42af..2fd2300d7371 100644 --- a/common/prque/lazyqueue.go +++ b/common/prque/lazyqueue.go @@ -163,7 +163,7 @@ func (q *LazyQueue) PopItem() interface{} { return i } -// Remove removes removes the item with the given index. +// Remove removes the item with the given index. func (q *LazyQueue) Remove(index int) interface{} { if index < 0 { return nil From de1cecb22e2a18ad70d4cb92bee122f4549c5b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 1 Jul 2022 14:38:26 +0300 Subject: [PATCH 069/715] eth/catalyst: disallow importing blocks via newPayload during snap sync (#25210) * eth/catalyst: disallow importing blocks via newPayload during snap sync * eth/catalyst: make tests pass by using full sync only * eth/catalysts: make the import delay a bit cleaner * eth/catalyst: fix typo Co-authored-by: Marius van der Wijden Co-authored-by: Marius van der Wijden --- eth/catalyst/api.go | 50 ++++++++++++++++++++++++++-------------- eth/catalyst/api_test.go | 2 +- eth/handler.go | 2 +- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index acc9c0e66ecb..cc1627f802fe 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" @@ -274,23 +275,7 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa // update after legit payload executions. parent := api.eth.BlockChain().GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { - // Stash the block away for a potential forced forckchoice update to it - // at a later time. - api.remoteBlocks.put(block.Hash(), block.Header()) - - // Although we don't want to trigger a sync, if there is one already in - // progress, try to extend if with the current payload request to relieve - // some strain from the forkchoice update. - if err := api.eth.Downloader().BeaconExtend(api.eth.SyncMode(), block.Header()); err == nil { - log.Debug("Payload accepted for sync extension", "number", params.Number, "hash", params.BlockHash) - return beacon.PayloadStatusV1{Status: beacon.SYNCING}, nil - } - // Either no beacon sync was started yet, or it rejected the delivered - // payload as non-integratable on top of the existing sync. We'll just - // have to rely on the beacon client to forcefully update the head with - // a forkchoice update request. - log.Warn("Ignoring payload with missing parent", "number", params.Number, "hash", params.BlockHash, "parent", params.ParentHash) - return beacon.PayloadStatusV1{Status: beacon.ACCEPTED}, nil + return api.delayPayloadImport(block) } // We have an existing parent, do some sanity checks to avoid the beacon client // triggering too early @@ -311,6 +296,13 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa log.Warn("Invalid timestamp", "parent", block.Time(), "block", block.Time()) return api.invalid(errors.New("invalid timestamp"), parent), nil } + // Another cornercase: if the node is in snap sync mode, but the CL client + // tries to make it import a block. That should be denied as pushing something + // into the database directly will conflict with the assumptions of snap sync + // that it has an empty db that it can fill itself. + if api.eth.SyncMode() != downloader.FullSync { + return api.delayPayloadImport(block) + } if !api.eth.BlockChain().HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { api.remoteBlocks.put(block.Hash(), block.Header()) log.Warn("State not available, ignoring new payload") @@ -345,6 +337,30 @@ func computePayloadId(headBlockHash common.Hash, params *beacon.PayloadAttribute return out } +// delayPayloadImport stashes the given block away for import at a later time, +// either via a forkchoice update or a sync extension. This method is meant to +// be called by the newpayload command when the block seems to be ok, but some +// prerequisite prevents it from being processed (e.g. no parent, or nap sync). +func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (beacon.PayloadStatusV1, error) { + // Stash the block away for a potential forced forkchoice update to it + // at a later time. + api.remoteBlocks.put(block.Hash(), block.Header()) + + // Although we don't want to trigger a sync, if there is one already in + // progress, try to extend if with the current payload request to relieve + // some strain from the forkchoice update. + if err := api.eth.Downloader().BeaconExtend(api.eth.SyncMode(), block.Header()); err == nil { + log.Debug("Payload accepted for sync extension", "number", block.NumberU64(), "hash", block.Hash()) + return beacon.PayloadStatusV1{Status: beacon.SYNCING}, nil + } + // Either no beacon sync was started yet, or it rejected the delivered + // payload as non-integratable on top of the existing sync. We'll just + // have to rely on the beacon client to forcefully update the head with + // a forkchoice update request. + log.Warn("Ignoring payload with missing parent", "number", block.NumberU64(), "hash", block.Hash(), "parent", block.ParentHash()) + return beacon.PayloadStatusV1{Status: beacon.ACCEPTED}, nil +} + // invalid returns a response "INVALID" with the latest valid hash supplied by latest or to the current head // if no latestValid block was provided. func (api *ConsensusAPI) invalid(err error, latestValid *types.Block) beacon.PayloadStatusV1 { diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 6171c14c432c..547b727f1c6a 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -403,7 +403,7 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) t.Fatal("can't create node:", err) } - ethcfg := ðconfig.Config{Genesis: genesis, Ethash: ethash.Config{PowMode: ethash.ModeFake}, SyncMode: downloader.SnapSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256} + ethcfg := ðconfig.Config{Genesis: genesis, Ethash: ethash.Config{PowMode: ethash.ModeFake}, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256} ethservice, err := eth.New(n, ethcfg) if err != nil { t.Fatal("can't create eth service:", err) diff --git a/eth/handler.go b/eth/handler.go index 43d03924defa..1418c73894c8 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -249,7 +249,7 @@ func newHandler(config *handlerConfig) (*handler, error) { // out a way yet where nodes can decide unilaterally whether the network is new // or not. This should be fixed if we figure out a solution. if atomic.LoadUint32(&h.snapSync) == 1 { - log.Warn("Fast syncing, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) + log.Warn("Snap syncing, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) return 0, nil } if h.merger.TDDReached() { From 953a29f5fd8a683ce5a54f18ef8e0a1bd6f607f0 Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Mon, 4 Jul 2022 03:21:00 -0400 Subject: [PATCH 070/715] Replace fmt.Errorf with errors.New in abi argument (#25181) Replace unnecessary fmt.Errorf with errors.New in accounts/abi/argument.go --- accounts/abi/argument.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index c5326d5700a6..ed204e0a81dd 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -18,6 +18,7 @@ package abi import ( "encoding/json" + "errors" "fmt" "reflect" "strings" @@ -79,7 +80,7 @@ func (arguments Arguments) isTuple() bool { func (arguments Arguments) Unpack(data []byte) ([]interface{}, error) { if len(data) == 0 { if len(arguments.NonIndexed()) != 0 { - return nil, fmt.Errorf("abi: attempting to unmarshall an empty string while arguments are expected") + return nil, errors.New("abi: attempting to unmarshall an empty string while arguments are expected") } return make([]interface{}, 0), nil } @@ -90,11 +91,11 @@ func (arguments Arguments) Unpack(data []byte) ([]interface{}, error) { func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte) error { // Make sure map is not nil if v == nil { - return fmt.Errorf("abi: cannot unpack into a nil map") + return errors.New("abi: cannot unpack into a nil map") } if len(data) == 0 { if len(arguments.NonIndexed()) != 0 { - return fmt.Errorf("abi: attempting to unmarshall an empty string while arguments are expected") + return errors.New("abi: attempting to unmarshall an empty string while arguments are expected") } return nil // Nothing to unmarshal, return } @@ -116,7 +117,7 @@ func (arguments Arguments) Copy(v interface{}, values []interface{}) error { } if len(values) == 0 { if len(arguments.NonIndexed()) != 0 { - return fmt.Errorf("abi: attempting to copy no values while arguments are expected") + return errors.New("abi: attempting to copy no values while arguments are expected") } return nil // Nothing to copy, return } From 2697e44d819377e39a781e5ab9f1814426b4b0f0 Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Mon, 4 Jul 2022 17:03:32 +0900 Subject: [PATCH 071/715] all: change format `0x%x` to `%#x` (#25221) --- accounts/scwallet/securechannel.go | 4 ++-- accounts/scwallet/wallet.go | 2 +- cmd/devp2p/internal/ethtest/snap.go | 4 ++-- cmd/evm/runner.go | 2 +- cmd/geth/dbcmd.go | 12 ++++++------ cmd/rlpdump/main.go | 2 +- cmd/rlpdump/rlpdump_test.go | 2 +- consensus/misc/forks.go | 2 +- core/asm/asm.go | 4 ++-- core/blockchain.go | 2 +- core/types/hashing_test.go | 2 +- core/vm/jump_table.go | 2 +- core/vm/opcodes.go | 2 +- core/vm/runtime/runtime_test.go | 4 ++-- eth/api.go | 2 +- eth/api_test.go | 2 +- eth/filters/api_test.go | 2 +- eth/tracers/logger/logger.go | 8 ++++---- internal/ethapi/api.go | 2 +- mobile/types.go | 4 ++-- signer/core/apitypes/types.go | 2 +- signer/core/signed_data.go | 4 ++-- tests/fuzzers/stacktrie/trie_fuzzer.go | 2 +- tests/fuzzers/trie/trie-fuzzer.go | 2 +- trie/trie_test.go | 2 +- 25 files changed, 39 insertions(+), 39 deletions(-) diff --git a/accounts/scwallet/securechannel.go b/accounts/scwallet/securechannel.go index 10887a8b43d0..b1b533eb7243 100644 --- a/accounts/scwallet/securechannel.go +++ b/accounts/scwallet/securechannel.go @@ -178,7 +178,7 @@ func (s *SecureChannelSession) mutuallyAuthenticate() error { return err } if response.Sw1 != 0x90 || response.Sw2 != 0x00 { - return fmt.Errorf("got unexpected response from MUTUALLY_AUTHENTICATE: 0x%x%x", response.Sw1, response.Sw2) + return fmt.Errorf("got unexpected response from MUTUALLY_AUTHENTICATE: %#x%x", response.Sw1, response.Sw2) } if len(response.Data) != scSecretLength { @@ -261,7 +261,7 @@ func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []b rapdu.deserialize(plainData) if rapdu.Sw1 != sw1Ok { - return nil, fmt.Errorf("unexpected response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", cla, ins, rapdu.Sw1, rapdu.Sw2) + return nil, fmt.Errorf("unexpected response status Cla=%#x, Ins=%#x, Sw=%#x%x", cla, ins, rapdu.Sw1, rapdu.Sw2) } return rapdu, nil diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index 2a2b83bd1b15..5082dec1cb33 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -167,7 +167,7 @@ func transmit(card *pcsc.Card, command *commandAPDU) (*responseAPDU, error) { } if response.Sw1 != sw1Ok { - return nil, fmt.Errorf("unexpected insecure response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", command.Cla, command.Ins, response.Sw1, response.Sw2) + return nil, fmt.Errorf("unexpected insecure response status Cla=%#x, Ins=%#x, Sw=%#x%x", command.Cla, command.Ins, response.Sw1, response.Sw2) } return response, nil diff --git a/cmd/devp2p/internal/ethtest/snap.go b/cmd/devp2p/internal/ethtest/snap.go index 9c3e88f9cb66..fa94c13ad237 100644 --- a/cmd/devp2p/internal/ethtest/snap.go +++ b/cmd/devp2p/internal/ethtest/snap.go @@ -496,10 +496,10 @@ func (s *Suite) snapGetAccountRange(t *utesting.T, tc *accRangeTest) error { } if len(hashes) > 0 { if exp, got := tc.expFirst, res.Accounts[0].Hash; exp != got { - return fmt.Errorf("expected first account 0x%x, got 0x%x", exp, got) + return fmt.Errorf("expected first account %#x, got %#x", exp, got) } if exp, got := tc.expLast, res.Accounts[len(res.Accounts)-1].Hash; exp != got { - return fmt.Errorf("expected last account 0x%x, got 0x%x", exp, got) + return fmt.Errorf("expected last account %#x, got %#x", exp, got) } } // Reconstruct a partial trie from the response and verify it diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 756d762b5348..05b9ccdebca7 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -309,7 +309,7 @@ allocated bytes: %d `, initialGas-leftOverGas, stats.time, stats.allocs, stats.bytesAllocated) } if tracer == nil { - fmt.Printf("0x%x\n", output) + fmt.Printf("%#x\n", output) if err != nil { fmt.Printf(" error: %v\n", err) } diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index be994def34d7..33e7efbef526 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -337,9 +337,9 @@ func checkStateContent(ctx *cli.Context) error { hasher.Read(got) if !bytes.Equal(k, got) { errs++ - fmt.Printf("Error at 0x%x\n", k) - fmt.Printf(" Hash: 0x%x\n", got) - fmt.Printf(" Data: 0x%x\n", v) + fmt.Printf("Error at %#x\n", k) + fmt.Printf(" Hash: %#x\n", got) + fmt.Printf(" Data: %#x\n", v) } if time.Since(lastLog) > 8*time.Second { log.Info("Iterating the database", "at", fmt.Sprintf("%#x", k), "elapsed", common.PrettyDuration(time.Since(startTime))) @@ -716,7 +716,7 @@ func showMetaData(ctx *cli.Context) error { if val == nil { return "" } - return fmt.Sprintf("%d (0x%x)", *val, *val) + return fmt.Sprintf("%d (%#x)", *val, *val) } data := [][]string{ {"databaseVersion", pp(rawdb.ReadDatabaseVersion(db))}, @@ -726,7 +726,7 @@ func showMetaData(ctx *cli.Context) error { if b := rawdb.ReadHeadBlock(db); b != nil { data = append(data, []string{"headBlock.Hash", fmt.Sprintf("%v", b.Hash())}) data = append(data, []string{"headBlock.Root", fmt.Sprintf("%v", b.Root())}) - data = append(data, []string{"headBlock.Number", fmt.Sprintf("%d (0x%x)", b.Number(), b.Number())}) + data = append(data, []string{"headBlock.Number", fmt.Sprintf("%d (%#x)", b.Number(), b.Number())}) } if b := rawdb.ReadSkeletonSyncStatus(db); b != nil { data = append(data, []string{"SkeletonSyncStatus", string(b)}) @@ -734,7 +734,7 @@ func showMetaData(ctx *cli.Context) error { if h := rawdb.ReadHeadHeader(db); h != nil { data = append(data, []string{"headHeader.Hash", fmt.Sprintf("%v", h.Hash())}) data = append(data, []string{"headHeader.Root", fmt.Sprintf("%v", h.Root)}) - data = append(data, []string{"headHeader.Number", fmt.Sprintf("%d (0x%x)", h.Number, h.Number)}) + data = append(data, []string{"headHeader.Number", fmt.Sprintf("%d (%#x)", h.Number, h.Number)}) } data = append(data, [][]string{{"frozen", fmt.Sprintf("%d items", ancients)}, {"lastPivotNumber", pp(rawdb.ReadLastPivotNumber(db))}, diff --git a/cmd/rlpdump/main.go b/cmd/rlpdump/main.go index 9c0af012480f..70337749aea3 100644 --- a/cmd/rlpdump/main.go +++ b/cmd/rlpdump/main.go @@ -83,7 +83,7 @@ func main() { if err != nil { die(err) } - fmt.Printf("0x%x\n", data) + fmt.Printf("%#x\n", data) return } else { err := rlpToText(r, out) diff --git a/cmd/rlpdump/rlpdump_test.go b/cmd/rlpdump/rlpdump_test.go index 899beef32f4a..a9ab57fdb880 100644 --- a/cmd/rlpdump/rlpdump_test.go +++ b/cmd/rlpdump/rlpdump_test.go @@ -43,7 +43,7 @@ func TestRoundtrip(t *testing.T) { t.Errorf("test %d: error %v", i, err) continue } - have := fmt.Sprintf("0x%x", rlpBytes) + have := fmt.Sprintf("%#x", rlpBytes) if have != want { t.Errorf("test %d: have\n%v\nwant:\n%v\n", i, have, want) } diff --git a/consensus/misc/forks.go b/consensus/misc/forks.go index 4a5e7c37e03c..a6f3303ea6fa 100644 --- a/consensus/misc/forks.go +++ b/consensus/misc/forks.go @@ -35,7 +35,7 @@ func VerifyForkHashes(config *params.ChainConfig, header *types.Header, uncle bo // If the homestead reprice hash is set, validate it if config.EIP150Block != nil && config.EIP150Block.Cmp(header.Number) == 0 { if config.EIP150Hash != (common.Hash{}) && config.EIP150Hash != header.Hash() { - return fmt.Errorf("homestead gas reprice fork: have 0x%x, want 0x%x", header.Hash(), config.EIP150Hash) + return fmt.Errorf("homestead gas reprice fork: have %#x, want %#x", header.Hash(), config.EIP150Hash) } } // All ok, return diff --git a/core/asm/asm.go b/core/asm/asm.go index f3f129714d31..7c1e14ec01ea 100644 --- a/core/asm/asm.go +++ b/core/asm/asm.go @@ -109,7 +109,7 @@ func PrintDisassembled(code string) error { it := NewInstructionIterator(script) for it.Next() { if it.Arg() != nil && 0 < len(it.Arg()) { - fmt.Printf("%05x: %v 0x%x\n", it.PC(), it.Op(), it.Arg()) + fmt.Printf("%05x: %v %#x\n", it.PC(), it.Op(), it.Arg()) } else { fmt.Printf("%05x: %v\n", it.PC(), it.Op()) } @@ -124,7 +124,7 @@ func Disassemble(script []byte) ([]string, error) { it := NewInstructionIterator(script) for it.Next() { if it.Arg() != nil && 0 < len(it.Arg()) { - instrs = append(instrs, fmt.Sprintf("%05x: %v 0x%x\n", it.PC(), it.Op(), it.Arg())) + instrs = append(instrs, fmt.Sprintf("%05x: %v %#x\n", it.PC(), it.Op(), it.Arg())) } else { instrs = append(instrs, fmt.Sprintf("%05x: %v\n", it.PC(), it.Op())) } diff --git a/core/blockchain.go b/core/blockchain.go index 3b677aca6ca6..0a5ba1da0b27 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2342,7 +2342,7 @@ func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, e Chain config: %v Number: %v -Hash: 0x%x +Hash: %#x %v Error: %v diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index 44726c9cbb9f..294a3977d03b 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -197,7 +197,7 @@ func printList(l types.DerivableList) { for i := 0; i < l.Len(); i++ { var buf bytes.Buffer l.EncodeIndex(i, &buf) - fmt.Printf("\"0x%x\",\n", buf.Bytes()) + fmt.Printf("\"%#x\",\n", buf.Bytes()) } fmt.Printf("},\n") } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index eef3b53d8c66..2524c9c99cc4 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -63,7 +63,7 @@ type JumpTable [256]*operation func validate(jt JumpTable) JumpTable { for i, op := range jt { if op == nil { - panic(fmt.Sprintf("op 0x%x is not set", i)) + panic(fmt.Sprintf("op %#x is not set", i)) } // The interpreter has an assumption that if the memorySize function is // set, then the dynamicGas function is also set. This is a somewhat diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 19252b01f256..77d619abb9c1 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -392,7 +392,7 @@ var opCodeToString = map[OpCode]string{ func (op OpCode) String() string { str := opCodeToString[op] if len(str) == 0 { - return fmt.Sprintf("opcode 0x%x not defined", int(op)) + return fmt.Sprintf("opcode %#x not defined", int(op)) } return str diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index ca4e64843695..627edae07786 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -503,7 +503,7 @@ func TestEip2929Cases(t *testing.T) { it := asm.NewInstructionIterator(code) for it.Next() { if it.Arg() != nil && 0 < len(it.Arg()) { - instrs = append(instrs, fmt.Sprintf("%v 0x%x", it.Op(), it.Arg())) + instrs = append(instrs, fmt.Sprintf("%v %#x", it.Op(), it.Arg())) } else { instrs = append(instrs, fmt.Sprintf("%v", it.Op())) } @@ -511,7 +511,7 @@ func TestEip2929Cases(t *testing.T) { ops := strings.Join(instrs, ", ") fmt.Printf("### Case %d\n\n", id) id++ - fmt.Printf("%v\n\nBytecode: \n```\n0x%x\n```\nOperations: \n```\n%v\n```\n\n", + fmt.Printf("%v\n\nBytecode: \n```\n%#x\n```\nOperations: \n```\n%v\n```\n\n", comment, code, ops) Execute(code, nil, &Config{ diff --git a/eth/api.go b/eth/api.go index b5053095a234..5d159108e6a9 100644 --- a/eth/api.go +++ b/eth/api.go @@ -316,7 +316,7 @@ func (api *DebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) if rlpBytes, err := rlp.EncodeToBytes(block); err != nil { blockRlp = err.Error() // Hacky, but hey, it works } else { - blockRlp = fmt.Sprintf("0x%x", rlpBytes) + blockRlp = fmt.Sprintf("%#x", rlpBytes) } if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig()); err != nil { blockJSON = map[string]interface{}{"error": err.Error()} diff --git a/eth/api_test.go b/eth/api_test.go index 39a1d5846004..aae04eaa907f 100644 --- a/eth/api_test.go +++ b/eth/api_test.go @@ -213,7 +213,7 @@ func TestStorageRangeAt(t *testing.T) { t.Error(err) } if !reflect.DeepEqual(result, test.want) { - t.Fatalf("wrong result for range 0x%x.., limit %d:\ngot %s\nwant %s", + t.Fatalf("wrong result for range %#x.., limit %d:\ngot %s\nwant %s", test.start, test.limit, dumper.Sdump(result), dumper.Sdump(&test.want)) } } diff --git a/eth/filters/api_test.go b/eth/filters/api_test.go index 02229a7549a7..0a80d0f8ddbd 100644 --- a/eth/filters/api_test.go +++ b/eth/filters/api_test.go @@ -56,7 +56,7 @@ func TestUnmarshalJSONNewFilterArgs(t *testing.T) { // from, to block number var test1 FilterCriteria - vector := fmt.Sprintf(`{"fromBlock":"0x%x","toBlock":"0x%x"}`, fromBlock, toBlock) + vector := fmt.Sprintf(`{"fromBlock":"%#x","toBlock":"%#x"}`, fromBlock, toBlock) if err := json.Unmarshal([]byte(vector), &test1); err != nil { t.Fatal(err) } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index fe850d6b3e61..bd326daaf666 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -224,7 +224,7 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration l.output = output l.err = err if l.cfg.Debug { - fmt.Printf("0x%x\n", output) + fmt.Printf("%#x\n", output) if err != nil { fmt.Printf(" error: %v\n", err) } @@ -346,11 +346,11 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { func (t *mdLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { t.env = env if !create { - fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n", + fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n", from.String(), to.String(), input, gas, value) } else { - fmt.Fprintf(t.out, "From: `%v`\nCreate at: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n", + fmt.Fprintf(t.out, "From: `%v`\nCreate at: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n", from.String(), to.String(), input, gas, value) } @@ -387,7 +387,7 @@ func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope } func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, tm time.Duration, err error) { - fmt.Fprintf(t.out, "\nOutput: `0x%x`\nConsumed gas: `%d`\nError: `%v`\n", + fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n", output, gasUsed, err) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b45c1f123f58..1c76825326ae 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1950,7 +1950,7 @@ func (api *DebugAPI) SeedHash(ctx context.Context, number uint64) (string, error if block == nil { return "", fmt.Errorf("block #%d not found", number) } - return fmt.Sprintf("0x%x", ethash.SeedHash(number)), nil + return fmt.Sprintf("%#x", ethash.SeedHash(number)), nil } // ChaindbProperty returns leveldb properties of the key-value database. diff --git a/mobile/types.go b/mobile/types.go index a224f12ab23a..f3f92e4d4ac3 100644 --- a/mobile/types.go +++ b/mobile/types.go @@ -55,7 +55,7 @@ func (n *Nonce) GetBytes() []byte { // GetHex retrieves the hex string representation of the block nonce. func (n *Nonce) GetHex() string { - return fmt.Sprintf("0x%x", n.nonce[:]) + return fmt.Sprintf("%#x", n.nonce[:]) } // String returns a printable representation of the nonce. @@ -75,7 +75,7 @@ func (b *Bloom) GetBytes() []byte { // GetHex retrieves the hex string representation of the bloom filter. func (b *Bloom) GetHex() string { - return fmt.Sprintf("0x%x", b.bloom[:]) + return fmt.Sprintf("%#x", b.bloom[:]) } // String returns a printable representation of the bloom filter. diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index f5c2fe2f3db9..7a5c7b8937d3 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -659,7 +659,7 @@ func formatPrimitiveValue(encType string, encValue interface{}) (string, error) if b, err := parseInteger(encType, encValue); err != nil { return "", err } else { - return fmt.Sprintf("%d (0x%x)", b, b), nil + return fmt.Sprintf("%d (%#x)", b, b), nil } } return "", fmt.Errorf("unhandled type %v", encType) diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go index 48559bd98cf7..1b4e91cb6da7 100644 --- a/signer/core/signed_data.go +++ b/signer/core/signed_data.go @@ -129,7 +129,7 @@ func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType { Name: "Full message for signing", Typ: "hexdata", - Value: fmt.Sprintf("0x%x", msg), + Value: fmt.Sprintf("%#x", msg), }, } req = &SignDataRequest{ContentType: mediaType, Rawdata: []byte(msg), Messages: messages, Hash: sighash} @@ -161,7 +161,7 @@ func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType { Name: "Clique header", Typ: "clique", - Value: fmt.Sprintf("clique header %d [0x%x]", header.Number, header.Hash()), + Value: fmt.Sprintf("clique header %d [%#x]", header.Number, header.Hash()), }, } // Clique uses V on the form 0 or 1 diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 772c776436f7..363b0d47c46b 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -185,7 +185,7 @@ func (f *fuzzer) fuzz() int { sort.Sort(vals) for _, kv := range vals { if f.debugging { - fmt.Printf("{\"0x%x\" , \"0x%x\"} // stacktrie.Update\n", kv.k, kv.v) + fmt.Printf("{\"%#x\" , \"%#x\"} // stacktrie.Update\n", kv.k, kv.v) } trieB.Update(kv.k, kv.v) } diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index 2301721c9311..e8ad9fcf25ce 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -159,7 +159,7 @@ func runRandTest(rt randTest) error { v := tr.Get(step.key) want := values[string(step.key)] if string(v) != want { - rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want) + rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) } case opCommit: _, _, rt[i].err = tr.Commit(nil) diff --git a/trie/trie_test.go b/trie/trie_test.go index ab65965b4972..371bdf01c02d 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -432,7 +432,7 @@ func runRandTest(rt randTest) bool { v := tr.Get(step.key) want := values[string(step.key)] if string(v) != want { - rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want) + rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) } case opCommit: _, _, rt[i].err = tr.Commit(nil) From 62470eeaf8c6d4b360cb228b25941cef2a98e1cf Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 4 Jul 2022 10:54:15 +0200 Subject: [PATCH 072/715] consensus/beacon: copy td value so we can modify it (#25230) * consensus/beacon: copy td value so we can modify it * consensus/beacon: copy td value so we can modify it --- consensus/beacon/consensus.go | 1 + 1 file changed, 1 insertion(+) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index e090a03990f6..2b4f6ee0d662 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -178,6 +178,7 @@ func verifyTerminalPoWBlock(chain consensus.ChainHeaderReader, preHeaders []*typ if td == nil { return 0, consensus.ErrUnknownAncestor } + td = new(big.Int).Set(td) // Check that all blocks before the last one are below the TTD for i, head := range preHeaders { if td.Cmp(chain.Config().TerminalTotalDifficulty) >= 0 { From e5371934216e90204ef03d81b2f135625bb37dc4 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 4 Jul 2022 11:24:06 +0200 Subject: [PATCH 073/715] core: allow external code to set the block validator for malicious tests (#25119) * core: don't validate state * core: allow external validator * core: revert * core: comments * Update blockchain_reader.go * core: move SetValidator to blockchain.go * core: rename method --- core/blockchain.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/blockchain.go b/core/blockchain.go index 0a5ba1da0b27..352871390712 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2374,3 +2374,10 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (i _, err := bc.hc.InsertHeaderChain(chain, start, bc.forker) return 0, err } + +// SetBlockValidatorForTesting sets the current validator. +// This method can be used to force an invalid blockchain to be verified for tests. +// This method is unsafe and should only be used before block import starts. +func (bc *BlockChain) SetBlockValidatorForTesting(v Validator) { + bc.validator = v +} From 5f6e870ee69977a2c071b76ee6ef2a0b5746331a Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 4 Jul 2022 11:25:17 +0200 Subject: [PATCH 074/715] core: apply ttd override to uninitialized db (#25136) * core: apply ttd override to genesis block * core: apply overrides properly --- core/genesis.go | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index aa7d704ea2c7..7dcc7cfc3fab 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -237,6 +237,18 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override if genesis != nil && genesis.Config == nil { return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig } + + applyOverrides := func(config *params.ChainConfig) { + if config != nil { + if overrideTerminalTotalDifficulty != nil { + config.TerminalTotalDifficulty = overrideTerminalTotalDifficulty + } + if overrideGrayGlacier != nil { + config.GrayGlacierBlock = overrideGrayGlacier + } + } + } + // Just commit the new block if there is no stored genesis block. stored := rawdb.ReadCanonicalHash(db, 0) if (stored == common.Hash{}) { @@ -250,6 +262,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override if err != nil { return genesis.Config, common.Hash{}, err } + applyOverrides(genesis.Config) return genesis.Config, block.Hash(), nil } // We have the genesis block in database(perhaps in ancient database) @@ -268,6 +281,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override if err != nil { return genesis.Config, hash, err } + applyOverrides(genesis.Config) return genesis.Config, block.Hash(), nil } // Check whether the genesis block is already written. @@ -279,12 +293,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override } // Get the existing chain configuration. newcfg := genesis.configOrDefault(stored) - if overrideGrayGlacier != nil { - newcfg.GrayGlacierBlock = overrideGrayGlacier - } - if overrideTerminalTotalDifficulty != nil { - newcfg.TerminalTotalDifficulty = overrideTerminalTotalDifficulty - } + applyOverrides(newcfg) if err := newcfg.CheckConfigForkOrder(); err != nil { return newcfg, common.Hash{}, err } @@ -301,12 +310,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override // apply the overrides. if genesis == nil && stored != params.MainnetGenesisHash { newcfg = storedcfg - if overrideGrayGlacier != nil { - newcfg.GrayGlacierBlock = overrideGrayGlacier - } - if overrideTerminalTotalDifficulty != nil { - newcfg.TerminalTotalDifficulty = overrideTerminalTotalDifficulty - } + applyOverrides(newcfg) } // Check config compatibility and write the config. Compatibility errors // are returned to the caller unless we're already at block zero. From 55f914a1d764dac4bd37a48173092b1f5c3b186d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=B9=E3=83=91=E3=82=A4=E3=82=AF?= <1311798+spkjp@users.noreply.github.com> Date: Mon, 4 Jul 2022 22:01:07 +0900 Subject: [PATCH 075/715] signer/core/apitypes: support primitive types int96/uint96 (#25105) I have a EIP712 typehash using uint96, but it's currently not supported by go-ethereum. This change fixes it. --- signer/core/apitypes/types.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 7a5c7b8937d3..49819fee3371 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -784,6 +784,8 @@ func isPrimitiveTypeValid(primitiveType string) bool { primitiveType == "int32[]" || primitiveType == "int64" || primitiveType == "int64[]" || + primitiveType == "int96" || + primitiveType == "int96[]" || primitiveType == "int128" || primitiveType == "int128[]" || primitiveType == "int256" || @@ -800,6 +802,8 @@ func isPrimitiveTypeValid(primitiveType string) bool { primitiveType == "uint32[]" || primitiveType == "uint64" || primitiveType == "uint64[]" || + primitiveType == "uint96" || + primitiveType == "uint96[]" || primitiveType == "uint128" || primitiveType == "uint128[]" || primitiveType == "uint256" || From f6ac80c5071f37f12677b5f79e3394724c82a369 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 4 Jul 2022 19:52:19 +0200 Subject: [PATCH 076/715] cmd/geth, cmd/devp2p: fix some cli parsing issues (#25234) * cmd/geth: add some missing argument count checks * internal/flags: skip cmds with no action func in MigrateGlobalFlags * internal/flags: add Merge * cmd/devp2p: re-add listener config flags in discv4 commands --- cmd/devp2p/discv4cmd.go | 16 +++++++++++++--- cmd/geth/chaincmd.go | 6 ++++-- cmd/geth/consolecmd.go | 4 ++++ internal/flags/helpers.go | 13 +++++++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/cmd/devp2p/discv4cmd.go b/cmd/devp2p/discv4cmd.go index 892a02b6591e..9d35880b128b 100644 --- a/cmd/devp2p/discv4cmd.go +++ b/cmd/devp2p/discv4cmd.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/devp2p/internal/v4test" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" @@ -49,32 +50,34 @@ var ( Usage: "Sends ping to a node", Action: discv4Ping, ArgsUsage: "", + Flags: v4NodeFlags, } discv4RequestRecordCommand = &cli.Command{ Name: "requestenr", Usage: "Requests a node record using EIP-868 enrRequest", Action: discv4RequestRecord, ArgsUsage: "", + Flags: v4NodeFlags, } discv4ResolveCommand = &cli.Command{ Name: "resolve", Usage: "Finds a node in the DHT", Action: discv4Resolve, ArgsUsage: "", - Flags: []cli.Flag{bootnodesFlag}, + Flags: v4NodeFlags, } discv4ResolveJSONCommand = &cli.Command{ Name: "resolve-json", Usage: "Re-resolves nodes in a nodes.json file", Action: discv4ResolveJSON, - Flags: []cli.Flag{bootnodesFlag}, + Flags: v4NodeFlags, ArgsUsage: "", } discv4CrawlCommand = &cli.Command{ Name: "crawl", Usage: "Updates a nodes.json file with random nodes found in the DHT", Action: discv4Crawl, - Flags: []cli.Flag{bootnodesFlag, crawlTimeoutFlag}, + Flags: flags.Merge(v4NodeFlags, []cli.Flag{crawlTimeoutFlag}), } discv4TestCommand = &cli.Command{ Name: "test", @@ -119,6 +122,13 @@ var ( } ) +var v4NodeFlags = []cli.Flag{ + bootnodesFlag, + nodekeyFlag, + nodedbFlag, + listenAddrFlag, +} + func discv4Ping(ctx *cli.Context) error { n := getNodeArg(ctx) disc := startV4(ctx) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 6914e1aa2da9..13ecde5bd665 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -166,10 +166,12 @@ This command dumps out the state for a given block (or latest, if none provided) // initGenesis will initialise the given JSON format genesis file and writes it as // the zero'd block (i.e. genesis) or will fail hard if it can't succeed. func initGenesis(ctx *cli.Context) error { - // Make sure we have a valid genesis JSON + if ctx.Args().Len() != 1 { + utils.Fatalf("need genesis.json file as the only argument") + } genesisPath := ctx.Args().First() if len(genesisPath) == 0 { - utils.Fatalf("Must supply path to genesis JSON file") + utils.Fatalf("invalid path to genesis file") } file, err := os.Open(genesisPath) if err != nil { diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index a62b6a6ad592..6f31e5f2898e 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -114,6 +114,10 @@ func localConsole(ctx *cli.Context) error { // remoteConsole will connect to a remote geth instance, attaching a JavaScript // console to it. func remoteConsole(ctx *cli.Context) error { + if ctx.Args().Len() > 1 { + utils.Fatalf("invalid command-line: too many arguments") + } + endpoint := ctx.Args().First() if endpoint == "" { cfg := defaultNodeConfig() diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index d0ad9c4cef4a..4bcdc816fe46 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -38,6 +38,15 @@ func NewApp(gitCommit, gitDate, usage string) *cli.App { return app } +// Merge merges the given flag slices. +func Merge(groups ...[]cli.Flag) []cli.Flag { + var ret []cli.Flag + for _, group := range groups { + ret = append(ret, group...) + } + return ret +} + var migrationApplied = map[*cli.Command]struct{}{} // MigrateGlobalFlags makes all global flag values available in the @@ -70,6 +79,10 @@ func MigrateGlobalFlags(ctx *cli.Context) { // This iterates over all commands and wraps their action function. iterate(ctx.App.Commands, func(cmd *cli.Command) { + if cmd.Action == nil { + return + } + action := cmd.Action cmd.Action = func(ctx *cli.Context) error { doMigrateFlags(ctx) From 87bb5db675057d35ef5cbad4e4a64f50a7f06e7e Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 5 Jul 2022 09:02:49 +0200 Subject: [PATCH 077/715] core: allow external processor (#25233) --- core/blockchain.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 352871390712..5a4ae9e10fe2 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2375,9 +2375,10 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (i return 0, err } -// SetBlockValidatorForTesting sets the current validator. +// SetBlockValidatorAndProcessorForTesting sets the current validator and processor. // This method can be used to force an invalid blockchain to be verified for tests. // This method is unsafe and should only be used before block import starts. -func (bc *BlockChain) SetBlockValidatorForTesting(v Validator) { +func (bc *BlockChain) SetBlockValidatorAndProcessorForTesting(v Validator, p Processor) { bc.validator = v + bc.processor = p } From 7217ef4c9cd27698f1b11891ccc91288f29e4f90 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 5 Jul 2022 09:05:10 +0200 Subject: [PATCH 078/715] consensus/beacon: verify timestamp is greater than parent timestamp (#25236) --- consensus/beacon/consensus.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 2b4f6ee0d662..ae4c05dad9e0 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -45,6 +45,7 @@ var ( errTooManyUncles = errors.New("too many uncles") errInvalidNonce = errors.New("invalid nonce") errInvalidUncleHash = errors.New("invalid uncle hash") + errInvalidTimestamp = errors.New("invalid timestamp") ) // Beacon is a consensus engine that combines the eth1 consensus and proof-of-stake @@ -213,7 +214,7 @@ func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Blo // - nonce is expected to be 0 // - unclehash is expected to be Hash(emptyHeader) // to be the desired constants -// (b) the timestamp is not verified anymore +// (b) we don't verify if a block is in the future anymore // (c) the extradata is limited to 32 bytes func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error { // Ensure that the header's extra-data section is of a reasonable size @@ -227,6 +228,10 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa if header.UncleHash != types.EmptyUncleHash { return errInvalidUncleHash } + // Verify the timestamp + if header.Time <= parent.Time { + return errInvalidTimestamp + } // Verify the block's difficulty to ensure it's the default constant if beaconDifficulty.Cmp(header.Difficulty) != 0 { return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, beaconDifficulty) From e3c1a7c671ec3e9ef33d72271be033a9c0b4f980 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 5 Jul 2022 14:45:44 +0200 Subject: [PATCH 079/715] go.mod: updated logfmt dependency (#25231) This fixes an issue in abigen tests with go 1.17. --- go.mod | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go.mod b/go.mod index e669cff88448..9753afeb78cb 100644 --- a/go.mod +++ b/go.mod @@ -82,9 +82,11 @@ require ( github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect + github.com/go-logfmt/logfmt v0.4.0 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect + github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect From cb7f35996d8f8dfd44172b72cbb08829a33db527 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 5 Jul 2022 14:48:34 +0200 Subject: [PATCH 080/715] internal/ethapi: add basefee to block overrides (#25219) --- internal/ethapi/api.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1c76825326ae..3e2929062203 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -889,6 +889,7 @@ type BlockOverrides struct { GasLimit *hexutil.Uint64 Coinbase *common.Address Random *common.Hash + BaseFee *hexutil.Big } // Apply overrides the given header fields into the given block context. @@ -914,6 +915,9 @@ func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) { if diff.Random != nil { blockCtx.Random = diff.Random } + if diff.BaseFee != nil { + blockCtx.BaseFee = diff.BaseFee.ToInt() + } } func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { From ed7a80f7fd0b945e96c1b13abeb717ce676af3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Wed, 6 Jul 2022 00:12:39 +0200 Subject: [PATCH 081/715] build: upgrade -dlgo version to Go 1.18.3 --- build/checksums.txt | 28 ++++++++++++++-------------- build/ci.go | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index f97e30770f82..6ec5c4ef50c4 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,19 +1,19 @@ # This file contains sha256 checksums of optional build dependencies. -efd43e0f1402e083b73a03d444b7b6576bb4c539ac46208b63a916b69aca4088 go1.18.1.src.tar.gz -3703e9a0db1000f18c0c7b524f3d378aac71219b4715a6a4c5683eb639f41a4d go1.18.1.darwin-amd64.tar.gz -6d5641a06edba8cd6d425fb0adad06bad80e2afe0fa91b4aa0e5aed1bc78f58e go1.18.1.darwin-arm64.tar.gz -b9a9063d4265d8ccc046c9b314194d6eadc47e56d0d637db81e98e68aad45035 go1.18.1.freebsd-386.tar.gz -2bc1c138d645e37dbbc63517dd1cf1bf33fc4cb95f442a6384df0418b5134e9f go1.18.1.freebsd-amd64.tar.gz -9a8df5dde9058f08ac01ecfaae42534610db398e487138788c01da26a0d41ff9 go1.18.1.linux-386.tar.gz -b3b815f47ababac13810fc6021eb73d65478e0b2db4b09d348eefad9581a2334 go1.18.1.linux-amd64.tar.gz -56a91851c97fb4697077abbca38860f735c32b38993ff79b088dac46e4735633 go1.18.1.linux-arm64.tar.gz -9edc01c8e7db64e9ceeffc8258359e027812886ceca3444e83c4eb96ddb068ee go1.18.1.linux-armv6l.tar.gz -33db623d1eecf362fe365107c12efc90eff0b9609e0b3345e258388019cb552a go1.18.1.linux-ppc64le.tar.gz -5d9301324148ed4dbfaa0800da43a843ffd65c834ee73fcf087255697c925f74 go1.18.1.linux-s390x.tar.gz -49ae65551acbfaa57b52fbefa0350b2072512ae3103b8cf1a919a02626dbc743 go1.18.1.windows-386.zip -c30bc3f1f7314a953fe208bd9cd5e24bd9403392a6c556ced3677f9f70f71fe1 go1.18.1.windows-amd64.zip -2c4a8265030eac37f906634f5c13c22c3d0ea725f2488e1bca005c6b981653d7 go1.18.1.windows-arm64.zip +0012386ddcbb5f3350e407c679923811dbd283fcdc421724931614a842ecbc2d go1.18.3.src.tar.gz +d9dcf8fc35da54c6f259be41954783a9f4984945a855d03a003a7fd6ea4c5ca1 go1.18.3.darwin-amd64.tar.gz +40ecd383c941cc9f0682e6a6f2a333539d58c7dea15c842434d03afafe2f7242 go1.18.3.darwin-arm64.tar.gz +dbf06c8b76f7e9bd2f2b8d47d8c748e9867c2bbbdb2e90240d54df3e5766ad18 go1.18.3.freebsd-386.tar.gz +b1c60641aa175aa92edf494e942e37db28086b9d534f072ad9609d081b614d39 go1.18.3.freebsd-amd64.tar.gz +72b73da021397a3a1ce182c19d2a890a5346bfe80885d9dd7d1ff04ce6597938 go1.18.3.linux-386.tar.gz +956f8507b302ab0bb747613695cdae10af99bbd39a90cae522b7c0302cc27245 go1.18.3.linux-amd64.tar.gz +beacbe1441bee4d7978b900136d1d6a71d150f0a9bb77e9d50c822065623a35a go1.18.3.linux-arm64.tar.gz +b8f0b5db24114388d5dcba7ca0698510ea05228b0402fcbeb0881f74ae9cb83b go1.18.3.linux-armv6l.tar.gz +5d42bd252e7af9f854df92e46bb2e88be7b2fb310cc937c0fe091afd8c4f2016 go1.18.3.linux-ppc64le.tar.gz +ebb4efddec5bbd22bdd9c87137cb3dd59e874b5dfcf93d00bef351c60d2c7401 go1.18.3.linux-s390x.tar.gz +6661798e9669c3f03498a2e018ed948d9f53a90c5ccbd05b4e4b36303facb33e go1.18.3.windows-386.zip +9c46023f3ad0300fcfd1e62f2b6c2dfd9667b1f2f5c7a720b14b792af831f071 go1.18.3.windows-amd64.zip +ea8fab36a03e5a62b747e2ab0977be2d0f3e2f04b41397b4abf57a8c24f0034c go1.18.3.windows-arm64.zip 658078aaaf7608693f37c4cf1380b2af418ab8b2d23fdb33e7e2d4339328590e golangci-lint-1.46.2-darwin-amd64.tar.gz 81f9b4afd62ec5e612ef8bc3b1d612a88b56ff289874831845cdad394427385f golangci-lint-1.46.2-darwin-arm64.tar.gz diff --git a/build/ci.go b/build/ci.go index 4b6f94c07d29..09aef549a00c 100644 --- a/build/ci.go +++ b/build/ci.go @@ -149,7 +149,7 @@ var ( // This is the version of go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.18.1" + dlgoVersion = "1.18.3" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) From 926b3e08ba926fa4c9b699dc496daa03be19ffa3 Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Wed, 6 Jul 2022 02:49:09 -0400 Subject: [PATCH 082/715] trie: fix typo in comment (#25241) paralallel -> parallel --- trie/hasher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trie/hasher.go b/trie/hasher.go index 2949a3ddeece..9e17d639fc95 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -30,7 +30,7 @@ type hasher struct { sha crypto.KeccakState tmp []byte encbuf rlp.EncoderBuffer - parallel bool // Whether to use paralallel threads when hashing + parallel bool // Whether to use parallel threads when hashing } // hasherPool holds pureHashers From e394d01f2a578765868355e98898bd17d3d076c1 Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Wed, 6 Jul 2022 22:16:05 +0900 Subject: [PATCH 083/715] core/types: fix typo in comment (#25249) --- core/types/hashing.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/types/hashing.go b/core/types/hashing.go index a115a8842ec3..3df75432a4b4 100644 --- a/core/types/hashing.go +++ b/core/types/hashing.go @@ -31,7 +31,7 @@ var hasherPool = sync.Pool{ New: func() interface{} { return sha3.NewLegacyKeccak256() }, } -// deriveBufferPool holds temporary encoder buffers for DeriveSha and TX encoding. +// encodeBufferPool holds temporary encoder buffers for DeriveSha and TX encoding. var encodeBufferPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } From ae8ce7202244621d6e80eb69fcc31683fa0d4cea Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 7 Jul 2022 14:50:28 -0500 Subject: [PATCH 084/715] internal/ethapi: fix chain ID check to return all non-zero IDs (#25244) --- internal/ethapi/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 3e2929062203..a3637969e81e 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1290,7 +1290,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber switch tx.Type() { case types.LegacyTxType: // if a legacy transaction has an EIP-155 chain id, include it explicitly - if id := tx.ChainId(); id.Sign() == 0 { + if id := tx.ChainId(); id.Sign() != 0 { result.ChainID = (*hexutil.Big)(id) } case types.AccessListTxType: From d83951543467bb6b8ec31c96c6f27775693a71b1 Mon Sep 17 00:00:00 2001 From: Brion <4777457+cifer76@users.noreply.github.com> Date: Sat, 9 Jul 2022 03:25:12 +0800 Subject: [PATCH 085/715] rpc: add graceful shutdown timeout for HTTP server (#25258) This change ensures the HTTP server will always terminate within at most 5s, even when all connections are busy and do not become idle. Co-authored-by: Felix Lange --- node/rpcstack.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/node/rpcstack.go b/node/rpcstack.go index 09692c0a0b19..455e29beaf65 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -27,6 +27,7 @@ import ( "strings" "sync" "sync/atomic" + "time" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" @@ -81,6 +82,10 @@ type httpServer struct { handlerNames map[string]string } +const ( + shutdownTimeout = 5 * time.Second +) + func newHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *httpServer { h := &httpServer{log: log, timeouts: timeouts, handlerNames: make(map[string]string)} @@ -261,7 +266,13 @@ func (h *httpServer) doStop() { h.wsHandler.Store((*rpcHandler)(nil)) wsHandler.server.Stop() } - h.server.Shutdown(context.Background()) + ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout) + defer cancel() + err := h.server.Shutdown(ctx) + if err == ctx.Err() { + h.log.Warn("HTTP server graceful shutdown timed out") + h.server.Close() + } h.listener.Close() h.log.Info("HTTP server stopped", "endpoint", h.listener.Addr()) From b3fc9574ecba5143ee1b61f172100c9228a04e18 Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Sun, 10 Jul 2022 17:15:54 +0900 Subject: [PATCH 086/715] p2p/discover: fix typos in comments (#25272) --- p2p/discover/ntp.go | 2 +- p2p/discover/table_util_test.go | 6 +++--- p2p/discover/v4_udp.go | 2 +- p2p/discover/v4_udp_test.go | 2 +- p2p/discover/v4wire/v4wire.go | 6 +++--- p2p/discover/v5_udp.go | 2 +- p2p/discover/v5wire/encoding.go | 8 ++++---- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/p2p/discover/ntp.go b/p2p/discover/ntp.go index 1bb52399fbc5..48ceffe95b8d 100644 --- a/p2p/discover/ntp.go +++ b/p2p/discover/ntp.go @@ -108,7 +108,7 @@ func sntpDrift(measurements int) (time.Duration, error) { // Calculate the drift based on an assumed answer time of RRT/2 drifts = append(drifts, sent.Sub(t)+elapsed/2) } - // Calculate average drif (drop two extremities to avoid outliers) + // Calculate average drift (drop two extremities to avoid outliers) sort.Sort(durationSlice(drifts)) drift := time.Duration(0) diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 47a2e7ac3caf..77e03ca9e7e4 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -134,8 +134,8 @@ func newPingRecorder() *pingRecorder { } } -// setRecord updates a node record. Future calls to ping and -// requestENR will return this record. +// updateRecord updates a node record. Future calls to ping and +// RequestENR will return this record. func (t *pingRecorder) updateRecord(n *enode.Node) { t.mu.Lock() defer t.mu.Unlock() @@ -162,7 +162,7 @@ func (t *pingRecorder) ping(n *enode.Node) (seq uint64, err error) { return seq, nil } -// requestENR simulates an ENR request. +// RequestENR simulates an ENR request. func (t *pingRecorder) RequestENR(n *enode.Node) (*enode.Node, error) { t.mu.Lock() defer t.mu.Unlock() diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index a3e1549075b3..95a6df8e1bd4 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -334,7 +334,7 @@ func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubke return nodes, err } -// RequestENR sends enrRequest to the given node and waits for a response. +// RequestENR sends ENRRequest to the given node and waits for a response. func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { addr := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} t.ensureBond(n.ID(), addr) diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 977fa85a06c6..e00bf2784cb0 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -490,7 +490,7 @@ func TestUDPv4_EIP868(t *testing.T) { t.Fatalf("invalid record: %v", err) } if !reflect.DeepEqual(n, wantNode) { - t.Fatalf("wrong node in enrResponse: %v", n) + t.Fatalf("wrong node in ENRResponse: %v", n) } }) } diff --git a/p2p/discover/v4wire/v4wire.go b/p2p/discover/v4wire/v4wire.go index d6bf3dc4600a..b07a6e341c31 100644 --- a/p2p/discover/v4wire/v4wire.go +++ b/p2p/discover/v4wire/v4wire.go @@ -86,16 +86,16 @@ type ( Rest []rlp.RawValue `rlp:"tail"` } - // enrRequest queries for the remote node's record. + // ENRRequest queries for the remote node's record. ENRRequest struct { Expiration uint64 // Ignore additional fields (for forward compatibility). Rest []rlp.RawValue `rlp:"tail"` } - // enrResponse is the reply to enrRequest. + // ENRResponse is the reply to ENRRequest. ENRResponse struct { - ReplyTok []byte // Hash of the enrRequest packet. + ReplyTok []byte // Hash of the ENRRequest packet. Record enr.Record // Ignore additional fields (for forward compatibility). Rest []rlp.RawValue `rlp:"tail"` diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 22fab7243501..69aaefa27897 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -347,7 +347,7 @@ func (t *UDPv5) ping(n *enode.Node) (uint64, error) { } } -// requestENR requests n's record. +// RequestENR requests n's record. func (t *UDPv5) RequestENR(n *enode.Node) (*enode.Node, error) { nodes, err := t.findnode(n, []uint{0}) if err != nil { diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index 8dc64de6dfd6..45f2f0883bad 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -300,7 +300,7 @@ func (c *Codec) encodeWhoareyou(toID enode.ID, packet *Whoareyou) (Header, error return head, nil } -// encodeHandshakeMessage encodes the handshake message packet header. +// encodeHandshakeHeader encodes the handshake message packet header. func (c *Codec) encodeHandshakeHeader(toID enode.ID, addr string, challenge *Whoareyou) (Header, *session, error) { // Ensure calling code sets challenge.node. if challenge.Node == nil { @@ -337,7 +337,7 @@ func (c *Codec) encodeHandshakeHeader(toID enode.ID, addr string, challenge *Who return head, session, err } -// encodeAuthHeader creates the auth header on a request packet following WHOAREYOU. +// makeHandshakeAuth creates the auth header on a request packet following WHOAREYOU. func (c *Codec) makeHandshakeAuth(toID enode.ID, addr string, challenge *Whoareyou) (*handshakeAuthData, *session, error) { auth := new(handshakeAuthData) auth.h.SrcID = c.localnode.ID() @@ -379,7 +379,7 @@ func (c *Codec) makeHandshakeAuth(toID enode.ID, addr string, challenge *Whoarey return auth, sec, err } -// encodeMessage encodes an encrypted message packet. +// encodeMessageHeader encodes an encrypted message packet. func (c *Codec) encodeMessageHeader(toID enode.ID, s *session) (Header, error) { head := c.makeHeader(toID, flagMessage, 0) @@ -632,7 +632,7 @@ func (h *StaticHeader) checkValid(packetLen int) error { return nil } -// headerMask returns a cipher for 'masking' / 'unmasking' packet headers. +// mask returns a cipher for 'masking' / 'unmasking' packet headers. func (h *Header) mask(destID enode.ID) cipher.Stream { block, err := aes.NewCipher(destID[:16]) if err != nil { From 44893be0d69578259ef411f81b648e0418457ce9 Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Tue, 12 Jul 2022 16:08:45 +0900 Subject: [PATCH 087/715] core, eth: pre-allocate map in storage copy (#25279) --- core/state/state_object.go | 2 +- eth/tracers/logger/logger.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 1ffb7eb40228..bc1ca1f40eaf 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -49,7 +49,7 @@ func (s Storage) String() (str string) { } func (s Storage) Copy() Storage { - cpy := make(Storage) + cpy := make(Storage, len(s)) for key, value := range s { cpy[key] = value } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index bd326daaf666..07aa2f2b4301 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -40,7 +40,7 @@ type Storage map[common.Hash]common.Hash // Copy duplicates the current storage. func (s Storage) Copy() Storage { - cpy := make(Storage) + cpy := make(Storage, len(s)) for key, value := range s { cpy[key] = value } From 3e759e28d7a032356450725bdb3273921ad41fb9 Mon Sep 17 00:00:00 2001 From: Philip Fan Date: Tue, 12 Jul 2022 16:10:12 +0800 Subject: [PATCH 088/715] eth/tracers: add initial revertReasonTracer tracer (#25265) Adds a native tracer that returns that in case of failure returns the error message or the revert reason of a transaction. Co-authored-by: Martin Holst Swende --- eth/tracers/native/revertreason.go | 108 +++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 eth/tracers/native/revertreason.go diff --git a/eth/tracers/native/revertreason.go b/eth/tracers/native/revertreason.go new file mode 100644 index 000000000000..b402396cb065 --- /dev/null +++ b/eth/tracers/native/revertreason.go @@ -0,0 +1,108 @@ +// Copyright 2022 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 native + +import ( + "bytes" + "encoding/json" + "math/big" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers" +) + +func init() { + register("revertReasonTracer", newRevertReasonTracer) +} + +var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4] + +// revertReasonTracer is a go implementation of the Tracer interface which +// track the error message or revert reason return by the contract. +type revertReasonTracer struct { + env *vm.EVM + revertReason string // The revert reason return from the tx, if tx success, empty string return + interrupt uint32 // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption +} + +// newRevertReasonTracer returns a new revert reason tracer. +func newRevertReasonTracer(_ *tracers.Context) tracers.Tracer { + return &revertReasonTracer{} +} + +// CaptureStart implements the EVMLogger interface to initialize the tracing operation. +func (t *revertReasonTracer) CaptureStart(env *vm.EVM, _ common.Address, _ common.Address, _ bool, _ []byte, _ uint64, _ *big.Int) { + t.env = env +} + +// CaptureEnd is called after the call finishes to finalize the tracing. +func (t *revertReasonTracer) CaptureEnd(output []byte, _ uint64, _ time.Duration, err error) { + if err != nil { + if err == vm.ErrExecutionReverted && len(output) > 4 && bytes.Equal(output[:4], revertSelector) { + errMsg, _ := abi.UnpackRevert(output) + t.revertReason = err.Error() + ": " + errMsg + } else { + t.revertReason = err.Error() + } + } +} + +// CaptureState implements the EVMLogger interface to trace a single step of VM execution. +func (t *revertReasonTracer) CaptureState(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ []byte, _ int, _ error) { +} + +// CaptureFault implements the EVMLogger interface to trace an execution fault. +func (t *revertReasonTracer) CaptureFault(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ int, _ error) { +} + +// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *revertReasonTracer) CaptureEnter(_ vm.OpCode, _ common.Address, _ common.Address, _ []byte, _ uint64, _ *big.Int) { + // Skip if tracing was interrupted + if atomic.LoadUint32(&t.interrupt) > 0 { + t.env.Cancel() + return + } +} + +// CaptureExit is called when EVM exits a scope, even if the scope didn't +// execute any code. +func (t *revertReasonTracer) CaptureExit(_ []byte, _ uint64, _ error) {} + +func (t *revertReasonTracer) CaptureTxStart(_ uint64) {} + +func (t *revertReasonTracer) CaptureTxEnd(_ uint64) {} + +// GetResult returns an error message json object. +func (t *revertReasonTracer) GetResult() (json.RawMessage, error) { + res, err := json.Marshal(t.revertReason) + if err != nil { + return nil, err + } + return res, t.reason +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (t *revertReasonTracer) Stop(err error) { + t.reason = err + atomic.StoreUint32(&t.interrupt, 1) +} From e66a538a36234eaa5062c08d6aa61e5b8409d9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 12 Jul 2022 14:06:23 +0300 Subject: [PATCH 089/715] params: enable DNS discovery on Sepolia too --- params/bootnodes.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/params/bootnodes.go b/params/bootnodes.go index 2ad230268bc6..b80997774536 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -116,6 +116,8 @@ func KnownDNSNetwork(genesis common.Hash, protocol string) string { net = "rinkeby" case GoerliGenesisHash: net = "goerli" + case SepoliaGenesisHash: + net = "sepolia" default: return "" } From 68cd0cda4a5b092a9cd6aee5887dbd2aea96a5e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 12 Jul 2022 14:35:35 +0300 Subject: [PATCH 090/715] internal/build: add a timestamp to the tar archive folder --- internal/build/archive.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/build/archive.go b/internal/build/archive.go index 8b3ac23d1d89..c16246070e8c 100644 --- a/internal/build/archive.go +++ b/internal/build/archive.go @@ -25,6 +25,7 @@ import ( "os" "path/filepath" "strings" + "time" ) type Archive interface { @@ -159,6 +160,7 @@ func (a *TarballArchive) Directory(name string) error { Name: a.dir, Mode: 0755, Typeflag: tar.TypeDir, + ModTime: time.Now(), }) } From 9f9657850fdcb69bbf5ccbbdc934e3fb56f5de79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Tue, 12 Jul 2022 23:19:41 +0200 Subject: [PATCH 091/715] build: upgrade -dlgo version to Go 1.18.4 --- build/checksums.txt | 28 ++++++++++++++-------------- build/ci.go | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 6ec5c4ef50c4..1a8f3cd76756 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,19 +1,19 @@ # This file contains sha256 checksums of optional build dependencies. -0012386ddcbb5f3350e407c679923811dbd283fcdc421724931614a842ecbc2d go1.18.3.src.tar.gz -d9dcf8fc35da54c6f259be41954783a9f4984945a855d03a003a7fd6ea4c5ca1 go1.18.3.darwin-amd64.tar.gz -40ecd383c941cc9f0682e6a6f2a333539d58c7dea15c842434d03afafe2f7242 go1.18.3.darwin-arm64.tar.gz -dbf06c8b76f7e9bd2f2b8d47d8c748e9867c2bbbdb2e90240d54df3e5766ad18 go1.18.3.freebsd-386.tar.gz -b1c60641aa175aa92edf494e942e37db28086b9d534f072ad9609d081b614d39 go1.18.3.freebsd-amd64.tar.gz -72b73da021397a3a1ce182c19d2a890a5346bfe80885d9dd7d1ff04ce6597938 go1.18.3.linux-386.tar.gz -956f8507b302ab0bb747613695cdae10af99bbd39a90cae522b7c0302cc27245 go1.18.3.linux-amd64.tar.gz -beacbe1441bee4d7978b900136d1d6a71d150f0a9bb77e9d50c822065623a35a go1.18.3.linux-arm64.tar.gz -b8f0b5db24114388d5dcba7ca0698510ea05228b0402fcbeb0881f74ae9cb83b go1.18.3.linux-armv6l.tar.gz -5d42bd252e7af9f854df92e46bb2e88be7b2fb310cc937c0fe091afd8c4f2016 go1.18.3.linux-ppc64le.tar.gz -ebb4efddec5bbd22bdd9c87137cb3dd59e874b5dfcf93d00bef351c60d2c7401 go1.18.3.linux-s390x.tar.gz -6661798e9669c3f03498a2e018ed948d9f53a90c5ccbd05b4e4b36303facb33e go1.18.3.windows-386.zip -9c46023f3ad0300fcfd1e62f2b6c2dfd9667b1f2f5c7a720b14b792af831f071 go1.18.3.windows-amd64.zip -ea8fab36a03e5a62b747e2ab0977be2d0f3e2f04b41397b4abf57a8c24f0034c go1.18.3.windows-arm64.zip +4525aa6b0e3cecb57845f4060a7075aafc9ab752bb7b6b4cf8a212d43078e1e4 go1.18.4.src.tar.gz +315e1a2b21a827c68da1b7f492b5dcbe81d8df8a79ebe50922df9588893f87f0 go1.18.4.darwin-amd64.tar.gz +04eed623d5143ffa44965b618b509e0beccccfd3a4a1bfebc0cdbcf906046769 go1.18.4.darwin-arm64.tar.gz +e5244fdcd6b6eaf785dbd8c6e02b4804a4d00409e7edecc63cd59fc8f37c34c5 go1.18.4.freebsd-386.tar.gz +fb00f8aaffcc80e0a2bd39db1d8e8e21ef0a691c564f7b7601383dd6adad4042 go1.18.4.freebsd-amd64.tar.gz +418232d905e18ece6cb13c4884bb1c68963d7d3b4d889671b3e5be8bd4059862 go1.18.4.linux-386.tar.gz +c9b099b68d93f5c5c8a8844a89f8db07eaa58270e3a1e01804f17f4cf8df02f5 go1.18.4.linux-amd64.tar.gz +35014d92b50d97da41dade965df7ebeb9a715da600206aa59ce1b2d05527421f go1.18.4.linux-arm64.tar.gz +7dfeab572e49638b0f3d9901457f0622c27b73301c2b99db9f5e9568ff40460c go1.18.4.linux-armv6l.tar.gz +f80acc4dc054ddc89ccc4869664e331bf16e0ac6e07830e94554162e66f66961 go1.18.4.linux-ppc64le.tar.gz +7e932f36e8f347feea2e706dcd32c1a464b1e5767ab2928ae460a37a975fe4a3 go1.18.4.linux-s390x.tar.gz +6343010a13ab783e553786b3cc3b4d63080128f61cf1e963505139c71ca66a0d go1.18.4.windows-386.zip +dfb93c517e050ba0cfc066802b38a8e7cda2ef666efd634859356b33f543cc49 go1.18.4.windows-amd64.zip +7d0d7b73592019d276f2bd44ee3cda0d8bd99356fdbf04fdb40c263518108ae4 go1.18.4.windows-arm64.zip 658078aaaf7608693f37c4cf1380b2af418ab8b2d23fdb33e7e2d4339328590e golangci-lint-1.46.2-darwin-amd64.tar.gz 81f9b4afd62ec5e612ef8bc3b1d612a88b56ff289874831845cdad394427385f golangci-lint-1.46.2-darwin-arm64.tar.gz diff --git a/build/ci.go b/build/ci.go index 09aef549a00c..edf97cdd09bc 100644 --- a/build/ci.go +++ b/build/ci.go @@ -149,7 +149,7 @@ var ( // This is the version of go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.18.3" + dlgoVersion = "1.18.4" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) From 93f981bb6105517c6fa3394270bd9cec5100b32e Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Thu, 14 Jul 2022 17:29:05 +0900 Subject: [PATCH 092/715] accounts/abi: fix typo in comment (#25271) --- accounts/abi/selector_parser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/abi/selector_parser.go b/accounts/abi/selector_parser.go index 88114e288eb3..d5472e374f5d 100644 --- a/accounts/abi/selector_parser.go +++ b/accounts/abi/selector_parser.go @@ -166,7 +166,7 @@ func ParseSelector(unescapedSelector string) (SelectorMarshaling, error) { return SelectorMarshaling{}, fmt.Errorf("failed to parse selector '%s': unexpected string '%s'", unescapedSelector, rest) } - // Reassemble the fake ABI and constuct the JSON + // Reassemble the fake ABI and construct the JSON fakeArgs, err := assembleArgs(args) if err != nil { return SelectorMarshaling{}, fmt.Errorf("failed to parse selector: %v", err) From 5b5dfba70a42f1cc09ec3f75b1f17edad8076e3d Mon Sep 17 00:00:00 2001 From: Jens W <8270201+DragonDev1906@users.noreply.github.com> Date: Thu, 14 Jul 2022 10:34:16 +0200 Subject: [PATCH 093/715] accounts/abi/bind/backends: return hash of new blocks (#25163) Co-authored-by: Jens --- accounts/abi/bind/backends/simulated.go | 6 ++- accounts/abi/bind/backends/simulated_test.go | 39 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index f5780c4a32c2..cd14afa14755 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -106,16 +106,20 @@ func (b *SimulatedBackend) Close() error { // Commit imports all the pending transactions as a single block and starts a // fresh new state. -func (b *SimulatedBackend) Commit() { +func (b *SimulatedBackend) Commit() common.Hash { b.mu.Lock() defer b.mu.Unlock() if _, err := b.blockchain.InsertChain([]*types.Block{b.pendingBlock}); err != nil { panic(err) // This cannot happen unless the simulator is wrong, fail in that case } + blockHash := b.pendingBlock.Hash() + // Using the last inserted block here makes it possible to build on a side // chain after a fork. b.rollback(b.pendingBlock) + + return blockHash } // Rollback aborts all pending transactions, reverting to the last committed state. diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index 2287055ebdfb..83367f098523 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -1335,3 +1335,42 @@ func TestForkResendTx(t *testing.T) { t.Errorf("TX included in wrong block: %d", h) } } + +func TestCommitReturnValue(t *testing.T) { + testAddr := crypto.PubkeyToAddress(testKey.PublicKey) + sim := simTestBackend(testAddr) + defer sim.Close() + + startBlockHeight := sim.blockchain.CurrentBlock().NumberU64() + + // Test if Commit returns the correct block hash + h1 := sim.Commit() + if h1 != sim.blockchain.CurrentBlock().Hash() { + t.Error("Commit did not return the hash of the last block.") + } + + // Create a block in the original chain (containing a transaction to force different block hashes) + head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough + gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1)) + _tx := types.NewTransaction(0, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil) + tx, _ := types.SignTx(_tx, types.HomesteadSigner{}, testKey) + sim.SendTransaction(context.Background(), tx) + h2 := sim.Commit() + + // Create another block in the original chain + sim.Commit() + + // Fork at the first bock + if err := sim.Fork(context.Background(), h1); err != nil { + t.Errorf("forking: %v", err) + } + + // Test if Commit returns the correct block hash after the reorg + h2fork := sim.Commit() + if h2 == h2fork { + t.Error("The block in the fork and the original block are the same block!") + } + if sim.blockchain.GetHeader(h2fork, startBlockHeight+2) == nil { + t.Error("Could not retrieve the just created block (side-chain)") + } +} From 434ca026c91116dd113cffe92bfae8a8d5c992ee Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 14 Jul 2022 04:17:25 -0600 Subject: [PATCH 094/715] internal/ethapi: error if tx args includes chain id that doesn't match local (#25157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * internal/ethapi: error if tx args includes chain id that doesn't match local * internal/ethapi: simplify code a bit Co-authored-by: Péter Szilágyi --- internal/ethapi/transaction_args.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 9c5950af58fe..cb2782ca052c 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -165,9 +165,15 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { args.Gas = &estimated log.Trace("Estimate gas usage automatically", "gas", args.Gas) } - if args.ChainID == nil { - id := (*hexutil.Big)(b.ChainConfig().ChainID) - args.ChainID = id + // If chain id is provided, ensure it matches the local chain id. Otherwise, set the local + // chain id as the default. + want := b.ChainConfig().ChainID + if args.ChainID != nil { + if have := (*big.Int)(args.ChainID); have.Cmp(want) != 0 { + return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, want) + } + } else { + args.ChainID = (*hexutil.Big)(want) } return nil } From 4766b1107fadcd5f31c96b0744a2a788c6e4a01c Mon Sep 17 00:00:00 2001 From: henridf Date: Thu, 14 Jul 2022 14:55:54 +0200 Subject: [PATCH 095/715] core: remove lock in BlockChain.ExportN (#25254) * Remove locking in (*BlockChain).ExportN Since ExportN is read-only, it shouldn't need the lock. (?) * Add hash check to detect reorgs during export. * fix check order * Update blockchain.go * Update blockchain.go Co-authored-by: rjl493456442 --- core/blockchain.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 5a4ae9e10fe2..fbeddecdbb29 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -739,22 +739,25 @@ func (bc *BlockChain) Export(w io.Writer) error { // ExportN writes a subset of the active chain to the given writer. func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { - if !bc.chainmu.TryLock() { - return errChainStopped - } - defer bc.chainmu.Unlock() - if first > last { return fmt.Errorf("export failed: first (%d) is greater than last (%d)", first, last) } log.Info("Exporting batch of blocks", "count", last-first+1) - start, reported := time.Now(), time.Now() + var ( + parentHash common.Hash + start = time.Now() + reported = time.Now() + ) for nr := first; nr <= last; nr++ { block := bc.GetBlockByNumber(nr) if block == nil { return fmt.Errorf("export failed on #%d: not found", nr) } + if nr > first && block.ParentHash() != parentHash { + return fmt.Errorf("export failed: chain reorg during export") + } + parentHash = block.Hash() if err := block.EncodeRLP(w); err != nil { return err } From 1c9afc56ae172b18a4d3d02e048f5e749b66efe6 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Fri, 15 Jul 2022 04:32:54 -0500 Subject: [PATCH 096/715] core: prevent negative fee during RPC calls (#25214) During RPC calls such as eth_call and eth_estimateGas, st.evm.Config.NoBaseFee is set which allows the gas price to be below the base fee. This results the tip being negative, and balance being subtracted from the coinbase instead of added to it, which results in a potentially negative coinbase balance interestingly. This can't happen during normal chain processing as outside of RPC calls the gas price is required to be at least the base fee, as NoBaseFee is false. This change prevents this behavior by disabling fee payment when the fee is not set. Co-authored-by: lightclient@protonmail.com Co-authored-by: Felix Lange --- core/state_transition.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/state_transition.go b/core/state_transition.go index 3b5f81b16632..0946c0372e2f 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -344,7 +344,16 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { if rules.IsLondon { effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)) } - st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)) + + if st.evm.Config.NoBaseFee && st.gasFeeCap.Sign() == 0 && st.gasTipCap.Sign() == 0 { + // Skip fee payment when NoBaseFee is set and the fee fields + // are 0. This avoids a negative effectiveTip being applied to + // the coinbase when simulating calls. + } else { + fee := new(big.Int).SetUint64(st.gasUsed()) + fee.Mul(fee, effectiveTip) + st.state.AddBalance(st.evm.Context.Coinbase, fee) + } return &ExecutionResult{ UsedGas: st.gasUsed(), From 1657e4393109596fd649b518ebcba75b97d0e1b6 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 15 Jul 2022 19:55:51 +0800 Subject: [PATCH 097/715] core, les, eth: port snap sync changes (#24898) core, eth, les, trie: rework snap sync --- core/state/statedb.go | 2 +- core/state/sync.go | 16 +- core/state/sync_test.go | 486 ++++++++++++++++++++++---------- eth/downloader/skeleton_test.go | 3 +- eth/protocols/snap/sort_test.go | 25 +- eth/protocols/snap/sync.go | 87 +++--- les/downloader/statesync.go | 71 +++-- trie/committer.go | 24 +- trie/sync.go | 301 ++++++++++++-------- trie/sync_test.go | 348 +++++++++++++++-------- trie/trie.go | 8 +- trie/trie_test.go | 2 +- 12 files changed, 864 insertions(+), 509 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index a36d65fce791..e945ab595013 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -940,7 +940,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { // The onleaf func is called _serially_, so we can reuse the same account // for unmarshalling every time. var account types.StateAccount - root, accountCommitted, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash) error { + root, accountCommitted, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash, _ []byte) error { if err := rlp.DecodeBytes(leaf, &account); err != nil { return nil } diff --git a/core/state/sync.go b/core/state/sync.go index cc7d01a2188d..00a4c67aa3cb 100644 --- a/core/state/sync.go +++ b/core/state/sync.go @@ -27,20 +27,20 @@ import ( ) // NewStateSync create a new state trie download scheduler. -func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(paths [][]byte, leaf []byte) error) *trie.Sync { +func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error) *trie.Sync { // Register the storage slot callback if the external callback is specified. - var onSlot func(paths [][]byte, hexpath []byte, leaf []byte, parent common.Hash) error + var onSlot func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error if onLeaf != nil { - onSlot = func(paths [][]byte, hexpath []byte, leaf []byte, parent common.Hash) error { - return onLeaf(paths, leaf) + onSlot = func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error { + return onLeaf(keys, leaf) } } // Register the account callback to connect the state trie and the storage // trie belongs to the contract. var syncer *trie.Sync - onAccount := func(paths [][]byte, hexpath []byte, leaf []byte, parent common.Hash) error { + onAccount := func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error { if onLeaf != nil { - if err := onLeaf(paths, leaf); err != nil { + if err := onLeaf(keys, leaf); err != nil { return err } } @@ -48,8 +48,8 @@ func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(p if err := rlp.Decode(bytes.NewReader(leaf), &obj); err != nil { return err } - syncer.AddSubTrie(obj.Root, hexpath, parent, onSlot) - syncer.AddCodeEntry(common.BytesToHash(obj.CodeHash), hexpath, parent) + syncer.AddSubTrie(obj.Root, path, parent, parentPath, onSlot) + syncer.AddCodeEntry(common.BytesToHash(obj.CodeHash), path, parent, parentPath) return nil } syncer = trie.NewSync(root, database, onAccount) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 83c5aa2df7a8..95c79eaf36ac 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -134,8 +134,8 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error { func TestEmptyStateSync(t *testing.T) { empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") sync := NewStateSync(empty, rawdb.NewMemoryDatabase(), nil) - if nodes, paths, codes := sync.Missing(1); len(nodes) != 0 || len(paths) != 0 || len(codes) != 0 { - t.Errorf(" content requested for empty state: %v, %v, %v", nodes, paths, codes) + if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { + t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes) } } @@ -160,6 +160,14 @@ func TestIterativeStateSyncBatchedByPath(t *testing.T) { testIterativeStateSync(t, 100, false, true) } +// stateElement represents the element in the state trie(bytecode or trie node). +type stateElement struct { + path string + hash common.Hash + code common.Hash + syncPath trie.SyncPath +} + func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { // Create a random state to copy srcDb, srcRoot, srcAccounts := makeTestState() @@ -172,54 +180,73 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { dstDb := rawdb.NewMemoryDatabase() sched := NewStateSync(srcRoot, dstDb, nil) - nodes, paths, codes := sched.Missing(count) var ( - hashQueue []common.Hash - pathQueue []trie.SyncPath + nodeElements []stateElement + codeElements []stateElement ) - if !bypath { - hashQueue = append(append(hashQueue[:0], nodes...), codes...) - } else { - hashQueue = append(hashQueue[:0], codes...) - pathQueue = append(pathQueue[:0], paths...) + paths, nodes, codes := sched.Missing(count) + for i := 0; i < len(paths); i++ { + nodeElements = append(nodeElements, stateElement{ + path: paths[i], + hash: nodes[i], + syncPath: trie.NewSyncPath([]byte(paths[i])), + }) } - for len(hashQueue)+len(pathQueue) > 0 { - results := make([]trie.SyncResult, len(hashQueue)+len(pathQueue)) - for i, hash := range hashQueue { - data, err := srcDb.TrieDB().Node(hash) - if err != nil { - data, err = srcDb.ContractCode(common.Hash{}, hash) - } + for i := 0; i < len(codes); i++ { + codeElements = append(codeElements, stateElement{ + code: codes[i], + }) + } + for len(nodeElements)+len(codeElements) > 0 { + var ( + nodeResults = make([]trie.NodeSyncResult, len(nodeElements)) + codeResults = make([]trie.CodeSyncResult, len(codeElements)) + ) + for i, element := range codeElements { + data, err := srcDb.ContractCode(common.Hash{}, element.code) if err != nil { - t.Fatalf("failed to retrieve node data for hash %x", hash) + t.Fatalf("failed to retrieve contract bytecode for hash %x", element.code) } - results[i] = trie.SyncResult{Hash: hash, Data: data} + codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data} } - for i, path := range pathQueue { - if len(path) == 1 { - data, _, err := srcTrie.TryGetNode(path[0]) - if err != nil { - t.Fatalf("failed to retrieve node data for path %x: %v", path, err) + for i, node := range nodeElements { + if bypath { + if len(node.syncPath) == 1 { + data, _, err := srcTrie.TryGetNode(node.syncPath[0]) + if err != nil { + t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[0], err) + } + nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} + } else { + var acc types.StateAccount + if err := rlp.DecodeBytes(srcTrie.Get(node.syncPath[0]), &acc); err != nil { + t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err) + } + stTrie, err := trie.New(common.BytesToHash(node.syncPath[0]), acc.Root, srcDb.TrieDB()) + if err != nil { + t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err) + } + data, _, err := stTrie.TryGetNode(node.syncPath[1]) + if err != nil { + t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[1], err) + } + nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} } - results[len(hashQueue)+i] = trie.SyncResult{Hash: crypto.Keccak256Hash(data), Data: data} } else { - var acc types.StateAccount - if err := rlp.DecodeBytes(srcTrie.Get(path[0]), &acc); err != nil { - t.Fatalf("failed to decode account on path %x: %v", path, err) - } - stTrie, err := trie.New(common.BytesToHash(path[0]), acc.Root, srcDb.TrieDB()) + data, err := srcDb.TrieDB().Node(node.hash) if err != nil { - t.Fatalf("failed to retriev storage trie for path %x: %v", path, err) + t.Fatalf("failed to retrieve node data for key %v", []byte(node.path)) } - data, _, err := stTrie.TryGetNode(path[1]) - if err != nil { - t.Fatalf("failed to retrieve node data for path %x: %v", path, err) - } - results[len(hashQueue)+i] = trie.SyncResult{Hash: crypto.Keccak256Hash(data), Data: data} + nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} } } - for _, result := range results { - if err := sched.Process(result); err != nil { + for _, result := range codeResults { + if err := sched.ProcessCode(result); err != nil { + t.Errorf("failed to process result %v", err) + } + } + for _, result := range nodeResults { + if err := sched.ProcessNode(result); err != nil { t.Errorf("failed to process result %v", err) } } @@ -229,12 +256,20 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { } batch.Write() - nodes, paths, codes = sched.Missing(count) - if !bypath { - hashQueue = append(append(hashQueue[:0], nodes...), codes...) - } else { - hashQueue = append(hashQueue[:0], codes...) - pathQueue = append(pathQueue[:0], paths...) + paths, nodes, codes = sched.Missing(count) + nodeElements = nodeElements[:0] + for i := 0; i < len(paths); i++ { + nodeElements = append(nodeElements, stateElement{ + path: paths[i], + hash: nodes[i], + syncPath: trie.NewSyncPath([]byte(paths[i])), + }) + } + codeElements = codeElements[:0] + for i := 0; i < len(codes); i++ { + codeElements = append(codeElements, stateElement{ + code: codes[i], + }) } } // Cross check that the two states are in sync @@ -251,26 +286,58 @@ func TestIterativeDelayedStateSync(t *testing.T) { dstDb := rawdb.NewMemoryDatabase() sched := NewStateSync(srcRoot, dstDb, nil) - nodes, _, codes := sched.Missing(0) - queue := append(append([]common.Hash{}, nodes...), codes...) - - for len(queue) > 0 { + var ( + nodeElements []stateElement + codeElements []stateElement + ) + paths, nodes, codes := sched.Missing(0) + for i := 0; i < len(paths); i++ { + nodeElements = append(nodeElements, stateElement{ + path: paths[i], + hash: nodes[i], + syncPath: trie.NewSyncPath([]byte(paths[i])), + }) + } + for i := 0; i < len(codes); i++ { + codeElements = append(codeElements, stateElement{ + code: codes[i], + }) + } + for len(nodeElements)+len(codeElements) > 0 { // Sync only half of the scheduled nodes - results := make([]trie.SyncResult, len(queue)/2+1) - for i, hash := range queue[:len(results)] { - data, err := srcDb.TrieDB().Node(hash) - if err != nil { - data, err = srcDb.ContractCode(common.Hash{}, hash) + var nodeProcessd int + var codeProcessd int + if len(codeElements) > 0 { + codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1) + for i, element := range codeElements[:len(codeResults)] { + data, err := srcDb.ContractCode(common.Hash{}, element.code) + if err != nil { + t.Fatalf("failed to retrieve contract bytecode for %x", element.code) + } + codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data} } - if err != nil { - t.Fatalf("failed to retrieve node data for %x", hash) + for _, result := range codeResults { + if err := sched.ProcessCode(result); err != nil { + t.Fatalf("failed to process result %v", err) + } } - results[i] = trie.SyncResult{Hash: hash, Data: data} + codeProcessd = len(codeResults) } - for _, result := range results { - if err := sched.Process(result); err != nil { - t.Fatalf("failed to process result %v", err) + if len(nodeElements) > 0 { + nodeResults := make([]trie.NodeSyncResult, len(nodeElements)/2+1) + for i, element := range nodeElements[:len(nodeResults)] { + data, err := srcDb.TrieDB().Node(element.hash) + if err != nil { + t.Fatalf("failed to retrieve contract bytecode for %x", element.code) + } + nodeResults[i] = trie.NodeSyncResult{Path: element.path, Data: data} + } + for _, result := range nodeResults { + if err := sched.ProcessNode(result); err != nil { + t.Fatalf("failed to process result %v", err) + } } + nodeProcessd = len(nodeResults) } batch := dstDb.NewBatch() if err := sched.Commit(batch); err != nil { @@ -278,8 +345,21 @@ func TestIterativeDelayedStateSync(t *testing.T) { } batch.Write() - nodes, _, codes = sched.Missing(0) - queue = append(append(queue[len(results):], nodes...), codes...) + paths, nodes, codes = sched.Missing(0) + nodeElements = nodeElements[nodeProcessd:] + for i := 0; i < len(paths); i++ { + nodeElements = append(nodeElements, stateElement{ + path: paths[i], + hash: nodes[i], + syncPath: trie.NewSyncPath([]byte(paths[i])), + }) + } + codeElements = codeElements[codeProcessd:] + for i := 0; i < len(codes); i++ { + codeElements = append(codeElements, stateElement{ + code: codes[i], + }) + } } // Cross check that the two states are in sync checkStateAccounts(t, dstDb, srcRoot, srcAccounts) @@ -299,40 +379,70 @@ func testIterativeRandomStateSync(t *testing.T, count int) { dstDb := rawdb.NewMemoryDatabase() sched := NewStateSync(srcRoot, dstDb, nil) - queue := make(map[common.Hash]struct{}) - nodes, _, codes := sched.Missing(count) - for _, hash := range append(nodes, codes...) { - queue[hash] = struct{}{} + nodeQueue := make(map[string]stateElement) + codeQueue := make(map[common.Hash]struct{}) + paths, nodes, codes := sched.Missing(count) + for i, path := range paths { + nodeQueue[path] = stateElement{ + path: path, + hash: nodes[i], + syncPath: trie.NewSyncPath([]byte(path)), + } } - for len(queue) > 0 { + for _, hash := range codes { + codeQueue[hash] = struct{}{} + } + for len(nodeQueue)+len(codeQueue) > 0 { // Fetch all the queued nodes in a random order - results := make([]trie.SyncResult, 0, len(queue)) - for hash := range queue { - data, err := srcDb.TrieDB().Node(hash) - if err != nil { - data, err = srcDb.ContractCode(common.Hash{}, hash) + if len(codeQueue) > 0 { + results := make([]trie.CodeSyncResult, 0, len(codeQueue)) + for hash := range codeQueue { + data, err := srcDb.ContractCode(common.Hash{}, hash) + if err != nil { + t.Fatalf("failed to retrieve node data for %x", hash) + } + results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) } - if err != nil { - t.Fatalf("failed to retrieve node data for %x", hash) + for _, result := range results { + if err := sched.ProcessCode(result); err != nil { + t.Fatalf("failed to process result %v", err) + } } - results = append(results, trie.SyncResult{Hash: hash, Data: data}) } - // Feed the retrieved results back and queue new tasks - for _, result := range results { - if err := sched.Process(result); err != nil { - t.Fatalf("failed to process result %v", err) + if len(nodeQueue) > 0 { + results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) + for path, element := range nodeQueue { + data, err := srcDb.TrieDB().Node(element.hash) + if err != nil { + t.Fatalf("failed to retrieve node data for %x %v %v", element.hash, []byte(element.path), element.path) + } + results = append(results, trie.NodeSyncResult{Path: path, Data: data}) + } + for _, result := range results { + if err := sched.ProcessNode(result); err != nil { + t.Fatalf("failed to process result %v", err) + } } } + // Feed the retrieved results back and queue new tasks batch := dstDb.NewBatch() if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) } batch.Write() - queue = make(map[common.Hash]struct{}) - nodes, _, codes = sched.Missing(count) - for _, hash := range append(nodes, codes...) { - queue[hash] = struct{}{} + nodeQueue = make(map[string]stateElement) + codeQueue = make(map[common.Hash]struct{}) + paths, nodes, codes := sched.Missing(count) + for i, path := range paths { + nodeQueue[path] = stateElement{ + path: path, + hash: nodes[i], + syncPath: trie.NewSyncPath([]byte(path)), + } + } + for _, hash := range codes { + codeQueue[hash] = struct{}{} } } // Cross check that the two states are in sync @@ -349,34 +459,62 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { dstDb := rawdb.NewMemoryDatabase() sched := NewStateSync(srcRoot, dstDb, nil) - queue := make(map[common.Hash]struct{}) - nodes, _, codes := sched.Missing(0) - for _, hash := range append(nodes, codes...) { - queue[hash] = struct{}{} + nodeQueue := make(map[string]stateElement) + codeQueue := make(map[common.Hash]struct{}) + paths, nodes, codes := sched.Missing(0) + for i, path := range paths { + nodeQueue[path] = stateElement{ + path: path, + hash: nodes[i], + syncPath: trie.NewSyncPath([]byte(path)), + } + } + for _, hash := range codes { + codeQueue[hash] = struct{}{} } - for len(queue) > 0 { + for len(nodeQueue)+len(codeQueue) > 0 { // Sync only half of the scheduled nodes, even those in random order - results := make([]trie.SyncResult, 0, len(queue)/2+1) - for hash := range queue { - delete(queue, hash) + if len(codeQueue) > 0 { + results := make([]trie.CodeSyncResult, 0, len(codeQueue)/2+1) + for hash := range codeQueue { + delete(codeQueue, hash) - data, err := srcDb.TrieDB().Node(hash) - if err != nil { - data, err = srcDb.ContractCode(common.Hash{}, hash) + data, err := srcDb.ContractCode(common.Hash{}, hash) + if err != nil { + t.Fatalf("failed to retrieve node data for %x", hash) + } + results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) + + if len(results) >= cap(results) { + break + } } - if err != nil { - t.Fatalf("failed to retrieve node data for %x", hash) + for _, result := range results { + if err := sched.ProcessCode(result); err != nil { + t.Fatalf("failed to process result %v", err) + } } - results = append(results, trie.SyncResult{Hash: hash, Data: data}) + } + if len(nodeQueue) > 0 { + results := make([]trie.NodeSyncResult, 0, len(nodeQueue)/2+1) + for path, element := range nodeQueue { + delete(nodeQueue, path) - if len(results) >= cap(results) { - break + data, err := srcDb.TrieDB().Node(element.hash) + if err != nil { + t.Fatalf("failed to retrieve node data for %x", element.hash) + } + results = append(results, trie.NodeSyncResult{Path: path, Data: data}) + + if len(results) >= cap(results) { + break + } } - } - // Feed the retrieved results back and queue new tasks - for _, result := range results { - if err := sched.Process(result); err != nil { - t.Fatalf("failed to process result %v", err) + // Feed the retrieved results back and queue new tasks + for _, result := range results { + if err := sched.ProcessNode(result); err != nil { + t.Fatalf("failed to process result %v", err) + } } } batch := dstDb.NewBatch() @@ -384,12 +522,17 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { t.Fatalf("failed to commit data: %v", err) } batch.Write() - for _, result := range results { - delete(queue, result.Hash) + + paths, nodes, codes := sched.Missing(0) + for i, path := range paths { + nodeQueue[path] = stateElement{ + path: path, + hash: nodes[i], + syncPath: trie.NewSyncPath([]byte(path)), + } } - nodes, _, codes = sched.Missing(0) - for _, hash := range append(nodes, codes...) { - queue[hash] = struct{}{} + for _, hash := range codes { + codeQueue[hash] = struct{}{} } } // Cross check that the two states are in sync @@ -416,28 +559,62 @@ func TestIncompleteStateSync(t *testing.T) { dstDb := rawdb.NewMemoryDatabase() sched := NewStateSync(srcRoot, dstDb, nil) - var added []common.Hash - - nodes, _, codes := sched.Missing(1) - queue := append(append([]common.Hash{}, nodes...), codes...) - - for len(queue) > 0 { + var ( + addedCodes []common.Hash + addedNodes []common.Hash + ) + nodeQueue := make(map[string]stateElement) + codeQueue := make(map[common.Hash]struct{}) + paths, nodes, codes := sched.Missing(1) + for i, path := range paths { + nodeQueue[path] = stateElement{ + path: path, + hash: nodes[i], + syncPath: trie.NewSyncPath([]byte(path)), + } + } + for _, hash := range codes { + codeQueue[hash] = struct{}{} + } + for len(nodeQueue)+len(codeQueue) > 0 { // Fetch a batch of state nodes - results := make([]trie.SyncResult, len(queue)) - for i, hash := range queue { - data, err := srcDb.TrieDB().Node(hash) - if err != nil { - data, err = srcDb.ContractCode(common.Hash{}, hash) + if len(codeQueue) > 0 { + results := make([]trie.CodeSyncResult, 0, len(codeQueue)) + for hash := range codeQueue { + data, err := srcDb.ContractCode(common.Hash{}, hash) + if err != nil { + t.Fatalf("failed to retrieve node data for %x", hash) + } + results = append(results, trie.CodeSyncResult{Hash: hash, Data: data}) + addedCodes = append(addedCodes, hash) } - if err != nil { - t.Fatalf("failed to retrieve node data for %x", hash) + // Process each of the state nodes + for _, result := range results { + if err := sched.ProcessCode(result); err != nil { + t.Fatalf("failed to process result %v", err) + } } - results[i] = trie.SyncResult{Hash: hash, Data: data} } - // Process each of the state nodes - for _, result := range results { - if err := sched.Process(result); err != nil { - t.Fatalf("failed to process result %v", err) + var nodehashes []common.Hash + if len(nodeQueue) > 0 { + results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) + for key, element := range nodeQueue { + data, err := srcDb.TrieDB().Node(element.hash) + if err != nil { + t.Fatalf("failed to retrieve node data for %x", element.hash) + } + results = append(results, trie.NodeSyncResult{Path: key, Data: data}) + + if element.hash != srcRoot { + addedNodes = append(addedNodes, element.hash) + } + nodehashes = append(nodehashes, element.hash) + } + // Process each of the state nodes + for _, result := range results { + if err := sched.ProcessNode(result); err != nil { + t.Fatalf("failed to process result %v", err) + } } } batch := dstDb.NewBatch() @@ -445,43 +622,44 @@ func TestIncompleteStateSync(t *testing.T) { t.Fatalf("failed to commit data: %v", err) } batch.Write() - for _, result := range results { - added = append(added, result.Hash) - // Check that all known sub-tries added so far are complete or missing entirely. - if _, ok := isCode[result.Hash]; ok { - continue - } + + for _, root := range nodehashes { // Can't use checkStateConsistency here because subtrie keys may have odd // length and crash in LeafKey. - if err := checkTrieConsistency(dstDb, result.Hash); err != nil { + if err := checkTrieConsistency(dstDb, root); err != nil { t.Fatalf("state inconsistent: %v", err) } } // Fetch the next batch to retrieve - nodes, _, codes = sched.Missing(1) - queue = append(append(queue[:0], nodes...), codes...) + nodeQueue = make(map[string]stateElement) + codeQueue = make(map[common.Hash]struct{}) + paths, nodes, codes := sched.Missing(1) + for i, path := range paths { + nodeQueue[path] = stateElement{ + path: path, + hash: nodes[i], + syncPath: trie.NewSyncPath([]byte(path)), + } + } + for _, hash := range codes { + codeQueue[hash] = struct{}{} + } } // Sanity check that removing any node from the database is detected - for _, node := range added[1:] { - var ( - key = node.Bytes() - _, code = isCode[node] - val []byte - ) - if code { - val = rawdb.ReadCode(dstDb, node) - rawdb.DeleteCode(dstDb, node) - } else { - val = rawdb.ReadTrieNode(dstDb, node) - rawdb.DeleteTrieNode(dstDb, node) + for _, node := range addedCodes { + val := rawdb.ReadCode(dstDb, node) + rawdb.DeleteCode(dstDb, node) + if err := checkStateConsistency(dstDb, srcRoot); err == nil { + t.Errorf("trie inconsistency not caught, missing: %x", node) } - if err := checkStateConsistency(dstDb, added[0]); err == nil { - t.Fatalf("trie inconsistency not caught, missing: %x", key) - } - if code { - rawdb.WriteCode(dstDb, node, val) - } else { - rawdb.WriteTrieNode(dstDb, node, val) + rawdb.WriteCode(dstDb, node, val) + } + for _, node := range addedNodes { + val := rawdb.ReadTrieNode(dstDb, node) + rawdb.DeleteTrieNode(dstDb, node) + if err := checkStateConsistency(dstDb, srcRoot); err == nil { + t.Errorf("trie inconsistency not caught, missing: %v", node.Hex()) } + rawdb.WriteTrieNode(dstDb, node, val) } } diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index 836efabebcb8..7d0b78dca65a 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -21,7 +21,6 @@ import ( "errors" "fmt" "math/big" - "os" "sync/atomic" "testing" "time" @@ -515,7 +514,7 @@ func TestSkeletonSyncExtend(t *testing.T) { // Tests that the skeleton sync correctly retrieves headers from one or more // peers without duplicates or other strange side effects. func TestSkeletonSyncRetrievals(t *testing.T) { - log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + //log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // Since skeleton headers don't need to be meaningful, beyond a parent hash // progression, create a long fake chain to test with. diff --git a/eth/protocols/snap/sort_test.go b/eth/protocols/snap/sort_test.go index 49730c886e7f..be0a8c570696 100644 --- a/eth/protocols/snap/sort_test.go +++ b/eth/protocols/snap/sort_test.go @@ -22,7 +22,6 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/trie" ) func hexToNibbles(s string) []byte { @@ -38,22 +37,17 @@ func hexToNibbles(s string) []byte { } func TestRequestSorting(t *testing.T) { - // - Path 0x9 -> {0x19} // - Path 0x99 -> {0x0099} // - Path 0x01234567890123456789012345678901012345678901234567890123456789019 -> {0x0123456789012345678901234567890101234567890123456789012345678901, 0x19} // - Path 0x012345678901234567890123456789010123456789012345678901234567890199 -> {0x0123456789012345678901234567890101234567890123456789012345678901, 0x0099} - var f = func(path string) (trie.SyncPath, TrieNodePathSet, common.Hash) { + var f = func(path string) string { data := hexToNibbles(path) - sp := trie.NewSyncPath(data) - tnps := TrieNodePathSet([][]byte(sp)) - hash := common.Hash{} - return sp, tnps, hash + return string(data) } var ( - hashes []common.Hash - paths []trie.SyncPath - pathsets []TrieNodePathSet + hashes []common.Hash + paths []string ) for _, x := range []string{ "0x9", @@ -67,15 +61,14 @@ func TestRequestSorting(t *testing.T) { "0x01234567890123456789012345678901012345678901234567890123456789010", "0x01234567890123456789012345678901012345678901234567890123456789011", } { - sp, _, hash := f(x) - hashes = append(hashes, hash) - paths = append(paths, sp) + paths = append(paths, f(x)) + hashes = append(hashes, common.Hash{}) } - _, paths, pathsets = sortByAccountPath(hashes, paths) + _, _, syncPaths, pathsets := sortByAccountPath(paths, hashes) { var b = new(bytes.Buffer) - for i := 0; i < len(paths); i++ { - fmt.Fprintf(b, "\n%d. paths %x", i, paths[i]) + for i := 0; i < len(syncPaths); i++ { + fmt.Fprintf(b, "\n%d. paths %x", i, syncPaths[i]) } want := ` 0. paths [0099] diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index d68e728ff211..b2462f5f892a 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -230,8 +230,8 @@ type trienodeHealRequest struct { timeout *time.Timer // Timer to track delivery timeout stale chan struct{} // Channel to signal the request was dropped - hashes []common.Hash // Trie node hashes to validate responses - paths []trie.SyncPath // Trie node paths requested for rescheduling + paths []string // Trie node paths for identifying trie node + hashes []common.Hash // Trie node hashes to validate responses task *healTask // Task which this request is filling (only access fields through the runloop!!) } @@ -240,9 +240,9 @@ type trienodeHealRequest struct { type trienodeHealResponse struct { task *healTask // Task which this request is filling - hashes []common.Hash // Hashes of the trie nodes to avoid double hashing - paths []trie.SyncPath // Trie node paths requested for rescheduling missing ones - nodes [][]byte // Actual trie nodes to store into the database (nil = missing) + paths []string // Paths of the trie nodes + hashes []common.Hash // Hashes of the trie nodes to avoid double hashing + nodes [][]byte // Actual trie nodes to store into the database (nil = missing) } // bytecodeHealRequest tracks a pending bytecode request to ensure responses are to @@ -321,8 +321,8 @@ type storageTask struct { type healTask struct { scheduler *trie.Sync // State trie sync scheduler defining the tasks - trieTasks map[common.Hash]trie.SyncPath // Set of trie node tasks currently queued for retrieval - codeTasks map[common.Hash]struct{} // Set of byte code tasks currently queued for retrieval + trieTasks map[string]common.Hash // Set of trie node tasks currently queued for retrieval, indexed by node path + codeTasks map[common.Hash]struct{} // Set of byte code tasks currently queued for retrieval, indexed by code hash } // SyncProgress is a database entry to allow suspending and resuming a snapshot state @@ -540,7 +540,7 @@ func (s *Syncer) Unregister(id string) error { return nil } -// Sync starts (or resumes a previous) sync cycle to iterate over an state trie +// Sync starts (or resumes a previous) sync cycle to iterate over a state trie // with the given root and reconstruct the nodes based on the snapshot leaves. // Previously downloaded segments will not be redownloaded of fixed, rather any // errors will be healed after the leaves are fully accumulated. @@ -551,7 +551,7 @@ func (s *Syncer) Sync(root common.Hash, cancel chan struct{}) error { s.root = root s.healer = &healTask{ scheduler: state.NewStateSync(root, s.db, s.onHealState), - trieTasks: make(map[common.Hash]trie.SyncPath), + trieTasks: make(map[string]common.Hash), codeTasks: make(map[common.Hash]struct{}), } s.statelessPeers = make(map[string]struct{}) @@ -743,7 +743,7 @@ func (s *Syncer) loadSyncStatus() { return } } - // Either we've failed to decode the previus state, or there was none. + // Either we've failed to decode the previous state, or there was none. // Start a fresh sync by chunking up the account range and scheduling // them for retrieval. s.tasks = nil @@ -1280,9 +1280,9 @@ func (s *Syncer) assignTrienodeHealTasks(success chan *trienodeHealResponse, fai want = maxTrieRequestCount + maxCodeRequestCount ) if have < want { - nodes, paths, codes := s.healer.scheduler.Missing(want - have) - for i, hash := range nodes { - s.healer.trieTasks[hash] = paths[i] + paths, hashes, codes := s.healer.scheduler.Missing(want - have) + for i, path := range paths { + s.healer.trieTasks[path] = hashes[i] } for _, hash := range codes { s.healer.codeTasks[hash] = struct{}{} @@ -1323,21 +1323,20 @@ func (s *Syncer) assignTrienodeHealTasks(success chan *trienodeHealResponse, fai } var ( hashes = make([]common.Hash, 0, cap) - paths = make([]trie.SyncPath, 0, cap) + paths = make([]string, 0, cap) pathsets = make([]TrieNodePathSet, 0, cap) ) - for hash, pathset := range s.healer.trieTasks { - delete(s.healer.trieTasks, hash) + for path, hash := range s.healer.trieTasks { + delete(s.healer.trieTasks, path) + paths = append(paths, path) hashes = append(hashes, hash) - paths = append(paths, pathset) - - if len(hashes) >= cap { + if len(paths) >= cap { break } } // Group requests by account hash - hashes, paths, pathsets = sortByAccountPath(hashes, paths) + paths, hashes, _, pathsets = sortByAccountPath(paths, hashes) req := &trienodeHealRequest{ peer: idle, id: reqid, @@ -1346,8 +1345,8 @@ func (s *Syncer) assignTrienodeHealTasks(success chan *trienodeHealResponse, fai revert: fail, cancel: cancel, stale: make(chan struct{}), - hashes: hashes, paths: paths, + hashes: hashes, task: s.healer, } req.timeout = time.AfterFunc(s.rates.TargetTimeout(), func() { @@ -1405,9 +1404,9 @@ func (s *Syncer) assignBytecodeHealTasks(success chan *bytecodeHealResponse, fai want = maxTrieRequestCount + maxCodeRequestCount ) if have < want { - nodes, paths, codes := s.healer.scheduler.Missing(want - have) - for i, hash := range nodes { - s.healer.trieTasks[hash] = paths[i] + paths, hashes, codes := s.healer.scheduler.Missing(want - have) + for i, path := range paths { + s.healer.trieTasks[path] = hashes[i] } for _, hash := range codes { s.healer.codeTasks[hash] = struct{}{} @@ -1703,10 +1702,10 @@ func (s *Syncer) revertTrienodeHealRequest(req *trienodeHealRequest) { s.lock.Unlock() // If there's a timeout timer still running, abort it and mark the trie node - // retrievals as not-pending, ready for resheduling + // retrievals as not-pending, ready for rescheduling req.timeout.Stop() - for i, hash := range req.hashes { - req.task.trieTasks[hash] = req.paths[i] + for i, path := range req.paths { + req.task.trieTasks[path] = req.hashes[i] } } @@ -2096,14 +2095,14 @@ func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) { // If the trie node was not delivered, reschedule it if node == nil { - res.task.trieTasks[hash] = res.paths[i] + res.task.trieTasks[res.paths[i]] = res.hashes[i] continue } // Push the trie node into the state syncer s.trienodeHealSynced++ s.trienodeHealBytes += common.StorageSize(len(node)) - err := s.healer.scheduler.Process(trie.SyncResult{Hash: hash, Data: node}) + err := s.healer.scheduler.ProcessNode(trie.NodeSyncResult{Path: res.paths[i], Data: node}) switch err { case nil: case trie.ErrAlreadyProcessed: @@ -2139,7 +2138,7 @@ func (s *Syncer) processBytecodeHealResponse(res *bytecodeHealResponse) { s.bytecodeHealSynced++ s.bytecodeHealBytes += common.StorageSize(len(node)) - err := s.healer.scheduler.Process(trie.SyncResult{Hash: hash, Data: node}) + err := s.healer.scheduler.ProcessCode(trie.CodeSyncResult{Hash: hash, Data: node}) switch err { case nil: case trie.ErrAlreadyProcessed: @@ -2666,9 +2665,9 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error } // Response validated, send it to the scheduler for filling response := &trienodeHealResponse{ + paths: req.paths, task: req.task, hashes: req.hashes, - paths: req.paths, nodes: nodes, } select { @@ -2913,8 +2912,9 @@ func (s *capacitySort) Swap(i, j int) { // healRequestSort implements the Sort interface, allowing sorting trienode // heal requests, which is a prerequisite for merging storage-requests. type healRequestSort struct { - hashes []common.Hash - paths []trie.SyncPath + paths []string + hashes []common.Hash + syncPaths []trie.SyncPath } func (t *healRequestSort) Len() int { @@ -2922,8 +2922,8 @@ func (t *healRequestSort) Len() int { } func (t *healRequestSort) Less(i, j int) bool { - a := t.paths[i] - b := t.paths[j] + a := t.syncPaths[i] + b := t.syncPaths[j] switch bytes.Compare(a[0], b[0]) { case -1: return true @@ -2944,8 +2944,9 @@ func (t *healRequestSort) Less(i, j int) bool { } func (t *healRequestSort) Swap(i, j int) { - t.hashes[i], t.hashes[j] = t.hashes[j], t.hashes[i] t.paths[i], t.paths[j] = t.paths[j], t.paths[i] + t.hashes[i], t.hashes[j] = t.hashes[j], t.hashes[i] + t.syncPaths[i], t.syncPaths[j] = t.syncPaths[j], t.syncPaths[i] } // Merge merges the pathsets, so that several storage requests concerning the @@ -2953,7 +2954,7 @@ func (t *healRequestSort) Swap(i, j int) { // OBS: This operation is moot if t has not first been sorted. func (t *healRequestSort) Merge() []TrieNodePathSet { var result []TrieNodePathSet - for _, path := range t.paths { + for _, path := range t.syncPaths { pathset := TrieNodePathSet([][]byte(path)) if len(path) == 1 { // It's an account reference. @@ -2962,7 +2963,7 @@ func (t *healRequestSort) Merge() []TrieNodePathSet { // It's a storage reference. end := len(result) - 1 if len(result) == 0 || !bytes.Equal(pathset[0], result[end][0]) { - // The account doesn't doesn't match last, create a new entry. + // The account doesn't match last, create a new entry. result = append(result, pathset) } else { // It's the same account as the previous one, add to the storage @@ -2976,9 +2977,13 @@ func (t *healRequestSort) Merge() []TrieNodePathSet { // sortByAccountPath takes hashes and paths, and sorts them. After that, it generates // the TrieNodePaths and merges paths which belongs to the same account path. -func sortByAccountPath(hashes []common.Hash, paths []trie.SyncPath) ([]common.Hash, []trie.SyncPath, []TrieNodePathSet) { - n := &healRequestSort{hashes, paths} +func sortByAccountPath(paths []string, hashes []common.Hash) ([]string, []common.Hash, []trie.SyncPath, []TrieNodePathSet) { + var syncPaths []trie.SyncPath + for _, path := range paths { + syncPaths = append(syncPaths, trie.NewSyncPath([]byte(path))) + } + n := &healRequestSort{paths, hashes, syncPaths} sort.Sort(n) pathsets := n.Merge() - return n.hashes, n.paths, pathsets + return n.paths, n.hashes, n.syncPaths, pathsets } diff --git a/les/downloader/statesync.go b/les/downloader/statesync.go index fd24c5150b3c..22f952155f11 100644 --- a/les/downloader/statesync.go +++ b/les/downloader/statesync.go @@ -34,7 +34,7 @@ import ( // a single data retrieval network packet. type stateReq struct { nItems uint16 // Number of items requested for download (max is 384, so uint16 is sufficient) - trieTasks map[common.Hash]*trieTask // Trie node download tasks to track previous attempts + trieTasks map[string]*trieTask // Trie node download tasks to track previous attempts codeTasks map[common.Hash]*codeTask // Byte code download tasks to track previous attempts timeout time.Duration // Maximum round trip time for this to complete timer *time.Timer // Timer to fire when the RTT timeout expires @@ -263,8 +263,8 @@ type stateSync struct { sched *trie.Sync // State trie sync scheduler defining the tasks keccak crypto.KeccakState // Keccak256 hasher to verify deliveries with - trieTasks map[common.Hash]*trieTask // Set of trie node tasks currently queued for retrieval - codeTasks map[common.Hash]*codeTask // Set of byte code tasks currently queued for retrieval + trieTasks map[string]*trieTask // Set of trie node tasks currently queued for retrieval, indexed by path + codeTasks map[common.Hash]*codeTask // Set of byte code tasks currently queued for retrieval, indexed by hash numUncommitted int bytesUncommitted int @@ -281,6 +281,7 @@ type stateSync struct { // trieTask represents a single trie node download task, containing a set of // peers already attempted retrieval from to detect stalled syncs and abort. type trieTask struct { + hash common.Hash path [][]byte attempts map[string]struct{} } @@ -299,7 +300,7 @@ func newStateSync(d *Downloader, root common.Hash) *stateSync { root: root, sched: state.NewStateSync(root, d.stateDB, nil), keccak: sha3.NewLegacyKeccak256().(crypto.KeccakState), - trieTasks: make(map[common.Hash]*trieTask), + trieTasks: make(map[string]*trieTask), codeTasks: make(map[common.Hash]*codeTask), deliver: make(chan *stateReq), cancel: make(chan struct{}), @@ -455,10 +456,11 @@ func (s *stateSync) assignTasks() { func (s *stateSync) fillTasks(n int, req *stateReq) (nodes []common.Hash, paths []trie.SyncPath, codes []common.Hash) { // Refill available tasks from the scheduler. if fill := n - (len(s.trieTasks) + len(s.codeTasks)); fill > 0 { - nodes, paths, codes := s.sched.Missing(fill) - for i, hash := range nodes { - s.trieTasks[hash] = &trieTask{ - path: paths[i], + paths, hashes, codes := s.sched.Missing(fill) + for i, path := range paths { + s.trieTasks[path] = &trieTask{ + hash: hashes[i], + path: trie.NewSyncPath([]byte(path)), attempts: make(map[string]struct{}), } } @@ -474,7 +476,7 @@ func (s *stateSync) fillTasks(n int, req *stateReq) (nodes []common.Hash, paths paths = make([]trie.SyncPath, 0, n) codes = make([]common.Hash, 0, n) - req.trieTasks = make(map[common.Hash]*trieTask, n) + req.trieTasks = make(map[string]*trieTask, n) req.codeTasks = make(map[common.Hash]*codeTask, n) for hash, t := range s.codeTasks { @@ -492,7 +494,7 @@ func (s *stateSync) fillTasks(n int, req *stateReq) (nodes []common.Hash, paths req.codeTasks[hash] = t delete(s.codeTasks, hash) } - for hash, t := range s.trieTasks { + for path, t := range s.trieTasks { // Stop when we've gathered enough requests if len(nodes)+len(codes) == n { break @@ -504,11 +506,11 @@ func (s *stateSync) fillTasks(n int, req *stateReq) (nodes []common.Hash, paths // Assign the request to this peer t.attempts[req.peer.id] = struct{}{} - nodes = append(nodes, hash) + nodes = append(nodes, t.hash) paths = append(paths, t.path) - req.trieTasks[hash] = t - delete(s.trieTasks, hash) + req.trieTasks[path] = t + delete(s.trieTasks, path) } req.nItems = uint16(len(nodes) + len(codes)) return nodes, paths, codes @@ -530,7 +532,7 @@ func (s *stateSync) process(req *stateReq) (int, error) { // Iterate over all the delivered data and inject one-by-one into the trie for _, blob := range req.response { - hash, err := s.processNodeData(blob) + hash, err := s.processNodeData(req.trieTasks, req.codeTasks, blob) switch err { case nil: s.numUncommitted++ @@ -543,13 +545,10 @@ func (s *stateSync) process(req *stateReq) (int, error) { default: return successful, fmt.Errorf("invalid state node %s: %v", hash.TerminalString(), err) } - // Delete from both queues (one delivery is enough for the syncer) - delete(req.trieTasks, hash) - delete(req.codeTasks, hash) } // Put unfulfilled tasks back into the retry queue npeers := s.d.peers.Len() - for hash, task := range req.trieTasks { + for path, task := range req.trieTasks { // If the node did deliver something, missing items may be due to a protocol // limit or a previous timeout + delayed delivery. Both cases should permit // the node to retry the missing items (to avoid single-peer stalls). @@ -559,10 +558,10 @@ func (s *stateSync) process(req *stateReq) (int, error) { // If we've requested the node too many times already, it may be a malicious // sync where nobody has the right data. Abort. if len(task.attempts) >= npeers { - return successful, fmt.Errorf("trie node %s failed with all peers (%d tries, %d peers)", hash.TerminalString(), len(task.attempts), npeers) + return successful, fmt.Errorf("trie node %s failed with all peers (%d tries, %d peers)", task.hash.TerminalString(), len(task.attempts), npeers) } // Missing item, place into the retry queue. - s.trieTasks[hash] = task + s.trieTasks[path] = task } for hash, task := range req.codeTasks { // If the node did deliver something, missing items may be due to a protocol @@ -585,13 +584,35 @@ func (s *stateSync) process(req *stateReq) (int, error) { // processNodeData tries to inject a trie node data blob delivered from a remote // peer into the state trie, returning whether anything useful was written or any // error occurred. -func (s *stateSync) processNodeData(blob []byte) (common.Hash, error) { - res := trie.SyncResult{Data: blob} +// +// If multiple requests correspond to the same hash, this method will inject the +// blob as a result for the first one only, leaving the remaining duplicates to +// be fetched again. +func (s *stateSync) processNodeData(nodeTasks map[string]*trieTask, codeTasks map[common.Hash]*codeTask, blob []byte) (common.Hash, error) { + var hash common.Hash s.keccak.Reset() s.keccak.Write(blob) - s.keccak.Read(res.Hash[:]) - err := s.sched.Process(res) - return res.Hash, err + s.keccak.Read(hash[:]) + + if _, present := codeTasks[hash]; present { + err := s.sched.ProcessCode(trie.CodeSyncResult{ + Hash: hash, + Data: blob, + }) + delete(codeTasks, hash) + return hash, err + } + for path, task := range nodeTasks { + if task.hash == hash { + err := s.sched.ProcessNode(trie.NodeSyncResult{ + Path: path, + Data: blob, + }) + delete(nodeTasks, path) + return hash, err + } + } + return common.Hash{}, trie.ErrNotRequested } // updateStats bumps the various state sync progress counters and displays a log diff --git a/trie/committer.go b/trie/committer.go index 9b7ecbf5fcce..7a392abab7f4 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -33,6 +33,7 @@ type leaf struct { size int // size of the rlp data (estimate) hash common.Hash // hash of rlp data node node // the node to commit + path []byte // the path from the root node } // committer is a type used for the trie Commit operation. A committer has some @@ -69,7 +70,7 @@ func (c *committer) Commit(n node, db *Database) (hashNode, int, error) { if db == nil { return nil, 0, errors.New("no db provided") } - h, committed, err := c.commit(n, db) + h, committed, err := c.commit(nil, n, db) if err != nil { return nil, 0, err } @@ -77,7 +78,7 @@ func (c *committer) Commit(n node, db *Database) (hashNode, int, error) { } // commit collapses a node down into a hash node and inserts it into the database -func (c *committer) commit(n node, db *Database) (node, int, error) { +func (c *committer) commit(path []byte, n node, db *Database) (node, int, error) { // if this path is clean, use available cached data hash, dirty := n.cache() if hash != nil && !dirty { @@ -93,7 +94,7 @@ func (c *committer) commit(n node, db *Database) (node, int, error) { // otherwise it can only be hashNode or valueNode. var childCommitted int if _, ok := cn.Val.(*fullNode); ok { - childV, committed, err := c.commit(cn.Val, db) + childV, committed, err := c.commit(append(path, cn.Key...), cn.Val, db) if err != nil { return nil, 0, err } @@ -101,20 +102,20 @@ func (c *committer) commit(n node, db *Database) (node, int, error) { } // The key needs to be copied, since we're delivering it to database collapsed.Key = hexToCompact(cn.Key) - hashedNode := c.store(collapsed, db) + hashedNode := c.store(path, collapsed, db) if hn, ok := hashedNode.(hashNode); ok { return hn, childCommitted + 1, nil } return collapsed, childCommitted, nil case *fullNode: - hashedKids, childCommitted, err := c.commitChildren(cn, db) + hashedKids, childCommitted, err := c.commitChildren(path, cn, db) if err != nil { return nil, 0, err } collapsed := cn.copy() collapsed.Children = hashedKids - hashedNode := c.store(collapsed, db) + hashedNode := c.store(path, collapsed, db) if hn, ok := hashedNode.(hashNode); ok { return hn, childCommitted + 1, nil } @@ -128,7 +129,7 @@ func (c *committer) commit(n node, db *Database) (node, int, error) { } // commitChildren commits the children of the given fullnode -func (c *committer) commitChildren(n *fullNode, db *Database) ([17]node, int, error) { +func (c *committer) commitChildren(path []byte, n *fullNode, db *Database) ([17]node, int, error) { var ( committed int children [17]node @@ -148,7 +149,7 @@ func (c *committer) commitChildren(n *fullNode, db *Database) ([17]node, int, er // Commit the child recursively and store the "hashed" value. // Note the returned node can be some embedded nodes, so it's // possible the type is not hashNode. - hashed, childCommitted, err := c.commit(child, db) + hashed, childCommitted, err := c.commit(append(path, byte(i)), child, db) if err != nil { return children, 0, err } @@ -165,7 +166,7 @@ func (c *committer) commitChildren(n *fullNode, db *Database) ([17]node, int, er // store hashes the node n and if we have a storage layer specified, it writes // the key/value pair to it and tracks any node->child references as well as any // node->external trie references. -func (c *committer) store(n node, db *Database) node { +func (c *committer) store(path []byte, n node, db *Database) node { // Larger nodes are replaced by their hash and stored in the database. var ( hash, _ = n.cache() @@ -189,6 +190,7 @@ func (c *committer) store(n node, db *Database) node { size: size, hash: common.BytesToHash(hash), node: n, + path: path, } } else if db != nil { // No leaf-callback used, but there's still a database. Do serial @@ -213,13 +215,13 @@ func (c *committer) commitLoop(db *Database) { switch n := n.(type) { case *shortNode: if child, ok := n.Val.(valueNode); ok { - c.onleaf(nil, nil, child, hash) + c.onleaf(nil, nil, child, hash, nil) } case *fullNode: // For children in range [0, 15], it's impossible // to contain valueNode. Only check the 17th child. if n.Children[16] != nil { - c.onleaf(nil, nil, n.Children[16].(valueNode), hash) + c.onleaf(nil, nil, n.Children[16].(valueNode), hash, nil) } } } diff --git a/trie/sync.go b/trie/sync.go index db51dd4b036a..7f4e67dbfecb 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" ) // ErrNotRequested is returned by the trie sync when it's requested to process a @@ -39,19 +40,6 @@ var ErrAlreadyProcessed = errors.New("already processed") // memory if the node was configured with a significant number of peers. const maxFetchesPerDepth = 16384 -// request represents a scheduled or already in-flight state retrieval request. -type request struct { - path []byte // Merkle path leading to this node for prioritization - hash common.Hash // Hash of the node data content to retrieve - data []byte // Data content of the node, cached until all subtrees complete - code bool // Whether this is a code entry - - parents []*request // Parent state nodes referencing this entry (notify all upon completion) - deps int // Number of dependencies before allowed to commit this node - - callback LeafCallback // Callback to invoke if a leaf node it reached on this branch -} - // SyncPath is a path tuple identifying a particular trie node either in a single // trie (account) or a layered trie (account -> storage). // @@ -85,30 +73,57 @@ func NewSyncPath(path []byte) SyncPath { return SyncPath{hexToKeybytes(path[:64]), hexToCompact(path[64:])} } -// SyncResult is a response with requested data along with it's hash. -type SyncResult struct { - Hash common.Hash // Hash of the originally unknown trie node - Data []byte // Data content of the retrieved node +// nodeRequest represents a scheduled or already in-flight trie node retrieval request. +type nodeRequest struct { + hash common.Hash // Hash of the trie node to retrieve + path []byte // Merkle path leading to this node for prioritization + data []byte // Data content of the node, cached until all subtrees complete + + parent *nodeRequest // Parent state node referencing this entry + deps int // Number of dependencies before allowed to commit this node + callback LeafCallback // Callback to invoke if a leaf node it reached on this branch +} + +// codeRequest represents a scheduled or already in-flight bytecode retrieval request. +type codeRequest struct { + hash common.Hash // Hash of the contract bytecode to retrieve + path []byte // Merkle path leading to this node for prioritization + data []byte // Data content of the node, cached until all subtrees complete + parents []*nodeRequest // Parent state nodes referencing this entry (notify all upon completion) +} + +// NodeSyncResult is a response with requested trie node along with its node path. +type NodeSyncResult struct { + Path string // Path of the originally unknown trie node + Data []byte // Data content of the retrieved trie node +} + +// CodeSyncResult is a response with requested bytecode along with its hash. +type CodeSyncResult struct { + Hash common.Hash // Hash the originally unknown bytecode + Data []byte // Data content of the retrieved bytecode } // syncMemBatch is an in-memory buffer of successfully downloaded but not yet // persisted data items. type syncMemBatch struct { - nodes map[common.Hash][]byte // In-memory membatch of recently completed nodes - codes map[common.Hash][]byte // In-memory membatch of recently completed codes + nodes map[string][]byte // In-memory membatch of recently completed nodes + hashes map[string]common.Hash // Hashes of recently completed nodes + codes map[common.Hash][]byte // In-memory membatch of recently completed codes } // newSyncMemBatch allocates a new memory-buffer for not-yet persisted trie nodes. func newSyncMemBatch() *syncMemBatch { return &syncMemBatch{ - nodes: make(map[common.Hash][]byte), - codes: make(map[common.Hash][]byte), + nodes: make(map[string][]byte), + hashes: make(map[string]common.Hash), + codes: make(map[common.Hash][]byte), } } -// hasNode reports the trie node with specific hash is already cached. -func (batch *syncMemBatch) hasNode(hash common.Hash) bool { - _, ok := batch.nodes[hash] +// hasNode reports the trie node with specific path is already cached. +func (batch *syncMemBatch) hasNode(path []byte) bool { + _, ok := batch.nodes[string(path)] return ok } @@ -122,12 +137,12 @@ func (batch *syncMemBatch) hasCode(hash common.Hash) bool { // unknown trie hashes to retrieve, accepts node data associated with said hashes // and reconstructs the trie step by step until all is done. type Sync struct { - database ethdb.KeyValueReader // Persistent database to check for existing entries - membatch *syncMemBatch // Memory buffer to avoid frequent database writes - nodeReqs map[common.Hash]*request // Pending requests pertaining to a trie node hash - codeReqs map[common.Hash]*request // Pending requests pertaining to a code hash - queue *prque.Prque // Priority queue with the pending requests - fetches map[int]int // Number of active fetches per trie node depth + database ethdb.KeyValueReader // Persistent database to check for existing entries + membatch *syncMemBatch // Memory buffer to avoid frequent database writes + nodeReqs map[string]*nodeRequest // Pending requests pertaining to a trie node path + codeReqs map[common.Hash]*codeRequest // Pending requests pertaining to a code hash + queue *prque.Prque // Priority queue with the pending requests + fetches map[int]int // Number of active fetches per trie node depth } // NewSync creates a new trie data download scheduler. @@ -135,51 +150,51 @@ func NewSync(root common.Hash, database ethdb.KeyValueReader, callback LeafCallb ts := &Sync{ database: database, membatch: newSyncMemBatch(), - nodeReqs: make(map[common.Hash]*request), - codeReqs: make(map[common.Hash]*request), + nodeReqs: make(map[string]*nodeRequest), + codeReqs: make(map[common.Hash]*codeRequest), queue: prque.New(nil), fetches: make(map[int]int), } - ts.AddSubTrie(root, nil, common.Hash{}, callback) + ts.AddSubTrie(root, nil, common.Hash{}, nil, callback) return ts } -// AddSubTrie registers a new trie to the sync code, rooted at the designated parent. -func (s *Sync) AddSubTrie(root common.Hash, path []byte, parent common.Hash, callback LeafCallback) { +// AddSubTrie registers a new trie to the sync code, rooted at the designated +// parent for completion tracking. The given path is a unique node path in +// hex format and contain all the parent path if it's layered trie node. +func (s *Sync) AddSubTrie(root common.Hash, path []byte, parent common.Hash, parentPath []byte, callback LeafCallback) { // Short circuit if the trie is empty or already known if root == emptyRoot { return } - if s.membatch.hasNode(root) { + if s.membatch.hasNode(path) { return } - // If database says this is a duplicate, then at least the trie node is - // present, and we hold the assumption that it's NOT legacy contract code. if rawdb.HasTrieNode(s.database, root) { return } // Assemble the new sub-trie sync request - req := &request{ - path: path, + req := &nodeRequest{ hash: root, + path: path, callback: callback, } // If this sub-trie has a designated parent, link them together if parent != (common.Hash{}) { - ancestor := s.nodeReqs[parent] + ancestor := s.nodeReqs[string(parentPath)] if ancestor == nil { panic(fmt.Sprintf("sub-trie ancestor not found: %x", parent)) } ancestor.deps++ - req.parents = append(req.parents, ancestor) + req.parent = ancestor } - s.schedule(req) + s.scheduleNodeRequest(req) } // AddCodeEntry schedules the direct retrieval of a contract code that should not // be interpreted as a trie node, but rather accepted and stored into the database // as is. -func (s *Sync) AddCodeEntry(hash common.Hash, path []byte, parent common.Hash) { +func (s *Sync) AddCodeEntry(hash common.Hash, path []byte, parent common.Hash, parentPath []byte) { // Short circuit if the entry is empty or already known if hash == emptyState { return @@ -196,30 +211,29 @@ func (s *Sync) AddCodeEntry(hash common.Hash, path []byte, parent common.Hash) { return } // Assemble the new sub-trie sync request - req := &request{ + req := &codeRequest{ path: path, hash: hash, - code: true, } // If this sub-trie has a designated parent, link them together if parent != (common.Hash{}) { - ancestor := s.nodeReqs[parent] // the parent of codereq can ONLY be nodereq + ancestor := s.nodeReqs[string(parentPath)] // the parent of codereq can ONLY be nodereq if ancestor == nil { panic(fmt.Sprintf("raw-entry ancestor not found: %x", parent)) } ancestor.deps++ req.parents = append(req.parents, ancestor) } - s.schedule(req) + s.scheduleCodeRequest(req) } // Missing retrieves the known missing nodes from the trie for retrieval. To aid // both eth/6x style fast sync and snap/1x style state sync, the paths of trie // nodes are returned too, as well as separate hash list for codes. -func (s *Sync) Missing(max int) (nodes []common.Hash, paths []SyncPath, codes []common.Hash) { +func (s *Sync) Missing(max int) ([]string, []common.Hash, []common.Hash) { var ( + nodePaths []string nodeHashes []common.Hash - nodePaths []SyncPath codeHashes []common.Hash ) for !s.queue.Empty() && (max == 0 || len(nodeHashes)+len(codeHashes) < max) { @@ -235,62 +249,77 @@ func (s *Sync) Missing(max int) (nodes []common.Hash, paths []SyncPath, codes [] s.queue.Pop() s.fetches[depth]++ - hash := item.(common.Hash) - if req, ok := s.nodeReqs[hash]; ok { - nodeHashes = append(nodeHashes, hash) - nodePaths = append(nodePaths, NewSyncPath(req.path)) - } else { - codeHashes = append(codeHashes, hash) + switch item.(type) { + case common.Hash: + codeHashes = append(codeHashes, item.(common.Hash)) + case string: + path := item.(string) + req, ok := s.nodeReqs[path] + if !ok { + log.Error("Missing node request", "path", path) + continue // System very wrong, shouldn't happen + } + nodePaths = append(nodePaths, path) + nodeHashes = append(nodeHashes, req.hash) } } - return nodeHashes, nodePaths, codeHashes + return nodePaths, nodeHashes, codeHashes } -// Process injects the received data for requested item. Note it can +// ProcessCode injects the received data for requested item. Note it can // happpen that the single response commits two pending requests(e.g. // there are two requests one for code and one for node but the hash // is same). In this case the second response for the same hash will // be treated as "non-requested" item or "already-processed" item but // there is no downside. -func (s *Sync) Process(result SyncResult) error { - // If the item was not requested either for code or node, bail out - if s.nodeReqs[result.Hash] == nil && s.codeReqs[result.Hash] == nil { +func (s *Sync) ProcessCode(result CodeSyncResult) error { + // If the code was not requested or it's already processed, bail out + req := s.codeReqs[result.Hash] + if req == nil { return ErrNotRequested } - // There is an pending code request for this data, commit directly - var filled bool - if req := s.codeReqs[result.Hash]; req != nil && req.data == nil { - filled = true - req.data = result.Data - s.commit(req) + if req.data != nil { + return ErrAlreadyProcessed } - // There is an pending node request for this data, fill it. - if req := s.nodeReqs[result.Hash]; req != nil && req.data == nil { - filled = true - // Decode the node data content and update the request - node, err := decodeNode(result.Hash[:], result.Data) - if err != nil { - return err - } - req.data = result.Data + req.data = result.Data + return s.commitCodeRequest(req) +} - // Create and schedule a request for all the children nodes - requests, err := s.children(req, node) - if err != nil { - return err - } - if len(requests) == 0 && req.deps == 0 { - s.commit(req) - } else { - req.deps += len(requests) - for _, child := range requests { - s.schedule(child) - } - } +// ProcessNode injects the received data for requested item. Note it can +// happen that the single response commits two pending requests(e.g. +// there are two requests one for code and one for node but the hash +// is same). In this case the second response for the same hash will +// be treated as "non-requested" item or "already-processed" item but +// there is no downside. +func (s *Sync) ProcessNode(result NodeSyncResult) error { + // If the trie node was not requested or it's already processed, bail out + req := s.nodeReqs[result.Path] + if req == nil { + return ErrNotRequested } - if !filled { + if req.data != nil { return ErrAlreadyProcessed } + // Decode the node data content and update the request + node, err := decodeNode(req.hash.Bytes(), result.Data) + if err != nil { + return err + } + req.data = result.Data + + // Create and schedule a request for all the children nodes + requests, err := s.children(req, node) + if err != nil { + return err + } + if len(requests) == 0 && req.deps == 0 { + s.commitNodeRequest(req) + } else { + req.deps += len(requests) + for _, child := range requests { + s.scheduleNodeRequest(child) + } + } return nil } @@ -298,11 +327,11 @@ func (s *Sync) Process(result SyncResult) error { // storage, returning any occurred error. func (s *Sync) Commit(dbw ethdb.Batch) error { // Dump the membatch into a database dbw - for key, value := range s.membatch.nodes { - rawdb.WriteTrieNode(dbw, key, value) + for path, value := range s.membatch.nodes { + rawdb.WriteTrieNode(dbw, s.membatch.hashes[path], value) } - for key, value := range s.membatch.codes { - rawdb.WriteCode(dbw, key, value) + for hash, value := range s.membatch.codes { + rawdb.WriteCode(dbw, hash, value) } // Drop the membatch data and return s.membatch = newSyncMemBatch() @@ -317,23 +346,31 @@ func (s *Sync) Pending() int { // schedule inserts a new state retrieval request into the fetch queue. If there // is already a pending request for this node, the new request will be discarded // and only a parent reference added to the old one. -func (s *Sync) schedule(req *request) { - var reqset = s.nodeReqs - if req.code { - reqset = s.codeReqs +func (s *Sync) scheduleNodeRequest(req *nodeRequest) { + s.nodeReqs[string(req.path)] = req + + // Schedule the request for future retrieval. This queue is shared + // by both node requests and code requests. + prio := int64(len(req.path)) << 56 // depth >= 128 will never happen, storage leaves will be included in their parents + for i := 0; i < 14 && i < len(req.path); i++ { + prio |= int64(15-req.path[i]) << (52 - i*4) // 15-nibble => lexicographic order } + s.queue.Push(string(req.path), prio) +} + +// schedule inserts a new state retrieval request into the fetch queue. If there +// is already a pending request for this node, the new request will be discarded +// and only a parent reference added to the old one. +func (s *Sync) scheduleCodeRequest(req *codeRequest) { // If we're already requesting this node, add a new reference and stop - if old, ok := reqset[req.hash]; ok { + if old, ok := s.codeReqs[req.hash]; ok { old.parents = append(old.parents, req.parents...) return } - reqset[req.hash] = req + s.codeReqs[req.hash] = req // Schedule the request for future retrieval. This queue is shared - // by both node requests and code requests. It can happen that there - // is a trie node and code has same hash. In this case two elements - // with same hash and same or different depth will be pushed. But it's - // ok the worst case is the second response will be treated as duplicated. + // by both node requests and code requests. prio := int64(len(req.path)) << 56 // depth >= 128 will never happen, storage leaves will be included in their parents for i := 0; i < 14 && i < len(req.path); i++ { prio |= int64(15-req.path[i]) << (52 - i*4) // 15-nibble => lexicographic order @@ -343,7 +380,7 @@ func (s *Sync) schedule(req *request) { // children retrieves all the missing children of a state trie entry for future // retrieval scheduling. -func (s *Sync) children(req *request, object node) ([]*request, error) { +func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { // Gather all the children of the node, irrelevant whether known or not type child struct { path []byte @@ -374,7 +411,7 @@ func (s *Sync) children(req *request, object node) ([]*request, error) { panic(fmt.Sprintf("unknown node: %+v", node)) } // Iterate over the children, and request all unknown ones - requests := make([]*request, 0, len(children)) + requests := make([]*nodeRequest, 0, len(children)) for _, child := range children { // Notify any external watcher of a new key/value node if req.callback != nil { @@ -386,7 +423,7 @@ func (s *Sync) children(req *request, object node) ([]*request, error) { paths = append(paths, hexToKeybytes(child.path[:2*common.HashLength])) paths = append(paths, hexToKeybytes(child.path[2*common.HashLength:])) } - if err := req.callback(paths, child.path, node, req.hash); err != nil { + if err := req.callback(paths, child.path, node, req.hash, req.path); err != nil { return nil, err } } @@ -394,20 +431,20 @@ func (s *Sync) children(req *request, object node) ([]*request, error) { // If the child references another node, resolve or schedule if node, ok := (child.node).(hashNode); ok { // Try to resolve the node from the local database - hash := common.BytesToHash(node) - if s.membatch.hasNode(hash) { + if s.membatch.hasNode(child.path) { continue } // If database says duplicate, then at least the trie node is present // and we hold the assumption that it's NOT legacy contract code. - if rawdb.HasTrieNode(s.database, hash) { + chash := common.BytesToHash(node) + if rawdb.HasTrieNode(s.database, chash) { continue } // Locally unknown node, schedule for retrieval - requests = append(requests, &request{ + requests = append(requests, &nodeRequest{ path: child.path, - hash: hash, - parents: []*request{req}, + hash: chash, + parent: req, callback: req.callback, }) } @@ -418,22 +455,40 @@ func (s *Sync) children(req *request, object node) ([]*request, error) { // commit finalizes a retrieval request and stores it into the membatch. If any // of the referencing parent requests complete due to this commit, they are also // committed themselves. -func (s *Sync) commit(req *request) (err error) { +func (s *Sync) commitNodeRequest(req *nodeRequest) error { // Write the node content to the membatch - if req.code { - s.membatch.codes[req.hash] = req.data - delete(s.codeReqs, req.hash) - s.fetches[len(req.path)]-- - } else { - s.membatch.nodes[req.hash] = req.data - delete(s.nodeReqs, req.hash) - s.fetches[len(req.path)]-- + s.membatch.nodes[string(req.path)] = req.data + s.membatch.hashes[string(req.path)] = req.hash + + delete(s.nodeReqs, string(req.path)) + s.fetches[len(req.path)]-- + + // Check parent for completion + if req.parent != nil { + req.parent.deps-- + if req.parent.deps == 0 { + if err := s.commitNodeRequest(req.parent); err != nil { + return err + } + } } + return nil +} + +// commit finalizes a retrieval request and stores it into the membatch. If any +// of the referencing parent requests complete due to this commit, they are also +// committed themselves. +func (s *Sync) commitCodeRequest(req *codeRequest) error { + // Write the node content to the membatch + s.membatch.codes[req.hash] = req.data + delete(s.codeReqs, req.hash) + s.fetches[len(req.path)]-- + // Check all parents for completion for _, parent := range req.parents { parent.deps-- if parent.deps == 0 { - if err := s.commit(parent); err != nil { + if err := s.commitNodeRequest(parent); err != nil { return err } } diff --git a/trie/sync_test.go b/trie/sync_test.go index 4c2c50d7a159..472c31a63b9b 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -87,6 +87,13 @@ func checkTrieConsistency(db *Database, root common.Hash) error { return it.Error() } +// trieElement represents the element in the state trie(bytecode or trie node). +type trieElement struct { + path string + hash common.Hash + syncPath SyncPath +} + // Tests that an empty trie is not scheduled for syncing. func TestEmptySync(t *testing.T) { dbA := NewDatabase(memorydb.New()) @@ -96,8 +103,8 @@ func TestEmptySync(t *testing.T) { for i, trie := range []*Trie{emptyA, emptyB} { sync := NewSync(trie.Hash(), memorydb.New(), nil) - if nodes, paths, codes := sync.Missing(1); len(nodes) != 0 || len(paths) != 0 || len(codes) != 0 { - t.Errorf("test %d: content requested for empty trie: %v, %v, %v", i, nodes, paths, codes) + if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { + t.Errorf("test %d: content requested for empty trie: %v, %v, %v", i, paths, nodes, codes) } } } @@ -118,35 +125,38 @@ func testIterativeSync(t *testing.T, count int, bypath bool) { triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) - nodes, paths, codes := sched.Missing(count) - var ( - hashQueue []common.Hash - pathQueue []SyncPath - ) - if !bypath { - hashQueue = append(append(hashQueue[:0], nodes...), codes...) - } else { - hashQueue = append(hashQueue[:0], codes...) - pathQueue = append(pathQueue[:0], paths...) + // The code requests are ignored here since there is no code + // at the testing trie. + paths, nodes, _ := sched.Missing(count) + var elements []trieElement + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) } - for len(hashQueue)+len(pathQueue) > 0 { - results := make([]SyncResult, len(hashQueue)+len(pathQueue)) - for i, hash := range hashQueue { - data, err := srcDb.Node(hash) - if err != nil { - t.Fatalf("failed to retrieve node data for hash %x: %v", hash, err) + for len(elements) > 0 { + results := make([]NodeSyncResult, len(elements)) + if !bypath { + for i, element := range elements { + data, err := srcDb.Node(element.hash) + if err != nil { + t.Fatalf("failed to retrieve node data for hash %x: %v", element.hash, err) + } + results[i] = NodeSyncResult{element.path, data} } - results[i] = SyncResult{hash, data} - } - for i, path := range pathQueue { - data, _, err := srcTrie.TryGetNode(path[0]) - if err != nil { - t.Fatalf("failed to retrieve node data for path %x: %v", path, err) + } else { + for i, element := range elements { + data, _, err := srcTrie.TryGetNode(element.syncPath[len(element.syncPath)-1]) + if err != nil { + t.Fatalf("failed to retrieve node data for path %x: %v", element.path, err) + } + results[i] = NodeSyncResult{element.path, data} } - results[len(hashQueue)+i] = SyncResult{crypto.Keccak256Hash(data), data} } for _, result := range results { - if err := sched.Process(result); err != nil { + if err := sched.ProcessNode(result); err != nil { t.Fatalf("failed to process result %v", err) } } @@ -156,12 +166,14 @@ func testIterativeSync(t *testing.T, count int, bypath bool) { } batch.Write() - nodes, paths, codes = sched.Missing(count) - if !bypath { - hashQueue = append(append(hashQueue[:0], nodes...), codes...) - } else { - hashQueue = append(hashQueue[:0], codes...) - pathQueue = append(pathQueue[:0], paths...) + paths, nodes, _ = sched.Missing(count) + elements = elements[:0] + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) } } // Cross check that the two tries are in sync @@ -179,21 +191,29 @@ func TestIterativeDelayedSync(t *testing.T) { triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) - nodes, _, codes := sched.Missing(10000) - queue := append(append([]common.Hash{}, nodes...), codes...) - - for len(queue) > 0 { + // The code requests are ignored here since there is no code + // at the testing trie. + paths, nodes, _ := sched.Missing(10000) + var elements []trieElement + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) + } + for len(elements) > 0 { // Sync only half of the scheduled nodes - results := make([]SyncResult, len(queue)/2+1) - for i, hash := range queue[:len(results)] { - data, err := srcDb.Node(hash) + results := make([]NodeSyncResult, len(elements)/2+1) + for i, element := range elements[:len(results)] { + data, err := srcDb.Node(element.hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } - results[i] = SyncResult{hash, data} + results[i] = NodeSyncResult{element.path, data} } for _, result := range results { - if err := sched.Process(result); err != nil { + if err := sched.ProcessNode(result); err != nil { t.Fatalf("failed to process result %v", err) } } @@ -203,8 +223,15 @@ func TestIterativeDelayedSync(t *testing.T) { } batch.Write() - nodes, _, codes = sched.Missing(10000) - queue = append(append(queue[len(results):], nodes...), codes...) + paths, nodes, _ = sched.Missing(10000) + elements = elements[len(results):] + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) + } } // Cross check that the two tries are in sync checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) @@ -225,24 +252,30 @@ func testIterativeRandomSync(t *testing.T, count int) { triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) - queue := make(map[common.Hash]struct{}) - nodes, _, codes := sched.Missing(count) - for _, hash := range append(nodes, codes...) { - queue[hash] = struct{}{} + // The code requests are ignored here since there is no code + // at the testing trie. + paths, nodes, _ := sched.Missing(count) + queue := make(map[string]trieElement) + for i, path := range paths { + queue[path] = trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + } } for len(queue) > 0 { // Fetch all the queued nodes in a random order - results := make([]SyncResult, 0, len(queue)) - for hash := range queue { - data, err := srcDb.Node(hash) + results := make([]NodeSyncResult, 0, len(queue)) + for path, element := range queue { + data, err := srcDb.Node(element.hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } - results = append(results, SyncResult{hash, data}) + results = append(results, NodeSyncResult{path, data}) } // Feed the retrieved results back and queue new tasks for _, result := range results { - if err := sched.Process(result); err != nil { + if err := sched.ProcessNode(result); err != nil { t.Fatalf("failed to process result %v", err) } } @@ -252,10 +285,14 @@ func testIterativeRandomSync(t *testing.T, count int) { } batch.Write() - queue = make(map[common.Hash]struct{}) - nodes, _, codes = sched.Missing(count) - for _, hash := range append(nodes, codes...) { - queue[hash] = struct{}{} + paths, nodes, _ = sched.Missing(count) + queue = make(map[string]trieElement) + for i, path := range paths { + queue[path] = trieElement{ + path: path, + hash: nodes[i], + syncPath: NewSyncPath([]byte(path)), + } } } // Cross check that the two tries are in sync @@ -273,20 +310,26 @@ func TestIterativeRandomDelayedSync(t *testing.T) { triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) - queue := make(map[common.Hash]struct{}) - nodes, _, codes := sched.Missing(10000) - for _, hash := range append(nodes, codes...) { - queue[hash] = struct{}{} + // The code requests are ignored here since there is no code + // at the testing trie. + paths, nodes, _ := sched.Missing(10000) + queue := make(map[string]trieElement) + for i, path := range paths { + queue[path] = trieElement{ + path: path, + hash: nodes[i], + syncPath: NewSyncPath([]byte(path)), + } } for len(queue) > 0 { // Sync only half of the scheduled nodes, even those in random order - results := make([]SyncResult, 0, len(queue)/2+1) - for hash := range queue { - data, err := srcDb.Node(hash) + results := make([]NodeSyncResult, 0, len(queue)/2+1) + for path, element := range queue { + data, err := srcDb.Node(element.hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } - results = append(results, SyncResult{hash, data}) + results = append(results, NodeSyncResult{path, data}) if len(results) >= cap(results) { break @@ -294,7 +337,7 @@ func TestIterativeRandomDelayedSync(t *testing.T) { } // Feed the retrieved results back and queue new tasks for _, result := range results { - if err := sched.Process(result); err != nil { + if err := sched.ProcessNode(result); err != nil { t.Fatalf("failed to process result %v", err) } } @@ -304,11 +347,15 @@ func TestIterativeRandomDelayedSync(t *testing.T) { } batch.Write() for _, result := range results { - delete(queue, result.Hash) - } - nodes, _, codes = sched.Missing(10000) - for _, hash := range append(nodes, codes...) { - queue[hash] = struct{}{} + delete(queue, result.Path) + } + paths, nodes, _ = sched.Missing(10000) + for i, path := range paths { + queue[path] = trieElement{ + path: path, + hash: nodes[i], + syncPath: NewSyncPath([]byte(path)), + } } } // Cross check that the two tries are in sync @@ -326,26 +373,35 @@ func TestDuplicateAvoidanceSync(t *testing.T) { triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) - nodes, _, codes := sched.Missing(0) - queue := append(append([]common.Hash{}, nodes...), codes...) + // The code requests are ignored here since there is no code + // at the testing trie. + paths, nodes, _ := sched.Missing(0) + var elements []trieElement + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) + } requested := make(map[common.Hash]struct{}) - for len(queue) > 0 { - results := make([]SyncResult, len(queue)) - for i, hash := range queue { - data, err := srcDb.Node(hash) + for len(elements) > 0 { + results := make([]NodeSyncResult, len(elements)) + for i, element := range elements { + data, err := srcDb.Node(element.hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } - if _, ok := requested[hash]; ok { - t.Errorf("hash %x already requested once", hash) + if _, ok := requested[element.hash]; ok { + t.Errorf("hash %x already requested once", element.hash) } - requested[hash] = struct{}{} + requested[element.hash] = struct{}{} - results[i] = SyncResult{hash, data} + results[i] = NodeSyncResult{element.path, data} } for _, result := range results { - if err := sched.Process(result); err != nil { + if err := sched.ProcessNode(result); err != nil { t.Fatalf("failed to process result %v", err) } } @@ -355,8 +411,15 @@ func TestDuplicateAvoidanceSync(t *testing.T) { } batch.Write() - nodes, _, codes = sched.Missing(0) - queue = append(append(queue[:0], nodes...), codes...) + paths, nodes, _ = sched.Missing(0) + elements = elements[:0] + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) + } } // Cross check that the two tries are in sync checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) @@ -373,23 +436,34 @@ func TestIncompleteSync(t *testing.T) { triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) - var added []common.Hash - - nodes, _, codes := sched.Missing(1) - queue := append(append([]common.Hash{}, nodes...), codes...) - for len(queue) > 0 { + // The code requests are ignored here since there is no code + // at the testing trie. + var ( + added []common.Hash + elements []trieElement + root = srcTrie.Hash() + ) + paths, nodes, _ := sched.Missing(1) + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) + } + for len(elements) > 0 { // Fetch a batch of trie nodes - results := make([]SyncResult, len(queue)) - for i, hash := range queue { - data, err := srcDb.Node(hash) + results := make([]NodeSyncResult, len(elements)) + for i, element := range elements { + data, err := srcDb.Node(element.hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } - results[i] = SyncResult{hash, data} + results[i] = NodeSyncResult{element.path, data} } // Process each of the trie nodes for _, result := range results { - if err := sched.Process(result); err != nil { + if err := sched.ProcessNode(result); err != nil { t.Fatalf("failed to process result %v", err) } } @@ -398,27 +472,36 @@ func TestIncompleteSync(t *testing.T) { t.Fatalf("failed to commit data: %v", err) } batch.Write() + for _, result := range results { - added = append(added, result.Hash) + hash := crypto.Keccak256Hash(result.Data) + if hash != root { + added = append(added, hash) + } // Check that all known sub-tries in the synced trie are complete - if err := checkTrieConsistency(triedb, result.Hash); err != nil { + if err := checkTrieConsistency(triedb, hash); err != nil { t.Fatalf("trie inconsistent: %v", err) } } // Fetch the next batch to retrieve - nodes, _, codes = sched.Missing(1) - queue = append(append(queue[:0], nodes...), codes...) + paths, nodes, _ = sched.Missing(1) + elements = elements[:0] + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) + } } // Sanity check that removing any node from the database is detected - for _, node := range added[1:] { - key := node.Bytes() - value, _ := diskdb.Get(key) - - diskdb.Delete(key) - if err := checkTrieConsistency(triedb, added[0]); err == nil { - t.Fatalf("trie inconsistency not caught, missing: %x", key) + for _, hash := range added { + value, _ := diskdb.Get(hash.Bytes()) + diskdb.Delete(hash.Bytes()) + if err := checkTrieConsistency(triedb, root); err == nil { + t.Fatalf("trie inconsistency not caught, missing: %x", hash) } - diskdb.Put(key, value) + diskdb.Put(hash.Bytes(), value) } } @@ -433,21 +516,33 @@ func TestSyncOrdering(t *testing.T) { triedb := NewDatabase(diskdb) sched := NewSync(srcTrie.Hash(), diskdb, nil) - nodes, paths, _ := sched.Missing(1) - queue := append([]common.Hash{}, nodes...) - reqs := append([]SyncPath{}, paths...) + // The code requests are ignored here since there is no code + // at the testing trie. + var ( + reqs []SyncPath + elements []trieElement + ) + paths, nodes, _ := sched.Missing(1) + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) + reqs = append(reqs, NewSyncPath([]byte(paths[i]))) + } - for len(queue) > 0 { - results := make([]SyncResult, len(queue)) - for i, hash := range queue { - data, err := srcDb.Node(hash) + for len(elements) > 0 { + results := make([]NodeSyncResult, len(elements)) + for i, element := range elements { + data, err := srcDb.Node(element.hash) if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + t.Fatalf("failed to retrieve node data for %x: %v", element.hash, err) } - results[i] = SyncResult{hash, data} + results[i] = NodeSyncResult{element.path, data} } for _, result := range results { - if err := sched.Process(result); err != nil { + if err := sched.ProcessNode(result); err != nil { t.Fatalf("failed to process result %v", err) } } @@ -457,9 +552,16 @@ func TestSyncOrdering(t *testing.T) { } batch.Write() - nodes, paths, _ = sched.Missing(1) - queue = append(queue[:0], nodes...) - reqs = append(reqs, paths...) + paths, nodes, _ = sched.Missing(1) + elements = elements[:0] + for i := 0; i < len(paths); i++ { + elements = append(elements, trieElement{ + path: paths[i], + hash: nodes[i], + syncPath: NewSyncPath([]byte(paths[i])), + }) + reqs = append(reqs, NewSyncPath([]byte(paths[i]))) + } } // Cross check that the two tries are in sync checkTrieContents(t, triedb, srcTrie.Hash().Bytes(), srcData) diff --git a/trie/trie.go b/trie/trie.go index 0c81cb2c3901..1e168402ad95 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -42,18 +42,18 @@ var ( // LeafCallback is a callback type invoked when a trie operation reaches a leaf // node. // -// The paths is a path tuple identifying a particular trie node either in a single -// trie (account) or a layered trie (account -> storage). Each path in the tuple +// The keys is a path tuple identifying a particular trie node either in a single +// trie (account) or a layered trie (account -> storage). Each key in the tuple // is in the raw format(32 bytes). // -// The hexpath is a composite hexary path identifying the trie node. All the key +// The path is a composite hexary path identifying the trie node. All the key // bytes are converted to the hexary nibbles and composited with the parent path // if the trie node is in a layered trie. // // It's used by state sync and commit to allow handling external references // between account and storage tries. And also it's used in the state healing // for extracting the raw states(leaf nodes) with corresponding paths. -type LeafCallback func(paths [][]byte, hexpath []byte, leaf []byte, parent common.Hash) error +type LeafCallback func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error // Trie is a Merkle Patricia Trie. // The zero value is an empty trie with no database. diff --git a/trie/trie_test.go b/trie/trie_test.go index 371bdf01c02d..7baae88aeabe 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -625,7 +625,7 @@ func BenchmarkCommitAfterHash(b *testing.B) { benchmarkCommitAfterHash(b, nil) }) var a types.StateAccount - onleaf := func(paths [][]byte, hexpath []byte, leaf []byte, parent common.Hash) error { + onleaf := func(paths [][]byte, hexpath []byte, leaf []byte, parent common.Hash, parentPath []byte) error { rlp.DecodeBytes(leaf, &a) return nil } From a54a230a083eaf68280a3e5607be8ee7eeae8a11 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 15 Jul 2022 14:01:07 +0200 Subject: [PATCH 098/715] tests: only activate merge on london rules (#25239) --- tests/state_test_util.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index f6d8e15001d8..d698b7c6fdd1 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -220,7 +220,8 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) context.GetHash = vmTestBlockHash context.BaseFee = baseFee - if t.json.Env.Random != nil { + context.Random = nil + if config.IsLondon(new(big.Int)) && t.json.Env.Random != nil { rnd := common.BigToHash(t.json.Env.Random) context.Random = &rnd context.Difficulty = big.NewInt(0) From e3df3d34cf96dcc8634911cec8d54052a577a25e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 15 Jul 2022 18:36:05 +0200 Subject: [PATCH 099/715] trie: fix 'gosimple' lint issue (#25309) --- trie/sync.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/trie/sync.go b/trie/sync.go index 7f4e67dbfecb..303fcbfa22e2 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -249,17 +249,16 @@ func (s *Sync) Missing(max int) ([]string, []common.Hash, []common.Hash) { s.queue.Pop() s.fetches[depth]++ - switch item.(type) { + switch item := item.(type) { case common.Hash: - codeHashes = append(codeHashes, item.(common.Hash)) + codeHashes = append(codeHashes, item) case string: - path := item.(string) - req, ok := s.nodeReqs[path] + req, ok := s.nodeReqs[item] if !ok { - log.Error("Missing node request", "path", path) + log.Error("Missing node request", "path", item) continue // System very wrong, shouldn't happen } - nodePaths = append(nodePaths, path) + nodePaths = append(nodePaths, item) nodeHashes = append(nodeHashes, req.hash) } } From a9ef135e2dd53682d106c6a2aede9187026cc1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=20=C4=90ANG?= Date: Fri, 15 Jul 2022 23:37:51 +0700 Subject: [PATCH 100/715] p2p/discover: apply netrestrict in discv5 response handler (#25304) --- p2p/discover/v5_udp.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 69aaefa27897..6ffa7bef7e1a 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -407,6 +407,9 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s if err := netutil.CheckRelayIP(c.node.IP(), node.IP()); err != nil { return nil, err } + if t.netrestrict != nil && !t.netrestrict.Contains(node.IP()) { + return nil, errors.New("not contained in netrestrict list") + } if c.node.UDP() <= 1024 { return nil, errLowPort } From a7d47ee77b5160ea5a13a7597f147e4895a39cba Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Mon, 18 Jul 2022 13:22:56 +0200 Subject: [PATCH 101/715] cmd/geth: remove redundant 0x in dbGet/dbDelete (#25315) --- cmd/geth/dbcmd.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 33e7efbef526..8b94609c14be 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -416,7 +416,7 @@ func dbGet(ctx *cli.Context) error { data, err := db.Get(key) if err != nil { - log.Info("Get operation failed", "key", fmt.Sprintf("0x%#x", key), "error", err) + log.Info("Get operation failed", "key", fmt.Sprintf("%#x", key), "error", err) return err } fmt.Printf("key %#x: %#x\n", key, data) @@ -444,7 +444,7 @@ func dbDelete(ctx *cli.Context) error { fmt.Printf("Previous value: %#x\n", data) } if err = db.Delete(key); err != nil { - log.Info("Delete operation returned an error", "key", fmt.Sprintf("0x%#x", key), "error", err) + log.Info("Delete operation returned an error", "key", fmt.Sprintf("%#x", key), "error", err) return err } return nil From e73e8bc706db3ecf72fa577348ac17f462ff453c Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 19 Jul 2022 11:44:48 +0200 Subject: [PATCH 102/715] accounts/abi: substitude arg%d to the range keyword (#25307) * accounts/abi: substitude arg%d to the range keyword * support more keywords * review feedback --- accounts/abi/bind/bind.go | 41 ++++++++++++++++++++++++++++++++-- accounts/abi/bind/bind_test.go | 39 +++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index a938e7dfcd85..dac43f70e234 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -43,6 +43,43 @@ const ( LangObjC ) +func isKeyWord(arg string) bool { + switch arg { + case "break": + case "case": + case "chan": + case "const": + case "continue": + case "default": + case "defer": + case "else": + case "fallthrough": + case "for": + case "func": + case "go": + case "goto": + case "if": + case "import": + case "interface": + case "iota": + case "map": + case "make": + case "new": + case "package": + case "range": + case "return": + case "select": + case "struct": + case "switch": + case "type": + case "var": + default: + return false + } + + return true +} + // Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant // to be used as is in client code, but rather as an intermediate struct which // enforces compile time type safety and naming convention opposed to having to @@ -114,7 +151,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] normalized.Inputs = make([]abi.Argument, len(original.Inputs)) copy(normalized.Inputs, original.Inputs) for j, input := range normalized.Inputs { - if input.Name == "" { + if input.Name == "" || isKeyWord(input.Name) { normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) } if hasStruct(input.Type) { @@ -158,7 +195,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] normalized.Inputs = make([]abi.Argument, len(original.Inputs)) copy(normalized.Inputs, original.Inputs) for j, input := range normalized.Inputs { - if input.Name == "" { + if input.Name == "" || isKeyWord(input.Name) { normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) } // Event is a bit special, we need to define event struct in binding, diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index b71d85ee6085..5fa803849df6 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -1971,7 +1971,7 @@ var bindTests = []struct { } } `, - bytecode: []string{`0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033`}, + bytecode: []string{"0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033"}, abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`}, imports: ` "math/big" @@ -2002,6 +2002,43 @@ var bindTests = []struct { } `, }, + { + name: "RangeKeyword", + contract: ` + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.4.22 <0.9.0; + contract keywordcontract { + function functionWithKeywordParameter(range uint256) public pure {} + } + `, + bytecode: []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"}, + abi: []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`}, + imports: ` + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/ethconfig" + `, + tester: ` + var ( + key, _ = crypto.GenerateKey() + user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) + sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil) + ) + _, tx, _, err := DeployRangeKeyword(user, sim) + if err != nil { + t.Fatalf("error deploying contract: %v", err) + } + sim.Commit() + + if _, err = bind.WaitDeployed(nil, sim, tx); err != nil { + t.Errorf("error deploying the contract: %v", err) + } + `, + }, } // Tests that packages generated by the binder can be successfully compiled and From 89b138cf2fe5c988eea8f2e74d042fc092849f8e Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 19 Jul 2022 14:50:17 +0200 Subject: [PATCH 103/715] params: Add Shanghai and Cancun blocks (#25305) * params: Add Shangai and Cancun blocks * fix copy/paste error Co-authored-by: Martin Holst Swende * fix typo in Shanghai name Co-authored-by: Martin Holst Swende --- params/config.go | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/params/config.go b/params/config.go index 26c5123e7129..1d530a8a6b6e 100644 --- a/params/config.go +++ b/params/config.go @@ -261,16 +261,16 @@ var ( // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil} + AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, new(EthashConfig), nil} // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} + AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, new(EthashConfig), nil} TestRules = TestChainConfig.Rules(new(big.Int), false) ) @@ -361,6 +361,8 @@ type ChainConfig struct { ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated) GrayGlacierBlock *big.Int `json:"grayGlacierBlock,omitempty"` // Eip-5133 (bomb delay) switch block (nil = no fork, 0 = already activated) MergeNetsplitBlock *big.Int `json:"mergeNetsplitBlock,omitempty"` // Virtual fork after The Merge to use as a network splitter + ShanghaiBlock *big.Int `json:"shanghaiBlock,omitempty"` // Shanghai switch block (nil = no fork, 0 = already on shanghai) + CancunBlock *big.Int `json:"cancunBlock,omitempty"` // Cancun switch block (nil = no fork, 0 = already on cancun) // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. @@ -444,6 +446,12 @@ func (c *ChainConfig) String() string { if c.GrayGlacierBlock != nil { banner += fmt.Sprintf(" - Gray Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md)\n", c.GrayGlacierBlock) } + if c.ShanghaiBlock != nil { + banner += fmt.Sprintf(" - Shanghai: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", c.ShanghaiBlock) + } + if c.CancunBlock != nil { + banner += fmt.Sprintf(" - Cancun: %-8v\n", c.CancunBlock) + } banner += "\n" // Add a special section for the merge as it's non-obvious @@ -539,6 +547,16 @@ func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *bi return parentTotalDiff.Cmp(c.TerminalTotalDifficulty) < 0 && totalDiff.Cmp(c.TerminalTotalDifficulty) >= 0 } +// IsShanghai returns whether num is either equal to the Shanghai fork block or greater. +func (c *ChainConfig) IsShanghai(num *big.Int) bool { + return isForked(c.ShanghaiBlock, num) +} + +// IsCancun returns whether num is either equal to the Cancun fork block or greater. +func (c *ChainConfig) IsCancun(num *big.Int) bool { + return isForked(c.CancunBlock, num) +} + // CheckCompatible checks whether scheduled fork transitions have been imported // with a mismatching chain configuration. func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError { @@ -582,6 +600,8 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "arrowGlacierBlock", block: c.ArrowGlacierBlock, optional: true}, {name: "grayGlacierBlock", block: c.GrayGlacierBlock, optional: true}, {name: "mergeNetsplitBlock", block: c.MergeNetsplitBlock, optional: true}, + {name: "shanghaiBlock", block: c.ShanghaiBlock, optional: true}, + {name: "cancunBlock", block: c.CancunBlock, optional: true}, } { if lastFork.name != "" { // Next one must be higher number @@ -660,6 +680,12 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, head) { return newCompatError("Merge netsplit fork block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock) } + if isForkIncompatible(c.ShanghaiBlock, newcfg.ShanghaiBlock, head) { + return newCompatError("Shanghai fork block", c.ShanghaiBlock, newcfg.ShanghaiBlock) + } + if isForkIncompatible(c.CancunBlock, newcfg.CancunBlock, head) { + return newCompatError("Cancun fork block", c.CancunBlock, newcfg.CancunBlock) + } return nil } @@ -728,7 +754,7 @@ type Rules struct { IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool - IsMerge bool + IsMerge, IsShanghai, isCancun bool } // Rules ensures c's ChainID is not nil. @@ -750,5 +776,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool) Rules { IsBerlin: c.IsBerlin(num), IsLondon: c.IsLondon(num), IsMerge: isMerge, + IsShanghai: c.IsShanghai(num), + isCancun: c.IsCancun(num), } } From a22fb936bbea5498d5ccd82b7b092e655c8cab71 Mon Sep 17 00:00:00 2001 From: Zachinquarantine Date: Thu, 21 Jul 2022 16:37:08 -0400 Subject: [PATCH 104/715] params: change Merge config to print simpler message This fixes #25366 --- params/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/config.go b/params/config.go index 1d530a8a6b6e..976007e7670d 100644 --- a/params/config.go +++ b/params/config.go @@ -456,7 +456,7 @@ func (c *ChainConfig) String() string { // Add a special section for the merge as it's non-obvious if c.TerminalTotalDifficulty == nil { - banner += "Merge not configured!\n" + banner += "The Merge is not yet available for this network!\n" banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)" } else { banner += "Merge configured:\n" From b214c499523a510cf0d97957e447eebbc95c5d94 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Fri, 22 Jul 2022 01:51:01 -0600 Subject: [PATCH 105/715] cmd/puppeth: remove support for exporting non-Geth genesis configurations (#25329) * cmd/puppeth: remove support for exporting non-Geth genesis configurations * remove unused function --- cmd/puppeth/genesis.go | 626 -------------------------------- cmd/puppeth/genesis_test.go | 95 ----- cmd/puppeth/module_dashboard.go | 31 -- cmd/puppeth/wizard_genesis.go | 31 +- 4 files changed, 2 insertions(+), 781 deletions(-) delete mode 100644 cmd/puppeth/genesis.go delete mode 100644 cmd/puppeth/genesis_test.go diff --git a/cmd/puppeth/genesis.go b/cmd/puppeth/genesis.go deleted file mode 100644 index ef1f977bf09f..000000000000 --- a/cmd/puppeth/genesis.go +++ /dev/null @@ -1,626 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "errors" - "math" - "math/big" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - math2 "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" -) - -// alethGenesisSpec represents the genesis specification format used by the -// C++ Ethereum implementation. -type alethGenesisSpec struct { - SealEngine string `json:"sealEngine"` - Params struct { - AccountStartNonce math2.HexOrDecimal64 `json:"accountStartNonce"` - MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"` - HomesteadForkBlock *hexutil.Big `json:"homesteadForkBlock,omitempty"` - DaoHardforkBlock math2.HexOrDecimal64 `json:"daoHardforkBlock"` - EIP150ForkBlock *hexutil.Big `json:"EIP150ForkBlock,omitempty"` - EIP158ForkBlock *hexutil.Big `json:"EIP158ForkBlock,omitempty"` - ByzantiumForkBlock *hexutil.Big `json:"byzantiumForkBlock,omitempty"` - ConstantinopleForkBlock *hexutil.Big `json:"constantinopleForkBlock,omitempty"` - ConstantinopleFixForkBlock *hexutil.Big `json:"constantinopleFixForkBlock,omitempty"` - IstanbulForkBlock *hexutil.Big `json:"istanbulForkBlock,omitempty"` - MinGasLimit hexutil.Uint64 `json:"minGasLimit"` - MaxGasLimit hexutil.Uint64 `json:"maxGasLimit"` - TieBreakingGas bool `json:"tieBreakingGas"` - GasLimitBoundDivisor math2.HexOrDecimal64 `json:"gasLimitBoundDivisor"` - MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"` - DifficultyBoundDivisor *math2.HexOrDecimal256 `json:"difficultyBoundDivisor"` - DurationLimit *math2.HexOrDecimal256 `json:"durationLimit"` - BlockReward *hexutil.Big `json:"blockReward"` - NetworkID hexutil.Uint64 `json:"networkID"` - ChainID hexutil.Uint64 `json:"chainID"` - AllowFutureBlocks bool `json:"allowFutureBlocks"` - } `json:"params"` - - Genesis struct { - Nonce types.BlockNonce `json:"nonce"` - Difficulty *hexutil.Big `json:"difficulty"` - MixHash common.Hash `json:"mixHash"` - Author common.Address `json:"author"` - Timestamp hexutil.Uint64 `json:"timestamp"` - ParentHash common.Hash `json:"parentHash"` - ExtraData hexutil.Bytes `json:"extraData"` - GasLimit hexutil.Uint64 `json:"gasLimit"` - } `json:"genesis"` - - Accounts map[common.UnprefixedAddress]*alethGenesisSpecAccount `json:"accounts"` -} - -// alethGenesisSpecAccount is the prefunded genesis account and/or precompiled -// contract definition. -type alethGenesisSpecAccount struct { - Balance *math2.HexOrDecimal256 `json:"balance,omitempty"` - Nonce uint64 `json:"nonce,omitempty"` - Precompiled *alethGenesisSpecBuiltin `json:"precompiled,omitempty"` -} - -// alethGenesisSpecBuiltin is the precompiled contract definition. -type alethGenesisSpecBuiltin struct { - Name string `json:"name,omitempty"` - StartingBlock *hexutil.Big `json:"startingBlock,omitempty"` - Linear *alethGenesisSpecLinearPricing `json:"linear,omitempty"` -} - -type alethGenesisSpecLinearPricing struct { - Base uint64 `json:"base"` - Word uint64 `json:"word"` -} - -// newAlethGenesisSpec converts a go-ethereum genesis block into a Aleth-specific -// chain specification format. -func newAlethGenesisSpec(network string, genesis *core.Genesis) (*alethGenesisSpec, error) { - // Only ethash is currently supported between go-ethereum and aleth - if genesis.Config.Ethash == nil { - return nil, errors.New("unsupported consensus engine") - } - // Reconstruct the chain spec in Aleth format - spec := &alethGenesisSpec{ - SealEngine: "Ethash", - } - // Some defaults - spec.Params.AccountStartNonce = 0 - spec.Params.TieBreakingGas = false - spec.Params.AllowFutureBlocks = false - - // Dao hardfork block is a special one. The fork block is listed as 0 in the - // config but aleth will sync with ETC clients up until the actual dao hard - // fork block. - spec.Params.DaoHardforkBlock = 0 - - if num := genesis.Config.HomesteadBlock; num != nil { - spec.Params.HomesteadForkBlock = (*hexutil.Big)(num) - } - if num := genesis.Config.EIP150Block; num != nil { - spec.Params.EIP150ForkBlock = (*hexutil.Big)(num) - } - if num := genesis.Config.EIP158Block; num != nil { - spec.Params.EIP158ForkBlock = (*hexutil.Big)(num) - } - if num := genesis.Config.ByzantiumBlock; num != nil { - spec.Params.ByzantiumForkBlock = (*hexutil.Big)(num) - } - if num := genesis.Config.ConstantinopleBlock; num != nil { - spec.Params.ConstantinopleForkBlock = (*hexutil.Big)(num) - } - if num := genesis.Config.PetersburgBlock; num != nil { - spec.Params.ConstantinopleFixForkBlock = (*hexutil.Big)(num) - } - if num := genesis.Config.IstanbulBlock; num != nil { - spec.Params.IstanbulForkBlock = (*hexutil.Big)(num) - } - spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64()) - spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64()) - spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize) - spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit) - spec.Params.MaxGasLimit = (hexutil.Uint64)(math.MaxInt64) - spec.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty) - spec.Params.DifficultyBoundDivisor = (*math2.HexOrDecimal256)(params.DifficultyBoundDivisor) - spec.Params.GasLimitBoundDivisor = (math2.HexOrDecimal64)(params.GasLimitBoundDivisor) - spec.Params.DurationLimit = (*math2.HexOrDecimal256)(params.DurationLimit) - spec.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward) - - spec.Genesis.Nonce = types.EncodeNonce(genesis.Nonce) - spec.Genesis.MixHash = genesis.Mixhash - spec.Genesis.Difficulty = (*hexutil.Big)(genesis.Difficulty) - spec.Genesis.Author = genesis.Coinbase - spec.Genesis.Timestamp = (hexutil.Uint64)(genesis.Timestamp) - spec.Genesis.ParentHash = genesis.ParentHash - spec.Genesis.ExtraData = genesis.ExtraData - spec.Genesis.GasLimit = (hexutil.Uint64)(genesis.GasLimit) - - for address, account := range genesis.Alloc { - spec.setAccount(address, account) - } - - spec.setPrecompile(1, &alethGenesisSpecBuiltin{Name: "ecrecover", - Linear: &alethGenesisSpecLinearPricing{Base: 3000}}) - spec.setPrecompile(2, &alethGenesisSpecBuiltin{Name: "sha256", - Linear: &alethGenesisSpecLinearPricing{Base: 60, Word: 12}}) - spec.setPrecompile(3, &alethGenesisSpecBuiltin{Name: "ripemd160", - Linear: &alethGenesisSpecLinearPricing{Base: 600, Word: 120}}) - spec.setPrecompile(4, &alethGenesisSpecBuiltin{Name: "identity", - Linear: &alethGenesisSpecLinearPricing{Base: 15, Word: 3}}) - if genesis.Config.ByzantiumBlock != nil { - spec.setPrecompile(5, &alethGenesisSpecBuiltin{Name: "modexp", - StartingBlock: (*hexutil.Big)(genesis.Config.ByzantiumBlock)}) - spec.setPrecompile(6, &alethGenesisSpecBuiltin{Name: "alt_bn128_G1_add", - StartingBlock: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - Linear: &alethGenesisSpecLinearPricing{Base: 500}}) - spec.setPrecompile(7, &alethGenesisSpecBuiltin{Name: "alt_bn128_G1_mul", - StartingBlock: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - Linear: &alethGenesisSpecLinearPricing{Base: 40000}}) - spec.setPrecompile(8, &alethGenesisSpecBuiltin{Name: "alt_bn128_pairing_product", - StartingBlock: (*hexutil.Big)(genesis.Config.ByzantiumBlock)}) - } - if genesis.Config.IstanbulBlock != nil { - if genesis.Config.ByzantiumBlock == nil { - return nil, errors.New("invalid genesis, istanbul fork is enabled while byzantium is not") - } - spec.setPrecompile(6, &alethGenesisSpecBuiltin{ - Name: "alt_bn128_G1_add", - StartingBlock: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - }) // Aleth hardcoded the gas policy - spec.setPrecompile(7, &alethGenesisSpecBuiltin{ - Name: "alt_bn128_G1_mul", - StartingBlock: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - }) // Aleth hardcoded the gas policy - spec.setPrecompile(9, &alethGenesisSpecBuiltin{ - Name: "blake2_compression", - StartingBlock: (*hexutil.Big)(genesis.Config.IstanbulBlock), - }) - } - return spec, nil -} - -func (spec *alethGenesisSpec) setPrecompile(address byte, data *alethGenesisSpecBuiltin) { - if spec.Accounts == nil { - spec.Accounts = make(map[common.UnprefixedAddress]*alethGenesisSpecAccount) - } - addr := common.UnprefixedAddress(common.BytesToAddress([]byte{address})) - if _, exist := spec.Accounts[addr]; !exist { - spec.Accounts[addr] = &alethGenesisSpecAccount{} - } - spec.Accounts[addr].Precompiled = data -} - -func (spec *alethGenesisSpec) setAccount(address common.Address, account core.GenesisAccount) { - if spec.Accounts == nil { - spec.Accounts = make(map[common.UnprefixedAddress]*alethGenesisSpecAccount) - } - - a, exist := spec.Accounts[common.UnprefixedAddress(address)] - if !exist { - a = &alethGenesisSpecAccount{} - spec.Accounts[common.UnprefixedAddress(address)] = a - } - a.Balance = (*math2.HexOrDecimal256)(account.Balance) - a.Nonce = account.Nonce - -} - -// parityChainSpec is the chain specification format used by Parity. -type parityChainSpec struct { - Name string `json:"name"` - Datadir string `json:"dataDir"` - Engine struct { - Ethash struct { - Params struct { - MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"` - DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"` - DurationLimit *hexutil.Big `json:"durationLimit"` - BlockReward map[string]string `json:"blockReward"` - DifficultyBombDelays map[string]string `json:"difficultyBombDelays"` - HomesteadTransition hexutil.Uint64 `json:"homesteadTransition"` - EIP100bTransition hexutil.Uint64 `json:"eip100bTransition"` - } `json:"params"` - } `json:"Ethash"` - } `json:"engine"` - - Params struct { - AccountStartNonce hexutil.Uint64 `json:"accountStartNonce"` - MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"` - MinGasLimit hexutil.Uint64 `json:"minGasLimit"` - GasLimitBoundDivisor math2.HexOrDecimal64 `json:"gasLimitBoundDivisor"` - NetworkID hexutil.Uint64 `json:"networkID"` - ChainID hexutil.Uint64 `json:"chainID"` - MaxCodeSize hexutil.Uint64 `json:"maxCodeSize"` - MaxCodeSizeTransition hexutil.Uint64 `json:"maxCodeSizeTransition"` - EIP98Transition hexutil.Uint64 `json:"eip98Transition"` - EIP150Transition hexutil.Uint64 `json:"eip150Transition"` - EIP160Transition hexutil.Uint64 `json:"eip160Transition"` - EIP161abcTransition hexutil.Uint64 `json:"eip161abcTransition"` - EIP161dTransition hexutil.Uint64 `json:"eip161dTransition"` - EIP155Transition hexutil.Uint64 `json:"eip155Transition"` - EIP140Transition hexutil.Uint64 `json:"eip140Transition"` - EIP211Transition hexutil.Uint64 `json:"eip211Transition"` - EIP214Transition hexutil.Uint64 `json:"eip214Transition"` - EIP658Transition hexutil.Uint64 `json:"eip658Transition"` - EIP145Transition hexutil.Uint64 `json:"eip145Transition"` - EIP1014Transition hexutil.Uint64 `json:"eip1014Transition"` - EIP1052Transition hexutil.Uint64 `json:"eip1052Transition"` - EIP1283Transition hexutil.Uint64 `json:"eip1283Transition"` - EIP1283DisableTransition hexutil.Uint64 `json:"eip1283DisableTransition"` - EIP1283ReenableTransition hexutil.Uint64 `json:"eip1283ReenableTransition"` - EIP1344Transition hexutil.Uint64 `json:"eip1344Transition"` - EIP1884Transition hexutil.Uint64 `json:"eip1884Transition"` - EIP2028Transition hexutil.Uint64 `json:"eip2028Transition"` - } `json:"params"` - - Genesis struct { - Seal struct { - Ethereum struct { - Nonce types.BlockNonce `json:"nonce"` - MixHash hexutil.Bytes `json:"mixHash"` - } `json:"ethereum"` - } `json:"seal"` - - Difficulty *hexutil.Big `json:"difficulty"` - Author common.Address `json:"author"` - Timestamp hexutil.Uint64 `json:"timestamp"` - ParentHash common.Hash `json:"parentHash"` - ExtraData hexutil.Bytes `json:"extraData"` - GasLimit hexutil.Uint64 `json:"gasLimit"` - } `json:"genesis"` - - Nodes []string `json:"nodes"` - Accounts map[common.UnprefixedAddress]*parityChainSpecAccount `json:"accounts"` -} - -// parityChainSpecAccount is the prefunded genesis account and/or precompiled -// contract definition. -type parityChainSpecAccount struct { - Balance math2.HexOrDecimal256 `json:"balance"` - Nonce math2.HexOrDecimal64 `json:"nonce,omitempty"` - Builtin *parityChainSpecBuiltin `json:"builtin,omitempty"` -} - -// parityChainSpecBuiltin is the precompiled contract definition. -type parityChainSpecBuiltin struct { - Name string `json:"name"` // Each builtin should has it own name - Pricing interface{} `json:"pricing"` // Each builtin should has it own price strategy - ActivateAt *hexutil.Big `json:"activate_at,omitempty"` // ActivateAt can't be omitted if empty, default means no fork -} - -// parityChainSpecPricing represents the different pricing models that builtin -// contracts might advertise using. -type parityChainSpecPricing struct { - Linear *parityChainSpecLinearPricing `json:"linear,omitempty"` - ModExp *parityChainSpecModExpPricing `json:"modexp,omitempty"` - - // Before the https://github.com/paritytech/parity-ethereum/pull/11039, - // Parity uses this format to config bn pairing price policy. - AltBnPairing *parityChainSepcAltBnPairingPricing `json:"alt_bn128_pairing,omitempty"` - - // Blake2F is the price per round of Blake2 compression - Blake2F *parityChainSpecBlakePricing `json:"blake2_f,omitempty"` -} - -type parityChainSpecLinearPricing struct { - Base uint64 `json:"base"` - Word uint64 `json:"word"` -} - -type parityChainSpecModExpPricing struct { - Divisor uint64 `json:"divisor"` -} - -// parityChainSpecAltBnConstOperationPricing defines the price -// policy for bn const operation(used after istanbul) -type parityChainSpecAltBnConstOperationPricing struct { - Price uint64 `json:"price"` -} - -// parityChainSepcAltBnPairingPricing defines the price policy -// for bn pairing. -type parityChainSepcAltBnPairingPricing struct { - Base uint64 `json:"base"` - Pair uint64 `json:"pair"` -} - -// parityChainSpecBlakePricing defines the price policy for blake2 f -// compression. -type parityChainSpecBlakePricing struct { - GasPerRound uint64 `json:"gas_per_round"` -} - -type parityChainSpecAlternativePrice struct { - AltBnConstOperationPrice *parityChainSpecAltBnConstOperationPricing `json:"alt_bn128_const_operations,omitempty"` - AltBnPairingPrice *parityChainSepcAltBnPairingPricing `json:"alt_bn128_pairing,omitempty"` -} - -// parityChainSpecVersionedPricing represents a single version price policy. -type parityChainSpecVersionedPricing struct { - Price *parityChainSpecAlternativePrice `json:"price,omitempty"` - Info string `json:"info,omitempty"` -} - -// newParityChainSpec converts a go-ethereum genesis block into a Parity specific -// chain specification format. -func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []string) (*parityChainSpec, error) { - // Only ethash is currently supported between go-ethereum and Parity - if genesis.Config.Ethash == nil { - return nil, errors.New("unsupported consensus engine") - } - // Reconstruct the chain spec in Parity's format - spec := &parityChainSpec{ - Name: network, - Nodes: bootnodes, - Datadir: strings.ToLower(network), - } - spec.Engine.Ethash.Params.BlockReward = make(map[string]string) - spec.Engine.Ethash.Params.DifficultyBombDelays = make(map[string]string) - // Frontier - spec.Engine.Ethash.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty) - spec.Engine.Ethash.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor) - spec.Engine.Ethash.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit) - spec.Engine.Ethash.Params.BlockReward["0x0"] = hexutil.EncodeBig(ethash.FrontierBlockReward) - - // Homestead - spec.Engine.Ethash.Params.HomesteadTransition = hexutil.Uint64(genesis.Config.HomesteadBlock.Uint64()) - - // Tangerine Whistle : 150 - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-608.md - spec.Params.EIP150Transition = hexutil.Uint64(genesis.Config.EIP150Block.Uint64()) - - // Spurious Dragon: 155, 160, 161, 170 - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-607.md - spec.Params.EIP155Transition = hexutil.Uint64(genesis.Config.EIP155Block.Uint64()) - spec.Params.EIP160Transition = hexutil.Uint64(genesis.Config.EIP155Block.Uint64()) - spec.Params.EIP161abcTransition = hexutil.Uint64(genesis.Config.EIP158Block.Uint64()) - spec.Params.EIP161dTransition = hexutil.Uint64(genesis.Config.EIP158Block.Uint64()) - - // Byzantium - if num := genesis.Config.ByzantiumBlock; num != nil { - spec.setByzantium(num) - } - // Constantinople - if num := genesis.Config.ConstantinopleBlock; num != nil { - spec.setConstantinople(num) - } - // ConstantinopleFix (remove eip-1283) - if num := genesis.Config.PetersburgBlock; num != nil { - spec.setConstantinopleFix(num) - } - // Istanbul - if num := genesis.Config.IstanbulBlock; num != nil { - spec.setIstanbul(num) - } - spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize) - spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit) - spec.Params.GasLimitBoundDivisor = (math2.HexOrDecimal64)(params.GasLimitBoundDivisor) - spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64()) - spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64()) - spec.Params.MaxCodeSize = params.MaxCodeSize - // geth has it set from zero - spec.Params.MaxCodeSizeTransition = 0 - - // Disable this one - spec.Params.EIP98Transition = math.MaxInt64 - - spec.Genesis.Seal.Ethereum.Nonce = types.EncodeNonce(genesis.Nonce) - spec.Genesis.Seal.Ethereum.MixHash = genesis.Mixhash[:] - spec.Genesis.Difficulty = (*hexutil.Big)(genesis.Difficulty) - spec.Genesis.Author = genesis.Coinbase - spec.Genesis.Timestamp = (hexutil.Uint64)(genesis.Timestamp) - spec.Genesis.ParentHash = genesis.ParentHash - spec.Genesis.ExtraData = genesis.ExtraData - spec.Genesis.GasLimit = (hexutil.Uint64)(genesis.GasLimit) - - spec.Accounts = make(map[common.UnprefixedAddress]*parityChainSpecAccount) - for address, account := range genesis.Alloc { - bal := math2.HexOrDecimal256(*account.Balance) - - spec.Accounts[common.UnprefixedAddress(address)] = &parityChainSpecAccount{ - Balance: bal, - Nonce: math2.HexOrDecimal64(account.Nonce), - } - } - spec.setPrecompile(1, &parityChainSpecBuiltin{Name: "ecrecover", - Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 3000}}}) - - spec.setPrecompile(2, &parityChainSpecBuiltin{ - Name: "sha256", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 60, Word: 12}}, - }) - spec.setPrecompile(3, &parityChainSpecBuiltin{ - Name: "ripemd160", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 600, Word: 120}}, - }) - spec.setPrecompile(4, &parityChainSpecBuiltin{ - Name: "identity", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 15, Word: 3}}, - }) - if genesis.Config.ByzantiumBlock != nil { - spec.setPrecompile(5, &parityChainSpecBuiltin{ - Name: "modexp", - ActivateAt: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - Pricing: &parityChainSpecPricing{ - ModExp: &parityChainSpecModExpPricing{Divisor: 20}, - }, - }) - spec.setPrecompile(6, &parityChainSpecBuiltin{ - Name: "alt_bn128_add", - ActivateAt: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - Pricing: &parityChainSpecPricing{ - Linear: &parityChainSpecLinearPricing{Base: 500, Word: 0}, - }, - }) - spec.setPrecompile(7, &parityChainSpecBuiltin{ - Name: "alt_bn128_mul", - ActivateAt: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - Pricing: &parityChainSpecPricing{ - Linear: &parityChainSpecLinearPricing{Base: 40000, Word: 0}, - }, - }) - spec.setPrecompile(8, &parityChainSpecBuiltin{ - Name: "alt_bn128_pairing", - ActivateAt: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - Pricing: &parityChainSpecPricing{ - AltBnPairing: &parityChainSepcAltBnPairingPricing{Base: 100000, Pair: 80000}, - }, - }) - } - if genesis.Config.IstanbulBlock != nil { - if genesis.Config.ByzantiumBlock == nil { - return nil, errors.New("invalid genesis, istanbul fork is enabled while byzantium is not") - } - spec.setPrecompile(6, &parityChainSpecBuiltin{ - Name: "alt_bn128_add", - ActivateAt: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - Pricing: map[*hexutil.Big]*parityChainSpecVersionedPricing{ - (*hexutil.Big)(big.NewInt(0)): { - Price: &parityChainSpecAlternativePrice{ - AltBnConstOperationPrice: &parityChainSpecAltBnConstOperationPricing{Price: 500}, - }, - }, - (*hexutil.Big)(genesis.Config.IstanbulBlock): { - Price: &parityChainSpecAlternativePrice{ - AltBnConstOperationPrice: &parityChainSpecAltBnConstOperationPricing{Price: 150}, - }, - }, - }, - }) - spec.setPrecompile(7, &parityChainSpecBuiltin{ - Name: "alt_bn128_mul", - ActivateAt: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - Pricing: map[*hexutil.Big]*parityChainSpecVersionedPricing{ - (*hexutil.Big)(big.NewInt(0)): { - Price: &parityChainSpecAlternativePrice{ - AltBnConstOperationPrice: &parityChainSpecAltBnConstOperationPricing{Price: 40000}, - }, - }, - (*hexutil.Big)(genesis.Config.IstanbulBlock): { - Price: &parityChainSpecAlternativePrice{ - AltBnConstOperationPrice: &parityChainSpecAltBnConstOperationPricing{Price: 6000}, - }, - }, - }, - }) - spec.setPrecompile(8, &parityChainSpecBuiltin{ - Name: "alt_bn128_pairing", - ActivateAt: (*hexutil.Big)(genesis.Config.ByzantiumBlock), - Pricing: map[*hexutil.Big]*parityChainSpecVersionedPricing{ - (*hexutil.Big)(big.NewInt(0)): { - Price: &parityChainSpecAlternativePrice{ - AltBnPairingPrice: &parityChainSepcAltBnPairingPricing{Base: 100000, Pair: 80000}, - }, - }, - (*hexutil.Big)(genesis.Config.IstanbulBlock): { - Price: &parityChainSpecAlternativePrice{ - AltBnPairingPrice: &parityChainSepcAltBnPairingPricing{Base: 45000, Pair: 34000}, - }, - }, - }, - }) - spec.setPrecompile(9, &parityChainSpecBuiltin{ - Name: "blake2_f", - ActivateAt: (*hexutil.Big)(genesis.Config.IstanbulBlock), - Pricing: &parityChainSpecPricing{ - Blake2F: &parityChainSpecBlakePricing{GasPerRound: 1}, - }, - }) - } - return spec, nil -} - -func (spec *parityChainSpec) setPrecompile(address byte, data *parityChainSpecBuiltin) { - if spec.Accounts == nil { - spec.Accounts = make(map[common.UnprefixedAddress]*parityChainSpecAccount) - } - a := common.UnprefixedAddress(common.BytesToAddress([]byte{address})) - if _, exist := spec.Accounts[a]; !exist { - spec.Accounts[a] = &parityChainSpecAccount{} - } - spec.Accounts[a].Builtin = data -} - -func (spec *parityChainSpec) setByzantium(num *big.Int) { - spec.Engine.Ethash.Params.BlockReward[hexutil.EncodeBig(num)] = hexutil.EncodeBig(ethash.ByzantiumBlockReward) - spec.Engine.Ethash.Params.DifficultyBombDelays[hexutil.EncodeBig(num)] = hexutil.EncodeUint64(3000000) - n := hexutil.Uint64(num.Uint64()) - spec.Engine.Ethash.Params.EIP100bTransition = n - spec.Params.EIP140Transition = n - spec.Params.EIP211Transition = n - spec.Params.EIP214Transition = n - spec.Params.EIP658Transition = n -} - -func (spec *parityChainSpec) setConstantinople(num *big.Int) { - spec.Engine.Ethash.Params.BlockReward[hexutil.EncodeBig(num)] = hexutil.EncodeBig(ethash.ConstantinopleBlockReward) - spec.Engine.Ethash.Params.DifficultyBombDelays[hexutil.EncodeBig(num)] = hexutil.EncodeUint64(2000000) - n := hexutil.Uint64(num.Uint64()) - spec.Params.EIP145Transition = n - spec.Params.EIP1014Transition = n - spec.Params.EIP1052Transition = n - spec.Params.EIP1283Transition = n -} - -func (spec *parityChainSpec) setConstantinopleFix(num *big.Int) { - spec.Params.EIP1283DisableTransition = hexutil.Uint64(num.Uint64()) -} - -func (spec *parityChainSpec) setIstanbul(num *big.Int) { - spec.Params.EIP1344Transition = hexutil.Uint64(num.Uint64()) - spec.Params.EIP1884Transition = hexutil.Uint64(num.Uint64()) - spec.Params.EIP2028Transition = hexutil.Uint64(num.Uint64()) - spec.Params.EIP1283ReenableTransition = hexutil.Uint64(num.Uint64()) -} - -// pyEthereumGenesisSpec represents the genesis specification format used by the -// Python Ethereum implementation. -type pyEthereumGenesisSpec struct { - Nonce types.BlockNonce `json:"nonce"` - Timestamp hexutil.Uint64 `json:"timestamp"` - ExtraData hexutil.Bytes `json:"extraData"` - GasLimit hexutil.Uint64 `json:"gasLimit"` - Difficulty *hexutil.Big `json:"difficulty"` - Mixhash common.Hash `json:"mixhash"` - Coinbase common.Address `json:"coinbase"` - Alloc core.GenesisAlloc `json:"alloc"` - ParentHash common.Hash `json:"parentHash"` -} - -// newPyEthereumGenesisSpec converts a go-ethereum genesis block into a Parity specific -// chain specification format. -func newPyEthereumGenesisSpec(network string, genesis *core.Genesis) (*pyEthereumGenesisSpec, error) { - // Only ethash is currently supported between go-ethereum and pyethereum - if genesis.Config.Ethash == nil { - return nil, errors.New("unsupported consensus engine") - } - spec := &pyEthereumGenesisSpec{ - Nonce: types.EncodeNonce(genesis.Nonce), - Timestamp: (hexutil.Uint64)(genesis.Timestamp), - ExtraData: genesis.ExtraData, - GasLimit: (hexutil.Uint64)(genesis.GasLimit), - Difficulty: (*hexutil.Big)(genesis.Difficulty), - Mixhash: genesis.Mixhash, - Coinbase: genesis.Coinbase, - Alloc: genesis.Alloc, - ParentHash: genesis.ParentHash, - } - return spec, nil -} diff --git a/cmd/puppeth/genesis_test.go b/cmd/puppeth/genesis_test.go deleted file mode 100644 index 605c1070a80c..000000000000 --- a/cmd/puppeth/genesis_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "encoding/json" - "os" - "reflect" - "strings" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/ethereum/go-ethereum/core" -) - -// Tests the go-ethereum to Aleth chainspec conversion for the Stureby testnet. -func TestAlethSturebyConverter(t *testing.T) { - blob, err := os.ReadFile("testdata/stureby_geth.json") - if err != nil { - t.Fatalf("could not read file: %v", err) - } - var genesis core.Genesis - if err := json.Unmarshal(blob, &genesis); err != nil { - t.Fatalf("failed parsing genesis: %v", err) - } - spec, err := newAlethGenesisSpec("stureby", &genesis) - if err != nil { - t.Fatalf("failed creating chainspec: %v", err) - } - - expBlob, err := os.ReadFile("testdata/stureby_aleth.json") - if err != nil { - t.Fatalf("could not read file: %v", err) - } - expspec := &alethGenesisSpec{} - if err := json.Unmarshal(expBlob, expspec); err != nil { - t.Fatalf("failed parsing genesis: %v", err) - } - if !reflect.DeepEqual(expspec, spec) { - t.Errorf("chainspec mismatch") - c := spew.ConfigState{ - DisablePointerAddresses: true, - SortKeys: true, - } - exp := strings.Split(c.Sdump(expspec), "\n") - got := strings.Split(c.Sdump(spec), "\n") - for i := 0; i < len(exp) && i < len(got); i++ { - if exp[i] != got[i] { - t.Logf("got: %v\nexp: %v\n", exp[i], got[i]) - } - } - } -} - -// Tests the go-ethereum to Parity chainspec conversion for the Stureby testnet. -func TestParitySturebyConverter(t *testing.T) { - blob, err := os.ReadFile("testdata/stureby_geth.json") - if err != nil { - t.Fatalf("could not read file: %v", err) - } - var genesis core.Genesis - if err := json.Unmarshal(blob, &genesis); err != nil { - t.Fatalf("failed parsing genesis: %v", err) - } - spec, err := newParityChainSpec("stureby", &genesis, []string{}) - if err != nil { - t.Fatalf("failed creating chainspec: %v", err) - } - enc, err := json.MarshalIndent(spec, "", " ") - if err != nil { - t.Fatalf("failed encoding chainspec: %v", err) - } - expBlob, err := os.ReadFile("testdata/stureby_parity.json") - if err != nil { - t.Fatalf("could not read file: %v", err) - } - if !bytes.Equal(expBlob, enc) { - t.Fatalf("chainspec mismatch") - } -} diff --git a/cmd/puppeth/module_dashboard.go b/cmd/puppeth/module_dashboard.go index 35cfada66fd3..fbbbb66501a7 100644 --- a/cmd/puppeth/module_dashboard.go +++ b/cmd/puppeth/module_dashboard.go @@ -18,7 +18,6 @@ package main import ( "bytes" - "encoding/json" "fmt" "html/template" "math/rand" @@ -582,36 +581,6 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da // Marshal the genesis spec files for go-ethereum and all the other clients genesis, _ := conf.Genesis.MarshalJSON() files[filepath.Join(workdir, network+".json")] = genesis - - if conf.Genesis.Config.Ethash != nil { - cppSpec, err := newAlethGenesisSpec(network, conf.Genesis) - if err != nil { - return nil, err - } - cppSpecJSON, _ := json.Marshal(cppSpec) - files[filepath.Join(workdir, network+"-cpp.json")] = cppSpecJSON - - harmonySpecJSON, _ := conf.Genesis.MarshalJSON() - files[filepath.Join(workdir, network+"-harmony.json")] = harmonySpecJSON - - paritySpec, err := newParityChainSpec(network, conf.Genesis, conf.bootnodes) - if err != nil { - return nil, err - } - paritySpecJSON, _ := json.Marshal(paritySpec) - files[filepath.Join(workdir, network+"-parity.json")] = paritySpecJSON - - pyethSpec, err := newPyEthereumGenesisSpec(network, conf.Genesis) - if err != nil { - return nil, err - } - pyethSpecJSON, _ := json.Marshal(pyethSpec) - files[filepath.Join(workdir, network+"-python.json")] = pyethSpecJSON - } else { - for _, client := range []string{"cpp", "harmony", "parity", "python"} { - files[filepath.Join(workdir, network+"-"+client+".json")] = []byte{} - } - } files[filepath.Join(workdir, "puppeth.png")] = dashboardMascot // Upload the deployment files to the remote server (and clean up afterwards) diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index cb056ab13356..ac17bc7b271c 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -250,8 +250,8 @@ func (w *wizard) manageGenesis() { case "2": // Save whatever genesis configuration we currently have fmt.Println() - fmt.Printf("Which folder to save the genesis specs into? (default = current)\n") - fmt.Printf(" Will create %s.json, %s-aleth.json, %s-harmony.json, %s-parity.json\n", w.network, w.network, w.network, w.network) + fmt.Printf("Which folder to save the genesis spec into? (default = current)\n") + fmt.Printf(" Will create %s.json\n", w.network) folder := w.readDefaultString(".") if err := os.MkdirAll(folder, 0755); err != nil { @@ -268,21 +268,6 @@ func (w *wizard) manageGenesis() { } log.Info("Saved native genesis chain spec", "path", gethJson) - // Export the genesis spec used by Aleth (formerly C++ Ethereum) - if spec, err := newAlethGenesisSpec(w.network, w.conf.Genesis); err != nil { - log.Error("Failed to create Aleth chain spec", "err", err) - } else { - saveGenesis(folder, w.network, "aleth", spec) - } - // Export the genesis spec used by Parity - if spec, err := newParityChainSpec(w.network, w.conf.Genesis, []string{}); err != nil { - log.Error("Failed to create Parity chain spec", "err", err) - } else { - saveGenesis(folder, w.network, "parity", spec) - } - // Export the genesis spec used by Harmony (formerly EthereumJ) - saveGenesis(folder, w.network, "harmony", w.conf.Genesis) - case "3": // Make sure we don't have any services running if len(w.conf.servers()) > 0 { @@ -298,15 +283,3 @@ func (w *wizard) manageGenesis() { return } } - -// saveGenesis JSON encodes an arbitrary genesis spec into a pre-defined file. -func saveGenesis(folder, network, client string, spec interface{}) { - path := filepath.Join(folder, fmt.Sprintf("%s-%s.json", network, client)) - - out, _ := json.MarshalIndent(spec, "", " ") - if err := os.WriteFile(path, out, 0644); err != nil { - log.Error("Failed to save genesis file", "client", client, "err", err) - return - } - log.Info("Saved genesis chain spec", "client", client, "path", path) -} From 1764f8f5590bdde7b823e2bbf42f77776f354688 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 22 Jul 2022 09:52:12 +0200 Subject: [PATCH 106/715] params: set goerli TTD to 10_790_000 (#25324) --- params/config.go | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/params/config.go b/params/config.go index 1d530a8a6b6e..a4159ed24593 100644 --- a/params/config.go +++ b/params/config.go @@ -214,21 +214,22 @@ var ( // GoerliChainConfig contains the chain parameters to run a node on the Görli test network. GoerliChainConfig = &ChainConfig{ - ChainID: big.NewInt(5), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(1_561_651), - MuirGlacierBlock: nil, - BerlinBlock: big.NewInt(4_460_644), - LondonBlock: big.NewInt(5_062_605), - ArrowGlacierBlock: nil, + ChainID: big.NewInt(5), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(1_561_651), + MuirGlacierBlock: nil, + BerlinBlock: big.NewInt(4_460_644), + LondonBlock: big.NewInt(5_062_605), + ArrowGlacierBlock: nil, + TerminalTotalDifficulty: big.NewInt(10_790_000), Clique: &CliqueConfig{ Period: 15, Epoch: 30000, From ba3919cac609134dc81b64250fc09c56dd65b46d Mon Sep 17 00:00:00 2001 From: Nikhil Suri Date: Fri, 22 Jul 2022 00:53:35 -0700 Subject: [PATCH 107/715] signer/core: add canonical TypedData hashing methods (#25283) --- signer/core/apitypes/types.go | 19 +++++++++++++++++++ signer/core/signed_data.go | 10 ++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 49819fee3371..6bab4ce35d75 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -251,6 +251,25 @@ type TypedDataDomain struct { Salt string `json:"salt"` } +// TypedDataAndHash is a helper function that calculates a hash for typed data conforming to EIP-712. +// This hash can then be safely used to calculate a signature. +// +// See https://eips.ethereum.org/EIPS/eip-712 for the full specification. +// +// This gives context to the signed typed data and prevents signing of transactions. +func TypedDataAndHash(typedData TypedData) ([]byte, string, error) { + domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) + if err != nil { + return nil, "", err + } + typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) + if err != nil { + return nil, "", err + } + rawData := fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash)) + return crypto.Keccak256([]byte(rawData)), rawData, nil +} + // HashStruct generates a keccak256 hash of the encoding of the provided data func (typedData *TypedData) HashStruct(primaryType string, data TypedDataMessage) (hexutil.Bytes, error) { encodedData, err := typedData.EncodeData(primaryType, data, 1) diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go index 1b4e91cb6da7..c0da22e62662 100644 --- a/signer/core/signed_data.go +++ b/signer/core/signed_data.go @@ -233,23 +233,17 @@ func (api *SignerAPI) SignTypedData(ctx context.Context, addr common.MixedcaseAd // - the signature preimage (hash) func (api *SignerAPI) signTypedData(ctx context.Context, addr common.MixedcaseAddress, typedData apitypes.TypedData, validationMessages *apitypes.ValidationMessages) (hexutil.Bytes, hexutil.Bytes, error) { - domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) + sighash, rawData, err := apitypes.TypedDataAndHash(typedData) if err != nil { return nil, nil, err } - typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) - if err != nil { - return nil, nil, err - } - rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) - sighash := crypto.Keccak256(rawData) messages, err := typedData.Format() if err != nil { return nil, nil, err } req := &SignDataRequest{ ContentType: apitypes.DataTyped.Mime, - Rawdata: rawData, + Rawdata: []byte(rawData), Messages: messages, Hash: sighash, Address: addr} From 62306a5ebef95caae25ebf899a3feb92a95ba511 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 23 Jul 2022 09:46:28 +0200 Subject: [PATCH 108/715] deps: update goleveldb --- go.mod | 2 +- go.sum | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 9753afeb78cb..9a943402281f 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 github.com/stretchr/testify v1.7.2 github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 - github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef github.com/urfave/cli/v2 v2.10.2 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 diff --git a/go.sum b/go.sum index 933c6a06bfb4..78e9f3434e71 100644 --- a/go.sum +++ b/go.sum @@ -327,12 +327,16 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -403,8 +407,12 @@ github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= From 22d71afc957e4035ba3c8e4eaf2ae9a0c4f71084 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Sat, 23 Jul 2022 09:54:11 +0200 Subject: [PATCH 109/715] params: set sepolia mergeNetsplitBlock to 1735371 (#25372) --- core/forkid/forkid_test.go | 10 ++++++++++ params/config.go | 1 + 2 files changed, 11 insertions(+) diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index ca698c47171d..2a0fb167d516 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -138,6 +138,16 @@ func TestCreation(t *testing.T) { {6000000, ID{Hash: checksumToBytes(0xB8C6299D), Next: 0}}, // Future London block }, }, + // Sepolia test cases + { + params.SepoliaChainConfig, + params.SepoliaGenesisHash, + []testcase{ + {0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin and first London block + {1735370, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Last London block + {1735371, ID{Hash: checksumToBytes(0xb96cbd13), Next: 0}}, // First MergeNetsplit block + }, + }, // Merge test cases { &mergeConfig, diff --git a/params/config.go b/params/config.go index a4159ed24593..78cfc0e65700 100644 --- a/params/config.go +++ b/params/config.go @@ -157,6 +157,7 @@ var ( BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(17_000_000_000_000_000), + MergeNetsplitBlock: big.NewInt(1735371), Ethash: new(EthashConfig), } From 3b2a6b34d92b84f6bfab058a46d9fc73c21365c7 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Sat, 23 Jul 2022 09:56:02 +0200 Subject: [PATCH 110/715] cmd/geth: eth/catalyst: enable authrpc by default (#25152) * cmd/geth: eth/catalyst: enable authrpc by default * eth/catalyst: rename catalyst -> Engine API in logs * eth/catalyst: don't panic --- cmd/geth/consolecmd_test.go | 2 +- cmd/geth/genesis_test.go | 2 +- cmd/geth/les_test.go | 2 +- cmd/utils/flags.go | 12 ++++-------- eth/catalyst/api.go | 10 +++++----- les/catalyst/api.go | 2 +- 6 files changed, 13 insertions(+), 17 deletions(-) diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index f4e8bf490a32..d5ebd74aedf4 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -41,7 +41,7 @@ func runMinimalGeth(t *testing.T, args ...string) *testgeth { // --ropsten to make the 'writing genesis to disk' faster (no accounts) // --networkid=1337 to avoid cache bump // --syncmode=full to avoid allocating fast sync bloom - allArgs := []string{"--ropsten", "--networkid", "1337", "--syncmode=full", "--port", "0", + allArgs := []string{"--ropsten", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0", "--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64", "--datadir.minfreedisk", "0"} return runGeth(t, append(allArgs, args...)...) diff --git a/cmd/geth/genesis_test.go b/cmd/geth/genesis_test.go index c95755f2d919..7667a8581158 100644 --- a/cmd/geth/genesis_test.go +++ b/cmd/geth/genesis_test.go @@ -83,7 +83,7 @@ func TestCustomGenesis(t *testing.T) { // Query the custom genesis block geth := runGeth(t, "--networkid", "1337", "--syncmode=full", "--cache", "16", - "--datadir", datadir, "--maxpeers", "0", "--port", "0", + "--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--exec", tt.query, "console") geth.ExpectRegexp(tt.result) diff --git a/cmd/geth/les_test.go b/cmd/geth/les_test.go index d86f41054dd8..d06c3b91d8a5 100644 --- a/cmd/geth/les_test.go +++ b/cmd/geth/les_test.go @@ -111,7 +111,7 @@ var nextIPC = uint32(0) func startGethWithIpc(t *testing.T, name string, args ...string) *gethrpc { ipcName := fmt.Sprintf("geth-%d.ipc", atomic.AddUint32(&nextIPC, 1)) - args = append([]string{"--networkid=42", "--port=0", "--ipcpath", ipcName}, args...) + args = append([]string{"--networkid=42", "--port=0", "--authrpc.port", "0", "--ipcpath", ipcName}, args...) t.Logf("Starting %v with rpc: %v", name, args) g := &gethrpc{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 47637a9dd255..68ef05fa2024 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1993,10 +1993,8 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend Fatalf("Failed to register the Ethereum service: %v", err) } stack.RegisterAPIs(tracers.APIs(backend.ApiBackend)) - if backend.BlockChain().Config().TerminalTotalDifficulty != nil { - if err := lescatalyst.Register(stack, backend); err != nil { - Fatalf("Failed to register the catalyst service: %v", err) - } + if err := lescatalyst.Register(stack, backend); err != nil { + Fatalf("Failed to register the Engine API service: %v", err) } return backend.ApiBackend, nil } @@ -2010,10 +2008,8 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend Fatalf("Failed to create the LES server: %v", err) } } - if backend.BlockChain().Config().TerminalTotalDifficulty != nil { - if err := ethcatalyst.Register(stack, backend); err != nil { - Fatalf("Failed to register the catalyst service: %v", err) - } + if err := ethcatalyst.Register(stack, backend); err != nil { + Fatalf("Failed to register the Engine API service: %v", err) } stack.RegisterAPIs(tracers.APIs(backend.APIBackend)) return backend.APIBackend, backend diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index feccff881e31..a72e1c41e973 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -37,9 +37,9 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -// Register adds catalyst APIs to the full node. +// Register adds the engine API to the full node. func Register(stack *node.Node, backend *eth.Ethereum) error { - log.Warn("Catalyst mode enabled", "protocol", "eth") + log.Warn("Engine API enabled", "protocol", "eth") stack.RegisterAPIs([]rpc.API{ { Namespace: "engine", @@ -62,7 +62,7 @@ type ConsensusAPI struct { // The underlying blockchain needs to have a valid terminal total difficulty set. func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { if eth.BlockChain().Config().TerminalTotalDifficulty == nil { - panic("Catalyst started without valid total difficulty") + log.Warn("Engine API started without valid total difficulty") } return &ConsensusAPI{ eth: eth, @@ -73,7 +73,7 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { // ForkchoiceUpdatedV1 has several responsibilities: // If the method is called with an empty head block: -// we return success, which can be used to check if the catalyst mode is enabled +// we return success, which can be used to check if the engine API is enabled // If the total difficulty was not reached: // we return INVALID // If the finalizedBlockHash is set: @@ -223,7 +223,7 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.Transit return nil, errors.New("invalid terminal total difficulty") } ttd := api.eth.BlockChain().Config().TerminalTotalDifficulty - if ttd.Cmp(config.TerminalTotalDifficulty.ToInt()) != 0 { + if ttd == nil || ttd.Cmp(config.TerminalTotalDifficulty.ToInt()) != 0 { log.Warn("Invalid TTD configured", "geth", ttd, "beacon", config.TerminalTotalDifficulty) return nil, fmt.Errorf("invalid ttd: execution %v consensus %v", ttd, config.TerminalTotalDifficulty) } diff --git a/les/catalyst/api.go b/les/catalyst/api.go index 9c2d17c79b1a..983fc7bff0bc 100644 --- a/les/catalyst/api.go +++ b/les/catalyst/api.go @@ -50,7 +50,7 @@ type ConsensusAPI struct { // The underlying blockchain needs to have a valid terminal total difficulty set. func NewConsensusAPI(les *les.LightEthereum) *ConsensusAPI { if les.BlockChain().Config().TerminalTotalDifficulty == nil { - panic("Catalyst started without valid total difficulty") + log.Warn("Catalyst started without valid total difficulty") } return &ConsensusAPI{les: les} } From b2be5f956f3c2cd72d29b0b6e75ac0c2b794f6bd Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 25 Jul 2022 11:06:22 +0200 Subject: [PATCH 111/715] eth/catalyst: better warning for ttd not configured (#25394) --- eth/catalyst/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index a72e1c41e973..f0f7be7bcddd 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -62,7 +62,7 @@ type ConsensusAPI struct { // The underlying blockchain needs to have a valid terminal total difficulty set. func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { if eth.BlockChain().Config().TerminalTotalDifficulty == nil { - log.Warn("Engine API started without valid total difficulty") + log.Warn("Engine API started but chain not configured for merge yet") } return &ConsensusAPI{ eth: eth, From 1ed8b7d24fd967fd11a5d6136dd5799ef6477f82 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 25 Jul 2022 17:07:44 +0800 Subject: [PATCH 112/715] cmd: use flags.Merge for grouping flags (#25392) --- cmd/geth/chaincmd.go | 21 +++++++++++---------- cmd/geth/config.go | 2 +- cmd/geth/consolecmd.go | 7 ++++--- cmd/geth/dbcmd.go | 27 ++++++++++++++------------- cmd/geth/main.go | 4 ++-- cmd/geth/snapshot.go | 15 ++++++++------- cmd/utils/flags.go | 9 --------- 7 files changed, 40 insertions(+), 45 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 13ecde5bd665..87863750615a 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" @@ -69,7 +70,7 @@ The dumpgenesis command dumps the genesis block configuration in JSON format to Name: "import", Usage: "Import a blockchain file", ArgsUsage: " ( ... ) ", - Flags: append([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.CacheFlag, utils.SyncModeFlag, utils.GCModeFlag, @@ -91,7 +92,7 @@ The dumpgenesis command dumps the genesis block configuration in JSON format to utils.MetricsInfluxDBBucketFlag, utils.MetricsInfluxDBOrganizationFlag, utils.TxLookupLimitFlag, - }, utils.DatabasePathFlags...), + }, utils.DatabasePathFlags), Description: ` The import command imports blocks from an RLP-encoded form. The form can be one file with several RLP-encoded blocks, or several files can be used. @@ -104,10 +105,10 @@ processing will proceed even if an individual RLP-file import failure occurs.`, Name: "export", Usage: "Export blockchain into file", ArgsUsage: " [ ]", - Flags: append([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.CacheFlag, utils.SyncModeFlag, - }, utils.DatabasePathFlags...), + }, utils.DatabasePathFlags), Description: ` Requires a first argument of the file to write to. Optional second and third arguments control the first and @@ -120,10 +121,10 @@ be gzipped.`, Name: "import-preimages", Usage: "Import the preimage database from an RLP stream", ArgsUsage: "", - Flags: append([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.CacheFlag, utils.SyncModeFlag, - }, utils.DatabasePathFlags...), + }, utils.DatabasePathFlags), Description: ` The import-preimages command imports hash preimages from an RLP encoded stream. It's deprecated, please use "geth db import" instead. @@ -134,10 +135,10 @@ It's deprecated, please use "geth db import" instead. Name: "export-preimages", Usage: "Export the preimage database into an RLP stream", ArgsUsage: "", - Flags: append([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.CacheFlag, utils.SyncModeFlag, - }, utils.DatabasePathFlags...), + }, utils.DatabasePathFlags), Description: ` The export-preimages command exports hash preimages to an RLP encoded stream. It's deprecated, please use "geth db export" instead. @@ -148,7 +149,7 @@ It's deprecated, please use "geth db export" instead. Name: "dump", Usage: "Dump a specific block from storage", ArgsUsage: "[? | ]", - Flags: append([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.CacheFlag, utils.IterativeOutputFlag, utils.ExcludeCodeFlag, @@ -156,7 +157,7 @@ It's deprecated, please use "geth db export" instead. utils.IncludeIncompletesFlag, utils.StartKeyFlag, utils.DumpLimitFlag, - }, utils.DatabasePathFlags...), + }, utils.DatabasePathFlags), Description: ` This command dumps out the state for a given block (or latest, if none provided). `, diff --git a/cmd/geth/config.go b/cmd/geth/config.go index a415aeabd2e9..710e71836607 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -49,7 +49,7 @@ var ( Name: "dumpconfig", Usage: "Show configuration values", ArgsUsage: "", - Flags: utils.GroupFlags(nodeFlags, rpcFlags), + Flags: flags.Merge(nodeFlags, rpcFlags), Description: `The dumpconfig command shows configuration values.`, } diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index 6f31e5f2898e..87bbe24b977a 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/console" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" "github.com/urfave/cli/v2" @@ -34,7 +35,7 @@ var ( Action: localConsole, Name: "console", Usage: "Start an interactive JavaScript environment", - Flags: utils.GroupFlags(nodeFlags, rpcFlags, consoleFlags), + Flags: flags.Merge(nodeFlags, rpcFlags, consoleFlags), Description: ` The Geth console is an interactive shell for the JavaScript runtime environment which exposes a node admin interface as well as the Ðapp JavaScript API. @@ -46,7 +47,7 @@ See https://geth.ethereum.org/docs/interface/javascript-console.`, Name: "attach", Usage: "Start an interactive JavaScript environment (connect to node)", ArgsUsage: "[endpoint]", - Flags: utils.GroupFlags([]cli.Flag{utils.DataDirFlag}, consoleFlags), + Flags: flags.Merge([]cli.Flag{utils.DataDirFlag}, consoleFlags), Description: ` The Geth console is an interactive shell for the JavaScript runtime environment which exposes a node admin interface as well as the Ðapp JavaScript API. @@ -59,7 +60,7 @@ This command allows to open a console on a running geth node.`, Name: "js", Usage: "(DEPRECATED) Execute the specified JavaScript files", ArgsUsage: " [jsfile...]", - Flags: utils.GroupFlags(nodeFlags, consoleFlags), + Flags: flags.Merge(nodeFlags, consoleFlags), Description: ` The JavaScript VM exposes a node admin interface as well as the Ðapp JavaScript API. See https://geth.ethereum.org/docs/interface/javascript-console`, diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 8b94609c14be..27661d2c982c 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie" "github.com/olekukonko/tablewriter" @@ -77,7 +78,7 @@ Remove blockchain and state databases`, Action: inspect, Name: "inspect", ArgsUsage: " ", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Usage: "Inspect the storage size for each type of data in the database", @@ -87,7 +88,7 @@ Remove blockchain and state databases`, Action: checkStateContent, Name: "check-state-content", ArgsUsage: "", - Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), Usage: "Verify that state data is cryptographically correct", Description: `This command iterates the entire database for 32-byte keys, looking for rlp-encoded trie nodes. For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates @@ -97,7 +98,7 @@ a data corruption.`, Action: dbStats, Name: "stats", Usage: "Print leveldb statistics", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), } @@ -105,7 +106,7 @@ a data corruption.`, Action: dbCompact, Name: "compact", Usage: "Compact leveldb database. WARNING: May take a very long time", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, utils.CacheFlag, utils.CacheDatabaseFlag, @@ -119,7 +120,7 @@ corruption if it is aborted during execution'!`, Name: "get", Usage: "Show the value of a database key", ArgsUsage: "", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "This command looks up the specified database key from the database.", @@ -129,7 +130,7 @@ corruption if it is aborted during execution'!`, Name: "delete", Usage: "Delete a database key (WARNING: may corrupt your database)", ArgsUsage: "", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: `This command deletes the specified database key from the database. @@ -140,7 +141,7 @@ WARNING: This is a low-level operation which may cause database corruption!`, Name: "put", Usage: "Set the value of a database key (WARNING: may corrupt your database)", ArgsUsage: " ", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: `This command sets a given database key to the given value. @@ -151,7 +152,7 @@ WARNING: This is a low-level operation which may cause database corruption!`, Name: "dumptrie", Usage: "Show the storage key/values of a given storage trie", ArgsUsage: " ", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "This command looks up the specified database key from the database.", @@ -161,7 +162,7 @@ WARNING: This is a low-level operation which may cause database corruption!`, Name: "freezer-index", Usage: "Dump out the index of a given freezer type", ArgsUsage: " ", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "This command displays information about the freezer index.", @@ -171,7 +172,7 @@ WARNING: This is a low-level operation which may cause database corruption!`, Name: "import", Usage: "Imports leveldb-data from an exported RLP dump.", ArgsUsage: " has .gz suffix, gzip compression will be used.", ArgsUsage: " ", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.", @@ -190,7 +191,7 @@ WARNING: This is a low-level operation which may cause database corruption!`, Action: showMetaData, Name: "metadata", Usage: "Shows metadata about the chain status.", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "Shows metadata about the chain status.", @@ -200,7 +201,7 @@ WARNING: This is a low-level operation which may cause database corruption!`, Name: "freezer-migrate", Usage: "Migrate legacy parts of the freezer. (WARNING: may take a long time)", ArgsUsage: "", - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: `The freezer-migrate command checks your database for receipts in a legacy format and updates those. diff --git a/cmd/geth/main.go b/cmd/geth/main.go index b0a849a3ba6a..9aae75974c66 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -58,7 +58,7 @@ var ( // The app that holds all commands and flags. app = flags.NewApp(gitCommit, gitDate, "the go-ethereum command line interface") // flags that configure the node - nodeFlags = utils.GroupFlags([]cli.Flag{ + nodeFlags = flags.Merge([]cli.Flag{ utils.IdentityFlag, utils.UnlockedAccountFlag, utils.PasswordFileFlag, @@ -243,7 +243,7 @@ func init() { } sort.Sort(cli.CommandsByName(app.Commands)) - app.Flags = utils.GroupFlags( + app.Flags = flags.Merge( nodeFlags, rpcFlags, consoleFlags, diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 82206b58b8ea..a218ae9cd292 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -56,7 +57,7 @@ var ( Usage: "Prune stale ethereum state data based on the snapshot", ArgsUsage: "", Action: pruneState, - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.CacheTrieJournalFlag, utils.BloomFilterSizeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), @@ -80,7 +81,7 @@ the trie clean cache with default directory will be deleted. Usage: "Recalculate state hash based on the snapshot for verification", ArgsUsage: "", Action: verifyState, - Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot verify-state will traverse the whole accounts and storages set based on the specified @@ -93,7 +94,7 @@ In other words, this command does the snapshot to trie conversion. Usage: "Check that there is no 'dangling' snap storage", ArgsUsage: "", Action: checkDanglingStorage, - Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot check-dangling-storage traverses the snap storage data, and verifies that all snapshot storage data has a corresponding account. @@ -104,7 +105,7 @@ data, and verifies that all snapshot storage data has a corresponding account. Usage: "Check all snapshot layers for the a specific account", ArgsUsage: "
", Action: checkAccount, - Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot inspect-account
checks all snapshot layers and prints out information about the specified address. @@ -115,7 +116,7 @@ information about the specified address. Usage: "Traverse the state with given root hash and perform quick verification", ArgsUsage: "", Action: traverseState, - Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot traverse-state will traverse the whole state from the given state root and will abort if any @@ -130,7 +131,7 @@ It's also usable without snapshot enabled. Usage: "Traverse the state with given root hash and perform detailed verification", ArgsUsage: "", Action: traverseRawState, - Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot traverse-rawstate will traverse the whole state from the given root and will abort if any referenced @@ -146,7 +147,7 @@ It's also usable without snapshot enabled. Usage: "Dump a specific block from storage (same as 'geth dump' but using snapshots)", ArgsUsage: "[? | ]", Action: dumpState, - Flags: utils.GroupFlags([]cli.Flag{ + Flags: flags.Merge([]cli.Flag{ utils.ExcludeCodeFlag, utils.ExcludeStorageFlag, utils.StartKeyFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 68ef05fa2024..f55719af4989 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -994,15 +994,6 @@ var ( } ) -// GroupFlags combines the given flag slices together and returns the merged one. -func GroupFlags(groups ...[]cli.Flag) []cli.Flag { - var ret []cli.Flag - for _, group := range groups { - ret = append(ret, group...) - } - return ret -} - // MakeDataDir retrieves the currently requested data directory, terminating // if none (or the empty string) is specified. If the node is starting a testnet, // then a subdirectory of the specified datadir will be used. From ff2259457ae218ecc9f15fb56c65a6dc51164823 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Mon, 25 Jul 2022 11:08:08 +0200 Subject: [PATCH 113/715] consensus/beacon: fix typo in comment (#25391) --- consensus/beacon/consensus.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index ae4c05dad9e0..0397b026f1f0 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -167,7 +167,7 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ return abort, results } -// verifyTerminalPoWBlock verifies that the preHeaders confirm to the specification +// verifyTerminalPoWBlock verifies that the preHeaders conform to the specification // wrt. their total difficulty. // It expects: // - preHeaders to be at least 1 element From 39900be087049f0cdcf4142e22e134bff5d622fd Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Mon, 25 Jul 2022 17:52:49 +0800 Subject: [PATCH 114/715] p2p/netutil: minor code cosmetic Signed-off-by: Abirdcfly --- p2p/netutil/error_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/p2p/netutil/error_test.go b/p2p/netutil/error_test.go index 645e48f83741..84d5c2c20621 100644 --- a/p2p/netutil/error_test.go +++ b/p2p/netutil/error_test.go @@ -66,7 +66,6 @@ func TestIsPacketTooBig(t *testing.T) { for i := range buf { if buf[i] != byte(i) { t.Fatalf("error in pattern") - break } } } From d2247d9f5d8e004c6e3396e3b223ad603bb67273 Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Mon, 25 Jul 2022 18:53:44 +0900 Subject: [PATCH 115/715] eth, internal, light: fix error string capitalization (#25364) --- eth/api.go | 2 +- eth/tracers/js/goja.go | 8 ++++---- internal/jsre/jsre.go | 4 ++-- light/txpool.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/eth/api.go b/eth/api.go index 5d159108e6a9..23b9743be950 100644 --- a/eth/api.go +++ b/eth/api.go @@ -582,5 +582,5 @@ func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error return uint64(i), nil } } - return 0, fmt.Errorf("No state found") + return 0, fmt.Errorf("no state found") } diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index f54c8010494f..ae8b09a0ffca 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -548,10 +548,10 @@ func (mo *memoryObj) slice(begin, end int64) ([]byte, error) { return []byte{}, nil } if end < begin || begin < 0 { - return nil, fmt.Errorf("Tracer accessed out of bound memory: offset %d, end %d", begin, end) + return nil, fmt.Errorf("tracer accessed out of bound memory: offset %d, end %d", begin, end) } if mo.memory.Len() < int(end) { - return nil, fmt.Errorf("Tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), begin, end-begin) + return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), begin, end-begin) } return mo.memory.GetCopy(begin, end-begin), nil } @@ -573,7 +573,7 @@ func (mo *memoryObj) GetUint(addr int64) goja.Value { // getUint returns the 32 bytes at the specified address interpreted as a uint. func (mo *memoryObj) getUint(addr int64) (*big.Int, error) { if mo.memory.Len() < int(addr)+32 || addr < 0 { - return nil, fmt.Errorf("Tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), addr, 32) + return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), addr, 32) } return new(big.Int).SetBytes(mo.memory.GetPtr(addr, 32)), nil } @@ -613,7 +613,7 @@ func (s *stackObj) Peek(idx int) goja.Value { // peek returns the nth-from-the-top element of the stack. func (s *stackObj) peek(idx int) (*big.Int, error) { if len(s.stack.Data()) <= idx || idx < 0 { - return nil, fmt.Errorf("Tracer accessed out of bound stack: size %d, index %d", len(s.stack.Data()), idx) + return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack.Data()), idx) } return s.stack.Back(idx).ToBig(), nil } diff --git a/internal/jsre/jsre.go b/internal/jsre/jsre.go index 4de80a9e901c..f6e21d2ef701 100644 --- a/internal/jsre/jsre.go +++ b/internal/jsre/jsre.go @@ -322,11 +322,11 @@ func (re *JSRE) loadScript(call Call) (goja.Value, error) { file = common.AbsolutePath(re.assetPath, file) source, err := os.ReadFile(file) if err != nil { - return nil, fmt.Errorf("Could not read file %s: %v", file, err) + return nil, fmt.Errorf("could not read file %s: %v", file, err) } value, err := compileAndRun(re.vm, file, string(source)) if err != nil { - return nil, fmt.Errorf("Error while compiling or running script: %v", err) + return nil, fmt.Errorf("error while compiling or running script: %v", err) } return value, nil } diff --git a/light/txpool.go b/light/txpool.go index a7df4aeec388..413337208b84 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -398,7 +398,7 @@ func (pool *TxPool) add(ctx context.Context, tx *types.Transaction) error { hash := tx.Hash() if pool.pending[hash] != nil { - return fmt.Errorf("Known transaction (%x)", hash[:4]) + return fmt.Errorf("known transaction (%x)", hash[:4]) } err := pool.validateTx(ctx, tx) if err != nil { From 6c4e5d06e7df2d50cc94007dd1b49da6dedb8f1c Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Mon, 25 Jul 2022 17:54:31 +0800 Subject: [PATCH 116/715] light: fix differTries err message in tests (#25358) --- light/trie_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/light/trie_test.go b/light/trie_test.go index e8294cc2a235..63dd9020f20c 100644 --- a/light/trie_test.go +++ b/light/trie_test.go @@ -76,7 +76,7 @@ func diffTries(t1, t2 state.Trie) error { case i1.Err != nil: return fmt.Errorf("full trie iterator error: %v", i1.Err) case i2.Err != nil: - return fmt.Errorf("light trie iterator error: %v", i1.Err) + return fmt.Errorf("light trie iterator error: %v", i2.Err) case i1.Next(): return fmt.Errorf("full trie iterator has more k/v pairs") case i2.Next(): From b196ad1c165ecd6c9edaca520e7161a58e50eb06 Mon Sep 17 00:00:00 2001 From: Delweng Date: Mon, 25 Jul 2022 18:14:03 +0800 Subject: [PATCH 117/715] all: add whitespace linter (#25312) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * golangci: typo Signed-off-by: Delweng * golangci: add whietspace Signed-off-by: Delweng * *: rm whitesapce using golangci-lint Signed-off-by: Delweng * cmd/puppeth: revert accidental resurrection Co-authored-by: Péter Szilágyi --- .golangci.yml | 23 ++++++++++--------- accounts/abi/bind/base_test.go | 1 - accounts/abi/error_handling.go | 1 - accounts/abi/event_test.go | 1 - accounts/abi/reflect.go | 1 - accounts/abi/unpack.go | 1 - accounts/keystore/keystore_test.go | 2 -- accounts/keystore/passphrase.go | 2 -- accounts/usbwallet/wallet.go | 1 - cmd/clef/main.go | 5 ---- cmd/devp2p/dns_cloudflare.go | 1 - cmd/devp2p/internal/ethtest/chain.go | 1 - cmd/devp2p/internal/ethtest/snap.go | 1 - cmd/devp2p/internal/ethtest/types.go | 1 - cmd/evm/internal/t8ntool/execution.go | 1 - cmd/evm/t8n_test.go | 3 --- cmd/geth/version_check_test.go | 1 - common/math/big_test.go | 3 --- common/types_test.go | 3 --- core/blockchain_test.go | 4 ---- core/state/snapshot/difflayer_test.go | 2 -- core/state/statedb_test.go | 1 - core/tx_pool_test.go | 1 - core/types/bloom9_test.go | 1 - core/types/transaction_signing_test.go | 1 - core/types/transaction_test.go | 1 - core/vm/instructions_test.go | 3 --- core/vm/interpreter.go | 1 - core/vm/interpreter_test.go | 1 - core/vm/jump_table.go | 1 - core/vm/runtime/runtime_test.go | 2 -- crypto/bls12381/field_element_test.go | 1 - crypto/bls12381/fp12.go | 2 -- crypto/bls12381/fp_test.go | 1 - crypto/bls12381/g2.go | 1 - crypto/ecies/ecies_test.go | 1 - eth/downloader/queue.go | 1 - eth/downloader/queue_test.go | 8 ------- eth/downloader/skeleton_test.go | 1 - eth/fetcher/block_fetcher.go | 1 - eth/filters/api.go | 1 - eth/filters/filter_test.go | 1 - eth/handler_eth_test.go | 1 - eth/protocols/eth/protocol_test.go | 2 -- eth/tracers/js/goja.go | 1 - ethclient/gethclient/gethclient.go | 1 - ethclient/gethclient/gethclient_test.go | 1 - ethstats/ethstats_test.go | 1 - graphql/service.go | 1 - internal/jsre/pretty.go | 1 - les/api_test.go | 1 - les/downloader/downloader.go | 1 - les/downloader/downloader_test.go | 1 - les/downloader/queue.go | 1 - les/downloader/queue_test.go | 8 ------- les/fetcher/block_fetcher.go | 1 - les/flowcontrol/manager_test.go | 1 - les/vflux/client/serverpool.go | 1 - les/vflux/client/wrsiterator.go | 1 - les/vflux/server/clientpool_test.go | 1 - metrics/influxdb/influxdbv2.go | 2 -- metrics/registry_test.go | 1 - miner/miner_test.go | 1 - mobile/ethclient.go | 1 - node/node_test.go | 2 -- node/rpcstack.go | 1 - p2p/simulations/http.go | 1 - p2p/simulations/http_test.go | 2 -- p2p/simulations/mocker.go | 1 - p2p/simulations/network.go | 4 ---- p2p/simulations/network_test.go | 3 --- rlp/decode_test.go | 1 - rlp/iterator.go | 1 - signer/core/api.go | 2 -- signer/core/api_test.go | 5 ---- signer/core/apitypes/types.go | 2 -- signer/core/auditlog.go | 1 - signer/core/cliui.go | 4 ---- signer/core/validation_test.go | 1 - signer/fourbyte/validation_test.go | 1 - signer/rules/rules.go | 1 - signer/rules/rules_test.go | 10 -------- signer/storage/aes_gcm_storage_test.go | 1 - tests/difficulty_test_util.go | 1 - tests/fuzzers/rangeproof/rangeproof-fuzzer.go | 1 - tests/fuzzers/stacktrie/trie_fuzzer.go | 1 - tests/fuzzers/trie/trie-fuzzer.go | 4 ---- tests/state_test.go | 1 - trie/stacktrie_test.go | 1 - trie/trie_test.go | 1 - 90 files changed, 12 insertions(+), 164 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b889c770dff6..4c1297223533 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -28,15 +28,16 @@ linters: - durationcheck - exportloopref - gosec + - whitespace - #- structcheck # lots of false positives - #- errcheck #lot of false positives - # - contextcheck - # - errchkjson # lots of false positives - # - errorlint # this check crashes - # - exhaustive # silly check - # - makezero # false positives - # - nilerr # several intentional + # - structcheck # lots of false positives + # - errcheck #lot of false positives + # - contextcheck + # - errchkjson # lots of false positives + # - errorlint # this check crashes + # - exhaustive # silly check + # - makezero # false positives + # - nilerr # several intentional linters-settings: gofmt: @@ -46,9 +47,9 @@ linters-settings: min-occurrences: 6 # minimum number of occurrences gosec: excludes: - - G404 # Use of weak random number generator - lots of FP - - G107 # Potential http request -- those are intentional - - G306 # G306: Expect WriteFile permissions to be 0600 or less + - G404 # Use of weak random number generator - lots of FP + - G107 # Potential http request -- those are intentional + - G306 # G306: Expect WriteFile permissions to be 0600 or less issues: exclude-rules: diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index 25b2f8a865f2..2307b9874b18 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -115,7 +115,6 @@ func (mc *mockPendingCaller) PendingCallContract(ctx context.Context, call ether } func TestPassingBlockNumber(t *testing.T) { - mc := &mockPendingCaller{ mockCaller: &mockCaller{ codeAtBytes: []byte{1, 2, 3}, diff --git a/accounts/abi/error_handling.go b/accounts/abi/error_handling.go index f0f71b6c9164..7add7072925e 100644 --- a/accounts/abi/error_handling.go +++ b/accounts/abi/error_handling.go @@ -73,7 +73,6 @@ func typeCheck(t Type, value reflect.Value) error { } else { return nil } - } // typeErr returns a formatted type casting error. diff --git a/accounts/abi/event_test.go b/accounts/abi/event_test.go index 3332f8a07216..8f73419496ba 100644 --- a/accounts/abi/event_test.go +++ b/accounts/abi/event_test.go @@ -161,7 +161,6 @@ func TestEventMultiValueWithArrayUnpack(t *testing.T) { } func TestEventTupleUnpack(t *testing.T) { - type EventTransfer struct { Value *big.Int } diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 35e5556d2c5a..eb21bb26451a 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -220,7 +220,6 @@ func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[stri // second round ~~~ for _, argName := range argNames { - structFieldName := ToCamelCase(argName) if structFieldName == "" { diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index 28c5c82bb3d5..800789295c19 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -115,7 +115,6 @@ func ReadFixedBytes(t Type, word []byte) (interface{}, error) { reflect.Copy(array, reflect.ValueOf(word[0:t.Size])) return array.Interface(), nil - } // forEachUnpack iteratively unpack elements. diff --git a/accounts/keystore/keystore_test.go b/accounts/keystore/keystore_test.go index 80c4d643e8e1..6a2e32f6d9c8 100644 --- a/accounts/keystore/keystore_test.go +++ b/accounts/keystore/keystore_test.go @@ -377,7 +377,6 @@ func TestImportExport(t *testing.T) { if _, err = ks2.Import(json, "new", "new"); err == nil { t.Errorf("importing a key twice succeeded") } - } // TestImportRace tests the keystore on races. @@ -402,7 +401,6 @@ func TestImportRace(t *testing.T) { if _, err := ks2.Import(json, "new", "new"); err != nil { atomic.AddUint32(&atom, 1) } - }() } wg.Wait() diff --git a/accounts/keystore/passphrase.go b/accounts/keystore/passphrase.go index 22772e93102f..1701fbf53634 100644 --- a/accounts/keystore/passphrase.go +++ b/accounts/keystore/passphrase.go @@ -138,7 +138,6 @@ func (ks keyStorePassphrase) JoinPath(filename string) string { // Encryptdata encrypts the data given as 'data' with the password 'auth'. func EncryptDataV3(data, auth []byte, scryptN, scryptP int) (CryptoJSON, error) { - salt := make([]byte, 32) if _, err := io.ReadFull(rand.Reader, salt); err != nil { panic("reading from crypto/rand failed: " + err.Error()) @@ -341,7 +340,6 @@ func getKDFKey(cryptoJSON CryptoJSON, auth string) ([]byte, error) { r := ensureInt(cryptoJSON.KDFParams["r"]) p := ensureInt(cryptoJSON.KDFParams["p"]) return scrypt.Key(authArray, salt, n, r, p, dkLen) - } else if cryptoJSON.KDF == "pbkdf2" { c := ensureInt(cryptoJSON.KDFParams["c"]) prf := cryptoJSON.KDFParams["prf"].(string) diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 382f3ddaee21..06ff0636ae20 100644 --- a/accounts/usbwallet/wallet.go +++ b/accounts/usbwallet/wallet.go @@ -526,7 +526,6 @@ func (w *wallet) signHash(account accounts.Account, hash []byte) ([]byte, error) // SignData signs keccak256(data). The mimetype parameter describes the type of data being signed func (w *wallet) SignData(account accounts.Account, mimeType string, data []byte) ([]byte, error) { - // Unless we are doing 712 signing, simply dispatch to signHash if !(mimeType == accounts.MimetypeTypedData && len(data) == 66 && data[0] == 0x19 && data[1] == 0x01) { return w.signHash(account, crypto.Keccak256(data)) diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 3c4989c87ce1..05290f52feb8 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -759,7 +759,6 @@ func confirm(text string) bool { } func testExternalUI(api *core.SignerAPI) { - ctx := context.WithValue(context.Background(), "remote", "clef binary") ctx = context.WithValue(ctx, "scheme", "in-proc") ctx = context.WithValue(ctx, "local", "main") @@ -859,7 +858,6 @@ func testExternalUI(api *core.SignerAPI) { expectDeny("signdata - text", err) } { // Sign transaction - api.UI.ShowInfo("Please reject next transaction") time.Sleep(delay) data := hexutil.Bytes([]byte{}) @@ -902,7 +900,6 @@ func testExternalUI(api *core.SignerAPI) { } result := fmt.Sprintf("Tests completed. %d errors:\n%s\n", len(errs), strings.Join(errs, "\n")) api.UI.ShowInfo(result) - } type encryptedSeedStorage struct { @@ -939,7 +936,6 @@ func decryptSeed(keyjson []byte, auth string) ([]byte, error) { // GenDoc outputs examples of all structures used in json-rpc communication func GenDoc(ctx *cli.Context) error { - var ( a = common.HexToAddress("0xdeadbeef000000000000000000000000deadbeef") b = common.HexToAddress("0x1111111122222222222233333333334444444444") @@ -1049,7 +1045,6 @@ func GenDoc(ctx *cli.Context) error { var tx types.Transaction tx.UnmarshalBinary(rlpdata) add("OnApproved - SignTransactionResult", desc, ðapi.SignTransactionResult{Raw: rlpdata, Tx: &tx}) - } { // User input add("UserInputRequest", "Sent when clef needs the user to provide data. If 'password' is true, the input field should be treated accordingly (echo-free)", diff --git a/cmd/devp2p/dns_cloudflare.go b/cmd/devp2p/dns_cloudflare.go index 73ecc13bc32d..92c6faf272ec 100644 --- a/cmd/devp2p/dns_cloudflare.go +++ b/cmd/devp2p/dns_cloudflare.go @@ -134,7 +134,6 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string) ttl := rootTTL if path != name { ttl = treeNodeTTLCloudflare // Max TTL permitted by Cloudflare - } record := cloudflare.DNSRecord{Type: "TXT", Name: path, Content: val, TTL: ttl} _, err = c.CreateDNSRecord(context.Background(), c.zoneID, record) diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index 0a17252a3503..65ffc6f81d28 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -119,7 +119,6 @@ func (c *Chain) GetHeaders(req GetBlockHeaders) (BlockHeaders, error) { for i := 1; i < int(req.Amount); i++ { blockNumber -= (1 - req.Skip) headers[i] = c.blocks[blockNumber].Header() - } return headers, nil diff --git a/cmd/devp2p/internal/ethtest/snap.go b/cmd/devp2p/internal/ethtest/snap.go index fa94c13ad237..032afeafcdad 100644 --- a/cmd/devp2p/internal/ethtest/snap.go +++ b/cmd/devp2p/internal/ethtest/snap.go @@ -350,7 +350,6 @@ func hexToCompact(hex []byte) []byte { // TestSnapTrieNodes various forms of GetTrieNodes requests. func (s *Suite) TestSnapTrieNodes(t *utesting.T) { - key := common.FromHex("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a") // helper function to iterate the key, and generate the compact-encoded // trie paths along the way. diff --git a/cmd/devp2p/internal/ethtest/types.go b/cmd/devp2p/internal/ethtest/types.go index e92b54394067..e69d94bb5c2c 100644 --- a/cmd/devp2p/internal/ethtest/types.go +++ b/cmd/devp2p/internal/ethtest/types.go @@ -315,7 +315,6 @@ func (c *Conn) ReadSnap(id uint64) (Message, error) { return nil, fmt.Errorf("could not rlp decode message: %v", err) } return snpMsg.(Message), nil - } return nil, fmt.Errorf("request timed out") } diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 241b57f55ea9..28fe77d2d07d 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -100,7 +100,6 @@ type rejectedTx struct { func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txs types.Transactions, miningReward int64, getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error)) (*state.StateDB, *ExecutionResult, error) { - // Capture errors for BLOCKHASH operation, if we haven't been supplied the // required blockhashes var hashError error diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 805eea90c45e..72c062e8d923 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -244,7 +244,6 @@ func TestT8n(t *testing.T) { expExitCode: 3, }, } { - args := []string{"t8n"} args = append(args, tc.output.get()...) args = append(args, tc.input.get(tc.base)...) @@ -355,7 +354,6 @@ func TestT9n(t *testing.T) { expExitCode: t8ntool.ErrorIO, }, } { - args := []string{"t9n"} args = append(args, tc.input.get(tc.base)...) @@ -475,7 +473,6 @@ func TestB11r(t *testing.T) { expOut: "exp.json", }, } { - args := []string{"b11r"} args = append(args, tc.input.get(tc.base)...) diff --git a/cmd/geth/version_check_test.go b/cmd/geth/version_check_test.go index b841ace5b2f9..bd4d820a7901 100644 --- a/cmd/geth/version_check_test.go +++ b/cmd/geth/version_check_test.go @@ -118,7 +118,6 @@ func TestMatching(t *testing.T) { version, vuln.Introduced, vuln.Fixed, vuln.Name, vulnIntro, current, vulnFixed) } } - } } for major := 1; major < 2; major++ { diff --git a/common/math/big_test.go b/common/math/big_test.go index f896ec65becf..803b5e1cc617 100644 --- a/common/math/big_test.go +++ b/common/math/big_test.go @@ -171,7 +171,6 @@ func BenchmarkByteAt(b *testing.B) { } func BenchmarkByteAtOld(b *testing.B) { - bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC") for i := 0; i < b.N; i++ { PaddedBigBytes(bigint, 32) @@ -244,7 +243,6 @@ func TestBigEndianByteAt(t *testing.T) { if actual != test.exp { t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.x, test.y, test.exp, actual) } - } } func TestLittleEndianByteAt(t *testing.T) { @@ -277,7 +275,6 @@ func TestLittleEndianByteAt(t *testing.T) { if actual != test.exp { t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.x, test.y, test.exp, actual) } - } } diff --git a/common/types_test.go b/common/types_test.go index 318e985f870b..94492278d84a 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -155,7 +155,6 @@ func BenchmarkAddressHex(b *testing.B) { } func TestMixedcaseAccount_Address(t *testing.T) { - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md // Note: 0X{checksum_addr} is not valid according to spec above @@ -192,9 +191,7 @@ func TestMixedcaseAccount_Address(t *testing.T) { if err := json.Unmarshal([]byte(r), &r2); err == nil { t.Errorf("Expected failure, input %v", r) } - } - } func TestHash_Scan(t *testing.T) { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index c1e1d6371e0d..8e94865366fe 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1235,7 +1235,6 @@ func TestSideLogRebirth(t *testing.T) { chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { if i == 1 { gen.OffsetTime(-9) // higher block difficulty - } }) if _, err := blockchain.InsertChain(chain); err != nil { @@ -1364,7 +1363,6 @@ done: t.Errorf("unexpected event fired: %v", e) case <-time.After(250 * time.Millisecond): } - } // Tests if the canonical block can be fetched from the database during chain insertion. @@ -2753,7 +2751,6 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in b.StopTimer() if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks { b.Fatalf("Transactions were not included, expected %d, got %d", numTxs*numBlocks, got) - } } } @@ -3522,7 +3519,6 @@ func TestEIP2718Transition(t *testing.T) { vm.GasQuickStep*2 + params.WarmStorageReadCostEIP2929 + params.ColdSloadCostEIP2929 if block.GasUsed() != expected { t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expected, block.GasUsed()) - } } diff --git a/core/state/snapshot/difflayer_test.go b/core/state/snapshot/difflayer_test.go index e15c1d5049b0..59db920481b0 100644 --- a/core/state/snapshot/difflayer_test.go +++ b/core/state/snapshot/difflayer_test.go @@ -332,7 +332,6 @@ func BenchmarkFlatten(b *testing.B) { value := make([]byte, 32) rand.Read(value) accStorage[randomHash()] = value - } storage[accountKey] = accStorage } @@ -382,7 +381,6 @@ func BenchmarkJournal(b *testing.B) { value := make([]byte, 32) rand.Read(value) accStorage[randomHash()] = value - } storage[accountKey] = accStorage } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index e9576d4dc44d..6af2d4523b32 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -699,7 +699,6 @@ func TestDeleteCreateRevert(t *testing.T) { // the Commit operation fails with an error // If we are missing trie nodes, we should not continue writing to the trie func TestMissingTrieNodes(t *testing.T) { - // Create an initial state with a few accounts memDb := rawdb.NewMemoryDatabase() db := NewDatabase(memDb) diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index dd2407470daa..2fd0f529f8f2 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -669,7 +669,6 @@ func TestTransactionPostponing(t *testing.T) { // Add a batch consecutive pending transactions for validation txs := []*types.Transaction{} for i, key := range keys { - for j := 0; j < 100; j++ { var tx *types.Transaction if (i+j)%2 == 0 { diff --git a/core/types/bloom9_test.go b/core/types/bloom9_test.go index 893df486dd1b..d3178d112efb 100644 --- a/core/types/bloom9_test.go +++ b/core/types/bloom9_test.go @@ -92,7 +92,6 @@ func BenchmarkBloom9Lookup(b *testing.B) { } func BenchmarkCreateBloom(b *testing.B) { - var txs = Transactions{ NewContractCreation(1, big.NewInt(1), 1, big.NewInt(1), nil), NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil), diff --git a/core/types/transaction_signing_test.go b/core/types/transaction_signing_test.go index 689fc38a9b66..1c775f129d65 100644 --- a/core/types/transaction_signing_test.go +++ b/core/types/transaction_signing_test.go @@ -111,7 +111,6 @@ func TestEIP155SigningVitalik(t *testing.T) { if from != addr { t.Errorf("%d: expected %x got %x", i, addr, from) } - } } diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 2e418b230986..67e5b3cce3f5 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -114,7 +114,6 @@ func TestEIP2718TransactionSigHash(t *testing.T) { // This test checks signature operations on access list transactions. func TestEIP2930Signer(t *testing.T) { - var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") keyAddr = crypto.PubkeyToAddress(key.PublicKey) diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index fb0fcc1da49d..602cde51015e 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -46,7 +46,6 @@ var commonParams []*twoOperandParams var twoOpMethods map[string]executionFunc func init() { - // Params is a list of common edgecases that should be used for some common tests params := []string{ "0000000000000000000000000000000000000000000000000000000000000000", // 0 @@ -92,7 +91,6 @@ func init() { } func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) { - var ( env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) stack = newstack() @@ -641,7 +639,6 @@ func TestCreate2Addreses(t *testing.T) { expected: "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0", }, } { - origin := common.BytesToAddress(common.FromHex(tt.origin)) salt := common.BytesToHash(common.FromHex(tt.salt)) code := common.FromHex(tt.code) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 4f1ebc43a229..40fe23dc516c 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -114,7 +114,6 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { // 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) { - // Increment the call depth which is restricted to 1024 in.evm.depth++ defer func() { in.evm.depth-- }() diff --git a/core/vm/interpreter_test.go b/core/vm/interpreter_test.go index dfae0f2e2af7..31ee9922dbac 100644 --- a/core/vm/interpreter_test.go +++ b/core/vm/interpreter_test.go @@ -73,5 +73,4 @@ func TestLoopInterrupt(t *testing.T) { } } } - } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 2524c9c99cc4..707b52e79daf 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -198,7 +198,6 @@ func newSpuriousDragonInstructionSet() JumpTable { instructionSet := newTangerineWhistleInstructionSet() instructionSet[EXP].dynamicGas = gasExpEIP158 return validate(instructionSet) - } // EIP 150 a.k.a Tangerine Whistle diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 627edae07786..8864219ff1ac 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -379,7 +379,6 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode // BenchmarkSimpleLoop test a pretty simple loop which loops until OOG // 55 ms func BenchmarkSimpleLoop(b *testing.B) { - staticCallIdentity := []byte{ byte(vm.JUMPDEST), // [ count ] // push args for the call @@ -498,7 +497,6 @@ func TestEip2929Cases(t *testing.T) { t.Skip("Test only useful for generating documentation") id := 1 prettyPrint := func(comment string, code []byte) { - instrs := make([]string, 0) it := asm.NewInstructionIterator(code) for it.Next() { diff --git a/crypto/bls12381/field_element_test.go b/crypto/bls12381/field_element_test.go index 0f6abd280cbb..70bbe5cfe5e7 100644 --- a/crypto/bls12381/field_element_test.go +++ b/crypto/bls12381/field_element_test.go @@ -102,7 +102,6 @@ func TestFieldElementEquality(t *testing.T) { if a12.equal(b12) { t.Fatal("a != a + 1") } - } func TestFieldElementHelpers(t *testing.T) { diff --git a/crypto/bls12381/fp12.go b/crypto/bls12381/fp12.go index 3141c76c3995..51e949fe5f04 100644 --- a/crypto/bls12381/fp12.go +++ b/crypto/bls12381/fp12.go @@ -96,7 +96,6 @@ func (e *fp12) add(c, a, b *fe12) { fp6 := e.fp6 fp6.add(&c[0], &a[0], &b[0]) fp6.add(&c[1], &a[1], &b[1]) - } func (e *fp12) double(c, a *fe12) { @@ -109,7 +108,6 @@ func (e *fp12) sub(c, a, b *fe12) { fp6 := e.fp6 fp6.sub(&c[0], &a[0], &b[0]) fp6.sub(&c[1], &a[1], &b[1]) - } func (e *fp12) neg(c, a *fe12) { diff --git a/crypto/bls12381/fp_test.go b/crypto/bls12381/fp_test.go index 97528d9db32e..0bad35de1630 100644 --- a/crypto/bls12381/fp_test.go +++ b/crypto/bls12381/fp_test.go @@ -465,7 +465,6 @@ func TestFpNonResidue(t *testing.T) { i -= 1 } } - } func TestFp2Serialization(t *testing.T) { diff --git a/crypto/bls12381/g2.go b/crypto/bls12381/g2.go index fa110e3edfc5..c2ca959bcca1 100644 --- a/crypto/bls12381/g2.go +++ b/crypto/bls12381/g2.go @@ -41,7 +41,6 @@ func (p *PointG2) Zero() *PointG2 { p[1].one() p[2].zero() return p - } type tempG2 struct { diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index 96e33da006fb..8ca42c9c8ee6 100644 --- a/crypto/ecies/ecies_test.go +++ b/crypto/ecies/ecies_test.go @@ -334,7 +334,6 @@ func testParamSelection(t *testing.T, c testCase) { if err == nil { t.Fatalf("ecies: encryption should not have succeeded (%s)\n", c.Name) } - } // Ensure that the basic public key validation in the decryption operation diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index ff34d932f018..de5708be32e7 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -817,7 +817,6 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, reqTimer metrics.Timer, resInMeter metrics.Meter, resDropMeter metrics.Meter, results int, validate func(index int, header *types.Header) error, reconstruct func(index int, result *fetchResult)) (int, error) { - // Short circuit if the data was never requested request := pendPool[id] if request == nil { diff --git a/eth/downloader/queue_test.go b/eth/downloader/queue_test.go index 09b18afe5df5..e2e9654eaee9 100644 --- a/eth/downloader/queue_test.go +++ b/eth/downloader/queue_test.go @@ -185,7 +185,6 @@ func TestBasics(t *testing.T) { if got, exp := fetchReq.Headers[0].Number.Uint64(), uint64(1); got != exp { t.Fatalf("expected header %d, got %d", exp, got) } - } if exp, got := q.blockTaskQueue.Size(), numOfBlocks-10; exp != got { t.Errorf("expected block task queue to be %d, got %d", exp, got) @@ -239,7 +238,6 @@ func TestEmptyBlocks(t *testing.T) { if fetchReq != nil { t.Fatal("there should be no body fetch tasks remaining") } - } if q.blockTaskQueue.Size() != numOfBlocks-10 { t.Errorf("expected block task queue to be %d, got %d", numOfBlocks-10, q.blockTaskQueue.Size()) @@ -280,7 +278,6 @@ func XTestDelivery(t *testing.T) { world.progress(10) if false { log.Root().SetHandler(log.StdoutHandler) - } q := newQueue(10, 10) var wg sync.WaitGroup @@ -315,7 +312,6 @@ func XTestDelivery(t *testing.T) { fmt.Printf("got %d results, %d tot\n", len(res), tot) // Now we can forget about these world.forget(res[len(res)-1].Header.Number.Uint64()) - } }() wg.Add(1) @@ -396,7 +392,6 @@ func XTestDelivery(t *testing.T) { } for i := 0; i < 50; i++ { time.Sleep(2990 * time.Millisecond) - } }() wg.Add(1) @@ -447,10 +442,8 @@ func (n *network) forget(blocknum uint64) { n.chain = n.chain[index:] n.receipts = n.receipts[index:] n.offset = int(blocknum) - } func (n *network) progress(numBlocks int) { - n.lock.Lock() defer n.lock.Unlock() //fmt.Printf("progressing...\n") @@ -458,7 +451,6 @@ func (n *network) progress(numBlocks int) { n.chain = append(n.chain, newBlocks...) n.receipts = append(n.receipts, newR...) n.cond.Broadcast() - } func (n *network) headers(from int) []*types.Header { diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index 7d0b78dca65a..42192571804a 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -790,7 +790,6 @@ func TestSkeletonSyncRetrievals(t *testing.T) { check := func() error { if len(progress.Subchains) != len(tt.midstate) { return fmt.Errorf("test %d, mid state: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.midstate)) - } for j := 0; j < len(progress.Subchains); j++ { if progress.Subchains[j].Head != tt.midstate[j].Head { diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index d75ba3f8e0ee..bd1a34c83c00 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -692,7 +692,6 @@ func (f *BlockFetcher) loop() { } else { f.forgetHash(hash) } - } if matched { task.transactions = append(task.transactions[:i], task.transactions[i+1:]...) diff --git a/eth/filters/api.go b/eth/filters/api.go index 6463a189b061..07714791d263 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -248,7 +248,6 @@ func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subsc } go func() { - for { select { case logs := <-matchedLogs: diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index f415046a82aa..ae4f069048f3 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -72,7 +72,6 @@ func BenchmarkFilters(b *testing.B) { receipt := makeReceipt(addr4) gen.AddUncheckedReceipt(receipt) gen.AddUncheckedTx(types.NewTransaction(999, common.HexToAddress("0x999"), big.NewInt(999), 999, gen.BaseFee(), nil)) - } }) for i, block := range chain { diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index dffbfbe612a2..453bc5e98e31 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -490,7 +490,6 @@ func TestCheckpointChallenge(t *testing.T) { } func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpoint bool, timeout bool, empty bool, match bool, drop bool) { - // Reduce the checkpoint handshake challenge timeout defer func(old time.Duration) { syncChallengeTimeout = old }(syncChallengeTimeout) syncChallengeTimeout = 250 * time.Millisecond diff --git a/eth/protocols/eth/protocol_test.go b/eth/protocols/eth/protocol_test.go index 5ca895774121..a86fbb0a6906 100644 --- a/eth/protocols/eth/protocol_test.go +++ b/eth/protocols/eth/protocol_test.go @@ -115,12 +115,10 @@ func TestEth66EmptyMessages(t *testing.T) { t.Errorf("test %d, type %T, have\n\t%x\nwant\n\t%x", i, msg, have, want) } } - } // TestEth66Messages tests the encoding of all redefined eth66 messages func TestEth66Messages(t *testing.T) { - // Some basic structs used during testing var ( header *types.Header diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index ae8b09a0ffca..a076168f7101 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -878,7 +878,6 @@ func (r *callframeResult) GetError() goja.Value { return r.vm.ToValue(r.err.Error()) } return goja.Undefined() - } func (r *callframeResult) setupObject() *goja.Object { diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index 7af2bf45d791..a86f4339f425 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -79,7 +79,6 @@ type StorageResult struct { // GetProof returns the account and storage values of the specified account including the Merkle-proof. // The block number can be nil, in which case the value is taken from the latest known block. func (ec *Client) GetProof(ctx context.Context, account common.Address, keys []string, blockNumber *big.Int) (*AccountResult, error) { - type storageResult struct { Key string `json:"key"` Value *hexutil.Big `json:"value"` diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index 758acc085b37..a0c17a034226 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -222,7 +222,6 @@ func testGetProof(t *testing.T, client *rpc.Client) { if proof.Key != testSlot.String() { t.Fatalf("invalid storage proof key, want: %v, got: %v", testSlot.String(), proof.Key) } - } func testGCStats(t *testing.T, client *rpc.Client) { diff --git a/ethstats/ethstats_test.go b/ethstats/ethstats_test.go index 0692ecdae9be..60322f765439 100644 --- a/ethstats/ethstats_test.go +++ b/ethstats/ethstats_test.go @@ -79,5 +79,4 @@ func TestParseEthstatsURL(t *testing.T) { t.Errorf("case=%d mismatch host value, got: %v ,want: %v", i, host, c.host) } } - } diff --git a/graphql/service.go b/graphql/service.go index 29d98ad74683..396a477005dd 100644 --- a/graphql/service.go +++ b/graphql/service.go @@ -52,7 +52,6 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write(responseJSON) - } // New constructs a new GraphQL service instance. diff --git a/internal/jsre/pretty.go b/internal/jsre/pretty.go index 4171e0090617..bd772b4927c2 100644 --- a/internal/jsre/pretty.go +++ b/internal/jsre/pretty.go @@ -219,7 +219,6 @@ func (ctx ppctx) fields(obj *goja.Object) []string { vals = append(vals, k) } } - } iterOwnAndConstructorKeys(ctx.vm, obj, add) sort.Strings(vals) diff --git a/les/api_test.go b/les/api_test.go index ea6870e35627..3db1c5fd5ec9 100644 --- a/les/api_test.go +++ b/les/api_test.go @@ -340,7 +340,6 @@ func freezeClient(ctx context.Context, t *testing.T, server *rpc.Client, clientI if err := server.CallContext(ctx, nil, "debug_freezeClient", clientID); err != nil { t.Fatalf("Failed to freeze client: %v", err) } - } func setCapacity(ctx context.Context, t *testing.T, server *rpc.Client, clientID enode.ID, cap uint64) { diff --git a/les/downloader/downloader.go b/les/downloader/downloader.go index 448a94192b87..b9da76d3478d 100644 --- a/les/downloader/downloader.go +++ b/les/downloader/downloader.go @@ -1330,7 +1330,6 @@ func (d *Downloader) fetchParts(deliveryCh chan dataPack, deliver func(dataPack) expire func() map[string]int, pending func() int, inFlight func() bool, reserve func(*peerConnection, int) (*fetchRequest, bool, bool), fetchHook func([]*types.Header), fetch func(*peerConnection, *fetchRequest) error, cancel func(*fetchRequest), capacity func(*peerConnection) int, idle func() ([]*peerConnection, int), setIdle func(*peerConnection, int, time.Time), kind string) error { - // Create a ticker to detect expired retrieval tasks ticker := time.NewTicker(100 * time.Millisecond) defer ticker.Stop() diff --git a/les/downloader/downloader_test.go b/les/downloader/downloader_test.go index b4b12b1b2957..792fc284619d 100644 --- a/les/downloader/downloader_test.go +++ b/les/downloader/downloader_test.go @@ -621,7 +621,6 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { t.Fatalf("block synchronization failed: %v", err) } tester.terminate() - } // Tests that simple synchronization against a forked chain works correctly. In diff --git a/les/downloader/queue.go b/les/downloader/queue.go index 04ec12cfa9e7..5744b3ee279d 100644 --- a/les/downloader/queue.go +++ b/les/downloader/queue.go @@ -833,7 +833,6 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque, pendPool map[string]*fetchRequest, reqTimer metrics.Timer, results int, validate func(index int, header *types.Header) error, reconstruct func(index int, result *fetchResult)) (int, error) { - // Short circuit if the data was never requested request := pendPool[id] if request == nil { diff --git a/les/downloader/queue_test.go b/les/downloader/queue_test.go index 2a884d30aaba..2da8e4958858 100644 --- a/les/downloader/queue_test.go +++ b/les/downloader/queue_test.go @@ -179,7 +179,6 @@ func TestBasics(t *testing.T) { if got, exp := fetchReq.Headers[0].Number.Uint64(), uint64(1); got != exp { t.Fatalf("expected header %d, got %d", exp, got) } - } if exp, got := q.blockTaskQueue.Size(), numOfBlocks-10; exp != got { t.Errorf("expected block task queue to be %d, got %d", exp, got) @@ -227,7 +226,6 @@ func TestEmptyBlocks(t *testing.T) { if fetchReq != nil { t.Fatal("there should be no body fetch tasks remaining") } - } if q.blockTaskQueue.Size() != numOfBlocks-10 { t.Errorf("expected block task queue to be %d, got %d", numOfBlocks-10, q.blockTaskQueue.Size()) @@ -268,7 +266,6 @@ func XTestDelivery(t *testing.T) { world.progress(10) if false { log.Root().SetHandler(log.StdoutHandler) - } q := newQueue(10, 10) var wg sync.WaitGroup @@ -299,7 +296,6 @@ func XTestDelivery(t *testing.T) { fmt.Printf("got %d results, %d tot\n", len(res), tot) // Now we can forget about these world.forget(res[len(res)-1].Header.Number.Uint64()) - } }() wg.Add(1) @@ -362,7 +358,6 @@ func XTestDelivery(t *testing.T) { } for i := 0; i < 50; i++ { time.Sleep(2990 * time.Millisecond) - } }() wg.Add(1) @@ -413,10 +408,8 @@ func (n *network) forget(blocknum uint64) { n.chain = n.chain[index:] n.receipts = n.receipts[index:] n.offset = int(blocknum) - } func (n *network) progress(numBlocks int) { - n.lock.Lock() defer n.lock.Unlock() //fmt.Printf("progressing...\n") @@ -424,7 +417,6 @@ func (n *network) progress(numBlocks int) { n.chain = append(n.chain, newBlocks...) n.receipts = append(n.receipts, newR...) n.cond.Broadcast() - } func (n *network) headers(from int) []*types.Header { diff --git a/les/fetcher/block_fetcher.go b/les/fetcher/block_fetcher.go index 283008db0f1e..86b3c552ce27 100644 --- a/les/fetcher/block_fetcher.go +++ b/les/fetcher/block_fetcher.go @@ -641,7 +641,6 @@ func (f *BlockFetcher) loop() { } else { f.forgetHash(hash) } - } if matched { task.transactions = append(task.transactions[:i], task.transactions[i+1:]...) diff --git a/les/flowcontrol/manager_test.go b/les/flowcontrol/manager_test.go index 9d2f88763614..564d813f15a3 100644 --- a/les/flowcontrol/manager_test.go +++ b/les/flowcontrol/manager_test.go @@ -104,7 +104,6 @@ func testConstantTotalCapacity(t *testing.T, nodeCount, maxCapacityNodes, random if ratio < 0.98 || ratio > 1.02 { t.Errorf("totalCost/totalCapacity/testLength ratio incorrect (expected: 1, got: %f)", ratio) } - } func (n *testNode) send(t *testing.T, now mclock.AbsTime) bool { diff --git a/les/vflux/client/serverpool.go b/les/vflux/client/serverpool.go index e481075f70bd..cf96f0ee3a23 100644 --- a/les/vflux/client/serverpool.go +++ b/les/vflux/client/serverpool.go @@ -222,7 +222,6 @@ func (s *serverPoolIterator) Close() { func (s *ServerPool) AddMetrics( suggestedTimeoutGauge, totalValueGauge, serverSelectableGauge, serverConnectedGauge metrics.Gauge, sessionValueMeter, serverDialedMeter metrics.Meter) { - s.suggestedTimeoutGauge = suggestedTimeoutGauge s.totalValueGauge = totalValueGauge s.sessionValueMeter = sessionValueMeter diff --git a/les/vflux/client/wrsiterator.go b/les/vflux/client/wrsiterator.go index 8a2e39ad4422..1b37cba6e5de 100644 --- a/les/vflux/client/wrsiterator.go +++ b/les/vflux/client/wrsiterator.go @@ -109,7 +109,6 @@ func (w *WrsIterator) chooseNode() *enode.Node { return w.ns.GetNode(id) } } - } // Close ends the iterator. diff --git a/les/vflux/server/clientpool_test.go b/les/vflux/server/clientpool_test.go index 49e66297a1b1..790ec5136078 100644 --- a/les/vflux/server/clientpool_test.go +++ b/les/vflux/server/clientpool_test.go @@ -410,7 +410,6 @@ func TestFreeClientKickedOut(t *testing.T) { clock.Run(5 * time.Minute) for i := 0; i < 10; i++ { connect(pool, newPoolTestPeer(i+10, kicked)) - } clock.Run(0) diff --git a/metrics/influxdb/influxdbv2.go b/metrics/influxdb/influxdbv2.go index 31f956481dae..c8eca4161614 100644 --- a/metrics/influxdb/influxdbv2.go +++ b/metrics/influxdb/influxdbv2.go @@ -81,7 +81,6 @@ func (r *v2Reporter) run() { } } } - } func (r *v2Reporter) send() { @@ -90,7 +89,6 @@ func (r *v2Reporter) send() { namespace := r.namespace switch metric := i.(type) { - case metrics.Counter: v := metric.Count() l := r.cache[name] diff --git a/metrics/registry_test.go b/metrics/registry_test.go index 6cfedfd88f00..d277ae5c3e47 100644 --- a/metrics/registry_test.go +++ b/metrics/registry_test.go @@ -307,5 +307,4 @@ func TestWalkRegistries(t *testing.T) { if prefix != "prefix.prefix2." { t.Fatal(prefix) } - } diff --git a/miner/miner_test.go b/miner/miner_test.go index cf619845dd47..5bf344fd7076 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -188,7 +188,6 @@ func TestStartStopMiner(t *testing.T) { waitForMiningState(t, miner, true) miner.Stop() waitForMiningState(t, miner, false) - } func TestCloseMiner(t *testing.T) { diff --git a/mobile/ethclient.go b/mobile/ethclient.go index 662125c4adeb..00bcb3a2b9bc 100644 --- a/mobile/ethclient.go +++ b/mobile/ethclient.go @@ -94,7 +94,6 @@ func (ec *EthereumClient) GetTransactionCount(ctx *Context, hash *Hash) (count i func (ec *EthereumClient) GetTransactionInBlock(ctx *Context, hash *Hash, index int) (tx *Transaction, _ error) { rawTx, err := ec.client.TransactionInBlock(ctx.context, hash.hash, uint(index)) return &Transaction{rawTx}, err - } // GetTransactionReceipt returns the receipt of a transaction by transaction hash. diff --git a/node/node_test.go b/node/node_test.go index 9f9febcacbfe..7c76e21f6baf 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -581,7 +581,6 @@ func (test rpcPrefixTest) check(t *testing.T, node *Node) { if err == nil { t.Errorf("Error: %s: WebSocket connection succeeded for path in wantNoWS", path) } - } } @@ -614,7 +613,6 @@ func doHTTPRequest(t *testing.T, req *http.Request) *http.Response { resp, err := client.Do(req) if err != nil { t.Fatalf("could not issue a GET request to the given endpoint: %v", err) - } return resp } diff --git a/node/rpcstack.go b/node/rpcstack.go index 455e29beaf65..9b5873e90a5f 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -438,7 +438,6 @@ func (h *virtualHostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // It's an IP address, we can serve that h.next.ServeHTTP(w, r) return - } // Not an IP address, but a hostname. Need to validate if _, exist := h.vhosts["*"]; exist { diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go index a344a8d5cbbe..b221a0597fc4 100644 --- a/p2p/simulations/http.go +++ b/p2p/simulations/http.go @@ -367,7 +367,6 @@ func (s *Server) StopMocker(w http.ResponseWriter, req *http.Request) { // GetMockerList returns a list of available mockers func (s *Server) GetMockers(w http.ResponseWriter, req *http.Request) { - list := GetMockerList() s.JSON(w, http.StatusOK, list) } diff --git a/p2p/simulations/http_test.go b/p2p/simulations/http_test.go index f5172f3f23db..5775977a41f0 100644 --- a/p2p/simulations/http_test.go +++ b/p2p/simulations/http_test.go @@ -489,7 +489,6 @@ func (t *expectEvents) expect(events ...*Event) { } switch expected.Type { - case EventTypeNode: if event.Node == nil { t.Fatal("expected event.Node to be set") @@ -514,7 +513,6 @@ func (t *expectEvents) expect(events ...*Event) { if event.Conn.Up != expected.Conn.Up { t.Fatalf("expected conn event %d to have up=%t, got up=%t", i, expected.Conn.Up, event.Conn.Up) } - } i++ diff --git a/p2p/simulations/mocker.go b/p2p/simulations/mocker.go index fd25e2c918dd..5a74b02c4347 100644 --- a/p2p/simulations/mocker.go +++ b/p2p/simulations/mocker.go @@ -157,7 +157,6 @@ func probabilistic(net *Network, quit chan struct{}, nodeCount int) { } wg.Wait() } - } //connect nodeCount number of nodes in a ring diff --git a/p2p/simulations/network.go b/p2p/simulations/network.go index 962910dd25bf..d6c5aca73c5c 100644 --- a/p2p/simulations/network.go +++ b/p2p/simulations/network.go @@ -235,7 +235,6 @@ func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub } peer := event.Peer switch event.Type { - case p2p.PeerEventTypeAdd: net.DidConnect(id, peer) @@ -247,7 +246,6 @@ func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub case p2p.PeerEventTypeMsgRecv: net.DidReceive(peer, id, event.Protocol, *event.MsgCode) - } case err := <-sub.Err(): @@ -927,7 +925,6 @@ func (net *Network) snapshot(addServices []string, removeServices []string) (*Sn if !haveSvc { cleanedServices = append(cleanedServices, svc) } - } snap.Nodes[i].Node.Config.Lifecycles = cleanedServices } @@ -1021,7 +1018,6 @@ func (net *Network) Load(snap *Snapshot) error { // Start connecting. for _, conn := range snap.Conns { - if !net.GetNode(conn.One).Up() || !net.GetNode(conn.Other).Up() { //in this case, at least one of the nodes of a connection is not up, //so it would result in the snapshot `Load` to fail diff --git a/p2p/simulations/network_test.go b/p2p/simulations/network_test.go index fa6936d273c5..ab8cf19462e7 100644 --- a/p2p/simulations/network_test.go +++ b/p2p/simulations/network_test.go @@ -36,7 +36,6 @@ import ( // Tests that a created snapshot with a minimal service only contains the expected connections // and that a network when loaded with this snapshot only contains those same connections func TestSnapshot(t *testing.T) { - // PART I // create snapshot from ring network @@ -204,7 +203,6 @@ OuterTwo: t.Fatal(ctx.Err()) case ev := <-evC: if ev.Type == EventTypeConn && !ev.Control { - // fail on any disconnect if !ev.Conn.Up { t.Fatalf("unexpected disconnect: %v -> %v", ev.Conn.One, ev.Conn.Other) @@ -693,7 +691,6 @@ func BenchmarkMinimalService(b *testing.B) { } func benchmarkMinimalServiceTmp(b *testing.B) { - // stop timer to discard setup time pollution args := strings.Split(b.Name(), "/") nodeCount, err := strconv.ParseInt(args[2], 10, 16) diff --git a/rlp/decode_test.go b/rlp/decode_test.go index e0d33dc43ee9..00722f847bbb 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -1043,7 +1043,6 @@ func TestInvalidOptionalField(t *testing.T) { t.Errorf("wrong error for %T: %v", test.v, err.Error()) } } - } func ExampleDecode() { diff --git a/rlp/iterator.go b/rlp/iterator.go index 353ef09fbdf2..6be574572e61 100644 --- a/rlp/iterator.go +++ b/rlp/iterator.go @@ -36,7 +36,6 @@ func NewListIterator(data RawValue) (*listIterator, error) { data: data[t : t+c], } return it, nil - } // Next forwards the iterator one step, returns true if it was not at end yet diff --git a/signer/core/api.go b/signer/core/api.go index f06fbeb76dd1..f10f03d83ac1 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -319,7 +319,6 @@ func (api *SignerAPI) openTrezor(url accounts.URL) { log.Warn("failed to open wallet", "wallet", url, "err", err) return } - } // startUSBListener starts a listener for USB events, for hardware wallet interaction @@ -612,7 +611,6 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args apitypes.SendTxA api.UI.OnApprovedTx(response) // ...and to the external caller return &response, nil - } func (api *SignerAPI) SignGnosisSafeTx(ctx context.Context, signerAddress common.MixedcaseAddress, gnosisTx GnosisSafeTx, methodSelector *string) (*GnosisSafeTx, error) { diff --git a/signer/core/api_test.go b/signer/core/api_test.go index 821af663fa81..6fa2af1836b2 100644 --- a/signer/core/api_test.go +++ b/signer/core/api_test.go @@ -55,7 +55,6 @@ func (ui *headlessUi) RegisterUIServer(api *core.UIServerAPI) {} func (ui *headlessUi) OnApprovedTx(tx ethapi.SignTransactionResult) {} func (ui *headlessUi) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) { - switch <-ui.approveCh { case "Y": return core.SignTxResponse{request.Transaction, true}, nil @@ -125,7 +124,6 @@ func setup(t *testing.T) (*core.SignerAPI, *headlessUi) { am := core.StartClefAccountManager(tmpDirName(t), true, true, "") api := core.NewSignerAPI(am, 1337, true, ui, db, true, &storage.NoStorage{}) return api, ui - } func createAccount(ui *headlessUi, api *core.SignerAPI, t *testing.T) { ui.approveCh <- "Y" @@ -139,7 +137,6 @@ func createAccount(ui *headlessUi, api *core.SignerAPI, t *testing.T) { } func failCreateAccountWithPassword(ui *headlessUi, api *core.SignerAPI, password string, t *testing.T) { - ui.approveCh <- "Y" // We will be asked three times to provide a suitable password ui.inputCh <- password @@ -169,7 +166,6 @@ func failCreateAccount(ui *headlessUi, api *core.SignerAPI, t *testing.T) { func list(ui *headlessUi, api *core.SignerAPI, t *testing.T) ([]common.Address, error) { ui.approveCh <- "A" return api.List(context.Background()) - } func TestNewAcc(t *testing.T) { @@ -321,5 +317,4 @@ func TestSignTx(t *testing.T) { if bytes.Equal(res.Raw, res2.Raw) { t.Error("Expected tx to be modified by UI") } - } diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 6bab4ce35d75..0652108f889e 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -545,7 +545,6 @@ func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interf return math.U256Bytes(b), nil } return nil, fmt.Errorf("unrecognized type '%s'", encType) - } // dataMismatchError generates an error for a mismatch between @@ -672,7 +671,6 @@ func formatPrimitiveValue(encType string, encValue interface{}) (string, error) } if strings.HasPrefix(encType, "bytes") { return fmt.Sprintf("%s", encValue), nil - } if strings.HasPrefix(encType, "uint") || strings.HasPrefix(encType, "int") { if b, err := parseInteger(encType, encValue); err != nil { diff --git a/signer/core/auditlog.go b/signer/core/auditlog.go index 663d6d131735..a0b292bf714c 100644 --- a/signer/core/auditlog.go +++ b/signer/core/auditlog.go @@ -110,7 +110,6 @@ func (l *AuditLogger) Version(ctx context.Context) (string, error) { data, err := l.api.Version(ctx) l.log.Info("Version", "type", "response", "data", data, "error", err) return data, err - } func NewAuditLogger(path string, api ExternalAPI) (*AuditLogger, error) { diff --git a/signer/core/cliui.go b/signer/core/cliui.go index 05c60906cc0c..187eb1390af7 100644 --- a/signer/core/cliui.go +++ b/signer/core/cliui.go @@ -59,7 +59,6 @@ func (ui *CommandlineUI) readString() string { } func (ui *CommandlineUI) OnInputRequired(info UserInputRequest) (UserInputResponse, error) { - fmt.Printf("## %s\n\n%s\n", info.Title, info.Prompt) defer fmt.Println("-----------------------") if info.IsPassword { @@ -147,7 +146,6 @@ func (ui *CommandlineUI) ApproveTx(request *SignTxRequest) (SignTxResponse, erro fmt.Printf(" * %s : %s\n", m.Typ, m.Message) } fmt.Println() - } fmt.Printf("\n") showMetadata(request.Meta) @@ -209,7 +207,6 @@ func (ui *CommandlineUI) ApproveListing(request *ListRequest) (ListResponse, err // ApproveNewAccount prompt the user for confirmation to create new Account, and reveal to caller func (ui *CommandlineUI) ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error) { - ui.mu.Lock() defer ui.mu.Unlock() @@ -245,7 +242,6 @@ func (ui *CommandlineUI) OnApprovedTx(tx ethapi.SignTransactionResult) { } func (ui *CommandlineUI) OnSignerStartup(info StartupInfo) { - fmt.Printf("------- Signer info -------\n") for k, v := range info.Info { fmt.Printf("* %v : %v\n", k, v) diff --git a/signer/core/validation_test.go b/signer/core/validation_test.go index 7105691d29c0..6adaa21afd4e 100644 --- a/signer/core/validation_test.go +++ b/signer/core/validation_test.go @@ -38,7 +38,6 @@ func TestPasswordValidation(t *testing.T) { if err == nil && test.shouldFail { t.Errorf("password '%v' should fail validation", test.pw) } else if err != nil && !test.shouldFail { - t.Errorf("password '%v' shound not fail validation, but did: %v", test.pw, err) } } diff --git a/signer/fourbyte/validation_test.go b/signer/fourbyte/validation_test.go index 2e6d9f2d9bb7..1b0ab507a864 100644 --- a/signer/fourbyte/validation_test.go +++ b/signer/fourbyte/validation_test.go @@ -53,7 +53,6 @@ func dummyTxArgs(t txtestcase) *apitypes.SendTxArgs { if t.i != "" { a := hexutil.Bytes(common.FromHex(t.i)) input = &a - } return &apitypes.SendTxArgs{ From: *from, diff --git a/signer/rules/rules.go b/signer/rules/rules.go index 6852d86f3ec7..95b02e9cecf0 100644 --- a/signer/rules/rules.go +++ b/signer/rules/rules.go @@ -67,7 +67,6 @@ func (r *rulesetUI) Init(javascriptRules string) error { return nil } func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (goja.Value, error) { - // Instantiate a fresh vm engine every time vm := goja.New() diff --git a/signer/rules/rules_test.go b/signer/rules/rules_test.go index af4ed2d7e132..32901e2ff14c 100644 --- a/signer/rules/rules_test.go +++ b/signer/rules/rules_test.go @@ -152,7 +152,6 @@ func TestListRequest(t *testing.T) { } func TestSignTxRequest(t *testing.T) { - js := ` function ApproveTx(r){ console.log("transaction.from", r.transaction.from); @@ -245,7 +244,6 @@ func (d *dummyUI) OnSignerStartup(info core.StartupInfo) { //TestForwarding tests that the rule-engine correctly dispatches requests to the next caller func TestForwarding(t *testing.T) { - js := "" ui := &dummyUI{make([]string, 0)} jsBackend := storage.NewEphemeralStorage() @@ -268,11 +266,8 @@ func TestForwarding(t *testing.T) { expCalls := 6 if len(ui.calls) != expCalls { - t.Errorf("Expected %d forwarded calls, got %d: %s", expCalls, len(ui.calls), strings.Join(ui.calls, ",")) - } - } func TestMissingFunc(t *testing.T) { @@ -296,10 +291,8 @@ func TestMissingFunc(t *testing.T) { t.Errorf("Expected missing method to cause non-approval") } t.Logf("Err %v", err) - } func TestStorage(t *testing.T) { - js := ` function testStorage(){ storage.put("mykey", "myvalue") @@ -348,7 +341,6 @@ func TestStorage(t *testing.T) { t.Errorf("Unexpected data, expected '%v', got '%v'", exp, retval) } t.Logf("Err %v", err) - } const ExampleTxWindow = ` @@ -548,7 +540,6 @@ func (d *dontCallMe) OnApprovedTx(tx ethapi.SignTransactionResult) { // if it does, that would be bad since developers may rely on that to store data, // instead of using the disk-based data storage func TestContextIsCleared(t *testing.T) { - js := ` function ApproveTx(){ if (typeof foobar == 'undefined') { @@ -580,7 +571,6 @@ func TestContextIsCleared(t *testing.T) { } func TestSignData(t *testing.T) { - js := `function ApproveListing(){ return "Approve" } diff --git a/signer/storage/aes_gcm_storage_test.go b/signer/storage/aes_gcm_storage_test.go index a2a95d9deedf..e1fea59280a8 100644 --- a/signer/storage/aes_gcm_storage_test.go +++ b/signer/storage/aes_gcm_storage_test.go @@ -51,7 +51,6 @@ func TestEncryption(t *testing.T) { } func TestFileStorage(t *testing.T) { - a := map[string]storedCredential{ "secret": { Iv: common.Hex2Bytes("cdb30036279601aeee60f16b"), diff --git a/tests/difficulty_test_util.go b/tests/difficulty_test_util.go index bda5a9611be8..62b978f9ef2b 100644 --- a/tests/difficulty_test_util.go +++ b/tests/difficulty_test_util.go @@ -65,5 +65,4 @@ func (test *DifficultyTest) Run(config *params.ChainConfig) error { test.CurrentTimestamp, test.CurrentBlockNumber, actual, exp) } return nil - } diff --git a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go index 229dea95b1c4..c2db919d5a97 100644 --- a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go +++ b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go @@ -163,7 +163,6 @@ func (f *fuzzer) fuzz() int { // Modify something in the proof db // add stuff to proof db // drop stuff from proof db - } if f.exhausted { break diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 363b0d47c46b..17d67a8758c2 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -138,7 +138,6 @@ func Debug(data []byte) int { } func (f *fuzzer) fuzz() int { - // This spongeDb is used to check the sequence of disk-db-writes var ( spongeA = &spongeDb{sponge: sha3.NewLegacyKeccak256()} diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index e8ad9fcf25ce..ca1509085b12 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -84,11 +84,9 @@ func (ds *dataSource) Ended() bool { } func Generate(input []byte) randTest { - var allKeys [][]byte r := newDataSource(input) genKey := func() []byte { - if len(allKeys) < 2 || r.readByte() < 0x0f { // new key key := make([]byte, r.readByte()%50) @@ -103,7 +101,6 @@ func Generate(input []byte) randTest { var steps randTest for i := 0; !r.Ended(); i++ { - step := randTestStep{op: int(r.readByte()) % opMax} switch step.op { case opUpdate: @@ -141,7 +138,6 @@ func Fuzz(input []byte) int { } func runRandTest(rt randTest) error { - triedb := trie.NewDatabase(memorydb.New()) tr := trie.NewEmpty(triedb) diff --git a/tests/state_test.go b/tests/state_test.go index 93d8a1210626..965ef71ba40e 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -249,7 +249,6 @@ func runBenchmark(b *testing.B, t *StateTest) { } statedb.RevertToSnapshot(snapshot) } - }) } } diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index f24c749716e5..069e4981d71a 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -345,7 +345,6 @@ func TestStacktrieNotModifyValues(t *testing.T) { if !bytes.Equal(have, want) { t.Fatalf("item %d, have %#x want %#x", i, have, want) } - } } diff --git a/trie/trie_test.go b/trie/trie_test.go index 7baae88aeabe..135e94e3d0a3 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -352,7 +352,6 @@ func TestRandomCases(t *testing.T) { {op: 1, key: common.Hex2Bytes("fd"), value: common.Hex2Bytes("")}, // step 25 } runRandTest(rt) - } // randTest performs random trie operations. From eb2b8cb4fd581a69b71d43f8ba8bcbebc4d9005b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 25 Jul 2022 16:49:16 +0300 Subject: [PATCH 118/715] eth/tracers/js: fix capitalization in tests --- eth/tracers/js/tracer_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 2863bd4451b8..0bdda770af4d 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -103,15 +103,15 @@ func TestTracer(t *testing.T) { { // tests that we don't panic on bad arguments to memory access code: "{depths: [], step: function(log) { this.depths.push(log.memory.slice(-1,-2)); }, fault: function() {}, result: function() { return this.depths; }}", want: ``, - fail: "Tracer accessed out of bound memory: offset -1, end -2 at step (:1:53(15)) in server-side tracer function 'step'", + fail: "tracer accessed out of bound memory: offset -1, end -2 at step (:1:53(15)) in server-side tracer function 'step'", }, { // tests that we don't panic on bad arguments to stack peeks code: "{depths: [], step: function(log) { this.depths.push(log.stack.peek(-1)); }, fault: function() {}, result: function() { return this.depths; }}", want: ``, - fail: "Tracer accessed out of bound stack: size 0, index -1 at step (:1:53(13)) in server-side tracer function 'step'", + fail: "tracer accessed out of bound stack: size 0, index -1 at step (:1:53(13)) in server-side tracer function 'step'", }, { // tests that we don't panic on bad arguments to memory getUint code: "{ depths: [], step: function(log, db) { this.depths.push(log.memory.getUint(-64));}, fault: function() {}, result: function() { return this.depths; }}", want: ``, - fail: "Tracer accessed out of bound memory: available 0, offset -64, size 32 at step (:1:58(13)) in server-side tracer function 'step'", + fail: "tracer accessed out of bound memory: available 0, offset -64, size 32 at step (:1:58(13)) in server-side tracer function 'step'", }, { // tests some general counting code: "{count: 0, step: function() { this.count += 1; }, fault: function() {}, result: function() { return this.count; }}", want: `3`, @@ -232,7 +232,7 @@ func TestIsPrecompile(t *testing.T) { t.Error(err) } if string(res) != "false" { - t.Errorf("Tracer should not consider blake2f as precompile in byzantium") + t.Errorf("tracer should not consider blake2f as precompile in byzantium") } tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil) @@ -242,7 +242,7 @@ func TestIsPrecompile(t *testing.T) { t.Error(err) } if string(res) != "true" { - t.Errorf("Tracer should consider blake2f as precompile in istanbul") + t.Errorf("tracer should consider blake2f as precompile in istanbul") } } From f3af3fd8dfaaea95898ed4e4be162dd07bae6fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 25 Jul 2022 16:51:04 +0300 Subject: [PATCH 119/715] eth: support bubbling up bad blocks from sync to the engine API (#25190) * eth: support bubbling up bad blocks from sync to the engine API * eth/catalyst: fix typo Co-authored-by: Marius van der Wijden * eth/catalyst: fix typo Co-authored-by: Marius van der Wijden * Update eth/catalyst/api.go * eth/catalyst: when forgetting bad hashes, also forget descendants * eth/catalyst: minor bad block tweaks for resilience Co-authored-by: Marius van der Wijden Co-authored-by: Martin Holst Swende --- core/beacon/types.go | 2 +- eth/catalyst/api.go | 139 ++++++++++++++++++++++++++++++++--- eth/catalyst/api_test.go | 6 +- eth/downloader/beaconsync.go | 7 ++ eth/downloader/downloader.go | 17 ++++- 5 files changed, 154 insertions(+), 17 deletions(-) diff --git a/core/beacon/types.go b/core/beacon/types.go index 97bf66cd3fe4..e25d724c0d55 100644 --- a/core/beacon/types.go +++ b/core/beacon/types.go @@ -42,7 +42,7 @@ type payloadAttributesMarshaling struct { //go:generate go run github.com/fjl/gencodec -type ExecutableDataV1 -field-override executableDataMarshaling -out gen_ed.go -// ExecutableDataV1 structure described at https://github.com/ethereum/execution-apis/src/engine/specification.md +// ExecutableDataV1 structure described at https://github.com/ethereum/execution-apis/tree/main/src/engine/specification.md type ExecutableDataV1 struct { ParentHash common.Hash `json:"parentHash" gencodec:"required"` FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index f0f7be7bcddd..9d4f11dfd44a 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -50,12 +50,47 @@ func Register(stack *node.Node, backend *eth.Ethereum) error { return nil } +const ( + // invalidBlockHitEviction is the number of times an invalid block can be + // referenced in forkchoice update or new payload before it is attempted + // to be reprocessed again. + invalidBlockHitEviction = 128 + + // invalidTipsetsCap is the max number of recent block hashes tracked that + // have lead to some bad ancestor block. It's just an OOM protection. + invalidTipsetsCap = 512 +) + type ConsensusAPI struct { - eth *eth.Ethereum + eth *eth.Ethereum + remoteBlocks *headerQueue // Cache of remote payloads received localBlocks *payloadQueue // Cache of local payloads generated - // Lock for the forkChoiceUpdated method - forkChoiceLock sync.Mutex + + // The forkchoice update and new payload method require us to return the + // latest valid hash in an invalid chain. To support that return, we need + // to track historical bad blocks as well as bad tipsets in case a chain + // is constantly built on it. + // + // There are a few important caveats in this mechanism: + // - The bad block tracking is ephemeral, in-memory only. We must never + // persist any bad block information to disk as a bug in Geth could end + // up blocking a valid chain, even if a later Geth update would accept + // it. + // - Bad blocks will get forgotten after a certain threshold of import + // attempts and will be retried. The rationale is that if the network + // really-really-really tries to feed us a block, we should give it a + // new chance, perhaps us being racey instead of the block being legit + // bad (this happened in Geth at a point with import vs. pending race). + // - Tracking all the blocks built on top of the bad one could be a bit + // problematic, so we will only track the head chain segment of a bad + // chain to allow discarding progressing bad chains and side chains, + // without tracking too much bad data. + invalidBlocksHits map[common.Hash]int // Emhemeral cache to track invalid blocks and their hit count + invalidTipsets map[common.Hash]*types.Header // Ephemeral cache to track invalid tipsets and their bad ancestor + invalidLock sync.Mutex // Protects the invalid maps from concurrent access + + forkChoiceLock sync.Mutex // Lock for the forkChoiceUpdated method } // NewConsensusAPI creates a new consensus api for the given backend. @@ -64,11 +99,16 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { if eth.BlockChain().Config().TerminalTotalDifficulty == nil { log.Warn("Engine API started but chain not configured for merge yet") } - return &ConsensusAPI{ - eth: eth, - remoteBlocks: newHeaderQueue(), - localBlocks: newPayloadQueue(), + api := &ConsensusAPI{ + eth: eth, + remoteBlocks: newHeaderQueue(), + localBlocks: newPayloadQueue(), + invalidBlocksHits: make(map[common.Hash]int), + invalidTipsets: make(map[common.Hash]*types.Header), } + eth.Downloader().SetBadBlockCallback(api.setInvalidAncestor) + + return api } // ForkchoiceUpdatedV1 has several responsibilities: @@ -96,6 +136,10 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa // reason. block := api.eth.BlockChain().GetBlockByHash(update.HeadBlockHash) if block == nil { + // If this block was previously invalidated, keep rejecting it here too + if res := api.checkInvalidAncestor(update.HeadBlockHash, update.HeadBlockHash); res != nil { + return beacon.ForkChoiceResponse{PayloadStatus: *res, PayloadID: nil}, nil + } // If the head hash is unknown (was not given to us in a newPayload request), // we cannot resolve the header, so not much to do. This could be extended in // the future to resolve from the `eth` network, but it's an unexpected case @@ -266,6 +310,10 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa hash := block.Hash() return beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &hash}, nil } + // If this block was rejected previously, keep rejecting it + if res := api.checkInvalidAncestor(block.Hash(), block.Hash()); res != nil { + return *res, nil + } // If the parent is missing, we - in theory - could trigger a sync, but that // would also entail a reorg. That is problematic if multiple sibling blocks // are being fed to us, and even more so, if some semi-distant uncle shortens @@ -293,7 +341,7 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa } if block.Time() <= parent.Time() { log.Warn("Invalid timestamp", "parent", block.Time(), "block", block.Time()) - return api.invalid(errors.New("invalid timestamp"), parent), nil + return api.invalid(errors.New("invalid timestamp"), parent.Header()), nil } // Another cornercase: if the node is in snap sync mode, but the CL client // tries to make it import a block. That should be denied as pushing something @@ -310,7 +358,13 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa log.Trace("Inserting block without sethead", "hash", block.Hash(), "number", block.Number) if err := api.eth.BlockChain().InsertBlockWithoutSetHead(block); err != nil { log.Warn("NewPayloadV1: inserting block failed", "error", err) - return api.invalid(err, parent), nil + + api.invalidLock.Lock() + api.invalidBlocksHits[block.Hash()] = 1 + api.invalidTipsets[block.Hash()] = block.Header() + api.invalidLock.Unlock() + + return api.invalid(err, parent.Header()), nil } // We've accepted a valid payload from the beacon client. Mark the local // chain transitions to notify other subsystems (e.g. downloader) of the @@ -339,8 +393,13 @@ func computePayloadId(headBlockHash common.Hash, params *beacon.PayloadAttribute // delayPayloadImport stashes the given block away for import at a later time, // either via a forkchoice update or a sync extension. This method is meant to // be called by the newpayload command when the block seems to be ok, but some -// prerequisite prevents it from being processed (e.g. no parent, or nap sync). +// prerequisite prevents it from being processed (e.g. no parent, or snap sync). func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (beacon.PayloadStatusV1, error) { + // Sanity check that this block's parent is not on a previously invalidated + // chain. If it is, mark the block as invalid too. + if res := api.checkInvalidAncestor(block.ParentHash(), block.Hash()); res != nil { + return *res, nil + } // Stash the block away for a potential forced forkchoice update to it // at a later time. api.remoteBlocks.put(block.Hash(), block.Header()) @@ -360,14 +419,70 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (beacon.PayloadS return beacon.PayloadStatusV1{Status: beacon.ACCEPTED}, nil } +// setInvalidAncestor is a callback for the downloader to notify us if a bad block +// is encountered during the async sync. +func (api *ConsensusAPI) setInvalidAncestor(invalid *types.Header, origin *types.Header) { + api.invalidLock.Lock() + defer api.invalidLock.Unlock() + + api.invalidTipsets[origin.Hash()] = invalid + api.invalidBlocksHits[invalid.Hash()]++ +} + +// checkInvalidAncestor checks whether the specified chain end links to a known +// bad ancestor. If yes, it constructs the payload failure response to return. +func (api *ConsensusAPI) checkInvalidAncestor(check common.Hash, head common.Hash) *beacon.PayloadStatusV1 { + api.invalidLock.Lock() + defer api.invalidLock.Unlock() + + // If the hash to check is unknown, return valid + invalid, ok := api.invalidTipsets[check] + if !ok { + return nil + } + // If the bad hash was hit too many times, evict it and try to reprocess in + // the hopes that we have a data race that we can exit out of. + badHash := invalid.Hash() + + api.invalidBlocksHits[badHash]++ + if api.invalidBlocksHits[badHash] >= invalidBlockHitEviction { + log.Warn("Too many bad block import attempt, trying", "number", invalid.Number, "hash", badHash) + delete(api.invalidBlocksHits, badHash) + + for descendant, badHeader := range api.invalidTipsets { + if badHeader.Hash() == badHash { + delete(api.invalidTipsets, descendant) + } + } + return nil + } + // Not too many failures yet, mark the head of the invalid chain as invalid + if check != head { + log.Warn("Marked new chain head as invalid", "hash", head, "badnumber", invalid.Number, "badhash", badHash) + for len(api.invalidTipsets) >= invalidTipsetsCap { + for key := range api.invalidTipsets { + delete(api.invalidTipsets, key) + break + } + } + api.invalidTipsets[head] = invalid + } + failure := "links to previously rejected block" + return &beacon.PayloadStatusV1{ + Status: beacon.INVALID, + LatestValidHash: &invalid.ParentHash, + ValidationError: &failure, + } +} + // invalid returns a response "INVALID" with the latest valid hash supplied by latest or to the current head // if no latestValid block was provided. -func (api *ConsensusAPI) invalid(err error, latestValid *types.Block) beacon.PayloadStatusV1 { +func (api *ConsensusAPI) invalid(err error, latestValid *types.Header) beacon.PayloadStatusV1 { currentHash := api.eth.BlockChain().CurrentBlock().Hash() if latestValid != nil { // Set latest valid hash to 0x0 if parent is PoW block currentHash = common.Hash{} - if latestValid.Difficulty().BitLen() == 0 { + if latestValid.Difficulty.BitLen() == 0 { // Otherwise set latest valid hash to parent hash currentHash = latestValid.Hash() } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 547b727f1c6a..0372aad6b79d 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -773,8 +773,8 @@ func TestTrickRemoteBlockCache(t *testing.T) { if err != nil { panic(err) } - if status.Status == beacon.INVALID { - panic("success") + if status.Status == beacon.VALID { + t.Error("invalid status: VALID on an invalid chain") } // Now reorg to the head of the invalid chain resp, err := apiB.ForkchoiceUpdatedV1(beacon.ForkchoiceStateV1{HeadBlockHash: payload.BlockHash, SafeBlockHash: payload.BlockHash, FinalizedBlockHash: payload.ParentHash}, nil) @@ -782,7 +782,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { t.Fatal(err) } if resp.PayloadStatus.Status == beacon.VALID { - t.Errorf("invalid status: expected INVALID got: %v", resp.PayloadStatus.Status) + t.Error("invalid status: VALID on an invalid chain") } time.Sleep(100 * time.Millisecond) } diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 533404f6c9b9..77353925813d 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -137,6 +137,13 @@ func (b *beaconBackfiller) setMode(mode SyncMode) { b.resume() } +// SetBadBlockCallback sets the callback to run when a bad block is hit by the +// block processor. This method is not thread safe and should be set only once +// on startup before system events are fired. +func (d *Downloader) SetBadBlockCallback(onBadBlock badBlockFn) { + d.badBlock = onBadBlock +} + // BeaconSync is the post-merge version of the chain synchronization, where the // chain is not downloaded from genesis onward, rather from trusted head announces // backwards. diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 1dcacba3a267..f9ac8e487bfa 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -85,6 +85,10 @@ var ( // peerDropFn is a callback type for dropping a peer detected as malicious. type peerDropFn func(id string) +// badBlockFn is a callback for the async beacon sync to notify the caller that +// the origin header requested to sync to, produced a chain with a bad block. +type badBlockFn func(invalid *types.Header, origin *types.Header) + // headerTask is a set of downloaded headers to queue along with their precomputed // hashes to avoid constant rehashing. type headerTask struct { @@ -113,6 +117,7 @@ type Downloader struct { // Callbacks dropPeer peerDropFn // Drops a peer for misbehaving + badBlock badBlockFn // Reports a block as rejected by the chain // Status synchroniseMock func(id string, hash common.Hash) error // Replacement for synchronise during testing @@ -1528,7 +1533,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { return errCancelContentProcessing default: } - // Retrieve the a batch of results to import + // Retrieve a batch of results to import first, last := results[0].Header, results[len(results)-1].Header log.Debug("Inserting downloaded chain", "items", len(results), "firstnum", first.Number, "firsthash", first.Hash(), @@ -1544,6 +1549,16 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { if index, err := d.blockchain.InsertChain(blocks); err != nil { if index < len(results) { log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err) + + // In post-merge, notify the engine API of encountered bad chains + if d.badBlock != nil { + head, _, err := d.skeleton.Bounds() + if err != nil { + log.Error("Failed to retrieve beacon bounds for bad block reporting", "err", err) + } else { + d.badBlock(blocks[index].Header(), head) + } + } } else { // The InsertChain method in blockchain.go will sometimes return an out-of-bounds index, // when it needs to preprocess blocks to import a sidechain. From c6dcd018d25998201eff1e1e264c9080847d92df Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 25 Jul 2022 17:42:05 +0200 Subject: [PATCH 120/715] core: eth: rpc: implement safe rpc block (#25165) * core: eth: rpc: implement safe rpc block * core: fix setHead, panics --- core/blockchain.go | 38 +++++++++++++++++++++++++++++++++++--- core/blockchain_reader.go | 6 ++++++ eth/api.go | 4 ++++ eth/api_backend.go | 16 +++++++++++++++- eth/catalyst/api.go | 2 ++ internal/jsre/deps/web3.js | 2 +- rpc/types.go | 10 ++++++++++ 7 files changed, 73 insertions(+), 5 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index fbeddecdbb29..506034b539a7 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -51,6 +51,7 @@ var ( headHeaderGauge = metrics.NewRegisteredGauge("chain/head/header", nil) headFastBlockGauge = metrics.NewRegisteredGauge("chain/head/receipt", nil) headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil) + headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil) accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil) accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil) @@ -191,6 +192,7 @@ type BlockChain struct { currentBlock atomic.Value // Current head of the block chain currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!) currentFinalizedBlock atomic.Value // Current finalized head + currentSafeBlock atomic.Value // Current safe head stateCache state.Database // State database to reuse between imports (contains state cache) bodyCache *lru.Cache // Cache for the most recent block bodies @@ -267,6 +269,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par bc.currentBlock.Store(nilBlock) bc.currentFastBlock.Store(nilBlock) bc.currentFinalizedBlock.Store(nilBlock) + bc.currentSafeBlock.Store(nilBlock) // Initialize the chain with ancient data if it isn't empty. var txIndexBlock uint64 @@ -464,11 +467,15 @@ func (bc *BlockChain) loadLastState() error { } } - // Restore the last known finalized block + // Restore the last known finalized block and safe block + // Note: the safe block is not stored on disk and it is set to the last + // known finalized block on startup if head := rawdb.ReadFinalizedBlockHash(bc.db); head != (common.Hash{}) { if block := bc.GetBlockByHash(head); block != nil { bc.currentFinalizedBlock.Store(block) headFinalizedBlockGauge.Update(int64(block.NumberU64())) + bc.currentSafeBlock.Store(block) + headSafeBlockGauge.Update(int64(block.NumberU64())) } } // Issue a status log for the user @@ -504,8 +511,23 @@ func (bc *BlockChain) SetHead(head uint64) error { // SetFinalized sets the finalized block. func (bc *BlockChain) SetFinalized(block *types.Block) { bc.currentFinalizedBlock.Store(block) - rawdb.WriteFinalizedBlockHash(bc.db, block.Hash()) - headFinalizedBlockGauge.Update(int64(block.NumberU64())) + if block != nil { + rawdb.WriteFinalizedBlockHash(bc.db, block.Hash()) + headFinalizedBlockGauge.Update(int64(block.NumberU64())) + } else { + rawdb.WriteFinalizedBlockHash(bc.db, common.Hash{}) + headFinalizedBlockGauge.Update(0) + } +} + +// SetSafe sets the safe block. +func (bc *BlockChain) SetSafe(block *types.Block) { + bc.currentSafeBlock.Store(block) + if block != nil { + headSafeBlockGauge.Update(int64(block.NumberU64())) + } else { + headSafeBlockGauge.Update(0) + } } // setHeadBeyondRoot rewinds the local chain to a new head with the extra condition @@ -663,6 +685,16 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo bc.txLookupCache.Purge() bc.futureBlocks.Purge() + // Clear safe block, finalized block if needed + if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.NumberU64() { + log.Warn("SetHead invalidated safe block") + bc.SetSafe(nil) + } + if finalized := bc.CurrentFinalizedBlock(); finalized != nil && head < finalized.NumberU64() { + log.Error("SetHead invalidated finalized block") + bc.SetFinalized(nil) + } + return rootNumber, bc.loadLastState() } diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index b8d4233c6ecd..96e9f80b6aac 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -55,6 +55,12 @@ func (bc *BlockChain) CurrentFinalizedBlock() *types.Block { return bc.currentFinalizedBlock.Load().(*types.Block) } +// CurrentSafeBlock retrieves the current safe block of the canonical +// chain. The block is retrieved from the blockchain's internal cache. +func (bc *BlockChain) CurrentSafeBlock() *types.Block { + return bc.currentSafeBlock.Load().(*types.Block) +} + // HasHeader checks if a block header is present in the database or not, caching // it if present. func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool { diff --git a/eth/api.go b/eth/api.go index 23b9743be950..ad8566dae26a 100644 --- a/eth/api.go +++ b/eth/api.go @@ -272,6 +272,8 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) { block = api.eth.blockchain.CurrentBlock() } else if blockNr == rpc.FinalizedBlockNumber { block = api.eth.blockchain.CurrentFinalizedBlock() + } else if blockNr == rpc.SafeBlockNumber { + block = api.eth.blockchain.CurrentSafeBlock() } else { block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr)) } @@ -350,6 +352,8 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex block = api.eth.blockchain.CurrentBlock() } else if number == rpc.FinalizedBlockNumber { block = api.eth.blockchain.CurrentFinalizedBlock() + } else if number == rpc.SafeBlockNumber { + block = api.eth.blockchain.CurrentSafeBlock() } else { block = api.eth.blockchain.GetBlockByNumber(uint64(number)) } diff --git a/eth/api_backend.go b/eth/api_backend.go index f942710e2d8d..1d8ba8ea5cae 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -74,7 +74,18 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb return b.eth.blockchain.CurrentBlock().Header(), nil } if number == rpc.FinalizedBlockNumber { - return b.eth.blockchain.CurrentFinalizedBlock().Header(), nil + block := b.eth.blockchain.CurrentFinalizedBlock() + if block != nil { + return block.Header(), nil + } + return nil, errors.New("finalized block not found") + } + if number == rpc.SafeBlockNumber { + block := b.eth.blockchain.CurrentSafeBlock() + if block != nil { + return block.Header(), nil + } + return nil, errors.New("safe block not found") } return b.eth.blockchain.GetHeaderByNumber(uint64(number)), nil } @@ -113,6 +124,9 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe if number == rpc.FinalizedBlockNumber { return b.eth.blockchain.CurrentFinalizedBlock(), nil } + if number == rpc.SafeBlockNumber { + return b.eth.blockchain.CurrentSafeBlock(), nil + } return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 9d4f11dfd44a..beffbb972563 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -235,6 +235,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa log.Warn("Safe block not in canonical chain") return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain")) } + // Set the safe block + api.eth.BlockChain().SetSafe(safeBlock) } // If payload generation was requested, create a new block to be potentially // sealed by the beacon client. The payload will be requested later, and we diff --git a/internal/jsre/deps/web3.js b/internal/jsre/deps/web3.js index f82d93bdc570..a291218ec51f 100644 --- a/internal/jsre/deps/web3.js +++ b/internal/jsre/deps/web3.js @@ -3696,7 +3696,7 @@ var outputBigNumberFormatter = function (number) { }; var isPredefinedBlockNumber = function (blockNumber) { - return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest' || blockNumber === 'finalized'; + return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest' || blockNumber === 'finalized' || blockNumber === 'safe'; }; var inputDefaultBlockNumberFormatter = function (blockNumber) { diff --git a/rpc/types.go b/rpc/types.go index 369e950aa162..e3d1a4896821 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -61,6 +61,7 @@ type jsonWriter interface { type BlockNumber int64 const ( + SafeBlockNumber = BlockNumber(-4) FinalizedBlockNumber = BlockNumber(-3) PendingBlockNumber = BlockNumber(-2) LatestBlockNumber = BlockNumber(-1) @@ -92,6 +93,9 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { case "finalized": *bn = FinalizedBlockNumber return nil + case "safe": + *bn = SafeBlockNumber + return nil } blckNum, err := hexutil.DecodeUint64(input) @@ -118,6 +122,8 @@ func (bn BlockNumber) MarshalText() ([]byte, error) { return []byte("pending"), nil case FinalizedBlockNumber: return []byte("finalized"), nil + case SafeBlockNumber: + return []byte("safe"), nil default: return hexutil.Uint64(bn).MarshalText() } @@ -168,6 +174,10 @@ func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error { bn := FinalizedBlockNumber bnh.BlockNumber = &bn return nil + case "safe": + bn := SafeBlockNumber + bnh.BlockNumber = &bn + return nil default: if len(input) == 66 { hash := common.Hash{} From 14b0eedacf8e7d3cdcfbc82a616810337a7f16ca Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 27 Jul 2022 14:31:13 +0800 Subject: [PATCH 121/715] go.mod: downgrade leveldb (#25413) --- go.mod | 2 +- go.sum | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 9a943402281f..4a769c7a2dca 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 github.com/stretchr/testify v1.7.2 github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 - github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef github.com/urfave/cli/v2 v2.10.2 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 diff --git a/go.sum b/go.sum index 78e9f3434e71..4b27867fbc79 100644 --- a/go.sum +++ b/go.sum @@ -331,6 +331,7 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= @@ -409,6 +410,8 @@ github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCA github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= @@ -499,6 +502,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -551,6 +555,8 @@ golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From 671094279e8d27f4b4c3c94bf8b636c26b473976 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 27 Jul 2022 13:53:06 +0200 Subject: [PATCH 122/715] params: go-ethereum v1.10.21 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 188b31d58b79..c1dd05955c50 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 21 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 10 // Minor version component of the current release + VersionPatch = 21 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 54007f5e0aeff30e5a2cb3276cb9bb2eaa55a841 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 27 Jul 2022 13:56:40 +0200 Subject: [PATCH 123/715] params: begin v1.10.22 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index c1dd05955c50..258be5d5db31 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 21 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 10 // Minor version component of the current release + VersionPatch = 22 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 9d76a9b94f1d4f8b8a9c212151d96d6a13cb6ead Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 28 Jul 2022 02:37:04 +0800 Subject: [PATCH 124/715] core, trie, eth, cmd: rework preimage store (#25287) * core, trie, eth, cmd: rework preimage store * trie: address comment --- cmd/evm/internal/t8ntool/execution.go | 2 +- core/state/state_test.go | 3 +- eth/api_test.go | 3 +- trie/database.go | 91 +++++-------------------- trie/preimages.go | 95 +++++++++++++++++++++++++++ trie/secure_trie.go | 17 +++-- 6 files changed, 127 insertions(+), 84 deletions(-) create mode 100644 trie/preimages.go diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 28fe77d2d07d..77f6ec37158b 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -268,7 +268,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB { - sdb := state.NewDatabase(db) + sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) statedb, _ := state.New(common.Hash{}, sdb, nil) for addr, a := range accounts { statedb.SetCode(addr, a.Code) diff --git a/core/state/state_test.go b/core/state/state_test.go index 0a55d7781fd1..b6b46e446fba 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/trie" ) type stateTest struct { @@ -40,7 +41,7 @@ func newStateTest() *stateTest { func TestDump(t *testing.T) { db := rawdb.NewMemoryDatabase() - sdb, _ := New(common.Hash{}, NewDatabaseWithConfig(db, nil), nil) + sdb, _ := New(common.Hash{}, NewDatabaseWithConfig(db, &trie.Config{Preimages: true}), nil) s := &stateTest{db: db, state: sdb} // generate a few entries diff --git a/eth/api_test.go b/eth/api_test.go index aae04eaa907f..250591c1079b 100644 --- a/eth/api_test.go +++ b/eth/api_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/trie" ) var dumper = spew.ConfigState{Indent: " "} @@ -66,7 +67,7 @@ func TestAccountRange(t *testing.T) { t.Parallel() var ( - statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), nil) + statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: true}) state, _ = state.New(common.Hash{}, statedb, nil) addrs = [AccountRangeMaxResults * 2]common.Address{} m = map[common.Address]bool{} diff --git a/trie/database.go b/trie/database.go index 2df2e859d7b4..8e1788a21239 100644 --- a/trie/database.go +++ b/trie/database.go @@ -74,8 +74,6 @@ type Database struct { oldest common.Hash // Oldest tracked node, flush-list head newest common.Hash // Newest tracked node, flush-list tail - preimages map[common.Hash][]byte // Preimages of nodes from the secure trie - gctime time.Duration // Time spent on garbage collection since last commit gcnodes uint64 // Nodes garbage collected since last commit gcsize common.StorageSize // Data storage garbage collected since last commit @@ -84,9 +82,9 @@ type Database struct { flushnodes uint64 // Nodes flushed since last commit flushsize common.StorageSize // Data storage flushed since last commit - dirtiesSize common.StorageSize // Storage size of the dirty node cache (exc. metadata) - childrenSize common.StorageSize // Storage size of the external children tracking - preimagesSize common.StorageSize // Storage size of the preimages cache + dirtiesSize common.StorageSize // Storage size of the dirty node cache (exc. metadata) + childrenSize common.StorageSize // Storage size of the external children tracking + preimages *preimageStore // The store for caching preimages lock sync.RWMutex } @@ -287,15 +285,17 @@ func NewDatabaseWithConfig(diskdb ethdb.KeyValueStore, config *Config) *Database cleans = fastcache.LoadFromFileOrNew(config.Journal, config.Cache*1024*1024) } } + var preimage *preimageStore + if config != nil && config.Preimages { + preimage = newPreimageStore(diskdb) + } db := &Database{ diskdb: diskdb, cleans: cleans, dirties: map[common.Hash]*cachedNode{{}: { children: make(map[common.Hash]uint16), }}, - } - if config == nil || config.Preimages { // TODO(karalabe): Flip to default off in the future - db.preimages = make(map[common.Hash][]byte) + preimages: preimage, } return db } @@ -341,24 +341,6 @@ func (db *Database) insert(hash common.Hash, size int, node node) { db.dirtiesSize += common.StorageSize(common.HashLength + entry.size) } -// insertPreimage writes a new trie node pre-image to the memory database if it's -// yet unknown. The method will NOT make a copy of the slice, -// only use if the preimage will NOT be changed later on. -// -// Note, this method assumes that the database's lock is held! -func (db *Database) insertPreimage(hash common.Hash, preimage []byte) { - // Short circuit if preimage collection is disabled - if db.preimages == nil { - return - } - // Track the preimage if a yet unknown one - if _, ok := db.preimages[hash]; ok { - return - } - db.preimages[hash] = preimage - db.preimagesSize += common.StorageSize(common.HashLength + len(preimage)) -} - // node retrieves a cached trie node from memory, or returns nil if none can be // found in the memory cache. func (db *Database) node(hash common.Hash) node { @@ -435,24 +417,6 @@ func (db *Database) Node(hash common.Hash) ([]byte, error) { return nil, errors.New("not found") } -// preimage retrieves a cached trie node pre-image from memory. If it cannot be -// found cached, the method queries the persistent database for the content. -func (db *Database) preimage(hash common.Hash) []byte { - // Short circuit if preimage collection is disabled - if db.preimages == nil { - return nil - } - // Retrieve the node from cache if available - db.lock.RLock() - preimage := db.preimages[hash] - db.lock.RUnlock() - - if preimage != nil { - return preimage - } - return rawdb.ReadPreimage(db.diskdb, hash) -} - // Nodes retrieves the hashes of all the nodes cached within the memory database. // This method is extremely expensive and should only be used to validate internal // states in test code. @@ -597,19 +561,8 @@ func (db *Database) Cap(limit common.StorageSize) error { // If the preimage cache got large enough, push to disk. If it's still small // leave for later to deduplicate writes. - flushPreimages := db.preimagesSize > 4*1024*1024 - if flushPreimages { - if db.preimages == nil { - log.Error("Attempted to write preimages whilst disabled") - } else { - rawdb.WritePreimages(batch, db.preimages) - if batch.ValueSize() > ethdb.IdealBatchSize { - if err := batch.Write(); err != nil { - return err - } - batch.Reset() - } - } + if db.preimages != nil { + db.preimages.commit(false) } // Keep committing nodes from the flush-list until we're below allowance oldest := db.oldest @@ -644,13 +597,6 @@ func (db *Database) Cap(limit common.StorageSize) error { db.lock.Lock() defer db.lock.Unlock() - if flushPreimages { - if db.preimages == nil { - log.Error("Attempted to reset preimage cache whilst disabled") - } else { - db.preimages, db.preimagesSize = make(map[common.Hash][]byte), 0 - } - } for db.oldest != oldest { node := db.dirties[db.oldest] delete(db.dirties, db.oldest) @@ -694,13 +640,7 @@ func (db *Database) Commit(node common.Hash, report bool, callback func(common.H // Move all of the accumulated preimages into a write batch if db.preimages != nil { - rawdb.WritePreimages(batch, db.preimages) - // Since we're going to replay trie node writes into the clean cache, flush out - // any batched pre-images before continuing. - if err := batch.Write(); err != nil { - return err - } - batch.Reset() + db.preimages.commit(true) } // Move the trie itself into the batch, flushing if enough data is accumulated nodes, storage := len(db.dirties), db.dirtiesSize @@ -723,9 +663,6 @@ func (db *Database) Commit(node common.Hash, report bool, callback func(common.H batch.Reset() // Reset the storage counters and bumped metrics - if db.preimages != nil { - db.preimages, db.preimagesSize = make(map[common.Hash][]byte), 0 - } memcacheCommitTimeTimer.Update(time.Since(start)) memcacheCommitSizeMeter.Mark(int64(storage - db.dirtiesSize)) memcacheCommitNodesMeter.Mark(int64(nodes - len(db.dirties))) @@ -837,7 +774,11 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize) { // counted. var metadataSize = common.StorageSize((len(db.dirties) - 1) * cachedNodeSize) var metarootRefs = common.StorageSize(len(db.dirties[common.Hash{}].children) * (common.HashLength + 2)) - return db.dirtiesSize + db.childrenSize + metadataSize - metarootRefs, db.preimagesSize + var preimageSize common.StorageSize + if db.preimages != nil { + preimageSize = db.preimages.size() + } + return db.dirtiesSize + db.childrenSize + metadataSize - metarootRefs, preimageSize } // saveCache saves clean state cache to given directory path diff --git a/trie/preimages.go b/trie/preimages.go new file mode 100644 index 000000000000..66f34117c1e8 --- /dev/null +++ b/trie/preimages.go @@ -0,0 +1,95 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package trie + +import ( + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" +) + +// preimageStore is the store for caching preimages of node key. +type preimageStore struct { + lock sync.RWMutex + disk ethdb.KeyValueStore + preimages map[common.Hash][]byte // Preimages of nodes from the secure trie + preimagesSize common.StorageSize // Storage size of the preimages cache +} + +// newPreimageStore initializes the store for caching preimages. +func newPreimageStore(disk ethdb.KeyValueStore) *preimageStore { + return &preimageStore{ + disk: disk, + preimages: make(map[common.Hash][]byte), + } +} + +// insertPreimage writes a new trie node pre-image to the memory database if it's +// yet unknown. The method will NOT make a copy of the slice, only use if the +// preimage will NOT be changed later on. +func (store *preimageStore) insertPreimage(preimages map[common.Hash][]byte) { + store.lock.Lock() + defer store.lock.Unlock() + + for hash, preimage := range preimages { + if _, ok := store.preimages[hash]; ok { + continue + } + store.preimages[hash] = preimage + store.preimagesSize += common.StorageSize(common.HashLength + len(preimage)) + } +} + +// preimage retrieves a cached trie node pre-image from memory. If it cannot be +// found cached, the method queries the persistent database for the content. +func (store *preimageStore) preimage(hash common.Hash) []byte { + store.lock.RLock() + preimage := store.preimages[hash] + store.lock.RUnlock() + + if preimage != nil { + return preimage + } + return rawdb.ReadPreimage(store.disk, hash) +} + +// commit flushes the cached preimages into the disk. +func (store *preimageStore) commit(force bool) error { + store.lock.Lock() + defer store.lock.Unlock() + + if store.preimagesSize <= 4*1024*1024 && !force { + return nil + } + batch := store.disk.NewBatch() + rawdb.WritePreimages(batch, store.preimages) + if err := batch.Write(); err != nil { + return err + } + store.preimages, store.preimagesSize = make(map[common.Hash][]byte), 0 + return nil +} + +// size returns the current storage size of accumulated preimages. +func (store *preimageStore) size() common.StorageSize { + store.lock.RLock() + defer store.lock.RUnlock() + + return store.preimagesSize +} diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 6a5cc89c9ffd..967194df9628 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -37,6 +37,7 @@ import ( // SecureTrie is not safe for concurrent use. type SecureTrie struct { trie Trie + preimages *preimageStore hashKeyBuf [common.HashLength]byte secKeyCache map[string][]byte secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch @@ -61,7 +62,7 @@ func NewSecure(owner common.Hash, root common.Hash, db *Database) (*SecureTrie, if err != nil { return nil, err } - return &SecureTrie{trie: *trie}, nil + return &SecureTrie{trie: *trie, preimages: db.preimages}, nil } // Get returns the value for key stored in the trie. @@ -153,7 +154,10 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte { if key, ok := t.getSecKeyCache()[string(shaKey)]; ok { return key } - return t.trie.db.preimage(common.BytesToHash(shaKey)) + if t.preimages == nil { + return nil + } + return t.preimages.preimage(common.BytesToHash(shaKey)) } // Commit writes all nodes and the secure hash pre-images to the trie's database. @@ -164,12 +168,12 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte { func (t *SecureTrie) Commit(onleaf LeafCallback) (common.Hash, int, error) { // Write all the pre-images to the actual disk database if len(t.getSecKeyCache()) > 0 { - if t.trie.db.preimages != nil { // Ugly direct check but avoids the below write lock - t.trie.db.lock.Lock() + if t.preimages != nil { + preimages := make(map[common.Hash][]byte) for hk, key := range t.secKeyCache { - t.trie.db.insertPreimage(common.BytesToHash([]byte(hk)), key) + preimages[common.BytesToHash([]byte(hk))] = key } - t.trie.db.lock.Unlock() + t.preimages.insertPreimage(preimages) } t.secKeyCache = make(map[string][]byte) } @@ -187,6 +191,7 @@ func (t *SecureTrie) Hash() common.Hash { func (t *SecureTrie) Copy() *SecureTrie { return &SecureTrie{ trie: *t.trie.Copy(), + preimages: t.preimages, secKeyCache: t.secKeyCache, } } From ad7106dfc4c7affd5e64369c4ec266b51ceae224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 28 Jul 2022 08:46:13 +0300 Subject: [PATCH 125/715] eth/catalyst: fix NewPayload warn log when dropping due to snap sync --- eth/catalyst/api.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index beffbb972563..7903a7e88887 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -417,7 +417,17 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (beacon.PayloadS // payload as non-integratable on top of the existing sync. We'll just // have to rely on the beacon client to forcefully update the head with // a forkchoice update request. - log.Warn("Ignoring payload with missing parent", "number", block.NumberU64(), "hash", block.Hash(), "parent", block.ParentHash()) + if api.eth.SyncMode() == downloader.FullSync { + // In full sync mode, failure to import a well-formed block can only mean + // that the parent state is missing and the syncer rejected extending the + // current cycle with the new payload. + log.Warn("Ignoring payload with missing parent", "number", block.NumberU64(), "hash", block.Hash(), "parent", block.ParentHash()) + } else { + // In non-full sync mode (i.e. snap sync) all payloads are rejected until + // snap sync terminates as snap sync relies on direct database injections + // and cannot afford concurrent out-if-band modifications via imports. + log.Warn("Ignoring payload while snap syncing", "number", block.NumberU64(), "hash", block.Hash()) + } return beacon.PayloadStatusV1{Status: beacon.ACCEPTED}, nil } From f26b63089abaa127625e99fe79240e8da533c63e Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 28 Jul 2022 08:30:50 +0200 Subject: [PATCH 126/715] node: set JWT expiry to 60 seconds (#25416) * node: set JWT expiry to 60 seconds * node: rename var --- node/jwt_handler.go | 6 ++++-- node/rpcstack_test.go | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/node/jwt_handler.go b/node/jwt_handler.go index 28d5b87c60bc..363f6b3aad47 100644 --- a/node/jwt_handler.go +++ b/node/jwt_handler.go @@ -24,6 +24,8 @@ import ( "github.com/golang-jwt/jwt/v4" ) +const jwtExpiryTimeout = 60 * time.Second + type jwtHandler struct { keyFunc func(token *jwt.Token) (interface{}, error) next http.Handler @@ -68,9 +70,9 @@ func (handler *jwtHandler) ServeHTTP(out http.ResponseWriter, r *http.Request) { http.Error(out, "token is expired", http.StatusForbidden) case claims.IssuedAt == nil: http.Error(out, "missing issued-at", http.StatusForbidden) - case time.Since(claims.IssuedAt.Time) > 5*time.Second: + case time.Since(claims.IssuedAt.Time) > jwtExpiryTimeout: http.Error(out, "stale token", http.StatusForbidden) - case time.Until(claims.IssuedAt.Time) > 5*time.Second: + case time.Until(claims.IssuedAt.Time) > jwtExpiryTimeout: http.Error(out, "future token", http.StatusForbidden) default: handler.next.ServeHTTP(out, r) diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index 58a02234025a..6fb16c504a9e 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -356,11 +356,11 @@ func TestJWT(t *testing.T) { expFail := []func() string{ // future func() string { - return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + 6})) + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + int64(jwtExpiryTimeout.Seconds()) + 1})) }, // stale func() string { - return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() - 6})) + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() - int64(jwtExpiryTimeout.Seconds()) - 1})) }, // wrong algo func() string { From f3549814a9f3198a700211c31a59a081d9c4bcf9 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 28 Jul 2022 15:01:35 +0200 Subject: [PATCH 127/715] eth/catalyst: return syncing not accepted (#25414) * eth/catalyst: return syncing not accepted * eth/catalyst: fix test --- eth/catalyst/api.go | 2 +- eth/catalyst/api_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 7903a7e88887..6287bdab4da0 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -428,7 +428,7 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (beacon.PayloadS // and cannot afford concurrent out-if-band modifications via imports. log.Warn("Ignoring payload while snap syncing", "number", block.NumberU64(), "hash", block.Hash()) } - return beacon.PayloadStatusV1{Status: beacon.ACCEPTED}, nil + return beacon.PayloadStatusV1{Status: beacon.SYNCING}, nil } // setInvalidAncestor is a callback for the downloader to notify us if a bad block diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 0372aad6b79d..df302f8211c7 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -662,8 +662,8 @@ func TestEmptyBlocks(t *testing.T) { if err != nil { t.Fatal(err) } - if status.Status != beacon.ACCEPTED { - t.Errorf("invalid status: expected ACCEPTED got: %v", status.Status) + if status.Status != beacon.SYNCING { + t.Errorf("invalid status: expected SYNCING got: %v", status.Status) } if status.LatestValidHash != nil { t.Fatalf("invalid LVH: got %v wanted nil", status.LatestValidHash) From 377c7d799ff62c6060939a4f95532df93a345f63 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 28 Jul 2022 15:16:15 +0200 Subject: [PATCH 128/715] eth/catalyst: return 0x0 if latestvalid is pow block (#25423) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * eth/catalyst: return 0x0 if latestvalid is pow block * eth/catalyst: return 0x0 if latestvalid is pow block * eth/catalyst: fix header retrieval, fix sign check Co-authored-by: Péter Szilágyi --- eth/catalyst/api.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 6287bdab4da0..c5f2313cabbc 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -479,10 +479,15 @@ func (api *ConsensusAPI) checkInvalidAncestor(check common.Hash, head common.Has } api.invalidTipsets[head] = invalid } + // If the last valid hash is the terminal pow block, return 0x0 for latest valid hash + lastValid := &invalid.ParentHash + if header := api.eth.BlockChain().GetHeader(invalid.ParentHash, invalid.Number.Uint64()-1); header != nil && header.Difficulty.Sign() != 0 { + lastValid = &common.Hash{} + } failure := "links to previously rejected block" return &beacon.PayloadStatusV1{ Status: beacon.INVALID, - LatestValidHash: &invalid.ParentHash, + LatestValidHash: lastValid, ValidationError: &failure, } } From 9ad508018e4790da0c1c00ac355f206fca12ab7c Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Fri, 29 Jul 2022 10:22:04 -0600 Subject: [PATCH 129/715] ethereum, ethclient: add FeeHistory support (#25403) Co-authored-by: Felix Lange --- ethclient/ethclient.go | 32 ++++++++++++++++++++++++++++++++ ethclient/ethclient_test.go | 23 +++++++++++++++++++++++ interfaces.go | 9 +++++++++ internal/ethapi/api.go | 1 + 4 files changed, 65 insertions(+) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 24edd8648ef3..8a001843187b 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -505,6 +505,38 @@ func (ec *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { return (*big.Int)(&hex), nil } +type feeHistoryResultMarshaling struct { + OldestBlock *hexutil.Big `json:"oldestBlock"` + Reward [][]*hexutil.Big `json:"reward,omitempty"` + BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"` + GasUsedRatio []float64 `json:"gasUsedRatio"` +} + +// FeeHistory retrieves the fee market history. +func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*ethereum.FeeHistory, error) { + var res feeHistoryResultMarshaling + if err := ec.c.CallContext(ctx, &res, "eth_feeHistory", hexutil.Uint(blockCount), toBlockNumArg(lastBlock), rewardPercentiles); err != nil { + return nil, err + } + reward := make([][]*big.Int, len(res.Reward)) + for i, r := range res.Reward { + reward[i] = make([]*big.Int, len(r)) + for j, r := range r { + reward[i][j] = (*big.Int)(r) + } + } + baseFee := make([]*big.Int, len(res.BaseFee)) + for i, b := range res.BaseFee { + baseFee[i] = (*big.Int)(b) + } + return ðereum.FeeHistory{ + OldestBlock: (*big.Int)(res.OldestBlock), + Reward: reward, + BaseFee: baseFee, + GasUsedRatio: res.GasUsedRatio, + }, nil +} + // EstimateGas tries to estimate the gas needed to execute a specific transaction based on // the current pending state of the backend blockchain. There is no guarantee that this is // the true gas limit requirement as other transactions may be added or removed by miners, diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 4a8727b37478..37add1bd36f0 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -508,6 +508,29 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) { if gasTipCap.Cmp(big.NewInt(234375000)) != 0 { t.Fatalf("unexpected gas tip cap: %v", gasTipCap) } + + // FeeHistory + history, err := ec.FeeHistory(context.Background(), 1, big.NewInt(2), []float64{95, 99}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + want := ðereum.FeeHistory{ + OldestBlock: big.NewInt(2), + Reward: [][]*big.Int{ + { + big.NewInt(234375000), + big.NewInt(234375000), + }, + }, + BaseFee: []*big.Int{ + big.NewInt(765625000), + big.NewInt(671627818), + }, + GasUsedRatio: []float64{0.008912678667376286}, + } + if !reflect.DeepEqual(history, want) { + t.Fatalf("FeeHistory result doesn't match expected: (got: %v, want: %v)", history, want) + } } func testCallContractAtHash(t *testing.T, client *rpc.Client) { diff --git a/interfaces.go b/interfaces.go index 76c1ef6908f2..e8d24a57cf7a 100644 --- a/interfaces.go +++ b/interfaces.go @@ -201,6 +201,15 @@ type GasPricer interface { SuggestGasPrice(ctx context.Context) (*big.Int, error) } +// FeeHistory provides recent fee market data that consumers can use to determine +// a reasonable maxPriorityFeePerGas value. +type FeeHistory struct { + OldestBlock *big.Int // block coresponding to first response value + Reward [][]*big.Int // list every txs priority fee per block + BaseFee []*big.Int // list of each block's base fee + GasUsedRatio []float64 // ratio of gas used out of the total available limit +} + // A PendingStateReader provides access to the pending state, which is the result of all // known executable transactions which have not yet been included in the blockchain. It is // commonly used to display the result of ’unconfirmed’ actions (e.g. wallet value diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a3637969e81e..90322033b935 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -86,6 +86,7 @@ type feeHistoryResult struct { GasUsedRatio []float64 `json:"gasUsedRatio"` } +// FeeHistory returns the fee market history. func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, int(blockCount), lastBlock, rewardPercentiles) if err != nil { From 029059947a9570e3b601686ae818c92d5f8f1b85 Mon Sep 17 00:00:00 2001 From: Seungbae Yu <72970043+dbadoy@users.noreply.github.com> Date: Sat, 30 Jul 2022 01:23:30 +0900 Subject: [PATCH 130/715] all: use AbsTime.Add instead of conversion (#25417) --- common/mclock/simclock.go | 4 ++-- common/prque/lazyqueue.go | 4 ++-- les/distributor.go | 2 +- les/flowcontrol/control.go | 2 +- les/utils/timeutils_test.go | 2 +- les/vflux/server/balance.go | 8 ++++---- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/common/mclock/simclock.go b/common/mclock/simclock.go index 766ca0f8736c..f5ad3f8bc0aa 100644 --- a/common/mclock/simclock.go +++ b/common/mclock/simclock.go @@ -58,7 +58,7 @@ func (s *Simulated) Run(d time.Duration) { s.mu.Lock() s.init() - end := s.now + AbsTime(d) + end := s.now.Add(d) var do []func() for len(s.scheduled) > 0 && s.scheduled[0].at <= end { ev := heap.Pop(&s.scheduled).(*simTimer) @@ -134,7 +134,7 @@ func (s *Simulated) AfterFunc(d time.Duration, fn func()) Timer { func (s *Simulated) schedule(d time.Duration, fn func()) *simTimer { s.init() - at := s.now + AbsTime(d) + at := s.now.Add(d) ev := &simTimer{do: fn, at: at, s: s} heap.Push(&s.scheduled, ev) s.cond.Broadcast() diff --git a/common/prque/lazyqueue.go b/common/prque/lazyqueue.go index 2fd2300d7371..6fdb6cc1b79f 100644 --- a/common/prque/lazyqueue.go +++ b/common/prque/lazyqueue.go @@ -87,13 +87,13 @@ func (q *LazyQueue) Refresh() { // refresh re-evaluates items in the older queue and swaps the two queues func (q *LazyQueue) refresh(now mclock.AbsTime) { - q.maxUntil = now + mclock.AbsTime(q.period) + q.maxUntil = now.Add(q.period) for q.queue[0].Len() != 0 { q.Push(heap.Pop(q.queue[0]).(*item).value) } q.queue[0], q.queue[1] = q.queue[1], q.queue[0] q.indexOffset = 1 - q.indexOffset - q.maxUntil += mclock.AbsTime(q.period) + q.maxUntil = q.maxUntil.Add(q.period) } // Push adds an item to the queue diff --git a/les/distributor.go b/les/distributor.go index 31150e4d731a..a0319c67f737 100644 --- a/les/distributor.go +++ b/les/distributor.go @@ -256,7 +256,7 @@ func (d *requestDistributor) queue(r *distReq) chan distPeer { if r.reqOrder == 0 { d.lastReqOrder++ r.reqOrder = d.lastReqOrder - r.waitForPeers = d.clock.Now() + mclock.AbsTime(waitForPeers) + r.waitForPeers = d.clock.Now().Add(waitForPeers) } // Assign the timestamp when the request is queued no matter it's // a new one or re-queued one. diff --git a/les/flowcontrol/control.go b/les/flowcontrol/control.go index 4f0de8231835..76a241fa5a7f 100644 --- a/les/flowcontrol/control.go +++ b/les/flowcontrol/control.go @@ -182,7 +182,7 @@ func (node *ClientNode) UpdateParams(params ServerParams) { return } } - node.updateSchedule = append(node.updateSchedule, scheduledUpdate{time: now + mclock.AbsTime(DecParamDelay), params: params}) + node.updateSchedule = append(node.updateSchedule, scheduledUpdate{time: now.Add(DecParamDelay), params: params}) } } diff --git a/les/utils/timeutils_test.go b/les/utils/timeutils_test.go index 9f9e1c2dc938..b219d0439dcb 100644 --- a/les/utils/timeutils_test.go +++ b/les/utils/timeutils_test.go @@ -37,7 +37,7 @@ func TestUpdateTimer(t *testing.T) { if updated := timer.Update(func(diff time.Duration) bool { return true }); !updated { t.Fatalf("Doesn't update the clock when reaching the threshold") } - if updated := timer.UpdateAt(sim.Now()+mclock.AbsTime(time.Second), func(diff time.Duration) bool { return true }); !updated { + if updated := timer.UpdateAt(sim.Now().Add(time.Second), func(diff time.Duration) bool { return true }); !updated { t.Fatalf("Doesn't update the clock when reaching the threshold") } timer = NewUpdateTimer(sim, 0) diff --git a/les/vflux/server/balance.go b/les/vflux/server/balance.go index 727ce09a432f..550c6d70ca8b 100644 --- a/les/vflux/server/balance.go +++ b/les/vflux/server/balance.go @@ -356,7 +356,7 @@ func (n *nodeBalance) estimatePriority(capacity uint64, addBalance int64, future b = n.reducedBalance(b, now, future, capacity, avgReqCost) } if bias > 0 { - b = n.reducedBalance(b, now+mclock.AbsTime(future), bias, capacity, 0) + b = n.reducedBalance(b, now.Add(future), bias, capacity, 0) } pri := n.balanceToPriority(now, b, capacity) // Ensure that biased estimates are always lower than actual priorities, even if @@ -512,7 +512,7 @@ func (n *nodeBalance) scheduleCheck(now mclock.AbsTime) { n.updateAfter(0) return } - if n.nextUpdate == 0 || n.nextUpdate > now+mclock.AbsTime(d) { + if n.nextUpdate == 0 || n.nextUpdate > now.Add(d) { if d > time.Second { // Note: if the scheduled update is not in the very near future then we // schedule the update a bit earlier. This way we do need to update a few @@ -520,7 +520,7 @@ func (n *nodeBalance) scheduleCheck(now mclock.AbsTime) { // brings the expected firing time a little bit closer. d = ((d - time.Second) * 7 / 8) + time.Second } - n.nextUpdate = now + mclock.AbsTime(d) + n.nextUpdate = now.Add(d) n.updateAfter(d) } } else { @@ -629,7 +629,7 @@ func (n *nodeBalance) reducedBalance(b balance, start mclock.AbsTime, dt time.Du // since the costs are applied continuously during the dt time period we calculate // the expiration offset at the middle of the period var ( - at = start + mclock.AbsTime(dt/2) + at = start.Add(dt / 2) dtf = float64(dt) ) if !b.pos.IsZero() { From 1af9e4f34caccc6bdc30c151b74f9689f5627c6d Mon Sep 17 00:00:00 2001 From: Delweng Date: Sat, 30 Jul 2022 00:28:14 +0800 Subject: [PATCH 131/715] cm/puppeth: fix crash when of ethstats specifier doesn't contain `:` (#25405) Signed-off-by: Delweng --- cmd/puppeth/module.go | 9 +++++++++ cmd/puppeth/module_explorer.go | 2 +- cmd/puppeth/module_faucet.go | 2 +- cmd/puppeth/module_node.go | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cmd/puppeth/module.go b/cmd/puppeth/module.go index b6a029a01a48..771ae38058bc 100644 --- a/cmd/puppeth/module.go +++ b/cmd/puppeth/module.go @@ -150,3 +150,12 @@ func checkPort(host string, port int) error { conn.Close() return nil } + +// getEthName gets the Ethereum Name from ethstats +func getEthName(s string) string { + n := strings.Index(s, ":") + if n >= 0 { + return s[:n] + } + return s +} diff --git a/cmd/puppeth/module_explorer.go b/cmd/puppeth/module_explorer.go index 1165f70fcf51..3812f9fdb963 100644 --- a/cmd/puppeth/module_explorer.go +++ b/cmd/puppeth/module_explorer.go @@ -104,7 +104,7 @@ func deployExplorer(client *sshClient, network string, bootnodes []string, confi "Datadir": config.node.datadir, "DBDir": config.dbdir, "EthPort": config.node.port, - "EthName": config.node.ethstats[:strings.Index(config.node.ethstats, ":")], + "EthName": getEthName(config.node.ethstats), "WebPort": config.port, "Transformer": transformer, }) diff --git a/cmd/puppeth/module_faucet.go b/cmd/puppeth/module_faucet.go index 88cb80ae4c42..a4f6e65694df 100644 --- a/cmd/puppeth/module_faucet.go +++ b/cmd/puppeth/module_faucet.go @@ -116,7 +116,7 @@ func deployFaucet(client *sshClient, network string, bootnodes []string, config "VHost": config.host, "ApiPort": config.port, "EthPort": config.node.port, - "EthName": config.node.ethstats[:strings.Index(config.node.ethstats, ":")], + "EthName": getEthName(config.node.ethstats), "CaptchaToken": config.captchaToken, "CaptchaSecret": config.captchaSecret, "FaucetAmount": config.amount, diff --git a/cmd/puppeth/module_node.go b/cmd/puppeth/module_node.go index 3ea96870d4f5..b8aa30db39a8 100644 --- a/cmd/puppeth/module_node.go +++ b/cmd/puppeth/module_node.go @@ -123,7 +123,7 @@ func deployNode(client *sshClient, network string, bootnodes []string, config *n "TotalPeers": config.peersTotal, "Light": config.peersLight > 0, "LightPeers": config.peersLight, - "Ethstats": config.ethstats[:strings.Index(config.ethstats, ":")], + "Ethstats": getEthName(config.ethstats), "Etherbase": config.etherbase, "GasTarget": config.gasTarget, "GasLimit": config.gasLimit, From fea569f90aa608abeb13cea6c9fd55f1d0a77f40 Mon Sep 17 00:00:00 2001 From: Rithwik Babu Date: Fri, 29 Jul 2022 11:29:01 -0500 Subject: [PATCH 132/715] eth: fix typo in comment (#25327) --- eth/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/api.go b/eth/api.go index ad8566dae26a..5d9a3cc3ad82 100644 --- a/eth/api.go +++ b/eth/api.go @@ -157,7 +157,7 @@ func (api *AdminAPI) ExportChain(file string, first *uint64, last *uint64) (bool } if _, err := os.Stat(file); err == nil { // File already exists. Allowing overwrite could be a DoS vector, - // since the 'file' may point to arbitrary paths on the drive + // since the 'file' may point to arbitrary paths on the drive. return false, errors.New("location would overwrite an existing file") } // Make sure we can create the file to export into From 49aa8a633b7333d16ff68777c95d45e897e1903f Mon Sep 17 00:00:00 2001 From: Henry <101552941+henry-0@users.noreply.github.com> Date: Mon, 1 Aug 2022 19:47:21 +0800 Subject: [PATCH 133/715] common/compiler: json unmarshalling error checks (#25449) complier/solidity:add json.Unmarshal err check --- common/compiler/solidity.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/common/compiler/solidity.go b/common/compiler/solidity.go index ad8a44aa04ae..9de94017c2ed 100644 --- a/common/compiler/solidity.go +++ b/common/compiler/solidity.go @@ -66,13 +66,16 @@ func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion strin contracts := make(map[string]*Contract) for name, info := range output.Contracts { // Parse the individual compilation results. - var abi interface{} + var abi, userdoc, devdoc interface{} if err := json.Unmarshal([]byte(info.Abi), &abi); err != nil { return nil, fmt.Errorf("solc: error reading abi definition (%v)", err) } - var userdoc, devdoc interface{} - json.Unmarshal([]byte(info.Userdoc), &userdoc) - json.Unmarshal([]byte(info.Devdoc), &devdoc) + if err := json.Unmarshal([]byte(info.Userdoc), &userdoc); err != nil { + return nil, fmt.Errorf("solc: error reading userdoc definition (%v)", err) + } + if err := json.Unmarshal([]byte(info.Devdoc), &devdoc); err != nil { + return nil, fmt.Errorf("solc: error reading devdoc definition (%v)", err) + } contracts[name] = &Contract{ Code: "0x" + info.Bin, From 6fd06ab0751f1312d48bf593c7f356dcd6f51ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 1 Aug 2022 15:13:25 +0300 Subject: [PATCH 134/715] cmd, core, eth, les, params: add merge-passed chain config (#24538) * cmd, core, eth, les, params: add merge-passed chain config * eth/catalyst, params: add various warning on malfunctioning beacons * eth/catalyst: fix warning for beacons without transition exchanges --- cmd/geth/config.go | 9 +- cmd/geth/main.go | 2 +- cmd/utils/flags.go | 11 +-- core/genesis.go | 6 +- core/rawdb/chain_freezer.go | 2 +- eth/backend.go | 2 +- eth/catalyst/api.go | 159 ++++++++++++++++++++++++++++++- eth/ethconfig/config.go | 6 +- eth/ethconfig/gen_config.go | 180 ++++++++++++++++++------------------ eth/handler.go | 19 +++- eth/sync.go | 2 +- les/client.go | 2 +- params/config.go | 92 ++++++++++-------- 13 files changed, 332 insertions(+), 160 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 710e71836607..2562de8ae9ea 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -20,7 +20,6 @@ import ( "bufio" "errors" "fmt" - "math/big" "os" "reflect" "unicode" @@ -157,12 +156,13 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // makeFullNode loads geth configuration and creates the Ethereum backend. func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { stack, cfg := makeConfigNode(ctx) - if ctx.IsSet(utils.OverrideGrayGlacierFlag.Name) { - cfg.Eth.OverrideGrayGlacier = new(big.Int).SetUint64(ctx.Uint64(utils.OverrideGrayGlacierFlag.Name)) - } if ctx.IsSet(utils.OverrideTerminalTotalDifficulty.Name) { cfg.Eth.OverrideTerminalTotalDifficulty = flags.GlobalBig(ctx, utils.OverrideTerminalTotalDifficulty.Name) } + if ctx.IsSet(utils.OverrideTerminalTotalDifficultyPassed.Name) { + override := ctx.Bool(utils.OverrideTerminalTotalDifficultyPassed.Name) + cfg.Eth.OverrideTerminalTotalDifficultyPassed = &override + } backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Warn users to migrate if they have a legacy freezer format. if eth != nil && !ctx.IsSet(utils.IgnoreLegacyReceiptsFlag.Name) { @@ -181,7 +181,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { utils.Fatalf("Database has receipts with a legacy format. Please run `geth db freezer-migrate`.") } } - // Configure GraphQL if requested if ctx.IsSet(utils.GraphQLEnabledFlag.Name) { utils.RegisterGraphQLService(stack, backend, cfg.Node) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 9aae75974c66..c0f636fb26ff 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -69,8 +69,8 @@ var ( utils.NoUSBFlag, utils.USBFlag, utils.SmartCardDaemonPathFlag, - utils.OverrideGrayGlacierFlag, utils.OverrideTerminalTotalDifficulty, + utils.OverrideTerminalTotalDifficultyPassed, utils.EthashCacheDirFlag, utils.EthashCachesInMemoryFlag, utils.EthashCachesOnDiskFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index f55719af4989..ff85e259aea3 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -262,17 +262,16 @@ var ( Value: 2048, Category: flags.EthCategory, } - OverrideGrayGlacierFlag = &cli.Uint64Flag{ - Name: "override.grayglacier", - Usage: "Manually specify Gray Glacier fork-block, overriding the bundled setting", - Category: flags.EthCategory, - } OverrideTerminalTotalDifficulty = &flags.BigFlag{ Name: "override.terminaltotaldifficulty", Usage: "Manually specify TerminalTotalDifficulty, overriding the bundled setting", Category: flags.EthCategory, } - + OverrideTerminalTotalDifficultyPassed = &cli.BoolFlag{ + Name: "override.terminaltotaldifficultypassed", + Usage: "Manually specify TerminalTotalDifficultyPassed, overriding the bundled setting", + Category: flags.EthCategory, + } // Light server and client settings LightServeFlag = &cli.IntFlag{ Name: "light.serve", diff --git a/core/genesis.go b/core/genesis.go index 7dcc7cfc3fab..45284f3deea6 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -233,7 +233,7 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig return SetupGenesisBlockWithOverride(db, genesis, nil, nil) } -func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, overrideGrayGlacier, overrideTerminalTotalDifficulty *big.Int) (*params.ChainConfig, common.Hash, error) { +func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, overrideTerminalTotalDifficulty *big.Int, overrideTerminalTotalDifficultyPassed *bool) (*params.ChainConfig, common.Hash, error) { if genesis != nil && genesis.Config == nil { return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig } @@ -243,8 +243,8 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override if overrideTerminalTotalDifficulty != nil { config.TerminalTotalDifficulty = overrideTerminalTotalDifficulty } - if overrideGrayGlacier != nil { - config.GrayGlacierBlock = overrideGrayGlacier + if overrideTerminalTotalDifficultyPassed != nil { + config.TerminalTotalDifficultyPassed = *overrideTerminalTotalDifficultyPassed } } } diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 4c49db2748b2..ec39b7b59cd2 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -241,7 +241,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { if n := len(ancients); n > 0 { context = append(context, []interface{}{"hash", ancients[n-1]}...) } - log.Info("Deep froze chain segment", context...) + log.Debug("Deep froze chain segment", context...) // Avoid database thrashing with tiny writes if frozen-first < freezerBatchLimit { diff --git a/eth/backend.go b/eth/backend.go index b16ce4b54fa0..ebe7001c7994 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -137,7 +137,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideGrayGlacier, config.OverrideTerminalTotalDifficulty) + chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideTerminalTotalDifficulty, config.OverrideTerminalTotalDifficultyPassed) if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { return nil, genesisErr } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index c5f2313cabbc..93b78a3867f5 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -22,6 +22,7 @@ import ( "encoding/binary" "errors" "fmt" + "math/big" "sync" "time" @@ -59,6 +60,11 @@ const ( // invalidTipsetsCap is the max number of recent block hashes tracked that // have lead to some bad ancestor block. It's just an OOM protection. invalidTipsetsCap = 512 + + // beaconUpdateTimeout is the max time allowed for a beacon client to signal + // use (from the last heartbeat) before it's consifered offline and the user + // is warned. + beaconUpdateTimeout = 30 * time.Second ) type ConsensusAPI struct { @@ -90,7 +96,17 @@ type ConsensusAPI struct { invalidTipsets map[common.Hash]*types.Header // Ephemeral cache to track invalid tipsets and their bad ancestor invalidLock sync.Mutex // Protects the invalid maps from concurrent access - forkChoiceLock sync.Mutex // Lock for the forkChoiceUpdated method + // Geth can appear to be stuck or do strange things if the beacon client is + // offline or is sending us strange data. Stash some update stats away so + // that we can warn the user and not have them open issues on our tracker. + lastTransitionUpdate time.Time + lastTransitionLock sync.Mutex + lastForkchoiceUpdate time.Time + lastForkchoiceLock sync.Mutex + lastNewPayloadUpdate time.Time + lastNewPayloadLock sync.Mutex + + forkchoiceLock sync.Mutex // Lock for the forkChoiceUpdated method } // NewConsensusAPI creates a new consensus api for the given backend. @@ -107,6 +123,7 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { invalidTipsets: make(map[common.Hash]*types.Header), } eth.Downloader().SetBadBlockCallback(api.setInvalidAncestor) + go api.heartbeat() return api } @@ -122,14 +139,18 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { // If there are payloadAttributes: // we try to assemble a block with the payloadAttributes and return its payloadID func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributesV1) (beacon.ForkChoiceResponse, error) { - api.forkChoiceLock.Lock() - defer api.forkChoiceLock.Unlock() + api.forkchoiceLock.Lock() + defer api.forkchoiceLock.Unlock() log.Trace("Engine API request received", "method", "ForkchoiceUpdated", "head", update.HeadBlockHash, "finalized", update.FinalizedBlockHash, "safe", update.SafeBlockHash) if update.HeadBlockHash == (common.Hash{}) { log.Warn("Forkchoice requested update to zero hash") return beacon.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this? } + // Stash away the last update to warn the user if the beacon client goes offline + api.lastForkchoiceLock.Lock() + api.lastForkchoiceUpdate = time.Now() + api.lastForkchoiceLock.Unlock() // Check whether we have the block yet in our database or not. If not, we'll // need to either trigger a sync, or to reject this forkchoice update for a @@ -265,15 +286,20 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa // ExchangeTransitionConfigurationV1 checks the given configuration against // the configuration of the node. func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.TransitionConfigurationV1) (*beacon.TransitionConfigurationV1, error) { + log.Trace("Engine API request received", "method", "ExchangeTransitionConfiguration", "ttd", config.TerminalTotalDifficulty) if config.TerminalTotalDifficulty == nil { return nil, errors.New("invalid terminal total difficulty") } + // Stash away the last update to warn the user if the beacon client goes offline + api.lastTransitionLock.Lock() + api.lastTransitionUpdate = time.Now() + api.lastTransitionLock.Unlock() + ttd := api.eth.BlockChain().Config().TerminalTotalDifficulty if ttd == nil || ttd.Cmp(config.TerminalTotalDifficulty.ToInt()) != 0 { log.Warn("Invalid TTD configured", "geth", ttd, "beacon", config.TerminalTotalDifficulty) return nil, fmt.Errorf("invalid ttd: execution %v consensus %v", ttd, config.TerminalTotalDifficulty) } - if config.TerminalBlockHash != (common.Hash{}) { if hash := api.eth.BlockChain().GetCanonicalHash(uint64(config.TerminalBlockNumber)); hash == config.TerminalBlockHash { return &beacon.TransitionConfigurationV1{ @@ -305,6 +331,11 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa log.Debug("Invalid NewPayload params", "params", params, "error", err) return beacon.PayloadStatusV1{Status: beacon.INVALIDBLOCKHASH}, nil } + // Stash away the last update to warn the user if the beacon client goes offline + api.lastNewPayloadLock.Lock() + api.lastNewPayloadUpdate = time.Now() + api.lastNewPayloadLock.Unlock() + // If we already have the block locally, ignore the entire execution and just // return a fake success. if block := api.eth.BlockChain().GetBlockByHash(params.BlockHash); block != nil { @@ -507,3 +538,123 @@ func (api *ConsensusAPI) invalid(err error, latestValid *types.Header) beacon.Pa errorMsg := err.Error() return beacon.PayloadStatusV1{Status: beacon.INVALID, LatestValidHash: ¤tHash, ValidationError: &errorMsg} } + +// heatbeat loops indefinitely, and checks if there have been beacon client updates +// received in the last while. If not - or if they but strange ones - it warns the +// user that something might be off with their consensus node. +// +// TODO(karalabe): Spin this goroutine down somehow +func (api *ConsensusAPI) heartbeat() { + // Sleep a bit more on startup since there's obviously no beacon client yet + // attached, so no need to print scary warnings to the user. + time.Sleep(beaconUpdateTimeout) + + var ( + offlineLogged time.Time + ) + for { + // Sleep a bit and retrieve the last known consensus updates + time.Sleep(5 * time.Second) + + // If the network is not yet merged/merging, don't bother scaring the user + ttd := api.eth.BlockChain().Config().TerminalTotalDifficulty + if ttd == nil { + continue + } + api.lastTransitionLock.Lock() + lastTransitionUpdate := api.lastTransitionUpdate + api.lastTransitionLock.Unlock() + + api.lastForkchoiceLock.Lock() + lastForkchoiceUpdate := api.lastForkchoiceUpdate + api.lastForkchoiceLock.Unlock() + + api.lastNewPayloadLock.Lock() + lastNewPayloadUpdate := api.lastNewPayloadUpdate + api.lastNewPayloadLock.Unlock() + + // If there have been no updates for the past while, warn the user + // that the beacon client is probably offline + if api.eth.BlockChain().Config().TerminalTotalDifficultyPassed || api.eth.Merger().TDDReached() { + if time.Since(lastForkchoiceUpdate) > beaconUpdateTimeout && time.Since(lastNewPayloadUpdate) > beaconUpdateTimeout { + if time.Since(lastTransitionUpdate) > beaconUpdateTimeout { + if time.Since(offlineLogged) > beaconUpdateTimeout { + if lastTransitionUpdate.IsZero() { + log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!") + } else { + log.Warn("Previously seen beacon client is offline. Please ensure it is operational to follow the chain!") + } + offlineLogged = time.Now() + } + continue + } + if time.Since(offlineLogged) > beaconUpdateTimeout { + if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { + log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") + } else { + log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!") + } + offlineLogged = time.Now() + } + continue + } + } else { + if time.Since(lastTransitionUpdate) > beaconUpdateTimeout { + if time.Since(offlineLogged) > beaconUpdateTimeout { + // Retrieve the last few blocks and make a rough estimate as + // to when the merge transition should happen + var ( + chain = api.eth.BlockChain() + head = chain.CurrentBlock() + htd = chain.GetTd(head.Hash(), head.NumberU64()) + eta time.Duration + ) + if head.NumberU64() > 0 && htd.Cmp(ttd) < 0 { + // Accumulate the last 64 difficulties to estimate the growth + var diff float64 + + block := head + for i := 0; i < 64; i++ { + diff += float64(block.Difficulty().Uint64()) + if parent := chain.GetBlock(block.ParentHash(), block.NumberU64()-1); parent == nil { + break + } else { + block = parent + } + } + // Estimate an ETA based on the block times and the difficulty growth + growth := diff / float64(head.Time()-block.Time()+1) // +1 to avoid div by zero + if growth > 0 { + if left := new(big.Int).Sub(ttd, htd); left.IsUint64() { + eta = time.Duration(float64(left.Uint64())/growth) * time.Second + } else { + eta = time.Duration(new(big.Int).Div(left, big.NewInt(int64(growth))).Uint64()) * time.Second + } + } + } + var message string + if htd.Cmp(ttd) > 0 { + if lastTransitionUpdate.IsZero() { + message = "Merge already reached, but no beacon client seen. Please launch one to follow the chain!" + } else { + message = "Merge already reached, but previously seen beacon client is offline. Please ensure it is operational to follow the chain!" + } + } else { + if lastTransitionUpdate.IsZero() { + message = "Merge is configured, but no beacon client seen. Please ensure you have one available before the transision arrives!" + } else { + message = "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transision arrives!" + } + } + if eta == 0 { + log.Warn(message) + } else { + log.Warn(message, "eta", common.PrettyAge(time.Now().Add(-eta))) // weird hack, but duration formatted doens't handle days + } + offlineLogged = time.Now() + } + continue + } + } + } +} diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index f9496359528b..7ba2faf791b4 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -205,11 +205,11 @@ type Config struct { // CheckpointOracle is the configuration for checkpoint oracle. CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - // Gray Glacier block override (TODO: remove after the fork) - OverrideGrayGlacier *big.Int `toml:",omitempty"` - // OverrideTerminalTotalDifficulty (TODO: remove after the fork) OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` + + // OverrideTerminalTotalDifficultyPassed (TODO: remove after the fork) + OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` } // CreateConsensusEngine creates a consensus engine for the given chain configuration. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index e714dd97ab19..a6528c8df5f7 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -18,49 +18,49 @@ import ( // MarshalTOML marshals as TOML. func (c Config) MarshalTOML() (interface{}, error) { type Config struct { - Genesis *core.Genesis `toml:",omitempty"` - NetworkId uint64 - SyncMode downloader.SyncMode - EthDiscoveryURLs []string - SnapDiscoveryURLs []string - NoPruning bool - NoPrefetch bool - TxLookupLimit uint64 `toml:",omitempty"` - RequiredBlocks map[uint64]common.Hash `toml:"-"` - LightServ int `toml:",omitempty"` - LightIngress int `toml:",omitempty"` - LightEgress int `toml:",omitempty"` - LightPeers int `toml:",omitempty"` - LightNoPrune bool `toml:",omitempty"` - LightNoSyncServe bool `toml:",omitempty"` - SyncFromCheckpoint bool `toml:",omitempty"` - UltraLightServers []string `toml:",omitempty"` - UltraLightFraction int `toml:",omitempty"` - UltraLightOnlyAnnounce bool `toml:",omitempty"` - SkipBcVersionCheck bool `toml:"-"` - DatabaseHandles int `toml:"-"` - DatabaseCache int - DatabaseFreezer string - TrieCleanCache int - TrieCleanCacheJournal string `toml:",omitempty"` - TrieCleanCacheRejournal time.Duration `toml:",omitempty"` - TrieDirtyCache int - TrieTimeout time.Duration - SnapshotCache int - Preimages bool - Miner miner.Config - Ethash ethash.Config - TxPool core.TxPoolConfig - GPO gasprice.Config - EnablePreimageRecording bool - DocRoot string `toml:"-"` - RPCGasCap uint64 - RPCEVMTimeout time.Duration - RPCTxFeeCap float64 - Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` - CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - OverrideGrayGlacier *big.Int `toml:",omitempty"` - OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` + Genesis *core.Genesis `toml:",omitempty"` + NetworkId uint64 + SyncMode downloader.SyncMode + EthDiscoveryURLs []string + SnapDiscoveryURLs []string + NoPruning bool + NoPrefetch bool + TxLookupLimit uint64 `toml:",omitempty"` + RequiredBlocks map[uint64]common.Hash `toml:"-"` + LightServ int `toml:",omitempty"` + LightIngress int `toml:",omitempty"` + LightEgress int `toml:",omitempty"` + LightPeers int `toml:",omitempty"` + LightNoPrune bool `toml:",omitempty"` + LightNoSyncServe bool `toml:",omitempty"` + SyncFromCheckpoint bool `toml:",omitempty"` + UltraLightServers []string `toml:",omitempty"` + UltraLightFraction int `toml:",omitempty"` + UltraLightOnlyAnnounce bool `toml:",omitempty"` + SkipBcVersionCheck bool `toml:"-"` + DatabaseHandles int `toml:"-"` + DatabaseCache int + DatabaseFreezer string + TrieCleanCache int + TrieCleanCacheJournal string `toml:",omitempty"` + TrieCleanCacheRejournal time.Duration `toml:",omitempty"` + TrieDirtyCache int + TrieTimeout time.Duration + SnapshotCache int + Preimages bool + Miner miner.Config + Ethash ethash.Config + TxPool core.TxPoolConfig + GPO gasprice.Config + EnablePreimageRecording bool + DocRoot string `toml:"-"` + RPCGasCap uint64 + RPCEVMTimeout time.Duration + RPCTxFeeCap float64 + Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` + CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` + OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` + OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` } var enc Config enc.Genesis = c.Genesis @@ -104,57 +104,57 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCTxFeeCap = c.RPCTxFeeCap enc.Checkpoint = c.Checkpoint enc.CheckpointOracle = c.CheckpointOracle - enc.OverrideGrayGlacier = c.OverrideGrayGlacier enc.OverrideTerminalTotalDifficulty = c.OverrideTerminalTotalDifficulty + enc.OverrideTerminalTotalDifficultyPassed = c.OverrideTerminalTotalDifficultyPassed return &enc, nil } // UnmarshalTOML unmarshals from TOML. func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { type Config struct { - Genesis *core.Genesis `toml:",omitempty"` - NetworkId *uint64 - SyncMode *downloader.SyncMode - EthDiscoveryURLs []string - SnapDiscoveryURLs []string - NoPruning *bool - NoPrefetch *bool - TxLookupLimit *uint64 `toml:",omitempty"` - RequiredBlocks map[uint64]common.Hash `toml:"-"` - LightServ *int `toml:",omitempty"` - LightIngress *int `toml:",omitempty"` - LightEgress *int `toml:",omitempty"` - LightPeers *int `toml:",omitempty"` - LightNoPrune *bool `toml:",omitempty"` - LightNoSyncServe *bool `toml:",omitempty"` - SyncFromCheckpoint *bool `toml:",omitempty"` - UltraLightServers []string `toml:",omitempty"` - UltraLightFraction *int `toml:",omitempty"` - UltraLightOnlyAnnounce *bool `toml:",omitempty"` - SkipBcVersionCheck *bool `toml:"-"` - DatabaseHandles *int `toml:"-"` - DatabaseCache *int - DatabaseFreezer *string - TrieCleanCache *int - TrieCleanCacheJournal *string `toml:",omitempty"` - TrieCleanCacheRejournal *time.Duration `toml:",omitempty"` - TrieDirtyCache *int - TrieTimeout *time.Duration - SnapshotCache *int - Preimages *bool - Miner *miner.Config - Ethash *ethash.Config - TxPool *core.TxPoolConfig - GPO *gasprice.Config - EnablePreimageRecording *bool - DocRoot *string `toml:"-"` - RPCGasCap *uint64 - RPCEVMTimeout *time.Duration - RPCTxFeeCap *float64 - Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` - CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - OverrideGrayGlacier *big.Int `toml:",omitempty"` - OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` + Genesis *core.Genesis `toml:",omitempty"` + NetworkId *uint64 + SyncMode *downloader.SyncMode + EthDiscoveryURLs []string + SnapDiscoveryURLs []string + NoPruning *bool + NoPrefetch *bool + TxLookupLimit *uint64 `toml:",omitempty"` + RequiredBlocks map[uint64]common.Hash `toml:"-"` + LightServ *int `toml:",omitempty"` + LightIngress *int `toml:",omitempty"` + LightEgress *int `toml:",omitempty"` + LightPeers *int `toml:",omitempty"` + LightNoPrune *bool `toml:",omitempty"` + LightNoSyncServe *bool `toml:",omitempty"` + SyncFromCheckpoint *bool `toml:",omitempty"` + UltraLightServers []string `toml:",omitempty"` + UltraLightFraction *int `toml:",omitempty"` + UltraLightOnlyAnnounce *bool `toml:",omitempty"` + SkipBcVersionCheck *bool `toml:"-"` + DatabaseHandles *int `toml:"-"` + DatabaseCache *int + DatabaseFreezer *string + TrieCleanCache *int + TrieCleanCacheJournal *string `toml:",omitempty"` + TrieCleanCacheRejournal *time.Duration `toml:",omitempty"` + TrieDirtyCache *int + TrieTimeout *time.Duration + SnapshotCache *int + Preimages *bool + Miner *miner.Config + Ethash *ethash.Config + TxPool *core.TxPoolConfig + GPO *gasprice.Config + EnablePreimageRecording *bool + DocRoot *string `toml:"-"` + RPCGasCap *uint64 + RPCEVMTimeout *time.Duration + RPCTxFeeCap *float64 + Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` + CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` + OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` + OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { @@ -283,11 +283,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.CheckpointOracle != nil { c.CheckpointOracle = dec.CheckpointOracle } - if dec.OverrideGrayGlacier != nil { - c.OverrideGrayGlacier = dec.OverrideGrayGlacier - } if dec.OverrideTerminalTotalDifficulty != nil { c.OverrideTerminalTotalDifficulty = dec.OverrideTerminalTotalDifficulty } + if dec.OverrideTerminalTotalDifficultyPassed != nil { + c.OverrideTerminalTotalDifficultyPassed = dec.OverrideTerminalTotalDifficultyPassed + } return nil } diff --git a/eth/handler.go b/eth/handler.go index 1418c73894c8..4224a9f33a84 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -191,11 +191,22 @@ func newHandler(config *handlerConfig) (*handler, error) { } } } - // Construct the downloader (long sync) and its backing state bloom if snap - // sync is requested. The downloader is responsible for deallocating the state - // bloom when it's done. + // Construct the downloader (long sync) h.downloader = downloader.New(h.checkpointNumber, config.Database, h.eventMux, h.chain, nil, h.removePeer, success) - + if ttd := h.chain.Config().TerminalTotalDifficulty; ttd != nil { + if h.chain.Config().TerminalTotalDifficultyPassed { + log.Info("Chain post-merge, sync via beacon client") + } else { + head := h.chain.CurrentBlock() + if td := h.chain.GetTd(head.Hash(), head.NumberU64()); td.Cmp(ttd) >= 0 { + log.Info("Chain post-TTD, sync via beacon client") + } else { + log.Warn("Chain pre-merge, sync via PoW (ensure beacon client is ready)") + } + } + } else if h.chain.Config().TerminalTotalDifficultyPassed { + log.Error("Chain configured post-merge, but without TTD. Are you debugging sync?") + } // Construct the fetcher (short sync) validator := func(header *types.Header) error { // All the block fetcher activities should be disabled diff --git a/eth/sync.go b/eth/sync.go index d67d2311d0d9..8fd86b578cf6 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -163,7 +163,7 @@ func (cs *chainSyncer) nextSyncOp() *chainSyncOp { // An alternative would be to check the local chain for exceeding the TTD and // avoid triggering a sync in that case, but that could also miss sibling or // other family TTD block being accepted. - if cs.handler.merger.TDDReached() { + if cs.handler.chain.Config().TerminalTotalDifficultyPassed || cs.handler.merger.TDDReached() { return nil } // Ensure we're at minimum peer count. diff --git a/les/client.go b/les/client.go index 44eaffec2373..7caaf2c18a58 100644 --- a/les/client.go +++ b/les/client.go @@ -93,7 +93,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { if err != nil { return nil, err } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideGrayGlacier, config.OverrideTerminalTotalDifficulty) + chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideTerminalTotalDifficulty, config.OverrideTerminalTotalDifficultyPassed) if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { return nil, genesisErr } diff --git a/params/config.go b/params/config.go index 47592e81612c..fda4c1aecda3 100644 --- a/params/config.go +++ b/params/config.go @@ -100,23 +100,24 @@ var ( // RopstenChainConfig contains the chain parameters to run a node on the Ropsten test network. RopstenChainConfig = &ChainConfig{ - ChainID: big.NewInt(3), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), - EIP155Block: big.NewInt(10), - EIP158Block: big.NewInt(10), - ByzantiumBlock: big.NewInt(1_700_000), - ConstantinopleBlock: big.NewInt(4_230_000), - PetersburgBlock: big.NewInt(4_939_394), - IstanbulBlock: big.NewInt(6_485_846), - MuirGlacierBlock: big.NewInt(7_117_117), - BerlinBlock: big.NewInt(9_812_189), - LondonBlock: big.NewInt(10_499_401), - TerminalTotalDifficulty: new(big.Int).SetUint64(50000000000000000), - Ethash: new(EthashConfig), + ChainID: big.NewInt(3), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), + EIP155Block: big.NewInt(10), + EIP158Block: big.NewInt(10), + ByzantiumBlock: big.NewInt(1_700_000), + ConstantinopleBlock: big.NewInt(4_230_000), + PetersburgBlock: big.NewInt(4_939_394), + IstanbulBlock: big.NewInt(6_485_846), + MuirGlacierBlock: big.NewInt(7_117_117), + BerlinBlock: big.NewInt(9_812_189), + LondonBlock: big.NewInt(10_499_401), + TerminalTotalDifficulty: new(big.Int).SetUint64(50_000_000_000_000_000), + TerminalTotalDifficultyPassed: true, + Ethash: new(EthashConfig), } // RopstenTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network. @@ -142,23 +143,24 @@ var ( // SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network. SepoliaChainConfig = &ChainConfig{ - ChainID: big.NewInt(11155111), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - MuirGlacierBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - TerminalTotalDifficulty: big.NewInt(17_000_000_000_000_000), - MergeNetsplitBlock: big.NewInt(1735371), - Ethash: new(EthashConfig), + ChainID: big.NewInt(11155111), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(17_000_000_000_000_000), + TerminalTotalDifficultyPassed: true, + MergeNetsplitBlock: big.NewInt(1735371), + Ethash: new(EthashConfig), } // SepoliaTrustedCheckpoint contains the light client trusted checkpoint for the Sepolia test network. @@ -263,16 +265,16 @@ var ( // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, new(EthashConfig), nil} + AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(EthashConfig), nil} // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} + AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, false, nil, &CliqueConfig{Period: 0, Epoch: 30000}} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, new(EthashConfig), nil} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(EthashConfig), nil} TestRules = TestChainConfig.Rules(new(big.Int), false) ) @@ -370,6 +372,11 @@ type ChainConfig struct { // the network that triggers the consensus upgrade. TerminalTotalDifficulty *big.Int `json:"terminalTotalDifficulty,omitempty"` + // TerminalTotalDifficultyPassed is a flag specifying that the network already + // passed the terminal total difficulty. Its purpose is to disable legacy sync + // even without having seen the TTD locally (safer long term). + TerminalTotalDifficultyPassed bool `json:"terminalTotalDifficultyPassed,omitempty"` + // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` @@ -408,12 +415,16 @@ func (c *ChainConfig) String() string { case c.Ethash != nil: if c.TerminalTotalDifficulty == nil { banner += "Consensus: Ethash (proof-of-work)\n" + } else if !c.TerminalTotalDifficultyPassed { + banner += "Consensus: Beacon (proof-of-stake), merging from Ethash (proof-of-work)\n" } else { banner += "Consensus: Beacon (proof-of-stake), merged from Ethash (proof-of-work)\n" } case c.Clique != nil: if c.TerminalTotalDifficulty == nil { banner += "Consensus: Clique (proof-of-authority)\n" + } else if !c.TerminalTotalDifficultyPassed { + banner += "Consensus: Beacon (proof-of-stake), merging from Clique (proof-of-authority)\n" } else { banner += "Consensus: Beacon (proof-of-stake), merged from Clique (proof-of-authority)\n" } @@ -462,9 +473,10 @@ func (c *ChainConfig) String() string { banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)" } else { banner += "Merge configured:\n" - banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)\n" - banner += fmt.Sprintf(" - Total terminal difficulty: %v\n", c.TerminalTotalDifficulty) - banner += fmt.Sprintf(" - Merge netsplit block: %-8v", c.MergeNetsplitBlock) + banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)\n" + banner += fmt.Sprintf(" - Network known to be merged: %v\n", c.TerminalTotalDifficultyPassed) + banner += fmt.Sprintf(" - Total terminal difficulty: %v\n", c.TerminalTotalDifficulty) + banner += fmt.Sprintf(" - Merge netsplit block: %-8v", c.MergeNetsplitBlock) } return banner } From 1b34ed2ed6c1d0b56891b5bd9b1850d9d31e1038 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 1 Aug 2022 16:33:39 +0200 Subject: [PATCH 135/715] eth: fix typo in catalyst api (#25460) eth: fix typo --- eth/catalyst/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 93b78a3867f5..6b5f94646fa7 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -641,9 +641,9 @@ func (api *ConsensusAPI) heartbeat() { } } else { if lastTransitionUpdate.IsZero() { - message = "Merge is configured, but no beacon client seen. Please ensure you have one available before the transision arrives!" + message = "Merge is configured, but no beacon client seen. Please ensure you have one available before the transition arrives!" } else { - message = "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transision arrives!" + message = "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transition arrives!" } } if eta == 0 { From 93eabcaa4ea93fb3a01bfa69ef54a772616d89ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Mon, 1 Aug 2022 18:21:58 +0200 Subject: [PATCH 136/715] build: upgrade -dlgo version to Go 1.18.5 --- build/checksums.txt | 28 ++++++++++++++-------------- build/ci.go | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 1a8f3cd76756..f7b13a0330f2 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,19 +1,19 @@ # This file contains sha256 checksums of optional build dependencies. -4525aa6b0e3cecb57845f4060a7075aafc9ab752bb7b6b4cf8a212d43078e1e4 go1.18.4.src.tar.gz -315e1a2b21a827c68da1b7f492b5dcbe81d8df8a79ebe50922df9588893f87f0 go1.18.4.darwin-amd64.tar.gz -04eed623d5143ffa44965b618b509e0beccccfd3a4a1bfebc0cdbcf906046769 go1.18.4.darwin-arm64.tar.gz -e5244fdcd6b6eaf785dbd8c6e02b4804a4d00409e7edecc63cd59fc8f37c34c5 go1.18.4.freebsd-386.tar.gz -fb00f8aaffcc80e0a2bd39db1d8e8e21ef0a691c564f7b7601383dd6adad4042 go1.18.4.freebsd-amd64.tar.gz -418232d905e18ece6cb13c4884bb1c68963d7d3b4d889671b3e5be8bd4059862 go1.18.4.linux-386.tar.gz -c9b099b68d93f5c5c8a8844a89f8db07eaa58270e3a1e01804f17f4cf8df02f5 go1.18.4.linux-amd64.tar.gz -35014d92b50d97da41dade965df7ebeb9a715da600206aa59ce1b2d05527421f go1.18.4.linux-arm64.tar.gz -7dfeab572e49638b0f3d9901457f0622c27b73301c2b99db9f5e9568ff40460c go1.18.4.linux-armv6l.tar.gz -f80acc4dc054ddc89ccc4869664e331bf16e0ac6e07830e94554162e66f66961 go1.18.4.linux-ppc64le.tar.gz -7e932f36e8f347feea2e706dcd32c1a464b1e5767ab2928ae460a37a975fe4a3 go1.18.4.linux-s390x.tar.gz -6343010a13ab783e553786b3cc3b4d63080128f61cf1e963505139c71ca66a0d go1.18.4.windows-386.zip -dfb93c517e050ba0cfc066802b38a8e7cda2ef666efd634859356b33f543cc49 go1.18.4.windows-amd64.zip -7d0d7b73592019d276f2bd44ee3cda0d8bd99356fdbf04fdb40c263518108ae4 go1.18.4.windows-arm64.zip +9920d3306a1ac536cdd2c796d6cb3c54bc559c226fc3cc39c32f1e0bd7f50d2a go1.18.5.src.tar.gz +828eeca8b5abea3e56921df8fa4b1101380a5ebcfee10acbc8ffe7ec0bf5876b go1.18.5.darwin-amd64.tar.gz +923a377c6fc9a2c789f5db61c24b8f64133f7889056897449891f256af34065f go1.18.5.darwin-arm64.tar.gz +c3d90264a706e2d88cfb44126dc6f0d008a48f00732e04bc377cea1a2b716a7c go1.18.5.freebsd-386.tar.gz +0de23843c568d388bc0f0e390a8966938cccaae0d74b698325f7175bac04e0c6 go1.18.5.freebsd-amd64.tar.gz +0c44f85d146c6f98c34e8ff436a42af22e90e36fe232d3d9d3101f23fd61362b go1.18.5.linux-386.tar.gz +9e5de37f9c49942c601b191ac5fba404b868bfc21d446d6960acc12283d6e5f2 go1.18.5.linux-amd64.tar.gz +006f6622718212363fa1ff004a6ab4d87bbbe772ec5631bab7cac10be346e4f1 go1.18.5.linux-arm64.tar.gz +d5ac34ac5f060a5274319aa04b7b11e41b123bd7887d64efb5f44ead236957af go1.18.5.linux-armv6l.tar.gz +2e37fb9c7cbaedd4e729492d658aa4cde821fc94117391a8105c13b25ca1c84b go1.18.5.linux-ppc64le.tar.gz +e3d536e7873639f85353e892444f83b14cb6670603961f215986ae8e28e8e07a go1.18.5.linux-s390x.tar.gz +7b3142ec0c5db991e7f73a231662a92429b90ee151fe47557acb566d8d9ae4d3 go1.18.5.windows-386.zip +73753620602d4b4469770040c53db55e5dd6af2ad07ecc18f71f164c3224eaad go1.18.5.windows-amd64.zip +4d154626affff12ef73ea1017af0e5b52dbc839ef92f6f9e76cf4f71278a5744 go1.18.5.windows-arm64.zip 658078aaaf7608693f37c4cf1380b2af418ab8b2d23fdb33e7e2d4339328590e golangci-lint-1.46.2-darwin-amd64.tar.gz 81f9b4afd62ec5e612ef8bc3b1d612a88b56ff289874831845cdad394427385f golangci-lint-1.46.2-darwin-arm64.tar.gz diff --git a/build/ci.go b/build/ci.go index edf97cdd09bc..526e76f38132 100644 --- a/build/ci.go +++ b/build/ci.go @@ -149,7 +149,7 @@ var ( // This is the version of go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.18.4" + dlgoVersion = "1.18.5" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) From a0b88ce869d6be243c6b1900d69b9401f2d2c092 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 1 Aug 2022 10:13:30 -0700 Subject: [PATCH 137/715] eth/gasprice/feehistory: support finalized block (#25442) --- eth/gasprice/feehistory.go | 78 +++++++++++++++++++++------------ eth/gasprice/feehistory_test.go | 2 + eth/gasprice/gasprice_test.go | 21 +++++++++ 3 files changed, 74 insertions(+), 27 deletions(-) diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 4113089afb1e..91835c164106 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -137,44 +137,68 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { // also returned if requested and available. // Note: an error is only returned if retrieving the head header has failed. If there are no // retrievable blocks in the specified range then zero block count is returned with no error. -func (oracle *Oracle) resolveBlockRange(ctx context.Context, lastBlock rpc.BlockNumber, blocks int) (*types.Block, []*types.Receipt, uint64, int, error) { +func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNumber, blocks int) (*types.Block, []*types.Receipt, uint64, int, error) { var ( - headBlock rpc.BlockNumber + headBlock *types.Header pendingBlock *types.Block pendingReceipts types.Receipts + err error ) - // query either pending block or head header and set headBlock - if lastBlock == rpc.PendingBlockNumber { - if pendingBlock, pendingReceipts = oracle.backend.PendingBlockAndReceipts(); pendingBlock != nil { - lastBlock = rpc.BlockNumber(pendingBlock.NumberU64()) - headBlock = lastBlock - 1 - } else { - // pending block not supported by backend, process until latest block - lastBlock = rpc.LatestBlockNumber - blocks-- - if blocks == 0 { - return nil, nil, 0, 0, nil + + // Get the chain's current head. + if headBlock, err = oracle.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber); err != nil { + return nil, nil, 0, 0, err + } + head := rpc.BlockNumber(headBlock.Number.Uint64()) + + // Fail if request block is beyond the chain's current head. + if head < reqEnd { + return nil, nil, 0, 0, fmt.Errorf("%w: requested %d, head %d", errRequestBeyondHead, reqEnd, head) + } + + // Resolve block tag. + if reqEnd < 0 { + var ( + resolved *types.Header + err error + ) + switch reqEnd { + case rpc.PendingBlockNumber: + if pendingBlock, pendingReceipts = oracle.backend.PendingBlockAndReceipts(); pendingBlock != nil { + resolved = pendingBlock.Header() + } else { + // Pending block not supported by backend, process only until latest block. + resolved = headBlock + + // Update total blocks to return to account for this. + blocks-- } + case rpc.LatestBlockNumber: + // Retrieved above. + resolved = headBlock + case rpc.SafeBlockNumber: + resolved, err = oracle.backend.HeaderByNumber(ctx, rpc.SafeBlockNumber) + case rpc.FinalizedBlockNumber: + resolved, err = oracle.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber) + case rpc.EarliestBlockNumber: + resolved, err = oracle.backend.HeaderByNumber(ctx, rpc.EarliestBlockNumber) } - } - if pendingBlock == nil { - // if pending block is not fetched then we retrieve the head header to get the head block number - if latestHeader, err := oracle.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber); err == nil { - headBlock = rpc.BlockNumber(latestHeader.Number.Uint64()) - } else { + if resolved == nil || err != nil { return nil, nil, 0, 0, err } + // Absolute number resolved. + reqEnd = rpc.BlockNumber(resolved.Number.Uint64()) } - if lastBlock == rpc.LatestBlockNumber { - lastBlock = headBlock - } else if pendingBlock == nil && lastBlock > headBlock { - return nil, nil, 0, 0, fmt.Errorf("%w: requested %d, head %d", errRequestBeyondHead, lastBlock, headBlock) + + // If there are no blocks to return, short circuit. + if blocks == 0 { + return nil, nil, 0, 0, nil } - // ensure not trying to retrieve before genesis - if rpc.BlockNumber(blocks) > lastBlock+1 { - blocks = int(lastBlock + 1) + // Ensure not trying to retrieve before genesis. + if int(reqEnd+1) < blocks { + blocks = int(reqEnd + 1) } - return pendingBlock, pendingReceipts, uint64(lastBlock), blocks, nil + return pendingBlock, pendingReceipts, uint64(reqEnd), blocks, nil } // FeeHistory returns data relevant for fee estimation based on the specified range of blocks. diff --git a/eth/gasprice/feehistory_test.go b/eth/gasprice/feehistory_test.go index c259eb0acf76..deece7f46150 100644 --- a/eth/gasprice/feehistory_test.go +++ b/eth/gasprice/feehistory_test.go @@ -50,6 +50,8 @@ func TestFeeHistory(t *testing.T) { {false, 1000, 1000, 2, rpc.PendingBlockNumber, nil, 32, 1, nil}, {true, 1000, 1000, 2, rpc.PendingBlockNumber, nil, 32, 2, nil}, {true, 1000, 1000, 2, rpc.PendingBlockNumber, []float64{0, 10}, 32, 2, nil}, + {false, 1000, 1000, 2, rpc.FinalizedBlockNumber, []float64{0, 10}, 24, 2, nil}, + {false, 1000, 1000, 2, rpc.SafeBlockNumber, []float64{0, 10}, 24, 2, nil}, } for i, c := range cases { config := Config{ diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 95a908fc1e9c..3806e993c282 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -45,6 +45,15 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber if number > testHead { return nil, nil } + if number == rpc.EarliestBlockNumber { + number = 0 + } + if number == rpc.FinalizedBlockNumber { + return b.chain.CurrentFinalizedBlock().Header(), nil + } + if number == rpc.SafeBlockNumber { + return b.chain.CurrentSafeBlock().Header(), nil + } if number == rpc.LatestBlockNumber { number = testHead } @@ -62,6 +71,15 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) if number > testHead { return nil, nil } + if number == rpc.EarliestBlockNumber { + number = 0 + } + if number == rpc.FinalizedBlockNumber { + return b.chain.CurrentFinalizedBlock(), nil + } + if number == rpc.SafeBlockNumber { + return b.chain.CurrentSafeBlock(), nil + } if number == rpc.LatestBlockNumber { number = testHead } @@ -109,6 +127,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke config.LondonBlock = londonBlock config.ArrowGlacierBlock = londonBlock config.GrayGlacierBlock = londonBlock + config.TerminalTotalDifficulty = common.Big0 engine := ethash.NewFaker() db := rawdb.NewMemoryDatabase() genesis, err := gspec.Commit(db) @@ -150,6 +169,8 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke t.Fatalf("Failed to create local chain, %v", err) } chain.InsertChain(blocks) + chain.SetFinalized(chain.GetBlockByNumber(25)) + chain.SetSafe(chain.GetBlockByNumber(25)) return &testBackend{chain: chain, pending: pending} } From 6fdc619413980f90770f13339a5d79a4672779ae Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Tue, 2 Aug 2022 18:03:23 +0530 Subject: [PATCH 138/715] consensus/ethash: remove temp files created during DAG generation (#25381) This makes it remove not only the actual DAG file, but also the temporary file which the DAG data is written to while generating. --- consensus/ethash/ethash.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 0efb3590f089..dfe00d4b93c0 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -278,8 +278,11 @@ func (c *cache) generate(dir string, limit int, lock bool, test bool) { // Iterate over all previous instances and delete old ones for ep := int(c.epoch) - limit; ep >= 0; ep-- { seed := seedHash(uint64(ep)*epochLength + 1) - path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s", algorithmRevision, seed[:8], endian)) - os.Remove(path) + path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s*", algorithmRevision, seed[:8], endian)) + files, _ := filepath.Glob(path) // find also the temp files that are generated. + for _, file := range files { + os.Remove(file) + } } }) } From d804a59ee1a0152e98bb8dbd5cfea522409a2a5e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 2 Aug 2022 14:48:55 +0200 Subject: [PATCH 139/715] cmd/devp2p/internal/ethtest: update tests for eth/67 (#25306) --- cmd/devp2p/internal/ethtest/chain.go | 4 +- cmd/devp2p/internal/ethtest/chain_test.go | 41 +- cmd/devp2p/internal/ethtest/helpers.go | 322 ++++---------- cmd/devp2p/internal/ethtest/snapTypes.go | 24 +- cmd/devp2p/internal/ethtest/suite.go | 476 ++++++--------------- cmd/devp2p/internal/ethtest/suite_test.go | 2 +- cmd/devp2p/internal/ethtest/transaction.go | 50 +-- cmd/devp2p/internal/ethtest/types.go | 153 +++---- cmd/devp2p/rlpxcmd.go | 8 +- 9 files changed, 327 insertions(+), 753 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index 65ffc6f81d28..df724f470481 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -96,12 +96,12 @@ func (c *Chain) Head() *types.Block { return c.blocks[c.Len()-1] } -func (c *Chain) GetHeaders(req GetBlockHeaders) (BlockHeaders, error) { +func (c *Chain) GetHeaders(req *GetBlockHeaders) ([]*types.Header, error) { if req.Amount < 1 { return nil, fmt.Errorf("no block headers requested") } - headers := make(BlockHeaders, req.Amount) + headers := make([]*types.Header, req.Amount) var blockNumber uint64 // range over blocks to check if our chain has the requested header diff --git a/cmd/devp2p/internal/ethtest/chain_test.go b/cmd/devp2p/internal/ethtest/chain_test.go index 0f232b150611..67221923a684 100644 --- a/cmd/devp2p/internal/ethtest/chain_test.go +++ b/cmd/devp2p/internal/ethtest/chain_test.go @@ -21,6 +21,7 @@ import ( "strconv" "testing" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/p2p" "github.com/stretchr/testify/assert" @@ -140,18 +141,18 @@ func TestChain_GetHeaders(t *testing.T) { var tests = []struct { req GetBlockHeaders - expected BlockHeaders + expected []*types.Header }{ { req: GetBlockHeaders{ - Origin: eth.HashOrNumber{ - Number: uint64(2), + GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ + Origin: eth.HashOrNumber{Number: uint64(2)}, + Amount: uint64(5), + Skip: 1, + Reverse: false, }, - Amount: uint64(5), - Skip: 1, - Reverse: false, }, - expected: BlockHeaders{ + expected: []*types.Header{ chain.blocks[2].Header(), chain.blocks[4].Header(), chain.blocks[6].Header(), @@ -161,14 +162,14 @@ func TestChain_GetHeaders(t *testing.T) { }, { req: GetBlockHeaders{ - Origin: eth.HashOrNumber{ - Number: uint64(chain.Len() - 1), + GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ + Origin: eth.HashOrNumber{Number: uint64(chain.Len() - 1)}, + Amount: uint64(3), + Skip: 0, + Reverse: true, }, - Amount: uint64(3), - Skip: 0, - Reverse: true, }, - expected: BlockHeaders{ + expected: []*types.Header{ chain.blocks[chain.Len()-1].Header(), chain.blocks[chain.Len()-2].Header(), chain.blocks[chain.Len()-3].Header(), @@ -176,14 +177,14 @@ func TestChain_GetHeaders(t *testing.T) { }, { req: GetBlockHeaders{ - Origin: eth.HashOrNumber{ - Hash: chain.Head().Hash(), + GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ + Origin: eth.HashOrNumber{Hash: chain.Head().Hash()}, + Amount: uint64(1), + Skip: 0, + Reverse: false, }, - Amount: uint64(1), - Skip: 0, - Reverse: false, }, - expected: BlockHeaders{ + expected: []*types.Header{ chain.Head().Header(), }, }, @@ -191,7 +192,7 @@ func TestChain_GetHeaders(t *testing.T) { for i, tt := range tests { t.Run(strconv.Itoa(i), func(t *testing.T) { - headers, err := chain.GetHeaders(tt.req) + headers, err := chain.GetHeaders(&tt.req) if err != nil { t.Fatal(err) } diff --git a/cmd/devp2p/internal/ethtest/helpers.go b/cmd/devp2p/internal/ethtest/helpers.go index df754d6ce61d..eeeb4f93cabf 100644 --- a/cmd/devp2p/internal/ethtest/helpers.go +++ b/cmd/devp2p/internal/ethtest/helpers.go @@ -43,21 +43,6 @@ var ( timeout = 20 * time.Second ) -// Is_66 checks if the node supports the eth66 protocol version, -// and if not, exists the test suite -func (s *Suite) Is_66(t *utesting.T) { - conn, err := s.dial66() - if err != nil { - t.Fatalf("dial failed: %v", err) - } - if err := conn.handshake(); err != nil { - t.Fatalf("handshake failed: %v", err) - } - if conn.negotiatedProtoVersion < 66 { - t.Fail() - } -} - // dial attempts to dial the given node and perform a handshake, // returning the created Conn if successful. func (s *Suite) dial() (*Conn, error) { @@ -76,31 +61,16 @@ func (s *Suite) dial() (*Conn, error) { } // set default p2p capabilities conn.caps = []p2p.Cap{ - {Name: "eth", Version: 64}, - {Name: "eth", Version: 65}, + {Name: "eth", Version: 66}, + {Name: "eth", Version: 67}, } - conn.ourHighestProtoVersion = 65 + conn.ourHighestProtoVersion = 67 return &conn, nil } -// dial66 attempts to dial the given node and perform a handshake, -// returning the created Conn with additional eth66 capabilities if -// successful -func (s *Suite) dial66() (*Conn, error) { - conn, err := s.dial() - if err != nil { - return nil, fmt.Errorf("dial failed: %v", err) - } - conn.caps = append(conn.caps, p2p.Cap{Name: "eth", Version: 66}) - conn.ourHighestProtoVersion = 66 - return conn, nil -} - -// dial66 attempts to dial the given node and perform a handshake, -// returning the created Conn with additional snap/1 capabilities if -// successful. +// dialSnap creates a connection with snap/1 capability. func (s *Suite) dialSnap() (*Conn, error) { - conn, err := s.dial66() + conn, err := s.dial() if err != nil { return nil, fmt.Errorf("dial failed: %v", err) } @@ -235,117 +205,68 @@ loop: // createSendAndRecvConns creates two connections, one for sending messages to the // node, and one for receiving messages from the node. -func (s *Suite) createSendAndRecvConns(isEth66 bool) (*Conn, *Conn, error) { - var ( - sendConn *Conn - recvConn *Conn - err error - ) - if isEth66 { - sendConn, err = s.dial66() - if err != nil { - return nil, nil, fmt.Errorf("dial failed: %v", err) - } - recvConn, err = s.dial66() - if err != nil { - sendConn.Close() - return nil, nil, fmt.Errorf("dial failed: %v", err) - } - } else { - sendConn, err = s.dial() - if err != nil { - return nil, nil, fmt.Errorf("dial failed: %v", err) - } - recvConn, err = s.dial() - if err != nil { - sendConn.Close() - return nil, nil, fmt.Errorf("dial failed: %v", err) - } +func (s *Suite) createSendAndRecvConns() (*Conn, *Conn, error) { + sendConn, err := s.dial() + if err != nil { + return nil, nil, fmt.Errorf("dial failed: %v", err) } - return sendConn, recvConn, nil -} - -func (c *Conn) readAndServe(chain *Chain, timeout time.Duration) Message { - if c.negotiatedProtoVersion == 66 { - _, msg := c.readAndServe66(chain, timeout) - return msg + recvConn, err := s.dial() + if err != nil { + sendConn.Close() + return nil, nil, fmt.Errorf("dial failed: %v", err) } - return c.readAndServe65(chain, timeout) + return sendConn, recvConn, nil } // readAndServe serves GetBlockHeaders requests while waiting // on another message from the node. -func (c *Conn) readAndServe65(chain *Chain, timeout time.Duration) Message { - start := time.Now() - for time.Since(start) < timeout { - c.SetReadDeadline(time.Now().Add(5 * time.Second)) - switch msg := c.Read().(type) { - case *Ping: - c.Write(&Pong{}) - case *GetBlockHeaders: - req := *msg - headers, err := chain.GetHeaders(req) - if err != nil { - return errorf("could not get headers for inbound header request: %v", err) - } - if err := c.Write(headers); err != nil { - return errorf("could not write to connection: %v", err) - } - default: - return msg - } - } - return errorf("no message received within %v", timeout) -} - -// readAndServe66 serves eth66 GetBlockHeaders requests while waiting -// on another message from the node. -func (c *Conn) readAndServe66(chain *Chain, timeout time.Duration) (uint64, Message) { +func (c *Conn) readAndServe(chain *Chain, timeout time.Duration) Message { start := time.Now() for time.Since(start) < timeout { c.SetReadDeadline(time.Now().Add(10 * time.Second)) - reqID, msg := c.Read66() - + msg := c.Read() switch msg := msg.(type) { case *Ping: c.Write(&Pong{}) - case GetBlockHeaders: + case *GetBlockHeaders: headers, err := chain.GetHeaders(msg) if err != nil { - return 0, errorf("could not get headers for inbound header request: %v", err) + return errorf("could not get headers for inbound header request: %v", err) } - resp := ð.BlockHeadersPacket66{ - RequestId: reqID, + resp := &BlockHeaders{ + RequestId: msg.ReqID(), BlockHeadersPacket: eth.BlockHeadersPacket(headers), } - if err := c.Write66(resp, BlockHeaders{}.Code()); err != nil { - return 0, errorf("could not write to connection: %v", err) + if err := c.Write(resp); err != nil { + return errorf("could not write to connection: %v", err) } default: - return reqID, msg + return msg } } - return 0, errorf("no message received within %v", timeout) + return errorf("no message received within %v", timeout) } // headersRequest executes the given `GetBlockHeaders` request. -func (c *Conn) headersRequest(request *GetBlockHeaders, chain *Chain, isEth66 bool, reqID uint64) (BlockHeaders, error) { +func (c *Conn) headersRequest(request *GetBlockHeaders, chain *Chain, reqID uint64) ([]*types.Header, error) { defer c.SetReadDeadline(time.Time{}) c.SetReadDeadline(time.Now().Add(20 * time.Second)) - // if on eth66 connection, perform eth66 GetBlockHeaders request - if isEth66 { - return getBlockHeaders66(chain, c, request, reqID) - } + + // write request + request.RequestId = reqID if err := c.Write(request); err != nil { - return nil, err + return nil, fmt.Errorf("could not write to connection: %v", err) } - switch msg := c.readAndServe(chain, timeout).(type) { - case *BlockHeaders: - return *msg, nil - default: - return nil, fmt.Errorf("invalid message: %s", pretty.Sdump(msg)) + + // wait for response + msg := c.waitForResponse(chain, timeout, request.RequestId) + resp, ok := msg.(*BlockHeaders) + if !ok { + return nil, fmt.Errorf("unexpected message received: %s", pretty.Sdump(msg)) } + headers := []*types.Header(resp.BlockHeadersPacket) + return headers, nil } func (c *Conn) snapRequest(msg Message, id uint64, chain *Chain) (Message, error) { @@ -357,28 +278,8 @@ func (c *Conn) snapRequest(msg Message, id uint64, chain *Chain) (Message, error return c.ReadSnap(id) } -// getBlockHeaders66 executes the given `GetBlockHeaders` request over the eth66 protocol. -func getBlockHeaders66(chain *Chain, conn *Conn, request *GetBlockHeaders, id uint64) (BlockHeaders, error) { - // write request - packet := eth.GetBlockHeadersPacket(*request) - req := ð.GetBlockHeadersPacket66{ - RequestId: id, - GetBlockHeadersPacket: &packet, - } - if err := conn.Write66(req, GetBlockHeaders{}.Code()); err != nil { - return nil, fmt.Errorf("could not write to connection: %v", err) - } - // wait for response - msg := conn.waitForResponse(chain, timeout, req.RequestId) - headers, ok := msg.(BlockHeaders) - if !ok { - return nil, fmt.Errorf("unexpected message received: %s", pretty.Sdump(msg)) - } - return headers, nil -} - // headersMatch returns whether the received headers match the given request -func headersMatch(expected BlockHeaders, headers BlockHeaders) bool { +func headersMatch(expected []*types.Header, headers []*types.Header) bool { return reflect.DeepEqual(expected, headers) } @@ -386,8 +287,8 @@ func headersMatch(expected BlockHeaders, headers BlockHeaders) bool { // request ID is received. func (c *Conn) waitForResponse(chain *Chain, timeout time.Duration, requestID uint64) Message { for { - id, msg := c.readAndServe66(chain, timeout) - if id == requestID { + msg := c.readAndServe(chain, timeout) + if msg.ReqID() == requestID { return msg } } @@ -395,9 +296,9 @@ func (c *Conn) waitForResponse(chain *Chain, timeout time.Duration, requestID ui // sendNextBlock broadcasts the next block in the chain and waits // for the node to propagate the block and import it into its chain. -func (s *Suite) sendNextBlock(isEth66 bool) error { +func (s *Suite) sendNextBlock() error { // set up sending and receiving connections - sendConn, recvConn, err := s.createSendAndRecvConns(isEth66) + sendConn, recvConn, err := s.createSendAndRecvConns() if err != nil { return err } @@ -420,7 +321,7 @@ func (s *Suite) sendNextBlock(isEth66 bool) error { return fmt.Errorf("failed to announce block: %v", err) } // wait for client to update its chain - if err = s.waitForBlockImport(recvConn, nextBlock, isEth66); err != nil { + if err = s.waitForBlockImport(recvConn, nextBlock); err != nil { return fmt.Errorf("failed to receive confirmation of block import: %v", err) } // update test suite chain @@ -465,29 +366,22 @@ func (s *Suite) waitAnnounce(conn *Conn, blockAnnouncement *NewBlock) error { } } -func (s *Suite) waitForBlockImport(conn *Conn, block *types.Block, isEth66 bool) error { +func (s *Suite) waitForBlockImport(conn *Conn, block *types.Block) error { defer conn.SetReadDeadline(time.Time{}) conn.SetReadDeadline(time.Now().Add(20 * time.Second)) // create request req := &GetBlockHeaders{ - Origin: eth.HashOrNumber{ - Hash: block.Hash(), + GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ + Origin: eth.HashOrNumber{Hash: block.Hash()}, + Amount: 1, }, - Amount: 1, } + // loop until BlockHeaders response contains desired block, confirming the // node imported the block for { - var ( - headers BlockHeaders - err error - ) - if isEth66 { - requestID := uint64(54) - headers, err = conn.headersRequest(req, s.chain, eth66, requestID) - } else { - headers, err = conn.headersRequest(req, s.chain, eth65, 0) - } + requestID := uint64(54) + headers, err := conn.headersRequest(req, s.chain, requestID) if err != nil { return fmt.Errorf("GetBlockHeader request failed: %v", err) } @@ -503,8 +397,8 @@ func (s *Suite) waitForBlockImport(conn *Conn, block *types.Block, isEth66 bool) } } -func (s *Suite) oldAnnounce(isEth66 bool) error { - sendConn, receiveConn, err := s.createSendAndRecvConns(isEth66) +func (s *Suite) oldAnnounce() error { + sendConn, receiveConn, err := s.createSendAndRecvConns() if err != nil { return err } @@ -550,23 +444,13 @@ func (s *Suite) oldAnnounce(isEth66 bool) error { return nil } -func (s *Suite) maliciousHandshakes(t *utesting.T, isEth66 bool) error { - var ( - conn *Conn - err error - ) - if isEth66 { - conn, err = s.dial66() - if err != nil { - return fmt.Errorf("dial failed: %v", err) - } - } else { - conn, err = s.dial() - if err != nil { - return fmt.Errorf("dial failed: %v", err) - } +func (s *Suite) maliciousHandshakes(t *utesting.T) error { + conn, err := s.dial() + if err != nil { + return fmt.Errorf("dial failed: %v", err) } defer conn.Close() + // write hello to client pub0 := crypto.FromECDSAPub(&conn.ourKey.PublicKey)[1:] handshakes := []*Hello{ @@ -627,16 +511,9 @@ func (s *Suite) maliciousHandshakes(t *utesting.T, isEth66 bool) error { } } // dial for the next round - if isEth66 { - conn, err = s.dial66() - if err != nil { - return fmt.Errorf("dial failed: %v", err) - } - } else { - conn, err = s.dial() - if err != nil { - return fmt.Errorf("dial failed: %v", err) - } + conn, err = s.dial() + if err != nil { + return fmt.Errorf("dial failed: %v", err) } } return nil @@ -654,6 +531,7 @@ func (s *Suite) maliciousStatus(conn *Conn) error { Genesis: s.chain.blocks[0].Hash(), ForkID: s.chain.ForkID(), } + // get status msg, err := conn.statusExchange(s.chain, status) if err != nil { @@ -664,6 +542,7 @@ func (s *Suite) maliciousStatus(conn *Conn) error { default: return fmt.Errorf("expected status, got: %#v ", msg) } + // wait for disconnect switch msg := conn.readAndServe(s.chain, timeout).(type) { case *Disconnect: @@ -675,9 +554,9 @@ func (s *Suite) maliciousStatus(conn *Conn) error { } } -func (s *Suite) hashAnnounce(isEth66 bool) error { +func (s *Suite) hashAnnounce() error { // create connections - sendConn, recvConn, err := s.createSendAndRecvConns(isEth66) + sendConn, recvConn, err := s.createSendAndRecvConns() if err != nil { return fmt.Errorf("failed to create connections: %v", err) } @@ -689,6 +568,7 @@ func (s *Suite) hashAnnounce(isEth66 bool) error { if err := recvConn.peer(s.chain, nil); err != nil { return fmt.Errorf("peering failed: %v", err) } + // create NewBlockHashes announcement type anno struct { Hash common.Hash // Hash of one particular block being announced @@ -700,56 +580,29 @@ func (s *Suite) hashAnnounce(isEth66 bool) error { if err := sendConn.Write(newBlockHash); err != nil { return fmt.Errorf("failed to write to connection: %v", err) } + // Announcement sent, now wait for a header request - var ( - id uint64 - msg Message - blockHeaderReq GetBlockHeaders - ) - if isEth66 { - id, msg = sendConn.Read66() - switch msg := msg.(type) { - case GetBlockHeaders: - blockHeaderReq = msg - default: - return fmt.Errorf("unexpected %s", pretty.Sdump(msg)) - } - if blockHeaderReq.Amount != 1 { - return fmt.Errorf("unexpected number of block headers requested: %v", blockHeaderReq.Amount) - } - if blockHeaderReq.Origin.Hash != announcement.Hash { - return fmt.Errorf("unexpected block header requested. Announced:\n %v\n Remote request:\n%v", - pretty.Sdump(announcement), - pretty.Sdump(blockHeaderReq)) - } - if err := sendConn.Write66(ð.BlockHeadersPacket66{ - RequestId: id, - BlockHeadersPacket: eth.BlockHeadersPacket{ - nextBlock.Header(), - }, - }, BlockHeaders{}.Code()); err != nil { - return fmt.Errorf("failed to write to connection: %v", err) - } - } else { - msg = sendConn.Read() - switch msg := msg.(type) { - case *GetBlockHeaders: - blockHeaderReq = *msg - default: - return fmt.Errorf("unexpected %s", pretty.Sdump(msg)) - } - if blockHeaderReq.Amount != 1 { - return fmt.Errorf("unexpected number of block headers requested: %v", blockHeaderReq.Amount) - } - if blockHeaderReq.Origin.Hash != announcement.Hash { - return fmt.Errorf("unexpected block header requested. Announced:\n %v\n Remote request:\n%v", - pretty.Sdump(announcement), - pretty.Sdump(blockHeaderReq)) - } - if err := sendConn.Write(&BlockHeaders{nextBlock.Header()}); err != nil { - return fmt.Errorf("failed to write to connection: %v", err) - } + msg := sendConn.Read() + blockHeaderReq, ok := msg.(*GetBlockHeaders) + if !ok { + return fmt.Errorf("unexpected %s", pretty.Sdump(msg)) } + if blockHeaderReq.Amount != 1 { + return fmt.Errorf("unexpected number of block headers requested: %v", blockHeaderReq.Amount) + } + if blockHeaderReq.Origin.Hash != announcement.Hash { + return fmt.Errorf("unexpected block header requested. Announced:\n %v\n Remote request:\n%v", + pretty.Sdump(announcement), + pretty.Sdump(blockHeaderReq)) + } + err = sendConn.Write(&BlockHeaders{ + RequestId: blockHeaderReq.ReqID(), + BlockHeadersPacket: eth.BlockHeadersPacket{nextBlock.Header()}, + }) + if err != nil { + return fmt.Errorf("failed to write to connection: %v", err) + } + // wait for block announcement msg = recvConn.readAndServe(s.chain, timeout) switch msg := msg.(type) { @@ -762,6 +615,7 @@ func (s *Suite) hashAnnounce(isEth66 bool) error { return fmt.Errorf("unexpected block hash announcement, wanted %v, got %v", nextBlock.Hash(), hashes[0].Hash) } + case *NewBlock: // node should only propagate NewBlock without having requested the body if the body is empty nextBlockBody := nextBlock.Body() @@ -780,7 +634,7 @@ func (s *Suite) hashAnnounce(isEth66 bool) error { return fmt.Errorf("unexpected: %s", pretty.Sdump(msg)) } // confirm node imported block - if err := s.waitForBlockImport(recvConn, nextBlock, isEth66); err != nil { + if err := s.waitForBlockImport(recvConn, nextBlock); err != nil { return fmt.Errorf("error waiting for node to import new block: %v", err) } // update the chain diff --git a/cmd/devp2p/internal/ethtest/snapTypes.go b/cmd/devp2p/internal/ethtest/snapTypes.go index e18cd5925cbb..6bcaa9291ab2 100644 --- a/cmd/devp2p/internal/ethtest/snapTypes.go +++ b/cmd/devp2p/internal/ethtest/snapTypes.go @@ -21,32 +21,40 @@ import "github.com/ethereum/go-ethereum/eth/protocols/snap" // GetAccountRange represents an account range query. type GetAccountRange snap.GetAccountRangePacket -func (g GetAccountRange) Code() int { return 33 } +func (msg GetAccountRange) Code() int { return 33 } +func (msg GetAccountRange) ReqID() uint64 { return msg.ID } type AccountRange snap.AccountRangePacket -func (g AccountRange) Code() int { return 34 } +func (msg AccountRange) Code() int { return 34 } +func (msg AccountRange) ReqID() uint64 { return msg.ID } type GetStorageRanges snap.GetStorageRangesPacket -func (g GetStorageRanges) Code() int { return 35 } +func (msg GetStorageRanges) Code() int { return 35 } +func (msg GetStorageRanges) ReqID() uint64 { return msg.ID } type StorageRanges snap.StorageRangesPacket -func (g StorageRanges) Code() int { return 36 } +func (msg StorageRanges) Code() int { return 36 } +func (msg StorageRanges) ReqID() uint64 { return msg.ID } type GetByteCodes snap.GetByteCodesPacket -func (g GetByteCodes) Code() int { return 37 } +func (msg GetByteCodes) Code() int { return 37 } +func (msg GetByteCodes) ReqID() uint64 { return msg.ID } type ByteCodes snap.ByteCodesPacket -func (g ByteCodes) Code() int { return 38 } +func (msg ByteCodes) Code() int { return 38 } +func (msg ByteCodes) ReqID() uint64 { return msg.ID } type GetTrieNodes snap.GetTrieNodesPacket -func (g GetTrieNodes) Code() int { return 39 } +func (msg GetTrieNodes) Code() int { return 39 } +func (msg GetTrieNodes) ReqID() uint64 { return msg.ID } type TrieNodes snap.TrieNodesPacket -func (g TrieNodes) Code() int { return 40 } +func (msg TrieNodes) Code() int { return 40 } +func (msg TrieNodes) ReqID() uint64 { return msg.ID } diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index 4ddd65b95865..7059b4ba738c 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -49,79 +49,30 @@ func NewSuite(dest *enode.Node, chainfile string, genesisfile string) (*Suite, e }, nil } -func (s *Suite) AllEthTests() []utesting.Test { +func (s *Suite) EthTests() []utesting.Test { return []utesting.Test{ // status - {Name: "TestStatus65", Fn: s.TestStatus65}, - {Name: "TestStatus66", Fn: s.TestStatus66}, + {Name: "TestStatus", Fn: s.TestStatus}, // get block headers - {Name: "TestGetBlockHeaders65", Fn: s.TestGetBlockHeaders65}, - {Name: "TestGetBlockHeaders66", Fn: s.TestGetBlockHeaders66}, - {Name: "TestSimultaneousRequests66", Fn: s.TestSimultaneousRequests66}, - {Name: "TestSameRequestID66", Fn: s.TestSameRequestID66}, - {Name: "TestZeroRequestID66", Fn: s.TestZeroRequestID66}, + {Name: "TestGetBlockHeaders", Fn: s.TestGetBlockHeaders}, + {Name: "TestSimultaneousRequests", Fn: s.TestSimultaneousRequests}, + {Name: "TestSameRequestID", Fn: s.TestSameRequestID}, + {Name: "TestZeroRequestID", Fn: s.TestZeroRequestID}, // get block bodies - {Name: "TestGetBlockBodies65", Fn: s.TestGetBlockBodies65}, - {Name: "TestGetBlockBodies66", Fn: s.TestGetBlockBodies66}, + {Name: "TestGetBlockBodies", Fn: s.TestGetBlockBodies}, // broadcast - {Name: "TestBroadcast65", Fn: s.TestBroadcast65}, - {Name: "TestBroadcast66", Fn: s.TestBroadcast66}, - {Name: "TestLargeAnnounce65", Fn: s.TestLargeAnnounce65}, - {Name: "TestLargeAnnounce66", Fn: s.TestLargeAnnounce66}, - {Name: "TestOldAnnounce65", Fn: s.TestOldAnnounce65}, - {Name: "TestOldAnnounce66", Fn: s.TestOldAnnounce66}, - {Name: "TestBlockHashAnnounce65", Fn: s.TestBlockHashAnnounce65}, - {Name: "TestBlockHashAnnounce66", Fn: s.TestBlockHashAnnounce66}, + {Name: "TestBroadcast", Fn: s.TestBroadcast}, + {Name: "TestLargeAnnounce", Fn: s.TestLargeAnnounce}, + {Name: "TestOldAnnounce", Fn: s.TestOldAnnounce}, + {Name: "TestBlockHashAnnounce", Fn: s.TestBlockHashAnnounce}, // malicious handshakes + status - {Name: "TestMaliciousHandshake65", Fn: s.TestMaliciousHandshake65}, - {Name: "TestMaliciousStatus65", Fn: s.TestMaliciousStatus65}, - {Name: "TestMaliciousHandshake66", Fn: s.TestMaliciousHandshake66}, - {Name: "TestMaliciousStatus66", Fn: s.TestMaliciousStatus66}, + {Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake}, + {Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus}, // test transactions - {Name: "TestTransaction65", Fn: s.TestTransaction65}, - {Name: "TestTransaction66", Fn: s.TestTransaction66}, - {Name: "TestMaliciousTx65", Fn: s.TestMaliciousTx65}, - {Name: "TestMaliciousTx66", Fn: s.TestMaliciousTx66}, - {Name: "TestLargeTxRequest66", Fn: s.TestLargeTxRequest66}, - {Name: "TestNewPooledTxs66", Fn: s.TestNewPooledTxs66}, - } -} - -func (s *Suite) EthTests() []utesting.Test { - return []utesting.Test{ - {Name: "TestStatus65", Fn: s.TestStatus65}, - {Name: "TestGetBlockHeaders65", Fn: s.TestGetBlockHeaders65}, - {Name: "TestGetBlockBodies65", Fn: s.TestGetBlockBodies65}, - {Name: "TestBroadcast65", Fn: s.TestBroadcast65}, - {Name: "TestLargeAnnounce65", Fn: s.TestLargeAnnounce65}, - {Name: "TestOldAnnounce65", Fn: s.TestOldAnnounce65}, - {Name: "TestBlockHashAnnounce65", Fn: s.TestBlockHashAnnounce65}, - {Name: "TestMaliciousHandshake65", Fn: s.TestMaliciousHandshake65}, - {Name: "TestMaliciousStatus65", Fn: s.TestMaliciousStatus65}, - {Name: "TestTransaction65", Fn: s.TestTransaction65}, - {Name: "TestMaliciousTx65", Fn: s.TestMaliciousTx65}, - } -} - -func (s *Suite) Eth66Tests() []utesting.Test { - return []utesting.Test{ - // only proceed with eth66 test suite if node supports eth 66 protocol - {Name: "TestStatus66", Fn: s.TestStatus66}, - {Name: "TestGetBlockHeaders66", Fn: s.TestGetBlockHeaders66}, - {Name: "TestSimultaneousRequests66", Fn: s.TestSimultaneousRequests66}, - {Name: "TestSameRequestID66", Fn: s.TestSameRequestID66}, - {Name: "TestZeroRequestID66", Fn: s.TestZeroRequestID66}, - {Name: "TestGetBlockBodies66", Fn: s.TestGetBlockBodies66}, - {Name: "TestBroadcast66", Fn: s.TestBroadcast66}, - {Name: "TestLargeAnnounce66", Fn: s.TestLargeAnnounce66}, - {Name: "TestOldAnnounce66", Fn: s.TestOldAnnounce66}, - {Name: "TestBlockHashAnnounce66", Fn: s.TestBlockHashAnnounce66}, - {Name: "TestMaliciousHandshake66", Fn: s.TestMaliciousHandshake66}, - {Name: "TestMaliciousStatus66", Fn: s.TestMaliciousStatus66}, - {Name: "TestTransaction66", Fn: s.TestTransaction66}, - {Name: "TestMaliciousTx66", Fn: s.TestMaliciousTx66}, - {Name: "TestLargeTxRequest66", Fn: s.TestLargeTxRequest66}, - {Name: "TestNewPooledTxs66", Fn: s.TestNewPooledTxs66}, + {Name: "TestTransaction", Fn: s.TestTransaction}, + {Name: "TestMaliciousTx", Fn: s.TestMaliciousTx}, + {Name: "TestLargeTxRequest", Fn: s.TestLargeTxRequest}, + {Name: "TestNewPooledTxs", Fn: s.TestNewPooledTxs}, } } @@ -135,14 +86,9 @@ func (s *Suite) SnapTests() []utesting.Test { } } -var ( - eth66 = true // indicates whether suite should negotiate eth66 connection - eth65 = false // indicates whether suite should negotiate eth65 connection or below. -) - -// TestStatus65 attempts to connect to the given node and exchange -// a status message with it. -func (s *Suite) TestStatus65(t *utesting.T) { +// TestStatus attempts to connect to the given node and exchange +// a status message with it on the eth protocol. +func (s *Suite) TestStatus(t *utesting.T) { conn, err := s.dial() if err != nil { t.Fatalf("dial failed: %v", err) @@ -153,79 +99,32 @@ func (s *Suite) TestStatus65(t *utesting.T) { } } -// TestStatus66 attempts to connect to the given node and exchange -// a status message with it on the eth66 protocol. -func (s *Suite) TestStatus66(t *utesting.T) { - conn, err := s.dial66() - if err != nil { - t.Fatalf("dial failed: %v", err) - } - defer conn.Close() - if err := conn.peer(s.chain, nil); err != nil { - t.Fatalf("peering failed: %v", err) - } -} - -// TestGetBlockHeaders65 tests whether the given node can respond to -// a `GetBlockHeaders` request accurately. -func (s *Suite) TestGetBlockHeaders65(t *utesting.T) { +// TestGetBlockHeaders tests whether the given node can respond to +// an eth `GetBlockHeaders` request and that the response is accurate. +func (s *Suite) TestGetBlockHeaders(t *utesting.T) { conn, err := s.dial() if err != nil { t.Fatalf("dial failed: %v", err) } defer conn.Close() - if err := conn.peer(s.chain, nil); err != nil { - t.Fatalf("handshake(s) failed: %v", err) - } - // write request - req := &GetBlockHeaders{ - Origin: eth.HashOrNumber{ - Hash: s.chain.blocks[1].Hash(), - }, - Amount: 2, - Skip: 1, - Reverse: false, - } - headers, err := conn.headersRequest(req, s.chain, eth65, 0) - if err != nil { - t.Fatalf("GetBlockHeaders request failed: %v", err) - } - // check for correct headers - expected, err := s.chain.GetHeaders(*req) - if err != nil { - t.Fatalf("failed to get headers for given request: %v", err) - } - if !headersMatch(expected, headers) { - t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers) - } -} - -// TestGetBlockHeaders66 tests whether the given node can respond to -// an eth66 `GetBlockHeaders` request and that the response is accurate. -func (s *Suite) TestGetBlockHeaders66(t *utesting.T) { - conn, err := s.dial66() - if err != nil { - t.Fatalf("dial failed: %v", err) - } - defer conn.Close() if err = conn.peer(s.chain, nil); err != nil { t.Fatalf("peering failed: %v", err) } // write request req := &GetBlockHeaders{ - Origin: eth.HashOrNumber{ - Hash: s.chain.blocks[1].Hash(), + GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ + Origin: eth.HashOrNumber{Hash: s.chain.blocks[1].Hash()}, + Amount: 2, + Skip: 1, + Reverse: false, }, - Amount: 2, - Skip: 1, - Reverse: false, } - headers, err := conn.headersRequest(req, s.chain, eth66, 33) + headers, err := conn.headersRequest(req, s.chain, 33) if err != nil { t.Fatalf("could not get block headers: %v", err) } // check for correct headers - expected, err := s.chain.GetHeaders(*req) + expected, err := s.chain.GetHeaders(req) if err != nil { t.Fatalf("failed to get headers for given request: %v", err) } @@ -234,12 +133,12 @@ func (s *Suite) TestGetBlockHeaders66(t *utesting.T) { } } -// TestSimultaneousRequests66 sends two simultaneous `GetBlockHeader` requests from +// TestSimultaneousRequests sends two simultaneous `GetBlockHeader` requests from // the same connection with different request IDs and checks to make sure the node // responds with the correct headers per request. -func (s *Suite) TestSimultaneousRequests66(t *utesting.T) { +func (s *Suite) TestSimultaneousRequests(t *utesting.T) { // create a connection - conn, err := s.dial66() + conn, err := s.dial() if err != nil { t.Fatalf("dial failed: %v", err) } @@ -247,8 +146,9 @@ func (s *Suite) TestSimultaneousRequests66(t *utesting.T) { if err := conn.peer(s.chain, nil); err != nil { t.Fatalf("peering failed: %v", err) } + // create two requests - req1 := ð.GetBlockHeadersPacket66{ + req1 := &GetBlockHeaders{ RequestId: uint64(111), GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ Origin: eth.HashOrNumber{ @@ -259,7 +159,7 @@ func (s *Suite) TestSimultaneousRequests66(t *utesting.T) { Reverse: false, }, } - req2 := ð.GetBlockHeadersPacket66{ + req2 := &GetBlockHeaders{ RequestId: uint64(222), GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ Origin: eth.HashOrNumber{ @@ -270,46 +170,49 @@ func (s *Suite) TestSimultaneousRequests66(t *utesting.T) { Reverse: false, }, } + // write the first request - if err := conn.Write66(req1, GetBlockHeaders{}.Code()); err != nil { + if err := conn.Write(req1); err != nil { t.Fatalf("failed to write to connection: %v", err) } // write the second request - if err := conn.Write66(req2, GetBlockHeaders{}.Code()); err != nil { + if err := conn.Write(req2); err != nil { t.Fatalf("failed to write to connection: %v", err) } + // wait for responses msg := conn.waitForResponse(s.chain, timeout, req1.RequestId) - headers1, ok := msg.(BlockHeaders) + headers1, ok := msg.(*BlockHeaders) if !ok { t.Fatalf("unexpected %s", pretty.Sdump(msg)) } msg = conn.waitForResponse(s.chain, timeout, req2.RequestId) - headers2, ok := msg.(BlockHeaders) + headers2, ok := msg.(*BlockHeaders) if !ok { t.Fatalf("unexpected %s", pretty.Sdump(msg)) } + // check received headers for accuracy - expected1, err := s.chain.GetHeaders(GetBlockHeaders(*req1.GetBlockHeadersPacket)) + expected1, err := s.chain.GetHeaders(req1) if err != nil { t.Fatalf("failed to get expected headers for request 1: %v", err) } - expected2, err := s.chain.GetHeaders(GetBlockHeaders(*req2.GetBlockHeadersPacket)) + expected2, err := s.chain.GetHeaders(req2) if err != nil { t.Fatalf("failed to get expected headers for request 2: %v", err) } - if !headersMatch(expected1, headers1) { + if !headersMatch(expected1, headers1.BlockHeadersPacket) { t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected1, headers1) } - if !headersMatch(expected2, headers2) { + if !headersMatch(expected2, headers2.BlockHeadersPacket) { t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected2, headers2) } } -// TestSameRequestID66 sends two requests with the same request ID to a +// TestSameRequestID sends two requests with the same request ID to a // single node. -func (s *Suite) TestSameRequestID66(t *utesting.T) { - conn, err := s.dial66() +func (s *Suite) TestSameRequestID(t *utesting.T) { + conn, err := s.dial() if err != nil { t.Fatalf("dial failed: %v", err) } @@ -319,7 +222,7 @@ func (s *Suite) TestSameRequestID66(t *utesting.T) { } // create requests reqID := uint64(1234) - request1 := ð.GetBlockHeadersPacket66{ + request1 := &GetBlockHeaders{ RequestId: reqID, GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ Origin: eth.HashOrNumber{ @@ -328,7 +231,7 @@ func (s *Suite) TestSameRequestID66(t *utesting.T) { Amount: 2, }, } - request2 := ð.GetBlockHeadersPacket66{ + request2 := &GetBlockHeaders{ RequestId: reqID, GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ Origin: eth.HashOrNumber{ @@ -337,45 +240,48 @@ func (s *Suite) TestSameRequestID66(t *utesting.T) { Amount: 2, }, } + // write the requests - if err = conn.Write66(request1, GetBlockHeaders{}.Code()); err != nil { + if err = conn.Write(request1); err != nil { t.Fatalf("failed to write to connection: %v", err) } - if err = conn.Write66(request2, GetBlockHeaders{}.Code()); err != nil { + if err = conn.Write(request2); err != nil { t.Fatalf("failed to write to connection: %v", err) } + // wait for responses msg := conn.waitForResponse(s.chain, timeout, reqID) - headers1, ok := msg.(BlockHeaders) + headers1, ok := msg.(*BlockHeaders) if !ok { t.Fatalf("unexpected %s", pretty.Sdump(msg)) } msg = conn.waitForResponse(s.chain, timeout, reqID) - headers2, ok := msg.(BlockHeaders) + headers2, ok := msg.(*BlockHeaders) if !ok { t.Fatalf("unexpected %s", pretty.Sdump(msg)) } + // check if headers match - expected1, err := s.chain.GetHeaders(GetBlockHeaders(*request1.GetBlockHeadersPacket)) + expected1, err := s.chain.GetHeaders(request1) if err != nil { t.Fatalf("failed to get expected block headers: %v", err) } - expected2, err := s.chain.GetHeaders(GetBlockHeaders(*request2.GetBlockHeadersPacket)) + expected2, err := s.chain.GetHeaders(request2) if err != nil { t.Fatalf("failed to get expected block headers: %v", err) } - if !headersMatch(expected1, headers1) { + if !headersMatch(expected1, headers1.BlockHeadersPacket) { t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected1, headers1) } - if !headersMatch(expected2, headers2) { + if !headersMatch(expected2, headers2.BlockHeadersPacket) { t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected2, headers2) } } -// TestZeroRequestID_66 checks that a message with a request ID of zero is still handled +// TestZeroRequestID checks that a message with a request ID of zero is still handled // by the node. -func (s *Suite) TestZeroRequestID66(t *utesting.T) { - conn, err := s.dial66() +func (s *Suite) TestZeroRequestID(t *utesting.T) { + conn, err := s.dial() if err != nil { t.Fatalf("dial failed: %v", err) } @@ -384,16 +290,16 @@ func (s *Suite) TestZeroRequestID66(t *utesting.T) { t.Fatalf("peering failed: %v", err) } req := &GetBlockHeaders{ - Origin: eth.HashOrNumber{ - Number: 0, + GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ + Origin: eth.HashOrNumber{Number: 0}, + Amount: 2, }, - Amount: 2, } - headers, err := conn.headersRequest(req, s.chain, eth66, 0) + headers, err := conn.headersRequest(req, s.chain, 0) if err != nil { t.Fatalf("failed to get block headers: %v", err) } - expected, err := s.chain.GetHeaders(*req) + expected, err := s.chain.GetHeaders(req) if err != nil { t.Fatalf("failed to get expected block headers: %v", err) } @@ -402,9 +308,9 @@ func (s *Suite) TestZeroRequestID66(t *utesting.T) { } } -// TestGetBlockBodies65 tests whether the given node can respond to +// TestGetBlockBodies tests whether the given node can respond to // a `GetBlockBodies` request and that the response is accurate. -func (s *Suite) TestGetBlockBodies65(t *utesting.T) { +func (s *Suite) TestGetBlockBodies(t *utesting.T) { conn, err := s.dial() if err != nil { t.Fatalf("dial failed: %v", err) @@ -415,126 +321,39 @@ func (s *Suite) TestGetBlockBodies65(t *utesting.T) { } // create block bodies request req := &GetBlockBodies{ - s.chain.blocks[54].Hash(), - s.chain.blocks[75].Hash(), - } - if err := conn.Write(req); err != nil { - t.Fatalf("could not write to connection: %v", err) - } - // wait for response - switch msg := conn.readAndServe(s.chain, timeout).(type) { - case *BlockBodies: - t.Logf("received %d block bodies", len(*msg)) - if len(*msg) != len(*req) { - t.Fatalf("wrong bodies in response: expected %d bodies, "+ - "got %d", len(*req), len(*msg)) - } - default: - t.Fatalf("unexpected: %s", pretty.Sdump(msg)) - } -} - -// TestGetBlockBodies66 tests whether the given node can respond to -// a `GetBlockBodies` request and that the response is accurate over -// the eth66 protocol. -func (s *Suite) TestGetBlockBodies66(t *utesting.T) { - conn, err := s.dial66() - if err != nil { - t.Fatalf("dial failed: %v", err) - } - defer conn.Close() - if err := conn.peer(s.chain, nil); err != nil { - t.Fatalf("peering failed: %v", err) - } - // create block bodies request - req := ð.GetBlockBodiesPacket66{ RequestId: uint64(55), GetBlockBodiesPacket: eth.GetBlockBodiesPacket{ s.chain.blocks[54].Hash(), s.chain.blocks[75].Hash(), }, } - if err := conn.Write66(req, GetBlockBodies{}.Code()); err != nil { + if err := conn.Write(req); err != nil { t.Fatalf("could not write to connection: %v", err) } // wait for block bodies response msg := conn.waitForResponse(s.chain, timeout, req.RequestId) - blockBodies, ok := msg.(BlockBodies) + resp, ok := msg.(*BlockBodies) if !ok { t.Fatalf("unexpected: %s", pretty.Sdump(msg)) } - t.Logf("received %d block bodies", len(blockBodies)) - if len(blockBodies) != len(req.GetBlockBodiesPacket) { + bodies := resp.BlockBodiesPacket + t.Logf("received %d block bodies", len(bodies)) + if len(bodies) != len(req.GetBlockBodiesPacket) { t.Fatalf("wrong bodies in response: expected %d bodies, "+ - "got %d", len(req.GetBlockBodiesPacket), len(blockBodies)) - } -} - -// TestBroadcast65 tests whether a block announcement is correctly -// propagated to the given node's peer(s). -func (s *Suite) TestBroadcast65(t *utesting.T) { - if err := s.sendNextBlock(eth65); err != nil { - t.Fatalf("block broadcast failed: %v", err) + "got %d", len(req.GetBlockBodiesPacket), len(bodies)) } } -// TestBroadcast66 tests whether a block announcement is correctly -// propagated to the given node's peer(s) on the eth66 protocol. -func (s *Suite) TestBroadcast66(t *utesting.T) { - if err := s.sendNextBlock(eth66); err != nil { +// TestBroadcast tests whether a block announcement is correctly +// propagated to the node's peers. +func (s *Suite) TestBroadcast(t *utesting.T) { + if err := s.sendNextBlock(); err != nil { t.Fatalf("block broadcast failed: %v", err) } } -// TestLargeAnnounce65 tests the announcement mechanism with a large block. -func (s *Suite) TestLargeAnnounce65(t *utesting.T) { - nextBlock := len(s.chain.blocks) - blocks := []*NewBlock{ - { - Block: largeBlock(), - TD: s.fullChain.TotalDifficultyAt(nextBlock), - }, - { - Block: s.fullChain.blocks[nextBlock], - TD: largeNumber(2), - }, - { - Block: largeBlock(), - TD: largeNumber(2), - }, - } - - for i, blockAnnouncement := range blocks { - t.Logf("Testing malicious announcement: %v\n", i) - conn, err := s.dial() - if err != nil { - t.Fatalf("dial failed: %v", err) - } - if err = conn.peer(s.chain, nil); err != nil { - t.Fatalf("peering failed: %v", err) - } - if err = conn.Write(blockAnnouncement); err != nil { - t.Fatalf("could not write to connection: %v", err) - } - // Invalid announcement, check that peer disconnected - switch msg := conn.readAndServe(s.chain, time.Second*8).(type) { - case *Disconnect: - case *Error: - break - default: - t.Fatalf("unexpected: %s wanted disconnect", pretty.Sdump(msg)) - } - conn.Close() - } - // Test the last block as a valid block - if err := s.sendNextBlock(eth65); err != nil { - t.Fatalf("failed to broadcast next block: %v", err) - } -} - -// TestLargeAnnounce66 tests the announcement mechanism with a large -// block over the eth66 protocol. -func (s *Suite) TestLargeAnnounce66(t *utesting.T) { +// TestLargeAnnounce tests the announcement mechanism with a large block. +func (s *Suite) TestLargeAnnounce(t *utesting.T) { nextBlock := len(s.chain.blocks) blocks := []*NewBlock{ { @@ -553,7 +372,7 @@ func (s *Suite) TestLargeAnnounce66(t *utesting.T) { for i, blockAnnouncement := range blocks[0:3] { t.Logf("Testing malicious announcement: %v\n", i) - conn, err := s.dial66() + conn, err := s.dial() if err != nil { t.Fatalf("dial failed: %v", err) } @@ -564,7 +383,7 @@ func (s *Suite) TestLargeAnnounce66(t *utesting.T) { t.Fatalf("could not write to connection: %v", err) } // Invalid announcement, check that peer disconnected - switch msg := conn.readAndServe(s.chain, time.Second*8).(type) { + switch msg := conn.readAndServe(s.chain, 8*time.Second).(type) { case *Disconnect: case *Error: break @@ -574,58 +393,35 @@ func (s *Suite) TestLargeAnnounce66(t *utesting.T) { conn.Close() } // Test the last block as a valid block - if err := s.sendNextBlock(eth66); err != nil { + if err := s.sendNextBlock(); err != nil { t.Fatalf("failed to broadcast next block: %v", err) } } -// TestOldAnnounce65 tests the announcement mechanism with an old block. -func (s *Suite) TestOldAnnounce65(t *utesting.T) { - if err := s.oldAnnounce(eth65); err != nil { - t.Fatal(err) - } -} - -// TestOldAnnounce66 tests the announcement mechanism with an old block, -// over the eth66 protocol. -func (s *Suite) TestOldAnnounce66(t *utesting.T) { - if err := s.oldAnnounce(eth66); err != nil { +// TestOldAnnounce tests the announcement mechanism with an old block. +func (s *Suite) TestOldAnnounce(t *utesting.T) { + if err := s.oldAnnounce(); err != nil { t.Fatal(err) } } -// TestBlockHashAnnounce65 sends a new block hash announcement and expects -// the node to perform a `GetBlockHeaders` request. -func (s *Suite) TestBlockHashAnnounce65(t *utesting.T) { - if err := s.hashAnnounce(eth65); err != nil { - t.Fatalf("block hash announcement failed: %v", err) - } -} - -// TestBlockHashAnnounce66 sends a new block hash announcement and expects +// TestBlockHashAnnounce sends a new block hash announcement and expects // the node to perform a `GetBlockHeaders` request. -func (s *Suite) TestBlockHashAnnounce66(t *utesting.T) { - if err := s.hashAnnounce(eth66); err != nil { +func (s *Suite) TestBlockHashAnnounce(t *utesting.T) { + if err := s.hashAnnounce(); err != nil { t.Fatalf("block hash announcement failed: %v", err) } } -// TestMaliciousHandshake65 tries to send malicious data during the handshake. -func (s *Suite) TestMaliciousHandshake65(t *utesting.T) { - if err := s.maliciousHandshakes(t, eth65); err != nil { - t.Fatal(err) - } -} - -// TestMaliciousHandshake66 tries to send malicious data during the handshake. -func (s *Suite) TestMaliciousHandshake66(t *utesting.T) { - if err := s.maliciousHandshakes(t, eth66); err != nil { +// TestMaliciousHandshake tries to send malicious data during the handshake. +func (s *Suite) TestMaliciousHandshake(t *utesting.T) { + if err := s.maliciousHandshakes(t); err != nil { t.Fatal(err) } } -// TestMaliciousStatus65 sends a status package with a large total difficulty. -func (s *Suite) TestMaliciousStatus65(t *utesting.T) { +// TestMaliciousStatus sends a status package with a large total difficulty. +func (s *Suite) TestMaliciousStatus(t *utesting.T) { conn, err := s.dial() if err != nil { t.Fatalf("dial failed: %v", err) @@ -637,58 +433,28 @@ func (s *Suite) TestMaliciousStatus65(t *utesting.T) { } } -// TestMaliciousStatus66 sends a status package with a large total -// difficulty over the eth66 protocol. -func (s *Suite) TestMaliciousStatus66(t *utesting.T) { - conn, err := s.dial66() - if err != nil { - t.Fatalf("dial failed: %v", err) - } - defer conn.Close() - - if err := s.maliciousStatus(conn); err != nil { - t.Fatal(err) - } -} - -// TestTransaction65 sends a valid transaction to the node and +// TestTransaction sends a valid transaction to the node and // checks if the transaction gets propagated. -func (s *Suite) TestTransaction65(t *utesting.T) { - if err := s.sendSuccessfulTxs(t, eth65); err != nil { +func (s *Suite) TestTransaction(t *utesting.T) { + if err := s.sendSuccessfulTxs(t); err != nil { t.Fatal(err) } } -// TestTransaction66 sends a valid transaction to the node and -// checks if the transaction gets propagated. -func (s *Suite) TestTransaction66(t *utesting.T) { - if err := s.sendSuccessfulTxs(t, eth66); err != nil { - t.Fatal(err) - } -} - -// TestMaliciousTx65 sends several invalid transactions and tests whether +// TestMaliciousTx sends several invalid transactions and tests whether // the node will propagate them. -func (s *Suite) TestMaliciousTx65(t *utesting.T) { - if err := s.sendMaliciousTxs(t, eth65); err != nil { +func (s *Suite) TestMaliciousTx(t *utesting.T) { + if err := s.sendMaliciousTxs(t); err != nil { t.Fatal(err) } } -// TestMaliciousTx66 sends several invalid transactions and tests whether -// the node will propagate them. -func (s *Suite) TestMaliciousTx66(t *utesting.T) { - if err := s.sendMaliciousTxs(t, eth66); err != nil { - t.Fatal(err) - } -} - -// TestLargeTxRequest66 tests whether a node can fulfill a large GetPooledTransactions +// TestLargeTxRequest tests whether a node can fulfill a large GetPooledTransactions // request. -func (s *Suite) TestLargeTxRequest66(t *utesting.T) { +func (s *Suite) TestLargeTxRequest(t *utesting.T) { // send the next block to ensure the node is no longer syncing and // is able to accept txs - if err := s.sendNextBlock(eth66); err != nil { + if err := s.sendNextBlock(); err != nil { t.Fatalf("failed to send next block: %v", err) } // send 2000 transactions to the node @@ -701,7 +467,7 @@ func (s *Suite) TestLargeTxRequest66(t *utesting.T) { } // set up connection to receive to ensure node is peered with the receiving connection // before tx request is sent - conn, err := s.dial66() + conn, err := s.dial() if err != nil { t.Fatalf("dial failed: %v", err) } @@ -714,17 +480,17 @@ func (s *Suite) TestLargeTxRequest66(t *utesting.T) { for _, hash := range hashMap { hashes = append(hashes, hash) } - getTxReq := ð.GetPooledTransactionsPacket66{ + getTxReq := &GetPooledTransactions{ RequestId: 1234, GetPooledTransactionsPacket: hashes, } - if err = conn.Write66(getTxReq, GetPooledTransactions{}.Code()); err != nil { + if err = conn.Write(getTxReq); err != nil { t.Fatalf("could not write to conn: %v", err) } // check that all received transactions match those that were sent to node switch msg := conn.waitForResponse(s.chain, timeout, getTxReq.RequestId).(type) { - case PooledTransactions: - for _, gotTx := range msg { + case *PooledTransactions: + for _, gotTx := range msg.PooledTransactionsPacket { if _, exists := hashMap[gotTx.Hash()]; !exists { t.Fatalf("unexpected tx received: %v", gotTx.Hash()) } @@ -734,12 +500,12 @@ func (s *Suite) TestLargeTxRequest66(t *utesting.T) { } } -// TestNewPooledTxs_66 tests whether a node will do a GetPooledTransactions +// TestNewPooledTxs tests whether a node will do a GetPooledTransactions // request upon receiving a NewPooledTransactionHashes announcement. -func (s *Suite) TestNewPooledTxs66(t *utesting.T) { +func (s *Suite) TestNewPooledTxs(t *utesting.T) { // send the next block to ensure the node is no longer syncing and // is able to accept txs - if err := s.sendNextBlock(eth66); err != nil { + if err := s.sendNextBlock(); err != nil { t.Fatalf("failed to send next block: %v", err) } @@ -757,7 +523,7 @@ func (s *Suite) TestNewPooledTxs66(t *utesting.T) { announce := NewPooledTransactionHashes(hashes) // send announcement - conn, err := s.dial66() + conn, err := s.dial() if err != nil { t.Fatalf("dial failed: %v", err) } @@ -771,11 +537,11 @@ func (s *Suite) TestNewPooledTxs66(t *utesting.T) { // wait for GetPooledTxs request for { - _, msg := conn.readAndServe66(s.chain, timeout) + msg := conn.readAndServe(s.chain, timeout) switch msg := msg.(type) { - case GetPooledTransactions: - if len(msg) != len(hashes) { - t.Fatalf("unexpected number of txs requested: wanted %d, got %d", len(hashes), len(msg)) + case *GetPooledTransactions: + if len(msg.GetPooledTransactionsPacket) != len(hashes) { + t.Fatalf("unexpected number of txs requested: wanted %d, got %d", len(hashes), len(msg.GetPooledTransactionsPacket)) } return // ignore propagated txs from previous tests diff --git a/cmd/devp2p/internal/ethtest/suite_test.go b/cmd/devp2p/internal/ethtest/suite_test.go index 924c80d01c8c..8a2b132fa3b1 100644 --- a/cmd/devp2p/internal/ethtest/suite_test.go +++ b/cmd/devp2p/internal/ethtest/suite_test.go @@ -45,7 +45,7 @@ func TestEthSuite(t *testing.T) { if err != nil { t.Fatalf("could not create new test suite: %v", err) } - for _, test := range suite.Eth66Tests() { + for _, test := range suite.EthTests() { t.Run(test.Name, func(t *testing.T) { result := utesting.RunTAP([]utesting.Test{{Name: test.Name, Fn: test.Fn}}, os.Stdout) if result[0].Failed { diff --git a/cmd/devp2p/internal/ethtest/transaction.go b/cmd/devp2p/internal/ethtest/transaction.go index 5d722f417a22..c4748bf8f7d8 100644 --- a/cmd/devp2p/internal/ethtest/transaction.go +++ b/cmd/devp2p/internal/ethtest/transaction.go @@ -32,7 +32,7 @@ import ( //var faucetAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") var faucetKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") -func (s *Suite) sendSuccessfulTxs(t *utesting.T, isEth66 bool) error { +func (s *Suite) sendSuccessfulTxs(t *utesting.T) error { tests := []*types.Transaction{ getNextTxFromChain(s), unknownTx(s), @@ -48,15 +48,15 @@ func (s *Suite) sendSuccessfulTxs(t *utesting.T, isEth66 bool) error { prevTx = tests[i-1] } // write tx to connection - if err := sendSuccessfulTx(s, tx, prevTx, isEth66); err != nil { + if err := sendSuccessfulTx(s, tx, prevTx); err != nil { return fmt.Errorf("send successful tx test failed: %v", err) } } return nil } -func sendSuccessfulTx(s *Suite, tx *types.Transaction, prevTx *types.Transaction, isEth66 bool) error { - sendConn, recvConn, err := s.createSendAndRecvConns(isEth66) +func sendSuccessfulTx(s *Suite, tx *types.Transaction, prevTx *types.Transaction) error { + sendConn, recvConn, err := s.createSendAndRecvConns() if err != nil { return err } @@ -73,8 +73,10 @@ func sendSuccessfulTx(s *Suite, tx *types.Transaction, prevTx *types.Transaction if err = recvConn.peer(s.chain, nil); err != nil { return fmt.Errorf("peering failed: %v", err) } + // update last nonce seen nonce = tx.Nonce() + // Wait for the transaction announcement for { switch msg := recvConn.readAndServe(s.chain, timeout).(type) { @@ -114,7 +116,7 @@ func sendSuccessfulTx(s *Suite, tx *types.Transaction, prevTx *types.Transaction } } -func (s *Suite) sendMaliciousTxs(t *utesting.T, isEth66 bool) error { +func (s *Suite) sendMaliciousTxs(t *utesting.T) error { badTxs := []*types.Transaction{ getOldTxFromChain(s), invalidNonceTx(s), @@ -122,16 +124,9 @@ func (s *Suite) sendMaliciousTxs(t *utesting.T, isEth66 bool) error { hugeGasPrice(s), hugeData(s), } + // setup receiving connection before sending malicious txs - var ( - recvConn *Conn - err error - ) - if isEth66 { - recvConn, err = s.dial66() - } else { - recvConn, err = s.dial() - } + recvConn, err := s.dial() if err != nil { return fmt.Errorf("dial failed: %v", err) } @@ -139,9 +134,10 @@ func (s *Suite) sendMaliciousTxs(t *utesting.T, isEth66 bool) error { if err = recvConn.peer(s.chain, nil); err != nil { return fmt.Errorf("peering failed: %v", err) } + for i, tx := range badTxs { t.Logf("Testing malicious tx propagation: %v\n", i) - if err = sendMaliciousTx(s, tx, isEth66); err != nil { + if err = sendMaliciousTx(s, tx); err != nil { return fmt.Errorf("malicious tx test failed:\ntx: %v\nerror: %v", tx, err) } } @@ -149,17 +145,8 @@ func (s *Suite) sendMaliciousTxs(t *utesting.T, isEth66 bool) error { return checkMaliciousTxPropagation(s, badTxs, recvConn) } -func sendMaliciousTx(s *Suite, tx *types.Transaction, isEth66 bool) error { - // setup connection - var ( - conn *Conn - err error - ) - if isEth66 { - conn, err = s.dial66() - } else { - conn, err = s.dial() - } +func sendMaliciousTx(s *Suite, tx *types.Transaction) error { + conn, err := s.dial() if err != nil { return fmt.Errorf("dial failed: %v", err) } @@ -167,6 +154,7 @@ func sendMaliciousTx(s *Suite, tx *types.Transaction, isEth66 bool) error { if err = conn.peer(s.chain, nil); err != nil { return fmt.Errorf("peering failed: %v", err) } + // write malicious tx if err = conn.Write(&Transactions{tx}); err != nil { return fmt.Errorf("failed to write to connection: %v", err) @@ -182,7 +170,7 @@ func sendMultipleSuccessfulTxs(t *utesting.T, s *Suite, txs []*types.Transaction txMsg := Transactions(txs) t.Logf("sending %d txs\n", len(txs)) - sendConn, recvConn, err := s.createSendAndRecvConns(true) + sendConn, recvConn, err := s.createSendAndRecvConns() if err != nil { return err } @@ -194,15 +182,19 @@ func sendMultipleSuccessfulTxs(t *utesting.T, s *Suite, txs []*types.Transaction if err = recvConn.peer(s.chain, nil); err != nil { return fmt.Errorf("peering failed: %v", err) } + // Send the transactions if err = sendConn.Write(&txMsg); err != nil { return fmt.Errorf("failed to write message to connection: %v", err) } + // update nonce nonce = txs[len(txs)-1].Nonce() - // Wait for the transaction announcement(s) and make sure all sent txs are being propagated + + // Wait for the transaction announcement(s) and make sure all sent txs are being propagated. + // all txs should be announced within 3 announcements. recvHashes := make([]common.Hash, 0) - // all txs should be announced within 3 announcements + for i := 0; i < 3; i++ { switch msg := recvConn.readAndServe(s.chain, timeout).(type) { case *Transactions: diff --git a/cmd/devp2p/internal/ethtest/types.go b/cmd/devp2p/internal/ethtest/types.go index e69d94bb5c2c..2c5cb94c699f 100644 --- a/cmd/devp2p/internal/ethtest/types.go +++ b/cmd/devp2p/internal/ethtest/types.go @@ -29,6 +29,7 @@ import ( type Message interface { Code() int + ReqID() uint64 } type Error struct { @@ -37,9 +38,11 @@ type Error struct { func (e *Error) Unwrap() error { return e.err } func (e *Error) Error() string { return e.err.Error() } -func (e *Error) Code() int { return -1 } func (e *Error) String() string { return e.Error() } +func (e *Error) Code() int { return -1 } +func (e *Error) ReqID() uint64 { return 0 } + func errorf(format string, args ...interface{}) *Error { return &Error{fmt.Errorf(format, args...)} } @@ -56,73 +59,88 @@ type Hello struct { Rest []rlp.RawValue `rlp:"tail"` } -func (h Hello) Code() int { return 0x00 } +func (msg Hello) Code() int { return 0x00 } +func (msg Hello) ReqID() uint64 { return 0 } // Disconnect is the RLP structure for a disconnect message. type Disconnect struct { Reason p2p.DiscReason } -func (d Disconnect) Code() int { return 0x01 } +func (msg Disconnect) Code() int { return 0x01 } +func (msg Disconnect) ReqID() uint64 { return 0 } type Ping struct{} -func (p Ping) Code() int { return 0x02 } +func (msg Ping) Code() int { return 0x02 } +func (msg Ping) ReqID() uint64 { return 0 } type Pong struct{} -func (p Pong) Code() int { return 0x03 } +func (msg Pong) Code() int { return 0x03 } +func (msg Pong) ReqID() uint64 { return 0 } // Status is the network packet for the status message for eth/64 and later. type Status eth.StatusPacket -func (s Status) Code() int { return 16 } +func (msg Status) Code() int { return 16 } +func (msg Status) ReqID() uint64 { return 0 } // NewBlockHashes is the network packet for the block announcements. type NewBlockHashes eth.NewBlockHashesPacket -func (nbh NewBlockHashes) Code() int { return 17 } +func (msg NewBlockHashes) Code() int { return 17 } +func (msg NewBlockHashes) ReqID() uint64 { return 0 } type Transactions eth.TransactionsPacket -func (t Transactions) Code() int { return 18 } +func (msg Transactions) Code() int { return 18 } +func (msg Transactions) ReqID() uint64 { return 18 } // GetBlockHeaders represents a block header query. -type GetBlockHeaders eth.GetBlockHeadersPacket +type GetBlockHeaders eth.GetBlockHeadersPacket66 -func (g GetBlockHeaders) Code() int { return 19 } +func (msg GetBlockHeaders) Code() int { return 19 } +func (msg GetBlockHeaders) ReqID() uint64 { return msg.RequestId } -type BlockHeaders eth.BlockHeadersPacket +type BlockHeaders eth.BlockHeadersPacket66 -func (bh BlockHeaders) Code() int { return 20 } +func (msg BlockHeaders) Code() int { return 20 } +func (msg BlockHeaders) ReqID() uint64 { return msg.RequestId } // GetBlockBodies represents a GetBlockBodies request -type GetBlockBodies eth.GetBlockBodiesPacket +type GetBlockBodies eth.GetBlockBodiesPacket66 -func (gbb GetBlockBodies) Code() int { return 21 } +func (msg GetBlockBodies) Code() int { return 21 } +func (msg GetBlockBodies) ReqID() uint64 { return msg.RequestId } // BlockBodies is the network packet for block content distribution. -type BlockBodies eth.BlockBodiesPacket +type BlockBodies eth.BlockBodiesPacket66 -func (bb BlockBodies) Code() int { return 22 } +func (msg BlockBodies) Code() int { return 22 } +func (msg BlockBodies) ReqID() uint64 { return msg.RequestId } // NewBlock is the network packet for the block propagation message. type NewBlock eth.NewBlockPacket -func (nb NewBlock) Code() int { return 23 } +func (msg NewBlock) Code() int { return 23 } +func (msg NewBlock) ReqID() uint64 { return 0 } // NewPooledTransactionHashes is the network packet for the tx hash propagation message. type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket -func (nb NewPooledTransactionHashes) Code() int { return 24 } +func (msg NewPooledTransactionHashes) Code() int { return 24 } +func (msg NewPooledTransactionHashes) ReqID() uint64 { return 0 } -type GetPooledTransactions eth.GetPooledTransactionsPacket +type GetPooledTransactions eth.GetPooledTransactionsPacket66 -func (gpt GetPooledTransactions) Code() int { return 25 } +func (msg GetPooledTransactions) Code() int { return 25 } +func (msg GetPooledTransactions) ReqID() uint64 { return msg.RequestId } -type PooledTransactions eth.PooledTransactionsPacket +type PooledTransactions eth.PooledTransactionsPacket66 -func (pt PooledTransactions) Code() int { return 26 } +func (msg PooledTransactions) Code() int { return 26 } +func (msg PooledTransactions) ReqID() uint64 { return msg.RequestId } // Conn represents an individual connection with a peer type Conn struct { @@ -135,62 +153,13 @@ type Conn struct { caps []p2p.Cap } -// Read reads an eth packet from the connection. +// Read reads an eth66 packet from the connection. func (c *Conn) Read() Message { code, rawData, _, err := c.Conn.Read() if err != nil { return errorf("could not read from connection: %v", err) } - var msg Message - switch int(code) { - case (Hello{}).Code(): - msg = new(Hello) - case (Ping{}).Code(): - msg = new(Ping) - case (Pong{}).Code(): - msg = new(Pong) - case (Disconnect{}).Code(): - msg = new(Disconnect) - case (Status{}).Code(): - msg = new(Status) - case (GetBlockHeaders{}).Code(): - msg = new(GetBlockHeaders) - case (BlockHeaders{}).Code(): - msg = new(BlockHeaders) - case (GetBlockBodies{}).Code(): - msg = new(GetBlockBodies) - case (BlockBodies{}).Code(): - msg = new(BlockBodies) - case (NewBlock{}).Code(): - msg = new(NewBlock) - case (NewBlockHashes{}).Code(): - msg = new(NewBlockHashes) - case (Transactions{}).Code(): - msg = new(Transactions) - case (NewPooledTransactionHashes{}).Code(): - msg = new(NewPooledTransactionHashes) - case (GetPooledTransactions{}.Code()): - msg = new(GetPooledTransactions) - case (PooledTransactions{}.Code()): - msg = new(PooledTransactions) - default: - return errorf("invalid message code: %d", code) - } - // if message is devp2p, decode here - if err := rlp.DecodeBytes(rawData, msg); err != nil { - return errorf("could not rlp decode message: %v", err) - } - return msg -} - -// Read66 reads an eth66 packet from the connection. -func (c *Conn) Read66() (uint64, Message) { - code, rawData, _, err := c.Conn.Read() - if err != nil { - return 0, errorf("could not read from connection: %v", err) - } - var msg Message switch int(code) { case (Hello{}).Code(): @@ -206,27 +175,27 @@ func (c *Conn) Read66() (uint64, Message) { case (GetBlockHeaders{}).Code(): ethMsg := new(eth.GetBlockHeadersPacket66) if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { - return 0, errorf("could not rlp decode message: %v", err) + return errorf("could not rlp decode message: %v", err) } - return ethMsg.RequestId, GetBlockHeaders(*ethMsg.GetBlockHeadersPacket) + return (*GetBlockHeaders)(ethMsg) case (BlockHeaders{}).Code(): ethMsg := new(eth.BlockHeadersPacket66) if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { - return 0, errorf("could not rlp decode message: %v", err) + return errorf("could not rlp decode message: %v", err) } - return ethMsg.RequestId, BlockHeaders(ethMsg.BlockHeadersPacket) + return (*BlockHeaders)(ethMsg) case (GetBlockBodies{}).Code(): ethMsg := new(eth.GetBlockBodiesPacket66) if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { - return 0, errorf("could not rlp decode message: %v", err) + return errorf("could not rlp decode message: %v", err) } - return ethMsg.RequestId, GetBlockBodies(ethMsg.GetBlockBodiesPacket) + return (*GetBlockBodies)(ethMsg) case (BlockBodies{}).Code(): ethMsg := new(eth.BlockBodiesPacket66) if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { - return 0, errorf("could not rlp decode message: %v", err) + return errorf("could not rlp decode message: %v", err) } - return ethMsg.RequestId, BlockBodies(ethMsg.BlockBodiesPacket) + return (*BlockBodies)(ethMsg) case (NewBlock{}).Code(): msg = new(NewBlock) case (NewBlockHashes{}).Code(): @@ -238,26 +207,26 @@ func (c *Conn) Read66() (uint64, Message) { case (GetPooledTransactions{}.Code()): ethMsg := new(eth.GetPooledTransactionsPacket66) if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { - return 0, errorf("could not rlp decode message: %v", err) + return errorf("could not rlp decode message: %v", err) } - return ethMsg.RequestId, GetPooledTransactions(ethMsg.GetPooledTransactionsPacket) + return (*GetPooledTransactions)(ethMsg) case (PooledTransactions{}.Code()): ethMsg := new(eth.PooledTransactionsPacket66) if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { - return 0, errorf("could not rlp decode message: %v", err) + return errorf("could not rlp decode message: %v", err) } - return ethMsg.RequestId, PooledTransactions(ethMsg.PooledTransactionsPacket) + return (*PooledTransactions)(ethMsg) default: msg = errorf("invalid message code: %d", code) } if msg != nil { if err := rlp.DecodeBytes(rawData, msg); err != nil { - return 0, errorf("could not rlp decode message: %v", err) + return errorf("could not rlp decode message: %v", err) } - return 0, msg + return msg } - return 0, errorf("invalid message: %s", string(rawData)) + return errorf("invalid message: %s", string(rawData)) } // Write writes a eth packet to the connection. @@ -270,16 +239,6 @@ func (c *Conn) Write(msg Message) error { return err } -// Write66 writes an eth66 packet to the connection. -func (c *Conn) Write66(req eth.Packet, code int) error { - payload, err := rlp.EncodeToBytes(req) - if err != nil { - return err - } - _, err = c.Conn.Write(uint64(code), payload) - return err -} - // ReadSnap reads a snap/1 response with the given id from the connection. func (c *Conn) ReadSnap(id uint64) (Message, error) { respId := id + 1 diff --git a/cmd/devp2p/rlpxcmd.go b/cmd/devp2p/rlpxcmd.go index 07978e4f8861..42b38120c475 100644 --- a/cmd/devp2p/rlpxcmd.go +++ b/cmd/devp2p/rlpxcmd.go @@ -22,7 +22,6 @@ import ( "github.com/ethereum/go-ethereum/cmd/devp2p/internal/ethtest" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/internal/utesting" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/rlpx" "github.com/ethereum/go-ethereum/rlp" @@ -110,12 +109,7 @@ func rlpxEthTest(ctx *cli.Context) error { if err != nil { exit(err) } - // check if given node supports eth66, and if so, run eth66 protocol tests as well - is66Failed, _ := utesting.Run(utesting.Test{Name: "Is_66", Fn: suite.Is_66}) - if is66Failed { - return runTests(ctx, suite.EthTests()) - } - return runTests(ctx, suite.AllEthTests()) + return runTests(ctx, suite.EthTests()) } // rlpxSnapTest runs the snap protocol test suite. From 9244f87dc1c8869a2632176f719e515217720a43 Mon Sep 17 00:00:00 2001 From: Tristan-Wilson <87238672+Tristan-Wilson@users.noreply.github.com> Date: Wed, 3 Aug 2022 07:50:12 -0700 Subject: [PATCH 140/715] node, rpc: add ReadHeaderTimeout config option (#25338) This change makes http.Server.ReadHeaderTimeout configurable separately from ReadTimeout for RPC servers. The default is set to the same as ReadTimeout, which in order to cause no change in existing deployments. --- node/endpoints.go | 13 +++++++++---- node/rpcstack.go | 1 + rpc/http.go | 15 ++++++++++++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/node/endpoints.go b/node/endpoints.go index efc311e7e317..14c12fd1f175 100644 --- a/node/endpoints.go +++ b/node/endpoints.go @@ -39,10 +39,11 @@ func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http. CheckTimeouts(&timeouts) // Bundle and start the HTTP server httpSrv := &http.Server{ - Handler: handler, - ReadTimeout: timeouts.ReadTimeout, - WriteTimeout: timeouts.WriteTimeout, - IdleTimeout: timeouts.IdleTimeout, + Handler: handler, + ReadTimeout: timeouts.ReadTimeout, + ReadHeaderTimeout: timeouts.ReadHeaderTimeout, + WriteTimeout: timeouts.WriteTimeout, + IdleTimeout: timeouts.IdleTimeout, } go httpSrv.Serve(listener) return httpSrv, listener.Addr(), err @@ -75,6 +76,10 @@ func CheckTimeouts(timeouts *rpc.HTTPTimeouts) { log.Warn("Sanitizing invalid HTTP read timeout", "provided", timeouts.ReadTimeout, "updated", rpc.DefaultHTTPTimeouts.ReadTimeout) timeouts.ReadTimeout = rpc.DefaultHTTPTimeouts.ReadTimeout } + if timeouts.ReadHeaderTimeout < time.Second { + log.Warn("Sanitizing invalid HTTP read header timeout", "provided", timeouts.ReadHeaderTimeout, "updated", rpc.DefaultHTTPTimeouts.ReadHeaderTimeout) + timeouts.ReadHeaderTimeout = rpc.DefaultHTTPTimeouts.ReadHeaderTimeout + } if timeouts.WriteTimeout < time.Second { log.Warn("Sanitizing invalid HTTP write timeout", "provided", timeouts.WriteTimeout, "updated", rpc.DefaultHTTPTimeouts.WriteTimeout) timeouts.WriteTimeout = rpc.DefaultHTTPTimeouts.WriteTimeout diff --git a/node/rpcstack.go b/node/rpcstack.go index 9b5873e90a5f..5d411fa61e81 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -134,6 +134,7 @@ func (h *httpServer) start() error { if h.timeouts != (rpc.HTTPTimeouts{}) { CheckTimeouts(&h.timeouts) h.server.ReadTimeout = h.timeouts.ReadTimeout + h.server.ReadHeaderTimeout = h.timeouts.ReadHeaderTimeout h.server.WriteTimeout = h.timeouts.WriteTimeout h.server.IdleTimeout = h.timeouts.IdleTimeout } diff --git a/rpc/http.go b/rpc/http.go index 9f4464957349..858d80858652 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -87,6 +87,14 @@ type HTTPTimeouts struct { // ReadHeaderTimeout. It is valid to use them both. ReadTimeout time.Duration + // ReadHeaderTimeout is the amount of time allowed to read + // request headers. The connection's read deadline is reset + // after reading the headers and the Handler can decide what + // is considered too slow for the body. If ReadHeaderTimeout + // is zero, the value of ReadTimeout is used. If both are + // zero, there is no timeout. + ReadHeaderTimeout time.Duration + // WriteTimeout is the maximum duration before timing out // writes of the response. It is reset whenever a new // request's header is read. Like ReadTimeout, it does not @@ -103,9 +111,10 @@ type HTTPTimeouts struct { // DefaultHTTPTimeouts represents the default timeout values used if further // configuration is not provided. var DefaultHTTPTimeouts = HTTPTimeouts{ - ReadTimeout: 30 * time.Second, - WriteTimeout: 30 * time.Second, - IdleTimeout: 120 * time.Second, + ReadTimeout: 30 * time.Second, + ReadHeaderTimeout: 30 * time.Second, + WriteTimeout: 30 * time.Second, + IdleTimeout: 120 * time.Second, } // DialHTTPWithClient creates a new RPC client that connects to an RPC server over HTTP From 6b6261b51fa46f7ed36d0589db641c14569ce036 Mon Sep 17 00:00:00 2001 From: yong <33920876+yzhaoyu@users.noreply.github.com> Date: Wed, 3 Aug 2022 22:56:57 +0800 Subject: [PATCH 141/715] core/types: fix typo in comment (#25359) --- core/types/bloom9.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/types/bloom9.go b/core/types/bloom9.go index 1793c2adc73c..a560a20724fd 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -154,7 +154,7 @@ func bloomValues(data []byte, hashbuf []byte) (uint, byte, uint, byte, uint, byt return i1, v1, i2, v2, i3, v3 } -// BloomLookup is a convenience-method to check presence int he bloom filter +// BloomLookup is a convenience-method to check presence in the bloom filter func BloomLookup(bin Bloom, topic bytesBacked) bool { return bin.Test(topic.Bytes()) } From 5fb463dddc928eec38de80f63ebdd9d7820d1a72 Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Thu, 4 Aug 2022 00:02:09 +0900 Subject: [PATCH 142/715] core: preallocate batch size in bloomIndexer (#25289) This change reduces allocations when committing bloombits indexes by creating the database batch with a larger initial size. --- core/bloom_indexer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/bloom_indexer.go b/core/bloom_indexer.go index 856746a1c088..68a35d811e41 100644 --- a/core/bloom_indexer.go +++ b/core/bloom_indexer.go @@ -75,7 +75,7 @@ func (b *BloomIndexer) Process(ctx context.Context, header *types.Header) error // Commit implements core.ChainIndexerBackend, finalizing the bloom section and // writing it out into the database. func (b *BloomIndexer) Commit() error { - batch := b.db.NewBatch() + batch := b.db.NewBatchWithSize((int(b.size) / 8) * types.BloomBitLength) for i := 0; i < types.BloomBitLength; i++ { bits, err := b.gen.Bitset(uint(i)) if err != nil { From 948e08d55bf185e4b80ca7a10d689cbfd3f7fcdd Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Wed, 3 Aug 2022 10:18:45 -0600 Subject: [PATCH 143/715] internal/ethapi: don't estimate gas if no limit provided in eth_createAccessList (#25467) Because the goal of eth_createAccessList is providing the caller with the largest-possible access list, it's generally not important that the gas limit used by the tracer will match the usage of the call exactly. Avoiding the gas estimation step is a performance improvement. As long as the call does not branch based on gas limit, the returned access list will be accurate. --- internal/ethapi/api.go | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 90322033b935..939dd69396f3 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1392,9 +1392,11 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH if db == nil || err != nil { return nil, 0, nil, err } - // If the gas amount is not set, extract this as it will depend on access - // lists and we'll need to reestimate every time - nogas := args.Gas == nil + // If the gas amount is not set, default to RPC gas cap. + if args.Gas == nil { + tmp := hexutil.Uint64(b.RPCGasCap()) + args.Gas = &tmp + } // Ensure any missing fields are filled, extract the recipient and input data if err := args.setDefaults(ctx, b); err != nil { @@ -1420,15 +1422,6 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH accessList := prevTracer.AccessList() log.Trace("Creating access list", "input", accessList) - // If no gas amount was specified, each unique access list needs it's own - // gas calculation. This is quite expensive, but we need to be accurate - // and it's convered by the sender only anyway. - if nogas { - args.Gas = nil - if err := args.setDefaults(ctx, b); err != nil { - return nil, 0, nil, err // shouldn't happen, just in case - } - } // Copy the original db so we don't modify it statedb := db.Copy() // Set the accesslist to the last al From f809cf6ea61388b1ff0b7580770648ad86be412c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 3 Aug 2022 19:08:32 +0200 Subject: [PATCH 144/715] graphql: embed *Resolver instead of backend interface (#25468) This creates some infrastructure to share resources between graphql API objects. --- graphql/graphql.go | 132 ++++++++++++++++++++++----------------------- graphql/service.go | 4 -- 2 files changed, 66 insertions(+), 70 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 0654fd1af388..0949c34803cf 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -76,14 +76,14 @@ func (b *Long) UnmarshalGraphQL(input interface{}) error { // Account represents an Ethereum account at a particular block. type Account struct { - backend ethapi.Backend + r *Resolver address common.Address blockNrOrHash rpc.BlockNumberOrHash } // getState fetches the StateDB object for an account. func (a *Account) getState(ctx context.Context) (*state.StateDB, error) { - state, _, err := a.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash) + state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash) return state, err } @@ -106,7 +106,7 @@ func (a *Account) Balance(ctx context.Context) (hexutil.Big, error) { func (a *Account) TransactionCount(ctx context.Context) (hexutil.Uint64, error) { // Ask transaction pool for the nonce which includes pending transactions if blockNr, ok := a.blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber { - nonce, err := a.backend.GetPoolNonce(ctx, a.address) + nonce, err := a.r.backend.GetPoolNonce(ctx, a.address) if err != nil { return 0, err } @@ -137,7 +137,7 @@ func (a *Account) Storage(ctx context.Context, args struct{ Slot common.Hash }) // Log represents an individual log message. All arguments are mandatory. type Log struct { - backend ethapi.Backend + r *Resolver transaction *Transaction log *types.Log } @@ -148,7 +148,7 @@ func (l *Log) Transaction(ctx context.Context) *Transaction { func (l *Log) Account(ctx context.Context, args BlockNumberArgs) *Account { return &Account{ - backend: l.backend, + r: l.r, address: l.log.Address, blockNrOrHash: args.NumberOrLatest(), } @@ -183,30 +183,30 @@ func (at *AccessTuple) StorageKeys(ctx context.Context) []common.Hash { // Transaction represents an Ethereum transaction. // backend and hash are mandatory; all others will be fetched when required. type Transaction struct { - backend ethapi.Backend - hash common.Hash - tx *types.Transaction - block *Block - index uint64 + r *Resolver + hash common.Hash + tx *types.Transaction + block *Block + index uint64 } // resolve returns the internal transaction object, fetching it if needed. func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, error) { if t.tx == nil { // Try to return an already finalized transaction - tx, blockHash, _, index, err := t.backend.GetTransaction(ctx, t.hash) + tx, blockHash, _, index, err := t.r.backend.GetTransaction(ctx, t.hash) if err == nil && tx != nil { t.tx = tx blockNrOrHash := rpc.BlockNumberOrHashWithHash(blockHash, false) t.block = &Block{ - backend: t.backend, + r: t.r, numberOrHash: &blockNrOrHash, } t.index = index return t.tx, nil } // No finalized transaction, try to retrieve it from the pool - t.tx = t.backend.GetPoolTransaction(t.hash) + t.tx = t.r.backend.GetPoolTransaction(t.hash) } return t.tx, nil } @@ -354,7 +354,7 @@ func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) (*Account, e return nil, nil } return &Account{ - backend: t.backend, + r: t.r, address: *to, blockNrOrHash: args.NumberOrLatest(), }, nil @@ -365,10 +365,10 @@ func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account, if err != nil || tx == nil { return nil, err } - signer := types.LatestSigner(t.backend.ChainConfig()) + signer := types.LatestSigner(t.r.backend.ChainConfig()) from, _ := types.Sender(signer, tx) return &Account{ - backend: t.backend, + r: t.r, address: from, blockNrOrHash: args.NumberOrLatest(), }, nil @@ -443,7 +443,7 @@ func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs) return nil, err } return &Account{ - backend: t.backend, + r: t.r, address: receipt.ContractAddress, blockNrOrHash: args.NumberOrLatest(), }, nil @@ -457,7 +457,7 @@ func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) { ret := make([]*Log, 0, len(receipt.Logs)) for _, log := range receipt.Logs { ret = append(ret, &Log{ - backend: t.backend, + r: t.r, transaction: t, log: log, }) @@ -539,7 +539,7 @@ type BlockType int // backend, and numberOrHash are mandatory. All other fields are lazily fetched // when required. type Block struct { - backend ethapi.Backend + r *Resolver numberOrHash *rpc.BlockNumberOrHash hash common.Hash header *types.Header @@ -558,7 +558,7 @@ func (b *Block) resolve(ctx context.Context) (*types.Block, error) { b.numberOrHash = &latest } var err error - b.block, err = b.backend.BlockByNumberOrHash(ctx, *b.numberOrHash) + b.block, err = b.r.backend.BlockByNumberOrHash(ctx, *b.numberOrHash) if b.block != nil && b.header == nil { b.header = b.block.Header() if hash, ok := b.numberOrHash.Hash(); ok { @@ -578,9 +578,9 @@ func (b *Block) resolveHeader(ctx context.Context) (*types.Header, error) { var err error if b.header == nil { if b.hash != (common.Hash{}) { - b.header, err = b.backend.HeaderByHash(ctx, b.hash) + b.header, err = b.r.backend.HeaderByHash(ctx, b.hash) } else { - b.header, err = b.backend.HeaderByNumberOrHash(ctx, *b.numberOrHash) + b.header, err = b.r.backend.HeaderByNumberOrHash(ctx, *b.numberOrHash) } } return b.header, err @@ -598,7 +598,7 @@ func (b *Block) resolveReceipts(ctx context.Context) ([]*types.Receipt, error) { } hash = header.Hash() } - receipts, err := b.backend.GetReceipts(ctx, hash) + receipts, err := b.r.backend.GetReceipts(ctx, hash) if err != nil { return nil, err } @@ -659,7 +659,7 @@ func (b *Block) NextBaseFeePerGas(ctx context.Context) (*hexutil.Big, error) { if err != nil { return nil, err } - chaincfg := b.backend.ChainConfig() + chaincfg := b.r.backend.ChainConfig() if header.BaseFee == nil { // Make sure next block doesn't enable EIP-1559 if !chaincfg.IsLondon(new(big.Int).Add(header.Number, common.Big1)) { @@ -679,7 +679,7 @@ func (b *Block) Parent(ctx context.Context) (*Block, error) { } num := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(b.header.Number.Uint64() - 1)) return &Block{ - backend: b.backend, + r: b.r, numberOrHash: &num, hash: b.header.ParentHash, }, nil @@ -767,7 +767,7 @@ func (b *Block) Ommers(ctx context.Context) (*[]*Block, error) { for _, uncle := range block.Uncles() { blockNumberOrHash := rpc.BlockNumberOrHashWithHash(uncle.Hash(), false) ret = append(ret, &Block{ - backend: b.backend, + r: b.r, numberOrHash: &blockNumberOrHash, header: uncle, }) @@ -800,7 +800,7 @@ func (b *Block) TotalDifficulty(ctx context.Context) (hexutil.Big, error) { } h = header.Hash() } - td := b.backend.GetTd(ctx, h) + td := b.r.backend.GetTd(ctx, h) if td == nil { return hexutil.Big{}, fmt.Errorf("total difficulty not found %x", b.hash) } @@ -853,7 +853,7 @@ func (b *Block) Miner(ctx context.Context, args BlockNumberArgs) (*Account, erro return nil, err } return &Account{ - backend: b.backend, + r: b.r, address: header.Coinbase, blockNrOrHash: args.NumberOrLatest(), }, nil @@ -876,11 +876,11 @@ func (b *Block) Transactions(ctx context.Context) (*[]*Transaction, error) { ret := make([]*Transaction, 0, len(block.Transactions())) for i, tx := range block.Transactions() { ret = append(ret, &Transaction{ - backend: b.backend, - hash: tx.Hash(), - tx: tx, - block: b, - index: uint64(i), + r: b.r, + hash: tx.Hash(), + tx: tx, + block: b, + index: uint64(i), }) } return &ret, nil @@ -897,11 +897,11 @@ func (b *Block) TransactionAt(ctx context.Context, args struct{ Index int32 }) ( } tx := txs[args.Index] return &Transaction{ - backend: b.backend, - hash: tx.Hash(), - tx: tx, - block: b, - index: uint64(args.Index), + r: b.r, + hash: tx.Hash(), + tx: tx, + block: b, + index: uint64(args.Index), }, nil } @@ -917,7 +917,7 @@ func (b *Block) OmmerAt(ctx context.Context, args struct{ Index int32 }) (*Block uncle := uncles[args.Index] blockNumberOrHash := rpc.BlockNumberOrHashWithHash(uncle.Hash(), false) return &Block{ - backend: b.backend, + r: b.r, numberOrHash: &blockNumberOrHash, header: uncle, }, nil @@ -944,7 +944,7 @@ type BlockFilterCriteria struct { // runFilter accepts a filter and executes it, returning all its results as // `Log` objects. -func runFilter(ctx context.Context, be ethapi.Backend, filter *filters.Filter) ([]*Log, error) { +func runFilter(ctx context.Context, r *Resolver, filter *filters.Filter) ([]*Log, error) { logs, err := filter.Logs(ctx) if err != nil || logs == nil { return nil, err @@ -952,8 +952,8 @@ func runFilter(ctx context.Context, be ethapi.Backend, filter *filters.Filter) ( ret := make([]*Log, 0, len(logs)) for _, log := range logs { ret = append(ret, &Log{ - backend: be, - transaction: &Transaction{backend: be, hash: log.TxHash}, + r: r, + transaction: &Transaction{r: r, hash: log.TxHash}, log: log, }) } @@ -978,10 +978,10 @@ func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteri hash = header.Hash() } // Construct the range filter - filter := filters.NewBlockFilter(b.backend, hash, addresses, topics) + filter := filters.NewBlockFilter(b.r.backend, hash, addresses, topics) // Run the filter and return all the logs - return runFilter(ctx, b.backend, filter) + return runFilter(ctx, b.r, filter) } func (b *Block) Account(ctx context.Context, args struct { @@ -994,7 +994,7 @@ func (b *Block) Account(ctx context.Context, args struct { } } return &Account{ - backend: b.backend, + r: b.r, address: args.Address, blockNrOrHash: *b.numberOrHash, }, nil @@ -1041,7 +1041,7 @@ func (b *Block) Call(ctx context.Context, args struct { return nil, err } } - result, err := ethapi.DoCall(ctx, b.backend, args.Data, *b.numberOrHash, nil, b.backend.RPCEVMTimeout(), b.backend.RPCGasCap()) + result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap()) if err != nil { return nil, err } @@ -1066,31 +1066,31 @@ func (b *Block) EstimateGas(ctx context.Context, args struct { return 0, err } } - gas, err := ethapi.DoEstimateGas(ctx, b.backend, args.Data, *b.numberOrHash, b.backend.RPCGasCap()) + gas, err := ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, b.r.backend.RPCGasCap()) return Long(gas), err } type Pending struct { - backend ethapi.Backend + r *Resolver } func (p *Pending) TransactionCount(ctx context.Context) (int32, error) { - txs, err := p.backend.GetPoolTransactions() + txs, err := p.r.backend.GetPoolTransactions() return int32(len(txs)), err } func (p *Pending) Transactions(ctx context.Context) (*[]*Transaction, error) { - txs, err := p.backend.GetPoolTransactions() + txs, err := p.r.backend.GetPoolTransactions() if err != nil { return nil, err } ret := make([]*Transaction, 0, len(txs)) for i, tx := range txs { ret = append(ret, &Transaction{ - backend: p.backend, - hash: tx.Hash(), - tx: tx, - index: uint64(i), + r: p.r, + hash: tx.Hash(), + tx: tx, + index: uint64(i), }) } return &ret, nil @@ -1101,7 +1101,7 @@ func (p *Pending) Account(ctx context.Context, args struct { }) *Account { pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) return &Account{ - backend: p.backend, + r: p.r, address: args.Address, blockNrOrHash: pendingBlockNr, } @@ -1111,7 +1111,7 @@ func (p *Pending) Call(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (*CallResult, error) { pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) - result, err := ethapi.DoCall(ctx, p.backend, args.Data, pendingBlockNr, nil, p.backend.RPCEVMTimeout(), p.backend.RPCGasCap()) + result, err := ethapi.DoCall(ctx, p.r.backend, args.Data, pendingBlockNr, nil, p.r.backend.RPCEVMTimeout(), p.r.backend.RPCGasCap()) if err != nil { return nil, err } @@ -1131,7 +1131,7 @@ func (p *Pending) EstimateGas(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (Long, error) { pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) - gas, err := ethapi.DoEstimateGas(ctx, p.backend, args.Data, pendingBlockNr, p.backend.RPCGasCap()) + gas, err := ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, pendingBlockNr, p.r.backend.RPCGasCap()) return Long(gas), err } @@ -1152,19 +1152,19 @@ func (r *Resolver) Block(ctx context.Context, args struct { number := rpc.BlockNumber(*args.Number) numberOrHash := rpc.BlockNumberOrHashWithNumber(number) block = &Block{ - backend: r.backend, + r: r, numberOrHash: &numberOrHash, } } else if args.Hash != nil { numberOrHash := rpc.BlockNumberOrHashWithHash(*args.Hash, false) block = &Block{ - backend: r.backend, + r: r, numberOrHash: &numberOrHash, } } else { numberOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) block = &Block{ - backend: r.backend, + r: r, numberOrHash: &numberOrHash, } } @@ -1199,7 +1199,7 @@ func (r *Resolver) Blocks(ctx context.Context, args struct { for i := from; i <= to; i++ { numberOrHash := rpc.BlockNumberOrHashWithNumber(i) block := &Block{ - backend: r.backend, + r: r, numberOrHash: &numberOrHash, } // Resolve the header to check for existence. @@ -1218,13 +1218,13 @@ func (r *Resolver) Blocks(ctx context.Context, args struct { } func (r *Resolver) Pending(ctx context.Context) *Pending { - return &Pending{r.backend} + return &Pending{r} } func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Hash }) (*Transaction, error) { tx := &Transaction{ - backend: r.backend, - hash: args.Hash, + r: r, + hash: args.Hash, } // Resolve the transaction; if it doesn't exist, return nil. t, err := tx.resolve(ctx) @@ -1284,8 +1284,8 @@ func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria topics = *args.Filter.Topics } // Construct the range filter - filter := filters.NewRangeFilter(filters.Backend(r.backend), begin, end, addresses, topics) - return runFilter(ctx, r.backend, filter) + filter := filters.NewRangeFilter(r.backend, begin, end, addresses, topics) + return runFilter(ctx, r, filter) } func (r *Resolver) GasPrice(ctx context.Context) (hexutil.Big, error) { diff --git a/graphql/service.go b/graphql/service.go index 396a477005dd..1a2ffaa9469d 100644 --- a/graphql/service.go +++ b/graphql/service.go @@ -56,10 +56,6 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // New constructs a new GraphQL service instance. func New(stack *node.Node, backend ethapi.Backend, cors, vhosts []string) error { - if backend == nil { - panic("missing backend") - } - // check if http server with given endpoint exists and enable graphQL on it return newHandler(stack, backend, cors, vhosts) } From 733d76a88d7a28434ab46bfe4f8e45821e7568b5 Mon Sep 17 00:00:00 2001 From: Delweng Date: Thu, 4 Aug 2022 15:42:03 +0800 Subject: [PATCH 145/715] node: remove noop path.Join (#25475) Signed-off-by: Delweng --- node/config_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/config_test.go b/node/config_test.go index 62b2fbbd16a3..e8af8ddcd87b 100644 --- a/node/config_test.go +++ b/node/config_test.go @@ -115,7 +115,7 @@ func TestNodeKeyPersistency(t *testing.T) { } config := &Config{Name: "unit-test", DataDir: dir, P2P: p2p.Config{PrivateKey: key}} config.NodeKey() - if _, err := os.Stat(filepath.Join(keyfile)); err == nil { + if _, err := os.Stat(keyfile); err == nil { t.Fatalf("one-shot node key persisted to data directory") } @@ -136,7 +136,7 @@ func TestNodeKeyPersistency(t *testing.T) { // Configure a new node and ensure the previously persisted key is loaded config = &Config{Name: "unit-test", DataDir: dir} config.NodeKey() - blob2, err := os.ReadFile(filepath.Join(keyfile)) + blob2, err := os.ReadFile(keyfile) if err != nil { t.Fatalf("failed to read previously persisted node key: %v", err) } From 8b53b92eb4628124ef7416ed515b9ffd0e0d71ff Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 4 Aug 2022 16:03:20 +0800 Subject: [PATCH 146/715] core, trie: rework trie committer (#25320) * all: rework trie and trie committer * all: get rid of internal cache in trie * all: fixes * trie: polish * core, trie: address comments * trie: fix imports * core/state: address comments * core/state/snapshot: polish * trie: remove unused code * trie: update tests * trie: don't set db as nil * trie: address comments * trie: unskip test --- core/blockchain.go | 6 +- core/state/database.go | 10 +- core/state/metrics.go | 12 +- core/state/snapshot/generate.go | 5 +- core/state/snapshot/generate_test.go | 54 +++----- core/state/state_object.go | 11 +- core/state/statedb.go | 47 ++++--- eth/protocols/snap/sync_test.go | 108 +++++++++++---- light/postprocess.go | 26 +++- light/trie.go | 6 +- tests/fuzzers/stacktrie/trie_fuzzer.go | 5 +- tests/fuzzers/trie/trie-fuzzer.go | 14 +- trie/committer.go | 183 +++++++++---------------- trie/database.go | 44 +++++- trie/iterator.go | 3 +- trie/iterator_test.go | 56 +++++--- trie/nodeset.go | 94 +++++++++++++ trie/proof.go | 14 +- trie/secure_trie.go | 16 ++- trie/secure_trie_test.go | 15 +- trie/sync_test.go | 13 +- trie/trie.go | 116 ++++++---------- trie/trie_test.go | 150 +++++++++----------- trie/util_test.go | 11 +- 24 files changed, 587 insertions(+), 432 deletions(-) create mode 100644 trie/nodeset.go diff --git a/core/blockchain.go b/core/blockchain.go index 506034b539a7..3638a1dcea16 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1244,7 +1244,7 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error { // writeBlockWithState writes block, metadata and corresponding state data to the // database. -func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB) error { +func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) error { // Calculate the total difficulty of the block ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1) if ptd == nil { @@ -1339,7 +1339,7 @@ func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types // writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead. // This function expects the chain mutex to be held. func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { - if err := bc.writeBlockWithState(block, receipts, logs, state); err != nil { + if err := bc.writeBlockWithState(block, receipts, state); err != nil { return NonStatTy, err } currentBlock := bc.CurrentBlock() @@ -1703,7 +1703,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) var status WriteStatus if !setHead { // Don't set the head, only insert the block - err = bc.writeBlockWithState(block, receipts, logs, statedb) + err = bc.writeBlockWithState(block, receipts, statedb) } else { status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) } diff --git a/core/state/database.go b/core/state/database.go index ce5d8d731715..8f662ecd3dab 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -88,9 +88,13 @@ type Trie interface { // can be used even if the trie doesn't have one. Hash() common.Hash - // Commit writes all nodes to the trie's memory database, tracking the internal - // and external (for account tries) references. - Commit(onleaf trie.LeafCallback) (common.Hash, int, error) + // 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 + Commit(collectLeaf bool) (common.Hash, *trie.NodeSet, error) // NodeIterator returns an iterator that returns nodes of the trie. Iteration // starts at the key after the given start key. diff --git a/core/state/metrics.go b/core/state/metrics.go index 7b40ff37aff0..35d2df92dda4 100644 --- a/core/state/metrics.go +++ b/core/state/metrics.go @@ -19,10 +19,10 @@ package state import "github.com/ethereum/go-ethereum/metrics" var ( - accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) - storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) - accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) - storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil) - accountCommittedMeter = metrics.NewRegisteredMeter("state/commit/account", nil) - storageCommittedMeter = metrics.NewRegisteredMeter("state/commit/storage", nil) + accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) + storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) + accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) + storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil) + accountTrieCommittedMeter = metrics.NewRegisteredMeter("state/commit/accountnodes", nil) + storageTriesCommittedMeter = metrics.NewRegisteredMeter("state/commit/storagenodes", nil) ) diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 36055856e1c7..bf714db4c2d0 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -367,7 +367,10 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, owner common.Hash, roo for i, key := range result.keys { snapTrie.Update(key, result.vals[i]) } - root, _, _ := snapTrie.Commit(nil) + root, nodes, _ := snapTrie.Commit(false) + if nodes != nil { + snapTrieDb.Update(trie.NewWithNodeSet(nodes)) + } snapTrieDb.Commit(root, false, nil) } // Construct the trie for state iteration, reuse the trie diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index fe81993e9d2f..8d89ca59a3c3 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -143,6 +143,7 @@ type testHelper struct { diskdb ethdb.Database triedb *trie.Database accTrie *trie.SecureTrie + nodes *trie.MergedNodeSet } func newHelper() *testHelper { @@ -153,6 +154,7 @@ func newHelper() *testHelper { diskdb: diskdb, triedb: triedb, accTrie: accTrie, + nodes: trie.NewMergedNodeSet(), } } @@ -184,17 +186,22 @@ func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string for i, k := range keys { stTrie.Update([]byte(k), []byte(vals[i])) } - var root common.Hash if !commit { - root = stTrie.Hash() - } else { - root, _, _ = stTrie.Commit(nil) + return stTrie.Hash().Bytes() + } + root, nodes, _ := stTrie.Commit(false) + if nodes != nil { + t.nodes.Merge(nodes) } return root.Bytes() } func (t *testHelper) Commit() common.Hash { - root, _, _ := t.accTrie.Commit(nil) + root, nodes, _ := t.accTrie.Commit(true) + if nodes != nil { + t.nodes.Merge(nodes) + } + t.triedb.Update(t.nodes) t.triedb.Commit(root, false, nil) return root } @@ -378,7 +385,7 @@ func TestGenerateCorruptAccountTrie(t *testing.T) { helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 - root, _, _ := helper.accTrie.Commit(nil) // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 + root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 // Delete an account trie leaf and ensure the generator chokes helper.triedb.Commit(root, false, nil) @@ -413,18 +420,8 @@ func TestGenerateMissingStorageTrie(t *testing.T) { helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 - root, _, _ := helper.accTrie.Commit(nil) - - // We can only corrupt the disk database, so flush the tries out - helper.triedb.Reference( - common.BytesToHash(stRoot), - common.HexToHash("0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e"), - ) - helper.triedb.Reference( - common.BytesToHash(stRoot), - common.HexToHash("0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2"), - ) - helper.triedb.Commit(root, false, nil) + + root := helper.Commit() // Delete a storage trie root and ensure the generator chokes helper.diskdb.Delete(stRoot) @@ -458,18 +455,7 @@ func TestGenerateCorruptStorageTrie(t *testing.T) { stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 - root, _, _ := helper.accTrie.Commit(nil) - - // We can only corrupt the disk database, so flush the tries out - helper.triedb.Reference( - common.BytesToHash(stRoot), - common.HexToHash("0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e"), - ) - helper.triedb.Reference( - common.BytesToHash(stRoot), - common.HexToHash("0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2"), - ) - helper.triedb.Commit(root, false, nil) + root := helper.Commit() // Delete a storage trie leaf and ensure the generator chokes helper.diskdb.Delete(common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371").Bytes()) @@ -825,10 +811,12 @@ func populateDangling(disk ethdb.KeyValueStore) { // This test will populate some dangling storages to see if they can be cleaned up. func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { var helper = newHelper() - stRoot := helper.makeStorageTrie(common.Hash{}, common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) + + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) @@ -858,10 +846,12 @@ func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { // This test will populate some dangling storages to see if they can be cleaned up. func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) { var helper = newHelper() - stRoot := helper.makeStorageTrie(common.Hash{}, common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) + stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) + + helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) populateDangling(helper.diskdb) diff --git a/core/state/state_object.go b/core/state/state_object.go index bc1ca1f40eaf..a23df895458c 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" ) var emptyCodeHash = crypto.Keccak256(nil) @@ -375,23 +376,23 @@ func (s *stateObject) updateRoot(db Database) { // CommitTrie the storage trie of the object to db. // This updates the trie root. -func (s *stateObject) CommitTrie(db Database) (int, error) { +func (s *stateObject) CommitTrie(db Database) (*trie.NodeSet, error) { // If nothing changed, don't bother with hashing anything if s.updateTrie(db) == nil { - return 0, nil + return nil, nil } if s.dbErr != nil { - return 0, s.dbErr + return nil, s.dbErr } // Track the amount of time wasted on committing the storage trie if metrics.EnabledExpensive { defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) } - root, committed, err := s.trie.Commit(nil) + root, nodes, err := s.trie.Commit(false) if err == nil { s.data.Root = root } - return committed, err + return nodes, err } // AddBalance adds amount to s's balance. diff --git a/core/state/statedb.go b/core/state/statedb.go index e945ab595013..322bc540b7a2 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -774,7 +774,7 @@ func (s *StateDB) GetRefund() uint64 { return s.refund } -// Finalise finalises the state by removing the s destructed objects and clears +// Finalise finalises the state by removing the destructed objects and clears // the journal as well as the refunds. Finalise, however, will not push any updates // into the tries just yet. Only IntermediateRoot or Commit will do that. func (s *StateDB) Finalise(deleteEmptyObjects bool) { @@ -844,7 +844,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // Although naively it makes sense to retrieve the account trie and then do // the contract storage and account updates sequentially, that short circuits // the account prefetcher. Instead, let's process all the storage updates - // first, giving the account prefeches just a few more milliseconds of time + // first, giving the account prefetches just a few more milliseconds of time // to pull useful data from disk. for addr := range s.stateObjectsPending { if obj := s.stateObjects[addr]; !obj.deleted { @@ -907,7 +907,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { s.IntermediateRoot(deleteEmptyObjects) // Commit objects to the trie, measuring the elapsed time - var storageCommitted int + var ( + accountTrieNodes int + storageTrieNodes int + nodes = trie.NewMergedNodeSet() + ) codeWriter := s.db.TrieDB().DiskDB().NewBatch() for addr := range s.stateObjectsDirty { if obj := s.stateObjects[addr]; !obj.deleted { @@ -917,11 +921,17 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { obj.dirtyCode = false } // Write any storage changes in the state object to its storage trie - committed, err := obj.CommitTrie(s.db) + set, err := obj.CommitTrie(s.db) if err != nil { return common.Hash{}, err } - storageCommitted += committed + // Merge the dirty nodes of storage trie into global set + if set != nil { + if err := nodes.Merge(set); err != nil { + return common.Hash{}, err + } + storageTrieNodes += set.Len() + } } } if len(s.stateObjectsDirty) > 0 { @@ -937,21 +947,17 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if metrics.EnabledExpensive { start = time.Now() } - // The onleaf func is called _serially_, so we can reuse the same account - // for unmarshalling every time. - var account types.StateAccount - root, accountCommitted, err := s.trie.Commit(func(_ [][]byte, _ []byte, leaf []byte, parent common.Hash, _ []byte) error { - if err := rlp.DecodeBytes(leaf, &account); err != nil { - return nil - } - if account.Root != emptyRoot { - s.db.TrieDB().Reference(account.Root, parent) - } - return nil - }) + root, set, err := s.trie.Commit(true) if err != nil { return common.Hash{}, err } + // Merge the dirty nodes of account trie into global set + if set != nil { + if err := nodes.Merge(set); err != nil { + return common.Hash{}, err + } + accountTrieNodes = set.Len() + } if metrics.EnabledExpensive { s.AccountCommits += time.Since(start) @@ -959,8 +965,8 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { storageUpdatedMeter.Mark(int64(s.StorageUpdated)) accountDeletedMeter.Mark(int64(s.AccountDeleted)) storageDeletedMeter.Mark(int64(s.StorageDeleted)) - accountCommittedMeter.Mark(int64(accountCommitted)) - storageCommittedMeter.Mark(int64(storageCommitted)) + accountTrieCommittedMeter.Mark(int64(accountTrieNodes)) + storageTriesCommittedMeter.Mark(int64(storageTrieNodes)) s.AccountUpdated, s.AccountDeleted = 0, 0 s.StorageUpdated, s.StorageDeleted = 0, 0 } @@ -984,6 +990,9 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { } s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil } + if err := s.db.TrieDB().Update(nodes); err != nil { + return common.Hash{}, err + } s.originalRoot = root return root, err } diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 85e4dc5e4f83..a13e8d308966 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1348,9 +1348,11 @@ func getCodeByHash(hash common.Hash) []byte { // makeAccountTrieNoStorage spits out a trie, along with the leafs func makeAccountTrieNoStorage(n int) (*trie.Trie, entrySlice) { - db := trie.NewDatabase(rawdb.NewMemoryDatabase()) - accTrie := trie.NewEmpty(db) - var entries entrySlice + var ( + db = trie.NewDatabase(rawdb.NewMemoryDatabase()) + accTrie = trie.NewEmpty(db) + entries entrySlice + ) for i := uint64(1); i <= uint64(n); i++ { value, _ := rlp.EncodeToBytes(&types.StateAccount{ Nonce: i, @@ -1364,7 +1366,13 @@ func makeAccountTrieNoStorage(n int) (*trie.Trie, entrySlice) { entries = append(entries, elem) } sort.Sort(entries) - accTrie.Commit(nil) + + // Commit the state changes into db and re-create the trie + // for accessing later. + root, nodes, _ := accTrie.Commit(false) + db.Update(trie.NewWithNodeSet(nodes)) + + accTrie, _ = trie.New(common.Hash{}, root, db) return accTrie, entries } @@ -1376,8 +1384,8 @@ func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) { entries entrySlice boundaries []common.Hash - db = trie.NewDatabase(rawdb.NewMemoryDatabase()) - trie = trie.NewEmpty(db) + db = trie.NewDatabase(rawdb.NewMemoryDatabase()) + accTrie = trie.NewEmpty(db) ) // Initialize boundaries var next common.Hash @@ -1404,7 +1412,7 @@ func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) { CodeHash: getCodeHash(uint64(i)), }) elem := &kv{boundaries[i].Bytes(), value} - trie.Update(elem.k, elem.v) + accTrie.Update(elem.k, elem.v) entries = append(entries, elem) } // Fill other accounts if required @@ -1416,12 +1424,18 @@ func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) { CodeHash: getCodeHash(i), }) elem := &kv{key32(i), value} - trie.Update(elem.k, elem.v) + accTrie.Update(elem.k, elem.v) entries = append(entries, elem) } sort.Sort(entries) - trie.Commit(nil) - return trie, entries + + // Commit the state changes into db and re-create the trie + // for accessing later. + root, nodes, _ := accTrie.Commit(false) + db.Update(trie.NewWithNodeSet(nodes)) + + accTrie, _ = trie.New(common.Hash{}, root, db) + return accTrie, entries } // makeAccountTrieWithStorageWithUniqueStorage creates an account trie where each accounts @@ -1431,8 +1445,10 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) entries entrySlice + storageRoots = make(map[common.Hash]common.Hash) storageTries = make(map[common.Hash]*trie.Trie) storageEntries = make(map[common.Hash]entrySlice) + nodes = trie.NewMergedNodeSet() ) // Create n accounts in the trie for i := uint64(1); i <= uint64(accounts); i++ { @@ -1442,9 +1458,9 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) codehash = getCodeHash(i) } // Create a storage trie - stTrie, stEntries := makeStorageTrieWithSeed(common.BytesToHash(key), uint64(slots), i, db) - stRoot := stTrie.Hash() - stTrie.Commit(nil) + stRoot, stNodes, stEntries := makeStorageTrieWithSeed(common.BytesToHash(key), uint64(slots), i, db) + nodes.Merge(stNodes) + value, _ := rlp.EncodeToBytes(&types.StateAccount{ Nonce: i, Balance: big.NewInt(int64(i)), @@ -1455,12 +1471,25 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) accTrie.Update(elem.k, elem.v) entries = append(entries, elem) - storageTries[common.BytesToHash(key)] = stTrie + storageRoots[common.BytesToHash(key)] = stRoot storageEntries[common.BytesToHash(key)] = stEntries } sort.Sort(entries) - accTrie.Commit(nil) + // Commit account trie + root, set, _ := accTrie.Commit(true) + nodes.Merge(set) + + // Commit gathered dirty nodes into database + db.Update(nodes) + + // Re-create tries with new root + accTrie, _ = trie.New(common.Hash{}, root, db) + for i := uint64(1); i <= uint64(accounts); i++ { + key := key32(i) + trie, _ := trie.New(common.BytesToHash(key), storageRoots[common.BytesToHash(key)], db) + storageTries[common.BytesToHash(key)] = trie + } return accTrie, entries, storageTries, storageEntries } @@ -1470,8 +1499,10 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) entries entrySlice + storageRoots = make(map[common.Hash]common.Hash) storageTries = make(map[common.Hash]*trie.Trie) storageEntries = make(map[common.Hash]entrySlice) + nodes = trie.NewMergedNodeSet() ) // Create n accounts in the trie for i := uint64(1); i <= uint64(accounts); i++ { @@ -1482,16 +1513,16 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie } // Make a storage trie var ( - stTrie *trie.Trie + stRoot common.Hash + stNodes *trie.NodeSet stEntries entrySlice ) if boundary { - stTrie, stEntries = makeBoundaryStorageTrie(common.BytesToHash(key), slots, db) + stRoot, stNodes, stEntries = makeBoundaryStorageTrie(common.BytesToHash(key), slots, db) } else { - stTrie, stEntries = makeStorageTrieWithSeed(common.BytesToHash(key), uint64(slots), 0, db) + stRoot, stNodes, stEntries = makeStorageTrieWithSeed(common.BytesToHash(key), uint64(slots), 0, db) } - stRoot := stTrie.Hash() - stTrie.Commit(nil) + nodes.Merge(stNodes) value, _ := rlp.EncodeToBytes(&types.StateAccount{ Nonce: i, @@ -1502,19 +1533,40 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie elem := &kv{key, value} accTrie.Update(elem.k, elem.v) entries = append(entries, elem) + // we reuse the same one for all accounts - storageTries[common.BytesToHash(key)] = stTrie + storageRoots[common.BytesToHash(key)] = stRoot storageEntries[common.BytesToHash(key)] = stEntries } sort.Sort(entries) - accTrie.Commit(nil) + + // Commit account trie + root, set, _ := accTrie.Commit(true) + nodes.Merge(set) + + // Commit gathered dirty nodes into database + db.Update(nodes) + + // Re-create tries with new root + accTrie, err := trie.New(common.Hash{}, root, db) + if err != nil { + panic(err) + } + for i := uint64(1); i <= uint64(accounts); i++ { + key := key32(i) + trie, err := trie.New(common.BytesToHash(key), storageRoots[common.BytesToHash(key)], db) + if err != nil { + panic(err) + } + storageTries[common.BytesToHash(key)] = trie + } return accTrie, entries, storageTries, storageEntries } // makeStorageTrieWithSeed fills a storage trie with n items, returning the // not-yet-committed trie and the sorted entries. The seeds can be used to ensure // that tries are unique. -func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (*trie.Trie, entrySlice) { +func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trie.NodeSet, entrySlice) { trie, _ := trie.New(owner, common.Hash{}, db) var entries entrySlice for i := uint64(1); i <= n; i++ { @@ -1530,14 +1582,14 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas entries = append(entries, elem) } sort.Sort(entries) - trie.Commit(nil) - return trie, entries + root, nodes, _ := trie.Commit(false) + return root, nodes, entries } // makeBoundaryStorageTrie constructs a storage trie. Instead of filling // storage slots normally, this function will fill a few slots which have // boundary hash. -func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (*trie.Trie, entrySlice) { +func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (common.Hash, *trie.NodeSet, entrySlice) { var ( entries entrySlice boundaries []common.Hash @@ -1581,8 +1633,8 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (*trie entries = append(entries, elem) } sort.Sort(entries) - trie.Commit(nil) - return trie, entries + root, nodes, _ := trie.Commit(false) + return root, nodes, entries } func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { diff --git a/light/postprocess.go b/light/postprocess.go index c09b00e71c81..0e50dab96717 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -217,7 +217,18 @@ func (c *ChtIndexerBackend) Process(ctx context.Context, header *types.Header) e // Commit implements core.ChainIndexerBackend func (c *ChtIndexerBackend) Commit() error { - root, _, err := c.trie.Commit(nil) + root, nodes, err := c.trie.Commit(false) + if err != nil { + return err + } + // Commit trie changes into trie database in case it's not nil. + if nodes != nil { + if err := c.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { + return err + } + } + // Re-create trie with newly generated root and updated database. + c.trie, err = trie.New(common.Hash{}, root, c.triedb) if err != nil { return err } @@ -453,7 +464,18 @@ func (b *BloomTrieIndexerBackend) Commit() error { b.trie.Delete(encKey[:]) } } - root, _, err := b.trie.Commit(nil) + root, nodes, err := b.trie.Commit(false) + if err != nil { + return err + } + // Commit trie changes into trie database in case it's not nil. + if nodes != nil { + if err := b.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { + return err + } + } + // Re-create trie with newly generated root and updated database. + b.trie, err = trie.New(common.Hash{}, root, b.triedb) if err != nil { return err } diff --git a/light/trie.go b/light/trie.go index 931ba30cb40a..a2ef8ebff3d3 100644 --- a/light/trie.go +++ b/light/trie.go @@ -137,11 +137,11 @@ func (t *odrTrie) TryDelete(key []byte) error { }) } -func (t *odrTrie) Commit(onleaf trie.LeafCallback) (common.Hash, int, error) { +func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trie.NodeSet, error) { if t.trie == nil { - return t.id.Root, 0, nil + return t.id.Root, nil, nil } - return t.trie.Commit(onleaf) + return t.trie.Commit(collectLeaf) } func (t *odrTrie) Hash() common.Hash { diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 17d67a8758c2..e6165df08c15 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -173,10 +173,13 @@ func (f *fuzzer) fuzz() int { return 0 } // Flush trie -> database - rootA, _, err := trieA.Commit(nil) + rootA, nodes, err := trieA.Commit(false) if err != nil { panic(err) } + if nodes != nil { + dbA.Update(trie.NewWithNodeSet(nodes)) + } // Flush memdb -> disk (sponge) dbA.Commit(rootA, false, nil) diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index ca1509085b12..f36b613d4786 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -51,9 +51,8 @@ const ( opUpdate = iota opDelete opGet - opCommit opHash - opReset + opCommit opItercheckhash opProve opMax // boundary value, not an actual op @@ -157,15 +156,18 @@ func runRandTest(rt randTest) error { if string(v) != want { rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) } - case opCommit: - _, _, rt[i].err = tr.Commit(nil) case opHash: tr.Hash() - case opReset: - hash, _, err := tr.Commit(nil) + case opCommit: + hash, nodes, err := tr.Commit(false) if err != nil { return err } + if nodes != nil { + if err := triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { + return err + } + } newtr, err := trie.New(common.Hash{}, hash, triedb) if err != nil { return err diff --git a/trie/committer.go b/trie/committer.go index 7a392abab7f4..d9f0ecf3dea4 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -17,72 +17,48 @@ package trie import ( - "errors" "fmt" - "sync" "github.com/ethereum/go-ethereum/common" ) -// leafChanSize is the size of the leafCh. It's a pretty arbitrary number, to allow -// some parallelism but not incur too much memory overhead. -const leafChanSize = 200 - -// leaf represents a trie leaf value +// leaf represents a trie leaf node type leaf struct { - size int // size of the rlp data (estimate) - hash common.Hash // hash of rlp data - node node // the node to commit - path []byte // the path from the root node + blob []byte // raw blob of leaf + parent common.Hash // the hash of parent node } -// committer is a type used for the trie Commit operation. A committer has some -// internal preallocated temp space, and also a callback that is invoked when -// leaves are committed. The leafs are passed through the `leafCh`, to allow -// some level of parallelism. -// By 'some level' of parallelism, it's still the case that all leaves will be -// processed sequentially - onleaf will never be called in parallel or out of order. +// committer is the tool used for the trie Commit operation. The committer will +// capture all dirty nodes during the commit process and keep them cached in +// insertion order. type committer struct { - onleaf LeafCallback - leafCh chan *leaf -} - -// committers live in a global sync.Pool -var committerPool = sync.Pool{ - New: func() interface{} { - return &committer{} - }, + nodes *NodeSet + collectLeaf bool } // newCommitter creates a new committer or picks one from the pool. -func newCommitter() *committer { - return committerPool.Get().(*committer) -} - -func returnCommitterToPool(h *committer) { - h.onleaf = nil - h.leafCh = nil - committerPool.Put(h) +func newCommitter(owner common.Hash, collectLeaf bool) *committer { + return &committer{ + nodes: NewNodeSet(owner), + collectLeaf: collectLeaf, + } } // Commit collapses a node down into a hash node and inserts it into the database -func (c *committer) Commit(n node, db *Database) (hashNode, int, error) { - if db == nil { - return nil, 0, errors.New("no db provided") - } - h, committed, err := c.commit(nil, n, db) +func (c *committer) Commit(n node) (hashNode, *NodeSet, error) { + h, err := c.commit(nil, n) if err != nil { - return nil, 0, err + return nil, nil, err } - return h.(hashNode), committed, nil + return h.(hashNode), c.nodes, nil } // commit collapses a node down into a hash node and inserts it into the database -func (c *committer) commit(path []byte, n node, db *Database) (node, int, error) { +func (c *committer) commit(path []byte, n node) (node, error) { // if this path is clean, use available cached data hash, dirty := n.cache() if hash != nil && !dirty { - return hash, 0, nil + return hash, nil } // Commit children, then parent, and remove the dirty flag. switch cn := n.(type) { @@ -92,36 +68,35 @@ func (c *committer) commit(path []byte, n node, db *Database) (node, int, error) // If the child is fullNode, recursively commit, // otherwise it can only be hashNode or valueNode. - var childCommitted int if _, ok := cn.Val.(*fullNode); ok { - childV, committed, err := c.commit(append(path, cn.Key...), cn.Val, db) + childV, err := c.commit(append(path, cn.Key...), cn.Val) if err != nil { - return nil, 0, err + return nil, err } - collapsed.Val, childCommitted = childV, committed + collapsed.Val = childV } // The key needs to be copied, since we're delivering it to database collapsed.Key = hexToCompact(cn.Key) - hashedNode := c.store(path, collapsed, db) + hashedNode := c.store(path, collapsed) if hn, ok := hashedNode.(hashNode); ok { - return hn, childCommitted + 1, nil + return hn, nil } - return collapsed, childCommitted, nil + return collapsed, nil case *fullNode: - hashedKids, childCommitted, err := c.commitChildren(path, cn, db) + hashedKids, err := c.commitChildren(path, cn) if err != nil { - return nil, 0, err + return nil, err } collapsed := cn.copy() collapsed.Children = hashedKids - hashedNode := c.store(path, collapsed, db) + hashedNode := c.store(path, collapsed) if hn, ok := hashedNode.(hashNode); ok { - return hn, childCommitted + 1, nil + return hn, nil } - return collapsed, childCommitted, nil + return collapsed, nil case hashNode: - return cn, 0, nil + return cn, nil default: // nil, valuenode shouldn't be committed panic(fmt.Sprintf("%T: invalid node: %v", n, n)) @@ -129,11 +104,8 @@ func (c *committer) commit(path []byte, n node, db *Database) (node, int, error) } // commitChildren commits the children of the given fullnode -func (c *committer) commitChildren(path []byte, n *fullNode, db *Database) ([17]node, int, error) { - var ( - committed int - children [17]node - ) +func (c *committer) commitChildren(path []byte, n *fullNode) ([17]node, error) { + var children [17]node for i := 0; i < 16; i++ { child := n.Children[i] if child == nil { @@ -149,88 +121,63 @@ func (c *committer) commitChildren(path []byte, n *fullNode, db *Database) ([17] // Commit the child recursively and store the "hashed" value. // Note the returned node can be some embedded nodes, so it's // possible the type is not hashNode. - hashed, childCommitted, err := c.commit(append(path, byte(i)), child, db) + hashed, err := c.commit(append(path, byte(i)), child) if err != nil { - return children, 0, err + return children, err } children[i] = hashed - committed += childCommitted } // For the 17th child, it's possible the type is valuenode. if n.Children[16] != nil { children[16] = n.Children[16] } - return children, committed, nil + return children, nil } // store hashes the node n and if we have a storage layer specified, it writes // the key/value pair to it and tracks any node->child references as well as any // node->external trie references. -func (c *committer) store(path []byte, n node, db *Database) node { +func (c *committer) store(path []byte, n node) node { // Larger nodes are replaced by their hash and stored in the database. - var ( - hash, _ = n.cache() - size int - ) + var hash, _ = n.cache() + + // This was not generated - must be a small node stored in the parent. + // In theory, we should check if the node is leaf here (embedded node + // usually is leaf node). But small value(less than 32bytes) is not + // our target(leaves in account trie only). if hash == nil { - // This was not generated - must be a small node stored in the parent. - // In theory, we should apply the leafCall here if it's not nil(embedded - // node usually contains value). But small value(less than 32bytes) is - // not our target. return n - } else { - // We have the hash already, estimate the RLP encoding-size of the node. - // The size is used for mem tracking, does not need to be exact - size = estimateSize(n) } - // If we're using channel-based leaf-reporting, send to channel. - // The leaf channel will be active only when there an active leaf-callback - if c.leafCh != nil { - c.leafCh <- &leaf{ - size: size, - hash: common.BytesToHash(hash), - node: n, - path: path, + // We have the hash already, estimate the RLP encoding-size of the node. + // The size is used for mem tracking, does not need to be exact + var ( + size = estimateSize(n) + nhash = common.BytesToHash(hash) + mnode = &memoryNode{ + hash: nhash, + node: simplifyNode(n), + size: uint16(size), } - } else if db != nil { - // No leaf-callback used, but there's still a database. Do serial - // insertion - db.insert(common.BytesToHash(hash), size, n) - } - return hash -} - -// commitLoop does the actual insert + leaf callback for nodes. -func (c *committer) commitLoop(db *Database) { - for item := range c.leafCh { - var ( - hash = item.hash - size = item.size - n = item.node - ) - // We are pooling the trie nodes into an intermediate memory cache - db.insert(hash, size, n) - - if c.onleaf != nil { - switch n := n.(type) { - case *shortNode: - if child, ok := n.Val.(valueNode); ok { - c.onleaf(nil, nil, child, hash, nil) - } - case *fullNode: - // For children in range [0, 15], it's impossible - // to contain valueNode. Only check the 17th child. - if n.Children[16] != nil { - c.onleaf(nil, nil, n.Children[16].(valueNode), hash, nil) - } + ) + // Collect the dirty node to nodeset for return. + c.nodes.add(string(path), mnode) + + // 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 + // length of leaves should be exactly same. + if c.collectLeaf { + if sn, ok := n.(*shortNode); ok { + if val, ok := sn.Val.(valueNode); ok { + c.nodes.addLeaf(&leaf{blob: val, parent: nhash}) } } } + return hash } // estimateSize estimates the size of an rlp-encoded node, without actually // rlp-encoding it (zero allocs). This method has been experimentally tried, and with a trie -// with 1000 leafs, the only errors above 1% are on small shortnodes, where this +// with 1000 leaves, the only errors above 1% are on small shortnodes, where this // method overestimates by 2 or 3 bytes (e.g. 37 instead of 35) func estimateSize(n node) int { switch n := n.(type) { diff --git a/trie/database.go b/trie/database.go index 8e1788a21239..81f0477aeb86 100644 --- a/trie/database.go +++ b/trie/database.go @@ -28,6 +28,7 @@ import ( "github.com/VictoriaMetrics/fastcache" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -305,14 +306,10 @@ func (db *Database) DiskDB() ethdb.KeyValueStore { return db.diskdb } -// insert inserts a collapsed trie node into the memory database. -// The blob size must be specified to allow proper size tracking. +// insert inserts a simplified trie node into the memory database. // All nodes inserted by this function will be reference tracked // and in theory should only used for **trie nodes** insertion. func (db *Database) insert(hash common.Hash, size int, node node) { - db.lock.Lock() - defer db.lock.Unlock() - // If the node's already cached, skip if _, ok := db.dirties[hash]; ok { return @@ -321,7 +318,7 @@ func (db *Database) insert(hash common.Hash, size int, node node) { // Create the cached entry for this node entry := &cachedNode{ - node: simplifyNode(node), + node: node, size: uint16(size), flushPrev: db.newest, } @@ -763,6 +760,41 @@ func (c *cleaner) Delete(key []byte) error { panic("not implemented") } +// Update inserts the dirty nodes in provided nodeset into database and +// link the account trie with multiple storage tries if necessary. +func (db *Database) Update(nodes *MergedNodeSet) error { + db.lock.Lock() + defer db.lock.Unlock() + + // Insert dirty nodes into the database. In the same tree, it must be + // ensured that children are inserted first, then parent so that children + // can be linked with their parent correctly. The order of writing between + // different tries(account trie, storage tries) is not required. + for owner, subset := range nodes.sets { + for _, path := range subset.paths { + n, ok := subset.nodes[path] + if !ok { + return fmt.Errorf("missing node %x %v", owner, path) + } + db.insert(n.hash, int(n.size), n.node) + } + } + // Link up the account trie and storage trie if the node points + // to an account trie leaf. + if set, present := nodes.sets[common.Hash{}]; present { + for _, n := range set.leaves { + var account types.StateAccount + if err := rlp.DecodeBytes(n.blob, &account); err != nil { + return err + } + if account.Root != emptyRoot { + db.reference(account.Root, n.parent) + } + } + } + return nil +} + // Size returns the current storage size of the memory cache in front of the // persistent database layer. func (db *Database) Size() (common.StorageSize, common.StorageSize) { diff --git a/trie/iterator.go b/trie/iterator.go index e0006ee05e3b..1e76625c6213 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -375,8 +375,7 @@ func (it *nodeIterator) resolveHash(hash hashNode, path []byte) (node, error) { } } } - resolved, err := it.trie.resolveHash(hash, path) - return resolved, err + return it.trie.resolveHash(hash, path) } func (it *nodeIterator) resolveBlob(hash hashNode, path []byte) ([]byte, error) { diff --git a/trie/iterator_test.go b/trie/iterator_test.go index e3e6d0e3a8fa..0a4c04c8b346 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -31,7 +31,7 @@ import ( ) func TestEmptyIterator(t *testing.T) { - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) iter := trie.NodeIterator(nil) seen := make(map[string]struct{}) @@ -44,7 +44,8 @@ func TestEmptyIterator(t *testing.T) { } func TestIterator(t *testing.T) { - trie := newEmpty() + db := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(db) vals := []struct{ k, v string }{ {"do", "verb"}, {"ether", "wookiedoo"}, @@ -59,8 +60,13 @@ func TestIterator(t *testing.T) { all[val.k] = val.v trie.Update([]byte(val.k), []byte(val.v)) } - trie.Commit(nil) + root, nodes, err := trie.Commit(false) + if err != nil { + t.Fatalf("Failed to commit trie %v", err) + } + db.Update(NewWithNodeSet(nodes)) + trie, _ = New(common.Hash{}, root, db) found := make(map[string]string) it := NewIterator(trie.NodeIterator(nil)) for it.Next() { @@ -80,7 +86,7 @@ type kv struct { } func TestIteratorLargeData(t *testing.T) { - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := make(map[string]*kv) for i := byte(0); i < 255; i++ { @@ -173,7 +179,7 @@ var testdata2 = []kvs{ } func TestIteratorSeek(t *testing.T) { - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range testdata1 { trie.Update([]byte(val.k), []byte(val.v)) } @@ -214,17 +220,23 @@ func checkIteratorOrder(want []kvs, it *Iterator) error { } func TestDifferenceIterator(t *testing.T) { - triea := newEmpty() + dba := NewDatabase(rawdb.NewMemoryDatabase()) + triea := NewEmpty(dba) for _, val := range testdata1 { triea.Update([]byte(val.k), []byte(val.v)) } - triea.Commit(nil) + rootA, nodesA, _ := triea.Commit(false) + dba.Update(NewWithNodeSet(nodesA)) + triea, _ = New(common.Hash{}, rootA, dba) - trieb := newEmpty() + dbb := NewDatabase(rawdb.NewMemoryDatabase()) + trieb := NewEmpty(dbb) for _, val := range testdata2 { trieb.Update([]byte(val.k), []byte(val.v)) } - trieb.Commit(nil) + rootB, nodesB, _ := trieb.Commit(false) + dbb.Update(NewWithNodeSet(nodesB)) + trieb, _ = New(common.Hash{}, rootB, dbb) found := make(map[string]string) di, _ := NewDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil)) @@ -250,17 +262,23 @@ func TestDifferenceIterator(t *testing.T) { } func TestUnionIterator(t *testing.T) { - triea := newEmpty() + dba := NewDatabase(rawdb.NewMemoryDatabase()) + triea := NewEmpty(dba) for _, val := range testdata1 { triea.Update([]byte(val.k), []byte(val.v)) } - triea.Commit(nil) + rootA, nodesA, _ := triea.Commit(false) + dba.Update(NewWithNodeSet(nodesA)) + triea, _ = New(common.Hash{}, rootA, dba) - trieb := newEmpty() + dbb := NewDatabase(rawdb.NewMemoryDatabase()) + trieb := NewEmpty(dbb) for _, val := range testdata2 { trieb.Update([]byte(val.k), []byte(val.v)) } - trieb.Commit(nil) + rootB, nodesB, _ := trieb.Commit(false) + dbb.Update(NewWithNodeSet(nodesB)) + trieb, _ = New(common.Hash{}, rootB, dbb) di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)}) it := NewIterator(di) @@ -316,7 +334,8 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { for _, val := range testdata1 { tr.Update([]byte(val.k), []byte(val.v)) } - tr.Commit(nil) + _, nodes, _ := tr.Commit(false) + triedb.Update(NewWithNodeSet(nodes)) if !memonly { triedb.Commit(tr.Hash(), true, nil) } @@ -407,7 +426,8 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { for _, val := range testdata1 { ctr.Update([]byte(val.k), []byte(val.v)) } - root, _, _ := ctr.Commit(nil) + root, nodes, _ := ctr.Commit(false) + triedb.Update(NewWithNodeSet(nodes)) if !memonly { triedb.Commit(root, true, nil) } @@ -525,7 +545,8 @@ func makeLargeTestTrie() (*Database, *SecureTrie, *loggingDb) { val = crypto.Keccak256(val) trie.Update(key, val) } - trie.Commit(nil) + _, nodes, _ := trie.Commit(false) + triedb.Update(NewWithNodeSet(nodes)) // Return the generated trie return triedb, trie, logDb } @@ -564,7 +585,8 @@ func TestIteratorNodeBlob(t *testing.T) { all[val.k] = val.v trie.Update([]byte(val.k), []byte(val.v)) } - trie.Commit(nil) + _, nodes, _ := trie.Commit(false) + triedb.Update(NewWithNodeSet(nodes)) triedb.Cap(0) found := make(map[common.Hash][]byte) diff --git a/trie/nodeset.go b/trie/nodeset.go new file mode 100644 index 000000000000..08b9b35ebc87 --- /dev/null +++ b/trie/nodeset.go @@ -0,0 +1,94 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package trie + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" +) + +// memoryNode is all the information we know about a single cached trie node +// in the memory. +type memoryNode struct { + hash common.Hash // Node hash, computed by hashing rlp value + size uint16 // Byte size of the useful cached data + node node // Cached collapsed trie node, or raw rlp data +} + +// NodeSet contains all dirty nodes collected during the commit operation. +// Each node is keyed by path. It's not thread-safe to use. +type NodeSet struct { + owner common.Hash // the identifier of the trie + paths []string // the path of dirty nodes, sort by insertion order + nodes map[string]*memoryNode // the map of dirty nodes, keyed by node path + leaves []*leaf // the list of dirty leaves +} + +// NewNodeSet initializes an empty node set to be used for tracking dirty nodes +// from a specific account or storage trie. The owner is zero for the account +// trie and the owning account address hash for storage tries. +func NewNodeSet(owner common.Hash) *NodeSet { + return &NodeSet{ + owner: owner, + nodes: make(map[string]*memoryNode), + } +} + +// add caches node with provided path and node object. +func (set *NodeSet) add(path string, node *memoryNode) { + set.paths = append(set.paths, path) + set.nodes[path] = node +} + +// addLeaf caches the provided leaf node. +func (set *NodeSet) addLeaf(node *leaf) { + set.leaves = append(set.leaves, node) +} + +// Len returns the number of dirty nodes contained in the set. +func (set *NodeSet) Len() int { + return len(set.nodes) +} + +// MergedNodeSet represents a merged dirty node set for a group of tries. +type MergedNodeSet struct { + sets map[common.Hash]*NodeSet +} + +// NewMergedNodeSet initializes an empty merged set. +func NewMergedNodeSet() *MergedNodeSet { + return &MergedNodeSet{sets: make(map[common.Hash]*NodeSet)} +} + +// NewWithNodeSet constructs a merged nodeset with the provided single set. +func NewWithNodeSet(set *NodeSet) *MergedNodeSet { + merged := NewMergedNodeSet() + merged.Merge(set) + return merged +} + +// Merge merges the provided dirty nodes of a trie into the set. The assumption +// is held that no duplicated set belonging to the same trie will be merged twice. +func (set *MergedNodeSet) Merge(other *NodeSet) error { + _, present := set.sets[other.owner] + if present { + return fmt.Errorf("duplicate trie for owner %#x", other.owner) + } + set.sets[other.owner] = other + return nil +} diff --git a/trie/proof.go b/trie/proof.go index 9bf9107562fa..fe3662c51a88 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -22,6 +22,7 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) @@ -35,9 +36,12 @@ import ( // with the node that proves the absence of the key. func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error { // Collect all nodes on the path to key. + var ( + prefix []byte + nodes []node + tn = t.root + ) key = keybytesToHex(key) - var nodes []node - tn := t.root for len(key) > 0 && tn != nil { switch n := tn.(type) { case *shortNode: @@ -46,16 +50,18 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) e tn = nil } else { tn = n.Val + prefix = append(prefix, n.Key...) key = key[len(n.Key):] } nodes = append(nodes, n) case *fullNode: tn = n.Children[key[0]] + prefix = append(prefix, key[0]) key = key[1:] nodes = append(nodes, n) case hashNode: var err error - tn, err = t.resolveHash(n, nil) + tn, err = t.resolveHash(n, prefix) if err != nil { log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) return err @@ -553,7 +559,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key } // Rebuild the trie with the leaf stream, the shape of trie // should be same with the original one. - tr := newWithRootNode(root) + tr := &Trie{root: root, db: NewDatabase(rawdb.NewMemoryDatabase())} if empty { tr.root = nil } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 967194df9628..59772815e294 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -160,12 +160,14 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte { return t.preimages.preimage(common.BytesToHash(shaKey)) } -// Commit writes all nodes and the secure hash pre-images to the trie's database. -// Nodes are stored with their sha3 hash as the key. -// -// Committing flushes nodes from memory. Subsequent Get calls will load nodes -// from the database. -func (t *SecureTrie) Commit(onleaf LeafCallback) (common.Hash, int, error) { +// 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). +// All cached preimages will be also flushed if preimages recording is enabled. +// 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 *SecureTrie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { // Write all the pre-images to the actual disk database if len(t.getSecKeyCache()) > 0 { if t.preimages != nil { @@ -178,7 +180,7 @@ func (t *SecureTrie) Commit(onleaf LeafCallback) (common.Hash, int, error) { t.secKeyCache = make(map[string][]byte) } // Commit the trie to its intermediate node database - return t.trie.Commit(onleaf) + return t.trie.Commit(collectLeaf) } // Hash returns the root hash of SecureTrie. It does not write to the diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index beea5845ad0d..524d1db949f0 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -18,6 +18,7 @@ package trie import ( "bytes" + "fmt" "runtime" "sync" "testing" @@ -57,9 +58,15 @@ func makeTestSecureTrie() (*Database, *SecureTrie, map[string][]byte) { trie.Update(key, val) } } - trie.Commit(nil) - - // Return the generated trie + root, nodes, err := trie.Commit(false) + if err != nil { + panic(fmt.Errorf("failed to commit trie %v", err)) + } + if err := triedb.Update(NewWithNodeSet(nodes)); err != nil { + panic(fmt.Errorf("failed to commit db %v", err)) + } + // Re-create the trie based on the new state + trie, _ = NewSecure(common.Hash{}, root, triedb) return triedb, trie, content } @@ -135,7 +142,7 @@ func TestSecureTrieConcurrency(t *testing.T) { tries[index].Update(key, val) } } - tries[index].Commit(nil) + tries[index].Commit(false) }(i) } // Wait for all threads to finish diff --git a/trie/sync_test.go b/trie/sync_test.go index 472c31a63b9b..c2ddb98c78d9 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -18,6 +18,7 @@ package trie import ( "bytes" + "fmt" "testing" "github.com/ethereum/go-ethereum/common" @@ -50,9 +51,15 @@ func makeTestTrie() (*Database, *SecureTrie, map[string][]byte) { trie.Update(key, val) } } - trie.Commit(nil) - - // Return the generated trie + root, nodes, err := trie.Commit(false) + if err != nil { + panic(fmt.Errorf("failed to commit trie %v", err)) + } + if err := triedb.Update(NewWithNodeSet(nodes)); err != nil { + panic(fmt.Errorf("failed to commit db %v", err)) + } + // Re-create the trie based on the new state + trie, _ = NewSecure(common.Hash{}, root, triedb) return triedb, trie, content } diff --git a/trie/trie.go b/trie/trie.go index 1e168402ad95..08f2480db551 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -21,10 +21,8 @@ import ( "bytes" "errors" "fmt" - "sync" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" @@ -55,23 +53,28 @@ var ( // for extracting the raw states(leaf nodes) with corresponding paths. type LeafCallback func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error -// Trie is a Merkle Patricia Trie. -// The zero value is an empty trie with no database. -// Use New to create a trie that sits on top of a database. +// Trie is a Merkle Patricia Trie. Use New to create a trie that sits on +// top of a database. Whenever trie performs a commit operation, the generated +// nodes will be gathered and returned in a set. Once the trie is committed, +// it's not usable anymore. Callers have to re-create the trie with new root +// based on the updated trie database. // // Trie is not safe for concurrent use. type Trie struct { - db *Database root node owner common.Hash // Keep track of the number leaves which have been inserted since the last // hashing operation. This number will not directly map to the number of - // actually unhashed nodes + // actually unhashed nodes. unhashed int - // tracer is the state diff tracer can be used to track newly added/deleted - // trie node. It will be reset after each commit operation. + // db is the handler trie can retrieve nodes from. It's + // only for reading purpose and not available for writing. + db *Database + + // tracer is the tool to track the trie changes. + // It will be reset after each commit operation. tracer *tracer } @@ -83,10 +86,10 @@ func (t *Trie) newFlag() nodeFlag { // Copy returns a copy of Trie. func (t *Trie) Copy() *Trie { return &Trie{ - db: t.db, root: t.root, owner: t.owner, unhashed: t.unhashed, + db: t.db, tracer: t.tracer.copy(), } } @@ -99,33 +102,9 @@ func (t *Trie) Copy() *Trie { // New will panic if db is nil and returns a MissingNodeError if root does // not exist in the database. Accessing the trie loads nodes from db on demand. func New(owner common.Hash, root common.Hash, db *Database) (*Trie, error) { - return newTrie(owner, root, db) -} - -// NewEmpty is a shortcut to create empty tree. It's mostly used in tests. -func NewEmpty(db *Database) *Trie { - tr, _ := newTrie(common.Hash{}, common.Hash{}, db) - return tr -} - -// newWithRootNode initializes the trie with the given root node. -// It's only used by range prover. -func newWithRootNode(root node) *Trie { - return &Trie{ - root: root, - //tracer: newTracer(), - db: NewDatabase(rawdb.NewMemoryDatabase()), - } -} - -// newTrie is the internal function used to construct the trie with given parameters. -func newTrie(owner common.Hash, root common.Hash, db *Database) (*Trie, error) { - if db == nil { - panic("trie.New called without a database") - } trie := &Trie{ - db: db, owner: owner, + db: db, //tracer: newTracer(), } if root != (common.Hash{}) && root != emptyRoot { @@ -138,6 +117,12 @@ func newTrie(owner common.Hash, root common.Hash, db *Database) (*Trie, error) { return trie, nil } +// NewEmpty is a shortcut to create empty tree. It's mostly used in tests. +func NewEmpty(db *Database) *Trie { + tr, _ := New(common.Hash{}, common.Hash{}, db) + return tr +} + // NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at // the key after the given start key. func (t *Trie) NodeIterator(start []byte) NodeIterator { @@ -512,7 +497,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { // shortNode{..., shortNode{...}}. Since the entry // might not be loaded yet, resolve it just for this // check. - cnode, err := t.resolve(n.Children[pos], prefix) + cnode, err := t.resolve(n.Children[pos], append(prefix, byte(pos))) if err != nil { return false, nil, err } @@ -572,6 +557,8 @@ func (t *Trie) resolve(n node, prefix []byte) (node, error) { return n, nil } +// resolveHash loads node from the underlying database with the provided +// node hash and path prefix. func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) { hash := common.BytesToHash(n) if node := t.db.node(hash); node != nil { @@ -580,6 +567,8 @@ func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) { return nil, &MissingNodeError{Owner: t.owner, NodeHash: hash, Path: prefix} } +// resolveHash loads rlp-encoded node blob from the underlying database +// with the provided node hash and path prefix. func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) { hash := common.BytesToHash(n) blob, _ := t.db.Node(hash) @@ -597,56 +586,37 @@ func (t *Trie) Hash() common.Hash { return common.BytesToHash(hash.(hashNode)) } -// Commit writes all nodes to the trie's memory database, tracking the internal -// and external (for account tries) references. -func (t *Trie) Commit(onleaf LeafCallback) (common.Hash, int, error) { - if t.db == nil { - panic("commit called on trie with nil database") - } +// 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 *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { defer t.tracer.reset() if t.root == nil { - return emptyRoot, 0, nil + return emptyRoot, nil, nil } // Derive the hash for all dirty nodes first. We hold the assumption // in the following procedure that all nodes are hashed. rootHash := t.Hash() - h := newCommitter() - defer returnCommitterToPool(h) - // Do a quick check if we really need to commit, before we spin - // up goroutines. This can happen e.g. if we load a trie for reading storage - // values, but don't write to it. + // Do a quick check if we really need to commit. This can happen e.g. + // if we load a trie for reading storage values, but don't write to it. if hashedNode, dirty := t.root.cache(); !dirty { // Replace the root node with the origin hash in order to // ensure all resolved nodes are dropped after the commit. t.root = hashedNode - return rootHash, 0, nil - } - var wg sync.WaitGroup - if onleaf != nil { - h.onleaf = onleaf - h.leafCh = make(chan *leaf, leafChanSize) - wg.Add(1) - go func() { - defer wg.Done() - h.commitLoop(t.db) - }() - } - newRoot, committed, err := h.Commit(t.root, t.db) - if onleaf != nil { - // The leafch is created in newCommitter if there was an onleaf callback - // provided. The commitLoop only _reads_ from it, and the commit - // operation was the sole writer. Therefore, it's safe to close this - // channel here. - close(h.leafCh) - wg.Wait() + return rootHash, nil, nil } + h := newCommitter(t.owner, collectLeaf) + newRoot, nodes, err := h.Commit(t.root) if err != nil { - return common.Hash{}, 0, err + return common.Hash{}, nil, err } t.root = newRoot - return rootHash, committed, nil + return rootHash, nodes, nil } // hashRoot calculates the root hash of the given trie @@ -667,10 +637,6 @@ func (t *Trie) Reset() { t.root = nil t.owner = common.Hash{} t.unhashed = 0 + //t.db = nil t.tracer.reset() } - -// Owner returns the associated trie owner. -func (t *Trie) Owner() common.Hash { - return t.owner -} diff --git a/trie/trie_test.go b/trie/trie_test.go index 135e94e3d0a3..3e29600bbd12 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -24,7 +24,6 @@ import ( "hash" "math/big" "math/rand" - "os" "reflect" "testing" "testing/quick" @@ -35,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/ethdb/leveldb" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/rlp" "golang.org/x/crypto/sha3" @@ -46,12 +44,6 @@ func init() { spew.Config.DisableMethods = false } -// Used for testing -func newEmpty() *Trie { - trie := NewEmpty(NewDatabase(memorydb.New())) - return trie -} - func TestEmptyTrie(t *testing.T) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) res := trie.Hash() @@ -91,7 +83,8 @@ func testMissingNode(t *testing.T, memonly bool) { trie := NewEmpty(triedb) updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") - root, _, _ := trie.Commit(nil) + root, nodes, _ := trie.Commit(false) + triedb.Update(NewWithNodeSet(nodes)) if !memonly { triedb.Commit(root, true, nil) } @@ -157,7 +150,7 @@ func testMissingNode(t *testing.T, memonly bool) { } func TestInsert(t *testing.T) { - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) updateString(trie, "doe", "reindeer") updateString(trie, "dog", "puppy") @@ -169,11 +162,11 @@ func TestInsert(t *testing.T) { t.Errorf("case 1: exp %x got %x", exp, root) } - trie = newEmpty() + trie = NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") - root, _, err := trie.Commit(nil) + root, _, err := trie.Commit(false) if err != nil { t.Fatalf("commit error: %v", err) } @@ -183,7 +176,8 @@ func TestInsert(t *testing.T) { } func TestGet(t *testing.T) { - trie := newEmpty() + db := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(db) updateString(trie, "doe", "reindeer") updateString(trie, "dog", "puppy") updateString(trie, "dogglesworth", "cat") @@ -193,21 +187,21 @@ func TestGet(t *testing.T) { if !bytes.Equal(res, []byte("puppy")) { t.Errorf("expected puppy got %x", res) } - unknown := getString(trie, "unknown") if unknown != nil { t.Errorf("expected nil got %x", unknown) } - if i == 1 { return } - trie.Commit(nil) + root, nodes, _ := trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) + trie, _ = New(common.Hash{}, root, db) } } func TestDelete(t *testing.T) { - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := []struct{ k, v string }{ {"do", "verb"}, {"ether", "wookiedoo"}, @@ -234,7 +228,7 @@ func TestDelete(t *testing.T) { } func TestEmptyValues(t *testing.T) { - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := []struct{ k, v string }{ {"do", "verb"}, @@ -258,7 +252,8 @@ func TestEmptyValues(t *testing.T) { } func TestReplication(t *testing.T) { - trie := newEmpty() + triedb := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(triedb) vals := []struct{ k, v string }{ {"do", "verb"}, {"ether", "wookiedoo"}, @@ -271,13 +266,14 @@ func TestReplication(t *testing.T) { for _, val := range vals { updateString(trie, val.k, val.v) } - exp, _, err := trie.Commit(nil) + exp, nodes, err := trie.Commit(false) if err != nil { t.Fatalf("commit error: %v", err) } + triedb.Update(NewWithNodeSet(nodes)) // create a new trie on top of the database and check that lookups work. - trie2, err := New(common.Hash{}, exp, trie.db) + trie2, err := New(common.Hash{}, exp, triedb) if err != nil { t.Fatalf("can't recreate trie at %x: %v", exp, err) } @@ -286,7 +282,7 @@ func TestReplication(t *testing.T) { t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) } } - hash, _, err := trie2.Commit(nil) + hash, nodes, err := trie2.Commit(false) if err != nil { t.Fatalf("commit error: %v", err) } @@ -294,6 +290,14 @@ func TestReplication(t *testing.T) { t.Errorf("root failure. expected %x got %x", exp, hash) } + // recreate the trie after commit + if nodes != nil { + triedb.Update(NewWithNodeSet(nodes)) + } + trie2, err = New(common.Hash{}, hash, triedb) + if err != nil { + t.Fatalf("can't recreate trie at %x: %v", exp, err) + } // perform some insertions on the new trie. vals2 := []struct{ k, v string }{ {"do", "verb"}, @@ -315,7 +319,7 @@ func TestReplication(t *testing.T) { } func TestLargeValue(t *testing.T) { - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) trie.Update([]byte("key1"), []byte{99, 99, 99, 99}) trie.Update([]byte("key2"), bytes.Repeat([]byte{1}, 32)) trie.Hash() @@ -369,9 +373,8 @@ const ( opUpdate = iota opDelete opGet - opCommit opHash - opReset + opCommit opItercheckhash opNodeDiff opMax // boundary value, not an actual op @@ -433,17 +436,17 @@ func runRandTest(rt randTest) bool { if string(v) != want { rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) } - case opCommit: - _, _, rt[i].err = tr.Commit(nil) - origTrie = tr.Copy() case opHash: tr.Hash() - case opReset: - hash, _, err := tr.Commit(nil) + case opCommit: + hash, nodes, err := tr.Commit(false) if err != nil { rt[i].err = err return false } + if nodes != nil { + triedb.Update(NewWithNodeSet(nodes)) + } newtr, err := New(common.Hash{}, hash, triedb) if err != nil { rt[i].err = err @@ -533,44 +536,31 @@ func TestRandom(t *testing.T) { } } -func BenchmarkGet(b *testing.B) { benchGet(b, false) } -func BenchmarkGetDB(b *testing.B) { benchGet(b, true) } +func BenchmarkGet(b *testing.B) { benchGet(b) } func BenchmarkUpdateBE(b *testing.B) { benchUpdate(b, binary.BigEndian) } func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) } const benchElemCount = 20000 -func benchGet(b *testing.B, commit bool) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) - if commit { - tmpdb := tempDB(b) - trie = NewEmpty(tmpdb) - } +func benchGet(b *testing.B) { + triedb := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(triedb) k := make([]byte, 32) for i := 0; i < benchElemCount; i++ { binary.LittleEndian.PutUint64(k, uint64(i)) trie.Update(k, k) } binary.LittleEndian.PutUint64(k, benchElemCount/2) - if commit { - trie.Commit(nil) - } b.ResetTimer() for i := 0; i < b.N; i++ { trie.Get(k) } b.StopTimer() - - if commit { - ldb := trie.db.diskdb.(*leveldb.Database) - ldb.Close() - os.RemoveAll(ldb.Path()) - } } func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) k := make([]byte, 32) b.ReportAllocs() for i := 0; i < b.N; i++ { @@ -600,7 +590,7 @@ func BenchmarkHash(b *testing.B) { // entries, then adding N more. addresses, accounts := makeAccounts(2 * b.N) // Insert the accounts into the trie and hash it - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) i := 0 for ; i < len(addresses)/2; i++ { trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) @@ -621,22 +611,17 @@ func BenchmarkHash(b *testing.B) { // insert into the trie before measuring the hashing. func BenchmarkCommitAfterHash(b *testing.B) { b.Run("no-onleaf", func(b *testing.B) { - benchmarkCommitAfterHash(b, nil) + benchmarkCommitAfterHash(b, false) }) - var a types.StateAccount - onleaf := func(paths [][]byte, hexpath []byte, leaf []byte, parent common.Hash, parentPath []byte) error { - rlp.DecodeBytes(leaf, &a) - return nil - } b.Run("with-onleaf", func(b *testing.B) { - benchmarkCommitAfterHash(b, onleaf) + benchmarkCommitAfterHash(b, true) }) } -func benchmarkCommitAfterHash(b *testing.B, onleaf LeafCallback) { +func benchmarkCommitAfterHash(b *testing.B, collectLeaf bool) { // Make the random benchmark deterministic addresses, accounts := makeAccounts(b.N) - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) } @@ -644,13 +629,13 @@ func benchmarkCommitAfterHash(b *testing.B, onleaf LeafCallback) { trie.Hash() b.ResetTimer() b.ReportAllocs() - trie.Commit(onleaf) + trie.Commit(collectLeaf) } func TestTinyTrie(t *testing.T) { // Create a realistic account trie to hash _, accounts := makeAccounts(5) - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001337"), accounts[3]) if exp, root := common.HexToHash("8c6a85a4d9fda98feff88450299e574e5378e32391f75a055d470ac0653f1005"), trie.Hash(); exp != root { t.Errorf("1: got %x, exp %x", root, exp) @@ -663,7 +648,7 @@ func TestTinyTrie(t *testing.T) { if exp, root := common.HexToHash("0608c1d1dc3905fa22204c7a0e43644831c3b6d3def0f274be623a948197e64a"), trie.Hash(); exp != root { t.Errorf("3: got %x, exp %x", root, exp) } - checktr := NewEmpty(trie.db) + checktr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) it := NewIterator(trie.NodeIterator(nil)) for it.Next() { checktr.Update(it.Key, it.Value) @@ -676,19 +661,19 @@ func TestTinyTrie(t *testing.T) { func TestCommitAfterHash(t *testing.T) { // Create a realistic account trie to hash addresses, accounts := makeAccounts(1000) - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Insert the accounts into the trie and hash it trie.Hash() - trie.Commit(nil) + trie.Commit(false) root := trie.Hash() exp := common.HexToHash("72f9d3f3fe1e1dd7b8936442e7642aef76371472d94319900790053c493f3fe6") if exp != root { t.Errorf("got %x, exp %x", root, exp) } - root, _, _ = trie.Commit(nil) + root, _, _ = trie.Commit(false) if exp != root { t.Errorf("got %x, exp %x", root, exp) } @@ -797,7 +782,8 @@ func TestCommitSequence(t *testing.T) { trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Flush trie -> database - root, _, _ := trie.Commit(nil) + root, nodes, _ := trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) db.Commit(root, false, func(c common.Hash) { // And spongify the callback-order @@ -849,7 +835,8 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { trie.Update(key, val) } // Flush trie -> database - root, _, _ := trie.Commit(nil) + root, nodes, _ := trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) db.Commit(root, false, func(c common.Hash) { // And spongify the callback-order @@ -875,7 +862,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} stTrie := NewStackTrie(stackTrieSponge) // Fill the trie with elements - for i := 1; i < count; i++ { + for i := 0; i < count; i++ { // For the stack trie, we need to do inserts in proper order key := make([]byte, 32) binary.BigEndian.PutUint64(key, uint64(i)) @@ -891,8 +878,9 @@ func TestCommitSequenceStackTrie(t *testing.T) { stTrie.TryUpdate(key, val) } // Flush trie -> database - root, _, _ := trie.Commit(nil) + root, nodes, _ := trie.Commit(false) // Flush memdb -> disk (sponge) + db.Update(NewWithNodeSet(nodes)) db.Commit(root, false, nil) // And flush stacktrie -> disk stRoot, err := stTrie.Commit() @@ -936,8 +924,9 @@ func TestCommitSequenceSmallRoot(t *testing.T) { trie.TryUpdate(key, []byte{0x1}) stTrie.TryUpdate(key, []byte{0x1}) // Flush trie -> database - root, _, _ := trie.Commit(nil) + root, nodes, _ := trie.Commit(false) // Flush memdb -> disk (sponge) + db.Update(NewWithNodeSet(nodes)) db.Commit(root, false, nil) // And flush stacktrie -> disk stRoot, err := stTrie.Commit() @@ -999,7 +988,7 @@ func BenchmarkHashFixedSize(b *testing.B) { func benchmarkHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { b.ReportAllocs() - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) } @@ -1050,14 +1039,14 @@ func BenchmarkCommitAfterHashFixedSize(b *testing.B) { func benchmarkCommitAfterHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { b.ReportAllocs() - trie := newEmpty() + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Insert the accounts into the trie and hash it trie.Hash() b.StartTimer() - trie.Commit(nil) + trie.Commit(false) b.StopTimer() } @@ -1102,26 +1091,19 @@ func BenchmarkDerefRootFixedSize(b *testing.B) { func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { b.ReportAllocs() - trie := newEmpty() + triedb := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(triedb) for i := 0; i < len(addresses); i++ { trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) } h := trie.Hash() - trie.Commit(nil) + _, nodes, _ := trie.Commit(false) + triedb.Update(NewWithNodeSet(nodes)) b.StartTimer() - trie.db.Dereference(h) + triedb.Dereference(h) b.StopTimer() } -func tempDB(tb testing.TB) *Database { - dir := tb.TempDir() - diskdb, err := leveldb.New(dir, 256, 0, "", false) - if err != nil { - panic(fmt.Sprintf("can't create temporary database: %v", err)) - } - return NewDatabase(diskdb) -} - func getString(trie *Trie, k string) []byte { return trie.Get([]byte(k)) } diff --git a/trie/util_test.go b/trie/util_test.go index 589eca62423a..252dc09e0804 100644 --- a/trie/util_test.go +++ b/trie/util_test.go @@ -19,12 +19,14 @@ package trie import ( "testing" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" ) // Tests if the trie diffs are tracked correctly. func TestTrieTracer(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) + db := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(db) trie.tracer = newTracer() // Insert a batch of entries, all the nodes should be marked as inserted @@ -65,8 +67,11 @@ func TestTrieTracer(t *testing.T) { t.Fatalf("Unexpected deleted node tracked %d", len(deleted)) } - // Commit the changes - trie.Commit(nil) + // Commit the changes and re-create with new root + root, nodes, _ := trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) + trie, _ = New(common.Hash{}, root, db) + trie.tracer = newTracer() // Delete all the elements, check deletion set for _, val := range vals { From f67e54c92fb7edcc44fa3739dfbc5d59790cc6f8 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 4 Aug 2022 16:13:18 +0200 Subject: [PATCH 147/715] core: use TryGetAccount to read what TryUpdateAccount has written (#25458) * core: use TryGetAccount to read where TryUpdateAccount has been used to write * Gary's review feedback * implement Gary's suggestion * fix bug + rename NewSecure into NewStateTrie * trie: add backwards-compatibility aliases for SecureTrie * Update database.go * make the linter happy Co-authored-by: Felix Lange Co-authored-by: rjl493456442 --- cmd/geth/snapshot.go | 8 +-- core/blockchain.go | 2 +- core/state/database.go | 15 +++-- core/state/pruner/pruner.go | 4 +- core/state/snapshot/generate_test.go | 6 +- core/state/statedb.go | 12 ++-- core/state/trie_prefetcher.go | 6 +- eth/api.go | 4 +- eth/protocols/snap/handler.go | 14 ++--- eth/protocols/snap/sync_test.go | 2 +- les/downloader/downloader_test.go | 2 +- light/trie.go | 16 +++++ trie/iterator_test.go | 4 +- trie/proof.go | 2 +- trie/secure_trie.go | 93 ++++++++++++++++++++-------- trie/secure_trie_test.go | 16 ++--- trie/sync_test.go | 8 +-- trie/trie.go | 16 ++--- 18 files changed, 142 insertions(+), 88 deletions(-) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index a218ae9cd292..39bef1f2d352 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -271,7 +271,7 @@ func traverseState(ctx *cli.Context) error { log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64()) } triedb := trie.NewDatabase(chaindb) - t, err := trie.NewSecure(common.Hash{}, root, triedb) + t, err := trie.NewStateTrie(common.Hash{}, root, triedb) if err != nil { log.Error("Failed to open trie", "root", root, "err", err) return err @@ -292,7 +292,7 @@ func traverseState(ctx *cli.Context) error { return err } if acc.Root != emptyRoot { - storageTrie, err := trie.NewSecure(common.BytesToHash(accIter.Key), acc.Root, triedb) + storageTrie, err := trie.NewStateTrie(common.BytesToHash(accIter.Key), acc.Root, triedb) if err != nil { log.Error("Failed to open storage trie", "root", acc.Root, "err", err) return err @@ -360,7 +360,7 @@ func traverseRawState(ctx *cli.Context) error { log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64()) } triedb := trie.NewDatabase(chaindb) - t, err := trie.NewSecure(common.Hash{}, root, triedb) + t, err := trie.NewStateTrie(common.Hash{}, root, triedb) if err != nil { log.Error("Failed to open trie", "root", root, "err", err) return err @@ -406,7 +406,7 @@ func traverseRawState(ctx *cli.Context) error { return errors.New("invalid account") } if acc.Root != emptyRoot { - storageTrie, err := trie.NewSecure(common.BytesToHash(accIter.LeafKey()), acc.Root, triedb) + storageTrie, err := trie.NewStateTrie(common.BytesToHash(accIter.LeafKey()), acc.Root, triedb) if err != nil { log.Error("Failed to open storage trie", "root", acc.Root, "err", err) return errors.New("missing storage trie") diff --git a/core/blockchain.go b/core/blockchain.go index 3638a1dcea16..f35de404619b 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -706,7 +706,7 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error { if block == nil { return fmt.Errorf("non existent block [%x..]", hash[:4]) } - if _, err := trie.NewSecure(common.Hash{}, block.Root(), bc.stateCache.TrieDB()); err != nil { + if _, err := trie.NewStateTrie(common.Hash{}, block.Root(), bc.stateCache.TrieDB()); err != nil { return err } diff --git a/core/state/database.go b/core/state/database.go index 8f662ecd3dab..edbf78ae311a 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -63,7 +63,7 @@ type Trie interface { // GetKey returns the sha3 preimage of a hashed key that was previously used // to store a value. // - // TODO(fjl): remove this when SecureTrie is removed + // TODO(fjl): remove this when StateTrie is removed GetKey([]byte) []byte // TryGet returns the value for key stored in the trie. The value bytes must @@ -71,8 +71,8 @@ type Trie interface { // trie.MissingNodeError is returned. TryGet(key []byte) ([]byte, error) - // TryUpdateAccount abstract an account write in the trie. - TryUpdateAccount(key []byte, account *types.StateAccount) error + // TryGetAccount abstract an account read from the trie. + TryGetAccount(key []byte) (*types.StateAccount, error) // TryUpdate 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 @@ -80,6 +80,9 @@ type Trie interface { // database, a trie.MissingNodeError is returned. TryUpdate(key, value []byte) error + // TryUpdateAccount abstract an account write to the trie. + TryUpdateAccount(key []byte, account *types.StateAccount) error + // TryDelete removes any existing value for key from the trie. If a node was not // found in the database, a trie.MissingNodeError is returned. TryDelete(key []byte) error @@ -137,7 +140,7 @@ type cachingDB struct { // OpenTrie opens the main account trie at a specific root hash. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { - tr, err := trie.NewSecure(common.Hash{}, root, db.db) + tr, err := trie.NewStateTrie(common.Hash{}, root, db.db) if err != nil { return nil, err } @@ -146,7 +149,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { // OpenStorageTrie opens the storage trie of an account. func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) { - tr, err := trie.NewSecure(addrHash, root, db.db) + tr, err := trie.NewStateTrie(addrHash, root, db.db) if err != nil { return nil, err } @@ -156,7 +159,7 @@ func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) { // CopyTrie returns an independent copy of the given trie. func (db *cachingDB) CopyTrie(t Trie) Trie { switch t := t.(type) { - case *trie.SecureTrie: + case *trie.StateTrie: return t.Copy() default: panic(fmt.Errorf("unknown trie type %T", t)) diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 2f4b068d88f3..2da2eda8b74d 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -410,7 +410,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { if genesis == nil { return errors.New("missing genesis block") } - t, err := trie.NewSecure(common.Hash{}, genesis.Root(), trie.NewDatabase(db)) + t, err := trie.NewStateTrie(common.Hash{}, genesis.Root(), trie.NewDatabase(db)) if err != nil { return err } @@ -430,7 +430,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { return err } if acc.Root != emptyRoot { - storageTrie, err := trie.NewSecure(common.BytesToHash(accIter.LeafKey()), acc.Root, trie.NewDatabase(db)) + storageTrie, err := trie.NewStateTrie(common.BytesToHash(accIter.LeafKey()), acc.Root, trie.NewDatabase(db)) if err != nil { return err } diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 8d89ca59a3c3..5e5ded61ea2f 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -142,14 +142,14 @@ func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) { type testHelper struct { diskdb ethdb.Database triedb *trie.Database - accTrie *trie.SecureTrie + accTrie *trie.StateTrie nodes *trie.MergedNodeSet } func newHelper() *testHelper { diskdb := rawdb.NewMemoryDatabase() triedb := trie.NewDatabase(diskdb) - accTrie, _ := trie.NewSecure(common.Hash{}, common.Hash{}, triedb) + accTrie, _ := trie.NewStateTrie(common.Hash{}, common.Hash{}, triedb) return &testHelper{ diskdb: diskdb, triedb: triedb, @@ -182,7 +182,7 @@ func (t *testHelper) addSnapStorage(accKey string, keys []string, vals []string) } func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string, vals []string, commit bool) []byte { - stTrie, _ := trie.NewSecure(owner, common.Hash{}, t.triedb) + stTrie, _ := trie.NewStateTrie(owner, common.Hash{}, t.triedb) for i, k := range keys { stTrie.Update([]byte(k), []byte(vals[i])) } diff --git a/core/state/statedb.go b/core/state/statedb.go index 322bc540b7a2..cd388d6a3641 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -537,20 +537,16 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { // If snapshot unavailable or reading from it failed, load from the database if data == nil { start := time.Now() - enc, err := s.trie.TryGet(addr.Bytes()) + var err error + data, err = s.trie.TryGetAccount(addr.Bytes()) if metrics.EnabledExpensive { s.AccountReads += time.Since(start) } if err != nil { - s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %v", addr.Bytes(), err)) + s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %w", addr.Bytes(), err)) return nil } - if len(enc) == 0 { - return nil - } - data = new(types.StateAccount) - if err := rlp.DecodeBytes(enc, data); err != nil { - log.Error("Failed to decode state object", "addr", addr, "err", err) + if data == nil { return nil } } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 4c817b1bc6fb..0f6bce3b8171 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -331,7 +331,11 @@ func (sf *subfetcher) loop() { if _, ok := sf.seen[string(task)]; ok { sf.dups++ } else { - sf.trie.TryGet(task) + if len(task) == len(common.Address{}) { + sf.trie.TryGetAccount(task) + } else { + sf.trie.TryGet(task) + } sf.seen[string(task)] = struct{}{} } } diff --git a/eth/api.go b/eth/api.go index 5d9a3cc3ad82..3ce8a2d1b8e5 100644 --- a/eth/api.go +++ b/eth/api.go @@ -506,11 +506,11 @@ func (api *DebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]c } triedb := api.eth.BlockChain().StateCache().TrieDB() - oldTrie, err := trie.NewSecure(common.Hash{}, startBlock.Root(), triedb) + oldTrie, err := trie.NewStateTrie(common.Hash{}, startBlock.Root(), triedb) if err != nil { return nil, err } - newTrie, err := trie.NewSecure(common.Hash{}, endBlock.Root(), triedb) + newTrie, err := trie.NewStateTrie(common.Hash{}, endBlock.Root(), triedb) if err != nil { return nil, err } diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 7ecf041e9a54..77bd96f46e8a 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -23,14 +23,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" - "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) @@ -415,15 +413,15 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP if origin != (common.Hash{}) || (abort && len(storage) > 0) { // Request started at a non-zero hash or was capped prematurely, add // the endpoint Merkle proofs - accTrie, err := trie.New(common.Hash{}, req.Root, chain.StateCache().TrieDB()) + accTrie, err := trie.NewStateTrie(common.Hash{}, req.Root, chain.StateCache().TrieDB()) if err != nil { return nil, nil } - var acc types.StateAccount - if err := rlp.DecodeBytes(accTrie.Get(account[:]), &acc); err != nil { + acc, err := accTrie.TryGetAccountWithPreHashedKey(account[:]) + if err != nil || acc == nil { return nil, nil } - stTrie, err := trie.New(account, acc.Root, chain.StateCache().TrieDB()) + stTrie, err := trie.NewStateTrie(account, acc.Root, chain.StateCache().TrieDB()) if err != nil { return nil, nil } @@ -489,7 +487,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s // Make sure we have the state associated with the request triedb := chain.StateCache().TrieDB() - accTrie, err := trie.NewSecure(common.Hash{}, req.Root, triedb) + accTrie, err := trie.NewStateTrie(common.Hash{}, req.Root, triedb) if err != nil { // We don't have the requested state available, bail out return nil, nil @@ -531,7 +529,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s if err != nil || account == nil { break } - stTrie, err := trie.NewSecure(common.BytesToHash(pathset[0]), common.BytesToHash(account.Root), triedb) + stTrie, err := trie.NewStateTrie(common.BytesToHash(pathset[0]), common.BytesToHash(account.Root), triedb) loads++ // always account database reads, even for failures if err != nil { break diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index a13e8d308966..4d9f631b5aab 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1658,7 +1658,7 @@ func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { } accounts++ if acc.Root != emptyRoot { - storeTrie, err := trie.NewSecure(common.BytesToHash(accIt.Key), acc.Root, triedb) + storeTrie, err := trie.NewStateTrie(common.BytesToHash(accIt.Key), acc.Root, triedb) if err != nil { t.Fatal(err) } diff --git a/les/downloader/downloader_test.go b/les/downloader/downloader_test.go index 792fc284619d..5eea49877969 100644 --- a/les/downloader/downloader_test.go +++ b/les/downloader/downloader_test.go @@ -229,7 +229,7 @@ func (dl *downloadTester) CurrentFastBlock() *types.Block { func (dl *downloadTester) FastSyncCommitHead(hash common.Hash) error { // For now only check that the state trie is correct if block := dl.GetBlockByHash(hash); block != nil { - _, err := trie.NewSecure(common.Hash{}, block.Root(), trie.NewDatabase(dl.stateDb)) + _, err := trie.NewStateTrie(common.Hash{}, block.Root(), trie.NewDatabase(dl.stateDb)) return err } return fmt.Errorf("non existent block: %x", hash[:4]) diff --git a/light/trie.go b/light/trie.go index a2ef8ebff3d3..5755e2cc1959 100644 --- a/light/trie.go +++ b/light/trie.go @@ -112,6 +112,22 @@ func (t *odrTrie) TryGet(key []byte) ([]byte, error) { return res, err } +func (t *odrTrie) TryGetAccount(key []byte) (*types.StateAccount, error) { + key = crypto.Keccak256(key) + var res types.StateAccount + err := t.do(key, func() (err error) { + value, err := t.trie.TryGet(key) + if err != nil { + return err + } + if value == nil { + return nil + } + return rlp.DecodeBytes(value, &res) + }) + return &res, err +} + func (t *odrTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { key = crypto.Keccak256(key) value, err := rlp.EncodeToBytes(acc) diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 0a4c04c8b346..e9d822a9a4f2 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -529,11 +529,11 @@ func (l *loggingDb) Close() error { } // makeLargeTestTrie create a sample test trie -func makeLargeTestTrie() (*Database, *SecureTrie, *loggingDb) { +func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) { // Create an empty trie logDb := &loggingDb{0, memorydb.New()} triedb := NewDatabase(logDb) - trie, _ := NewSecure(common.Hash{}, common.Hash{}, triedb) + trie, _ := NewStateTrie(common.Hash{}, common.Hash{}, triedb) // Fill it with some arbitrary data for i := 0; i < 10000; i++ { diff --git a/trie/proof.go b/trie/proof.go index fe3662c51a88..fa8361eefd58 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -100,7 +100,7 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) e // 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 node), ending // with the node that proves the absence of the key. -func (t *SecureTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error { +func (t *StateTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) error { return t.trie.Prove(key, fromLevel, proofDb) } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 59772815e294..28b3473c011f 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -25,25 +25,35 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -// SecureTrie wraps a trie with key hashing. In a secure trie, all +// SecureTrie is the old name of StateTrie. +// Deprecated: use StateTrie. +type SecureTrie = StateTrie + +// NewSecure creates a new StateTrie. +// Deprecated: use NewStateTrie. +func NewSecure(owner common.Hash, root common.Hash, db *Database) (*SecureTrie, error) { + return NewStateTrie(owner, root, db) +} + +// StateTrie wraps a trie with key hashing. In a secure trie, all // access operations hash the key using keccak256. This prevents // calling code from creating long chains of nodes that // increase the access time. // -// Contrary to a regular trie, a SecureTrie can only be created with +// Contrary to a regular trie, a StateTrie can only be created with // New and must have an attached database. The database also stores // the preimage of each key. // -// SecureTrie is not safe for concurrent use. -type SecureTrie struct { +// StateTrie is not safe for concurrent use. +type StateTrie struct { trie Trie preimages *preimageStore hashKeyBuf [common.HashLength]byte secKeyCache map[string][]byte - secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch + secKeyCacheOwner *StateTrie // Pointer to self, replace the key cache on mismatch } -// NewSecure creates a trie with an existing root node from a backing database +// NewStateTrie creates a trie with an existing root node from a backing database // and optional intermediate in-memory node pool. // // If root is the zero hash or the sha3 hash of an empty string, the @@ -54,7 +64,7 @@ type SecureTrie struct { // Loaded nodes are kept around until their 'cache generation' expires. // A new cache generation is created by each call to Commit. // cachelimit sets the number of past cache generations to keep. -func NewSecure(owner common.Hash, root common.Hash, db *Database) (*SecureTrie, error) { +func NewStateTrie(owner common.Hash, root common.Hash, db *Database) (*StateTrie, error) { if db == nil { panic("trie.NewSecure called without a database") } @@ -62,12 +72,12 @@ func NewSecure(owner common.Hash, root common.Hash, db *Database) (*SecureTrie, if err != nil { return nil, err } - return &SecureTrie{trie: *trie, preimages: db.preimages}, nil + return &StateTrie{trie: *trie, preimages: db.preimages}, nil } // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. -func (t *SecureTrie) Get(key []byte) []byte { +func (t *StateTrie) Get(key []byte) []byte { res, err := t.TryGet(key) if err != nil { log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) @@ -78,19 +88,50 @@ func (t *SecureTrie) Get(key []byte) []byte { // TryGet 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 MissingNodeError is returned. -func (t *SecureTrie) TryGet(key []byte) ([]byte, error) { +func (t *StateTrie) TryGet(key []byte) ([]byte, error) { return t.trie.TryGet(t.hashKey(key)) } +func (t *StateTrie) TryGetAccount(key []byte) (*types.StateAccount, error) { + var ret types.StateAccount + res, err := t.trie.TryGet(t.hashKey(key)) + if err != nil { + log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + return &ret, err + } + if res == nil { + return nil, nil + } + err = rlp.DecodeBytes(res, &ret) + return &ret, err +} + +// TryGetAccountWithPreHashedKey does the same thing as TryGetAccount, however +// it expects a key that is already hashed. This constitutes an abstraction leak, +// since the client code needs to know the key format. +func (t *StateTrie) TryGetAccountWithPreHashedKey(key []byte) (*types.StateAccount, error) { + var ret types.StateAccount + res, err := t.trie.TryGet(key) + if err != nil { + log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + return &ret, err + } + if res == nil { + return nil, nil + } + err = rlp.DecodeBytes(res, &ret) + return &ret, err +} + // TryGetNode 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. -func (t *SecureTrie) TryGetNode(path []byte) ([]byte, int, error) { +func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { return t.trie.TryGetNode(path) } // TryUpdateAccount account will abstract the write of an account to the // secure trie. -func (t *SecureTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { +func (t *StateTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { hk := t.hashKey(key) data, err := rlp.EncodeToBytes(acc) if err != nil { @@ -109,7 +150,7 @@ func (t *SecureTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error // // The value bytes must not be modified by the caller while they are // stored in the trie. -func (t *SecureTrie) Update(key, value []byte) { +func (t *StateTrie) Update(key, value []byte) { if err := t.TryUpdate(key, value); err != nil { log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) } @@ -123,7 +164,7 @@ func (t *SecureTrie) Update(key, value []byte) { // stored in the trie. // // If a node was not found in the database, a MissingNodeError is returned. -func (t *SecureTrie) TryUpdate(key, value []byte) error { +func (t *StateTrie) TryUpdate(key, value []byte) error { hk := t.hashKey(key) err := t.trie.TryUpdate(hk, value) if err != nil { @@ -134,7 +175,7 @@ func (t *SecureTrie) TryUpdate(key, value []byte) error { } // Delete removes any existing value for key from the trie. -func (t *SecureTrie) Delete(key []byte) { +func (t *StateTrie) Delete(key []byte) { if err := t.TryDelete(key); err != nil { log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) } @@ -142,7 +183,7 @@ func (t *SecureTrie) Delete(key []byte) { // TryDelete removes any existing value for key from the trie. // If a node was not found in the database, a MissingNodeError is returned. -func (t *SecureTrie) TryDelete(key []byte) error { +func (t *StateTrie) TryDelete(key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) return t.trie.TryDelete(hk) @@ -150,7 +191,7 @@ func (t *SecureTrie) TryDelete(key []byte) error { // GetKey returns the sha3 preimage of a hashed key that was // previously used to store a value. -func (t *SecureTrie) GetKey(shaKey []byte) []byte { +func (t *StateTrie) GetKey(shaKey []byte) []byte { if key, ok := t.getSecKeyCache()[string(shaKey)]; ok { return key } @@ -167,7 +208,7 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte { // All cached preimages will be also flushed if preimages recording is enabled. // 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 *SecureTrie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { +func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { // Write all the pre-images to the actual disk database if len(t.getSecKeyCache()) > 0 { if t.preimages != nil { @@ -183,15 +224,15 @@ func (t *SecureTrie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { return t.trie.Commit(collectLeaf) } -// Hash returns the root hash of SecureTrie. It does not write to the +// Hash returns the root hash of StateTrie. It does not write to the // database and can be used even if the trie doesn't have one. -func (t *SecureTrie) Hash() common.Hash { +func (t *StateTrie) Hash() common.Hash { return t.trie.Hash() } -// Copy returns a copy of SecureTrie. -func (t *SecureTrie) Copy() *SecureTrie { - return &SecureTrie{ +// Copy returns a copy of StateTrie. +func (t *StateTrie) Copy() *StateTrie { + return &StateTrie{ trie: *t.trie.Copy(), preimages: t.preimages, secKeyCache: t.secKeyCache, @@ -200,14 +241,14 @@ func (t *SecureTrie) Copy() *SecureTrie { // NodeIterator returns an iterator that returns nodes of the underlying trie. Iteration // starts at the key after the given start key. -func (t *SecureTrie) NodeIterator(start []byte) NodeIterator { +func (t *StateTrie) NodeIterator(start []byte) NodeIterator { return t.trie.NodeIterator(start) } // hashKey returns the hash of key as an ephemeral buffer. // The caller must not hold onto the return value because it will become // invalid on the next call to hashKey or secKey. -func (t *SecureTrie) hashKey(key []byte) []byte { +func (t *StateTrie) hashKey(key []byte) []byte { h := newHasher(false) h.sha.Reset() h.sha.Write(key) @@ -219,7 +260,7 @@ func (t *SecureTrie) hashKey(key []byte) []byte { // getSecKeyCache returns the current secure key cache, creating a new one if // ownership changed (i.e. the current secure trie is a copy of another owning // the actual cache). -func (t *SecureTrie) getSecKeyCache() map[string][]byte { +func (t *StateTrie) getSecKeyCache() map[string][]byte { if t != t.secKeyCacheOwner { t.secKeyCacheOwner = t t.secKeyCache = make(map[string][]byte) diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index 524d1db949f0..05bddb21b3bc 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -28,16 +28,16 @@ import ( "github.com/ethereum/go-ethereum/ethdb/memorydb" ) -func newEmptySecure() *SecureTrie { - trie, _ := NewSecure(common.Hash{}, common.Hash{}, NewDatabase(memorydb.New())) +func newEmptySecure() *StateTrie { + trie, _ := NewStateTrie(common.Hash{}, common.Hash{}, NewDatabase(memorydb.New())) return trie } -// makeTestSecureTrie creates a large enough secure trie for testing. -func makeTestSecureTrie() (*Database, *SecureTrie, map[string][]byte) { +// makeTestStateTrie creates a large enough secure trie for testing. +func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) { // Create an empty trie triedb := NewDatabase(memorydb.New()) - trie, _ := NewSecure(common.Hash{}, common.Hash{}, triedb) + trie, _ := NewStateTrie(common.Hash{}, common.Hash{}, triedb) // Fill it with some arbitrary data content := make(map[string][]byte) @@ -112,12 +112,12 @@ func TestSecureGetKey(t *testing.T) { } } -func TestSecureTrieConcurrency(t *testing.T) { +func TestStateTrieConcurrency(t *testing.T) { // Create an initial trie and copy if for concurrent access - _, trie, _ := makeTestSecureTrie() + _, trie, _ := makeTestStateTrie() threads := runtime.NumCPU() - tries := make([]*SecureTrie, threads) + tries := make([]*StateTrie, threads) for i := 0; i < threads; i++ { tries[i] = trie.Copy() } diff --git a/trie/sync_test.go b/trie/sync_test.go index c2ddb98c78d9..9fd1d636c036 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -27,10 +27,10 @@ import ( ) // makeTestTrie create a sample test trie to test node-wise reconstruction. -func makeTestTrie() (*Database, *SecureTrie, map[string][]byte) { +func makeTestTrie() (*Database, *StateTrie, map[string][]byte) { // Create an empty trie triedb := NewDatabase(memorydb.New()) - trie, _ := NewSecure(common.Hash{}, common.Hash{}, triedb) + trie, _ := NewStateTrie(common.Hash{}, common.Hash{}, triedb) // Fill it with some arbitrary data content := make(map[string][]byte) @@ -67,7 +67,7 @@ func makeTestTrie() (*Database, *SecureTrie, map[string][]byte) { // content map. func checkTrieContents(t *testing.T, db *Database, root []byte, content map[string][]byte) { // Check root availability and trie contents - trie, err := NewSecure(common.Hash{}, common.BytesToHash(root), db) + trie, err := NewStateTrie(common.Hash{}, common.BytesToHash(root), db) if err != nil { t.Fatalf("failed to create trie at %x: %v", root, err) } @@ -84,7 +84,7 @@ func checkTrieContents(t *testing.T, db *Database, root []byte, content map[stri // checkTrieConsistency checks that all nodes in a trie are indeed present. func checkTrieConsistency(db *Database, root common.Hash) error { // Create and iterate a trie rooted in a subnode - trie, err := NewSecure(common.Hash{}, root, db) + trie, err := NewStateTrie(common.Hash{}, root, db) if err != nil { return nil // Consider a non existent state consistent } diff --git a/trie/trie.go b/trie/trie.go index 08f2480db551..9274d88380cc 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -23,10 +23,8 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) var ( @@ -275,14 +273,6 @@ func (t *Trie) Update(key, value []byte) { } } -func (t *Trie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { - data, err := rlp.EncodeToBytes(acc) - if err != nil { - return fmt.Errorf("can't encode object at %x: %w", key[:], err) - } - return t.TryUpdate(key, data) -} - // TryUpdate associates key with value in the trie. Subsequent calls to // Get will return value. If value has length zero, any existing value // is deleted from the trie and calls to Get will return nil. @@ -292,6 +282,12 @@ func (t *Trie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { // // If a node was not found in the database, a MissingNodeError is returned. func (t *Trie) TryUpdate(key, value []byte) error { + return t.tryUpdate(key, value) +} + +// tryUpdate expects an RLP-encoded value and performs the core function +// for TryUpdate and TryUpdateAccount. +func (t *Trie) tryUpdate(key, value []byte) error { t.unhashed++ k := keybytesToHex(key) if len(value) != 0 { From e44d6551c3c872584722c366c863381f7e91df91 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 8 Aug 2022 17:08:36 +0800 Subject: [PATCH 148/715] cmd, core, ethdb, node: move chain freezer one folder deeper (#25487) * cmd, core, ethdb, node: create chain freezer in a sub folder * core/rawdb: remove unused code * core, ethdb, node: add AncientDatadir API back * cmd, core: extend freezer info dump for sub-ancient-store * core/rawdb: rework freezer inspector * core/rawdb: address comments from Peter * core/rawdb: fix build issue --- cmd/geth/dbcmd.go | 53 ++++++++------------ cmd/utils/flags.go | 2 +- core/rawdb/accessors_chain.go | 26 +++++----- core/rawdb/ancient_scheme.go | 86 ++++++++++++++++++++++++++++++++ core/rawdb/chain_freezer.go | 10 ++-- core/rawdb/chain_iterator.go | 2 +- core/rawdb/database.go | 50 ++++++++++++++++--- core/rawdb/freezer.go | 11 +--- core/rawdb/freezer_table.go | 8 ++- core/rawdb/freezer_table_test.go | 2 +- core/rawdb/schema.go | 27 ---------- ethdb/database.go | 5 +- node/node.go | 22 ++++---- 13 files changed, 191 insertions(+), 113 deletions(-) create mode 100644 core/rawdb/ancient_scheme.go diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 27661d2c982c..ab74277123d7 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -22,7 +22,6 @@ import ( "os" "os/signal" "path/filepath" - "sort" "strconv" "strings" "syscall" @@ -160,8 +159,8 @@ WARNING: This is a low-level operation which may cause database corruption!`, dbDumpFreezerIndex = &cli.Command{ Action: freezerInspect, Name: "freezer-index", - Usage: "Dump out the index of a given freezer type", - ArgsUsage: " ", + Usage: "Dump out the index of a specific freezer table", + ArgsUsage: " ", Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), @@ -275,7 +274,7 @@ func inspect(ctx *cli.Context) error { start []byte ) if ctx.NArg() > 2 { - return fmt.Errorf("Max 2 arguments: %v", ctx.Command.ArgsUsage) + return fmt.Errorf("max 2 arguments: %v", ctx.Command.ArgsUsage) } if ctx.NArg() >= 1 { if d, err := hexutil.Decode(ctx.Args().Get(0)); err != nil { @@ -536,43 +535,35 @@ func dbDumpTrie(ctx *cli.Context) error { } func freezerInspect(ctx *cli.Context) error { - var ( - start, end int64 - disableSnappy bool - err error - ) - if ctx.NArg() < 3 { + if ctx.NArg() < 4 { return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage) } - kind := ctx.Args().Get(0) - if noSnap, ok := rawdb.FreezerNoSnappy[kind]; !ok { - var options []string - for opt := range rawdb.FreezerNoSnappy { - options = append(options, opt) - } - sort.Strings(options) - return fmt.Errorf("Could read freezer-type '%v'. Available options: %v", kind, options) - } else { - disableSnappy = noSnap - } - if start, err = strconv.ParseInt(ctx.Args().Get(1), 10, 64); err != nil { - log.Info("Could read start-param", "error", err) + var ( + freezer = ctx.Args().Get(0) + table = ctx.Args().Get(1) + ) + start, err := strconv.ParseInt(ctx.Args().Get(2), 10, 64) + if err != nil { + log.Info("Could not read start-param", "err", err) return err } - if end, err = strconv.ParseInt(ctx.Args().Get(2), 10, 64); err != nil { - log.Info("Could read count param", "error", err) + end, err := strconv.ParseInt(ctx.Args().Get(3), 10, 64) + if err != nil { + log.Info("Could not read count param", "err", err) return err } stack, _ := makeConfigNode(ctx) defer stack.Close() - path := filepath.Join(stack.ResolvePath("chaindata"), "ancient") - log.Info("Opening freezer", "location", path, "name", kind) - if f, err := rawdb.NewFreezerTable(path, kind, disableSnappy, true); err != nil { + + db := utils.MakeChainDatabase(ctx, stack, true) + defer db.Close() + + ancient, err := db.AncientDatadir() + if err != nil { + log.Info("Failed to retrieve ancient root", "err", err) return err - } else { - f.DumpIndex(start, end) } - return nil + return rawdb.InspectFreezerTable(ancient, freezer, table, start, end) } func importLDBdata(ctx *cli.Context) error { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ff85e259aea3..efea9349250d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -91,7 +91,7 @@ var ( } AncientFlag = &flags.DirectoryFlag{ Name: "datadir.ancient", - Usage: "Data directory for ancient chain segments (default = inside chaindata)", + Usage: "Root directory for ancient data (default = inside chaindata)", Category: flags.EthCategory, } MinFreeDiskSpaceFlag = &flags.DirectoryFlag{ diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 8ea2e2ca7273..aeba3690d228 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -37,7 +37,7 @@ import ( func ReadCanonicalHash(db ethdb.Reader, number uint64) common.Hash { var data []byte db.ReadAncients(func(reader ethdb.AncientReaderOp) error { - data, _ = reader.Ancient(freezerHashTable, number) + data, _ = reader.Ancient(chainFreezerHashTable, number) if len(data) == 0 { // Get it by hash from leveldb data, _ = db.Get(headerHashKey(number)) @@ -335,7 +335,7 @@ func ReadHeaderRange(db ethdb.Reader, number uint64, count uint64) []rlp.RawValu } // read remaining from ancients max := count * 700 - data, err := db.AncientRange(freezerHeaderTable, i+1-count, count, max) + data, err := db.AncientRange(chainFreezerHeaderTable, i+1-count, count, max) if err == nil && uint64(len(data)) == count { // the data is on the order [h, h+1, .., n] -- reordering needed for i := range data { @@ -352,7 +352,7 @@ func ReadHeaderRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValu // First try to look up the data in ancient database. Extra hash // comparison is necessary since ancient database only maintains // the canonical data. - data, _ = reader.Ancient(freezerHeaderTable, number) + data, _ = reader.Ancient(chainFreezerHeaderTable, number) if len(data) > 0 && crypto.Keccak256Hash(data) == hash { return nil } @@ -428,7 +428,7 @@ func deleteHeaderWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number // isCanon is an internal utility method, to check whether the given number/hash // is part of the ancient (canon) set. func isCanon(reader ethdb.AncientReaderOp, number uint64, hash common.Hash) bool { - h, err := reader.Ancient(freezerHashTable, number) + h, err := reader.Ancient(chainFreezerHashTable, number) if err != nil { return false } @@ -444,7 +444,7 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue db.ReadAncients(func(reader ethdb.AncientReaderOp) error { // Check if the data is in ancients if isCanon(reader, number, hash) { - data, _ = reader.Ancient(freezerBodiesTable, number) + data, _ = reader.Ancient(chainFreezerBodiesTable, number) return nil } // If not, try reading from leveldb @@ -459,7 +459,7 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue func ReadCanonicalBodyRLP(db ethdb.Reader, number uint64) rlp.RawValue { var data []byte db.ReadAncients(func(reader ethdb.AncientReaderOp) error { - data, _ = reader.Ancient(freezerBodiesTable, number) + data, _ = reader.Ancient(chainFreezerBodiesTable, number) if len(data) > 0 { return nil } @@ -527,7 +527,7 @@ func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { db.ReadAncients(func(reader ethdb.AncientReaderOp) error { // Check if the data is in ancients if isCanon(reader, number, hash) { - data, _ = reader.Ancient(freezerDifficultyTable, number) + data, _ = reader.Ancient(chainFreezerDifficultyTable, number) return nil } // If not, try reading from leveldb @@ -587,7 +587,7 @@ func ReadReceiptsRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawVa db.ReadAncients(func(reader ethdb.AncientReaderOp) error { // Check if the data is in ancients if isCanon(reader, number, hash) { - data, _ = reader.Ancient(freezerReceiptTable, number) + data, _ = reader.Ancient(chainFreezerReceiptTable, number) return nil } // If not, try reading from leveldb @@ -819,19 +819,19 @@ func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *types.Header, receipts []*types.ReceiptForStorage, td *big.Int) error { num := block.NumberU64() - if err := op.AppendRaw(freezerHashTable, num, block.Hash().Bytes()); err != nil { + if err := op.AppendRaw(chainFreezerHashTable, num, block.Hash().Bytes()); err != nil { return fmt.Errorf("can't add block %d hash: %v", num, err) } - if err := op.Append(freezerHeaderTable, num, header); err != nil { + if err := op.Append(chainFreezerHeaderTable, num, header); err != nil { return fmt.Errorf("can't append block header %d: %v", num, err) } - if err := op.Append(freezerBodiesTable, num, block.Body()); err != nil { + if err := op.Append(chainFreezerBodiesTable, num, block.Body()); err != nil { return fmt.Errorf("can't append block body %d: %v", num, err) } - if err := op.Append(freezerReceiptTable, num, receipts); err != nil { + if err := op.Append(chainFreezerReceiptTable, num, receipts); err != nil { return fmt.Errorf("can't append block %d receipts: %v", num, err) } - if err := op.Append(freezerDifficultyTable, num, td); err != nil { + if err := op.Append(chainFreezerDifficultyTable, num, td); err != nil { return fmt.Errorf("can't append block %d total difficulty: %v", num, err) } return nil diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go new file mode 100644 index 000000000000..3da061cbd977 --- /dev/null +++ b/core/rawdb/ancient_scheme.go @@ -0,0 +1,86 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rawdb + +import "fmt" + +// The list of table names of chain freezer. +const ( + // chainFreezerHeaderTable indicates the name of the freezer header table. + chainFreezerHeaderTable = "headers" + + // chainFreezerHashTable indicates the name of the freezer canonical hash table. + chainFreezerHashTable = "hashes" + + // chainFreezerBodiesTable indicates the name of the freezer block body table. + chainFreezerBodiesTable = "bodies" + + // chainFreezerReceiptTable indicates the name of the freezer receipts table. + chainFreezerReceiptTable = "receipts" + + // chainFreezerDifficultyTable indicates the name of the freezer total difficulty table. + chainFreezerDifficultyTable = "diffs" +) + +// chainFreezerNoSnappy configures whether compression is disabled for the ancient-tables. +// Hashes and difficulties don't compress well. +var chainFreezerNoSnappy = map[string]bool{ + chainFreezerHeaderTable: false, + chainFreezerHashTable: true, + chainFreezerBodiesTable: false, + chainFreezerReceiptTable: false, + chainFreezerDifficultyTable: true, +} + +// The list of identifiers of ancient stores. +var ( + chainFreezerName = "chain" // the folder name of chain segment ancient store. +) + +// freezers the collections of all builtin freezers. +var freezers = []string{chainFreezerName} + +// InspectFreezerTable dumps out the index of a specific freezer table. The passed +// ancient indicates the path of root ancient directory where the chain freezer can +// be opened. Start and end specify the range for dumping out indexes. +// Note this function can only be used for debugging purposes. +func InspectFreezerTable(ancient string, freezerName string, tableName string, start, end int64) error { + var ( + path string + tables map[string]bool + ) + switch freezerName { + case chainFreezerName: + path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy + default: + return fmt.Errorf("unknown freezer, supported ones: %v", freezers) + } + noSnappy, exist := tables[tableName] + if !exist { + var names []string + for name := range tables { + names = append(names, name) + } + return fmt.Errorf("unknown table, supported ones: %v", names) + } + table, err := newFreezerTable(path, tableName, noSnappy, true) + if err != nil { + return err + } + table.dumpIndexStdout(start, end) + return nil +} diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index ec39b7b59cd2..7d9c9c015649 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -278,19 +278,19 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash } // Write to the batch. - if err := op.AppendRaw(freezerHashTable, number, hash[:]); err != nil { + if err := op.AppendRaw(chainFreezerHashTable, number, hash[:]); err != nil { return fmt.Errorf("can't write hash to Freezer: %v", err) } - if err := op.AppendRaw(freezerHeaderTable, number, header); err != nil { + if err := op.AppendRaw(chainFreezerHeaderTable, number, header); err != nil { return fmt.Errorf("can't write header to Freezer: %v", err) } - if err := op.AppendRaw(freezerBodiesTable, number, body); err != nil { + if err := op.AppendRaw(chainFreezerBodiesTable, number, body); err != nil { return fmt.Errorf("can't write body to Freezer: %v", err) } - if err := op.AppendRaw(freezerReceiptTable, number, receipts); err != nil { + if err := op.AppendRaw(chainFreezerReceiptTable, number, receipts); err != nil { return fmt.Errorf("can't write receipts to Freezer: %v", err) } - if err := op.AppendRaw(freezerDifficultyTable, number, td); err != nil { + if err := op.AppendRaw(chainFreezerDifficultyTable, number, td); err != nil { return fmt.Errorf("can't write td to Freezer: %v", err) } diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 21e42f42d43a..867fed63ad92 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -50,7 +50,7 @@ func InitDatabaseFromFreezer(db ethdb.Database) { if i+count > frozen { count = frozen - i } - data, err := db.AncientRange(freezerHashTable, i, count, 32*count) + data, err := db.AncientRange(chainFreezerHashTable, i, count, 32*count) if err != nil { log.Crit("Failed to init database from freezer", "err", err) } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 3fbee41dad3c..831ca69c4c07 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "os" + "path" "sync/atomic" "time" @@ -34,10 +35,16 @@ import ( // freezerdb is a database wrapper that enabled freezer data retrievals. type freezerdb struct { + ancientRoot string ethdb.KeyValueStore ethdb.AncientStore } +// AncientDatadir returns the path of root ancient directory. +func (frdb *freezerdb) AncientDatadir() (string, error) { + return frdb.ancientRoot, nil +} + // Close implements io.Closer, closing both the fast key-value store as well as // the slow ancient tables. func (frdb *freezerdb) Close() error { @@ -162,12 +169,36 @@ func NewDatabase(db ethdb.KeyValueStore) ethdb.Database { return &nofreezedb{KeyValueStore: db} } +// resolveChainFreezerDir is a helper function which resolves the absolute path +// of chain freezer by considering backward compatibility. +func resolveChainFreezerDir(ancient string) string { + // Check if the chain freezer is already present in the specified + // sub folder, if not then two possibilities: + // - chain freezer is not initialized + // - chain freezer exists in legacy location (root ancient folder) + freezer := path.Join(ancient, chainFreezerName) + if !common.FileExist(freezer) { + if !common.FileExist(ancient) { + // The entire ancient store is not initialized, still use the sub + // folder for initialization. + } else { + // Ancient root is already initialized, then we hold the assumption + // that chain freezer is also initialized and located in root folder. + // In this case fallback to legacy location. + freezer = ancient + log.Info("Found legacy ancient chain path", "location", ancient) + } + } + return freezer +} + // NewDatabaseWithFreezer creates a high level database on top of a given key- // value data store with a freezer moving immutable chain segments into cold -// storage. -func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace string, readonly bool) (ethdb.Database, error) { +// storage. The passed ancient indicates the path of root ancient directory +// where the chain freezer can be opened. +func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace string, readonly bool) (ethdb.Database, error) { // Create the idle freezer instance - frdb, err := newChainFreezer(freezer, namespace, readonly, freezerTableSize, FreezerNoSnappy) + frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly, freezerTableSize, chainFreezerNoSnappy) if err != nil { return nil, err } @@ -198,7 +229,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace st // If the freezer already contains something, ensure that the genesis blocks // match, otherwise we might mix up freezers across chains and destroy both // the freezer and the key-value store. - frgenesis, err := frdb.Ancient(freezerHashTable, 0) + frgenesis, err := frdb.Ancient(chainFreezerHashTable, 0) if err != nil { return nil, fmt.Errorf("failed to retrieve genesis from ancient %v", err) } else if !bytes.Equal(kvgenesis, frgenesis) { @@ -244,6 +275,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace st }() } return &freezerdb{ + ancientRoot: ancient, KeyValueStore: db, AncientStore: frdb, }, nil @@ -273,13 +305,15 @@ func NewLevelDBDatabase(file string, cache int, handles int, namespace string, r } // NewLevelDBDatabaseWithFreezer creates a persistent key-value database with a -// freezer moving immutable chain segments into cold storage. -func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, freezer string, namespace string, readonly bool) (ethdb.Database, error) { +// freezer moving immutable chain segments into cold storage. The passed ancient +// indicates the path of root ancient directory where the chain freezer can be +// opened. +func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, ancient string, namespace string, readonly bool) (ethdb.Database, error) { kvdb, err := leveldb.New(file, cache, handles, namespace, readonly) if err != nil { return nil, err } - frdb, err := NewDatabaseWithFreezer(kvdb, freezer, namespace, readonly) + frdb, err := NewDatabaseWithFreezer(kvdb, ancient, namespace, readonly) if err != nil { kvdb.Close() return nil, err @@ -441,7 +475,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { } // Inspect append-only file store then. ancientSizes := []*common.StorageSize{&ancientHeadersSize, &ancientBodiesSize, &ancientReceiptsSize, &ancientHashesSize, &ancientTdsSize} - for i, category := range []string{freezerHeaderTable, freezerBodiesTable, freezerReceiptTable, freezerHashTable, freezerDifficultyTable} { + for i, category := range []string{chainFreezerHeaderTable, chainFreezerBodiesTable, chainFreezerReceiptTable, chainFreezerHashTable, chainFreezerDifficultyTable} { if size, err := db.AncientSize(category); err == nil { *ancientSizes[i] += common.StorageSize(size) total += common.StorageSize(size) diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 63fd8cdcf86f..6dea98c3d3c4 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -68,8 +68,6 @@ type Freezer struct { frozen uint64 // Number of blocks already frozen tail uint64 // Number of the first stored item in the freezer - datadir string // Path of root directory of ancient store - // This lock synchronizes writers and the truncate operation, as well as // the "atomic" (batched) read operations. writeLock sync.RWMutex @@ -111,7 +109,6 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui readonly: readonly, tables: make(map[string]*freezerTable), instanceLock: lock, - datadir: datadir, } // Create the tables. @@ -429,7 +426,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error { // Set up new dir for the migrated table, the content of which // we'll at the end move over to the ancients dir. migrationPath := filepath.Join(ancientsPath, "migration") - newTable, err := NewFreezerTable(migrationPath, kind, table.noCompression, false) + newTable, err := newFreezerTable(migrationPath, kind, table.noCompression, false) if err != nil { return err } @@ -486,11 +483,5 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error { if err := os.Remove(migrationPath); err != nil { return err } - return nil } - -// AncientDatadir returns the root directory path of the ancient store. -func (f *Freezer) AncientDatadir() (string, error) { - return f.datadir, nil -} diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index dd4a80efcbc5..51d7d1930854 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -123,8 +123,8 @@ type freezerTable struct { lock sync.RWMutex // Mutex protecting the data file descriptors } -// NewFreezerTable opens the given path as a freezer table. -func NewFreezerTable(path, name string, disableSnappy, readonly bool) (*freezerTable, error) { +// newFreezerTable opens the given path as a freezer table. +func newFreezerTable(path, name string, disableSnappy, readonly bool) (*freezerTable, error) { return newTable(path, name, metrics.NilMeter{}, metrics.NilMeter{}, metrics.NilGauge{}, freezerTableSize, disableSnappy, readonly) } @@ -884,9 +884,7 @@ func (t *freezerTable) Sync() error { return t.head.Sync() } -// DumpIndex is a debug print utility function, mainly for testing. It can also -// be used to analyse a live freezer table index. -func (t *freezerTable) DumpIndex(start, stop int64) { +func (t *freezerTable) dumpIndexStdout(start, stop int64) { t.dumpIndex(os.Stdout, start, stop) } diff --git a/core/rawdb/freezer_table_test.go b/core/rawdb/freezer_table_test.go index 0bddcf721136..ea28e71756de 100644 --- a/core/rawdb/freezer_table_test.go +++ b/core/rawdb/freezer_table_test.go @@ -902,7 +902,7 @@ func TestSequentialRead(t *testing.T) { } // Write 15 bytes 30 times writeChunks(t, f, 30, 15) - f.DumpIndex(0, 30) + f.dumpIndexStdout(0, 30) f.Close() } { // Open it, iterate, verify iteration diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 041c9f044967..a55ebdff74a2 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -111,33 +111,6 @@ var ( preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) ) -const ( - // freezerHeaderTable indicates the name of the freezer header table. - freezerHeaderTable = "headers" - - // freezerHashTable indicates the name of the freezer canonical hash table. - freezerHashTable = "hashes" - - // freezerBodiesTable indicates the name of the freezer block body table. - freezerBodiesTable = "bodies" - - // freezerReceiptTable indicates the name of the freezer receipts table. - freezerReceiptTable = "receipts" - - // freezerDifficultyTable indicates the name of the freezer total difficulty table. - freezerDifficultyTable = "diffs" -) - -// FreezerNoSnappy configures whether compression is disabled for the ancient-tables. -// Hashes and difficulties don't compress well. -var FreezerNoSnappy = map[string]bool{ - freezerHeaderTable: false, - freezerHashTable: true, - freezerBodiesTable: false, - freezerReceiptTable: false, - freezerDifficultyTable: true, -} - // LegacyTxLookupEntry is the legacy TxLookupEntry definition with some unnecessary // fields. type LegacyTxLookupEntry struct { diff --git a/ethdb/database.go b/ethdb/database.go index e8faa2d868cc..361218f24742 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -142,7 +142,9 @@ type AncientWriteOp interface { // AncientStater wraps the Stat method of a backing data store. type AncientStater interface { - // AncientDatadir returns the root directory path of the ancient store. + // AncientDatadir returns the path of root ancient directory. Empty string + // will be returned if ancient store is not enabled at all. The returned + // path can be used to construct the path of other freezers. AncientDatadir() (string, error) } @@ -172,7 +174,6 @@ type Stater interface { type AncientStore interface { AncientReader AncientWriter - AncientStater io.Closer } diff --git a/node/node.go b/node/node.go index 0a2b9eb83692..b60e32f22fd2 100644 --- a/node/node.go +++ b/node/node.go @@ -703,7 +703,7 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r // also attaching a chain freezer to it that moves ancient chain data from the // database to immutable append-only files. If the node is an ephemeral one, a // memory database is returned. -func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string, readonly bool) (ethdb.Database, error) { +func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient string, namespace string, readonly bool) (ethdb.Database, error) { n.lock.Lock() defer n.lock.Unlock() if n.state == closedState { @@ -715,14 +715,7 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, if n.config.DataDir == "" { db = rawdb.NewMemoryDatabase() } else { - root := n.ResolvePath(name) - switch { - case freezer == "": - freezer = filepath.Join(root, "ancient") - case !filepath.IsAbs(freezer): - freezer = n.ResolvePath(freezer) - } - db, err = rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace, readonly) + db, err = rawdb.NewLevelDBDatabaseWithFreezer(n.ResolvePath(name), cache, handles, n.ResolveAncient(name, ancient), namespace, readonly) } if err == nil { @@ -736,6 +729,17 @@ func (n *Node) ResolvePath(x string) string { return n.config.ResolvePath(x) } +// ResolveAncient returns the absolute path of the root ancient directory. +func (n *Node) ResolveAncient(name string, ancient string) string { + switch { + case ancient == "": + ancient = filepath.Join(n.ResolvePath(name), "ancient") + case !filepath.IsAbs(ancient): + ancient = n.ResolvePath(ancient) + } + return ancient +} + // closeTrackingDB wraps the Close method of a database. When the database is closed by the // service, the wrapper removes it from the node's database map. This ensures that Node // won't auto-close the database if it is closed by the service that opened it. From e93442c6cfca34aec3f83a03b35a97592571cce4 Mon Sep 17 00:00:00 2001 From: int88 <106391185+int88@users.noreply.github.com> Date: Mon, 8 Aug 2022 21:07:54 +0800 Subject: [PATCH 149/715] eth/downloader: fix log errors of queue_test.go (#25494) --- eth/downloader/queue_test.go | 4 ++-- les/downloader/queue_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eth/downloader/queue_test.go b/eth/downloader/queue_test.go index e2e9654eaee9..d2dfbceffbf5 100644 --- a/eth/downloader/queue_test.go +++ b/eth/downloader/queue_test.go @@ -156,7 +156,7 @@ func TestBasics(t *testing.T) { // The second peer should hit throttling if !throttle { - t.Fatalf("should not throttle") + t.Fatalf("should throttle") } // And not get any fetches at all, since it was throttled to begin with if fetchReq != nil { @@ -251,7 +251,7 @@ func TestEmptyBlocks(t *testing.T) { // there should be nothing to fetch, blocks are empty if fetchReq != nil { - t.Fatal("there should be no body fetch tasks remaining") + t.Fatal("there should be no receipt fetch tasks remaining") } } if q.blockTaskQueue.Size() != numOfBlocks-10 { diff --git a/les/downloader/queue_test.go b/les/downloader/queue_test.go index 2da8e4958858..848979479171 100644 --- a/les/downloader/queue_test.go +++ b/les/downloader/queue_test.go @@ -150,7 +150,7 @@ func TestBasics(t *testing.T) { // The second peer should hit throttling if !throttle { - t.Fatalf("should not throttle") + t.Fatalf("should throttle") } // And not get any fetches at all, since it was throttled to begin with if fetchReq != nil { @@ -239,7 +239,7 @@ func TestEmptyBlocks(t *testing.T) { // there should be nothing to fetch, blocks are empty if fetchReq != nil { - t.Fatal("there should be no body fetch tasks remaining") + t.Fatal("there should be no receipt fetch tasks remaining") } } if q.blockTaskQueue.Size() != numOfBlocks-10 { From e4b3bd6f26493edb379271787468b3cc36d3af16 Mon Sep 17 00:00:00 2001 From: int88 <106391185+int88@users.noreply.github.com> Date: Tue, 9 Aug 2022 06:20:46 +0800 Subject: [PATCH 150/715] core: fix uncle creation in TestFastVsFullChains (#25476) Co-authored-by: Felix Lange --- core/blockchain_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 8e94865366fe..517cb5e1d507 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -759,9 +759,9 @@ func TestFastVsFullChains(t *testing.T) { block.AddTx(tx) } } - // If the block number is a multiple of 5, add a few bonus uncles to the block - if i%5 == 5 { - block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))}) + // If the block number is a multiple of 5, add an uncle to the block + if i%5 == 4 { + block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 2).Hash(), Number: big.NewInt(int64(i))}) } }) // Import the chain as an archive node for the comparison baseline From 759d795c56cc158c4c296a0767a51cc262259fbc Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Tue, 9 Aug 2022 04:23:41 -0400 Subject: [PATCH 151/715] eth: formatted error nit (#25499) --- eth/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/api.go b/eth/api.go index 3ce8a2d1b8e5..5642ef4c3f12 100644 --- a/eth/api.go +++ b/eth/api.go @@ -586,5 +586,5 @@ func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error return uint64(i), nil } } - return 0, fmt.Errorf("no state found") + return 0, errors.New("no state found") } From 86de2e516e5a4a2bbe1d29b46a0f460fbdde8303 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 9 Aug 2022 11:04:57 +0200 Subject: [PATCH 152/715] eth/tracers: add onlyTopCall option to callTracer (#25430) This PR allows users to pass in a config object directly to the tracers. Previously only the struct logger was configurable. It also adds an option to the call tracer which if enabled makes it ignore any subcall and collect only information about the top-level call. See #25419 for discussion. The tracers will silently ignore if they are passed a config they don't care about. --- core/vm/runtime/runtime_test.go | 6 +- eth/tracers/api.go | 11 +-- .../internal/tracetest/calltrace_test.go | 15 ++-- .../testdata/call_tracer/simple_onlytop.json | 72 +++++++++++++++++++ eth/tracers/js/goja.go | 13 +++- eth/tracers/js/tracer_test.go | 48 ++++++++++--- eth/tracers/native/4byte.go | 4 +- eth/tracers/native/call.go | 21 +++++- eth/tracers/native/noop.go | 4 +- eth/tracers/native/prestate.go | 4 +- eth/tracers/native/revertreason.go | 4 +- eth/tracers/native/tracer.go | 7 +- eth/tracers/tracers.go | 6 +- 13 files changed, 174 insertions(+), 41 deletions(-) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 8864219ff1ac..0fb287292896 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -333,7 +333,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) cfg.GasLimit = gas if len(tracerCode) > 0 { - tracer, err := tracers.New(tracerCode, new(tracers.Context)) + tracer, err := tracers.New(tracerCode, new(tracers.Context), nil) if err != nil { b.Fatal(err) } @@ -832,7 +832,7 @@ func TestRuntimeJSTracer(t *testing.T) { statedb.SetCode(common.HexToAddress("0xee"), calleeCode) statedb.SetCode(common.HexToAddress("0xff"), depressedCode) - tracer, err := tracers.New(jsTracer, new(tracers.Context)) + tracer, err := tracers.New(jsTracer, new(tracers.Context), nil) if err != nil { t.Fatal(err) } @@ -868,7 +868,7 @@ func TestJSTracerCreateTx(t *testing.T) { code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)} statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - tracer, err := tracers.New(jsTracer, new(tracers.Context)) + tracer, err := tracers.New(jsTracer, new(tracers.Context), nil) if err != nil { t.Fatal(err) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 4041b1770777..014e2f6ad8d1 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -20,6 +20,7 @@ import ( "bufio" "bytes" "context" + "encoding/json" "errors" "fmt" "os" @@ -169,15 +170,15 @@ type TraceConfig struct { Tracer *string Timeout *string Reexec *uint64 + // Config specific to given tracer. Note struct logger + // config are historically embedded in main object. + TracerConfig json.RawMessage } // TraceCallConfig is the config for traceCall API. It holds one more // field to override the state for tracing. type TraceCallConfig struct { - *logger.Config - Tracer *string - Timeout *string - Reexec *uint64 + TraceConfig StateOverrides *ethapi.StateOverride BlockOverrides *ethapi.BlockOverrides } @@ -882,7 +883,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex // Default tracer is the struct logger tracer = logger.NewStructLogger(config.Config) if config.Tracer != nil { - tracer, err = New(*config.Tracer, txctx) + tracer, err = New(*config.Tracer, txctx, config.TracerConfig) if err != nil { return nil, err } diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index cbf20ed00c0c..cabddac49902 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -118,10 +118,11 @@ type callTrace struct { // callTracerTest defines a single test to check the call tracer against. type callTracerTest struct { - Genesis *core.Genesis `json:"genesis"` - Context *callContext `json:"context"` - Input string `json:"input"` - Result *callTrace `json:"result"` + Genesis *core.Genesis `json:"genesis"` + Context *callContext `json:"context"` + Input string `json:"input"` + TracerConfig json.RawMessage `json:"tracerConfig"` + Result *callTrace `json:"result"` } // Iterates over all the input-output datasets in the tracer test harness and @@ -179,7 +180,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { } _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) ) - tracer, err := tracers.New(tracerName, new(tracers.Context)) + tracer, err := tracers.New(tracerName, new(tracers.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) } @@ -293,7 +294,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - tracer, err := tracers.New(tracerName, new(tracers.Context)) + tracer, err := tracers.New(tracerName, new(tracers.Context), nil) if err != nil { b.Fatalf("failed to create call tracer: %v", err) } @@ -359,7 +360,7 @@ func TestZeroValueToNotExitCall(t *testing.T) { } _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false) // Create the tracer, the EVM environment and run it - tracer, err := tracers.New("callTracer", nil) + tracer, err := tracers.New("callTracer", nil, nil) if err != nil { t.Fatalf("failed to create call tracer: %v", err) } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json new file mode 100644 index 000000000000..ac1fef44098e --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json @@ -0,0 +1,72 @@ +{ + "context": { + "difficulty": "3502894804", + "gasLimit": "4722976", + "miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724", + "number": "2289806", + "timestamp": "1513601314" + }, + "genesis": { + "alloc": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "code": "0x", + "nonce": "22", + "storage": {} + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "code": "0x", + "nonce": "29072", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3509749784", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "4727564", + "hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada", + "nonce": "0x4eb12e19c16d43da", + "number": "2289805", + "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", + "timestamp": "1513601261", + "totalDifficulty": "7143276353481064" + }, + "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", + "tracerConfig": { + "onlyTopCall": true + }, + "result": { + "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", + "gas": "0x10738", + "gasUsed": "0x3ef9", + "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "type": "CALL", + "value": "0x0" + } +} diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index a076168f7101..8238bb603dd3 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -125,7 +125,7 @@ type jsTracer struct { // The methods `result` and `fault` are required to be present. // The methods `step`, `enter`, and `exit` are optional, but note that // `enter` and `exit` always go together. -func newJsTracer(code string, ctx *tracers.Context) (tracers.Tracer, error) { +func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { if c, ok := assetTracers[code]; ok { code = c } @@ -177,6 +177,17 @@ func newJsTracer(code string, ctx *tracers.Context) (tracers.Tracer, error) { t.exit = exit t.result = result t.fault = fault + + // Pass in config + if setup, ok := goja.AssertFunction(obj.Get("setup")); ok { + cfgStr := "{}" + if cfg != nil { + cfgStr = string(cfg) + } + if _, err := setup(obj, vm.ToValue(cfgStr)); err != nil { + return nil, err + } + } // Setup objects carrying data to JS. These are created once and re-used. t.log = &steplog{ vm: vm, diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 0bdda770af4d..80a002d5af28 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -85,7 +85,7 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon func TestTracer(t *testing.T) { execTracer := func(code string) ([]byte, string) { t.Helper() - tracer, err := newJsTracer(code, nil) + tracer, err := newJsTracer(code, nil, nil) if err != nil { t.Fatal(err) } @@ -149,7 +149,7 @@ func TestTracer(t *testing.T) { func TestHalt(t *testing.T) { timeout := errors.New("stahp") - tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil) + tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil, nil) if err != nil { t.Fatal(err) } @@ -163,7 +163,7 @@ func TestHalt(t *testing.T) { } func TestHaltBetweenSteps(t *testing.T) { - tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil) + tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil, nil) if err != nil { t.Fatal(err) } @@ -187,7 +187,7 @@ func TestHaltBetweenSteps(t *testing.T) { func TestNoStepExec(t *testing.T) { execTracer := func(code string) []byte { t.Helper() - tracer, err := newJsTracer(code, nil) + tracer, err := newJsTracer(code, nil, nil) if err != nil { t.Fatal(err) } @@ -221,7 +221,7 @@ func TestIsPrecompile(t *testing.T) { chaincfg.IstanbulBlock = big.NewInt(200) chaincfg.BerlinBlock = big.NewInt(300) txCtx := vm.TxContext{GasPrice: big.NewInt(100000)} - tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil) + tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil) if err != nil { t.Fatal(err) } @@ -235,7 +235,7 @@ func TestIsPrecompile(t *testing.T) { t.Errorf("tracer should not consider blake2f as precompile in byzantium") } - tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil) + tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil) blockCtx = vm.BlockContext{BlockNumber: big.NewInt(250)} res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg) if err != nil { @@ -248,14 +248,14 @@ func TestIsPrecompile(t *testing.T) { func TestEnterExit(t *testing.T) { // test that either both or none of enter() and exit() are defined - if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context)); err == nil { + if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil); err == nil { t.Fatal("tracer creation should've failed without exit() definition") } - if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context)); err != nil { + if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil); err != nil { t.Fatal(err) } // test that the enter and exit method are correctly invoked and the values passed - tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context)) + tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil) if err != nil { t.Fatal(err) } @@ -274,3 +274,33 @@ func TestEnterExit(t *testing.T) { t.Errorf("Number of invocations of enter() and exit() is wrong. Have %s, want %s\n", have, want) } } + +func TestSetup(t *testing.T) { + // Test empty config + _, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil) + if err != nil { + t.Error(err) + } + + cfg, err := json.Marshal(map[string]string{"foo": "bar"}) + if err != nil { + t.Fatal(err) + } + // Test no setup func + _, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg) + if err != nil { + t.Fatal(err) + } + // Test config value + tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg) + if err != nil { + t.Fatal(err) + } + have, err := tracer.GetResult() + if err != nil { + t.Fatal(err) + } + if string(have) != `"bar"` { + t.Errorf("tracer returned wrong result. have: %s, want: \"bar\"\n", string(have)) + } +} diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 92cc70994c32..34e608bfd60d 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -55,11 +55,11 @@ type fourByteTracer struct { // newFourByteTracer returns a native go tracer which collects // 4 byte-identifiers of a tx, and implements vm.EVMLogger. -func newFourByteTracer(ctx *tracers.Context) tracers.Tracer { +func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { t := &fourByteTracer{ ids: make(map[string]int), } - return t + return t, nil } // isPrecompiled returns whether the addr is a precompile. Logic borrowed from newJsTracer in eth/tracers/js/tracer.go diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index d334e328a5ff..7af0e658a8bf 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -50,16 +50,27 @@ type callFrame struct { type callTracer struct { env *vm.EVM callstack []callFrame + config callTracerConfig interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption } +type callTracerConfig struct { + OnlyTopCall bool `json:"onlyTopCall"` // If true, call tracer won't collect any subcalls +} + // newCallTracer returns a native go tracer which tracks // call frames of a tx, and implements vm.EVMLogger. -func newCallTracer(ctx *tracers.Context) tracers.Tracer { +func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { + var config callTracerConfig + if cfg != nil { + if err := json.Unmarshal(cfg, &config); err != nil { + return nil, err + } + } // First callframe contains tx context info // and is populated on start and end. - return &callTracer{callstack: make([]callFrame, 1)} + return &callTracer{callstack: make([]callFrame, 1), config: config}, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. @@ -101,6 +112,9 @@ func (t *callTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ * // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if t.config.OnlyTopCall { + return + } // Skip if tracing was interrupted if atomic.LoadUint32(&t.interrupt) > 0 { t.env.Cancel() @@ -121,6 +135,9 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. // CaptureExit is called when EVM exits a scope, even if the scope didn't // execute any code. func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { + if t.config.OnlyTopCall { + return + } size := len(t.callstack) if size <= 1 { return diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index 0849fd74e987..c252b2408fc9 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -35,8 +35,8 @@ func init() { type noopTracer struct{} // newNoopTracer returns a new noop tracer. -func newNoopTracer(ctx *tracers.Context) tracers.Tracer { - return &noopTracer{} +func newNoopTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { + return &noopTracer{}, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 4d289ca62210..b513f383b9c2 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -51,10 +51,10 @@ type prestateTracer struct { reason error // Textual reason for the interruption } -func newPrestateTracer(ctx *tracers.Context) tracers.Tracer { +func newPrestateTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { // First callframe contains tx context info // and is populated on start and end. - return &prestateTracer{prestate: prestate{}} + return &prestateTracer{prestate: prestate{}}, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. diff --git a/eth/tracers/native/revertreason.go b/eth/tracers/native/revertreason.go index b402396cb065..d09b86100901 100644 --- a/eth/tracers/native/revertreason.go +++ b/eth/tracers/native/revertreason.go @@ -46,8 +46,8 @@ type revertReasonTracer struct { } // newRevertReasonTracer returns a new revert reason tracer. -func newRevertReasonTracer(_ *tracers.Context) tracers.Tracer { - return &revertReasonTracer{} +func newRevertReasonTracer(_ *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { + return &revertReasonTracer{}, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. diff --git a/eth/tracers/native/tracer.go b/eth/tracers/native/tracer.go index 3bab870ea510..9587caf19fd1 100644 --- a/eth/tracers/native/tracer.go +++ b/eth/tracers/native/tracer.go @@ -35,6 +35,7 @@ func init() { package native import ( + "encoding/json" "errors" "github.com/ethereum/go-ethereum/eth/tracers" @@ -46,7 +47,7 @@ func init() { } // ctorFn is the constructor signature of a native tracer. -type ctorFn = func(*tracers.Context) tracers.Tracer +type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error) /* ctors is a map of package-local tracer constructors. @@ -71,12 +72,12 @@ func register(name string, ctor ctorFn) { } // lookup returns a tracer, if one can be matched to the given name. -func lookup(name string, ctx *tracers.Context) (tracers.Tracer, error) { +func lookup(name string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { if ctors == nil { ctors = make(map[string]ctorFn) } if ctor, ok := ctors[name]; ok { - return ctor(ctx), nil + return ctor(ctx, cfg) } return nil, errors.New("no tracer found") } diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index e7073e7d2edf..3d2d1256c091 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -42,7 +42,7 @@ type Tracer interface { Stop(err error) } -type lookupFunc func(string, *Context) (Tracer, error) +type lookupFunc func(string, *Context, json.RawMessage) (Tracer, error) var ( lookups []lookupFunc @@ -62,9 +62,9 @@ func RegisterLookup(wildcard bool, lookup lookupFunc) { // New returns a new instance of a tracer, by iterating through the // registered lookups. -func New(code string, ctx *Context) (Tracer, error) { +func New(code string, ctx *Context, cfg json.RawMessage) (Tracer, error) { for _, lookup := range lookups { - if tracer, err := lookup(code, ctx); err == nil { + if tracer, err := lookup(code, ctx, cfg); err == nil { return tracer, nil } } From a41ea8a97cd0f9db7a87e2dd15b380d4f1fbc311 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 9 Aug 2022 17:44:39 +0800 Subject: [PATCH 153/715] all: cleanup the APIs for initializing genesis (#25473) * all: polish tests * core: apply feedback from Guillaume * core: fix comment --- cmd/devp2p/internal/ethtest/chain.go | 2 +- cmd/evm/runner.go | 2 +- cmd/faucet/faucet.go | 2 +- consensus/clique/snapshot_test.go | 4 +- core/blockchain_test.go | 4 +- core/genesis.go | 78 +++++++++++++------------ core/genesis_test.go | 14 ++--- core/rawdb/accessors_metadata.go | 13 +++-- core/rawdb/schema.go | 4 +- eth/catalyst/api_test.go | 2 +- eth/downloader/downloader_test.go | 6 +- eth/downloader/queue_test.go | 14 ++--- eth/downloader/testchain_test.go | 9 ++- eth/fetcher/block_fetcher_test.go | 12 ++-- eth/filters/filter_test.go | 18 +++++- eth/gasprice/gasprice_test.go | 8 +-- ethclient/ethclient_test.go | 2 +- ethclient/gethclient/gethclient_test.go | 2 +- les/catalyst/api_test.go | 2 +- les/downloader/queue_test.go | 14 ++--- les/downloader/testchain_test.go | 7 ++- les/fetcher/block_fetcher_test.go | 13 +++-- les/peer_test.go | 3 +- miner/stress/beacon/main.go | 2 +- tests/state_test.go | 2 +- tests/state_test_util.go | 2 +- 26 files changed, 133 insertions(+), 108 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index df724f470481..83ceb2a4f2c5 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -139,7 +139,7 @@ func loadChain(chainfile string, genesis string) (*Chain, error) { if err != nil { return nil, err } - gblock := gen.ToBlock(nil) + gblock := gen.ToBlock() blocks, err := blocksFromFile(chainfile, gblock) if err != nil { diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 05b9ccdebca7..9b1975c0500e 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -138,7 +138,7 @@ func runCmd(ctx *cli.Context) error { gen := readGenesis(ctx.String(GenesisFlag.Name)) genesisConfig = gen db := rawdb.NewMemoryDatabase() - genesis := gen.ToBlock(db) + genesis := gen.MustCommit(db) statedb, _ = state.New(genesis.Root(), state.NewDatabase(db), nil) chainConfig = gen.Config } else { diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 6c8796076c07..d49b9ed29d93 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -248,7 +248,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network ui cfg.SyncMode = downloader.LightSync cfg.NetworkId = network cfg.Genesis = genesis - utils.SetDNSDiscoveryDefaults(&cfg, genesis.ToBlock(nil).Hash()) + utils.SetDNSDiscoveryDefaults(&cfg, genesis.ToBlock().Hash()) lesBackend, err := les.New(stack, &cfg) if err != nil { diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 094868ca744d..b87ad8c23a7c 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -403,7 +403,7 @@ func TestClique(t *testing.T) { } // Create a pristine blockchain with the genesis injected db := rawdb.NewMemoryDatabase() - genesis.Commit(db) + genesisBlock := genesis.MustCommit(db) // Assemble a chain of headers from the cast votes config := *params.TestChainConfig @@ -414,7 +414,7 @@ func TestClique(t *testing.T) { engine := New(config.Clique, db) engine.fakeDiff = true - blocks, _ := core.GenerateChain(&config, genesis.ToBlock(db), engine, db, len(tt.votes), func(j int, gen *core.BlockGen) { + blocks, _ := core.GenerateChain(&config, genesisBlock, engine, db, len(tt.votes), func(j int, gen *core.BlockGen) { // Cast the vote contained in this block gen.SetCoinbase(accounts.address(tt.votes[j].voted)) if tt.votes[j].auth { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 517cb5e1d507..44256f6187da 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1941,8 +1941,8 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon Alloc: GenesisAlloc{addr: {Balance: big.NewInt(math.MaxInt64)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - signer = types.LatestSigner(gspec.Config) - genesis, _ = gspec.Commit(db) + signer = types.LatestSigner(gspec.Config) + genesis = gspec.MustCommit(db) ) // Generate and import the canonical chain diskdb := rawdb.NewMemoryDatabase() diff --git a/core/genesis.go b/core/genesis.go index 45284f3deea6..71214e84f505 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -80,10 +80,12 @@ func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error { return nil } -// flush adds allocated genesis accounts into a fresh new statedb and -// commit the state changes into the given database handler. -func (ga *GenesisAlloc) flush(db ethdb.Database) (common.Hash, error) { - statedb, err := state.New(common.Hash{}, state.NewDatabase(db), nil) +// deriveHash computes the state root according to the genesis specification. +func (ga *GenesisAlloc) deriveHash() (common.Hash, error) { + // Create an ephemeral in-memory database for computing hash, + // all the derived states will be discarded to not pollute disk. + db := state.NewDatabase(rawdb.NewMemoryDatabase()) + statedb, err := state.New(common.Hash{}, db, nil) if err != nil { return common.Hash{}, err } @@ -95,25 +97,39 @@ func (ga *GenesisAlloc) flush(db ethdb.Database) (common.Hash, error) { statedb.SetState(addr, key, value) } } + return statedb.Commit(false) +} + +// flush is very similar with deriveHash, but the main difference is +// all the generated states will be persisted into the given database. +// Also, the genesis state specification will be flushed as well. +func (ga *GenesisAlloc) flush(db ethdb.Database) error { + statedb, err := state.New(common.Hash{}, state.NewDatabase(db), nil) + if err != nil { + return err + } + for addr, account := range *ga { + statedb.AddBalance(addr, account.Balance) + statedb.SetCode(addr, account.Code) + statedb.SetNonce(addr, account.Nonce) + for key, value := range account.Storage { + statedb.SetState(addr, key, value) + } + } root, err := statedb.Commit(false) if err != nil { - return common.Hash{}, err + return err } err = statedb.Database().TrieDB().Commit(root, true, nil) if err != nil { - return common.Hash{}, err + return err } - return root, nil -} - -// write writes the json marshaled genesis state into database -// with the given block hash as the unique identifier. -func (ga *GenesisAlloc) write(db ethdb.KeyValueWriter, hash common.Hash) error { + // Marshal the genesis state specification and persist. blob, err := json.Marshal(ga) if err != nil { return err } - rawdb.WriteGenesisState(db, hash, blob) + rawdb.WriteGenesisStateSpec(db, root, blob) return nil } @@ -121,7 +137,7 @@ func (ga *GenesisAlloc) write(db ethdb.KeyValueWriter, hash common.Hash) error { // hash and commits them into the given database handler. func CommitGenesisState(db ethdb.Database, hash common.Hash) error { var alloc GenesisAlloc - blob := rawdb.ReadGenesisState(db, hash) + blob := rawdb.ReadGenesisStateSpec(db, hash) if len(blob) != 0 { if err := alloc.UnmarshalJSON(blob); err != nil { return err @@ -151,8 +167,7 @@ func CommitGenesisState(db ethdb.Database, hash common.Hash) error { return errors.New("not found") } } - _, err := alloc.flush(db) - return err + return alloc.flush(db) } // GenesisAccount is an account in the state of the genesis block. @@ -273,7 +288,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override genesis = DefaultGenesisBlock() } // Ensure the stored genesis matches with the given one. - hash := genesis.ToBlock(nil).Hash() + hash := genesis.ToBlock().Hash() if hash != stored { return genesis.Config, hash, &GenesisMismatchError{stored, hash} } @@ -286,7 +301,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override } // Check whether the genesis block is already written. if genesis != nil { - hash := genesis.ToBlock(nil).Hash() + hash := genesis.ToBlock().Hash() if hash != stored { return genesis.Config, hash, &GenesisMismatchError{stored, hash} } @@ -347,13 +362,9 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { } } -// ToBlock creates the genesis block and writes state of a genesis specification -// to the given database (or discards it if nil). -func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { - if db == nil { - db = rawdb.NewMemoryDatabase() - } - root, err := g.Alloc.flush(db) +// ToBlock returns the genesis block according to genesis specification. +func (g *Genesis) ToBlock() *types.Block { + root, err := g.Alloc.deriveHash() if err != nil { panic(err) } @@ -390,7 +401,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { // Commit writes the block and state of a genesis specification to the database. // The block is committed as the canonical head block. func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { - block := g.ToBlock(db) + block := g.ToBlock() if block.Number().Sign() != 0 { return nil, errors.New("can't commit genesis block with number > 0") } @@ -404,7 +415,10 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength { return nil, errors.New("can't start clique chain without signers") } - if err := g.Alloc.write(db, block.Hash()); err != nil { + // All the checks has passed, flush the states derived from the genesis + // specification as well as the specification itself into the provided + // database. + if err := g.Alloc.flush(db); err != nil { return nil, err } rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) @@ -428,15 +442,6 @@ func (g *Genesis) MustCommit(db ethdb.Database) *types.Block { return block } -// GenesisBlockForTesting creates and writes a block in which addr has the given wei balance. -func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block { - g := Genesis{ - Alloc: GenesisAlloc{addr: {Balance: balance}}, - BaseFee: big.NewInt(params.InitialBaseFee), - } - return g.MustCommit(db) -} - // DefaultGenesisBlock returns the Ethereum main net genesis block. func DefaultGenesisBlock() *Genesis { return &Genesis{ @@ -498,6 +503,7 @@ func DefaultSepoliaGenesisBlock() *Genesis { } } +// DefaultKilnGenesisBlock returns the kiln network genesis block. func DefaultKilnGenesisBlock() *Genesis { g := new(Genesis) reader := strings.NewReader(KilnAllocData) diff --git a/core/genesis_test.go b/core/genesis_test.go index e8010e3d4ebd..ba3423e32a08 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -178,7 +178,7 @@ func TestGenesisHashes(t *testing.T) { t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex()) } // Test via ToBlock - if have := c.genesis.ToBlock(nil).Hash(); have != c.want { + if have := c.genesis.ToBlock().Hash(); have != c.want { t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex()) } } @@ -192,11 +192,7 @@ func TestGenesis_Commit(t *testing.T) { } db := rawdb.NewMemoryDatabase() - genesisBlock, err := genesis.Commit(db) - if err != nil { - t.Fatal(err) - } - + genesisBlock := genesis.MustCommit(db) if genesis.Difficulty != nil { t.Fatalf("assumption wrong") } @@ -221,12 +217,12 @@ func TestReadWriteGenesisAlloc(t *testing.T) { {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, {2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}}, } - hash = common.HexToHash("0xdeadbeef") + hash, _ = alloc.deriveHash() ) - alloc.write(db, hash) + alloc.flush(db) var reload GenesisAlloc - err := reload.UnmarshalJSON(rawdb.ReadGenesisState(db, hash)) + err := reload.UnmarshalJSON(rawdb.ReadGenesisStateSpec(db, hash)) if err != nil { t.Fatalf("Failed to load genesis state %v", err) } diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go index f5a161adb688..7a9e6442f011 100644 --- a/core/rawdb/accessors_metadata.go +++ b/core/rawdb/accessors_metadata.go @@ -81,15 +81,16 @@ func WriteChainConfig(db ethdb.KeyValueWriter, hash common.Hash, cfg *params.Cha } } -// ReadGenesisState retrieves the genesis state based on the given genesis hash. -func ReadGenesisState(db ethdb.KeyValueReader, hash common.Hash) []byte { - data, _ := db.Get(genesisKey(hash)) +// ReadGenesisStateSpec retrieves the genesis state specification based on the +// given genesis hash. +func ReadGenesisStateSpec(db ethdb.KeyValueReader, hash common.Hash) []byte { + data, _ := db.Get(genesisStateSpecKey(hash)) return data } -// WriteGenesisState writes the genesis state into the disk. -func WriteGenesisState(db ethdb.KeyValueWriter, hash common.Hash, data []byte) { - if err := db.Put(genesisKey(hash), data); err != nil { +// WriteGenesisStateSpec writes the genesis state specification into the disk. +func WriteGenesisStateSpec(db ethdb.KeyValueWriter, hash common.Hash, data []byte) { + if err := db.Put(genesisStateSpecKey(hash), data); err != nil { log.Crit("Failed to store genesis state", "err", err) } } diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index a55ebdff74a2..d5f751da3a13 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -220,7 +220,7 @@ func configKey(hash common.Hash) []byte { return append(configPrefix, hash.Bytes()...) } -// genesisKey = genesisPrefix + hash -func genesisKey(hash common.Hash) []byte { +// genesisStateSpecKey = genesisPrefix + hash +func genesisStateSpecKey(hash common.Hash) []byte { return append(genesisPrefix, hash.Bytes()...) } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index df302f8211c7..0d945993eb37 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -69,7 +69,7 @@ func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) { g.AddTx(tx) testNonce++ } - gblock := genesis.ToBlock(db) + gblock := genesis.MustCommit(db) engine := ethash.NewFaker() blocks, _ := core.GenerateChain(config, gblock, engine, db, n, generate) totalDifficulty := big.NewInt(0) diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 5e77d3272d63..1c126bdaed38 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -68,7 +68,11 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester { t.Cleanup(func() { db.Close() }) - core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000)) + gspec := core.Genesis{ + Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + gspec.MustCommit(db) chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { diff --git a/eth/downloader/queue_test.go b/eth/downloader/queue_test.go index d2dfbceffbf5..8631b27c9275 100644 --- a/eth/downloader/queue_test.go +++ b/eth/downloader/queue_test.go @@ -27,24 +27,18 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" ) -var ( - testdb = rawdb.NewMemoryDatabase() - genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000000000)) -) - // 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. 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) { + 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 if !empty && i%2 == 0 { @@ -70,10 +64,10 @@ var emptyChain *chainData func init() { // Create a chain of blocks to import targetBlocks := 128 - blocks, _ := makeChain(targetBlocks, 0, genesis, false) + blocks, _ := makeChain(targetBlocks, 0, testGenesis, false) chain = &chainData{blocks, 0} - blocks, _ = makeChain(targetBlocks, 0, genesis, true) + blocks, _ = makeChain(targetBlocks, 0, testGenesis, true) emptyChain = &chainData{blocks, 0} } @@ -271,7 +265,7 @@ func TestEmptyBlocks(t *testing.T) { // some more advanced scenarios func XTestDelivery(t *testing.T) { // the outside network, holding blocks - blo, rec := makeChain(128, 0, genesis, false) + blo, rec := makeChain(128, 0, testGenesis, false) world := newNetwork() world.receipts = rec world.chain = blo diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 8b873343cac4..785da40b5989 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -37,7 +37,12 @@ var ( testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testAddress = crypto.PubkeyToAddress(testKey.PublicKey) testDB = rawdb.NewMemoryDatabase() - testGenesis = core.GenesisBlockForTesting(testDB, testAddress, big.NewInt(1000000000000000)) + + testGspec = core.Genesis{ + Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + testGenesis = testGspec.MustCommit(testDB) ) // The common prefix of all test chains: @@ -212,7 +217,7 @@ func newTestBlockchain(blocks []*types.Block) *core.BlockChain { panic("Requested chain generation outside of init") } db := rawdb.NewMemoryDatabase() - core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000)) + testGspec.MustCommit(db) chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { diff --git a/eth/fetcher/block_fetcher_test.go b/eth/fetcher/block_fetcher_test.go index 06c61ae55d20..bf7946952e49 100644 --- a/eth/fetcher/block_fetcher_test.go +++ b/eth/fetcher/block_fetcher_test.go @@ -36,10 +36,14 @@ import ( ) var ( - testdb = rawdb.NewMemoryDatabase() - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - testAddress = crypto.PubkeyToAddress(testKey.PublicKey) - genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000000000)) + testdb = rawdb.NewMemoryDatabase() + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + testAddress = crypto.PubkeyToAddress(testKey.PublicKey) + gspec = core.Genesis{ + Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + genesis = gspec.MustCommit(testdb) unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil)) ) diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index ae4f069048f3..59fdde7e809b 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -50,10 +50,17 @@ func BenchmarkFilters(b *testing.B) { addr2 = common.BytesToAddress([]byte("jeff")) addr3 = common.BytesToAddress([]byte("ethereum")) addr4 = common.BytesToAddress([]byte("random addresses please")) + + gspec = core.Genesis{ + Alloc: core.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + genesis = gspec.ToBlock() ) defer db.Close() - genesis := core.GenesisBlockForTesting(db, addr1, big.NewInt(1000000)) + gspec.MustCommit(db) + chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 100010, func(i int, gen *core.BlockGen) { switch i { case 2403: @@ -105,10 +112,17 @@ func TestFilters(t *testing.T) { hash2 = common.BytesToHash([]byte("topic2")) hash3 = common.BytesToHash([]byte("topic3")) hash4 = common.BytesToHash([]byte("topic4")) + + gspec = core.Genesis{ + Alloc: core.GenesisAlloc{addr: {Balance: big.NewInt(1000000)}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + genesis = gspec.ToBlock() ) defer db.Close() - genesis := core.GenesisBlockForTesting(db, addr, big.NewInt(1000000)) + gspec.MustCommit(db) + chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 1000, func(i int, gen *core.BlockGen) { switch i { case 1: diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 3806e993c282..d405188f8194 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -130,10 +130,8 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke config.TerminalTotalDifficulty = common.Big0 engine := ethash.NewFaker() db := rawdb.NewMemoryDatabase() - genesis, err := gspec.Commit(db) - if err != nil { - t.Fatal(err) - } + genesis := gspec.MustCommit(db) + // Generate testing blocks blocks, _ := core.GenerateChain(gspec.Config, genesis, engine, db, testHead+1, func(i int, b *core.BlockGen) { b.SetCoinbase(common.Address{1}) @@ -163,7 +161,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke }) // Construct testing chain diskdb := rawdb.NewMemoryDatabase() - gspec.Commit(diskdb) + gspec.MustCommit(diskdb) chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec.Config, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create local chain, %v", err) diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 37add1bd36f0..d78a12fae72b 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -248,7 +248,7 @@ func generateTestChain() []*types.Block { g.AddTx(testTx2) } } - gblock := genesis.ToBlock(db) + gblock := genesis.MustCommit(db) engine := ethash.NewFaker() blocks, _ := core.GenerateChain(genesis.Config, gblock, engine, db, 2, generate) blocks = append([]*types.Block{gblock}, blocks...) diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index a0c17a034226..b78d11c3283f 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -83,7 +83,7 @@ func generateTestChain() (*core.Genesis, []*types.Block) { g.OffsetTime(5) g.SetExtra([]byte("test")) } - gblock := genesis.ToBlock(db) + gblock := genesis.MustCommit(db) engine := ethash.NewFaker() blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate) blocks = append([]*types.Block{gblock}, blocks...) diff --git a/les/catalyst/api_test.go b/les/catalyst/api_test.go index 70a6d24719ea..26c49d6ef908 100644 --- a/les/catalyst/api_test.go +++ b/les/catalyst/api_test.go @@ -55,7 +55,7 @@ func generatePreMergeChain(n int) (*core.Genesis, []*types.Header, []*types.Bloc Timestamp: 9000, BaseFee: big.NewInt(params.InitialBaseFee), } - gblock := genesis.ToBlock(db) + gblock := genesis.MustCommit(db) engine := ethash.NewFaker() blocks, _ := core.GenerateChain(config, gblock, engine, db, n, nil) totalDifficulty := big.NewInt(0) diff --git a/les/downloader/queue_test.go b/les/downloader/queue_test.go index 848979479171..44b2208595ff 100644 --- a/les/downloader/queue_test.go +++ b/les/downloader/queue_test.go @@ -27,23 +27,17 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) -var ( - testdb = rawdb.NewMemoryDatabase() - genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000000000)) -) - // 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. 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) { + 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 if !empty && i%2 == 0 { @@ -69,10 +63,10 @@ var emptyChain *chainData func init() { // Create a chain of blocks to import targetBlocks := 128 - blocks, _ := makeChain(targetBlocks, 0, genesis, false) + blocks, _ := makeChain(targetBlocks, 0, testGenesis, false) chain = &chainData{blocks, 0} - blocks, _ = makeChain(targetBlocks, 0, genesis, true) + blocks, _ = makeChain(targetBlocks, 0, testGenesis, true) emptyChain = &chainData{blocks, 0} } @@ -259,7 +253,7 @@ func TestEmptyBlocks(t *testing.T) { // some more advanced scenarios func XTestDelivery(t *testing.T) { // the outside network, holding blocks - blo, rec := makeChain(128, 0, genesis, false) + blo, rec := makeChain(128, 0, testGenesis, false) world := newNetwork() world.receipts = rec world.chain = blo diff --git a/les/downloader/testchain_test.go b/les/downloader/testchain_test.go index b9865f7e032b..400eec94e7c4 100644 --- a/les/downloader/testchain_test.go +++ b/les/downloader/testchain_test.go @@ -35,7 +35,12 @@ var ( testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testAddress = crypto.PubkeyToAddress(testKey.PublicKey) testDB = rawdb.NewMemoryDatabase() - testGenesis = core.GenesisBlockForTesting(testDB, testAddress, big.NewInt(1000000000000000)) + + gspec = core.Genesis{ + Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + testGenesis = gspec.MustCommit(testDB) ) // The common prefix of all test chains: diff --git a/les/fetcher/block_fetcher_test.go b/les/fetcher/block_fetcher_test.go index de066ac26b5f..caff7a3b3559 100644 --- a/les/fetcher/block_fetcher_test.go +++ b/les/fetcher/block_fetcher_test.go @@ -35,10 +35,15 @@ import ( ) var ( - testdb = rawdb.NewMemoryDatabase() - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - testAddress = crypto.PubkeyToAddress(testKey.PublicKey) - genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000000000)) + testdb = rawdb.NewMemoryDatabase() + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + testAddress = crypto.PubkeyToAddress(testKey.PublicKey) + + gspec = core.Genesis{ + Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + genesis = gspec.MustCommit(testdb) unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil)) ) diff --git a/les/peer_test.go b/les/peer_test.go index d6551ce6b639..b8a1482a040a 100644 --- a/les/peer_test.go +++ b/les/peer_test.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/forkid" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" @@ -100,7 +99,7 @@ type fakeChain struct{} func (f *fakeChain) Config() *params.ChainConfig { return params.MainnetChainConfig } func (f *fakeChain) Genesis() *types.Block { - return core.DefaultGenesisBlock().ToBlock(rawdb.NewMemoryDatabase()) + return core.DefaultGenesisBlock().ToBlock() } func (f *fakeChain) CurrentHeader() *types.Header { return &types.Header{Number: big.NewInt(10000000)} } diff --git a/miner/stress/beacon/main.go b/miner/stress/beacon/main.go index 439bcc5d10bd..88af84c7fcd3 100644 --- a/miner/stress/beacon/main.go +++ b/miner/stress/beacon/main.go @@ -236,7 +236,7 @@ func newNodeManager(genesis *core.Genesis) *nodeManager { return &nodeManager{ close: make(chan struct{}), genesis: genesis, - genesisBlock: genesis.ToBlock(nil), + genesisBlock: genesis.ToBlock(), } } diff --git a/tests/state_test.go b/tests/state_test.go index 965ef71ba40e..d33ebc4b00db 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -193,7 +193,7 @@ func runBenchmark(b *testing.B, t *StateTest) { return } vmconfig.ExtraEips = eips - block := t.genesis(config).ToBlock(nil) + block := t.genesis(config).ToBlock() _, statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, false) var baseFee *big.Int diff --git a/tests/state_test_util.go b/tests/state_test_util.go index d698b7c6fdd1..38cdbc4d6504 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -184,7 +184,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh return nil, nil, common.Hash{}, UnsupportedForkError{subtest.Fork} } vmconfig.ExtraEips = eips - block := t.genesis(config).ToBlock(nil) + block := t.genesis(config).ToBlock() snaps, statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter) var baseFee *big.Int From 877ef7f09e5296b15033dccb0e3a318f3583a6ca Mon Sep 17 00:00:00 2001 From: ycyraum Date: Wed, 10 Aug 2022 08:02:37 +0200 Subject: [PATCH 154/715] core: remove unused bc ChainContext in applyTransaction --- core/state_processor.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index d4c77ae41042..e511697c5f6a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -79,7 +79,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.Prepare(tx.Hash(), i) - receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) + receipt, err := applyTransaction(msg, p.config, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -92,7 +92,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return receipts, allLogs, *usedGas, nil } -func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { +func applyTransaction(msg types.Message, config *params.ChainConfig, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) evm.Reset(txContext, statedb) @@ -149,5 +149,5 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // Create a new context to be used in the EVM environment blockContext := NewEVMBlockContext(header, bc, author) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) - return applyTransaction(msg, config, bc, author, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) + return applyTransaction(msg, config, author, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) } From 1a18c14c43035fbcad98e986b8ac40719a8c15dc Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 10 Aug 2022 09:31:15 +0200 Subject: [PATCH 155/715] signer/rules: register clef api properly when rules are used (#25455) signer/rules: register clef api properly when rules are used, fixes #25298 --- signer/rules/rules.go | 1 + 1 file changed, 1 insertion(+) diff --git a/signer/rules/rules.go b/signer/rules/rules.go index 95b02e9cecf0..5ed4514e0227 100644 --- a/signer/rules/rules.go +++ b/signer/rules/rules.go @@ -59,6 +59,7 @@ func NewRuleEvaluator(next core.UIClientAPI, jsbackend storage.Storage) (*rulese return c, nil } func (r *rulesetUI) RegisterUIServer(api *core.UIServerAPI) { + r.next.RegisterUIServer(api) // TODO, make it possible to query from js } From c0cc6f63629678ad7a8d9a33dc17bcf26122bde0 Mon Sep 17 00:00:00 2001 From: 0xe3b0c4 <110295932+0xe3b0c4@users.noreply.github.com> Date: Wed, 10 Aug 2022 16:30:59 +0800 Subject: [PATCH 156/715] build: add static linking support (#25492) This adds support for building statically-linked executables using ci.go. Static linking is enabled by default in Docker builds, making it possible to use the geth executable in any Docker image, regardless of the Linux distribution the Dockerfile is based on. Co-authored-by: Felix Lange --- Dockerfile | 2 +- Dockerfile.alltools | 2 +- build/ci.go | 33 ++++++++++++++++++++++----------- internal/build/util.go | 19 +++++++++++++++++-- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/Dockerfile b/Dockerfile index 70299190f90f..143c92f27f50 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ COPY go.sum /go-ethereum/ RUN cd /go-ethereum && go mod download ADD . /go-ethereum -RUN cd /go-ethereum && go run build/ci.go install ./cmd/geth +RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth # Pull Geth into a second stage deploy alpine container FROM alpine:latest diff --git a/Dockerfile.alltools b/Dockerfile.alltools index b11492cabc9c..176c4592206d 100644 --- a/Dockerfile.alltools +++ b/Dockerfile.alltools @@ -14,7 +14,7 @@ COPY go.sum /go-ethereum/ RUN cd /go-ethereum && go mod download ADD . /go-ethereum -RUN cd /go-ethereum && go run build/ci.go install +RUN cd /go-ethereum && go run build/ci.go install -static # Pull all binaries into a second stage deploy alpine container FROM alpine:latest diff --git a/build/ci.go b/build/ci.go index 526e76f38132..f91de328bebc 100644 --- a/build/ci.go +++ b/build/ci.go @@ -200,9 +200,10 @@ func main() { func doInstall(cmdline []string) { var ( - dlgo = flag.Bool("dlgo", false, "Download Go and build with it") - arch = flag.String("arch", "", "Architecture to cross build for") - cc = flag.String("cc", "", "C compiler to cross build with") + dlgo = flag.Bool("dlgo", false, "Download Go and build with it") + arch = flag.String("arch", "", "Architecture to cross build for") + cc = flag.String("cc", "", "C compiler to cross build with") + staticlink = flag.Bool("static", false, "Create statically-linked executable") ) flag.CommandLine.Parse(cmdline) @@ -213,9 +214,12 @@ func doInstall(cmdline []string) { tc.Root = build.DownloadGo(csdb, dlgoVersion) } + // Disable CLI markdown doc generation in release builds. + buildTags := []string{"urfave_cli_no_docs"} + // Configure the build. env := build.Env() - gobuild := tc.Go("build", buildFlags(env)...) + gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...) // arm64 CI builders are memory-constrained and can't handle concurrent builds, // better disable it. This check isn't the best, it should probably @@ -224,9 +228,6 @@ func doInstall(cmdline []string) { gobuild.Args = append(gobuild.Args, "-p", "1") } - // Disable CLI markdown doc generation in release builds. - gobuild.Args = append(gobuild.Args, "-tags", "urfave_cli_no_docs") - // We use -trimpath to avoid leaking local paths into the built executables. gobuild.Args = append(gobuild.Args, "-trimpath") @@ -251,7 +252,7 @@ func doInstall(cmdline []string) { } // buildFlags returns the go tool flags for building. -func buildFlags(env build.Environment) (flags []string) { +func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) { var ld []string if env.Commit != "" { ld = append(ld, "-X", "main.gitCommit="+env.Commit) @@ -262,14 +263,24 @@ func buildFlags(env build.Environment) (flags []string) { if runtime.GOOS == "darwin" { ld = append(ld, "-s") } - // Enforce the stacksize to 8M, which is the case on most platforms apart from - // alpine Linux. if runtime.GOOS == "linux" { - ld = append(ld, "-extldflags", "-Wl,-z,stack-size=0x800000") + // Enforce the stacksize to 8M, which is the case on most platforms apart from + // alpine Linux. + extld := []string{"-Wl,-z,stack-size=0x800000"} + if staticLinking { + extld = append(extld, "-static") + // Under static linking, use of certain glibc features must be + // disabled to avoid shared library dependencies. + buildTags = append(buildTags, "osusergo", "netgo") + } + ld = append(ld, "-extldflags", "'"+strings.Join(extld, " ")+"'") } if len(ld) > 0 { flags = append(flags, "-ldflags", strings.Join(ld, " ")) } + if len(buildTags) > 0 { + flags = append(flags, "-tags", strings.Join(buildTags, ",")) + } return flags } diff --git a/internal/build/util.go b/internal/build/util.go index 654349fac307..9a721e9b83b1 100644 --- a/internal/build/util.go +++ b/internal/build/util.go @@ -29,6 +29,7 @@ import ( "os/exec" "path" "path/filepath" + "strconv" "strings" "text/template" "time" @@ -39,7 +40,7 @@ var DryRunFlag = flag.Bool("n", false, "dry run, don't execute commands") // MustRun executes the given command and exits the host process for // any error. func MustRun(cmd *exec.Cmd) { - fmt.Println(">>>", strings.Join(cmd.Args, " ")) + fmt.Println(">>>", printArgs(cmd.Args)) if !*DryRunFlag { cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout @@ -49,6 +50,20 @@ func MustRun(cmd *exec.Cmd) { } } +func printArgs(args []string) string { + var s strings.Builder + for i, arg := range args { + if i > 0 { + s.WriteByte(' ') + } + if strings.IndexByte(arg, ' ') >= 0 { + arg = strconv.QuoteToASCII(arg) + } + s.WriteString(arg) + } + return s.String() +} + func MustRunCommand(cmd string, args ...string) { MustRun(exec.Command(cmd, args...)) } @@ -121,7 +136,7 @@ func UploadSFTP(identityFile, host, dir string, files []string) error { sftp.Args = append(sftp.Args, "-i", identityFile) } sftp.Args = append(sftp.Args, host) - fmt.Println(">>>", strings.Join(sftp.Args, " ")) + fmt.Println(">>>", printArgs(sftp.Args)) if *DryRunFlag { return nil } From 366d2169fbc0e0f803b68c042b77b6b480836dbc Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Thu, 11 Aug 2022 00:25:54 -0700 Subject: [PATCH 157/715] accounts/abi: display name in "method/event not found" error (#25512) --- accounts/abi/abi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index ed5b6e92ef9c..81bbee2f2b4a 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -95,7 +95,7 @@ func (abi ABI) getArguments(name string, data []byte) (Arguments, error) { args = event.Inputs } if args == nil { - return nil, errors.New("abi: could not locate named method or event") + return nil, fmt.Errorf("abi: could not locate named method or event: %s", name) } return args, nil } From 0be9d76e3702cfae92f042cf6a113e22479de3f5 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 11 Aug 2022 02:56:53 -0600 Subject: [PATCH 158/715] internal/ethapi: rework setDefaults for tx args so fee logic is separate (#25197) Co-authored-by: bobpkr --- internal/ethapi/transaction_args.go | 118 ++++---- internal/ethapi/transaction_args_test.go | 342 +++++++++++++++++++++++ 2 files changed, 410 insertions(+), 50 deletions(-) create mode 100644 internal/ethapi/transaction_args_test.go diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index cb2782ca052c..787ac65777e0 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -75,56 +75,8 @@ func (args *TransactionArgs) data() []byte { // setDefaults fills in default values for unspecified tx fields. func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { - if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { - return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") - } - // After london, default to 1559 unless gasPrice is set - head := b.CurrentHeader() - // If user specifies both maxPriorityfee and maxFee, then we do not - // need to consult the chain for defaults. It's definitely a London tx. - if args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil { - // In this clause, user left some fields unspecified. - if b.ChainConfig().IsLondon(head.Number) && args.GasPrice == nil { - if args.MaxPriorityFeePerGas == nil { - tip, err := b.SuggestGasTipCap(ctx) - if err != nil { - return err - } - args.MaxPriorityFeePerGas = (*hexutil.Big)(tip) - } - if args.MaxFeePerGas == nil { - gasFeeCap := new(big.Int).Add( - (*big.Int)(args.MaxPriorityFeePerGas), - new(big.Int).Mul(head.BaseFee, big.NewInt(2)), - ) - args.MaxFeePerGas = (*hexutil.Big)(gasFeeCap) - } - if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { - return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) - } - } else { - if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil { - return errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet") - } - if args.GasPrice == nil { - price, err := b.SuggestGasTipCap(ctx) - if err != nil { - return err - } - if b.ChainConfig().IsLondon(head.Number) { - // The legacy tx gas price suggestion should not add 2x base fee - // because all fees are consumed, so it would result in a spiral - // upwards. - price.Add(price, head.BaseFee) - } - args.GasPrice = (*hexutil.Big)(price) - } - } - } else { - // Both maxPriorityfee and maxFee set by caller. Sanity-check their internal relation - if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { - return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) - } + if err := args.setFeeDefaults(ctx, b); err != nil { + return err } if args.Value == nil { args.Value = new(hexutil.Big) @@ -178,6 +130,72 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { return nil } +// setFeeDefaults fills in default fee values for unspecified tx fields. +func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) error { + // If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error. + if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { + return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") + } + // If the tx has completely specified a fee mechanism, no default is needed. This allows users + // who are not yet synced past London to get defaults for other tx values. See + // https://github.com/ethereum/go-ethereum/pull/23274 for more information. + eip1559ParamsSet := args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil + if (args.GasPrice != nil && !eip1559ParamsSet) || (args.GasPrice == nil && eip1559ParamsSet) { + // Sanity check the EIP-1559 fee parameters if present. + if args.GasPrice == nil && args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { + return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) + } + return nil + } + // Now attempt to fill in default value depending on whether London is active or not. + head := b.CurrentHeader() + if b.ChainConfig().IsLondon(head.Number) { + // London is active, set maxPriorityFeePerGas and maxFeePerGas. + if err := args.setLondonFeeDefaults(ctx, head, b); err != nil { + return err + } + } else { + if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil { + return fmt.Errorf("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active") + } + // London not active, set gas price. + price, err := b.SuggestGasTipCap(ctx) + if err != nil { + return err + } + args.GasPrice = (*hexutil.Big)(price) + } + return nil +} + +// setLondonFeeDefaults fills in reasonable default fee values for unspecified fields. +func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *types.Header, b Backend) error { + // Set maxPriorityFeePerGas if it is missing. + if args.MaxPriorityFeePerGas == nil { + tip, err := b.SuggestGasTipCap(ctx) + if err != nil { + return err + } + args.MaxPriorityFeePerGas = (*hexutil.Big)(tip) + } + // Set maxFeePerGas if it is missing. + if args.MaxFeePerGas == nil { + // Set the max fee to be 2 times larger than the previous block's base fee. + // The additional slack allows the tx to not become invalidated if the base + // fee is rising. + val := new(big.Int).Add( + args.MaxPriorityFeePerGas.ToInt(), + new(big.Int).Mul(head.BaseFee, big.NewInt(2)), + ) + args.MaxFeePerGas = (*hexutil.Big)(val) + } + // Both EIP-1559 fee parameters are now set; sanity check them. + if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { + return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) + } + return nil +} + // ToMessage converts the transaction arguments to the Message type used by the // core evm. This method is used in calls and traces that do not require a real // live transaction. diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go new file mode 100644 index 000000000000..92f009aa849e --- /dev/null +++ b/internal/ethapi/transaction_args_test.go @@ -0,0 +1,342 @@ +// Copyright 2022 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 ethapi + +import ( + "context" + "fmt" + "math/big" + "reflect" + "testing" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" +) + +// TestSetFeeDefaults tests the logic for filling in default fee values works as expected. +func TestSetFeeDefaults(t *testing.T) { + type test struct { + name string + isLondon bool + in *TransactionArgs + want *TransactionArgs + err error + } + + var ( + b = newBackendMock() + fortytwo = (*hexutil.Big)(big.NewInt(42)) + maxFee = (*hexutil.Big)(new(big.Int).Add(new(big.Int).Mul(b.current.BaseFee, big.NewInt(2)), fortytwo.ToInt())) + al = &types.AccessList{types.AccessTuple{Address: common.Address{0xaa}, StorageKeys: []common.Hash{{0x01}}}} + ) + + tests := []test{ + // Legacy txs + { + "legacy tx pre-London", + false, + &TransactionArgs{}, + &TransactionArgs{GasPrice: fortytwo}, + nil, + }, + { + "legacy tx post-London, explicit gas price", + true, + &TransactionArgs{GasPrice: fortytwo}, + &TransactionArgs{GasPrice: fortytwo}, + nil, + }, + + // Access list txs + { + "access list tx pre-London", + false, + &TransactionArgs{AccessList: al}, + &TransactionArgs{AccessList: al, GasPrice: fortytwo}, + nil, + }, + { + "access list tx post-London, explicit gas price", + false, + &TransactionArgs{AccessList: al, GasPrice: fortytwo}, + &TransactionArgs{AccessList: al, GasPrice: fortytwo}, + nil, + }, + { + "access list tx post-London", + true, + &TransactionArgs{AccessList: al}, + &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, + nil, + }, + { + "access list tx post-London, only max fee", + true, + &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee}, + &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, + nil, + }, + { + "access list tx post-London, only priority fee", + true, + &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee}, + &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, + nil, + }, + + // Dynamic fee txs + { + "dynamic tx post-London", + true, + &TransactionArgs{}, + &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, + nil, + }, + { + "dynamic tx post-London, only max fee", + true, + &TransactionArgs{MaxFeePerGas: maxFee}, + &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, + nil, + }, + { + "dynamic tx post-London, only priority fee", + true, + &TransactionArgs{MaxFeePerGas: maxFee}, + &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, + nil, + }, + { + "dynamic fee tx pre-London, maxFee set", + false, + &TransactionArgs{MaxFeePerGas: maxFee}, + nil, + fmt.Errorf("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active"), + }, + { + "dynamic fee tx pre-London, priorityFee set", + false, + &TransactionArgs{MaxPriorityFeePerGas: fortytwo}, + nil, + fmt.Errorf("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active"), + }, + { + "dynamic fee tx, maxFee < priorityFee", + true, + &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: (*hexutil.Big)(big.NewInt(1000))}, + nil, + fmt.Errorf("maxFeePerGas (0x3e) < maxPriorityFeePerGas (0x3e8)"), + }, + { + "dynamic fee tx, maxFee < priorityFee while setting default", + true, + &TransactionArgs{MaxFeePerGas: (*hexutil.Big)(big.NewInt(7))}, + nil, + fmt.Errorf("maxFeePerGas (0x7) < maxPriorityFeePerGas (0x2a)"), + }, + + // Misc + { + "set all fee parameters", + false, + &TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, + nil, + fmt.Errorf("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"), + }, + { + "set gas price and maxPriorityFee", + false, + &TransactionArgs{GasPrice: fortytwo, MaxPriorityFeePerGas: fortytwo}, + nil, + fmt.Errorf("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"), + }, + { + "set gas price and maxFee", + true, + &TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee}, + nil, + fmt.Errorf("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"), + }, + } + + ctx := context.Background() + for i, test := range tests { + if test.isLondon { + b.activateLondon() + } else { + b.deactivateLondon() + } + got := test.in + err := got.setFeeDefaults(ctx, b) + if err != nil && err.Error() == test.err.Error() { + // Test threw expected error. + continue + } else if err != nil { + t.Fatalf("test %d (%s): unexpected error: %s", i, test.name, err) + } + if !reflect.DeepEqual(got, test.want) { + t.Fatalf("test %d (%s): did not fill defaults as expected: (got: %v, want: %v)", i, test.name, got, test.want) + } + } +} + +type backendMock struct { + current *types.Header + config *params.ChainConfig +} + +func newBackendMock() *backendMock { + config := ¶ms.ChainConfig{ + ChainID: big.NewInt(42), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(1000), + } + return &backendMock{ + current: &types.Header{ + Difficulty: big.NewInt(10000000000), + Number: big.NewInt(1100), + GasLimit: 8_000_000, + GasUsed: 8_000_000, + Time: 555, + Extra: make([]byte, 32), + BaseFee: big.NewInt(10), + }, + config: config, + } +} + +func (b *backendMock) activateLondon() { + b.current.Number = big.NewInt(1100) +} + +func (b *backendMock) deactivateLondon() { + b.current.Number = big.NewInt(900) +} +func (b *backendMock) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { + return big.NewInt(42), nil +} +func (b *backendMock) CurrentHeader() *types.Header { return b.current } +func (b *backendMock) ChainConfig() *params.ChainConfig { return b.config } + +// Other methods needed to implement Backend interface. +func (b *backendMock) SyncProgress() ethereum.SyncProgress { return ethereum.SyncProgress{} } +func (b *backendMock) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { + return nil, nil, nil, nil, nil +} +func (b *backendMock) ChainDb() ethdb.Database { return nil } +func (b *backendMock) AccountManager() *accounts.Manager { return nil } +func (b *backendMock) ExtRPCEnabled() bool { return false } +func (b *backendMock) RPCGasCap() uint64 { return 0 } +func (b *backendMock) RPCEVMTimeout() time.Duration { return time.Second } +func (b *backendMock) RPCTxFeeCap() float64 { return 0 } +func (b *backendMock) UnprotectedAllowed() bool { return false } +func (b *backendMock) SetHead(number uint64) {} +func (b *backendMock) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { + return nil, nil +} +func (b *backendMock) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { + return nil, nil +} +func (b *backendMock) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { + return nil, nil +} +func (b *backendMock) CurrentBlock() *types.Block { return nil } +func (b *backendMock) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { + return nil, nil +} +func (b *backendMock) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { + return nil, nil +} +func (b *backendMock) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { + return nil, nil +} +func (b *backendMock) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { + return nil, nil, nil +} +func (b *backendMock) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { + return nil, nil, nil +} +func (b *backendMock) PendingBlockAndReceipts() (*types.Block, types.Receipts) { return nil, nil } +func (b *backendMock) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { + return nil, nil +} +func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } +func (b *backendMock) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { + return nil, nil, nil +} +func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil } +func (b *backendMock) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { + return nil +} +func (b *backendMock) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { + return nil +} +func (b *backendMock) SendTx(ctx context.Context, signedTx *types.Transaction) error { return nil } +func (b *backendMock) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { + return nil, [32]byte{}, 0, 0, nil +} +func (b *backendMock) GetPoolTransactions() (types.Transactions, error) { return nil, nil } +func (b *backendMock) GetPoolTransaction(txHash common.Hash) *types.Transaction { return nil } +func (b *backendMock) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { + return 0, nil +} +func (b *backendMock) Stats() (pending int, queued int) { return 0, 0 } +func (b *backendMock) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { + return nil, nil +} +func (b *backendMock) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) { + return nil, nil +} +func (b *backendMock) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription { return nil } +func (b *backendMock) BloomStatus() (uint64, uint64) { return 0, 0 } +func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) { + return nil, nil +} +func (b *backendMock) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {} +func (b *backendMock) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return nil } +func (b *backendMock) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { + return nil +} +func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { + return nil +} + +func (b *backendMock) Engine() consensus.Engine { return nil } From 141cd425310b503c5678e674a8c3872cf46b7086 Mon Sep 17 00:00:00 2001 From: ycyraum Date: Fri, 12 Aug 2022 13:58:06 +0200 Subject: [PATCH 159/715] core/genesis: remove calaverasAllocData (#25516) core/genesis: calaverasAllocData no longer used --- core/genesis_alloc.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/genesis_alloc.go b/core/genesis_alloc.go index 041c55424238..16df390575c2 100644 --- a/core/genesis_alloc.go +++ b/core/genesis_alloc.go @@ -25,7 +25,6 @@ const mainnetAllocData = "\xfa\x04]X\u0793\r\x83b\x011\x8e\u0189\x9agT\x06\x908' const ropstenAllocData = "\xf9\x03\xa4\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x80\xc2\v\x80\xc2\f\x80\xc2\r\x80\xc2\x0e\x80\xc2\x0f\x80\xc2\x10\x80\xc2\x11\x80\xc2\x12\x80\xc2\x13\x80\xc2\x14\x80\xc2\x15\x80\xc2\x16\x80\xc2\x17\x80\xc2\x18\x80\xc2\x19\x80\xc2\x1a\x80\xc2\x1b\x80\xc2\x1c\x80\xc2\x1d\x80\xc2\x1e\x80\xc2\x1f\x80\xc2 \x80\xc2!\x80\xc2\"\x80\xc2#\x80\xc2$\x80\xc2%\x80\xc2&\x80\xc2'\x80\xc2(\x80\xc2)\x80\xc2*\x80\xc2+\x80\xc2,\x80\xc2-\x80\xc2.\x80\xc2/\x80\xc20\x80\xc21\x80\xc22\x80\xc23\x80\xc24\x80\xc25\x80\xc26\x80\xc27\x80\xc28\x80\xc29\x80\xc2:\x80\xc2;\x80\xc2<\x80\xc2=\x80\xc2>\x80\xc2?\x80\xc2@\x80\xc2A\x80\xc2B\x80\xc2C\x80\xc2D\x80\xc2E\x80\xc2F\x80\xc2G\x80\xc2H\x80\xc2I\x80\xc2J\x80\xc2K\x80\xc2L\x80\xc2M\x80\xc2N\x80\xc2O\x80\xc2P\x80\xc2Q\x80\xc2R\x80\xc2S\x80\xc2T\x80\xc2U\x80\xc2V\x80\xc2W\x80\xc2X\x80\xc2Y\x80\xc2Z\x80\xc2[\x80\xc2\\\x80\xc2]\x80\xc2^\x80\xc2_\x80\xc2`\x80\xc2a\x80\xc2b\x80\xc2c\x80\xc2d\x80\xc2e\x80\xc2f\x80\xc2g\x80\xc2h\x80\xc2i\x80\xc2j\x80\xc2k\x80\xc2l\x80\xc2m\x80\xc2n\x80\xc2o\x80\xc2p\x80\xc2q\x80\xc2r\x80\xc2s\x80\xc2t\x80\xc2u\x80\xc2v\x80\xc2w\x80\xc2x\x80\xc2y\x80\xc2z\x80\xc2{\x80\xc2|\x80\xc2}\x80\xc2~\x80\xc2\u007f\x80\u00c1\x80\x80\u00c1\x81\x80\u00c1\x82\x80\u00c1\x83\x80\u00c1\x84\x80\u00c1\x85\x80\u00c1\x86\x80\u00c1\x87\x80\u00c1\x88\x80\u00c1\x89\x80\u00c1\x8a\x80\u00c1\x8b\x80\u00c1\x8c\x80\u00c1\x8d\x80\u00c1\x8e\x80\u00c1\x8f\x80\u00c1\x90\x80\u00c1\x91\x80\u00c1\x92\x80\u00c1\x93\x80\u00c1\x94\x80\u00c1\x95\x80\u00c1\x96\x80\u00c1\x97\x80\u00c1\x98\x80\u00c1\x99\x80\u00c1\x9a\x80\u00c1\x9b\x80\u00c1\x9c\x80\u00c1\x9d\x80\u00c1\x9e\x80\u00c1\x9f\x80\u00c1\xa0\x80\u00c1\xa1\x80\u00c1\xa2\x80\u00c1\xa3\x80\u00c1\xa4\x80\u00c1\xa5\x80\u00c1\xa6\x80\u00c1\xa7\x80\u00c1\xa8\x80\u00c1\xa9\x80\u00c1\xaa\x80\u00c1\xab\x80\u00c1\xac\x80\u00c1\xad\x80\u00c1\xae\x80\u00c1\xaf\x80\u00c1\xb0\x80\u00c1\xb1\x80\u00c1\xb2\x80\u00c1\xb3\x80\u00c1\xb4\x80\u00c1\xb5\x80\u00c1\xb6\x80\u00c1\xb7\x80\u00c1\xb8\x80\u00c1\xb9\x80\u00c1\xba\x80\u00c1\xbb\x80\u00c1\xbc\x80\u00c1\xbd\x80\u00c1\xbe\x80\u00c1\xbf\x80\u00c1\xc0\x80\u00c1\xc1\x80\u00c1\u0080\u00c1\u00c0\u00c1\u0100\u00c1\u0140\u00c1\u0180\u00c1\u01c0\u00c1\u0200\u00c1\u0240\u00c1\u0280\u00c1\u02c0\u00c1\u0300\u00c1\u0340\u00c1\u0380\u00c1\u03c0\u00c1\u0400\u00c1\u0440\u00c1\u0480\u00c1\u04c0\u00c1\u0500\u00c1\u0540\u00c1\u0580\u00c1\u05c0\u00c1\u0600\u00c1\u0640\u00c1\u0680\u00c1\u06c0\u00c1\u0700\u00c1\u0740\u00c1\u0780\u00c1\u07c0\u00c1\xe0\x80\u00c1\xe1\x80\u00c1\xe2\x80\u00c1\xe3\x80\u00c1\xe4\x80\u00c1\xe5\x80\u00c1\xe6\x80\u00c1\xe7\x80\u00c1\xe8\x80\u00c1\xe9\x80\u00c1\xea\x80\u00c1\xeb\x80\u00c1\xec\x80\u00c1\xed\x80\u00c1\xee\x80\u00c1\xef\x80\u00c1\xf0\x80\u00c1\xf1\x80\u00c1\xf2\x80\u00c1\xf3\x80\u00c1\xf4\x80\u00c1\xf5\x80\u00c1\xf6\x80\u00c1\xf7\x80\u00c1\xf8\x80\u00c1\xf9\x80\u00c1\xfa\x80\u00c1\xfb\x80\u00c1\xfc\x80\u00c1\xfd\x80\u00c1\xfe\x80\u00c1\xff\x80\u3507KT\xa8\xbd\x15)f\xd6?pk\xae\x1f\xfe\xb0A\x19!\xe5\x8d\f\x9f,\x9c\xd0Ft\xed\xea@\x00\x00\x00" const rinkebyAllocData = "\xf9\x03\xb7\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xf6\x941\xb9\x8d\x14\x00{\xde\xe67)\x80\x86\x98\x8a\v\xbd1\x18E#\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" const goerliAllocData = "\xf9\x04\x06\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xe0\x94L*\xe4\x82Y5\x05\xf0\x16<\xde\xfc\a>\x81\xc6<\xdaA\a\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xa8\xe8\xf1G2e\x8eKQ\xe8q\x191\x05:\x8ai\xba\xf2\xb1\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe1\x94\u0665\x17\x9f\t\x1d\x85\x05\x1d<\x98'\x85\xef\xd1E\\\uc199\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\u08bdBX\xd2v\x887\xba\xa2j(\xfeq\xdc\a\x9f\x84\u01cbJG\xe3\xc1$H\xf4\xad\x00\x00\x00" -const calaverasAllocData = "\xf9\x06\x14\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xf6\x94\x0e\x89\xe2\xae\xdb\x1c\xfc\u06d4$\xd4\x1a\x1f!\x8fA2s\x81r\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\x10A\xaf\xbc\xb3Y\u0568\xdcX\xc1[/\xf5\x13T\xff\x8a!}\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94#o\xf1\xe9t\x19\xae\x93\xad\x80\xca\xfb\xaa!\"\f]x\xfb}\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94`\xad\xc0\xf8\x9aA\xaf#|\xe75T\xed\xe1p\xd73\xec\x14\xe0\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94y\x9d2\x9e_X4\x19\x16|\xd7\"\x96$\x85\x92n3\x8fJ\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94|\xf5\xb7\x9b\xfe)\x1ag\xab\x02\xb3\x93\xe4V\xcc\xc4\xc2f\xf7S\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\x8a\x8e\xaf\xb1\xcfb\xbf\xbe\xb1t\x17i\xda\xe1\xa9\xddG\x99a\x92\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\x8b\xa1\xf1\tU\x1b\xd42\x800\x12dZ\xc16\xdd\xd6M\xbar\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\xb0*.\xda\x1b1\u007f\xbd\x16v\x01(\x83k\n\u015bV\x0e\x9d\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\xba\xdc\r\xe9\xe0yK\x04\x9b^\xa6<>\x1ei\x8a4v\xc1r\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\xf00\v\ue24a\xe2r\xeb4~\x83i\xac\fv\xdfB\xc9?\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\xfe;U~\x8f\xb6+\x89\xf4\x91kr\x1b\xe5\\\ub08d\xbds\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" const sepoliaAllocData = "\xf9\x01\xee\u0791i\x16\xa8{\x823?BE\x04f#\xb27\x94\xc6\\\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\x10\xf5\xd4XT\xe08\a\x14\x85\xac\x9e@#\b\u03c0\xd2\xd2\xfe\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\u0794y\x9d2\x9e_X4\x19\x16|\xd7\"\x96$\x85\x92n3\x8fJ\x88\r\u0db3\xa7d\x00\x00\xe0\x94|\xf5\xb7\x9b\xfe)\x1ag\xab\x02\xb3\x93\xe4V\xcc\xc4\xc2f\xf7S\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x8b\u007f\tw\xbbO\x0f\xbepv\xfa\"\xbc$\xac\xa0CX?^\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa2\xa6\xd949\x14O\xfeM'\xc9\xe0\x88\xdc\u0637\x83\x94bc\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xaa\xec\x869DA\xf9\x15\xbc\xe3\xe6\xab9\x99w\xe9\x90o;i\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u1532\x1c3\xde\x1f\xab?\xa1T\x99\xc6+Y\xfe\f\xc3%\x00 \u044bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xbc\x11)Y6\xaay\u0554\x13\x9d\xe1\xb2\xe1&)AO;\u06ca\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xbe\xef2\xca[\x9a\x19\x8d'\xb4\xe0/LpC\x9f\xe6\x03V\u03ca\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\xd7\xd7lX\xb3\xa5\x19\xe9\xfal\xc4\xd2-\xc0\x17%\x9b\u011f\x1e\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xd7\xed\xdbx\xed)[<\x96)$\x0e\x89$\xfb\x8d\x88t\xdd\u060a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\u0665\x17\x9f\t\x1d\x85\x05\x1d<\x98'\x85\xef\xd1E\\\uc199\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xe2\xe2e\x90(\x147\x84\xd5W\xbc\xeco\xf3\xa0r\x10H\x88\n\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xf4|\xae\x1c\xf7\x9c\xa6u\x8b\xfcx}\xbd!\u6f7eq\x12\xb8\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00" const KilnAllocData = `{ "config": { From 0016eb7eeeb42568c8c20d0cb560ddfc9a938fad Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 15 Aug 2022 10:04:58 +0200 Subject: [PATCH 160/715] params: set ttdpassed on goerli (#25519) --- params/config.go | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/params/config.go b/params/config.go index fda4c1aecda3..87658b372e60 100644 --- a/params/config.go +++ b/params/config.go @@ -217,22 +217,23 @@ var ( // GoerliChainConfig contains the chain parameters to run a node on the Görli test network. GoerliChainConfig = &ChainConfig{ - ChainID: big.NewInt(5), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(1_561_651), - MuirGlacierBlock: nil, - BerlinBlock: big.NewInt(4_460_644), - LondonBlock: big.NewInt(5_062_605), - ArrowGlacierBlock: nil, - TerminalTotalDifficulty: big.NewInt(10_790_000), + ChainID: big.NewInt(5), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(1_561_651), + MuirGlacierBlock: nil, + BerlinBlock: big.NewInt(4_460_644), + LondonBlock: big.NewInt(5_062_605), + ArrowGlacierBlock: nil, + TerminalTotalDifficulty: big.NewInt(10_790_000), + TerminalTotalDifficultyPassed: true, Clique: &CliqueConfig{ Period: 15, Epoch: 30000, From c4ab7d229117fdaa24292d84c1d450a727cb3e9f Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 16 Aug 2022 08:38:23 +0200 Subject: [PATCH 161/715] params: set mainnet terminal total difficulty for the merge (#25528) * params: set mainnet ttd to 58_750_000_000_000_000_000_000 * params: set mainnet ttd to 58_750_000_000_000_000_000_000 --- params/config.go | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/params/config.go b/params/config.go index 87658b372e60..4d6eec8939bc 100644 --- a/params/config.go +++ b/params/config.go @@ -55,26 +55,29 @@ var CheckpointOracles = map[common.Hash]*CheckpointOracleConfig{ } var ( + MainnetTerminalTotalDifficulty, _ = new(big.Int).SetString("58_750_000_000_000_000_000_000", 0) + // MainnetChainConfig is the chain parameters to run a node on the main network. MainnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(1_150_000), - DAOForkBlock: big.NewInt(1_920_000), - DAOForkSupport: true, - EIP150Block: big.NewInt(2_463_000), - EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), - EIP155Block: big.NewInt(2_675_000), - EIP158Block: big.NewInt(2_675_000), - ByzantiumBlock: big.NewInt(4_370_000), - ConstantinopleBlock: big.NewInt(7_280_000), - PetersburgBlock: big.NewInt(7_280_000), - IstanbulBlock: big.NewInt(9_069_000), - MuirGlacierBlock: big.NewInt(9_200_000), - BerlinBlock: big.NewInt(12_244_000), - LondonBlock: big.NewInt(12_965_000), - ArrowGlacierBlock: big.NewInt(13_773_000), - GrayGlacierBlock: big.NewInt(15_050_000), - Ethash: new(EthashConfig), + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(1_150_000), + DAOForkBlock: big.NewInt(1_920_000), + DAOForkSupport: true, + EIP150Block: big.NewInt(2_463_000), + EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), + EIP155Block: big.NewInt(2_675_000), + EIP158Block: big.NewInt(2_675_000), + ByzantiumBlock: big.NewInt(4_370_000), + ConstantinopleBlock: big.NewInt(7_280_000), + PetersburgBlock: big.NewInt(7_280_000), + IstanbulBlock: big.NewInt(9_069_000), + MuirGlacierBlock: big.NewInt(9_200_000), + BerlinBlock: big.NewInt(12_244_000), + LondonBlock: big.NewInt(12_965_000), + ArrowGlacierBlock: big.NewInt(13_773_000), + GrayGlacierBlock: big.NewInt(15_050_000), + TerminalTotalDifficulty: MainnetTerminalTotalDifficulty, // 58_750_000_000_000_000_000_000 + Ethash: new(EthashConfig), } // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network. @@ -471,10 +474,10 @@ func (c *ChainConfig) String() string { // Add a special section for the merge as it's non-obvious if c.TerminalTotalDifficulty == nil { banner += "The Merge is not yet available for this network!\n" - banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)" + banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md" } else { banner += "Merge configured:\n" - banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)\n" + banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md\n" banner += fmt.Sprintf(" - Network known to be merged: %v\n", c.TerminalTotalDifficultyPassed) banner += fmt.Sprintf(" - Total terminal difficulty: %v\n", c.TerminalTotalDifficulty) banner += fmt.Sprintf(" - Merge netsplit block: %-8v", c.MergeNetsplitBlock) From 12185e40e06ec9d68a3780f56ec70a0a831b25bc Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Wed, 17 Aug 2022 13:12:10 +0200 Subject: [PATCH 162/715] core, trie: flush preimages to db on blockchain close (#25533) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * core, trie: flush preimages to db on database close Co-authored-by: rjl493456442 * rename Close to CommitPreimages for clarity * core, trie: nitpick fixes Co-authored-by: rjl493456442 Co-authored-by: Péter Szilágyi --- core/blockchain.go | 4 ++++ trie/database.go | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/core/blockchain.go b/core/blockchain.go index f35de404619b..ee95cfb6cb66 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -893,6 +893,10 @@ func (bc *BlockChain) Stop() { log.Error("Dangling trie nodes after full cleanup") } } + // Flush the collected preimages to disk + if err := bc.stateCache.TrieDB().CommitPreimages(); err != nil { + log.Error("Failed to commit trie preimages", "err", err) + } // Ensure all live cached entries be saved into disk, so that we can skip // cache warmup when node restarts. if bc.cacheConfig.TrieCleanJournal != "" { diff --git a/trie/database.go b/trie/database.go index 81f0477aeb86..8c9f47176845 100644 --- a/trie/database.go +++ b/trie/database.go @@ -852,3 +852,16 @@ func (db *Database) SaveCachePeriodically(dir string, interval time.Duration, st } } } + +// CommitPreimages flushes the dangling preimages to disk. It is meant to be +// called when closing the blockchain object, so that preimages are persisted +// to the database. +func (db *Database) CommitPreimages() error { + db.lock.Lock() + defer db.lock.Unlock() + + if db.preimages == nil { + return nil + } + return db.preimages.commit(true) +} From 6da5c1644db87655d07db4b2a8a23b0c5fad619d Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Wed, 17 Aug 2022 13:14:49 +0200 Subject: [PATCH 163/715] core/state, trie, light: add a TryDeleteAccount method (#25531) * core/state, trie, light: Add a DeleteAccount method * review feedback * Update database.go * pr triage feedback Co-authored-by: rjl493456442 --- core/state/database.go | 3 +++ core/state/statedb.go | 2 +- light/trie.go | 8 ++++++++ trie/secure_trie.go | 7 +++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/core/state/database.go b/core/state/database.go index edbf78ae311a..96b6bcfe6551 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -87,6 +87,9 @@ type Trie interface { // found in the database, a trie.MissingNodeError is returned. TryDelete(key []byte) error + // TryDeleteAccount abstracts an account deletion from the trie. + TryDeleteAccount(key []byte) error + // Hash returns the root hash of the trie. It does not write to the database and // can be used even if the trie doesn't have one. Hash() common.Hash diff --git a/core/state/statedb.go b/core/state/statedb.go index cd388d6a3641..5c97dd94ade1 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -484,7 +484,7 @@ func (s *StateDB) deleteStateObject(obj *stateObject) { } // Delete the account from the trie addr := obj.Address() - if err := s.trie.TryDelete(addr[:]); err != nil { + if err := s.trie.TryDeleteAccount(addr[:]); err != nil { s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err)) } } diff --git a/light/trie.go b/light/trie.go index 5755e2cc1959..f60edaa3b177 100644 --- a/light/trie.go +++ b/light/trie.go @@ -153,6 +153,14 @@ func (t *odrTrie) TryDelete(key []byte) error { }) } +// TryDeleteACcount abstracts an account deletion from the trie. +func (t *odrTrie) TryDeleteAccount(key []byte) error { + key = crypto.Keccak256(key) + return t.do(key, func() error { + return t.trie.TryDelete(key) + }) +} + func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trie.NodeSet, error) { if t.trie == nil { return t.id.Root, nil, nil diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 28b3473c011f..3d468f56ee0a 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -189,6 +189,13 @@ func (t *StateTrie) TryDelete(key []byte) error { return t.trie.TryDelete(hk) } +// TryDeleteACcount abstracts an account deletion from the trie. +func (t *StateTrie) TryDeleteAccount(key []byte) error { + hk := t.hashKey(key) + delete(t.getSecKeyCache(), string(hk)) + return t.trie.TryDelete(hk) +} + // GetKey returns the sha3 preimage of a hashed key that was // previously used to store a value. func (t *StateTrie) GetKey(shaKey []byte) []byte { From a50c006b49ef0411e3389b801f5b4594c72fe3b3 Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Wed, 17 Aug 2022 20:16:18 +0900 Subject: [PATCH 164/715] core: make tx journal check and open atomic (#25530) * core: reduce system call about `os` * avoid deprecated method --- core/tx_journal.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/tx_journal.go b/core/tx_journal.go index 5453ee191658..62344f564676 100644 --- a/core/tx_journal.go +++ b/core/tx_journal.go @@ -19,6 +19,7 @@ package core import ( "errors" "io" + "io/fs" "os" "github.com/ethereum/go-ethereum/common" @@ -57,12 +58,12 @@ func newTxJournal(path string) *txJournal { // load parses a transaction journal dump from disk, loading its contents into // the specified pool. func (journal *txJournal) load(add func([]*types.Transaction) []error) error { - // Skip the parsing if the journal file doesn't exist at all - if !common.FileExist(journal.path) { - return nil - } // Open the journal for loading any past transactions input, err := os.Open(journal.path) + if errors.Is(err, fs.ErrNotExist) { + // Skip the parsing if the journal file doesn't exist at all + return nil + } if err != nil { return err } From 23ac8df15302bbde098cab6d711abdd24843d66a Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 18 Aug 2022 13:28:06 +0200 Subject: [PATCH 165/715] cmd. core: save preimages on genesis creation (#25538) force preimage dump for genesis --- core/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index 71214e84f505..c3b5d0b57094 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -104,7 +104,7 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) { // all the generated states will be persisted into the given database. // Also, the genesis state specification will be flushed as well. func (ga *GenesisAlloc) flush(db ethdb.Database) error { - statedb, err := state.New(common.Hash{}, state.NewDatabase(db), nil) + statedb, err := state.New(common.Hash{}, state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}), nil) if err != nil { return err } From cce7f084388adf9097f730ae48631a55de2e3be1 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Thu, 18 Aug 2022 17:34:57 -0500 Subject: [PATCH 166/715] rlp/rlpgen: fix error handling when target type not found (#25547) typ will be nil when lookupStructType returns an error. cfg.Type should be used instead. --- rlp/rlpgen/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rlp/rlpgen/main.go b/rlp/rlpgen/main.go index 17d7e64e0842..25d4393cc656 100644 --- a/rlp/rlpgen/main.go +++ b/rlp/rlpgen/main.go @@ -106,7 +106,7 @@ func (cfg *Config) process() (code []byte, err error) { // Find the type and generate. typ, err := lookupStructType(pkg.Scope(), cfg.Type) if err != nil { - return nil, fmt.Errorf("can't find %s in %s: %v", typ, pkg, err) + return nil, fmt.Errorf("can't find %s in %s: %v", cfg.Type, pkg, err) } code, err = bctx.generate(typ, cfg.GenerateEncoder, cfg.GenerateDecoder) if err != nil { From a1b8892384eed99beb3f3364cfd13b049a1c0167 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 19 Aug 2022 06:39:47 +0800 Subject: [PATCH 167/715] trie: improve node rlp decoding performance (#25357) This avoids copying the input []byte while decoding trie nodes. In most cases, particularly when the input slice is provided by the underlying database, this optimization is safe to use. For cases where the origin of the input slice is unclear, the copying version is retained. The new code performs better even when the input must be copied, because it is now only copied once in decodeNode. --- trie/database.go | 14 ++++-- trie/node.go | 30 ++++++++++-- trie/node_test.go | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 7 deletions(-) diff --git a/trie/database.go b/trie/database.go index 8c9f47176845..8c154ba96df6 100644 --- a/trie/database.go +++ b/trie/database.go @@ -163,7 +163,10 @@ func (n *cachedNode) rlp() []byte { // or by regenerating it from the rlp encoded blob. func (n *cachedNode) obj(hash common.Hash) node { if node, ok := n.node.(rawNode); ok { - return mustDecodeNode(hash[:], node) + // The raw-blob format nodes are loaded from either from + // clean cache or the database, they are all in their own + // copy and safe to use unsafe decoder. + return mustDecodeNodeUnsafe(hash[:], node) } return expandNode(hash[:], n.node) } @@ -346,7 +349,10 @@ func (db *Database) node(hash common.Hash) node { if enc := db.cleans.Get(nil, hash[:]); enc != nil { memcacheCleanHitMeter.Mark(1) memcacheCleanReadMeter.Mark(int64(len(enc))) - return mustDecodeNode(hash[:], enc) + + // The returned value from cache is in its own copy, + // safe to use mustDecodeNodeUnsafe for decoding. + return mustDecodeNodeUnsafe(hash[:], enc) } } // Retrieve the node from the dirty cache if available @@ -371,7 +377,9 @@ func (db *Database) node(hash common.Hash) node { memcacheCleanMissMeter.Mark(1) memcacheCleanWriteMeter.Mark(int64(len(enc))) } - return mustDecodeNode(hash[:], enc) + // The returned value from database is in its own copy, + // safe to use mustDecodeNodeUnsafe for decoding. + return mustDecodeNodeUnsafe(hash[:], enc) } // Node retrieves an encoded cached trie node from memory. If it cannot be found diff --git a/trie/node.go b/trie/node.go index bf3f024bb8a7..6ce6551ded8c 100644 --- a/trie/node.go +++ b/trie/node.go @@ -99,6 +99,7 @@ func (n valueNode) fstring(ind string) string { return fmt.Sprintf("%x ", []byte(n)) } +// mustDecodeNode is a wrapper of decodeNode and panic if any error is encountered. func mustDecodeNode(hash, buf []byte) node { n, err := decodeNode(hash, buf) if err != nil { @@ -107,8 +108,29 @@ func mustDecodeNode(hash, buf []byte) node { return n } -// decodeNode parses the RLP encoding of a trie node. +// mustDecodeNodeUnsafe is a wrapper of decodeNodeUnsafe and panic if any error is +// encountered. +func mustDecodeNodeUnsafe(hash, buf []byte) node { + n, err := decodeNodeUnsafe(hash, buf) + if err != nil { + panic(fmt.Sprintf("node %x: %v", hash, err)) + } + return n +} + +// decodeNode parses the RLP encoding of a trie node. It will deep-copy the passed +// byte slice for decoding, so it's safe to modify the byte slice afterwards. The- +// decode performance of this function is not optimal, but it is suitable for most +// scenarios with low performance requirements and hard to determine whether the +// byte slice be modified or not. func decodeNode(hash, buf []byte) (node, error) { + return decodeNodeUnsafe(hash, common.CopyBytes(buf)) +} + +// decodeNodeUnsafe parses the RLP encoding of a trie node. The passed byte slice +// will be directly referenced by node without bytes deep copy, so the input MUST +// not be changed after. +func decodeNodeUnsafe(hash, buf []byte) (node, error) { if len(buf) == 0 { return nil, io.ErrUnexpectedEOF } @@ -141,7 +163,7 @@ func decodeShort(hash, elems []byte) (node, error) { if err != nil { return nil, fmt.Errorf("invalid value node: %v", err) } - return &shortNode{key, append(valueNode{}, val...), flag}, nil + return &shortNode{key, valueNode(val), flag}, nil } r, _, err := decodeRef(rest) if err != nil { @@ -164,7 +186,7 @@ func decodeFull(hash, elems []byte) (*fullNode, error) { return n, err } if len(val) > 0 { - n.Children[16] = append(valueNode{}, val...) + n.Children[16] = valueNode(val) } return n, nil } @@ -190,7 +212,7 @@ func decodeRef(buf []byte) (node, []byte, error) { // empty node return nil, rest, nil case kind == rlp.String && len(val) == 32: - return append(hashNode{}, val...), rest, nil + return hashNode(val), rest, nil default: return nil, nil, fmt.Errorf("invalid RLP string size %d (want 0 or 32)", len(val)) } diff --git a/trie/node_test.go b/trie/node_test.go index ac1d8fbef3e6..9b8b33748fa7 100644 --- a/trie/node_test.go +++ b/trie/node_test.go @@ -20,6 +20,7 @@ import ( "bytes" "testing" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" ) @@ -92,3 +93,123 @@ func TestDecodeFullNode(t *testing.T) { t.Fatalf("decode full node err: %v", err) } } + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkEncodeShortNode +// BenchmarkEncodeShortNode-8 16878850 70.81 ns/op 48 B/op 1 allocs/op +func BenchmarkEncodeShortNode(b *testing.B) { + node := &shortNode{ + Key: []byte{0x1, 0x2}, + Val: hashNode(randBytes(32)), + } + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + nodeToBytes(node) + } +} + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkEncodeFullNode +// BenchmarkEncodeFullNode-8 4323273 284.4 ns/op 576 B/op 1 allocs/op +func BenchmarkEncodeFullNode(b *testing.B) { + node := &fullNode{} + for i := 0; i < 16; i++ { + node.Children[i] = hashNode(randBytes(32)) + } + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + nodeToBytes(node) + } +} + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkDecodeShortNode +// BenchmarkDecodeShortNode-8 7925638 151.0 ns/op 157 B/op 4 allocs/op +func BenchmarkDecodeShortNode(b *testing.B) { + node := &shortNode{ + Key: []byte{0x1, 0x2}, + Val: hashNode(randBytes(32)), + } + blob := nodeToBytes(node) + hash := crypto.Keccak256(blob) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + mustDecodeNode(hash, blob) + } +} + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkDecodeShortNodeUnsafe +// BenchmarkDecodeShortNodeUnsafe-8 9027476 128.6 ns/op 109 B/op 3 allocs/op +func BenchmarkDecodeShortNodeUnsafe(b *testing.B) { + node := &shortNode{ + Key: []byte{0x1, 0x2}, + Val: hashNode(randBytes(32)), + } + blob := nodeToBytes(node) + hash := crypto.Keccak256(blob) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + mustDecodeNodeUnsafe(hash, blob) + } +} + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkDecodeFullNode +// BenchmarkDecodeFullNode-8 1597462 761.9 ns/op 1280 B/op 18 allocs/op +func BenchmarkDecodeFullNode(b *testing.B) { + node := &fullNode{} + for i := 0; i < 16; i++ { + node.Children[i] = hashNode(randBytes(32)) + } + blob := nodeToBytes(node) + hash := crypto.Keccak256(blob) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + mustDecodeNode(hash, blob) + } +} + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkDecodeFullNodeUnsafe +// BenchmarkDecodeFullNodeUnsafe-8 1789070 687.1 ns/op 704 B/op 17 allocs/op +func BenchmarkDecodeFullNodeUnsafe(b *testing.B) { + node := &fullNode{} + for i := 0; i < 16; i++ { + node.Children[i] = hashNode(randBytes(32)) + } + blob := nodeToBytes(node) + hash := crypto.Keccak256(blob) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + mustDecodeNodeUnsafe(hash, blob) + } +} From 2c5648d8915dc6f4cd822a379819d774beba0dc5 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Fri, 19 Aug 2022 01:00:21 -0500 Subject: [PATCH 168/715] all: fix some typos (#25551) * Fix some typos * Fix some mistakes * Revert 4byte.json * Fix an incorrect fix * Change files to fails --- accounts/abi/reflect_test.go | 2 +- accounts/keystore/account_cache_test.go | 2 +- accounts/keystore/file_cache.go | 4 +-- accounts/keystore/keystore_test.go | 2 +- accounts/usbwallet/trezor.go | 4 +-- accounts/usbwallet/wallet.go | 2 +- build/ci.go | 2 +- cmd/faucet/faucet.go | 2 +- cmd/geth/consolecmd_test.go | 2 +- cmd/puppeth/ssh.go | 2 +- common/prque/prque.go | 4 +-- consensus/clique/snapshot_test.go | 4 +-- console/console.go | 6 ++-- core/blockchain.go | 4 +-- core/blockchain_repair_test.go | 32 +++++++++---------- core/rawdb/accessors_chain_test.go | 2 +- core/rawdb/database.go | 2 +- core/rawdb/freezer_table.go | 2 +- core/state/snapshot/iterator_fast.go | 4 +-- core/state/snapshot/snapshot_test.go | 2 +- core/state/statedb.go | 6 ++-- core/state/statedb_test.go | 2 +- core/state/sync_test.go | 12 +++---- core/state/trie_prefetcher.go | 2 +- core/types/block.go | 2 +- core/types/block_test.go | 2 +- core/vm/runtime/runtime_test.go | 4 +-- crypto/bls12381/isogeny.go | 4 +-- eth/catalyst/api.go | 4 +-- eth/downloader/api.go | 2 +- eth/downloader/beaconsync.go | 2 +- eth/downloader/downloader.go | 4 +-- eth/downloader/downloader_test.go | 8 ++--- eth/downloader/fetchers_concurrent.go | 6 ++-- eth/downloader/fetchers_concurrent_bodies.go | 4 +-- eth/downloader/fetchers_concurrent_headers.go | 4 +-- .../fetchers_concurrent_receipts.go | 6 ++-- eth/downloader/queue.go | 2 +- eth/downloader/skeleton.go | 12 +++---- eth/downloader/skeleton_test.go | 14 ++++---- eth/ethconfig/config.go | 2 +- eth/fetcher/tx_fetcher.go | 10 +++--- eth/fetcher/tx_fetcher_test.go | 6 ++-- eth/filters/api.go | 2 +- eth/peerset.go | 2 +- eth/protocols/eth/broadcast.go | 2 +- eth/protocols/eth/dispatcher.go | 2 +- eth/protocols/eth/handler_test.go | 2 +- eth/protocols/eth/peer.go | 2 +- eth/protocols/snap/handler.go | 2 +- eth/protocols/snap/peer.go | 8 ++--- eth/protocols/snap/sync.go | 26 +++++++-------- eth/state_accessor.go | 2 +- eth/tracers/api.go | 10 +++--- .../internal/tracetest/calltrace_test.go | 2 +- ethclient/ethclient_test.go | 2 +- ethdb/memorydb/memorydb.go | 2 +- interfaces.go | 2 +- internal/ethapi/api.go | 2 +- les/downloader/api.go | 2 +- les/downloader/downloader.go | 4 +-- les/downloader/downloader_test.go | 4 +-- les/downloader/queue.go | 2 +- les/fetcher.go | 2 +- les/flowcontrol/manager.go | 2 +- les/odr.go | 2 +- les/vflux/client/fillset_test.go | 2 +- les/vflux/client/serverpool_test.go | 2 +- les/vflux/server/balance.go | 2 +- les/vflux/server/balance_test.go | 4 +-- les/vflux/server/status.go | 2 +- light/lightchain.go | 2 +- light/odr_util.go | 4 +-- light/postprocess.go | 4 +-- light/trie.go | 2 +- light/txpool.go | 2 +- metrics/gauge_float64_test.go | 2 +- metrics/gauge_test.go | 2 +- metrics/prometheus/prometheus.go | 2 +- miner/unconfirmed_test.go | 2 +- miner/worker_test.go | 2 +- mobile/accounts.go | 6 ++-- mobile/init.go | 2 +- node/rpcstack_test.go | 2 +- p2p/discover/v4_udp.go | 2 +- p2p/discover/v5_udp.go | 2 +- p2p/msgrate/msgrate.go | 6 ++-- p2p/tracker/tracker.go | 2 +- rpc/server.go | 2 +- signer/rules/rules_test.go | 8 ++--- signer/storage/aes_gcm_storage.go | 2 +- trie/hasher.go | 2 +- trie/proof_test.go | 32 +++++++++---------- trie/secure_trie_test.go | 2 +- 94 files changed, 200 insertions(+), 200 deletions(-) diff --git a/accounts/abi/reflect_test.go b/accounts/abi/reflect_test.go index cf13a79da84e..76ef1ad2aa39 100644 --- a/accounts/abi/reflect_test.go +++ b/accounts/abi/reflect_test.go @@ -32,7 +32,7 @@ type reflectTest struct { var reflectTests = []reflectTest{ { - name: "OneToOneCorrespondance", + name: "OneToOneCorrespondence", args: []string{"fieldA"}, struc: struct { FieldA int `abi:"fieldA"` diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index bdcd81182512..daea497d1ae7 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -318,7 +318,7 @@ func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error { func TestUpdatedKeyfileContents(t *testing.T) { t.Parallel() - // Create a temporary kesytore to test with + // Create a temporary keystore to test with rand.Seed(time.Now().UnixNano()) dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-updatedkeyfilecontents-test-%d-%d", os.Getpid(), rand.Int())) ks := NewKeyStore(dir, LightScryptN, LightScryptP) diff --git a/accounts/keystore/file_cache.go b/accounts/keystore/file_cache.go index b3ecf8946b53..79f9a2963743 100644 --- a/accounts/keystore/file_cache.go +++ b/accounts/keystore/file_cache.go @@ -39,7 +39,7 @@ type fileCache struct { func (fc *fileCache) scan(keyDir string) (mapset.Set, mapset.Set, mapset.Set, error) { t0 := time.Now() - // List all the failes from the keystore folder + // List all the files from the keystore folder files, err := os.ReadDir(keyDir) if err != nil { return nil, nil, nil, err @@ -61,7 +61,7 @@ func (fc *fileCache) scan(keyDir string) (mapset.Set, mapset.Set, mapset.Set, er log.Trace("Ignoring file on account scan", "path", path) continue } - // Gather the set of all and fresly modified files + // Gather the set of all and freshly modified files all.Add(path) info, err := fi.Info() diff --git a/accounts/keystore/keystore_test.go b/accounts/keystore/keystore_test.go index 6a2e32f6d9c8..4cdf0b1ed6ce 100644 --- a/accounts/keystore/keystore_test.go +++ b/accounts/keystore/keystore_test.go @@ -214,7 +214,7 @@ func TestSignRace(t *testing.T) { // Tests that the wallet notifier loop starts and stops correctly based on the // addition and removal of wallet event subscriptions. func TestWalletNotifierLifecycle(t *testing.T) { - // Create a temporary kesytore to test with + // Create a temporary keystore to test with _, ks := tmpKeyStore(t, false) // Ensure that the notification updater is not running yet diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index c2182b88d03b..e385682a5833 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -196,10 +196,10 @@ func (w *trezorDriver) trezorDerive(derivationPath []uint32) (common.Address, er if _, err := w.trezorExchange(&trezor.EthereumGetAddress{AddressN: derivationPath}, address); err != nil { return common.Address{}, err } - if addr := address.GetAddressBin(); len(addr) > 0 { // Older firmwares use binary fomats + if addr := address.GetAddressBin(); len(addr) > 0 { // Older firmwares use binary formats return common.BytesToAddress(addr), nil } - if addr := address.GetAddressHex(); len(addr) > 0 { // Newer firmwares use hexadecimal fomats + if addr := address.GetAddressHex(); len(addr) > 0 { // Newer firmwares use hexadecimal formats return common.HexToAddress(addr), nil } return common.Address{}, errors.New("missing derived address") diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 06ff0636ae20..0e399a6d09ab 100644 --- a/accounts/usbwallet/wallet.go +++ b/accounts/usbwallet/wallet.go @@ -380,7 +380,7 @@ func (w *wallet) selfDerive() { // of legacy-ledger, the first account on the legacy-path will // be shown to the user, even if we don't actively track it if i < len(nextAddrs)-1 { - w.log.Info("Skipping trakcking first account on legacy path, use personal.deriveAccount(,, false) to track", + w.log.Info("Skipping tracking first account on legacy path, use personal.deriveAccount(,, false) to track", "path", path, "address", nextAddrs[i]) break } diff --git a/build/ci.go b/build/ci.go index f91de328bebc..80b040045939 100644 --- a/build/ci.go +++ b/build/ci.go @@ -608,7 +608,7 @@ func doDocker(cmdline []string) { } if mismatch { // Build numbers mismatching, retry in a short time to - // avoid concurrent failes in both publisher images. If + // avoid concurrent fails in both publisher images. If // however the retry failed too, it means the concurrent // builder is still crunching, let that do the publish. if i == 0 { diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index d49b9ed29d93..dfb7d326dc49 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -709,7 +709,7 @@ func authTwitter(url string, tokenV1, tokenV2 string) (string, string, string, c case tokenV2 != "": return authTwitterWithTokenV2(tweetID, tokenV2) } - // Twiter API token isn't provided so we just load the public posts + // Twitter API token isn't provided so we just load the public posts // and scrape it for the Ethereum address and profile URL. We need to load // the mobile page though since the main page loads tweet contents via JS. url = strings.Replace(url, "https://twitter.com/", "https://mobile.twitter.com/", 1) diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index d5ebd74aedf4..442b82df0b3c 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -155,7 +155,7 @@ To exit, press ctrl-d or type exit } // trulyRandInt generates a crypto random integer used by the console tests to -// not clash network ports with other tests running cocurrently. +// not clash network ports with other tests running concurrently. func trulyRandInt(lo, hi int) int { num, _ := rand.Int(rand.Reader, big.NewInt(int64(hi-lo))) return int(num.Int64()) + lo diff --git a/cmd/puppeth/ssh.go b/cmd/puppeth/ssh.go index 0c23ab556228..a20b3bfda209 100644 --- a/cmd/puppeth/ssh.go +++ b/cmd/puppeth/ssh.go @@ -163,7 +163,7 @@ func dial(server string, pubkey []byte) (*sshClient, error) { return nil } // We have a mismatch, forbid connecting - return errors.New("ssh key mismatch, readd the machine to update") + return errors.New("ssh key mismatch, re-add the machine to update") } client, err := ssh.Dial("tcp", hostport, &ssh.ClientConfig{User: username, Auth: auths, HostKeyCallback: keycheck}) if err != nil { diff --git a/common/prque/prque.go b/common/prque/prque.go index 54c78b5fc2ba..fb02e3418c28 100755 --- a/common/prque/prque.go +++ b/common/prque/prque.go @@ -41,13 +41,13 @@ func (p *Prque) Push(data interface{}, priority int64) { heap.Push(p.cont, &item{data, priority}) } -// Peek returns the value with the greates priority but does not pop it off. +// Peek returns the value with the greatest priority but does not pop it off. func (p *Prque) Peek() (interface{}, int64) { item := p.cont.blocks[0][0] return item.value, item.priority } -// Pops the value with the greates priority off the stack and returns it. +// Pops the value with the greatest priority off the stack and returns it. // Currently no shrinking is done. func (p *Prque) Pop() (interface{}, int64) { item := heap.Pop(p.cont).(*item) diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index b87ad8c23a7c..4a067c62554a 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -305,7 +305,7 @@ func TestClique(t *testing.T) { }, { // Ensure that pending votes don't survive authorization status changes. This // corner case can only appear if a signer is quickly added, removed and then - // readded (or the inverse), while one of the original voters dropped. If a + // re-added (or the inverse), while one of the original voters dropped. If a // past vote is left cached in the system somewhere, this will interfere with // the final signer outcome. signers: []string{"A", "B", "C", "D", "E"}, @@ -344,7 +344,7 @@ func TestClique(t *testing.T) { }, failure: errUnauthorizedSigner, }, { - // An authorized signer that signed recenty should not be able to sign again + // An authorized signer that signed recently should not be able to sign again signers: []string{"A", "B"}, votes: []testerVote{ {signer: "A"}, diff --git a/console/console.go b/console/console.go index c8f6c9cfeec5..7b9ed27e15ec 100644 --- a/console/console.go +++ b/console/console.go @@ -290,7 +290,7 @@ func (c *Console) AutoCompleteInput(line string, pos int) (string, []string, str if len(line) == 0 || pos == 0 { return "", nil, "" } - // Chunck data to relevant part for autocompletion + // Chunk data to relevant part for autocompletion // E.g. in case of nested lines eth.getBalance(eth.coinb start := pos - 1 for ; start > 0; start-- { @@ -407,7 +407,7 @@ func (c *Console) StopInteractive() { } } -// Interactive starts an interactive user session, where in.put is propted from +// Interactive starts an interactive user session, where input is prompted from // the configured user prompter. func (c *Console) Interactive() { var ( @@ -497,7 +497,7 @@ func (c *Console) readLines(input chan<- string, errc chan<- error, prompt <-cha } } -// countIndents returns the number of identations for the given input. +// countIndents returns the number of indentations for the given input. // In case of invalid input such as var a = } the result can be negative. func countIndents(input string) int { var ( diff --git a/core/blockchain.go b/core/blockchain.go index ee95cfb6cb66..a98c3b4dbeb3 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1375,7 +1375,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types } // In theory we should fire a ChainHeadEvent when we inject // a canonical block, but sometimes we can insert a batch of - // canonicial blocks. Avoid firing too many ChainHeadEvents, + // canonical blocks. Avoid firing too many ChainHeadEvents, // we will fire an accumulated ChainHeadEvent and disable fire // event here. if emitHeadEvent { @@ -1612,7 +1612,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // block in the middle. It can only happen in the clique chain. Whenever // we insert blocks via `insertSideChain`, we only commit `td`, `header` // and `body` if it's non-existent. Since we don't have receipts without - // reexecution, so nothing to commit. But if the sidechain will be adpoted + // reexecution, so nothing to commit. But if the sidechain will be adopted // as the canonical chain eventually, it needs to be reexecuted for missing // state, but if it's this special case here(skip reexecution) we will lose // the empty receipt entry. diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 24309405d2b3..feed8a177789 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -564,7 +564,7 @@ func testShortReorgedSnapSyncingRepair(t *testing.T, snapshots bool) { // Tests a recovery for a long canonical chain with frozen blocks where a recent // block - newer than the ancient limit - was already committed to disk and then // the process crashed. In this case we expect the chain to be rolled back to the -// committed block, with everything afterwads kept as fast sync data. +// committed block, with everything afterwards kept as fast sync data. func TestLongShallowRepair(t *testing.T) { testLongShallowRepair(t, false) } func TestLongShallowRepairWithSnapshots(t *testing.T) { testLongShallowRepair(t, true) } @@ -609,7 +609,7 @@ func testLongShallowRepair(t *testing.T, snapshots bool) { // Tests a recovery for a long canonical chain with frozen blocks where a recent // block - older than the ancient limit - was already committed to disk and then // the process crashed. In this case we expect the chain to be rolled back to the -// committed block, with everything afterwads deleted. +// committed block, with everything afterwards deleted. func TestLongDeepRepair(t *testing.T) { testLongDeepRepair(t, false) } func TestLongDeepRepairWithSnapshots(t *testing.T) { testLongDeepRepair(t, true) } @@ -653,7 +653,7 @@ func testLongDeepRepair(t *testing.T, snapshots bool) { // Tests a recovery for a long canonical chain with frozen blocks where the fast // sync pivot point - newer than the ancient limit - was already committed, after // which the process crashed. In this case we expect the chain to be rolled back -// to the committed block, with everything afterwads kept as fast sync data. +// to the committed block, with everything afterwards kept as fast sync data. func TestLongSnapSyncedShallowRepair(t *testing.T) { testLongSnapSyncedShallowRepair(t, false) } @@ -702,7 +702,7 @@ func testLongSnapSyncedShallowRepair(t *testing.T, snapshots bool) { // Tests a recovery for a long canonical chain with frozen blocks where the fast // sync pivot point - older than the ancient limit - was already committed, after // which the process crashed. In this case we expect the chain to be rolled back -// to the committed block, with everything afterwads deleted. +// to the committed block, with everything afterwards deleted. func TestLongSnapSyncedDeepRepair(t *testing.T) { testLongSnapSyncedDeepRepair(t, false) } func TestLongSnapSyncedDeepRepairWithSnapshots(t *testing.T) { testLongSnapSyncedDeepRepair(t, true) } @@ -843,7 +843,7 @@ func testLongSnapSyncingDeepRepair(t *testing.T, snapshots bool) { // side chain, where a recent block - newer than the ancient limit - was already // committed to disk and then the process crashed. In this test scenario the side // chain is below the committed block. In this case we expect the chain to be -// rolled back to the committed block, with everything afterwads kept as fast +// rolled back to the committed block, with everything afterwards kept as fast // sync data; the side chain completely nuked by the freezer. func TestLongOldForkedShallowRepair(t *testing.T) { testLongOldForkedShallowRepair(t, false) @@ -895,7 +895,7 @@ func testLongOldForkedShallowRepair(t *testing.T, snapshots bool) { // side chain, where a recent block - older than the ancient limit - was already // committed to disk and then the process crashed. In this test scenario the side // chain is below the committed block. In this case we expect the canonical chain -// to be rolled back to the committed block, with everything afterwads deleted; +// to be rolled back to the committed block, with everything afterwards deleted; // the side chain completely nuked by the freezer. func TestLongOldForkedDeepRepair(t *testing.T) { testLongOldForkedDeepRepair(t, false) } func TestLongOldForkedDeepRepairWithSnapshots(t *testing.T) { testLongOldForkedDeepRepair(t, true) } @@ -942,7 +942,7 @@ func testLongOldForkedDeepRepair(t *testing.T, snapshots bool) { // side chain, where the fast sync pivot point - newer than the ancient limit - // was already committed to disk and then the process crashed. In this test scenario // the side chain is below the committed block. In this case we expect the chain -// to be rolled back to the committed block, with everything afterwads kept as +// to be rolled back to the committed block, with everything afterwards kept as // fast sync data; the side chain completely nuked by the freezer. func TestLongOldForkedSnapSyncedShallowRepair(t *testing.T) { testLongOldForkedSnapSyncedShallowRepair(t, false) @@ -994,7 +994,7 @@ func testLongOldForkedSnapSyncedShallowRepair(t *testing.T, snapshots bool) { // side chain, where the fast sync pivot point - older than the ancient limit - // was already committed to disk and then the process crashed. In this test scenario // the side chain is below the committed block. In this case we expect the canonical -// chain to be rolled back to the committed block, with everything afterwads deleted; +// chain to be rolled back to the committed block, with everything afterwards deleted; // the side chain completely nuked by the freezer. func TestLongOldForkedSnapSyncedDeepRepair(t *testing.T) { testLongOldForkedSnapSyncedDeepRepair(t, false) @@ -1149,7 +1149,7 @@ func testLongOldForkedSnapSyncingDeepRepair(t *testing.T, snapshots bool) { // side chain, where a recent block - newer than the ancient limit - was already // committed to disk and then the process crashed. In this test scenario the side // chain is above the committed block. In this case we expect the chain to be -// rolled back to the committed block, with everything afterwads kept as fast +// rolled back to the committed block, with everything afterwards kept as fast // sync data; the side chain completely nuked by the freezer. func TestLongNewerForkedShallowRepair(t *testing.T) { testLongNewerForkedShallowRepair(t, false) @@ -1201,7 +1201,7 @@ func testLongNewerForkedShallowRepair(t *testing.T, snapshots bool) { // side chain, where a recent block - older than the ancient limit - was already // committed to disk and then the process crashed. In this test scenario the side // chain is above the committed block. In this case we expect the canonical chain -// to be rolled back to the committed block, with everything afterwads deleted; +// to be rolled back to the committed block, with everything afterwards deleted; // the side chain completely nuked by the freezer. func TestLongNewerForkedDeepRepair(t *testing.T) { testLongNewerForkedDeepRepair(t, false) } func TestLongNewerForkedDeepRepairWithSnapshots(t *testing.T) { testLongNewerForkedDeepRepair(t, true) } @@ -1248,7 +1248,7 @@ func testLongNewerForkedDeepRepair(t *testing.T, snapshots bool) { // side chain, where the fast sync pivot point - newer than the ancient limit - // was already committed to disk and then the process crashed. In this test scenario // the side chain is above the committed block. In this case we expect the chain -// to be rolled back to the committed block, with everything afterwads kept as fast +// to be rolled back to the committed block, with everything afterwards kept as fast // sync data; the side chain completely nuked by the freezer. func TestLongNewerForkedSnapSyncedShallowRepair(t *testing.T) { testLongNewerForkedSnapSyncedShallowRepair(t, false) @@ -1300,7 +1300,7 @@ func testLongNewerForkedSnapSyncedShallowRepair(t *testing.T, snapshots bool) { // side chain, where the fast sync pivot point - older than the ancient limit - // was already committed to disk and then the process crashed. In this test scenario // the side chain is above the committed block. In this case we expect the canonical -// chain to be rolled back to the committed block, with everything afterwads deleted; +// chain to be rolled back to the committed block, with everything afterwards deleted; // the side chain completely nuked by the freezer. func TestLongNewerForkedSnapSyncedDeepRepair(t *testing.T) { testLongNewerForkedSnapSyncedDeepRepair(t, false) @@ -1454,7 +1454,7 @@ func testLongNewerForkedSnapSyncingDeepRepair(t *testing.T, snapshots bool) { // Tests a recovery for a long canonical chain with frozen blocks and a longer side // chain, where a recent block - newer than the ancient limit - was already committed // to disk and then the process crashed. In this case we expect the chain to be -// rolled back to the committed block, with everything afterwads kept as fast sync +// rolled back to the committed block, with everything afterwards kept as fast sync // data. The side chain completely nuked by the freezer. func TestLongReorgedShallowRepair(t *testing.T) { testLongReorgedShallowRepair(t, false) } func TestLongReorgedShallowRepairWithSnapshots(t *testing.T) { testLongReorgedShallowRepair(t, true) } @@ -1501,7 +1501,7 @@ func testLongReorgedShallowRepair(t *testing.T, snapshots bool) { // Tests a recovery for a long canonical chain with frozen blocks and a longer side // chain, where a recent block - older than the ancient limit - was already committed // to disk and then the process crashed. In this case we expect the canonical chains -// to be rolled back to the committed block, with everything afterwads deleted. The +// to be rolled back to the committed block, with everything afterwards deleted. The // side chain completely nuked by the freezer. func TestLongReorgedDeepRepair(t *testing.T) { testLongReorgedDeepRepair(t, false) } func TestLongReorgedDeepRepairWithSnapshots(t *testing.T) { testLongReorgedDeepRepair(t, true) } @@ -1548,7 +1548,7 @@ func testLongReorgedDeepRepair(t *testing.T, snapshots bool) { // side chain, where the fast sync pivot point - newer than the ancient limit - // was already committed to disk and then the process crashed. In this case we // expect the chain to be rolled back to the committed block, with everything -// afterwads kept as fast sync data. The side chain completely nuked by the +// afterwards kept as fast sync data. The side chain completely nuked by the // freezer. func TestLongReorgedSnapSyncedShallowRepair(t *testing.T) { testLongReorgedSnapSyncedShallowRepair(t, false) @@ -1600,7 +1600,7 @@ func testLongReorgedSnapSyncedShallowRepair(t *testing.T, snapshots bool) { // side chain, where the fast sync pivot point - older than the ancient limit - // was already committed to disk and then the process crashed. In this case we // expect the canonical chains to be rolled back to the committed block, with -// everything afterwads deleted. The side chain completely nuked by the freezer. +// everything afterwards deleted. The side chain completely nuked by the freezer. func TestLongReorgedSnapSyncedDeepRepair(t *testing.T) { testLongReorgedSnapSyncedDeepRepair(t, false) } diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index dbb13caa416c..21d23e1f0c8b 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -285,7 +285,7 @@ func TestTdStorage(t *testing.T) { func TestCanonicalMappingStorage(t *testing.T) { db := NewMemoryDatabase() - // Create a test canonical number and assinged hash to move around + // Create a test canonical number and assigned hash to move around hash, number := common.Hash{0: 0xff}, uint64(314) if entry := ReadCanonicalHash(db, number); entry != (common.Hash{}) { t.Fatalf("Non existent canonical mapping returned: %v", entry) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 831ca69c4c07..1eaf033bbefa 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -260,7 +260,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st if kvblob, _ := db.Get(headerHashKey(1)); len(kvblob) == 0 { return nil, errors.New("ancient chain segments already extracted, please set --datadir.ancient to the correct path") } - // Block #1 is still in the database, we're allowed to init a new feezer + // Block #1 is still in the database, we're allowed to init a new freezer } // Otherwise, the head header is still the genesis, we're allowed to init a new // freezer. diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 51d7d1930854..3fe691cf6d2a 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -46,7 +46,7 @@ var ( errNotSupported = errors.New("this operation is not supported") ) -// indexEntry contains the number/id of the file that the data resides in, aswell as the +// indexEntry contains the number/id of the file that the data resides in, as well as the // offset within the file to the end of the data. // In serialized form, the filenum is stored as uint16. type indexEntry struct { diff --git a/core/state/snapshot/iterator_fast.go b/core/state/snapshot/iterator_fast.go index 48069b8fcf5c..435c28e96f9e 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -319,7 +319,7 @@ func (fi *fastIterator) Slot() []byte { } // Release iterates over all the remaining live layer iterators and releases each -// of thme individually. +// of them individually. func (fi *fastIterator) Release() { for _, it := range fi.iterators { it.it.Release() @@ -327,7 +327,7 @@ func (fi *fastIterator) Release() { fi.iterators = nil } -// Debug is a convencience helper during testing +// Debug is a convenience helper during testing func (fi *fastIterator) Debug() { for _, it := range fi.iterators { fmt.Printf("[p=%v v=%v] ", it.priority, it.it.Hash()[0]) diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index bc4e5cbd0462..7c8077b652ed 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -265,7 +265,7 @@ func TestPostCapBasicDataAccess(t *testing.T) { snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil) snaps.Update(common.HexToHash("0xb3"), common.HexToHash("0xb2"), nil, setAccount("0xb3"), nil) - // checkExist verifies if an account exiss in a snapshot + // checkExist verifies if an account exists in a snapshot checkExist := func(layer *diffLayer, key string) error { if data, _ := layer.Account(common.HexToHash(key)); data == nil { return fmt.Errorf("expected %x to exist, got nil", common.HexToHash(key)) diff --git a/core/state/statedb.go b/core/state/statedb.go index 5c97dd94ade1..50eee8183c31 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -792,7 +792,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // If state snapshotting is active, also mark the destruction there. // Note, we can't do this only at the end of a block because multiple // transactions within the same block might self destruct and then - // ressurrect an account; but the snapshotter needs both events. + // resurrect an account; but the snapshotter needs both events. if s.snap != nil { s.snapDestructs[obj.addrHash] = struct{}{} // We need to maintain account deletions explicitly (will remain set indefinitely) delete(s.snapAccounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a ressurrect) @@ -891,7 +891,7 @@ func (s *StateDB) clearJournalAndRefund() { s.journal = newJournal() s.refund = 0 } - s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entires + s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entries } // Commit writes the state to the underlying in-memory trie database. @@ -938,7 +938,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { log.Crit("Failed to commit dirty codes", "error", err) } } - // Write the account trie changes, measuing the amount of wasted time + // Write the account trie changes, measuring the amount of wasted time var start time.Time if metrics.EnabledExpensive { start = time.Now() diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 6af2d4523b32..092a4fb8711f 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -771,7 +771,7 @@ func TestStateDBAccessList(t *testing.T) { t.Fatalf("expected %x to be in access list", address) } } - // Check that only the expected addresses are present in the acesslist + // Check that only the expected addresses are present in the access list for address := range state.accessList.addresses { if _, exist := addressMap[address]; !exist { t.Fatalf("extra address %x in access list", address) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 95c79eaf36ac..3d9fe556d2ad 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -305,8 +305,8 @@ func TestIterativeDelayedStateSync(t *testing.T) { } for len(nodeElements)+len(codeElements) > 0 { // Sync only half of the scheduled nodes - var nodeProcessd int - var codeProcessd int + var nodeProcessed int + var codeProcessed int if len(codeElements) > 0 { codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1) for i, element := range codeElements[:len(codeResults)] { @@ -321,7 +321,7 @@ func TestIterativeDelayedStateSync(t *testing.T) { t.Fatalf("failed to process result %v", err) } } - codeProcessd = len(codeResults) + codeProcessed = len(codeResults) } if len(nodeElements) > 0 { nodeResults := make([]trie.NodeSyncResult, len(nodeElements)/2+1) @@ -337,7 +337,7 @@ func TestIterativeDelayedStateSync(t *testing.T) { t.Fatalf("failed to process result %v", err) } } - nodeProcessd = len(nodeResults) + nodeProcessed = len(nodeResults) } batch := dstDb.NewBatch() if err := sched.Commit(batch); err != nil { @@ -346,7 +346,7 @@ func TestIterativeDelayedStateSync(t *testing.T) { batch.Write() paths, nodes, codes = sched.Missing(0) - nodeElements = nodeElements[nodeProcessd:] + nodeElements = nodeElements[nodeProcessed:] for i := 0; i < len(paths); i++ { nodeElements = append(nodeElements, stateElement{ path: paths[i], @@ -354,7 +354,7 @@ func TestIterativeDelayedStateSync(t *testing.T) { syncPath: trie.NewSyncPath([]byte(paths[i])), }) } - codeElements = codeElements[codeProcessd:] + codeElements = codeElements[codeProcessed:] for i := 0; i < len(codes); i++ { codeElements = append(codeElements, stateElement{ code: codes[i], diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 0f6bce3b8171..83e8966d4c9f 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -212,7 +212,7 @@ type subfetcher struct { wake chan struct{} // Wake channel if a new task is scheduled stop chan struct{} // Channel to interrupt processing - term chan struct{} // Channel to signal iterruption + term chan struct{} // Channel to signal interruption copy chan chan Trie // Channel to request a copy of the current trie seen map[string]struct{} // Tracks the entries already loaded diff --git a/core/types/block.go b/core/types/block.go index 589a34cef6b5..7525a88f5a38 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -317,7 +317,7 @@ func (b *Block) Header() *Header { return CopyHeader(b.header) } func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles} } // Size returns the true RLP encoded storage size of the block, either by encoding -// and returning it, or returning a previsouly cached value. +// and returning it, or returning a previously cached value. func (b *Block) Size() common.StorageSize { if size := b.size.Load(); size != nil { return size.(common.StorageSize) diff --git a/core/types/block_test.go b/core/types/block_test.go index aa1db2f4faad..9e7f581b1dc4 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -314,7 +314,7 @@ func TestRlpDecodeParentHash(t *testing.T) { } // Also test a very very large header. { - // The rlp-encoding of the heder belowCauses _total_ length of 65540, + // The rlp-encoding of the header belowCauses _total_ length of 65540, // which is the first to blow the fast-path. h := &Header{ ParentHash: want, diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 0fb287292896..ab77e284df35 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -457,7 +457,7 @@ func BenchmarkSimpleLoop(b *testing.B) { byte(vm.JUMP), } - calllRevertingContractWithInput := []byte{ + callRevertingContractWithInput := []byte{ byte(vm.JUMPDEST), // // push args for the call byte(vm.PUSH1), 0, // out size @@ -485,7 +485,7 @@ func BenchmarkSimpleLoop(b *testing.B) { benchmarkNonModifyingCode(100000000, loopingCode, "loop-100M", "", b) benchmarkNonModifyingCode(100000000, callInexistant, "call-nonexist-100M", "", b) benchmarkNonModifyingCode(100000000, callEOA, "call-EOA-100M", "", b) - benchmarkNonModifyingCode(100000000, calllRevertingContractWithInput, "call-reverting-100M", "", b) + benchmarkNonModifyingCode(100000000, callRevertingContractWithInput, "call-reverting-100M", "", b) //benchmarkNonModifyingCode(10000000, staticCallIdentity, "staticcall-identity-10M", b) //benchmarkNonModifyingCode(10000000, loopingCode, "loop-10M", b) diff --git a/crypto/bls12381/isogeny.go b/crypto/bls12381/isogeny.go index c3cb0a6f7bf0..a63f585dd00a 100644 --- a/crypto/bls12381/isogeny.go +++ b/crypto/bls12381/isogeny.go @@ -19,7 +19,7 @@ package bls12381 // isogenyMapG1 applies 11-isogeny map for BLS12-381 G1 defined at draft-irtf-cfrg-hash-to-curve-06. func isogenyMapG1(x, y *fe) { // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-C.2 - params := isogenyConstansG1 + params := isogenyConstantsG1 degree := 15 xNum, xDen, yNum, yDen := new(fe), new(fe), new(fe), new(fe) xNum.set(params[0][degree]) @@ -76,7 +76,7 @@ func isogenyMapG2(e *fp2, x, y *fe2) { y.set(yNum) } -var isogenyConstansG1 = [4][16]*fe{ +var isogenyConstantsG1 = [4][16]*fe{ { {0x4d18b6f3af00131c, 0x19fa219793fee28c, 0x3f2885f1467f19ae, 0x23dcea34f2ffb304, 0xd15b58d2ffc00054, 0x0913be200a20bef4}, {0x898985385cdbbd8b, 0x3c79e43cc7d966aa, 0x1597e193f4cd233a, 0x8637ef1e4d6623ad, 0x11b22deed20d827b, 0x07097bc5998784ad}, diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 6b5f94646fa7..358529459b1c 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -539,7 +539,7 @@ func (api *ConsensusAPI) invalid(err error, latestValid *types.Header) beacon.Pa return beacon.PayloadStatusV1{Status: beacon.INVALID, LatestValidHash: ¤tHash, ValidationError: &errorMsg} } -// heatbeat loops indefinitely, and checks if there have been beacon client updates +// heartbeat loops indefinitely, and checks if there have been beacon client updates // received in the last while. If not - or if they but strange ones - it warns the // user that something might be off with their consensus node. // @@ -649,7 +649,7 @@ func (api *ConsensusAPI) heartbeat() { if eta == 0 { log.Warn(message) } else { - log.Warn(message, "eta", common.PrettyAge(time.Now().Add(-eta))) // weird hack, but duration formatted doens't handle days + log.Warn(message, "eta", common.PrettyAge(time.Now().Add(-eta))) // weird hack, but duration formatted doesn't handle days } offlineLogged = time.Now() } diff --git a/eth/downloader/api.go b/eth/downloader/api.go index b36dd6386500..b3f7113bcde9 100644 --- a/eth/downloader/api.go +++ b/eth/downloader/api.go @@ -125,7 +125,7 @@ type SyncingResult struct { Status ethereum.SyncProgress `json:"status"` } -// uninstallSyncSubscriptionRequest uninstalles a syncing subscription in the API event loop. +// uninstallSyncSubscriptionRequest uninstalls a syncing subscription in the API event loop. type uninstallSyncSubscriptionRequest struct { c chan interface{} uninstalled chan interface{} diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 77353925813d..484a4e20de64 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -236,7 +236,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { // Binary search to find the ancestor start, end := beaconTail.Number.Uint64()-1, number if number := beaconHead.Number.Uint64(); end > number { - // This shouldn't really happen in a healty network, but if the consensus + // This shouldn't really happen in a healthy network, but if the consensus // clients feeds us a shorter chain as the canonical, we should not attempt // to access non-existent skeleton items. log.Warn("Beacon head lower than local chain", "beacon", number, "local", end) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index f9ac8e487bfa..c04352f0aac6 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -364,7 +364,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, // The beacon header syncer is async. It will start this synchronization and // will continue doing other tasks. However, if synchronization needs to be // cancelled, the syncer needs to know if we reached the startup point (and - // inited the cancel cannel) or not yet. Make sure that we'll signal even in + // inited the cancel channel) or not yet. Make sure that we'll signal even in // case of a failure. if beaconPing != nil { defer func() { @@ -1461,7 +1461,7 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode } d.syncStatsLock.Unlock() - // Signal the content downloaders of the availablility of new tasks + // Signal the content downloaders of the availability of new tasks for _, ch := range []chan bool{d.queue.blockWakeCh, d.queue.receiptWakeCh} { select { case ch <- true: diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 1c126bdaed38..450ed61efc5d 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -360,7 +360,7 @@ func (dlp *downloadTesterPeer) RequestAccountRange(id uint64, root, origin, limi } // RequestStorageRanges fetches a batch of storage slots belonging to one or -// more accounts. If slots from only one accout is requested, an origin marker +// more accounts. If slots from only one account is requested, an origin marker // may also be used to retrieve from there. func (dlp *downloadTesterPeer) RequestStorageRanges(id uint64, root common.Hash, accounts []common.Hash, origin, limit []byte, bytes uint64) error { // Create the request and service it @@ -399,7 +399,7 @@ func (dlp *downloadTesterPeer) RequestByteCodes(id uint64, hashes []common.Hash, } // RequestTrieNodes fetches a batch of account or storage trie nodes rooted in -// a specificstate trie. +// a specific state trie. func (dlp *downloadTesterPeer) RequestTrieNodes(id uint64, root common.Hash, paths []snap.TrieNodePathSet, bytes uint64) error { req := &snap.GetTrieNodesPacket{ ID: id, @@ -571,8 +571,8 @@ func testForkedSync(t *testing.T, protocol uint, mode SyncMode) { assertOwnChain(t, tester, len(chainB.blocks)) } -// Tests that synchronising against a much shorter but much heavyer fork works -// corrently and is not dropped. +// Tests that synchronising against a much shorter but much heavier fork works +// currently and is not dropped. func TestHeavyForkedSync66Full(t *testing.T) { testHeavyForkedSync(t, eth.ETH66, FullSync) } func TestHeavyForkedSync66Snap(t *testing.T) { testHeavyForkedSync(t, eth.ETH66, SnapSync) } func TestHeavyForkedSync66Light(t *testing.T) { testHeavyForkedSync(t, eth.ETH66, LightSync) } diff --git a/eth/downloader/fetchers_concurrent.go b/eth/downloader/fetchers_concurrent.go index a0aa197175a3..44e6aa8f8d88 100644 --- a/eth/downloader/fetchers_concurrent.go +++ b/eth/downloader/fetchers_concurrent.go @@ -47,7 +47,7 @@ type typedQueue interface { // capacity is responsible for calculating how many items of the abstracted // type a particular peer is estimated to be able to retrieve within the - // alloted round trip time. + // allotted round trip time. capacity(peer *peerConnection, rtt time.Duration) int // updateCapacity is responsible for updating how many items of the abstracted @@ -58,7 +58,7 @@ type typedQueue interface { // from the download queue to the specified peer. reserve(peer *peerConnection, items int) (*fetchRequest, bool, bool) - // unreserve is resposible for removing the current retrieval allocation + // unreserve is responsible for removing the current retrieval allocation // assigned to a specific peer and placing it back into the pool to allow // reassigning to some other peer. unreserve(peer string) int @@ -190,7 +190,7 @@ func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { req, err := queue.request(peer, request, responses) if err != nil { // Sending the request failed, which generally means the peer - // was diconnected in between assignment and network send. + // was disconnected in between assignment and network send. // Although all peer removal operations return allocated tasks // to the queue, that is async, and we can do better here by // immediately pushing the unfulfilled requests. diff --git a/eth/downloader/fetchers_concurrent_bodies.go b/eth/downloader/fetchers_concurrent_bodies.go index a8de410323f3..e84206fe9951 100644 --- a/eth/downloader/fetchers_concurrent_bodies.go +++ b/eth/downloader/fetchers_concurrent_bodies.go @@ -41,7 +41,7 @@ func (q *bodyQueue) pending() int { } // capacity is responsible for calculating how many bodies a particular peer is -// estimated to be able to retrieve within the alloted round trip time. +// estimated to be able to retrieve within the allotted round trip time. func (q *bodyQueue) capacity(peer *peerConnection, rtt time.Duration) int { return peer.BodyCapacity(rtt) } @@ -58,7 +58,7 @@ func (q *bodyQueue) reserve(peer *peerConnection, items int) (*fetchRequest, boo return q.queue.ReserveBodies(peer, items) } -// unreserve is resposible for removing the current body retrieval allocation +// unreserve is responsible for removing the current body retrieval allocation // assigned to a specific peer and placing it back into the pool to allow // reassigning to some other peer. func (q *bodyQueue) unreserve(peer string) int { diff --git a/eth/downloader/fetchers_concurrent_headers.go b/eth/downloader/fetchers_concurrent_headers.go index bd3bb3e00bf3..84c7f209865a 100644 --- a/eth/downloader/fetchers_concurrent_headers.go +++ b/eth/downloader/fetchers_concurrent_headers.go @@ -41,7 +41,7 @@ func (q *headerQueue) pending() int { } // capacity is responsible for calculating how many headers a particular peer is -// estimated to be able to retrieve within the alloted round trip time. +// estimated to be able to retrieve within the allotted round trip time. func (q *headerQueue) capacity(peer *peerConnection, rtt time.Duration) int { return peer.HeaderCapacity(rtt) } @@ -58,7 +58,7 @@ func (q *headerQueue) reserve(peer *peerConnection, items int) (*fetchRequest, b return q.queue.ReserveHeaders(peer, items), false, false } -// unreserve is resposible for removing the current header retrieval allocation +// unreserve is responsible for removing the current header retrieval allocation // assigned to a specific peer and placing it back into the pool to allow // reassigning to some other peer. func (q *headerQueue) unreserve(peer string) int { diff --git a/eth/downloader/fetchers_concurrent_receipts.go b/eth/downloader/fetchers_concurrent_receipts.go index fee2c34101d2..1c853c218443 100644 --- a/eth/downloader/fetchers_concurrent_receipts.go +++ b/eth/downloader/fetchers_concurrent_receipts.go @@ -28,7 +28,7 @@ import ( // concurrent fetcher and the downloader. type receiptQueue Downloader -// waker returns a notification channel that gets pinged in case more reecipt +// waker returns a notification channel that gets pinged in case more receipt // fetches have been queued up, so the fetcher might assign it to idle peers. func (q *receiptQueue) waker() chan bool { return q.queue.receiptWakeCh @@ -41,7 +41,7 @@ func (q *receiptQueue) pending() int { } // capacity is responsible for calculating how many receipts a particular peer is -// estimated to be able to retrieve within the alloted round trip time. +// estimated to be able to retrieve within the allotted round trip time. func (q *receiptQueue) capacity(peer *peerConnection, rtt time.Duration) int { return peer.ReceiptCapacity(rtt) } @@ -58,7 +58,7 @@ func (q *receiptQueue) reserve(peer *peerConnection, items int) (*fetchRequest, return q.queue.ReserveReceipts(peer, items) } -// unreserve is resposible for removing the current receipt retrieval allocation +// unreserve is responsible for removing the current receipt retrieval allocation // assigned to a specific peer and placing it back into the pool to allow // reassigning to some other peer. func (q *receiptQueue) unreserve(peer string) int { diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index de5708be32e7..a8d2ea83a9ee 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -859,7 +859,7 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, if res, stale, err := q.resultCache.GetDeliverySlot(header.Number.Uint64()); err == nil { reconstruct(accepted, res) } else { - // else: betweeen here and above, some other peer filled this result, + // else: between here and above, some other peer filled this result, // or it was indeed a no-op. This should not happen, but if it does it's // not something to panic about log.Error("Delivery stale", "stale", stale, "number", header.Number.Uint64(), "err", err) diff --git a/eth/downloader/skeleton.go b/eth/downloader/skeleton.go index be4e8fbfc10c..e627c6ae5a35 100644 --- a/eth/downloader/skeleton.go +++ b/eth/downloader/skeleton.go @@ -51,7 +51,7 @@ const requestHeaders = 512 // errSyncLinked is an internal helper error to signal that the current sync // cycle linked up to the genesis block, this the skeleton syncer should ping // the backfiller to resume. Since we already have that logic on sync start, -// piggie-back on that instead of 2 entrypoints. +// piggy-back on that instead of 2 entrypoints. var errSyncLinked = errors.New("sync linked") // errSyncMerged is an internal helper error to signal that the current sync @@ -148,7 +148,7 @@ type backfiller interface { // suspend requests the backfiller to abort any running full or snap sync // based on the skeleton chain as it might be invalid. The backfiller should // gracefully handle multiple consecutive suspends without a resume, even - // on initial sartup. + // on initial startup. // // The method should return the last block header that has been successfully // backfilled, or nil if the backfiller was not resumed. @@ -209,7 +209,7 @@ type skeleton struct { headEvents chan *headUpdate // Notification channel for new heads terminate chan chan error // Termination channel to abort sync - terminated chan struct{} // Channel to signal that the syner is dead + terminated chan struct{} // Channel to signal that the syncer is dead // Callback hooks used during testing syncStarting func() // callback triggered after a sync cycle is inited but before started @@ -553,7 +553,7 @@ func (s *skeleton) initSync(head *types.Header) { return } } - // Either we've failed to decode the previus state, or there was none. Start + // Either we've failed to decode the previous state, or there was none. Start // a fresh sync with a single subchain represented by the currently sent // chain head. s.progress = &skeletonProgress{ @@ -823,7 +823,7 @@ func (s *skeleton) executeTask(peer *peerConnection, req *headerRequest) { } } -// revertRequests locates all the currently pending reuqests from a particular +// revertRequests locates all the currently pending requests from a particular // peer and reverts them, rescheduling for others to fulfill. func (s *skeleton) revertRequests(peer string) { // Gather the requests first, revertals need the lock too @@ -871,7 +871,7 @@ func (s *skeleton) revertRequest(req *headerRequest) { delete(s.requests, req.id) // Remove the request from the tracked set and mark the task as not-pending, - // ready for resheduling + // ready for rescheduling s.scratchOwners[(s.scratchHead-req.head)/requestHeaders] = "" } diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index 42192571804a..6bcbac3a89fe 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -53,7 +53,7 @@ func newHookedBackfiller() backfiller { // suspend requests the backfiller to abort any running full or snap sync // based on the skeleton chain as it might be invalid. The backfiller should // gracefully handle multiple consecutive suspends without a resume, even -// on initial sartup. +// on initial startup. func (hf *hookedBackfiller) suspend() *types.Header { if hf.suspendHook != nil { hf.suspendHook() @@ -111,7 +111,7 @@ func newSkeletonTestPeerWithHook(id string, headers []*types.Header, serve func( // function can be used to retrieve batches of headers from the particular peer. func (p *skeletonTestPeer) RequestHeadersByNumber(origin uint64, amount int, skip int, reverse bool, sink chan *eth.Response) (*eth.Request, error) { // Since skeleton test peer are in-memory mocks, dropping the does not make - // them inaccepssible. As such, check a local `dropped` field to see if the + // them inaccessible. As such, check a local `dropped` field to see if the // peer has been dropped and should not respond any more. if atomic.LoadUint64(&p.dropped) != 0 { return nil, errors.New("peer already dropped") @@ -204,7 +204,7 @@ func (p *skeletonTestPeer) RequestReceipts([]common.Hash, chan *eth.Response) (* panic("skeleton sync must not request receipts") } -// Tests various sync initialzations based on previous leftovers in the database +// Tests various sync initializations based on previous leftovers in the database // and announced heads. func TestSkeletonSyncInit(t *testing.T) { // Create a few key headers @@ -227,7 +227,7 @@ func TestSkeletonSyncInit(t *testing.T) { newstate: []*subchain{{Head: 50, Tail: 50}}, }, // Empty database with only the genesis set with a leftover empty sync - // progess. This is a synthetic case, just for the sake of covering things. + // progress. This is a synthetic case, just for the sake of covering things. { oldstate: []*subchain{}, head: block50, @@ -533,13 +533,13 @@ func TestSkeletonSyncRetrievals(t *testing.T) { peers []*skeletonTestPeer // Initial peer set to start the sync with midstate []*subchain // Expected sync state after initial cycle midserve uint64 // Expected number of header retrievals after initial cycle - middrop uint64 // Expectd number of peers dropped after initial cycle + middrop uint64 // Expected number of peers dropped after initial cycle - newHead *types.Header // New header to annount on top of the old one + newHead *types.Header // New header to anoint on top of the old one newPeer *skeletonTestPeer // New peer to join the skeleton syncer endstate []*subchain // Expected sync state after the post-init event endserve uint64 // Expected number of header retrievals after the post-init event - enddrop uint64 // Expectd number of peers dropped after the post-init event + enddrop uint64 // Expected number of peers dropped after the post-init event }{ // Completely empty database with only the genesis set. The sync is expected // to create a single subchain with the requested head. No peers however, so diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 7ba2faf791b4..d1323de7b0f4 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -196,7 +196,7 @@ type Config struct { RPCEVMTimeout time.Duration // RPCTxFeeCap is the global transaction fee(price * gaslimit) cap for - // send-transction variants. The unit is ether. + // send-transaction variants. The unit is ether. RPCTxFeeCap float64 // Checkpoint is a hardcoded checkpoint which can be nil. diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index a23cd24bf106..035e0c2ec7d8 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -120,7 +120,7 @@ type txDelivery struct { direct bool // Whether this is a direct reply or a broadcast } -// txDrop is the notiication that a peer has disconnected. +// txDrop is the notification that a peer has disconnected. type txDrop struct { peer string } @@ -260,7 +260,7 @@ func (f *TxFetcher) Notify(peer string, hashes []common.Hash) error { // Enqueue imports a batch of received transaction into the transaction pool // and the fetcher. This method may be called by both transaction broadcasts and // direct request replies. The differentiation is important so the fetcher can -// re-shedule missing transactions as soon as possible. +// re-schedule missing transactions as soon as possible. func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) error { // Keep track of all the propagated transactions if direct { @@ -558,7 +558,7 @@ func (f *TxFetcher) loop() { // In case of a direct delivery, also reschedule anything missing // from the original query if delivery.direct { - // Mark the reqesting successful (independent of individual status) + // Mark the requesting successful (independent of individual status) txRequestDoneMeter.Mark(int64(len(delivery.hashes))) // Make sure something was pending, nuke it @@ -607,7 +607,7 @@ func (f *TxFetcher) loop() { delete(f.alternates, hash) delete(f.fetching, hash) } - // Something was delivered, try to rechedule requests + // Something was delivered, try to reschedule requests f.scheduleFetches(timeoutTimer, timeoutTrigger, nil) // Partial delivery may enable others to deliver too } @@ -719,7 +719,7 @@ func (f *TxFetcher) rescheduleWait(timer *mclock.Timer, trigger chan struct{}) { // should be rescheduled if some request is pending. In practice, a timeout will // cause the timer to be rescheduled every 5 secs (until the peer comes through or // disconnects). This is a limitation of the fetcher code because we don't trac -// pending requests and timed out requests separatey. Without double tracking, if +// pending requests and timed out requests separately. Without double tracking, if // we simply didn't reschedule the timer on all-timeout then the timer would never // be set again since len(request) > 0 => something's running. func (f *TxFetcher) rescheduleTimeout(timer *mclock.Timer, trigger chan struct{}) { diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index ce8d02af7ddf..4c06712f7759 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -1011,7 +1011,7 @@ func TestTransactionFetcherOutOfBoundDeliveries(t *testing.T) { } // Tests that dropping a peer cleans out all internal data structures in all the -// live or danglng stages. +// live or dangling stages. func TestTransactionFetcherDrop(t *testing.T) { testTransactionFetcherParallel(t, txFetcherTest{ init: func() *TxFetcher { @@ -1121,7 +1121,7 @@ func TestTransactionFetcherDropRescheduling(t *testing.T) { } // This test reproduces a crash caught by the fuzzer. The root cause was a -// dangling transaction timing out and clashing on readd with a concurrently +// dangling transaction timing out and clashing on re-add with a concurrently // announced one. func TestTransactionFetcherFuzzCrash01(t *testing.T) { testTransactionFetcherParallel(t, txFetcherTest{ @@ -1148,7 +1148,7 @@ func TestTransactionFetcherFuzzCrash01(t *testing.T) { } // This test reproduces a crash caught by the fuzzer. The root cause was a -// dangling transaction getting peer-dropped and clashing on readd with a +// dangling transaction getting peer-dropped and clashing on re-add with a // concurrently announced one. func TestTransactionFetcherFuzzCrash02(t *testing.T) { testTransactionFetcherParallel(t, txFetcherTest{ diff --git a/eth/filters/api.go b/eth/filters/api.go index 07714791d263..3b8933d0af97 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -36,7 +36,7 @@ import ( // and associated subscription in the event system. type filter struct { typ Type - deadline *time.Timer // filter is inactiv when deadline triggers + deadline *time.Timer // filter is inactive when deadline triggers hashes []common.Hash crit FilterCriteria logs []*types.Log diff --git a/eth/peerset.go b/eth/peerset.go index 3e54a481e36b..b9cc1e03aca3 100644 --- a/eth/peerset.go +++ b/eth/peerset.go @@ -41,7 +41,7 @@ var ( errPeerNotRegistered = errors.New("peer not registered") // errSnapWithoutEth is returned if a peer attempts to connect only on the - // snap protocol without advertizing the eth main protocol. + // snap protocol without advertising the eth main protocol. errSnapWithoutEth = errors.New("peer connected on snap without compatible eth support") ) diff --git a/eth/protocols/eth/broadcast.go b/eth/protocols/eth/broadcast.go index 09330cfdf320..6fc15f136bff 100644 --- a/eth/protocols/eth/broadcast.go +++ b/eth/protocols/eth/broadcast.go @@ -36,7 +36,7 @@ type blockPropagation struct { td *big.Int } -// broadcastBlocks is a write loop that multiplexes blocks and block accouncements +// broadcastBlocks is a write loop that multiplexes blocks and block announcements // to the remote peer. The goal is to have an async writer that does not lock up // node internals and at the same time rate limits queued data. func (p *Peer) broadcastBlocks() { diff --git a/eth/protocols/eth/dispatcher.go b/eth/protocols/eth/dispatcher.go index bf88d400d4a0..65a935d55548 100644 --- a/eth/protocols/eth/dispatcher.go +++ b/eth/protocols/eth/dispatcher.go @@ -224,7 +224,7 @@ func (p *Peer) dispatcher() { switch { case res.Req == nil: // Response arrived with an untracked ID. Since even cancelled - // requests are tracked until fulfilment, a dangling repsponse + // requests are tracked until fulfilment, a dangling response // means the remote peer implements the protocol badly. resOp.fail <- errDanglingResponse diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index bf836e8f5132..2707a420bc6a 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -94,7 +94,7 @@ func (b *testBackend) Chain() *core.BlockChain { return b.chain } func (b *testBackend) TxPool() TxPool { return b.txpool } func (b *testBackend) RunPeer(peer *Peer, handler Handler) error { - // Normally the backend would do peer mainentance and handshakes. All that + // Normally the backend would do peer maintenance and handshakes. All that // is omitted and we will just give control back to the handler. return handler(peer) } diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index 22674d65b041..a23726384d70 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -133,7 +133,7 @@ func (p *Peer) ID() string { return p.id } -// Version retrieves the peer's negoatiated `eth` protocol version. +// Version retrieves the peer's negotiated `eth` protocol version. func (p *Peer) Version() uint { return p.version } diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 77bd96f46e8a..41380d96f571 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -504,7 +504,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s var ( nodes [][]byte bytes uint64 - loads int // Trie hash expansions to cound database reads + loads int // Trie hash expansions to count database reads ) for _, pathset := range req.Paths { switch len(pathset) { diff --git a/eth/protocols/snap/peer.go b/eth/protocols/snap/peer.go index 87a62d2f8a41..235d499ffdc9 100644 --- a/eth/protocols/snap/peer.go +++ b/eth/protocols/snap/peer.go @@ -61,12 +61,12 @@ func (p *Peer) ID() string { return p.id } -// Version retrieves the peer's negoatiated `snap` protocol version. +// Version retrieves the peer's negotiated `snap` protocol version. func (p *Peer) Version() uint { return p.version } -// Log overrides the P2P logget with the higher level one containing only the id. +// Log overrides the P2P logger with the higher level one containing only the id. func (p *Peer) Log() log.Logger { return p.logger } @@ -87,7 +87,7 @@ func (p *Peer) RequestAccountRange(id uint64, root common.Hash, origin, limit co } // RequestStorageRange fetches a batch of storage slots belonging to one or more -// accounts. If slots from only one accout is requested, an origin marker may also +// accounts. If slots from only one account is requested, an origin marker may also // be used to retrieve from there. func (p *Peer) RequestStorageRanges(id uint64, root common.Hash, accounts []common.Hash, origin, limit []byte, bytes uint64) error { if len(accounts) == 1 && origin != nil { @@ -119,7 +119,7 @@ func (p *Peer) RequestByteCodes(id uint64, hashes []common.Hash, bytes uint64) e } // RequestTrieNodes fetches a batch of account or storage trie nodes rooted in -// a specificstate trie. +// a specific state trie. func (p *Peer) RequestTrieNodes(id uint64, root common.Hash, paths []TrieNodePathSet, bytes uint64) error { p.logger.Trace("Fetching set of trie nodes", "reqid", id, "root", root, "pathsets", len(paths), "bytes", common.StorageSize(bytes)) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index b2462f5f892a..deaa4456e0fd 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -365,7 +365,7 @@ type SyncPeer interface { RequestAccountRange(id uint64, root, origin, limit common.Hash, bytes uint64) error // RequestStorageRanges fetches a batch of storage slots belonging to one or - // more accounts. If slots from only one accout is requested, an origin marker + // more accounts. If slots from only one account is requested, an origin marker // may also be used to retrieve from there. RequestStorageRanges(id uint64, root common.Hash, accounts []common.Hash, origin, limit []byte, bytes uint64) error @@ -373,7 +373,7 @@ type SyncPeer interface { RequestByteCodes(id uint64, hashes []common.Hash, bytes uint64) error // RequestTrieNodes fetches a batch of account or storage trie nodes rooted in - // a specificstate trie. + // a specific state trie. RequestTrieNodes(id uint64, root common.Hash, paths []TrieNodePathSet, bytes uint64) error // Log retrieves the peer's own contextual logger. @@ -1183,10 +1183,10 @@ func (s *Syncer) assignStorageTasks(success chan *storageResponse, fail chan *st } if subtask == nil { // No large contract required retrieval, but small ones available - for acccount, root := range task.stateTasks { - delete(task.stateTasks, acccount) + for account, root := range task.stateTasks { + delete(task.stateTasks, account) - accounts = append(accounts, acccount) + accounts = append(accounts, account) roots = append(roots, root) if len(accounts) >= storageSets { @@ -1486,7 +1486,7 @@ func (s *Syncer) assignBytecodeHealTasks(success chan *bytecodeHealResponse, fai } } -// revertRequests locates all the currently pending reuqests from a particular +// revertRequests locates all the currently pending requests from a particular // peer and reverts them, rescheduling for others to fulfill. func (s *Syncer) revertRequests(peer string) { // Gather the requests first, revertals need the lock too @@ -1575,7 +1575,7 @@ func (s *Syncer) revertAccountRequest(req *accountRequest) { s.lock.Unlock() // If there's a timeout timer still running, abort it and mark the account - // task as not-pending, ready for resheduling + // task as not-pending, ready for rescheduling req.timeout.Stop() if req.task.req == req { req.task.req = nil @@ -1616,7 +1616,7 @@ func (s *Syncer) revertBytecodeRequest(req *bytecodeRequest) { s.lock.Unlock() // If there's a timeout timer still running, abort it and mark the code - // retrievals as not-pending, ready for resheduling + // retrievals as not-pending, ready for rescheduling req.timeout.Stop() for _, hash := range req.hashes { req.task.codeTasks[hash] = struct{}{} @@ -1657,7 +1657,7 @@ func (s *Syncer) revertStorageRequest(req *storageRequest) { s.lock.Unlock() // If there's a timeout timer still running, abort it and mark the storage - // task as not-pending, ready for resheduling + // task as not-pending, ready for rescheduling req.timeout.Stop() if req.subTask != nil { req.subTask.req = nil @@ -1743,7 +1743,7 @@ func (s *Syncer) revertBytecodeHealRequest(req *bytecodeHealRequest) { s.lock.Unlock() // If there's a timeout timer still running, abort it and mark the code - // retrievals as not-pending, ready for resheduling + // retrievals as not-pending, ready for rescheduling req.timeout.Stop() for _, hash := range req.hashes { req.task.codeTasks[hash] = struct{}{} @@ -2035,7 +2035,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { } tr.Commit() } - // Persist the received storage segements. These flat state maybe + // Persist the received storage segments. These flat state maybe // outdated during the sync, but it can be fixed later during the // snapshot generation. for j := 0; j < len(res.hashes[i]); j++ { @@ -2170,7 +2170,7 @@ func (s *Syncer) forwardAccountTask(task *accountTask) { } task.res = nil - // Persist the received account segements. These flat state maybe + // Persist the received account segments. These flat state maybe // outdated during the sync, but it can be fixed later during the // snapshot generation. oldAccountBytes := s.accountBytes @@ -2773,7 +2773,7 @@ func (s *Syncer) onHealByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) e } // onHealState is a callback method to invoke when a flat state(account -// or storage slot) is downloded during the healing stage. The flat states +// or storage slot) is downloaded during the healing stage. The flat states // can be persisted blindly and can be fixed later in the generation stage. // Note it's not concurrent safe, please handle the concurrent issue outside. func (s *Syncer) onHealState(paths [][]byte, value []byte) error { diff --git a/eth/state_accessor.go b/eth/state_accessor.go index f01db93a6785..12dba8a0a9b0 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -44,7 +44,7 @@ import ( // perform Commit or other 'save-to-disk' changes, this should be set to false to avoid // storing trash persistently // - preferDisk: this arg can be used by the caller to signal that even though the 'base' is provided, -// it would be preferrable to start from a fresh state, if we have it on disk. +// it would be preferable to start from a fresh state, if we have it on disk. func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { var ( current *types.Block diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 014e2f6ad8d1..092950e78fa9 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -116,7 +116,7 @@ func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.H return header } -// chainContext construts the context reader which is used by the evm for reading +// chainContext constructs the context reader which is used by the evm for reading // the necessary chain context. func (api *API) chainContext(ctx context.Context) core.ChainContext { return &chainContext{api: api, ctx: ctx} @@ -202,10 +202,10 @@ type blockTraceTask struct { statedb *state.StateDB // Intermediate state prepped for tracing block *types.Block // Block to trace the transactions from rootref common.Hash // Trie root reference held for this task - results []*txTraceResult // Trace results procudes by the task + results []*txTraceResult // Trace results produced by the task } -// blockTraceResult represets the results of tracing a single block when an entire +// blockTraceResult represents the results of tracing a single block when an entire // chain is being traced. type blockTraceResult struct { Block hexutil.Uint64 `json:"block"` // Block number corresponding to this trace @@ -563,7 +563,7 @@ func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Has // traceBlock configures a new tracer according to the provided configuration, and // executes all the transactions contained within. The return value will be one item -// per transaction, dependent on the requestd tracer. +// per transaction, dependent on the requested tracer. func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) { if block.NumberU64() == 0 { return nil, errors.New("genesis is not traceable") @@ -707,7 +707,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } } for i, tx := range block.Transactions() { - // Prepare the trasaction for un-traced execution + // Prepare the transaction for un-traced execution var ( msg, _ = tx.AsMessage(signer, block.BaseFee()) txContext = core.NewEVMTxContext(msg) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index cabddac49902..d2c50656d9a8 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -39,7 +39,7 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" - // Force-load native and js pacakges, to trigger registration + // Force-load native and js packages, to trigger registration _ "github.com/ethereum/go-ethereum/eth/tracers/js" _ "github.com/ethereum/go-ethereum/eth/tracers/native" ) diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index d78a12fae72b..f2f4a5765d13 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -581,7 +581,7 @@ func testCallContract(t *testing.T, client *rpc.Client) { if _, err := ec.CallContract(context.Background(), msg, big.NewInt(1)); err != nil { t.Fatalf("unexpected error: %v", err) } - // PendingCallCOntract + // PendingCallContract if _, err := ec.PendingCallContract(context.Background(), msg); err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index e94570cb3f0e..7e4fd7e5e7f0 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -66,7 +66,7 @@ func NewWithCap(size int) *Database { } // Close deallocates the internal map and ensures any consecutive data access op -// failes with an error. +// fails with an error. func (db *Database) Close() error { db.lock.Lock() defer db.lock.Unlock() diff --git a/interfaces.go b/interfaces.go index e8d24a57cf7a..eb9af60076e0 100644 --- a/interfaces.go +++ b/interfaces.go @@ -204,7 +204,7 @@ type GasPricer interface { // FeeHistory provides recent fee market data that consumers can use to determine // a reasonable maxPriorityFeePerGas value. type FeeHistory struct { - OldestBlock *big.Int // block coresponding to first response value + OldestBlock *big.Int // block corresponding to first response value Reward [][]*big.Int // list every txs priority fee per block BaseFee []*big.Int // list of each block's base fee GasUsedRatio []float64 // ratio of gas used out of the total available limit diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 939dd69396f3..e6740942d859 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -988,7 +988,7 @@ func newRevertError(result *core.ExecutionResult) *revertError { } } -// revertError is an API error that encompassas an EVM revertal with JSON error +// revertError is an API error that encompasses an EVM revertal with JSON error // code and a binary data blob. type revertError struct { error diff --git a/les/downloader/api.go b/les/downloader/api.go index b1a81b6b76d3..21200b676c64 100644 --- a/les/downloader/api.go +++ b/les/downloader/api.go @@ -125,7 +125,7 @@ type SyncingResult struct { Status ethereum.SyncProgress `json:"status"` } -// uninstallSyncSubscriptionRequest uninstalles a syncing subscription in the API event loop. +// uninstallSyncSubscriptionRequest uninstalls a syncing subscription in the API event loop. type uninstallSyncSubscriptionRequest struct { c chan interface{} uninstalled chan interface{} diff --git a/les/downloader/downloader.go b/les/downloader/downloader.go index b9da76d3478d..6352b1c21729 100644 --- a/les/downloader/downloader.go +++ b/les/downloader/downloader.go @@ -1625,7 +1625,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error { log.Warn("Invalid header encountered", "number", chunk[n].Number, "hash", chunk[n].Hash(), "parent", chunk[n].ParentHash, "err", err) return fmt.Errorf("%w: %v", errInvalidChain, err) } - // All verifications passed, track all headers within the alloted limits + // All verifications passed, track all headers within the allotted limits if mode == FastSync { head := chunk[len(chunk)-1].Number.Uint64() if head-rollback > uint64(fsHeaderSafetyNet) { @@ -1663,7 +1663,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error { } d.syncStatsLock.Unlock() - // Signal the content downloaders of the availablility of new tasks + // Signal the content downloaders of the availability of new tasks for _, ch := range []chan bool{d.bodyWakeCh, d.receiptWakeCh} { select { case ch <- true: diff --git a/les/downloader/downloader_test.go b/les/downloader/downloader_test.go index 5eea49877969..c56870ff1784 100644 --- a/les/downloader/downloader_test.go +++ b/les/downloader/downloader_test.go @@ -653,8 +653,8 @@ func testForkedSync(t *testing.T, protocol uint, mode SyncMode) { assertOwnForkedChain(t, tester, testChainBase.len(), []int{chainA.len(), chainB.len()}) } -// Tests that synchronising against a much shorter but much heavyer fork works -// corrently and is not dropped. +// Tests that synchronising against a much shorter but much heavier fork works +// correctly and is not dropped. func TestHeavyForkedSync66Full(t *testing.T) { testHeavyForkedSync(t, eth.ETH66, FullSync) } func TestHeavyForkedSync66Fast(t *testing.T) { testHeavyForkedSync(t, eth.ETH66, FastSync) } func TestHeavyForkedSync66Light(t *testing.T) { testHeavyForkedSync(t, eth.ETH66, LightSync) } diff --git a/les/downloader/queue.go b/les/downloader/queue.go index 5744b3ee279d..b165b6b5c1c7 100644 --- a/les/downloader/queue.go +++ b/les/downloader/queue.go @@ -872,7 +872,7 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, if res, stale, err := q.resultCache.GetDeliverySlot(header.Number.Uint64()); err == nil { reconstruct(accepted, res) } else { - // else: betweeen here and above, some other peer filled this result, + // else: between here and above, some other peer filled this result, // or it was indeed a no-op. This should not happen, but if it does it's // not something to panic about log.Error("Delivery stale", "stale", stale, "number", header.Number.Uint64(), "err", err) diff --git a/les/fetcher.go b/les/fetcher.go index cf62c8f70776..6861eebcf5e9 100644 --- a/les/fetcher.go +++ b/les/fetcher.go @@ -252,7 +252,7 @@ func (f *lightFetcher) forEachPeer(check func(id enode.ID, p *fetcherPeer) bool) // request will be made for header retrieval. // // - re-sync trigger -// If the local chain lags too much, then the fetcher will enter "synnchronise" +// If the local chain lags too much, then the fetcher will enter "synchronise" // mode to retrieve missing headers in batch. func (f *lightFetcher) mainloop() { defer f.wg.Done() diff --git a/les/flowcontrol/manager.go b/les/flowcontrol/manager.go index 4ffbee58f0d0..4367974d632e 100644 --- a/les/flowcontrol/manager.go +++ b/les/flowcontrol/manager.go @@ -55,7 +55,7 @@ var ( // ClientManager controls the capacity assigned to the clients of a server. // Since ServerParams guarantee a safe lower estimate for processable requests // even in case of all clients being active, ClientManager calculates a -// corrigated buffer value and usually allows a higher remaining buffer value +// corrugated buffer value and usually allows a higher remaining buffer value // to be returned with each reply. type ClientManager struct { clock mclock.Clock diff --git a/les/odr.go b/les/odr.go index 10ff0854d385..2643a534787f 100644 --- a/les/odr.go +++ b/les/odr.go @@ -126,7 +126,7 @@ const ( // RetrieveTxStatus retrieves the transaction status from the LES network. // There is no guarantee in the LES protocol that the mined transaction will // be retrieved back for sure because of different reasons(the transaction -// is unindexed, the malicous server doesn't reply it deliberately, etc). +// is unindexed, the malicious server doesn't reply it deliberately, etc). // Therefore, unretrieved transactions(UNKNOWN) will receive a certain number // of retries, thus giving a weak guarantee. func (odr *LesOdr) RetrieveTxStatus(ctx context.Context, req *light.TxStatusRequest) error { diff --git a/les/vflux/client/fillset_test.go b/les/vflux/client/fillset_test.go index ca5af8f07ecc..ddb12a82f9b3 100644 --- a/les/vflux/client/fillset_test.go +++ b/les/vflux/client/fillset_test.go @@ -104,7 +104,7 @@ func TestFillSet(t *testing.T) { fs.SetTarget(10) expWaiting(4, true) expNotWaiting() - // remove all previosly set flags + // remove all previously set flags ns.ForEach(sfTest1, nodestate.Flags{}, func(node *enode.Node, state nodestate.Flags) { ns.SetState(node, nodestate.Flags{}, sfTest1, 0) }) diff --git a/les/vflux/client/serverpool_test.go b/les/vflux/client/serverpool_test.go index 9f83c5f7f2c0..f1fd987d7edb 100644 --- a/les/vflux/client/serverpool_test.go +++ b/les/vflux/client/serverpool_test.go @@ -66,7 +66,7 @@ type ServerPoolTest struct { // (accessed from both the main thread and the preNeg callback) preNegLock sync.Mutex queryWg *sync.WaitGroup // a new wait group is created each time the simulation is started - stopping bool // stopping avoid callind queryWg.Add after queryWg.Wait + stopping bool // stopping avoid calling queryWg.Add after queryWg.Wait cycle, conn, servedConn int serviceCycles, dialCount int diff --git a/les/vflux/server/balance.go b/les/vflux/server/balance.go index 550c6d70ca8b..b09f7bb5012b 100644 --- a/les/vflux/server/balance.go +++ b/les/vflux/server/balance.go @@ -623,7 +623,7 @@ func (n *nodeBalance) priorityToBalance(priority int64, capacity uint64) (uint64 return 0, uint64(-priority) } -// reducedBalance estimates the reduced balance at a given time in the fututre based +// reducedBalance estimates the reduced balance at a given time in the future based // on the given balance, the time factor and an estimated average request cost per time ratio func (n *nodeBalance) reducedBalance(b balance, start mclock.AbsTime, dt time.Duration, capacity uint64, avgReqCost float64) balance { // since the costs are applied continuously during the dt time period we calculate diff --git a/les/vflux/server/balance_test.go b/les/vflux/server/balance_test.go index 9f253cabf48d..7c100aab509f 100644 --- a/les/vflux/server/balance_test.go +++ b/les/vflux/server/balance_test.go @@ -54,7 +54,7 @@ func newBalanceTestSetup(db ethdb.KeyValueStore, posExp, negExp utils.ValueExpir // Initialize and customize the setup for the balance testing clock := &mclock.Simulated{} setup := newServerSetup() - setup.clientField = setup.setup.NewField("balancTestClient", reflect.TypeOf(balanceTestClient{})) + setup.clientField = setup.setup.NewField("balanceTestClient", reflect.TypeOf(balanceTestClient{})) ns := nodestate.NewNodeStateMachine(nil, nil, clock, setup.setup) if posExp == nil { @@ -298,7 +298,7 @@ func TestEstimatedPriority(t *testing.T) { } } -func TestPostiveBalanceCounting(t *testing.T) { +func TestPositiveBalanceCounting(t *testing.T) { b := newBalanceTestSetup(nil, nil, nil) defer b.stop() diff --git a/les/vflux/server/status.go b/les/vflux/server/status.go index 469190777b25..2d7e25b68461 100644 --- a/les/vflux/server/status.go +++ b/les/vflux/server/status.go @@ -41,7 +41,7 @@ type serverSetup struct { activeFlag nodestate.Flags // Flag is set if the node is active inactiveFlag nodestate.Flags // Flag is set if the node is inactive capacityField nodestate.Field // Field contains the capacity of the node - queueField nodestate.Field // Field contains the infomration in the priority queue + queueField nodestate.Field // Field contains the information in the priority queue } // newServerSetup initializes the setup for state machine and returns the flags/fields group. diff --git a/light/lightchain.go b/light/lightchain.go index 2a8e3672145a..dca97ce45ce6 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -397,7 +397,7 @@ func (lc *LightChain) SetCanonical(header *types.Header) error { // // The verify parameter can be used to fine tune whether nonce verification // should be done or not. The reason behind the optional check is because some -// of the header retrieval mechanisms already need to verfy nonces, as well as +// of the header retrieval mechanisms already need to verify nonces, as well as // because nonces can be verified sparsely, not needing to check each. // // In the case of a light chain, InsertHeaderChain also creates and posts light diff --git a/light/odr_util.go b/light/odr_util.go index bbbcdbce2135..48631139b488 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -272,9 +272,9 @@ func GetBloomBits(ctx context.Context, odr OdrBackend, bit uint, sections []uint // GetTransaction retrieves a canonical transaction by hash and also returns // its position in the chain. There is no guarantee in the LES protocol that // the mined transaction will be retrieved back for sure because of different -// reasons(the transaction is unindexed, the malicous server doesn't reply it +// reasons(the transaction is unindexed, the malicious server doesn't reply it // deliberately, etc). Therefore, unretrieved transactions will receive a certain -// number of retrys, thus giving a weak guarantee. +// number of retries, thus giving a weak guarantee. func GetTransaction(ctx context.Context, odr OdrBackend, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { r := &TxStatusRequest{Hashes: []common.Hash{txHash}} if err := odr.RetrieveTxStatus(ctx, r); err != nil || r.Status[0].Status != core.TxStatusIncluded { diff --git a/light/postprocess.go b/light/postprocess.go index 0e50dab96717..3f9da659333e 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -313,7 +313,7 @@ var ( BloomTrieTablePrefix = "blt-" ) -// GetBloomTrieRoot reads the BloomTrie root assoctiated to the given section from the database +// GetBloomTrieRoot reads the BloomTrie root associated to the given section from the database func GetBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], sectionIdx) @@ -321,7 +321,7 @@ func GetBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.H return common.BytesToHash(data) } -// StoreBloomTrieRoot writes the BloomTrie root assoctiated to the given section into the database +// StoreBloomTrieRoot writes the BloomTrie root associated to the given section into the database func StoreBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root common.Hash) { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], sectionIdx) diff --git a/light/trie.go b/light/trie.go index f60edaa3b177..b88265e87d40 100644 --- a/light/trie.go +++ b/light/trie.go @@ -153,7 +153,7 @@ func (t *odrTrie) TryDelete(key []byte) error { }) } -// TryDeleteACcount abstracts an account deletion from the trie. +// TryDeleteAccount abstracts an account deletion from the trie. func (t *odrTrie) TryDeleteAccount(key []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { diff --git a/light/txpool.go b/light/txpool.go index 413337208b84..b3e1a62e1893 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -71,7 +71,7 @@ type TxPool struct { eip2718 bool // Fork indicator whether we are in the eip2718 stage. } -// TxRelayBackend provides an interface to the mechanism that forwards transacions +// TxRelayBackend provides an interface to the mechanism that forwards transactions // to the ETH network. The implementations of the functions should be non-blocking. // // Send instructs backend to forward new transactions diff --git a/metrics/gauge_float64_test.go b/metrics/gauge_float64_test.go index 02b75580c4e5..7b854d232ba8 100644 --- a/metrics/gauge_float64_test.go +++ b/metrics/gauge_float64_test.go @@ -2,7 +2,7 @@ package metrics import "testing" -func BenchmarkGuageFloat64(b *testing.B) { +func BenchmarkGaugeFloat64(b *testing.B) { g := NewGaugeFloat64() b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/metrics/gauge_test.go b/metrics/gauge_test.go index 3aee143455c3..a98fe985d8c2 100644 --- a/metrics/gauge_test.go +++ b/metrics/gauge_test.go @@ -5,7 +5,7 @@ import ( "testing" ) -func BenchmarkGuage(b *testing.B) { +func BenchmarkGauge(b *testing.B) { g := NewGauge() b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index 9ad5ec7e9929..c8408d8cab85 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -36,7 +36,7 @@ func Handler(reg metrics.Registry) http.Handler { }) sort.Strings(names) - // Aggregate all the metris into a Prometheus collector + // Aggregate all the metrics into a Prometheus collector c := newCollector() for _, name := range names { diff --git a/miner/unconfirmed_test.go b/miner/unconfirmed_test.go index dc83cb92652d..60958f658abc 100644 --- a/miner/unconfirmed_test.go +++ b/miner/unconfirmed_test.go @@ -74,7 +74,7 @@ func TestUnconfirmedShifts(t *testing.T) { if n := pool.blocks.Len(); n != int(limit)/2 { t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit/2) } - // Try to shift all the remaining blocks out and verify emptyness + // Try to shift all the remaining blocks out and verify emptiness pool.Shift(start + 2*uint64(limit)) if n := pool.blocks.Len(); n != 0 { t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0) diff --git a/miner/worker_test.go b/miner/worker_test.go index bda0fd4899b0..ec5ba67e1c65 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -494,7 +494,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co } w.start() - time.Sleep(time.Second) // Ensure two tasks have been summitted due to start opt + time.Sleep(time.Second) // Ensure two tasks have been submitted due to start opt atomic.StoreUint32(&start, 1) w.setRecommitInterval(3 * time.Second) diff --git a/mobile/accounts.go b/mobile/accounts.go index 4d979bffff5d..d9eab93a741d 100644 --- a/mobile/accounts.go +++ b/mobile/accounts.go @@ -212,10 +212,10 @@ func (ks *KeyStore) ImportECDSAKey(key []byte, passphrase string) (account *Acco // ImportPreSaleKey decrypts the given Ethereum presale wallet and stores // a key file in the key directory. The key file is encrypted with the same passphrase. -func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (ccount *Account, _ error) { - account, err := ks.keystore.ImportPreSaleKey(common.CopyBytes(keyJSON), passphrase) +func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (account *Account, _ error) { + acc, err := ks.keystore.ImportPreSaleKey(common.CopyBytes(keyJSON), passphrase) if err != nil { return nil, err } - return &Account{account}, nil + return &Account{acc}, nil } diff --git a/mobile/init.go b/mobile/init.go index 2025d85edc92..94f5baf28be7 100644 --- a/mobile/init.go +++ b/mobile/init.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Contains initialization code for the mbile library. +// Contains initialization code for the mobile library. package geth diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index 6fb16c504a9e..09acf7ea0458 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -100,7 +100,7 @@ func TestWebsocketOrigins(t *testing.T) { expFail: []string{ "test", // no scheme, required by spec "http://test", // wrong scheme - "http://test.foo", "https://a.test.x", // subdomain variatoins + "http://test.foo", "https://a.test.x", // subdomain variations "http://testx:8540", "https://xtest:8540"}, }, // ip tests diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 95a6df8e1bd4..67cd2c004cf6 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -525,7 +525,7 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { t.log.Debug("Temporary UDP read error", "err", err) continue } else if err != nil { - // Shut down the loop for permament errors. + // Shut down the loop for permanent errors. if !errors.Is(err, io.EOF) { t.log.Debug("UDP read error", "err", err) } diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 6ffa7bef7e1a..071ed65adc7f 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -625,7 +625,7 @@ func (t *UDPv5) readLoop() { t.log.Debug("Temporary UDP read error", "err", err) continue } else if err != nil { - // Shut down the loop for permament errors. + // Shut down the loop for permanent errors. if !errors.Is(err, io.EOF) { t.log.Debug("UDP read error", "err", err) } diff --git a/p2p/msgrate/msgrate.go b/p2p/msgrate/msgrate.go index 5bfa27b43378..d4e0eb8b5aa3 100644 --- a/p2p/msgrate/msgrate.go +++ b/p2p/msgrate/msgrate.go @@ -111,7 +111,7 @@ const tuningImpact = 0.25 // local link is saturated. In that case, the live measurements will force us // to reduce request sizes until the throughput gets stable. // -// Lastly, message rate measurements allows us to detect if a peer is unsuaully +// Lastly, message rate measurements allows us to detect if a peer is unusually // slow compared to other peers, in which case we can decide to keep it around // or free up the slot so someone closer. // @@ -127,7 +127,7 @@ type Tracker struct { // in their sizes. // // Callers of course are free to use the item counter as a byte counter if - // or when their protocol of choise if capped by bytes instead of items. + // or when their protocol of choice if capped by bytes instead of items. // (eg. eth.getHeaders vs snap.getAccountRange). capacity map[uint64]float64 @@ -157,7 +157,7 @@ func NewTracker(caps map[uint64]float64, rtt time.Duration) *Tracker { } // Capacity calculates the number of items the peer is estimated to be able to -// retrieve within the alloted time slot. The method will round up any division +// retrieve within the allotted time slot. The method will round up any division // errors and will add an additional overestimation ratio on top. The reason for // overshooting the capacity is because certain message types might not increase // the load proportionally to the requested items, so fetching a bit more might diff --git a/p2p/tracker/tracker.go b/p2p/tracker/tracker.go index 69a49087e2c4..6a733b9ba51e 100644 --- a/p2p/tracker/tracker.go +++ b/p2p/tracker/tracker.go @@ -121,7 +121,7 @@ func (t *Tracker) Track(peer string, version uint, reqCode uint64, resCode uint6 } // clean is called automatically when a preset time passes without a response -// being dleivered for the first network request. +// being delivered for the first network request. func (t *Tracker) clean() { t.lock.Lock() defer t.lock.Unlock() diff --git a/rpc/server.go b/rpc/server.go index babc5688e264..bf1f71a28e26 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -160,7 +160,7 @@ type PeerInfo struct { // Address of client. This will usually contain the IP address and port. RemoteAddr string - // Addditional information for HTTP and WebSocket connections. + // Additional information for HTTP and WebSocket connections. HTTP struct { // Protocol version, i.e. "HTTP/1.1". This is not set for WebSocket. Version string diff --git a/signer/rules/rules_test.go b/signer/rules/rules_test.go index 32901e2ff14c..c35da8ecc188 100644 --- a/signer/rules/rules_test.go +++ b/signer/rules/rules_test.go @@ -44,7 +44,7 @@ Three things can happen: 3. Anything else; other return values [*], method not implemented or exception occurred during processing. This means that the operation will continue to manual processing, via the regular UI method chosen by the user. -[*] Note: Future version of the ruleset may use more complex json-based returnvalues, making it possible to not +[*] Note: Future version of the ruleset may use more complex json-based return values, making it possible to not only respond Approve/Reject/Manual, but also modify responses. For example, choose to list only one, but not all accounts in a list-request. The points above will continue to hold for non-json based responses ("Approve"/"Reject"). @@ -242,7 +242,7 @@ func (d *dummyUI) OnApprovedTx(tx ethapi.SignTransactionResult) { func (d *dummyUI) OnSignerStartup(info core.StartupInfo) { } -//TestForwarding tests that the rule-engine correctly dispatches requests to the next caller +// TestForwarding tests that the rule-engine correctly dispatches requests to the next caller func TestForwarding(t *testing.T) { js := "" ui := &dummyUI{make([]string, 0)} @@ -434,7 +434,7 @@ func dummyTx(value hexutil.Big) *core.SignTxRequest { Gas: gas, }, Callinfo: []apitypes.ValidationInfo{ - {Typ: "Warning", Message: "All your base are bellong to us"}, + {Typ: "Warning", Message: "All your base are belong to us"}, }, Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"}, } @@ -536,7 +536,7 @@ func (d *dontCallMe) OnApprovedTx(tx ethapi.SignTransactionResult) { d.t.Fatalf("Did not expect next-handler to be called") } -//TestContextIsCleared tests that the rule-engine does not retain variables over several requests. +// TestContextIsCleared tests that the rule-engine does not retain variables over several requests. // if it does, that would be bad since developers may rely on that to store data, // instead of using the disk-based data storage func TestContextIsCleared(t *testing.T) { diff --git a/signer/storage/aes_gcm_storage.go b/signer/storage/aes_gcm_storage.go index f09bfa7d4f06..928d643dd618 100644 --- a/signer/storage/aes_gcm_storage.go +++ b/signer/storage/aes_gcm_storage.go @@ -143,7 +143,7 @@ func (s *AESEncryptedStorage) writeEncryptedStorage(creds map[string]storedCrede // encrypt encrypts plaintext with the given key, with additional data // The 'additionalData' is used to place the (plaintext) KV-store key into the V, -// to prevent the possibility to alter a K, or swap two entries in the KV store with eachother. +// to prevent the possibility to alter a K, or swap two entries in the KV store with each other. func encrypt(key []byte, plaintext []byte, additionalData []byte) ([]byte, []byte, error) { block, err := aes.NewCipher(key) if err != nil { diff --git a/trie/hasher.go b/trie/hasher.go index 9e17d639fc95..183e96c229ca 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -191,7 +191,7 @@ func (h *hasher) hashData(data []byte) hashNode { } // proofHash is used to construct trie proofs, and returns the 'collapsed' -// node (for later RLP encoding) aswell as the hashed node -- unless the +// node (for later RLP encoding) as well as the hashed node -- unless the // node is smaller than 32 bytes, in which case it will be returned as is. // This method does not do anything on value- or hash-nodes. func (h *hasher) proofHash(original node) (collapsed, hashed node) { diff --git a/trie/proof_test.go b/trie/proof_test.go index 8db035256e32..61667b20ab13 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -205,7 +205,7 @@ func TestRangeProofWithNonExistentProof(t *testing.T) { proof := memorydb.New() // Short circuit if the decreased key is same with the previous key - first := decreseKey(common.CopyBytes(entries[start].k)) + first := decreaseKey(common.CopyBytes(entries[start].k)) if start != 0 && bytes.Equal(first, entries[start-1].k) { continue } @@ -214,7 +214,7 @@ func TestRangeProofWithNonExistentProof(t *testing.T) { continue } // Short circuit if the increased key is same with the next key - last := increseKey(common.CopyBytes(entries[end-1].k)) + last := increaseKey(common.CopyBytes(entries[end-1].k)) if end != len(entries) && bytes.Equal(last, entries[end].k) { continue } @@ -274,7 +274,7 @@ func TestRangeProofWithInvalidNonExistentProof(t *testing.T) { // Case 1 start, end := 100, 200 - first := decreseKey(common.CopyBytes(entries[start].k)) + first := decreaseKey(common.CopyBytes(entries[start].k)) proof := memorydb.New() if err := trie.Prove(first, 0, proof); err != nil { @@ -297,7 +297,7 @@ func TestRangeProofWithInvalidNonExistentProof(t *testing.T) { // Case 2 start, end = 100, 200 - last := increseKey(common.CopyBytes(entries[end-1].k)) + last := increaseKey(common.CopyBytes(entries[end-1].k)) proof = memorydb.New() if err := trie.Prove(entries[start].k, 0, proof); err != nil { t.Fatalf("Failed to prove the first node %v", err) @@ -343,7 +343,7 @@ func TestOneElementRangeProof(t *testing.T) { // One element with left non-existent edge proof start = 1000 - first := decreseKey(common.CopyBytes(entries[start].k)) + first := decreaseKey(common.CopyBytes(entries[start].k)) proof = memorydb.New() if err := trie.Prove(first, 0, proof); err != nil { t.Fatalf("Failed to prove the first node %v", err) @@ -358,7 +358,7 @@ func TestOneElementRangeProof(t *testing.T) { // One element with right non-existent edge proof start = 1000 - last := increseKey(common.CopyBytes(entries[start].k)) + last := increaseKey(common.CopyBytes(entries[start].k)) proof = memorydb.New() if err := trie.Prove(entries[start].k, 0, proof); err != nil { t.Fatalf("Failed to prove the first node %v", err) @@ -373,7 +373,7 @@ func TestOneElementRangeProof(t *testing.T) { // One element with two non-existent edge proofs start = 1000 - first, last = decreseKey(common.CopyBytes(entries[start].k)), increseKey(common.CopyBytes(entries[start].k)) + first, last = decreaseKey(common.CopyBytes(entries[start].k)), increaseKey(common.CopyBytes(entries[start].k)) proof = memorydb.New() if err := trie.Prove(first, 0, proof); err != nil { t.Fatalf("Failed to prove the first node %v", err) @@ -641,9 +641,9 @@ func TestSameSideProofs(t *testing.T) { sort.Sort(entries) pos := 1000 - first := decreseKey(common.CopyBytes(entries[pos].k)) - first = decreseKey(first) - last := decreseKey(common.CopyBytes(entries[pos].k)) + first := decreaseKey(common.CopyBytes(entries[pos].k)) + first = decreaseKey(first) + last := decreaseKey(common.CopyBytes(entries[pos].k)) proof := memorydb.New() if err := trie.Prove(first, 0, proof); err != nil { @@ -657,9 +657,9 @@ func TestSameSideProofs(t *testing.T) { t.Fatalf("Expected error, got nil") } - first = increseKey(common.CopyBytes(entries[pos].k)) - last = increseKey(common.CopyBytes(entries[pos].k)) - last = increseKey(last) + first = increaseKey(common.CopyBytes(entries[pos].k)) + last = increaseKey(common.CopyBytes(entries[pos].k)) + last = increaseKey(last) proof = memorydb.New() if err := trie.Prove(first, 0, proof); err != nil { @@ -765,7 +765,7 @@ func TestEmptyRangeProof(t *testing.T) { } for _, c := range cases { proof := memorydb.New() - first := increseKey(common.CopyBytes(entries[c.pos].k)) + first := increaseKey(common.CopyBytes(entries[c.pos].k)) if err := trie.Prove(first, 0, proof); err != nil { t.Fatalf("Failed to prove the first node %v", err) } @@ -904,7 +904,7 @@ func mutateByte(b []byte) { } } -func increseKey(key []byte) []byte { +func increaseKey(key []byte) []byte { for i := len(key) - 1; i >= 0; i-- { key[i]++ if key[i] != 0x0 { @@ -914,7 +914,7 @@ func increseKey(key []byte) []byte { return key } -func decreseKey(key []byte) []byte { +func decreaseKey(key []byte) []byte { for i := len(key) - 1; i >= 0; i-- { key[i]-- if key[i] != 0xff { diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index 05bddb21b3bc..862c3a3ec43d 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -121,7 +121,7 @@ func TestStateTrieConcurrency(t *testing.T) { for i := 0; i < threads; i++ { tries[i] = trie.Copy() } - // Start a batch of goroutines interactng with the trie + // Start a batch of goroutines interacting with the trie pend := new(sync.WaitGroup) pend.Add(threads) for i := 0; i < threads; i++ { From fa1305f8bf1b1e6c4eadf4d12c9dd8ce7ddc4c6c Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 19 Aug 2022 14:01:09 +0800 Subject: [PATCH 169/715] internal/ethapi: fix comment typo (#25548) --- internal/ethapi/transaction_args.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 787ac65777e0..e07248db5d69 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -238,7 +238,7 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (t gasPrice = args.GasPrice.ToInt() gasFeeCap, gasTipCap = gasPrice, gasPrice } else { - // User specified 1559 gas feilds (or none), use those + // User specified 1559 gas fields (or none), use those gasFeeCap = new(big.Int) if args.MaxFeePerGas != nil { gasFeeCap = args.MaxFeePerGas.ToInt() From 32e849061559d2c15d8c9f8752317b3df7ed267d Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 19 Aug 2022 14:01:43 +0800 Subject: [PATCH 170/715] accounts/abi/bind/backends: typo fix (#25549) --- accounts/abi/bind/backends/simulated.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index cd14afa14755..e03f2e1202b1 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -609,7 +609,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM // User specified the legacy gas field, convert to 1559 gas typing call.GasFeeCap, call.GasTipCap = call.GasPrice, call.GasPrice } else { - // User specified 1559 gas feilds (or none), use those + // User specified 1559 gas fields (or none), use those if call.GasFeeCap == nil { call.GasFeeCap = new(big.Int) } From 656dc8cc0034d3dd57b5e1baecb788d9c4e9929d Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Fri, 19 Aug 2022 01:02:47 -0500 Subject: [PATCH 171/715] eth, les: unlock downloader peerSet if there's an error (#25546) Unlock peerSet if there's an error in the downloader --- eth/downloader/peer.go | 1 + les/downloader/peer.go | 1 + 2 files changed, 2 insertions(+) diff --git a/eth/downloader/peer.go b/eth/downloader/peer.go index d74d23e74d55..6b8269495948 100644 --- a/eth/downloader/peer.go +++ b/eth/downloader/peer.go @@ -237,6 +237,7 @@ func (ps *peerSet) Register(p *peerConnection) error { } p.rates = msgrate.NewTracker(ps.rates.MeanCapacities(), ps.rates.MedianRoundTrip()) if err := ps.rates.Track(p.id, p.rates); err != nil { + ps.lock.Unlock() return err } ps.peers[p.id] = p diff --git a/les/downloader/peer.go b/les/downloader/peer.go index 5a92e9cf9b87..c2161e2dae42 100644 --- a/les/downloader/peer.go +++ b/les/downloader/peer.go @@ -350,6 +350,7 @@ func (ps *peerSet) Register(p *peerConnection) error { } p.rates = msgrate.NewTracker(ps.rates.MeanCapacities(), ps.rates.MedianRoundTrip()) if err := ps.rates.Track(p.id, p.rates); err != nil { + ps.lock.Unlock() return err } ps.peers[p.id] = p From 9762ddf8b0e9d471600c99f158479912f4870c52 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Fri, 19 Aug 2022 01:03:45 -0500 Subject: [PATCH 172/715] cmd/geth: parse uint64 value with ParseUint instead of Atoi (#25545) Parse uint64 value with ParseUint instead of Atoi --- cmd/geth/chaincmd.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 87863750615a..a3016c4b091f 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -384,12 +384,12 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth return nil, nil, common.Hash{}, fmt.Errorf("block %x not found", hash) } } else { - number, err := strconv.Atoi(arg) + number, err := strconv.ParseUint(arg, 10, 64) if err != nil { return nil, nil, common.Hash{}, err } - if hash := rawdb.ReadCanonicalHash(db, uint64(number)); hash != (common.Hash{}) { - header = rawdb.ReadHeader(db, hash, uint64(number)) + if hash := rawdb.ReadCanonicalHash(db, number); hash != (common.Hash{}) { + header = rawdb.ReadHeader(db, hash, number) } else { return nil, nil, common.Hash{}, fmt.Errorf("header for block %d not found", number) } From 77308cd6fceb99e276c1e2753d92ff82c6f1a962 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 19 Aug 2022 10:37:53 +0200 Subject: [PATCH 173/715] consensus/beacon: check ttd reached on pos blocks (#25552) * consensus/beacon: check ttd reached on pos blocks * consensus/beacon: check ttd reached on pos blocks * consensus/beacon: check ttd reached on pos blocks --- consensus/beacon/consensus.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 0397b026f1f0..949c8ad816ce 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -114,8 +114,16 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ } } - // All the headers have passed the transition point, use new rules. if len(preHeaders) == 0 { + // All the headers are pos headers. Verify that the parent block reached total terminal difficulty. + if reached, _ := IsTTDReached(chain, headers[0].ParentHash, headers[0].Number.Uint64()-1); !reached { + // TTD not reached for the first block, mark subsequent with invalid terminal block + results := make(chan error, len(headers)) + for i := 0; i < len(headers); i++ { + results <- consensus.ErrInvalidTerminalBlock + } + return make(chan struct{}), results + } return beacon.verifyHeaders(chain, headers, nil) } From 36874b63a1b56eed2b8e4b47ccea0337920b84b8 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Fri, 19 Aug 2022 11:14:59 +0200 Subject: [PATCH 174/715] eth/filters: add global block logs cache (#25459) This adds a cache for block logs which is shared by all filters. The cache size of is configurable using the `--cache.blocklogs` flag. Co-authored-by: Felix Lange --- accounts/abi/bind/backends/simulated.go | 31 ++++---- cmd/geth/config.go | 11 ++- cmd/geth/main.go | 1 + cmd/utils/flags.go | 34 +++++++-- eth/api_backend.go | 14 +--- eth/backend.go | 5 -- eth/ethconfig/config.go | 4 + eth/ethconfig/gen_config.go | 6 ++ eth/filters/api.go | 20 ++--- eth/filters/bench_test.go | 16 ++-- eth/filters/filter.go | 97 +++++++++++-------------- eth/filters/filter_system.go | 85 +++++++++++++++++++++- eth/filters/filter_system_test.go | 77 +++++++++----------- eth/filters/filter_test.go | 20 ++--- ethclient/gethclient/gethclient_test.go | 7 ++ graphql/graphql.go | 39 ++++++++-- graphql/graphql_test.go | 9 ++- graphql/service.go | 9 ++- internal/ethapi/backend.go | 14 ++-- les/api_backend.go | 7 +- les/client.go | 4 - 21 files changed, 310 insertions(+), 200 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index e03f2e1202b1..0ce752103c9a 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -68,7 +68,8 @@ type SimulatedBackend struct { pendingState *state.StateDB // Currently pending state that will be the active on request pendingReceipts types.Receipts // Currently receipts for the pending block - events *filters.EventSystem // Event system for filtering log events live + events *filters.EventSystem // for filtering log events live + filterSystem *filters.FilterSystem // for filtering database logs config *params.ChainConfig } @@ -86,7 +87,11 @@ func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.Genesis blockchain: blockchain, config: genesis.Config, } - backend.events = filters.NewEventSystem(&filterBackend{database, blockchain, backend}, false) + + filterBackend := &filterBackend{database, blockchain, backend} + backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{}) + backend.events = filters.NewEventSystem(backend.filterSystem, false) + backend.rollback(blockchain.CurrentBlock()) return backend } @@ -689,7 +694,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter var filter *filters.Filter if query.BlockHash != nil { // Block filter requested, construct a single-shot filter - filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain, b}, *query.BlockHash, query.Addresses, query.Topics) + filter = b.filterSystem.NewBlockFilter(*query.BlockHash, query.Addresses, query.Topics) } else { // Initialize unset filter boundaries to run from genesis to chain head from := int64(0) @@ -701,7 +706,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter to = query.ToBlock.Int64() } // Construct the range filter - filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain, b}, from, to, query.Addresses, query.Topics) + filter = b.filterSystem.NewRangeFilter(from, to, query.Addresses, query.Topics) } // Run the filter and return all the logs logs, err := filter.Logs(ctx) @@ -827,7 +832,8 @@ type filterBackend struct { backend *SimulatedBackend } -func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db } +func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db } + func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") } func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) { @@ -853,19 +859,8 @@ func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (typ return rawdb.ReadReceipts(fb.db, hash, *number, fb.bc.Config()), nil } -func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { - number := rawdb.ReadHeaderNumber(fb.db, hash) - if number == nil { - return nil, nil - } - receipts := rawdb.ReadReceipts(fb.db, hash, *number, fb.bc.Config()) - if receipts == nil { - return nil, nil - } - logs := make([][]*types.Log, len(receipts)) - for i, receipt := range receipts { - logs[i] = receipt.Logs - } +func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { + logs := rawdb.ReadLogs(fb.db, hash, number, fb.bc.Config()) return logs, nil } diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 2562de8ae9ea..30565fda6185 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -163,7 +163,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { override := ctx.Bool(utils.OverrideTerminalTotalDifficultyPassed.Name) cfg.Eth.OverrideTerminalTotalDifficultyPassed = &override } + backend, eth := utils.RegisterEthService(stack, &cfg.Eth) + // Warn users to migrate if they have a legacy freezer format. if eth != nil && !ctx.IsSet(utils.IgnoreLegacyReceiptsFlag.Name) { firstIdx := uint64(0) @@ -181,10 +183,15 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { utils.Fatalf("Database has receipts with a legacy format. Please run `geth db freezer-migrate`.") } } - // Configure GraphQL if requested + + // Configure log filter RPC API. + filterSystem := utils.RegisterFilterAPI(stack, backend, &cfg.Eth) + + // Configure GraphQL if requested. if ctx.IsSet(utils.GraphQLEnabledFlag.Name) { - utils.RegisterGraphQLService(stack, backend, cfg.Node) + utils.RegisterGraphQLService(stack, backend, filterSystem, &cfg.Node) } + // Add the Ethereum Stats daemon if requested. if cfg.Ethstats.URL != "" { utils.RegisterEthStatsService(stack, backend, cfg.Ethstats.URL) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index c0f636fb26ff..b9e3ed31e813 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -117,6 +117,7 @@ var ( utils.CacheSnapshotFlag, utils.CacheNoPrefetchFlag, utils.CachePreimagesFlag, + utils.CacheLogSizeFlag, utils.FDLimitFlag, utils.ListenPortFlag, utils.DiscoveryPortFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index efea9349250d..9e95193343a9 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -43,6 +43,7 @@ import ( ethcatalyst "github.com/ethereum/go-ethereum/eth/catalyst" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" @@ -64,6 +65,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" pcsclite "github.com/gballet/go-libpcsclite" gopsutil "github.com/shirou/gopsutil/mem" "github.com/urfave/cli/v2" @@ -491,6 +493,12 @@ var ( Usage: "Enable recording the SHA3/keccak preimages of trie keys", Category: flags.PerfCategory, } + CacheLogSizeFlag = &cli.IntFlag{ + Name: "cache.blocklogs", + Usage: "Size (in number of blocks) of the log cache for filtering", + Category: flags.PerfCategory, + Value: ethconfig.Defaults.FilterLogCacheSize, + } FDLimitFlag = &cli.IntFlag{ Name: "fdlimit", Usage: "Raise the open file descriptor resource limit (default = system fd limit)", @@ -1808,6 +1816,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheSnapshotFlag.Name) { cfg.SnapshotCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheSnapshotFlag.Name) / 100 } + if ctx.IsSet(CacheLogSizeFlag.Name) { + cfg.FilterLogCacheSize = ctx.Int(CacheLogSizeFlag.Name) + } if !ctx.Bool(SnapshotFlag.Name) { // If snap-sync is requested, this flag is also required if cfg.SyncMode == downloader.SnapSync { @@ -2005,21 +2016,34 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend return backend.APIBackend, backend } -// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to -// the given node. +// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to the node. func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url string) { if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil { Fatalf("Failed to register the Ethereum Stats service: %v", err) } } -// RegisterGraphQLService is a utility function to construct a new service and register it against a node. -func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, cfg node.Config) { - if err := graphql.New(stack, backend, cfg.GraphQLCors, cfg.GraphQLVirtualHosts); err != nil { +// RegisterGraphQLService adds the GraphQL API to the node. +func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cfg *node.Config) { + err := graphql.New(stack, backend, filterSystem, cfg.GraphQLCors, cfg.GraphQLVirtualHosts) + if err != nil { Fatalf("Failed to register the GraphQL service: %v", err) } } +// RegisterFilterAPI adds the eth log filtering RPC API to the node. +func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconfig.Config) *filters.FilterSystem { + isLightClient := ethcfg.SyncMode == downloader.LightSync + filterSystem := filters.NewFilterSystem(backend, filters.Config{ + LogCacheSize: ethcfg.FilterLogCacheSize, + }) + stack.RegisterAPIs([]rpc.API{{ + Namespace: "eth", + Service: filters.NewFilterAPI(filterSystem, isLightClient), + }}) + return filterSystem +} + func SetupMetrics(ctx *cli.Context) { if metrics.Enabled { log.Info("Enabling metrics collection") diff --git a/eth/api_backend.go b/eth/api_backend.go index 1d8ba8ea5cae..00ecacc31df7 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -19,7 +19,6 @@ package eth import ( "context" "errors" - "fmt" "math/big" "time" @@ -202,17 +201,8 @@ func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (type return b.eth.blockchain.GetReceiptsByHash(hash), nil } -func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { - db := b.eth.ChainDb() - number := rawdb.ReadHeaderNumber(db, hash) - if number == nil { - return nil, fmt.Errorf("failed to get block number for hash %#x", hash) - } - logs := rawdb.ReadLogs(db, hash, *number, b.eth.blockchain.Config()) - if logs == nil { - return nil, fmt.Errorf("failed to get logs for block #%d (0x%s)", *number, hash.TerminalString()) - } - return logs, nil +func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { + return rawdb.ReadLogs(b.eth.chainDb, hash, number, b.ChainConfig()), nil } func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { diff --git a/eth/backend.go b/eth/backend.go index ebe7001c7994..778207636344 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -25,7 +25,6 @@ import ( "strings" "sync" "sync/atomic" - "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" @@ -41,7 +40,6 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" @@ -315,9 +313,6 @@ func (s *Ethereum) APIs() []rpc.API { }, { Namespace: "eth", Service: downloader.NewDownloaderAPI(s.handler.downloader, s.eventMux), - }, { - Namespace: "eth", - Service: filters.NewFilterAPI(s.APIBackend, false, 5*time.Minute), }, { Namespace: "admin", Service: NewAdminAPI(s), diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index d1323de7b0f4..5690366421dc 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -83,6 +83,7 @@ var Defaults = Config{ TrieDirtyCache: 256, TrieTimeout: 60 * time.Minute, SnapshotCache: 102, + FilterLogCacheSize: 32, Miner: miner.Config{ GasCeil: 30000000, GasPrice: big.NewInt(params.GWei), @@ -171,6 +172,9 @@ type Config struct { SnapshotCache int Preimages bool + // This is the number of blocks for which logs will be cached in the filter system. + FilterLogCacheSize int + // Mining options Miner miner.Config diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index a6528c8df5f7..9c7a04364d20 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -48,6 +48,7 @@ func (c Config) MarshalTOML() (interface{}, error) { TrieTimeout time.Duration SnapshotCache int Preimages bool + FilterLogCacheSize int Miner miner.Config Ethash ethash.Config TxPool core.TxPoolConfig @@ -93,6 +94,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.TrieTimeout = c.TrieTimeout enc.SnapshotCache = c.SnapshotCache enc.Preimages = c.Preimages + enc.FilterLogCacheSize = c.FilterLogCacheSize enc.Miner = c.Miner enc.Ethash = c.Ethash enc.TxPool = c.TxPool @@ -142,6 +144,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { TrieTimeout *time.Duration SnapshotCache *int Preimages *bool + FilterLogCacheSize *int Miner *miner.Config Ethash *ethash.Config TxPool *core.TxPoolConfig @@ -250,6 +253,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.Preimages != nil { c.Preimages = *dec.Preimages } + if dec.FilterLogCacheSize != nil { + c.FilterLogCacheSize = *dec.FilterLogCacheSize + } if dec.Miner != nil { c.Miner = *dec.Miner } diff --git a/eth/filters/api.go b/eth/filters/api.go index 3b8933d0af97..43e63d5ba98a 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -46,7 +46,7 @@ type filter struct { // FilterAPI offers support to create and manage filters. This will allow external clients to retrieve various // information related to the Ethereum protocol such als blocks, transactions and logs. type FilterAPI struct { - backend Backend + sys *FilterSystem events *EventSystem filtersMu sync.Mutex filters map[rpc.ID]*filter @@ -54,14 +54,14 @@ type FilterAPI struct { } // NewFilterAPI returns a new FilterAPI instance. -func NewFilterAPI(backend Backend, lightMode bool, timeout time.Duration) *FilterAPI { +func NewFilterAPI(system *FilterSystem, lightMode bool) *FilterAPI { api := &FilterAPI{ - backend: backend, - events: NewEventSystem(backend, lightMode), + sys: system, + events: NewEventSystem(system, lightMode), filters: make(map[rpc.ID]*filter), - timeout: timeout, + timeout: system.cfg.Timeout, } - go api.timeoutLoop(timeout) + go api.timeoutLoop(system.cfg.Timeout) return api } @@ -320,7 +320,7 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type var filter *Filter if crit.BlockHash != nil { // Block filter requested, construct a single-shot filter - filter = NewBlockFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics) + filter = api.sys.NewBlockFilter(*crit.BlockHash, crit.Addresses, crit.Topics) } else { // Convert the RPC block numbers into internal representations begin := rpc.LatestBlockNumber.Int64() @@ -332,7 +332,7 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type end = crit.ToBlock.Int64() } // Construct the range filter - filter = NewRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics) + filter = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics) } // Run the filter and return all the logs logs, err := filter.Logs(ctx) @@ -371,7 +371,7 @@ func (api *FilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Lo var filter *Filter if f.crit.BlockHash != nil { // Block filter requested, construct a single-shot filter - filter = NewBlockFilter(api.backend, *f.crit.BlockHash, f.crit.Addresses, f.crit.Topics) + filter = api.sys.NewBlockFilter(*f.crit.BlockHash, f.crit.Addresses, f.crit.Topics) } else { // Convert the RPC block numbers into internal representations begin := rpc.LatestBlockNumber.Int64() @@ -383,7 +383,7 @@ func (api *FilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Lo end = f.crit.ToBlock.Int64() } // Construct the range filter - filter = NewRangeFilter(api.backend, begin, end, f.crit.Addresses, f.crit.Topics) + filter = api.sys.NewRangeFilter(begin, end, f.crit.Addresses, f.crit.Topics) } // Run the filter and return all the logs logs, err := filter.Logs(ctx) diff --git a/eth/filters/bench_test.go b/eth/filters/bench_test.go index 694d73735028..73b96b77af62 100644 --- a/eth/filters/bench_test.go +++ b/eth/filters/bench_test.go @@ -122,22 +122,27 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) { b.Log("Running filter benchmarks...") start = time.Now() - var backend *testBackend + var ( + backend *testBackend + sys *FilterSystem + ) for i := 0; i < benchFilterCnt; i++ { if i%20 == 0 { db.Close() db, _ = rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false) backend = &testBackend{db: db, sections: cnt} + sys = NewFilterSystem(backend, Config{}) } var addr common.Address addr[0] = byte(i) addr[1] = byte(i / 256) - filter := NewRangeFilter(backend, 0, int64(cnt*sectionSize-1), []common.Address{addr}, nil) + filter := sys.NewRangeFilter(0, int64(cnt*sectionSize-1), []common.Address{addr}, nil) if _, err := filter.Logs(context.Background()); err != nil { - b.Error("filter.Find error:", err) + b.Error("filter.Logs error:", err) } } + d = time.Since(start) b.Log("Finished running filter benchmarks") b.Log(" ", d, "total ", d/time.Duration(benchFilterCnt), "per address", d*time.Duration(1000000)/time.Duration(benchFilterCnt*cnt*sectionSize), "per million blocks") @@ -171,10 +176,11 @@ func BenchmarkNoBloomBits(b *testing.B) { clearBloomBits(db) + _, sys := newTestFilterSystem(b, db, Config{}) + b.Log("Running filter benchmarks...") start := time.Now() - backend := &testBackend{db: db} - filter := NewRangeFilter(backend, 0, int64(*headNum), []common.Address{{}}, nil) + filter := sys.NewRangeFilter(0, int64(*headNum), []common.Address{{}}, nil) filter.Logs(context.Background()) d := time.Since(start) b.Log("Finished running filter benchmarks") diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 9ff7ab7f55e1..0a70c9ece1db 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -22,37 +22,15 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/rpc" ) -type Backend interface { - ChainDb() ethdb.Database - HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) - HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) - GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) - GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) - PendingBlockAndReceipts() (*types.Block, types.Receipts) - - SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription - SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription - SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription - SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription - SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription - - BloomStatus() (uint64, uint64) - ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) -} - // Filter can be used to retrieve and filter logs. type Filter struct { - backend Backend + sys *FilterSystem - db ethdb.Database addresses []common.Address topics [][]common.Hash @@ -64,7 +42,7 @@ type Filter struct { // NewRangeFilter creates a new filter which uses a bloom filter on blocks to // figure out whether a particular block is interesting or not. -func NewRangeFilter(backend Backend, begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter { +func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter { // Flatten the address and topic filter clauses into a single bloombits filter // system. Since the bloombits are not positional, nil topics are permitted, // which get flattened into a nil byte slice. @@ -83,10 +61,10 @@ func NewRangeFilter(backend Backend, begin, end int64, addresses []common.Addres } filters = append(filters, filter) } - size, _ := backend.BloomStatus() + size, _ := sys.backend.BloomStatus() // Create a generic filter and convert it into a range filter - filter := newFilter(backend, addresses, topics) + filter := newFilter(sys, addresses, topics) filter.matcher = bloombits.NewMatcher(size, filters) filter.begin = begin @@ -97,21 +75,20 @@ func NewRangeFilter(backend Backend, begin, end int64, addresses []common.Addres // NewBlockFilter creates a new filter which directly inspects the contents of // a block to figure out whether it is interesting or not. -func NewBlockFilter(backend Backend, block common.Hash, addresses []common.Address, topics [][]common.Hash) *Filter { +func (sys *FilterSystem) NewBlockFilter(block common.Hash, addresses []common.Address, topics [][]common.Hash) *Filter { // Create a generic filter and convert it into a block filter - filter := newFilter(backend, addresses, topics) + filter := newFilter(sys, addresses, topics) filter.block = block return filter } // newFilter creates a generic filter that can either filter based on a block hash, // or based on range queries. The search criteria needs to be explicitly set. -func newFilter(backend Backend, addresses []common.Address, topics [][]common.Hash) *Filter { +func newFilter(sys *FilterSystem, addresses []common.Address, topics [][]common.Hash) *Filter { return &Filter{ - backend: backend, + sys: sys, addresses: addresses, topics: topics, - db: backend.ChainDb(), } } @@ -120,14 +97,14 @@ func newFilter(backend Backend, addresses []common.Address, topics [][]common.Ha func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { // If we're doing singleton block filtering, execute and return if f.block != (common.Hash{}) { - header, err := f.backend.HeaderByHash(ctx, f.block) + header, err := f.sys.backend.HeaderByHash(ctx, f.block) if err != nil { return nil, err } if header == nil { return nil, errors.New("unknown block") } - return f.blockLogs(ctx, header) + return f.blockLogs(ctx, header, false) } // Short-cut if all we care about is pending logs if f.begin == rpc.PendingBlockNumber.Int64() { @@ -137,7 +114,7 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { return f.pendingLogs() } // Figure out the limits of the filter range - header, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) + header, _ := f.sys.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) if header == nil { return nil, nil } @@ -156,7 +133,7 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { var ( logs []*types.Log err error - size, sections = f.backend.BloomStatus() + size, sections = f.sys.backend.BloomStatus() ) if indexed := sections * size; indexed > uint64(f.begin) { if indexed > end { @@ -192,7 +169,7 @@ func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, err } defer session.Close() - f.backend.ServiceFilter(ctx, session) + f.sys.backend.ServiceFilter(ctx, session) // Iterate over the matches until exhausted or context closed var logs []*types.Log @@ -211,11 +188,11 @@ func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, err f.begin = int64(number) + 1 // Retrieve the suggested block and pull any truly matching logs - header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(number)) + header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(number)) if header == nil || err != nil { return logs, err } - found, err := f.checkMatches(ctx, header) + found, err := f.blockLogs(ctx, header, true) if err != nil { return logs, err } @@ -233,11 +210,11 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e var logs []*types.Log for ; f.begin <= int64(end); f.begin++ { - header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin)) + header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin)) if header == nil || err != nil { return logs, err } - found, err := f.blockLogs(ctx, header) + found, err := f.blockLogs(ctx, header, false) if err != nil { return logs, err } @@ -247,34 +224,34 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e } // blockLogs returns the logs matching the filter criteria within a single block. -func (f *Filter) blockLogs(ctx context.Context, header *types.Header) (logs []*types.Log, err error) { - if bloomFilter(header.Bloom, f.addresses, f.topics) { - found, err := f.checkMatches(ctx, header) +func (f *Filter) blockLogs(ctx context.Context, header *types.Header, skipBloom bool) ([]*types.Log, error) { + // Fast track: no filtering criteria + if len(f.addresses) == 0 && len(f.topics) == 0 { + list, err := f.sys.cachedGetLogs(ctx, header.Hash(), header.Number.Uint64()) if err != nil { - return logs, err + return nil, err } - logs = append(logs, found...) + return flatten(list), nil + } else if skipBloom || bloomFilter(header.Bloom, f.addresses, f.topics) { + return f.checkMatches(ctx, header) } - return logs, nil + return nil, nil } // checkMatches checks if the receipts belonging to the given header contain any log events that // match the filter criteria. This function is called when the bloom filter signals a potential match. -func (f *Filter) checkMatches(ctx context.Context, header *types.Header) (logs []*types.Log, err error) { - // Get the logs of the block - logsList, err := f.backend.GetLogs(ctx, header.Hash()) +func (f *Filter) checkMatches(ctx context.Context, header *types.Header) ([]*types.Log, error) { + logsList, err := f.sys.cachedGetLogs(ctx, header.Hash(), header.Number.Uint64()) if err != nil { return nil, err } - var unfiltered []*types.Log - for _, logs := range logsList { - unfiltered = append(unfiltered, logs...) - } - logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics) + + unfiltered := flatten(logsList) + logs := filterLogs(unfiltered, nil, nil, f.addresses, f.topics) if len(logs) > 0 { // We have matching logs, check if we need to resolve full logs via the light client if logs[0].TxHash == (common.Hash{}) { - receipts, err := f.backend.GetReceipts(ctx, header.Hash()) + receipts, err := f.sys.backend.GetReceipts(ctx, header.Hash()) if err != nil { return nil, err } @@ -291,7 +268,7 @@ func (f *Filter) checkMatches(ctx context.Context, header *types.Header) (logs [ // pendingLogs returns the logs matching the filter criteria within the pending block. func (f *Filter) pendingLogs() ([]*types.Log, error) { - block, receipts := f.backend.PendingBlockAndReceipts() + block, receipts := f.sys.backend.PendingBlockAndReceipts() if bloomFilter(block.Bloom(), f.addresses, f.topics) { var unfiltered []*types.Log for _, r := range receipts { @@ -376,3 +353,11 @@ func bloomFilter(bloom types.Bloom, addresses []common.Address, topics [][]commo } return true } + +func flatten(list [][]*types.Log) []*types.Log { + var flat []*types.Log + for _, logs := range list { + flat = append(flat, logs...) + } + return flat +} diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index c1a1b408b7a7..79a9b089f422 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -27,13 +27,90 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" + lru "github.com/hashicorp/golang-lru" ) +// Config represents the configuration of the filter system. +type Config struct { + LogCacheSize int // maximum number of cached blocks (default: 32) + Timeout time.Duration // how long filters stay active (default: 5min) +} + +func (cfg Config) withDefaults() Config { + if cfg.Timeout == 0 { + cfg.Timeout = 5 * time.Minute + } + if cfg.LogCacheSize == 0 { + cfg.LogCacheSize = 32 + } + return cfg +} + +type Backend interface { + ChainDb() ethdb.Database + HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) + HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) + GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) + GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) + PendingBlockAndReceipts() (*types.Block, types.Receipts) + + SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription + SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription + SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription + SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription + SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription + + BloomStatus() (uint64, uint64) + ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) +} + +// FilterSystem holds resources shared by all filters. +type FilterSystem struct { + backend Backend + logsCache *lru.Cache + cfg *Config +} + +// NewFilterSystem creates a filter system. +func NewFilterSystem(backend Backend, config Config) *FilterSystem { + config = config.withDefaults() + + cache, err := lru.New(config.LogCacheSize) + if err != nil { + panic(err) + } + return &FilterSystem{ + backend: backend, + logsCache: cache, + cfg: &config, + } +} + +// cachedGetLogs loads block logs from the backend and caches the result. +func (sys *FilterSystem) cachedGetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { + cached, ok := sys.logsCache.Get(blockHash) + if ok { + return cached.([][]*types.Log), nil + } + + logs, err := sys.backend.GetLogs(ctx, blockHash, number) + if err != nil { + return nil, err + } + if logs == nil { + return nil, fmt.Errorf("failed to get logs for block #%d (0x%s)", number, blockHash.TerminalString()) + } + sys.logsCache.Add(blockHash, logs) + return logs, nil +} + // Type determines the kind of filter and is used to put the filter in to // the correct bucket when added. type Type byte @@ -84,6 +161,7 @@ type subscription struct { // subscription which match the subscription criteria. type EventSystem struct { backend Backend + sys *FilterSystem lightMode bool lastHead *types.Header @@ -110,9 +188,10 @@ type EventSystem struct { // // The returned manager has a loop that needs to be stopped with the Stop function // or by stopping the given mux. -func NewEventSystem(backend Backend, lightMode bool) *EventSystem { +func NewEventSystem(sys *FilterSystem, lightMode bool) *EventSystem { m := &EventSystem{ - backend: backend, + sys: sys, + backend: sys.backend, lightMode: lightMode, install: make(chan *subscription), uninstall: make(chan *subscription), @@ -405,7 +484,7 @@ func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common. // Get the logs of the block ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - logsList, err := es.backend.GetLogs(ctx, header.Hash()) + logsList, err := es.sys.cachedGetLogs(ctx, header.Hash(), header.Number.Uint64()) if err != nil { return nil } diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index c7fc4331b222..51bda29b4244 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -39,10 +39,6 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -var ( - deadline = 5 * time.Minute -) - type testBackend struct { db ethdb.Database sections uint64 @@ -91,17 +87,8 @@ func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types. return nil, nil } -func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { - number := rawdb.ReadHeaderNumber(b.db, hash) - if number == nil { - return nil, nil - } - receipts := rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig) - - logs := make([][]*types.Log, len(receipts)) - for i, receipt := range receipts { - logs[i] = receipt.Logs - } +func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { + logs := rawdb.ReadLogs(b.db, hash, number, params.TestChainConfig) return logs, nil } @@ -160,6 +147,12 @@ func (b *testBackend) ServiceFilter(ctx context.Context, session *bloombits.Matc }() } +func newTestFilterSystem(t testing.TB, db ethdb.Database, cfg Config) (*testBackend, *FilterSystem) { + backend := &testBackend{db: db} + sys := NewFilterSystem(backend, cfg) + return backend, sys +} + // TestBlockSubscription tests if a block subscription returns block hashes for posted chain events. // It creates multiple subscriptions: // - one at the start and should receive all posted chain events and a second (blockHashes) @@ -169,12 +162,12 @@ func TestBlockSubscription(t *testing.T) { t.Parallel() var ( - db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} - api = NewFilterAPI(backend, false, deadline) - genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) - chain, _ = core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {}) - chainEvents = []core.ChainEvent{} + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(t, db, Config{}) + api = NewFilterAPI(sys, false) + genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + chain, _ = core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {}) + chainEvents = []core.ChainEvent{} ) for _, blk := range chain { @@ -221,9 +214,9 @@ func TestPendingTxFilter(t *testing.T) { t.Parallel() var ( - db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} - api = NewFilterAPI(backend, false, deadline) + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(t, db, Config{}) + api = NewFilterAPI(sys, false) transactions = []*types.Transaction{ types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), @@ -276,9 +269,9 @@ func TestPendingTxFilter(t *testing.T) { // If not it must return an error. func TestLogFilterCreation(t *testing.T) { var ( - db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} - api = NewFilterAPI(backend, false, deadline) + db = rawdb.NewMemoryDatabase() + _, sys = newTestFilterSystem(t, db, Config{}) + api = NewFilterAPI(sys, false) testCases = []struct { crit FilterCriteria @@ -323,9 +316,9 @@ func TestInvalidLogFilterCreation(t *testing.T) { t.Parallel() var ( - db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} - api = NewFilterAPI(backend, false, deadline) + db = rawdb.NewMemoryDatabase() + _, sys = newTestFilterSystem(t, db, Config{}) + api = NewFilterAPI(sys, false) ) // different situations where log filter creation should fail. @@ -346,8 +339,8 @@ func TestInvalidLogFilterCreation(t *testing.T) { func TestInvalidGetLogsRequest(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} - api = NewFilterAPI(backend, false, deadline) + _, sys = newTestFilterSystem(t, db, Config{}) + api = NewFilterAPI(sys, false) blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") ) @@ -370,9 +363,9 @@ func TestLogFilter(t *testing.T) { t.Parallel() var ( - db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} - api = NewFilterAPI(backend, false, deadline) + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(t, db, Config{}) + api = NewFilterAPI(sys, false) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") @@ -484,9 +477,9 @@ func TestPendingLogsSubscription(t *testing.T) { t.Parallel() var ( - db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} - api = NewFilterAPI(backend, false, deadline) + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(t, db, Config{}) + api = NewFilterAPI(sys, false) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") @@ -668,10 +661,10 @@ func TestPendingTxFilterDeadlock(t *testing.T) { timeout := 100 * time.Millisecond var ( - db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} - api = NewFilterAPI(backend, false, timeout) - done = make(chan struct{}) + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(t, db, Config{Timeout: timeout}) + api = NewFilterAPI(sys, false) + done = make(chan struct{}) ) go func() { diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 59fdde7e809b..2c1f7cadf43a 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -44,7 +44,7 @@ func BenchmarkFilters(b *testing.B) { var ( db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "", false) - backend = &testBackend{db: db} + _, sys = newTestFilterSystem(b, db, Config{}) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = common.BytesToAddress([]byte("jeff")) @@ -89,7 +89,7 @@ func BenchmarkFilters(b *testing.B) { } b.ResetTimer() - filter := NewRangeFilter(backend, 0, -1, []common.Address{addr1, addr2, addr3, addr4}, nil) + filter := sys.NewRangeFilter(0, -1, []common.Address{addr1, addr2, addr3, addr4}, nil) for i := 0; i < b.N; i++ { logs, _ := filter.Logs(context.Background()) @@ -104,7 +104,7 @@ func TestFilters(t *testing.T) { var ( db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "", false) - backend = &testBackend{db: db} + _, sys = newTestFilterSystem(t, db, Config{}) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key1.PublicKey) @@ -175,14 +175,14 @@ func TestFilters(t *testing.T) { rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i]) } - filter := NewRangeFilter(backend, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) + filter := sys.NewRangeFilter(0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) logs, _ := filter.Logs(context.Background()) if len(logs) != 4 { t.Error("expected 4 log, got", len(logs)) } - filter = NewRangeFilter(backend, 900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}) + filter = sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}) logs, _ = filter.Logs(context.Background()) if len(logs) != 1 { t.Error("expected 1 log, got", len(logs)) @@ -191,7 +191,7 @@ func TestFilters(t *testing.T) { t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) } - filter = NewRangeFilter(backend, 990, -1, []common.Address{addr}, [][]common.Hash{{hash3}}) + filter = sys.NewRangeFilter(990, -1, []common.Address{addr}, [][]common.Hash{{hash3}}) logs, _ = filter.Logs(context.Background()) if len(logs) != 1 { t.Error("expected 1 log, got", len(logs)) @@ -200,7 +200,7 @@ func TestFilters(t *testing.T) { t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) } - filter = NewRangeFilter(backend, 1, 10, nil, [][]common.Hash{{hash1, hash2}}) + filter = sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}) logs, _ = filter.Logs(context.Background()) if len(logs) != 2 { @@ -208,7 +208,7 @@ func TestFilters(t *testing.T) { } failHash := common.BytesToHash([]byte("fail")) - filter = NewRangeFilter(backend, 0, -1, nil, [][]common.Hash{{failHash}}) + filter = sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{failHash}}) logs, _ = filter.Logs(context.Background()) if len(logs) != 0 { @@ -216,14 +216,14 @@ func TestFilters(t *testing.T) { } failAddr := common.BytesToAddress([]byte("failmenow")) - filter = NewRangeFilter(backend, 0, -1, []common.Address{failAddr}, nil) + filter = sys.NewRangeFilter(0, -1, []common.Address{failAddr}, nil) logs, _ = filter.Logs(context.Background()) if len(logs) != 0 { t.Error("expected 0 log, got", len(logs)) } - filter = NewRangeFilter(backend, 0, -1, nil, [][]common.Hash{{failHash}, {hash1}}) + filter = sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{failHash}, {hash1}}) logs, _ = filter.Logs(context.Background()) if len(logs) != 0 { diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index b78d11c3283f..a0f4eaaf5db4 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" @@ -60,6 +61,12 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { if err != nil { t.Fatalf("can't create new ethereum service: %v", err) } + filterSystem := filters.NewFilterSystem(ethservice.APIBackend, filters.Config{}) + n.RegisterAPIs([]rpc.API{{ + Namespace: "eth", + Service: filters.NewFilterAPI(filterSystem, false), + }}) + // Import the test chain. if err := n.Start(); err != nil { t.Fatalf("can't start test node: %v", err) diff --git a/graphql/graphql.go b/graphql/graphql.go index 0949c34803cf..97b460c205ce 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -450,12 +450,36 @@ func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs) } func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) { - receipt, err := t.getReceipt(ctx) - if err != nil || receipt == nil { + if _, err := t.resolve(ctx); err != nil { return nil, err } - ret := make([]*Log, 0, len(receipt.Logs)) - for _, log := range receipt.Logs { + if t.block == nil { + return nil, nil + } + if _, ok := t.block.numberOrHash.Hash(); !ok { + header, err := t.r.backend.HeaderByNumberOrHash(ctx, *t.block.numberOrHash) + if err != nil { + return nil, err + } + hash := header.Hash() + t.block.numberOrHash.BlockHash = &hash + } + return t.getLogs(ctx) +} + +// getLogs returns log objects for the given tx. +// Assumes block hash is resolved. +func (t *Transaction) getLogs(ctx context.Context) (*[]*Log, error) { + var ( + hash, _ = t.block.numberOrHash.Hash() + filter = t.r.filterSystem.NewBlockFilter(hash, nil, nil) + logs, err = filter.Logs(ctx) + ) + if err != nil { + return nil, err + } + ret := make([]*Log, 0, len(logs)) + for _, log := range logs { ret = append(ret, &Log{ r: t.r, transaction: t, @@ -978,7 +1002,7 @@ func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteri hash = header.Hash() } // Construct the range filter - filter := filters.NewBlockFilter(b.r.backend, hash, addresses, topics) + filter := b.r.filterSystem.NewBlockFilter(hash, addresses, topics) // Run the filter and return all the logs return runFilter(ctx, b.r, filter) @@ -1137,7 +1161,8 @@ func (p *Pending) EstimateGas(ctx context.Context, args struct { // Resolver is the top-level object in the GraphQL hierarchy. type Resolver struct { - backend ethapi.Backend + backend ethapi.Backend + filterSystem *filters.FilterSystem } func (r *Resolver) Block(ctx context.Context, args struct { @@ -1284,7 +1309,7 @@ func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria topics = *args.Filter.Topics } // Construct the range filter - filter := filters.NewRangeFilter(r.backend, begin, end, addresses, topics) + filter := r.filterSystem.NewRangeFilter(begin, end, addresses, topics) return runFilter(ctx, r, filter) } diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 4b7f7bf96021..d55f4e063486 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" @@ -50,7 +51,7 @@ func TestBuildSchema(t *testing.T) { } defer stack.Close() // Make sure the schema can be parsed and matched up to the object model. - if err := newHandler(stack, nil, []string{}, []string{}); err != nil { + if err := newHandler(stack, nil, nil, []string{}, []string{}); err != nil { t.Errorf("Could not construct GraphQL handler: %v", err) } } @@ -263,7 +264,8 @@ func createGQLService(t *testing.T, stack *node.Node) { t.Fatalf("could not create import blocks: %v", err) } // create gql service - err = New(stack, ethBackend.APIBackend, []string{}, []string{}) + filterSystem := filters.NewFilterSystem(ethBackend.APIBackend, filters.Config{}) + err = New(stack, ethBackend.APIBackend, filterSystem, []string{}, []string{}) if err != nil { t.Fatalf("could not create graphql service: %v", err) } @@ -348,7 +350,8 @@ func createGQLServiceWithTransactions(t *testing.T, stack *node.Node) { t.Fatalf("could not create import blocks: %v", err) } // create gql service - err = New(stack, ethBackend.APIBackend, []string{}, []string{}) + filterSystem := filters.NewFilterSystem(ethBackend.APIBackend, filters.Config{}) + err = New(stack, ethBackend.APIBackend, filterSystem, []string{}, []string{}) if err != nil { t.Fatalf("could not create graphql service: %v", err) } diff --git a/graphql/service.go b/graphql/service.go index 1a2ffaa9469d..019026bc7ea7 100644 --- a/graphql/service.go +++ b/graphql/service.go @@ -20,6 +20,7 @@ import ( "encoding/json" "net/http" + "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/node" "github.com/graph-gophers/graphql-go" @@ -55,14 +56,14 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } // New constructs a new GraphQL service instance. -func New(stack *node.Node, backend ethapi.Backend, cors, vhosts []string) error { - return newHandler(stack, backend, cors, vhosts) +func New(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) error { + return newHandler(stack, backend, filterSystem, cors, vhosts) } // newHandler returns a new `http.Handler` that will answer GraphQL queries. // It additionally exports an interactive query browser on the / endpoint. -func newHandler(stack *node.Node, backend ethapi.Backend, cors, vhosts []string) error { - q := Resolver{backend} +func newHandler(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) error { + q := Resolver{backend, filterSystem} s, err := graphql.ParseSchema(schema, &q) if err != nil { diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index d13547f234a3..5b4ceb631069 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -27,10 +27,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" @@ -84,16 +84,12 @@ type Backend interface { TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription - // Filter API - BloomStatus() (uint64, uint64) - GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) - ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) - SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription - SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription - SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription - ChainConfig() *params.ChainConfig Engine() consensus.Engine + + // eth/filters needs to be initialized from this backend type, so methods needed by + // it must also be included here. + filters.Backend } func GetAPIs(apiBackend Backend) []rpc.API { diff --git a/les/api_backend.go b/les/api_backend.go index 11a9ca128aab..5b4213134b24 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -168,11 +168,8 @@ func (b *LesApiBackend) GetReceipts(ctx context.Context, hash common.Hash) (type return nil, nil } -func (b *LesApiBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { - if number := rawdb.ReadHeaderNumber(b.eth.chainDb, hash); number != nil { - return light.GetBlockLogs(ctx, b.eth.odr, hash, *number) - } - return nil, nil +func (b *LesApiBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { + return light.GetBlockLogs(ctx, b.eth.odr, hash, number) } func (b *LesApiBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { diff --git a/les/client.go b/les/client.go index 7caaf2c18a58..6504fe2af8f6 100644 --- a/les/client.go +++ b/les/client.go @@ -32,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -298,9 +297,6 @@ func (s *LightEthereum) APIs() []rpc.API { }, { Namespace: "eth", Service: downloader.NewDownloaderAPI(s.handler.downloader, s.eventMux), - }, { - Namespace: "eth", - Service: filters.NewFilterAPI(s.ApiBackend, true, 5*time.Minute), }, { Namespace: "net", Service: s.netRPCService, From 08658806268f4c570c682e87681881ac35123fe9 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Fri, 19 Aug 2022 18:15:04 +0800 Subject: [PATCH 175/715] accounts/abi: fix set function (#25477) * accounts/abi: fix set function * don't break things * update test --- accounts/abi/reflect.go | 2 +- accounts/abi/unpack_test.go | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index eb21bb26451a..7917fa98095b 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -99,7 +99,7 @@ func mustArrayToByteSlice(value reflect.Value) reflect.Value { func set(dst, src reflect.Value) error { dstType, srcType := dst.Type(), src.Type() switch { - case dstType.Kind() == reflect.Interface && dst.Elem().IsValid(): + 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{}): return set(dst.Elem(), src) diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index ae3565c71e29..363e0cd5943e 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -352,6 +352,11 @@ func TestMethodMultiReturn(t *testing.T) { &[]interface{}{&expected.Int, &expected.String}, "", "Can unpack into a slice", + }, { + &[]interface{}{&bigint, ""}, + &[]interface{}{&expected.Int, expected.String}, + "", + "Can unpack into a slice without indirection", }, { &[2]interface{}{&bigint, new(string)}, &[2]interface{}{&expected.Int, &expected.String}, From ac7ad811b4d2ba0b93f9272e2487253026620b48 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 19 Aug 2022 14:48:49 +0200 Subject: [PATCH 176/715] internal/ethapi: fix build regression (#25555) --- internal/ethapi/transaction_args_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 92f009aa849e..28dc561c36e4 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -298,6 +298,9 @@ func (b *backendMock) PendingBlockAndReceipts() (*types.Block, types.Receipts) { func (b *backendMock) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { return nil, nil } +func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { + return nil, nil +} func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } func (b *backendMock) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { return nil, nil, nil @@ -325,11 +328,8 @@ func (b *backendMock) TxPoolContent() (map[common.Address]types.Transactions, ma func (b *backendMock) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) { return nil, nil } -func (b *backendMock) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription { return nil } -func (b *backendMock) BloomStatus() (uint64, uint64) { return 0, 0 } -func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) { - return nil, nil -} +func (b *backendMock) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription { return nil } +func (b *backendMock) BloomStatus() (uint64, uint64) { return 0, 0 } func (b *backendMock) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {} func (b *backendMock) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return nil } func (b *backendMock) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { From 0ce494b60cd00d70f1f9f2dd0b9bfbd76204168a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 19 Aug 2022 15:59:36 +0200 Subject: [PATCH 177/715] eth/fetcher: don't spend too much time on transaction inclusion (#25524) * eth/fetcher: introduce some lag in tx fetching * eth/fetcher: change conditions a bit * eth/fetcher: use per-batch quota check * eth/fetcher: fix some comments * eth/fetcher: address review concerns * eth/fetcher: fix panic + add warn log * eth/fetcher: fix log * eth/fetcher: fix log * cmd/devp2p/internal/ethtest: fix ignorign tx announcements from prev. tests * cmd/devp2p/internal/ethtest: fix TestLargeTxRequest This increases the number of tx relay messages the test waits for. Since go-ethereum now processes incoming txs in smaller batches, the announcement messages it sends are also smaller. Co-authored-by: Felix Lange --- cmd/devp2p/internal/ethtest/helpers.go | 6 +- cmd/devp2p/internal/ethtest/suite.go | 4 + cmd/devp2p/internal/ethtest/transaction.go | 6 +- eth/fetcher/tx_fetcher.go | 98 +++++++++++++--------- 4 files changed, 72 insertions(+), 42 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/helpers.go b/cmd/devp2p/internal/ethtest/helpers.go index eeeb4f93cabf..b57649ade99d 100644 --- a/cmd/devp2p/internal/ethtest/helpers.go +++ b/cmd/devp2p/internal/ethtest/helpers.go @@ -357,9 +357,13 @@ func (s *Suite) waitAnnounce(conn *Conn, blockAnnouncement *NewBlock) error { return fmt.Errorf("wrong block hash in announcement: expected %v, got %v", blockAnnouncement.Block.Hash(), hashes[0].Hash) } return nil + + // ignore tx announcements from previous tests case *NewPooledTransactionHashes: - // ignore tx announcements from previous tests continue + case *Transactions: + continue + default: return fmt.Errorf("unexpected: %s", pretty.Sdump(msg)) } diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index 7059b4ba738c..4497478d72d6 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -544,9 +544,13 @@ func (s *Suite) TestNewPooledTxs(t *utesting.T) { t.Fatalf("unexpected number of txs requested: wanted %d, got %d", len(hashes), len(msg.GetPooledTransactionsPacket)) } return + // ignore propagated txs from previous tests case *NewPooledTransactionHashes: continue + case *Transactions: + continue + // ignore block announcements from previous tests case *NewBlockHashes: continue diff --git a/cmd/devp2p/internal/ethtest/transaction.go b/cmd/devp2p/internal/ethtest/transaction.go index c4748bf8f7d8..baa55bd49268 100644 --- a/cmd/devp2p/internal/ethtest/transaction.go +++ b/cmd/devp2p/internal/ethtest/transaction.go @@ -29,7 +29,7 @@ import ( "github.com/ethereum/go-ethereum/params" ) -//var faucetAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") +// var faucetAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") var faucetKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") func (s *Suite) sendSuccessfulTxs(t *utesting.T) error { @@ -192,10 +192,10 @@ func sendMultipleSuccessfulTxs(t *utesting.T, s *Suite, txs []*types.Transaction nonce = txs[len(txs)-1].Nonce() // Wait for the transaction announcement(s) and make sure all sent txs are being propagated. - // all txs should be announced within 3 announcements. + // all txs should be announced within a couple announcements. recvHashes := make([]common.Hash, 0) - for i := 0; i < 3; i++ { + for i := 0; i < 20; i++ { switch msg := recvConn.readAndServe(s.chain, timeout).(type) { case *Transactions: for _, tx := range *msg { diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index 035e0c2ec7d8..7c8f16df531f 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -262,57 +262,79 @@ func (f *TxFetcher) Notify(peer string, hashes []common.Hash) error { // direct request replies. The differentiation is important so the fetcher can // re-schedule missing transactions as soon as possible. func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) error { - // Keep track of all the propagated transactions - if direct { - txReplyInMeter.Mark(int64(len(txs))) - } else { - txBroadcastInMeter.Mark(int64(len(txs))) + var ( + inMeter = txReplyInMeter + knownMeter = txReplyKnownMeter + underpricedMeter = txReplyUnderpricedMeter + otherRejectMeter = txReplyOtherRejectMeter + ) + if !direct { + inMeter = txBroadcastInMeter + knownMeter = txBroadcastKnownMeter + underpricedMeter = txBroadcastUnderpricedMeter + otherRejectMeter = txBroadcastOtherRejectMeter } + // Keep track of all the propagated transactions + inMeter.Mark(int64(len(txs))) + // Push all the transactions into the pool, tracking underpriced ones to avoid // re-requesting them and dropping the peer in case of malicious transfers. var ( - added = make([]common.Hash, 0, len(txs)) - duplicate int64 - underpriced int64 - otherreject int64 + added = make([]common.Hash, 0, len(txs)) + delay time.Duration ) - errs := f.addTxs(txs) - for i, err := range errs { - // Track the transaction hash if the price is too low for us. - // Avoid re-request this transaction when we receive another - // announcement. - if errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced) { - for f.underpriced.Cardinality() >= maxTxUnderpricedSetSize { - f.underpriced.Pop() - } - f.underpriced.Add(txs[i].Hash()) + // proceed in batches + for i := 0; i < len(txs); i += 128 { + end := i + 128 + if end > len(txs) { + end = len(txs) } - // Track a few interesting failure types - switch { - case err == nil: // Noop, but need to handle to not count these + var ( + duplicate int64 + underpriced int64 + otherreject int64 + ) + batch := txs[i:end] + for j, err := range f.addTxs(batch) { + // Track the transaction hash if the price is too low for us. + // Avoid re-request this transaction when we receive another + // announcement. + if errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced) { + for f.underpriced.Cardinality() >= maxTxUnderpricedSetSize { + f.underpriced.Pop() + } + f.underpriced.Add(batch[j].Hash()) + } + // Track a few interesting failure types + switch { + case err == nil: // Noop, but need to handle to not count these - case errors.Is(err, core.ErrAlreadyKnown): - duplicate++ + case errors.Is(err, core.ErrAlreadyKnown): + duplicate++ - case errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced): - underpriced++ + case errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced): + underpriced++ - default: - otherreject++ + default: + otherreject++ + } + added = append(added, batch[j].Hash()) + } + knownMeter.Mark(duplicate) + underpricedMeter.Mark(underpriced) + otherRejectMeter.Mark(otherreject) + + // If 'other reject' is >25% of the deliveries in any batch, abort. Either we are + // out of sync with the chain or the peer is griefing us. + if otherreject > 128/4 { + delay = 200 * time.Millisecond + log.Warn("Peer delivering useless transactions", "peer", peer, "ignored", len(txs)-end) + break } - added = append(added, txs[i].Hash()) - } - if direct { - txReplyKnownMeter.Mark(duplicate) - txReplyUnderpricedMeter.Mark(underpriced) - txReplyOtherRejectMeter.Mark(otherreject) - } else { - txBroadcastKnownMeter.Mark(duplicate) - txBroadcastUnderpricedMeter.Mark(underpriced) - txBroadcastOtherRejectMeter.Mark(otherreject) } select { case f.cleanup <- &txDelivery{origin: peer, hashes: added, direct: direct}: + time.Sleep(delay) return nil case <-f.quit: return errTerminated From 02418c2fa965e61f5bc1e66e1063482eb5293e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 22 Aug 2022 10:14:56 +0300 Subject: [PATCH 178/715] Revert "eth/fetcher: don't spend too much time on transaction inclusion" (#25567) Revert "eth/fetcher: don't spend too much time on transaction inclusion (#25524)" This reverts commit 0ce494b60cd00d70f1f9f2dd0b9bfbd76204168a. --- cmd/devp2p/internal/ethtest/helpers.go | 6 +- cmd/devp2p/internal/ethtest/suite.go | 4 - cmd/devp2p/internal/ethtest/transaction.go | 6 +- eth/fetcher/tx_fetcher.go | 98 +++++++++------------- 4 files changed, 42 insertions(+), 72 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/helpers.go b/cmd/devp2p/internal/ethtest/helpers.go index b57649ade99d..eeeb4f93cabf 100644 --- a/cmd/devp2p/internal/ethtest/helpers.go +++ b/cmd/devp2p/internal/ethtest/helpers.go @@ -357,13 +357,9 @@ func (s *Suite) waitAnnounce(conn *Conn, blockAnnouncement *NewBlock) error { return fmt.Errorf("wrong block hash in announcement: expected %v, got %v", blockAnnouncement.Block.Hash(), hashes[0].Hash) } return nil - - // ignore tx announcements from previous tests case *NewPooledTransactionHashes: + // ignore tx announcements from previous tests continue - case *Transactions: - continue - default: return fmt.Errorf("unexpected: %s", pretty.Sdump(msg)) } diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index 4497478d72d6..7059b4ba738c 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -544,13 +544,9 @@ func (s *Suite) TestNewPooledTxs(t *utesting.T) { t.Fatalf("unexpected number of txs requested: wanted %d, got %d", len(hashes), len(msg.GetPooledTransactionsPacket)) } return - // ignore propagated txs from previous tests case *NewPooledTransactionHashes: continue - case *Transactions: - continue - // ignore block announcements from previous tests case *NewBlockHashes: continue diff --git a/cmd/devp2p/internal/ethtest/transaction.go b/cmd/devp2p/internal/ethtest/transaction.go index baa55bd49268..c4748bf8f7d8 100644 --- a/cmd/devp2p/internal/ethtest/transaction.go +++ b/cmd/devp2p/internal/ethtest/transaction.go @@ -29,7 +29,7 @@ import ( "github.com/ethereum/go-ethereum/params" ) -// var faucetAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") +//var faucetAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") var faucetKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") func (s *Suite) sendSuccessfulTxs(t *utesting.T) error { @@ -192,10 +192,10 @@ func sendMultipleSuccessfulTxs(t *utesting.T, s *Suite, txs []*types.Transaction nonce = txs[len(txs)-1].Nonce() // Wait for the transaction announcement(s) and make sure all sent txs are being propagated. - // all txs should be announced within a couple announcements. + // all txs should be announced within 3 announcements. recvHashes := make([]common.Hash, 0) - for i := 0; i < 20; i++ { + for i := 0; i < 3; i++ { switch msg := recvConn.readAndServe(s.chain, timeout).(type) { case *Transactions: for _, tx := range *msg { diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index 7c8f16df531f..035e0c2ec7d8 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -262,79 +262,57 @@ func (f *TxFetcher) Notify(peer string, hashes []common.Hash) error { // direct request replies. The differentiation is important so the fetcher can // re-schedule missing transactions as soon as possible. func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) error { - var ( - inMeter = txReplyInMeter - knownMeter = txReplyKnownMeter - underpricedMeter = txReplyUnderpricedMeter - otherRejectMeter = txReplyOtherRejectMeter - ) - if !direct { - inMeter = txBroadcastInMeter - knownMeter = txBroadcastKnownMeter - underpricedMeter = txBroadcastUnderpricedMeter - otherRejectMeter = txBroadcastOtherRejectMeter - } // Keep track of all the propagated transactions - inMeter.Mark(int64(len(txs))) - + if direct { + txReplyInMeter.Mark(int64(len(txs))) + } else { + txBroadcastInMeter.Mark(int64(len(txs))) + } // Push all the transactions into the pool, tracking underpriced ones to avoid // re-requesting them and dropping the peer in case of malicious transfers. var ( - added = make([]common.Hash, 0, len(txs)) - delay time.Duration + added = make([]common.Hash, 0, len(txs)) + duplicate int64 + underpriced int64 + otherreject int64 ) - // proceed in batches - for i := 0; i < len(txs); i += 128 { - end := i + 128 - if end > len(txs) { - end = len(txs) - } - var ( - duplicate int64 - underpriced int64 - otherreject int64 - ) - batch := txs[i:end] - for j, err := range f.addTxs(batch) { - // Track the transaction hash if the price is too low for us. - // Avoid re-request this transaction when we receive another - // announcement. - if errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced) { - for f.underpriced.Cardinality() >= maxTxUnderpricedSetSize { - f.underpriced.Pop() - } - f.underpriced.Add(batch[j].Hash()) + errs := f.addTxs(txs) + for i, err := range errs { + // Track the transaction hash if the price is too low for us. + // Avoid re-request this transaction when we receive another + // announcement. + if errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced) { + for f.underpriced.Cardinality() >= maxTxUnderpricedSetSize { + f.underpriced.Pop() } - // Track a few interesting failure types - switch { - case err == nil: // Noop, but need to handle to not count these + f.underpriced.Add(txs[i].Hash()) + } + // Track a few interesting failure types + switch { + case err == nil: // Noop, but need to handle to not count these - case errors.Is(err, core.ErrAlreadyKnown): - duplicate++ + case errors.Is(err, core.ErrAlreadyKnown): + duplicate++ - case errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced): - underpriced++ + case errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced): + underpriced++ - default: - otherreject++ - } - added = append(added, batch[j].Hash()) - } - knownMeter.Mark(duplicate) - underpricedMeter.Mark(underpriced) - otherRejectMeter.Mark(otherreject) - - // If 'other reject' is >25% of the deliveries in any batch, abort. Either we are - // out of sync with the chain or the peer is griefing us. - if otherreject > 128/4 { - delay = 200 * time.Millisecond - log.Warn("Peer delivering useless transactions", "peer", peer, "ignored", len(txs)-end) - break + default: + otherreject++ } + added = append(added, txs[i].Hash()) + } + if direct { + txReplyKnownMeter.Mark(duplicate) + txReplyUnderpricedMeter.Mark(underpriced) + txReplyOtherRejectMeter.Mark(otherreject) + } else { + txBroadcastKnownMeter.Mark(duplicate) + txBroadcastUnderpricedMeter.Mark(underpriced) + txBroadcastOtherRejectMeter.Mark(otherreject) } select { case f.cleanup <- &txDelivery{origin: peer, hashes: added, direct: direct}: - time.Sleep(delay) return nil case <-f.quit: return errTerminated From 395f3d4bf689c199e93e05af57ebff09b10f1c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 22 Aug 2022 11:27:39 +0300 Subject: [PATCH 179/715] eth/catalyst: warn less frequently if no beacon client is available (#25569) * eth/catalyst: warn less frequently if no beacon client is available * eth/catalyst: tweak warning frequency a bit * eth/catalyst: some more tweaks * Update api.go Co-authored-by: Felix Lange --- eth/catalyst/api.go | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 358529459b1c..b159f34e64ba 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -61,10 +61,23 @@ const ( // have lead to some bad ancestor block. It's just an OOM protection. invalidTipsetsCap = 512 - // beaconUpdateTimeout is the max time allowed for a beacon client to signal - // use (from the last heartbeat) before it's consifered offline and the user + // beaconUpdateStartupTimeout is the time to wait for a beacon client to get + // attached before starting to issue warnings. + beaconUpdateStartupTimeout = 30 * time.Second + + // beaconUpdateExchangeTimeout is the max time allowed for a beacon client to + // do a transition config exchange before it's considered offline and the user // is warned. - beaconUpdateTimeout = 30 * time.Second + beaconUpdateExchangeTimeout = 2 * time.Minute + + // beaconUpdateConsensusTimeout is the max time allowed for a beacon client + // to send a consensus update before it's considered offline and the user is + // warned. + beaconUpdateConsensusTimeout = 30 * time.Second + + // beaconUpdateWarnFrequency is the frequency at which to warn the user that + // the beacon client is offline. + beaconUpdateWarnFrequency = 5 * time.Minute ) type ConsensusAPI struct { @@ -545,9 +558,9 @@ func (api *ConsensusAPI) invalid(err error, latestValid *types.Header) beacon.Pa // // TODO(karalabe): Spin this goroutine down somehow func (api *ConsensusAPI) heartbeat() { - // Sleep a bit more on startup since there's obviously no beacon client yet + // Sleep a bit on startup since there's obviously no beacon client yet // attached, so no need to print scary warnings to the user. - time.Sleep(beaconUpdateTimeout) + time.Sleep(beaconUpdateStartupTimeout) var ( offlineLogged time.Time @@ -576,9 +589,9 @@ func (api *ConsensusAPI) heartbeat() { // If there have been no updates for the past while, warn the user // that the beacon client is probably offline if api.eth.BlockChain().Config().TerminalTotalDifficultyPassed || api.eth.Merger().TDDReached() { - if time.Since(lastForkchoiceUpdate) > beaconUpdateTimeout && time.Since(lastNewPayloadUpdate) > beaconUpdateTimeout { - if time.Since(lastTransitionUpdate) > beaconUpdateTimeout { - if time.Since(offlineLogged) > beaconUpdateTimeout { + if time.Since(lastForkchoiceUpdate) > beaconUpdateConsensusTimeout && time.Since(lastNewPayloadUpdate) > beaconUpdateConsensusTimeout { + if time.Since(lastTransitionUpdate) > beaconUpdateExchangeTimeout { + if time.Since(offlineLogged) > beaconUpdateWarnFrequency { if lastTransitionUpdate.IsZero() { log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!") } else { @@ -588,7 +601,7 @@ func (api *ConsensusAPI) heartbeat() { } continue } - if time.Since(offlineLogged) > beaconUpdateTimeout { + if time.Since(offlineLogged) > beaconUpdateWarnFrequency { if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") } else { @@ -597,10 +610,12 @@ func (api *ConsensusAPI) heartbeat() { offlineLogged = time.Now() } continue + } else { + offlineLogged = time.Time{} } } else { - if time.Since(lastTransitionUpdate) > beaconUpdateTimeout { - if time.Since(offlineLogged) > beaconUpdateTimeout { + if time.Since(lastTransitionUpdate) > beaconUpdateExchangeTimeout { + if time.Since(offlineLogged) > beaconUpdateWarnFrequency { // Retrieve the last few blocks and make a rough estimate as // to when the merge transition should happen var ( @@ -654,6 +669,8 @@ func (api *ConsensusAPI) heartbeat() { offlineLogged = time.Now() } continue + } else { + offlineLogged = time.Time{} } } } From 2de49b04e56cf07f011d6d91f9d5c08847aabe8e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 22 Aug 2022 10:36:39 +0200 Subject: [PATCH 180/715] params: release go-ethereum v1.10.22 --- params/version.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/params/version.go b/params/version.go index 258be5d5db31..5105f3578e82 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 22 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 10 // Minor version component of the current release + VersionPatch = 22 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. @@ -41,9 +41,9 @@ var VersionWithMeta = func() string { return v }() -// ArchiveVersion holds the textual version string used for Geth archives. -// e.g. "1.8.11-dea1ce05" for stable releases, or -// "1.8.13-unstable-21c059b6" for unstable releases +// ArchiveVersion holds the textual version string used for Geth archives. e.g. +// "1.8.11-dea1ce05" for stable releases, or "1.8.13-unstable-21c059b6" for unstable +// releases. func ArchiveVersion(gitCommit string) string { vsn := Version if VersionMeta != "stable" { From 6d711f0c001ccb536c5ead8bd5d07828819e7d61 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 22 Aug 2022 10:39:18 +0200 Subject: [PATCH 181/715] params: begin v1.10.23 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 5105f3578e82..e858944dd7da 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 22 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 10 // Minor version component of the current release + VersionPatch = 23 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 81bd998353789980a6ef3e493b3562750b416d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 23 Aug 2022 14:02:51 +0300 Subject: [PATCH 182/715] core, eth/downloader: handle spurious junk bodies from racey rollbacks (#25578) * eth/downloader: handle junkbodies/receipts in the beacon sync * core: check for header presence when checking for blocks --- core/blockchain_reader.go | 3 +++ eth/downloader/skeleton.go | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 96e9f80b6aac..5814c8a0daee 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -137,6 +137,9 @@ func (bc *BlockChain) HasBlock(hash common.Hash, number uint64) bool { if bc.blockCache.Contains(hash) { return true } + if !bc.HasHeader(hash, number) { + return false + } return rawdb.HasBody(bc.db, hash, number) } diff --git a/eth/downloader/skeleton.go b/eth/downloader/skeleton.go index e627c6ae5a35..517b8378c518 100644 --- a/eth/downloader/skeleton.go +++ b/eth/downloader/skeleton.go @@ -358,6 +358,7 @@ func (s *skeleton) sync(head *types.Header) (*types.Header, error) { // If the sync is already done, resume the backfiller. When the loop stops, // terminate the backfiller too. linked := len(s.progress.Subchains) == 1 && + rawdb.HasHeader(s.db, s.progress.Subchains[0].Next, s.scratchHead) && rawdb.HasBody(s.db, s.progress.Subchains[0].Next, s.scratchHead) && rawdb.HasReceipts(s.db, s.progress.Subchains[0].Next, s.scratchHead) if linked { @@ -946,12 +947,12 @@ func (s *skeleton) processResponse(res *headerResponse) (linked bool, merged boo // In the case of full sync it would be enough to check for the body, // but even a full syncing node will generate a receipt once block // processing is done, so it's just one more "needless" check. - var ( - hasBody = rawdb.HasBody(s.db, header.ParentHash, header.Number.Uint64()-1) - hasReceipt = rawdb.HasReceipts(s.db, header.ParentHash, header.Number.Uint64()-1) - ) - if hasBody && hasReceipt { - linked = true + // + // The weird cascading checks are done to minimize the database reads. + linked = rawdb.HasHeader(s.db, header.ParentHash, header.Number.Uint64()-1) && + rawdb.HasBody(s.db, header.ParentHash, header.Number.Uint64()-1) && + rawdb.HasReceipts(s.db, header.ParentHash, header.Number.Uint64()-1) + if linked { break } } From 5758d1fb1162f14ebb2420017d83181e576e3d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 23 Aug 2022 21:17:12 +0300 Subject: [PATCH 183/715] core/state, trie: fix trie flush order for proper pruning --- core/state/statedb_test.go | 40 ++++++++++++++++++++++++++++++++++++++ trie/database.go | 19 +++++++++++++++--- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 092a4fb8711f..6fe36a7ecffd 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -914,3 +914,43 @@ func TestStateDBAccessList(t *testing.T) { t.Fatalf("expected empty, got %d", got) } } + +// Tests that account and storage tries are flushed in the correct order and that +// no data loss occurs. +func TestFlushOrderDataLoss(t *testing.T) { + // Create a state trie with many accounts and slots + var ( + memdb = rawdb.NewMemoryDatabase() + statedb = NewDatabase(memdb) + state, _ = New(common.Hash{}, statedb, nil) + ) + for a := byte(0); a < 10; a++ { + state.CreateAccount(common.Address{a}) + for s := byte(0); s < 10; s++ { + state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s}) + } + } + root, err := state.Commit(false) + if err != nil { + t.Fatalf("failed to commit state trie: %v", err) + } + statedb.TrieDB().Reference(root, common.Hash{}) + if err := statedb.TrieDB().Cap(1024); err != nil { + t.Fatalf("failed to cap trie dirty cache: %v", err) + } + if err := statedb.TrieDB().Commit(root, false, nil); err != nil { + t.Fatalf("failed to commit state trie: %v", err) + } + // Reopen the state trie from flushed disk and verify it + state, err = New(root, NewDatabase(memdb), nil) + if err != nil { + t.Fatalf("failed to reopen state trie: %v", err) + } + for a := byte(0); a < 10; a++ { + for s := byte(0); s < 10; s++ { + if have := state.GetState(common.Address{a}, common.Hash{a, s}); have != (common.Hash{a, s}) { + t.Errorf("account %d: slot %d: state mismatch: have %x, want %x", a, s, have, common.Hash{a, s}) + } + } + } +} diff --git a/trie/database.go b/trie/database.go index 8c154ba96df6..b10bbca9bdba 100644 --- a/trie/database.go +++ b/trie/database.go @@ -776,9 +776,22 @@ func (db *Database) Update(nodes *MergedNodeSet) error { // Insert dirty nodes into the database. In the same tree, it must be // ensured that children are inserted first, then parent so that children - // can be linked with their parent correctly. The order of writing between - // different tries(account trie, storage tries) is not required. - for owner, subset := range nodes.sets { + // can be linked with their parent correctly. + // + // Note, the storage tries must be flushed before the account trie to + // retain the invariant that children go into the dirty cache first. + var order []common.Hash + for owner := range nodes.sets { + if owner == (common.Hash{}) { + continue + } + order = append(order, owner) + } + if _, ok := nodes.sets[common.Hash{}]; ok { + order = append(order, common.Hash{}) + } + for _, owner := range order { + subset := nodes.sets[owner] for _, path := range subset.paths { n, ok := subset.nodes[path] if !ok { From 45a660a4f217fc00378665773fb0a60beebac9bd Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 23 Aug 2022 20:48:50 +0200 Subject: [PATCH 184/715] consensus/beacon: don't ignore errors --- consensus/beacon/consensus.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 949c8ad816ce..7e4d657413ed 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -79,7 +79,10 @@ func (beacon *Beacon) Author(header *types.Header) (common.Address, error) { // VerifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum consensus engine. func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error { - reached, _ := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) + reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) + if err != nil { + return err + } if !reached { return beacon.ethone.VerifyHeader(chain, header, seal) } @@ -116,11 +119,14 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ if len(preHeaders) == 0 { // All the headers are pos headers. Verify that the parent block reached total terminal difficulty. - if reached, _ := IsTTDReached(chain, headers[0].ParentHash, headers[0].Number.Uint64()-1); !reached { + if reached, err := IsTTDReached(chain, headers[0].ParentHash, headers[0].Number.Uint64()-1); !reached { // TTD not reached for the first block, mark subsequent with invalid terminal block + if err == nil { + err = consensus.ErrInvalidTerminalBlock + } results := make(chan error, len(headers)) for i := 0; i < len(headers); i++ { - results <- consensus.ErrInvalidTerminalBlock + results <- err } return make(chan struct{}), results } From d901d85377c2c2f05f09f423c7d739c0feecd90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 24 Aug 2022 12:09:02 +0300 Subject: [PATCH 185/715] params: release Geth v1.10.23 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index e858944dd7da..5f24b41f2852 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 23 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 10 // Minor version component of the current release + VersionPatch = 23 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 57896d6fbe496891e5b711df5232e3cc03ce82ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 24 Aug 2022 12:11:17 +0300 Subject: [PATCH 186/715] params: begin v1.10.24 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 5f24b41f2852..a0f16b29810e 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 23 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 10 // Minor version component of the current release + VersionPatch = 24 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 6c40aed146d9901baede6030887f19db2c60b10c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 25 Aug 2022 10:37:04 +0200 Subject: [PATCH 187/715] params: begin go-ethereum v1.11 release cycle --- params/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/params/version.go b/params/version.go index a0f16b29810e..317241539325 100644 --- a/params/version.go +++ b/params/version.go @@ -22,8 +22,8 @@ import ( const ( VersionMajor = 1 // Major version component of the current release - VersionMinor = 10 // Minor version component of the current release - VersionPatch = 24 // Patch version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 0 // Patch version component of the current release VersionMeta = "unstable" // Version metadata to append to the version string ) From 70e1e65b1d026d5fc5208d9b066d1d2daaa5ae2c Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 25 Aug 2022 02:41:37 -0600 Subject: [PATCH 188/715] internal/ethapi: rename debug getters to match spec (#25176) Some small fixes to get the existing debug methods to conform to the spec. Mainly dropping the encoding information from the method name as it should be deduced from the debug context and allowing the method to be invoked by either block number or block hash. It also adds the method debug_getTransaction which returns the raw tx bytes by tx hash. This is pretty much equivalent to the eth_getRawTransactionByHash method. --- internal/ethapi/api.go | 54 ++++++++++++++++++++++++++++++------- internal/web3ext/web3ext.go | 13 ++++++--- 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e6740942d859..89c95c50744c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1888,25 +1888,45 @@ func NewDebugAPI(b Backend) *DebugAPI { return &DebugAPI{b: b} } -// GetHeaderRlp retrieves the RLP encoded for of a single header. -func (api *DebugAPI) GetHeaderRlp(ctx context.Context, number uint64) (hexutil.Bytes, error) { - header, _ := api.b.HeaderByNumber(ctx, rpc.BlockNumber(number)) +// GetRawHeader retrieves the RLP encoding for a single header. +func (api *DebugAPI) GetRawHeader(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + var hash common.Hash + if h, ok := blockNrOrHash.Hash(); ok { + hash = h + } else { + block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return nil, err + } + hash = block.Hash() + } + header, _ := api.b.HeaderByHash(ctx, hash) if header == nil { - return nil, fmt.Errorf("header #%d not found", number) + return nil, fmt.Errorf("header #%d not found", hash) } return rlp.EncodeToBytes(header) } -// GetBlockRlp retrieves the RLP encoded for of a single block. -func (api *DebugAPI) GetBlockRlp(ctx context.Context, number uint64) (hexutil.Bytes, error) { - block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) +// GetRawBlock retrieves the RLP encoded for a single block. +func (api *DebugAPI) GetRawBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + var hash common.Hash + if h, ok := blockNrOrHash.Hash(); ok { + hash = h + } else { + block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return nil, err + } + hash = block.Hash() + } + block, _ := api.b.BlockByHash(ctx, hash) if block == nil { - return nil, fmt.Errorf("block #%d not found", number) + return nil, fmt.Errorf("block #%d not found", hash) } return rlp.EncodeToBytes(block) } -// GetRawReceipts retrieves the binary-encoded raw receipts of a single block. +// GetRawReceipts retrieves the binary-encoded receipts of a single block. func (api *DebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]hexutil.Bytes, error) { var hash common.Hash if h, ok := blockNrOrHash.Hash(); ok { @@ -1933,6 +1953,22 @@ func (api *DebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.Block return result, nil } +// GetRawTransaction returns the bytes of the transaction for the given hash. +func (s *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { + // Retrieve a finalized transaction, or a pooled otherwise + tx, _, _, _, err := s.b.GetTransaction(ctx, hash) + if err != nil { + return nil, err + } + if tx == nil { + if tx = s.b.GetPoolTransaction(hash); tx == nil { + // Transaction not found anywhere, abort + return nil, nil + } + } + return tx.MarshalBinary() +} + // PrintBlock retrieves a block and returns its pretty printed form. func (api *DebugAPI) PrintBlock(ctx context.Context, number uint64) (string, error) { block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 88c31c04da19..134562bde6fc 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -224,13 +224,13 @@ web3._extend({ outputFormatter: console.log }), new web3._extend.Method({ - name: 'getHeaderRlp', - call: 'debug_getHeaderRlp', + name: 'getRawHeader', + call: 'debug_getRawHeader', params: 1 }), new web3._extend.Method({ - name: 'getBlockRlp', - call: 'debug_getBlockRlp', + name: 'getRawBlock', + call: 'debug_getRawBlock', params: 1 }), new web3._extend.Method({ @@ -238,6 +238,11 @@ web3._extend({ call: 'debug_getRawReceipts', params: 1 }), + new web3._extend.Method({ + name: 'getRawTransaction', + call: 'debug_getRawTransaction', + params: 1 + }), new web3._extend.Method({ name: 'setHead', call: 'debug_setHead', From f03c37b73e966249ef9e51178c4631a54c3efdc1 Mon Sep 17 00:00:00 2001 From: xinbenlv Date: Thu, 25 Aug 2022 04:59:50 -0400 Subject: [PATCH 189/715] accounts/abi/bind: add const for tx fee elasticity multiplier (#25504) Co-authored-by: Felix Lange Co-authored-by: rjl493456442 --- accounts/abi/bind/base.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index fe330014d35a..88b997684a40 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -32,6 +32,8 @@ import ( "github.com/ethereum/go-ethereum/event" ) +const basefeeWiggleMultiplier = 2 + // SignerFn is a signer function callback when a contract requires a method to // sign the transaction before submission. type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error) @@ -254,7 +256,7 @@ func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Add if gasFeeCap == nil { gasFeeCap = new(big.Int).Add( gasTipCap, - new(big.Int).Mul(head.BaseFee, big.NewInt(2)), + new(big.Int).Mul(head.BaseFee, big.NewInt(basefeeWiggleMultiplier)), ) } if gasFeeCap.Cmp(gasTipCap) < 0 { From c394c308e6211e3d09d608f0f1042f1637c83706 Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Mon, 29 Aug 2022 16:16:34 +0800 Subject: [PATCH 190/715] all: remove duplicate word in comments (#25618) Signed-off-by: Abirdcfly Signed-off-by: Abirdcfly --- cmd/devp2p/nodesetcmd.go | 2 +- core/error.go | 2 +- core/state/snapshot/difflayer.go | 2 +- core/tx_noncer.go | 2 +- p2p/discover/v4wire/v4wire.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/devp2p/nodesetcmd.go b/cmd/devp2p/nodesetcmd.go index f6b629278ecd..2cf104592834 100644 --- a/cmd/devp2p/nodesetcmd.go +++ b/cmd/devp2p/nodesetcmd.go @@ -181,7 +181,7 @@ func parseFilterLimit(args []string) (int, error) { return limit, nil } -// andFilter parses node filters in args and and returns a single filter that requires all +// andFilter parses node filters in args and returns a single filter that requires all // of them to match. func andFilter(args []string) (nodeFilter, error) { checks, err := parseFilters(args) diff --git a/core/error.go b/core/error.go index 51ebefc137bc..5b69c8dcaf26 100644 --- a/core/error.go +++ b/core/error.go @@ -91,7 +91,7 @@ var ( ErrFeeCapVeryHigh = errors.New("max fee per gas higher than 2^256-1") // ErrFeeCapTooLow is returned if the transaction fee cap is less than the - // the base fee of the block. + // base fee of the block. ErrFeeCapTooLow = errors.New("max fee per gas less than block base fee") // ErrSenderNoEOA is returned if the sender of a transaction is a contract. diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index 822c91f15cb8..f916a020e7bc 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -68,7 +68,7 @@ var ( bloomFuncs = math.Round((bloomSize / float64(aggregatorItemLimit)) * math.Log(2)) // the bloom offsets are runtime constants which determines which part of the - // the account/storage hash the hasher functions looks at, to determine the + // account/storage hash the hasher functions looks at, to determine the // bloom key for an account/slot. This is randomized at init(), so that the // global population of nodes do not all display the exact same behaviour with // regards to bloom content diff --git a/core/tx_noncer.go b/core/tx_noncer.go index d6d220077507..51fa8cf5a1f9 100644 --- a/core/tx_noncer.go +++ b/core/tx_noncer.go @@ -64,7 +64,7 @@ func (txn *txNoncer) set(addr common.Address, nonce uint64) { } // setIfLower updates a new virtual nonce into the virtual state database if the -// the new one is lower. +// new one is lower. func (txn *txNoncer) setIfLower(addr common.Address, nonce uint64) { txn.lock.Lock() defer txn.lock.Unlock() diff --git a/p2p/discover/v4wire/v4wire.go b/p2p/discover/v4wire/v4wire.go index b07a6e341c31..02ee459d1479 100644 --- a/p2p/discover/v4wire/v4wire.go +++ b/p2p/discover/v4wire/v4wire.go @@ -60,7 +60,7 @@ type ( Pong struct { // This field should mirror the UDP envelope address // of the ping packet, which provides a way to discover the - // the external address (after NAT). + // external address (after NAT). To Endpoint ReplyTok []byte // This contains the hash of the ping packet. Expiration uint64 // Absolute timestamp at which the packet becomes invalid. From 6e6b5087f19fb726d75d01059cda5c5b43164b06 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 30 Aug 2022 14:38:35 +0200 Subject: [PATCH 191/715] cmd/geth: fix legacy receipt detection for empty db (#25609) --- cmd/geth/config.go | 5 +++-- cmd/geth/dbcmd.go | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 30565fda6185..d877e2b5dda0 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -175,12 +175,13 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { if cfg.Eth.NetworkId == 1 && ghash == params.MainnetGenesisHash { firstIdx = 46147 } - isLegacy, _, err := dbHasLegacyReceipts(eth.ChainDb(), firstIdx) + isLegacy, firstLegacy, err := dbHasLegacyReceipts(eth.ChainDb(), firstIdx) if err != nil { log.Error("Failed to check db for legacy receipts", "err", err) } else if isLegacy { stack.Close() - utils.Fatalf("Database has receipts with a legacy format. Please run `geth db freezer-migrate`.") + log.Error("Database has receipts with a legacy format", "firstLegacy", firstLegacy) + utils.Fatalf("Aborting. Please run `geth db freezer-migrate`.") } } diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index ab74277123d7..bb53a632e862 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -822,11 +822,15 @@ func dbHasLegacyReceipts(db ethdb.Database, firstIdx uint64) (bool, uint64, erro } } } - // Is first non-empty receipt legacy? first, err := db.Ancient("receipts", firstIdx) if err != nil { return false, 0, err } + // We looped over all receipts and they were all empty + if bytes.Equal(first, emptyRLPList) { + return false, 0, nil + } + // Is first non-empty receipt legacy? legacy, err = types.IsLegacyStoredReceipts(first) return legacy, firstIdx, err } From 6d882a51e0e42fb991ddc12375b58c3b38e6c865 Mon Sep 17 00:00:00 2001 From: uji <49834542+uji@users.noreply.github.com> Date: Tue, 30 Aug 2022 21:40:15 +0900 Subject: [PATCH 192/715] build: fix ignored errors (#25591) --- build/ci.go | 5 ++++- build/update-license.go | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/build/ci.go b/build/ci.go index 80b040045939..24f225b72030 100644 --- a/build/ci.go +++ b/build/ci.go @@ -982,7 +982,10 @@ func doWindowsInstaller(cmdline []string) { if env.Commit != "" { version[2] += "-" + env.Commit[:8] } - installer, _ := filepath.Abs("geth-" + archiveBasename(*arch, params.ArchiveVersion(env.Commit)) + ".exe") + installer, err := filepath.Abs("geth-" + archiveBasename(*arch, params.ArchiveVersion(env.Commit)) + ".exe") + if err != nil { + log.Fatalf("Failed to convert installer file path: %v", err) + } build.MustRunCommand("makensis.exe", "/DOUTPUTFILE="+installer, "/DMAJORVERSION="+version[0], diff --git a/build/update-license.go b/build/update-license.go index 5bad996cc45b..f61536470a19 100644 --- a/build/update-license.go +++ b/build/update-license.go @@ -342,7 +342,10 @@ func isGenerated(file string) bool { } defer fd.Close() buf := make([]byte, 2048) - n, _ := fd.Read(buf) + n, err := fd.Read(buf) + if err != nil { + return false + } buf = buf[:n] for _, l := range bytes.Split(buf, []byte("\n")) { if bytes.HasPrefix(l, []byte("// Code generated")) { From 44b36a0cdd681ae6292f6e6b7fd05dbf69589d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Tue, 30 Aug 2022 14:48:04 +0200 Subject: [PATCH 193/715] docs: specify execution client (#25566) Co-authored-by: Felix Lange --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b20eb5b748b4..d1377726893c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## Go Ethereum -Official Golang implementation of the Ethereum protocol. +Official Golang execution layer implementation of the Ethereum protocol. [![API Reference]( https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667 From 8df8eb4e7af495305d2ea101c49cdae9c1261027 Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Tue, 30 Aug 2022 07:56:39 -0500 Subject: [PATCH 194/715] ethclient: add 'finalized' and 'safe' block number support (#25580) --- ethclient/ethclient.go | 8 ++++++++ ethclient/gethclient/gethclient.go | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 8a001843187b..766efcf57140 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -570,6 +570,14 @@ func toBlockNumArg(number *big.Int) string { if number.Cmp(pending) == 0 { return "pending" } + finalized := big.NewInt(int64(rpc.FinalizedBlockNumber)) + if number.Cmp(finalized) == 0 { + return "finalized" + } + safe := big.NewInt(int64(rpc.SafeBlockNumber)) + if number.Cmp(safe) == 0 { + return "safe" + } return hexutil.EncodeBig(number) } diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index a86f4339f425..edc441bd1ee9 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -187,6 +187,14 @@ func toBlockNumArg(number *big.Int) string { if number.Cmp(pending) == 0 { return "pending" } + finalized := big.NewInt(int64(rpc.FinalizedBlockNumber)) + if number.Cmp(finalized) == 0 { + return "finalized" + } + safe := big.NewInt(int64(rpc.SafeBlockNumber)) + if number.Cmp(safe) == 0 { + return "safe" + } return hexutil.EncodeBig(number) } From 7813b675f51ff95915ffff7992d6d66bc03fb982 Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Tue, 30 Aug 2022 22:25:02 +0900 Subject: [PATCH 195/715] node: change JWT error status to 401 Unauthorized (#25629) --- node/jwt_handler.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/node/jwt_handler.go b/node/jwt_handler.go index 363f6b3aad47..637ae19686e2 100644 --- a/node/jwt_handler.go +++ b/node/jwt_handler.go @@ -51,7 +51,7 @@ func (handler *jwtHandler) ServeHTTP(out http.ResponseWriter, r *http.Request) { strToken = strings.TrimPrefix(auth, "Bearer ") } if len(strToken) == 0 { - http.Error(out, "missing token", http.StatusForbidden) + http.Error(out, "missing token", http.StatusUnauthorized) return } // We explicitly set only HS256 allowed, and also disables the @@ -63,17 +63,17 @@ func (handler *jwtHandler) ServeHTTP(out http.ResponseWriter, r *http.Request) { switch { case err != nil: - http.Error(out, err.Error(), http.StatusForbidden) + http.Error(out, err.Error(), http.StatusUnauthorized) case !token.Valid: - http.Error(out, "invalid token", http.StatusForbidden) + http.Error(out, "invalid token", http.StatusUnauthorized) case !claims.VerifyExpiresAt(time.Now(), false): // optional - http.Error(out, "token is expired", http.StatusForbidden) + http.Error(out, "token is expired", http.StatusUnauthorized) case claims.IssuedAt == nil: - http.Error(out, "missing issued-at", http.StatusForbidden) + http.Error(out, "missing issued-at", http.StatusUnauthorized) case time.Since(claims.IssuedAt.Time) > jwtExpiryTimeout: - http.Error(out, "stale token", http.StatusForbidden) + http.Error(out, "stale token", http.StatusUnauthorized) case time.Until(claims.IssuedAt.Time) > jwtExpiryTimeout: - http.Error(out, "future token", http.StatusForbidden) + http.Error(out, "future token", http.StatusUnauthorized) default: handler.next.ServeHTTP(out, r) } From 2b6df280de60c0bb70014e9b03885ef76fde4c61 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 30 Aug 2022 16:41:09 +0200 Subject: [PATCH 196/715] node: fix regression in TestJWT (#25635) --- node/rpcstack_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index 09acf7ea0458..ebc253800623 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -412,8 +412,10 @@ func TestJWT(t *testing.T) { if err := wsRequest(t, wsUrl, "Authorization", token); err == nil { t.Errorf("tc %d-ws, token '%v': expected not to allow, got ok", i, token) } + token = tokenFn() - if resp := rpcRequest(t, htUrl, "Authorization", token); resp.StatusCode != 403 { + resp := rpcRequest(t, htUrl, "Authorization", token) + if resp.StatusCode != http.StatusUnauthorized { t.Errorf("tc %d-http, token '%v': expected not to allow, got %v", i, token, resp.StatusCode) } } From d10c28030944d1c32febba3f45ae8c175ab34063 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 31 Aug 2022 00:22:28 +0800 Subject: [PATCH 197/715] all: move genesis initialization to blockchain (#25523) * all: move genesis initialization to blockchain * core: add one more check * core: fix tests --- accounts/abi/bind/backends/simulated.go | 2 +- cmd/utils/flags.go | 21 ++- consensus/clique/clique_test.go | 7 +- consensus/clique/snapshot_test.go | 3 +- core/bench_test.go | 9 +- core/block_validator_test.go | 33 ++--- core/blockchain.go | 24 +++- core/blockchain_repair_test.go | 20 ++- core/blockchain_sethead_test.go | 8 +- core/blockchain_snapshot_test.go | 28 ++-- core/blockchain_test.go | 171 +++++++++++++++--------- core/chain_makers_test.go | 2 +- core/dao_test.go | 49 ++++--- core/genesis.go | 55 +++++++- core/genesis_test.go | 2 +- core/state_processor_test.go | 6 +- eth/backend.go | 55 ++++---- eth/downloader/downloader_test.go | 5 +- eth/downloader/testchain_test.go | 3 +- eth/ethconfig/config.go | 28 ++-- eth/gasprice/gasprice_test.go | 2 +- eth/handler_eth_test.go | 4 +- eth/handler_test.go | 7 +- eth/protocols/eth/handler_test.go | 7 +- eth/tracers/api_test.go | 52 ++++--- les/client.go | 11 +- light/odr_test.go | 5 +- light/trie_test.go | 5 +- light/txpool_test.go | 5 +- miner/miner_test.go | 2 +- miner/worker_test.go | 4 +- params/config.go | 5 +- tests/block_test_util.go | 5 +- tests/fuzzers/les/les-fuzzer.go | 2 +- tests/fuzzers/snap/fuzz_handler.go | 4 +- 35 files changed, 406 insertions(+), 245 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 0ce752103c9a..0095edbdb4b0 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -80,7 +80,7 @@ type SimulatedBackend struct { func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc} genesis.MustCommit(database) - blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := core.NewBlockChain(database, nil, &genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) backend := &SimulatedBackend{ database: database, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 9e95193343a9..fb2aa7c21587 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -33,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -2166,20 +2165,20 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { } // MakeChain creates a chain manager from set command line flags. -func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { - var err error - chainDb = MakeChainDatabase(ctx, stack, false) // TODO(rjl493456442) support read-only database - config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) +func MakeChain(ctx *cli.Context, stack *node.Node) (*core.BlockChain, ethdb.Database) { + var ( + gspec = MakeGenesis(ctx) + chainDb = MakeChainDatabase(ctx, stack, false) // TODO(rjl493456442) support read-only database + ) + cliqueConfig, err := core.LoadCliqueConfig(chainDb, gspec) if err != nil { Fatalf("%v", err) } - - var engine consensus.Engine - ethashConf := ethconfig.Defaults.Ethash + ethashConfig := ethconfig.Defaults.Ethash if ctx.Bool(FakePoWFlag.Name) { - ethashConf.PowMode = ethash.ModeFake + ethashConfig.PowMode = ethash.ModeFake } - engine = ethconfig.CreateConsensusEngine(stack, config, ðashConf, nil, false, chainDb) + engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, nil, false, chainDb) if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } @@ -2209,7 +2208,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai // TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only. // Disable transaction indexing/unindexing by default. - chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil) + chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil) if err != nil { Fatalf("Can't create BlockChain: %v", err) } diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index 1bd32acd3746..74d884a21b9f 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -45,6 +45,7 @@ func TestReimportMirroredState(t *testing.T) { signer = new(types.HomesteadSigner) ) genspec := &core.Genesis{ + Config: params.AllCliqueProtocolChanges, ExtraData: make([]byte, extraVanity+common.AddressLength+extraSeal), Alloc: map[common.Address]core.GenesisAccount{ addr: {Balance: big.NewInt(10000000000000000)}, @@ -55,7 +56,7 @@ func TestReimportMirroredState(t *testing.T) { genesis := genspec.MustCommit(db) // Generate a batch of blocks, each properly signed - chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil) defer chain.Stop() blocks, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, 3, func(i int, block *core.BlockGen) { @@ -89,7 +90,7 @@ func TestReimportMirroredState(t *testing.T) { db = rawdb.NewMemoryDatabase() genspec.MustCommit(db) - chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) + chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil) defer chain.Stop() if _, err := chain.InsertChain(blocks[:2]); err != nil { @@ -102,7 +103,7 @@ func TestReimportMirroredState(t *testing.T) { // Simulate a crash by creating a new chain on top of the database, without // flushing the dirty states out. Insert the last block, triggering a sidechain // reimport. - chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) + chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil) defer chain.Stop() if _, err := chain.InsertChain(blocks[2:]); err != nil { diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 4a067c62554a..a1e481abbf46 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -411,6 +411,7 @@ func TestClique(t *testing.T) { Period: 1, Epoch: tt.epoch, } + genesis.Config = &config engine := New(config.Clique, db) engine.fakeDiff = true @@ -450,7 +451,7 @@ func TestClique(t *testing.T) { batches[len(batches)-1] = append(batches[len(batches)-1], block) } // Pass all the headers through clique and ensure tallying succeeds - chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Errorf("test %d: failed to create test chain: %v", i, err) continue diff --git a/core/bench_test.go b/core/bench_test.go index 3006e5513171..e448310e4d58 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -196,7 +196,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Time the insertion of the new chain. // State and blocks are stored in the same DB. - chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + chainman, _ := NewBlockChain(db, nil, &gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() @@ -262,6 +262,11 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) { rawdb.WriteCanonicalHash(db, hash, n) rawdb.WriteTd(db, hash, n, big.NewInt(int64(n+1))) + if n == 0 { + rawdb.WriteChainConfig(db, hash, params.AllEthashProtocolChanges) + } + rawdb.WriteHeadHeaderHash(db, hash) + if full || n == 0 { block := types.NewBlockWithHeader(header) rawdb.WriteBody(db, hash, n, block.Body()) @@ -303,7 +308,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } - chain, err := NewBlockChain(db, &cacheConfig, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, &cacheConfig, nil, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { b.Fatalf("error creating chain: %v", err) } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 8dee8d576070..815bc86552a7 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -49,7 +49,7 @@ func TestHeaderVerification(t *testing.T) { headers[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer chain.Stop() for i := 0; i < len(blocks); i++ { @@ -89,12 +89,12 @@ func TestHeaderVerificationForMergingEthash(t *testing.T) { testHeaderVerificati // Tests the verification for eth1/2 merging, including pre-merge and post-merge func testHeaderVerificationForMerging(t *testing.T, isClique bool) { var ( - testdb = rawdb.NewMemoryDatabase() - preBlocks []*types.Block - postBlocks []*types.Block - runEngine consensus.Engine - chainConfig *params.ChainConfig - merger = consensus.NewMerger(rawdb.NewMemoryDatabase()) + testdb = rawdb.NewMemoryDatabase() + preBlocks []*types.Block + postBlocks []*types.Block + runEngine consensus.Engine + genspec *Genesis + merger = consensus.NewMerger(rawdb.NewMemoryDatabase()) ) if isClique { var ( @@ -102,7 +102,8 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { addr = crypto.PubkeyToAddress(key.PublicKey) engine = clique.New(params.AllCliqueProtocolChanges.Clique, testdb) ) - genspec := &Genesis{ + genspec = &Genesis{ + Config: params.AllCliqueProtocolChanges, ExtraData: make([]byte, 32+common.AddressLength+crypto.SignatureLength), Alloc: map[common.Address]GenesisAccount{ addr: {Balance: big.NewInt(1)}, @@ -133,11 +134,11 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { config := *params.AllCliqueProtocolChanges config.TerminalTotalDifficulty = big.NewInt(int64(td)) postBlocks, _ = GenerateChain(&config, preBlocks[len(preBlocks)-1], genEngine, testdb, 8, nil) - chainConfig = &config runEngine = beacon.New(engine) + genspec.Config = &config } else { - gspec := &Genesis{Config: params.TestChainConfig} - genesis := gspec.MustCommit(testdb) + genspec = &Genesis{Config: params.TestChainConfig} + genesis := genspec.MustCommit(testdb) genEngine := beacon.New(ethash.NewFaker()) preBlocks, _ = GenerateChain(params.TestChainConfig, genesis, genEngine, testdb, 8, nil) @@ -150,8 +151,8 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { config.TerminalTotalDifficulty = big.NewInt(int64(td)) postBlocks, _ = GenerateChain(params.TestChainConfig, preBlocks[len(preBlocks)-1], genEngine, testdb, 8, nil) - chainConfig = &config runEngine = beacon.New(ethash.NewFaker()) + genspec.Config = &config } preHeaders := make([]*types.Header, len(preBlocks)) @@ -169,7 +170,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { t.Logf("Log header after the merging %d: %v", block.NumberU64(), string(blob)) } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(testdb, nil, chainConfig, runEngine, vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, genspec, nil, runEngine, vm.Config{}, nil, nil) defer chain.Stop() // Verify the blocks before the merging @@ -280,11 +281,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { var results <-chan error if valid { - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } else { - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, gspec, nil, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } @@ -347,7 +348,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { defer runtime.GOMAXPROCS(old) // Start the verifications and immediately abort - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, gspec, nil, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil) defer chain.Stop() abort, results := chain.engine.VerifyHeaders(chain, headers, seals) diff --git a/core/blockchain.go b/core/blockchain.go index a98c3b4dbeb3..f588cc50bd6f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -23,6 +23,7 @@ import ( "io" "math/big" "sort" + "strings" "sync" "sync/atomic" "time" @@ -218,7 +219,7 @@ type BlockChain struct { // NewBlockChain returns a fully initialised block chain using information // available in the database. It initialises the default Ethereum Validator // and Processor. -func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64) (*BlockChain, error) { +func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis, overrides *ChainOverrides, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64) (*BlockChain, error) { if cacheConfig == nil { cacheConfig = defaultCacheConfig } @@ -229,6 +230,21 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par txLookupCache, _ := lru.New(txLookupCacheLimit) futureBlocks, _ := lru.New(maxFutureBlocks) + // Setup the genesis block, commit the provided genesis specification + // to database if the genesis block is not present yet, or load the + // stored one from database. + chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, genesis, overrides) + if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { + return nil, genesisErr + } + log.Info("") + log.Info(strings.Repeat("-", 153)) + for _, line := range strings.Split(chainConfig.String(), "\n") { + log.Info(line) + } + log.Info(strings.Repeat("-", 153)) + log.Info("") + bc := &BlockChain{ chainConfig: chainConfig, cacheConfig: cacheConfig, @@ -409,6 +425,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par triedb.SaveCachePeriodically(bc.cacheConfig.TrieCleanJournal, bc.cacheConfig.TrieCleanRejournal, bc.quit) }() } + // Rewind the chain in case of an incompatible config upgrade. + if compat, ok := genesisErr.(*params.ConfigCompatError); ok { + log.Warn("Rewinding chain to upgrade configuration", "err", compat) + bc.SetHead(compat.RewindTo) + rawdb.WriteChainConfig(db, genesisHash, chainConfig) + } return bc, nil } diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index feed8a177789..04154158c9d9 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1764,7 +1764,11 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { // Initialize a fresh chain var ( - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec = &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.AllEthashProtocolChanges, + } + genesis = gspec.MustCommit(db) engine = ethash.NewFullFaker() config = &CacheConfig{ TrieCleanLimit: 256, @@ -1778,7 +1782,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { config.SnapshotLimit = 256 config.SnapshotWait = true } - chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -1831,7 +1835,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { } defer db.Close() - newChain, err := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + newChain, err := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -1888,7 +1892,11 @@ func TestIssue23496(t *testing.T) { // Initialize a fresh chain var ( - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec = &Genesis{ + Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), + } + genesis = gspec.MustCommit(db) engine = ethash.NewFullFaker() config = &CacheConfig{ TrieCleanLimit: 256, @@ -1898,7 +1906,7 @@ func TestIssue23496(t *testing.T) { SnapshotWait: true, } ) - chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -1942,7 +1950,7 @@ func TestIssue23496(t *testing.T) { } defer db.Close() - chain, err = NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + chain, err = NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index d8103b5b5c50..c5df7949ef6c 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -1964,7 +1964,11 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { // Initialize a fresh chain var ( - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec = &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.AllEthashProtocolChanges, + } + genesis = gspec.MustCommit(db) engine = ethash.NewFullFaker() config = &CacheConfig{ TrieCleanLimit: 256, @@ -1977,7 +1981,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { config.SnapshotLimit = 256 config.SnapshotWait = true } - chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index 189eee59a009..01a88d7a3c7d 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -54,6 +54,7 @@ type snapshotTestBasic struct { db ethdb.Database gendb ethdb.Database engine consensus.Engine + gspec *Genesis } func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Block) { @@ -66,7 +67,11 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo } // Initialize a fresh chain var ( - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec = &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.AllEthashProtocolChanges, + } + genesis = gspec.MustCommit(db) engine = ethash.NewFullFaker() gendb = rawdb.NewMemoryDatabase() @@ -75,7 +80,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo // will happen during the block insertion. cacheConfig = defaultCacheConfig ) - chain, err := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -118,6 +123,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo basic.db = db basic.gendb = gendb basic.engine = engine + basic.gspec = gspec return chain, blocks } @@ -219,7 +225,7 @@ func (snaptest *snapshotTest) test(t *testing.T) { // Restart the chain normally chain.Stop() - newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -255,13 +261,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { // the crash, we do restart twice here: one after the crash and one // after the normal stop. It's used to ensure the broken snapshot // can be detected all the time. - newchain, err := NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(newdb, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } newchain.Stop() - newchain, err = NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = NewBlockChain(newdb, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -297,7 +303,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, } - newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -305,7 +311,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { newchain.Stop() // Restart the chain with enabling the snapshot - newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -333,7 +339,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) { chain.SetHead(snaptest.setHead) chain.Stop() - newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -368,7 +374,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, } - newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -384,13 +390,13 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { SnapshotLimit: 256, SnapshotWait: false, // Don't wait rebuild } - _, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + _, err = NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } // Simulate the blockchain crash. - newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 44256f6187da..713ac2809a2a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -53,12 +53,16 @@ var ( // header only chain. func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) { var ( - db = rawdb.NewMemoryDatabase() - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + db = rawdb.NewMemoryDatabase() + gspec = &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.AllEthashProtocolChanges, + } + genesis = gspec.MustCommit(db) ) // Initialize a fresh chain with only a genesis block - blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) // Create and inject the requested chain if n == 0 { return db, blockchain, nil @@ -654,7 +658,11 @@ func testReorgBadHashes(t *testing.T, full bool) { blockchain.Stop() // Create a new BlockChain and check that it rolled back the state. - ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + gspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.AllEthashProtocolChanges, + } + ncm, err := NewBlockChain(blockchain.db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } @@ -767,7 +775,7 @@ func TestFastVsFullChains(t *testing.T) { // Import the chain as an archive node for the comparison baseline archiveDb := rawdb.NewMemoryDatabase() gspec.MustCommit(archiveDb) - archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + archive, _ := NewBlockChain(archiveDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { @@ -776,7 +784,7 @@ func TestFastVsFullChains(t *testing.T) { // Fast import the chain as a non-archive node to test fastDb := rawdb.NewMemoryDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -797,7 +805,7 @@ func TestFastVsFullChains(t *testing.T) { } defer ancientDb.Close() gspec.MustCommit(ancientDb) - ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { @@ -915,7 +923,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { archiveCaching := *defaultCacheConfig archiveCaching.TrieDirtyDisabled = true - archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } @@ -928,7 +936,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb := makeDb() defer fastDb.Close() - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -948,7 +956,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a ancient-first node and ensure all pointers are updated ancientDb := makeDb() defer ancientDb.Close() - ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { @@ -967,7 +975,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a light node and ensure all pointers are updated lightDb := makeDb() defer lightDb.Close() - light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + light, _ := NewBlockChain(lightDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -1036,7 +1044,7 @@ func TestChainTxReorgs(t *testing.T) { } }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -1106,7 +1114,7 @@ func TestLogReorgs(t *testing.T) { signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) @@ -1159,7 +1167,7 @@ func TestLogRebirth(t *testing.T) { genesis = gspec.MustCommit(db) signer = types.LatestSigner(gspec.Config) engine = ethash.NewFaker() - blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) ) defer blockchain.Stop() @@ -1222,7 +1230,7 @@ func TestSideLogRebirth(t *testing.T) { gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} genesis = gspec.MustCommit(db) signer = types.LatestSigner(gspec.Config) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ) defer blockchain.Stop() @@ -1296,7 +1304,7 @@ func TestReorgSideEvent(t *testing.T) { signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {}) @@ -1427,7 +1435,7 @@ func TestEIP155Transition(t *testing.T) { genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { @@ -1535,7 +1543,7 @@ func TestEIP161AccountRemoval(t *testing.T) { } genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) { @@ -1592,7 +1600,11 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { engine := ethash.NewFaker() db := rawdb.NewMemoryDatabase() - genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec := &Genesis{ + Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), + } + genesis := gspec.MustCommit(db) blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // Generate a bunch of fork blocks, each side forking from the canonical chain @@ -1610,7 +1622,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1637,7 +1649,11 @@ func TestTrieForkGC(t *testing.T) { engine := ethash.NewFaker() db := rawdb.NewMemoryDatabase() - genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.TestChainConfig, + } + genesis := gspec.MustCommit(db) blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // Generate a bunch of fork blocks, each side forking from the canonical chain @@ -1652,9 +1668,9 @@ func TestTrieForkGC(t *testing.T) { } // Import the canonical and fork chain side by side, forcing the trie cache to cache both diskdb := rawdb.NewMemoryDatabase() - (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) + gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1683,7 +1699,11 @@ func TestLargeReorgTrieGC(t *testing.T) { engine := ethash.NewFaker() db := rawdb.NewMemoryDatabase() - genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.TestChainConfig, + } + genesis := gspec.MustCommit(db) shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) @@ -1691,9 +1711,9 @@ func TestLargeReorgTrieGC(t *testing.T) { // Import the shared chain and the original canonical one diskdb := rawdb.NewMemoryDatabase() - (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) + gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1751,7 +1771,7 @@ func TestBlockchainRecovery(t *testing.T) { } defer ancientDb.Close() gspec.MustCommit(ancientDb) - ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -1771,7 +1791,7 @@ func TestBlockchainRecovery(t *testing.T) { rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash()) // Reopen broken blockchain again - ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ = NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() if num := ancient.CurrentBlock().NumberU64(); num != 0 { t.Errorf("head block mismatch: have #%v, want #%v", num, 0) @@ -1812,15 +1832,15 @@ func TestInsertReceiptChainRollback(t *testing.T) { } // Set up a BlockChain that uses the ancient store. - frdir := t.TempDir() - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } defer ancientDb.Close() + gspec := Genesis{Config: params.AllEthashProtocolChanges} gspec.MustCommit(ancientDb) - ancientChain, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancientChain, _ := NewBlockChain(ancientDb, nil, &gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancientChain.Stop() // Import the canonical header chain. @@ -1868,7 +1888,11 @@ func TestLowDiffLongChain(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() db := rawdb.NewMemoryDatabase() - genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.TestChainConfig, + } + genesis := gspec.MustCommit(db) // We must use a pretty long chain to ensure that the fork doesn't overtake us // until after at least 128 blocks post tip @@ -1879,9 +1903,9 @@ func TestLowDiffLongChain(t *testing.T) { // Import the canonical chain diskdb := rawdb.NewMemoryDatabase() - (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) + gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1947,7 +1971,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Generate and import the canonical chain diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, &chainConfig, runEngine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, runEngine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2063,7 +2087,11 @@ func testInsertKnownChainData(t *testing.T, typ string) { engine := ethash.NewFaker() db := rawdb.NewMemoryDatabase() - genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec := &Genesis{ + Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), + } + genesis := gspec.MustCommit(db) blocks, receipts := GenerateChain(params.TestChainConfig, genesis, engine, db, 32, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // A longer chain but total difficulty is lower. @@ -2074,15 +2102,14 @@ func testInsertKnownChainData(t *testing.T, typ string) { b.OffsetTime(-9) // A higher difficulty }) // Import the shared chain and the original canonical one - dir := t.TempDir() - chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false) + chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } - (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb) + gspec.MustCommit(chaindb) defer chaindb.Close() - chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2202,8 +2229,12 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i // Copy the TestChainConfig so we can modify it during tests chainConfig := *params.TestChainConfig var ( - db = rawdb.NewMemoryDatabase() - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: &chainConfig}).MustCommit(db) + db = rawdb.NewMemoryDatabase() + gspec = &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: &chainConfig, + } + genesis = gspec.MustCommit(db) runMerger = consensus.NewMerger(db) runEngine = beacon.New(ethash.NewFaker()) genEngine = beacon.New(ethash.NewFaker()) @@ -2242,7 +2273,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb) defer chaindb.Close() - chain, err := NewBlockChain(chaindb, nil, &chainConfig, runEngine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, nil, gspec, nil, runEngine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2350,7 +2381,11 @@ func getLongAndShortChains() (bc *BlockChain, longChain []*types.Block, heavyCha // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() db := rawdb.NewMemoryDatabase() - genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.TestChainConfig, + } + genesis := gspec.MustCommit(db) // Generate and import the canonical chain, // Offset the time, to keep the difficulty low @@ -2358,9 +2393,9 @@ func getLongAndShortChains() (bc *BlockChain, longChain []*types.Block, heavyCha b.SetCoinbase(common.Address{1}) }) diskdb := rawdb.NewMemoryDatabase() - (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) + gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) } @@ -2390,12 +2425,12 @@ func getLongAndShortChains() (bc *BlockChain, longChain []*types.Block, heavyCha shorterTd.Add(shorterTd, b.Difficulty()) } if shorterTd.Cmp(longerTd) <= 0 { - return nil, nil, nil, fmt.Errorf("Test is moot, heavyChain td (%v) must be larger than canon td (%v)", shorterTd, longerTd) + return nil, nil, nil, fmt.Errorf("test is moot, heavyChain td (%v) must be larger than canon td (%v)", shorterTd, longerTd) } longerNum := longChain[len(longChain)-1].NumberU64() shorterNum := heavyChain[len(heavyChain)-1].NumberU64() if shorterNum >= longerNum { - return nil, nil, nil, fmt.Errorf("Test is moot, heavyChain num (%v) must be lower than canon num (%v)", shorterNum, longerNum) + return nil, nil, nil, fmt.Errorf("test is moot, heavyChain num (%v) must be lower than canon num (%v)", shorterNum, longerNum) } return chain, longChain, heavyChain, nil } @@ -2549,7 +2584,7 @@ func TestTransactionIndices(t *testing.T) { // Import all blocks into ancient db l := uint64(0) - chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2575,7 +2610,7 @@ func TestTransactionIndices(t *testing.T) { } gspec.MustCommit(ancientDb) l := l - chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err = NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2601,7 +2636,7 @@ func TestTransactionIndices(t *testing.T) { tails := []uint64{0, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */, 69 /* 132 - 64 + 1 */, 0} for i, l := range limit { l := l - chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err = NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2676,7 +2711,7 @@ func TestSkipStaleTxIndicesInSnapSync(t *testing.T) { // Import all blocks into ancient db, only HEAD-32 indices are kept. l := uint64(32) - chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2702,7 +2737,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) bankFunds = big.NewInt(100000000000000000) - gspec = Genesis{ + gspec = &Genesis{ Config: params.TestChainConfig, Alloc: GenesisAlloc{ testBankAddress: {Balance: bankFunds}, @@ -2740,7 +2775,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { b.Fatalf("failed to create tester chain: %v", err) } @@ -2815,14 +2850,18 @@ func TestSideImportPrunedBlocks(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() db := rawdb.NewMemoryDatabase() - genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + gspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.TestChainConfig, + } + genesis := gspec.MustCommit(db) // Generate and import the canonical chain blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil) diskdb := rawdb.NewMemoryDatabase() - (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + gspec.MustCommit(diskdb) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2916,7 +2955,7 @@ func TestDeleteCreateRevert(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3027,7 +3066,7 @@ func TestDeleteRecreateSlots(t *testing.T) { // Import the canonical chain diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{ Debug: true, Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3107,7 +3146,7 @@ func TestDeleteRecreateAccount(t *testing.T) { // Import the canonical chain diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{ Debug: true, Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3280,7 +3319,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { // Import the canonical chain diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3414,7 +3453,7 @@ func TestInitThenFailCreateContract(t *testing.T) { // Import the canonical chain diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3504,7 +3543,7 @@ func TestEIP2718Transition(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3598,7 +3637,7 @@ func TestEIP1559Transition(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3705,7 +3744,7 @@ func TestSetCanonical(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3811,7 +3850,7 @@ func TestCanonicalHashMarker(t *testing.T) { // Initialize test chain diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 85a029f7c757..166ac3f227fc 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -79,7 +79,7 @@ func ExampleGenerateChain() { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/dao_test.go b/core/dao_test.go index c9c765a3832a..8089b5470aaf 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -30,32 +30,45 @@ import ( // blocks based on their extradata fields. func TestDAOForkRangeExtradata(t *testing.T) { forkBlock := big.NewInt(32) + chainConfig := *params.NonActivatedConfig + chainConfig.HomesteadBlock = big.NewInt(0) // Generate a common prefix for both pro-forkers and non-forkers db := rawdb.NewMemoryDatabase() - gspec := &Genesis{BaseFee: big.NewInt(params.InitialBaseFee)} + gspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: &chainConfig, + } genesis := gspec.MustCommit(db) - prefix, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) + prefix, _ := GenerateChain(&chainConfig, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) // Create the concurrent, conflicting two nodes proDb := rawdb.NewMemoryDatabase() - gspec.MustCommit(proDb) - - proConf := *params.TestChainConfig + proConf := *params.NonActivatedConfig + proConf.HomesteadBlock = big.NewInt(0) proConf.DAOForkBlock = forkBlock proConf.DAOForkSupport = true + progspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: &proConf, + } + gspec.MustCommit(proDb) - proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil) + proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer proBc.Stop() conDb := rawdb.NewMemoryDatabase() - gspec.MustCommit(conDb) - - conConf := *params.TestChainConfig + conConf := *params.NonActivatedConfig + conConf.HomesteadBlock = big.NewInt(0) conConf.DAOForkBlock = forkBlock conConf.DAOForkSupport = false + congspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: &conConf, + } + gspec.MustCommit(conDb) - conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil) + conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer conBc.Stop() if _, err := proBc.InsertChain(prefix); err != nil { @@ -68,8 +81,8 @@ func TestDAOForkRangeExtradata(t *testing.T) { for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { // Create a pro-fork block, and try to feed into the no-fork chain db = rawdb.NewMemoryDatabase() - gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil) + congspec.MustCommit(db) + bc, _ := NewBlockChain(db, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -93,8 +106,8 @@ func TestDAOForkRangeExtradata(t *testing.T) { } // Create a no-fork block, and try to feed into the pro-fork chain db = rawdb.NewMemoryDatabase() - gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil) + progspec.MustCommit(db) + bc, _ = NewBlockChain(db, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) @@ -119,8 +132,8 @@ func TestDAOForkRangeExtradata(t *testing.T) { } // Verify that contra-forkers accept pro-fork extra-datas after forking finishes db = rawdb.NewMemoryDatabase() - gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil) + congspec.MustCommit(db) + bc, _ := NewBlockChain(db, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -139,8 +152,8 @@ func TestDAOForkRangeExtradata(t *testing.T) { } // Verify that pro-forkers accept contra-fork extra-datas after forking finishes db = rawdb.NewMemoryDatabase() - gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil) + progspec.MustCommit(db) + bc, _ = NewBlockChain(db, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) diff --git a/core/genesis.go b/core/genesis.go index c3b5d0b57094..5b5b9c72a1e7 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -211,7 +211,6 @@ func (h *storageJSON) UnmarshalText(text []byte) error { } offset := len(h) - len(text)/2 // pad on the left if _, err := hex.Decode(h[offset:], text); err != nil { - fmt.Println(err) return fmt.Errorf("invalid hex storage key/value %q", text) } return nil @@ -231,6 +230,12 @@ func (e *GenesisMismatchError) Error() string { return fmt.Sprintf("database contains incompatible genesis (have %x, new %x)", e.Stored, e.New) } +// ChainOverrides contains the changes to chain config. +type ChainOverrides struct { + OverrideTerminalTotalDifficulty *big.Int + OverrideTerminalTotalDifficultyPassed *bool +} + // SetupGenesisBlock writes or updates the genesis block in db. // The block that will be used is: // @@ -245,21 +250,21 @@ func (e *GenesisMismatchError) Error() string { // // The returned chain configuration is never nil. func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { - return SetupGenesisBlockWithOverride(db, genesis, nil, nil) + return SetupGenesisBlockWithOverride(db, genesis, nil) } -func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, overrideTerminalTotalDifficulty *big.Int, overrideTerminalTotalDifficultyPassed *bool) (*params.ChainConfig, common.Hash, error) { +func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, error) { if genesis != nil && genesis.Config == nil { return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig } applyOverrides := func(config *params.ChainConfig) { if config != nil { - if overrideTerminalTotalDifficulty != nil { - config.TerminalTotalDifficulty = overrideTerminalTotalDifficulty + if overrides != nil && overrides.OverrideTerminalTotalDifficulty != nil { + config.TerminalTotalDifficulty = overrides.OverrideTerminalTotalDifficulty } - if overrideTerminalTotalDifficultyPassed != nil { - config.TerminalTotalDifficultyPassed = *overrideTerminalTotalDifficultyPassed + if overrides != nil && overrides.OverrideTerminalTotalDifficultyPassed != nil { + config.TerminalTotalDifficultyPassed = *overrides.OverrideTerminalTotalDifficultyPassed } } } @@ -341,6 +346,42 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override return newcfg, stored, nil } +// LoadCliqueConfig loads the stored clique config if the chain config +// is already present in database, otherwise, return the config in the +// provided genesis specification. Note the returned clique config can +// be nil if we are not in the clique network. +func LoadCliqueConfig(db ethdb.Database, genesis *Genesis) (*params.CliqueConfig, error) { + // Load the stored chain config from the database. It can be nil + // in case the database is empty. Notably, we only care about the + // chain config corresponds to the canonical chain. + stored := rawdb.ReadCanonicalHash(db, 0) + if stored != (common.Hash{}) { + storedcfg := rawdb.ReadChainConfig(db, stored) + if storedcfg != nil { + return storedcfg.Clique, nil + } + } + // Load the clique config from the provided genesis specification. + if genesis != nil { + // Reject invalid genesis spec without valid chain config + if genesis.Config == nil { + return nil, errGenesisNoConfig + } + // If the canonical genesis header is present, but the chain + // config is missing(initialize the empty leveldb with an + // external ancient chain segment), ensure the provided genesis + // is matched. + if stored != (common.Hash{}) && genesis.ToBlock().Hash() != stored { + return nil, &GenesisMismatchError{stored, genesis.ToBlock().Hash()} + } + return genesis.Config.Clique, nil + } + // There is no stored chain config and no new config provided, + // In this case the default chain config(mainnet) will be used, + // namely ethash is the specified consensus engine, return nil. + return nil, nil +} + func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { switch { case g != nil: diff --git a/core/genesis_test.go b/core/genesis_test.go index ba3423e32a08..a7d04f53fe23 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -117,7 +117,7 @@ func TestSetupGenesis(t *testing.T) { // Advance to block #4, past the homestead transition block of customg. genesis := oldcustomg.MustCommit(db) - bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(db, nil, &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) defer bc.Stop() blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index aa8e4bebf9d4..42faa28d058f 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -92,7 +92,7 @@ func TestStateProcessorErrors(t *testing.T) { }, } genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ) defer blockchain.Stop() bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) @@ -233,7 +233,7 @@ func TestStateProcessorErrors(t *testing.T) { }, } genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ) defer blockchain.Stop() for i, tt := range []struct { @@ -273,7 +273,7 @@ func TestStateProcessorErrors(t *testing.T) { }, } genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ) defer blockchain.Stop() for i, tt := range []struct { diff --git a/eth/backend.go b/eth/backend.go index 778207636344..dca96e4f9d6c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -22,7 +22,6 @@ import ( "fmt" "math/big" "runtime" - "strings" "sync" "sync/atomic" @@ -126,38 +125,30 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) - // Transfer mining-related config to the ethash config. - ethashConfig := config.Ethash - ethashConfig.NotifyFull = config.Miner.NotifyFull - // Assemble the Ethereum object chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/", false) if err != nil { return nil, err } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideTerminalTotalDifficulty, config.OverrideTerminalTotalDifficultyPassed) - if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { - return nil, genesisErr - } - log.Info("") - log.Info(strings.Repeat("-", 153)) - for _, line := range strings.Split(chainConfig.String(), "\n") { - log.Info(line) - } - log.Info(strings.Repeat("-", 153)) - log.Info("") - if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil { log.Error("Failed to recover state", "error", err) } - merger := consensus.NewMerger(chainDb) + // Transfer mining-related config to the ethash config. + ethashConfig := config.Ethash + ethashConfig.NotifyFull = config.Miner.NotifyFull + cliqueConfig, err := core.LoadCliqueConfig(chainDb, config.Genesis) + if err != nil { + return nil, err + } + engine := ethconfig.CreateConsensusEngine(stack, ðashConfig, cliqueConfig, config.Miner.Notify, config.Miner.Noverify, chainDb) + eth := &Ethereum{ config: config, - merger: merger, + merger: consensus.NewMerger(chainDb), chainDb: chainDb, eventMux: stack.EventMux(), accountManager: stack.AccountManager(), - engine: ethconfig.CreateConsensusEngine(stack, chainConfig, ðashConfig, config.Miner.Notify, config.Miner.Noverify, chainDb), + engine: engine, closeBloomHandler: make(chan struct{}), networkID: config.NetworkId, gasPrice: config.Miner.GasPrice, @@ -201,34 +192,36 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { Preimages: config.Preimages, } ) - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) + // Override the chain config with provided settings. + var overrides core.ChainOverrides + if config.OverrideTerminalTotalDifficulty != nil { + overrides.OverrideTerminalTotalDifficulty = config.OverrideTerminalTotalDifficulty + } + if config.OverrideTerminalTotalDifficultyPassed != nil { + overrides.OverrideTerminalTotalDifficultyPassed = config.OverrideTerminalTotalDifficultyPassed + } + eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) if err != nil { return nil, err } - // Rewind the chain in case of an incompatible config upgrade. - if compat, ok := genesisErr.(*params.ConfigCompatError); ok { - log.Warn("Rewinding chain to upgrade configuration", "err", compat) - eth.blockchain.SetHead(compat.RewindTo) - rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) - } eth.bloomIndexer.Start(eth.blockchain) if config.TxPool.Journal != "" { config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) } - eth.txPool = core.NewTxPool(config.TxPool, chainConfig, eth.blockchain) + eth.txPool = core.NewTxPool(config.TxPool, eth.blockchain.Config(), eth.blockchain) // Permit the downloader to use the trie cache allowance during fast sync cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit checkpoint := config.Checkpoint if checkpoint == nil { - checkpoint = params.TrustedCheckpoints[genesisHash] + checkpoint = params.TrustedCheckpoints[eth.blockchain.Genesis().Hash()] } if eth.handler, err = newHandler(&handlerConfig{ Database: chainDb, Chain: eth.blockchain, TxPool: eth.txPool, - Merger: merger, + Merger: eth.merger, Network: config.NetworkId, Sync: config.SyncMode, BloomCache: uint64(cacheLimit), @@ -239,7 +232,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { return nil, err } - eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock) + eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine, eth.isLocalBlock) eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil} diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 450ed61efc5d..eb72f0fc3cc6 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -68,13 +68,14 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester { t.Cleanup(func() { db.Close() }) - gspec := core.Genesis{ + gspec := &core.Genesis{ + Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } gspec.MustCommit(db) - chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { panic(err) } diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 785da40b5989..1c96681e2f5b 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -39,6 +39,7 @@ var ( testDB = rawdb.NewMemoryDatabase() testGspec = core.Genesis{ + Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } @@ -219,7 +220,7 @@ func newTestBlockchain(blocks []*types.Block) *core.BlockChain { db := rawdb.NewMemoryDatabase() testGspec.MustCommit(db) - chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, nil, &testGspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { panic(err) } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 5690366421dc..a897294175ea 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -217,13 +217,13 @@ type Config struct { } // CreateConsensusEngine creates a consensus engine for the given chain configuration. -func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine { +func CreateConsensusEngine(stack *node.Node, ethashConfig *ethash.Config, cliqueConfig *params.CliqueConfig, notify []string, noverify bool, db ethdb.Database) consensus.Engine { // If proof-of-authority is requested, set it up var engine consensus.Engine - if chainConfig.Clique != nil { - engine = clique.New(chainConfig.Clique, db) + if cliqueConfig != nil { + engine = clique.New(cliqueConfig, db) } else { - switch config.PowMode { + switch ethashConfig.PowMode { case ethash.ModeFake: log.Warn("Ethash used in fake mode") case ethash.ModeTest: @@ -232,16 +232,16 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, co log.Warn("Ethash used in shared mode") } engine = ethash.New(ethash.Config{ - PowMode: config.PowMode, - CacheDir: stack.ResolvePath(config.CacheDir), - CachesInMem: config.CachesInMem, - CachesOnDisk: config.CachesOnDisk, - CachesLockMmap: config.CachesLockMmap, - DatasetDir: config.DatasetDir, - DatasetsInMem: config.DatasetsInMem, - DatasetsOnDisk: config.DatasetsOnDisk, - DatasetsLockMmap: config.DatasetsLockMmap, - NotifyFull: config.NotifyFull, + PowMode: ethashConfig.PowMode, + CacheDir: stack.ResolvePath(ethashConfig.CacheDir), + CachesInMem: ethashConfig.CachesInMem, + CachesOnDisk: ethashConfig.CachesOnDisk, + CachesLockMmap: ethashConfig.CachesLockMmap, + DatasetDir: ethashConfig.DatasetDir, + DatasetsInMem: ethashConfig.DatasetsInMem, + DatasetsOnDisk: ethashConfig.DatasetsOnDisk, + DatasetsLockMmap: ethashConfig.DatasetsLockMmap, + NotifyFull: ethashConfig.NotifyFull, }, notify, noverify) engine.(*ethash.Ethash).SetThreads(-1) // Disable CPU mining } diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index d405188f8194..5830312fd139 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -162,7 +162,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke // Construct testing chain diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec.Config, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create local chain, %v", err) } diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 453bc5e98e31..9c2fcd36f7ab 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -105,8 +105,8 @@ func testForkIDSplit(t *testing.T, protocol uint) { genesisNoFork = gspecNoFork.MustCommit(dbNoFork) genesisProFork = gspecProFork.MustCommit(dbProFork) - chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil) - chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil) + chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, gspecNoFork, nil, engine, vm.Config{}, nil, nil) + chainProFork, _ = core.NewBlockChain(dbProFork, nil, gspecProFork, nil, engine, vm.Config{}, nil, nil) blocksNoFork, _ = core.GenerateChain(configNoFork, genesisNoFork, engine, dbNoFork, 2, nil) blocksProFork, _ = core.GenerateChain(configProFork, genesisProFork, engine, dbProFork, 2, nil) diff --git a/eth/handler_test.go b/eth/handler_test.go index d967b6df935e..044130f40f8c 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -133,12 +133,13 @@ func newTestHandler() *testHandler { func newTestHandlerWithBlocks(blocks int) *testHandler { // Create a database pre-initialize with a genesis block db := rawdb.NewMemoryDatabase() - (&core.Genesis{ + gspec := &core.Genesis{ Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}}, - }).MustCommit(db) + } + gspec.MustCommit(db) - chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, nil) if _, err := chain.InsertChain(bs); err != nil { diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 2707a420bc6a..ea2edc4a9164 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -63,12 +63,13 @@ func newTestBackend(blocks int) *testBackend { func newTestBackendWithGenerator(blocks int, generator func(int, *core.BlockGen)) *testBackend { // Create a database pre-initialize with a genesis block db := rawdb.NewMemoryDatabase() - (&core.Genesis{ + gspec := &core.Genesis{ Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, - }).MustCommit(db) + } + gspec.MustCommit(db) - chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator) if _, err := chain.InsertChain(bs); err != nil { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index bc12b9275160..b75b6793592c 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -82,7 +82,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i SnapshotLimit: 0, TrieDirtyDisabled: true, // Archive mode } - chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -182,11 +182,14 @@ func TestTraceCall(t *testing.T) { // Initialize test accounts accounts := newAccounts(3) - genesis := &core.Genesis{Alloc: core.GenesisAlloc{ - accounts[0].addr: {Balance: big.NewInt(params.Ether)}, - accounts[1].addr: {Balance: big.NewInt(params.Ether)}, - accounts[2].addr: {Balance: big.NewInt(params.Ether)}, - }} + genesis := &core.Genesis{ + Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(params.Ether)}, + accounts[1].addr: {Balance: big.NewInt(params.Ether)}, + accounts[2].addr: {Balance: big.NewInt(params.Ether)}, + }, + } genBlocks := 10 signer := types.HomesteadSigner{} api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { @@ -312,10 +315,13 @@ func TestTraceTransaction(t *testing.T) { // Initialize test accounts accounts := newAccounts(2) - genesis := &core.Genesis{Alloc: core.GenesisAlloc{ - accounts[0].addr: {Balance: big.NewInt(params.Ether)}, - accounts[1].addr: {Balance: big.NewInt(params.Ether)}, - }} + genesis := &core.Genesis{ + Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(params.Ether)}, + accounts[1].addr: {Balance: big.NewInt(params.Ether)}, + }, + } target := common.Hash{} signer := types.HomesteadSigner{} api := NewAPI(newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) { @@ -349,11 +355,14 @@ func TestTraceBlock(t *testing.T) { // Initialize test accounts accounts := newAccounts(3) - genesis := &core.Genesis{Alloc: core.GenesisAlloc{ - accounts[0].addr: {Balance: big.NewInt(params.Ether)}, - accounts[1].addr: {Balance: big.NewInt(params.Ether)}, - accounts[2].addr: {Balance: big.NewInt(params.Ether)}, - }} + genesis := &core.Genesis{ + Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(params.Ether)}, + accounts[1].addr: {Balance: big.NewInt(params.Ether)}, + accounts[2].addr: {Balance: big.NewInt(params.Ether)}, + }, + } genBlocks := 10 signer := types.HomesteadSigner{} api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { @@ -424,11 +433,14 @@ func TestTracingWithOverrides(t *testing.T) { t.Parallel() // Initialize test accounts accounts := newAccounts(3) - genesis := &core.Genesis{Alloc: core.GenesisAlloc{ - accounts[0].addr: {Balance: big.NewInt(params.Ether)}, - accounts[1].addr: {Balance: big.NewInt(params.Ether)}, - accounts[2].addr: {Balance: big.NewInt(params.Ether)}, - }} + genesis := &core.Genesis{ + Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(params.Ether)}, + accounts[1].addr: {Balance: big.NewInt(params.Ether)}, + accounts[2].addr: {Balance: big.NewInt(params.Ether)}, + }, + } genBlocks := 10 signer := types.HomesteadSigner{} api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { diff --git a/les/client.go b/les/client.go index 6504fe2af8f6..6e6beeb0001a 100644 --- a/les/client.go +++ b/les/client.go @@ -92,7 +92,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { if err != nil { return nil, err } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideTerminalTotalDifficulty, config.OverrideTerminalTotalDifficultyPassed) + var overrides core.ChainOverrides + if config.OverrideTerminalTotalDifficulty != nil { + overrides.OverrideTerminalTotalDifficulty = config.OverrideTerminalTotalDifficulty + } + if config.OverrideTerminalTotalDifficultyPassed != nil { + overrides.OverrideTerminalTotalDifficultyPassed = config.OverrideTerminalTotalDifficultyPassed + } + chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, &overrides) if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { return nil, genesisErr } @@ -121,7 +128,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { reqDist: newRequestDistributor(peers, &mclock.System{}), accountManager: stack.AccountManager(), merger: merger, - engine: ethconfig.CreateConsensusEngine(stack, chainConfig, &config.Ethash, nil, false, chainDb), + engine: ethconfig.CreateConsensusEngine(stack, &config.Ethash, chainConfig.Clique, nil, false, chainDb), bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations), p2pServer: stack.Server(), diff --git a/light/odr_test.go b/light/odr_test.go index ec109f61f2bf..d08963af6628 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -253,7 +253,8 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { var ( sdb = rawdb.NewMemoryDatabase() ldb = rawdb.NewMemoryDatabase() - gspec = core.Genesis{ + gspec = &core.Genesis{ + Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, BaseFee: big.NewInt(params.InitialBaseFee), } @@ -261,7 +262,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { ) gspec.MustCommit(ldb) // Assemble the test environment - blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil) + blockchain, _ := core.NewBlockChain(sdb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { t.Fatal(err) diff --git a/light/trie_test.go b/light/trie_test.go index 63dd9020f20c..581469c41f49 100644 --- a/light/trie_test.go +++ b/light/trie_test.go @@ -37,14 +37,15 @@ func TestNodeIterator(t *testing.T) { var ( fulldb = rawdb.NewMemoryDatabase() lightdb = rawdb.NewMemoryDatabase() - gspec = core.Genesis{ + gspec = &core.Genesis{ + Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, BaseFee: big.NewInt(params.InitialBaseFee), } genesis = gspec.MustCommit(fulldb) ) gspec.MustCommit(lightdb) - blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil) + blockchain, _ := core.NewBlockChain(fulldb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) diff --git a/light/txpool_test.go b/light/txpool_test.go index cc2651d29ae5..78cac513cbaf 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -83,7 +83,8 @@ func TestTxPool(t *testing.T) { var ( sdb = rawdb.NewMemoryDatabase() ldb = rawdb.NewMemoryDatabase() - gspec = core.Genesis{ + gspec = &core.Genesis{ + Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, BaseFee: big.NewInt(params.InitialBaseFee), } @@ -91,7 +92,7 @@ func TestTxPool(t *testing.T) { ) gspec.MustCommit(ldb) // Assemble the test environment - blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil) + blockchain, _ := core.NewBlockChain(sdb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) diff --git a/miner/miner_test.go b/miner/miner_test.go index 5bf344fd7076..d49c07d964ca 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -256,7 +256,7 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { // Create consensus engine engine := clique.New(chainConfig.Clique, chainDB) // Create Ethereum backend - bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(chainDB, nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("can't create new chain %v", err) } diff --git a/miner/worker_test.go b/miner/worker_test.go index ec5ba67e1c65..3c70b4baafb6 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -136,7 +136,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine } genesis := gspec.MustCommit(db) - chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, &gspec, nil, engine, vm.Config{}, nil, nil) txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) // Generate a small n-block chain and an uncle block for it @@ -236,7 +236,7 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) { // This test chain imports the mined blocks. db2 := rawdb.NewMemoryDatabase() b.genesis.MustCommit(db2) - chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db2, nil, b.genesis, nil, engine, vm.Config{}, nil, nil) defer chain.Stop() // Ignore empty commit here for less noise. diff --git a/params/config.go b/params/config.go index 4d6eec8939bc..d535d230493c 100644 --- a/params/config.go +++ b/params/config.go @@ -278,8 +278,9 @@ var ( // adding flags to the config to also have to set these fields. AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, false, nil, &CliqueConfig{Period: 0, Epoch: 30000}} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(EthashConfig), nil} - TestRules = TestChainConfig.Rules(new(big.Int), false) + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(EthashConfig), nil} + NonActivatedConfig = &ChainConfig{big.NewInt(1), nil, nil, false, nil, common.Hash{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, new(EthashConfig), nil} + TestRules = TestChainConfig.Rules(new(big.Int), false) ) // NetworkNames are user friendly names to use in the chain spec banner. diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 76f0b880b4a8..80f93d7c08b3 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -106,7 +106,8 @@ func (t *BlockTest) Run(snapshotter bool) error { // import pre accounts & construct test genesis block & state root db := rawdb.NewMemoryDatabase() - gblock, err := t.genesis(config).Commit(db) + gspec := t.genesis(config) + gblock, err := gspec.Commit(db) if err != nil { return err } @@ -127,7 +128,7 @@ func (t *BlockTest) Run(snapshotter bool) error { cache.SnapshotLimit = 1 cache.SnapshotWait = true } - chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, cache, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { return err } diff --git a/tests/fuzzers/les/les-fuzzer.go b/tests/fuzzers/les/les-fuzzer.go index 677702208871..bb50da2bd841 100644 --- a/tests/fuzzers/les/les-fuzzer.go +++ b/tests/fuzzers/les/les-fuzzer.go @@ -80,7 +80,7 @@ func makechain() (bc *core.BlockChain, addrHashes, txHashes []common.Hash) { addrHashes = append(addrHashes, crypto.Keccak256Hash(addr[:])) txHashes = append(txHashes, tx.Hash()) }) - bc, _ = core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = core.NewBlockChain(db, nil, &gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if _, err := bc.InsertChain(blocks); err != nil { panic(err) } diff --git a/tests/fuzzers/snap/fuzz_handler.go b/tests/fuzzers/snap/fuzz_handler.go index 1ae61df29dc7..6c370b043e72 100644 --- a/tests/fuzzers/snap/fuzz_handler.go +++ b/tests/fuzzers/snap/fuzz_handler.go @@ -62,7 +62,7 @@ func getChain() *core.BlockChain { } ga[common.BytesToAddress(a)] = acc } - gspec := core.Genesis{ + gspec := &core.Genesis{ Config: params.TestChainConfig, Alloc: ga, } @@ -79,7 +79,7 @@ func getChain() *core.BlockChain { SnapshotWait: true, } trieRoot = blocks[len(blocks)-1].Root() - bc, _ := core.NewBlockChain(db, cacheConf, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := core.NewBlockChain(db, cacheConf, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if _, err := bc.InsertChain(blocks); err != nil { panic(err) } From 362256ebff446e29f9309e48ce4405576c096f62 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 31 Aug 2022 12:28:35 +0200 Subject: [PATCH 198/715] eth/catalyst: adjust eta for themerge (#25601) * eth/catalyst: adjust eta for themerge * squash * squash * eth/catalyst: address review concerns --- eth/catalyst/api.go | 151 ++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 77 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index b159f34e64ba..19dd28e643ca 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -564,16 +564,16 @@ func (api *ConsensusAPI) heartbeat() { var ( offlineLogged time.Time + ttd = api.eth.BlockChain().Config().TerminalTotalDifficulty ) + // If the network is not yet merged/merging, don't bother continuing. + if ttd == nil { + return + } for { // Sleep a bit and retrieve the last known consensus updates time.Sleep(5 * time.Second) - // If the network is not yet merged/merging, don't bother scaring the user - ttd := api.eth.BlockChain().Config().TerminalTotalDifficulty - if ttd == nil { - continue - } api.lastTransitionLock.Lock() lastTransitionUpdate := api.lastTransitionUpdate api.lastTransitionLock.Unlock() @@ -589,89 +589,86 @@ func (api *ConsensusAPI) heartbeat() { // If there have been no updates for the past while, warn the user // that the beacon client is probably offline if api.eth.BlockChain().Config().TerminalTotalDifficultyPassed || api.eth.Merger().TDDReached() { - if time.Since(lastForkchoiceUpdate) > beaconUpdateConsensusTimeout && time.Since(lastNewPayloadUpdate) > beaconUpdateConsensusTimeout { - if time.Since(lastTransitionUpdate) > beaconUpdateExchangeTimeout { - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - if lastTransitionUpdate.IsZero() { - log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!") - } else { - log.Warn("Previously seen beacon client is offline. Please ensure it is operational to follow the chain!") - } - offlineLogged = time.Now() - } - continue - } - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { - log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") - } else { - log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!") - } - offlineLogged = time.Now() - } - continue - } else { + if time.Since(lastForkchoiceUpdate) <= beaconUpdateConsensusTimeout || time.Since(lastNewPayloadUpdate) <= beaconUpdateConsensusTimeout { offlineLogged = time.Time{} + continue } - } else { if time.Since(lastTransitionUpdate) > beaconUpdateExchangeTimeout { if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - // Retrieve the last few blocks and make a rough estimate as - // to when the merge transition should happen - var ( - chain = api.eth.BlockChain() - head = chain.CurrentBlock() - htd = chain.GetTd(head.Hash(), head.NumberU64()) - eta time.Duration - ) - if head.NumberU64() > 0 && htd.Cmp(ttd) < 0 { - // Accumulate the last 64 difficulties to estimate the growth - var diff float64 - - block := head - for i := 0; i < 64; i++ { - diff += float64(block.Difficulty().Uint64()) - if parent := chain.GetBlock(block.ParentHash(), block.NumberU64()-1); parent == nil { - break - } else { - block = parent - } - } - // Estimate an ETA based on the block times and the difficulty growth - growth := diff / float64(head.Time()-block.Time()+1) // +1 to avoid div by zero - if growth > 0 { - if left := new(big.Int).Sub(ttd, htd); left.IsUint64() { - eta = time.Duration(float64(left.Uint64())/growth) * time.Second - } else { - eta = time.Duration(new(big.Int).Div(left, big.NewInt(int64(growth))).Uint64()) * time.Second - } - } - } - var message string - if htd.Cmp(ttd) > 0 { - if lastTransitionUpdate.IsZero() { - message = "Merge already reached, but no beacon client seen. Please launch one to follow the chain!" - } else { - message = "Merge already reached, but previously seen beacon client is offline. Please ensure it is operational to follow the chain!" - } - } else { - if lastTransitionUpdate.IsZero() { - message = "Merge is configured, but no beacon client seen. Please ensure you have one available before the transition arrives!" - } else { - message = "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transition arrives!" - } - } - if eta == 0 { - log.Warn(message) + if lastTransitionUpdate.IsZero() { + log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!") } else { - log.Warn(message, "eta", common.PrettyAge(time.Now().Add(-eta))) // weird hack, but duration formatted doesn't handle days + log.Warn("Previously seen beacon client is offline. Please ensure it is operational to follow the chain!") } offlineLogged = time.Now() } continue + } + if time.Since(offlineLogged) > beaconUpdateWarnFrequency { + if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { + log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") + } else { + log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!") + } + offlineLogged = time.Now() + } + continue + } + if time.Since(lastTransitionUpdate) <= beaconUpdateExchangeTimeout { + offlineLogged = time.Time{} + continue + } + if time.Since(offlineLogged) > beaconUpdateWarnFrequency { + // Retrieve the last few blocks and make a rough estimate as + // to when the merge transition should happen + var ( + chain = api.eth.BlockChain() + head = chain.CurrentHeader() + htd = chain.GetTd(head.Hash(), head.Number.Uint64()) + ) + if htd.Cmp(ttd) >= 0 { + if lastTransitionUpdate.IsZero() { + log.Warn("Merge already reached, but no beacon client seen. Please launch one to follow the chain!") + } else { + log.Warn("Merge already reached, but previously seen beacon client is offline. Please ensure it is operational to follow the chain!") + } + offlineLogged = time.Now() + continue + } + var eta time.Duration + if head.Number.Uint64() > 0 { + // Accumulate the last 64 difficulties to estimate the growth + var ( + deltaDiff uint64 + deltaTime uint64 + current = head + ) + for i := 0; i < 64; i++ { + parent := chain.GetHeader(current.ParentHash, current.Number.Uint64()-1) + if parent == nil { + break + } + deltaDiff += current.Difficulty.Uint64() + deltaTime += current.Time - parent.Time + current = parent + } + // Estimate an ETA based on the block times and the difficulty growth + if deltaTime > 0 { + growth := deltaDiff / deltaTime + left := new(big.Int).Sub(ttd, htd) + eta = time.Duration(new(big.Int).Div(left, new(big.Int).SetUint64(growth)).Uint64()) * time.Second + } + } + message := "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transition arrives!" + if lastTransitionUpdate.IsZero() { + message = "Merge is configured, but no beacon client seen. Please ensure you have one available before the transition arrives!" + } + if eta < time.Second { + log.Warn(message) } else { - offlineLogged = time.Time{} + log.Warn(message, "eta", common.PrettyAge(time.Now().Add(-eta))) // weird hack, but duration formatted doesn't handle days } + offlineLogged = time.Now() } } } From 279afd7947cb915073cddc78bd21eddeb6677910 Mon Sep 17 00:00:00 2001 From: Jakub Freebit <49676311+jakub-freebit@users.noreply.github.com> Date: Wed, 31 Aug 2022 19:31:16 +0900 Subject: [PATCH 199/715] mobile: close node on error (#25643) --- mobile/geth.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mobile/geth.go b/mobile/geth.go index 709b68cbded8..204e29c8be04 100644 --- a/mobile/geth.go +++ b/mobile/geth.go @@ -156,6 +156,7 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { // Parse the user supplied genesis spec if not mainnet genesis = new(core.Genesis) if err := json.Unmarshal([]byte(config.EthereumGenesis), genesis); err != nil { + rawStack.Close() return nil, fmt.Errorf("invalid genesis spec: %v", err) } // If we have the Ropsten testnet, hard code the chain configs too @@ -196,11 +197,13 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { ethConf.DatabaseCache = config.EthereumDatabaseCache lesBackend, err := les.New(rawStack, ðConf) if err != nil { + rawStack.Close() return nil, fmt.Errorf("ethereum init: %v", err) } // If netstats reporting is requested, do it if config.EthereumNetStats != "" { if err := ethstats.New(rawStack, lesBackend.ApiBackend, lesBackend.Engine(), config.EthereumNetStats); err != nil { + rawStack.Close() return nil, fmt.Errorf("netstats init: %v", err) } } From 8cfcb41e57401193a766565f56d2a1c3e318aa62 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Wed, 31 Aug 2022 16:14:53 +0200 Subject: [PATCH 200/715] graphql: return correct logs for tx (#25612) * graphql: fix tx logs * minor * Use optimized search for selecting tx logs --- graphql/graphql.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 97b460c205ce..66c25841db98 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "math/big" + "sort" "strconv" "github.com/ethereum/go-ethereum" @@ -478,13 +479,16 @@ func (t *Transaction) getLogs(ctx context.Context) (*[]*Log, error) { if err != nil { return nil, err } - ret := make([]*Log, 0, len(logs)) - for _, log := range logs { + var ret []*Log + // Select tx logs from all block logs + ix := sort.Search(len(logs), func(i int) bool { return uint64(logs[i].TxIndex) == t.index }) + for ix < len(logs) && uint64(logs[ix].TxIndex) == t.index { ret = append(ret, &Log{ r: t.r, transaction: t, - log: log, + log: logs[ix], }) + ix++ } return &ret, nil } From 3d68bb03c37ac78c6f93c3d4c96ff4b877c83ae6 Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Wed, 31 Aug 2022 10:26:39 -0400 Subject: [PATCH 201/715] trie: fix grammar in comment (#25648) --- trie/database.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trie/database.go b/trie/database.go index b10bbca9bdba..8d426c252347 100644 --- a/trie/database.go +++ b/trie/database.go @@ -163,7 +163,7 @@ func (n *cachedNode) rlp() []byte { // or by regenerating it from the rlp encoded blob. func (n *cachedNode) obj(hash common.Hash) node { if node, ok := n.node.(rawNode); ok { - // The raw-blob format nodes are loaded from either from + // The raw-blob format nodes are loaded either from the // clean cache or the database, they are all in their own // copy and safe to use unsafe decoder. return mustDecodeNodeUnsafe(hash[:], node) From dafa40e7a71947ea68a7e1d2b7575d55ed45fe07 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 31 Aug 2022 17:58:18 +0200 Subject: [PATCH 202/715] eth/protocols/snap: fix problems due to idle-but-busy peers --- eth/protocols/snap/sync.go | 90 +++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index deaa4456e0fd..1455bacbcb88 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -2248,14 +2248,18 @@ func (s *Syncer) OnAccounts(peer SyncPeer, id uint64, hashes []common.Hash, acco // Whether or not the response is valid, we can mark the peer as idle and // notify the scheduler to assign a new task. If the response is invalid, // we'll drop the peer in a bit. + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.peers[peer.ID()]; ok { + s.accountIdlers[peer.ID()] = struct{}{} + } + select { + case s.update <- struct{}{}: + default: + } + }() s.lock.Lock() - if _, ok := s.peers[peer.ID()]; ok { - s.accountIdlers[peer.ID()] = struct{}{} - } - select { - case s.update <- struct{}{}: - default: - } // Ensure the response is for a valid request req, ok := s.accountReqs[id] if !ok { @@ -2360,14 +2364,18 @@ func (s *Syncer) onByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) error // Whether or not the response is valid, we can mark the peer as idle and // notify the scheduler to assign a new task. If the response is invalid, // we'll drop the peer in a bit. + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.peers[peer.ID()]; ok { + s.bytecodeIdlers[peer.ID()] = struct{}{} + } + select { + case s.update <- struct{}{}: + default: + } + }() s.lock.Lock() - if _, ok := s.peers[peer.ID()]; ok { - s.bytecodeIdlers[peer.ID()] = struct{}{} - } - select { - case s.update <- struct{}{}: - default: - } // Ensure the response is for a valid request req, ok := s.bytecodeReqs[id] if !ok { @@ -2469,14 +2477,18 @@ func (s *Syncer) OnStorage(peer SyncPeer, id uint64, hashes [][]common.Hash, slo // Whether or not the response is valid, we can mark the peer as idle and // notify the scheduler to assign a new task. If the response is invalid, // we'll drop the peer in a bit. + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.peers[peer.ID()]; ok { + s.storageIdlers[peer.ID()] = struct{}{} + } + select { + case s.update <- struct{}{}: + default: + } + }() s.lock.Lock() - if _, ok := s.peers[peer.ID()]; ok { - s.storageIdlers[peer.ID()] = struct{}{} - } - select { - case s.update <- struct{}{}: - default: - } // Ensure the response is for a valid request req, ok := s.storageReqs[id] if !ok { @@ -2596,14 +2608,18 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error // Whether or not the response is valid, we can mark the peer as idle and // notify the scheduler to assign a new task. If the response is invalid, // we'll drop the peer in a bit. + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.peers[peer.ID()]; ok { + s.trienodeHealIdlers[peer.ID()] = struct{}{} + } + select { + case s.update <- struct{}{}: + default: + } + }() s.lock.Lock() - if _, ok := s.peers[peer.ID()]; ok { - s.trienodeHealIdlers[peer.ID()] = struct{}{} - } - select { - case s.update <- struct{}{}: - default: - } // Ensure the response is for a valid request req, ok := s.trienodeHealReqs[id] if !ok { @@ -2691,14 +2707,18 @@ func (s *Syncer) onHealByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) e // Whether or not the response is valid, we can mark the peer as idle and // notify the scheduler to assign a new task. If the response is invalid, // we'll drop the peer in a bit. + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + if _, ok := s.peers[peer.ID()]; ok { + s.bytecodeHealIdlers[peer.ID()] = struct{}{} + } + select { + case s.update <- struct{}{}: + default: + } + }() s.lock.Lock() - if _, ok := s.peers[peer.ID()]; ok { - s.bytecodeHealIdlers[peer.ID()] = struct{}{} - } - select { - case s.update <- struct{}{}: - default: - } // Ensure the response is for a valid request req, ok := s.bytecodeHealReqs[id] if !ok { From 3f79afb5990eccf323bfb516cc950e1e6d52062f Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 1 Sep 2022 00:18:18 +0800 Subject: [PATCH 203/715] trie: cleanup stateTrie (#25640) It's a trivial PR to hide the error log when the trie node is not found in the database. The idea for this change is for all TryXXX functions, the error is already returned and we don't need to fire a log explicitly. Recently there are a few tickets #25613 #25589 reporting that the trie nodes are missing because of debug.SetHead. The root cause is after resetting, the chain rewinds to a historical point and re-imports the blocks on top. Since the node is already synced and started to accept transactions previously, these transactions are still kept in the txpool and verified by txpool with a live state. This live state is constructed based on the live trie database, which is changed fast by node referencing and de-referencing. Unfortunately, when we construct a live state(like the state in txpool), we don't reference the state we have. The blockchain will garbage collect the intermediate version nodes in another thread which leads the broken live state. The best solution for this is to forcibly obtain a reference for all live states we create and call release function once it's used up. But it might end up with more junks persisted into disk. Will try to find an elegant solution later in the following PR. --- trie/secure_trie.go | 85 +++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 3d468f56ee0a..db44d05355f6 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -35,14 +35,14 @@ func NewSecure(owner common.Hash, root common.Hash, db *Database) (*SecureTrie, return NewStateTrie(owner, root, db) } -// StateTrie wraps a trie with key hashing. In a secure trie, all +// StateTrie wraps a trie with key hashing. In a stateTrie trie, all // access operations hash the key using keccak256. This prevents // calling code from creating long chains of nodes that // increase the access time. // // Contrary to a regular trie, a StateTrie can only be created with // New and must have an attached database. The database also stores -// the preimage of each key. +// the preimage of each key if preimage recording is enabled. // // StateTrie is not safe for concurrent use. type StateTrie struct { @@ -53,17 +53,11 @@ type StateTrie struct { secKeyCacheOwner *StateTrie // Pointer to self, replace the key cache on mismatch } -// NewStateTrie creates a trie with an existing root node from a backing database -// and optional intermediate in-memory node pool. +// NewStateTrie creates a trie with an existing root node from a backing database. // // If root is the zero hash or the sha3 hash of an empty string, the // trie is initially empty. Otherwise, New will panic if db is nil // and returns MissingNodeError if the root node cannot be found. -// -// Accessing the trie loads nodes from the database or node pool on demand. -// Loaded nodes are kept around until their 'cache generation' expires. -// A new cache generation is created by each call to Commit. -// cachelimit sets the number of past cache generations to keep. func NewStateTrie(owner common.Hash, root common.Hash, db *Database) (*StateTrie, error) { if db == nil { panic("trie.NewSecure called without a database") @@ -87,63 +81,46 @@ func (t *StateTrie) Get(key []byte) []byte { // TryGet 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 MissingNodeError is returned. +// If the specified node 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) TryGet(key []byte) ([]byte, error) { return t.trie.TryGet(t.hashKey(key)) } +// TryGetAccount attempts to retrieve an account with provided trie path. +// 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. func (t *StateTrie) TryGetAccount(key []byte) (*types.StateAccount, error) { - var ret types.StateAccount res, err := t.trie.TryGet(t.hashKey(key)) - if err != nil { - log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) - return &ret, err - } - if res == nil { - return nil, nil + if res == nil || err != nil { + return nil, err } - err = rlp.DecodeBytes(res, &ret) - return &ret, err + ret := new(types.StateAccount) + err = rlp.DecodeBytes(res, ret) + return ret, err } // TryGetAccountWithPreHashedKey does the same thing as TryGetAccount, however // it expects a key that is already hashed. This constitutes an abstraction leak, // since the client code needs to know the key format. func (t *StateTrie) TryGetAccountWithPreHashedKey(key []byte) (*types.StateAccount, error) { - var ret types.StateAccount res, err := t.trie.TryGet(key) - if err != nil { - log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) - return &ret, err - } - if res == nil { - return nil, nil + if res == nil || err != nil { + return nil, err } - err = rlp.DecodeBytes(res, &ret) - return &ret, err + ret := new(types.StateAccount) + err = rlp.DecodeBytes(res, ret) + return ret, err } // TryGetNode 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. +// If a trie node is not found in the database, a MissingNodeError is returned. func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { return t.trie.TryGetNode(path) } -// TryUpdateAccount account will abstract the write of an account to the -// secure trie. -func (t *StateTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { - hk := t.hashKey(key) - data, err := rlp.EncodeToBytes(acc) - if err != nil { - return err - } - if err := t.trie.TryUpdate(hk, data); err != nil { - return err - } - t.getSecKeyCache()[string(hk)] = common.CopyBytes(key) - return nil -} - // Update associates key with value in the trie. Subsequent calls to // Get will return value. If value has length zero, any existing value // is deleted from the trie and calls to Get will return nil. @@ -163,7 +140,7 @@ func (t *StateTrie) Update(key, value []byte) { // The value bytes must not be modified by the caller while they are // stored in the trie. // -// If a node was not found in the database, a MissingNodeError is returned. +// If a node is not found in the database, a MissingNodeError is returned. func (t *StateTrie) TryUpdate(key, value []byte) error { hk := t.hashKey(key) err := t.trie.TryUpdate(hk, value) @@ -174,6 +151,21 @@ func (t *StateTrie) TryUpdate(key, value []byte) error { return nil } +// TryUpdateAccount account will abstract the write of an account to the +// secure trie. +func (t *StateTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { + hk := t.hashKey(key) + data, err := rlp.EncodeToBytes(acc) + if err != nil { + return err + } + if err := t.trie.TryUpdate(hk, data); err != nil { + return err + } + t.getSecKeyCache()[string(hk)] = common.CopyBytes(key) + return nil +} + // Delete removes any existing value for key from the trie. func (t *StateTrie) Delete(key []byte) { if err := t.TryDelete(key); err != nil { @@ -182,14 +174,15 @@ func (t *StateTrie) Delete(key []byte) { } // TryDelete removes any existing value for key from the trie. -// If a node was not found in the database, a MissingNodeError is returned. +// If the specified trie node is not in the trie, nothing will be changed. +// If a node is not found in the database, a MissingNodeError is returned. func (t *StateTrie) TryDelete(key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) return t.trie.TryDelete(hk) } -// TryDeleteACcount abstracts an account deletion from the trie. +// TryDeleteAccount abstracts an account deletion from the trie. func (t *StateTrie) TryDeleteAccount(key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) From 95a2c221d4c780346cf8766d1b416a8147d17e39 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 31 Aug 2022 20:29:39 +0200 Subject: [PATCH 204/715] eth/catalyst: prevent division by zero (#25654) eth/catalyst: prevent diff by zero --- eth/catalyst/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 19dd28e643ca..5ab61524a7cd 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -656,7 +656,7 @@ func (api *ConsensusAPI) heartbeat() { if deltaTime > 0 { growth := deltaDiff / deltaTime left := new(big.Int).Sub(ttd, htd) - eta = time.Duration(new(big.Int).Div(left, new(big.Int).SetUint64(growth)).Uint64()) * time.Second + eta = time.Duration(new(big.Int).Div(left, new(big.Int).SetUint64(growth+1)).Uint64()) * time.Second } } message := "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transition arrives!" From d79bd2f0f6e41be0d53075d0bb5e2655b274745a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 1 Sep 2022 08:41:10 +0200 Subject: [PATCH 205/715] trie: better error reporting (#25645) --- trie/proof.go | 2 +- trie/secure_trie.go | 8 +++----- trie/stacktrie.go | 3 +-- trie/trie.go | 6 +++--- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/trie/proof.go b/trie/proof.go index fa8361eefd58..ef73aed2e409 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -63,7 +63,7 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) e var err error tn, err = t.resolveHash(n, prefix) if err != nil { - log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + log.Error("Unhandled trie error in Trie.Prove", "err", err) return err } default: diff --git a/trie/secure_trie.go b/trie/secure_trie.go index db44d05355f6..1da152477d38 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -17,8 +17,6 @@ package trie import ( - "fmt" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" @@ -74,7 +72,7 @@ func NewStateTrie(owner common.Hash, root common.Hash, db *Database) (*StateTrie func (t *StateTrie) Get(key []byte) []byte { res, err := t.TryGet(key) if err != nil { - log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + log.Error("Unhandled trie error in StateTrie.Get", "err", err) } return res } @@ -129,7 +127,7 @@ func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { // stored in the trie. func (t *StateTrie) Update(key, value []byte) { if err := t.TryUpdate(key, value); err != nil { - log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + log.Error("Unhandled trie error in StateTrie.Update", "err", err) } } @@ -169,7 +167,7 @@ func (t *StateTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error // Delete removes any existing value for key from the trie. func (t *StateTrie) Delete(key []byte) { if err := t.TryDelete(key); err != nil { - log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + log.Error("Unhandled trie error in StateTrie.Delete", "err", err) } } diff --git a/trie/stacktrie.go b/trie/stacktrie.go index a22fa0dd6797..cc50b817b65d 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -21,7 +21,6 @@ import ( "bytes" "encoding/gob" "errors" - "fmt" "io" "sync" @@ -207,7 +206,7 @@ func (st *StackTrie) TryUpdate(key, value []byte) error { func (st *StackTrie) Update(key, value []byte) { if err := st.TryUpdate(key, value); err != nil { - log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + log.Error("Unhandled trie error in StackTrie.Update", "err", err) } } diff --git a/trie/trie.go b/trie/trie.go index 9274d88380cc..e5897b8d7c51 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -132,7 +132,7 @@ func (t *Trie) NodeIterator(start []byte) NodeIterator { func (t *Trie) Get(key []byte) []byte { res, err := t.TryGet(key) if err != nil { - log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + log.Error("Unhandled trie error in Trie.Get", "err", err) } return res } @@ -269,7 +269,7 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new // stored in the trie. func (t *Trie) Update(key, value []byte) { if err := t.TryUpdate(key, value); err != nil { - log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + log.Error("Unhandled trie error in Trie.Update", "err", err) } } @@ -388,7 +388,7 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error // Delete removes any existing value for key from the trie. func (t *Trie) Delete(key []byte) { if err := t.TryDelete(key); err != nil { - log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) + log.Error("Unhandled trie error in Trie.Delete", "err", err) } } From d46184c9694d9f3d28910880f588de3dcfca9e0c Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 1 Sep 2022 15:34:32 +0800 Subject: [PATCH 206/715] core/state: filter out nil trie for copy (#25575) --- core/state/trie_prefetcher.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 83e8966d4c9f..678774a62b76 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -126,6 +126,9 @@ func (p *triePrefetcher) copy() *triePrefetcher { // If the prefetcher is already a copy, duplicate the data if p.fetches != nil { for root, fetch := range p.fetches { + if fetch == nil { + continue + } copy.fetches[root] = p.db.CopyTrie(fetch) } return copy From d2027accdc6d15ef6fc0b5f0639a06c72ab54892 Mon Sep 17 00:00:00 2001 From: Jakub Freebit <49676311+jakub-freebit@users.noreply.github.com> Date: Fri, 2 Sep 2022 23:53:58 +0900 Subject: [PATCH 207/715] mobile: register filter APIs (#25642) This fixes a regression introduced in PR #25459. --- mobile/geth.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mobile/geth.go b/mobile/geth.go index 204e29c8be04..7dee93b77ca5 100644 --- a/mobile/geth.go +++ b/mobile/geth.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethstats" "github.com/ethereum/go-ethereum/internal/debug" @@ -35,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" ) // NodeConfig represents the collection of configuration values to fine tune the Geth @@ -200,6 +202,14 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { rawStack.Close() return nil, fmt.Errorf("ethereum init: %v", err) } + // Register log filter RPC API. + filterSystem := filters.NewFilterSystem(lesBackend.ApiBackend, filters.Config{ + LogCacheSize: ethConf.FilterLogCacheSize, + }) + rawStack.RegisterAPIs([]rpc.API{{ + Namespace: "eth", + Service: filters.NewFilterAPI(filterSystem, true), + }}) // If netstats reporting is requested, do it if config.EthereumNetStats != "" { if err := ethstats.New(rawStack, lesBackend.ApiBackend, lesBackend.Engine(), config.EthereumNetStats); err != nil { From 198fa956f4daed3602edd7695759483b1fac9b7a Mon Sep 17 00:00:00 2001 From: xternet Date: Fri, 2 Sep 2022 16:58:20 +0200 Subject: [PATCH 208/715] README.md: improve grammar (#25646) Co-authored-by: Felix Lange --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index d1377726893c..5506001287fe 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ directory. | **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI page](https://geth.ethereum.org/docs/interface/command-line-options) for command line options. | | `clef` | Stand-alone signing tool, which can be used as a backend signer for `geth`. | | `devp2p` | Utilities to interact with nodes on the networking layer, without running a full blockchain. | -| `abigen` | Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://docs.soliditylang.org/en/develop/abi-spec.html) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://geth.ethereum.org/docs/dapp/native-bindings) page for details. | +| `abigen` | Source code generator to convert Ethereum contract definitions into easy-to-use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://docs.soliditylang.org/en/develop/abi-spec.html) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://geth.ethereum.org/docs/dapp/native-bindings) page for details. | | `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | | `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug run`). | | `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | @@ -65,14 +65,14 @@ Recommended: * Fast CPU with 4+ cores * 16GB+ RAM -* High Performance SSD with at least 1TB free space +* High-performance SSD with at least 1TB of free space * 25+ MBit/sec download Internet service ### Full node on the main Ethereum network By far the most common scenario is people wanting to simply interact with the Ethereum network: create accounts; transfer funds; deploy and interact with contracts. For this -particular use-case the user doesn't care about years-old historical data, so we can +particular use case, the user doesn't care about years-old historical data, so we can sync quickly to the current state of the network. To do so: ```shell @@ -83,11 +83,11 @@ This command will: * Start `geth` in snap sync mode (default, can be changed with the `--syncmode` flag), causing it to download more data in exchange for avoiding processing the entire history of the Ethereum network, which is very CPU intensive. - * Start up `geth`'s built-in interactive [JavaScript console](https://geth.ethereum.org/docs/interface/javascript-console), + * Start the built-in interactive [JavaScript console](https://geth.ethereum.org/docs/interface/javascript-console), (via the trailing `console` subcommand) through which you can interact using [`web3` methods](https://github.com/ChainSafe/web3.js/blob/0.20.7/DOCUMENTATION.md) (note: the `web3` version bundled within `geth` is very old, and not up to date with official docs), as well as `geth`'s own [management APIs](https://geth.ethereum.org/docs/rpc/server). - This tool is optional and if you leave it out you can always attach to an already running + This tool is optional and if you leave it out you can always attach it to an already running `geth` instance with `geth attach`. ### A Full node on the Görli test network @@ -102,12 +102,12 @@ the main network, but with play-Ether only. $ geth --goerli console ``` -The `console` subcommand has the exact same meaning as above and they are equally -useful on the testnet too. Please, see above for their explanations if you've skipped here. +The `console` subcommand has the same meaning as above and is equally +useful on the testnet too. Specifying the `--goerli` flag, however, will reconfigure your `geth` instance a bit: - * Instead of connecting the main Ethereum network, the client will connect to the Görli + * Instead of connecting to the main Ethereum network, the client will connect to the Görli test network, which uses different P2P bootnodes, different network IDs and genesis states. * Instead of using the default data directory (`~/.ethereum` on Linux for example), `geth` @@ -118,9 +118,9 @@ Specifying the `--goerli` flag, however, will reconfigure your `geth` instance a `geth attach /goerli/geth.ipc`. Windows users are not affected by this. -*Note: Although there are some internal protective measures to prevent transactions from -crossing over between the main network and test network, you should make sure to always -use separate accounts for play-money and real-money. Unless you manually move +*Note: Although some internal protective measures prevent transactions from +crossing over between the main network and test network, you should always +use separate accounts for play and real money. Unless you manually move accounts, `geth` will by default correctly separate the two networks and will not make any accounts available between them.* @@ -155,7 +155,7 @@ configuration file via: $ geth --config /path/to/your_config.toml ``` -To get an idea how the file should look like you can use the `dumpconfig` subcommand to +To get an idea of how the file should look like you can use the `dumpconfig` subcommand to export your existing configuration: ```shell @@ -175,7 +175,7 @@ docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \ ethereum/client-go ``` -This will start `geth` in snap-sync mode with a DB memory allowance of 1GB just as the +This will start `geth` in snap-sync mode with a DB memory allowance of 1GB, as the above command does. It will also create a persistent volume in your home directory for saving your blockchain as well as map the default ports. There is also an `alpine` tag available for a slim version of the image. @@ -209,7 +209,7 @@ HTTP based JSON-RPC API options: * `--ws.addr` WS-RPC server listening interface (default: `localhost`) * `--ws.port` WS-RPC server listening port (default: `8546`) * `--ws.api` API's offered over the WS-RPC interface (default: `eth,net,web3`) - * `--ws.origins` Origins from which to accept websockets requests + * `--ws.origins` Origins from which to accept WebSocket requests * `--ipcdisable` Disable the IPC-RPC server * `--ipcapi` API's offered over the IPC-RPC interface (default: `admin,debug,eth,miner,net,personal,txpool,web3`) * `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it) @@ -327,7 +327,7 @@ requiring an OpenCL or CUDA enabled `ethminer` instance. For information on such setup, please consult the [EtherMining subreddit](https://www.reddit.com/r/EtherMining/) and the [ethminer](https://github.com/ethereum-mining/ethminer) repository. -In a private network setting, however a single CPU miner instance is more than enough for +In a private network setting, however, a single CPU miner instance is more than enough for practical purposes as it can produce a stable stream of blocks at the correct intervals without needing heavy resources (consider running on a single thread, no need for multiple ones either). To start a `geth` instance for mining, run it with all your usual flags, extended @@ -344,7 +344,7 @@ transactions are accepted at (`--miner.gasprice`). ## Contribution -Thank you for considering to help out with the source code! We welcome contributions +Thank you for considering helping out with the source code! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes! If you'd like to contribute to go-ethereum, please fork, fix, commit and send a pull request @@ -374,6 +374,6 @@ The go-ethereum library (i.e. all code outside of the `cmd` directory) is licens [GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html), also included in our repository in the `COPYING.LESSER` file. -The go-ethereum binaries (i.e. all code inside of the `cmd` directory) is licensed under the +The go-ethereum binaries (i.e. all code inside of the `cmd` directory) are licensed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), also included in our repository in the `COPYING` file. From d6a12bc7b8549ea2a341e18ebb3eff8ef03fff7d Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Fri, 2 Sep 2022 17:08:25 +0200 Subject: [PATCH 209/715] eth/tracers/js: fill in log.refund field (#25661) For some reason, an accessor method for this field exists in JS, but the value was never actually assigned. --- eth/tracers/js/goja.go | 1 + 1 file changed, 1 insertion(+) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 8238bb603dd3..526520c7866f 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -259,6 +259,7 @@ func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope log.pc = uint(pc) log.gas = uint(gas) log.cost = uint(cost) + log.refund = uint(t.env.StateDB.GetRefund()) log.depth = uint(depth) log.err = err if _, err := t.step(t.obj, t.logValue, t.dbValue); err != nil { From 7f2890a9be1f91368582479f171248b972b45ae3 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 2 Sep 2022 17:28:33 +0200 Subject: [PATCH 210/715] eth/fetcher: throttle peers which deliver many invalid transactions (#25573) Co-authored-by: Felix Lange --- cmd/devp2p/internal/ethtest/helpers.go | 6 +- cmd/devp2p/internal/ethtest/suite.go | 4 + cmd/devp2p/internal/ethtest/transaction.go | 6 +- eth/fetcher/tx_fetcher.go | 94 +++++++++++++--------- 4 files changed, 68 insertions(+), 42 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/helpers.go b/cmd/devp2p/internal/ethtest/helpers.go index eeeb4f93cabf..b57649ade99d 100644 --- a/cmd/devp2p/internal/ethtest/helpers.go +++ b/cmd/devp2p/internal/ethtest/helpers.go @@ -357,9 +357,13 @@ func (s *Suite) waitAnnounce(conn *Conn, blockAnnouncement *NewBlock) error { return fmt.Errorf("wrong block hash in announcement: expected %v, got %v", blockAnnouncement.Block.Hash(), hashes[0].Hash) } return nil + + // ignore tx announcements from previous tests case *NewPooledTransactionHashes: - // ignore tx announcements from previous tests continue + case *Transactions: + continue + default: return fmt.Errorf("unexpected: %s", pretty.Sdump(msg)) } diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index 7059b4ba738c..4497478d72d6 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -544,9 +544,13 @@ func (s *Suite) TestNewPooledTxs(t *utesting.T) { t.Fatalf("unexpected number of txs requested: wanted %d, got %d", len(hashes), len(msg.GetPooledTransactionsPacket)) } return + // ignore propagated txs from previous tests case *NewPooledTransactionHashes: continue + case *Transactions: + continue + // ignore block announcements from previous tests case *NewBlockHashes: continue diff --git a/cmd/devp2p/internal/ethtest/transaction.go b/cmd/devp2p/internal/ethtest/transaction.go index c4748bf8f7d8..baa55bd49268 100644 --- a/cmd/devp2p/internal/ethtest/transaction.go +++ b/cmd/devp2p/internal/ethtest/transaction.go @@ -29,7 +29,7 @@ import ( "github.com/ethereum/go-ethereum/params" ) -//var faucetAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") +// var faucetAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") var faucetKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") func (s *Suite) sendSuccessfulTxs(t *utesting.T) error { @@ -192,10 +192,10 @@ func sendMultipleSuccessfulTxs(t *utesting.T, s *Suite, txs []*types.Transaction nonce = txs[len(txs)-1].Nonce() // Wait for the transaction announcement(s) and make sure all sent txs are being propagated. - // all txs should be announced within 3 announcements. + // all txs should be announced within a couple announcements. recvHashes := make([]common.Hash, 0) - for i := 0; i < 3; i++ { + for i := 0; i < 20; i++ { switch msg := recvConn.readAndServe(s.chain, timeout).(type) { case *Transactions: for _, tx := range *msg { diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index 035e0c2ec7d8..677a6422b011 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -262,54 +262,72 @@ func (f *TxFetcher) Notify(peer string, hashes []common.Hash) error { // direct request replies. The differentiation is important so the fetcher can // re-schedule missing transactions as soon as possible. func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) error { - // Keep track of all the propagated transactions - if direct { - txReplyInMeter.Mark(int64(len(txs))) - } else { - txBroadcastInMeter.Mark(int64(len(txs))) + var ( + inMeter = txReplyInMeter + knownMeter = txReplyKnownMeter + underpricedMeter = txReplyUnderpricedMeter + otherRejectMeter = txReplyOtherRejectMeter + ) + if !direct { + inMeter = txBroadcastInMeter + knownMeter = txBroadcastKnownMeter + underpricedMeter = txBroadcastUnderpricedMeter + otherRejectMeter = txBroadcastOtherRejectMeter } + // Keep track of all the propagated transactions + inMeter.Mark(int64(len(txs))) + // Push all the transactions into the pool, tracking underpriced ones to avoid // re-requesting them and dropping the peer in case of malicious transfers. var ( - added = make([]common.Hash, 0, len(txs)) - duplicate int64 - underpriced int64 - otherreject int64 + added = make([]common.Hash, 0, len(txs)) ) - errs := f.addTxs(txs) - for i, err := range errs { - // Track the transaction hash if the price is too low for us. - // Avoid re-request this transaction when we receive another - // announcement. - if errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced) { - for f.underpriced.Cardinality() >= maxTxUnderpricedSetSize { - f.underpriced.Pop() - } - f.underpriced.Add(txs[i].Hash()) + // proceed in batches + for i := 0; i < len(txs); i += 128 { + end := i + 128 + if end > len(txs) { + end = len(txs) } - // Track a few interesting failure types - switch { - case err == nil: // Noop, but need to handle to not count these + var ( + duplicate int64 + underpriced int64 + otherreject int64 + ) + batch := txs[i:end] + for j, err := range f.addTxs(batch) { + // Track the transaction hash if the price is too low for us. + // Avoid re-request this transaction when we receive another + // announcement. + if errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced) { + for f.underpriced.Cardinality() >= maxTxUnderpricedSetSize { + f.underpriced.Pop() + } + f.underpriced.Add(batch[j].Hash()) + } + // Track a few interesting failure types + switch { + case err == nil: // Noop, but need to handle to not count these - case errors.Is(err, core.ErrAlreadyKnown): - duplicate++ + case errors.Is(err, core.ErrAlreadyKnown): + duplicate++ - case errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced): - underpriced++ + case errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced): + underpriced++ - default: - otherreject++ + default: + otherreject++ + } + added = append(added, batch[j].Hash()) + } + knownMeter.Mark(duplicate) + underpricedMeter.Mark(underpriced) + otherRejectMeter.Mark(otherreject) + + // If 'other reject' is >25% of the deliveries in any batch, sleep a bit. + if otherreject > 128/4 { + time.Sleep(200 * time.Millisecond) + log.Warn("Peer delivering stale transactions", "peer", peer, "rejected", otherreject) } - added = append(added, txs[i].Hash()) - } - if direct { - txReplyKnownMeter.Mark(duplicate) - txReplyUnderpricedMeter.Mark(underpriced) - txReplyOtherRejectMeter.Mark(otherreject) - } else { - txBroadcastKnownMeter.Mark(duplicate) - txBroadcastUnderpricedMeter.Mark(underpriced) - txBroadcastOtherRejectMeter.Mark(otherreject) } select { case f.cleanup <- &txDelivery{origin: peer, hashes: added, direct: direct}: From 90711efb0ab6360c37ab2135ab961daf05e83a74 Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 2 Sep 2022 17:40:41 +0200 Subject: [PATCH 211/715] node, rpc: add JWT auth support in client (#24911) This adds a generic mechanism for 'dial options' in the RPC client, and also implements a specific dial option for the JWT authentication mechanism used by the engine API. Some real tests for the server-side authentication handling are also added. Co-authored-by: Joshua Gutow Co-authored-by: Felix Lange --- node/config.go | 2 +- node/jwt_auth.go | 45 ++++++++ node/node.go | 13 +++ node/node_auth_test.go | 237 +++++++++++++++++++++++++++++++++++++++++ rpc/client.go | 45 ++++++-- rpc/client_opt.go | 106 ++++++++++++++++++ rpc/client_opt_test.go | 25 +++++ rpc/http.go | 54 +++++++--- rpc/ipc.go | 8 +- rpc/stdio.go | 8 +- rpc/websocket.go | 78 ++++++++++---- 11 files changed, 573 insertions(+), 48 deletions(-) create mode 100644 node/jwt_auth.go create mode 100644 node/node_auth_test.go create mode 100644 rpc/client_opt.go create mode 100644 rpc/client_opt_test.go diff --git a/node/config.go b/node/config.go index 2047299fb5d7..49959d5ec5de 100644 --- a/node/config.go +++ b/node/config.go @@ -201,7 +201,7 @@ type Config struct { // AllowUnprotectedTxs allows non EIP-155 protected transactions to be send over RPC. AllowUnprotectedTxs bool `toml:",omitempty"` - // JWTSecret is the hex-encoded jwt secret. + // JWTSecret is the path to the hex-encoded jwt secret. JWTSecret string `toml:",omitempty"` } diff --git a/node/jwt_auth.go b/node/jwt_auth.go new file mode 100644 index 000000000000..d4f8193ca7f2 --- /dev/null +++ b/node/jwt_auth.go @@ -0,0 +1,45 @@ +// Copyright 2022 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 node + +import ( + "fmt" + "net/http" + "time" + + "github.com/ethereum/go-ethereum/rpc" + "github.com/golang-jwt/jwt/v4" +) + +// NewJWTAuth creates an rpc client authentication provider that uses JWT. The +// secret MUST be 32 bytes (256 bits) as defined by the Engine-API authentication spec. +// +// See https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md +// for more details about this authentication scheme. +func NewJWTAuth(jwtsecret [32]byte) rpc.HTTPAuth { + return func(h http.Header) error { + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ + "iat": &jwt.NumericDate{Time: time.Now()}, + }) + s, err := token.SignedString(jwtsecret[:]) + if err != nil { + return fmt.Errorf("failed to create JWT token: %w", err) + } + h.Set("Authorization", "Bearer "+s) + return nil + } +} diff --git a/node/node.go b/node/node.go index b60e32f22fd2..3cbefef022e5 100644 --- a/node/node.go +++ b/node/node.go @@ -668,6 +668,19 @@ func (n *Node) WSEndpoint() string { return "ws://" + n.ws.listenAddr() + n.ws.wsConfig.prefix } +// HTTPAuthEndpoint returns the URL of the authenticated HTTP server. +func (n *Node) HTTPAuthEndpoint() string { + return "http://" + n.httpAuth.listenAddr() +} + +// WSAuthEndpoint returns the current authenticated JSON-RPC over WebSocket endpoint. +func (n *Node) WSAuthEndpoint() string { + if n.httpAuth.wsAllowed() { + return "ws://" + n.httpAuth.listenAddr() + n.httpAuth.wsConfig.prefix + } + return "ws://" + n.wsAuth.listenAddr() + n.wsAuth.wsConfig.prefix +} + // EventMux retrieves the event multiplexer used by all the network services in // the current protocol stack. func (n *Node) EventMux() *event.TypeMux { diff --git a/node/node_auth_test.go b/node/node_auth_test.go new file mode 100644 index 000000000000..597cd8531f79 --- /dev/null +++ b/node/node_auth_test.go @@ -0,0 +1,237 @@ +// Copyright 2022 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 node + +import ( + "context" + crand "crypto/rand" + "fmt" + "net/http" + "os" + "path" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + "github.com/golang-jwt/jwt/v4" +) + +type helloRPC string + +func (ta helloRPC) HelloWorld() (string, error) { + return string(ta), nil +} + +type authTest struct { + name string + endpoint string + prov rpc.HTTPAuth + expectDialFail bool + expectCall1Fail bool + expectCall2Fail bool +} + +func (at *authTest) Run(t *testing.T) { + ctx := context.Background() + cl, err := rpc.DialOptions(ctx, at.endpoint, rpc.WithHTTPAuth(at.prov)) + if at.expectDialFail { + if err == nil { + t.Fatal("expected initial dial to fail") + } else { + return + } + } + if err != nil { + t.Fatalf("failed to dial rpc endpoint: %v", err) + } + + var x string + err = cl.CallContext(ctx, &x, "engine_helloWorld") + if at.expectCall1Fail { + if err == nil { + t.Fatal("expected call 1 to fail") + } else { + return + } + } + if err != nil { + t.Fatalf("failed to call rpc endpoint: %v", err) + } + if x != "hello engine" { + t.Fatalf("method was silent but did not return expected value: %q", x) + } + + err = cl.CallContext(ctx, &x, "eth_helloWorld") + if at.expectCall2Fail { + if err == nil { + t.Fatal("expected call 2 to fail") + } else { + return + } + } + if err != nil { + t.Fatalf("failed to call rpc endpoint: %v", err) + } + if x != "hello eth" { + t.Fatalf("method was silent but did not return expected value: %q", x) + } +} + +func TestAuthEndpoints(t *testing.T) { + var secret [32]byte + if _, err := crand.Read(secret[:]); err != nil { + t.Fatalf("failed to create jwt secret: %v", err) + } + // Geth must read it from a file, and does not support in-memory JWT secrets, so we create a temporary file. + jwtPath := path.Join(t.TempDir(), "jwt_secret") + if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(secret[:])), 0600); err != nil { + t.Fatalf("failed to prepare jwt secret file: %v", err) + } + // We get ports assigned by the node automatically + conf := &Config{ + HTTPHost: "127.0.0.1", + HTTPPort: 0, + WSHost: "127.0.0.1", + WSPort: 0, + AuthAddr: "127.0.0.1", + AuthPort: 0, + JWTSecret: jwtPath, + + WSModules: []string{"eth", "engine"}, + HTTPModules: []string{"eth", "engine"}, + } + node, err := New(conf) + if err != nil { + t.Fatalf("could not create a new node: %v", err) + } + // register dummy apis so we can test the modules are available and reachable with authentication + node.RegisterAPIs([]rpc.API{ + { + Namespace: "engine", + Version: "1.0", + Service: helloRPC("hello engine"), + Public: true, + Authenticated: true, + }, + { + Namespace: "eth", + Version: "1.0", + Service: helloRPC("hello eth"), + Public: true, + Authenticated: true, + }, + }) + if err := node.Start(); err != nil { + t.Fatalf("failed to start test node: %v", err) + } + defer node.Close() + + // sanity check we are running different endpoints + if a, b := node.WSEndpoint(), node.WSAuthEndpoint(); a == b { + t.Fatalf("expected ws and auth-ws endpoints to be different, got: %q and %q", a, b) + } + if a, b := node.HTTPEndpoint(), node.HTTPAuthEndpoint(); a == b { + t.Fatalf("expected http and auth-http endpoints to be different, got: %q and %q", a, b) + } + + goodAuth := NewJWTAuth(secret) + var otherSecret [32]byte + if _, err := crand.Read(otherSecret[:]); err != nil { + t.Fatalf("failed to create jwt secret: %v", err) + } + badAuth := NewJWTAuth(otherSecret) + + notTooLong := time.Second * 57 + tooLong := time.Second * 60 + requestDelay := time.Second + + testCases := []authTest{ + // Auth works + {name: "ws good", endpoint: node.WSAuthEndpoint(), prov: goodAuth, expectCall1Fail: false}, + {name: "http good", endpoint: node.HTTPAuthEndpoint(), prov: goodAuth, expectCall1Fail: false}, + + // Try a bad auth + {name: "ws bad", endpoint: node.WSAuthEndpoint(), prov: badAuth, expectDialFail: true}, // ws auth is immediate + {name: "http bad", endpoint: node.HTTPAuthEndpoint(), prov: badAuth, expectCall1Fail: true}, // http auth is on first call + + // A common mistake with JWT is to allow the "none" algorithm, which is a valid JWT but not secure. + {name: "ws none", endpoint: node.WSAuthEndpoint(), prov: noneAuth(secret), expectDialFail: true}, + {name: "http none", endpoint: node.HTTPAuthEndpoint(), prov: noneAuth(secret), expectCall1Fail: true}, + + // claims of 5 seconds or more, older or newer, are not allowed + {name: "ws too old", endpoint: node.WSAuthEndpoint(), prov: offsetTimeAuth(secret, -tooLong), expectDialFail: true}, + {name: "http too old", endpoint: node.HTTPAuthEndpoint(), prov: offsetTimeAuth(secret, -tooLong), expectCall1Fail: true}, + // note: for it to be too long we need to add a delay, so that once we receive the request, the difference has not dipped below the "tooLong" + {name: "ws too new", endpoint: node.WSAuthEndpoint(), prov: offsetTimeAuth(secret, tooLong+requestDelay), expectDialFail: true}, + {name: "http too new", endpoint: node.HTTPAuthEndpoint(), prov: offsetTimeAuth(secret, tooLong+requestDelay), expectCall1Fail: true}, + + // Try offset the time, but stay just within bounds + {name: "ws old", endpoint: node.WSAuthEndpoint(), prov: offsetTimeAuth(secret, -notTooLong)}, + {name: "http old", endpoint: node.HTTPAuthEndpoint(), prov: offsetTimeAuth(secret, -notTooLong)}, + {name: "ws new", endpoint: node.WSAuthEndpoint(), prov: offsetTimeAuth(secret, notTooLong)}, + {name: "http new", endpoint: node.HTTPAuthEndpoint(), prov: offsetTimeAuth(secret, notTooLong)}, + + // ws only authenticates on initial dial, then continues communication + {name: "ws single auth", endpoint: node.WSAuthEndpoint(), prov: changingAuth(goodAuth, badAuth)}, + {name: "http call fail auth", endpoint: node.HTTPAuthEndpoint(), prov: changingAuth(goodAuth, badAuth), expectCall2Fail: true}, + {name: "http call fail time", endpoint: node.HTTPAuthEndpoint(), prov: changingAuth(goodAuth, offsetTimeAuth(secret, tooLong+requestDelay)), expectCall2Fail: true}, + } + + for _, testCase := range testCases { + t.Run(testCase.name, testCase.Run) + } +} + +func noneAuth(secret [32]byte) rpc.HTTPAuth { + return func(header http.Header) error { + token := jwt.NewWithClaims(jwt.SigningMethodNone, jwt.MapClaims{ + "iat": &jwt.NumericDate{Time: time.Now()}, + }) + s, err := token.SignedString(secret[:]) + if err != nil { + return fmt.Errorf("failed to create JWT token: %w", err) + } + header.Set("Authorization", "Bearer "+s) + return nil + } +} + +func changingAuth(provs ...rpc.HTTPAuth) rpc.HTTPAuth { + i := 0 + return func(header http.Header) error { + i += 1 + if i > len(provs) { + i = len(provs) + } + return provs[i-1](header) + } +} + +func offsetTimeAuth(secret [32]byte, offset time.Duration) rpc.HTTPAuth { + return func(header http.Header) error { + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ + "iat": &jwt.NumericDate{Time: time.Now().Add(offset)}, + }) + s, err := token.SignedString(secret[:]) + if err != nil { + return fmt.Errorf("failed to create JWT token: %w", err) + } + header.Set("Authorization", "Bearer "+s) + return nil + } +} diff --git a/rpc/client.go b/rpc/client.go index d3ce0297754c..8288f976ebeb 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "net/url" + "os" "reflect" "strconv" "sync/atomic" @@ -99,7 +100,7 @@ type Client struct { reqTimeout chan *requestOp // removes response IDs when call timeout expires } -type reconnectFunc func(ctx context.Context) (ServerCodec, error) +type reconnectFunc func(context.Context) (ServerCodec, error) type clientContextKey struct{} @@ -153,14 +154,16 @@ func (op *requestOp) wait(ctx context.Context, c *Client) (*jsonrpcMessage, erro // // The currently supported URL schemes are "http", "https", "ws" and "wss". If rawurl is a // file name with no URL scheme, a local socket connection is established using UNIX -// domain sockets on supported platforms and named pipes on Windows. If you want to -// configure transport options, use DialHTTP, DialWebsocket or DialIPC instead. +// domain sockets on supported platforms and named pipes on Windows. +// +// If you want to further configure the transport, use DialOptions instead of this +// function. // // For websocket connections, the origin is set to the local host name. // -// The client reconnects automatically if the connection is lost. +// The client reconnects automatically when the connection is lost. func Dial(rawurl string) (*Client, error) { - return DialContext(context.Background(), rawurl) + return DialOptions(context.Background(), rawurl) } // DialContext creates a new RPC client, just like Dial. @@ -168,22 +171,46 @@ func Dial(rawurl string) (*Client, error) { // The context is used to cancel or time out the initial connection establishment. It does // not affect subsequent interactions with the client. func DialContext(ctx context.Context, rawurl string) (*Client, error) { + return DialOptions(ctx, rawurl) +} + +// DialOptions creates a new RPC client for the given URL. You can supply any of the +// pre-defined client options to configure the underlying transport. +// +// The context is used to cancel or time out the initial connection establishment. It does +// not affect subsequent interactions with the client. +// +// The client reconnects automatically when the connection is lost. +func DialOptions(ctx context.Context, rawurl string, options ...ClientOption) (*Client, error) { u, err := url.Parse(rawurl) if err != nil { return nil, err } + + cfg := new(clientConfig) + for _, opt := range options { + opt.applyOption(cfg) + } + + var reconnect reconnectFunc switch u.Scheme { case "http", "https": - return DialHTTP(rawurl) + reconnect = newClientTransportHTTP(rawurl, cfg) case "ws", "wss": - return DialWebsocket(ctx, rawurl, "") + rc, err := newClientTransportWS(rawurl, cfg) + if err != nil { + return nil, err + } + reconnect = rc case "stdio": - return DialStdIO(ctx) + reconnect = newClientTransportIO(os.Stdin, os.Stdout) case "": - return DialIPC(ctx, rawurl) + reconnect = newClientTransportIPC(rawurl) default: return nil, fmt.Errorf("no known transport for URL scheme %q", u.Scheme) } + + return newClient(ctx, reconnect) } // ClientFromContext retrieves the client from the context, if any. This can be used to perform diff --git a/rpc/client_opt.go b/rpc/client_opt.go new file mode 100644 index 000000000000..5ad7c22b3ce7 --- /dev/null +++ b/rpc/client_opt.go @@ -0,0 +1,106 @@ +// Copyright 2022 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 rpc + +import ( + "net/http" + + "github.com/gorilla/websocket" +) + +// ClientOption is a configuration option for the RPC client. +type ClientOption interface { + applyOption(*clientConfig) +} + +type clientConfig struct { + httpClient *http.Client + httpHeaders http.Header + httpAuth HTTPAuth + + wsDialer *websocket.Dialer +} + +func (cfg *clientConfig) initHeaders() { + if cfg.httpHeaders == nil { + cfg.httpHeaders = make(http.Header) + } +} + +func (cfg *clientConfig) setHeader(key, value string) { + cfg.initHeaders() + cfg.httpHeaders.Set(key, value) +} + +type optionFunc func(*clientConfig) + +func (fn optionFunc) applyOption(opt *clientConfig) { + fn(opt) +} + +// WithWebsocketDialer configures the websocket.Dialer used by the RPC client. +func WithWebsocketDialer(dialer websocket.Dialer) ClientOption { + return optionFunc(func(cfg *clientConfig) { + cfg.wsDialer = &dialer + }) +} + +// WithHeader configures HTTP headers set by the RPC client. Headers set using this option +// will be used for both HTTP and WebSocket connections. +func WithHeader(key, value string) ClientOption { + return optionFunc(func(cfg *clientConfig) { + cfg.initHeaders() + cfg.httpHeaders.Set(key, value) + }) +} + +// WithHeaders configures HTTP headers set by the RPC client. Headers set using this +// option will be used for both HTTP and WebSocket connections. +func WithHeaders(headers http.Header) ClientOption { + return optionFunc(func(cfg *clientConfig) { + cfg.initHeaders() + for k, vs := range headers { + cfg.httpHeaders[k] = vs + } + }) +} + +// WithHTTPClient configures the http.Client used by the RPC client. +func WithHTTPClient(c *http.Client) ClientOption { + return optionFunc(func(cfg *clientConfig) { + cfg.httpClient = c + }) +} + +// WithHTTPAuth configures HTTP request authentication. The given provider will be called +// whenever a request is made. Note that only one authentication provider can be active at +// any time. +func WithHTTPAuth(a HTTPAuth) ClientOption { + if a == nil { + panic("nil auth") + } + return optionFunc(func(cfg *clientConfig) { + cfg.httpAuth = a + }) +} + +// A HTTPAuth function is called by the client whenever a HTTP request is sent. +// The function must be safe for concurrent use. +// +// Usually, HTTPAuth functions will call h.Set("authorization", "...") to add +// auth information to the request. +type HTTPAuth func(h http.Header) error diff --git a/rpc/client_opt_test.go b/rpc/client_opt_test.go new file mode 100644 index 000000000000..d7cc2572a776 --- /dev/null +++ b/rpc/client_opt_test.go @@ -0,0 +1,25 @@ +package rpc_test + +import ( + "context" + "net/http" + "time" + + "github.com/ethereum/go-ethereum/rpc" +) + +// This example configures a HTTP-based RPC client with two options - one setting the +// overall request timeout, the other adding a custom HTTP header to all requests. +func ExampleDialOptions() { + tokenHeader := rpc.WithHeader("x-token", "foo") + httpClient := rpc.WithHTTPClient(&http.Client{ + Timeout: 10 * time.Second, + }) + + ctx := context.Background() + c, err := rpc.DialOptions(ctx, "http://rpc.example.com", httpClient, tokenHeader) + if err != nil { + panic(err) + } + c.Close() +} diff --git a/rpc/http.go b/rpc/http.go index 858d80858652..8595959afb66 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -45,6 +45,7 @@ type httpConn struct { closeCh chan interface{} mu sync.Mutex // protects headers headers http.Header + auth HTTPAuth } // httpConn implements ServerCodec, but it is treated specially by Client @@ -117,8 +118,15 @@ var DefaultHTTPTimeouts = HTTPTimeouts{ IdleTimeout: 120 * time.Second, } +// DialHTTP creates a new RPC client that connects to an RPC server over HTTP. +func DialHTTP(endpoint string) (*Client, error) { + return DialHTTPWithClient(endpoint, new(http.Client)) +} + // DialHTTPWithClient creates a new RPC client that connects to an RPC server over HTTP // using the provided HTTP Client. +// +// Deprecated: use DialOptions and the WithHTTPClient option. func DialHTTPWithClient(endpoint string, client *http.Client) (*Client, error) { // Sanity check URL so we don't end up with a client that will fail every request. _, err := url.Parse(endpoint) @@ -126,24 +134,35 @@ func DialHTTPWithClient(endpoint string, client *http.Client) (*Client, error) { return nil, err } - initctx := context.Background() - headers := make(http.Header, 2) + var cfg clientConfig + fn := newClientTransportHTTP(endpoint, &cfg) + return newClient(context.Background(), fn) +} + +func newClientTransportHTTP(endpoint string, cfg *clientConfig) reconnectFunc { + headers := make(http.Header, 2+len(cfg.httpHeaders)) headers.Set("accept", contentType) headers.Set("content-type", contentType) - return newClient(initctx, func(context.Context) (ServerCodec, error) { - hc := &httpConn{ - client: client, - headers: headers, - url: endpoint, - closeCh: make(chan interface{}), - } - return hc, nil - }) -} + for key, values := range cfg.httpHeaders { + headers[key] = values + } -// DialHTTP creates a new RPC client that connects to an RPC server over HTTP. -func DialHTTP(endpoint string) (*Client, error) { - return DialHTTPWithClient(endpoint, new(http.Client)) + client := cfg.httpClient + if client == nil { + client = new(http.Client) + } + + hc := &httpConn{ + client: client, + headers: headers, + url: endpoint, + auth: cfg.httpAuth, + closeCh: make(chan interface{}), + } + + return func(ctx context.Context) (ServerCodec, error) { + return hc, nil + } } func (c *Client) sendHTTP(ctx context.Context, op *requestOp, msg interface{}) error { @@ -195,6 +214,11 @@ func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadClos hc.mu.Lock() req.Header = hc.headers.Clone() hc.mu.Unlock() + if hc.auth != nil { + if err := hc.auth(req.Header); err != nil { + return nil, err + } + } // do request resp, err := hc.client.Do(req) diff --git a/rpc/ipc.go b/rpc/ipc.go index 07a211c6277c..d9e0de62e877 100644 --- a/rpc/ipc.go +++ b/rpc/ipc.go @@ -46,11 +46,15 @@ func (s *Server) ServeListener(l net.Listener) error { // The context is used for the initial connection establishment. It does not // affect subsequent interactions with the client. func DialIPC(ctx context.Context, endpoint string) (*Client, error) { - return newClient(ctx, func(ctx context.Context) (ServerCodec, error) { + return newClient(ctx, newClientTransportIPC(endpoint)) +} + +func newClientTransportIPC(endpoint string) reconnectFunc { + return func(ctx context.Context) (ServerCodec, error) { conn, err := newIPCConnection(ctx, endpoint) if err != nil { return nil, err } return NewCodec(conn), err - }) + } } diff --git a/rpc/stdio.go b/rpc/stdio.go index be2bab1c98bd..ae32db26ef1c 100644 --- a/rpc/stdio.go +++ b/rpc/stdio.go @@ -32,12 +32,16 @@ func DialStdIO(ctx context.Context) (*Client, error) { // DialIO creates a client which uses the given IO channels func DialIO(ctx context.Context, in io.Reader, out io.Writer) (*Client, error) { - return newClient(ctx, func(_ context.Context) (ServerCodec, error) { + return newClient(ctx, newClientTransportIO(in, out)) +} + +func newClientTransportIO(in io.Reader, out io.Writer) reconnectFunc { + return func(context.Context) (ServerCodec, error) { return NewCodec(stdioConn{ in: in, out: out, }), nil - }) + } } type stdioConn struct { diff --git a/rpc/websocket.go b/rpc/websocket.go index 28380d8aa4ae..f2a923446cac 100644 --- a/rpc/websocket.go +++ b/rpc/websocket.go @@ -181,24 +181,23 @@ func parseOriginURL(origin string) (string, string, string, error) { return scheme, hostname, port, nil } -// DialWebsocketWithDialer creates a new RPC client that communicates with a JSON-RPC server -// that is listening on the given endpoint using the provided dialer. +// DialWebsocketWithDialer creates a new RPC client using WebSocket. +// +// The context is used for the initial connection establishment. It does not +// affect subsequent interactions with the client. +// +// Deprecated: use DialOptions and the WithWebsocketDialer option. func DialWebsocketWithDialer(ctx context.Context, endpoint, origin string, dialer websocket.Dialer) (*Client, error) { - endpoint, header, err := wsClientHeaders(endpoint, origin) + cfg := new(clientConfig) + cfg.wsDialer = &dialer + if origin != "" { + cfg.setHeader("origin", origin) + } + connect, err := newClientTransportWS(endpoint, cfg) if err != nil { return nil, err } - return newClient(ctx, func(ctx context.Context) (ServerCodec, error) { - conn, resp, err := dialer.DialContext(ctx, endpoint, header) - if err != nil { - hErr := wsHandshakeError{err: err} - if resp != nil { - hErr.status = resp.Status - } - return nil, hErr - } - return newWebsocketCodec(conn, endpoint, header), nil - }) + return newClient(ctx, connect) } // DialWebsocket creates a new RPC client that communicates with a JSON-RPC server @@ -207,12 +206,53 @@ func DialWebsocketWithDialer(ctx context.Context, endpoint, origin string, diale // The context is used for the initial connection establishment. It does not // affect subsequent interactions with the client. func DialWebsocket(ctx context.Context, endpoint, origin string) (*Client, error) { - dialer := websocket.Dialer{ - ReadBufferSize: wsReadBuffer, - WriteBufferSize: wsWriteBuffer, - WriteBufferPool: wsBufferPool, + cfg := new(clientConfig) + if origin != "" { + cfg.setHeader("origin", origin) + } + connect, err := newClientTransportWS(endpoint, cfg) + if err != nil { + return nil, err + } + return newClient(ctx, connect) +} + +func newClientTransportWS(endpoint string, cfg *clientConfig) (reconnectFunc, error) { + dialer := cfg.wsDialer + if dialer == nil { + dialer = &websocket.Dialer{ + ReadBufferSize: wsReadBuffer, + WriteBufferSize: wsWriteBuffer, + WriteBufferPool: wsBufferPool, + } + } + + dialURL, header, err := wsClientHeaders(endpoint, "") + if err != nil { + return nil, err + } + for key, values := range cfg.httpHeaders { + header[key] = values + } + + connect := func(ctx context.Context) (ServerCodec, error) { + header := header.Clone() + if cfg.httpAuth != nil { + if err := cfg.httpAuth(header); err != nil { + return nil, err + } + } + conn, resp, err := dialer.DialContext(ctx, dialURL, header) + if err != nil { + hErr := wsHandshakeError{err: err} + if resp != nil { + hErr.status = resp.Status + } + return nil, hErr + } + return newWebsocketCodec(conn, dialURL, header), nil } - return DialWebsocketWithDialer(ctx, endpoint, origin, dialer) + return connect, nil } func wsClientHeaders(endpoint, origin string) (string, http.Header, error) { From 38e002f4641c2779c897ccaca575ec5ddeee9254 Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Sat, 3 Sep 2022 00:47:29 +0900 Subject: [PATCH 212/715] rpc: check that "version" is "2.0" in request objects (#25570) The JSON-RPC spec requires the "version" field to be exactly "2.0", so we should verify that. This change is not backwards-compatible with sloppy client implementations, but I decided to go ahead with it anyway because the failure will be caught via the returned error. --- rpc/json.go | 10 +++++++--- rpc/subscription_test.go | 2 +- rpc/testdata/invalid-badversion.js | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 rpc/testdata/invalid-badversion.js diff --git a/rpc/json.go b/rpc/json.go index 6024f1e7dc9b..6b2ac2d52a7b 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -58,21 +58,25 @@ type jsonrpcMessage struct { } func (msg *jsonrpcMessage) isNotification() bool { - return msg.ID == nil && msg.Method != "" + return msg.hasValidVersion() && msg.ID == nil && msg.Method != "" } func (msg *jsonrpcMessage) isCall() bool { - return msg.hasValidID() && msg.Method != "" + return msg.hasValidVersion() && msg.hasValidID() && msg.Method != "" } func (msg *jsonrpcMessage) isResponse() bool { - return msg.hasValidID() && msg.Method == "" && msg.Params == nil && (msg.Result != nil || msg.Error != nil) + return msg.hasValidVersion() && msg.hasValidID() && msg.Method == "" && msg.Params == nil && (msg.Result != nil || msg.Error != nil) } func (msg *jsonrpcMessage) hasValidID() bool { return len(msg.ID) > 0 && msg.ID[0] != '{' && msg.ID[0] != '[' } +func (msg *jsonrpcMessage) hasValidVersion() bool { + return msg.Version == vsn +} + func (msg *jsonrpcMessage) isSubscribe() bool { return strings.HasSuffix(msg.Method, subscribeMethodSuffix) } diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index a920205c001f..b2704578291e 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -79,7 +79,7 @@ func TestSubscriptions(t *testing.T) { request := map[string]interface{}{ "id": i, "method": fmt.Sprintf("%s_subscribe", namespace), - "version": "2.0", + "jsonrpc": "2.0", "params": []interface{}{"someSubscription", notificationCount, i}, } if err := out.Encode(&request); err != nil { diff --git a/rpc/testdata/invalid-badversion.js b/rpc/testdata/invalid-badversion.js new file mode 100644 index 000000000000..75b5291dc3f0 --- /dev/null +++ b/rpc/testdata/invalid-badversion.js @@ -0,0 +1,19 @@ +// This test checks processing of messages with invalid Version. + +--> {"jsonrpc":"2.0","id":1,"method":"test_echo","params":["x", 3]} +<-- {"jsonrpc":"2.0","id":1,"result":{"String":"x","Int":3,"Args":null}} + +--> {"jsonrpc":"2.1","id":1,"method":"test_echo","params":["x", 3]} +<-- {"jsonrpc":"2.0","id":1,"error":{"code":-32600,"message":"invalid request"}} + +--> {"jsonrpc":"go-ethereum","id":1,"method":"test_echo","params":["x", 3]} +<-- {"jsonrpc":"2.0","id":1,"error":{"code":-32600,"message":"invalid request"}} + +--> {"jsonrpc":1,"id":1,"method":"test_echo","params":["x", 3]} +<-- {"jsonrpc":"2.0","id":1,"error":{"code":-32600,"message":"invalid request"}} + +--> {"jsonrpc":2.0,"id":1,"method":"test_echo","params":["x", 3]} +<-- {"jsonrpc":"2.0","id":1,"error":{"code":-32600,"message":"invalid request"}} + +--> {"id":1,"method":"test_echo","params":["x", 3]} +<-- {"jsonrpc":"2.0","id":1,"error":{"code":-32600,"message":"invalid request"}} From 0d68b6bf10350f981caa19cd88f4847e67f28a63 Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Sat, 3 Sep 2022 00:48:26 +0900 Subject: [PATCH 213/715] trie: fix typo in comment (#25667) --- trie/secure_trie.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 1da152477d38..e26c22465504 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -58,7 +58,7 @@ type StateTrie struct { // and returns MissingNodeError if the root node cannot be found. func NewStateTrie(owner common.Hash, root common.Hash, db *Database) (*StateTrie, error) { if db == nil { - panic("trie.NewSecure called without a database") + panic("trie.NewStateTrie called without a database") } trie, err := New(owner, root, db) if err != nil { From 4b9c307d26f19ff228cca379aeace974f26df6ce Mon Sep 17 00:00:00 2001 From: Amir Hossein <77993374+Kamandlou@users.noreply.github.com> Date: Fri, 2 Sep 2022 20:37:55 +0430 Subject: [PATCH 214/715] trie: fix unhandled error in test (#25628) --- trie/util_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/trie/util_test.go b/trie/util_test.go index 252dc09e0804..cf6758e63d4a 100644 --- a/trie/util_test.go +++ b/trie/util_test.go @@ -69,7 +69,9 @@ func TestTrieTracer(t *testing.T) { // Commit the changes and re-create with new root root, nodes, _ := trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) + if err := db.Update(NewWithNodeSet(nodes)); err != nil { + t.Fatal(err) + } trie, _ = New(common.Hash{}, root, db) trie.tracer = newTracer() From 731885809c185665131eb70c74735265c966ebea Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 5 Sep 2022 14:06:16 +0200 Subject: [PATCH 215/715] eth/tracers/js: improve integer types in log object (#25668) All fields related to gas must be represented as uint64. Depth is internally tracked as int, so it makes sense to also store it as int. --- eth/tracers/js/goja.go | 44 ++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 526520c7866f..8360403aa164 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -256,11 +256,11 @@ func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope log.memory.memory = scope.Memory log.stack.stack = scope.Stack log.contract.contract = scope.Contract - log.pc = uint(pc) - log.gas = uint(gas) - log.cost = uint(cost) - log.refund = uint(t.env.StateDB.GetRefund()) - log.depth = uint(depth) + log.pc = pc + log.gas = gas + log.cost = cost + log.refund = t.env.StateDB.GetRefund() + log.depth = depth log.err = err if _, err := t.step(t.obj, t.logValue, t.dbValue); err != nil { t.onError("step", err) @@ -908,33 +908,19 @@ type steplog struct { stack *stackObj contract *contractObj - pc uint - gas uint - cost uint - depth uint - refund uint + pc uint64 + gas uint64 + cost uint64 + depth int + refund uint64 err error } -func (l *steplog) GetPC() uint { - return l.pc -} - -func (l *steplog) GetGas() uint { - return l.gas -} - -func (l *steplog) GetCost() uint { - return l.cost -} - -func (l *steplog) GetDepth() uint { - return l.depth -} - -func (l *steplog) GetRefund() uint { - return l.refund -} +func (l *steplog) GetPC() uint64 { return l.pc } +func (l *steplog) GetGas() uint64 { return l.gas } +func (l *steplog) GetCost() uint64 { return l.cost } +func (l *steplog) GetDepth() int { return l.depth } +func (l *steplog) GetRefund() uint64 { return l.refund } func (l *steplog) GetError() goja.Value { if l.err != nil { From a9ec2ab2e602f2db048f84ca1f4753288571fdd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 6 Sep 2022 12:57:03 +0300 Subject: [PATCH 216/715] trie: check childrens' existence concurrently for snap heal --- trie/sync.go | 57 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/trie/sync.go b/trie/sync.go index 303fcbfa22e2..862ce7e16e6c 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -19,6 +19,7 @@ package trie import ( "errors" "fmt" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/prque" @@ -381,11 +382,11 @@ func (s *Sync) scheduleCodeRequest(req *codeRequest) { // retrieval scheduling. func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { // Gather all the children of the node, irrelevant whether known or not - type child struct { + type childNode struct { path []byte node node } - var children []child + var children []childNode switch node := (object).(type) { case *shortNode: @@ -393,14 +394,14 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { if hasTerm(key) { key = key[:len(key)-1] } - children = []child{{ + children = []childNode{{ node: node.Val, path: append(append([]byte(nil), req.path...), key...), }} case *fullNode: for i := 0; i < 17; i++ { if node.Children[i] != nil { - children = append(children, child{ + children = append(children, childNode{ node: node.Children[i], path: append(append([]byte(nil), req.path...), byte(i)), }) @@ -410,7 +411,10 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { panic(fmt.Sprintf("unknown node: %+v", node)) } // Iterate over the children, and request all unknown ones - requests := make([]*nodeRequest, 0, len(children)) + var ( + missing = make(chan *nodeRequest, len(children)) + pending sync.WaitGroup + ) for _, child := range children { // Notify any external watcher of a new key/value node if req.callback != nil { @@ -433,19 +437,36 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { if s.membatch.hasNode(child.path) { continue } - // If database says duplicate, then at least the trie node is present - // and we hold the assumption that it's NOT legacy contract code. - chash := common.BytesToHash(node) - if rawdb.HasTrieNode(s.database, chash) { - continue - } - // Locally unknown node, schedule for retrieval - requests = append(requests, &nodeRequest{ - path: child.path, - hash: chash, - parent: req, - callback: req.callback, - }) + // Check the presence of children concurrently + pending.Add(1) + go func(child childNode) { + defer pending.Done() + + // If database says duplicate, then at least the trie node is present + // and we hold the assumption that it's NOT legacy contract code. + chash := common.BytesToHash(node) + if rawdb.HasTrieNode(s.database, chash) { + return + } + // Locally unknown node, schedule for retrieval + missing <- &nodeRequest{ + path: child.path, + hash: chash, + parent: req, + callback: req.callback, + } + }(child) + } + } + pending.Wait() + + requests := make([]*nodeRequest, 0, len(children)) + for done := false; !done; { + select { + case miss := <-missing: + requests = append(requests, miss) + default: + done = true } } return requests, nil From 5ddedd2f83729cc91b6e52858f9b3ff58888836d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 7 Sep 2022 15:08:56 +0800 Subject: [PATCH 217/715] core, light, trie: remove DiskDB function from trie database (#25690) --- core/state/database.go | 14 ++++++++++++-- core/state/iterator_test.go | 3 +-- core/state/snapshot/generate_test.go | 24 ++++++++++++------------ core/state/statedb.go | 2 +- core/state/sync_test.go | 4 ++-- light/trie.go | 4 ++++ trie/database.go | 5 ----- 7 files changed, 32 insertions(+), 24 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index 96b6bcfe6551..9b4fd8946e2b 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -54,6 +54,9 @@ type Database interface { // ContractCodeSize retrieves a particular contracts code's size. ContractCodeSize(addrHash, codeHash common.Hash) (int, error) + // DiskDB returns the underlying key-value disk database. + DiskDB() ethdb.KeyValueStore + // TrieDB retrieves the low level trie database used for data storage. TrieDB() *trie.Database } @@ -130,6 +133,7 @@ func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { csc, _ := lru.New(codeSizeCacheSize) return &cachingDB{ db: trie.NewDatabaseWithConfig(db, config), + disk: db, codeSizeCache: csc, codeCache: fastcache.New(codeCacheSize), } @@ -137,6 +141,7 @@ func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { type cachingDB struct { db *trie.Database + disk ethdb.KeyValueStore codeSizeCache *lru.Cache codeCache *fastcache.Cache } @@ -174,7 +179,7 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 { return code, nil } - code := rawdb.ReadCode(db.db.DiskDB(), codeHash) + code := rawdb.ReadCode(db.disk, codeHash) if len(code) > 0 { db.codeCache.Set(codeHash.Bytes(), code) db.codeSizeCache.Add(codeHash, len(code)) @@ -190,7 +195,7 @@ func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]b if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 { return code, nil } - code := rawdb.ReadCodeWithPrefix(db.db.DiskDB(), codeHash) + code := rawdb.ReadCodeWithPrefix(db.disk, codeHash) if len(code) > 0 { db.codeCache.Set(codeHash.Bytes(), code) db.codeSizeCache.Add(codeHash, len(code)) @@ -208,6 +213,11 @@ func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, erro return len(code), err } +// DiskDB returns the underlying key-value disk database. +func (db *cachingDB) DiskDB() ethdb.KeyValueStore { + return db.disk +} + // TrieDB retrieves any intermediate trie-node caching layer. func (db *cachingDB) TrieDB() *trie.Database { return db.db diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index d1afe9ca3eb7..f9337512647a 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -21,7 +21,6 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" ) // Tests that the node iterator indeed walks over the entire database contents. @@ -55,7 +54,7 @@ func TestNodeIteratorCoverage(t *testing.T) { t.Errorf("state entry not reported %x", hash) } } - it := db.TrieDB().DiskDB().(ethdb.Database).NewIterator(nil, nil) + it := db.DiskDB().NewIterator(nil, nil) for it.Next() { key := it.Key() if bytes.HasPrefix(key, []byte("secure-key-")) { diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 5e5ded61ea2f..447ca80cae4b 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -491,12 +491,12 @@ func TestGenerateWithExtraAccounts(t *testing.T) { // Identical in the snap key := hashData([]byte("acc-1")) - rawdb.WriteAccountSnapshot(helper.triedb.DiskDB(), key, val) - rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("key-1")), []byte("val-1")) - rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("key-2")), []byte("val-2")) - rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("key-3")), []byte("val-3")) - rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("key-4")), []byte("val-4")) - rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("key-5")), []byte("val-5")) + rawdb.WriteAccountSnapshot(helper.diskdb, key, val) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-1")), []byte("val-1")) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-2")), []byte("val-2")) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-3")), []byte("val-3")) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-4")), []byte("val-4")) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("key-5")), []byte("val-5")) } { // Account two exists only in the snapshot @@ -508,15 +508,15 @@ func TestGenerateWithExtraAccounts(t *testing.T) { acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()} val, _ := rlp.EncodeToBytes(acc) key := hashData([]byte("acc-2")) - rawdb.WriteAccountSnapshot(helper.triedb.DiskDB(), key, val) - rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("b-key-1")), []byte("b-val-1")) - rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("b-key-2")), []byte("b-val-2")) - rawdb.WriteStorageSnapshot(helper.triedb.DiskDB(), key, hashData([]byte("b-key-3")), []byte("b-val-3")) + rawdb.WriteAccountSnapshot(helper.diskdb, key, val) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-1")), []byte("b-val-1")) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-2")), []byte("b-val-2")) + rawdb.WriteStorageSnapshot(helper.diskdb, key, hashData([]byte("b-key-3")), []byte("b-val-3")) } root := helper.Commit() // To verify the test: If we now inspect the snap db, there should exist extraneous storage items - if data := rawdb.ReadStorageSnapshot(helper.triedb.DiskDB(), hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data == nil { + if data := rawdb.ReadStorageSnapshot(helper.diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data == nil { t.Fatalf("expected snap storage to exist") } snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) @@ -534,7 +534,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) { snap.genAbort <- stop <-stop // If we now inspect the snap db, there should exist no extraneous storage items - if data := rawdb.ReadStorageSnapshot(helper.triedb.DiskDB(), hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil { + if data := rawdb.ReadStorageSnapshot(helper.diskdb, hashData([]byte("acc-2")), hashData([]byte("b-key-1"))); data != nil { t.Fatalf("expected slot to be removed, got %v", string(data)) } } diff --git a/core/state/statedb.go b/core/state/statedb.go index 50eee8183c31..a649e0bd11d3 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -908,7 +908,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { storageTrieNodes int nodes = trie.NewMergedNodeSet() ) - codeWriter := s.db.TrieDB().DiskDB().NewBatch() + codeWriter := s.db.DiskDB().NewBatch() for addr := range s.stateObjectsDirty { if obj := s.stateObjects[addr]; !obj.deleted { // Write any contract code associated with the state object diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 3d9fe556d2ad..d16c7ce7322c 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -100,7 +100,7 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accou } // checkTrieConsistency checks that all nodes in a (sub-)trie are indeed present. -func checkTrieConsistency(db ethdb.Database, root common.Hash) error { +func checkTrieConsistency(db ethdb.KeyValueStore, root common.Hash) error { if v, _ := db.Get(root[:]); v == nil { return nil // Consider a non existent state consistent. } @@ -553,7 +553,7 @@ func TestIncompleteStateSync(t *testing.T) { } } isCode[common.BytesToHash(emptyCodeHash)] = struct{}{} - checkTrieConsistency(srcDb.TrieDB().DiskDB().(ethdb.Database), srcRoot) + checkTrieConsistency(srcDb.DiskDB(), srcRoot) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() diff --git a/light/trie.go b/light/trie.go index b88265e87d40..0f2e38625539 100644 --- a/light/trie.go +++ b/light/trie.go @@ -96,6 +96,10 @@ func (db *odrDatabase) TrieDB() *trie.Database { return nil } +func (db *odrDatabase) DiskDB() ethdb.KeyValueStore { + panic("not implemented") +} + type odrTrie struct { db *odrDatabase id *TrieID diff --git a/trie/database.go b/trie/database.go index 8d426c252347..cca2bb085317 100644 --- a/trie/database.go +++ b/trie/database.go @@ -304,11 +304,6 @@ func NewDatabaseWithConfig(diskdb ethdb.KeyValueStore, config *Config) *Database return db } -// DiskDB retrieves the persistent storage backing the trie database. -func (db *Database) DiskDB() ethdb.KeyValueStore { - return db.diskdb -} - // insert inserts a simplified trie node into the memory database. // All nodes inserted by this function will be reference tracked // and in theory should only used for **trie nodes** insertion. From a32a02f237cbcce4c7555fe84b1684d333997110 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 7 Sep 2022 17:48:34 +0800 Subject: [PATCH 218/715] params: update chts (#25707) --- params/config.go | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/params/config.go b/params/config.go index d535d230493c..64b5abb7cc9d 100644 --- a/params/config.go +++ b/params/config.go @@ -82,10 +82,10 @@ var ( // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network. MainnetTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 451, - SectionHead: common.HexToHash("0xe47f84b9967eb2ad2afff74d59901b63134660011822fdababaf8fdd18a75aa6"), - CHTRoot: common.HexToHash("0xc31e0462ca3d39a46111bb6b63ac4e1cac84089472b7474a319d582f72b3f0c0"), - BloomRoot: common.HexToHash("0x7c9f25ce3577a3ab330d52a7343f801899cf9d4980c69f81de31ccc1a055c809"), + SectionIndex: 471, + SectionHead: common.HexToHash("0xa03d6354f5ca8d33203bb646ac26a964f240ee54728dcb7483faff0204ec4c9b"), + CHTRoot: common.HexToHash("0x29efeeea3540b7f499b4214d5262bd1fcd87253de10a878f92e6497d848b186f"), + BloomRoot: common.HexToHash("0x2ff6a93ff5e78e823bfc80c6ec856bfe9b20c4ffd0af3cef644a916eabcd3c84"), } // MainnetCheckpointOracle contains a set of configs for the main network oracle. @@ -125,10 +125,10 @@ var ( // RopstenTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network. RopstenTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 346, - SectionHead: common.HexToHash("0xafa0384ebd13a751fb7475aaa7fc08ac308925c8b2e2195bca2d4ab1878a7a84"), - CHTRoot: common.HexToHash("0x522ae1f334bfa36033b2315d0b9954052780700b69448ecea8d5877e0f7ee477"), - BloomRoot: common.HexToHash("0x4093fd53b0d2cc50181dca353fe66f03ae113e7cb65f869a4dfb5905de6a0493"), + SectionIndex: 393, + SectionHead: common.HexToHash("0x04479087c89428c6ed0d4ff25642776f0c35747d8ecef90547fa3ce4ebec8606"), + CHTRoot: common.HexToHash("0xaa100968cebe48dba3a8f196f044db04113d5a938ff083838ce6f2c588d416ad"), + BloomRoot: common.HexToHash("0xb9108d510c4b50b60793feead27620781bc1c2164e072d8022201c4eb7c36ba0"), } // RopstenCheckpointOracle contains a set of configs for the Ropsten test network oracle. @@ -168,10 +168,10 @@ var ( // SepoliaTrustedCheckpoint contains the light client trusted checkpoint for the Sepolia test network. SepoliaTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 34, - SectionHead: common.HexToHash("0xe361400fcbc468d641e7bdd0b0946a3548e97c5d2703b124f04a3f1deccec244"), - CHTRoot: common.HexToHash("0xea6768fd288dce7d84f590884908ec39e4de78e6e1a38de5c5419b0f49a42f91"), - BloomRoot: common.HexToHash("0x06d32f35d5a611bfd0333ad44e39c619449824167d8ef2913edc48a8112be2cd"), + SectionIndex: 55, + SectionHead: common.HexToHash("0xb70ea113ab4db9d6e015c5b55d486713f60c40bda666121914a71ce3aec53a75"), + CHTRoot: common.HexToHash("0x206456d8847b66aaf427ed551f55e24cff90241bdb0a02583c761bf8164f78e4"), + BloomRoot: common.HexToHash("0x4369228d59a8fe285fee874c636531091e659b3b1294bb978eb159860a1cede2"), } // RinkebyChainConfig contains the chain parameters to run a node on the Rinkeby test network. @@ -200,10 +200,10 @@ var ( // RinkebyTrustedCheckpoint contains the light client trusted checkpoint for the Rinkeby test network. RinkebyTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 326, - SectionHead: common.HexToHash("0x941a41a153b0e36cb15d9d193d1d0f9715bdb2435efd1c95119b64168667ce00"), - CHTRoot: common.HexToHash("0xe2331e00d579cf4093091dee35bef772e63c2341380c276041dc22563c8aba2e"), - BloomRoot: common.HexToHash("0x595206febcf118958c2bc1218ea71d01fd04b8f97ad71813df4be0af5b36b0e5"), + SectionIndex: 344, + SectionHead: common.HexToHash("0x06bb973aecce633df8cda532ff75b9d0b38c16de2545f52eaf745f858d0fe616"), + CHTRoot: common.HexToHash("0xf1c80b9270ef9fb7907362bca006f8349f0c38d45b83167b57638f54211c6aca"), + BloomRoot: common.HexToHash("0xd72187253f49bce9d471f5e0ddf2b5008ba695d7a1be1192d52fb4d8b01970c6"), } // RinkebyCheckpointOracle contains a set of configs for the Rinkeby test network oracle. @@ -245,10 +245,10 @@ var ( // GoerliTrustedCheckpoint contains the light client trusted checkpoint for the Görli test network. GoerliTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 210, - SectionHead: common.HexToHash("0xbb11eaf551a6c06f74a6c7bbfe1699cbf64b8f248b64691da916dd443176db2f"), - CHTRoot: common.HexToHash("0x9934ae326d00d9c7de2e074c0e51689efb7fa7fcba18929ff4279c27259c45e6"), - BloomRoot: common.HexToHash("0x7fe3bd4fd45194aa8a5cfe5ac590edff1f870d3d98d3c310494e7f67613a87ff"), + SectionIndex: 229, + SectionHead: common.HexToHash("0xc5a7b57cb4af7b3d4cc251ac5f29acaac94e7464365358e7ad26129083b7729a"), + CHTRoot: common.HexToHash("0x54c0d5c756d9c48eda26ea13c2a49c2e31f1cb7dfb01514ddc49f3d24272c77e"), + BloomRoot: common.HexToHash("0xd681970a496f6187d089f8c8665a3587b5a78212d79b6ceef97c0dabd0188e56"), } // GoerliCheckpointOracle contains a set of configs for the Goerli test network oracle. From d30e39b2f833fb75f1e529cd405061fb6b548b8d Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 7 Sep 2022 13:09:52 +0200 Subject: [PATCH 219/715] core/vm: rename RANDOM to PREVRANDAO (#25691) See: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4399.md > This EIP supplants the semantics of the return value of existing DIFFICULTY (0x44) opcode and renames the opcode to PREVRANDAO (0x44). --- core/vm/evm.go | 2 +- core/vm/jump_table.go | 2 +- core/vm/opcodes.go | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index dd55618bf812..888f4812a590 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -75,7 +75,7 @@ type BlockContext struct { Time *big.Int // Provides information for TIME Difficulty *big.Int // Provides information for DIFFICULTY BaseFee *big.Int // Provides information for BASEFEE - Random *common.Hash // Provides information for RANDOM + Random *common.Hash // Provides information for PREVRANDAO } // TxContext provides the EVM with information about a transaction. diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 707b52e79daf..94229436d23c 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -80,7 +80,7 @@ func validate(jt JumpTable) JumpTable { func newMergeInstructionSet() JumpTable { instructionSet := newLondonInstructionSet() - instructionSet[RANDOM] = &operation{ + instructionSet[PREVRANDAO] = &operation{ execute: opRandom, constantGas: GasQuickStep, minStack: minStack(0, 1), diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 77d619abb9c1..70d854f15e9f 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -99,6 +99,7 @@ const ( NUMBER OpCode = 0x43 DIFFICULTY OpCode = 0x44 RANDOM OpCode = 0x44 // Same as DIFFICULTY + PREVRANDAO OpCode = 0x44 // Same as DIFFICULTY GASLIMIT OpCode = 0x45 CHAINID OpCode = 0x46 SELFBALANCE OpCode = 0x47 @@ -280,7 +281,7 @@ var opCodeToString = map[OpCode]string{ COINBASE: "COINBASE", TIMESTAMP: "TIMESTAMP", NUMBER: "NUMBER", - DIFFICULTY: "DIFFICULTY", // TODO (MariusVanDerWijden) rename to RANDOM post merge + DIFFICULTY: "DIFFICULTY", // TODO (MariusVanDerWijden) rename to PREVRANDAO post merge GASLIMIT: "GASLIMIT", CHAINID: "CHAINID", SELFBALANCE: "SELFBALANCE", From dea1fb3cfc9e9f14bb49750289aa787ca96d44fa Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 8 Sep 2022 02:21:59 +0800 Subject: [PATCH 220/715] all: cleanup tests (#25641) Follow-up to PR #25523 to cleanup all relevant tests. --- accounts/abi/bind/backends/simulated.go | 7 +- consensus/clique/clique_test.go | 7 +- consensus/clique/snapshot_test.go | 10 +- core/bench_test.go | 7 +- core/block_validator_test.go | 88 ++-- core/blockchain_repair_test.go | 16 +- core/blockchain_sethead_test.go | 9 +- core/blockchain_snapshot_test.go | 17 +- core/blockchain_test.go | 559 +++++++++--------------- core/chain_makers.go | 40 +- core/dao_test.go | 36 +- core/headerchain_test.go | 14 +- core/rlp_test.go | 10 +- core/state_processor_test.go | 9 +- eth/catalyst/api_test.go | 12 +- eth/downloader/downloader_test.go | 2 - eth/downloader/testchain_test.go | 9 +- eth/fetcher/block_fetcher_test.go | 5 +- eth/filters/filter_system_test.go | 9 +- eth/filters/filter_test.go | 27 +- eth/gasprice/gasprice_test.go | 8 +- eth/handler_eth_test.go | 7 +- eth/handler_test.go | 4 +- eth/protocols/eth/handler_test.go | 7 +- eth/tracers/api_test.go | 10 +- ethclient/ethclient_test.go | 9 +- ethclient/gethclient/gethclient_test.go | 11 +- les/catalyst/api_test.go | 10 +- les/odr_test.go | 2 +- light/odr_test.go | 28 +- light/trie_test.go | 9 +- light/txpool_test.go | 7 +- miner/worker_test.go | 46 +- tests/fuzzers/les/les-fuzzer.go | 8 +- tests/fuzzers/snap/fuzz_handler.go | 7 +- 35 files changed, 427 insertions(+), 639 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 0095edbdb4b0..7cd03d14e465 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -78,8 +78,11 @@ type SimulatedBackend struct { // and uses a simulated blockchain for testing purposes. // A simulated backend always uses chainID 1337. func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { - genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc} - genesis.MustCommit(database) + genesis := core.Genesis{ + Config: params.AllEthashProtocolChanges, + GasLimit: gasLimit, + Alloc: alloc, + } blockchain, _ := core.NewBlockChain(database, nil, &genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) backend := &SimulatedBackend{ diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index 74d884a21b9f..f213bc8247d6 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -53,13 +53,12 @@ func TestReimportMirroredState(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), } copy(genspec.ExtraData[extraVanity:], addr[:]) - genesis := genspec.MustCommit(db) // Generate a batch of blocks, each properly signed - chain, _ := core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, engine, vm.Config{}, nil, nil) defer chain.Stop() - blocks, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, 3, func(i int, block *core.BlockGen) { + _, blocks, _ := core.GenerateChainWithGenesis(genspec, engine, 3, func(i int, block *core.BlockGen) { // The chain maker doesn't have access to a chain, so the difficulty will be // lets unset (nil). Set it here to the correct value. block.SetDifficulty(diffInTurn) @@ -88,8 +87,6 @@ func TestReimportMirroredState(t *testing.T) { } // Insert the first two blocks and make sure the chain is valid db = rawdb.NewMemoryDatabase() - genspec.MustCommit(db) - chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil, nil) defer chain.Stop() diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index a1e481abbf46..4f9222d0927a 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -401,9 +401,6 @@ func TestClique(t *testing.T) { for j, signer := range signers { copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:]) } - // Create a pristine blockchain with the genesis injected - db := rawdb.NewMemoryDatabase() - genesisBlock := genesis.MustCommit(db) // Assemble a chain of headers from the cast votes config := *params.TestChainConfig @@ -412,10 +409,11 @@ func TestClique(t *testing.T) { Epoch: tt.epoch, } genesis.Config = &config - engine := New(config.Clique, db) + + engine := New(config.Clique, rawdb.NewMemoryDatabase()) engine.fakeDiff = true - blocks, _ := core.GenerateChain(&config, genesisBlock, engine, db, len(tt.votes), func(j int, gen *core.BlockGen) { + _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, len(tt.votes), func(j int, gen *core.BlockGen) { // Cast the vote contained in this block gen.SetCoinbase(accounts.address(tt.votes[j].voted)) if tt.votes[j].auth { @@ -451,7 +449,7 @@ func TestClique(t *testing.T) { batches[len(batches)-1] = append(batches[len(batches)-1], block) } // Pass all the headers through clique and ensure tallying succeeds - chain, err := core.NewBlockChain(db, nil, genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Errorf("test %d: failed to create test chain: %v", i, err) continue diff --git a/core/bench_test.go b/core/bench_test.go index e448310e4d58..f7cf0146060d 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -187,16 +187,15 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Generate a chain of b.N blocks using the supplied block // generator function. - gspec := Genesis{ + gspec := &Genesis{ Config: params.TestChainConfig, Alloc: GenesisAlloc{benchRootAddr: {Balance: benchRootFunds}}, } - genesis := gspec.MustCommit(db) - chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, b.N, gen) + _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), b.N, gen) // Time the insertion of the new chain. // State and blocks are stored in the same DB. - chainman, _ := NewBlockChain(db, nil, &gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chainman, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 815bc86552a7..3bdb20e7e1e7 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -39,17 +39,15 @@ import ( func TestHeaderVerification(t *testing.T) { // Create a simple chain to verify var ( - testdb = rawdb.NewMemoryDatabase() - gspec = &Genesis{Config: params.TestChainConfig} - genesis = gspec.MustCommit(testdb) - blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) + gspec = &Genesis{Config: params.TestChainConfig} + _, blocks, _ = GenerateChainWithGenesis(gspec, ethash.NewFaker(), 8, nil) ) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { headers[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(testdb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer chain.Stop() for i := 0; i < len(blocks); i++ { @@ -89,21 +87,21 @@ func TestHeaderVerificationForMergingEthash(t *testing.T) { testHeaderVerificati // Tests the verification for eth1/2 merging, including pre-merge and post-merge func testHeaderVerificationForMerging(t *testing.T, isClique bool) { var ( - testdb = rawdb.NewMemoryDatabase() + gspec *Genesis preBlocks []*types.Block postBlocks []*types.Block - runEngine consensus.Engine - genspec *Genesis + engine consensus.Engine merger = consensus.NewMerger(rawdb.NewMemoryDatabase()) ) if isClique { var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key.PublicKey) - engine = clique.New(params.AllCliqueProtocolChanges.Clique, testdb) + config = *params.AllCliqueProtocolChanges ) - genspec = &Genesis{ - Config: params.AllCliqueProtocolChanges, + engine = beacon.New(clique.New(params.AllCliqueProtocolChanges.Clique, rawdb.NewMemoryDatabase())) + gspec = &Genesis{ + Config: &config, ExtraData: make([]byte, 32+common.AddressLength+crypto.SignatureLength), Alloc: map[common.Address]GenesisAccount{ addr: {Balance: big.NewInt(1)}, @@ -111,50 +109,44 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { BaseFee: big.NewInt(params.InitialBaseFee), Difficulty: new(big.Int), } - copy(genspec.ExtraData[32:], addr[:]) - genesis := genspec.MustCommit(testdb) + copy(gspec.ExtraData[32:], addr[:]) - genEngine := beacon.New(engine) - preBlocks, _ = GenerateChain(params.AllCliqueProtocolChanges, genesis, genEngine, testdb, 8, nil) td := 0 - for i, block := range preBlocks { + genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 8, nil) + for i, block := range blocks { header := block.Header() if i > 0 { - header.ParentHash = preBlocks[i-1].Hash() + header.ParentHash = blocks[i-1].Hash() } header.Extra = make([]byte, 32+crypto.SignatureLength) header.Difficulty = big.NewInt(2) - sig, _ := crypto.Sign(genEngine.SealHash(header).Bytes(), key) + sig, _ := crypto.Sign(engine.SealHash(header).Bytes(), key) copy(header.Extra[len(header.Extra)-crypto.SignatureLength:], sig) - preBlocks[i] = block.WithSeal(header) + blocks[i] = block.WithSeal(header) + // calculate td td += int(block.Difficulty().Uint64()) } - config := *params.AllCliqueProtocolChanges - config.TerminalTotalDifficulty = big.NewInt(int64(td)) - postBlocks, _ = GenerateChain(&config, preBlocks[len(preBlocks)-1], genEngine, testdb, 8, nil) - runEngine = beacon.New(engine) - genspec.Config = &config + preBlocks = blocks + gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(td)) + postBlocks, _ = GenerateChain(gspec.Config, preBlocks[len(preBlocks)-1], engine, genDb, 8, nil) } else { - genspec = &Genesis{Config: params.TestChainConfig} - genesis := genspec.MustCommit(testdb) - genEngine := beacon.New(ethash.NewFaker()) + config := *params.TestChainConfig + gspec = &Genesis{Config: &config} + engine = beacon.New(ethash.NewFaker()) - preBlocks, _ = GenerateChain(params.TestChainConfig, genesis, genEngine, testdb, 8, nil) td := 0 + genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 8, nil) for _, block := range preBlocks { // calculate td td += int(block.Difficulty().Uint64()) } - config := *params.TestChainConfig - config.TerminalTotalDifficulty = big.NewInt(int64(td)) - postBlocks, _ = GenerateChain(params.TestChainConfig, preBlocks[len(preBlocks)-1], genEngine, testdb, 8, nil) - - runEngine = beacon.New(ethash.NewFaker()) - genspec.Config = &config + preBlocks = blocks + gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(td)) + postBlocks, _ = GenerateChain(gspec.Config, preBlocks[len(preBlocks)-1], engine, genDb, 8, nil) } - + // Assemble header batch preHeaders := make([]*types.Header, len(preBlocks)) for i, block := range preBlocks { preHeaders[i] = block.Header() @@ -170,12 +162,12 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { t.Logf("Log header after the merging %d: %v", block.NumberU64(), string(blob)) } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(testdb, nil, genspec, nil, runEngine, vm.Config{}, nil, nil) + chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) defer chain.Stop() // Verify the blocks before the merging for i := 0; i < len(preBlocks); i++ { - _, results := runEngine.VerifyHeaders(chain, []*types.Header{preHeaders[i]}, []bool{true}) + _, results := engine.VerifyHeaders(chain, []*types.Header{preHeaders[i]}, []bool{true}) // Wait for the verification result select { case result := <-results: @@ -200,7 +192,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { // Verify the blocks after the merging for i := 0; i < len(postBlocks); i++ { - _, results := runEngine.VerifyHeaders(chain, []*types.Header{postHeaders[i]}, []bool{true}) + _, results := engine.VerifyHeaders(chain, []*types.Header{postHeaders[i]}, []bool{true}) // Wait for the verification result select { case result := <-results: @@ -232,7 +224,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { headers = append(headers, block.Header()) seals = append(seals, true) } - _, results := runEngine.VerifyHeaders(chain, headers, seals) + _, results := engine.VerifyHeaders(chain, headers, seals) for i := 0; i < len(headers); i++ { select { case result := <-results: @@ -259,10 +251,8 @@ func TestHeaderConcurrentVerification32(t *testing.T) { testHeaderConcurrentVeri func testHeaderConcurrentVerification(t *testing.T, threads int) { // Create a simple chain to verify var ( - testdb = rawdb.NewMemoryDatabase() - gspec = &Genesis{Config: params.TestChainConfig} - genesis = gspec.MustCommit(testdb) - blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) + gspec = &Genesis{Config: params.TestChainConfig} + _, blocks, _ = GenerateChainWithGenesis(gspec, ethash.NewFaker(), 8, nil) ) headers := make([]*types.Header, len(blocks)) seals := make([]bool, len(blocks)) @@ -281,11 +271,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { var results <-chan error if valid { - chain, _ := NewBlockChain(testdb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } else { - chain, _ := NewBlockChain(testdb, nil, gspec, nil, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } @@ -331,10 +321,8 @@ func TestHeaderConcurrentAbortion32(t *testing.T) { testHeaderConcurrentAbortion func testHeaderConcurrentAbortion(t *testing.T, threads int) { // Create a simple chain to verify var ( - testdb = rawdb.NewMemoryDatabase() - gspec = &Genesis{Config: params.TestChainConfig} - genesis = gspec.MustCommit(testdb) - blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 1024, nil) + gspec = &Genesis{Config: params.TestChainConfig} + _, blocks, _ = GenerateChainWithGenesis(gspec, ethash.NewFaker(), 1024, nil) ) headers := make([]*types.Header, len(blocks)) seals := make([]bool, len(blocks)) @@ -348,7 +336,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { defer runtime.GOMAXPROCS(old) // Start the verifications and immediately abort - chain, _ := NewBlockChain(testdb, nil, gspec, nil, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil) defer chain.Stop() abort, results := chain.engine.VerifyHeaders(chain, headers, seals) diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 04154158c9d9..6e61f89c3b14 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1768,9 +1768,8 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges, } - genesis = gspec.MustCommit(db) - engine = ethash.NewFullFaker() - config = &CacheConfig{ + engine = ethash.NewFullFaker() + config = &CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, @@ -1789,14 +1788,14 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { // If sidechain blocks are needed, make a light chain and import it var sideblocks types.Blocks if tt.sidechainBlocks > 0 { - sideblocks, _ = GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *BlockGen) { + sideblocks, _ = GenerateChain(gspec.Config, gspec.ToBlock(), engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{0x01}) }) if _, err := chain.InsertChain(sideblocks); err != nil { t.Fatalf("Failed to import side chain: %v", err) } } - canonblocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *BlockGen) { + canonblocks, _ := GenerateChain(gspec.Config, gspec.ToBlock(), engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{0x02}) b.SetDifficulty(big.NewInt(1000000)) }) @@ -1896,9 +1895,8 @@ func TestIssue23496(t *testing.T) { Config: params.TestChainConfig, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(db) - engine = ethash.NewFullFaker() - config = &CacheConfig{ + engine = ethash.NewFullFaker() + config = &CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, @@ -1910,7 +1908,7 @@ func TestIssue23496(t *testing.T) { if err != nil { t.Fatalf("Failed to create chain: %v", err) } - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), 4, func(i int, b *BlockGen) { + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 4, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{0x02}) b.SetDifficulty(big.NewInt(1000000)) }) diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index c5df7949ef6c..1eb588d02fd1 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -1968,9 +1968,8 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges, } - genesis = gspec.MustCommit(db) - engine = ethash.NewFullFaker() - config = &CacheConfig{ + engine = ethash.NewFullFaker() + config = &CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, @@ -1988,14 +1987,14 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { // If sidechain blocks are needed, make a light chain and import it var sideblocks types.Blocks if tt.sidechainBlocks > 0 { - sideblocks, _ = GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *BlockGen) { + sideblocks, _ = GenerateChain(gspec.Config, gspec.ToBlock(), engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{0x01}) }) if _, err := chain.InsertChain(sideblocks); err != nil { t.Fatalf("Failed to import side chain: %v", err) } } - canonblocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *BlockGen) { + canonblocks, _ := GenerateChain(gspec.Config, gspec.ToBlock(), engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{0x02}) b.SetDifficulty(big.NewInt(1000000)) }) diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index 01a88d7a3c7d..1b38ad51e985 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -52,7 +52,7 @@ type snapshotTestBasic struct { // share fields, set in runtime datadir string db ethdb.Database - gendb ethdb.Database + genDb ethdb.Database engine consensus.Engine gspec *Genesis } @@ -71,9 +71,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges, } - genesis = gspec.MustCommit(db) - engine = ethash.NewFullFaker() - gendb = rawdb.NewMemoryDatabase() + engine = ethash.NewFullFaker() // Snapshot is enabled, the first snapshot is created from the Genesis. // The snapshot memory allowance is 256MB, it means no snapshot flush @@ -84,7 +82,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo if err != nil { t.Fatalf("Failed to create chain: %v", err) } - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, gendb, basic.chainBlocks, func(i int, b *BlockGen) {}) + genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, basic.chainBlocks, func(i int, b *BlockGen) {}) // Insert the blocks with configured settings. var breakpoints []uint64 @@ -121,7 +119,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo // Set runtime fields basic.datadir = datadir basic.db = db - basic.gendb = gendb + basic.genDb = genDb basic.engine = engine basic.gspec = gspec return chain, blocks @@ -207,7 +205,7 @@ func (basic *snapshotTestBasic) dump() string { func (basic *snapshotTestBasic) teardown() { basic.db.Close() - basic.gendb.Close() + basic.genDb.Close() os.RemoveAll(basic.datadir) } @@ -294,7 +292,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { // Insert blocks without enabling snapshot if gapping is required. chain.Stop() - gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.gapped, func(i int, b *BlockGen) {}) + gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.gapped, func(i int, b *BlockGen) {}) // Insert a few more blocks without enabling snapshot var cacheConfig = &CacheConfig{ @@ -378,7 +376,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } - newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {}) + newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.newBlocks, func(i int, b *BlockGen) {}) newchain.InsertChain(newBlocks) newchain.Stop() @@ -395,7 +393,6 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { t.Fatalf("Failed to recreate chain: %v", err) } // Simulate the blockchain crash. - newchain, err = NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 713ac2809a2a..c17a81048f24 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -50,33 +50,32 @@ var ( // newCanonical creates a chain database, and injects a deterministic canonical // chain. Depending on the full flag, if creates either a full block chain or a -// header only chain. -func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) { +// header only chain. The database and genesis specification for block generation +// are also returned in case more test blocks are needed later. +func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *Genesis, *BlockChain, error) { var ( - db = rawdb.NewMemoryDatabase() - gspec = &Genesis{ + genesis = &Genesis{ BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges, } - genesis = gspec.MustCommit(db) ) - // Initialize a fresh chain with only a genesis block - blockchain, _ := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) + // Create and inject the requested chain if n == 0 { - return db, blockchain, nil + return rawdb.NewMemoryDatabase(), genesis, blockchain, nil } if full { // Full block-chain requested - blocks := makeBlockChain(genesis, n, engine, db, canonicalSeed) + genDb, blocks := makeBlockChainWithGenesis(genesis, n, engine, canonicalSeed) _, err := blockchain.InsertChain(blocks) - return db, blockchain, err + return genDb, genesis, blockchain, err } // Header-only chain requested - headers := makeHeaderChain(genesis.Header(), n, engine, db, canonicalSeed) + genDb, headers := makeHeaderChainWithGenesis(genesis, n, engine, canonicalSeed) _, err := blockchain.InsertHeaderChain(headers, 1) - return db, blockchain, err + return genDb, genesis, blockchain, err } func newGwei(n int64) *big.Int { @@ -86,7 +85,7 @@ func newGwei(n int64) *big.Int { // Test fork of length N starting from block i func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int)) { // Copy old chain up to #i into a new db - db, blockchain2, err := newCanonical(ethash.NewFaker(), i, full) + genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full) if err != nil { t.Fatal("could not make new canonical in testFork", err) } @@ -110,12 +109,12 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara headerChainB []*types.Header ) if full { - blockChainB = makeBlockChain(blockchain2.CurrentBlock(), n, ethash.NewFaker(), db, forkSeed) + blockChainB = makeBlockChain(blockchain2.chainConfig, blockchain2.CurrentBlock(), n, ethash.NewFaker(), genDb, forkSeed) if _, err := blockchain2.InsertChain(blockChainB); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } } else { - headerChainB = makeHeaderChain(blockchain2.CurrentHeader(), n, ethash.NewFaker(), db, forkSeed) + headerChainB = makeHeaderChain(blockchain2.chainConfig, blockchain2.CurrentHeader(), n, ethash.NewFaker(), genDb, forkSeed) if _, err := blockchain2.InsertHeaderChain(headerChainB, 1); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } @@ -201,13 +200,13 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error } func TestLastBlock(t *testing.T) { - _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } defer blockchain.Stop() - blocks := makeBlockChain(blockchain.CurrentBlock(), 1, ethash.NewFullFaker(), blockchain.db, 0) + blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 1, ethash.NewFullFaker(), genDb, 0) if _, err := blockchain.InsertChain(blocks); err != nil { t.Fatalf("Failed to insert block: %v", err) } @@ -220,7 +219,7 @@ func TestLastBlock(t *testing.T) { // The chain is reorged to whatever specified. func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full bool) { // Copy old chain up to #i into a new db - db, blockchain2, err := newCanonical(ethash.NewFaker(), i, full) + genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full) if err != nil { t.Fatal("could not make new canonical in testFork", err) } @@ -241,7 +240,7 @@ func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full b // Extend the newly created chain if full { - blockChainB := makeBlockChain(blockchain2.CurrentBlock(), n, ethash.NewFaker(), db, forkSeed) + blockChainB := makeBlockChain(blockchain2.chainConfig, blockchain2.CurrentBlock(), n, ethash.NewFaker(), genDb, forkSeed) if _, err := blockchain2.InsertChain(blockChainB); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } @@ -252,7 +251,7 @@ func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full b t.Fatalf("failed to reorg to the given chain") } } else { - headerChainB := makeHeaderChain(blockchain2.CurrentHeader(), n, ethash.NewFaker(), db, forkSeed) + headerChainB := makeHeaderChain(blockchain2.chainConfig, blockchain2.CurrentHeader(), n, ethash.NewFaker(), genDb, forkSeed) if _, err := blockchain2.InsertHeaderChain(headerChainB, 1); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } @@ -274,7 +273,7 @@ func testExtendCanonical(t *testing.T, full bool) { length := 5 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -302,7 +301,7 @@ func testExtendCanonicalAfterMerge(t *testing.T, full bool) { length := 5 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -321,7 +320,7 @@ func testShorterFork(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -351,7 +350,7 @@ func testShorterForkAfterMerge(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -374,7 +373,7 @@ func testLongerFork(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -397,7 +396,7 @@ func testLongerForkAfterMerge(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -420,7 +419,7 @@ func testEqualFork(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -450,7 +449,7 @@ func testEqualForkAfterMerge(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, processor, err := newCanonical(ethash.NewFaker(), length, full) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -470,7 +469,7 @@ func TestBrokenBlockChain(t *testing.T) { testBrokenChain(t, true) } func testBrokenChain(t *testing.T, full bool) { // Make chain starting from genesis - db, blockchain, err := newCanonical(ethash.NewFaker(), 10, full) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 10, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -478,12 +477,12 @@ func testBrokenChain(t *testing.T, full bool) { // Create a forked chain, and try to insert with a missing link if full { - chain := makeBlockChain(blockchain.CurrentBlock(), 5, ethash.NewFaker(), db, forkSeed)[1:] + chain := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 5, ethash.NewFaker(), genDb, forkSeed)[1:] if err := testBlockChainImport(chain, blockchain); err == nil { t.Errorf("broken block chain not reported") } } else { - chain := makeHeaderChain(blockchain.CurrentHeader(), 5, ethash.NewFaker(), db, forkSeed)[1:] + chain := makeHeaderChain(blockchain.chainConfig, blockchain.CurrentHeader(), 5, ethash.NewFaker(), genDb, forkSeed)[1:] if err := testHeaderChainImport(chain, blockchain); err == nil { t.Errorf("broken header chain not reported") } @@ -521,17 +520,17 @@ func testReorgShort(t *testing.T, full bool) { func testReorg(t *testing.T, first, second []int64, td int64, full bool) { // Create a pristine chain and database - db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } defer blockchain.Stop() // Insert an easy and a difficult chain afterwards - easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), db, len(first), func(i int, b *BlockGen) { + easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), genDb, len(first), func(i int, b *BlockGen) { b.OffsetTime(first[i]) }) - diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), db, len(second), func(i int, b *BlockGen) { + diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), genDb, len(second), func(i int, b *BlockGen) { b.OffsetTime(second[i]) }) if full { @@ -594,7 +593,7 @@ func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } func testBadHashes(t *testing.T, full bool) { // Create a pristine chain and database - db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -602,14 +601,14 @@ func testBadHashes(t *testing.T, full bool) { // Create a chain, ban a hash and try to import if full { - blocks := makeBlockChain(blockchain.CurrentBlock(), 3, ethash.NewFaker(), db, 10) + blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 3, ethash.NewFaker(), genDb, 10) BadHashes[blocks[2].Header().Hash()] = true defer func() { delete(BadHashes, blocks[2].Header().Hash()) }() _, err = blockchain.InsertChain(blocks) } else { - headers := makeHeaderChain(blockchain.CurrentHeader(), 3, ethash.NewFaker(), db, 10) + headers := makeHeaderChain(blockchain.chainConfig, blockchain.CurrentHeader(), 3, ethash.NewFaker(), genDb, 10) BadHashes[headers[2].Hash()] = true defer func() { delete(BadHashes, headers[2].Hash()) }() @@ -628,13 +627,13 @@ func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } func testReorgBadHashes(t *testing.T, full bool) { // Create a pristine chain and database - db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + genDb, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } // Create a chain, import and ban afterwards - headers := makeHeaderChain(blockchain.CurrentHeader(), 4, ethash.NewFaker(), db, 10) - blocks := makeBlockChain(blockchain.CurrentBlock(), 4, ethash.NewFaker(), db, 10) + headers := makeHeaderChain(blockchain.chainConfig, blockchain.CurrentHeader(), 4, ethash.NewFaker(), genDb, 10) + blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 4, ethash.NewFaker(), genDb, 10) if full { if _, err = blockchain.InsertChain(blocks); err != nil { @@ -658,10 +657,6 @@ func testReorgBadHashes(t *testing.T, full bool) { blockchain.Stop() // Create a new BlockChain and check that it rolled back the state. - gspec := &Genesis{ - BaseFee: big.NewInt(params.InitialBaseFee), - Config: params.AllEthashProtocolChanges, - } ncm, err := NewBlockChain(blockchain.db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) @@ -688,7 +683,7 @@ func TestBlocksInsertNonceError(t *testing.T) { testInsertNonceError(t, true) } func testInsertNonceError(t *testing.T, full bool) { for i := 1; i < 25 && !t.Failed(); i++ { // Create a pristine chain and database - db, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -701,7 +696,7 @@ func testInsertNonceError(t *testing.T, full bool) { failNum uint64 ) if full { - blocks := makeBlockChain(blockchain.CurrentBlock(), i, ethash.NewFaker(), db, 0) + blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), i, ethash.NewFaker(), genDb, 0) failAt = rand.Int() % len(blocks) failNum = blocks[failAt].NumberU64() @@ -709,7 +704,7 @@ func testInsertNonceError(t *testing.T, full bool) { blockchain.engine = ethash.NewFakeFailer(failNum) failRes, err = blockchain.InsertChain(blocks) } else { - headers := makeHeaderChain(blockchain.CurrentHeader(), i, ethash.NewFaker(), db, 0) + headers := makeHeaderChain(blockchain.chainConfig, blockchain.CurrentHeader(), i, ethash.NewFaker(), genDb, 0) failAt = rand.Int() % len(headers) failNum = headers[failAt].Number.Uint64() @@ -742,7 +737,6 @@ func testInsertNonceError(t *testing.T, full bool) { func TestFastVsFullChains(t *testing.T) { // Configure and generate a sample block chain var ( - gendb = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000000000) @@ -751,10 +745,9 @@ func TestFastVsFullChains(t *testing.T) { Alloc: GenesisAlloc{address: {Balance: funds}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(gendb) - signer = types.LatestSigner(gspec.Config) + signer = types.LatestSigner(gspec.Config) ) - blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, 1024, func(i int, block *BlockGen) { + _, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 1024, func(i int, block *BlockGen) { block.SetCoinbase(common.Address{0x00}) // If the block number is multiple of 3, send a few bonus transactions to the miner @@ -774,7 +767,6 @@ func TestFastVsFullChains(t *testing.T) { }) // Import the chain as an archive node for the comparison baseline archiveDb := rawdb.NewMemoryDatabase() - gspec.MustCommit(archiveDb) archive, _ := NewBlockChain(archiveDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer archive.Stop() @@ -783,7 +775,6 @@ func TestFastVsFullChains(t *testing.T) { } // Fast import the chain as a non-archive node to test fastDb := rawdb.NewMemoryDatabase() - gspec.MustCommit(fastDb) fast, _ := NewBlockChain(fastDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() @@ -798,13 +789,11 @@ func TestFastVsFullChains(t *testing.T) { t.Fatalf("failed to insert receipt %d: %v", n, err) } // Freezer style fast import the chain. - frdir := t.TempDir() - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } defer ancientDb.Close() - gspec.MustCommit(ancientDb) ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() @@ -875,7 +864,6 @@ func TestFastVsFullChains(t *testing.T) { func TestLightVsFastVsFullChainHeads(t *testing.T) { // Configure and generate a sample block chain var ( - gendb = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000000000) @@ -884,19 +872,16 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { Alloc: GenesisAlloc{address: {Balance: funds}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(gendb) ) height := uint64(1024) - blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), nil) + _, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil) // makeDb creates a db instance for testing. makeDb := func() ethdb.Database { - dir := t.TempDir() - db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false) + db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } - gspec.MustCommit(db) return db } // Configure a subchain to roll back @@ -995,7 +980,6 @@ func TestChainTxReorgs(t *testing.T) { addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) - db = rawdb.NewMemoryDatabase() gspec = &Genesis{ Config: params.TestChainConfig, GasLimit: 3141592, @@ -1005,8 +989,7 @@ func TestChainTxReorgs(t *testing.T) { addr3: {Balance: big.NewInt(1000000000000000)}, }, } - genesis = gspec.MustCommit(db) - signer = types.LatestSigner(gspec.Config) + signer = types.LatestSigner(gspec.Config) ) // Create two transactions shared between the chains: @@ -1026,7 +1009,7 @@ func TestChainTxReorgs(t *testing.T) { // - futureAdd: transaction added after the reorg has already finished var pastAdd, freshAdd, futureAdd *types.Transaction - chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) { + _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) { switch i { case 0: pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key2) @@ -1044,6 +1027,7 @@ func TestChainTxReorgs(t *testing.T) { } }) // Import the chain. This runs all block validation rules. + db := rawdb.NewMemoryDatabase() blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) @@ -1051,7 +1035,7 @@ func TestChainTxReorgs(t *testing.T) { defer blockchain.Stop() // overwrite the old chain - chain, _ = GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) { + _, chain, _ = GenerateChainWithGenesis(gspec, ethash.NewFaker(), 5, func(i int, gen *BlockGen) { switch i { case 0: pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key3) @@ -1106,20 +1090,19 @@ func TestLogReorgs(t *testing.T) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) - db = rawdb.NewMemoryDatabase() + // this code generates a log - code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") - gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} - genesis = gspec.MustCommit(db) - signer = types.LatestSigner(gspec.Config) + code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") + gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} + signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) blockchain.SubscribeRemovedLogsEvent(rmLogsCh) - chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { + _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *BlockGen) { if i == 1 { tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, code), signer, key1) if err != nil { @@ -1132,7 +1115,7 @@ func TestLogReorgs(t *testing.T) { t.Fatalf("failed to insert chain: %v", err) } - chain, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {}) + _, chain, _ = GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {}) done := make(chan struct{}) go func() { ev := <-rmLogsCh @@ -1162,14 +1145,11 @@ func TestLogRebirth(t *testing.T) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) - db = rawdb.NewMemoryDatabase() gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} - genesis = gspec.MustCommit(db) signer = types.LatestSigner(gspec.Config) engine = ethash.NewFaker() - blockchain, _ = NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) ) - defer blockchain.Stop() // The event channels. @@ -1179,7 +1159,7 @@ func TestLogRebirth(t *testing.T) { blockchain.SubscribeRemovedLogsEvent(rmLogsCh) // This chain contains a single log. - chain, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2, func(i int, gen *BlockGen) { + genDb, chain, _ := GenerateChainWithGenesis(gspec, engine, 2, func(i int, gen *BlockGen) { if i == 1 { tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) if err != nil { @@ -1195,7 +1175,7 @@ func TestLogRebirth(t *testing.T) { // Generate long reorg chain containing another log. Inserting the // chain removes one log and adds one. - forkChain, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2, func(i int, gen *BlockGen) { + _, forkChain, _ := GenerateChainWithGenesis(gspec, engine, 2, func(i int, gen *BlockGen) { if i == 1 { tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) if err != nil { @@ -1213,7 +1193,7 @@ func TestLogRebirth(t *testing.T) { // This chain segment is rooted in the original chain, but doesn't contain any logs. // When inserting it, the canonical chain switches away from forkChain and re-emits // the log event for the old chain, as well as a RemovedLogsEvent for forkChain. - newBlocks, _ := GenerateChain(params.TestChainConfig, chain[len(chain)-1], engine, db, 1, func(i int, gen *BlockGen) {}) + newBlocks, _ := GenerateChain(gspec.Config, chain[len(chain)-1], engine, genDb, 1, func(i int, gen *BlockGen) {}) if _, err := blockchain.InsertChain(newBlocks); err != nil { t.Fatalf("failed to insert forked chain: %v", err) } @@ -1226,13 +1206,10 @@ func TestSideLogRebirth(t *testing.T) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) - db = rawdb.NewMemoryDatabase() gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} - genesis = gspec.MustCommit(db) signer = types.LatestSigner(gspec.Config) - blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ) - defer blockchain.Stop() newLogCh := make(chan []*types.Log, 10) @@ -1240,7 +1217,7 @@ func TestSideLogRebirth(t *testing.T) { blockchain.SubscribeLogsEvent(newLogCh) blockchain.SubscribeRemovedLogsEvent(rmLogsCh) - chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { + _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *BlockGen) { if i == 1 { gen.OffsetTime(-9) // higher block difficulty } @@ -1251,7 +1228,7 @@ func TestSideLogRebirth(t *testing.T) { checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) // Generate side chain with lower difficulty - sideChain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { + genDb, sideChain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *BlockGen) { if i == 1 { tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) if err != nil { @@ -1266,7 +1243,7 @@ func TestSideLogRebirth(t *testing.T) { checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) // Generate a new block based on side chain. - newBlocks, _ := GenerateChain(params.TestChainConfig, sideChain[len(sideChain)-1], ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + newBlocks, _ := GenerateChain(gspec.Config, sideChain[len(sideChain)-1], ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := blockchain.InsertChain(newBlocks); err != nil { t.Fatalf("failed to insert forked chain: %v", err) } @@ -1293,26 +1270,23 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan Re func TestReorgSideEvent(t *testing.T) { var ( - db = rawdb.NewMemoryDatabase() key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) gspec = &Genesis{ Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}, } - genesis = gspec.MustCommit(db) - signer = types.LatestSigner(gspec.Config) + signer = types.LatestSigner(gspec.Config) ) - - blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() - chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {}) + _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {}) if _, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert chain: %v", err) } - replacementBlocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, gen *BlockGen) { + _, replacementBlocks, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 4, func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, nil), signer, key1) if i == 2 { gen.OffsetTime(-9) @@ -1375,13 +1349,13 @@ done: // Tests if the canonical block can be fetched from the database during chain insertion. func TestCanonicalBlockRetrieval(t *testing.T) { - _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) + _, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } defer blockchain.Stop() - chain, _ := GenerateChain(blockchain.chainConfig, blockchain.genesisBlock, ethash.NewFaker(), blockchain.db, 10, func(i int, gen *BlockGen) {}) + _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 10, func(i int, gen *BlockGen) {}) var pend sync.WaitGroup pend.Add(len(chain)) @@ -1423,22 +1397,21 @@ func TestCanonicalBlockRetrieval(t *testing.T) { func TestEIP155Transition(t *testing.T) { // Configure and generate a sample block chain var ( - db = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) deleteAddr = common.Address{1} gspec = &Genesis{ - Config: ¶ms.ChainConfig{ChainID: big.NewInt(1), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}, - Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(2), + HomesteadBlock: new(big.Int), + }, + Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, } - genesis = gspec.MustCommit(db) ) - - blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - defer blockchain.Stop() - - blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { + genDb, blocks, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 4, func(i int, block *BlockGen) { var ( tx *types.Transaction err error @@ -1480,6 +1453,9 @@ func TestEIP155Transition(t *testing.T) { } }) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + defer blockchain.Stop() + if _, err := blockchain.InsertChain(blocks); err != nil { t.Fatal(err) } @@ -1500,8 +1476,13 @@ func TestEIP155Transition(t *testing.T) { } // generate an invalid chain id transaction - config := ¶ms.ChainConfig{ChainID: big.NewInt(2), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)} - blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { + config := ¶ms.ChainConfig{ + ChainID: big.NewInt(2), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(2), + HomesteadBlock: new(big.Int), + } + blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), genDb, 4, func(i int, block *BlockGen) { var ( tx *types.Transaction err error @@ -1526,7 +1507,6 @@ func TestEIP155Transition(t *testing.T) { func TestEIP161AccountRemoval(t *testing.T) { // Configure and generate a sample block chain var ( - db = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) @@ -1541,12 +1521,8 @@ func TestEIP161AccountRemoval(t *testing.T) { }, Alloc: GenesisAlloc{address: {Balance: funds}}, } - genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - defer blockchain.Stop() - - blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) { + _, blocks, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, block *BlockGen) { var ( tx *types.Transaction err error @@ -1566,6 +1542,9 @@ func TestEIP161AccountRemoval(t *testing.T) { block.AddTx(tx) }) // account must exist pre eip 161 + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + defer blockchain.Stop() + if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil { t.Fatal(err) } @@ -1598,31 +1577,25 @@ func TestEIP161AccountRemoval(t *testing.T) { func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() - - db := rawdb.NewMemoryDatabase() - gspec := &Genesis{ + genesis := &Genesis{ Config: params.TestChainConfig, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis := gspec.MustCommit(db) - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // Generate a bunch of fork blocks, each side forking from the canonical chain forks := make([]*types.Block, len(blocks)) for i := 0; i < len(forks); i++ { - parent := genesis + parent := genesis.ToBlock() if i > 0 { parent = blocks[i-1] } - fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) + fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) forks[i] = fork[0] } // Import the canonical and fork chain side by side, verifying the current block // and current header consistency - diskdb := rawdb.NewMemoryDatabase() - (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1647,30 +1620,24 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { func TestTrieForkGC(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() - - db := rawdb.NewMemoryDatabase() - gspec := &Genesis{ - BaseFee: big.NewInt(params.InitialBaseFee), + genesis := &Genesis{ Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), } - genesis := gspec.MustCommit(db) - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // Generate a bunch of fork blocks, each side forking from the canonical chain forks := make([]*types.Block, len(blocks)) for i := 0; i < len(forks); i++ { - parent := genesis + parent := genesis.ToBlock() if i > 0 { parent = blocks[i-1] } - fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) + fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) forks[i] = fork[0] } // Import the canonical and fork chain side by side, forcing the trie cache to cache both - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1697,23 +1664,16 @@ func TestTrieForkGC(t *testing.T) { func TestLargeReorgTrieGC(t *testing.T) { // Generate the original common chain segment and the two competing forks engine := ethash.NewFaker() - - db := rawdb.NewMemoryDatabase() - gspec := &Genesis{ - BaseFee: big.NewInt(params.InitialBaseFee), + genesis := &Genesis{ Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), } - genesis := gspec.MustCommit(db) - - shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) - competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) + genDb, shared, _ := GenerateChainWithGenesis(genesis, engine, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + original, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) + competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) // Import the shared chain and the original canonical one - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1752,25 +1712,20 @@ func TestLargeReorgTrieGC(t *testing.T) { func TestBlockchainRecovery(t *testing.T) { // Configure and generate a sample block chain var ( - gendb = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}} - genesis = gspec.MustCommit(gendb) ) height := uint64(1024) - blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), nil) + _, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil) // Import the chain as a ancient-first node and ensure all pointers are updated - frdir := t.TempDir() - - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } defer ancientDb.Close() - gspec.MustCommit(ancientDb) ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) headers := make([]*types.Header, len(blocks)) @@ -1807,7 +1762,7 @@ func TestBlockchainRecovery(t *testing.T) { // This test checks that InsertReceiptChain will roll back correctly when attempting to insert a side chain. func TestInsertReceiptChainRollback(t *testing.T) { // Generate forked chain. The returned BlockChain object is used to process the side chain blocks. - tmpChain, sideblocks, canonblocks, err := getLongAndShortChains() + tmpChain, sideblocks, canonblocks, gspec, err := getLongAndShortChains() if err != nil { t.Fatal(err) } @@ -1838,9 +1793,7 @@ func TestInsertReceiptChainRollback(t *testing.T) { } defer ancientDb.Close() - gspec := Genesis{Config: params.AllEthashProtocolChanges} - gspec.MustCommit(ancientDb) - ancientChain, _ := NewBlockChain(ancientDb, nil, &gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancientChain, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancientChain.Stop() // Import the canonical header chain. @@ -1887,25 +1840,19 @@ func TestInsertReceiptChainRollback(t *testing.T) { func TestLowDiffLongChain(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() - db := rawdb.NewMemoryDatabase() - gspec := &Genesis{ - BaseFee: big.NewInt(params.InitialBaseFee), + genesis := &Genesis{ Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), } - genesis := gspec.MustCommit(db) - // We must use a pretty long chain to ensure that the fork doesn't overtake us // until after at least 128 blocks post tip - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 6*TriesInMemory, func(i int, b *BlockGen) { + genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) b.OffsetTime(-9) }) // Import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1914,7 +1861,7 @@ func TestLowDiffLongChain(t *testing.T) { } // Generate fork chain, starting from an early block parent := blocks[10] - fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 8*TriesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) @@ -1947,15 +1894,11 @@ func TestLowDiffLongChain(t *testing.T) { // 0: the transition happens since genesis // 1: the transition happens after some chain segments func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommonAncestorAndPruneblock int, mergePoint int) { - // Copy the TestChainConfig so we can modify it during tests - chainConfig := *params.TestChainConfig // Generate a canonical chain to act as the main dataset + chainConfig := *params.TestChainConfig var ( - merger = consensus.NewMerger(rawdb.NewMemoryDatabase()) - genEngine = beacon.New(ethash.NewFaker()) - runEngine = beacon.New(ethash.NewFaker()) - db = rawdb.NewMemoryDatabase() - + merger = consensus.NewMerger(rawdb.NewMemoryDatabase()) + engine = beacon.New(ethash.NewFaker()) key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key.PublicKey) nonce = uint64(0) @@ -1965,13 +1908,10 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon Alloc: GenesisAlloc{addr: {Balance: big.NewInt(math.MaxInt64)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - signer = types.LatestSigner(gspec.Config) - genesis = gspec.MustCommit(db) + signer = types.LatestSigner(gspec.Config) ) // Generate and import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec, nil, runEngine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1983,7 +1923,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Set the terminal total difficulty in the config gspec.Config.TerminalTotalDifficulty = big.NewInt(0) } - blocks, _ := GenerateChain(&chainConfig, genesis, genEngine, db, 2*TriesInMemory, func(i int, gen *BlockGen) { + genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key) if err != nil { t.Fatalf("failed to create tx: %v", err) @@ -2023,7 +1963,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Generate fork chain, make it longer than canon parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock parent := blocks[parentIndex] - fork, _ := GenerateChain(&chainConfig, parent, genEngine, db, 2*TriesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) // Prepend the parent(s) @@ -2085,19 +2025,17 @@ func TestInsertKnownBlocks(t *testing.T) { testInsertKnownChainData(t, "bl func testInsertKnownChainData(t *testing.T, typ string) { engine := ethash.NewFaker() - - db := rawdb.NewMemoryDatabase() - gspec := &Genesis{ + genesis := &Genesis{ Config: params.TestChainConfig, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis := gspec.MustCommit(db) + genDb, blocks, receipts := GenerateChainWithGenesis(genesis, engine, 32, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - blocks, receipts := GenerateChain(params.TestChainConfig, genesis, engine, db, 32, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // A longer chain but total difficulty is lower. - blocks2, receipts2 := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], engine, db, 65, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + blocks2, receipts2 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 65, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + // A shorter chain but total difficulty is higher. - blocks3, receipts3 := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], engine, db, 64, func(i int, b *BlockGen) { + blocks3, receipts3 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) b.OffsetTime(-9) // A higher difficulty }) @@ -2106,10 +2044,9 @@ func testInsertKnownChainData(t *testing.T, typ string) { if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } - gspec.MustCommit(chaindb) defer chaindb.Close() - chain, err := NewBlockChain(chaindb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2229,51 +2166,37 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i // Copy the TestChainConfig so we can modify it during tests chainConfig := *params.TestChainConfig var ( - db = rawdb.NewMemoryDatabase() - gspec = &Genesis{ + genesis = &Genesis{ BaseFee: big.NewInt(params.InitialBaseFee), Config: &chainConfig, } - genesis = gspec.MustCommit(db) - runMerger = consensus.NewMerger(db) - runEngine = beacon.New(ethash.NewFaker()) - genEngine = beacon.New(ethash.NewFaker()) + engine = beacon.New(ethash.NewFaker()) ) - applyMerge := func(engine *beacon.Beacon, height int) { - if engine != nil { - runMerger.FinalizePoS() - // Set the terminal total difficulty in the config - chainConfig.TerminalTotalDifficulty = big.NewInt(int64(height)) - } - } - // Apply merging since genesis if mergeHeight == 0 { - applyMerge(genEngine, 0) + genesis.Config.TerminalTotalDifficulty = big.NewInt(0) } - blocks, receipts := GenerateChain(&chainConfig, genesis, genEngine, db, 32, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + genDb, blocks, receipts := GenerateChainWithGenesis(genesis, engine, 32, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // Apply merging after the first segment if mergeHeight == 1 { - applyMerge(genEngine, len(blocks)) + genesis.Config.TerminalTotalDifficulty = big.NewInt(int64(len(blocks))) } // Longer chain and shorter chain - blocks2, receipts2 := GenerateChain(&chainConfig, blocks[len(blocks)-1], genEngine, db, 65, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - blocks3, receipts3 := GenerateChain(&chainConfig, blocks[len(blocks)-1], genEngine, db, 64, func(i int, b *BlockGen) { + blocks2, receipts2 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 65, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + blocks3, receipts3 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) b.OffsetTime(-9) // Time shifted, difficulty shouldn't be changed }) // Import the shared chain and the original canonical one - dir := t.TempDir() - chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false) + chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } - (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb) defer chaindb.Close() - chain, err := NewBlockChain(chaindb, nil, gspec, nil, runEngine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2324,11 +2247,6 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } } } - - // Apply merging since genesis if required - if mergeHeight == 0 { - applyMerge(runEngine, 0) - } if err := inserter(blocks, receipts); err != nil { t.Fatalf("failed to insert chain data: %v", err) } @@ -2348,11 +2266,6 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } asserter(t, blocks[len(blocks)-1]) - // Apply merging after the first segment - if mergeHeight == 1 { - applyMerge(runEngine, len(blocks)) - } - // Import a longer chain with some known data as prefix. if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil { t.Fatalf("failed to insert chain data: %v", err) @@ -2377,36 +2290,30 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } // getLongAndShortChains returns two chains: A is longer, B is heavier. -func getLongAndShortChains() (bc *BlockChain, longChain []*types.Block, heavyChain []*types.Block, err error) { +func getLongAndShortChains() (*BlockChain, []*types.Block, []*types.Block, *Genesis, error) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() - db := rawdb.NewMemoryDatabase() - gspec := &Genesis{ - BaseFee: big.NewInt(params.InitialBaseFee), + genesis := &Genesis{ Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), } - genesis := gspec.MustCommit(db) - // Generate and import the canonical chain, // Offset the time, to keep the difficulty low - longChain, _ = GenerateChain(params.TestChainConfig, genesis, engine, db, 80, func(i int, b *BlockGen) { + genDb, longChain, _ := GenerateChainWithGenesis(genesis, engine, 80, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { - return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) + return nil, nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) } - // Generate fork chain, make it shorter than canon, with common ancestor pretty early parentIndex := 3 parent := longChain[parentIndex] - heavyChainExt, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 75, func(i int, b *BlockGen) { + heavyChainExt, _ := GenerateChain(genesis.Config, parent, engine, genDb, 75, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) b.OffsetTime(-9) }) + var heavyChain []*types.Block heavyChain = append(heavyChain, longChain[:parentIndex+1]...) heavyChain = append(heavyChain, heavyChainExt...) @@ -2425,14 +2332,14 @@ func getLongAndShortChains() (bc *BlockChain, longChain []*types.Block, heavyCha shorterTd.Add(shorterTd, b.Difficulty()) } if shorterTd.Cmp(longerTd) <= 0 { - return nil, nil, nil, fmt.Errorf("test is moot, heavyChain td (%v) must be larger than canon td (%v)", shorterTd, longerTd) + return nil, nil, nil, nil, fmt.Errorf("test is moot, heavyChain td (%v) must be larger than canon td (%v)", shorterTd, longerTd) } longerNum := longChain[len(longChain)-1].NumberU64() shorterNum := heavyChain[len(heavyChain)-1].NumberU64() if shorterNum >= longerNum { - return nil, nil, nil, fmt.Errorf("test is moot, heavyChain num (%v) must be lower than canon num (%v)", shorterNum, longerNum) + return nil, nil, nil, nil, fmt.Errorf("test is moot, heavyChain num (%v) must be lower than canon num (%v)", shorterNum, longerNum) } - return chain, longChain, heavyChain, nil + return chain, longChain, heavyChain, genesis, nil } // TestReorgToShorterRemovesCanonMapping tests that if we @@ -2441,7 +2348,7 @@ func getLongAndShortChains() (bc *BlockChain, longChain []*types.Block, heavyCha // 3. Then there should be no canon mapping for the block at height X // 4. The forked block should still be retrievable by hash func TestReorgToShorterRemovesCanonMapping(t *testing.T) { - chain, canonblocks, sideblocks, err := getLongAndShortChains() + chain, canonblocks, sideblocks, _, err := getLongAndShortChains() if err != nil { t.Fatal(err) } @@ -2477,7 +2384,7 @@ func TestReorgToShorterRemovesCanonMapping(t *testing.T) { // as TestReorgToShorterRemovesCanonMapping, but applied on headerchain // imports -- that is, for fast sync func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) { - chain, canonblocks, sideblocks, err := getLongAndShortChains() + chain, canonblocks, sideblocks, _, err := getLongAndShortChains() if err != nil { t.Fatal(err) } @@ -2520,7 +2427,6 @@ func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) { func TestTransactionIndices(t *testing.T) { // Configure and generate a sample block chain var ( - gendb = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(100000000000000000) @@ -2529,18 +2435,17 @@ func TestTransactionIndices(t *testing.T) { Alloc: GenesisAlloc{address: {Balance: funds}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(gendb) - signer = types.LatestSigner(gspec.Config) + signer = types.LatestSigner(gspec.Config) ) height := uint64(128) - blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), func(i int, block *BlockGen) { + genDb, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), func(i int, block *BlockGen) { tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key) if err != nil { panic(err) } block.AddTx(tx) }) - blocks2, _ := GenerateChain(gspec.Config, blocks[len(blocks)-1], ethash.NewFaker(), gendb, 10, nil) + blocks2, _ := GenerateChain(gspec.Config, blocks[len(blocks)-1], ethash.NewFaker(), genDb, 10, nil) check := func(tail *uint64, chain *BlockChain) { stored := rawdb.ReadTxIndexTail(chain.db) @@ -2580,8 +2485,6 @@ func TestTransactionIndices(t *testing.T) { if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } - gspec.MustCommit(ancientDb) - // Import all blocks into ancient db l := uint64(0) chain, err := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) @@ -2608,7 +2511,6 @@ func TestTransactionIndices(t *testing.T) { if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } - gspec.MustCommit(ancientDb) l := l chain, err = NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { @@ -2630,7 +2532,6 @@ func TestTransactionIndices(t *testing.T) { t.Fatalf("failed to create temp freezer db: %v", err) } defer ancientDb.Close() - gspec.MustCommit(ancientDb) limit = []uint64{0, 64 /* drop stale */, 32 /* shorten history */, 64 /* extend history */, 0 /* restore all */} tails := []uint64{0, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */, 69 /* 132 - 64 + 1 */, 0} @@ -2650,16 +2551,13 @@ func TestTransactionIndices(t *testing.T) { func TestSkipStaleTxIndicesInSnapSync(t *testing.T) { // Configure and generate a sample block chain var ( - gendb = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(100000000000000000) gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}} - genesis = gspec.MustCommit(gendb) signer = types.LatestSigner(gspec.Config) ) - height := uint64(128) - blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), func(i int, block *BlockGen) { + _, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 128, func(i int, block *BlockGen) { tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key) if err != nil { panic(err) @@ -2701,13 +2599,11 @@ func TestSkipStaleTxIndicesInSnapSync(t *testing.T) { } } - frdir := t.TempDir() - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) if err != nil { t.Fatalf("failed to create temp freezer db: %v", err) } defer ancientDb.Close() - gspec.MustCommit(ancientDb) // Import all blocks into ancient db, only HEAD-32 indices are kept. l := uint64(32) @@ -2751,8 +2647,6 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in ) // Generate the original common chain segment and the two competing forks engine := ethash.NewFaker() - db := rawdb.NewMemoryDatabase() - genesis := gspec.MustCommit(db) blockGenerator := func(i int, block *BlockGen) { block.SetCoinbase(common.Address{1}) @@ -2767,15 +2661,12 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in } } - shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, numBlocks, blockGenerator) + _, shared, _ := GenerateChainWithGenesis(gspec, engine, numBlocks, blockGenerator) b.StopTimer() b.ResetTimer() for i := 0; i < b.N; i++ { // Import the shared chain and the original canonical one - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { b.Fatalf("failed to create tester chain: %v", err) } @@ -2849,19 +2740,14 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { func TestSideImportPrunedBlocks(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() - db := rawdb.NewMemoryDatabase() - gspec := &Genesis{ - BaseFee: big.NewInt(params.InitialBaseFee), + genesis := &Genesis{ Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), } - genesis := gspec.MustCommit(db) - // Generate and import the canonical chain - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil) - diskdb := rawdb.NewMemoryDatabase() + _, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, nil) - gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2899,11 +2785,9 @@ func TestSideImportPrunedBlocks(t *testing.T) { // first, but the journal wiped the entire state object on create-revert. func TestDeleteCreateRevert(t *testing.T) { var ( - aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") - bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") - // Generate a canonical chain to act as the main dataset + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") + bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() // A sender who makes transactions, has some funds key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -2937,10 +2821,9 @@ func TestDeleteCreateRevert(t *testing.T) { }, }, } - genesis = gspec.MustCommit(db) ) - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) // One transaction to AAAA tx, _ := types.SignTx(types.NewTransaction(0, aa, @@ -2952,10 +2835,7 @@ func TestDeleteCreateRevert(t *testing.T) { b.AddTx(tx) }) // Import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2973,9 +2853,8 @@ func TestDeleteCreateRevert(t *testing.T) { // and then the new slots exist func TestDeleteRecreateSlots(t *testing.T) { var ( - // Generate a canonical chain to act as the main dataset engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() + // A sender who makes transactions, has some funds key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) @@ -3050,9 +2929,7 @@ func TestDeleteRecreateSlots(t *testing.T) { }, }, } - genesis := gspec.MustCommit(db) - - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) // One transaction to AA, to kill it tx, _ := types.SignTx(types.NewTransaction(0, aa, @@ -3064,9 +2941,7 @@ func TestDeleteRecreateSlots(t *testing.T) { b.AddTx(tx) }) // Import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ Debug: true, Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3100,9 +2975,8 @@ func TestDeleteRecreateSlots(t *testing.T) { // Expected outcome is that _all_ slots are cleared from A func TestDeleteRecreateAccount(t *testing.T) { var ( - // Generate a canonical chain to act as the main dataset engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() + // A sender who makes transactions, has some funds key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) @@ -3130,9 +3004,8 @@ func TestDeleteRecreateAccount(t *testing.T) { }, }, } - genesis := gspec.MustCommit(db) - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) // One transaction to AA, to kill it tx, _ := types.SignTx(types.NewTransaction(0, aa, @@ -3144,9 +3017,7 @@ func TestDeleteRecreateAccount(t *testing.T) { b.AddTx(tx) }) // Import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ Debug: true, Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3176,9 +3047,8 @@ func TestDeleteRecreateAccount(t *testing.T) { // and then the new slots exist func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { var ( - // Generate a canonical chain to act as the main dataset engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() + // A sender who makes transactions, has some funds key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) @@ -3254,7 +3124,6 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { }, }, } - genesis := gspec.MustCommit(db) var nonce uint64 type expectation struct { @@ -3291,7 +3160,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { return tx } - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 150, func(i int, b *BlockGen) { + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 150, func(i int, b *BlockGen) { var exp = new(expectation) exp.blocknum = i + 1 exp.values = make(map[int]int) @@ -3317,9 +3186,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { current = exp }) // Import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3378,9 +3245,8 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { // func TestInitThenFailCreateContract(t *testing.T) { var ( - // Generate a canonical chain to act as the main dataset engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() + // A sender who makes transactions, has some funds key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) @@ -3439,9 +3305,8 @@ func TestInitThenFailCreateContract(t *testing.T) { }, }, } - genesis := gspec.MustCommit(db) nonce := uint64(0) - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 4, func(i int, b *BlockGen) { + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 4, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) // One transaction to BB tx, _ := types.SignTx(types.NewTransaction(nonce, bb, @@ -3451,9 +3316,7 @@ func TestInitThenFailCreateContract(t *testing.T) { }) // Import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3490,11 +3353,8 @@ func TestInitThenFailCreateContract(t *testing.T) { // correctly. func TestEIP2718Transition(t *testing.T) { var ( - aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") - - // Generate a canonical chain to act as the main dataset + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() // A sender who makes transactions, has some funds key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -3517,10 +3377,9 @@ func TestEIP2718Transition(t *testing.T) { }, }, } - genesis = gspec.MustCommit(db) ) - - blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) { + // Generate blocks + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) // One transaction to 0xAAAA @@ -3540,10 +3399,7 @@ func TestEIP2718Transition(t *testing.T) { }) // Import the canonical chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3572,11 +3428,8 @@ func TestEIP2718Transition(t *testing.T) { // 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap). func TestEIP1559Transition(t *testing.T) { var ( - aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") - - // Generate a canonical chain to act as the main dataset + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() // A sender who makes transactions, has some funds key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -3606,10 +3459,9 @@ func TestEIP1559Transition(t *testing.T) { gspec.Config.BerlinBlock = common.Big0 gspec.Config.LondonBlock = common.Big0 - genesis := gspec.MustCommit(db) signer := types.LatestSigner(gspec.Config) - blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) { + genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) // One transaction to 0xAAAA @@ -3633,11 +3485,7 @@ func TestEIP1559Transition(t *testing.T) { b.AddTx(tx) }) - - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3673,7 +3521,7 @@ func TestEIP1559Transition(t *testing.T) { t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) } - blocks, _ = GenerateChain(gspec.Config, block, engine, db, 1, func(i int, b *BlockGen) { + blocks, _ = GenerateChain(gspec.Config, block, engine, genDb, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) txdata := &types.LegacyTx{ @@ -3720,7 +3568,6 @@ func TestSetCanonical(t *testing.T) { //log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) var ( - db = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(100000000000000000) @@ -3729,22 +3576,18 @@ func TestSetCanonical(t *testing.T) { Alloc: GenesisAlloc{address: {Balance: funds}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(db) - signer = types.LatestSigner(gspec.Config) - engine = ethash.NewFaker() + signer = types.LatestSigner(gspec.Config) + engine = ethash.NewFaker() ) // Generate and import the canonical chain - canon, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, func(i int, gen *BlockGen) { + _, canon, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key) if err != nil { panic(err) } gen.AddTx(tx) }) - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3753,7 +3596,7 @@ func TestSetCanonical(t *testing.T) { } // Generate the side chain and import them - side, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, func(i int, gen *BlockGen) { + _, side, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.header.BaseFee, nil), signer, key) if err != nil { panic(err) @@ -3835,22 +3678,18 @@ func TestCanonicalHashMarker(t *testing.T) { } for _, c := range cases { var ( - db = rawdb.NewMemoryDatabase() gspec = &Genesis{ Config: params.TestChainConfig, Alloc: GenesisAlloc{}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(db) - engine = ethash.NewFaker() + engine = ethash.NewFaker() ) - forkA, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, c.forkA, func(i int, gen *BlockGen) {}) - forkB, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, c.forkB, func(i int, gen *BlockGen) {}) + _, forkA, _ := GenerateChainWithGenesis(gspec, engine, c.forkA, func(i int, gen *BlockGen) {}) + _, forkB, _ := GenerateChainWithGenesis(gspec, engine, c.forkB, func(i int, gen *BlockGen) {}) // Initialize test chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/chain_makers.go b/core/chain_makers.go index c7bf60a4b06e..88a1c4e87024 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -284,6 +285,19 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse return blocks, receipts } +// GenerateChainWithGenesis is a wrapper of GenerateChain which will initialize +// genesis block to database first according to the provided genesis specification +// then generate chain on top. +func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) { + db := rawdb.NewMemoryDatabase() + _, err := genesis.Commit(db) + if err != nil { + panic(err) + } + blocks, receipts := GenerateChain(genesis.Config, genesis.ToBlock(), engine, db, n, gen) + return db, blocks, receipts +} + func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { var time uint64 if parent.Time() == 0 { @@ -316,8 +330,8 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S } // makeHeaderChain creates a deterministic chain of headers rooted at parent. -func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Header { - blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, engine, db, seed) +func makeHeaderChain(chainConfig *params.ChainConfig, parent *types.Header, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Header { + blocks := makeBlockChain(chainConfig, types.NewBlockWithHeader(parent), n, engine, db, seed) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { headers[i] = block.Header() @@ -325,14 +339,32 @@ func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db et return headers } +// makeHeaderChainWithGenesis creates a deterministic chain of headers from genesis. +func makeHeaderChainWithGenesis(genesis *Genesis, n int, engine consensus.Engine, seed int) (ethdb.Database, []*types.Header) { + db, blocks := makeBlockChainWithGenesis(genesis, n, engine, seed) + headers := make([]*types.Header, len(blocks)) + for i, block := range blocks { + headers[i] = block.Header() + } + return db, headers +} + // makeBlockChain creates a deterministic chain of blocks rooted at parent. -func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Block { - blocks, _ := GenerateChain(params.TestChainConfig, parent, engine, db, n, func(i int, b *BlockGen) { +func makeBlockChain(chainConfig *params.ChainConfig, parent *types.Block, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Block { + blocks, _ := GenerateChain(chainConfig, parent, engine, db, n, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) }) return blocks } +// makeBlockChain creates a deterministic chain of blocks from genesis +func makeBlockChainWithGenesis(genesis *Genesis, n int, engine consensus.Engine, seed int) (ethdb.Database, []*types.Block) { + db, blocks, _ := GenerateChainWithGenesis(genesis, engine, n, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) + }) + return db, blocks +} + type fakeChainReader struct { config *params.ChainConfig } diff --git a/core/dao_test.go b/core/dao_test.go index 8089b5470aaf..44405447deaa 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -34,13 +34,11 @@ func TestDAOForkRangeExtradata(t *testing.T) { chainConfig.HomesteadBlock = big.NewInt(0) // Generate a common prefix for both pro-forkers and non-forkers - db := rawdb.NewMemoryDatabase() gspec := &Genesis{ BaseFee: big.NewInt(params.InitialBaseFee), Config: &chainConfig, } - genesis := gspec.MustCommit(db) - prefix, _ := GenerateChain(&chainConfig, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) + genDb, prefix, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) // Create the concurrent, conflicting two nodes proDb := rawdb.NewMemoryDatabase() @@ -52,8 +50,6 @@ func TestDAOForkRangeExtradata(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), Config: &proConf, } - gspec.MustCommit(proDb) - proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer proBc.Stop() @@ -66,8 +62,6 @@ func TestDAOForkRangeExtradata(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), Config: &conConf, } - gspec.MustCommit(conDb) - conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer conBc.Stop() @@ -80,9 +74,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { // Create a pro-fork block, and try to feed into the no-fork chain - db = rawdb.NewMemoryDatabase() - congspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -95,19 +87,17 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true, nil); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } - blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err == nil { t.Fatalf("contra-fork chain accepted pro-fork block: %v", blocks[0]) } // Create a proper no-fork block for the contra-forker - blocks, _ = GenerateChain(&conConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&conConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err != nil { t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err) } // Create a no-fork block, and try to feed into the pro-fork chain - db = rawdb.NewMemoryDatabase() - progspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) @@ -120,20 +110,18 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true, nil); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } - blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err == nil { t.Fatalf("pro-fork chain accepted contra-fork block: %v", blocks[0]) } // Create a proper pro-fork block for the pro-forker - blocks, _ = GenerateChain(&proConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&proConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err != nil { t.Fatalf("pro-fork chain didn't accepted pro-fork block: %v", err) } } // Verify that contra-forkers accept pro-fork extra-datas after forking finishes - db = rawdb.NewMemoryDatabase() - congspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -146,14 +134,12 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true, nil); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } - blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err != nil { t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err) } // Verify that pro-forkers accept contra-fork extra-datas after forking finishes - db = rawdb.NewMemoryDatabase() - progspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) @@ -166,7 +152,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true, nil); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } - blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err != nil { t.Fatalf("pro-fork chain didn't accept contra-fork block post-fork: %v", err) } diff --git a/core/headerchain_test.go b/core/headerchain_test.go index ed0522671fb8..fe083b003145 100644 --- a/core/headerchain_test.go +++ b/core/headerchain_test.go @@ -27,7 +27,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -70,19 +69,18 @@ func testInsert(t *testing.T, hc *HeaderChain, chain []*types.Header, wantStatus // This test checks status reporting of InsertHeaderChain. func TestHeaderInsertion(t *testing.T) { var ( - db = rawdb.NewMemoryDatabase() - genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + db = rawdb.NewMemoryDatabase() + gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges} ) - - hc, err := NewHeaderChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), func() bool { return false }) + gspec.Commit(db) + hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false }) if err != nil { t.Fatal(err) } // chain A: G->A1->A2...A128 - chainA := makeHeaderChain(genesis.Header(), 128, ethash.NewFaker(), db, 10) + genDb, chainA := makeHeaderChainWithGenesis(gspec, 128, ethash.NewFaker(), 10) // chain B: G->A1->B1...B128 - chainB := makeHeaderChain(chainA[0], 128, ethash.NewFaker(), db, 10) - log.Root().SetHandler(log.StdoutHandler) + chainB := makeHeaderChain(gspec.Config, chainA[0], 128, ethash.NewFaker(), genDb, 10) forker := NewForkChoice(hc, nil) // Inserting 64 headers on an empty chain, expecting diff --git a/core/rlp_test.go b/core/rlp_test.go index bf5a934ce551..a2fb4937f8bb 100644 --- a/core/rlp_test.go +++ b/core/rlp_test.go @@ -23,7 +23,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" @@ -33,10 +32,9 @@ import ( func getBlock(transactions int, uncles int, dataSize int) *types.Block { var ( - aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") - // Generate a canonical chain to act as the main dataset + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") engine = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() + // A sender who makes transactions, has some funds key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) @@ -45,11 +43,9 @@ func getBlock(transactions int, uncles int, dataSize int) *types.Block { Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}, } - genesis = gspec.MustCommit(db) ) - // We need to generate as many blocks +1 as uncles - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, uncles+1, + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, uncles+1, func(n int, b *BlockGen) { if n == uncles { // Add transactions and stuff on the last block diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 42faa28d058f..1df4a0e80418 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -91,7 +91,6 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - genesis = gspec.MustCommit(db) blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ) defer blockchain.Stop() @@ -197,7 +196,7 @@ func TestStateProcessorErrors(t *testing.T) { want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000", }, } { - block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config) + block := GenerateBadBlock(gspec.ToBlock(), ethash.NewFaker(), tt.txs, gspec.Config) _, err := blockchain.InsertChain(types.Blocks{block}) if err == nil { t.Fatal("block imported without errors") @@ -232,7 +231,6 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - genesis = gspec.MustCommit(db) blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ) defer blockchain.Stop() @@ -247,7 +245,7 @@ func TestStateProcessorErrors(t *testing.T) { want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: transaction type not supported", }, } { - block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config) + block := GenerateBadBlock(gspec.ToBlock(), ethash.NewFaker(), tt.txs, gspec.Config) _, err := blockchain.InsertChain(types.Blocks{block}) if err == nil { t.Fatal("block imported without errors") @@ -272,7 +270,6 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - genesis = gspec.MustCommit(db) blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ) defer blockchain.Stop() @@ -287,7 +284,7 @@ func TestStateProcessorErrors(t *testing.T) { want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, codehash: 0x9280914443471259d4570a8661015ae4a5b80186dbc619658fb494bebc3da3d1", }, } { - block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config) + block := GenerateBadBlock(gspec.ToBlock(), ethash.NewFaker(), tt.txs, gspec.Config) _, err := blockchain.InsertChain(types.Blocks{block}) if err == nil { t.Fatal("block imported without errors") diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 0d945993eb37..7e8f322df53b 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/beacon" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -51,10 +50,9 @@ var ( ) func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) { - db := rawdb.NewMemoryDatabase() - config := params.AllEthashProtocolChanges + config := *params.AllEthashProtocolChanges genesis := &core.Genesis{ - Config: config, + Config: &config, Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, ExtraData: []byte("test genesis"), Timestamp: 9000, @@ -65,13 +63,11 @@ func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) { generate := func(i int, g *core.BlockGen) { g.OffsetTime(5) g.SetExtra([]byte("test")) - tx, _ := types.SignTx(types.NewTransaction(testNonce, common.HexToAddress("0x9a9070028361F7AAbeB3f2F2Dc07F82C4a98A02a"), big.NewInt(1), params.TxGas, big.NewInt(params.InitialBaseFee*2), nil), types.LatestSigner(config), testKey) + tx, _ := types.SignTx(types.NewTransaction(testNonce, common.HexToAddress("0x9a9070028361F7AAbeB3f2F2Dc07F82C4a98A02a"), big.NewInt(1), params.TxGas, big.NewInt(params.InitialBaseFee*2), nil), types.LatestSigner(&config), testKey) g.AddTx(tx) testNonce++ } - gblock := genesis.MustCommit(db) - engine := ethash.NewFaker() - blocks, _ := core.GenerateChain(config, gblock, engine, db, n, generate) + _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), n, generate) totalDifficulty := big.NewInt(0) for _, b := range blocks { totalDifficulty.Add(totalDifficulty, b.Difficulty()) diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index eb72f0fc3cc6..36d6795e7afe 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -73,8 +73,6 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester { Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - gspec.MustCommit(db) - chain, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { panic(err) diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 1c96681e2f5b..01f81a7b1cde 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -38,7 +38,7 @@ var ( testAddress = crypto.PubkeyToAddress(testKey.PublicKey) testDB = rawdb.NewMemoryDatabase() - testGspec = core.Genesis{ + testGspec = &core.Genesis{ Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), @@ -160,7 +160,7 @@ func (tc *testChain) copy(newlen int) *testChain { // contains a transaction and every 5th an uncle to allow testing correct block // reassembly. func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool) { - blocks, _ := core.GenerateChain(params.TestChainConfig, parent, ethash.NewFaker(), testDB, n, func(i int, block *core.BlockGen) { + blocks, _ := core.GenerateChain(testGspec.Config, parent, ethash.NewFaker(), testDB, n, func(i int, block *core.BlockGen) { block.SetCoinbase(common.Address{seed}) // If a heavy chain is requested, delay blocks to raise difficulty if heavy { @@ -217,10 +217,7 @@ func newTestBlockchain(blocks []*types.Block) *core.BlockChain { if pregenerated { panic("Requested chain generation outside of init") } - db := rawdb.NewMemoryDatabase() - testGspec.MustCommit(db) - - chain, err := core.NewBlockChain(db, nil, &testGspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, testGspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { panic(err) } diff --git a/eth/fetcher/block_fetcher_test.go b/eth/fetcher/block_fetcher_test.go index bf7946952e49..9e5693c02e5a 100644 --- a/eth/fetcher/block_fetcher_test.go +++ b/eth/fetcher/block_fetcher_test.go @@ -39,7 +39,8 @@ var ( testdb = rawdb.NewMemoryDatabase() testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testAddress = crypto.PubkeyToAddress(testKey.PublicKey) - gspec = core.Genesis{ + gspec = &core.Genesis{ + Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } @@ -52,7 +53,7 @@ var ( // contains a transaction and every 5th an uncle to allow testing correct block // reassembly. func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { - blocks, _ := core.GenerateChain(params.TestChainConfig, parent, ethash.NewFaker(), testdb, n, func(i int, block *core.BlockGen) { + blocks, _ := core.GenerateChain(gspec.Config, parent, ethash.NewFaker(), testdb, n, func(i int, block *core.BlockGen) { block.SetCoinbase(common.Address{seed}) // If the block number is multiple of 3, send a bonus transaction to the miner diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 51bda29b4244..73a4ab2d4fca 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -165,9 +165,12 @@ func TestBlockSubscription(t *testing.T) { db = rawdb.NewMemoryDatabase() backend, sys = newTestFilterSystem(t, db, Config{}) api = NewFilterAPI(sys, false) - genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) - chain, _ = core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {}) - chainEvents = []core.ChainEvent{} + genesis = &core.Genesis{ + Config: params.TestChainConfig, + BaseFee: big.NewInt(params.InitialBaseFee), + } + _, chain, _ = core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 10, func(i int, gen *core.BlockGen) {}) + chainEvents = []core.ChainEvent{} ) for _, blk := range chain { diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 2c1f7cadf43a..39ed46cec761 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -40,10 +40,8 @@ func makeReceipt(addr common.Address) *types.Receipt { } func BenchmarkFilters(b *testing.B) { - dir := b.TempDir() - var ( - db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "", false) + db, _ = rawdb.NewLevelDBDatabase(b.TempDir(), 0, 0, "", false) _, sys = newTestFilterSystem(b, db, Config{}) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) @@ -51,17 +49,14 @@ func BenchmarkFilters(b *testing.B) { addr3 = common.BytesToAddress([]byte("ethereum")) addr4 = common.BytesToAddress([]byte("random addresses please")) - gspec = core.Genesis{ + gspec = &core.Genesis{ Alloc: core.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.ToBlock() ) defer db.Close() - gspec.MustCommit(db) - - chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 100010, func(i int, gen *core.BlockGen) { + _, chain, receipts := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 100010, func(i int, gen *core.BlockGen) { switch i { case 2403: receipt := makeReceipt(addr1) @@ -100,10 +95,8 @@ func BenchmarkFilters(b *testing.B) { } func TestFilters(t *testing.T) { - dir := t.TempDir() - var ( - db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "", false) + db, _ = rawdb.NewLevelDBDatabase(t.TempDir(), 0, 0, "", false) _, sys = newTestFilterSystem(t, db, Config{}) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key1.PublicKey) @@ -113,17 +106,15 @@ func TestFilters(t *testing.T) { hash3 = common.BytesToHash([]byte("topic3")) hash4 = common.BytesToHash([]byte("topic4")) - gspec = core.Genesis{ + gspec = &core.Genesis{ + Config: params.TestChainConfig, Alloc: core.GenesisAlloc{addr: {Balance: big.NewInt(1000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.ToBlock() ) defer db.Close() - gspec.MustCommit(db) - - chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 1000, func(i int, gen *core.BlockGen) { + _, chain, receipts := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 1000, func(i int, gen *core.BlockGen) { switch i { case 1: receipt := types.NewReceipt(nil, false, 0) @@ -168,6 +159,10 @@ func TestFilters(t *testing.T) { gen.AddUncheckedTx(types.NewTransaction(999, common.HexToAddress("0x999"), big.NewInt(999), 999, gen.BaseFee(), nil)) } }) + // The test txs are not properly signed, can't simply create a chain + // and then import blocks. TODO(rjl493456442) try to get rid of the + // manual database writes. + gspec.MustCommit(db) for i, block := range chain { rawdb.WriteBlock(db, block) rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 5830312fd139..a4399661fcf0 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -129,11 +129,9 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke config.GrayGlacierBlock = londonBlock config.TerminalTotalDifficulty = common.Big0 engine := ethash.NewFaker() - db := rawdb.NewMemoryDatabase() - genesis := gspec.MustCommit(db) // Generate testing blocks - blocks, _ := core.GenerateChain(gspec.Config, genesis, engine, db, testHead+1, func(i int, b *core.BlockGen) { + _, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, testHead+1, func(i int, b *core.BlockGen) { b.SetCoinbase(common.Address{1}) var txdata types.TxData @@ -160,9 +158,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke b.AddTx(types.MustSignNewTx(key, signer, txdata)) }) // Construct testing chain - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create local chain, %v", err) } diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 9c2fcd36f7ab..9f0c36f950c5 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -102,14 +102,11 @@ func testForkIDSplit(t *testing.T, protocol uint) { gspecNoFork = &core.Genesis{Config: configNoFork} gspecProFork = &core.Genesis{Config: configProFork} - genesisNoFork = gspecNoFork.MustCommit(dbNoFork) - genesisProFork = gspecProFork.MustCommit(dbProFork) - chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, gspecNoFork, nil, engine, vm.Config{}, nil, nil) chainProFork, _ = core.NewBlockChain(dbProFork, nil, gspecProFork, nil, engine, vm.Config{}, nil, nil) - blocksNoFork, _ = core.GenerateChain(configNoFork, genesisNoFork, engine, dbNoFork, 2, nil) - blocksProFork, _ = core.GenerateChain(configProFork, genesisProFork, engine, dbProFork, 2, nil) + _, blocksNoFork, _ = core.GenerateChainWithGenesis(gspecNoFork, engine, 2, nil) + _, blocksProFork, _ = core.GenerateChainWithGenesis(gspecProFork, engine, 2, nil) ethNoFork, _ = newHandler(&handlerConfig{ Database: dbNoFork, diff --git a/eth/handler_test.go b/eth/handler_test.go index 044130f40f8c..8939e53a952a 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -137,11 +137,9 @@ func newTestHandlerWithBlocks(blocks int) *testHandler { Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}}, } - gspec.MustCommit(db) - chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, nil) + _, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, nil) if _, err := chain.InsertChain(bs); err != nil { panic(err) } diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index ea2edc4a9164..ef534ba37697 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -67,14 +67,15 @@ func newTestBackendWithGenerator(blocks int, generator func(int, *core.BlockGen) Config: params.TestChainConfig, Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, } - gspec.MustCommit(db) - chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator) + _, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, generator) if _, err := chain.InsertChain(bs); err != nil { panic(err) } + for _, block := range bs { + chain.StateCache().TrieDB().Commit(block.Root(), false, nil) + } txconfig := core.DefaultTxPoolConfig txconfig.Journal = "" // Don't litter the disk with test journals diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index b75b6793592c..40d860b857d1 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -61,20 +61,14 @@ type testBackend struct { func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend { backend := &testBackend{ - chainConfig: params.TestChainConfig, + chainConfig: gspec.Config, engine: ethash.NewFaker(), chaindb: rawdb.NewMemoryDatabase(), } // Generate blocks for testing - gspec.Config = backend.chainConfig - var ( - gendb = rawdb.NewMemoryDatabase() - genesis = gspec.MustCommit(gendb) - ) - blocks, _ := core.GenerateChain(backend.chainConfig, genesis, backend.engine, gendb, n, generator) + _, blocks, _ := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator) // Import the canonical chain - gspec.MustCommit(backend.chaindb) cacheConfig := &core.CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index f2f4a5765d13..67b1fde7569c 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -238,7 +237,6 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { } func generateTestChain() []*types.Block { - db := rawdb.NewMemoryDatabase() generate := func(i int, g *core.BlockGen) { g.OffsetTime(5) g.SetExtra([]byte("test")) @@ -248,11 +246,8 @@ func generateTestChain() []*types.Block { g.AddTx(testTx2) } } - gblock := genesis.MustCommit(db) - engine := ethash.NewFaker() - blocks, _ := core.GenerateChain(genesis.Config, gblock, engine, db, 2, generate) - blocks = append([]*types.Block{gblock}, blocks...) - return blocks + _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 2, generate) + return append([]*types.Block{genesis.ToBlock()}, blocks...) } func TestEthClient(t *testing.T) { diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index a0f4eaaf5db4..e77c6015a215 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -78,10 +77,8 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { } func generateTestChain() (*core.Genesis, []*types.Block) { - db := rawdb.NewMemoryDatabase() - config := params.AllEthashProtocolChanges genesis := &core.Genesis{ - Config: config, + Config: params.AllEthashProtocolChanges, Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance, Storage: map[common.Hash]common.Hash{testSlot: testValue}}}, ExtraData: []byte("test genesis"), Timestamp: 9000, @@ -90,10 +87,8 @@ func generateTestChain() (*core.Genesis, []*types.Block) { g.OffsetTime(5) g.SetExtra([]byte("test")) } - gblock := genesis.MustCommit(db) - engine := ethash.NewFaker() - blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate) - blocks = append([]*types.Block{gblock}, blocks...) + _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 1, generate) + blocks = append([]*types.Block{genesis.ToBlock()}, blocks...) return genesis, blocks } diff --git a/les/catalyst/api_test.go b/les/catalyst/api_test.go index 26c49d6ef908..6d0eedeccb77 100644 --- a/les/catalyst/api_test.go +++ b/les/catalyst/api_test.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/beacon" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/downloader" @@ -46,18 +45,15 @@ var ( ) func generatePreMergeChain(n int) (*core.Genesis, []*types.Header, []*types.Block) { - db := rawdb.NewMemoryDatabase() - config := params.AllEthashProtocolChanges + config := *params.AllEthashProtocolChanges genesis := &core.Genesis{ - Config: config, + Config: &config, Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, ExtraData: []byte("test genesis"), Timestamp: 9000, BaseFee: big.NewInt(params.InitialBaseFee), } - gblock := genesis.MustCommit(db) - engine := ethash.NewFaker() - blocks, _ := core.GenerateChain(config, gblock, engine, db, n, nil) + _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), n, nil) totalDifficulty := big.NewInt(0) var headers []*types.Header diff --git a/les/odr_test.go b/les/odr_test.go index 24b8e2ae3111..48fd9f95e394 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -129,7 +129,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai data[35] = byte(i) if bc != nil { header := bc.GetHeaderByHash(bhash) - statedb, err := state.New(header.Root, state.NewDatabase(db), nil) + statedb, err := state.New(header.Root, bc.StateCache(), nil) if err == nil { from := statedb.GetOrNewStateObject(bankAddr) diff --git a/light/odr_test.go b/light/odr_test.go index d08963af6628..7f5670587545 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -36,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie" ) var ( @@ -57,6 +56,7 @@ type testOdr struct { OdrBackend indexerConfig *IndexerConfig sdb, ldb ethdb.Database + serverState state.Database disable bool } @@ -82,7 +82,18 @@ func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error { req.Receipts = rawdb.ReadRawReceipts(odr.sdb, req.Hash, *number) } case *TrieRequest: - t, _ := trie.New(common.BytesToHash(req.Id.AccKey), req.Id.Root, trie.NewDatabase(odr.sdb)) + var ( + err error + t state.Trie + ) + if len(req.Id.AccKey) > 0 { + t, err = odr.serverState.OpenStorageTrie(common.BytesToHash(req.Id.AccKey), req.Id.Root) + } else { + t, err = odr.serverState.OpenTrie(req.Id.Root) + } + if err != nil { + panic(err) + } nodes := NewNodeSet() t.Prove(req.Key, 0, nodes) req.Proof = nodes @@ -149,7 +160,7 @@ func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc st = NewState(ctx, header, lc.Odr()) } else { header := bc.GetHeaderByHash(bhash) - st, _ = state.New(header.Root, state.NewDatabase(db), nil) + st, _ = state.New(header.Root, bc.StateCache(), nil) } var res []byte @@ -189,7 +200,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain } else { chain = bc header = bc.GetHeaderByHash(bhash) - st, _ = state.New(header.Root, state.NewDatabase(db), nil) + st, _ = state.New(header.Root, bc.StateCache(), nil) } // Perform read-only call. @@ -258,18 +269,17 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(sdb) ) - gspec.MustCommit(ldb) // Assemble the test environment blockchain, _ := core.NewBlockChain(sdb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) - gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen) + _, gchain, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 4, testChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { t.Fatal(err) } - odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig} - lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil) + gspec.MustCommit(ldb) + odr := &testOdr{sdb: sdb, ldb: ldb, serverState: blockchain.StateCache(), indexerConfig: TestClientIndexerConfig} + lightchain, err := NewLightChain(odr, gspec.Config, ethash.NewFullFaker(), nil) if err != nil { t.Fatal(err) } diff --git a/light/trie_test.go b/light/trie_test.go index 581469c41f49..0ab3eb02a064 100644 --- a/light/trie_test.go +++ b/light/trie_test.go @@ -42,20 +42,19 @@ func TestNodeIterator(t *testing.T) { Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(fulldb) ) - gspec.MustCommit(lightdb) blockchain, _ := core.NewBlockChain(fulldb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) - gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen) + _, gchain, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 4, testChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) } + gspec.MustCommit(lightdb) ctx := context.Background() - odr := &testOdr{sdb: fulldb, ldb: lightdb, indexerConfig: TestClientIndexerConfig} + odr := &testOdr{sdb: fulldb, ldb: lightdb, serverState: blockchain.StateCache(), indexerConfig: TestClientIndexerConfig} head := blockchain.CurrentHeader() lightTrie, _ := NewStateDatabase(ctx, head, odr).OpenTrie(head.Root) - fullTrie, _ := state.NewDatabase(fulldb).OpenTrie(head.Root) + fullTrie, _ := blockchain.StateCache().OpenTrie(head.Root) if err := diffTries(fullTrie, lightTrie); err != nil { t.Fatal(err) } diff --git a/light/txpool_test.go b/light/txpool_test.go index 78cac513cbaf..53732acfa8c8 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -88,17 +88,16 @@ func TestTxPool(t *testing.T) { Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(sdb) ) - gspec.MustCommit(ldb) // Assemble the test environment blockchain, _ := core.NewBlockChain(sdb, nil, gspec, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) - gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen) + _, gchain, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), poolTestBlocks, txPoolTestChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) } - odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig} + gspec.MustCommit(ldb) + odr := &testOdr{sdb: sdb, ldb: ldb, serverState: blockchain.StateCache(), indexerConfig: TestClientIndexerConfig} relay := &testTxRelay{ send: make(chan int, 1), discard: make(chan int, 1), diff --git a/miner/worker_test.go b/miner/worker_test.go index 3c70b4baafb6..2f1939f75981 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -118,11 +118,10 @@ type testWorkerBackend struct { } func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend { - var gspec = core.Genesis{ + var gspec = &core.Genesis{ Config: chainConfig, Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, } - switch e := engine.(type) { case *clique.Clique: gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) @@ -134,34 +133,35 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine default: t.Fatalf("unexpected consensus engine type: %T", engine) } - genesis := gspec.MustCommit(db) - - chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, &gspec, nil, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil, nil) txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) // Generate a small n-block chain and an uncle block for it + var uncle *types.Block if n > 0 { - blocks, _ := core.GenerateChain(chainConfig, genesis, engine, db, n, func(i int, gen *core.BlockGen) { + genDb, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, func(i int, gen *core.BlockGen) { gen.SetCoinbase(testBankAddress) }) if _, err := chain.InsertChain(blocks); err != nil { t.Fatalf("failed to insert origin chain: %v", err) } + parent := chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) + blocks, _ = core.GenerateChain(chainConfig, parent, engine, genDb, 1, func(i int, gen *core.BlockGen) { + gen.SetCoinbase(testUserAddress) + }) + uncle = blocks[0] + } else { + _, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, 1, func(i int, gen *core.BlockGen) { + gen.SetCoinbase(testUserAddress) + }) + uncle = blocks[0] } - parent := genesis - if n > 0 { - parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) - } - blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) { - gen.SetCoinbase(testUserAddress) - }) - return &testWorkerBackend{ db: db, chain: chain, txPool: txpool, - genesis: &gspec, - uncleBlock: blocks[0], + genesis: gspec, + uncleBlock: uncle, } } @@ -217,26 +217,22 @@ func TestGenerateBlockAndImportClique(t *testing.T) { func testGenerateBlockAndImport(t *testing.T, isClique bool) { var ( engine consensus.Engine - chainConfig *params.ChainConfig + chainConfig params.ChainConfig db = rawdb.NewMemoryDatabase() ) if isClique { - chainConfig = params.AllCliqueProtocolChanges + chainConfig = *params.AllCliqueProtocolChanges chainConfig.Clique = ¶ms.CliqueConfig{Period: 1, Epoch: 30000} engine = clique.New(chainConfig.Clique, db) } else { - chainConfig = params.AllEthashProtocolChanges + chainConfig = *params.AllEthashProtocolChanges engine = ethash.NewFaker() } - - chainConfig.LondonBlock = big.NewInt(0) - w, b := newTestWorker(t, chainConfig, engine, db, 0) + w, b := newTestWorker(t, &chainConfig, engine, db, 0) defer w.close() // This test chain imports the mined blocks. - db2 := rawdb.NewMemoryDatabase() - b.genesis.MustCommit(db2) - chain, _ := core.NewBlockChain(db2, nil, b.genesis, nil, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, b.genesis, nil, engine, vm.Config{}, nil, nil) defer chain.Stop() // Ignore empty commit here for less noise. diff --git a/tests/fuzzers/les/les-fuzzer.go b/tests/fuzzers/les/les-fuzzer.go index bb50da2bd841..d3a25a31c084 100644 --- a/tests/fuzzers/les/les-fuzzer.go +++ b/tests/fuzzers/les/les-fuzzer.go @@ -54,15 +54,13 @@ var ( ) func makechain() (bc *core.BlockChain, addrHashes, txHashes []common.Hash) { - db := rawdb.NewMemoryDatabase() - gspec := core.Genesis{ + gspec := &core.Genesis{ Config: params.TestChainConfig, Alloc: core.GenesisAlloc{bankAddr: {Balance: bankFunds}}, GasLimit: 100000000, } - genesis := gspec.MustCommit(db) signer := types.HomesteadSigner{} - blocks, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, testChainLen, + _, blocks, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), testChainLen, func(i int, gen *core.BlockGen) { var ( tx *types.Transaction @@ -80,7 +78,7 @@ func makechain() (bc *core.BlockChain, addrHashes, txHashes []common.Hash) { addrHashes = append(addrHashes, crypto.Keccak256Hash(addr[:])) txHashes = append(txHashes, tx.Hash()) }) - bc, _ = core.NewBlockChain(db, nil, &gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if _, err := bc.InsertChain(blocks); err != nil { panic(err) } diff --git a/tests/fuzzers/snap/fuzz_handler.go b/tests/fuzzers/snap/fuzz_handler.go index 6c370b043e72..2e5dcd6e29a0 100644 --- a/tests/fuzzers/snap/fuzz_handler.go +++ b/tests/fuzzers/snap/fuzz_handler.go @@ -39,7 +39,6 @@ import ( var trieRoot common.Hash func getChain() *core.BlockChain { - db := rawdb.NewMemoryDatabase() ga := make(core.GenesisAlloc, 1000) var a = make([]byte, 20) var mkStorage = func(k, v int) (common.Hash, common.Hash) { @@ -66,9 +65,7 @@ func getChain() *core.BlockChain { Config: params.TestChainConfig, Alloc: ga, } - genesis := gspec.MustCommit(db) - blocks, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 2, - func(i int, gen *core.BlockGen) {}) + _, blocks, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *core.BlockGen) {}) cacheConf := &core.CacheConfig{ TrieCleanLimit: 0, TrieDirtyLimit: 0, @@ -79,7 +76,7 @@ func getChain() *core.BlockChain { SnapshotWait: true, } trieRoot = blocks[len(blocks)-1].Root() - bc, _ := core.NewBlockChain(db, cacheConf, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), cacheConf, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if _, err := bc.InsertChain(blocks); err != nil { panic(err) } From b1f6dccfbaa5712adafabd374b89d8d12e4ad3ad Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 8 Sep 2022 02:25:58 +0800 Subject: [PATCH 221/715] eth, les: rework chain tracer (#25143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR simplifies the logic of chain tracer and also adds the unit tests. The most important change has been made in this PR is the state management. Whenever a tracing state is acquired there is a corresponding release function be returned as well. It must be called once the state is used up, otherwise resource leaking can happen. And also the logic of state management has been simplified a lot. Specifically, the state provider(eth backend, les backend) should ensure the state is available and referenced. State customers can use the state according to their own needs, or build other states based on the given state. But once the release function is called, there is no guarantee of the availability of the state. Co-authored-by: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Co-authored-by: Péter Szilágyi --- eth/api.go | 4 +- eth/api_backend.go | 7 +- eth/state_accessor.go | 107 +++++++++++++-------- eth/tracers/api.go | 208 ++++++++++++++++++++++++---------------- eth/tracers/api_test.go | 105 +++++++++++++++++--- les/api_backend.go | 5 +- les/state_accessor.go | 27 +++--- 7 files changed, 308 insertions(+), 155 deletions(-) diff --git a/eth/api.go b/eth/api.go index 5642ef4c3f12..3b5bb5f0aa9c 100644 --- a/eth/api.go +++ b/eth/api.go @@ -411,10 +411,12 @@ func (api *DebugAPI) StorageRangeAt(blockHash common.Hash, txIndex int, contract if block == nil { return StorageRangeResult{}, fmt.Errorf("block %#x not found", blockHash) } - _, _, statedb, err := api.eth.stateAtTransaction(block, txIndex, 0) + _, _, statedb, release, err := api.eth.stateAtTransaction(block, txIndex, 0) if err != nil { return StorageRangeResult{}, err } + defer release() + st := statedb.StorageTrie(contractAddress) if st == nil { return StorageRangeResult{}, fmt.Errorf("account %x doesn't exist", contractAddress) diff --git a/eth/api_backend.go b/eth/api_backend.go index 00ecacc31df7..97c22c8fbbe9 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/gasprice" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/miner" @@ -363,10 +364,10 @@ func (b *EthAPIBackend) StartMining(threads int) error { return b.eth.StartMining(threads) } -func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive, preferDisk bool) (*state.StateDB, error) { - return b.eth.StateAtBlock(block, reexec, base, checkLive, preferDisk) +func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) { + return b.eth.StateAtBlock(block, reexec, base, readOnly, preferDisk) } -func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) { +func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtTransaction(block, txIndex, reexec) } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 12dba8a0a9b0..4651ef3066f6 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -26,39 +26,59 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie" ) +// noopReleaser is returned in case there is no operation expected +// for releasing state. +var noopReleaser = tracers.StateReleaseFunc(func() {}) + // StateAtBlock retrieves the state database associated with a certain block. // If no state is locally available for the given block, a number of blocks // are attempted to be reexecuted to generate the desired state. The optional -// base layer statedb can be passed then it's regarded as the statedb of the +// base layer statedb can be provided which is regarded as the statedb of the // parent block. +// +// An additional release function will be returned if the requested state is +// available. Release is expected to be invoked when the returned state is no longer needed. +// Its purpose is to prevent resource leaking. Though it can be noop in some cases. +// // Parameters: -// - block: The block for which we want the state (== state at the stateRoot of the parent) -// - reexec: The maximum number of blocks to reprocess trying to obtain the desired state -// - base: If the caller is tracing multiple blocks, the caller can provide the parent state -// continuously from the callsite. -// - checklive: if true, then the live 'blockchain' state database is used. If the caller want to -// perform Commit or other 'save-to-disk' changes, this should be set to false to avoid -// storing trash persistently -// - preferDisk: this arg can be used by the caller to signal that even though the 'base' is provided, -// it would be preferable to start from a fresh state, if we have it on disk. -func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { +// - block: The block for which we want the state(state = block.Root) +// - reexec: The maximum number of blocks to reprocess trying to obtain the desired state +// - base: If the caller is tracing multiple blocks, the caller can provide the parent +// state continuously from the callsite. +// - readOnly: If true, then the live 'blockchain' state database is used. No mutation should +// be made from caller, e.g. perform Commit or other 'save-to-disk' changes. +// Otherwise, the trash generated by caller may be persisted permanently. +// - preferDisk: this arg can be used by the caller to signal that even though the 'base' is +// provided, it would be preferable to start from a fresh state, if we have it +// on disk. +func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) { var ( current *types.Block database state.Database report = true origin = block.NumberU64() ) - // Check the live database first if we have the state fully available, use that. - if checkLive { - statedb, err = eth.blockchain.StateAt(block.Root()) - if err == nil { - return statedb, nil + // The state is only for reading purposes, check the state presence in + // live database. + if readOnly { + // The state is available in live database, create a reference + // on top to prevent garbage collection and return a release + // function to deref it. + if statedb, err = eth.blockchain.StateAt(block.Root()); err == nil { + statedb.Database().TrieDB().Reference(block.Root(), common.Hash{}) + return statedb, func() { + statedb.Database().TrieDB().Dereference(block.Root()) + }, nil } } + // The state is both for reading and writing, or it's unavailable in disk, + // try to construct/recover the state over an ephemeral trie.Database for + // isolating the live one. if base != nil { if preferDisk { // Create an ephemeral trie.Database for isolating the live one. Otherwise @@ -66,37 +86,37 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state database = state.NewDatabaseWithConfig(eth.chainDb, &trie.Config{Cache: 16}) if statedb, err = state.New(block.Root(), database, nil); err == nil { log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number()) - return statedb, nil + return statedb, noopReleaser, nil } } // The optional base statedb is given, mark the start point as parent block statedb, database, report = base, base.Database(), false current = eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) } else { - // Otherwise try to reexec blocks until we find a state or reach our limit + // Otherwise, try to reexec blocks until we find a state or reach our limit current = block // Create an ephemeral trie.Database for isolating the live one. Otherwise // the internal junks created by tracing will be persisted into the disk. database = state.NewDatabaseWithConfig(eth.chainDb, &trie.Config{Cache: 16}) - // If we didn't check the dirty database, do check the clean one, otherwise - // we would rewind past a persisted block (specific corner case is chain - // tracing from the genesis). - if !checkLive { + // If we didn't check the live database, do check state over ephemeral database, + // otherwise we would rewind past a persisted block (specific corner case is + // chain tracing from the genesis). + if !readOnly { statedb, err = state.New(current.Root(), database, nil) if err == nil { - return statedb, nil + return statedb, noopReleaser, nil } } // Database does not have the state for the given block, try to regenerate for i := uint64(0); i < reexec; i++ { if current.NumberU64() == 0 { - return nil, errors.New("genesis state is missing") + return nil, nil, errors.New("genesis state is missing") } parent := eth.blockchain.GetBlock(current.ParentHash(), current.NumberU64()-1) if parent == nil { - return nil, fmt.Errorf("missing block %v %d", current.ParentHash(), current.NumberU64()-1) + return nil, nil, fmt.Errorf("missing block %v %d", current.ParentHash(), current.NumberU64()-1) } current = parent @@ -108,13 +128,14 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state if err != nil { switch err.(type) { case *trie.MissingNodeError: - return nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexec) + return nil, nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexec) default: - return nil, err + return nil, nil, err } } } - // State was available at historical point, regenerate + // State is available at historical point, re-execute the blocks on top for + // the desired state. var ( start = time.Now() logged time.Time @@ -129,22 +150,24 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state // Retrieve the next block to regenerate and process it next := current.NumberU64() + 1 if current = eth.blockchain.GetBlockByNumber(next); current == nil { - return nil, fmt.Errorf("block #%d not found", next) + return nil, nil, fmt.Errorf("block #%d not found", next) } _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) if err != nil { - return nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) + return nil, nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) } // Finalize the state so any modifications are written to the trie root, err := statedb.Commit(eth.blockchain.Config().IsEIP158(current.Number())) if err != nil { - return nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w", + return nil, nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w", current.NumberU64(), current.Root().Hex(), err) } statedb, err = state.New(root, database, nil) if err != nil { - return nil, fmt.Errorf("state reset after block %d failed: %v", current.NumberU64(), err) + return nil, nil, fmt.Errorf("state reset after block %d failed: %v", current.NumberU64(), err) } + // Hold the state reference and also drop the parent state + // to prevent accumulating too many nodes in memory. database.TrieDB().Reference(root, common.Hash{}) if parent != (common.Hash{}) { database.TrieDB().Dereference(parent) @@ -155,28 +178,28 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state nodes, imgs := database.TrieDB().Size() log.Info("Historical state regenerated", "block", current.NumberU64(), "elapsed", time.Since(start), "nodes", nodes, "preimages", imgs) } - return statedb, nil + return statedb, func() { database.TrieDB().Dereference(block.Root()) }, nil } // stateAtTransaction returns the execution environment of a certain transaction. -func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) { +func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { // Short circuit if it's genesis block. if block.NumberU64() == 0 { - return nil, vm.BlockContext{}, nil, errors.New("no transaction in genesis") + return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis") } // Create the parent state database parent := eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { - return nil, vm.BlockContext{}, nil, fmt.Errorf("parent %#x not found", block.ParentHash()) + return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("parent %#x not found", block.ParentHash()) } // Lookup the statedb of parent block from the live database, // otherwise regenerate it on the flight. - statedb, err := eth.StateAtBlock(parent, reexec, nil, true, false) + statedb, release, err := eth.StateAtBlock(parent, reexec, nil, true, false) if err != nil { - return nil, vm.BlockContext{}, nil, err + return nil, vm.BlockContext{}, nil, nil, err } if txIndex == 0 && len(block.Transactions()) == 0 { - return nil, vm.BlockContext{}, statedb, nil + return nil, vm.BlockContext{}, statedb, release, nil } // Recompute transactions up to the target index. signer := types.MakeSigner(eth.blockchain.Config(), block.Number()) @@ -186,17 +209,17 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) if idx == txIndex { - return msg, context, statedb, nil + return msg, context, statedb, release, nil } // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{}) statedb.Prepare(tx.Hash(), idx) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { - return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) + return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } // Ensure any modifications are committed to the state // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) } - return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) + return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 092950e78fa9..0cf2f45a8729 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -63,6 +63,10 @@ const ( defaultTracechainMemLimit = common.StorageSize(500 * 1024 * 1024) ) +// StateReleaseFunc is used to deallocate resources held by constructing a +// historical state for tracing purposes. +type StateReleaseFunc func() + // Backend interface provides the common API services (that are provided by // both full and light clients) with access to necessary functions. type Backend interface { @@ -75,11 +79,8 @@ type Backend interface { ChainConfig() *params.ChainConfig Engine() consensus.Engine ChainDb() ethdb.Database - // StateAtBlock returns the state corresponding to the stateroot of the block. - // N.B: For executing transactions on block N, the required stateRoot is block N-1, - // so this method should be called with the parent. - StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive, preferDisk bool) (*state.StateDB, error) - StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) + StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) + StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) } // API is the collection of tracing APIs exposed over the private debugging endpoint. @@ -201,7 +202,7 @@ type txTraceResult struct { type blockTraceTask struct { statedb *state.StateDB // Intermediate state prepped for tracing block *types.Block // Block to trace the transactions from - rootref common.Hash // Trie root reference held for this task + release StateReleaseFunc // The function to release the held resource for this task results []*txTraceResult // Trace results produced by the task } @@ -234,13 +235,6 @@ func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, conf if from.Number().Cmp(to.Number()) >= 0 { return nil, fmt.Errorf("end block (#%d) needs to come after start block (#%d)", end, start) } - return api.traceChain(ctx, from, to, config) -} - -// traceChain configures a new tracer according to the provided configuration, and -// executes all the transactions contained within. The return value will be one item -// per transaction, dependent on the requested tracer. -func (api *API) traceChain(ctx context.Context, start, end *types.Block, config *TraceConfig) (*rpc.Subscription, error) { // Tracing a chain is a **long** operation, only do with subscriptions notifier, supported := rpc.NotifierFromContext(ctx) if !supported { @@ -248,8 +242,45 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config } sub := notifier.CreateSubscription() - // Prepare all the states for tracing. Note this procedure can take very - // long time. Timeout mechanism is necessary. + resCh := api.traceChain(from, to, config, notifier.Closed()) + go func() { + for result := range resCh { + notifier.Notify(sub.ID, result) + } + }() + return sub, nil +} + +// releaser is a helper tool responsible for caching the release +// callbacks of tracing state. +type releaser struct { + releases []StateReleaseFunc + lock sync.Mutex +} + +func (r *releaser) add(release StateReleaseFunc) { + r.lock.Lock() + defer r.lock.Unlock() + + r.releases = append(r.releases, release) +} + +func (r *releaser) call() { + r.lock.Lock() + defer r.lock.Unlock() + + for _, release := range r.releases { + release() + } + r.releases = r.releases[:0] +} + +// traceChain configures a new tracer according to the provided configuration, and +// executes all the transactions contained within. The tracing chain range includes +// the end block but excludes the start one. The return value will be one item per +// transaction, dependent on the requested tracer. +// The tracing procedure should be aborted in case the closed signal is received. +func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan interface{}) chan *blockTraceResult { reexec := defaultTraceReexec if config != nil && config.Reexec != nil { reexec = *config.Reexec @@ -260,20 +291,23 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config threads = blocks } var ( - pend = new(sync.WaitGroup) - tasks = make(chan *blockTraceTask, threads) - results = make(chan *blockTraceTask, threads) - localctx = context.Background() + pend = new(sync.WaitGroup) + ctx = context.Background() + taskCh = make(chan *blockTraceTask, threads) + resCh = make(chan *blockTraceTask, threads) + reler = new(releaser) ) for th := 0; th < threads; th++ { pend.Add(1) go func() { defer pend.Done() - // Fetch and execute the next block trace tasks - for task := range tasks { - signer := types.MakeSigner(api.backend.ChainConfig(), task.block.Number()) - blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(localctx), nil) + // Fetch and execute the block trace taskCh + for task := range taskCh { + var ( + signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number()) + blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil) + ) // Trace all the transactions contained within for i, tx := range task.block.Transactions() { msg, _ := tx.AsMessage(signer, task.block.BaseFee()) @@ -282,7 +316,7 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config TxIndex: i, TxHash: tx.Hash(), } - res, err := api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config) + res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) if err != nil { task.results[i] = &txTraceResult{Error: err.Error()} log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) @@ -292,36 +326,38 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number())) task.results[i] = &txTraceResult{Result: res} } - // Stream the result back to the user or abort on teardown + // Tracing state is used up, queue it for de-referencing + reler.add(task.release) + + // Stream the result back to the result catcher or abort on teardown select { - case results <- task: - case <-notifier.Closed(): + case resCh <- task: + case <-closed: return } } }() } // Start a goroutine to feed all the blocks into the tracers - var ( - begin = time.Now() - derefTodo []common.Hash // list of hashes to dereference from the db - derefsMu sync.Mutex // mutex for the derefs - ) - go func() { var ( logged time.Time + begin = time.Now() number uint64 traced uint64 failed error - parent common.Hash statedb *state.StateDB + release StateReleaseFunc ) // Ensure everything is properly cleaned up on any exit path defer func() { - close(tasks) + close(taskCh) pend.Wait() + // Clean out any pending derefs. + reler.call() + + // Log the chain result switch { case failed != nil: log.Warn("Chain tracing failed", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin), "err", failed) @@ -330,105 +366,97 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config default: log.Info("Chain tracing finished", "start", start.NumberU64(), "end", end.NumberU64(), "transactions", traced, "elapsed", time.Since(begin)) } - close(results) + close(resCh) }() - var preferDisk bool // Feed all the blocks both into the tracer, as well as fast process concurrently for number = start.NumberU64(); number < end.NumberU64(); number++ { // Stop tracing if interruption was requested select { - case <-notifier.Closed(): + case <-closed: return default: } - // clean out any derefs - derefsMu.Lock() - for _, h := range derefTodo { - statedb.Database().TrieDB().Dereference(h) - } - derefTodo = derefTodo[:0] - derefsMu.Unlock() - // Print progress logs if long enough time elapsed if time.Since(logged) > 8*time.Second { logged = time.Now() log.Info("Tracing chain segment", "start", start.NumberU64(), "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin)) } - // Retrieve the parent state to trace on top - block, err := api.blockByNumber(localctx, rpc.BlockNumber(number)) + // Retrieve the parent block and target block for tracing. + block, err := api.blockByNumber(ctx, rpc.BlockNumber(number)) if err != nil { failed = err break } - // Prepare the statedb for tracing. Don't use the live database for - // tracing to avoid persisting state junks into the database. - statedb, err = api.backend.StateAtBlock(localctx, block, reexec, statedb, false, preferDisk) + next, err := api.blockByNumber(ctx, rpc.BlockNumber(number+1)) if err != nil { failed = err break } - if trieDb := statedb.Database().TrieDB(); trieDb != nil { - // Hold the reference for tracer, will be released at the final stage - trieDb.Reference(block.Root(), common.Hash{}) - - // Release the parent state because it's already held by the tracer - if parent != (common.Hash{}) { - trieDb.Dereference(parent) - } - // Prefer disk if the trie db memory grows too much - s1, s2 := trieDb.Size() - if !preferDisk && (s1+s2) > defaultTracechainMemLimit { - log.Info("Switching to prefer-disk mode for tracing", "size", s1+s2) - preferDisk = true - } + // Prepare the statedb for tracing. Don't use the live database for + // tracing to avoid persisting state junks into the database. Switch + // over to `preferDisk` mode only if the memory usage exceeds the + // limit, the trie database will be reconstructed from scratch only + // if the relevant state is available in disk. + var preferDisk bool + if statedb != nil { + s1, s2 := statedb.Database().TrieDB().Size() + preferDisk = s1+s2 > defaultTracechainMemLimit } - parent = block.Root() - - next, err := api.blockByNumber(localctx, rpc.BlockNumber(number+1)) + statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, statedb, false, preferDisk) if err != nil { failed = err break } + // Clean out any pending derefs. Note this step must be done after + // constructing tracing state, because the tracing state of block + // next depends on the parent state and construction may fail if + // we release too early. + reler.call() + // Send the block over to the concurrent tracers (if not in the fast-forward phase) txs := next.Transactions() select { - case tasks <- &blockTraceTask{statedb: statedb.Copy(), block: next, rootref: block.Root(), results: make([]*txTraceResult, len(txs))}: - case <-notifier.Closed(): + case taskCh <- &blockTraceTask{statedb: statedb.Copy(), block: next, release: release, results: make([]*txTraceResult, len(txs))}: + case <-closed: + reler.add(release) return } traced += uint64(len(txs)) } }() - // Keep reading the trace results and stream the to the user + // Keep reading the trace results and stream them to result channel. + retCh := make(chan *blockTraceResult) go func() { + defer close(retCh) var ( - done = make(map[uint64]*blockTraceResult) next = start.NumberU64() + 1 + done = make(map[uint64]*blockTraceResult) ) - for res := range results { + for res := range resCh { // Queue up next received result result := &blockTraceResult{ Block: hexutil.Uint64(res.block.NumberU64()), Hash: res.block.Hash(), Traces: res.results, } - // Schedule any parent tries held in memory by this task for dereferencing done[uint64(result.Block)] = result - derefsMu.Lock() - derefTodo = append(derefTodo, res.rootref) - derefsMu.Unlock() - // Stream completed traces to the user, aborting on the first error + + // Stream completed traces to the result channel for result, ok := done[next]; ok; result, ok = done[next] { if len(result.Traces) > 0 || next == end.NumberU64() { - notifier.Notify(sub.ID, result) + // It will be blocked in case the channel consumer doesn't take the + // tracing result in time(e.g. the websocket connect is not stable) + // which will eventually block the entire chain tracer. It's the + // expected behavior to not waste node resources for a non-active user. + retCh <- result } delete(done, next) next++ } } }() - return sub, nil + return retCh } // TraceBlockByNumber returns the structured logs created during the execution of @@ -515,10 +543,12 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config if config != nil && config.Reexec != nil { reexec = *config.Reexec } - statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) + statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { return nil, err } + defer release() + var ( roots []common.Hash signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) @@ -576,10 +606,12 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac if config != nil && config.Reexec != nil { reexec = *config.Reexec } - statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) + statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { return nil, err } + defer release() + // Execute all the transaction contained within the block concurrently var ( signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) @@ -666,10 +698,12 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block if config != nil && config.Reexec != nil { reexec = *config.Reexec } - statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) + statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { return nil, err } + defer release() + // Retrieve the tracing configurations, or use default values var ( logConfig logger.Config @@ -793,10 +827,12 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * if err != nil { return nil, err } - msg, vmctx, statedb, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec) + msg, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec) if err != nil { return nil, err } + defer release() + txctx := &Context{ BlockHash: blockHash, TxIndex: int(index), @@ -837,10 +873,12 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc if config != nil && config.Reexec != nil { reexec = *config.Reexec } - statedb, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false) + statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false) if err != nil { return nil, err } + defer release() + vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) // Apply the customization rules if required. if config != nil { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 40d860b857d1..414ba6fe996c 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -26,6 +26,7 @@ import ( "math/big" "reflect" "sort" + "sync/atomic" "testing" "time" @@ -57,6 +58,9 @@ type testBackend struct { engine consensus.Engine chaindb ethdb.Database chain *core.BlockChain + + refHook func() // Hook is invoked when the requested state is referenced + relHook func() // Hook is invoked when the requested state is released } func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend { @@ -133,25 +137,33 @@ func (b *testBackend) ChainDb() ethdb.Database { return b.chaindb } -func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (*state.StateDB, error) { +func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) { statedb, err := b.chain.StateAt(block.Root()) if err != nil { - return nil, errStateNotFound + return nil, nil, errStateNotFound + } + if b.refHook != nil { + b.refHook() + } + release := func() { + if b.relHook != nil { + b.relHook() + } } - return statedb, nil + return statedb, release, nil } -func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) { +func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) { parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { - return nil, vm.BlockContext{}, nil, errBlockNotFound + return nil, vm.BlockContext{}, nil, nil, errBlockNotFound } - statedb, err := b.chain.StateAt(parent.Root()) + statedb, release, err := b.StateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { - return nil, vm.BlockContext{}, nil, errStateNotFound + return nil, vm.BlockContext{}, nil, nil, errStateNotFound } if txIndex == 0 && len(block.Transactions()) == 0 { - return nil, vm.BlockContext{}, statedb, nil + return nil, vm.BlockContext{}, statedb, release, nil } // Recompute transactions up to the target index. signer := types.MakeSigner(b.chainConfig, block.Number()) @@ -160,15 +172,15 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), b.chain, nil) if idx == txIndex { - return msg, context, statedb, nil + return msg, context, statedb, release, nil } vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{}) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { - return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) + return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) } - return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) + return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) } func TestTraceCall(t *testing.T) { @@ -622,3 +634,74 @@ func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.H } return &m } + +func TestTraceChain(t *testing.T) { + // Initialize test accounts + accounts := newAccounts(3) + genesis := &core.Genesis{Alloc: core.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(params.Ether)}, + accounts[1].addr: {Balance: big.NewInt(params.Ether)}, + accounts[2].addr: {Balance: big.NewInt(params.Ether)}, + }} + genBlocks := 50 + signer := types.HomesteadSigner{} + + var ( + ref uint32 // total refs has made + rel uint32 // total rels has made + nonce uint64 + ) + backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { + // Transfer from account[0] to account[1] + // value: 1000 wei + // fee: 0 wei + for j := 0; j < i+1; j++ { + tx, _ := types.SignTx(types.NewTransaction(nonce, accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) + b.AddTx(tx) + nonce += 1 + } + }) + backend.refHook = func() { atomic.AddUint32(&ref, 1) } + backend.relHook = func() { atomic.AddUint32(&rel, 1) } + api := NewAPI(backend) + + single := `{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}` + var cases = []struct { + start uint64 + end uint64 + config *TraceConfig + }{ + {0, 50, nil}, // the entire chain range, blocks [1, 50] + {10, 20, nil}, // the middle chain range, blocks [11, 20] + } + for _, c := range cases { + ref, rel = 0, 0 // clean up the counters + + from, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.start)) + to, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.end)) + resCh := api.traceChain(from, to, c.config, nil) + + next := c.start + 1 + for result := range resCh { + if next != uint64(result.Block) { + t.Error("Unexpected tracing block") + } + if len(result.Traces) != int(next) { + t.Error("Unexpected tracing result") + } + for _, trace := range result.Traces { + blob, _ := json.Marshal(trace) + if string(blob) != single { + t.Error("Unexpected tracing result") + } + } + next += 1 + } + if next != c.end+1 { + t.Error("Missing tracing block") + } + if ref != rel { + t.Errorf("Ref and deref actions are not equal, ref %d rel %d", ref, rel) + } + } +} diff --git a/les/api_backend.go b/les/api_backend.go index 5b4213134b24..71cfbbed1e55 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/gasprice" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/light" @@ -321,10 +322,10 @@ func (b *LesApiBackend) CurrentHeader() *types.Header { return b.eth.blockchain.CurrentHeader() } -func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (*state.StateDB, error) { +func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtBlock(ctx, block, reexec) } -func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) { +func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) } diff --git a/les/state_accessor.go b/les/state_accessor.go index 112e6fd44d12..a2d49fbf31ce 100644 --- a/les/state_accessor.go +++ b/les/state_accessor.go @@ -25,31 +25,36 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/light" ) +// noopReleaser is returned in case there is no operation expected +// for releasing state. +var noopReleaser = tracers.StateReleaseFunc(func() {}) + // stateAtBlock retrieves the state database associated with a certain block. -func (leth *LightEthereum) stateAtBlock(ctx context.Context, block *types.Block, reexec uint64) (*state.StateDB, error) { - return light.NewState(ctx, block.Header(), leth.odr), nil +func (leth *LightEthereum) stateAtBlock(ctx context.Context, block *types.Block, reexec uint64) (*state.StateDB, tracers.StateReleaseFunc, error) { + return light.NewState(ctx, block.Header(), leth.odr), noopReleaser, nil } // stateAtTransaction returns the execution environment of a certain transaction. -func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) { +func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { // Short circuit if it's genesis block. if block.NumberU64() == 0 { - return nil, vm.BlockContext{}, nil, errors.New("no transaction in genesis") + return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis") } // Create the parent state database parent, err := leth.blockchain.GetBlock(ctx, block.ParentHash(), block.NumberU64()-1) if err != nil { - return nil, vm.BlockContext{}, nil, err + return nil, vm.BlockContext{}, nil, nil, err } - statedb, err := leth.stateAtBlock(ctx, parent, reexec) + statedb, release, err := leth.stateAtBlock(ctx, parent, reexec) if err != nil { - return nil, vm.BlockContext{}, nil, err + return nil, vm.BlockContext{}, nil, nil, err } if txIndex == 0 && len(block.Transactions()) == 0 { - return nil, vm.BlockContext{}, statedb, nil + return nil, vm.BlockContext{}, statedb, release, nil } // Recompute transactions up to the target index. signer := types.MakeSigner(leth.blockchain.Config(), block.Number()) @@ -60,16 +65,16 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types. context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil) statedb.Prepare(tx.Hash(), idx) if idx == txIndex { - return msg, context, statedb, nil + return msg, context, statedb, release, nil } // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{}) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { - return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) + return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } // Ensure any modifications are committed to the state // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) } - return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) + return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) } From 6a575eda6fe1736923e3e6df261d4ed78ba32e08 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 8 Sep 2022 14:06:06 +0800 Subject: [PATCH 222/715] eth/tracer: fix broken test (#25715) --- eth/tracers/api_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 414ba6fe996c..346813ae2c77 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -638,11 +638,14 @@ func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.H func TestTraceChain(t *testing.T) { // Initialize test accounts accounts := newAccounts(3) - genesis := &core.Genesis{Alloc: core.GenesisAlloc{ - accounts[0].addr: {Balance: big.NewInt(params.Ether)}, - accounts[1].addr: {Balance: big.NewInt(params.Ether)}, - accounts[2].addr: {Balance: big.NewInt(params.Ether)}, - }} + genesis := &core.Genesis{ + Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(params.Ether)}, + accounts[1].addr: {Balance: big.NewInt(params.Ether)}, + accounts[2].addr: {Balance: big.NewInt(params.Ether)}, + }, + } genBlocks := 50 signer := types.HomesteadSigner{} From 8363f79f8fd735d6264e7549e7f861467fbf6c78 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Thu, 8 Sep 2022 03:36:07 -0700 Subject: [PATCH 223/715] trie: update comments + err check for preimages (#25672) This PR includes minor updates to comments in trie/committer that reference insertion to the db, and adds an err != nil check for the return value of preimages.commit. --- trie/committer.go | 17 +++++++++-------- trie/database.go | 8 ++++++-- trie/secure_trie.go | 8 ++++---- trie/trie.go | 6 +++--- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/trie/committer.go b/trie/committer.go index d9f0ecf3dea4..28fc5a63f940 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -44,7 +44,8 @@ func newCommitter(owner common.Hash, collectLeaf bool) *committer { } } -// Commit collapses a node down into a hash node and inserts it into the database +// Commit collapses a node down into a hash node and returns it along with +// the modified nodeset. func (c *committer) Commit(n node) (hashNode, *NodeSet, error) { h, err := c.commit(nil, n) if err != nil { @@ -53,7 +54,7 @@ func (c *committer) Commit(n node) (hashNode, *NodeSet, error) { return h.(hashNode), c.nodes, nil } -// commit collapses a node down into a hash node and inserts it into the database +// commit collapses a node down into a hash node and returns it. func (c *committer) commit(path []byte, n node) (node, error) { // if this path is clean, use available cached data hash, dirty := n.cache() @@ -75,7 +76,8 @@ func (c *committer) commit(path []byte, n node) (node, error) { } collapsed.Val = childV } - // The key needs to be copied, since we're delivering it to database + // The key needs to be copied, since we're adding it to the + // modified nodeset. collapsed.Key = hexToCompact(cn.Key) hashedNode := c.store(path, collapsed) if hn, ok := hashedNode.(hashNode); ok { @@ -134,17 +136,16 @@ func (c *committer) commitChildren(path []byte, n *fullNode) ([17]node, error) { return children, nil } -// store hashes the node n and if we have a storage layer specified, it writes -// the key/value pair to it and tracks any node->child references as well as any -// node->external trie references. +// store hashes the node n and adds it to the modified nodeset. If leaf collection +// is enabled, leaf nodes will be tracked in the modified nodeset as well. func (c *committer) store(path []byte, n node) node { // Larger nodes are replaced by their hash and stored in the database. var hash, _ = n.cache() // This was not generated - must be a small node stored in the parent. // In theory, we should check if the node is leaf here (embedded node - // usually is leaf node). But small value(less than 32bytes) is not - // our target(leaves in account trie only). + // usually is leaf node). But small value (less than 32bytes) is not + // our target (leaves in account trie only). if hash == nil { return n } diff --git a/trie/database.go b/trie/database.go index cca2bb085317..79de0ed65c48 100644 --- a/trie/database.go +++ b/trie/database.go @@ -562,7 +562,9 @@ func (db *Database) Cap(limit common.StorageSize) error { // If the preimage cache got large enough, push to disk. If it's still small // leave for later to deduplicate writes. if db.preimages != nil { - db.preimages.commit(false) + if err := db.preimages.commit(false); err != nil { + return err + } } // Keep committing nodes from the flush-list until we're below allowance oldest := db.oldest @@ -640,7 +642,9 @@ func (db *Database) Commit(node common.Hash, report bool, callback func(common.H // Move all of the accumulated preimages into a write batch if db.preimages != nil { - db.preimages.commit(true) + if err := db.preimages.commit(true); err != nil { + return err + } } // Move the trie itself into the batch, flushing if enough data is accumulated nodes, storage := len(db.dirties), db.dirtiesSize diff --git a/trie/secure_trie.go b/trie/secure_trie.go index e26c22465504..0b7d33b2199d 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -199,10 +199,10 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { return t.preimages.preimage(common.BytesToHash(shaKey)) } -// Commit collects all dirty nodes in the trie and replace them with the -// corresponding node hash. All collected nodes(including dirty leaves if +// Commit collects all dirty nodes in the trie and replaces 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). +// The returned nodeset can be nil if the trie is clean (nothing to commit). // All cached preimages will be also flushed if preimages recording is enabled. // 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 @@ -218,7 +218,7 @@ func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { } t.secKeyCache = make(map[string][]byte) } - // Commit the trie to its intermediate node database + // Commit the trie and return its modified nodeset. return t.trie.Commit(collectLeaf) } diff --git a/trie/trie.go b/trie/trie.go index e5897b8d7c51..1ef1469c8dd3 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -582,10 +582,10 @@ func (t *Trie) Hash() common.Hash { return common.BytesToHash(hash.(hashNode)) } -// Commit collects all dirty nodes in the trie and replace them with the -// corresponding node hash. All collected nodes(including dirty leaves if +// Commit collects all dirty nodes in the trie and replaces 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). +// 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 *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { From de8d5fa0423e5c2dfbf12eed3694ce4e6b90203c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 9 Sep 2022 11:42:57 +0300 Subject: [PATCH 224/715] eth/protocols/snap: throttle trie heal requests when peers DoS us (#25666) * eth/protocols/snap: throttle trie heal requests when peers DoS us * eth/protocols/snap: lower heal throttle log to debug Co-authored-by: Martin Holst Swende * eth/protocols/snap: fix comment Co-authored-by: Martin Holst Swende --- eth/protocols/snap/sync.go | 107 ++++++++++++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 7 deletions(-) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 1455bacbcb88..eb8260bf7c97 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -21,10 +21,12 @@ import ( "encoding/json" "errors" "fmt" + gomath "math" "math/big" "math/rand" "sort" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -78,6 +80,29 @@ const ( // and waste round trip times. If it's too high, we're capping responses and // waste bandwidth. maxTrieRequestCount = maxRequestSize / 512 + + // trienodeHealRateMeasurementImpact is the impact a single measurement has on + // the local node's trienode processing capacity. A value closer to 0 reacts + // slower to sudden changes, but it is also more stable against temporary hiccups. + trienodeHealRateMeasurementImpact = 0.005 + + // minTrienodeHealThrottle is the minimum divisor for throttling trie node + // heal requests to avoid overloading the local node and exessively expanding + // the state trie bedth wise. + minTrienodeHealThrottle = 1 + + // maxTrienodeHealThrottle is the maximum divisor for throttling trie node + // heal requests to avoid overloading the local node and exessively expanding + // the state trie bedth wise. + maxTrienodeHealThrottle = maxTrieRequestCount + + // trienodeHealThrottleIncrease is the multiplier for the throttle when the + // rate of arriving data is higher than the rate of processing it. + trienodeHealThrottleIncrease = 1.33 + + // trienodeHealThrottleDecrease is the divisor for the throttle when the + // rate of arriving data is lower than the rate of processing it. + trienodeHealThrottleDecrease = 1.25 ) var ( @@ -431,6 +456,11 @@ type Syncer struct { trienodeHealReqs map[uint64]*trienodeHealRequest // Trie node requests currently running bytecodeHealReqs map[uint64]*bytecodeHealRequest // Bytecode requests currently running + trienodeHealRate float64 // Average heal rate for processing trie node data + trienodeHealPend uint64 // Number of trie nodes currently pending for processing + trienodeHealThrottle float64 // Divisor for throttling the amount of trienode heal data requested + trienodeHealThrottled time.Time // Timestamp the last time the throttle was updated + trienodeHealSynced uint64 // Number of state trie nodes downloaded trienodeHealBytes common.StorageSize // Number of state trie bytes persisted to disk trienodeHealDups uint64 // Number of state trie nodes already processed @@ -476,9 +506,10 @@ func NewSyncer(db ethdb.KeyValueStore) *Syncer { trienodeHealIdlers: make(map[string]struct{}), bytecodeHealIdlers: make(map[string]struct{}), - trienodeHealReqs: make(map[uint64]*trienodeHealRequest), - bytecodeHealReqs: make(map[uint64]*bytecodeHealRequest), - stateWriter: db.NewBatch(), + trienodeHealReqs: make(map[uint64]*trienodeHealRequest), + bytecodeHealReqs: make(map[uint64]*bytecodeHealRequest), + trienodeHealThrottle: maxTrienodeHealThrottle, // Tune downward instead of insta-filling with junk + stateWriter: db.NewBatch(), extProgress: new(SyncProgress), } @@ -1321,6 +1352,10 @@ func (s *Syncer) assignTrienodeHealTasks(success chan *trienodeHealResponse, fai if cap > maxTrieRequestCount { cap = maxTrieRequestCount } + cap = int(float64(cap) / s.trienodeHealThrottle) + if cap <= 0 { + cap = 1 + } var ( hashes = make([]common.Hash, 0, cap) paths = make([]string, 0, cap) @@ -2090,6 +2125,10 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { // processTrienodeHealResponse integrates an already validated trienode response // into the healer tasks. func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) { + var ( + start = time.Now() + fills int + ) for i, hash := range res.hashes { node := res.nodes[i] @@ -2098,6 +2137,8 @@ func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) { res.task.trieTasks[res.paths[i]] = res.hashes[i] continue } + fills++ + // Push the trie node into the state syncer s.trienodeHealSynced++ s.trienodeHealBytes += common.StorageSize(len(node)) @@ -2121,6 +2162,50 @@ func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) { log.Crit("Failed to persist healing data", "err", err) } log.Debug("Persisted set of healing data", "type", "trienodes", "bytes", common.StorageSize(batch.ValueSize())) + + // Calculate the processing rate of one filled trie node + rate := float64(fills) / (float64(time.Since(start)) / float64(time.Second)) + + // Update the currently measured trienode queueing and processing throughput. + // + // The processing rate needs to be updated uniformly independent if we've + // processed 1x100 trie nodes or 100x1 to keep the rate consistent even in + // the face of varying network packets. As such, we cannot just measure the + // time it took to process N trie nodes and update once, we need one update + // per trie node. + // + // Naively, that would be: + // + // for i:=0; i time.Second { + // Periodically adjust the trie node throttler + if float64(pending) > 2*s.trienodeHealRate { + s.trienodeHealThrottle *= trienodeHealThrottleIncrease + } else { + s.trienodeHealThrottle /= trienodeHealThrottleDecrease + } + if s.trienodeHealThrottle > maxTrienodeHealThrottle { + s.trienodeHealThrottle = maxTrienodeHealThrottle + } else if s.trienodeHealThrottle < minTrienodeHealThrottle { + s.trienodeHealThrottle = minTrienodeHealThrottle + } + s.trienodeHealThrottled = time.Now() + + log.Debug("Updated trie node heal throttler", "rate", s.trienodeHealRate, "pending", pending, "throttle", s.trienodeHealThrottle) + } } // processBytecodeHealResponse integrates an already validated bytecode response @@ -2655,10 +2740,12 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error // Cross reference the requested trienodes with the response to find gaps // that the serving node is missing - hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) - hash := make([]byte, 32) - - nodes := make([][]byte, len(req.hashes)) + var ( + hasher = sha3.NewLegacyKeccak256().(crypto.KeccakState) + hash = make([]byte, 32) + nodes = make([][]byte, len(req.hashes)) + fills uint64 + ) for i, j := 0, 0; i < len(trienodes); i++ { // Find the next hash that we've been served, leaving misses with nils hasher.Reset() @@ -2670,16 +2757,22 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error } if j < len(req.hashes) { nodes[j] = trienodes[i] + fills++ j++ continue } // We've either ran out of hashes, or got unrequested data logger.Warn("Unexpected healing trienodes", "count", len(trienodes)-i) + // Signal this request as failed, and ready for rescheduling s.scheduleRevertTrienodeHealRequest(req) return errors.New("unexpected healing trienode") } // Response validated, send it to the scheduler for filling + atomic.AddUint64(&s.trienodeHealPend, fills) + defer func() { + atomic.AddUint64(&s.trienodeHealPend, ^(fills - 1)) + }() response := &trienodeHealResponse{ paths: req.paths, task: req.task, From 06151eb581c4b4e5d88d04a8dabe74080c8a3af1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 9 Sep 2022 10:47:30 +0200 Subject: [PATCH 225/715] p2p/msgrate: be more lenient when calculating 'mean' (#25653) The p2p msgrate tracker is a thing which tries to estimate some mean round-trip times. However, it did so in a very curious way: if a node had 200 peers, it would sort their 200 respective rtt estimates, and then it would pick item number 2 as the mean. So effectively taking third fastest and calling it mean. This probably works "ok" when the number of peers are low (there are other factors too, such as ttlScaling which takes some of the edge off this) -- however when the number of peers is high, it becomes very skewed. This PR instead bases the 'mean' on the square root of the length of the list. Still pretty harsh, but a bit more lenient. --- p2p/msgrate/msgrate.go | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/p2p/msgrate/msgrate.go b/p2p/msgrate/msgrate.go index d4e0eb8b5aa3..adc3758f5b71 100644 --- a/p2p/msgrate/msgrate.go +++ b/p2p/msgrate/msgrate.go @@ -38,14 +38,6 @@ const measurementImpact = 0.1 // to fetch more than some local stable value. const capacityOverestimation = 1.01 -// qosTuningPeers is the number of best peers to tune round trip times based on. -// An Ethereum node doesn't need hundreds of connections to operate correctly, -// so instead of lowering our download speed to the median of potentially many -// bad nodes, we can target a smaller set of vey good nodes. At worse this will -// result in less nodes to sync from, but that's still better than some hogging -// the pipeline. -const qosTuningPeers = 5 - // rttMinEstimate is the minimal round trip time to target requests for. Since // every request entails a 2 way latency + bandwidth + serving database lookups, // it should be generous enough to permit meaningful work to be done on top of @@ -303,11 +295,15 @@ func (t *Trackers) medianRoundTrip() time.Duration { } sort.Float64s(rtts) - median := rttMaxEstimate - if qosTuningPeers <= len(rtts) { - median = time.Duration(rtts[qosTuningPeers/2]) // Median of our best few peers - } else if len(rtts) > 0 { - median = time.Duration(rtts[len(rtts)/2]) // Median of all out connected peers + var median time.Duration + switch len(rtts) { + case 0: + median = rttMaxEstimate + case 1: + median = time.Duration(rtts[0]) + default: + idx := int(math.Sqrt(float64(len(rtts)))) + median = time.Duration(rtts[idx]) } // Restrict the RTT into some QoS defaults, irrelevant of true RTT if median < rttMinEstimate { From 610cf02c4a821f16ffecec68c633d7294fb6dc79 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Fri, 9 Sep 2022 05:03:23 -0700 Subject: [PATCH 226/715] rpc: improve error codes for internal server errors (#25678) This changes the error code returned by the RPC server in certain situations: - handler panic: code -32603 - result marshaling error: code -32603 - attempt to subscribe via HTTP: code -32001 In all of the above cases, the server previously returned the default error code -32000. Co-authored-by: Nicholas Zhao Co-authored-by: Felix Lange --- rpc/client_test.go | 8 ++++++-- rpc/errors.go | 18 +++++++++++++++++- rpc/handler.go | 6 ++++-- rpc/json.go | 5 ++--- rpc/server_test.go | 2 +- rpc/service.go | 3 +-- rpc/testdata/internal-error.js | 7 +++++++ rpc/testservice_test.go | 14 ++++++++++++++ 8 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 rpc/testdata/internal-error.js diff --git a/rpc/client_test.go b/rpc/client_test.go index 04c847d0d626..51df76f7fe44 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -82,11 +82,15 @@ func TestClientErrorData(t *testing.T) { } // Check code. + // The method handler returns an error value which implements the rpc.Error + // interface, i.e. it has a custom error code. The server returns this error code. + expectedCode := testError{}.ErrorCode() if e, ok := err.(Error); !ok { t.Fatalf("client did not return rpc.Error, got %#v", e) - } else if e.ErrorCode() != (testError{}.ErrorCode()) { - t.Fatalf("wrong error code %d, want %d", e.ErrorCode(), testError{}.ErrorCode()) + } else if e.ErrorCode() != expectedCode { + t.Fatalf("wrong error code %d, want %d", e.ErrorCode(), expectedCode) } + // Check data. if e, ok := err.(DataError); !ok { t.Fatalf("client did not return rpc.DataError, got %#v", e) diff --git a/rpc/errors.go b/rpc/errors.go index 4c06a745fbd8..9a19e9fe67f5 100644 --- a/rpc/errors.go +++ b/rpc/errors.go @@ -54,9 +54,15 @@ var ( _ Error = new(invalidRequestError) _ Error = new(invalidMessageError) _ Error = new(invalidParamsError) + _ Error = new(internalServerError) ) -const defaultErrorCode = -32000 +const ( + errcodeDefault = -32000 + errcodeNotificationsUnsupported = -32001 + errcodePanic = -32603 + errcodeMarshalError = -32603 +) type methodNotFoundError struct{ method string } @@ -101,3 +107,13 @@ type invalidParamsError struct{ message string } func (e *invalidParamsError) ErrorCode() int { return -32602 } func (e *invalidParamsError) Error() string { return e.message } + +// internalServerError is used for server errors during request processing. +type internalServerError struct { + code int + message string +} + +func (e *internalServerError) ErrorCode() int { return e.code } + +func (e *internalServerError) Error() string { return e.message } diff --git a/rpc/handler.go b/rpc/handler.go index cd95a067f3e2..22ad98149f8c 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -48,7 +48,6 @@ import ( // if err := op.wait(...); err != nil { // h.removeRequestOp(op) // timeout, etc. // } -// type handler struct { reg *serviceRegistry unsubscribeCb *callback @@ -354,7 +353,10 @@ func (h *handler) handleCall(cp *callProc, msg *jsonrpcMessage) *jsonrpcMessage // handleSubscribe processes *_subscribe method calls. func (h *handler) handleSubscribe(cp *callProc, msg *jsonrpcMessage) *jsonrpcMessage { if !h.allowSubscribe { - return msg.errorResponse(ErrNotificationsUnsupported) + return msg.errorResponse(&internalServerError{ + code: errcodeNotificationsUnsupported, + message: ErrNotificationsUnsupported.Error(), + }) } // Subscription method name is first argument. diff --git a/rpc/json.go b/rpc/json.go index 6b2ac2d52a7b..1064939ff8b6 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -104,15 +104,14 @@ func (msg *jsonrpcMessage) errorResponse(err error) *jsonrpcMessage { func (msg *jsonrpcMessage) response(result interface{}) *jsonrpcMessage { enc, err := json.Marshal(result) if err != nil { - // TODO: wrap with 'internal server error' - return msg.errorResponse(err) + return msg.errorResponse(&internalServerError{errcodeMarshalError, err.Error()}) } return &jsonrpcMessage{Version: vsn, ID: msg.ID, Result: enc} } func errorMessage(err error) *jsonrpcMessage { msg := &jsonrpcMessage{Version: vsn, ID: null, Error: &jsonError{ - Code: defaultErrorCode, + Code: errcodeDefault, Message: err.Error(), }} ec, ok := err.(Error) diff --git a/rpc/server_test.go b/rpc/server_test.go index d09d31634bee..c9abe53e5210 100644 --- a/rpc/server_test.go +++ b/rpc/server_test.go @@ -45,7 +45,7 @@ func TestServerRegisterName(t *testing.T) { t.Fatalf("Expected service calc to be registered") } - wantCallbacks := 10 + wantCallbacks := 12 if len(svc.callbacks) != wantCallbacks { t.Errorf("Expected %d callbacks for service 'service', got %d", wantCallbacks, len(svc.callbacks)) } diff --git a/rpc/service.go b/rpc/service.go index bef891ea1125..cfdfba023a0a 100644 --- a/rpc/service.go +++ b/rpc/service.go @@ -18,7 +18,6 @@ package rpc import ( "context" - "errors" "fmt" "reflect" "runtime" @@ -199,7 +198,7 @@ func (c *callback) call(ctx context.Context, method string, args []reflect.Value buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] log.Error("RPC method " + method + " crashed: " + fmt.Sprintf("%v\n%s", err, buf)) - errRes = errors.New("method handler crashed") + errRes = &internalServerError{errcodePanic, "method handler crashed"} } }() // Run the callback. diff --git a/rpc/testdata/internal-error.js b/rpc/testdata/internal-error.js new file mode 100644 index 000000000000..2ba387401f24 --- /dev/null +++ b/rpc/testdata/internal-error.js @@ -0,0 +1,7 @@ +// These tests trigger various 'internal error' conditions. + +--> {"jsonrpc":"2.0","id":1,"method":"test_marshalError","params": []} +<-- {"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"json: error calling MarshalText for type *rpc.MarshalErrObj: marshal error"}} + +--> {"jsonrpc":"2.0","id":2,"method":"test_panic","params": []} +<-- {"jsonrpc":"2.0","id":2,"error":{"code":-32603,"message":"method handler crashed"}} diff --git a/rpc/testservice_test.go b/rpc/testservice_test.go index 253e26328900..8454a4019222 100644 --- a/rpc/testservice_test.go +++ b/rpc/testservice_test.go @@ -70,6 +70,12 @@ func (testError) Error() string { return "testError" } func (testError) ErrorCode() int { return 444 } func (testError) ErrorData() interface{} { return "testError data" } +type MarshalErrObj struct{} + +func (o *MarshalErrObj) MarshalText() ([]byte, error) { + return nil, errors.New("marshal error") +} + func (s *testService) NoArgsRets() {} func (s *testService) Echo(str string, i int, args *echoArgs) echoResult { @@ -114,6 +120,14 @@ func (s *testService) ReturnError() error { return testError{} } +func (s *testService) MarshalError() *MarshalErrObj { + return &MarshalErrObj{} +} + +func (s *testService) Panic() string { + panic("service panic") +} + func (s *testService) CallMeBack(ctx context.Context, method string, args []interface{}) (interface{}, error) { c, ok := ClientFromContext(ctx) if !ok { From 389021a5afd01147c851870c693ded8760e6a08c Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 9 Sep 2022 15:25:55 +0200 Subject: [PATCH 227/715] core: place a cap on reorglogs (#25711) This PR makes the event-sending for deleted and new logs happen in batches, to prevent OOM situation due to large reorgs. Co-authored-by: Felix Lange --- core/blockchain.go | 78 ++++++++++++++-------------------- core/blockchain_test.go | 94 +++++++++++++++++++++++++++++------------ 2 files changed, 98 insertions(+), 74 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index f588cc50bd6f..f73bbb09c226 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2000,21 +2000,6 @@ func (bc *BlockChain) collectLogs(hash common.Hash, removed bool) []*types.Log { return logs } -// mergeLogs returns a merged log slice with specified sort order. -func mergeLogs(logs [][]*types.Log, reverse bool) []*types.Log { - var ret []*types.Log - if reverse { - for i := len(logs) - 1; i >= 0; i-- { - ret = append(ret, logs[i]...) - } - } else { - for i := 0; i < len(logs); i++ { - ret = append(ret, logs[i]...) - } - } - return ret -} - // reorg takes two blocks, an old chain and a new chain and will reconstruct the // blocks and inserts them to be part of the new canonical chain and accumulates // potential missing transactions and post an event about them. @@ -2028,9 +2013,6 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { deletedTxs []common.Hash addedTxs []common.Hash - - deletedLogs [][]*types.Log - rebirthLogs [][]*types.Log ) // Reduce the longer chain to the same number as the shorter one if oldBlock.NumberU64() > newBlock.NumberU64() { @@ -2040,12 +2022,6 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { for _, tx := range oldBlock.Transactions() { deletedTxs = append(deletedTxs, tx.Hash()) } - - // Collect deleted logs for notification - logs := bc.collectLogs(oldBlock.Hash(), true) - if len(logs) > 0 { - deletedLogs = append(deletedLogs, logs) - } } } else { // New chain is longer, stash all blocks away for subsequent insertion @@ -2072,12 +2048,6 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { for _, tx := range oldBlock.Transactions() { deletedTxs = append(deletedTxs, tx.Hash()) } - - // Collect deleted logs for notification - logs := bc.collectLogs(oldBlock.Hash(), true) - if len(logs) > 0 { - deletedLogs = append(deletedLogs, logs) - } newChain = append(newChain, newBlock) // Step back with both chains @@ -2151,28 +2121,42 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { log.Crit("Failed to delete useless indexes", "err", err) } - // Collect the logs - for i := len(newChain) - 1; i >= 1; i-- { - // Collect reborn logs due to chain reorg - logs := bc.collectLogs(newChain[i].Hash(), false) - if len(logs) > 0 { - rebirthLogs = append(rebirthLogs, logs) + // Send out events for logs from the old canon chain, and 'reborn' + // logs from the new canon chain. The number of logs can be very + // high, so the events are sent in batches of size around 512. + + // Deleted logs + blocks: + var deletedLogs []*types.Log + for i := len(oldChain) - 1; i >= 0; i-- { + // Also send event for blocks removed from the canon chain. + bc.chainSideFeed.Send(ChainSideEvent{Block: oldChain[i]}) + + // Collect deleted logs for notification + if logs := bc.collectLogs(oldChain[i].Hash(), true); len(logs) > 0 { + deletedLogs = append(deletedLogs, logs...) + } + if len(deletedLogs) > 512 { + bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs}) + deletedLogs = nil } } - // If any logs need to be fired, do it now. In theory we could avoid creating - // this goroutine if there are no events to fire, but realistcally that only - // ever happens if we're reorging empty blocks, which will only happen on idle - // networks where performance is not an issue either way. if len(deletedLogs) > 0 { - bc.rmLogsFeed.Send(RemovedLogsEvent{mergeLogs(deletedLogs, true)}) + bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs}) } - if len(rebirthLogs) > 0 { - bc.logsFeed.Send(mergeLogs(rebirthLogs, false)) - } - if len(oldChain) > 0 { - for i := len(oldChain) - 1; i >= 0; i-- { - bc.chainSideFeed.Send(ChainSideEvent{Block: oldChain[i]}) + + // New logs: + var rebirthLogs []*types.Log + for i := len(newChain) - 1; i >= 1; i-- { + if logs := bc.collectLogs(newChain[i].Hash(), false); len(logs) > 0 { + rebirthLogs = append(rebirthLogs, logs...) } + if len(rebirthLogs) > 512 { + bc.logsFeed.Send(rebirthLogs) + rebirthLogs = nil + } + } + if len(rebirthLogs) > 0 { + bc.logsFeed.Send(rebirthLogs) } return nil } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index c17a81048f24..06c43658ed9b 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1158,37 +1158,53 @@ func TestLogRebirth(t *testing.T) { blockchain.SubscribeLogsEvent(newLogCh) blockchain.SubscribeRemovedLogsEvent(rmLogsCh) - // This chain contains a single log. - genDb, chain, _ := GenerateChainWithGenesis(gspec, engine, 2, func(i int, gen *BlockGen) { - if i == 1 { - tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) - if err != nil { - t.Fatalf("failed to create tx: %v", err) + // This chain contains 10 logs. + genDb, chain, _ := GenerateChainWithGenesis(gspec, engine, 3, func(i int, gen *BlockGen) { + if i < 2 { + for ii := 0; ii < 5; ii++ { + tx, err := types.SignNewTx(key1, signer, &types.LegacyTx{ + Nonce: gen.TxNonce(addr1), + GasPrice: gen.header.BaseFee, + Gas: uint64(1000001), + Data: logCode, + }) + if err != nil { + t.Fatalf("failed to create tx: %v", err) + } + gen.AddTx(tx) } - gen.AddTx(tx) } }) if _, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert chain: %v", err) } - checkLogEvents(t, newLogCh, rmLogsCh, 1, 0) + checkLogEvents(t, newLogCh, rmLogsCh, 10, 0) - // Generate long reorg chain containing another log. Inserting the - // chain removes one log and adds one. - _, forkChain, _ := GenerateChainWithGenesis(gspec, engine, 2, func(i int, gen *BlockGen) { - if i == 1 { - tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, logCode), signer, key1) + // Generate long reorg chain containing more logs. Inserting the + // chain removes one log and adds four. + _, forkChain, _ := GenerateChainWithGenesis(gspec, engine, 3, func(i int, gen *BlockGen) { + if i == 2 { + // The last (head) block is not part of the reorg-chain, we can ignore it + return + } + for ii := 0; ii < 5; ii++ { + tx, err := types.SignNewTx(key1, signer, &types.LegacyTx{ + Nonce: gen.TxNonce(addr1), + GasPrice: gen.header.BaseFee, + Gas: uint64(1000000), + Data: logCode, + }) if err != nil { t.Fatalf("failed to create tx: %v", err) } gen.AddTx(tx) - gen.OffsetTime(-9) // higher block difficulty } + gen.OffsetTime(-9) // higher block difficulty }) if _, err := blockchain.InsertChain(forkChain); err != nil { t.Fatalf("failed to insert forked chain: %v", err) } - checkLogEvents(t, newLogCh, rmLogsCh, 1, 1) + checkLogEvents(t, newLogCh, rmLogsCh, 10, 10) // This chain segment is rooted in the original chain, but doesn't contain any logs. // When inserting it, the canonical chain switches away from forkChain and re-emits @@ -1197,7 +1213,7 @@ func TestLogRebirth(t *testing.T) { if _, err := blockchain.InsertChain(newBlocks); err != nil { t.Fatalf("failed to insert forked chain: %v", err) } - checkLogEvents(t, newLogCh, rmLogsCh, 1, 1) + checkLogEvents(t, newLogCh, rmLogsCh, 10, 10) } // This test is a variation of TestLogRebirth. It verifies that log events are emitted @@ -1252,19 +1268,43 @@ func TestSideLogRebirth(t *testing.T) { func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan RemovedLogsEvent, wantNew, wantRemoved int) { t.Helper() - - if len(logsCh) != wantNew { - t.Fatalf("wrong number of log events: got %d, want %d", len(logsCh), wantNew) - } - if len(rmLogsCh) != wantRemoved { - t.Fatalf("wrong number of removed log events: got %d, want %d", len(rmLogsCh), wantRemoved) - } + var ( + countNew int + countRm int + prev int + ) // Drain events. - for i := 0; i < len(logsCh); i++ { - <-logsCh + for len(logsCh) > 0 { + x := <-logsCh + countNew += len(x) + for _, log := range x { + // We expect added logs to be in ascending order: 0:0, 0:1, 1:0 ... + have := 100*int(log.BlockNumber) + int(log.TxIndex) + if have < prev { + t.Fatalf("Expected new logs to arrive in ascending order (%d < %d)", have, prev) + } + prev = have + } + } + prev = 0 + for len(rmLogsCh) > 0 { + x := <-rmLogsCh + countRm += len(x.Logs) + for _, log := range x.Logs { + // We expect removed logs to be in ascending order: 0:0, 0:1, 1:0 ... + have := 100*int(log.BlockNumber) + int(log.TxIndex) + if have < prev { + t.Fatalf("Expected removed logs to arrive in ascending order (%d < %d)", have, prev) + } + prev = have + } + } + + if countNew != wantNew { + t.Fatalf("wrong number of log events: got %d, want %d", countNew, wantNew) } - for i := 0; i < len(rmLogsCh); i++ { - <-rmLogsCh + if countRm != wantRemoved { + t.Fatalf("wrong number of removed log events: got %d, want %d", countRm, wantRemoved) } } From b628d7276624c2d8ea7dd97d2259a2c2fce7d3cc Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sat, 10 Sep 2022 13:25:40 +0200 Subject: [PATCH 228/715] build: upgrade to go 1.19 (#25726) This changes the CI / release builds to use the latest Go version. It also upgrades golangci-lint to a newer version compatible with Go 1.19. In Go 1.19, godoc has gained official support for links and lists. The syntax for code blocks in doc comments has changed and now requires a leading tab character. gofmt adapts comments to the new syntax automatically, so there are a lot of comment re-formatting changes in this PR. We need to apply the new format in order to pass the CI lint stage with Go 1.19. With the linter upgrade, I have decided to disable 'gosec' - it produces too many false-positive warnings. The 'deadcode' and 'varcheck' linters have also been removed because golangci-lint warns about them being unmaintained. 'unused' provides similar coverage and we already have it enabled, so we don't lose much with this change. --- .golangci.yml | 17 +- .travis.yml | 20 +- accounts/abi/abi_test.go | 34 +-- accounts/abi/bind/backends/simulated_test.go | 91 ++++---- accounts/abi/reflect.go | 35 +-- accounts/abi/utils.go | 15 +- accounts/accounts.go | 6 +- accounts/hd.go | 2 +- accounts/scwallet/wallet.go | 3 + accounts/url.go | 7 +- accounts/usbwallet/ledger.go | 162 +++++++------ accounts/usbwallet/trezor.go | 18 +- .../usbwallet/trezor/messages-common.pb.go | 26 +-- .../usbwallet/trezor/messages-ethereum.pb.go | 20 +- .../trezor/messages-management.pb.go | 48 ++-- accounts/usbwallet/trezor/messages.pb.go | 2 +- build/checksums.txt | 70 +++--- build/ci.go | 25 +- cmd/evm/internal/t8ntool/transition.go | 5 +- cmd/p2psim/main.go | 21 +- common/hexutil/hexutil.go | 2 +- common/math/big.go | 8 +- common/prque/lazyqueue.go | 7 +- consensus/beacon/consensus.go | 7 +- consensus/ethash/api.go | 9 +- consensus/ethash/sealer.go | 9 +- consensus/misc/dao.go | 9 +- core/beacon/types.go | 8 +- core/blockchain_test.go | 57 ++--- core/genesis.go | 8 +- core/mkalloc.go | 8 +- core/rawdb/freezer.go | 14 +- core/state/pruner/pruner.go | 6 +- core/state/snapshot/generate_test.go | 2 + core/state/snapshot/snapshot.go | 8 +- core/state/statedb.go | 4 +- core/state_transition.go | 48 ++-- core/vm/contracts.go | 8 +- core/vm/gas_table.go | 53 +++-- core/vm/instructions.go | 32 +-- crypto/crypto.go | 2 +- crypto/secp256k1/curve.go | 1 - .../secp256k1/libsecp256k1/contrib/dummy.go | 1 + crypto/secp256k1/libsecp256k1/dummy.go | 1 + .../secp256k1/libsecp256k1/include/dummy.go | 1 + crypto/secp256k1/libsecp256k1/src/dummy.go | 1 + .../libsecp256k1/src/modules/dummy.go | 1 + .../libsecp256k1/src/modules/ecdh/dummy.go | 1 + .../src/modules/recovery/dummy.go | 1 + eth/catalyst/api.go | 22 +- eth/catalyst/api_test.go | 12 +- eth/downloader/downloader.go | 8 +- eth/downloader/queue.go | 7 +- eth/downloader/resultstore.go | 9 +- eth/gasprice/feehistory.go | 9 +- eth/protocols/snap/sync_test.go | 4 +- eth/state_accessor.go | 20 +- eth/tracers/native/4byte.go | 17 +- eth/tracers/native/tracer.go | 32 ++- ethdb/leveldb/leveldb.go | 15 +- ethstats/ethstats.go | 18 +- internal/cmdtest/test_cmd.go | 2 +- internal/ethapi/api.go | 8 +- internal/flags/helpers.go | 4 +- les/api.go | 16 +- les/catalyst/api.go | 22 +- les/downloader/downloader.go | 40 ++-- les/downloader/queue.go | 7 +- les/downloader/resultstore.go | 9 +- les/fetcher.go | 22 +- light/txpool.go | 17 +- log/doc.go | 218 +++++++++--------- log/format.go | 6 +- log/handler.go | 38 ++- log/handler_glog.go | 12 +- metrics/influxdb/influxdbv2.go | 8 - mobile/big.go | 1 - mobile/discover.go | 6 +- mobile/doc.go | 2 +- node/doc.go | 64 +++-- node/node_example_test.go | 4 +- p2p/dial.go | 11 +- p2p/discover/v5wire/encoding_test.go | 3 +- p2p/dnsdisc/tree.go | 42 ++-- p2p/enode/urlv4.go | 6 +- p2p/enr/enr.go | 2 +- p2p/message.go | 5 +- p2p/nat/nat.go | 12 +- p2p/simulations/adapters/types.go | 7 +- p2p/simulations/mocker.go | 22 +- params/denomination.go | 3 +- rlp/decode.go | 2 +- rlp/doc.go | 45 ++-- rpc/doc.go | 57 +++-- rpc/handler.go | 14 +- signer/core/api_test.go | 2 +- signer/core/apitypes/types.go | 2 +- tests/block_test_util.go | 17 +- tests/fuzzers/bls12381/precompile_fuzzer.go | 14 +- tests/fuzzers/difficulty/difficulty-fuzz.go | 12 +- tests/fuzzers/rangeproof/rangeproof-fuzzer.go | 13 +- tests/fuzzers/stacktrie/trie_fuzzer.go | 12 +- tests/fuzzers/trie/trie-fuzzer.go | 12 +- tests/init_test.go | 1 + trie/hasher.go | 4 +- trie/proof.go | 20 +- trie/stacktrie.go | 9 +- 107 files changed, 998 insertions(+), 974 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 4c1297223533..8a054667e6d8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -12,7 +12,6 @@ run: linters: disable-all: true enable: - - deadcode - goconst - goimports - gosimple @@ -20,14 +19,12 @@ linters: - ineffassign - misspell - unconvert - - varcheck - typecheck - unused - staticcheck - bidichk - durationcheck - exportloopref - - gosec - whitespace # - structcheck # lots of false positives @@ -45,11 +42,6 @@ linters-settings: goconst: min-len: 3 # minimum length of string constant min-occurrences: 6 # minimum number of occurrences - gosec: - excludes: - - G404 # Use of weak random number generator - lots of FP - - G107 # Potential http request -- those are intentional - - G306 # G306: Expect WriteFile permissions to be 0600 or less issues: exclude-rules: @@ -58,16 +50,15 @@ issues: - deadcode - staticcheck - path: internal/build/pgp.go - text: 'SA1019: package golang.org/x/crypto/openpgp is deprecated' + text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' - path: core/vm/contracts.go - text: 'SA1019: package golang.org/x/crypto/ripemd160 is deprecated' + text: 'SA1019: "golang.org/x/crypto/ripemd160" is deprecated: RIPEMD-160 is a legacy hash and should not be used for new applications.' - path: accounts/usbwallet/trezor.go - text: 'SA1019: package github.com/golang/protobuf/proto is deprecated' + text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.' - path: accounts/usbwallet/trezor/ - text: 'SA1019: package github.com/golang/protobuf/proto is deprecated' + text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.' exclude: - 'SA1019: event.TypeMux is deprecated: use Feed' - 'SA1019: strings.Title is deprecated' - 'SA1019: strings.Title has been deprecated since Go 1.18 and an alternative has been available since Go 1.0: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead.' - 'SA1029: should not use built-in type string as key for value' - - 'G306: Expect WriteFile permissions to be 0600 or less' diff --git a/.travis.yml b/.travis.yml index e08e271f3f12..a32b44506664 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ jobs: - stage: lint os: linux dist: bionic - go: 1.18.x + go: 1.19.x env: - lint git: @@ -31,7 +31,7 @@ jobs: os: linux arch: amd64 dist: bionic - go: 1.18.x + go: 1.19.x env: - docker services: @@ -48,7 +48,7 @@ jobs: os: linux arch: arm64 dist: bionic - go: 1.18.x + go: 1.19.x env: - docker services: @@ -65,7 +65,7 @@ jobs: if: type = push os: linux dist: bionic - go: 1.18.x + go: 1.19.x env: - ubuntu-ppa - GO111MODULE=on @@ -90,7 +90,7 @@ jobs: os: linux dist: bionic sudo: required - go: 1.18.x + go: 1.19.x env: - azure-linux - GO111MODULE=on @@ -162,7 +162,7 @@ jobs: - stage: build if: type = push os: osx - go: 1.18.x + go: 1.19.x env: - azure-osx - azure-ios @@ -194,7 +194,7 @@ jobs: os: linux arch: amd64 dist: bionic - go: 1.18.x + go: 1.19.x env: - GO111MODULE=on script: @@ -214,7 +214,7 @@ jobs: - stage: build os: linux dist: bionic - go: 1.17.x + go: 1.18.x env: - GO111MODULE=on script: @@ -225,7 +225,7 @@ jobs: if: type = cron os: linux dist: bionic - go: 1.18.x + go: 1.19.x env: - azure-purge - GO111MODULE=on @@ -239,7 +239,7 @@ jobs: if: type = cron os: linux dist: bionic - go: 1.18.x + go: 1.19.x env: - GO111MODULE=on script: diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index cd9433ca7f73..96c11e096462 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -165,8 +165,9 @@ func TestInvalidABI(t *testing.T) { // TestConstructor tests a constructor function. // The test is based on the following contract: -// contract TestConstructor { -// constructor(uint256 a, uint256 b) public{} +// +// contract TestConstructor { +// constructor(uint256 a, uint256 b) public{} // } func TestConstructor(t *testing.T) { json := `[{ "inputs": [{"internalType": "uint256","name": "a","type": "uint256" },{ "internalType": "uint256","name": "b","type": "uint256"}],"stateMutability": "nonpayable","type": "constructor"}]` @@ -724,16 +725,19 @@ func TestBareEvents(t *testing.T) { } // TestUnpackEvent is based on this contract: -// contract T { -// event received(address sender, uint amount, bytes memo); -// event receivedAddr(address sender); -// function receive(bytes memo) external payable { -// received(msg.sender, msg.value, memo); -// receivedAddr(msg.sender); -// } -// } +// +// contract T { +// event received(address sender, uint amount, bytes memo); +// event receivedAddr(address sender); +// function receive(bytes memo) external payable { +// received(msg.sender, msg.value, memo); +// receivedAddr(msg.sender); +// } +// } +// // When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt: -// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]} +// +// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]} func TestUnpackEvent(t *testing.T) { const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]` abi, err := JSON(strings.NewReader(abiJSON)) @@ -1078,8 +1082,9 @@ func TestDoubleDuplicateMethodNames(t *testing.T) { // TestDoubleDuplicateEventNames checks that if send0 already exists, there won't be a name // conflict and that the second send event will be renamed send1. // The test runs the abi of the following contract. -// contract DuplicateEvent { -// event send(uint256 a); +// +// contract DuplicateEvent { +// event send(uint256 a); // event send0(); // event send(); // } @@ -1106,7 +1111,8 @@ func TestDoubleDuplicateEventNames(t *testing.T) { // TestUnnamedEventParam checks that an event with unnamed parameters is // correctly handled. // The test runs the abi of the following contract. -// contract TestEvent { +// +// contract TestEvent { // event send(uint256, uint256); // } func TestUnnamedEventParam(t *testing.T) { diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index 83367f098523..bb19b5455b03 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -93,17 +93,18 @@ func TestSimulatedBackend(t *testing.T) { var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") -// the following is based on this contract: -// contract T { -// event received(address sender, uint amount, bytes memo); -// event receivedAddr(address sender); +// the following is based on this contract: // -// function receive(bytes calldata memo) external payable returns (string memory res) { -// emit received(msg.sender, msg.value, memo); -// emit receivedAddr(msg.sender); -// return "hello world"; -// } -// } +// contract T { +// event received(address sender, uint amount, bytes memo); +// event receivedAddr(address sender); +// +// function receive(bytes calldata memo) external payable returns (string memory res) { +// emit received(msg.sender, msg.value, memo); +// emit receivedAddr(msg.sender); +// return "hello world"; +// } +// } const abiJSON = `[ { "constant": false, "inputs": [ { "name": "memo", "type": "bytes" } ], "name": "receive", "outputs": [ { "name": "res", "type": "string" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "sender", "type": "address" }, { "indexed": false, "name": "amount", "type": "uint256" }, { "indexed": false, "name": "memo", "type": "bytes" } ], "name": "received", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "sender", "type": "address" } ], "name": "receivedAddr", "type": "event" } ]` const abiBin = `0x608060405234801561001057600080fd5b506102a0806100206000396000f3fe60806040526004361061003b576000357c010000000000000000000000000000000000000000000000000000000090048063a69b6ed014610040575b600080fd5b6100b76004803603602081101561005657600080fd5b810190808035906020019064010000000081111561007357600080fd5b82018360208201111561008557600080fd5b803590602001918460018302840111640100000000831117156100a757600080fd5b9091929391929390505050610132565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f75780820151818401526020810190506100dc565b50505050905090810190601f1680156101245780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60607f75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed33348585604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509550505050505060405180910390a17f46923992397eac56cf13058aced2a1871933622717e27b24eabc13bf9dd329c833604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a16040805190810160405280600b81526020017f68656c6c6f20776f726c6400000000000000000000000000000000000000000081525090509291505056fea165627a7a72305820ff0c57dad254cfeda48c9cfb47f1353a558bccb4d1bc31da1dae69315772d29e0029` const deployedCode = `60806040526004361061003b576000357c010000000000000000000000000000000000000000000000000000000090048063a69b6ed014610040575b600080fd5b6100b76004803603602081101561005657600080fd5b810190808035906020019064010000000081111561007357600080fd5b82018360208201111561008557600080fd5b803590602001918460018302840111640100000000831117156100a757600080fd5b9091929391929390505050610132565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f75780820151818401526020810190506100dc565b50505050905090810190601f1680156101245780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60607f75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed33348585604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509550505050505060405180910390a17f46923992397eac56cf13058aced2a1871933622717e27b24eabc13bf9dd329c833604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a16040805190810160405280600b81526020017f68656c6c6f20776f726c6400000000000000000000000000000000000000000081525090509291505056fea165627a7a72305820ff0c57dad254cfeda48c9cfb47f1353a558bccb4d1bc31da1dae69315772d29e0029` @@ -417,12 +418,13 @@ func TestEstimateGas(t *testing.T) { /* pragma solidity ^0.6.4; contract GasEstimation { - function PureRevert() public { revert(); } - function Revert() public { revert("revert reason");} - function OOG() public { for (uint i = 0; ; i++) {}} - function Assert() public { assert(false);} - function Valid() public {} - }*/ + function PureRevert() public { revert(); } + function Revert() public { revert("revert reason");} + function OOG() public { for (uint i = 0; ; i++) {}} + function Assert() public { assert(false);} + function Valid() public {} + } + */ const contractAbi = "[{\"inputs\":[],\"name\":\"Assert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OOG\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PureRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Revert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Valid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" const contractBin = "0x60806040523480156100115760006000fd5b50610017565b61016e806100266000396000f3fe60806040523480156100115760006000fd5b506004361061005c5760003560e01c806350f6fe3414610062578063aa8b1d301461006c578063b9b046f914610076578063d8b9839114610080578063e09fface1461008a5761005c565b60006000fd5b61006a610094565b005b6100746100ad565b005b61007e6100b5565b005b6100886100c2565b005b610092610135565b005b6000600090505b5b808060010191505061009b565b505b565b60006000fd5b565b600015156100bf57fe5b5b565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f72657665727420726561736f6e0000000000000000000000000000000000000081526020015060200191505060405180910390fd5b565b5b56fea2646970667358221220345bbcbb1a5ecf22b53a78eaebf95f8ee0eceff6d10d4b9643495084d2ec934a64736f6c63430006040033" @@ -994,7 +996,8 @@ func TestCodeAt(t *testing.T) { } // When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt: -// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]} +// +// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]} func TestPendingAndCallContract(t *testing.T) { testAddr := crypto.PubkeyToAddress(testKey.PublicKey) sim := simTestBackend(testAddr) @@ -1057,27 +1060,27 @@ func TestPendingAndCallContract(t *testing.T) { // This test is based on the following contract: /* contract Reverter { - function revertString() public pure{ - require(false, "some error"); - } - function revertNoString() public pure { - require(false, ""); - } - function revertASM() public pure { - assembly { - revert(0x0, 0x0) - } - } - function noRevert() public pure { - assembly { - // Assembles something that looks like require(false, "some error") but is not reverted - mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000) - mstore(0x4, 0x0000000000000000000000000000000000000000000000000000000000000020) - mstore(0x24, 0x000000000000000000000000000000000000000000000000000000000000000a) - mstore(0x44, 0x736f6d65206572726f7200000000000000000000000000000000000000000000) - return(0x0, 0x64) - } - } + function revertString() public pure{ + require(false, "some error"); + } + function revertNoString() public pure { + require(false, ""); + } + function revertASM() public pure { + assembly { + revert(0x0, 0x0) + } + } + function noRevert() public pure { + assembly { + // Assembles something that looks like require(false, "some error") but is not reverted + mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000) + mstore(0x4, 0x0000000000000000000000000000000000000000000000000000000000000020) + mstore(0x24, 0x000000000000000000000000000000000000000000000000000000000000000a) + mstore(0x44, 0x736f6d65206572726f7200000000000000000000000000000000000000000000) + return(0x0, 0x64) + } + } }*/ func TestCallContractRevert(t *testing.T) { testAddr := crypto.PubkeyToAddress(testKey.PublicKey) @@ -1204,11 +1207,11 @@ func TestFork(t *testing.T) { /* Example contract to test event emission: -pragma solidity >=0.7.0 <0.9.0; -contract Callable { - event Called(); - function Call() public { emit Called(); } -} + pragma solidity >=0.7.0 <0.9.0; + contract Callable { + event Called(); + function Call() public { emit Called(); } + } */ const callableAbi = "[{\"anonymous\":false,\"inputs\":[],\"name\":\"Called\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"Call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" @@ -1226,7 +1229,7 @@ const callableBin = "6080604052348015600f57600080fd5b5060998061001e6000396000f3f // 7. Mine two blocks to trigger a reorg. // 8. Check that the event was removed. // 9. Re-send the transaction and mine a block. -// 10. Check that the event was reborn. +// 10. Check that the event was reborn. func TestForkLogsReborn(t *testing.T) { testAddr := crypto.PubkeyToAddress(testKey.PublicKey) sim := simTestBackend(testAddr) diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 7917fa98095b..1f84b111a3db 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -25,16 +25,19 @@ import ( ) // ConvertType converts an interface of a runtime type into a interface of the -// given type -// e.g. turn -// var fields []reflect.StructField -// fields = append(fields, reflect.StructField{ -// Name: "X", -// Type: reflect.TypeOf(new(big.Int)), -// Tag: reflect.StructTag("json:\"" + "x" + "\""), -// } -// into -// type TupleT struct { X *big.Int } +// given type, e.g. turn this code: +// +// var fields []reflect.StructField +// +// fields = append(fields, reflect.StructField{ +// Name: "X", +// Type: reflect.TypeOf(new(big.Int)), +// Tag: reflect.StructTag("json:\"" + "x" + "\""), +// } +// +// into: +// +// type TupleT struct { X *big.Int } func ConvertType(in interface{}, proto interface{}) interface{} { protoType := reflect.TypeOf(proto) if reflect.TypeOf(in).ConvertibleTo(protoType) { @@ -170,11 +173,13 @@ func setStruct(dst, src reflect.Value) error { } // mapArgNamesToStructFields maps a slice of argument names to struct fields. -// first round: for each Exportable field that contains a `abi:""` tag -// and this field name exists in the given argument name list, pair them together. -// second round: for each argument name that has not been already linked, -// find what variable is expected to be mapped into, if it exists and has not been -// used, pair them. +// +// first round: for each Exportable field that contains a `abi:""` tag and this field name +// exists in the given argument name list, pair them together. +// +// second round: for each argument name that has not been already linked, find what +// variable is expected to be mapped into, if it exists and has not been used, pair them. +// // Note this function assumes the given value is a struct value. func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[string]string, error) { typ := value.Type() diff --git a/accounts/abi/utils.go b/accounts/abi/utils.go index e24df5b7003d..b1537ca58dd3 100644 --- a/accounts/abi/utils.go +++ b/accounts/abi/utils.go @@ -21,15 +21,14 @@ import "fmt" // ResolveNameConflict returns the next available name for a given thing. // This helper can be used for lots of purposes: // -// - In solidity function overloading is supported, this function can fix -// the name conflicts of overloaded functions. -// - In golang binding generation, the parameter(in function, event, error, -// and struct definition) name will be converted to camelcase style which -// may eventually lead to name conflicts. +// - In solidity function overloading is supported, this function can fix +// the name conflicts of overloaded functions. +// - In golang binding generation, the parameter(in function, event, error, +// and struct definition) name will be converted to camelcase style which +// may eventually lead to name conflicts. // -// Name conflicts are mostly resolved by adding number suffix. -// e.g. if the abi contains Methods send, send1 -// ResolveNameConflict would return send2 for input send. +// Name conflicts are mostly resolved by adding number suffix. e.g. if the abi contains +// Methods "send" and "send1", ResolveNameConflict would return "send2" for input "send". func ResolveNameConflict(rawName string, used func(string) bool) string { name := rawName ok := used(name) diff --git a/accounts/accounts.go b/accounts/accounts.go index 179a33c59fd3..6c351a9649ea 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -177,7 +177,8 @@ type Backend interface { // safely used to calculate a signature from. // // The hash is calculated as -// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). +// +// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). // // This gives context to the signed message and prevents signing of transactions. func TextHash(data []byte) []byte { @@ -189,7 +190,8 @@ func TextHash(data []byte) []byte { // safely used to calculate a signature from. // // The hash is calculated as -// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). +// +// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). // // This gives context to the signed message and prevents signing of transactions. func TextAndHash(data []byte) ([]byte, string) { diff --git a/accounts/hd.go b/accounts/hd.go index 3009f19b6577..daca75ebbcb7 100644 --- a/accounts/hd.go +++ b/accounts/hd.go @@ -46,7 +46,7 @@ var LegacyLedgerBaseDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 // The BIP-32 spec https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki // defines derivation paths to be of the form: // -// m / purpose' / coin_type' / account' / change / address_index +// m / purpose' / coin_type' / account' / change / address_index // // The BIP-44 spec https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki // defines that the `purpose` be 44' (or 0x8000002C) for crypto currencies, and diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index 5082dec1cb33..e66717c3b1ad 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -879,6 +879,7 @@ func (s *Session) walletStatus() (*walletStatus, error) { } // derivationPath fetches the wallet's current derivation path from the card. +// //lint:ignore U1000 needs to be added to the console interface func (s *Session) derivationPath() (accounts.DerivationPath, error) { response, err := s.Channel.transmitEncrypted(claSCWallet, insStatus, statusP1Path, 0, nil) @@ -994,6 +995,7 @@ func (s *Session) derive(path accounts.DerivationPath) (accounts.Account, error) } // keyExport contains information on an exported keypair. +// //lint:ignore U1000 needs to be added to the console interface type keyExport struct { PublicKey []byte `asn1:"tag:0"` @@ -1001,6 +1003,7 @@ type keyExport struct { } // publicKey returns the public key for the current derivation path. +// //lint:ignore U1000 needs to be added to the console interface func (s *Session) publicKey() ([]byte, error) { response, err := s.Channel.transmitEncrypted(claSCWallet, insExportKey, exportP1Any, exportP2Pubkey, nil) diff --git a/accounts/url.go b/accounts/url.go index 12a84414a057..39b00e5b4498 100644 --- a/accounts/url.go +++ b/accounts/url.go @@ -92,10 +92,9 @@ func (u *URL) UnmarshalJSON(input []byte) error { // Cmp compares x and y and returns: // -// -1 if x < y -// 0 if x == y -// +1 if x > y -// +// -1 if x < y +// 0 if x == y +// +1 if x > y func (u URL) Cmp(url URL) int { if u.Scheme == url.Scheme { return strings.Compare(u.Path, url.Path) diff --git a/accounts/usbwallet/ledger.go b/accounts/usbwallet/ledger.go index 3de3b4091cfc..cda94280fdd2 100644 --- a/accounts/usbwallet/ledger.go +++ b/accounts/usbwallet/ledger.go @@ -195,18 +195,18 @@ func (w *ledgerDriver) SignTypedMessage(path accounts.DerivationPath, domainHash // // The version retrieval protocol is defined as follows: // -// CLA | INS | P1 | P2 | Lc | Le -// ----+-----+----+----+----+--- -// E0 | 06 | 00 | 00 | 00 | 04 +// CLA | INS | P1 | P2 | Lc | Le +// ----+-----+----+----+----+--- +// E0 | 06 | 00 | 00 | 00 | 04 // // With no input data, and the output data being: // -// Description | Length -// ---------------------------------------------------+-------- -// Flags 01: arbitrary data signature enabled by user | 1 byte -// Application major version | 1 byte -// Application minor version | 1 byte -// Application patch version | 1 byte +// Description | Length +// ---------------------------------------------------+-------- +// Flags 01: arbitrary data signature enabled by user | 1 byte +// Application major version | 1 byte +// Application minor version | 1 byte +// Application patch version | 1 byte func (w *ledgerDriver) ledgerVersion() ([3]byte, error) { // Send the request and wait for the response reply, err := w.ledgerExchange(ledgerOpGetConfiguration, 0, 0, nil) @@ -227,32 +227,32 @@ func (w *ledgerDriver) ledgerVersion() ([3]byte, error) { // // The address derivation protocol is defined as follows: // -// CLA | INS | P1 | P2 | Lc | Le -// ----+-----+----+----+-----+--- -// E0 | 02 | 00 return address -// 01 display address and confirm before returning -// | 00: do not return the chain code -// | 01: return the chain code -// | var | 00 +// CLA | INS | P1 | P2 | Lc | Le +// ----+-----+----+----+-----+--- +// E0 | 02 | 00 return address +// 01 display address and confirm before returning +// | 00: do not return the chain code +// | 01: return the chain code +// | var | 00 // // Where the input data is: // -// Description | Length -// -------------------------------------------------+-------- -// Number of BIP 32 derivations to perform (max 10) | 1 byte -// First derivation index (big endian) | 4 bytes -// ... | 4 bytes -// Last derivation index (big endian) | 4 bytes +// Description | Length +// -------------------------------------------------+-------- +// Number of BIP 32 derivations to perform (max 10) | 1 byte +// First derivation index (big endian) | 4 bytes +// ... | 4 bytes +// Last derivation index (big endian) | 4 bytes // // And the output data is: // -// Description | Length -// ------------------------+------------------- -// Public Key length | 1 byte -// Uncompressed Public Key | arbitrary -// Ethereum address length | 1 byte -// Ethereum address | 40 bytes hex ascii -// Chain code if requested | 32 bytes +// Description | Length +// ------------------------+------------------- +// Public Key length | 1 byte +// Uncompressed Public Key | arbitrary +// Ethereum address length | 1 byte +// Ethereum address | 40 bytes hex ascii +// Chain code if requested | 32 bytes func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, error) { // Flatten the derivation path into the Ledger request path := make([]byte, 1+4*len(derivationPath)) @@ -290,35 +290,35 @@ func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, er // // The transaction signing protocol is defined as follows: // -// CLA | INS | P1 | P2 | Lc | Le -// ----+-----+----+----+-----+--- -// E0 | 04 | 00: first transaction data block -// 80: subsequent transaction data block -// | 00 | variable | variable +// CLA | INS | P1 | P2 | Lc | Le +// ----+-----+----+----+-----+--- +// E0 | 04 | 00: first transaction data block +// 80: subsequent transaction data block +// | 00 | variable | variable // // Where the input for the first transaction block (first 255 bytes) is: // -// Description | Length -// -------------------------------------------------+---------- -// Number of BIP 32 derivations to perform (max 10) | 1 byte -// First derivation index (big endian) | 4 bytes -// ... | 4 bytes -// Last derivation index (big endian) | 4 bytes -// RLP transaction chunk | arbitrary +// Description | Length +// -------------------------------------------------+---------- +// Number of BIP 32 derivations to perform (max 10) | 1 byte +// First derivation index (big endian) | 4 bytes +// ... | 4 bytes +// Last derivation index (big endian) | 4 bytes +// RLP transaction chunk | arbitrary // // And the input for subsequent transaction blocks (first 255 bytes) are: // -// Description | Length -// ----------------------+---------- -// RLP transaction chunk | arbitrary +// Description | Length +// ----------------------+---------- +// RLP transaction chunk | arbitrary // // And the output data is: // -// Description | Length -// ------------+--------- -// signature V | 1 byte -// signature R | 32 bytes -// signature S | 32 bytes +// Description | Length +// ------------+--------- +// signature V | 1 byte +// signature R | 32 bytes +// signature S | 32 bytes func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) { // Flatten the derivation path into the Ledger request path := make([]byte, 1+4*len(derivationPath)) @@ -392,30 +392,28 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction // // The signing protocol is defined as follows: // -// CLA | INS | P1 | P2 | Lc | Le -// ----+-----+----+-----------------------------+-----+--- -// E0 | 0C | 00 | implementation version : 00 | variable | variable +// CLA | INS | P1 | P2 | Lc | Le +// ----+-----+----+-----------------------------+-----+--- +// E0 | 0C | 00 | implementation version : 00 | variable | variable // // Where the input is: // -// Description | Length -// -------------------------------------------------+---------- -// Number of BIP 32 derivations to perform (max 10) | 1 byte -// First derivation index (big endian) | 4 bytes -// ... | 4 bytes -// Last derivation index (big endian) | 4 bytes -// domain hash | 32 bytes -// message hash | 32 bytes -// -// +// Description | Length +// -------------------------------------------------+---------- +// Number of BIP 32 derivations to perform (max 10) | 1 byte +// First derivation index (big endian) | 4 bytes +// ... | 4 bytes +// Last derivation index (big endian) | 4 bytes +// domain hash | 32 bytes +// message hash | 32 bytes // // And the output data is: // -// Description | Length -// ------------+--------- -// signature V | 1 byte -// signature R | 32 bytes -// signature S | 32 bytes +// Description | Length +// ------------+--------- +// signature V | 1 byte +// signature R | 32 bytes +// signature S | 32 bytes func (w *ledgerDriver) ledgerSignTypedMessage(derivationPath []uint32, domainHash []byte, messageHash []byte) ([]byte, error) { // Flatten the derivation path into the Ledger request path := make([]byte, 1+4*len(derivationPath)) @@ -454,12 +452,12 @@ func (w *ledgerDriver) ledgerSignTypedMessage(derivationPath []uint32, domainHas // // The common transport header is defined as follows: // -// Description | Length -// --------------------------------------+---------- -// Communication channel ID (big endian) | 2 bytes -// Command tag | 1 byte -// Packet sequence index (big endian) | 2 bytes -// Payload | arbitrary +// Description | Length +// --------------------------------------+---------- +// Communication channel ID (big endian) | 2 bytes +// Command tag | 1 byte +// Packet sequence index (big endian) | 2 bytes +// Payload | arbitrary // // The Communication channel ID allows commands multiplexing over the same // physical link. It is not used for the time being, and should be set to 0101 @@ -473,15 +471,15 @@ func (w *ledgerDriver) ledgerSignTypedMessage(derivationPath []uint32, domainHas // // APDU Command payloads are encoded as follows: // -// Description | Length -// ----------------------------------- -// APDU length (big endian) | 2 bytes -// APDU CLA | 1 byte -// APDU INS | 1 byte -// APDU P1 | 1 byte -// APDU P2 | 1 byte -// APDU length | 1 byte -// Optional APDU data | arbitrary +// Description | Length +// ----------------------------------- +// APDU length (big endian) | 2 bytes +// APDU CLA | 1 byte +// APDU INS | 1 byte +// APDU P1 | 1 byte +// APDU P2 | 1 byte +// APDU length | 1 byte +// Optional APDU data | arbitrary func (w *ledgerDriver) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) { // Construct the message payload, possibly split into multiple chunks apdu := make([]byte, 2, 7+len(data)) diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index e385682a5833..9644dc4e02c9 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -84,15 +84,15 @@ func (w *trezorDriver) Status() (string, error) { // Open implements usbwallet.driver, attempting to initialize the connection to // the Trezor hardware wallet. Initializing the Trezor is a two or three phase operation: -// * The first phase is to initialize the connection and read the wallet's -// features. This phase is invoked if the provided passphrase is empty. The -// device will display the pinpad as a result and will return an appropriate -// error to notify the user that a second open phase is needed. -// * The second phase is to unlock access to the Trezor, which is done by the -// user actually providing a passphrase mapping a keyboard keypad to the pin -// number of the user (shuffled according to the pinpad displayed). -// * If needed the device will ask for passphrase which will require calling -// open again with the actual passphrase (3rd phase) +// - The first phase is to initialize the connection and read the wallet's +// features. This phase is invoked if the provided passphrase is empty. The +// device will display the pinpad as a result and will return an appropriate +// error to notify the user that a second open phase is needed. +// - The second phase is to unlock access to the Trezor, which is done by the +// user actually providing a passphrase mapping a keyboard keypad to the pin +// number of the user (shuffled according to the pinpad displayed). +// - If needed the device will ask for passphrase which will require calling +// open again with the actual passphrase (3rd phase) func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error { w.device, w.failure = device, nil diff --git a/accounts/usbwallet/trezor/messages-common.pb.go b/accounts/usbwallet/trezor/messages-common.pb.go index 304bec0e360a..b396c6d8b554 100644 --- a/accounts/usbwallet/trezor/messages-common.pb.go +++ b/accounts/usbwallet/trezor/messages-common.pb.go @@ -94,7 +94,7 @@ func (Failure_FailureType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_aaf30d059fdbc38d, []int{1, 0} } -//* +// * // Type of button request type ButtonRequest_ButtonRequestType int32 @@ -175,7 +175,7 @@ func (ButtonRequest_ButtonRequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_aaf30d059fdbc38d, []int{2, 0} } -//* +// * // Type of PIN request type PinMatrixRequest_PinMatrixRequestType int32 @@ -220,7 +220,7 @@ func (PinMatrixRequest_PinMatrixRequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_aaf30d059fdbc38d, []int{4, 0} } -//* +// * // Response: Success of the previous request // @end type Success struct { @@ -262,7 +262,7 @@ func (m *Success) GetMessage() string { return "" } -//* +// * // Response: Failure of the previous request // @end type Failure struct { @@ -312,7 +312,7 @@ func (m *Failure) GetMessage() string { return "" } -//* +// * // Response: Device is waiting for HW button press. // @auxstart // @next ButtonAck @@ -363,7 +363,7 @@ func (m *ButtonRequest) GetData() string { return "" } -//* +// * // Request: Computer agrees to wait for HW button press // @auxend type ButtonAck struct { @@ -397,7 +397,7 @@ func (m *ButtonAck) XXX_DiscardUnknown() { var xxx_messageInfo_ButtonAck proto.InternalMessageInfo -//* +// * // Response: Device is asking computer to show PIN matrix and awaits PIN encoded using this matrix scheme // @auxstart // @next PinMatrixAck @@ -440,7 +440,7 @@ func (m *PinMatrixRequest) GetType() PinMatrixRequest_PinMatrixRequestType { return PinMatrixRequest_PinMatrixRequestType_Current } -//* +// * // Request: Computer responds with encoded PIN // @auxend type PinMatrixAck struct { @@ -482,7 +482,7 @@ func (m *PinMatrixAck) GetPin() string { return "" } -//* +// * // Response: Device awaits encryption passphrase // @auxstart // @next PassphraseAck @@ -525,7 +525,7 @@ func (m *PassphraseRequest) GetOnDevice() bool { return false } -//* +// * // Request: Send passphrase back // @next PassphraseStateRequest type PassphraseAck struct { @@ -575,7 +575,7 @@ func (m *PassphraseAck) GetState() []byte { return nil } -//* +// * // Response: Device awaits passphrase state // @next PassphraseStateAck type PassphraseStateRequest struct { @@ -617,7 +617,7 @@ func (m *PassphraseStateRequest) GetState() []byte { return nil } -//* +// * // Request: Send passphrase state back // @auxend type PassphraseStateAck struct { @@ -651,7 +651,7 @@ func (m *PassphraseStateAck) XXX_DiscardUnknown() { var xxx_messageInfo_PassphraseStateAck proto.InternalMessageInfo -//* +// * // Structure representing BIP32 (hierarchical deterministic) node // Used for imports of private key into the device and exporting public key out of device // @embed diff --git a/accounts/usbwallet/trezor/messages-ethereum.pb.go b/accounts/usbwallet/trezor/messages-ethereum.pb.go index 5d664f5ba447..230a48279d48 100644 --- a/accounts/usbwallet/trezor/messages-ethereum.pb.go +++ b/accounts/usbwallet/trezor/messages-ethereum.pb.go @@ -21,7 +21,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package -//* +// * // Request: Ask device for public key corresponding to address_n path // @start // @next EthereumPublicKey @@ -73,7 +73,7 @@ func (m *EthereumGetPublicKey) GetShowDisplay() bool { return false } -//* +// * // Response: Contains public key derived from device private seed // @end type EthereumPublicKey struct { @@ -123,7 +123,7 @@ func (m *EthereumPublicKey) GetXpub() string { return "" } -//* +// * // Request: Ask device for Ethereum address corresponding to address_n path // @start // @next EthereumAddress @@ -175,7 +175,7 @@ func (m *EthereumGetAddress) GetShowDisplay() bool { return false } -//* +// * // Response: Contains an Ethereum address derived from device private seed // @end type EthereumAddress struct { @@ -225,7 +225,7 @@ func (m *EthereumAddress) GetAddressHex() string { return "" } -//* +// * // Request: Ask device to sign transaction // All fields are optional from the protocol's point of view. Each field defaults to value `0` if missing. // Note: the first at most 1024 bytes of data MUST be transmitted as part of this message. @@ -351,7 +351,7 @@ func (m *EthereumSignTx) GetTxType() uint32 { return 0 } -//* +// * // Response: Device asks for more data from transaction payload, or returns the signature. // If data_length is set, device awaits that many more bytes of payload. // Otherwise, the signature_* fields contain the computed transaction signature. All three fields will be present. @@ -420,7 +420,7 @@ func (m *EthereumTxRequest) GetSignatureS() []byte { return nil } -//* +// * // Request: Transaction payload data. // @next EthereumTxRequest type EthereumTxAck struct { @@ -462,7 +462,7 @@ func (m *EthereumTxAck) GetDataChunk() []byte { return nil } -//* +// * // Request: Ask device to sign message // @start // @next EthereumMessageSignature @@ -514,7 +514,7 @@ func (m *EthereumSignMessage) GetMessage() []byte { return nil } -//* +// * // Response: Signed message // @end type EthereumMessageSignature struct { @@ -572,7 +572,7 @@ func (m *EthereumMessageSignature) GetAddressHex() string { return "" } -//* +// * // Request: Ask device to verify message // @start // @next Success diff --git a/accounts/usbwallet/trezor/messages-management.pb.go b/accounts/usbwallet/trezor/messages-management.pb.go index f5c872f1fb5b..91bfca1e3f08 100644 --- a/accounts/usbwallet/trezor/messages-management.pb.go +++ b/accounts/usbwallet/trezor/messages-management.pb.go @@ -21,7 +21,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package -//* +// * // Structure representing passphrase source type ApplySettings_PassphraseSourceType int32 @@ -66,7 +66,7 @@ func (ApplySettings_PassphraseSourceType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_0c720c20d27aa029, []int{4, 0} } -//* +// * // Type of recovery procedure. These should be used as bitmask, e.g., // `RecoveryDeviceType_ScrambledWords | RecoveryDeviceType_Matrix` // listing every method supported by the host computer. @@ -114,7 +114,7 @@ func (RecoveryDevice_RecoveryDeviceType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_0c720c20d27aa029, []int{17, 0} } -//* +// * // Type of Recovery Word request type WordRequest_WordRequestType int32 @@ -159,7 +159,7 @@ func (WordRequest_WordRequestType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_0c720c20d27aa029, []int{18, 0} } -//* +// * // Request: Reset device to default state and ask for device details // @start // @next Features @@ -210,7 +210,7 @@ func (m *Initialize) GetSkipPassphrase() bool { return false } -//* +// * // Request: Ask for device details (no device reset) // @start // @next Features @@ -245,7 +245,7 @@ func (m *GetFeatures) XXX_DiscardUnknown() { var xxx_messageInfo_GetFeatures proto.InternalMessageInfo -//* +// * // Response: Reports various information about the device // @end type Features struct { @@ -495,7 +495,7 @@ func (m *Features) GetNoBackup() bool { return false } -//* +// * // Request: clear session (removes cached PIN, passphrase, etc). // @start // @next Success @@ -530,7 +530,7 @@ func (m *ClearSession) XXX_DiscardUnknown() { var xxx_messageInfo_ClearSession proto.InternalMessageInfo -//* +// * // Request: change language and/or label of the device // @start // @next Success @@ -622,7 +622,7 @@ func (m *ApplySettings) GetDisplayRotation() uint32 { return 0 } -//* +// * // Request: set flags of the device // @start // @next Success @@ -666,7 +666,7 @@ func (m *ApplyFlags) GetFlags() uint32 { return 0 } -//* +// * // Request: Starts workflow for setting/changing/removing the PIN // @start // @next Success @@ -710,7 +710,7 @@ func (m *ChangePin) GetRemove() bool { return false } -//* +// * // Request: Test if the device is alive, device sends back the message in Success response // @start // @next Success @@ -777,7 +777,7 @@ func (m *Ping) GetPassphraseProtection() bool { return false } -//* +// * // Request: Abort last operation that required user interaction // @start // @next Failure @@ -812,7 +812,7 @@ func (m *Cancel) XXX_DiscardUnknown() { var xxx_messageInfo_Cancel proto.InternalMessageInfo -//* +// * // Request: Request a sample of random data generated by hardware RNG. May be used for testing. // @start // @next Entropy @@ -856,7 +856,7 @@ func (m *GetEntropy) GetSize() uint32 { return 0 } -//* +// * // Response: Reply with random data generated by internal RNG // @end type Entropy struct { @@ -898,7 +898,7 @@ func (m *Entropy) GetEntropy() []byte { return nil } -//* +// * // Request: Request device to wipe all sensitive data and settings // @start // @next Success @@ -934,7 +934,7 @@ func (m *WipeDevice) XXX_DiscardUnknown() { var xxx_messageInfo_WipeDevice proto.InternalMessageInfo -//* +// * // Request: Load seed and related internal settings from the computer // @start // @next Success @@ -1036,7 +1036,7 @@ func (m *LoadDevice) GetU2FCounter() uint32 { return 0 } -//* +// * // Request: Ask device to do initialization involving user interaction // @start // @next EntropyRequest @@ -1147,7 +1147,7 @@ func (m *ResetDevice) GetNoBackup() bool { return false } -//* +// * // Request: Perform backup of the device seed if not backed up using ResetDevice // @start // @next Success @@ -1182,7 +1182,7 @@ func (m *BackupDevice) XXX_DiscardUnknown() { var xxx_messageInfo_BackupDevice proto.InternalMessageInfo -//* +// * // Response: Ask for additional entropy from host computer // @next EntropyAck type EntropyRequest struct { @@ -1216,7 +1216,7 @@ func (m *EntropyRequest) XXX_DiscardUnknown() { var xxx_messageInfo_EntropyRequest proto.InternalMessageInfo -//* +// * // Request: Provide additional entropy for seed generation function // @next Success type EntropyAck struct { @@ -1258,7 +1258,7 @@ func (m *EntropyAck) GetEntropy() []byte { return nil } -//* +// * // Request: Start recovery workflow asking user for specific words of mnemonic // Used to recovery device safely even on untrusted computer. // @start @@ -1369,7 +1369,7 @@ func (m *RecoveryDevice) GetDryRun() bool { return false } -//* +// * // Response: Device is waiting for user to enter word of the mnemonic // Its position is shown only on device's internal display. // @next WordAck @@ -1412,7 +1412,7 @@ func (m *WordRequest) GetType() WordRequest_WordRequestType { return WordRequest_WordRequestType_Plain } -//* +// * // Request: Computer replies with word from the mnemonic // @next WordRequest // @next Success @@ -1456,7 +1456,7 @@ func (m *WordAck) GetWord() string { return "" } -//* +// * // Request: Set U2F counter // @start // @next Success diff --git a/accounts/usbwallet/trezor/messages.pb.go b/accounts/usbwallet/trezor/messages.pb.go index 6278bd8ee02c..af0c957144d2 100644 --- a/accounts/usbwallet/trezor/messages.pb.go +++ b/accounts/usbwallet/trezor/messages.pb.go @@ -22,7 +22,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package -//* +// * // Mapping between TREZOR wire identifier (uint) and a protobuf message type MessageType int32 diff --git a/build/checksums.txt b/build/checksums.txt index f7b13a0330f2..2725329fbc09 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,38 +1,38 @@ # This file contains sha256 checksums of optional build dependencies. -9920d3306a1ac536cdd2c796d6cb3c54bc559c226fc3cc39c32f1e0bd7f50d2a go1.18.5.src.tar.gz -828eeca8b5abea3e56921df8fa4b1101380a5ebcfee10acbc8ffe7ec0bf5876b go1.18.5.darwin-amd64.tar.gz -923a377c6fc9a2c789f5db61c24b8f64133f7889056897449891f256af34065f go1.18.5.darwin-arm64.tar.gz -c3d90264a706e2d88cfb44126dc6f0d008a48f00732e04bc377cea1a2b716a7c go1.18.5.freebsd-386.tar.gz -0de23843c568d388bc0f0e390a8966938cccaae0d74b698325f7175bac04e0c6 go1.18.5.freebsd-amd64.tar.gz -0c44f85d146c6f98c34e8ff436a42af22e90e36fe232d3d9d3101f23fd61362b go1.18.5.linux-386.tar.gz -9e5de37f9c49942c601b191ac5fba404b868bfc21d446d6960acc12283d6e5f2 go1.18.5.linux-amd64.tar.gz -006f6622718212363fa1ff004a6ab4d87bbbe772ec5631bab7cac10be346e4f1 go1.18.5.linux-arm64.tar.gz -d5ac34ac5f060a5274319aa04b7b11e41b123bd7887d64efb5f44ead236957af go1.18.5.linux-armv6l.tar.gz -2e37fb9c7cbaedd4e729492d658aa4cde821fc94117391a8105c13b25ca1c84b go1.18.5.linux-ppc64le.tar.gz -e3d536e7873639f85353e892444f83b14cb6670603961f215986ae8e28e8e07a go1.18.5.linux-s390x.tar.gz -7b3142ec0c5db991e7f73a231662a92429b90ee151fe47557acb566d8d9ae4d3 go1.18.5.windows-386.zip -73753620602d4b4469770040c53db55e5dd6af2ad07ecc18f71f164c3224eaad go1.18.5.windows-amd64.zip -4d154626affff12ef73ea1017af0e5b52dbc839ef92f6f9e76cf4f71278a5744 go1.18.5.windows-arm64.zip +27871baa490f3401414ad793fba49086f6c855b1c584385ed7771e1204c7e179 go1.19.1.src.tar.gz +b2828a2b05f0d2169afc74c11ed010775bf7cf0061822b275697b2f470495fb7 go1.19.1.darwin-amd64.tar.gz +e46aecce83a9289be16ce4ba9b8478a5b89b8aa0230171d5c6adbc0c66640548 go1.19.1.darwin-arm64.tar.gz +cfaca8c1d5784d2bc21e12d8893cfd2dc885a60db4c1a9a95e4ffc694d0925ce go1.19.1.freebsd-386.tar.gz +db5b8f232e12c655cc6cde6af1adf4d27d842541807802d747c86161e89efa0a go1.19.1.freebsd-amd64.tar.gz +9acc57342400c5b0c2da07b5b01b50da239dd4a7fad41a1fb56af8363ef4133f go1.19.1.linux-386.tar.gz +acc512fbab4f716a8f97a8b3fbaa9ddd39606a28be6c2515ef7c6c6311acffde go1.19.1.linux-amd64.tar.gz +49960821948b9c6b14041430890eccee58c76b52e2dbaafce971c3c38d43df9f go1.19.1.linux-arm64.tar.gz +efe93f5671621ee84ce5e262e1e21acbc72acefbaba360f21778abd083d4ad16 go1.19.1.linux-armv6l.tar.gz +4137984aa353de9c5ec1bd8fb3cd00a0624b75eafa3d4ec13d2f3f48261dba2e go1.19.1.linux-ppc64le.tar.gz +ca1005cc80a3dd726536b4c6ea5fef0318939351ff273eff420bd66a377c74eb go1.19.1.linux-s390x.tar.gz +bc7043e7a9a8d34aacd06f8c2f70e166d1d148f6800814cff790c45b9ab31cee go1.19.1.windows-386.zip +b33584c1d93b0e9c783de876b7aa99d3018bdeccd396aeb6d516a74e9d88d55f go1.19.1.windows-amd64.zip +d8cf3f04762fa7d5d9c82dfa15b5adaae2404463af3bc8dcd7f89837512501fe go1.19.1.windows-arm64.zip -658078aaaf7608693f37c4cf1380b2af418ab8b2d23fdb33e7e2d4339328590e golangci-lint-1.46.2-darwin-amd64.tar.gz -81f9b4afd62ec5e612ef8bc3b1d612a88b56ff289874831845cdad394427385f golangci-lint-1.46.2-darwin-arm64.tar.gz -943486e703e62ec55ecd90caeb22bcd39f8cc3962a93eec18c06b7bae12cb46f golangci-lint-1.46.2-freebsd-386.tar.gz -a75dd9ba7e08e8315c411697171db5375c0f6a1ece9e6fbeb9e9a4386822e17d golangci-lint-1.46.2-freebsd-amd64.tar.gz -83eedca1af72e8be055a1235177eb1b33524fbf08bec5730df2e6c3efade2b23 golangci-lint-1.46.2-freebsd-armv6.tar.gz -513d276c490de6f82baa01f9346d8d78b385f2ae97608f42f05d1f0f1314cd54 golangci-lint-1.46.2-freebsd-armv7.tar.gz -461a60016d516c69d406dc3e2d4957b722dbe684b7085dfac4802d0f84409e27 golangci-lint-1.46.2-linux-386.tar.gz -242cd4f2d6ac0556e315192e8555784d13da5d1874e51304711570769c4f2b9b golangci-lint-1.46.2-linux-amd64.tar.gz -ff5448ada2b3982581984d64b0dec614dba0a3ea4cab2d6a343c77927fc89f7e golangci-lint-1.46.2-linux-arm64.tar.gz -177f5210ef04aee282bfbc6ec519d36af5fb7d2b2c8d3f4ea5e59fdba71b0a27 golangci-lint-1.46.2-linux-armv6.tar.gz -10dd512a36ee978a1009edbca3ba3af410f0fda8df4d85f0e4793a24213870cc golangci-lint-1.46.2-linux-armv7.tar.gz -67779fa517c688c9db1090c3c456117d95c6b92979c623fe8cce8fb84251f21e golangci-lint-1.46.2-linux-mips64.tar.gz -c085f0f57bdccbb2c902a41b72ce210a3dfff16ca856789374745ab52004b6ee golangci-lint-1.46.2-linux-mips64le.tar.gz -abecef6421499248e58ed75d2938bc12b4b1f98b057f25060680b77bb51a881e golangci-lint-1.46.2-linux-ppc64le.tar.gz -134843a8f5c5c182c11979ea75f5866945d54757b2a04f3e5e04a0cf4fbf3a39 golangci-lint-1.46.2-linux-riscv64.tar.gz -9fe21a9476567aafe7a2e1a926b9641a39f920d4c0ea8eda9d968bc6136337f9 golangci-lint-1.46.2-linux-s390x.tar.gz -b48a421ec12a43f8fc8f977b9cf7d4a1ea1c4b97f803a238de7d3ce4ab23a84b golangci-lint-1.46.2-windows-386.zip -604acc1378a566abb0eac799362f3a37b7fcb5fa2268aeb2d5d954c829367301 golangci-lint-1.46.2-windows-amd64.zip -927def10db073da9687594072e6a3d9c891f67fa897105a2cfd715e018e7386c golangci-lint-1.46.2-windows-arm64.zip -729b76ed1d8b4e2612e38772b211503cb940e00a137bbaace1aa066f7c943737 golangci-lint-1.46.2-windows-armv6.zip -ea27c86d91e0b245ecbcfbf6cdb4ac0522d4bc6dca56bba02ea1bc77ad2917ac golangci-lint-1.46.2-windows-armv7.zip +20cd1215e0420db8cfa94a6cd3c9d325f7b39c07f2415a02d111568d8bc9e271 golangci-lint-1.49.0-darwin-amd64.tar.gz +cabb1a4c35fe1dadbe5a81550a00871281a331e7660cd85ae16e936a7f0f6cfc golangci-lint-1.49.0-darwin-arm64.tar.gz +f834c3b09580cf763b5d30b0c33c83cb13d7a822b5ed5d724143f121ffe28c97 golangci-lint-1.49.0-freebsd-386.tar.gz +4ca91c9f3aa79a71da441b7220a3e799365ff7a24caf9f04fcda12066c5ab0f7 golangci-lint-1.49.0-freebsd-amd64.tar.gz +37de789245248eea375d05080e11b4662a08762c353752575167611e65658454 golangci-lint-1.49.0-freebsd-armv6.tar.gz +3abed2bd3a8134b501fdc9cc9a0e60d616c86389e4fcdd1f79ceae7458974378 golangci-lint-1.49.0-freebsd-armv7.tar.gz +ef2860d90d83aee6713f697f23372cd93ac41a16439fdcb3c4ac86ba0f306860 golangci-lint-1.49.0-linux-386.tar.gz +5badc6e9fee2003621efa07e385910d9a88c89b38f6c35aded153193c5125178 golangci-lint-1.49.0-linux-amd64.tar.gz +b57ed03d29b8ca69be9925edd67ea305b6013cd5c97507d205fbe2979f71f2b5 golangci-lint-1.49.0-linux-arm64.tar.gz +4a41cff3af7f5304751f7bbf4ea617c14ebc1f88481a28a013e61b06d1f7102c golangci-lint-1.49.0-linux-armv6.tar.gz +14a9683af483ee7052dd0ce7d6140e0b502d6001bea3de606b8e7cce2c673539 golangci-lint-1.49.0-linux-armv7.tar.gz +33edf757bc2611204fdb40b212900866a57ded4eea62c1b19c10bfc375359afa golangci-lint-1.49.0-linux-mips64.tar.gz +280f7902f90d162566f1691a300663dd8db6e225e65384fe66b6fb2362e0b314 golangci-lint-1.49.0-linux-mips64le.tar.gz +103bcb7ce6c668e0a7e95e5c5355892d74f5d15391443430472e66d652906a15 golangci-lint-1.49.0-linux-ppc64le.tar.gz +4636ff9b01ddb18a2c1a953fc134207711b0a5d874d04ac66f915e9cfff0e8e0 golangci-lint-1.49.0-linux-riscv64.tar.gz +029e0844931a2d3edc771d67e17fe17928f04f80c1a9aa165160a543e8a7e8d4 golangci-lint-1.49.0-linux-s390x.tar.gz +e9cb6f691e62a4d8b28dd52d2eab57cca72acfd5083b3c5417a72d2eb64def09 golangci-lint-1.49.0-windows-386.zip +d058dfb0c7fbd73be70f285d3f8d4d424192fe9b19760ddbb0b2c4b743b8656c golangci-lint-1.49.0-windows-amd64.zip +c049d80297228db7065eabeac5114f77f04415dcd9b944e8d7c6426d9dd6e9dd golangci-lint-1.49.0-windows-arm64.zip +ec9164bab7134ddb94f51c17fd37c109b0801ecd5494b6c0e27ca7898fbd7469 golangci-lint-1.49.0-windows-armv6.zip +68fd9e880d98073f436c58b6f6d2c141881ef49b06ca31137bc19da4e4e3b996 golangci-lint-1.49.0-windows-armv7.zip diff --git a/build/ci.go b/build/ci.go index 24f225b72030..4c8062eafb77 100644 --- a/build/ci.go +++ b/build/ci.go @@ -24,19 +24,18 @@ Usage: go run build/ci.go Available commands are: - install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables - test [ -coverage ] [ packages... ] -- runs the tests - lint -- runs certain pre-selected linters - archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -signify key-envvar ] [ -upload dest ] -- archives build artifacts - importkeys -- imports signing keys from env - debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package - nsis -- creates a Windows NSIS installer - aar [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an Android archive - xcode [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an iOS XCode framework - purge [ -store blobstore ] [ -days threshold ] -- purges old archives from the blobstore + install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables + test [ -coverage ] [ packages... ] -- runs the tests + lint -- runs certain pre-selected linters + archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -signify key-envvar ] [ -upload dest ] -- archives build artifacts + importkeys -- imports signing keys from env + debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package + nsis -- creates a Windows NSIS installer + aar [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an Android archive + xcode [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an iOS XCode framework + purge [ -store blobstore ] [ -days threshold ] -- purges old archives from the blobstore For all commands, -n prevents execution of external programs (dry run mode). - */ package main @@ -149,7 +148,7 @@ var ( // This is the version of go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.18.5" + dlgoVersion = "1.19.1" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) @@ -347,7 +346,7 @@ func doLint(cmdline []string) { // downloadLinter downloads and unpacks golangci-lint. func downloadLinter(cachedir string) string { - const version = "1.46.2" + const version = "1.49.0" csdb := build.MustLoadChecksums("build/checksums.txt") arch := runtime.GOARCH diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 73a28e91c097..e2d9cced2255 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -334,8 +334,9 @@ func (t *txWithKey) UnmarshalJSON(input []byte) error { // signUnsignedTransactions converts the input txs to canonical transactions. // // The transactions can have two forms, either -// 1. unsigned or -// 2. signed +// 1. unsigned or +// 2. signed +// // For (1), r, s, v, need so be zero, and the `secretKey` needs to be set. // If so, we sign it here and now, with the given `secretKey` // If the condition above is not met, then it's considered a signed transaction. diff --git a/cmd/p2psim/main.go b/cmd/p2psim/main.go index 4edb0a9ab43d..8b3cb29b1a0a 100644 --- a/cmd/p2psim/main.go +++ b/cmd/p2psim/main.go @@ -19,21 +19,20 @@ // Here is an example of creating a 2 node network with the first node // connected to the second: // -// $ p2psim node create -// Created node01 +// $ p2psim node create +// Created node01 // -// $ p2psim node start node01 -// Started node01 +// $ p2psim node start node01 +// Started node01 // -// $ p2psim node create -// Created node02 +// $ p2psim node create +// Created node02 // -// $ p2psim node start node02 -// Started node02 -// -// $ p2psim node connect node01 node02 -// Connected node01 to node02 +// $ p2psim node start node02 +// Started node02 // +// $ p2psim node connect node01 node02 +// Connected node01 to node02 package main import ( diff --git a/common/hexutil/hexutil.go b/common/hexutil/hexutil.go index e0241f5f2b07..d3201850a8e4 100644 --- a/common/hexutil/hexutil.go +++ b/common/hexutil/hexutil.go @@ -18,7 +18,7 @@ Package hexutil implements hex encoding with 0x prefix. This encoding is used by the Ethereum RPC API to transport binary data in JSON payloads. -Encoding Rules +# Encoding Rules All hex data must have prefix "0x". diff --git a/common/math/big.go b/common/math/big.go index 1af5b4d879d6..48427810e1ce 100644 --- a/common/math/big.go +++ b/common/math/big.go @@ -227,10 +227,10 @@ func U256Bytes(n *big.Int) []byte { // S256 interprets x as a two's complement number. // x must not exceed 256 bits (the result is undefined if it does) and is not modified. // -// S256(0) = 0 -// S256(1) = 1 -// S256(2**255) = -2**255 -// S256(2**256-1) = -1 +// S256(0) = 0 +// S256(1) = 1 +// S256(2**255) = -2**255 +// S256(2**256-1) = -1 func S256(x *big.Int) *big.Int { if x.Cmp(tt255) < 0 { return x diff --git a/common/prque/lazyqueue.go b/common/prque/lazyqueue.go index 6fdb6cc1b79f..13ef3ed2cdbf 100644 --- a/common/prque/lazyqueue.go +++ b/common/prque/lazyqueue.go @@ -26,9 +26,10 @@ import ( // LazyQueue is a priority queue data structure where priorities can change over // time and are only evaluated on demand. // Two callbacks are required: -// - priority evaluates the actual priority of an item -// - maxPriority gives an upper estimate for the priority in any moment between -// now and the given absolute time +// - priority evaluates the actual priority of an item +// - maxPriority gives an upper estimate for the priority in any moment between +// now and the given absolute time +// // If the upper estimate is exceeded then Update should be called for that item. // A global Refresh function should also be called periodically. type LazyQueue struct { diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 7e4d657413ed..6d108856e6d6 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -224,10 +224,11 @@ func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Blo // verifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum consensus engine. The difference between the beacon and classic is // (a) The following fields are expected to be constants: -// - difficulty is expected to be 0 -// - nonce is expected to be 0 -// - unclehash is expected to be Hash(emptyHeader) +// - difficulty is expected to be 0 +// - nonce is expected to be 0 +// - unclehash is expected to be Hash(emptyHeader) // to be the desired constants +// // (b) we don't verify if a block is in the future anymore // (c) the extradata is limited to 32 bytes func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error { diff --git a/consensus/ethash/api.go b/consensus/ethash/api.go index f4d3802e0b37..da3b0751be54 100644 --- a/consensus/ethash/api.go +++ b/consensus/ethash/api.go @@ -34,10 +34,11 @@ type API struct { // GetWork returns a work package for external miner. // // The work package consists of 3 strings: -// result[0] - 32 bytes hex encoded current block header pow-hash -// result[1] - 32 bytes hex encoded seed hash used for DAG -// result[2] - 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty -// result[3] - hex encoded block number +// +// result[0] - 32 bytes hex encoded current block header pow-hash +// result[1] - 32 bytes hex encoded seed hash used for DAG +// result[2] - 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty +// result[3] - hex encoded block number func (api *API) GetWork() ([4]string, error) { if api.ethash.remote == nil { return [4]string{}, errors.New("not supported") diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index 6fa60ef6a8bb..ec4696390028 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -339,10 +339,11 @@ func (s *remoteSealer) loop() { // makeWork creates a work package for external miner. // // The work package consists of 3 strings: -// result[0], 32 bytes hex encoded current block header pow-hash -// result[1], 32 bytes hex encoded seed hash used for DAG -// result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty -// result[3], hex encoded block number +// +// result[0], 32 bytes hex encoded current block header pow-hash +// result[1], 32 bytes hex encoded seed hash used for DAG +// result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty +// result[3], hex encoded block number func (s *remoteSealer) makeWork(block *types.Block) { hash := s.ethash.SealHash(block.Header()) s.currentWork[0] = hash.Hex() diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go index 36df036f2735..96995616de56 100644 --- a/consensus/misc/dao.go +++ b/consensus/misc/dao.go @@ -40,10 +40,11 @@ var ( // ensure it conforms to DAO hard-fork rules. // // DAO hard-fork extension to the header validity: -// a) if the node is no-fork, do not accept blocks in the [fork, fork+10) range -// with the fork specific extra-data set -// b) if the node is pro-fork, require blocks in the specific range to have the -// unique extra-data set. +// +// - if the node is no-fork, do not accept blocks in the [fork, fork+10) range +// with the fork specific extra-data set. +// - if the node is pro-fork, require blocks in the specific range to have the +// unique extra-data set. func VerifyDAOHeaderExtraData(config *params.ChainConfig, header *types.Header) error { // Short circuit validation if the node doesn't care about the DAO fork if config.DAOForkBlock == nil { diff --git a/core/beacon/types.go b/core/beacon/types.go index e25d724c0d55..e06ab5c692d9 100644 --- a/core/beacon/types.go +++ b/core/beacon/types.go @@ -136,9 +136,11 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) { // ExecutableDataToBlock constructs a block from executable data. // It verifies that the following fields: -// len(extraData) <= 32 -// uncleHash = emptyUncleHash -// difficulty = 0 +// +// len(extraData) <= 32 +// uncleHash = emptyUncleHash +// difficulty = 0 +// // and that the blockhash of the constructed block matches the parameters. func ExecutableDataToBlock(params ExecutableDataV1) (*types.Block, error) { txs, err := decodeTransactions(params.Transactions) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 06c43658ed9b..08061bc2498a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1875,8 +1875,8 @@ func TestInsertReceiptChainRollback(t *testing.T) { // overtake the 'canon' chain until after it's passed canon by about 200 blocks. // // Details at: -// - https://github.com/ethereum/go-ethereum/issues/18977 -// - https://github.com/ethereum/go-ethereum/pull/18988 +// - https://github.com/ethereum/go-ethereum/issues/18977 +// - https://github.com/ethereum/go-ethereum/pull/18988 func TestLowDiffLongChain(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() @@ -2023,14 +2023,16 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon } // Tests that importing a sidechain (S), where -// - S is sidechain, containing blocks [Sn...Sm] -// - C is canon chain, containing blocks [G..Cn..Cm] -// - The common ancestor Cc is pruned -// - The first block in S: Sn, is == Cn +// - S is sidechain, containing blocks [Sn...Sm] +// - C is canon chain, containing blocks [G..Cn..Cm] +// - The common ancestor Cc is pruned +// - The first block in S: Sn, is == Cn +// // That is: the sidechain for import contains some blocks already present in canon chain. -// So the blocks are -// [ Cn, Cn+1, Cc, Sn+3 ... Sm] -// ^ ^ ^ pruned +// So the blocks are: +// +// [ Cn, Cn+1, Cc, Sn+3 ... Sm] +// ^ ^ ^ pruned func TestPrunedImportSide(t *testing.T) { //glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))) //glogger.Verbosity(3) @@ -2774,9 +2776,9 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { // This internally leads to a sidechain import, since the blocks trigger an // ErrPrunedAncestor error. // This may e.g. happen if -// 1. Downloader rollbacks a batch of inserted blocks and exits -// 2. Downloader starts to sync again -// 3. The blocks fetched are all known and canonical blocks +// 1. Downloader rollbacks a batch of inserted blocks and exits +// 2. Downloader starts to sync again +// 3. The blocks fetched are all known and canonical blocks func TestSideImportPrunedBlocks(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() @@ -3269,20 +3271,19 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { // TestInitThenFailCreateContract tests a pretty notorious case that happened // on mainnet over blocks 7338108, 7338110 and 7338115. -// - Block 7338108: address e771789f5cccac282f23bb7add5690e1f6ca467c is initiated -// with 0.001 ether (thus created but no code) -// - Block 7338110: a CREATE2 is attempted. The CREATE2 would deploy code on -// the same address e771789f5cccac282f23bb7add5690e1f6ca467c. However, the -// deployment fails due to OOG during initcode execution -// - Block 7338115: another tx checks the balance of -// e771789f5cccac282f23bb7add5690e1f6ca467c, and the snapshotter returned it as -// zero. +// - Block 7338108: address e771789f5cccac282f23bb7add5690e1f6ca467c is initiated +// with 0.001 ether (thus created but no code) +// - Block 7338110: a CREATE2 is attempted. The CREATE2 would deploy code on +// the same address e771789f5cccac282f23bb7add5690e1f6ca467c. However, the +// deployment fails due to OOG during initcode execution +// - Block 7338115: another tx checks the balance of +// e771789f5cccac282f23bb7add5690e1f6ca467c, and the snapshotter returned it as +// zero. // // The problem being that the snapshotter maintains a destructset, and adds items // to the destructset in case something is created "onto" an existing item. // We need to either roll back the snapDestructs, or not place it into snapDestructs // in the first place. -// func TestInitThenFailCreateContract(t *testing.T) { var ( engine = ethash.NewFaker() @@ -3459,13 +3460,13 @@ func TestEIP2718Transition(t *testing.T) { // TestEIP1559Transition tests the following: // -// 1. A transaction whose gasFeeCap is greater than the baseFee is valid. -// 2. Gas accounting for access lists on EIP-1559 transactions is correct. -// 3. Only the transaction's tip will be received by the coinbase. -// 4. The transaction sender pays for both the tip and baseFee. -// 5. The coinbase receives only the partially realized tip when -// gasFeeCap - gasTipCap < baseFee. -// 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap). +// 1. A transaction whose gasFeeCap is greater than the baseFee is valid. +// 2. Gas accounting for access lists on EIP-1559 transactions is correct. +// 3. Only the transaction's tip will be received by the coinbase. +// 4. The transaction sender pays for both the tip and baseFee. +// 5. The coinbase receives only the partially realized tip when +// gasFeeCap - gasTipCap < baseFee. +// 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap). func TestEIP1559Transition(t *testing.T) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") diff --git a/core/genesis.go b/core/genesis.go index 5b5b9c72a1e7..1c62bb1a137e 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -239,10 +239,10 @@ type ChainOverrides struct { // SetupGenesisBlock writes or updates the genesis block in db. // The block that will be used is: // -// genesis == nil genesis != nil -// +------------------------------------------ -// db has no genesis | main-net default | genesis -// db has genesis | from DB | genesis (if compatible) +// genesis == nil genesis != nil +// +------------------------------------------ +// db has no genesis | main-net default | genesis +// db has genesis | from DB | genesis (if compatible) // // The stored chain configuration will be updated if it is compatible (i.e. does not // specify a fork block below the local head block). In case of a conflict, the diff --git a/core/mkalloc.go b/core/mkalloc.go index df167d7082cd..e4c2ec0d83e9 100644 --- a/core/mkalloc.go +++ b/core/mkalloc.go @@ -18,12 +18,10 @@ // +build none /* +The mkalloc tool creates the genesis allocation constants in genesis_alloc.go +It outputs a const declaration that contains an RLP-encoded list of (address, balance) tuples. - The mkalloc tool creates the genesis allocation constants in genesis_alloc.go - It outputs a const declaration that contains an RLP-encoded list of (address, balance) tuples. - - go run mkalloc.go genesis.json - + go run mkalloc.go genesis.json */ package main diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 6dea98c3d3c4..53bd989a482d 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -57,10 +57,10 @@ const freezerTableSize = 2 * 1000 * 1000 * 1000 // Freezer is a memory mapped append-only database to store immutable ordered // data into flat files: // -// - The append-only nature ensures that disk writes are minimized. -// - The memory mapping ensures we can max out system memory for caching without -// reserving it for go-ethereum. This would also reduce the memory requirements -// of Geth, and thus also GC overhead. +// - The append-only nature ensures that disk writes are minimized. +// - The memory mapping ensures we can max out system memory for caching without +// reserving it for go-ethereum. This would also reduce the memory requirements +// of Geth, and thus also GC overhead. type Freezer struct { // WARNING: The `frozen` and `tail` fields are accessed atomically. On 32 bit platforms, only // 64-bit aligned fields can be atomic. The struct is guaranteed to be so aligned, @@ -188,9 +188,9 @@ func (f *Freezer) Ancient(kind string, number uint64) ([]byte, error) { // AncientRange retrieves multiple items in sequence, starting from the index 'start'. // It will return -// - at most 'max' items, -// - at least 1 item (even if exceeding the maxByteSize), but will otherwise -// return as many items as fit into maxByteSize. +// - at most 'max' items, +// - at least 1 item (even if exceeding the maxByteSize), but will otherwise +// return as many items as fit into maxByteSize. func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) { if table := f.tables[kind]; table != nil { return table.RetrieveItems(start, count, maxBytes) diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 2da2eda8b74d..87bc357a5c10 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -66,9 +66,9 @@ var ( // Pruner is an offline tool to prune the stale state with the // help of the snapshot. The workflow of pruner is very simple: // -// - iterate the snapshot, reconstruct the relevant state -// - iterate the database, delete all other state entries which -// don't belong to the target state and the genesis state +// - iterate the snapshot, reconstruct the relevant state +// - iterate the database, delete all other state entries which +// don't belong to the target state and the genesis state // // It can take several hours(around 2 hours for mainnet) to finish // the whole pruning work. It's recommended to run this offline tool diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 447ca80cae4b..58cfb464ff7b 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -220,10 +220,12 @@ func (t *testHelper) CommitAndGenerate() (common.Hash, *diskLayer) { // - miss in the beginning // - miss in the middle // - miss in the end +// // - the contract(non-empty storage) has wrong storage slots // - wrong slots in the beginning // - wrong slots in the middle // - wrong slots in the end +// // - the contract(non-empty storage) has extra storage slots // - extra slots in the beginning // - extra slots in the middle diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 76200851e469..a6c77fbb9860 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -179,10 +179,10 @@ type Tree struct { // If the memory layers in the journal do not match the disk layer (e.g. there is // a gap) or the journal is missing, there are two repair cases: // -// - if the 'recovery' parameter is true, all memory diff-layers will be discarded. -// This case happens when the snapshot is 'ahead' of the state trie. -// - otherwise, the entire snapshot is considered invalid and will be recreated on -// a background thread. +// - if the 'recovery' parameter is true, all memory diff-layers will be discarded. +// This case happens when the snapshot is 'ahead' of the state trie. +// - otherwise, the entire snapshot is considered invalid and will be recreated on +// a background thread. func New(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, root common.Hash, async bool, rebuild bool, recovery bool) (*Tree, error) { // Create a new, empty snapshot tree snap := &Tree{ diff --git a/core/state/statedb.go b/core/state/statedb.go index a649e0bd11d3..b05f1742f57c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -600,8 +600,8 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) // CreateAccount is called during the EVM CREATE operation. The situation might arise that // a contract does the following: // -// 1. sends funds to sha(account ++ (nonce + 1)) -// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1) +// 1. sends funds to sha(account ++ (nonce + 1)) +// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1) // // Carrying over the balance ensures that Ether doesn't disappear. func (s *StateDB) CreateAccount(addr common.Address) { diff --git a/core/state_transition.go b/core/state_transition.go index 0946c0372e2f..4048c02507a9 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -31,23 +31,26 @@ import ( var emptyCodeHash = crypto.Keccak256Hash(nil) -/* -The State Transitioning Model - -A state transition is a change made when a transaction is applied to the current world state -The state transitioning model does all the necessary work to work out a valid new state root. - -1) Nonce handling -2) Pre pay gas -3) Create a new state object if the recipient is \0*32 -4) Value transfer -== If contract creation == - 4a) Attempt to run transaction data - 4b) If valid, use result as code for the new state object -== end == -5) Run Script section -6) Derive new state root -*/ +// The State Transitioning Model +// +// A state transition is a change made when a transaction is applied to the current world +// state. The state transitioning model does all the necessary work to work out a valid new +// state root. +// +// 1. Nonce handling +// 2. Pre pay gas +// 3. Create a new state object if the recipient is \0*32 +// 4. Value transfer +// +// == If contract creation == +// +// 4a. Attempt to run transaction data +// 4b. If valid, use result as code for the new state object +// +// == end == +// +// 5. Run Script section +// 6. Derive new state root type StateTransition struct { gp *GasPool msg Message @@ -262,13 +265,10 @@ func (st *StateTransition) preCheck() error { // TransitionDb will transition the state by applying the current message and // returning the evm execution result with following fields. // -// - used gas: -// total gas used (including gas being refunded) -// - returndata: -// the returned data from evm -// - concrete execution error: -// various **EVM** error which aborts the execution, -// e.g. ErrOutOfGas, ErrExecutionReverted +// - used gas: total gas used (including gas being refunded) +// - returndata: the returned data from evm +// - concrete execution error: various EVM errors which abort the execution, e.g. +// ErrOutOfGas, ErrExecutionReverted // // However if any consensus issue encountered, return the error directly with // nil evm execution result. diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 1b832b638695..3a6b956ebc45 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -263,10 +263,10 @@ var ( // modexpMultComplexity implements bigModexp multComplexity formula, as defined in EIP-198 // -// def mult_complexity(x): -// if x <= 64: return x ** 2 -// elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072 -// else: return x ** 2 // 16 + 480 * x - 199680 +// def mult_complexity(x): +// if x <= 64: return x ** 2 +// elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072 +// else: return x ** 2 // 16 + 480 * x - 199680 // // where is x is max(length_of_MODULUS, length_of_BASE) func modexpMultComplexity(x *big.Int) *big.Int { diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 4c2cb3e5cf79..57fb1a8d98b2 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -117,20 +117,21 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi return params.SstoreResetGas, nil } } + // The new gas metering is based on net gas costs (EIP-1283): // - // 1. If current value equals new value (this is a no-op), 200 gas is deducted. - // 2. If current value does not equal new value - // 2.1. If original value equals current value (this storage slot has not been changed by the current execution context) - // 2.1.1. If original value is 0, 20000 gas is deducted. - // 2.1.2. Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter. - // 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses. - // 2.2.1. If original value is not 0 - // 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0. - // 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter. - // 2.2.2. If original value equals new value (this storage slot is reset) - // 2.2.2.1. If original value is 0, add 19800 gas to refund counter. - // 2.2.2.2. Otherwise, add 4800 gas to refund counter. + // (1.) If current value equals new value (this is a no-op), 200 gas is deducted. + // (2.) If current value does not equal new value + // (2.1.) If original value equals current value (this storage slot has not been changed by the current execution context) + // (2.1.1.) If original value is 0, 20000 gas is deducted. + // (2.1.2.) Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter. + // (2.2.) If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses. + // (2.2.1.) If original value is not 0 + // (2.2.1.1.) If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0. + // (2.2.1.2.) If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter. + // (2.2.2.) If original value equals new value (this storage slot is reset) + // (2.2.2.1.) If original value is 0, add 19800 gas to refund counter. + // (2.2.2.2.) Otherwise, add 4800 gas to refund counter. value := common.Hash(y.Bytes32()) if current == value { // noop (1) return params.NetSstoreNoopGas, nil @@ -162,19 +163,21 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi return params.NetSstoreDirtyGas, nil } -// 0. If *gasleft* is less than or equal to 2300, fail the current call. -// 1. If current value equals new value (this is a no-op), SLOAD_GAS is deducted. -// 2. If current value does not equal new value: -// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context): -// 2.1.1. If original value is 0, SSTORE_SET_GAS (20K) gas is deducted. -// 2.1.2. Otherwise, SSTORE_RESET_GAS gas is deducted. If new value is 0, add SSTORE_CLEARS_SCHEDULE to refund counter. -// 2.2. If original value does not equal current value (this storage slot is dirty), SLOAD_GAS gas is deducted. Apply both of the following clauses: -// 2.2.1. If original value is not 0: -// 2.2.1.1. If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEARS_SCHEDULE gas from refund counter. -// 2.2.1.2. If new value is 0 (also means that current value is not 0), add SSTORE_CLEARS_SCHEDULE gas to refund counter. -// 2.2.2. If original value equals new value (this storage slot is reset): -// 2.2.2.1. If original value is 0, add SSTORE_SET_GAS - SLOAD_GAS to refund counter. -// 2.2.2.2. Otherwise, add SSTORE_RESET_GAS - SLOAD_GAS gas to refund counter. +// Here come the EIP220 rules: +// +// (0.) If *gasleft* is less than or equal to 2300, fail the current call. +// (1.) If current value equals new value (this is a no-op), SLOAD_GAS is deducted. +// (2.) If current value does not equal new value: +// (2.1.) If original value equals current value (this storage slot has not been changed by the current execution context): +// (2.1.1.) If original value is 0, SSTORE_SET_GAS (20K) gas is deducted. +// (2.1.2.) Otherwise, SSTORE_RESET_GAS gas is deducted. If new value is 0, add SSTORE_CLEARS_SCHEDULE to refund counter. +// (2.2.) If original value does not equal current value (this storage slot is dirty), SLOAD_GAS gas is deducted. Apply both of the following clauses: +// (2.2.1.) If original value is not 0: +// (2.2.1.1.) If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEARS_SCHEDULE gas from refund counter. +// (2.2.1.2.) If new value is 0 (also means that current value is not 0), add SSTORE_CLEARS_SCHEDULE gas to refund counter. +// (2.2.2.) If original value equals new value (this storage slot is reset): +// (2.2.2.1.) If original value is 0, add SSTORE_SET_GAS - SLOAD_GAS to refund counter. +// (2.2.2.2.) Otherwise, add SSTORE_RESET_GAS - SLOAD_GAS gas to refund counter. func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { // If we fail the minimum gas availability invariant, fail (0) if contract.Gas <= params.SstoreSentryGasEIP2200 { diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 92be3bf259a3..104bf6d75ff0 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -392,29 +392,29 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // opExtCodeHash returns the code hash of a specified account. // There are several cases when the function is called, while we can relay everything // to `state.GetCodeHash` function to ensure the correctness. -// (1) Caller tries to get the code hash of a normal contract account, state -// should return the relative code hash and set it as the result. // -// (2) Caller tries to get the code hash of a non-existent account, state should -// return common.Hash{} and zero will be set as the result. +// 1. Caller tries to get the code hash of a normal contract account, state +// should return the relative code hash and set it as the result. // -// (3) Caller tries to get the code hash for an account without contract code, -// state should return emptyCodeHash(0xc5d246...) as the result. +// 2. Caller tries to get the code hash of a non-existent account, state should +// return common.Hash{} and zero will be set as the result. // -// (4) Caller tries to get the code hash of a precompiled account, the result -// should be zero or emptyCodeHash. +// 3. Caller tries to get the code hash for an account without contract code, state +// should return emptyCodeHash(0xc5d246...) as the result. // -// It is worth noting that in order to avoid unnecessary create and clean, -// all precompile accounts on mainnet have been transferred 1 wei, so the return -// here should be emptyCodeHash. -// If the precompile account is not transferred any amount on a private or +// 4. Caller tries to get the code hash of a precompiled account, the result should be +// zero or emptyCodeHash. +// +// It is worth noting that in order to avoid unnecessary create and clean, all precompile +// accounts on mainnet have been transferred 1 wei, so the return here should be +// emptyCodeHash. If the precompile account is not transferred any amount on a private or // customized chain, the return value will be zero. // -// (5) Caller tries to get the code hash for an account which is marked as suicided -// in the current transaction, the code hash of this account should be returned. +// 5. Caller tries to get the code hash for an account which is marked as suicided +// in the current transaction, the code hash of this account should be returned. // -// (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. +// 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) { slot := scope.Stack.peek() address := common.Address(slot.Bytes20()) diff --git a/crypto/crypto.go b/crypto/crypto.go index 45ea72747e6d..e51b63becac9 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -35,7 +35,7 @@ import ( "golang.org/x/crypto/sha3" ) -//SignatureLength indicates the byte length required to carry a signature with recovery id. +// SignatureLength indicates the byte length required to carry a signature with recovery id. const SignatureLength = 64 + 1 // 64 bytes ECDSA signature + 1 byte recovery id // RecoveryIDOffset points to the byte offset within the signature that contains the recovery id. diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go index fa1b199a3484..9b26ab292859 100644 --- a/crypto/secp256k1/curve.go +++ b/crypto/secp256k1/curve.go @@ -105,7 +105,6 @@ func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { return x3.Cmp(y2) == 0 } -//TODO: double check if the function is okay // affineFromJacobian reverses the Jacobian transform. See the comment at the // top of the file. func (BitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { diff --git a/crypto/secp256k1/libsecp256k1/contrib/dummy.go b/crypto/secp256k1/libsecp256k1/contrib/dummy.go index fda594be9914..2c946210c54d 100644 --- a/crypto/secp256k1/libsecp256k1/contrib/dummy.go +++ b/crypto/secp256k1/libsecp256k1/contrib/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/dummy.go b/crypto/secp256k1/libsecp256k1/dummy.go index 379b16992f47..04bbe3d76ecc 100644 --- a/crypto/secp256k1/libsecp256k1/dummy.go +++ b/crypto/secp256k1/libsecp256k1/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/include/dummy.go b/crypto/secp256k1/libsecp256k1/include/dummy.go index 5af540c73c4a..64c71b8451d8 100644 --- a/crypto/secp256k1/libsecp256k1/include/dummy.go +++ b/crypto/secp256k1/libsecp256k1/include/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/dummy.go b/crypto/secp256k1/libsecp256k1/src/dummy.go index 65868f38a8ea..2df270adc35e 100644 --- a/crypto/secp256k1/libsecp256k1/src/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/modules/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/dummy.go index 3c7a696439f0..99c538db51b0 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/modules/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go index b6fc38327ec8..48c2e0aa5453 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go index b9491f0cb9f4..8efbd7abe71b 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 5ab61524a7cd..754d8b214ca7 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -142,15 +142,19 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { } // ForkchoiceUpdatedV1 has several responsibilities: -// If the method is called with an empty head block: -// we return success, which can be used to check if the engine API is enabled -// If the total difficulty was not reached: -// we return INVALID -// If the finalizedBlockHash is set: -// we check if we have the finalizedBlockHash in our db, if not we start a sync -// We try to set our blockchain to the headBlock -// If there are payloadAttributes: -// we try to assemble a block with the payloadAttributes and return its payloadID +// +// We try to set our blockchain to the headBlock. +// +// If the method is called with an empty head block: we return success, which can be used +// to check if the engine API is enabled. +// +// If the total difficulty was not reached: we return INVALID. +// +// If the finalizedBlockHash is set: we check if we have the finalizedBlockHash in our db, +// if not we start a sync. +// +// If there are payloadAttributes: we try to assemble a block with the payloadAttributes +// and return its payloadID. func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributesV1) (beacon.ForkChoiceResponse, error) { api.forkchoiceLock.Lock() defer api.forkchoiceLock.Unlock() diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 7e8f322df53b..ae53462ff812 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -519,18 +519,18 @@ func TestExchangeTransitionConfig(t *testing.T) { TestNewPayloadOnInvalidChain sets up a valid chain and tries to feed blocks from an invalid chain to test if latestValidHash (LVH) works correctly. -We set up the following chain where P1 ... Pn and P1'' are valid while +We set up the following chain where P1 ... Pn and P1” are valid while P1' is invalid. We expect (1) The LVH to point to the current inserted payload if it was valid. (2) The LVH to point to the valid parent on an invalid payload (if the parent is available). (3) If the parent is unavailable, the LVH should not be set. -CommonAncestor◄─▲── P1 ◄── P2 ◄─ P3 ◄─ ... ◄─ Pn - │ - └── P1' ◄─ P2' ◄─ P3' ◄─ ... ◄─ Pn' - │ - └── P1'' + CommonAncestor◄─▲── P1 ◄── P2 ◄─ P3 ◄─ ... ◄─ Pn + │ + └── P1' ◄─ P2' ◄─ P3' ◄─ ... ◄─ Pn' + │ + └── P1'' */ func TestNewPayloadOnInvalidChain(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(10) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index c04352f0aac6..af28d9e82097 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -741,9 +741,11 @@ func (d *Downloader) fetchHead(p *peerConnection) (head *types.Header, pivot *ty // calculateRequestSpan calculates what headers to request from a peer when trying to determine the // common ancestor. // It returns parameters to be used for peer.RequestHeadersByNumber: -// from - starting block number -// count - number of headers to request -// skip - number of headers to skip +// +// from - starting block number +// count - number of headers to request +// skip - number of headers to skip +// // and also returns 'max', the last block which is expected to be returned by the remote peers, // given the (from,count,skip) func calculateRequestSpan(remoteHeight, localHeight uint64) (int64, int, int, uint64) { diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index a8d2ea83a9ee..26c41711ded5 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -480,9 +480,10 @@ func (q *queue) ReserveReceipts(p *peerConnection, count int) (*fetchRequest, bo // to access the queue, so they already need a lock anyway. // // Returns: -// item - the fetchRequest -// progress - whether any progress was made -// throttle - if the caller should throttle for a while +// +// item - the fetchRequest +// progress - whether any progress was made +// throttle - if the caller should throttle for a while func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque, pendPool map[string]*fetchRequest, kind uint) (*fetchRequest, bool, bool) { // Short circuit if the pool has been depleted, or if the peer's already diff --git a/eth/downloader/resultstore.go b/eth/downloader/resultstore.go index 3162cd6d5b42..2dcbbe16c916 100644 --- a/eth/downloader/resultstore.go +++ b/eth/downloader/resultstore.go @@ -71,10 +71,11 @@ func (r *resultStore) SetThrottleThreshold(threshold uint64) uint64 { // wants to reserve headers for fetching. // // It returns the following: -// stale - if true, this item is already passed, and should not be requested again -// throttled - if true, the store is at capacity, this particular header is not prio now -// item - the result to store data into -// err - any error that occurred +// +// stale - if true, this item is already passed, and should not be requested again +// throttled - if true, the store is at capacity, this particular header is not prio now +// item - the result to store data into +// err - any error that occurred func (r *resultStore) AddFetch(header *types.Header, fastSync bool) (stale, throttled bool, item *fetchResult, err error) { r.lock.Lock() defer r.lock.Unlock() diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 91835c164106..6028ef03cf15 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -208,10 +208,11 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNum // actually processed range is returned to avoid ambiguity when parts of the requested range // are not available or when the head has changed during processing this request. // Three arrays are returned based on the processed blocks: -// - reward: the requested percentiles of effective priority fees per gas of transactions in each -// block, sorted in ascending order and weighted by gas used. -// - baseFee: base fee per gas in the given block -// - gasUsedRatio: gasUsed/gasLimit in the given block +// - reward: the requested percentiles of effective priority fees per gas of transactions in each +// block, sorted in ascending order and weighted by gas used. +// - baseFee: base fee per gas in the given block +// - gasUsedRatio: gasUsed/gasLimit in the given block +// // Note: baseFee includes the next block after the newest of the returned range, because this // value can be derived from the newest block. func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 4d9f631b5aab..451245706564 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -368,8 +368,8 @@ func createStorageRequestResponse(t *testPeer, root common.Hash, accounts []comm return hashes, slots, proofs } -// the createStorageRequestResponseAlwaysProve tests a cornercase, where it always -// supplies the proof for the last account, even if it is 'complete'.h +// createStorageRequestResponseAlwaysProve tests a cornercase, where the peer always +// supplies the proof for the last account, even if it is 'complete'. func createStorageRequestResponseAlwaysProve(t *testPeer, root common.Hash, accounts []common.Hash, bOrigin, bLimit []byte, max uint64) (hashes [][]common.Hash, slots [][][]byte, proofs [][]byte) { var size uint64 max = max * 3 / 4 diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 4651ef3066f6..ca59024aed48 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -46,16 +46,16 @@ var noopReleaser = tracers.StateReleaseFunc(func() {}) // Its purpose is to prevent resource leaking. Though it can be noop in some cases. // // Parameters: -// - block: The block for which we want the state(state = block.Root) -// - reexec: The maximum number of blocks to reprocess trying to obtain the desired state -// - base: If the caller is tracing multiple blocks, the caller can provide the parent -// state continuously from the callsite. -// - readOnly: If true, then the live 'blockchain' state database is used. No mutation should -// be made from caller, e.g. perform Commit or other 'save-to-disk' changes. -// Otherwise, the trash generated by caller may be persisted permanently. -// - preferDisk: this arg can be used by the caller to signal that even though the 'base' is -// provided, it would be preferable to start from a fresh state, if we have it -// on disk. +// - block: The block for which we want the state(state = block.Root) +// - reexec: The maximum number of blocks to reprocess trying to obtain the desired state +// - base: If the caller is tracing multiple blocks, the caller can provide the parent +// state continuously from the callsite. +// - readOnly: If true, then the live 'blockchain' state database is used. No mutation should +// be made from caller, e.g. perform Commit or other 'save-to-disk' changes. +// Otherwise, the trash generated by caller may be persisted permanently. +// - preferDisk: this arg can be used by the caller to signal that even though the 'base' is +// provided, it would be preferable to start from a fresh state, if we have it +// on disk. func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) { var ( current *types.Block diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 34e608bfd60d..7fb1c5e6c612 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -37,14 +37,15 @@ func init() { // a reversed signature can be matched against the size of the data. // // Example: -// > debug.traceTransaction( "0x214e597e35da083692f5386141e69f47e973b2c56e7a8073b1ea08fd7571e9de", {tracer: "4byteTracer"}) -// { -// 0x27dc297e-128: 1, -// 0x38cc4831-0: 2, -// 0x524f3889-96: 1, -// 0xadf59f99-288: 1, -// 0xc281d19e-0: 1 -// } +// +// > debug.traceTransaction( "0x214e597e35da083692f5386141e69f47e973b2c56e7a8073b1ea08fd7571e9de", {tracer: "4byteTracer"}) +// { +// 0x27dc297e-128: 1, +// 0x38cc4831-0: 2, +// 0x524f3889-96: 1, +// 0xadf59f99-288: 1, +// 0xc281d19e-0: 1 +// } type fourByteTracer struct { env *vm.EVM ids map[string]int // ids aggregates the 4byte ids found diff --git a/eth/tracers/native/tracer.go b/eth/tracers/native/tracer.go index 9587caf19fd1..f70d4b2af1ae 100644 --- a/eth/tracers/native/tracer.go +++ b/eth/tracers/native/tracer.go @@ -14,24 +14,20 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -/* -Package native is a collection of tracers written in go. - -In order to add a native tracer and have it compiled into the binary, a new -file needs to be added to this folder, containing an implementation of the -`eth.tracers.Tracer` interface. - -Aside from implementing the tracer, it also needs to register itself, using the -`register` method -- and this needs to be done in the package initialization. - -Example: - -```golang -func init() { - register("noopTracerNative", newNoopTracer) -} -``` -*/ +// Package native is a collection of tracers written in go. +// +// In order to add a native tracer and have it compiled into the binary, a new +// file needs to be added to this folder, containing an implementation of the +// `eth.tracers.Tracer` interface. +// +// Aside from implementing the tracer, it also needs to register itself, using the +// `register` method -- and this needs to be done in the package initialization. +// +// Example: +// +// func init() { +// register("noopTracerNative", newNoopTracer) +// } package native import ( diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 15bd4e6eb3b5..0467531721c2 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -266,13 +266,14 @@ func (db *Database) Path() string { // the metrics subsystem. // // This is how a LevelDB stats table looks like (currently): -// Compactions -// Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB) -// -------+------------+---------------+---------------+---------------+--------------- -// 0 | 0 | 0.00000 | 1.27969 | 0.00000 | 12.31098 -// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294 -// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884 -// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000 +// +// Compactions +// Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB) +// -------+------------+---------------+---------------+---------------+--------------- +// 0 | 0 | 0.00000 | 1.27969 | 0.00000 | 12.31098 +// 1 | 85 | 109.27913 | 28.09293 | 213.92493 | 214.26294 +// 2 | 523 | 1000.37159 | 7.26059 | 66.86342 | 66.77884 +// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000 // // This is how the write delay look like (currently): // DelayN:5 Delay:406.604657ms Paused: false diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go index 5d60efab2ec1..f6ad360519c6 100644 --- a/ethstats/ethstats.go +++ b/ethstats/ethstats.go @@ -102,13 +102,17 @@ type Service struct { // websocket. // // From Gorilla websocket docs: -// Connections support one concurrent reader and one concurrent writer. -// Applications are responsible for ensuring that no more than one goroutine calls the write methods -// - NextWriter, SetWriteDeadline, WriteMessage, WriteJSON, EnableWriteCompression, SetCompressionLevel -// concurrently and that no more than one goroutine calls the read methods -// - NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler -// concurrently. -// The Close and WriteControl methods can be called concurrently with all other methods. +// +// Connections support one concurrent reader and one concurrent writer. Applications are +// responsible for ensuring that +// - no more than one goroutine calls the write methods +// NextWriter, SetWriteDeadline, WriteMessage, WriteJSON, EnableWriteCompression, +// SetCompressionLevel concurrently; and +// - that no more than one goroutine calls the +// read methods NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, +// SetPingHandler concurrently. +// +// The Close and WriteControl methods can be called concurrently with all other methods. type connWrapper struct { conn *websocket.Conn diff --git a/internal/cmdtest/test_cmd.go b/internal/cmdtest/test_cmd.go index b837c9c399ca..fd7a4a8b7f4c 100644 --- a/internal/cmdtest/test_cmd.go +++ b/internal/cmdtest/test_cmd.go @@ -83,7 +83,7 @@ func (tt *TestCmd) Run(name string, args ...string) { // InputLine writes the given text to the child's stdin. // This method can also be called from an expect template, e.g.: // -// geth.expect(`Passphrase: {{.InputLine "password"}}`) +// geth.expect(`Passphrase: {{.InputLine "password"}}`) func (tt *TestCmd) InputLine(s string) string { io.WriteString(tt.stdin, s+"\n") return "" diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 89c95c50744c..ac2fab4018d5 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -731,10 +731,10 @@ func (s *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) m } // GetBlockByNumber returns the requested canonical block. -// * When blockNr is -1 the chain head is returned. -// * When blockNr is -2 the pending chain head is returned. -// * When fullTx is true all transactions in the block are returned, otherwise -// only the transaction hash is returned. +// - When blockNr is -1 the chain head is returned. +// - When blockNr is -2 the pending chain head is returned. +// - When fullTx is true all transactions in the block are returned, otherwise +// only the transaction hash is returned. func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { block, err := s.b.BlockByNumber(ctx, number) if block != nil && err == nil { diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index 4bcdc816fe46..de1d29ffd4b9 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -54,11 +54,11 @@ var migrationApplied = map[*cli.Command]struct{}{} // // Example: // -// geth account new --keystore /tmp/mykeystore --lightkdf +// geth account new --keystore /tmp/mykeystore --lightkdf // // is equivalent after calling this method with: // -// geth --keystore /tmp/mykeystore --lightkdf account new +// geth --keystore /tmp/mykeystore --lightkdf account new // // i.e. in the subcommand Action function of 'account new', ctx.Bool("lightkdf) // will return true even if --lightkdf is set as a global option. diff --git a/les/api.go b/les/api.go index dc8639381777..76714baef086 100644 --- a/les/api.go +++ b/les/api.go @@ -366,10 +366,11 @@ func NewLightAPI(backend *lesCommons) *LightAPI { // LatestCheckpoint returns the latest local checkpoint package. // // The checkpoint package consists of 4 strings: -// result[0], hex encoded latest section index -// result[1], 32 bytes hex encoded latest section head hash -// result[2], 32 bytes hex encoded latest section canonical hash trie root hash -// result[3], 32 bytes hex encoded latest section bloom trie root hash +// +// result[0], hex encoded latest section index +// result[1], 32 bytes hex encoded latest section head hash +// result[2], 32 bytes hex encoded latest section canonical hash trie root hash +// result[3], 32 bytes hex encoded latest section bloom trie root hash func (api *LightAPI) LatestCheckpoint() ([4]string, error) { var res [4]string cp := api.backend.latestLocalCheckpoint() @@ -384,9 +385,10 @@ func (api *LightAPI) LatestCheckpoint() ([4]string, error) { // GetLocalCheckpoint returns the specific local checkpoint package. // // The checkpoint package consists of 3 strings: -// result[0], 32 bytes hex encoded latest section head hash -// result[1], 32 bytes hex encoded latest section canonical hash trie root hash -// result[2], 32 bytes hex encoded latest section bloom trie root hash +// +// result[0], 32 bytes hex encoded latest section head hash +// result[1], 32 bytes hex encoded latest section canonical hash trie root hash +// result[2], 32 bytes hex encoded latest section bloom trie root hash func (api *LightAPI) GetCheckpoint(index uint64) ([3]string, error) { var res [3]string cp := api.backend.localCheckpoint(index) diff --git a/les/catalyst/api.go b/les/catalyst/api.go index 983fc7bff0bc..abd1c9a901b3 100644 --- a/les/catalyst/api.go +++ b/les/catalyst/api.go @@ -56,15 +56,19 @@ func NewConsensusAPI(les *les.LightEthereum) *ConsensusAPI { } // ForkchoiceUpdatedV1 has several responsibilities: -// If the method is called with an empty head block: -// we return success, which can be used to check if the catalyst mode is enabled -// If the total difficulty was not reached: -// we return INVALID -// If the finalizedBlockHash is set: -// we check if we have the finalizedBlockHash in our db, if not we start a sync -// We try to set our blockchain to the headBlock -// If there are payloadAttributes: -// we return an error since block creation is not supported in les mode +// +// We try to set our blockchain to the headBlock. +// +// If the method is called with an empty head block: we return success, which can be used +// to check if the catalyst mode is enabled. +// +// If the total difficulty was not reached: we return INVALID. +// +// If the finalizedBlockHash is set: we check if we have the finalizedBlockHash in our db, +// if not we start a sync. +// +// If there are payloadAttributes: we return an error since block creation is not +// supported in les mode. func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributesV1) (beacon.ForkChoiceResponse, error) { if heads.HeadBlockHash == (common.Hash{}) { log.Warn("Forkchoice requested update to zero hash") diff --git a/les/downloader/downloader.go b/les/downloader/downloader.go index 6352b1c21729..740fdbdad1a3 100644 --- a/les/downloader/downloader.go +++ b/les/downloader/downloader.go @@ -693,9 +693,11 @@ func (d *Downloader) fetchHead(p *peerConnection) (head *types.Header, pivot *ty // calculateRequestSpan calculates what headers to request from a peer when trying to determine the // common ancestor. // It returns parameters to be used for peer.RequestHeadersByNumber: -// from - starting block number -// count - number of headers to request -// skip - number of headers to skip +// +// from - starting block number +// count - number of headers to request +// skip - number of headers to skip +// // and also returns 'max', the last block which is expected to be returned by the remote peers, // given the (from,count,skip) func calculateRequestSpan(remoteHeight, localHeight uint64) (int64, int, int, uint64) { @@ -1310,22 +1312,22 @@ func (d *Downloader) fetchReceipts(from uint64) error { // various callbacks to handle the slight differences between processing them. // // The instrumentation parameters: -// - errCancel: error type to return if the fetch operation is cancelled (mostly makes logging nicer) -// - deliveryCh: channel from which to retrieve downloaded data packets (merged from all concurrent peers) -// - deliver: processing callback to deliver data packets into type specific download queues (usually within `queue`) -// - wakeCh: notification channel for waking the fetcher when new tasks are available (or sync completed) -// - expire: task callback method to abort requests that took too long and return the faulty peers (traffic shaping) -// - pending: task callback for the number of requests still needing download (detect completion/non-completability) -// - inFlight: task callback for the number of in-progress requests (wait for all active downloads to finish) -// - throttle: task callback to check if the processing queue is full and activate throttling (bound memory use) -// - reserve: task callback to reserve new download tasks to a particular peer (also signals partial completions) -// - fetchHook: tester callback to notify of new tasks being initiated (allows testing the scheduling logic) -// - fetch: network callback to actually send a particular download request to a physical remote peer -// - cancel: task callback to abort an in-flight download request and allow rescheduling it (in case of lost peer) -// - capacity: network callback to retrieve the estimated type-specific bandwidth capacity of a peer (traffic shaping) -// - idle: network callback to retrieve the currently (type specific) idle peers that can be assigned tasks -// - setIdle: network callback to set a peer back to idle and update its estimated capacity (traffic shaping) -// - kind: textual label of the type being downloaded to display in log messages +// - errCancel: error type to return if the fetch operation is cancelled (mostly makes logging nicer) +// - deliveryCh: channel from which to retrieve downloaded data packets (merged from all concurrent peers) +// - deliver: processing callback to deliver data packets into type specific download queues (usually within `queue`) +// - wakeCh: notification channel for waking the fetcher when new tasks are available (or sync completed) +// - expire: task callback method to abort requests that took too long and return the faulty peers (traffic shaping) +// - pending: task callback for the number of requests still needing download (detect completion/non-completability) +// - inFlight: task callback for the number of in-progress requests (wait for all active downloads to finish) +// - throttle: task callback to check if the processing queue is full and activate throttling (bound memory use) +// - reserve: task callback to reserve new download tasks to a particular peer (also signals partial completions) +// - fetchHook: tester callback to notify of new tasks being initiated (allows testing the scheduling logic) +// - fetch: network callback to actually send a particular download request to a physical remote peer +// - cancel: task callback to abort an in-flight download request and allow rescheduling it (in case of lost peer) +// - capacity: network callback to retrieve the estimated type-specific bandwidth capacity of a peer (traffic shaping) +// - idle: network callback to retrieve the currently (type specific) idle peers that can be assigned tasks +// - setIdle: network callback to set a peer back to idle and update its estimated capacity (traffic shaping) +// - kind: textual label of the type being downloaded to display in log messages func (d *Downloader) fetchParts(deliveryCh chan dataPack, deliver func(dataPack) (int, error), wakeCh chan bool, expire func() map[string]int, pending func() int, inFlight func() bool, reserve func(*peerConnection, int) (*fetchRequest, bool, bool), fetchHook func([]*types.Header), fetch func(*peerConnection, *fetchRequest) error, cancel func(*fetchRequest), capacity func(*peerConnection) int, diff --git a/les/downloader/queue.go b/les/downloader/queue.go index b165b6b5c1c7..98ebff526e83 100644 --- a/les/downloader/queue.go +++ b/les/downloader/queue.go @@ -477,9 +477,10 @@ func (q *queue) ReserveReceipts(p *peerConnection, count int) (*fetchRequest, bo // to access the queue, so they already need a lock anyway. // // Returns: -// item - the fetchRequest -// progress - whether any progress was made -// throttle - if the caller should throttle for a while +// +// item - the fetchRequest +// progress - whether any progress was made +// throttle - if the caller should throttle for a while func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque, pendPool map[string]*fetchRequest, kind uint) (*fetchRequest, bool, bool) { // Short circuit if the pool has been depleted, or if the peer's already diff --git a/les/downloader/resultstore.go b/les/downloader/resultstore.go index 3162cd6d5b42..2dcbbe16c916 100644 --- a/les/downloader/resultstore.go +++ b/les/downloader/resultstore.go @@ -71,10 +71,11 @@ func (r *resultStore) SetThrottleThreshold(threshold uint64) uint64 { // wants to reserve headers for fetching. // // It returns the following: -// stale - if true, this item is already passed, and should not be requested again -// throttled - if true, the store is at capacity, this particular header is not prio now -// item - the result to store data into -// err - any error that occurred +// +// stale - if true, this item is already passed, and should not be requested again +// throttled - if true, the store is at capacity, this particular header is not prio now +// item - the result to store data into +// err - any error that occurred func (r *resultStore) AddFetch(header *types.Header, fastSync bool) (stale, throttled bool, item *fetchResult, err error) { r.lock.Lock() defer r.lock.Unlock() diff --git a/les/fetcher.go b/les/fetcher.go index 6861eebcf5e9..ef37d80cd6f4 100644 --- a/les/fetcher.go +++ b/les/fetcher.go @@ -242,18 +242,20 @@ func (f *lightFetcher) forEachPeer(check func(id enode.ID, p *fetcherPeer) bool) } // mainloop is the main event loop of the light fetcher, which is responsible for -// - announcement maintenance(ulc) -// If we are running in ultra light client mode, then all announcements from -// the trusted servers are maintained. If the same announcements from trusted -// servers reach the threshold, then the relevant header is requested for retrieval. // -// - block header retrieval -// Whenever we receive announce with higher td compared with local chain, the -// request will be made for header retrieval. +// - announcement maintenance(ulc) // -// - re-sync trigger -// If the local chain lags too much, then the fetcher will enter "synchronise" -// mode to retrieve missing headers in batch. +// If we are running in ultra light client mode, then all announcements from +// the trusted servers are maintained. If the same announcements from trusted +// servers reach the threshold, then the relevant header is requested for retrieval. +// +// - block header retrieval +// Whenever we receive announce with higher td compared with local chain, the +// request will be made for header retrieval. +// +// - re-sync trigger +// If the local chain lags too much, then the fetcher will enter "synchronise" +// mode to retrieve missing headers in batch. func (f *lightFetcher) mainloop() { defer f.wg.Done() diff --git a/light/txpool.go b/light/txpool.go index b3e1a62e1893..0f24fe1bc515 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -71,15 +71,16 @@ type TxPool struct { eip2718 bool // Fork indicator whether we are in the eip2718 stage. } -// TxRelayBackend provides an interface to the mechanism that forwards transactions -// to the ETH network. The implementations of the functions should be non-blocking. +// TxRelayBackend provides an interface to the mechanism that forwards transactions to the +// ETH network. The implementations of the functions should be non-blocking. // -// Send instructs backend to forward new transactions -// NewHead notifies backend about a new head after processed by the tx pool, -// including mined and rolled back transactions since the last event -// Discard notifies backend about transactions that should be discarded either -// because they have been replaced by a re-send or because they have been mined -// long ago and no rollback is expected +// Send instructs backend to forward new transactions NewHead notifies backend about a new +// head after processed by the tx pool, including mined and rolled back transactions since +// the last event. +// +// Discard notifies backend about transactions that should be discarded either because +// they have been replaced by a re-send or because they have been mined long ago and no +// rollback is expected. type TxRelayBackend interface { Send(txs types.Transactions) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) diff --git a/log/doc.go b/log/doc.go index 993743c0fd5c..d2e15140e4e0 100644 --- a/log/doc.go +++ b/log/doc.go @@ -7,27 +7,25 @@ This package enforces you to only log key/value pairs. Keys must be strings. Val any type that you like. The default output format is logfmt, but you may also choose to use JSON instead if that suits you. Here's how you log: - log.Info("page accessed", "path", r.URL.Path, "user_id", user.id) + log.Info("page accessed", "path", r.URL.Path, "user_id", user.id) This will output a line that looks like: - lvl=info t=2014-05-02T16:07:23-0700 msg="page accessed" path=/org/71/profile user_id=9 + lvl=info t=2014-05-02T16:07:23-0700 msg="page accessed" path=/org/71/profile user_id=9 -Getting Started +# Getting Started To get started, you'll want to import the library: - import log "github.com/inconshreveable/log15" - + import log "github.com/inconshreveable/log15" Now you're ready to start logging: - func main() { - log.Info("Program starting", "args", os.Args()) - } - + func main() { + log.Info("Program starting", "args", os.Args()) + } -Convention +# Convention Because recording a human-meaningful message is common and good practice, the first argument to every logging method is the value to the *implicit* key 'msg'. @@ -40,38 +38,35 @@ you to favor terseness, ordering, and speed over safety. This is a reasonable tr logging functions. You don't need to explicitly state keys/values, log15 understands that they alternate in the variadic argument list: - log.Warn("size out of bounds", "low", lowBound, "high", highBound, "val", val) + log.Warn("size out of bounds", "low", lowBound, "high", highBound, "val", val) If you really do favor your type-safety, you may choose to pass a log.Ctx instead: - log.Warn("size out of bounds", log.Ctx{"low": lowBound, "high": highBound, "val": val}) - + log.Warn("size out of bounds", log.Ctx{"low": lowBound, "high": highBound, "val": val}) -Context loggers +# Context loggers Frequently, you want to add context to a logger so that you can track actions associated with it. An http request is a good example. You can easily create new loggers that have context that is automatically included with each log line: - requestlogger := log.New("path", r.URL.Path) + requestlogger := log.New("path", r.URL.Path) - // later - requestlogger.Debug("db txn commit", "duration", txnTimer.Finish()) + // later + requestlogger.Debug("db txn commit", "duration", txnTimer.Finish()) This will output a log line that includes the path context that is attached to the logger: - lvl=dbug t=2014-05-02T16:07:23-0700 path=/repo/12/add_hook msg="db txn commit" duration=0.12 + lvl=dbug t=2014-05-02T16:07:23-0700 path=/repo/12/add_hook msg="db txn commit" duration=0.12 - -Handlers +# Handlers The Handler interface defines where log lines are printed to and how they are formatted. Handler is a single interface that is inspired by net/http's handler interface: - type Handler interface { - Log(r *Record) error - } - + type Handler interface { + Log(r *Record) error + } Handlers can filter records, format them, or dispatch to multiple other Handlers. This package implements a number of Handlers for common logging patterns that are @@ -79,49 +74,49 @@ easily composed to create flexible, custom logging structures. Here's an example handler that prints logfmt output to Stdout: - handler := log.StreamHandler(os.Stdout, log.LogfmtFormat()) + handler := log.StreamHandler(os.Stdout, log.LogfmtFormat()) Here's an example handler that defers to two other handlers. One handler only prints records from the rpc package in logfmt to standard out. The other prints records at Error level or above in JSON formatted output to the file /var/log/service.json - handler := log.MultiHandler( - log.LvlFilterHandler(log.LvlError, log.Must.FileHandler("/var/log/service.json", log.JSONFormat())), - log.MatchFilterHandler("pkg", "app/rpc" log.StdoutHandler()) - ) + handler := log.MultiHandler( + log.LvlFilterHandler(log.LvlError, log.Must.FileHandler("/var/log/service.json", log.JSONFormat())), + log.MatchFilterHandler("pkg", "app/rpc" log.StdoutHandler()) + ) -Logging File Names and Line Numbers +# Logging File Names and Line Numbers This package implements three Handlers that add debugging information to the context, CallerFileHandler, CallerFuncHandler and CallerStackHandler. Here's an example that adds the source file and line number of each logging call to the context. - h := log.CallerFileHandler(log.StdoutHandler) - log.Root().SetHandler(h) - ... - log.Error("open file", "err", err) + h := log.CallerFileHandler(log.StdoutHandler) + log.Root().SetHandler(h) + ... + log.Error("open file", "err", err) This will output a line that looks like: - lvl=eror t=2014-05-02T16:07:23-0700 msg="open file" err="file not found" caller=data.go:42 + lvl=eror t=2014-05-02T16:07:23-0700 msg="open file" err="file not found" caller=data.go:42 Here's an example that logs the call stack rather than just the call site. - h := log.CallerStackHandler("%+v", log.StdoutHandler) - log.Root().SetHandler(h) - ... - log.Error("open file", "err", err) + h := log.CallerStackHandler("%+v", log.StdoutHandler) + log.Root().SetHandler(h) + ... + log.Error("open file", "err", err) This will output a line that looks like: - lvl=eror t=2014-05-02T16:07:23-0700 msg="open file" err="file not found" stack="[pkg/data.go:42 pkg/cmd/main.go]" + lvl=eror t=2014-05-02T16:07:23-0700 msg="open file" err="file not found" stack="[pkg/data.go:42 pkg/cmd/main.go]" The "%+v" format instructs the handler to include the path of the source file relative to the compile time GOPATH. The github.com/go-stack/stack package documents the full list of formatting verbs and modifiers available. -Custom Handlers +# Custom Handlers The Handler interface is so simple that it's also trivial to write your own. Let's create an example handler which tries to write to one handler, but if that fails it falls back to @@ -129,24 +124,24 @@ writing to another handler and includes the error that it encountered when tryin to the primary. This might be useful when trying to log over a network socket, but if that fails you want to log those records to a file on disk. - type BackupHandler struct { - Primary Handler - Secondary Handler - } + type BackupHandler struct { + Primary Handler + Secondary Handler + } - func (h *BackupHandler) Log (r *Record) error { - err := h.Primary.Log(r) - if err != nil { - r.Ctx = append(ctx, "primary_err", err) - return h.Secondary.Log(r) - } - return nil - } + func (h *BackupHandler) Log (r *Record) error { + err := h.Primary.Log(r) + if err != nil { + r.Ctx = append(ctx, "primary_err", err) + return h.Secondary.Log(r) + } + return nil + } This pattern is so useful that a generic version that handles an arbitrary number of Handlers is included as part of this library called FailoverHandler. -Logging Expensive Operations +# Logging Expensive Operations Sometimes, you want to log values that are extremely expensive to compute, but you don't want to pay the price of computing them if you haven't turned up your logging level to a high level of detail. @@ -155,50 +150,50 @@ This package provides a simple type to annotate a logging operation that you wan lazily, just when it is about to be logged, so that it would not be evaluated if an upstream Handler filters it out. Just wrap any function which takes no arguments with the log.Lazy type. For example: - func factorRSAKey() (factors []int) { - // return the factors of a very large number - } + func factorRSAKey() (factors []int) { + // return the factors of a very large number + } - log.Debug("factors", log.Lazy{factorRSAKey}) + log.Debug("factors", log.Lazy{factorRSAKey}) If this message is not logged for any reason (like logging at the Error level), then factorRSAKey is never evaluated. -Dynamic context values +# Dynamic context values The same log.Lazy mechanism can be used to attach context to a logger which you want to be evaluated when the message is logged, but not when the logger is created. For example, let's imagine a game where you have Player objects: - type Player struct { - name string - alive bool - log.Logger - } + type Player struct { + name string + alive bool + log.Logger + } You always want to log a player's name and whether they're alive or dead, so when you create the player object, you might do: - p := &Player{name: name, alive: true} - p.Logger = log.New("name", p.name, "alive", p.alive) + p := &Player{name: name, alive: true} + p.Logger = log.New("name", p.name, "alive", p.alive) Only now, even after a player has died, the logger will still report they are alive because the logging context is evaluated when the logger was created. By using the Lazy wrapper, we can defer the evaluation of whether the player is alive or not to each log message, so that the log records will reflect the player's current state no matter when the log message is written: - p := &Player{name: name, alive: true} - isAlive := func() bool { return p.alive } - player.Logger = log.New("name", p.name, "alive", log.Lazy{isAlive}) + p := &Player{name: name, alive: true} + isAlive := func() bool { return p.alive } + player.Logger = log.New("name", p.name, "alive", log.Lazy{isAlive}) -Terminal Format +# Terminal Format If log15 detects that stdout is a terminal, it will configure the default handler for it (which is log.StdoutHandler) to use TerminalFormat. This format logs records nicely for your terminal, including color-coded output based on log level. -Error Handling +# Error Handling Becasuse log15 allows you to step around the type system, there are a few ways you can specify invalid arguments to the logging functions. You could, for example, wrap something that is not @@ -216,61 +211,61 @@ are encouraged to return errors only if they fail to write their log records out syslog daemon is not responding. This allows the construction of useful handlers which cope with those failures like the FailoverHandler. -Library Use +# Library Use log15 is intended to be useful for library authors as a way to provide configurable logging to users of their library. Best practice for use in a library is to always disable all output for your logger by default and to provide a public Logger instance that consumers of your library can configure. Like so: - package yourlib + package yourlib - import "github.com/inconshreveable/log15" + import "github.com/inconshreveable/log15" - var Log = log.New() + var Log = log.New() - func init() { - Log.SetHandler(log.DiscardHandler()) - } + func init() { + Log.SetHandler(log.DiscardHandler()) + } Users of your library may then enable it if they like: - import "github.com/inconshreveable/log15" - import "example.com/yourlib" + import "github.com/inconshreveable/log15" + import "example.com/yourlib" - func main() { - handler := // custom handler setup - yourlib.Log.SetHandler(handler) - } + func main() { + handler := // custom handler setup + yourlib.Log.SetHandler(handler) + } -Best practices attaching logger context +# Best practices attaching logger context The ability to attach context to a logger is a powerful one. Where should you do it and why? I favor embedding a Logger directly into any persistent object in my application and adding unique, tracing context keys to it. For instance, imagine I am writing a web browser: - type Tab struct { - url string - render *RenderingContext - // ... + type Tab struct { + url string + render *RenderingContext + // ... - Logger - } + Logger + } - func NewTab(url string) *Tab { - return &Tab { - // ... - url: url, + func NewTab(url string) *Tab { + return &Tab { + // ... + url: url, - Logger: log.New("url", url), - } - } + Logger: log.New("url", url), + } + } When a new tab is created, I assign a logger to it with the url of the tab as context so it can easily be traced through the logs. Now, whenever we perform any operation with the tab, we'll log with its embedded logger and it will include the tab title automatically: - tab.Debug("moved position", "idx", tab.idx) + tab.Debug("moved position", "idx", tab.idx) There's only one problem. What if the tab url changes? We could use log.Lazy to make sure the current url is always written, but that @@ -285,29 +280,29 @@ function to let you generate what you might call "surrogate keys" They're just random hex identifiers to use for tracing. Back to our Tab example, we would prefer to set up our Logger like so: - import logext "github.com/inconshreveable/log15/ext" + import logext "github.com/inconshreveable/log15/ext" - t := &Tab { - // ... - url: url, - } + t := &Tab { + // ... + url: url, + } - t.Logger = log.New("id", logext.RandId(8), "url", log.Lazy{t.getUrl}) - return t + t.Logger = log.New("id", logext.RandId(8), "url", log.Lazy{t.getUrl}) + return t Now we'll have a unique traceable identifier even across loading new urls, but we'll still be able to see the tab's current url in the log messages. -Must +# Must For all Handler functions which can return an error, there is a version of that function which will return no error but panics on failure. They are all available on the Must object. For example: - log.Must.FileHandler("/path", log.JSONFormat) - log.Must.NetHandler("tcp", ":1234", log.JSONFormat) + log.Must.FileHandler("/path", log.JSONFormat) + log.Must.NetHandler("tcp", ":1234", log.JSONFormat) -Inspiration and Credit +# Inspiration and Credit All of the following excellent projects inspired the design of this library: @@ -325,9 +320,8 @@ github.com/spacemonkeygo/spacelog golang's stdlib, notably io and net/http -The Name +# The Name https://xkcd.com/927/ - */ package log diff --git a/log/format.go b/log/format.go index baf8fddac0f6..613dc33be769 100644 --- a/log/format.go +++ b/log/format.go @@ -79,12 +79,11 @@ type TerminalStringer interface { // a terminal with color-coded level output and terser human friendly timestamp. // This format should only be used for interactive programs or while developing. // -// [LEVEL] [TIME] MESSAGE key=value key=value ... +// [LEVEL] [TIME] MESSAGE key=value key=value ... // // Example: // -// [DBUG] [May 16 20:58:45] remove route ns=haproxy addr=127.0.0.1:50002 -// +// [DBUG] [May 16 20:58:45] remove route ns=haproxy addr=127.0.0.1:50002 func TerminalFormat(usecolor bool) Format { return FormatFunc(func(r *Record) []byte { var color = 0 @@ -149,7 +148,6 @@ func TerminalFormat(usecolor bool) Format { // format for key/value pairs. // // For more details see: http://godoc.org/github.com/kr/logfmt -// func LogfmtFormat() Format { return FormatFunc(func(r *Record) []byte { common := []interface{}{r.KeyNames.Time, r.Time, r.KeyNames.Lvl, r.Lvl, r.KeyNames.Msg, r.Msg} diff --git a/log/handler.go b/log/handler.go index 4b9515fa15de..892cfcc3e1ac 100644 --- a/log/handler.go +++ b/log/handler.go @@ -136,15 +136,14 @@ func CallerStackHandler(format string, h Handler) Handler { // wrapped Handler if the given function evaluates true. For example, // to only log records where the 'err' key is not nil: // -// logger.SetHandler(FilterHandler(func(r *Record) bool { -// for i := 0; i < len(r.Ctx); i += 2 { -// if r.Ctx[i] == "err" { -// return r.Ctx[i+1] != nil -// } -// } -// return false -// }, h)) -// +// logger.SetHandler(FilterHandler(func(r *Record) bool { +// for i := 0; i < len(r.Ctx); i += 2 { +// if r.Ctx[i] == "err" { +// return r.Ctx[i+1] != nil +// } +// } +// return false +// }, h)) func FilterHandler(fn func(r *Record) bool, h Handler) Handler { return FuncHandler(func(r *Record) error { if fn(r) { @@ -159,8 +158,7 @@ func FilterHandler(fn func(r *Record) bool, h Handler) Handler { // context matches the value. For example, to only log records // from your ui package: // -// log.MatchFilterHandler("pkg", "app/ui", log.StdoutHandler) -// +// log.MatchFilterHandler("pkg", "app/ui", log.StdoutHandler) func MatchFilterHandler(key string, value interface{}, h Handler) Handler { return FilterHandler(func(r *Record) (pass bool) { switch key { @@ -186,8 +184,7 @@ func MatchFilterHandler(key string, value interface{}, h Handler) Handler { // level to the wrapped Handler. For example, to only // log Error/Crit records: // -// log.LvlFilterHandler(log.LvlError, log.StdoutHandler) -// +// log.LvlFilterHandler(log.LvlError, log.StdoutHandler) func LvlFilterHandler(maxLvl Lvl, h Handler) Handler { return FilterHandler(func(r *Record) (pass bool) { return r.Lvl <= maxLvl @@ -199,10 +196,9 @@ func LvlFilterHandler(maxLvl Lvl, h Handler) Handler { // to different locations. For example, to log to a file and // standard error: // -// log.MultiHandler( -// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()), -// log.StderrHandler) -// +// log.MultiHandler( +// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()), +// log.StderrHandler) func MultiHandler(hs ...Handler) Handler { return FuncHandler(func(r *Record) error { for _, h := range hs { @@ -220,10 +216,10 @@ func MultiHandler(hs ...Handler) Handler { // to writing to a file if the network fails, and then to // standard out if the file write fails: // -// log.FailoverHandler( -// log.Must.NetHandler("tcp", ":9090", log.JSONFormat()), -// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()), -// log.StdoutHandler) +// log.FailoverHandler( +// log.Must.NetHandler("tcp", ":9090", log.JSONFormat()), +// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()), +// log.StdoutHandler) // // All writes that do not go to the first handler will add context with keys of // the form "failover_err_{idx}" which explain the error encountered while diff --git a/log/handler_glog.go b/log/handler_glog.go index 9b1d4efaf46e..b5186d4b27ec 100644 --- a/log/handler_glog.go +++ b/log/handler_glog.go @@ -82,14 +82,14 @@ func (h *GlogHandler) Verbosity(level Lvl) { // // For instance: // -// pattern="gopher.go=3" -// sets the V level to 3 in all Go files named "gopher.go" +// pattern="gopher.go=3" +// sets the V level to 3 in all Go files named "gopher.go" // -// pattern="foo=3" -// sets V to 3 in all files of any packages whose import path ends in "foo" +// pattern="foo=3" +// sets V to 3 in all files of any packages whose import path ends in "foo" // -// pattern="foo/*=3" -// sets V to 3 in all files of any packages whose import path contains "foo" +// pattern="foo/*=3" +// sets V to 3 in all files of any packages whose import path contains "foo" func (h *GlogHandler) Vmodule(ruleset string) error { var filter []pattern for _, rule := range strings.Split(ruleset, ",") { diff --git a/metrics/influxdb/influxdbv2.go b/metrics/influxdb/influxdbv2.go index c8eca4161614..dc4c04fae16c 100644 --- a/metrics/influxdb/influxdbv2.go +++ b/metrics/influxdb/influxdbv2.go @@ -1,11 +1,3 @@ -// -// 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 influxdb import ( diff --git a/mobile/big.go b/mobile/big.go index c08bcf93f285..af5f9d89168a 100644 --- a/mobile/big.go +++ b/mobile/big.go @@ -77,7 +77,6 @@ func (bi *BigInt) SetInt64(x int64) { // -1 if x < 0 // 0 if x == 0 // +1 if x > 0 -// func (bi *BigInt) Sign() int { return bi.bigint.Sign() } diff --git a/mobile/discover.go b/mobile/discover.go index 2c699f08be04..0fbc86de261a 100644 --- a/mobile/discover.go +++ b/mobile/discover.go @@ -38,8 +38,8 @@ type Enode struct { // // For incomplete nodes, the designator must look like one of these // -// enode:// -// +// enode:// +// // // For complete nodes, the node ID is encoded in the username portion // of the URL, separated from the host by an @ sign. The hostname can @@ -52,7 +52,7 @@ type Enode struct { // a node with IP address 10.3.58.6, TCP listening port 30303 // and UDP discovery port 30301. // -// enode://@10.3.58.6:30303?discport=30301 +// enode://@10.3.58.6:30303?discport=30301 func NewEnode(rawurl string) (*Enode, error) { node, err := enode.Parse(enode.ValidSchemes, rawurl) if err != nil { diff --git a/mobile/doc.go b/mobile/doc.go index 20131afc2ee0..a4d4949ee923 100644 --- a/mobile/doc.go +++ b/mobile/doc.go @@ -20,7 +20,7 @@ // with pieces plucked from go-ethereum, rather to allow writing native dapps on // mobile platforms. Keep this in mind when using or extending this package! // -// API limitations +// # API limitations // // Since gomobile cannot bridge arbitrary types between Go and Android/iOS, the // exposed APIs need to be manually wrapped into simplified types, with custom diff --git a/node/doc.go b/node/doc.go index b257f412fed1..4474e43660d9 100644 --- a/node/doc.go +++ b/node/doc.go @@ -21,25 +21,22 @@ In the model exposed by this package, a node is a collection of services which u resources to provide RPC APIs. Services can also offer devp2p protocols, which are wired up to the devp2p network when the node instance is started. - -Node Lifecycle +# Node Lifecycle The Node object has a lifecycle consisting of three basic states, INITIALIZING, RUNNING and CLOSED. - - ●───────┐ - New() - │ - ▼ - INITIALIZING ────Start()─┐ - │ │ - │ ▼ - Close() RUNNING - │ │ - ▼ │ - CLOSED ◀──────Close()─┘ - + ●───────┐ + New() + │ + ▼ + INITIALIZING ────Start()─┐ + │ │ + │ ▼ + Close() RUNNING + │ │ + ▼ │ + CLOSED ◀──────Close()─┘ Creating a Node allocates basic resources such as the data directory and returns the node in its INITIALIZING state. Lifecycle objects, RPC APIs and peer-to-peer networking @@ -58,8 +55,7 @@ objects and shuts down RPC and peer-to-peer networking. You must always call Close on Node, even if the node was not started. - -Resources Managed By Node +# Resources Managed By Node All file-system resources used by a node instance are located in a directory called the data directory. The location of each resource can be overridden through additional node @@ -83,8 +79,7 @@ without a data directory, databases are opened in memory instead. Node also creates the shared store of encrypted Ethereum account keys. Services can access the account manager through the service context. - -Sharing Data Directory Among Instances +# Sharing Data Directory Among Instances Multiple node instances can share a single data directory if they have distinct instance names (set through the Name config option). Sharing behaviour depends on the type of @@ -102,26 +97,25 @@ create one database for each instance. The account key store is shared among all node instances using the same data directory unless its location is changed through the KeyStoreDir configuration option. - -Data Directory Sharing Example +# Data Directory Sharing Example In this example, two node instances named A and B are started with the same data directory. Node instance A opens the database "db", node instance B opens the databases "db" and "db-2". The following files will be created in the data directory: - data-directory/ - A/ - nodekey -- devp2p node key of instance A - nodes/ -- devp2p discovery knowledge database of instance A - db/ -- LevelDB content for "db" - A.ipc -- JSON-RPC UNIX domain socket endpoint of instance A - B/ - nodekey -- devp2p node key of node B - nodes/ -- devp2p discovery knowledge database of instance B - static-nodes.json -- devp2p static node list of instance B - db/ -- LevelDB content for "db" - db-2/ -- LevelDB content for "db-2" - B.ipc -- JSON-RPC UNIX domain socket endpoint of instance B - keystore/ -- account key store, used by both instances + data-directory/ + A/ + nodekey -- devp2p node key of instance A + nodes/ -- devp2p discovery knowledge database of instance A + db/ -- LevelDB content for "db" + A.ipc -- JSON-RPC UNIX domain socket endpoint of instance A + B/ + nodekey -- devp2p node key of node B + nodes/ -- devp2p discovery knowledge database of instance B + static-nodes.json -- devp2p static node list of instance B + db/ -- LevelDB content for "db" + db-2/ -- LevelDB content for "db-2" + B.ipc -- JSON-RPC UNIX domain socket endpoint of instance B + keystore/ -- account key store, used by both instances */ package node diff --git a/node/node_example_test.go b/node/node_example_test.go index d54fe03067df..e45ee49a25a0 100644 --- a/node/node_example_test.go +++ b/node/node_example_test.go @@ -27,8 +27,8 @@ import ( // life cycle management. // // The following methods are needed to implement a node.Lifecycle: -// - Start() error - method invoked when the node is ready to start the service -// - Stop() error - method invoked when the node terminates the service +// - Start() error - method invoked when the node is ready to start the service +// - Stop() error - method invoked when the node terminates the service type SampleLifecycle struct{} func (s *SampleLifecycle) Start() error { fmt.Println("Service starting..."); return nil } diff --git a/p2p/dial.go b/p2p/dial.go index 0d70e6f4a33b..02878fae4d31 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -84,13 +84,12 @@ var ( // dialer creates outbound connections and submits them into Server. // Two types of peer connections can be created: // -// - static dials are pre-configured connections. The dialer attempts -// keep these nodes connected at all times. -// -// - dynamic dials are created from node discovery results. The dialer -// continuously reads candidate nodes from its input iterator and attempts -// to create peer connections to nodes arriving through the iterator. +// - static dials are pre-configured connections. The dialer attempts +// keep these nodes connected at all times. // +// - dynamic dials are created from node discovery results. The dialer +// continuously reads candidate nodes from its input iterator and attempts +// to create peer connections to nodes arriving through the iterator. type dialScheduler struct { dialConfig setupFunc dialSetupFunc diff --git a/p2p/discover/v5wire/encoding_test.go b/p2p/discover/v5wire/encoding_test.go index 18aa1db1a41b..14c9da8c53a6 100644 --- a/p2p/discover/v5wire/encoding_test.go +++ b/p2p/discover/v5wire/encoding_test.go @@ -38,8 +38,7 @@ import ( // To regenerate discv5 test vectors, run // -// go test -run TestVectors -write-test-vectors -// +// go test -run TestVectors -write-test-vectors var writeTestVectorsFlag = flag.Bool("write-test-vectors", false, "Overwrite discv5 test vectors in testdata/") var ( diff --git a/p2p/dnsdisc/tree.go b/p2p/dnsdisc/tree.go index 7d11e07ef742..a3f426e42806 100644 --- a/p2p/dnsdisc/tree.go +++ b/p2p/dnsdisc/tree.go @@ -117,32 +117,32 @@ func (t *Tree) Nodes() []*enode.Node { We want to keep the UDP size below 512 bytes. The UDP size is roughly: UDP length = 8 + UDP payload length ( 229 ) UPD Payload length: - - dns.id 2 - - dns.flags 2 - - dns.count.queries 2 - - dns.count.answers 2 - - dns.count.auth_rr 2 - - dns.count.add_rr 2 - - queries (query-size + 6) - - answers : - - dns.resp.name 2 - - dns.resp.type 2 - - dns.resp.class 2 - - dns.resp.ttl 4 - - dns.resp.len 2 - - dns.txt.length 1 - - dns.txt resp_data_size - -So the total size is roughly a fixed overhead of `39`, and the size of the -query (domain name) and response. -The query size is, for example, FVY6INQ6LZ33WLCHO3BPR3FH6Y.snap.mainnet.ethdisco.net (52) + - dns.id 2 + - dns.flags 2 + - dns.count.queries 2 + - dns.count.answers 2 + - dns.count.auth_rr 2 + - dns.count.add_rr 2 + - queries (query-size + 6) + - answers : + - dns.resp.name 2 + - dns.resp.type 2 + - dns.resp.class 2 + - dns.resp.ttl 4 + - dns.resp.len 2 + - dns.txt.length 1 + - dns.txt resp_data_size + +So the total size is roughly a fixed overhead of `39`, and the size of the query (domain +name) and response. The query size is, for example, +FVY6INQ6LZ33WLCHO3BPR3FH6Y.snap.mainnet.ethdisco.net (52) We also have some static data in the response, such as `enrtree-branch:`, and potentially splitting the response up with `" "`, leaving us with a size of roughly `400` that we need to stay below. -The number `370` is used to have some margin for extra overhead (for example, the dns query -may be larger - more subdomains). +The number `370` is used to have some margin for extra overhead (for example, the dns +query may be larger - more subdomains). */ const ( hashAbbrevSize = 1 + 16*13/8 // Size of an encoded hash (plus comma) diff --git a/p2p/enode/urlv4.go b/p2p/enode/urlv4.go index c445049102a7..0272eee98725 100644 --- a/p2p/enode/urlv4.go +++ b/p2p/enode/urlv4.go @@ -54,8 +54,8 @@ func MustParseV4(rawurl string) *Node { // // For incomplete nodes, the designator must look like one of these // -// enode:// -// +// enode:// +// // // For complete nodes, the node ID is encoded in the username portion // of the URL, separated from the host by an @ sign. The hostname can @@ -68,7 +68,7 @@ func MustParseV4(rawurl string) *Node { // a node with IP address 10.3.58.6, TCP listening port 30303 // and UDP discovery port 30301. // -// enode://@10.3.58.6:30303?discport=30301 +// enode://@10.3.58.6:30303?discport=30301 func ParseV4(rawurl string) (*Node, error) { if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil { id, err := parsePubkey(m[1]) diff --git a/p2p/enr/enr.go b/p2p/enr/enr.go index 15891813b41a..438c7b8a3b36 100644 --- a/p2p/enr/enr.go +++ b/p2p/enr/enr.go @@ -19,7 +19,7 @@ // stored in key/value pairs. To store and retrieve key/values in a record, use the Entry // interface. // -// Signature Handling +// # Signature Handling // // Records must be signed before transmitting them to another node. // diff --git a/p2p/message.go b/p2p/message.go index 7cbe0f1dc83e..24f21456d8e5 100644 --- a/p2p/message.go +++ b/p2p/message.go @@ -107,12 +107,11 @@ func Send(w MsgWriter, msgcode uint64, data interface{}) error { // SendItems writes an RLP with the given code and data elements. // For a call such as: // -// SendItems(w, code, e1, e2, e3) +// SendItems(w, code, e1, e2, e3) // // the message payload will be an RLP list containing the items: // -// [e1, e2, e3] -// +// [e1, e2, e3] func SendItems(w MsgWriter, msgcode uint64, elems ...interface{}) error { return Send(w, msgcode, elems) } diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go index 9d5519b9c4d5..b7c840bc5aee 100644 --- a/p2p/nat/nat.go +++ b/p2p/nat/nat.go @@ -53,12 +53,12 @@ type Interface interface { // The following formats are currently accepted. // Note that mechanism names are not case-sensitive. // -// "" or "none" return nil -// "extip:77.12.33.4" will assume the local machine is reachable on the given IP -// "any" uses the first auto-detected mechanism -// "upnp" uses the Universal Plug and Play protocol -// "pmp" uses NAT-PMP with an auto-detected gateway address -// "pmp:192.168.0.1" uses NAT-PMP with the given gateway address +// "" or "none" return nil +// "extip:77.12.33.4" will assume the local machine is reachable on the given IP +// "any" uses the first auto-detected mechanism +// "upnp" uses the Universal Plug and Play protocol +// "pmp" uses NAT-PMP with an auto-detected gateway address +// "pmp:192.168.0.1" uses NAT-PMP with the given gateway address func Parse(spec string) (Interface, error) { var ( parts = strings.SplitN(spec, ":", 2) diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go index aeb8ef77726b..3b4e05a90147 100644 --- a/p2p/simulations/adapters/types.go +++ b/p2p/simulations/adapters/types.go @@ -39,10 +39,9 @@ import ( // Node represents a node in a simulation network which is created by a // NodeAdapter, for example: // -// * SimNode - An in-memory node -// * ExecNode - A child process node -// * DockerNode - A Docker container node -// +// - SimNode, an in-memory node in the same process +// - ExecNode, a child process node +// - DockerNode, a node running in a Docker container type Node interface { // Addr returns the node's address (e.g. an Enode URL) Addr() []byte diff --git a/p2p/simulations/mocker.go b/p2p/simulations/mocker.go index 5a74b02c4347..47193d83ccb8 100644 --- a/p2p/simulations/mocker.go +++ b/p2p/simulations/mocker.go @@ -29,20 +29,20 @@ import ( "github.com/ethereum/go-ethereum/p2p/simulations/adapters" ) -//a map of mocker names to its function +// a map of mocker names to its function var mockerList = map[string]func(net *Network, quit chan struct{}, nodeCount int){ "startStop": startStop, "probabilistic": probabilistic, "boot": boot, } -//Lookup a mocker by its name, returns the mockerFn +// Lookup a mocker by its name, returns the mockerFn func LookupMocker(mockerType string) func(net *Network, quit chan struct{}, nodeCount int) { return mockerList[mockerType] } -//Get a list of mockers (keys of the map) -//Useful for frontend to build available mocker selection +// Get a list of mockers (keys of the map) +// Useful for frontend to build available mocker selection func GetMockerList() []string { list := make([]string, 0, len(mockerList)) for k := range mockerList { @@ -51,7 +51,7 @@ func GetMockerList() []string { return list } -//The boot mockerFn only connects the node in a ring and doesn't do anything else +// The boot mockerFn only connects the node in a ring and doesn't do anything else func boot(net *Network, quit chan struct{}, nodeCount int) { _, err := connectNodesInRing(net, nodeCount) if err != nil { @@ -59,7 +59,7 @@ func boot(net *Network, quit chan struct{}, nodeCount int) { } } -//The startStop mockerFn stops and starts nodes in a defined period (ticker) +// The startStop mockerFn stops and starts nodes in a defined period (ticker) func startStop(net *Network, quit chan struct{}, nodeCount int) { nodes, err := connectNodesInRing(net, nodeCount) if err != nil { @@ -96,10 +96,10 @@ func startStop(net *Network, quit chan struct{}, nodeCount int) { } } -//The probabilistic mocker func has a more probabilistic pattern -//(the implementation could probably be improved): -//nodes are connected in a ring, then a varying number of random nodes is selected, -//mocker then stops and starts them in random intervals, and continues the loop +// The probabilistic mocker func has a more probabilistic pattern +// (the implementation could probably be improved): +// nodes are connected in a ring, then a varying number of random nodes is selected, +// mocker then stops and starts them in random intervals, and continues the loop func probabilistic(net *Network, quit chan struct{}, nodeCount int) { nodes, err := connectNodesInRing(net, nodeCount) if err != nil { @@ -159,7 +159,7 @@ func probabilistic(net *Network, quit chan struct{}, nodeCount int) { } } -//connect nodeCount number of nodes in a ring +// connect nodeCount number of nodes in a ring func connectNodesInRing(net *Network, nodeCount int) ([]enode.ID, error) { ids := make([]enode.ID, nodeCount) for i := 0; i < nodeCount; i++ { diff --git a/params/denomination.go b/params/denomination.go index fb4da7f4125a..bcedd271e0e2 100644 --- a/params/denomination.go +++ b/params/denomination.go @@ -19,8 +19,7 @@ package params // These are the multipliers for ether denominations. // Example: To get the wei value of an amount in 'gwei', use // -// new(big.Int).Mul(value, big.NewInt(params.GWei)) -// +// new(big.Int).Mul(value, big.NewInt(params.GWei)) const ( Wei = 1 GWei = 1e9 diff --git a/rlp/decode.go b/rlp/decode.go index 9214dbfb3720..c9b265241455 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -76,7 +76,7 @@ type Decoder interface { // Note that Decode does not set an input limit for all readers and may be vulnerable to // panics cause by huge value sizes. If you need an input limit, use // -// NewStream(r, limit).Decode(val) +// NewStream(r, limit).Decode(val) func Decode(r io.Reader, val interface{}) error { stream := streamPool.Get().(*Stream) defer streamPool.Put(stream) diff --git a/rlp/doc.go b/rlp/doc.go index e4404c978da7..eeeee9a43a0c 100644 --- a/rlp/doc.go +++ b/rlp/doc.go @@ -27,8 +27,7 @@ value zero equivalent to the empty string). RLP values are distinguished by a type tag. The type tag precedes the value in the input stream and defines the size and kind of the bytes that follow. - -Encoding Rules +# Encoding Rules Package rlp uses reflection and encodes RLP based on the Go type of the value. @@ -58,8 +57,7 @@ An interface value encodes as the value contained in the interface. Floating point numbers, maps, channels and functions are not supported. - -Decoding Rules +# Decoding Rules Decoding uses the following type-dependent rules: @@ -93,30 +91,29 @@ or one (true). To decode into an interface value, one of these types is stored in the value: - []interface{}, for RLP lists - []byte, for RLP strings + []interface{}, for RLP lists + []byte, for RLP strings Non-empty interface types are not supported when decoding. Signed integers, floating point numbers, maps, channels and functions cannot be decoded into. - -Struct Tags +# Struct Tags As with other encoding packages, the "-" tag ignores fields. - type StructWithIgnoredField struct{ - Ignored uint `rlp:"-"` - Field uint - } + type StructWithIgnoredField struct{ + Ignored uint `rlp:"-"` + Field uint + } Go struct values encode/decode as RLP lists. There are two ways of influencing the mapping of fields to list elements. The "tail" tag, which may only be used on the last exported struct field, allows slurping up any excess list elements into a slice. - type StructWithTail struct{ - Field uint - Tail []string `rlp:"tail"` - } + type StructWithTail struct{ + Field uint + Tail []string `rlp:"tail"` + } The "optional" tag says that the field may be omitted if it is zero-valued. If this tag is used on a struct field, all subsequent public fields must also be declared optional. @@ -128,11 +125,11 @@ When decoding into a struct, optional fields may be omitted from the end of the list. For the example below, this means input lists of one, two, or three elements are accepted. - type StructWithOptionalFields struct{ - Required uint - Optional1 uint `rlp:"optional"` - Optional2 uint `rlp:"optional"` - } + type StructWithOptionalFields struct{ + Required uint + Optional1 uint `rlp:"optional"` + Optional2 uint `rlp:"optional"` + } The "nil", "nilList" and "nilString" tags apply to pointer-typed fields only, and change the decoding rules for the field type. For regular pointer fields without the "nil" tag, @@ -140,9 +137,9 @@ input values must always match the required input length exactly and the decoder produce nil values. When the "nil" tag is set, input values of size zero decode as a nil pointer. This is especially useful for recursive types. - type StructWithNilField struct { - Field *[3]byte `rlp:"nil"` - } + type StructWithNilField struct { + Field *[3]byte `rlp:"nil"` + } In the example above, Field allows two possible input sizes. For input 0xC180 (a list containing an empty string) Field is set to nil after decoding. For input 0xC483000000 (a diff --git a/rpc/doc.go b/rpc/doc.go index e0a6324675e6..7c87793dcab6 100644 --- a/rpc/doc.go +++ b/rpc/doc.go @@ -15,7 +15,6 @@ // along with the go-ethereum library. If not, see . /* - Package rpc implements bi-directional JSON-RPC 2.0 on multiple transports. It provides access to the exported methods of an object across a network or other I/O @@ -23,16 +22,16 @@ connection. After creating a server or client instance, objects can be registere them visible as 'services'. Exported methods that follow specific conventions can be called remotely. It also has support for the publish/subscribe pattern. -RPC Methods +# RPC Methods Methods that satisfy the following criteria are made available for remote access: - - method must be exported - - method returns 0, 1 (response or error) or 2 (response and error) values + - method must be exported + - method returns 0, 1 (response or error) or 2 (response and error) values An example method: - func (s *CalcService) Add(a, b int) (int, error) + func (s *CalcService) Add(a, b int) (int, error) When the returned error isn't nil the returned integer is ignored and the error is sent back to the client. Otherwise the returned integer is sent back to the client. @@ -41,7 +40,7 @@ Optional arguments are supported by accepting pointer values as arguments. E.g. to do the addition in an optional finite field we can accept a mod argument as pointer value. - func (s *CalcService) Add(a, b int, mod *int) (int, error) + func (s *CalcService) Add(a, b int, mod *int) (int, error) This RPC method can be called with 2 integers and a null value as third argument. In that case the mod argument will be nil. Or it can be called with 3 integers, in that case mod @@ -56,40 +55,40 @@ to the client out of order. An example server which uses the JSON codec: - type CalculatorService struct {} + type CalculatorService struct {} - func (s *CalculatorService) Add(a, b int) int { - return a + b - } + func (s *CalculatorService) Add(a, b int) int { + return a + b + } - func (s *CalculatorService) Div(a, b int) (int, error) { - if b == 0 { - return 0, errors.New("divide by zero") - } - return a/b, nil - } + func (s *CalculatorService) Div(a, b int) (int, error) { + if b == 0 { + return 0, errors.New("divide by zero") + } + return a/b, nil + } - calculator := new(CalculatorService) - server := NewServer() - server.RegisterName("calculator", calculator) - l, _ := net.ListenUnix("unix", &net.UnixAddr{Net: "unix", Name: "/tmp/calculator.sock"}) - server.ServeListener(l) + calculator := new(CalculatorService) + server := NewServer() + server.RegisterName("calculator", calculator) + l, _ := net.ListenUnix("unix", &net.UnixAddr{Net: "unix", Name: "/tmp/calculator.sock"}) + server.ServeListener(l) -Subscriptions +# Subscriptions The package also supports the publish subscribe pattern through the use of subscriptions. A method that is considered eligible for notifications must satisfy the following criteria: - - method must be exported - - first method argument type must be context.Context - - method must have return types (rpc.Subscription, error) + - method must be exported + - first method argument type must be context.Context + - method must have return types (rpc.Subscription, error) An example method: - func (s *BlockChainService) NewBlocks(ctx context.Context) (rpc.Subscription, error) { - ... - } + func (s *BlockChainService) NewBlocks(ctx context.Context) (rpc.Subscription, error) { + ... + } When the service containing the subscription method is registered to the server, for example under the "blockchain" namespace, a subscription is created by calling the @@ -101,7 +100,7 @@ the client and server. The server will close the connection for any write error. For more information about subscriptions, see https://github.com/ethereum/go-ethereum/wiki/RPC-PUB-SUB. -Reverse Calls +# Reverse Calls In any method handler, an instance of rpc.Client can be accessed through the ClientFromContext method. Using this client instance, server-to-client method calls can be diff --git a/rpc/handler.go b/rpc/handler.go index 22ad98149f8c..f3052e7eb822 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -34,20 +34,20 @@ import ( // // The entry points for incoming messages are: // -// h.handleMsg(message) -// h.handleBatch(message) +// h.handleMsg(message) +// h.handleBatch(message) // // Outgoing calls use the requestOp struct. Register the request before sending it // on the connection: // -// op := &requestOp{ids: ...} -// h.addRequestOp(op) +// op := &requestOp{ids: ...} +// h.addRequestOp(op) // // Now send the request, then wait for the reply to be delivered through handleMsg: // -// if err := op.wait(...); err != nil { -// h.removeRequestOp(op) // timeout, etc. -// } +// if err := op.wait(...); err != nil { +// h.removeRequestOp(op) // timeout, etc. +// } type handler struct { reg *serviceRegistry unsubscribeCb *callback diff --git a/signer/core/api_test.go b/signer/core/api_test.go index 6fa2af1836b2..9bb55bddca31 100644 --- a/signer/core/api_test.go +++ b/signer/core/api_test.go @@ -39,7 +39,7 @@ import ( "github.com/ethereum/go-ethereum/signer/storage" ) -//Used for testing +// Used for testing type headlessUi struct { approveCh chan string // to send approve/deny inputCh chan string // to send password diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 0652108f889e..2c8907ac822e 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -64,7 +64,7 @@ func (vs *ValidationMessages) Info(msg string) { vs.Messages = append(vs.Messages, ValidationInfo{INFO, msg}) } -/// getWarnings returns an error with all messages of type WARN of above, or nil if no warnings were present +// getWarnings returns an error with all messages of type WARN of above, or nil if no warnings were present func (v *ValidationMessages) GetWarnings() error { var messages []string for _, msg := range v.Messages { diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 80f93d7c08b3..313a703fae8f 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -175,17 +175,18 @@ func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { } } -/* See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II +/* +See https://github.com/ethereum/tests/wiki/Blockchain-Tests-II - Whether a block is valid or not is a bit subtle, it's defined by presence of - blockHeader, transactions and uncleHeaders fields. If they are missing, the block is - invalid and we must verify that we do not accept it. + Whether a block is valid or not is a bit subtle, it's defined by presence of + blockHeader, transactions and uncleHeaders fields. If they are missing, the block is + invalid and we must verify that we do not accept it. - Since some tests mix valid and invalid blocks we need to check this for every block. + Since some tests mix valid and invalid blocks we need to check this for every block. - If a block is invalid it does not necessarily fail the test, if it's invalidness is - expected we are expected to ignore it and continue processing and then validate the - post state. + If a block is invalid it does not necessarily fail the test, if it's invalidness is + expected we are expected to ignore it and continue processing and then validate the + post state. */ func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error) { validBlocks := make([]btBlock, 0) diff --git a/tests/fuzzers/bls12381/precompile_fuzzer.go b/tests/fuzzers/bls12381/precompile_fuzzer.go index bc3c45652603..cab2bcba3863 100644 --- a/tests/fuzzers/bls12381/precompile_fuzzer.go +++ b/tests/fuzzers/bls12381/precompile_fuzzer.go @@ -70,12 +70,14 @@ func checkInput(id byte, inputLen int) bool { panic("programmer error") } -// The fuzzer functions must return -// 1 if the fuzzer should increase priority of the -// given input during subsequent fuzzing (for example, the input is lexically -// correct and was parsed successfully); -// -1 if the input must not be added to corpus even if gives new coverage; and -// 0 otherwise +// The function must return +// +// - 1 if the fuzzer should increase priority of the +// given input during subsequent fuzzing (for example, the input is lexically +// correct and was parsed successfully); +// - -1 if the input must not be added to corpus even if gives new coverage; and +// - 0 otherwise +// // other values are reserved for future use. func fuzz(id byte, data []byte) int { // Even on bad input, it should not crash, so we still test the gas calc diff --git a/tests/fuzzers/difficulty/difficulty-fuzz.go b/tests/fuzzers/difficulty/difficulty-fuzz.go index 2112abac1afa..5612a4e70660 100644 --- a/tests/fuzzers/difficulty/difficulty-fuzz.go +++ b/tests/fuzzers/difficulty/difficulty-fuzz.go @@ -67,11 +67,13 @@ func (f *fuzzer) readBool() bool { } // The function must return -// 1 if the fuzzer should increase priority of the -// given input during subsequent fuzzing (for example, the input is lexically -// correct and was parsed successfully); -// -1 if the input must not be added to corpus even if gives new coverage; and -// 0 otherwise +// +// - 1 if the fuzzer should increase priority of the +// given input during subsequent fuzzing (for example, the input is lexically +// correct and was parsed successfully); +// - -1 if the input must not be added to corpus even if gives new coverage; and +// - 0 otherwise +// // other values are reserved for future use. func Fuzz(data []byte) int { f := fuzzer{ diff --git a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go index c2db919d5a97..16242a66ec6e 100644 --- a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go +++ b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go @@ -180,11 +180,14 @@ func (f *fuzzer) fuzz() int { } // The function must return -// 1 if the fuzzer should increase priority of the -// given input during subsequent fuzzing (for example, the input is lexically -// correct and was parsed successfully); -// -1 if the input must not be added to corpus even if gives new coverage; and -// 0 otherwise; other values are reserved for future use. +// +// - 1 if the fuzzer should increase priority of the +// given input during subsequent fuzzing (for example, the input is lexically +// correct and was parsed successfully); +// - -1 if the input must not be added to corpus even if gives new coverage; and +// - 0 otherwise +// +// other values are reserved for future use. func Fuzz(input []byte) int { if len(input) < 100 { return 0 diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index e6165df08c15..95a1fc464e07 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -114,11 +114,13 @@ func (k kvs) Swap(i, j int) { } // The function must return -// 1 if the fuzzer should increase priority of the -// given input during subsequent fuzzing (for example, the input is lexically -// correct and was parsed successfully); -// -1 if the input must not be added to corpus even if gives new coverage; and -// 0 otherwise +// +// - 1 if the fuzzer should increase priority of the +// given input during subsequent fuzzing (for example, the input is lexically +// correct and was parsed successfully); +// - -1 if the input must not be added to corpus even if gives new coverage; and +// - 0 otherwise +// // other values are reserved for future use. func Fuzz(data []byte) int { f := fuzzer{ diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index f36b613d4786..25e137602ca1 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -119,11 +119,13 @@ func Generate(input []byte) randTest { } // The function must return -// 1 if the fuzzer should increase priority of the -// given input during subsequent fuzzing (for example, the input is lexically -// correct and was parsed successfully); -// -1 if the input must not be added to corpus even if gives new coverage; and -// 0 otherwise +// +// - 1 if the fuzzer should increase priority of the +// given input during subsequent fuzzing (for example, the input is lexically +// correct and was parsed successfully); +// - -1 if the input must not be added to corpus even if gives new coverage; and +// - 0 otherwise +// // other values are reserved for future use. func Fuzz(input []byte) int { program := Generate(input) diff --git a/tests/init_test.go b/tests/init_test.go index 4ef5aaf7378f..9d315f9511c9 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -116,6 +116,7 @@ func (tm *testMatcher) skipLoad(pattern string) { } // fails adds an expected failure for tests matching the pattern. +// //nolint:unused func (tm *testMatcher) fails(pattern string, reason string) { if reason == "" { diff --git a/trie/hasher.go b/trie/hasher.go index 183e96c229ca..e594d6d6b2ae 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -170,8 +170,8 @@ func (h *hasher) fullnodeToHash(n *fullNode, force bool) node { // // All node encoding must be done like this: // -// node.encode(h.encbuf) -// enc := h.encodedBytes() +// node.encode(h.encbuf) +// enc := h.encodedBytes() // // This convention exists because node.encode can only be inlined/escape-analyzed when // called on a concrete receiver type. diff --git a/trie/proof.go b/trie/proof.go index ef73aed2e409..8c00bcf5329d 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -339,9 +339,9 @@ findFork: // unset removes all internal node references either the left most or right most. // It can meet these scenarios: // -// - The given path is existent in the trie, unset the associated nodes with the -// specific direction -// - The given path is non-existent in the trie +// - The given path is existent in the trie, unset the associated nodes with the +// specific direction +// - The given path is non-existent in the trie // - the fork point is a fullnode, the corresponding child pointed by path // is nil, return // - the fork point is a shortnode, the shortnode is included in the range, @@ -458,15 +458,15 @@ func hasRightElement(node node, key []byte) bool { // Expect the normal case, this function can also be used to verify the following // range proofs: // -// - All elements proof. In this case the proof can be nil, but the range should -// be all the leaves in the trie. +// - All elements proof. In this case the proof can be nil, but the range should +// be all the leaves in the trie. // -// - One element proof. In this case no matter the edge proof is a non-existent -// proof or not, we can always verify the correctness of the proof. +// - One element proof. In this case no matter the edge proof is a non-existent +// proof or not, we can always verify the correctness of the proof. // -// - Zero element proof. In this case a single non-existent proof is enough to prove. -// Besides, if there are still some other leaves available on the right side, then -// an error will be returned. +// - Zero element proof. In this case a single non-existent proof is enough to prove. +// Besides, if there are still some other leaves available on the right side, then +// an error will be returned. // // Except returning the error to indicate the proof is valid or not, the function will // also return a flag to indicate whether there exists more accounts/slots in the trie. diff --git a/trie/stacktrie.go b/trie/stacktrie.go index cc50b817b65d..d37375d35d52 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -375,11 +375,12 @@ func (st *StackTrie) insert(key, value []byte) { // hash converts st into a 'hashedNode', if possible. Possible outcomes: // // 1. The rlp-encoded value was >= 32 bytes: -// - Then the 32-byte `hash` will be accessible in `st.val`. -// - And the 'st.type' will be 'hashedNode' +// - Then the 32-byte `hash` will be accessible in `st.val`. +// - And the 'st.type' will be 'hashedNode' +// // 2. The rlp-encoded value was < 32 bytes -// - Then the <32 byte rlp-encoded value will be accessible in 'st.val'. -// - And the 'st.type' will be 'hashedNode' AGAIN +// - Then the <32 byte rlp-encoded value will be accessible in 'st.val'. +// - And the 'st.type' will be 'hashedNode' AGAIN // // This method also sets 'st.type' to hashedNode, and clears 'st.key'. func (st *StackTrie) hash() { From 0c1888a36753b3770b42fe318b93b407dc106a47 Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Mon, 12 Sep 2022 22:02:03 +0900 Subject: [PATCH 229/715] p2p/discover/v5wire: reject packets smaller than 63 bytes (#25740) --- p2p/discover/v5wire/encoding.go | 8 ++++++-- p2p/discover/v5wire/encoding_test.go | 10 +++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index 45f2f0883bad..d605d7080332 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -90,6 +90,10 @@ const ( minVersion = 1 sizeofMaskingIV = 16 + // The minimum size of any Discovery v5 packet is 63 bytes. + // Should reject packets smaller than minPacketSize. + minPacketSize = 63 + minMessageSize = 48 // this refers to data after static headers randomPacketMsgSize = 20 ) @@ -415,10 +419,10 @@ func (c *Codec) encryptMessage(s *session, p Packet, head *Header, headerData [] // Decode decodes a discovery packet. func (c *Codec) Decode(input []byte, addr string) (src enode.ID, n *enode.Node, p Packet, err error) { - // Unmask the static header. - if len(input) < sizeofStaticPacketData { + if len(input) < minPacketSize { return enode.ID{}, nil, nil, errTooShort } + // Unmask the static header. var head Header copy(head.IV[:], input[:sizeofMaskingIV]) mask := head.mask(c.localnode.ID()) diff --git a/p2p/discover/v5wire/encoding_test.go b/p2p/discover/v5wire/encoding_test.go index 14c9da8c53a6..a08cffa2a576 100644 --- a/p2p/discover/v5wire/encoding_test.go +++ b/p2p/discover/v5wire/encoding_test.go @@ -274,7 +274,15 @@ func TestDecodeErrorsV5(t *testing.T) { net := newHandshakeTest() defer net.close() - net.nodeA.expectDecodeErr(t, errTooShort, []byte{}) + b := make([]byte, 0) + net.nodeA.expectDecodeErr(t, errTooShort, b) + + b = make([]byte, 62) + net.nodeA.expectDecodeErr(t, errTooShort, b) + + b = make([]byte, 63) + net.nodeA.expectDecodeErr(t, errInvalidHeader, b) + // TODO some more tests would be nice :) // - check invalid authdata sizes // - check invalid handshake data sizes From 3a4cef5402d8b58831f95a909f8a1bdf3acffe3c Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Mon, 12 Sep 2022 22:02:41 +0900 Subject: [PATCH 230/715] core: preallocate maps in TxPool helper methods (#25737) --- core/tx_pool.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index 1c25442dd9c5..ee8b9f7a43f0 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -498,11 +498,11 @@ func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common pool.mu.Lock() defer pool.mu.Unlock() - pending := make(map[common.Address]types.Transactions) + pending := make(map[common.Address]types.Transactions, len(pool.pending)) for addr, list := range pool.pending { pending[addr] = list.Flatten() } - queued := make(map[common.Address]types.Transactions) + queued := make(map[common.Address]types.Transactions, len(pool.queue)) for addr, list := range pool.queue { queued[addr] = list.Flatten() } @@ -1588,7 +1588,7 @@ type accountSet struct { // derivations. func newAccountSet(signer types.Signer, addrs ...common.Address) *accountSet { as := &accountSet{ - accounts: make(map[common.Address]struct{}), + accounts: make(map[common.Address]struct{}, len(addrs)), signer: signer, } for _, addr := range addrs { From 9a3bd114e7df143053508351cd28e17105ea1a39 Mon Sep 17 00:00:00 2001 From: Benjamin Prosnitz Date: Tue, 13 Sep 2022 08:02:34 -0400 Subject: [PATCH 231/715] accounts/abi: fix typo in error message (#25742) --- accounts/abi/unpack.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index 800789295c19..0de99cd2b68c 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -123,7 +123,7 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size) } if start+32*size > len(output) { - return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size) + return nil, fmt.Errorf("abi: cannot marshal into go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size) } // this value will become our slice or our array, depending on the type From 818ff32ff5bf4674c5ee234f1b7a261148cf91b1 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 13 Sep 2022 21:49:52 +0200 Subject: [PATCH 232/715] graphql: fixes missing tx logs (#25745) * graphql: fix tx logs * graphql: refactor test service setup * graphql: add test for tx logs --- graphql/graphql.go | 2 +- graphql/graphql_test.go | 227 +++++++++++++++++++++------------------- graphql/service.go | 9 +- 3 files changed, 124 insertions(+), 114 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 66c25841db98..356ff669fb16 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -481,7 +481,7 @@ func (t *Transaction) getLogs(ctx context.Context) (*[]*Log, error) { } var ret []*Log // Select tx logs from all block logs - ix := sort.Search(len(logs), func(i int) bool { return uint64(logs[i].TxIndex) == t.index }) + ix := sort.Search(len(logs), func(i int) bool { return uint64(logs[i].TxIndex) >= t.index }) for ix < len(logs) && uint64(logs[ix].TxIndex) == t.index { ret = append(ret, &Log{ r: t.r, diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index d55f4e063486..491c73152113 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -17,6 +17,8 @@ package graphql import ( + "context" + "encoding/json" "fmt" "io" "math/big" @@ -51,15 +53,21 @@ func TestBuildSchema(t *testing.T) { } defer stack.Close() // Make sure the schema can be parsed and matched up to the object model. - if err := newHandler(stack, nil, nil, []string{}, []string{}); err != nil { + if _, err := newHandler(stack, nil, nil, []string{}, []string{}); err != nil { t.Errorf("Could not construct GraphQL handler: %v", err) } } // Tests that a graphQL request is successfully handled when graphql is enabled on the specified endpoint func TestGraphQLBlockSerialization(t *testing.T) { - stack := createNode(t, true, false) + stack := createNode(t) defer stack.Close() + genesis := &core.Genesis{ + Config: params.AllEthashProtocolChanges, + GasLimit: 11500000, + Difficulty: big.NewInt(1048576), + } + newGQLService(t, stack, genesis, 10, func(i int, gen *core.BlockGen) {}) // start node if err := stack.Start(); err != nil { t.Fatalf("could not start node: %v", err) @@ -161,8 +169,55 @@ func TestGraphQLBlockSerialization(t *testing.T) { } func TestGraphQLBlockSerializationEIP2718(t *testing.T) { - stack := createNode(t, true, true) + // Account for signing txes + var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000000000) + dad = common.HexToAddress("0x0000000000000000000000000000000000000dad") + ) + stack := createNode(t) defer stack.Close() + genesis := &core.Genesis{ + Config: params.AllEthashProtocolChanges, + GasLimit: 11500000, + Difficulty: big.NewInt(1048576), + Alloc: core.GenesisAlloc{ + address: {Balance: funds}, + // The address 0xdad sloads 0x00 and 0x01 + dad: { + Code: []byte{byte(vm.PC), byte(vm.PC), byte(vm.SLOAD), byte(vm.SLOAD)}, + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + BaseFee: big.NewInt(params.InitialBaseFee), + } + signer := types.LatestSigner(genesis.Config) + newGQLService(t, stack, genesis, 1, func(i int, gen *core.BlockGen) { + gen.SetCoinbase(common.Address{1}) + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: uint64(0), + To: &dad, + Value: big.NewInt(100), + Gas: 50000, + GasPrice: big.NewInt(params.InitialBaseFee), + }) + gen.AddTx(tx) + tx, _ = types.SignNewTx(key, signer, &types.AccessListTx{ + ChainID: genesis.Config.ChainID, + Nonce: uint64(1), + To: &dad, + Gas: 30000, + GasPrice: big.NewInt(params.InitialBaseFee), + Value: big.NewInt(50), + AccessList: types.AccessList{{ + Address: dad, + StorageKeys: []common.Hash{{0}}, + }}, + }) + gen.AddTx(tx) + }) // start node if err := stack.Start(); err != nil { t.Fatalf("could not start node: %v", err) @@ -198,7 +253,7 @@ func TestGraphQLBlockSerializationEIP2718(t *testing.T) { // Tests that a graphQL request is not handled successfully when graphql is not enabled on the specified endpoint func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) { - stack := createNode(t, false, false) + stack := createNode(t) defer stack.Close() if err := stack.Start(); err != nil { t.Fatalf("could not start node: %v", err) @@ -212,7 +267,59 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) { assert.Equal(t, http.StatusNotFound, resp.StatusCode) } -func createNode(t *testing.T, gqlEnabled bool, txEnabled bool) *node.Node { +func TestGraphQLTransactionLogs(t *testing.T) { + var ( + key, _ = crypto.GenerateKey() + addr = crypto.PubkeyToAddress(key.PublicKey) + dadStr = "0x0000000000000000000000000000000000000dad" + dad = common.HexToAddress(dadStr) + genesis = &core.Genesis{ + Config: params.AllEthashProtocolChanges, + GasLimit: 11500000, + Difficulty: big.NewInt(1048576), + Alloc: core.GenesisAlloc{ + addr: {Balance: big.NewInt(params.Ether)}, + dad: { + // LOG0(0, 0), LOG0(0, 0), RETURN(0, 0) + Code: common.Hex2Bytes("60006000a060006000a060006000f3"), + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + } + signer = types.LatestSigner(genesis.Config) + stack = createNode(t) + ) + defer stack.Close() + + handler := newGQLService(t, stack, genesis, 1, func(i int, gen *core.BlockGen) { + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) + gen.AddTx(tx) + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Nonce: 1, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) + gen.AddTx(tx) + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Nonce: 2, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) + gen.AddTx(tx) + }) + // start node + if err := stack.Start(); err != nil { + t.Fatalf("could not start node: %v", err) + } + query := `{block { transactions { logs { account { address } } } } }` + res := handler.Schema.Exec(context.Background(), query, "", map[string]interface{}{}) + if res.Errors != nil { + t.Fatalf("graphql query failed: %v", res.Errors) + } + have, err := json.Marshal(res.Data) + if err != nil { + t.Fatalf("failed to encode graphql response: %s", err) + } + want := fmt.Sprintf(`{"block":{"transactions":[{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]}]}}`, dadStr, dadStr, dadStr, dadStr, dadStr, dadStr) + if string(have) != want { + t.Errorf("response unmatch. expected %s, got %s", want, have) + } +} + +func createNode(t *testing.T) *node.Node { stack, err := node.New(&node.Config{ HTTPHost: "127.0.0.1", HTTPPort: 0, @@ -222,83 +329,12 @@ func createNode(t *testing.T, gqlEnabled bool, txEnabled bool) *node.Node { if err != nil { t.Fatalf("could not create node: %v", err) } - if !gqlEnabled { - return stack - } - if !txEnabled { - createGQLService(t, stack) - } else { - createGQLServiceWithTransactions(t, stack) - } return stack } -func createGQLService(t *testing.T, stack *node.Node) { - // create backend - ethConf := ðconfig.Config{ - Genesis: &core.Genesis{ - Config: params.AllEthashProtocolChanges, - GasLimit: 11500000, - Difficulty: big.NewInt(1048576), - }, - Ethash: ethash.Config{ - PowMode: ethash.ModeFake, - }, - NetworkId: 1337, - TrieCleanCache: 5, - TrieCleanCacheJournal: "triecache", - TrieCleanCacheRejournal: 60 * time.Minute, - TrieDirtyCache: 5, - TrieTimeout: 60 * time.Minute, - SnapshotCache: 5, - } - ethBackend, err := eth.New(stack, ethConf) - if err != nil { - t.Fatalf("could not create eth backend: %v", err) - } - // Create some blocks and import them - chain, _ := core.GenerateChain(params.AllEthashProtocolChanges, ethBackend.BlockChain().Genesis(), - ethash.NewFaker(), ethBackend.ChainDb(), 10, func(i int, gen *core.BlockGen) {}) - _, err = ethBackend.BlockChain().InsertChain(chain) - if err != nil { - t.Fatalf("could not create import blocks: %v", err) - } - // create gql service - filterSystem := filters.NewFilterSystem(ethBackend.APIBackend, filters.Config{}) - err = New(stack, ethBackend.APIBackend, filterSystem, []string{}, []string{}) - if err != nil { - t.Fatalf("could not create graphql service: %v", err) - } -} - -func createGQLServiceWithTransactions(t *testing.T, stack *node.Node) { - // create backend - key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address := crypto.PubkeyToAddress(key.PublicKey) - funds := big.NewInt(1000000000000000) - dad := common.HexToAddress("0x0000000000000000000000000000000000000dad") - +func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) *handler { ethConf := ðconfig.Config{ - Genesis: &core.Genesis{ - Config: params.AllEthashProtocolChanges, - GasLimit: 11500000, - Difficulty: big.NewInt(1048576), - Alloc: core.GenesisAlloc{ - address: {Balance: funds}, - // The address 0xdad sloads 0x00 and 0x01 - dad: { - Code: []byte{ - byte(vm.PC), - byte(vm.PC), - byte(vm.SLOAD), - byte(vm.SLOAD), - }, - Nonce: 0, - Balance: big.NewInt(0), - }, - }, - BaseFee: big.NewInt(params.InitialBaseFee), - }, + Genesis: gspec, Ethash: ethash.Config{ PowMode: ethash.ModeFake, }, @@ -310,49 +346,22 @@ func createGQLServiceWithTransactions(t *testing.T, stack *node.Node) { TrieTimeout: 60 * time.Minute, SnapshotCache: 5, } - ethBackend, err := eth.New(stack, ethConf) if err != nil { t.Fatalf("could not create eth backend: %v", err) } - signer := types.LatestSigner(ethConf.Genesis.Config) - - legacyTx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ - Nonce: uint64(0), - To: &dad, - Value: big.NewInt(100), - Gas: 50000, - GasPrice: big.NewInt(params.InitialBaseFee), - }) - envelopTx, _ := types.SignNewTx(key, signer, &types.AccessListTx{ - ChainID: ethConf.Genesis.Config.ChainID, - Nonce: uint64(1), - To: &dad, - Gas: 30000, - GasPrice: big.NewInt(params.InitialBaseFee), - Value: big.NewInt(50), - AccessList: types.AccessList{{ - Address: dad, - StorageKeys: []common.Hash{{0}}, - }}, - }) - // Create some blocks and import them chain, _ := core.GenerateChain(params.AllEthashProtocolChanges, ethBackend.BlockChain().Genesis(), - ethash.NewFaker(), ethBackend.ChainDb(), 1, func(i int, b *core.BlockGen) { - b.SetCoinbase(common.Address{1}) - b.AddTx(legacyTx) - b.AddTx(envelopTx) - }) - + ethash.NewFaker(), ethBackend.ChainDb(), genBlocks, genfunc) _, err = ethBackend.BlockChain().InsertChain(chain) if err != nil { t.Fatalf("could not create import blocks: %v", err) } - // create gql service + // Set up handler filterSystem := filters.NewFilterSystem(ethBackend.APIBackend, filters.Config{}) - err = New(stack, ethBackend.APIBackend, filterSystem, []string{}, []string{}) + handler, err := newHandler(stack, ethBackend.APIBackend, filterSystem, []string{}, []string{}) if err != nil { t.Fatalf("could not create graphql service: %v", err) } + return handler } diff --git a/graphql/service.go b/graphql/service.go index 019026bc7ea7..6f6e58335991 100644 --- a/graphql/service.go +++ b/graphql/service.go @@ -57,17 +57,18 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // New constructs a new GraphQL service instance. func New(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) error { - return newHandler(stack, backend, filterSystem, cors, vhosts) + _, err := newHandler(stack, backend, filterSystem, cors, vhosts) + return err } // newHandler returns a new `http.Handler` that will answer GraphQL queries. // It additionally exports an interactive query browser on the / endpoint. -func newHandler(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) error { +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) if err != nil { - return err + return nil, err } h := handler{Schema: s} handler := node.NewHTTPHandlerStack(h, cors, vhosts, nil) @@ -76,5 +77,5 @@ func newHandler(stack *node.Node, backend ethapi.Backend, filterSystem *filters. stack.RegisterHandler("GraphQL", "/graphql", handler) stack.RegisterHandler("GraphQL", "/graphql/", handler) - return nil + return &h, nil } From 9d717167aaf27a48d56ad9d1a2c36f90eba1cc13 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Wed, 14 Sep 2022 12:05:03 +0200 Subject: [PATCH 233/715] cmd/geth: add a verkle subcommand (#25718) * cmd/geth: add a verkle subcommand * fix copyright year * remove unused command parameters * check that the output file was successfully written to Co-authored-by: Martin Holst Swende * cmd/geth: goimports fix Co-authored-by: Martin Holst Swende --- cmd/geth/main.go | 2 + cmd/geth/verkle.go | 213 +++++++++++++++++++++++++++++++++++++++++++++ go.mod | 2 + go.sum | 5 ++ 4 files changed, 222 insertions(+) create mode 100644 cmd/geth/verkle.go diff --git a/cmd/geth/main.go b/cmd/geth/main.go index b9e3ed31e813..70b354ae148b 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -241,6 +241,8 @@ func init() { utils.ShowDeprecated, // See snapshot.go snapshotCommand, + // See verkle.go + verkleCommand, } sort.Sort(cli.CommandsByName(app.Commands)) diff --git a/cmd/geth/verkle.go b/cmd/geth/verkle.go new file mode 100644 index 000000000000..f85ec37ea924 --- /dev/null +++ b/cmd/geth/verkle.go @@ -0,0 +1,213 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "bytes" + "encoding/hex" + "errors" + "fmt" + "os" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/log" + "github.com/gballet/go-verkle" + cli "github.com/urfave/cli/v2" +) + +var ( + zero [32]byte + + verkleCommand = &cli.Command{ + Name: "verkle", + Usage: "A set of experimental verkle tree management commands", + Category: "MISCELLANEOUS COMMANDS", + Description: "", + Subcommands: []*cli.Command{ + { + Name: "verify", + Usage: "verify the conversion of a MPT into a verkle tree", + ArgsUsage: "", + Action: verifyVerkle, + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), + Description: ` +geth verkle verify +This command takes a root commitment and attempts to rebuild the tree. + `, + }, + { + Name: "dump", + Usage: "Dump a verkle tree to a DOT file", + ArgsUsage: " [ ...]", + Action: expandVerkle, + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), + Description: ` +geth verkle dump [ ...] +This command will produce a dot file representing the tree, rooted at . +in which key1, key2, ... are expanded. + `, + }, + }, + } +) + +// recurse into each child to ensure they can be loaded from the db. The tree isn't rebuilt +// (only its nodes are loaded) so there is no need to flush them, the garbage collector should +// take care of that for us. +func checkChildren(root verkle.VerkleNode, resolver verkle.NodeResolverFn) error { + switch node := root.(type) { + case *verkle.InternalNode: + for i, child := range node.Children() { + childC := child.ComputeCommitment().Bytes() + + childS, err := resolver(childC[:]) + if bytes.Equal(childC[:], zero[:]) { + continue + } + if err != nil { + return fmt.Errorf("could not find child %x in db: %w", childC, err) + } + // depth is set to 0, the tree isn't rebuilt so it's not a problem + childN, err := verkle.ParseNode(childS, 0, childC[:]) + if err != nil { + return fmt.Errorf("decode error child %x in db: %w", child.ComputeCommitment().Bytes(), err) + } + if err := checkChildren(childN, resolver); err != nil { + return fmt.Errorf("%x%w", i, err) // write the path to the erroring node + } + } + case *verkle.LeafNode: + // sanity check: ensure at least one value is non-zero + + for i := 0; i < verkle.NodeWidth; i++ { + if len(node.Value(i)) != 0 { + return nil + } + } + return fmt.Errorf("Both balance and nonce are 0") + case verkle.Empty: + // nothing to do + default: + return fmt.Errorf("unsupported type encountered %v", root) + } + + return nil +} + +func verifyVerkle(ctx *cli.Context) error { + stack, _ := makeConfigNode(ctx) + defer stack.Close() + + chaindb := utils.MakeChainDatabase(ctx, stack, true) + headBlock := rawdb.ReadHeadBlock(chaindb) + if headBlock == nil { + log.Error("Failed to load head block") + return errors.New("no head block") + } + if ctx.NArg() > 1 { + log.Error("Too many arguments given") + return errors.New("too many arguments") + } + var ( + rootC common.Hash + err error + ) + if ctx.NArg() == 1 { + rootC, err = parseRoot(ctx.Args().First()) + if err != nil { + log.Error("Failed to resolve state root", "error", err) + return err + } + log.Info("Rebuilding the tree", "root", rootC) + } else { + rootC = headBlock.Root() + log.Info("Rebuilding the tree", "root", rootC, "number", headBlock.NumberU64()) + } + + serializedRoot, err := chaindb.Get(rootC[:]) + if err != nil { + return err + } + root, err := verkle.ParseNode(serializedRoot, 0, rootC[:]) + if err != nil { + return err + } + + if err := checkChildren(root, chaindb.Get); err != nil { + log.Error("Could not rebuild the tree from the database", "err", err) + return err + } + + log.Info("Tree was rebuilt from the database") + return nil +} + +func expandVerkle(ctx *cli.Context) error { + stack, _ := makeConfigNode(ctx) + defer stack.Close() + + chaindb := utils.MakeChainDatabase(ctx, stack, true) + var ( + rootC common.Hash + keylist [][]byte + err error + ) + if ctx.NArg() >= 2 { + rootC, err = parseRoot(ctx.Args().First()) + if err != nil { + log.Error("Failed to resolve state root", "error", err) + return err + } + keylist = make([][]byte, 0, ctx.Args().Len()-1) + args := ctx.Args().Slice() + for i := range args[1:] { + key, err := hex.DecodeString(args[i+1]) + log.Info("decoded key", "arg", args[i+1], "key", key) + if err != nil { + return fmt.Errorf("error decoding key #%d: %w", i+1, err) + } + keylist = append(keylist, key) + } + log.Info("Rebuilding the tree", "root", rootC) + } else { + return fmt.Errorf("usage: %s root key1 [key 2...]", ctx.App.Name) + } + + serializedRoot, err := chaindb.Get(rootC[:]) + if err != nil { + return err + } + root, err := verkle.ParseNode(serializedRoot, 0, rootC[:]) + if err != nil { + return err + } + + for i, key := range keylist { + log.Info("Reading key", "index", i, "key", keylist[0]) + root.Get(key, chaindb.Get) + } + + if err := os.WriteFile("dump.dot", []byte(verkle.ToDot(root)), 0600); err != nil { + log.Error("Failed to dump file", "err", err) + } else { + log.Info("Tree was dumped to file", "file", "dump.dot") + } + return nil +} diff --git a/go.mod b/go.mod index 4a769c7a2dca..72613343948e 100644 --- a/go.mod +++ b/go.mod @@ -78,10 +78,12 @@ require ( github.com/aws/smithy-go v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect + github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 // indirect github.com/go-logfmt/logfmt v0.4.0 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect diff --git a/go.sum b/go.sum index 4b27867fbc79..72d9b25e2021 100644 --- a/go.sum +++ b/go.sum @@ -86,6 +86,8 @@ github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 h1:6IrxszG5G+O7zhtkWxq6+unVvnrm1fqV2Pe+T95DUzw= +github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= @@ -134,6 +136,8 @@ github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgx github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 h1:AB7YjNrzlVHsYz06zCULVV2zYCEft82P86dSmtwxKL0= +github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732/go.mod h1:o/XfIXWi4/GqbQirfRm5uTbXMG5NpqxkxblnbZ+QM9I= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -569,6 +573,7 @@ golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= From 25b35c97289a8db4753cdf5ab7f2b306ec71794d Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 14 Sep 2022 18:37:53 +0200 Subject: [PATCH 234/715] node: fix HTTP server always force closing (#25755) Co-authored-by: Felix Lange --- node/rpcstack.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node/rpcstack.go b/node/rpcstack.go index 5d411fa61e81..f45435bab22d 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -267,13 +267,15 @@ func (h *httpServer) doStop() { h.wsHandler.Store((*rpcHandler)(nil)) wsHandler.server.Stop() } + ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout) defer cancel() err := h.server.Shutdown(ctx) - if err == ctx.Err() { + if err != nil && err == ctx.Err() { h.log.Warn("HTTP server graceful shutdown timed out") h.server.Close() } + h.listener.Close() h.log.Info("HTTP server stopped", "endpoint", h.listener.Addr()) From 0ee8b273f22a24d25b9595d5d66443e6fdd3c18a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Sep 2022 13:18:23 +0200 Subject: [PATCH 235/715] core: fix log order in "Imported new chain segment" (#25768) --- core/blockchain_insert.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/blockchain_insert.go b/core/blockchain_insert.go index 479eccc83e47..8f496e182c9e 100644 --- a/core/blockchain_insert.go +++ b/core/blockchain_insert.go @@ -56,9 +56,9 @@ func (st *insertStats) report(chain []*types.Block, index int, dirty common.Stor // Assemble the log context and send it to the logger context := []interface{}{ + "number", end.Number(), "hash", end.Hash(), "blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000, "elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed), - "number", end.Number(), "hash", end.Hash(), } if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute { context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) From 3db4a13230435640267a01669d3c2b66202cfa9c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Sep 2022 15:21:44 +0200 Subject: [PATCH 236/715] node: fix lint issue in rpcstack.go (#25774) --- node/rpcstack.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/rpcstack.go b/node/rpcstack.go index f45435bab22d..8244c892ff50 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -267,7 +267,7 @@ func (h *httpServer) doStop() { h.wsHandler.Store((*rpcHandler)(nil)) wsHandler.server.Stop() } - + ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout) defer cancel() err := h.server.Shutdown(ctx) @@ -275,7 +275,7 @@ func (h *httpServer) doStop() { h.log.Warn("HTTP server graceful shutdown timed out") h.server.Close() } - + h.listener.Close() h.log.Info("HTTP server stopped", "endpoint", h.listener.Addr()) From 1d2f5cf610aa6ec9ae3e5b78d52c11f9d9ec3ad4 Mon Sep 17 00:00:00 2001 From: pinkiebell <40266861+pinkiebell@users.noreply.github.com> Date: Thu, 15 Sep 2022 15:36:31 +0200 Subject: [PATCH 237/715] les/catalyst/api: add support for ExchangeTransitionConfigurationV1 (#25752) This method is missing in light client mode and breaks consensus clients that require a valid response. --- les/catalyst/api.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/les/catalyst/api.go b/les/catalyst/api.go index abd1c9a901b3..822e0af038a7 100644 --- a/les/catalyst/api.go +++ b/les/catalyst/api.go @@ -22,6 +22,7 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/log" @@ -189,3 +190,31 @@ func (api *ConsensusAPI) setCanonical(newHead common.Hash) error { } return nil } + +// ExchangeTransitionConfigurationV1 checks the given configuration against +// the configuration of the node. +func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.TransitionConfigurationV1) (*beacon.TransitionConfigurationV1, error) { + log.Trace("Engine API request received", "method", "ExchangeTransitionConfiguration", "ttd", config.TerminalTotalDifficulty) + if config.TerminalTotalDifficulty == nil { + return nil, errors.New("invalid terminal total difficulty") + } + + ttd := api.les.BlockChain().Config().TerminalTotalDifficulty + if ttd == nil || ttd.Cmp(config.TerminalTotalDifficulty.ToInt()) != 0 { + log.Warn("Invalid TTD configured", "geth", ttd, "beacon", config.TerminalTotalDifficulty) + return nil, fmt.Errorf("invalid ttd: execution %v consensus %v", ttd, config.TerminalTotalDifficulty) + } + + if config.TerminalBlockHash != (common.Hash{}) { + if hash := api.les.BlockChain().GetCanonicalHash(uint64(config.TerminalBlockNumber)); hash == config.TerminalBlockHash { + return &beacon.TransitionConfigurationV1{ + TerminalTotalDifficulty: (*hexutil.Big)(ttd), + TerminalBlockHash: config.TerminalBlockHash, + TerminalBlockNumber: config.TerminalBlockNumber, + }, nil + } + return nil, fmt.Errorf("invalid terminal block hash") + } + + return &beacon.TransitionConfigurationV1{TerminalTotalDifficulty: (*hexutil.Big)(ttd)}, nil +} From a89b7addd462e73e1f1c48fc56a8766c15d6d2f7 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 15 Sep 2022 17:50:54 +0200 Subject: [PATCH 238/715] params: set TerminalTotalDifficultyPassed to true (#25769) * params: set TerminalTotalDifficultyPassed to true * Update params/config.go Co-authored-by: Martin Holst Swende --- params/config.go | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/params/config.go b/params/config.go index 64b5abb7cc9d..191a6c87205b 100644 --- a/params/config.go +++ b/params/config.go @@ -59,25 +59,26 @@ var ( // MainnetChainConfig is the chain parameters to run a node on the main network. MainnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(1_150_000), - DAOForkBlock: big.NewInt(1_920_000), - DAOForkSupport: true, - EIP150Block: big.NewInt(2_463_000), - EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), - EIP155Block: big.NewInt(2_675_000), - EIP158Block: big.NewInt(2_675_000), - ByzantiumBlock: big.NewInt(4_370_000), - ConstantinopleBlock: big.NewInt(7_280_000), - PetersburgBlock: big.NewInt(7_280_000), - IstanbulBlock: big.NewInt(9_069_000), - MuirGlacierBlock: big.NewInt(9_200_000), - BerlinBlock: big.NewInt(12_244_000), - LondonBlock: big.NewInt(12_965_000), - ArrowGlacierBlock: big.NewInt(13_773_000), - GrayGlacierBlock: big.NewInt(15_050_000), - TerminalTotalDifficulty: MainnetTerminalTotalDifficulty, // 58_750_000_000_000_000_000_000 - Ethash: new(EthashConfig), + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(1_150_000), + DAOForkBlock: big.NewInt(1_920_000), + DAOForkSupport: true, + EIP150Block: big.NewInt(2_463_000), + EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), + EIP155Block: big.NewInt(2_675_000), + EIP158Block: big.NewInt(2_675_000), + ByzantiumBlock: big.NewInt(4_370_000), + ConstantinopleBlock: big.NewInt(7_280_000), + PetersburgBlock: big.NewInt(7_280_000), + IstanbulBlock: big.NewInt(9_069_000), + MuirGlacierBlock: big.NewInt(9_200_000), + BerlinBlock: big.NewInt(12_244_000), + LondonBlock: big.NewInt(12_965_000), + ArrowGlacierBlock: big.NewInt(13_773_000), + GrayGlacierBlock: big.NewInt(15_050_000), + TerminalTotalDifficulty: MainnetTerminalTotalDifficulty, // 58_750_000_000_000_000_000_000 + TerminalTotalDifficultyPassed: true, + Ethash: new(EthashConfig), } // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network. From 57a65f00c9518dd29b876e72756a287d0d365012 Mon Sep 17 00:00:00 2001 From: Amir Hossein <77993374+Kamandlou@users.noreply.github.com> Date: Fri, 16 Sep 2022 02:05:53 +0430 Subject: [PATCH 239/715] trie: handle more batch commit errors in Database (#25674) --- trie/database.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/trie/database.go b/trie/database.go index 79de0ed65c48..30120570ab57 100644 --- a/trie/database.go +++ b/trie/database.go @@ -662,8 +662,9 @@ func (db *Database) Commit(node common.Hash, report bool, callback func(common.H // Uncache any leftovers in the last batch db.lock.Lock() defer db.lock.Unlock() - - batch.Replay(uncacher) + if err := batch.Replay(uncacher); err != nil { + return err + } batch.Reset() // Reset the storage counters and bumped metrics @@ -711,9 +712,12 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane return err } db.lock.Lock() - batch.Replay(uncacher) + err := batch.Replay(uncacher) batch.Reset() db.lock.Unlock() + if err != nil { + return err + } } return nil } From 83989a19be58a49c609ade9e9d996cf78853e21d Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 16 Sep 2022 17:33:48 +0800 Subject: [PATCH 240/715] core/rawdb: fix leak of backoff timer (#25776) --- core/rawdb/chain_freezer.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 7d9c9c015649..212ec73ed73d 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -92,6 +92,8 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { backoff bool triggered chan struct{} // Used in tests ) + timer := time.NewTimer(freezerRecheckInterval) + defer timer.Stop() for { select { case <-f.quit: @@ -106,8 +108,9 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { triggered = nil } select { - case <-time.NewTimer(freezerRecheckInterval).C: + case <-timer.C: backoff = false + timer.Reset(freezerRecheckInterval) case triggered = <-f.trigger: backoff = false case <-f.quit: From d213cb0924a75273a6d6b4edb5d9ffcbeae49c3e Mon Sep 17 00:00:00 2001 From: George Carder Date: Fri, 16 Sep 2022 02:40:42 -0700 Subject: [PATCH 241/715] crypto/bls12381: docfix of g1 Affine (#25729) bls12381: docfix of g1 Affine. --- crypto/bls12381/g1.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/bls12381/g1.go b/crypto/bls12381/g1.go index d853823cd298..52e12cc3a259 100644 --- a/crypto/bls12381/g1.go +++ b/crypto/bls12381/g1.go @@ -228,7 +228,7 @@ func (g *G1) IsAffine(p *PointG1) bool { return p[2].isOne() } -// Add adds two G1 points p1, p2 and assigns the result to point at first argument. +// Affine calculates affine form of given G1 point. func (g *G1) Affine(p *PointG1) *PointG1 { if g.IsZero(p) { return p From 8ade5e6c144afb7ac389ae28b50cb68a0dbec7b8 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Fri, 16 Sep 2022 18:16:32 +0200 Subject: [PATCH 242/715] internal/ethapi: return error when requesting invalid trie key (#25762) This change makes eth_getProof and eth_getStorageAt return an error when the argument contains invalid hex in storage keys. Co-authored-by: Felix Lange --- internal/ethapi/api.go | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index ac2fab4018d5..2e410605222c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -18,6 +18,7 @@ package ethapi import ( "context" + "encoding/hex" "errors" "fmt" "math/big" @@ -674,15 +675,19 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st } // create the proof for the storageKeys - for i, key := range storageKeys { + for i, hexKey := range storageKeys { + key, err := decodeHash(hexKey) + if err != nil { + return nil, err + } if storageTrie != nil { - proof, storageError := state.GetStorageProof(address, common.HexToHash(key)) + proof, storageError := state.GetStorageProof(address, key) if storageError != nil { return nil, storageError } - storageProof[i] = StorageResult{key, (*hexutil.Big)(state.GetState(address, common.HexToHash(key)).Big()), toHexSlice(proof)} + storageProof[i] = StorageResult{hexKey, (*hexutil.Big)(state.GetState(address, key).Big()), toHexSlice(proof)} } else { - storageProof[i] = StorageResult{key, &hexutil.Big{}, []string{}} + storageProof[i] = StorageResult{hexKey, &hexutil.Big{}, []string{}} } } @@ -703,6 +708,22 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st }, state.Error() } +// decodeHash parses a hex-encoded 32-byte hash. The input may optionally +// be prefixed by 0x and can have an byte length up to 32. +func decodeHash(s string) (common.Hash, error) { + if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") { + s = s[2:] + } + b, err := hex.DecodeString(s) + if err != nil { + return common.Hash{}, fmt.Errorf("hex string invalid") + } + if len(b) > 32 { + return common.Hash{}, fmt.Errorf("hex string too long, want at most 32 bytes") + } + return common.BytesToHash(b), nil +} + // GetHeaderByNumber returns the requested canonical block header. // * When blockNr is -1 the chain head is returned. // * When blockNr is -2 the pending chain head is returned. @@ -821,12 +842,16 @@ func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blo // GetStorageAt returns the storage from the state at the given address, key and // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block // numbers are also allowed. -func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { +func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } - res := state.GetState(address, common.HexToHash(key)) + key, err := decodeHash(hexKey) + if err != nil { + return nil, fmt.Errorf("unable to decode storage key: %s", err) + } + res := state.GetState(address, key) return res[:], state.Error() } From ada603fab5c854b36a1d7d9af0ba5aeeafa49d15 Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Sat, 17 Sep 2022 01:23:13 +0900 Subject: [PATCH 243/715] core: don't cache zero nonce in txNoncer (#25603) This changes the nonce cache used by TxPool to not store cached nonces for non-existing accounts. --- core/tx_noncer.go | 8 ++++++-- core/tx_pool.go | 3 --- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/tx_noncer.go b/core/tx_noncer.go index 51fa8cf5a1f9..257beffa06c6 100644 --- a/core/tx_noncer.go +++ b/core/tx_noncer.go @@ -49,7 +49,9 @@ func (txn *txNoncer) get(addr common.Address) uint64 { defer txn.lock.Unlock() if _, ok := txn.nonces[addr]; !ok { - txn.nonces[addr] = txn.fallback.GetNonce(addr) + if nonce := txn.fallback.GetNonce(addr); nonce != 0 { + txn.nonces[addr] = nonce + } } return txn.nonces[addr] } @@ -70,7 +72,9 @@ func (txn *txNoncer) setIfLower(addr common.Address, nonce uint64) { defer txn.lock.Unlock() if _, ok := txn.nonces[addr]; !ok { - txn.nonces[addr] = txn.fallback.GetNonce(addr) + if nonce := txn.fallback.GetNonce(addr); nonce != 0 { + txn.nonces[addr] = nonce + } } if txn.nonces[addr] <= nonce { return diff --git a/core/tx_pool.go b/core/tx_pool.go index ee8b9f7a43f0..22328963dfb1 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -463,9 +463,6 @@ func (pool *TxPool) SetGasPrice(price *big.Int) { // Nonce returns the next nonce of an account, with all transactions executable // by the pool already applied on top. func (pool *TxPool) Nonce(addr common.Address) uint64 { - pool.mu.RLock() - defer pool.mu.RUnlock() - return pool.pendingNonces.get(addr) } From 8e5201551dab455eff7c8413dc682dad29dec0cd Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Sat, 17 Sep 2022 21:27:10 +0200 Subject: [PATCH 244/715] core: more compact bad block report (#25714) This shortens the chain config summary in bad block reports, and adds go-ethereum version information as well. Co-authored-by: Felix Lange --- core/badblock.go | 157 +++++++++++++++++++++++++++++++++++++++++++++ core/blockchain.go | 21 +----- les/client.go | 2 +- params/config.go | 4 +- 4 files changed, 162 insertions(+), 22 deletions(-) create mode 100644 core/badblock.go diff --git a/core/badblock.go b/core/badblock.go new file mode 100644 index 000000000000..a2fdfac714da --- /dev/null +++ b/core/badblock.go @@ -0,0 +1,157 @@ +// Copyright 2022 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 core + +import ( + "fmt" + "runtime" + "runtime/debug" + "strings" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" +) + +const ourPath = "github.com/ethereum/go-ethereum" // Path to our module + +// summarizeBadBlock returns a string summarizing the bad block and other +// relevant information. +func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *params.ChainConfig, err error) string { + var receiptString string + for i, receipt := range receipts { + receiptString += fmt.Sprintf("\n %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x", + i, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.ContractAddress.Hex(), + receipt.Status, receipt.TxHash.Hex(), receipt.Logs, receipt.Bloom, receipt.PostState) + } + version, vcs := runtimeInfo() + platform := fmt.Sprintf("%s %s %s %s", version, runtime.Version(), runtime.GOARCH, runtime.GOOS) + if vcs != "" { + vcs = fmt.Sprintf("\nVCS: %s", vcs) + } + return fmt.Sprintf(` +########## BAD BLOCK ######### +Block: %v (%#x) +Error: %v +Platform: %v%v +Chain config: %#v +Receipts: %v +############################## +`, block.Number(), block.Hash(), err, platform, vcs, config, receiptString) +} + +// runtimeInfo returns build and platform information about the current binary. +// +// If the package that is currently executing is a prefixed by our go-ethereum +// module path, it will print out commit and date VCS information. Otherwise, +// it will assume it's imported by a third-party and will return the imported +// version and whether it was replaced by another module. +func runtimeInfo() (string, string) { + var ( + version = params.VersionWithMeta + vcs = "" + buildInfo, ok = debug.ReadBuildInfo() + ) + if ok { + version = versionInfo(buildInfo) + if status, ok := vcsInfo(buildInfo); ok { + modified := "" + if status.modified { + modified = " (dirty)" + } + vcs = status.revision + "-" + status.time + modified + } + } + return version, vcs +} + +// versionInfo returns version information for the currently executing +// implementation. +// +// Depending on how the code is instansiated, it returns different amounts of +// information. If it is unable to determine which module is related to our +// package it falls back to the hardcoded values in the params package. +func versionInfo(info *debug.BuildInfo) string { + // If the main package is from our repo, prefix version with "geth". + if strings.HasPrefix(info.Path, ourPath) { + return fmt.Sprintf("geth %s", info.Main.Version) + } + // Not our main package, so explicitly print out the module path and + // version. + var version string + if info.Main.Path != "" && info.Main.Version != "" { + // These can be empty when invoked with "go run". + version = fmt.Sprintf("%s@%s ", info.Main.Path, info.Main.Version) + } + mod := findModule(info, ourPath) + if mod == nil { + // If our module path wasn't imported, it's unclear which + // version of our code they are running. Fallback to hardcoded + // version. + return version + fmt.Sprintf("geth %s", params.VersionWithMeta) + } + // Our package is a dependency for the main module. Return path and + // version data for both. + version += fmt.Sprintf("%s@%s", mod.Path, mod.Version) + if mod.Replace != nil { + // If our package was replaced by something else, also note that. + version += fmt.Sprintf(" (replaced by %s@%s)", mod.Replace.Path, mod.Replace.Version) + } + return version +} + +type status struct { + revision string + time string + modified bool +} + +// vcsInfo returns VCS information of the build. +func vcsInfo(info *debug.BuildInfo) (s status, ok bool) { + for _, v := range info.Settings { + switch v.Key { + case "vcs.revision": + if len(v.Value) < 8 { + s.revision = v.Value + } else { + s.revision = v.Value[:8] + } + case "vcs.modified": + if v.Value == "true" { + s.modified = true + } + case "vcs.time": + s.time = v.Value + } + } + if s.revision != "" && s.time != "" { + ok = true + } + return +} + +// findModule returns the module at path. +func findModule(info *debug.BuildInfo, path string) *debug.Module { + if info.Path == ourPath { + return &info.Main + } + for _, mod := range info.Deps { + if mod.Path == path { + return mod + } + } + return nil +} diff --git a/core/blockchain.go b/core/blockchain.go index f73bbb09c226..eec9c772124f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -239,7 +239,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } log.Info("") log.Info(strings.Repeat("-", 153)) - for _, line := range strings.Split(chainConfig.String(), "\n") { + for _, line := range strings.Split(chainConfig.Description(), "\n") { log.Info(line) } log.Info(strings.Repeat("-", 153)) @@ -2375,24 +2375,7 @@ func (bc *BlockChain) maintainTxIndex(ancients uint64) { // reportBlock logs a bad block error. func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) { rawdb.WriteBadBlock(bc.db, block) - - var receiptString string - for i, receipt := range receipts { - receiptString += fmt.Sprintf("\t %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x\n", - i, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.ContractAddress.Hex(), - receipt.Status, receipt.TxHash.Hex(), receipt.Logs, receipt.Bloom, receipt.PostState) - } - log.Error(fmt.Sprintf(` -########## BAD BLOCK ######### -Chain config: %v - -Number: %v -Hash: %#x -%v - -Error: %v -############################## -`, bc.chainConfig, block.Number(), block.Hash(), receiptString, err)) + log.Error(summarizeBadBlock(block, receipts, bc.Config(), err)) } // InsertHeaderChain attempts to insert the given header chain in to the local diff --git a/les/client.go b/les/client.go index 6e6beeb0001a..c304bf86f8a8 100644 --- a/les/client.go +++ b/les/client.go @@ -105,7 +105,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { } log.Info("") log.Info(strings.Repeat("-", 153)) - for _, line := range strings.Split(chainConfig.String(), "\n") { + for _, line := range strings.Split(chainConfig.Description(), "\n") { log.Info(line) } log.Info(strings.Repeat("-", 153)) diff --git a/params/config.go b/params/config.go index 191a6c87205b..22b36b7d68e3 100644 --- a/params/config.go +++ b/params/config.go @@ -407,8 +407,8 @@ func (c *CliqueConfig) String() string { return "clique" } -// String implements the fmt.Stringer interface. -func (c *ChainConfig) String() string { +// Description returns a human-readable description of ChainConfig. +func (c *ChainConfig) Description() string { var banner string // Create some basinc network config output From 468d1844c7a32b51eebce6c5f35c44a66b9acf64 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 19 Sep 2022 10:04:16 +0200 Subject: [PATCH 245/715] core: move build version reading to its own package (#25806) This fixes the build with Go 1.17, which does not have BuildInfo.Settings yet. --- core/blockchain.go | 27 ++++++ internal/version/vcs_fallback.go | 28 ++++++ internal/version/vcs_go1.18.go | 48 ++++++++++ .../version/version.go | 92 ++++--------------- 4 files changed, 123 insertions(+), 72 deletions(-) create mode 100644 internal/version/vcs_fallback.go create mode 100644 internal/version/vcs_go1.18.go rename core/badblock.go => internal/version/version.go (61%) diff --git a/core/blockchain.go b/core/blockchain.go index eec9c772124f..fe127b5ea8ab 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -22,6 +22,7 @@ import ( "fmt" "io" "math/big" + "runtime" "sort" "strings" "sync" @@ -40,6 +41,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/syncx" + "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" @@ -2378,6 +2380,31 @@ func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, e log.Error(summarizeBadBlock(block, receipts, bc.Config(), err)) } +// summarizeBadBlock returns a string summarizing the bad block and other +// relevant information. +func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *params.ChainConfig, err error) string { + var receiptString string + for i, receipt := range receipts { + receiptString += fmt.Sprintf("\n %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x", + i, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.ContractAddress.Hex(), + receipt.Status, receipt.TxHash.Hex(), receipt.Logs, receipt.Bloom, receipt.PostState) + } + version, vcs := version.Info() + platform := fmt.Sprintf("%s %s %s %s", version, runtime.Version(), runtime.GOARCH, runtime.GOOS) + if vcs != "" { + vcs = fmt.Sprintf("\nVCS: %s", vcs) + } + return fmt.Sprintf(` +########## BAD BLOCK ######### +Block: %v (%#x) +Error: %v +Platform: %v%v +Chain config: %#v +Receipts: %v +############################## +`, block.Number(), block.Hash(), err, platform, vcs, config, receiptString) +} + // InsertHeaderChain attempts to insert the given header chain in to the local // chain, possibly creating a reorg. If an error is returned, it will return the // index number of the failing header as well an error describing what went wrong. diff --git a/internal/version/vcs_fallback.go b/internal/version/vcs_fallback.go new file mode 100644 index 000000000000..6d7f32e735f9 --- /dev/null +++ b/internal/version/vcs_fallback.go @@ -0,0 +1,28 @@ +// Copyright 2022 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 !go1.18 +// +build !go1.18 + +package version + +import "runtime/debug" + +// In Go versions before 1.18, VCS information is not available. + +func vcsInfo(info *debug.BuildInfo) (gitStatus, bool) { + return gitStatus{}, false +} diff --git a/internal/version/vcs_go1.18.go b/internal/version/vcs_go1.18.go new file mode 100644 index 000000000000..d5b9c97a1666 --- /dev/null +++ b/internal/version/vcs_go1.18.go @@ -0,0 +1,48 @@ +// Copyright 2022 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 go1.18 +// +build go1.18 + +package version + +import "runtime/debug" + +// In go 1.18 and beyond, the go tool embeds VCS information into the build. + +// vcsInfo returns VCS information of the build. +func vcsInfo(info *debug.BuildInfo) (s gitStatus, ok bool) { + for _, v := range info.Settings { + switch v.Key { + case "vcs.revision": + if len(v.Value) < 8 { + s.revision = v.Value + } else { + s.revision = v.Value[:8] + } + case "vcs.modified": + if v.Value == "true" { + s.modified = true + } + case "vcs.time": + s.time = v.Value + } + } + if s.revision != "" && s.time != "" { + ok = true + } + return +} diff --git a/core/badblock.go b/internal/version/version.go similarity index 61% rename from core/badblock.go rename to internal/version/version.go index a2fdfac714da..e4b9ee490768 100644 --- a/core/badblock.go +++ b/internal/version/version.go @@ -14,70 +14,48 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package core +// Package version implements reading of build version information. +package version import ( "fmt" - "runtime" "runtime/debug" "strings" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) const ourPath = "github.com/ethereum/go-ethereum" // Path to our module -// summarizeBadBlock returns a string summarizing the bad block and other -// relevant information. -func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *params.ChainConfig, err error) string { - var receiptString string - for i, receipt := range receipts { - receiptString += fmt.Sprintf("\n %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x", - i, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.ContractAddress.Hex(), - receipt.Status, receipt.TxHash.Hex(), receipt.Logs, receipt.Bloom, receipt.PostState) - } - version, vcs := runtimeInfo() - platform := fmt.Sprintf("%s %s %s %s", version, runtime.Version(), runtime.GOARCH, runtime.GOOS) - if vcs != "" { - vcs = fmt.Sprintf("\nVCS: %s", vcs) - } - return fmt.Sprintf(` -########## BAD BLOCK ######### -Block: %v (%#x) -Error: %v -Platform: %v%v -Chain config: %#v -Receipts: %v -############################## -`, block.Number(), block.Hash(), err, platform, vcs, config, receiptString) -} - // runtimeInfo returns build and platform information about the current binary. // // If the package that is currently executing is a prefixed by our go-ethereum // module path, it will print out commit and date VCS information. Otherwise, // it will assume it's imported by a third-party and will return the imported // version and whether it was replaced by another module. -func runtimeInfo() (string, string) { - var ( - version = params.VersionWithMeta - vcs = "" - buildInfo, ok = debug.ReadBuildInfo() - ) - if ok { - version = versionInfo(buildInfo) - if status, ok := vcsInfo(buildInfo); ok { - modified := "" - if status.modified { - modified = " (dirty)" - } - vcs = status.revision + "-" + status.time + modified +func Info() (version, vcs string) { + version = params.VersionWithMeta + buildInfo, ok := debug.ReadBuildInfo() + if !ok { + return version, "" + } + version = versionInfo(buildInfo) + if status, ok := vcsInfo(buildInfo); ok { + modified := "" + if status.modified { + modified = " (dirty)" } + vcs = status.revision + "-" + status.time + modified } return version, vcs } +type gitStatus struct { + revision string + time string + modified bool +} + // versionInfo returns version information for the currently executing // implementation. // @@ -113,36 +91,6 @@ func versionInfo(info *debug.BuildInfo) string { return version } -type status struct { - revision string - time string - modified bool -} - -// vcsInfo returns VCS information of the build. -func vcsInfo(info *debug.BuildInfo) (s status, ok bool) { - for _, v := range info.Settings { - switch v.Key { - case "vcs.revision": - if len(v.Value) < 8 { - s.revision = v.Value - } else { - s.revision = v.Value[:8] - } - case "vcs.modified": - if v.Value == "true" { - s.modified = true - } - case "vcs.time": - s.time = v.Value - } - } - if s.revision != "" && s.time != "" { - ok = true - } - return -} - // findModule returns the module at path. func findModule(info *debug.BuildInfo, path string) *debug.Module { if info.Path == ourPath { From d728ba97d89ef4f44fa38a06418d3db7a08ce549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 20 Sep 2022 14:14:24 +0300 Subject: [PATCH 246/715] eth: fix a rare datarace on CHT challenge reply / shutdown --- eth/handler.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/eth/handler.go b/eth/handler.go index 4224a9f33a84..143147b0c815 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -391,11 +391,16 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { if h.checkpointHash != (common.Hash{}) { // Request the peer's checkpoint header for chain height/weight validation resCh := make(chan *eth.Response) - if _, err := peer.RequestHeadersByNumber(h.checkpointNumber, 1, 0, false, resCh); err != nil { + + req, err := peer.RequestHeadersByNumber(h.checkpointNumber, 1, 0, false, resCh) + if err != nil { return err } // Start a timer to disconnect if the peer doesn't reply in time go func() { + // Ensure the request gets cancelled in case of error/drop + defer req.Close() + timeout := time.NewTimer(syncChallengeTimeout) defer timeout.Stop() @@ -437,10 +442,15 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { // If we have any explicit peer required block hashes, request them for number, hash := range h.requiredBlocks { resCh := make(chan *eth.Response) - if _, err := peer.RequestHeadersByNumber(number, 1, 0, false, resCh); err != nil { + + req, err := peer.RequestHeadersByNumber(number, 1, 0, false, resCh) + if err != nil { return err } - go func(number uint64, hash common.Hash) { + go func(number uint64, hash common.Hash, req *eth.Request) { + // Ensure the request gets cancelled in case of error/drop + defer req.Close() + timeout := time.NewTimer(syncChallengeTimeout) defer timeout.Stop() @@ -469,7 +479,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { peer.Log().Warn("Required block challenge timed out, dropping", "addr", peer.RemoteAddr(), "type", peer.Name()) h.removePeer(peer.ID()) } - }(number, hash) + }(number, hash, req) } // Handle incoming messages until the connection is torn down return handler(peer) From d8ada03eacbb54c18105f6c3f6f6d6ff4536f5b0 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 20 Sep 2022 06:58:03 -0600 Subject: [PATCH 247/715] core/vm: return copy of input slice in identity precompile, avoid returndata copy (#25183) * core/vm: return copy of input slice in identity precompile. don't deep copy return data slice upon call completion * make use of common.CopyBytes --- core/vm/contracts.go | 2 +- core/vm/instructions.go | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 3a6b956ebc45..44aa930d47a3 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -235,7 +235,7 @@ func (c *dataCopy) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas } func (c *dataCopy) Run(in []byte) ([]byte, error) { - return in, nil + return common.CopyBytes(in), nil } // bigModExp implements a native big integer exponential modular operation. diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 104bf6d75ff0..12490025f511 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -697,7 +697,6 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt } stack.push(&temp) if err == nil || err == ErrExecutionReverted { - ret = common.CopyBytes(ret) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } scope.Contract.Gas += returnGas @@ -733,7 +732,6 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ } stack.push(&temp) if err == nil || err == ErrExecutionReverted { - ret = common.CopyBytes(ret) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } scope.Contract.Gas += returnGas @@ -762,7 +760,6 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext } stack.push(&temp) if err == nil || err == ErrExecutionReverted { - ret = common.CopyBytes(ret) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } scope.Contract.Gas += returnGas @@ -791,7 +788,6 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) } stack.push(&temp) if err == nil || err == ErrExecutionReverted { - ret = common.CopyBytes(ret) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } scope.Contract.Gas += returnGas From 338bb2e36c3a2c81e786ab255dd1b9bf762fb95d Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Wed, 21 Sep 2022 09:49:17 +0200 Subject: [PATCH 248/715] core/blockchain: downgrade tx indexing and unindexing logs (#25832) core/blockchain: downgrade tx indexing and unindexing logs from info to debug If a user has a finite tx lookup limit, they will see an "unindexing" info level log each time a block is imported. This information might help a user understand that they are removing the index each block and some txs may not be retrievable by hash, but overall it is generally more of a nuisance than a benefit. This change downgrades the log to a debug log. --- core/rawdb/chain_iterator.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 867fed63ad92..121f6d39dda3 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -243,7 +243,7 @@ func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan case <-interrupt: log.Debug("Transaction indexing interrupted", "blocks", blocks, "txs", txs, "tail", lastNum, "elapsed", common.PrettyDuration(time.Since(start))) default: - log.Info("Indexed transactions", "blocks", blocks, "txs", txs, "tail", lastNum, "elapsed", common.PrettyDuration(time.Since(start))) + log.Debug("Indexed transactions", "blocks", blocks, "txs", txs, "tail", lastNum, "elapsed", common.PrettyDuration(time.Since(start))) } } @@ -335,7 +335,7 @@ func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt ch case <-interrupt: log.Debug("Transaction unindexing interrupted", "blocks", blocks, "txs", txs, "tail", to, "elapsed", common.PrettyDuration(time.Since(start))) default: - log.Info("Unindexed transactions", "blocks", blocks, "txs", txs, "tail", to, "elapsed", common.PrettyDuration(time.Since(start))) + log.Debug("Unindexed transactions", "blocks", blocks, "txs", txs, "tail", to, "elapsed", common.PrettyDuration(time.Since(start))) } } From 5d11d38f4dc292103d05cd3f115b377663ff87ec Mon Sep 17 00:00:00 2001 From: makcandrov <108467407+makcandrov@users.noreply.github.com> Date: Wed, 21 Sep 2022 00:55:48 -0700 Subject: [PATCH 249/715] eth/tracers: fix trace config for `TraceCall` (#25821) Co-authored-by: AtomicAzzaz Co-authored-by: ewile --- eth/tracers/api.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 0cf2f45a8729..1e04bea411f3 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -895,12 +895,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc var traceConfig *TraceConfig if config != nil { - traceConfig = &TraceConfig{ - Config: config.Config, - Tracer: config.Tracer, - Timeout: config.Timeout, - Reexec: config.Reexec, - } + traceConfig = &config.TraceConfig } return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig) } From 6eb8f3225e23f392705a072b534627a9ff637fe1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 21 Sep 2022 13:48:09 +0200 Subject: [PATCH 250/715] eth/catalyst: add locking around newpayload (#25816) Sometimes we get stuck on db compaction, and the CL re-issues the "same" command to us multiple times. Each request get stuck on the same place, in the middle of the handler. This changes makes it so we do not reprocess the same payload, but instead detects it early. --- eth/catalyst/api.go | 17 ++++++ eth/catalyst/api_test.go | 112 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 124 insertions(+), 5 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 754d8b214ca7..2756a02e2f6d 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -120,6 +120,7 @@ type ConsensusAPI struct { lastNewPayloadLock sync.Mutex forkchoiceLock sync.Mutex // Lock for the forkChoiceUpdated method + newPayloadLock sync.Mutex // Lock for the NewPayload method } // NewConsensusAPI creates a new consensus api for the given backend. @@ -342,6 +343,22 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.Execu // NewPayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.PayloadStatusV1, error) { + // The locking here is, strictly, not required. Without these locks, this can happen: + // + // 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to + // api.eth.BlockChain().InsertBlockWithoutSetHead, where it is blocked on + // e.g database compaction. + // 2. The call times out on the CL layer, which issues another NewPayload (execdata-N) call. + // Similarly, this also get stuck on the same place. Importantly, since the + // first call has not gone through, the early checks for "do we already have this block" + // will all return false. + // 3. When the db compaction ends, then N calls inserting the same payload are processed + // sequentially. + // Hence, we use a lock here, to be sure that the previous call has finished before we + // check whether we already have the block locally. + api.newPayloadLock.Lock() + defer api.newPayloadLock.Unlock() + log.Trace("Engine API request received", "method", "ExecutePayload", "number", params.Number, "hash", params.BlockHash) block, err := beacon.ExecutableDataToBlock(params) if err != nil { diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index ae53462ff812..ec26f35e8d7d 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "math/big" + "sync" "testing" "time" @@ -277,10 +278,12 @@ func TestEth2NewBlock(t *testing.T) { t.Fatalf("Failed to convert executable data to block %v", err) } newResp, err := api.NewPayloadV1(*execData) - if err != nil || newResp.Status != "VALID" { + switch { + case err != nil: t.Fatalf("Failed to insert block: %v", err) - } - if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1 { + case newResp.Status != "VALID": + t.Fatalf("Failed to insert block: %v", newResp.Status) + case ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1: t.Fatalf("Chain head shouldn't be updated") } checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) @@ -292,8 +295,8 @@ func TestEth2NewBlock(t *testing.T) { if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { t.Fatalf("Failed to insert block: %v", err) } - if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() { - t.Fatalf("Chain head should be updated") + if have, want := ethservice.BlockChain().CurrentBlock().NumberU64(), block.NumberU64(); have != want { + t.Fatalf("Chain head should be updated, have %d want %d", have, want) } checkLogEvents(t, newLogCh, rmLogsCh, 1, 0) @@ -855,3 +858,102 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status) } } + +// TestSimultaneousNewBlock does several parallel inserts, both as +// newPayLoad and forkchoiceUpdate. This is to test that the api behaves +// well even of the caller is not being 'serial'. +func TestSimultaneousNewBlock(t *testing.T) { + genesis, preMergeBlocks := generatePreMergeChain(10) + n, ethservice := startEthService(t, genesis, preMergeBlocks) + defer n.Close() + + var ( + api = NewConsensusAPI(ethservice) + parent = preMergeBlocks[len(preMergeBlocks)-1] + ) + for i := 0; i < 10; i++ { + statedb, _ := ethservice.BlockChain().StateAt(parent.Root()) + ethservice.TxPool().AddLocal(types.MustSignNewTx(testKey, types.LatestSigner(ethservice.BlockChain().Config()), + &types.DynamicFeeTx{ + Nonce: statedb.GetNonce(testAddr), + Value: big.NewInt(0), + GasFeeCap: big.NewInt(2 * params.InitialBaseFee), + GasTipCap: big.NewInt(2 * params.InitialBaseFee), + ChainID: genesis.Config.ChainID, + Gas: 1000000, + To: &common.Address{99}, + })) + execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{ + Timestamp: parent.Time() + 5, + }) + if err != nil { + t.Fatalf("Failed to create the executable data %v", err) + } + // Insert it 10 times in parallel. Should be ignored. + { + var ( + wg sync.WaitGroup + testErr error + errMu sync.Mutex + ) + wg.Add(10) + for ii := 0; ii < 10; ii++ { + go func() { + defer wg.Done() + if newResp, err := api.NewPayloadV1(*execData); err != nil { + errMu.Lock() + testErr = fmt.Errorf("Failed to insert block: %w", err) + errMu.Unlock() + } else if newResp.Status != "VALID" { + errMu.Lock() + testErr = fmt.Errorf("Failed to insert block: %v", newResp.Status) + errMu.Unlock() + } + }() + } + wg.Wait() + if testErr != nil { + t.Fatal(testErr) + } + } + block, err := beacon.ExecutableDataToBlock(*execData) + if err != nil { + t.Fatalf("Failed to convert executable data to block %v", err) + } + if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1 { + t.Fatalf("Chain head shouldn't be updated") + } + fcState := beacon.ForkchoiceStateV1{ + HeadBlockHash: block.Hash(), + SafeBlockHash: block.Hash(), + FinalizedBlockHash: block.Hash(), + } + { + var ( + wg sync.WaitGroup + testErr error + errMu sync.Mutex + ) + wg.Add(10) + // Do each FCU 10 times + for ii := 0; ii < 10; ii++ { + go func() { + defer wg.Done() + if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { + errMu.Lock() + testErr = fmt.Errorf("Failed to insert block: %w", err) + errMu.Unlock() + } + }() + } + wg.Wait() + if testErr != nil { + t.Fatal(testErr) + } + } + if have, want := ethservice.BlockChain().CurrentBlock().NumberU64(), block.NumberU64(); have != want { + t.Fatalf("Chain head should be updated, have %d want %d", have, want) + } + parent = block + } +} From 400ab0d94f455b7ac207dc58faa3b27d7aebee7a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 21 Sep 2022 15:12:45 +0200 Subject: [PATCH 251/715] eth/catalyst: make tests run faster (#25818) --- eth/catalyst/api_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index ec26f35e8d7d..480a30b52dc5 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -414,7 +414,6 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) n.Close() t.Fatal("can't import test blocks:", err) } - time.Sleep(500 * time.Millisecond) // give txpool enough time to consume head event ethservice.SetEtherbase(testAddr) ethservice.SetSynced() From 6215b925237c3727286c3e1b560bc370a97963c4 Mon Sep 17 00:00:00 2001 From: Delweng Date: Thu, 22 Sep 2022 21:43:47 +0800 Subject: [PATCH 252/715] cmd/utils: make --authrpc.jwtsecret a DirectoryFlag (#25849) Signed-off-by: Delweng --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index fb2aa7c21587..4017f210891d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -631,7 +631,7 @@ var ( Value: strings.Join(node.DefaultConfig.AuthVirtualHosts, ","), Category: flags.APICategory, } - JWTSecretFlag = &cli.StringFlag{ + JWTSecretFlag = &flags.DirectoryFlag{ Name: "authrpc.jwtsecret", Usage: "Path to a JWT secret to use for authenticated RPC endpoints", Category: flags.APICategory, From fb500d12d546c6b76f771fa7da5cbbdb61451be7 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 23 Sep 2022 10:11:41 +0200 Subject: [PATCH 253/715] eth/protocols/snap: make log messages more clear that sync is ongoing (#25837) * eth/protocols/snap: make log messages more clear that sync is ongoing * Update sync.go Co-authored-by: Felix Lange --- eth/protocols/snap/sync.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index eb8260bf7c97..e23693789723 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -2962,7 +2962,7 @@ func (s *Syncer) reportSyncProgress(force bool) { storage = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.storageSynced), s.storageBytes.TerminalString()) bytecode = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.bytecodeSynced), s.bytecodeBytes.TerminalString()) ) - log.Info("State sync in progress", "synced", progress, "state", synced, + log.Info("Syncing: state download in progress", "synced", progress, "state", synced, "accounts", accounts, "slots", storage, "codes", bytecode, "eta", common.PrettyDuration(estTime-elapsed)) } @@ -2981,7 +2981,7 @@ func (s *Syncer) reportHealProgress(force bool) { accounts = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.accountHealed), s.accountHealedBytes.TerminalString()) storage = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(s.storageHealed), s.storageHealedBytes.TerminalString()) ) - log.Info("State heal in progress", "accounts", accounts, "slots", storage, + log.Info("Syncing: state healing in progress", "accounts", accounts, "slots", storage, "codes", bytecode, "nodes", trienode, "pending", s.healer.scheduler.Pending()) } From 220bdd3277e677dd3dfe80483f53158b794df1e8 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Fri, 23 Sep 2022 10:25:16 +0200 Subject: [PATCH 254/715] .github: add CL client to issue template (#25814) --- .github/ISSUE_TEMPLATE/bug.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 2aa2c48a600b..45bfd986ac6e 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -9,6 +9,7 @@ assignees: '' #### System information Geth version: `geth version` +CL client & version: e.g. lighthouse/nimbus/prysm@v1.0.0 OS & Version: Windows/Linux/OSX Commit hash : (if `develop`) @@ -27,4 +28,4 @@ Commit hash : (if `develop`) [backtrace] ```` -When submitting logs: please submit them as text and not screenshots. \ No newline at end of file +When submitting logs: please submit them as text and not screenshots. From e6d4aedb8c9ee24431f748d5caba165ce92faae5 Mon Sep 17 00:00:00 2001 From: "Boqin@MetaSecureLabs" Date: Fri, 23 Sep 2022 16:51:12 +0800 Subject: [PATCH 255/715] p2p: add channel buffers to avoid goroutine leaks in tests (#24929) --- p2p/discover/v4_udp_test.go | 2 +- p2p/dnsdisc/client_test.go | 2 +- p2p/simulations/examples/ping-pong.go | 2 +- p2p/simulations/http_test.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index e00bf2784cb0..f4fd9b246fd3 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -313,7 +313,7 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) { test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.IP, time.Now()) // queue a pending findnode request - resultc, errc := make(chan []*node), make(chan error) + resultc, errc := make(chan []*node, 1), make(chan error, 1) go func() { rid := encodePubkey(&test.remotekey.PublicKey).id() ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget) diff --git a/p2p/dnsdisc/client_test.go b/p2p/dnsdisc/client_test.go index 0a9a96e62167..93380fdcd3eb 100644 --- a/p2p/dnsdisc/client_test.go +++ b/p2p/dnsdisc/client_test.go @@ -265,7 +265,7 @@ func TestIteratorEmptyTree(t *testing.T) { resolver.add(tree1.ToTXT("n")) // Start the iterator. - node := make(chan *enode.Node) + node := make(chan *enode.Node, 1) it, err := c.NewIterator(url) if err != nil { t.Fatal(err) diff --git a/p2p/simulations/examples/ping-pong.go b/p2p/simulations/examples/ping-pong.go index 2f4c56054876..d9b51dc09bb0 100644 --- a/p2p/simulations/examples/ping-pong.go +++ b/p2p/simulations/examples/ping-pong.go @@ -139,7 +139,7 @@ const ( func (p *pingPongService) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { log := p.log.New("peer.id", peer.ID()) - errC := make(chan error) + errC := make(chan error, 1) go func() { for range time.Tick(10 * time.Second) { log.Info("sending ping") diff --git a/p2p/simulations/http_test.go b/p2p/simulations/http_test.go index 5775977a41f0..05e43238abb5 100644 --- a/p2p/simulations/http_test.go +++ b/p2p/simulations/http_test.go @@ -596,7 +596,7 @@ func TestHTTPSnapshot(t *testing.T) { network, s := testHTTPServer(t) defer s.Close() - var eventsDone = make(chan struct{}) + var eventsDone = make(chan struct{}, 1) count := 1 eventsDoneChan := make(chan *Event) eventSub := network.Events().Subscribe(eventsDoneChan) From 65f3c1b46fa0f247cc774643aa4cb938bbed184b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 23 Sep 2022 14:08:25 +0200 Subject: [PATCH 256/715] internal/version: use gitCommit injection in version handling code (#25851) This changes the CI build to store the git commit and date into package internal/version instead of package main. Doing this essentially merges our two ways of tracking the go-ethereum version into a single place, achieving two objectives: - Bad block reports, which use version.Info(), will now have the git commit information even when geth is built in an environment such as launchpad.net where git access is unavailable. - For geth builds created by `go build ./cmd/geth` (i.e. not using `go run build/ci.go install`), git information stored by the go tool is now used in the p2p node name as well as in `geth version` and `geth version-check`. --- build/ci.go | 4 +-- cmd/abigen/main.go | 11 ++----- cmd/checkpoint-admin/main.go | 9 +----- cmd/clef/main.go | 8 +---- cmd/devp2p/main.go | 18 ++--------- cmd/ethkey/main.go | 6 +--- cmd/evm/main.go | 9 ++---- cmd/faucet/faucet.go | 9 ++---- cmd/geth/config.go | 4 ++- cmd/geth/main.go | 7 ++--- cmd/geth/misccmd.go | 19 +++++------ cmd/p2psim/main.go | 8 +---- internal/flags/helpers.go | 6 ++-- internal/version/vcs_fallback.go | 4 +-- internal/version/vcs_go1.18.go | 29 ++++++++++------- internal/version/version.go | 54 ++++++++++++++++++++++++++------ 16 files changed, 100 insertions(+), 105 deletions(-) diff --git a/build/ci.go b/build/ci.go index 4c8062eafb77..043c13b76e3c 100644 --- a/build/ci.go +++ b/build/ci.go @@ -254,8 +254,8 @@ func doInstall(cmdline []string) { func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (flags []string) { var ld []string if env.Commit != "" { - ld = append(ld, "-X", "main.gitCommit="+env.Commit) - ld = append(ld, "-X", "main.gitDate="+env.Date) + ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitCommit="+env.Commit) + ld = append(ld, "-X", "github.com/ethereum/go-ethereum/internal/version.gitDate="+env.Date) } // Strip DWARF on darwin. This used to be required for certain things, // and there is no downside to this, so we just keep doing it. diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 56ebfa9e9bb9..075e98930e67 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -33,14 +33,6 @@ import ( "github.com/urfave/cli/v2" ) -var ( - // Git SHA1 commit hash of the release (set via linker flags) - gitCommit = "" - gitDate = "" - - app *cli.App -) - var ( // Flags needed by abigen abiFlag = &cli.StringFlag{ @@ -82,8 +74,9 @@ var ( } ) +var app = flags.NewApp("Ethereum ABI wrapper code generator") + func init() { - app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") app.Name = "abigen" app.Flags = []cli.Flag{ abiFlag, diff --git a/cmd/checkpoint-admin/main.go b/cmd/checkpoint-admin/main.go index 0604ccaad622..ca0bae737591 100644 --- a/cmd/checkpoint-admin/main.go +++ b/cmd/checkpoint-admin/main.go @@ -28,16 +28,9 @@ import ( "github.com/urfave/cli/v2" ) -var ( - // Git SHA1 commit hash of the release (set via linker flags) - gitCommit = "" - gitDate = "" - - app *cli.App -) +var app = flags.NewApp("ethereum checkpoint helper tool") func init() { - app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") app.Commands = []*cli.Command{ commandStatus, commandDeploy, diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 05290f52feb8..a3e4815ed5fa 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -215,13 +215,7 @@ The gendoc generates example structures of the json-rpc communication types. `} ) -var ( - // Git SHA1 commit hash of the release (set via linker flags) - gitCommit = "" - gitDate = "" - - app = flags.NewApp(gitCommit, gitDate, "Manage Ethereum account operations") -) +var app = flags.NewApp("Manage Ethereum account operations") func init() { app.Name = "Clef" diff --git a/cmd/devp2p/main.go b/cmd/devp2p/main.go index 51b9fdb76119..9e13d29ab72d 100644 --- a/cmd/devp2p/main.go +++ b/cmd/devp2p/main.go @@ -19,30 +19,17 @@ package main import ( "fmt" "os" - "path/filepath" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) -var ( - // Git information set by linker when building with ci.go. - gitCommit string - gitDate string - app = &cli.App{ - Name: filepath.Base(os.Args[0]), - Usage: "go-ethereum devp2p tool", - Version: params.VersionWithCommit(gitCommit, gitDate), - Writer: os.Stdout, - HideVersion: true, - } -) +var app = flags.NewApp("go-ethereum devp2p tool") func init() { - // Set up the CLI app. + app.HideVersion = true app.Flags = append(app.Flags, debug.Flags...) app.Before = func(ctx *cli.Context) error { flags.MigrateGlobalFlags(ctx) @@ -56,6 +43,7 @@ func init() { fmt.Fprintf(os.Stderr, "No such command: %s\n", cmd) os.Exit(1) } + // Add subcommands. app.Commands = []*cli.Command{ enrdumpCommand, diff --git a/cmd/ethkey/main.go b/cmd/ethkey/main.go index 2b21f3cd70a4..25c0d104f61e 100644 --- a/cmd/ethkey/main.go +++ b/cmd/ethkey/main.go @@ -28,14 +28,10 @@ const ( defaultKeyfileName = "keyfile.json" ) -// Git SHA1 commit hash of the release (set via linker flags) -var gitCommit = "" -var gitDate = "" - var app *cli.App func init() { - app = flags.NewApp(gitCommit, gitDate, "an Ethereum key manager") + app = flags.NewApp("Ethereum key manager") app.Commands = []*cli.Command{ commandGenerate, commandInspect, diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 994b6436ad94..5f9e75f48c6f 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -27,13 +27,6 @@ import ( "github.com/urfave/cli/v2" ) -var ( - gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags) - gitDate = "" - - app = flags.NewApp(gitCommit, gitDate, "the evm command line interface") -) - var ( DebugFlag = &cli.BoolFlag{ Name: "debug", @@ -192,6 +185,8 @@ var blockBuilderCommand = &cli.Command{ }, } +var app = flags.NewApp("the evm command line interface") + func init() { app.Flags = []cli.Flag{ BenchFlag, diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index dfb7d326dc49..bec1f6d33b8e 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -49,6 +49,7 @@ import ( "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethstats" + "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -93,11 +94,6 @@ var ( ether = new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil) ) -var ( - gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags) - gitDate = "" // Git commit date YYYYMMDD of the release (set via linker flags) -) - //go:embed faucet.html var websiteTmpl string @@ -226,9 +222,10 @@ type wsConn struct { func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network uint64, stats string, ks *keystore.KeyStore, index []byte) (*faucet, error) { // Assemble the raw devp2p protocol stack + git, _ := version.VCS() stack, err := node.New(&node.Config{ Name: "geth", - Version: params.VersionWithCommit(gitCommit, gitDate), + Version: params.VersionWithCommit(git.Commit, git.Date), DataDir: filepath.Join(os.Getenv("HOME"), ".faucet"), P2P: p2p.Config{ NAT: nat.Any(), diff --git a/cmd/geth/config.go b/cmd/geth/config.go index d877e2b5dda0..a8cee0d13a59 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" @@ -108,9 +109,10 @@ func loadConfig(file string, cfg *gethConfig) error { } func defaultNodeConfig() node.Config { + git, _ := version.VCS() cfg := node.DefaultConfig cfg.Name = clientIdentifier - cfg.Version = params.VersionWithCommit(gitCommit, gitDate) + cfg.Version = params.VersionWithCommit(git.Commit, git.Date) cfg.HTTPModules = append(cfg.HTTPModules, "eth") cfg.WSModules = append(cfg.WSModules, "eth") cfg.IPCPath = "geth.ipc" diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 70b354ae148b..43885ca421bb 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -52,11 +52,6 @@ const ( ) var ( - // Git SHA1 commit hash of the release (set via linker flags) - gitCommit = "" - gitDate = "" - // The app that holds all commands and flags. - app = flags.NewApp(gitCommit, gitDate, "the go-ethereum command line interface") // flags that configure the node nodeFlags = flags.Merge([]cli.Flag{ utils.IdentityFlag, @@ -205,6 +200,8 @@ var ( } ) +var app = flags.NewApp("the go-ethereum command line interface") + func init() { // Initialize the CLI app and start Geth app.Action = geth diff --git a/cmd/geth/misccmd.go b/cmd/geth/misccmd.go index cc5feea9fbc9..d8a523c63221 100644 --- a/cmd/geth/misccmd.go +++ b/cmd/geth/misccmd.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) @@ -38,9 +39,7 @@ var ( VersionCheckVersionFlag = &cli.StringFlag{ Name: "check.version", Usage: "Version to check", - Value: fmt.Sprintf("Geth/v%v/%v-%v/%v", - params.VersionWithCommit(gitCommit, gitDate), - runtime.GOOS, runtime.GOARCH, runtime.Version()), + Value: version.ClientName(clientIdentifier), } makecacheCommand = &cli.Command{ Action: makecache, @@ -67,7 +66,7 @@ Regular users do not need to execute it. `, } versionCommand = &cli.Command{ - Action: version, + Action: printVersion, Name: "version", Usage: "Print version numbers", ArgsUsage: " ", @@ -127,14 +126,16 @@ func makedag(ctx *cli.Context) error { return nil } -func version(ctx *cli.Context) error { +func printVersion(ctx *cli.Context) error { + git, _ := version.VCS() + fmt.Println(strings.Title(clientIdentifier)) fmt.Println("Version:", params.VersionWithMeta) - if gitCommit != "" { - fmt.Println("Git Commit:", gitCommit) + if git.Commit != "" { + fmt.Println("Git Commit:", git.Commit) } - if gitDate != "" { - fmt.Println("Git Commit Date:", gitDate) + if git.Date != "" { + fmt.Println("Git Commit Date:", git.Date) } fmt.Println("Architecture:", runtime.GOARCH) fmt.Println("Go Version:", runtime.Version()) diff --git a/cmd/p2psim/main.go b/cmd/p2psim/main.go index 8b3cb29b1a0a..a3546d405b5f 100644 --- a/cmd/p2psim/main.go +++ b/cmd/p2psim/main.go @@ -100,14 +100,8 @@ var ( } ) -var ( - // Git information set by linker when building with ci.go. - gitCommit string - gitDate string -) - func main() { - app := flags.NewApp(gitCommit, gitDate, "devp2p simulation command-line client") + app := flags.NewApp("devp2p simulation command-line client") app.Flags = []cli.Flag{ apiFlag, } diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index de1d29ffd4b9..46409f4dfdb0 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -20,15 +20,17 @@ import ( "fmt" "strings" + "github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) // NewApp creates an app with sane defaults. -func NewApp(gitCommit, gitDate, usage string) *cli.App { +func NewApp(usage string) *cli.App { + git, _ := version.VCS() app := cli.NewApp() app.EnableBashCompletion = true - app.Version = params.VersionWithCommit(gitCommit, gitDate) + app.Version = params.VersionWithCommit(git.Commit, git.Date) app.Usage = usage app.Copyright = "Copyright 2013-2022 The go-ethereum Authors" app.Before = func(ctx *cli.Context) error { diff --git a/internal/version/vcs_fallback.go b/internal/version/vcs_fallback.go index 6d7f32e735f9..f792c68cdb4c 100644 --- a/internal/version/vcs_fallback.go +++ b/internal/version/vcs_fallback.go @@ -23,6 +23,6 @@ import "runtime/debug" // In Go versions before 1.18, VCS information is not available. -func vcsInfo(info *debug.BuildInfo) (gitStatus, bool) { - return gitStatus{}, false +func buildInfoVCS(info *debug.BuildInfo) (VCSInfo, bool) { + return VCSInfo{}, false } diff --git a/internal/version/vcs_go1.18.go b/internal/version/vcs_go1.18.go index d5b9c97a1666..53cd41fb3097 100644 --- a/internal/version/vcs_go1.18.go +++ b/internal/version/vcs_go1.18.go @@ -19,29 +19,36 @@ package version -import "runtime/debug" +import ( + "runtime/debug" + "time" +) // In go 1.18 and beyond, the go tool embeds VCS information into the build. -// vcsInfo returns VCS information of the build. -func vcsInfo(info *debug.BuildInfo) (s gitStatus, ok bool) { +const ( + govcsTimeLayout = "2006-01-02T15:04:05Z" + ourTimeLayout = "20060102" +) + +// buildInfoVCS returns VCS information of the build. +func buildInfoVCS(info *debug.BuildInfo) (s VCSInfo, ok bool) { for _, v := range info.Settings { switch v.Key { case "vcs.revision": - if len(v.Value) < 8 { - s.revision = v.Value - } else { - s.revision = v.Value[:8] - } + s.Commit = v.Value case "vcs.modified": if v.Value == "true" { - s.modified = true + s.Dirty = true } case "vcs.time": - s.time = v.Value + t, err := time.Parse(govcsTimeLayout, v.Value) + if err == nil { + s.Date = t.Format(ourTimeLayout) + } } } - if s.revision != "" && s.time != "" { + if s.Commit != "" && s.Date != "" { ok = true } return diff --git a/internal/version/version.go b/internal/version/version.go index e4b9ee490768..4959102f7d84 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -19,6 +19,7 @@ package version import ( "fmt" + "runtime" "runtime/debug" "strings" @@ -27,6 +28,43 @@ import ( const ourPath = "github.com/ethereum/go-ethereum" // Path to our module +// These variables are set at build-time by the linker when the build is +// done by build/ci.go. +var gitCommit, gitDate string + +// VCSInfo represents the git repository state. +type VCSInfo struct { + Commit string // head commit hash + Date string // commit time in YYYYMMDD format + Dirty bool +} + +// VCS returns version control information of the current executable. +func VCS() (VCSInfo, bool) { + if gitCommit != "" { + // Use information set by the build script if present. + return VCSInfo{Commit: gitCommit, Date: gitDate}, true + } + if buildInfo, ok := debug.ReadBuildInfo(); ok { + if buildInfo.Main.Path == ourPath { + return buildInfoVCS(buildInfo) + } + } + return VCSInfo{}, false +} + +// ClientName creates a software name/version identifier according to common +// conventions in the Ethereum p2p network. +func ClientName(clientIdentifier string) string { + git, _ := VCS() + return fmt.Sprintf("%s/v%v/%v-%v/%v", + strings.Title(clientIdentifier), + params.VersionWithCommit(git.Commit, git.Date), + runtime.GOOS, runtime.GOARCH, + runtime.Version(), + ) +} + // runtimeInfo returns build and platform information about the current binary. // // If the package that is currently executing is a prefixed by our go-ethereum @@ -40,22 +78,20 @@ func Info() (version, vcs string) { return version, "" } version = versionInfo(buildInfo) - if status, ok := vcsInfo(buildInfo); ok { + if status, ok := VCS(); ok { modified := "" - if status.modified { + if status.Dirty { modified = " (dirty)" } - vcs = status.revision + "-" + status.time + modified + commit := status.Commit + if len(commit) > 8 { + commit = commit[:8] + } + vcs = commit + "-" + status.Date + modified } return version, vcs } -type gitStatus struct { - revision string - time string - modified bool -} - // versionInfo returns version information for the currently executing // implementation. // From e87806727df7350a641f05d4998f7ec3a59c50e3 Mon Sep 17 00:00:00 2001 From: Sebastian Stammler Date: Fri, 23 Sep 2022 19:04:02 +0200 Subject: [PATCH 257/715] cmd/abigen: change --exc to exclude by type name (#22620) The abigen exclusion pattern, previously on the form "path:type", now supports wildcards. Examples "*:type" to exclude a named type in all files, or "/path/to/foo.sol:*" all types in foo.sol. --- cmd/abigen/main.go | 20 +++++++----- cmd/abigen/namefilter.go | 58 +++++++++++++++++++++++++++++++++++ cmd/abigen/namefilter_test.go | 38 +++++++++++++++++++++++ 3 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 cmd/abigen/namefilter.go create mode 100644 cmd/abigen/namefilter_test.go diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 075e98930e67..83b6c5e4289f 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -154,9 +154,12 @@ func abigen(c *cli.Context) error { types = append(types, kind) } else { // Generate the list of types to exclude from binding - exclude := make(map[string]bool) - for _, kind := range strings.Split(c.String(excFlag.Name), ",") { - exclude[strings.ToLower(kind)] = true + var exclude *nameFilter + if c.IsSet(excFlag.Name) { + var err error + if exclude, err = newNameFilter(strings.Split(c.String(excFlag.Name), ",")...); err != nil { + utils.Fatalf("Failed to parse excludes: %v", err) + } } var contracts map[string]*compiler.Contract @@ -181,7 +184,11 @@ func abigen(c *cli.Context) error { } // Gather all non-excluded contract for binding for name, contract := range contracts { - if exclude[strings.ToLower(name)] { + // fully qualified name is of the form : + nameParts := strings.Split(name, ":") + typeName := nameParts[len(nameParts)-1] + if exclude != nil && exclude.Matches(name) { + fmt.Fprintf(os.Stderr, "excluding: %v\n", name) continue } abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse @@ -191,15 +198,14 @@ func abigen(c *cli.Context) error { abis = append(abis, string(abi)) bins = append(bins, contract.Code) sigs = append(sigs, contract.Hashes) - nameParts := strings.Split(name, ":") - types = append(types, nameParts[len(nameParts)-1]) + types = append(types, typeName) // Derive the library placeholder which is a 34 character prefix of the // hex encoding of the keccak256 hash of the fully qualified library name. // Note that the fully qualified library name is the path of its source // file and the library name separated by ":". libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] // the first 2 chars are 0x - libs[libPattern] = nameParts[len(nameParts)-1] + libs[libPattern] = typeName } } // Extract all aliases from the flags diff --git a/cmd/abigen/namefilter.go b/cmd/abigen/namefilter.go new file mode 100644 index 000000000000..eea5c643c442 --- /dev/null +++ b/cmd/abigen/namefilter.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "strings" +) + +type nameFilter struct { + fulls map[string]bool // path/to/contract.sol:Type + files map[string]bool // path/to/contract.sol:* + types map[string]bool // *:Type +} + +func newNameFilter(patterns ...string) (*nameFilter, error) { + f := &nameFilter{ + fulls: make(map[string]bool), + files: make(map[string]bool), + types: make(map[string]bool), + } + for _, pattern := range patterns { + if err := f.add(pattern); err != nil { + return nil, err + } + } + return f, nil +} + +func (f *nameFilter) add(pattern string) error { + ft := strings.Split(pattern, ":") + if len(ft) != 2 { + // filenames and types must not include ':' symbol + return fmt.Errorf("invalid pattern: %s", pattern) + } + + file, typ := ft[0], ft[1] + if file == "*" { + f.types[typ] = true + return nil + } else if typ == "*" { + f.files[file] = true + return nil + } + f.fulls[pattern] = true + return nil +} + +func (f *nameFilter) Matches(name string) bool { + ft := strings.Split(name, ":") + if len(ft) != 2 { + // If contract names are always of the fully-qualified form + // :, then this case will never happen. + return false + } + + file, typ := ft[0], ft[1] + // full paths > file paths > types + return f.fulls[name] || f.files[file] || f.types[typ] +} diff --git a/cmd/abigen/namefilter_test.go b/cmd/abigen/namefilter_test.go new file mode 100644 index 000000000000..42ba55be5eb5 --- /dev/null +++ b/cmd/abigen/namefilter_test.go @@ -0,0 +1,38 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNameFilter(t *testing.T) { + _, err := newNameFilter("Foo") + require.Error(t, err) + _, err = newNameFilter("too/many:colons:Foo") + require.Error(t, err) + + f, err := newNameFilter("a/path:A", "*:B", "c/path:*") + require.NoError(t, err) + + for _, tt := range []struct { + name string + match bool + }{ + {"a/path:A", true}, + {"unknown/path:A", false}, + {"a/path:X", false}, + {"unknown/path:X", false}, + {"any/path:B", true}, + {"c/path:X", true}, + {"c/path:foo:B", false}, + } { + match := f.Matches(tt.name) + if tt.match { + assert.True(t, match, "expected match") + } else { + assert.False(t, match, "expected no match") + } + } +} From 9b35f3f5b1c6d3fe0986f9dccf884f005754c510 Mon Sep 17 00:00:00 2001 From: Zachinquarantine Date: Fri, 23 Sep 2022 13:33:15 -0400 Subject: [PATCH 258/715] tests, les, eth: remove mentions of deprecated Morden testnet (#23570) * remove morden * Update commons.go * Update handler.go * empty commit to make appveyor happy --- eth/protocols/eth/handler.go | 2 +- les/commons.go | 2 +- tests/difficulty_test.go | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 3a0b21c30bdb..87b1f20a2dc2 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -127,7 +127,7 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2 // NodeInfo represents a short summary of the `eth` sub-protocol metadata // known about the host peer. type NodeInfo struct { - Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3, Rinkeby=4) + Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Ropsten=3, Rinkeby=4, Goerli=5) Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules diff --git a/les/commons.go b/les/commons.go index d090fc21fcca..e83319543d36 100644 --- a/les/commons.go +++ b/les/commons.go @@ -63,7 +63,7 @@ type lesCommons struct { // NodeInfo represents a short summary of the Ethereum sub-protocol metadata // known about the host peer. type NodeInfo struct { - Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3, Rinkeby=4) + Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Ropsten=3, Rinkeby=4, Goerli=5) Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules diff --git a/tests/difficulty_test.go b/tests/difficulty_test.go index 8239850b7617..af9b0f86bd9a 100644 --- a/tests/difficulty_test.go +++ b/tests/difficulty_test.go @@ -52,11 +52,8 @@ func TestDifficulty(t *testing.T) { // files are 2 years old, contains strange values dt.skipLoad("difficultyCustomHomestead\\.json") - dt.skipLoad("difficultyMorden\\.json") - dt.skipLoad("difficultyOlimpic\\.json") dt.config("Ropsten", *params.RopstenChainConfig) - dt.config("Morden", *params.RopstenChainConfig) dt.config("Frontier", params.ChainConfig{}) dt.config("Homestead", params.ChainConfig{ From 3da42f85d9b8daea589753e5d3163e4e2846a545 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Sat, 24 Sep 2022 02:20:36 +0800 Subject: [PATCH 259/715] all: clean up the configs for pruner and snapshotter (#22396) This PR cleans up the configurations for pruner and snapshotter by passing a config struct. And also, this PR disables the snapshot background generation if the chain is opened in "read-only" mode. The read-only mode is necessary in some cases. For example, we have a list of commands to open the etheruem node in "read-only" mode, like export-chain. In these cases, the snapshot background generation is non expected and should be banned explicitly. --- cmd/geth/snapshot.go | 27 +++++++++++-- cmd/utils/flags.go | 4 +- core/blockchain.go | 11 +++++- core/state/pruner/pruner.go | 67 +++++++++++++++++++++------------ core/state/snapshot/journal.go | 11 ++++-- core/state/snapshot/snapshot.go | 25 ++++++++---- tests/state_test_util.go | 8 +++- 7 files changed, 109 insertions(+), 44 deletions(-) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 39bef1f2d352..bbacdaf46354 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -170,7 +170,14 @@ func pruneState(ctx *cli.Context) error { defer stack.Close() chaindb := utils.MakeChainDatabase(ctx, stack, false) - pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.Uint64(utils.BloomFilterSizeFlag.Name)) + defer chaindb.Close() + + prunerconfig := pruner.Config{ + Datadir: stack.ResolvePath(""), + Cachedir: stack.ResolvePath(config.Eth.TrieCleanCacheJournal), + BloomSize: ctx.Uint64(utils.BloomFilterSizeFlag.Name), + } + pruner, err := pruner.NewPruner(chaindb, prunerconfig) if err != nil { log.Error("Failed to open snapshot tree", "err", err) return err @@ -199,12 +206,20 @@ func verifyState(ctx *cli.Context) error { defer stack.Close() chaindb := utils.MakeChainDatabase(ctx, stack, true) + defer chaindb.Close() + headBlock := rawdb.ReadHeadBlock(chaindb) if headBlock == nil { log.Error("Failed to load head block") return errors.New("no head block") } - snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, headBlock.Root(), false, false, false) + snapconfig := snapshot.Config{ + CacheSize: 256, + Recovery: false, + NoBuild: true, + AsyncBuild: false, + } + snaptree, err := snapshot.New(snapconfig, chaindb, trie.NewDatabase(chaindb), headBlock.Root()) if err != nil { log.Error("Failed to open snapshot tree", "err", err) return err @@ -479,7 +494,13 @@ func dumpState(ctx *cli.Context) error { if err != nil { return err } - snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, root, false, false, false) + snapConfig := snapshot.Config{ + CacheSize: 256, + Recovery: false, + NoBuild: true, + AsyncBuild: false, + } + snaptree, err := snapshot.New(snapConfig, db, trie.NewDatabase(db), root) if err != nil { return err } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 4017f210891d..33d6cf6327af 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2198,6 +2198,9 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (*core.BlockChain, ethdb.Data if !ctx.Bool(SnapshotFlag.Name) { cache.SnapshotLimit = 0 // Disabled } + // Disable snapshot generation/wiping by default + cache.SnapshotNoBuild = true + if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) { cache.TrieCleanLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 } @@ -2206,7 +2209,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (*core.BlockChain, ethdb.Data } vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)} - // TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only. // Disable transaction indexing/unindexing by default. chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil) if err != nil { diff --git a/core/blockchain.go b/core/blockchain.go index fe127b5ea8ab..671b9caf13d1 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -135,7 +135,8 @@ type CacheConfig struct { SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory Preimages bool // Whether to store preimage of trie key to the disk - SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it + SnapshotNoBuild bool // Whether the background generation is allowed + SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it } // defaultCacheConfig are the default caching values if none are specified by the @@ -399,7 +400,13 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis log.Warn("Enabling snapshot recovery", "chainhead", head.NumberU64(), "diskbase", *layer) recover = true } - bc.snaps, _ = snapshot.New(bc.db, bc.stateCache.TrieDB(), bc.cacheConfig.SnapshotLimit, head.Root(), !bc.cacheConfig.SnapshotWait, true, recover) + snapconfig := snapshot.Config{ + CacheSize: bc.cacheConfig.SnapshotLimit, + Recovery: recover, + NoBuild: bc.cacheConfig.SnapshotNoBuild, + AsyncBuild: !bc.cacheConfig.SnapshotWait, + } + bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.stateCache.TrieDB(), head.Root()) } // Start future block processor. diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 87bc357a5c10..4ea54f8aace4 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -63,6 +63,13 @@ var ( emptyCode = crypto.Keccak256(nil) ) +// Config includes all the configurations for pruning. +type Config struct { + Datadir string // The directory of the state database + Cachedir string // The directory of state clean cache + BloomSize uint64 // The Megabytes of memory allocated to bloom-filter +} + // Pruner is an offline tool to prune the stale state with the // help of the snapshot. The workflow of pruner is very simple: // @@ -75,40 +82,44 @@ var ( // periodically in order to release the disk usage and improve the // disk read performance to some extent. type Pruner struct { - db ethdb.Database - stateBloom *stateBloom - datadir string - trieCachePath string - headHeader *types.Header - snaptree *snapshot.Tree + config Config + chainHeader *types.Header + db ethdb.Database + stateBloom *stateBloom + snaptree *snapshot.Tree } // NewPruner creates the pruner instance. -func NewPruner(db ethdb.Database, datadir, trieCachePath string, bloomSize uint64) (*Pruner, error) { +func NewPruner(db ethdb.Database, config Config) (*Pruner, error) { headBlock := rawdb.ReadHeadBlock(db) if headBlock == nil { return nil, errors.New("Failed to load head block") } - snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, headBlock.Root(), false, false, false) + snapconfig := snapshot.Config{ + CacheSize: 256, + Recovery: false, + NoBuild: true, + AsyncBuild: false, + } + snaptree, err := snapshot.New(snapconfig, db, trie.NewDatabase(db), headBlock.Root()) if err != nil { return nil, err // The relevant snapshot(s) might not exist } // Sanitize the bloom filter size if it's too small. - if bloomSize < 256 { - log.Warn("Sanitizing bloomfilter size", "provided(MB)", bloomSize, "updated(MB)", 256) - bloomSize = 256 + if config.BloomSize < 256 { + log.Warn("Sanitizing bloomfilter size", "provided(MB)", config.BloomSize, "updated(MB)", 256) + config.BloomSize = 256 } - stateBloom, err := newStateBloomWithSize(bloomSize) + stateBloom, err := newStateBloomWithSize(config.BloomSize) if err != nil { return nil, err } return &Pruner{ - db: db, - stateBloom: stateBloom, - datadir: datadir, - trieCachePath: trieCachePath, - headHeader: headBlock.Header(), - snaptree: snaptree, + config: config, + chainHeader: headBlock.Header(), + db: db, + stateBloom: stateBloom, + snaptree: snaptree, }, nil } @@ -236,12 +247,12 @@ func (p *Pruner) Prune(root common.Hash) error { // reuse it for pruning instead of generating a new one. It's // mandatory because a part of state may already be deleted, // the recovery procedure is necessary. - _, stateBloomRoot, err := findBloomFilter(p.datadir) + _, stateBloomRoot, err := findBloomFilter(p.config.Datadir) if err != nil { return err } if stateBloomRoot != (common.Hash{}) { - return RecoverPruning(p.datadir, p.db, p.trieCachePath) + return RecoverPruning(p.config.Datadir, p.db, p.config.Cachedir) } // If the target state root is not specified, use the HEAD-127 as the // target. The reason for picking it is: @@ -252,7 +263,7 @@ func (p *Pruner) Prune(root common.Hash) error { // Retrieve all snapshot layers from the current HEAD. // In theory there are 128 difflayers + 1 disk layer present, // so 128 diff layers are expected to be returned. - layers = p.snaptree.Snapshots(p.headHeader.Root, 128, true) + layers = p.snaptree.Snapshots(p.chainHeader.Root, 128, true) if len(layers) != 128 { // Reject if the accumulated diff layers are less than 128. It // means in most of normal cases, there is no associated state @@ -294,7 +305,7 @@ func (p *Pruner) Prune(root common.Hash) error { } } else { if len(layers) > 0 { - log.Info("Selecting bottom-most difflayer as the pruning target", "root", root, "height", p.headHeader.Number.Uint64()-127) + log.Info("Selecting bottom-most difflayer as the pruning target", "root", root, "height", p.chainHeader.Number.Uint64()-127) } else { log.Info("Selecting user-specified state as the pruning target", "root", root) } @@ -303,7 +314,7 @@ func (p *Pruner) Prune(root common.Hash) error { // It's necessary otherwise in the next restart we will hit the // deleted state root in the "clean cache" so that the incomplete // state is picked for usage. - deleteCleanTrieCache(p.trieCachePath) + deleteCleanTrieCache(p.config.Cachedir) // All the state roots of the middle layer should be forcibly pruned, // otherwise the dangling state will be left. @@ -325,7 +336,7 @@ func (p *Pruner) Prune(root common.Hash) error { if err := extractGenesis(p.db, p.stateBloom); err != nil { return err } - filterName := bloomFilterName(p.datadir, root) + filterName := bloomFilterName(p.config.Datadir, root) log.Info("Writing state bloom to disk", "name", filterName) if err := p.stateBloom.Commit(filterName, filterName+stateBloomFileTempSuffix); err != nil { @@ -362,7 +373,13 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err // - The state HEAD is rewound already because of multiple incomplete `prune-state` // In this case, even the state HEAD is not exactly matched with snapshot, it // still feasible to recover the pruning correctly. - snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, headBlock.Root(), false, false, true) + snapconfig := snapshot.Config{ + CacheSize: 256, + Recovery: true, + NoBuild: true, + AsyncBuild: false, + } + snaptree, err := snapshot.New(snapconfig, db, trie.NewDatabase(db), headBlock.Root()) if err != nil { return err // The relevant snapshot(s) might not exist } diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index 9a22f2737306..c1a4cc3d47e5 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -120,7 +120,7 @@ func loadAndParseJournal(db ethdb.KeyValueStore, base *diskLayer) (snapshot, jou } // loadSnapshot loads a pre-existing state snapshot backed by a key-value store. -func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, root common.Hash, recovery bool) (snapshot, bool, error) { +func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, root common.Hash, cache int, recovery bool, noBuild bool) (snapshot, bool, error) { // If snapshotting is disabled (initial sync in progress), don't do anything, // wait for the chain to permit us to do something meaningful if rawdb.ReadSnapshotDisabled(diskdb) { @@ -140,7 +140,7 @@ func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, } snapshot, generator, err := loadAndParseJournal(diskdb, base) if err != nil { - log.Warn("Failed to load new-format journal", "error", err) + log.Warn("Failed to load journal", "error", err) return nil, false, err } // Entire snapshot journal loaded, sanity check the head. If the loaded @@ -164,13 +164,16 @@ func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, // disk layer. log.Warn("Snapshot is not continuous with chain", "snaproot", head, "chainroot", root) } - // Everything loaded correctly, resume any suspended operations + // Load the disk layer status from the generator if it's not complete if !generator.Done { - // Whether or not wiping was in progress, load any generator progress too base.genMarker = generator.Marker if base.genMarker == nil { base.genMarker = []byte{} } + } + // Everything loaded correctly, resume any suspended operations + // if the background generation is allowed + if !generator.Done && !noBuild { base.genPending = make(chan struct{}) base.genAbort = make(chan chan *generatorStats) diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index a6c77fbb9860..ee18f4bcdcf6 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -148,6 +148,14 @@ type snapshot interface { StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) } +// Config includes the configurations for snapshots. +type Config struct { + CacheSize int // Megabytes permitted to use for read caches + Recovery bool // Indicator that the snapshots is in the recovery mode + NoBuild bool // Indicator that the snapshots generation is disallowed + AsyncBuild bool // The snapshot generation is allowed to be constructed asynchronously +} + // Tree is an Ethereum state snapshot tree. It consists of one persistent base // layer backed by a key-value store, on top of which arbitrarily many in-memory // diff layers are topped. The memory diffs can form a tree with branching, but @@ -158,9 +166,9 @@ type snapshot interface { // storage data to avoid expensive multi-level trie lookups; and to allow sorted, // cheap iteration of the account/storage tries for sync aid. type Tree struct { + config Config // Snapshots configurations diskdb ethdb.KeyValueStore // Persistent database to store the snapshot triedb *trie.Database // In-memory cache to access the trie through - cache int // Megabytes permitted to use for read caches layers map[common.Hash]snapshot // Collection of all known layers lock sync.RWMutex @@ -183,26 +191,27 @@ type Tree struct { // This case happens when the snapshot is 'ahead' of the state trie. // - otherwise, the entire snapshot is considered invalid and will be recreated on // a background thread. -func New(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, root common.Hash, async bool, rebuild bool, recovery bool) (*Tree, error) { +func New(config Config, diskdb ethdb.KeyValueStore, triedb *trie.Database, root common.Hash) (*Tree, error) { // Create a new, empty snapshot tree snap := &Tree{ + config: config, diskdb: diskdb, triedb: triedb, - cache: cache, layers: make(map[common.Hash]snapshot), } - if !async { + // Create the building waiter iff the background generation is allowed + if !config.NoBuild && !config.AsyncBuild { defer snap.waitBuild() } // Attempt to load a previously persisted snapshot and rebuild one if failed - head, disabled, err := loadSnapshot(diskdb, triedb, cache, root, recovery) + head, disabled, err := loadSnapshot(diskdb, triedb, root, config.CacheSize, config.Recovery, config.NoBuild) if disabled { log.Warn("Snapshot maintenance disabled (syncing)") return snap, nil } if err != nil { - if rebuild { - log.Warn("Failed to load snapshot, regenerating", "err", err) + log.Warn("Failed to load snapshot", "err", err) + if !config.NoBuild { snap.Rebuild(root) return snap, nil } @@ -727,7 +736,7 @@ func (t *Tree) Rebuild(root common.Hash) { // generator will run a wiper first if there's not one running right now. log.Info("Rebuilding state snapshot") t.layers = map[common.Hash]snapshot{ - root: generateSnapshot(t.diskdb, t.triedb, t.cache, root), + root: generateSnapshot(t.diskdb, t.triedb, t.config.CacheSize, root), } } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 38cdbc4d6504..e24fc57b3b63 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -267,7 +267,13 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter boo var snaps *snapshot.Tree if snapshotter { - snaps, _ = snapshot.New(db, sdb.TrieDB(), 1, root, false, true, false) + snapconfig := snapshot.Config{ + CacheSize: 1, + Recovery: false, + NoBuild: false, + AsyncBuild: false, + } + snaps, _ = snapshot.New(snapconfig, db, sdb.TrieDB(), root) } statedb, _ = state.New(root, sdb, snaps) return snaps, statedb From 15b4a4bf2ef44605264dab15ca6006f643d36c5e Mon Sep 17 00:00:00 2001 From: Zachinquarantine Date: Fri, 23 Sep 2022 16:32:10 -0400 Subject: [PATCH 260/715] cmd/puppeth, cmd/utils: finalize removal of gasTarget flag (#24370) This PR fully removes the --miner.gastarget flag, as previously it was only hidden from the geth --help command, but could still be used. --- cmd/geth/main.go | 1 - cmd/puppeth/module_node.go | 11 ++--------- cmd/puppeth/wizard_node.go | 6 +----- cmd/utils/flags.go | 3 --- cmd/utils/flags_legacy.go | 9 --------- 5 files changed, 3 insertions(+), 27 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 43885ca421bb..5d54ee41ca2f 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -121,7 +121,6 @@ var ( utils.MiningEnabledFlag, utils.MinerThreadsFlag, utils.MinerNotifyFlag, - utils.LegacyMinerGasTargetFlag, utils.MinerGasLimitFlag, utils.MinerGasPriceFlag, utils.MinerEtherbaseFlag, diff --git a/cmd/puppeth/module_node.go b/cmd/puppeth/module_node.go index b8aa30db39a8..734dd0405128 100644 --- a/cmd/puppeth/module_node.go +++ b/cmd/puppeth/module_node.go @@ -42,7 +42,7 @@ ADD genesis.json /genesis.json RUN \ echo 'geth --cache 512 init /genesis.json' > geth.sh && \{{if .Unlock}} echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}} - echo $'exec geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --nat extip:{{.IP}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--miner.etherbase {{.Etherbase}} --mine --miner.threads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --miner.gastarget {{.GasTarget}} --miner.gaslimit {{.GasLimit}} --miner.gasprice {{.GasPrice}}' >> geth.sh + echo $'exec geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --nat extip:{{.IP}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--miner.etherbase {{.Etherbase}} --mine --miner.threads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --miner.gaslimit {{.GasLimit}} --miner.gasprice {{.GasPrice}}' >> geth.sh ENTRYPOINT ["/bin/sh", "geth.sh"] ` @@ -68,7 +68,6 @@ services: - LIGHT_PEERS={{.LightPeers}} - STATS_NAME={{.Ethstats}} - MINER_NAME={{.Etherbase}} - - GAS_TARGET={{.GasTarget}} - GAS_LIMIT={{.GasLimit}} - GAS_PRICE={{.GasPrice}} logging: @@ -106,7 +105,6 @@ func deployNode(client *sshClient, network string, bootnodes []string, config *n "Bootnodes": strings.Join(bootnodes, ","), "Ethstats": config.ethstats, "Etherbase": config.etherbase, - "GasTarget": uint64(1000000 * config.gasTarget), "GasLimit": uint64(1000000 * config.gasLimit), "GasPrice": uint64(1000000000 * config.gasPrice), "Unlock": config.keyJSON != "", @@ -125,7 +123,6 @@ func deployNode(client *sshClient, network string, bootnodes []string, config *n "LightPeers": config.peersLight, "Ethstats": getEthName(config.ethstats), "Etherbase": config.etherbase, - "GasTarget": config.gasTarget, "GasLimit": config.gasLimit, "GasPrice": config.gasPrice, }) @@ -164,7 +161,6 @@ type nodeInfos struct { etherbase string keyJSON string keyPass string - gasTarget float64 gasLimit float64 gasPrice float64 } @@ -179,10 +175,9 @@ func (info *nodeInfos) Report() map[string]string { "Peer count (light nodes)": strconv.Itoa(info.peersLight), "Ethstats username": info.ethstats, } - if info.gasTarget > 0 { + if info.gasLimit > 0 { // Miner or signer node report["Gas price (minimum accepted)"] = fmt.Sprintf("%0.3f GWei", info.gasPrice) - report["Gas floor (baseline target)"] = fmt.Sprintf("%0.3f MGas", info.gasTarget) report["Gas ceil (target maximum)"] = fmt.Sprintf("%0.3f MGas", info.gasLimit) if info.etherbase != "" { @@ -223,7 +218,6 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error) // Resolve a few types from the environmental variables totalPeers, _ := strconv.Atoi(infos.envvars["TOTAL_PEERS"]) lightPeers, _ := strconv.Atoi(infos.envvars["LIGHT_PEERS"]) - gasTarget, _ := strconv.ParseFloat(infos.envvars["GAS_TARGET"], 64) gasLimit, _ := strconv.ParseFloat(infos.envvars["GAS_LIMIT"], 64) gasPrice, _ := strconv.ParseFloat(infos.envvars["GAS_PRICE"], 64) @@ -263,7 +257,6 @@ func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error) etherbase: infos.envvars["MINER_NAME"], keyJSON: keyJSON, keyPass: keyPass, - gasTarget: gasTarget, gasLimit: gasLimit, gasPrice: gasPrice, } diff --git a/cmd/puppeth/wizard_node.go b/cmd/puppeth/wizard_node.go index 2bae33214283..c38750875aad 100644 --- a/cmd/puppeth/wizard_node.go +++ b/cmd/puppeth/wizard_node.go @@ -50,7 +50,7 @@ func (w *wizard) deployNode(boot bool) { if boot { infos = &nodeInfos{port: 30303, peersTotal: 512, peersLight: 256} } else { - infos = &nodeInfos{port: 30303, peersTotal: 50, peersLight: 0, gasTarget: 7.5, gasLimit: 10, gasPrice: 1} + infos = &nodeInfos{port: 30303, peersTotal: 50, peersLight: 0, gasLimit: 10, gasPrice: 1} } } existed := err == nil @@ -148,10 +148,6 @@ func (w *wizard) deployNode(boot bool) { } } // Establish the gas dynamics to be enforced by the signer - fmt.Println() - fmt.Printf("What gas limit should empty blocks target (MGas)? (default = %0.3f)\n", infos.gasTarget) - infos.gasTarget = w.readDefaultFloat(infos.gasTarget) - fmt.Println() fmt.Printf("What gas limit should full blocks target (MGas)? (default = %0.3f)\n", infos.gasLimit) infos.gasLimit = w.readDefaultFloat(infos.gasLimit) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 33d6cf6327af..595fe3360fe0 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1649,9 +1649,6 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) { if ctx.IsSet(MinerNoVerifyFlag.Name) { cfg.Noverify = ctx.Bool(MinerNoVerifyFlag.Name) } - if ctx.IsSet(LegacyMinerGasTargetFlag.Name) { - log.Warn("The generic --miner.gastarget flag is deprecated and will be removed in the future!") - } } func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) { diff --git a/cmd/utils/flags_legacy.go b/cmd/utils/flags_legacy.go index 651c69bd0492..930b68fb91d0 100644 --- a/cmd/utils/flags_legacy.go +++ b/cmd/utils/flags_legacy.go @@ -19,7 +19,6 @@ package utils import ( "fmt" - "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/flags" "github.com/urfave/cli/v2" ) @@ -33,7 +32,6 @@ var ShowDeprecated = &cli.Command{ } var DeprecatedFlags = []cli.Flag{ - LegacyMinerGasTargetFlag, NoUSBFlag, } @@ -44,13 +42,6 @@ var ( Usage: "Disables monitoring for and managing USB hardware wallets (deprecated)", Category: flags.DeprecatedCategory, } - // (Deprecated July 2021, shown in aliased flags section) - LegacyMinerGasTargetFlag = &cli.Uint64Flag{ - Name: "miner.gastarget", - Usage: "Target gas floor for mined blocks (deprecated)", - Value: ethconfig.Defaults.Miner.GasFloor, - Category: flags.DeprecatedCategory, - } ) // showDeprecated displays deprecated flags that will be soon removed from the codebase. From 367e60549af9b6551e0f7604b33a5b1c891f6b23 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Mon, 26 Sep 2022 15:10:39 +0800 Subject: [PATCH 261/715] core/types: improve accuracy of header.Size() (#25859) The header.Size() method did not take the basefee into account. --- core/types/block.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/types/block.go b/core/types/block.go index 7525a88f5a38..8942082b6e48 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -117,7 +117,11 @@ var headerSize = common.StorageSize(reflect.TypeOf(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. func (h *Header) Size() common.StorageSize { - return headerSize + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen())/8) + var baseFeeBits int + if h.BaseFee != nil { + baseFeeBits = h.BaseFee.BitLen() + } + return headerSize + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen()+baseFeeBits)/8) } // SanityCheck checks a few basic things -- these checks are way beyond what From 4dc212d4f1aadfdf9def02cfaa87896595931f9b Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 26 Sep 2022 09:56:45 +0200 Subject: [PATCH 262/715] eth/tracers: pad memory slice on OOB case (#25213) * eth/tracers: pad memory slice on oob case * eth/tracers/js: fix testfailure due to err msg capitalization Co-authored-by: Martin Holst Swende --- eth/tracers/js/goja.go | 22 +++++++++++++++++++--- eth/tracers/js/tracer_test.go | 33 +++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 8360403aa164..7bb323f6985c 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -33,6 +33,10 @@ import ( jsassets "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers" ) +const ( + memoryPadLimit = 1024 * 1024 +) + var assetTracers = make(map[string]string) // init retrieves the JavaScript transaction tracers included in go-ethereum. @@ -562,10 +566,15 @@ func (mo *memoryObj) slice(begin, end int64) ([]byte, error) { if end < begin || begin < 0 { return nil, fmt.Errorf("tracer accessed out of bound memory: offset %d, end %d", begin, end) } - if mo.memory.Len() < int(end) { - return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), begin, end-begin) + mlen := mo.memory.Len() + if end-int64(mlen) > memoryPadLimit { + return nil, fmt.Errorf("tracer reached limit for padding memory slice: end %d, memorySize %d", end, mlen) } - return mo.memory.GetCopy(begin, end-begin), nil + slice := make([]byte, end-begin) + end = min(end, int64(mo.memory.Len())) + ptr := mo.memory.GetPtr(begin, end-begin) + copy(slice[:], ptr[:]) + return slice, nil } func (mo *memoryObj) GetUint(addr int64) goja.Value { @@ -945,3 +954,10 @@ func (l *steplog) setupObject() *goja.Object { o.Set("contract", l.contract.setupObject()) return o } + +func min(a, b int64) int64 { + if a < b { + return a + } + return b +} diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 80a002d5af28..02789d6713ed 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -60,7 +60,7 @@ func testCtx() *vmContext { return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} } -func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig) (json.RawMessage, error) { +func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { var ( env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Debug: true, Tracer: tracer}) gasLimit uint64 = 31000 @@ -69,6 +69,9 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon contract = vm.NewContract(account{}, account{}, value, startGas) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} + if contractCode != nil { + contract.Code = contractCode + } tracer.CaptureTxStart(gasLimit) tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value) @@ -83,22 +86,23 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon } func TestTracer(t *testing.T) { - execTracer := func(code string) ([]byte, string) { + execTracer := func(code string, contract []byte) ([]byte, string) { t.Helper() tracer, err := newJsTracer(code, nil, nil) if err != nil { t.Fatal(err) } - ret, err := runTrace(tracer, testCtx(), params.TestChainConfig) + ret, err := runTrace(tracer, testCtx(), params.TestChainConfig, contract) if err != nil { return nil, err.Error() // Stringify to allow comparison without nil checks } return ret, "" } for i, tt := range []struct { - code string - want string - fail string + code string + want string + fail string + contract []byte }{ { // tests that we don't panic on bad arguments to memory access code: "{depths: [], step: function(log) { this.depths.push(log.memory.slice(-1,-2)); }, fault: function() {}, result: function() { return this.depths; }}", @@ -139,9 +143,18 @@ func TestTracer(t *testing.T) { }, { code: "{res: null, step: function(log) { var address = Array.prototype.slice.call(log.contract.getAddress()); this.res = toAddress(address); }, fault: function() {}, result: function() { return this.res }}", want: `{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0}`, + }, { + code: "{res: [], step: function(log) { var op = log.op.toString(); if (op === 'MSTORE8' || op === 'STOP') { this.res.push(log.memory.slice(0, 2)) } }, fault: function() {}, result: function() { return this.res }}", + want: `[{"0":0,"1":0},{"0":255,"1":0}]`, + contract: []byte{byte(vm.PUSH1), byte(0xff), byte(vm.PUSH1), byte(0x00), byte(vm.MSTORE8), byte(vm.STOP)}, + }, { + code: "{res: [], step: function(log) { if (log.op.toString() === 'STOP') { this.res.push(log.memory.slice(5, 1025 * 1024)) } }, fault: function() {}, result: function() { return this.res }}", + want: "", + fail: "tracer reached limit for padding memory slice: end 1049600, memorySize 32 at step (:1:83(23)) in server-side tracer function 'step'", + contract: []byte{byte(vm.PUSH1), byte(0xff), byte(vm.PUSH1), byte(0x00), byte(vm.MSTORE8), byte(vm.STOP)}, }, } { - if have, err := execTracer(tt.code); tt.want != string(have) || tt.fail != err { + if have, err := execTracer(tt.code, tt.contract); tt.want != string(have) || tt.fail != err { t.Errorf("testcase %d: expected return value to be '%s' got '%s', error to be '%s' got '%s'\n\tcode: %v", i, tt.want, string(have), tt.fail, err, tt.code) } } @@ -157,7 +170,7 @@ func TestHalt(t *testing.T) { time.Sleep(1 * time.Second) tracer.Stop(timeout) }() - if _, err = runTrace(tracer, testCtx(), params.TestChainConfig); !strings.Contains(err.Error(), "stahp") { + if _, err = runTrace(tracer, testCtx(), params.TestChainConfig, nil); !strings.Contains(err.Error(), "stahp") { t.Errorf("Expected timeout error, got %v", err) } } @@ -227,7 +240,7 @@ func TestIsPrecompile(t *testing.T) { } blockCtx := vm.BlockContext{BlockNumber: big.NewInt(150)} - res, err := runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg) + res, err := runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg, nil) if err != nil { t.Error(err) } @@ -237,7 +250,7 @@ func TestIsPrecompile(t *testing.T) { tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil) blockCtx = vm.BlockContext{BlockNumber: big.NewInt(250)} - res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg) + res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg, nil) if err != nil { t.Error(err) } From a3c6d1d9b6a33a4e5007ded00cf3483b06cf2838 Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 26 Sep 2022 11:30:50 +0200 Subject: [PATCH 263/715] cmd/faucet: fix readme typos (#25867) * Fix: typos Fix: typos * Undo change Undo change --- cmd/faucet/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/faucet/README.md b/cmd/faucet/README.md index c31676b0dac1..6e9b14ebc78a 100644 --- a/cmd/faucet/README.md +++ b/cmd/faucet/README.md @@ -2,13 +2,13 @@ The `faucet` is a simplistic web application with the goal of distributing small amounts of Ether in private and test networks. -Users need to post their Ethereum addresses to fund in a Twitter status update or public Facebook post and share the link to the faucet. The faucet will in turn deduplicate user requests and send the Ether. After a funding round, the faucet prevents the same user requesting again for a pre-configured amount of time, proportional to the amount of Ether requested. +Users need to post their Ethereum addresses to fund in a Twitter status update or public Facebook post and share the link to the faucet. The faucet will in turn deduplicate user requests and send the Ether. After a funding round, the faucet prevents the same user from requesting again for a pre-configured amount of time, proportional to the amount of Ether requested. ## Operation The `faucet` is a single binary app (everything included) with all configurations set via command line flags and a few files. -First thing's first, the `faucet` needs to connect to an Ethereum network, for which it needs the necessary genesis and network infos. Each of the following flags must be set: +First things first, the `faucet` needs to connect to an Ethereum network, for which it needs the necessary genesis and network infos. Each of the following flags must be set: - `-genesis` is a path to a file containing the network `genesis.json`. or using: - `-goerli` with the faucet with Görli network config @@ -50,4 +50,4 @@ Sybil protection via Facebook uses the website to directly download post data th ## Miscellaneous -Beside the above - mostly essential - CLI flags, there are a number that can be used to fine tune the `faucet`'s operation. Please see `faucet --help` for a full list. \ No newline at end of file +Beside the above - mostly essential - CLI flags, there are a number that can be used to fine-tune the `faucet`'s operation. Please see `faucet --help` for a full list. From e004e7d256d9fb60573a0de941d039634d844de9 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 26 Sep 2022 11:34:15 +0200 Subject: [PATCH 264/715] core: fix datarace in txpool, fixes #25870 and #25869 (#25872) core: fix datarace in txpool pendingnoce, fixes #25870 --- core/tx_pool.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/tx_pool.go b/core/tx_pool.go index 22328963dfb1..ee8b9f7a43f0 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -463,6 +463,9 @@ func (pool *TxPool) SetGasPrice(price *big.Int) { // Nonce returns the next nonce of an account, with all transactions executable // by the pool already applied on top. func (pool *TxPool) Nonce(addr common.Address) uint64 { + pool.mu.RLock() + defer pool.mu.RUnlock() + return pool.pendingNonces.get(addr) } From b32d20324e48766f155c0de1d371c37e2cf405e0 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Mon, 26 Sep 2022 18:33:21 +0800 Subject: [PATCH 265/715] eth/downloader, les/downloader: fix subtle flaw in queue delivery (#25861) * fix queue.deliver * les/downloader: fix queue.deliver Co-authored-by: Martin Holst Swende --- eth/downloader/queue.go | 2 +- les/downloader/queue.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 26c41711ded5..ab3ae3d77d0a 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -857,7 +857,7 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, } for _, header := range request.Headers[:i] { - if res, stale, err := q.resultCache.GetDeliverySlot(header.Number.Uint64()); err == nil { + if res, stale, err := q.resultCache.GetDeliverySlot(header.Number.Uint64()); err == nil && !stale { reconstruct(accepted, res) } else { // else: between here and above, some other peer filled this result, diff --git a/les/downloader/queue.go b/les/downloader/queue.go index 98ebff526e83..fe08c810a11f 100644 --- a/les/downloader/queue.go +++ b/les/downloader/queue.go @@ -870,7 +870,7 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, } for _, header := range request.Headers[:i] { - if res, stale, err := q.resultCache.GetDeliverySlot(header.Number.Uint64()); err == nil { + if res, stale, err := q.resultCache.GetDeliverySlot(header.Number.Uint64()); err == nil && !stale { reconstruct(accepted, res) } else { // else: between here and above, some other peer filled this result, From c55c56cf0a1fc4b217628c3e776849ad7d6cc632 Mon Sep 17 00:00:00 2001 From: Leon <316032931@qq.com> Date: Mon, 26 Sep 2022 19:20:38 +0800 Subject: [PATCH 266/715] core/vm: better handle error on eip activation check (#25131) * core/vm: correct logic for eip check of NewEVMInterpreter * refactor --- core/vm/interpreter.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 40fe23dc516c..04256bb4bdbe 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -90,15 +90,18 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { default: cfg.JumpTable = &frontierInstructionSet } - for i, eip := range cfg.ExtraEips { + var extraEips []int + for _, eip := range cfg.ExtraEips { copy := *cfg.JumpTable if err := EnableEIP(eip, ©); err != nil { // Disable it, so caller can check if it's activated or not - cfg.ExtraEips = append(cfg.ExtraEips[:i], cfg.ExtraEips[i+1:]...) log.Error("EIP activation failed", "eip", eip, "error", err) + } else { + extraEips = append(extraEips, eip) } cfg.JumpTable = © } + cfg.ExtraEips = extraEips } return &EVMInterpreter{ From 7227c9ef072b2bb974f20786b92f6eac418242e3 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 26 Sep 2022 05:55:18 -0600 Subject: [PATCH 267/715] cmd/geth: make dumpgenesis load genesis datadir if it exists (#25135) `geth dumpgenesis` currently does not respect the content of the data directory. Instead, it outputs the genesis block created by command-line flags. This PR fixes it to read the genesis from the database, if the database already exists. Co-authored-by: Martin Holst Swende --- cmd/geth/chaincmd.go | 42 ++++++++++++++++++++++++++++++++++-------- cmd/utils/flags.go | 14 +++++++++++--- core/genesis.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 11 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index a3016c4b091f..c89f736169ef 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -61,9 +61,10 @@ It expects the genesis file as argument.`, Name: "dumpgenesis", Usage: "Dumps genesis block JSON configuration to stdout", ArgsUsage: "", - Flags: utils.NetworkFlags, + Flags: append([]cli.Flag{utils.DataDirFlag}, utils.NetworkFlags...), Description: ` -The dumpgenesis command dumps the genesis block configuration in JSON format to stdout.`, +The dumpgenesis command prints the genesis configuration of the network preset +if one is set. Otherwise it prints the genesis from the datadir.`, } importCommand = &cli.Command{ Action: importChain, @@ -203,14 +204,39 @@ func initGenesis(ctx *cli.Context) error { } func dumpGenesis(ctx *cli.Context) error { - // TODO(rjl493456442) support loading from the custom datadir - genesis := utils.MakeGenesis(ctx) - if genesis == nil { - genesis = core.DefaultGenesisBlock() + // if there is a testnet preset enabled, dump that + if utils.IsNetworkPreset(ctx) { + genesis := utils.MakeGenesis(ctx) + if err := json.NewEncoder(os.Stdout).Encode(genesis); err != nil { + utils.Fatalf("could not encode genesis: %s", err) + } + return nil + } + // dump whatever already exists in the datadir + stack, _ := makeConfigNode(ctx) + for _, name := range []string{"chaindata", "lightchaindata"} { + db, err := stack.OpenDatabase(name, 0, 0, "", true) + if err != nil { + if !os.IsNotExist(err) { + return err + } + continue + } + genesis, err := core.ReadGenesis(db) + if err != nil { + utils.Fatalf("failed to read genesis: %s", err) + } + db.Close() + + if err := json.NewEncoder(os.Stdout).Encode(*genesis); err != nil { + utils.Fatalf("could not encode stored genesis: %s", err) + } + return nil } - if err := json.NewEncoder(os.Stdout).Encode(genesis); err != nil { - utils.Fatalf("could not encode genesis") + if ctx.IsSet(utils.DataDirFlag.Name) { + utils.Fatalf("no existing datadir at %s", stack.Config().DataDir) } + utils.Fatalf("no network preset provided. no exisiting genesis in the default datadir") return nil } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 595fe3360fe0..745b9f088eb3 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -988,9 +988,7 @@ var ( KilnFlag, } // NetworkFlags is the flag group of all built-in supported networks. - NetworkFlags = append([]cli.Flag{ - MainnetFlag, - }, TestnetFlags...) + NetworkFlags = append([]cli.Flag{MainnetFlag}, TestnetFlags...) // DatabasePathFlags is the flag group of all database path flags. DatabasePathFlags = []cli.Flag{ @@ -2140,6 +2138,16 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. return chainDb } +func IsNetworkPreset(ctx *cli.Context) bool { + for _, flag := range NetworkFlags { + bFlag, _ := flag.(*cli.BoolFlag) + if ctx.IsSet(bFlag.Name) { + return true + } + } + return false +} + func MakeGenesis(ctx *cli.Context) *core.Genesis { var genesis *core.Genesis switch { diff --git a/core/genesis.go b/core/genesis.go index 1c62bb1a137e..8b855147972d 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -65,6 +65,41 @@ type Genesis struct { BaseFee *big.Int `json:"baseFeePerGas"` } +func ReadGenesis(db ethdb.Database) (*Genesis, error) { + var genesis Genesis + stored := rawdb.ReadCanonicalHash(db, 0) + if (stored == common.Hash{}) { + return nil, fmt.Errorf("invalid genesis hash in database: %x", stored) + } + blob := rawdb.ReadGenesisStateSpec(db, stored) + if blob == nil { + return nil, fmt.Errorf("genesis state missing from db") + } + if len(blob) != 0 { + if err := genesis.Alloc.UnmarshalJSON(blob); err != nil { + return nil, fmt.Errorf("could not unmarshal genesis state json: %s", err) + } + } + genesis.Config = rawdb.ReadChainConfig(db, stored) + if genesis.Config == nil { + return nil, fmt.Errorf("genesis config missing from db") + } + genesisBlock := rawdb.ReadBlock(db, stored, 0) + if genesisBlock == nil { + return nil, fmt.Errorf("genesis block missing from db") + } + genesisHeader := genesisBlock.Header() + genesis.Nonce = genesisHeader.Nonce.Uint64() + genesis.Timestamp = genesisHeader.Time + genesis.ExtraData = genesisHeader.Extra + genesis.GasLimit = genesisHeader.GasLimit + genesis.Difficulty = genesisHeader.Difficulty + genesis.Mixhash = genesisHeader.MixDigest + genesis.Coinbase = genesisHeader.Coinbase + + return &genesis, nil +} + // GenesisAlloc specifies the initial state that is part of the genesis block. type GenesisAlloc map[common.Address]GenesisAccount From 3ec6fe6101004ce4dcece3ac49a45d6e927efc79 Mon Sep 17 00:00:00 2001 From: meowsbits Date: Mon, 26 Sep 2022 07:00:56 -0700 Subject: [PATCH 268/715] tests: fix state test error checking (#25702) Some tests define an 'expectException' error but the tests runner does not check for conditions where this test value is filled (error expected) but in which no error is returned by the test runner. An example of this scenario is GeneralStateTests/stTransactionTest/HighGasPrice.json, which expects a 'TR_NoFunds' error, but the test runner does not return any error. Signed-off-by: meows --- tests/state_test.go | 20 ++++++-------------- tests/state_test_util.go | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/tests/state_test.go b/tests/state_test.go index d33ebc4b00db..cd287413bdc5 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -57,12 +57,12 @@ func TestState(t *testing.T) { // Broken tests: // Expected failures: - //st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test") - //st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/3`, "bug in test") - //st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/0`, "bug in test") - //st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/3`, "bug in test") - //st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/0`, "bug in test") - //st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/3`, "bug in test") + // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test") + // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/3`, "bug in test") + // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/0`, "bug in test") + // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/3`, "bug in test") + // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/0`, "bug in test") + // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/3`, "bug in test") // For Istanbul, older tests were moved into LegacyTests for _, dir := range []string{ @@ -78,10 +78,6 @@ func TestState(t *testing.T) { t.Run(key+"/trie", func(t *testing.T) { withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { _, _, err := test.Run(subtest, vmconfig, false) - if err != nil && len(test.json.Post[subtest.Fork][subtest.Index].ExpectException) > 0 { - // Ignore expected errors (TODO MariusVanDerWijden check error string) - return nil - } return st.checkFailure(t, err) }) }) @@ -93,10 +89,6 @@ func TestState(t *testing.T) { return err } } - if err != nil && len(test.json.Post[subtest.Fork][subtest.Index].ExpectException) > 0 { - // Ignore expected errors (TODO MariusVanDerWijden check error string) - return nil - } return st.checkFailure(t, err) }) }) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index e24fc57b3b63..838e85dca2b7 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -159,11 +159,39 @@ func (t *StateTest) Subtests() []StateSubtest { return sub } +// checkError checks if the error returned by the state transition matches any expected error. +// A failing expectation returns a wrapped version of the original error, if any, +// or a new error detailing the failing expectation. +// This function does not return or modify the original error, it only evaluates and returns expectations for the error. +func (t *StateTest) checkError(subtest StateSubtest, err error) error { + expectedError := t.json.Post[subtest.Fork][subtest.Index].ExpectException + if err == nil && expectedError == "" { + return nil + } + if err == nil && expectedError != "" { + return fmt.Errorf("expected error %q, got no error", expectedError) + } + if err != nil && expectedError == "" { + return fmt.Errorf("unexpected error: %w", err) + } + if err != nil && expectedError != "" { + // Ignore expected errors (TODO MariusVanDerWijden check error string) + return nil + } + return nil +} + // Run executes a specific subtest and verifies the post-state and logs func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool) (*snapshot.Tree, *state.StateDB, error) { snaps, statedb, root, err := t.RunNoVerify(subtest, vmconfig, snapshotter) + if checkedErr := t.checkError(subtest, err); checkedErr != nil { + return snaps, statedb, checkedErr + } + // The error has been checked; if it was unexpected, it's already returned. if err != nil { - return snaps, statedb, err + // Here, an error exists but it was expected. + // We do not check the post state or logs. + return snaps, statedb, nil } post := t.json.Post[subtest.Fork][subtest.Index] // N.B: We need to do this in a two-step process, because the first Commit takes care @@ -231,7 +259,8 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh snapshot := statedb.Snapshot() gaspool := new(core.GasPool) gaspool.AddGas(block.GasLimit()) - if _, err := core.ApplyMessage(evm, msg, gaspool); err != nil { + _, err = core.ApplyMessage(evm, msg, gaspool) + if err != nil { statedb.RevertToSnapshot(snapshot) } // Add 0-value mining reward. This only makes a difference in the cases @@ -244,7 +273,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh statedb.Commit(config.IsEIP158(block.Number())) // And _now_ get the state root root := statedb.IntermediateRoot(config.IsEIP158(block.Number())) - return snaps, statedb, root, nil + return snaps, statedb, root, err } func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { From fc3e6d0162a0689228bf396e9903da79bb630cb2 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 26 Sep 2022 18:35:44 +0200 Subject: [PATCH 269/715] eth/tracers: use gencodec for native tracers (#25637) The call tracer and prestate tracer store data JSON-encoded in memory. In order to support alternative encodings (specifically RLP), it's better to keep data a native format during tracing. This PR does marshalling at the end, using gencodec. OBS! This PR changes the call tracer result slightly: - Order of type and value fields are changed (should not matter). - Output fields are completely omitted when they're empty (no more output: "0x"). Previously, this was only _sometimes_ omitted (e.g. when call ended in a non-revert error) and otherwise 0x when the output was actually empty. --- eth/tracers/native/4byte.go | 4 + eth/tracers/native/call.go | 100 +++++++++++------------ eth/tracers/native/gen_account_json.go | 56 +++++++++++++ eth/tracers/native/gen_callframe_json.go | 95 +++++++++++++++++++++ eth/tracers/native/prestate.go | 24 ++++-- 5 files changed, 219 insertions(+), 60 deletions(-) create mode 100644 eth/tracers/native/gen_account_json.go create mode 100644 eth/tracers/native/gen_callframe_json.go diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 7fb1c5e6c612..29f3bccb1a56 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -151,3 +151,7 @@ func (t *fourByteTracer) Stop(err error) { t.reason = err atomic.StoreUint32(&t.interrupt, 1) } + +func bytesToHex(s []byte) string { + return "0x" + common.Bytes2Hex(s) +} diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 7af0e658a8bf..54ae6dc8ab99 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -20,31 +20,47 @@ import ( "encoding/json" "errors" "math/big" - "strconv" - "strings" "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" ) +//go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go + func init() { register("callTracer", newCallTracer) } type callFrame struct { - Type string `json:"type"` - From string `json:"from"` - To string `json:"to,omitempty"` - Value string `json:"value,omitempty"` - Gas string `json:"gas"` - GasUsed string `json:"gasUsed"` - Input string `json:"input"` - Output string `json:"output,omitempty"` - Error string `json:"error,omitempty"` - Calls []callFrame `json:"calls,omitempty"` + Type vm.OpCode `json:"-"` + From common.Address `json:"from"` + Gas uint64 `json:"gas"` + GasUsed uint64 `json:"gasUsed"` + To common.Address `json:"to,omitempty" rlp:"optional"` + Input []byte `json:"input" rlp:"optional"` + Output []byte `json:"output,omitempty" rlp:"optional"` + Error string `json:"error,omitempty" rlp:"optional"` + Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + // Placed at end on purpose. The RLP will be decoded to 0 instead of + // nil if there are non-empty elements after in the struct. + Value *big.Int `json:"value,omitempty" rlp:"optional"` +} + +func (f callFrame) TypeString() string { + return f.Type.String() +} + +type callFrameMarshaling struct { + TypeString string `json:"type"` + Gas hexutil.Uint64 + GasUsed hexutil.Uint64 + Value *hexutil.Big + Input hexutil.Bytes + Output hexutil.Bytes } type callTracer struct { @@ -77,28 +93,29 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, e func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { t.env = env t.callstack[0] = callFrame{ - Type: "CALL", - From: addrToHex(from), - To: addrToHex(to), - Input: bytesToHex(input), - Gas: uintToHex(gas), - Value: bigToHex(value), + Type: vm.CALL, + From: from, + To: to, + Input: common.CopyBytes(input), + Gas: gas, + Value: value, } if create { - t.callstack[0].Type = "CREATE" + t.callstack[0].Type = vm.CREATE } } // CaptureEnd is called after the call finishes to finalize the tracing. func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { - t.callstack[0].GasUsed = uintToHex(gasUsed) + t.callstack[0].GasUsed = gasUsed + output = common.CopyBytes(output) if err != nil { t.callstack[0].Error = err.Error() if err.Error() == "execution reverted" && len(output) > 0 { - t.callstack[0].Output = bytesToHex(output) + t.callstack[0].Output = output } } else { - t.callstack[0].Output = bytesToHex(output) + t.callstack[0].Output = output } } @@ -122,12 +139,12 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. } call := callFrame{ - Type: typ.String(), - From: addrToHex(from), - To: addrToHex(to), - Input: bytesToHex(input), - Gas: uintToHex(gas), - Value: bigToHex(value), + Type: typ, + From: from, + To: to, + Input: common.CopyBytes(input), + Gas: gas, + Value: value, } t.callstack = append(t.callstack, call) } @@ -147,13 +164,13 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack = t.callstack[:size-1] size -= 1 - call.GasUsed = uintToHex(gasUsed) + call.GasUsed = gasUsed if err == nil { - call.Output = bytesToHex(output) + call.Output = common.CopyBytes(output) } else { call.Error = err.Error() - if call.Type == "CREATE" || call.Type == "CREATE2" { - call.To = "" + if call.Type == vm.CREATE || call.Type == vm.CREATE2 { + call.To = common.Address{} } } t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) @@ -181,22 +198,3 @@ func (t *callTracer) Stop(err error) { t.reason = err atomic.StoreUint32(&t.interrupt, 1) } - -func bytesToHex(s []byte) string { - return "0x" + common.Bytes2Hex(s) -} - -func bigToHex(n *big.Int) string { - if n == nil { - return "" - } - return "0x" + n.Text(16) -} - -func uintToHex(n uint64) string { - return "0x" + strconv.FormatUint(n, 16) -} - -func addrToHex(a common.Address) string { - return strings.ToLower(a.Hex()) -} diff --git a/eth/tracers/native/gen_account_json.go b/eth/tracers/native/gen_account_json.go new file mode 100644 index 000000000000..25dc77dc7455 --- /dev/null +++ b/eth/tracers/native/gen_account_json.go @@ -0,0 +1,56 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package native + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*accountMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (a account) MarshalJSON() ([]byte, error) { + type account struct { + Balance *hexutil.Big `json:"balance"` + Nonce uint64 `json:"nonce"` + Code hexutil.Bytes `json:"code"` + Storage map[common.Hash]common.Hash `json:"storage"` + } + var enc account + enc.Balance = (*hexutil.Big)(a.Balance) + enc.Nonce = a.Nonce + enc.Code = a.Code + enc.Storage = a.Storage + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (a *account) UnmarshalJSON(input []byte) error { + type account struct { + Balance *hexutil.Big `json:"balance"` + Nonce *uint64 `json:"nonce"` + Code *hexutil.Bytes `json:"code"` + Storage map[common.Hash]common.Hash `json:"storage"` + } + var dec account + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Balance != nil { + a.Balance = (*big.Int)(dec.Balance) + } + if dec.Nonce != nil { + a.Nonce = *dec.Nonce + } + if dec.Code != nil { + a.Code = *dec.Code + } + if dec.Storage != nil { + a.Storage = dec.Storage + } + return nil +} diff --git a/eth/tracers/native/gen_callframe_json.go b/eth/tracers/native/gen_callframe_json.go new file mode 100644 index 000000000000..baf0e32e6c68 --- /dev/null +++ b/eth/tracers/native/gen_callframe_json.go @@ -0,0 +1,95 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package native + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/vm" +) + +var _ = (*callFrameMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (c callFrame) MarshalJSON() ([]byte, error) { + type callFrame0 struct { + Type vm.OpCode `json:"-"` + From common.Address `json:"from"` + To common.Address `json:"to,omitempty" rlp:"optional"` + Gas hexutil.Uint64 `json:"gas"` + GasUsed hexutil.Uint64 `json:"gasUsed"` + Input hexutil.Bytes `json:"input" rlp:"optional"` + Output hexutil.Bytes `json:"output,omitempty" rlp:"optional"` + Error string `json:"error,omitempty" rlp:"optional"` + Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` + TypeString string `json:"type"` + } + var enc callFrame0 + enc.Type = c.Type + enc.From = c.From + enc.To = c.To + enc.Gas = hexutil.Uint64(c.Gas) + enc.GasUsed = hexutil.Uint64(c.GasUsed) + enc.Input = c.Input + enc.Output = c.Output + enc.Error = c.Error + enc.Calls = c.Calls + enc.Value = (*hexutil.Big)(c.Value) + enc.TypeString = c.TypeString() + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (c *callFrame) UnmarshalJSON(input []byte) error { + type callFrame0 struct { + Type *vm.OpCode `json:"-"` + From *common.Address `json:"from"` + To *common.Address `json:"to,omitempty" rlp:"optional"` + Gas *hexutil.Uint64 `json:"gas"` + GasUsed *hexutil.Uint64 `json:"gasUsed"` + Input *hexutil.Bytes `json:"input" rlp:"optional"` + Output *hexutil.Bytes `json:"output,omitempty" rlp:"optional"` + Error *string `json:"error,omitempty" rlp:"optional"` + Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` + } + var dec callFrame0 + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Type != nil { + c.Type = *dec.Type + } + if dec.From != nil { + c.From = *dec.From + } + if dec.To != nil { + c.To = *dec.To + } + if dec.Gas != nil { + c.Gas = uint64(*dec.Gas) + } + if dec.GasUsed != nil { + c.GasUsed = uint64(*dec.GasUsed) + } + if dec.Input != nil { + c.Input = *dec.Input + } + if dec.Output != nil { + c.Output = *dec.Output + } + if dec.Error != nil { + c.Error = *dec.Error + } + if dec.Calls != nil { + c.Calls = dec.Calls + } + if dec.Value != nil { + c.Value = (*big.Int)(dec.Value) + } + return nil +} diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index b513f383b9c2..918143a334e8 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -29,18 +29,25 @@ import ( "github.com/ethereum/go-ethereum/eth/tracers" ) +//go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go + func init() { register("prestateTracer", newPrestateTracer) } type prestate = map[common.Address]*account type account struct { - Balance string `json:"balance"` + Balance *big.Int `json:"balance"` Nonce uint64 `json:"nonce"` - Code string `json:"code"` + Code []byte `json:"code"` Storage map[common.Hash]common.Hash `json:"storage"` } +type accountMarshaling struct { + Balance *hexutil.Big + Code hexutil.Bytes +} + type prestateTracer struct { env *vm.EVM prestate prestate @@ -67,17 +74,16 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo t.lookupAccount(to) // The recipient balance includes the value transferred. - toBal := hexutil.MustDecodeBig(t.prestate[to].Balance) - toBal = new(big.Int).Sub(toBal, value) - t.prestate[to].Balance = hexutil.EncodeBig(toBal) + toBal := new(big.Int).Sub(t.prestate[to].Balance, value) + t.prestate[to].Balance = toBal // The sender balance is after reducing: value and gasLimit. // We need to re-add them to get the pre-tx balance. - fromBal := hexutil.MustDecodeBig(t.prestate[from].Balance) + fromBal := t.prestate[from].Balance gasPrice := env.TxContext.GasPrice consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit)) fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) - t.prestate[from].Balance = hexutil.EncodeBig(fromBal) + t.prestate[from].Balance = fromBal t.prestate[from].Nonce-- } @@ -160,9 +166,9 @@ func (t *prestateTracer) lookupAccount(addr common.Address) { return } t.prestate[addr] = &account{ - Balance: bigToHex(t.env.StateDB.GetBalance(addr)), + Balance: t.env.StateDB.GetBalance(addr), Nonce: t.env.StateDB.GetNonce(addr), - Code: bytesToHex(t.env.StateDB.GetCode(addr)), + Code: t.env.StateDB.GetCode(addr), Storage: make(map[common.Hash]common.Hash), } } From bff84a99fe5f9814807b1cce106f1d38e47488c7 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 27 Sep 2022 16:01:02 +0800 Subject: [PATCH 270/715] cmd, core, eth, les, light: track deleted nodes (#25757) * cmd, core, eth, les, light: track deleted nodes * trie: add docs * trie: address comments * cmd, core, eth, les, light, trie: trie id * trie: add tests * trie, core: updates * trie: fix imports * trie: add utility print-method for nodeset * trie: import err * trie: fix go vet warnings Co-authored-by: Martin Holst Swende --- cmd/geth/dbcmd.go | 39 ++++--- cmd/geth/snapshot.go | 10 +- core/blockchain.go | 13 ++- core/state/database.go | 8 +- core/state/iterator.go | 2 +- core/state/metrics.go | 14 +-- core/state/pruner/pruner.go | 7 +- core/state/snapshot/generate.go | 27 ++--- core/state/snapshot/generate_test.go | 5 +- core/state/state_object.go | 4 +- core/state/statedb.go | 49 ++++++--- core/state/sync_test.go | 7 +- core/state/trie_prefetcher.go | 8 +- eth/api.go | 4 +- eth/protocols/snap/handler.go | 12 ++- eth/protocols/snap/sync_test.go | 23 +++-- les/downloader/downloader_test.go | 2 +- les/handler_test.go | 8 +- les/request_test.go | 1 + les/server_handler.go | 4 +- les/server_requests.go | 2 +- light/odr.go | 12 ++- light/odr_test.go | 2 +- light/postprocess.go | 89 ++++++++-------- light/trie.go | 21 ++-- tests/fuzzers/trie/trie-fuzzer.go | 3 +- trie/committer.go | 32 +++++- trie/database.go | 32 +++++- trie/iterator.go | 14 ++- trie/iterator_test.go | 16 +-- trie/nodeset.go | 147 ++++++++++++++++++++++++--- trie/proof.go | 10 +- trie/secure_trie.go | 13 ++- trie/secure_trie_test.go | 6 +- trie/sync_test.go | 12 +-- trie/trie.go | 79 +++++++------- trie/trie_id.go | 55 ++++++++++ trie/trie_reader.go | 106 +++++++++++++++++++ trie/trie_test.go | 72 +++++++++---- trie/util_test.go | 120 +++++++++++++++++++++- trie/utils.go | 55 ++++++---- 41 files changed, 862 insertions(+), 283 deletions(-) create mode 100644 trie/trie_id.go create mode 100644 trie/trie_reader.go diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index bb53a632e862..9d834ee14b9d 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -150,7 +150,7 @@ WARNING: This is a low-level operation which may cause database corruption!`, Action: dbDumpTrie, Name: "dumptrie", Usage: "Show the storage key/values of a given storage trie", - ArgsUsage: " ", + ArgsUsage: " ", Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), @@ -486,7 +486,7 @@ func dbPut(ctx *cli.Context) error { // dbDumpTrie shows the key-value slots of a given storage trie func dbDumpTrie(ctx *cli.Context) error { - if ctx.NArg() < 1 { + if ctx.NArg() < 3 { return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage) } stack, _ := makeConfigNode(ctx) @@ -494,30 +494,41 @@ func dbDumpTrie(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() + var ( - root []byte - start []byte - max = int64(-1) - err error + state []byte + storage []byte + account []byte + start []byte + max = int64(-1) + err error ) - if root, err = hexutil.Decode(ctx.Args().Get(0)); err != nil { - log.Info("Could not decode the root", "error", err) + if state, err = hexutil.Decode(ctx.Args().Get(0)); err != nil { + log.Info("Could not decode the state root", "error", err) return err } - stRoot := common.BytesToHash(root) - if ctx.NArg() >= 2 { - if start, err = hexutil.Decode(ctx.Args().Get(1)); err != nil { + if account, err = hexutil.Decode(ctx.Args().Get(1)); err != nil { + log.Info("Could not decode the account hash", "error", err) + return err + } + if storage, err = hexutil.Decode(ctx.Args().Get(2)); err != nil { + log.Info("Could not decode the storage trie root", "error", err) + return err + } + if ctx.NArg() > 3 { + if start, err = hexutil.Decode(ctx.Args().Get(3)); err != nil { log.Info("Could not decode the seek position", "error", err) return err } } - if ctx.NArg() >= 3 { - if max, err = strconv.ParseInt(ctx.Args().Get(2), 10, 64); err != nil { + if ctx.NArg() > 4 { + if max, err = strconv.ParseInt(ctx.Args().Get(4), 10, 64); err != nil { log.Info("Could not decode the max count", "error", err) return err } } - theTrie, err := trie.New(common.Hash{}, stRoot, trie.NewDatabase(db)) + id := trie.StorageTrieID(common.BytesToHash(state), common.BytesToHash(account), common.BytesToHash(storage)) + theTrie, err := trie.New(id, trie.NewDatabase(db)) if err != nil { return err } diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index bbacdaf46354..a556f36a416a 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -286,7 +286,7 @@ func traverseState(ctx *cli.Context) error { log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64()) } triedb := trie.NewDatabase(chaindb) - t, err := trie.NewStateTrie(common.Hash{}, root, triedb) + t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb) if err != nil { log.Error("Failed to open trie", "root", root, "err", err) return err @@ -307,7 +307,8 @@ func traverseState(ctx *cli.Context) error { return err } if acc.Root != emptyRoot { - storageTrie, err := trie.NewStateTrie(common.BytesToHash(accIter.Key), acc.Root, triedb) + id := trie.StorageTrieID(root, common.BytesToHash(accIter.Key), acc.Root) + storageTrie, err := trie.NewStateTrie(id, triedb) if err != nil { log.Error("Failed to open storage trie", "root", acc.Root, "err", err) return err @@ -375,7 +376,7 @@ func traverseRawState(ctx *cli.Context) error { log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64()) } triedb := trie.NewDatabase(chaindb) - t, err := trie.NewStateTrie(common.Hash{}, root, triedb) + t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb) if err != nil { log.Error("Failed to open trie", "root", root, "err", err) return err @@ -421,7 +422,8 @@ func traverseRawState(ctx *cli.Context) error { return errors.New("invalid account") } if acc.Root != emptyRoot { - storageTrie, err := trie.NewStateTrie(common.BytesToHash(accIter.LeafKey()), acc.Root, triedb) + id := trie.StorageTrieID(root, common.BytesToHash(accIter.LeafKey()), acc.Root) + storageTrie, err := trie.NewStateTrie(id, triedb) if err != nil { log.Error("Failed to open storage trie", "root", acc.Root, "err", err) return errors.New("missing storage trie") diff --git a/core/blockchain.go b/core/blockchain.go index 671b9caf13d1..2d77ecf01b85 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -70,6 +70,8 @@ var ( snapshotStorageReadTimer = metrics.NewRegisteredTimer("chain/snapshot/storage/reads", nil) snapshotCommitTimer = metrics.NewRegisteredTimer("chain/snapshot/commits", nil) + triedbCommitTimer = metrics.NewRegisteredTimer("chain/triedb/commits", nil) + blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil) blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil) blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil) @@ -737,10 +739,10 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error { if block == nil { return fmt.Errorf("non existent block [%x..]", hash[:4]) } - if _, err := trie.NewStateTrie(common.Hash{}, block.Root(), bc.stateCache.TrieDB()); err != nil { - return err + root := block.Root() + if !bc.HasState(root) { + return fmt.Errorf("non existent state [%x..]", root[:4]) } - // If all checks out, manually set the head block. if !bc.chainmu.TryLock() { return errChainStopped @@ -752,7 +754,7 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error { // Destroy any existing state snapshot and regenerate it in the background, // also resuming the normal maintenance of any previously paused snapshot. if bc.snaps != nil { - bc.snaps.Rebuild(block.Root()) + bc.snaps.Rebuild(root) } log.Info("Committed new head block", "number", block.Number(), "hash", hash) return nil @@ -1750,8 +1752,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them + triedbCommitTimer.Update(statedb.TrieDBCommits) // Triedb commits are complete, we can mark them - blockWriteTimer.Update(time.Since(substart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits) + blockWriteTimer.Update(time.Since(substart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) blockInsertTimer.UpdateSince(start) // Report the import stats before returning the various results diff --git a/core/state/database.go b/core/state/database.go index 9b4fd8946e2b..5e3d9a9d388a 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -43,7 +43,7 @@ type Database interface { OpenTrie(root common.Hash) (Trie, error) // OpenStorageTrie opens the storage trie of an account. - OpenStorageTrie(addrHash, root common.Hash) (Trie, error) + OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) // CopyTrie returns an independent copy of the given trie. CopyTrie(Trie) Trie @@ -148,7 +148,7 @@ type cachingDB struct { // OpenTrie opens the main account trie at a specific root hash. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { - tr, err := trie.NewStateTrie(common.Hash{}, root, db.db) + tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.db) if err != nil { return nil, err } @@ -156,8 +156,8 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { } // OpenStorageTrie opens the storage trie of an account. -func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) { - tr, err := trie.NewStateTrie(addrHash, root, db.db) +func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) { + tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, addrHash, root), db.db) if err != nil { return nil, err } diff --git a/core/state/iterator.go b/core/state/iterator.go index 611df52431eb..ba7efd4653b3 100644 --- a/core/state/iterator.go +++ b/core/state/iterator.go @@ -109,7 +109,7 @@ func (it *NodeIterator) step() error { if err := rlp.Decode(bytes.NewReader(it.stateIt.LeafBlob()), &account); err != nil { return err } - dataTrie, err := it.state.db.OpenStorageTrie(common.BytesToHash(it.stateIt.LeafKey()), account.Root) + dataTrie, err := it.state.db.OpenStorageTrie(it.state.originalRoot, common.BytesToHash(it.stateIt.LeafKey()), account.Root) if err != nil { return err } diff --git a/core/state/metrics.go b/core/state/metrics.go index 35d2df92dda4..e702ef3a81a6 100644 --- a/core/state/metrics.go +++ b/core/state/metrics.go @@ -19,10 +19,12 @@ package state import "github.com/ethereum/go-ethereum/metrics" var ( - accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) - storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) - accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) - storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil) - accountTrieCommittedMeter = metrics.NewRegisteredMeter("state/commit/accountnodes", nil) - storageTriesCommittedMeter = metrics.NewRegisteredMeter("state/commit/storagenodes", nil) + accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) + storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) + accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) + storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil) + accountTrieUpdatedMeter = metrics.NewRegisteredMeter("state/update/accountnodes", nil) + storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil) + accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil) + storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil) ) diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 4ea54f8aace4..214699208471 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -93,7 +93,7 @@ type Pruner struct { func NewPruner(db ethdb.Database, config Config) (*Pruner, error) { headBlock := rawdb.ReadHeadBlock(db) if headBlock == nil { - return nil, errors.New("Failed to load head block") + return nil, errors.New("failed to load head block") } snapconfig := snapshot.Config{ CacheSize: 256, @@ -427,7 +427,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { if genesis == nil { return errors.New("missing genesis block") } - t, err := trie.NewStateTrie(common.Hash{}, genesis.Root(), trie.NewDatabase(db)) + t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), trie.NewDatabase(db)) if err != nil { return err } @@ -447,7 +447,8 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { return err } if acc.Root != emptyRoot { - storageTrie, err := trie.NewStateTrie(common.BytesToHash(accIter.LeafKey()), acc.Root, trie.NewDatabase(db)) + id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root) + storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db)) if err != nil { return err } diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index bf714db4c2d0..8589aa784f67 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -166,7 +166,7 @@ func (result *proofResult) forEach(callback func(key []byte, val []byte) error) // // The proof result will be returned if the range proving is finished, otherwise // the error will be returned to abort the entire procedure. -func (dl *diskLayer) proveRange(ctx *generatorContext, owner common.Hash, root common.Hash, prefix []byte, kind string, origin []byte, max int, valueConvertFn func([]byte) ([]byte, error)) (*proofResult, error) { +func (dl *diskLayer) proveRange(ctx *generatorContext, trieId *trie.ID, prefix []byte, kind string, origin []byte, max int, valueConvertFn func([]byte) ([]byte, error)) (*proofResult, error) { var ( keys [][]byte vals [][]byte @@ -233,8 +233,9 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, owner common.Hash, root c }(time.Now()) // The snap state is exhausted, pass the entire key/val set for verification + root := trieId.Root if origin == nil && !diskMore { - stackTr := trie.NewStackTrieWithOwner(nil, owner) + stackTr := trie.NewStackTrie(nil) for i, key := range keys { stackTr.TryUpdate(key, vals[i]) } @@ -248,7 +249,7 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, owner common.Hash, root c return &proofResult{keys: keys, vals: vals}, nil } // Snap state is chunked, generate edge proofs for verification. - tr, err := trie.New(owner, root, dl.triedb) + tr, err := trie.New(trieId, dl.triedb) if err != nil { ctx.stats.Log("Trie missing, state snapshotting paused", dl.root, dl.genMarker) return nil, errMissingTrie @@ -313,9 +314,9 @@ type onStateCallback func(key []byte, val []byte, write bool, delete bool) error // generateRange generates the state segment with particular prefix. Generation can // either verify the correctness of existing state through range-proof and skip // generation, or iterate trie to regenerate state on demand. -func (dl *diskLayer) generateRange(ctx *generatorContext, owner common.Hash, root common.Hash, prefix []byte, kind string, origin []byte, max int, onState onStateCallback, valueConvertFn func([]byte) ([]byte, error)) (bool, []byte, error) { +func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefix []byte, kind string, origin []byte, max int, onState onStateCallback, valueConvertFn func([]byte) ([]byte, error)) (bool, []byte, error) { // Use range prover to check the validity of the flat state in the range - result, err := dl.proveRange(ctx, owner, root, prefix, kind, origin, max, valueConvertFn) + result, err := dl.proveRange(ctx, trieId, prefix, kind, origin, max, valueConvertFn) if err != nil { return false, nil, err } @@ -363,7 +364,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, owner common.Hash, roo if len(result.keys) > 0 { snapNodeCache = memorydb.New() snapTrieDb := trie.NewDatabase(snapNodeCache) - snapTrie, _ := trie.New(owner, common.Hash{}, snapTrieDb) + snapTrie := trie.NewEmpty(snapTrieDb) for i, key := range result.keys { snapTrie.Update(key, result.vals[i]) } @@ -377,7 +378,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, owner common.Hash, roo // if it's already opened with some nodes resolved. tr := result.tr if tr == nil { - tr, err = trie.New(owner, root, dl.triedb) + tr, err = trie.New(trieId, dl.triedb) if err != nil { ctx.stats.Log("Trie missing, state snapshotting paused", dl.root, dl.genMarker) return false, nil, errMissingTrie @@ -460,7 +461,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, owner common.Hash, roo } else { snapAccountTrieReadCounter.Inc((time.Since(start) - internal).Nanoseconds()) } - logger.Debug("Regenerated state range", "root", root, "last", hexutil.Encode(last), + logger.Debug("Regenerated state range", "root", trieId.Root, "last", hexutil.Encode(last), "count", count, "created", created, "updated", updated, "untouched", untouched, "deleted", deleted) // If there are either more trie items, or there are more snap items @@ -511,7 +512,7 @@ func (dl *diskLayer) checkAndFlush(ctx *generatorContext, current []byte) error // generateStorages generates the missing storage slots of the specific contract. // It's supposed to restart the generation from the given origin position. -func generateStorages(ctx *generatorContext, dl *diskLayer, account common.Hash, storageRoot common.Hash, storeMarker []byte) error { +func generateStorages(ctx *generatorContext, dl *diskLayer, stateRoot common.Hash, account common.Hash, storageRoot common.Hash, storeMarker []byte) error { onStorage := func(key []byte, val []byte, write bool, delete bool) error { defer func(start time.Time) { snapStorageWriteCounter.Inc(time.Since(start).Nanoseconds()) @@ -540,7 +541,8 @@ func generateStorages(ctx *generatorContext, dl *diskLayer, account common.Hash, // Loop for re-generating the missing storage slots. var origin = common.CopyBytes(storeMarker) for { - exhausted, last, err := dl.generateRange(ctx, account, storageRoot, append(rawdb.SnapshotStoragePrefix, account.Bytes()...), snapStorage, origin, storageCheckRange, onStorage, nil) + id := trie.StorageTrieID(stateRoot, account, storageRoot) + exhausted, last, err := dl.generateRange(ctx, id, append(rawdb.SnapshotStoragePrefix, account.Bytes()...), snapStorage, origin, storageCheckRange, onStorage, nil) if err != nil { return err // The procedure it aborted, either by external signal or internal error. } @@ -624,7 +626,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er if accMarker != nil && bytes.Equal(account[:], accMarker) && len(dl.genMarker) > common.HashLength { storeMarker = dl.genMarker[common.HashLength:] } - if err := generateStorages(ctx, dl, account, acc.Root, storeMarker); err != nil { + if err := generateStorages(ctx, dl, dl.root, account, acc.Root, storeMarker); err != nil { return err } } @@ -640,7 +642,8 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er } origin := common.CopyBytes(accMarker) for { - exhausted, last, err := dl.generateRange(ctx, common.Hash{}, dl.root, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, FullAccountRLP) + id := trie.StateTrieID(dl.root) + exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, FullAccountRLP) if err != nil { return err // The procedure it aborted, either by external signal or internal error. } diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 58cfb464ff7b..784d76859e44 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -149,7 +149,7 @@ type testHelper struct { func newHelper() *testHelper { diskdb := rawdb.NewMemoryDatabase() triedb := trie.NewDatabase(diskdb) - accTrie, _ := trie.NewStateTrie(common.Hash{}, common.Hash{}, triedb) + accTrie, _ := trie.NewStateTrie(trie.StateTrieID(common.Hash{}), triedb) return &testHelper{ diskdb: diskdb, triedb: triedb, @@ -182,7 +182,8 @@ func (t *testHelper) addSnapStorage(accKey string, keys []string, vals []string) } func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string, vals []string, commit bool) []byte { - stTrie, _ := trie.NewStateTrie(owner, common.Hash{}, t.triedb) + id := trie.StorageTrieID(stateRoot, owner, common.Hash{}) + stTrie, _ := trie.NewStateTrie(id, t.triedb) for i, k := range keys { stTrie.Update([]byte(k), []byte(vals[i])) } diff --git a/core/state/state_object.go b/core/state/state_object.go index a23df895458c..178b93059317 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -159,9 +159,9 @@ func (s *stateObject) getTrie(db Database) Trie { } if s.trie == nil { var err error - s.trie, err = db.OpenStorageTrie(s.addrHash, s.data.Root) + s.trie, err = db.OpenStorageTrie(s.db.originalRoot, s.addrHash, s.data.Root) if err != nil { - s.trie, _ = db.OpenStorageTrie(s.addrHash, common.Hash{}) + s.trie, _ = db.OpenStorageTrie(s.db.originalRoot, s.addrHash, common.Hash{}) s.setError(fmt.Errorf("can't create storage trie: %v", err)) } } diff --git a/core/state/statedb.go b/core/state/statedb.go index b05f1742f57c..29a1ccf2d737 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -120,6 +120,7 @@ type StateDB struct { SnapshotAccountReads time.Duration SnapshotStorageReads time.Duration SnapshotCommits time.Duration + TrieDBCommits time.Duration AccountUpdated int StorageUpdated int @@ -904,9 +905,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { // Commit objects to the trie, measuring the elapsed time var ( - accountTrieNodes int - storageTrieNodes int - nodes = trie.NewMergedNodeSet() + accountTrieNodesUpdated int + accountTrieNodesDeleted int + storageTrieNodesUpdated int + storageTrieNodesDeleted int + nodes = trie.NewMergedNodeSet() ) codeWriter := s.db.DiskDB().NewBatch() for addr := range s.stateObjectsDirty { @@ -926,7 +929,9 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if err := nodes.Merge(set); err != nil { return common.Hash{}, err } - storageTrieNodes += set.Len() + updates, deleted := set.Size() + storageTrieNodesUpdated += updates + storageTrieNodesDeleted += deleted } } } @@ -952,7 +957,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if err := nodes.Merge(set); err != nil { return common.Hash{}, err } - accountTrieNodes = set.Len() + accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size() } if metrics.EnabledExpensive { s.AccountCommits += time.Since(start) @@ -961,16 +966,16 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { storageUpdatedMeter.Mark(int64(s.StorageUpdated)) accountDeletedMeter.Mark(int64(s.AccountDeleted)) storageDeletedMeter.Mark(int64(s.StorageDeleted)) - accountTrieCommittedMeter.Mark(int64(accountTrieNodes)) - storageTriesCommittedMeter.Mark(int64(storageTrieNodes)) + accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated)) + accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted)) + storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated)) + storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted)) s.AccountUpdated, s.AccountDeleted = 0, 0 s.StorageUpdated, s.StorageDeleted = 0, 0 } // If snapshotting is enabled, update the snapshot tree with this new version if s.snap != nil { - if metrics.EnabledExpensive { - defer func(start time.Time) { s.SnapshotCommits += time.Since(start) }(time.Now()) - } + start := time.Now() // Only update if there's a state transition (skip empty Clique blocks) if parent := s.snap.Root(); parent != root { if err := s.snaps.Update(root, parent, s.snapDestructs, s.snapAccounts, s.snapStorage); err != nil { @@ -984,13 +989,29 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { log.Warn("Failed to cap snapshot tree", "root", root, "layers", 128, "err", err) } } + if metrics.EnabledExpensive { + s.SnapshotCommits += time.Since(start) + } s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil } - if err := s.db.TrieDB().Update(nodes); err != nil { - return common.Hash{}, err + if root == (common.Hash{}) { + root = emptyRoot + } + origin := s.originalRoot + if origin == (common.Hash{}) { + origin = emptyRoot + } + if root != origin { + start := time.Now() + if err := s.db.TrieDB().Update(nodes); err != nil { + return common.Hash{}, err + } + s.originalRoot = root + if metrics.EnabledExpensive { + s.TrieDBCommits += time.Since(start) + } } - s.originalRoot = root - return root, err + return root, nil } // PrepareAccessList handles the preparatory steps for executing a state transition with diff --git a/core/state/sync_test.go b/core/state/sync_test.go index d16c7ce7322c..dbcbb7c96344 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -104,7 +104,7 @@ func checkTrieConsistency(db ethdb.KeyValueStore, root common.Hash) error { if v, _ := db.Get(root[:]); v == nil { return nil // Consider a non existent state consistent. } - trie, err := trie.New(common.Hash{}, root, trie.NewDatabase(db)) + trie, err := trie.New(trie.StateTrieID(root), trie.NewDatabase(db)) if err != nil { return err } @@ -174,7 +174,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { if commit { srcDb.TrieDB().Commit(srcRoot, false, nil) } - srcTrie, _ := trie.New(common.Hash{}, srcRoot, srcDb.TrieDB()) + srcTrie, _ := trie.New(trie.StateTrieID(srcRoot), srcDb.TrieDB()) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() @@ -222,7 +222,8 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { if err := rlp.DecodeBytes(srcTrie.Get(node.syncPath[0]), &acc); err != nil { t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err) } - stTrie, err := trie.New(common.BytesToHash(node.syncPath[0]), acc.Root, srcDb.TrieDB()) + id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root) + stTrie, err := trie.New(id, srcDb.TrieDB()) if err != nil { t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err) } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 678774a62b76..2e16f587ce56 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -150,7 +150,7 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, keys [][] id := p.trieID(owner, root) fetcher := p.fetchers[id] if fetcher == nil { - fetcher = newSubfetcher(p.db, owner, root) + fetcher = newSubfetcher(p.db, p.root, owner, root) p.fetchers[id] = fetcher } fetcher.schedule(keys) @@ -206,6 +206,7 @@ func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string { // the trie being worked on is retrieved from the prefetcher. type subfetcher struct { db Database // Database to load trie nodes through + state common.Hash // Root hash of the state to prefetch owner common.Hash // Owner of the trie, usually account hash root common.Hash // Root hash of the trie to prefetch trie Trie // Trie being populated with nodes @@ -225,9 +226,10 @@ type subfetcher struct { // newSubfetcher creates a goroutine to prefetch state items belonging to a // particular root hash. -func newSubfetcher(db Database, owner common.Hash, root common.Hash) *subfetcher { +func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash) *subfetcher { sf := &subfetcher{ db: db, + state: state, owner: owner, root: root, wake: make(chan struct{}, 1), @@ -298,7 +300,7 @@ func (sf *subfetcher) loop() { } sf.trie = trie } else { - trie, err := sf.db.OpenStorageTrie(sf.owner, sf.root) + trie, err := sf.db.OpenStorageTrie(sf.state, sf.owner, sf.root) if err != nil { log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) return diff --git a/eth/api.go b/eth/api.go index 3b5bb5f0aa9c..e480dde8f64f 100644 --- a/eth/api.go +++ b/eth/api.go @@ -508,11 +508,11 @@ func (api *DebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]c } triedb := api.eth.BlockChain().StateCache().TrieDB() - oldTrie, err := trie.NewStateTrie(common.Hash{}, startBlock.Root(), triedb) + oldTrie, err := trie.NewStateTrie(trie.StateTrieID(startBlock.Root()), triedb) if err != nil { return nil, err } - newTrie, err := trie.NewStateTrie(common.Hash{}, endBlock.Root(), triedb) + newTrie, err := trie.NewStateTrie(trie.StateTrieID(endBlock.Root()), triedb) if err != nil { return nil, err } diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 41380d96f571..aa245ab7e62d 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -283,7 +283,7 @@ func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePac req.Bytes = softResponseLimit } // Retrieve the requested state and bail out if non existent - tr, err := trie.New(common.Hash{}, req.Root, chain.StateCache().TrieDB()) + tr, err := trie.New(trie.StateTrieID(req.Root), chain.StateCache().TrieDB()) if err != nil { return nil, nil } @@ -413,7 +413,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP if origin != (common.Hash{}) || (abort && len(storage) > 0) { // Request started at a non-zero hash or was capped prematurely, add // the endpoint Merkle proofs - accTrie, err := trie.NewStateTrie(common.Hash{}, req.Root, chain.StateCache().TrieDB()) + accTrie, err := trie.NewStateTrie(trie.StateTrieID(req.Root), chain.StateCache().TrieDB()) if err != nil { return nil, nil } @@ -421,7 +421,8 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP if err != nil || acc == nil { return nil, nil } - stTrie, err := trie.NewStateTrie(account, acc.Root, chain.StateCache().TrieDB()) + id := trie.StorageTrieID(req.Root, account, acc.Root) + stTrie, err := trie.NewStateTrie(id, chain.StateCache().TrieDB()) if err != nil { return nil, nil } @@ -487,7 +488,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s // Make sure we have the state associated with the request triedb := chain.StateCache().TrieDB() - accTrie, err := trie.NewStateTrie(common.Hash{}, req.Root, triedb) + accTrie, err := trie.NewStateTrie(trie.StateTrieID(req.Root), triedb) if err != nil { // We don't have the requested state available, bail out return nil, nil @@ -529,7 +530,8 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s if err != nil || account == nil { break } - stTrie, err := trie.NewStateTrie(common.BytesToHash(pathset[0]), common.BytesToHash(account.Root), triedb) + id := trie.StorageTrieID(req.Root, common.BytesToHash(pathset[0]), common.BytesToHash(account.Root)) + stTrie, err := trie.NewStateTrie(id, triedb) loads++ // always account database reads, even for failures if err != nil { break diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 451245706564..1d1ce932e073 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1372,7 +1372,7 @@ func makeAccountTrieNoStorage(n int) (*trie.Trie, entrySlice) { root, nodes, _ := accTrie.Commit(false) db.Update(trie.NewWithNodeSet(nodes)) - accTrie, _ = trie.New(common.Hash{}, root, db) + accTrie, _ = trie.New(trie.StateTrieID(root), db) return accTrie, entries } @@ -1434,7 +1434,7 @@ func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) { root, nodes, _ := accTrie.Commit(false) db.Update(trie.NewWithNodeSet(nodes)) - accTrie, _ = trie.New(common.Hash{}, root, db) + accTrie, _ = trie.New(trie.StateTrieID(root), db) return accTrie, entries } @@ -1484,10 +1484,11 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) db.Update(nodes) // Re-create tries with new root - accTrie, _ = trie.New(common.Hash{}, root, db) + accTrie, _ = trie.New(trie.StateTrieID(root), db) for i := uint64(1); i <= uint64(accounts); i++ { key := key32(i) - trie, _ := trie.New(common.BytesToHash(key), storageRoots[common.BytesToHash(key)], db) + id := trie.StorageTrieID(root, common.BytesToHash(key), storageRoots[common.BytesToHash(key)]) + trie, _ := trie.New(id, db) storageTries[common.BytesToHash(key)] = trie } return accTrie, entries, storageTries, storageEntries @@ -1548,13 +1549,14 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie db.Update(nodes) // Re-create tries with new root - accTrie, err := trie.New(common.Hash{}, root, db) + accTrie, err := trie.New(trie.StateTrieID(root), db) if err != nil { panic(err) } for i := uint64(1); i <= uint64(accounts); i++ { key := key32(i) - trie, err := trie.New(common.BytesToHash(key), storageRoots[common.BytesToHash(key)], db) + id := trie.StorageTrieID(root, common.BytesToHash(key), storageRoots[common.BytesToHash(key)]) + trie, err := trie.New(id, db) if err != nil { panic(err) } @@ -1567,7 +1569,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie // not-yet-committed trie and the sorted entries. The seeds can be used to ensure // that tries are unique. func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trie.NodeSet, entrySlice) { - trie, _ := trie.New(owner, common.Hash{}, db) + trie, _ := trie.New(trie.StorageTrieID(common.Hash{}, owner, common.Hash{}), db) var entries entrySlice for i := uint64(1); i <= n; i++ { // store 'x' at slot 'x' @@ -1593,7 +1595,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo var ( entries entrySlice boundaries []common.Hash - trie, _ = trie.New(owner, common.Hash{}, db) + trie, _ = trie.New(trie.StorageTrieID(common.Hash{}, owner, common.Hash{}), db) ) // Initialize boundaries var next common.Hash @@ -1640,7 +1642,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { t.Helper() triedb := trie.NewDatabase(db) - accTrie, err := trie.New(common.Hash{}, root, triedb) + accTrie, err := trie.New(trie.StateTrieID(root), triedb) if err != nil { t.Fatal(err) } @@ -1658,7 +1660,8 @@ func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { } accounts++ if acc.Root != emptyRoot { - storeTrie, err := trie.NewStateTrie(common.BytesToHash(accIt.Key), acc.Root, triedb) + id := trie.StorageTrieID(root, common.BytesToHash(accIt.Key), acc.Root) + storeTrie, err := trie.NewStateTrie(id, triedb) if err != nil { t.Fatal(err) } diff --git a/les/downloader/downloader_test.go b/les/downloader/downloader_test.go index c56870ff1784..1704d3e7433a 100644 --- a/les/downloader/downloader_test.go +++ b/les/downloader/downloader_test.go @@ -229,7 +229,7 @@ func (dl *downloadTester) CurrentFastBlock() *types.Block { func (dl *downloadTester) FastSyncCommitHead(hash common.Hash) error { // For now only check that the state trie is correct if block := dl.GetBlockByHash(hash); block != nil { - _, err := trie.NewStateTrie(common.Hash{}, block.Root(), trie.NewDatabase(dl.stateDb)) + _, err := trie.NewStateTrie(trie.StateTrieID(block.Root()), trie.NewDatabase(dl.stateDb)) return err } return fmt.Errorf("non existent block: %x", hash[:4]) diff --git a/les/handler_test.go b/les/handler_test.go index 56d7d55b5a5f..ecf97bf9d109 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -405,7 +405,7 @@ func testGetProofs(t *testing.T, protocol int) { accounts := []common.Address{bankAddr, userAddr1, userAddr2, signerAddr, {}} for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ { header := bc.GetHeaderByNumber(i) - trie, _ := trie.New(common.Hash{}, header.Root, trie.NewDatabase(server.db)) + trie, _ := trie.New(trie.StateTrieID(header.Root), trie.NewDatabase(server.db)) for _, acc := range accounts { req := ProofReq{ @@ -456,7 +456,7 @@ func testGetStaleProof(t *testing.T, protocol int) { var expected []rlp.RawValue if wantOK { proofsV2 := light.NewNodeSet() - t, _ := trie.New(common.Hash{}, header.Root, trie.NewDatabase(server.db)) + t, _ := trie.New(trie.StateTrieID(header.Root), trie.NewDatabase(server.db)) t.Prove(account, 0, proofsV2) expected = proofsV2.NodeList() } @@ -512,7 +512,7 @@ func testGetCHTProofs(t *testing.T, protocol int) { AuxData: [][]byte{rlp}, } root := light.GetChtRoot(server.db, 0, bc.GetHeaderByNumber(config.ChtSize-1).Hash()) - trie, _ := trie.New(common.Hash{}, root, trie.NewDatabase(rawdb.NewTable(server.db, light.ChtTablePrefix))) + trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, light.ChtTablePrefix))) trie.Prove(key, 0, &proofsV2.Proofs) // Assemble the requests for the different protocols requestsV2 := []HelperTrieReq{{ @@ -577,7 +577,7 @@ func testGetBloombitsProofs(t *testing.T, protocol int) { var proofs HelperTrieResps root := light.GetBloomTrieRoot(server.db, 0, bc.GetHeaderByNumber(config.BloomTrieSize-1).Hash()) - trie, _ := trie.New(common.Hash{}, root, trie.NewDatabase(rawdb.NewTable(server.db, light.BloomTrieTablePrefix))) + trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, light.BloomTrieTablePrefix))) trie.Prove(key, 0, &proofs.Proofs) // Send the proof request and verify the response diff --git a/les/request_test.go b/les/request_test.go index c65405e37522..9b52e6bd86ad 100644 --- a/les/request_test.go +++ b/les/request_test.go @@ -104,6 +104,7 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) { bhash := rawdb.ReadCanonicalHash(server.db, i) if req := fn(client.db, bhash, i); req != nil { ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + err := client.handler.backend.odr.Retrieve(ctx, req) cancel() diff --git a/les/server_handler.go b/les/server_handler.go index a199a34a7254..32a38f64cc44 100644 --- a/les/server_handler.go +++ b/les/server_handler.go @@ -359,7 +359,7 @@ func (h *serverHandler) AddTxsSync() bool { // getAccount retrieves an account from the state based on root. func getAccount(triedb *trie.Database, root, hash common.Hash) (types.StateAccount, error) { - trie, err := trie.New(common.Hash{}, root, triedb) + trie, err := trie.New(trie.StateTrieID(root), triedb) if err != nil { return types.StateAccount{}, err } @@ -391,7 +391,7 @@ func (h *serverHandler) GetHelperTrie(typ uint, index uint64) *trie.Trie { if root == (common.Hash{}) { return nil } - trie, _ := trie.New(common.Hash{}, root, trie.NewDatabase(rawdb.NewTable(h.chainDb, prefix))) + trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(h.chainDb, prefix))) return trie } diff --git a/les/server_requests.go b/les/server_requests.go index bab5f733d549..b0eb2371e028 100644 --- a/les/server_requests.go +++ b/les/server_requests.go @@ -428,7 +428,7 @@ func handleGetProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) { p.bumpInvalid() continue } - trie, err = statedb.OpenStorageTrie(common.BytesToHash(request.AccKey), account.Root) + trie, err = statedb.OpenStorageTrie(root, common.BytesToHash(request.AccKey), account.Root) if trie == nil || err != nil { p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "root", account.Root, "err", err) continue diff --git a/light/odr.go b/light/odr.go index 9521dd53e85a..7cebe010d41f 100644 --- a/light/odr.go +++ b/light/odr.go @@ -53,9 +53,11 @@ type OdrRequest interface { // TrieID identifies a state or account storage trie type TrieID struct { - BlockHash, Root common.Hash - BlockNumber uint64 - AccKey []byte + BlockHash common.Hash + BlockNumber uint64 + StateRoot common.Hash + Root common.Hash + AccKey []byte } // StateTrieID returns a TrieID for a state trie belonging to a certain block @@ -64,8 +66,9 @@ func StateTrieID(header *types.Header) *TrieID { return &TrieID{ BlockHash: header.Hash(), BlockNumber: header.Number.Uint64(), - AccKey: nil, + StateRoot: header.Root, Root: header.Root, + AccKey: nil, } } @@ -76,6 +79,7 @@ func StorageTrieID(state *TrieID, addrHash, root common.Hash) *TrieID { return &TrieID{ BlockHash: state.BlockHash, BlockNumber: state.BlockNumber, + StateRoot: state.StateRoot, AccKey: addrHash[:], Root: root, } diff --git a/light/odr_test.go b/light/odr_test.go index 7f5670587545..903c7f6f90a6 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -87,7 +87,7 @@ func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error { t state.Trie ) if len(req.Id.AccKey) > 0 { - t, err = odr.serverState.OpenStorageTrie(common.BytesToHash(req.Id.AccKey), req.Id.Root) + t, err = odr.serverState.OpenStorageTrie(req.Id.StateRoot, common.BytesToHash(req.Id.AccKey), req.Id.Root) } else { t, err = odr.serverState.OpenTrie(req.Id.Root) } diff --git a/light/postprocess.go b/light/postprocess.go index 3f9da659333e..bd17eca8a3d2 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -25,7 +25,6 @@ import ( "math/big" "time" - mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/bitutil" "github.com/ethereum/go-ethereum/core" @@ -134,7 +133,6 @@ type ChtIndexerBackend struct { diskdb, trieTable ethdb.Database odr OdrBackend triedb *trie.Database - trieset mapset.Set section, sectionSize uint64 lastHash common.Hash trie *trie.Trie @@ -148,7 +146,6 @@ func NewChtIndexer(db ethdb.Database, odr OdrBackend, size, confirms uint64, dis odr: odr, trieTable: trieTable, triedb: trie.NewDatabaseWithConfig(trieTable, &trie.Config{Cache: 1}), // Use a tiny cache only to keep memory down - trieset: mapset.NewSet(), sectionSize: size, disablePruning: disablePruning, } @@ -187,12 +184,12 @@ func (c *ChtIndexerBackend) Reset(ctx context.Context, section uint64, lastSecti root = GetChtRoot(c.diskdb, section-1, lastSectionHead) } var err error - c.trie, err = trie.New(common.Hash{}, root, c.triedb) + c.trie, err = trie.New(trie.TrieID(root), c.triedb) if err != nil && c.odr != nil { err = c.fetchMissingNodes(ctx, section, root) if err == nil { - c.trie, err = trie.New(common.Hash{}, root, c.triedb) + c.trie, err = trie.New(trie.TrieID(root), c.triedb) } } c.section = section @@ -226,38 +223,44 @@ func (c *ChtIndexerBackend) Commit() error { if err := c.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { return err } + if err := c.triedb.Commit(root, false, nil); err != nil { + return err + } } // Re-create trie with newly generated root and updated database. - c.trie, err = trie.New(common.Hash{}, root, c.triedb) + c.trie, err = trie.New(trie.TrieID(root), c.triedb) if err != nil { return err } // Pruning historical trie nodes if necessary. if !c.disablePruning { - // Flush the triedb and track the latest trie nodes. - c.trieset.Clear() - c.triedb.Commit(root, false, func(hash common.Hash) { c.trieset.Add(hash) }) - it := c.trieTable.NewIterator(nil, nil) defer it.Release() var ( - deleted int - remaining int - t = time.Now() + deleted int + batch = c.trieTable.NewBatch() + t = time.Now() ) + hashes := make(map[common.Hash]struct{}) + if nodes != nil { + for _, hash := range nodes.Hashes() { + hashes[hash] = struct{}{} + } + } for it.Next() { trimmed := bytes.TrimPrefix(it.Key(), []byte(ChtTablePrefix)) - if !c.trieset.Contains(common.BytesToHash(trimmed)) { - c.trieTable.Delete(trimmed) - deleted += 1 - } else { - remaining += 1 + if len(trimmed) == common.HashLength { + if _, ok := hashes[common.BytesToHash(trimmed)]; !ok { + batch.Delete(trimmed) + deleted += 1 + } } } - log.Debug("Prune historical CHT trie nodes", "deleted", deleted, "remaining", remaining, "elapsed", common.PrettyDuration(time.Since(t))) - } else { - c.triedb.Commit(root, false, nil) + if err := batch.Write(); err != nil { + return err + } + log.Debug("Prune historical CHT trie nodes", "deleted", deleted, "remaining", len(hashes), "elapsed", common.PrettyDuration(time.Since(t))) } log.Info("Storing CHT", "section", c.section, "head", fmt.Sprintf("%064x", c.lastHash), "root", fmt.Sprintf("%064x", root)) StoreChtRoot(c.diskdb, c.section, c.lastHash, root) @@ -333,7 +336,6 @@ type BloomTrieIndexerBackend struct { disablePruning bool diskdb, trieTable ethdb.Database triedb *trie.Database - trieset mapset.Set odr OdrBackend section uint64 parentSize uint64 @@ -351,7 +353,6 @@ func NewBloomTrieIndexer(db ethdb.Database, odr OdrBackend, parentSize, size uin odr: odr, trieTable: trieTable, triedb: trie.NewDatabaseWithConfig(trieTable, &trie.Config{Cache: 1}), // Use a tiny cache only to keep memory down - trieset: mapset.NewSet(), parentSize: parentSize, size: size, disablePruning: disablePruning, @@ -414,11 +415,11 @@ func (b *BloomTrieIndexerBackend) Reset(ctx context.Context, section uint64, las root = GetBloomTrieRoot(b.diskdb, section-1, lastSectionHead) } var err error - b.trie, err = trie.New(common.Hash{}, root, b.triedb) + b.trie, err = trie.New(trie.TrieID(root), b.triedb) if err != nil && b.odr != nil { err = b.fetchMissingNodes(ctx, section, root) if err == nil { - b.trie, err = trie.New(common.Hash{}, root, b.triedb) + b.trie, err = trie.New(trie.TrieID(root), b.triedb) } } b.section = section @@ -473,38 +474,44 @@ func (b *BloomTrieIndexerBackend) Commit() error { if err := b.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { return err } + if err := b.triedb.Commit(root, false, nil); err != nil { + return err + } } // Re-create trie with newly generated root and updated database. - b.trie, err = trie.New(common.Hash{}, root, b.triedb) + b.trie, err = trie.New(trie.TrieID(root), b.triedb) if err != nil { return err } // Pruning historical trie nodes if necessary. if !b.disablePruning { - // Flush the triedb and track the latest trie nodes. - b.trieset.Clear() - b.triedb.Commit(root, false, func(hash common.Hash) { b.trieset.Add(hash) }) - it := b.trieTable.NewIterator(nil, nil) defer it.Release() var ( - deleted int - remaining int - t = time.Now() + deleted int + batch = b.trieTable.NewBatch() + t = time.Now() ) + hashes := make(map[common.Hash]struct{}) + if nodes != nil { + for _, hash := range nodes.Hashes() { + hashes[hash] = struct{}{} + } + } for it.Next() { trimmed := bytes.TrimPrefix(it.Key(), []byte(BloomTrieTablePrefix)) - if !b.trieset.Contains(common.BytesToHash(trimmed)) { - b.trieTable.Delete(trimmed) - deleted += 1 - } else { - remaining += 1 + if len(trimmed) == common.HashLength { + if _, ok := hashes[common.BytesToHash(trimmed)]; !ok { + batch.Delete(trimmed) + deleted += 1 + } } } - log.Debug("Prune historical bloom trie nodes", "deleted", deleted, "remaining", remaining, "elapsed", common.PrettyDuration(time.Since(t))) - } else { - b.triedb.Commit(root, false, nil) + if err := batch.Write(); err != nil { + return err + } + log.Debug("Prune historical bloom trie nodes", "deleted", deleted, "remaining", len(hashes), "elapsed", common.PrettyDuration(time.Since(t))) } sectionHead := b.sectionHeads[b.bloomTrieRatio-1] StoreBloomTrieRoot(b.diskdb, b.section, sectionHead, root) diff --git a/light/trie.go b/light/trie.go index 0f2e38625539..0092eee136c3 100644 --- a/light/trie.go +++ b/light/trie.go @@ -54,7 +54,7 @@ func (db *odrDatabase) OpenTrie(root common.Hash) (state.Trie, error) { return &odrTrie{db: db, id: db.id}, nil } -func (db *odrDatabase) OpenStorageTrie(addrHash, root common.Hash) (state.Trie, error) { +func (db *odrDatabase) OpenStorageTrie(state, addrHash, root common.Hash) (state.Trie, error) { return &odrTrie{db: db, id: StorageTrieID(db.id, addrHash, root)}, nil } @@ -63,8 +63,7 @@ func (db *odrDatabase) CopyTrie(t state.Trie) state.Trie { case *odrTrie: cpy := &odrTrie{db: t.db, id: t.id} if t.trie != nil { - cpytrie := *t.trie - cpy.trie = &cpytrie + cpy.trie = t.trie.Copy() } return cpy default: @@ -197,11 +196,13 @@ func (t *odrTrie) do(key []byte, fn func() error) error { for { var err error if t.trie == nil { - var owner common.Hash + var id *trie.ID if len(t.id.AccKey) > 0 { - owner = common.BytesToHash(t.id.AccKey) + id = trie.StorageTrieID(t.id.StateRoot, common.BytesToHash(t.id.AccKey), t.id.Root) + } else { + id = trie.StateTrieID(t.id.StateRoot) } - t.trie, err = trie.New(owner, t.id.Root, trie.NewDatabase(t.db.backend.Database())) + t.trie, err = trie.New(id, trie.NewDatabase(t.db.backend.Database())) } if err == nil { err = fn() @@ -227,11 +228,13 @@ func newNodeIterator(t *odrTrie, startkey []byte) trie.NodeIterator { // Open the actual non-ODR trie if that hasn't happened yet. if t.trie == nil { it.do(func() error { - var owner common.Hash + var id *trie.ID if len(t.id.AccKey) > 0 { - owner = common.BytesToHash(t.id.AccKey) + id = trie.StorageTrieID(t.id.StateRoot, common.BytesToHash(t.id.AccKey), t.id.Root) + } else { + id = trie.StateTrieID(t.id.StateRoot) } - t, err := trie.New(owner, t.id.Root, trie.NewDatabase(t.db.backend.Database())) + t, err := trie.New(id, trie.NewDatabase(t.db.backend.Database())) if err == nil { it.t.trie = t } diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index 25e137602ca1..8467bdafa6b6 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -21,7 +21,6 @@ import ( "encoding/binary" "fmt" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/trie" ) @@ -170,7 +169,7 @@ func runRandTest(rt randTest) error { return err } } - newtr, err := trie.New(common.Hash{}, hash, triedb) + newtr, err := trie.New(trie.TrieID(hash), triedb) if err != nil { return err } diff --git a/trie/committer.go b/trie/committer.go index 28fc5a63f940..90191cf9b1dd 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -33,13 +33,15 @@ type leaf struct { // insertion order. type committer struct { nodes *NodeSet + tracer *tracer collectLeaf bool } // newCommitter creates a new committer or picks one from the pool. -func newCommitter(owner common.Hash, collectLeaf bool) *committer { +func newCommitter(owner common.Hash, tracer *tracer, collectLeaf bool) *committer { return &committer{ nodes: NewNodeSet(owner), + tracer: tracer, collectLeaf: collectLeaf, } } @@ -51,6 +53,20 @@ func (c *committer) Commit(n node) (hashNode, *NodeSet, error) { if err != nil { return nil, nil, err } + // Some nodes can be deleted from trie which can't be captured by committer + // itself. Iterate all deleted nodes tracked by tracer and marked them as + // deleted only if they are present in database previously. + for _, path := range c.tracer.deleteList() { + // There are a few possibilities for this scenario(the node is deleted + // but not present in database previously), for example the node was + // embedded in the parent and now deleted from the trie. In this case + // it's noop from database's perspective. + val := c.tracer.getPrev(path) + if len(val) == 0 { + continue + } + c.nodes.markDeleted(path, val) + } return h.(hashNode), c.nodes, nil } @@ -83,6 +99,12 @@ func (c *committer) commit(path []byte, n node) (node, error) { if hn, ok := hashedNode.(hashNode); ok { return hn, nil } + // The short node now is embedded in its parent. Mark the node as + // deleted if it's present in database previously. It's equivalent + // as deletion from database's perspective. + if prev := c.tracer.getPrev(path); len(prev) != 0 { + c.nodes.markDeleted(path, prev) + } return collapsed, nil case *fullNode: hashedKids, err := c.commitChildren(path, cn) @@ -96,6 +118,12 @@ func (c *committer) commit(path []byte, n node) (node, error) { if hn, ok := hashedNode.(hashNode); ok { return hn, nil } + // The full node now is embedded in its parent. Mark the node as + // deleted if it's present in database previously. It's equivalent + // as deletion from database's perspective. + if prev := c.tracer.getPrev(path); len(prev) != 0 { + c.nodes.markDeleted(path, prev) + } return collapsed, nil case hashNode: return cn, nil @@ -161,7 +189,7 @@ func (c *committer) store(path []byte, n node) node { } ) // Collect the dirty node to nodeset for return. - c.nodes.add(string(path), mnode) + c.nodes.markUpdated(path, mnode, c.tracer.getPrev(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/database.go b/trie/database.go index 30120570ab57..76ca188add9c 100644 --- a/trie/database.go +++ b/trie/database.go @@ -795,8 +795,8 @@ func (db *Database) Update(nodes *MergedNodeSet) error { } for _, owner := range order { subset := nodes.sets[owner] - for _, path := range subset.paths { - n, ok := subset.nodes[path] + for _, path := range subset.updates.order { + n, ok := subset.updates.nodes[path] if !ok { return fmt.Errorf("missing node %x %v", owner, path) } @@ -837,6 +837,34 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize) { return db.dirtiesSize + db.childrenSize + metadataSize - metarootRefs, preimageSize } +// GetReader retrieves a node reader belonging to the given state root. +func (db *Database) GetReader(root common.Hash) Reader { + return newHashReader(db) +} + +// hashReader is reader of hashDatabase which implements the Reader interface. +type hashReader struct { + db *Database +} + +// newHashReader initializes the hash reader. +func newHashReader(db *Database) *hashReader { + return &hashReader{db: db} +} + +// Node retrieves the trie node with the given node hash. +// No error will be returned if the node is not found. +func (reader *hashReader) Node(_ common.Hash, _ []byte, hash common.Hash) (node, error) { + return reader.db.node(hash), nil +} + +// NodeBlob retrieves the RLP-encoded trie node blob with the given node hash. +// No error will be returned if the node is not found. +func (reader *hashReader) NodeBlob(_ common.Hash, _ []byte, hash common.Hash) ([]byte, error) { + blob, _ := reader.db.Node(hash) + return blob, nil +} + // saveCache saves clean state cache to given directory path // using specified CPU cores. func (db *Database) saveCache(dir string, threads int) error { diff --git a/trie/iterator.go b/trie/iterator.go index 1e76625c6213..b13651fc0439 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -375,7 +375,12 @@ func (it *nodeIterator) resolveHash(hash hashNode, path []byte) (node, error) { } } } - return it.trie.resolveHash(hash, path) + // Retrieve the specified node from the underlying node reader. + // it.trie.resolveAndTrack is not used since in that function the + // loaded blob will be tracked, while it's not required here since + // all loaded nodes won't be linked to trie at all and track nodes + // may lead to out-of-memory issue. + return it.trie.reader.node(path, common.BytesToHash(hash)) } func (it *nodeIterator) resolveBlob(hash hashNode, path []byte) ([]byte, error) { @@ -384,7 +389,12 @@ func (it *nodeIterator) resolveBlob(hash hashNode, path []byte) ([]byte, error) return blob, nil } } - return it.trie.resolveBlob(hash, path) + // Retrieve the specified node from the underlying node reader. + // it.trie.resolveAndTrack is not used since in that function the + // loaded blob will be tracked, while it's not required here since + // all loaded nodes won't be linked to trie at all and track nodes + // may lead to out-of-memory issue. + return it.trie.reader.nodeBlob(path, common.BytesToHash(hash)) } func (st *nodeIteratorState) resolve(it *nodeIterator, path []byte) error { diff --git a/trie/iterator_test.go b/trie/iterator_test.go index e9d822a9a4f2..74b87a25c233 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -66,7 +66,7 @@ func TestIterator(t *testing.T) { } db.Update(NewWithNodeSet(nodes)) - trie, _ = New(common.Hash{}, root, db) + trie, _ = New(TrieID(root), db) found := make(map[string]string) it := NewIterator(trie.NodeIterator(nil)) for it.Next() { @@ -227,7 +227,7 @@ func TestDifferenceIterator(t *testing.T) { } rootA, nodesA, _ := triea.Commit(false) dba.Update(NewWithNodeSet(nodesA)) - triea, _ = New(common.Hash{}, rootA, dba) + triea, _ = New(TrieID(rootA), dba) dbb := NewDatabase(rawdb.NewMemoryDatabase()) trieb := NewEmpty(dbb) @@ -236,7 +236,7 @@ func TestDifferenceIterator(t *testing.T) { } rootB, nodesB, _ := trieb.Commit(false) dbb.Update(NewWithNodeSet(nodesB)) - trieb, _ = New(common.Hash{}, rootB, dbb) + trieb, _ = New(TrieID(rootB), dbb) found := make(map[string]string) di, _ := NewDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil)) @@ -269,7 +269,7 @@ func TestUnionIterator(t *testing.T) { } rootA, nodesA, _ := triea.Commit(false) dba.Update(NewWithNodeSet(nodesA)) - triea, _ = New(common.Hash{}, rootA, dba) + triea, _ = New(TrieID(rootA), dba) dbb := NewDatabase(rawdb.NewMemoryDatabase()) trieb := NewEmpty(dbb) @@ -278,7 +278,7 @@ func TestUnionIterator(t *testing.T) { } rootB, nodesB, _ := trieb.Commit(false) dbb.Update(NewWithNodeSet(nodesB)) - trieb, _ = New(common.Hash{}, rootB, dbb) + trieb, _ = New(TrieID(rootB), dbb) di, _ := NewUnionIterator([]NodeIterator{triea.NodeIterator(nil), trieb.NodeIterator(nil)}) it := NewIterator(di) @@ -356,7 +356,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { } for i := 0; i < 20; i++ { // Create trie that will load all nodes from DB. - tr, _ := New(common.Hash{}, tr.Hash(), triedb) + tr, _ := New(TrieID(tr.Hash()), triedb) // Remove a random node from the database. It can't be the root node // because that one is already loaded. @@ -445,7 +445,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { } // Create a new iterator that seeks to "bars". Seeking can't proceed because // the node is missing. - tr, _ := New(common.Hash{}, root, triedb) + tr, _ := New(TrieID(root), triedb) it := tr.NodeIterator([]byte("bars")) missing, ok := it.Error().(*MissingNodeError) if !ok { @@ -533,7 +533,7 @@ func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) { // Create an empty trie logDb := &loggingDb{0, memorydb.New()} triedb := NewDatabase(logDb) - trie, _ := NewStateTrie(common.Hash{}, common.Hash{}, triedb) + trie, _ := NewStateTrie(TrieID(common.Hash{}), triedb) // Fill it with some arbitrary data for i := 0; i < 10000; i++ { diff --git a/trie/nodeset.go b/trie/nodeset.go index 08b9b35ebc87..0f9d4ea01570 100644 --- a/trie/nodeset.go +++ b/trie/nodeset.go @@ -18,6 +18,8 @@ package trie import ( "fmt" + "reflect" + "strings" "github.com/ethereum/go-ethereum/common" ) @@ -25,18 +27,77 @@ import ( // memoryNode is all the information we know about a single cached trie node // in the memory. type memoryNode struct { - hash common.Hash // Node hash, computed by hashing rlp value - size uint16 // Byte size of the useful cached data - node node // Cached collapsed trie node, or raw rlp data + hash common.Hash // Node hash, computed by hashing rlp value, empty for deleted nodes + size uint16 // Byte size of the useful cached data, 0 for deleted nodes + node node // Cached collapsed trie node, or raw rlp data, nil for deleted nodes +} + +// memoryNodeSize is the raw size of a memoryNode data structure without any +// node data included. It's an approximate size, but should be a lot better +// than not counting them. +// nolint:unused +var memoryNodeSize = int(reflect.TypeOf(memoryNode{}).Size()) + +// memorySize returns the total memory size used by this node. +// nolint:unused +func (n *memoryNode) memorySize(key int) int { + return int(n.size) + memoryNodeSize + key +} + +// rlp returns the raw rlp encoded blob of the cached trie node, either directly +// from the cache, or by regenerating it from the collapsed node. +// nolint:unused +func (n *memoryNode) rlp() []byte { + if node, ok := n.node.(rawNode); ok { + return node + } + return nodeToBytes(n.node) +} + +// obj returns the decoded and expanded trie node, either directly from the cache, +// or by regenerating it from the rlp encoded blob. +// nolint:unused +func (n *memoryNode) obj() node { + if node, ok := n.node.(rawNode); ok { + return mustDecodeNode(n.hash[:], node) + } + return expandNode(n.hash[:], n.node) +} + +// nodeWithPrev wraps the memoryNode with the previous node value. +type nodeWithPrev struct { + *memoryNode + prev []byte // RLP-encoded previous value, nil means it's non-existent +} + +// unwrap returns the internal memoryNode object. +// nolint:unused +func (n *nodeWithPrev) unwrap() *memoryNode { + return n.memoryNode +} + +// memorySize returns the total memory size used by this node. It overloads +// the function in memoryNode by counting the size of previous value as well. +// nolint: unused +func (n *nodeWithPrev) memorySize(key int) int { + return n.memoryNode.memorySize(key) + len(n.prev) +} + +// nodesWithOrder represents a collection of dirty nodes which includes +// newly-inserted and updated nodes. The modification order of all nodes +// is represented by order list. +type nodesWithOrder struct { + order []string // the path list of dirty nodes, sort by insertion order + nodes map[string]*nodeWithPrev // the map of dirty nodes, keyed by node path } // NodeSet contains all dirty nodes collected during the commit operation. // Each node is keyed by path. It's not thread-safe to use. type NodeSet struct { - owner common.Hash // the identifier of the trie - paths []string // the path of dirty nodes, sort by insertion order - nodes map[string]*memoryNode // the map of dirty nodes, keyed by node path - leaves []*leaf // the list of dirty leaves + owner common.Hash // the identifier of the trie + updates *nodesWithOrder // the set of updated nodes(newly inserted, updated) + deletes map[string][]byte // the map of deleted nodes, keyed by node + leaves []*leaf // the list of dirty leaves } // NewNodeSet initializes an empty node set to be used for tracking dirty nodes @@ -45,24 +106,78 @@ type NodeSet struct { func NewNodeSet(owner common.Hash) *NodeSet { return &NodeSet{ owner: owner, - nodes: make(map[string]*memoryNode), + updates: &nodesWithOrder{ + nodes: make(map[string]*nodeWithPrev), + }, + deletes: make(map[string][]byte), + } +} + +// NewNodeSetWithDeletion initializes the nodeset with provided deletion set. +func NewNodeSetWithDeletion(owner common.Hash, paths [][]byte, prev [][]byte) *NodeSet { + set := NewNodeSet(owner) + for i, path := range paths { + set.markDeleted(path, prev[i]) } + return set } -// add caches node with provided path and node object. -func (set *NodeSet) add(path string, node *memoryNode) { - set.paths = append(set.paths, path) - set.nodes[path] = node +// markUpdated marks the node as dirty(newly-inserted or updated) with provided +// node path, node object along with its previous value. +func (set *NodeSet) markUpdated(path []byte, node *memoryNode, prev []byte) { + set.updates.order = append(set.updates.order, string(path)) + set.updates.nodes[string(path)] = &nodeWithPrev{ + memoryNode: node, + prev: prev, + } +} + +// markDeleted marks the node as deleted with provided path and previous value. +func (set *NodeSet) markDeleted(path []byte, prev []byte) { + set.deletes[string(path)] = prev } -// addLeaf caches the provided leaf node. +// addLeaf collects the provided leaf node into set. func (set *NodeSet) addLeaf(node *leaf) { set.leaves = append(set.leaves, node) } -// Len returns the number of dirty nodes contained in the set. -func (set *NodeSet) Len() int { - return len(set.nodes) +// Size returns the number of updated and deleted nodes contained in the set. +func (set *NodeSet) Size() (int, int) { + return len(set.updates.order), len(set.deletes) +} + +// Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can +// we get rid of it? +func (set *NodeSet) Hashes() []common.Hash { + var ret []common.Hash + for _, node := range set.updates.nodes { + ret = append(ret, node.hash) + } + return ret +} + +// Summary returns a string-representation of the NodeSet. +func (set *NodeSet) Summary() string { + var out = new(strings.Builder) + fmt.Fprintf(out, "nodeset owner: %v\n", set.owner) + if set.updates != nil { + for _, key := range set.updates.order { + updated := set.updates.nodes[key] + if updated.prev != nil { + fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", key, updated.hash, updated.prev) + } else { + fmt.Fprintf(out, " [+]: %x -> %v\n", key, updated.hash) + } + } + } + for k, n := range set.deletes { + fmt.Fprintf(out, " [-]: %x -> %x\n", k, n) + } + for _, n := range set.leaves { + fmt.Fprintf(out, "[leaf]: %v\n", n) + } + return out.String() } // MergedNodeSet represents a merged dirty node set for a group of tries. diff --git a/trie/proof.go b/trie/proof.go index 8c00bcf5329d..8e706f886b59 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -22,7 +22,6 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) @@ -60,8 +59,13 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWriter) e key = key[1:] nodes = append(nodes, n) case hashNode: + // Retrieve the specified node from the underlying node reader. + // trie.resolveAndTrack is not used since in that function the + // loaded blob will be tracked, while it's not required here since + // all loaded nodes won't be linked to trie at all and track nodes + // may lead to out-of-memory issue. var err error - tn, err = t.resolveHash(n, prefix) + tn, err = t.reader.node(prefix, common.BytesToHash(n)) if err != nil { log.Error("Unhandled trie error in Trie.Prove", "err", err) return err @@ -559,7 +563,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key } // Rebuild the trie with the leaf stream, the shape of trie // should be same with the original one. - tr := &Trie{root: root, db: NewDatabase(rawdb.NewMemoryDatabase())} + tr := &Trie{root: root, reader: newEmptyReader()} if empty { tr.root = nil } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 0b7d33b2199d..96faab158265 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -29,8 +29,13 @@ type SecureTrie = StateTrie // NewSecure creates a new StateTrie. // Deprecated: use NewStateTrie. -func NewSecure(owner common.Hash, root common.Hash, db *Database) (*SecureTrie, error) { - return NewStateTrie(owner, root, db) +func NewSecure(stateRoot common.Hash, owner common.Hash, root common.Hash, db *Database) (*SecureTrie, error) { + id := &ID{ + StateRoot: stateRoot, + Owner: owner, + Root: root, + } + return NewStateTrie(id, db) } // StateTrie wraps a trie with key hashing. In a stateTrie trie, all @@ -56,11 +61,11 @@ type StateTrie struct { // If root is the zero hash or the sha3 hash of an empty string, the // trie is initially empty. Otherwise, New will panic if db is nil // and returns MissingNodeError if the root node cannot be found. -func NewStateTrie(owner common.Hash, root common.Hash, db *Database) (*StateTrie, error) { +func NewStateTrie(id *ID, db *Database) (*StateTrie, error) { if db == nil { panic("trie.NewStateTrie called without a database") } - trie, err := New(owner, root, db) + trie, err := New(id, db) if err != nil { return nil, err } diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index 862c3a3ec43d..ab8462607d99 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -29,7 +29,7 @@ import ( ) func newEmptySecure() *StateTrie { - trie, _ := NewStateTrie(common.Hash{}, common.Hash{}, NewDatabase(memorydb.New())) + trie, _ := NewStateTrie(TrieID(common.Hash{}), NewDatabase(memorydb.New())) return trie } @@ -37,7 +37,7 @@ func newEmptySecure() *StateTrie { func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) { // Create an empty trie triedb := NewDatabase(memorydb.New()) - trie, _ := NewStateTrie(common.Hash{}, common.Hash{}, triedb) + trie, _ := NewStateTrie(TrieID(common.Hash{}), triedb) // Fill it with some arbitrary data content := make(map[string][]byte) @@ -66,7 +66,7 @@ func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) { panic(fmt.Errorf("failed to commit db %v", err)) } // Re-create the trie based on the new state - trie, _ = NewSecure(common.Hash{}, root, triedb) + trie, _ = NewStateTrie(TrieID(root), triedb) return triedb, trie, content } diff --git a/trie/sync_test.go b/trie/sync_test.go index 9fd1d636c036..a02527855300 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -30,7 +30,7 @@ import ( func makeTestTrie() (*Database, *StateTrie, map[string][]byte) { // Create an empty trie triedb := NewDatabase(memorydb.New()) - trie, _ := NewStateTrie(common.Hash{}, common.Hash{}, triedb) + trie, _ := NewStateTrie(TrieID(common.Hash{}), triedb) // Fill it with some arbitrary data content := make(map[string][]byte) @@ -59,7 +59,7 @@ func makeTestTrie() (*Database, *StateTrie, map[string][]byte) { panic(fmt.Errorf("failed to commit db %v", err)) } // Re-create the trie based on the new state - trie, _ = NewSecure(common.Hash{}, root, triedb) + trie, _ = NewStateTrie(TrieID(root), triedb) return triedb, trie, content } @@ -67,7 +67,7 @@ func makeTestTrie() (*Database, *StateTrie, map[string][]byte) { // content map. func checkTrieContents(t *testing.T, db *Database, root []byte, content map[string][]byte) { // Check root availability and trie contents - trie, err := NewStateTrie(common.Hash{}, common.BytesToHash(root), db) + trie, err := NewStateTrie(TrieID(common.BytesToHash(root)), db) if err != nil { t.Fatalf("failed to create trie at %x: %v", root, err) } @@ -84,7 +84,7 @@ func checkTrieContents(t *testing.T, db *Database, root []byte, content map[stri // checkTrieConsistency checks that all nodes in a trie are indeed present. func checkTrieConsistency(db *Database, root common.Hash) error { // Create and iterate a trie rooted in a subnode - trie, err := NewStateTrie(common.Hash{}, root, db) + trie, err := NewStateTrie(TrieID(root), db) if err != nil { return nil // Consider a non existent state consistent } @@ -105,8 +105,8 @@ type trieElement struct { func TestEmptySync(t *testing.T) { dbA := NewDatabase(memorydb.New()) dbB := NewDatabase(memorydb.New()) - emptyA := NewEmpty(dbA) - emptyB, _ := New(common.Hash{}, emptyRoot, dbB) + emptyA, _ := New(TrieID(common.Hash{}), dbA) + emptyB, _ := New(TrieID(emptyRoot), dbB) for i, trie := range []*Trie{emptyA, emptyB} { sync := NewSync(trie.Hash(), memorydb.New(), nil) diff --git a/trie/trie.go b/trie/trie.go index 1ef1469c8dd3..bec6a1cc7891 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -67,9 +67,8 @@ type Trie struct { // actually unhashed nodes. unhashed int - // db is the handler trie can retrieve nodes from. It's - // only for reading purpose and not available for writing. - db *Database + // reader is the handler trie can retrieve nodes from. + reader *trieReader // tracer is the tool to track the trie changes. // It will be reset after each commit operation. @@ -87,26 +86,29 @@ func (t *Trie) Copy() *Trie { root: t.root, owner: t.owner, unhashed: t.unhashed, - db: t.db, + reader: t.reader, tracer: t.tracer.copy(), } } -// New creates a trie with an existing root node from db and an assigned -// owner for storage proximity. -// -// If root is the zero hash or the sha3 hash of an empty string, the -// trie is initially empty and does not require a database. Otherwise, -// New will panic if db is nil and returns a MissingNodeError if root does -// not exist in the database. Accessing the trie loads nodes from db on demand. -func New(owner common.Hash, root common.Hash, db *Database) (*Trie, error) { +// New creates the trie instance with provided trie id and the read-only +// database. The state specified by trie id must be available, otherwise +// an error will be returned. The trie root specified by trie id can be +// zero hash or the sha3 hash of an empty string, then trie is initially +// empty, otherwise, the root node must be present in database or returns +// a MissingNodeError if not. +func New(id *ID, db NodeReader) (*Trie, error) { + reader, err := newTrieReader(id.StateRoot, id.Owner, db) + if err != nil { + return nil, err + } trie := &Trie{ - owner: owner, - db: db, + owner: id.Owner, + reader: reader, //tracer: newTracer(), } - if root != (common.Hash{}) && root != emptyRoot { - rootnode, err := trie.resolveHash(root[:], nil) + if id.Root != (common.Hash{}) && id.Root != emptyRoot { + rootnode, err := trie.resolveAndTrack(id.Root[:], nil) if err != nil { return nil, err } @@ -117,7 +119,7 @@ func New(owner common.Hash, root common.Hash, db *Database) (*Trie, error) { // NewEmpty is a shortcut to create empty tree. It's mostly used in tests. func NewEmpty(db *Database) *Trie { - tr, _ := New(common.Hash{}, common.Hash{}, db) + tr, _ := New(TrieID(common.Hash{}), db) return tr } @@ -173,7 +175,7 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode } return value, n, didResolve, err case hashNode: - child, err := t.resolveHash(n, key[:pos]) + child, err := t.resolveAndTrack(n, key[:pos]) if err != nil { return nil, n, true, err } @@ -219,7 +221,7 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new if hash == nil { return nil, origNode, 0, errors.New("non-consensus node") } - blob, err := t.db.Node(common.BytesToHash(hash)) + blob, err := t.reader.nodeBlob(path, common.BytesToHash(hash)) return blob, origNode, 1, err } // Path still needs to be traversed, descend into children @@ -249,7 +251,7 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new return item, n, resolved, err case hashNode: - child, err := t.resolveHash(n, path[:pos]) + child, err := t.resolveAndTrack(n, path[:pos]) if err != nil { return nil, n, 1, err } @@ -370,7 +372,7 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error // We've hit a part of the trie that isn't loaded yet. Load // the node and insert into it. This leaves all child nodes on // the path to the value in the trie. - rn, err := t.resolveHash(n, prefix) + rn, err := t.resolveAndTrack(n, prefix) if err != nil { return false, nil, err } @@ -524,7 +526,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { // We've hit a part of the trie that isn't loaded yet. Load // the node and delete from it. This leaves all child nodes on // the path to the value in the trie. - rn, err := t.resolveHash(n, prefix) + rn, err := t.resolveAndTrack(n, prefix) if err != nil { return false, nil, err } @@ -548,30 +550,22 @@ func concat(s1 []byte, s2 ...byte) []byte { func (t *Trie) resolve(n node, prefix []byte) (node, error) { if n, ok := n.(hashNode); ok { - return t.resolveHash(n, prefix) + return t.resolveAndTrack(n, prefix) } return n, nil } -// resolveHash loads node from the underlying database with the provided -// node hash and path prefix. -func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) { - hash := common.BytesToHash(n) - if node := t.db.node(hash); node != nil { - return node, nil - } - return nil, &MissingNodeError{Owner: t.owner, NodeHash: hash, Path: prefix} -} - -// resolveHash loads rlp-encoded node blob from the underlying database -// with the provided node hash and path prefix. -func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) { - hash := common.BytesToHash(n) - blob, _ := t.db.Node(hash) - if len(blob) != 0 { - return blob, nil +// resolveAndTrack loads node from the underlying store with the given node hash +// and path prefix and also tracks the loaded node blob in tracer treated as the +// node's original value. The rlp-encoded blob is preferred to be loaded from +// database because it's easy to decode node while complex to encode node to blob. +func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { + blob, err := t.reader.nodeBlob(prefix, common.BytesToHash(n)) + if err != nil { + return nil, err } - return nil, &MissingNodeError{Owner: t.owner, NodeHash: hash, Path: prefix} + t.tracer.onRead(prefix, blob) + return mustDecodeNode(n, blob), nil } // Hash returns the root hash of the trie. It does not write to the @@ -606,7 +600,7 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { t.root = hashedNode return rootHash, nil, nil } - h := newCommitter(t.owner, collectLeaf) + h := newCommitter(t.owner, t.tracer, collectLeaf) newRoot, nodes, err := h.Commit(t.root) if err != nil { return common.Hash{}, nil, err @@ -633,6 +627,5 @@ func (t *Trie) Reset() { t.root = nil t.owner = common.Hash{} t.unhashed = 0 - //t.db = nil t.tracer.reset() } diff --git a/trie/trie_id.go b/trie/trie_id.go new file mode 100644 index 000000000000..8ab490ca3b1c --- /dev/null +++ b/trie/trie_id.go @@ -0,0 +1,55 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see + +package trie + +import "github.com/ethereum/go-ethereum/common" + +// ID is the identifier for uniquely identifying a trie. +type ID struct { + StateRoot common.Hash // The root of the corresponding state(block.root) + Owner common.Hash // The contract address hash which the trie belongs to + Root common.Hash // The root hash of trie +} + +// StateTrieID constructs an identifier for state trie with the provided state root. +func StateTrieID(root common.Hash) *ID { + return &ID{ + StateRoot: root, + Owner: common.Hash{}, + Root: root, + } +} + +// StorageTrieID constructs an identifier for storage trie which belongs to a certain +// state and contract specified by the stateRoot and owner. +func StorageTrieID(stateRoot common.Hash, owner common.Hash, root common.Hash) *ID { + return &ID{ + StateRoot: stateRoot, + Owner: owner, + Root: root, + } +} + +// TrieID constructs an identifier for a standard trie(not a second-layer trie) +// with provided root. It's mostly used in tests and some other tries like CHT trie. +func TrieID(root common.Hash) *ID { + return &ID{ + StateRoot: root, + Owner: common.Hash{}, + Root: root, + } +} diff --git a/trie/trie_reader.go b/trie/trie_reader.go new file mode 100644 index 000000000000..14186159b71b --- /dev/null +++ b/trie/trie_reader.go @@ -0,0 +1,106 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package trie + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" +) + +// Reader wraps the Node and NodeBlob method of a backing trie store. +type Reader interface { + // Node retrieves the trie node with the provided trie identifier, hexary + // node path and the corresponding node hash. + // No error will be returned if the node is not found. + Node(owner common.Hash, path []byte, hash common.Hash) (node, error) + + // NodeBlob retrieves the RLP-encoded trie node blob with the provided trie + // identifier, hexary node path and the corresponding node hash. + // No error will be returned if the node is not found. + NodeBlob(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) +} + +// NodeReader wraps all the necessary functions for accessing trie node. +type NodeReader interface { + // GetReader returns a reader for accessing all trie nodes with provided + // state root. Nil is returned in case the state is not available. + GetReader(root common.Hash) Reader +} + +// trieReader is a wrapper of the underlying node reader. It's not safe +// for concurrent usage. +type trieReader struct { + owner common.Hash + reader Reader + banned map[string]struct{} // Marker to prevent node from being accessed, for tests +} + +// newTrieReader initializes the trie reader with the given node reader. +func newTrieReader(stateRoot, owner common.Hash, db NodeReader) (*trieReader, error) { + reader := db.GetReader(stateRoot) + if reader == nil { + return nil, fmt.Errorf("state not found #%x", stateRoot) + } + return &trieReader{owner: owner, reader: reader}, nil +} + +// newEmptyReader initializes the pure in-memory reader. All read operations +// should be forbidden and returns the MissingNodeError. +func newEmptyReader() *trieReader { + return &trieReader{} +} + +// node retrieves the trie node with the provided trie node information. +// An MissingNodeError will be returned in case the node is not found or +// any error is encountered. +func (r *trieReader) node(path []byte, hash common.Hash) (node, error) { + // Perform the logics in tests for preventing trie node access. + if r.banned != nil { + if _, ok := r.banned[string(path)]; ok { + return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} + } + } + if r.reader == nil { + return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} + } + node, err := r.reader.Node(r.owner, path, hash) + if err != nil || node == nil { + return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path, err: err} + } + return node, nil +} + +// node retrieves the rlp-encoded trie node with the provided trie node +// information. An MissingNodeError will be returned in case the node is +// not found or any error is encountered. +func (r *trieReader) nodeBlob(path []byte, hash common.Hash) ([]byte, error) { + // Perform the logics in tests for preventing trie node access. + if r.banned != nil { + if _, ok := r.banned[string(path)]; ok { + return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} + } + } + if r.reader == nil { + return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} + } + blob, err := r.reader.NodeBlob(r.owner, path, hash) + if err != nil || len(blob) == 0 { + return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path, err: err} + } + return blob, nil +} diff --git a/trie/trie_test.go b/trie/trie_test.go index 3e29600bbd12..d2a599ffdd64 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -64,7 +64,8 @@ func TestNull(t *testing.T) { } func TestMissingRoot(t *testing.T) { - trie, err := New(common.Hash{}, common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(memorydb.New())) + root := common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") + trie, err := New(TrieID(root), NewDatabase(memorydb.New())) if trie != nil { t.Error("New returned non-nil trie for invalid root") } @@ -89,27 +90,27 @@ func testMissingNode(t *testing.T, memonly bool) { triedb.Commit(root, true, nil) } - trie, _ = New(common.Hash{}, root, triedb) + trie, _ = New(TrieID(root), triedb) _, err := trie.TryGet([]byte("120000")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(common.Hash{}, root, triedb) + trie, _ = New(TrieID(root), triedb) _, err = trie.TryGet([]byte("120099")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(common.Hash{}, root, triedb) + trie, _ = New(TrieID(root), triedb) _, err = trie.TryGet([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(common.Hash{}, root, triedb) + trie, _ = New(TrieID(root), triedb) err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(common.Hash{}, root, triedb) + trie, _ = New(TrieID(root), triedb) err = trie.TryDelete([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) @@ -122,27 +123,27 @@ func testMissingNode(t *testing.T, memonly bool) { diskdb.Delete(hash[:]) } - trie, _ = New(common.Hash{}, root, triedb) + trie, _ = New(TrieID(root), triedb) _, err = trie.TryGet([]byte("120000")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - trie, _ = New(common.Hash{}, root, triedb) + trie, _ = New(TrieID(root), triedb) _, err = trie.TryGet([]byte("120099")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - trie, _ = New(common.Hash{}, root, triedb) + trie, _ = New(TrieID(root), triedb) _, err = trie.TryGet([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } - trie, _ = New(common.Hash{}, root, triedb) + trie, _ = New(TrieID(root), triedb) err = trie.TryUpdate([]byte("120099"), []byte("zxcv")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } - trie, _ = New(common.Hash{}, root, triedb) + trie, _ = New(TrieID(root), triedb) err = trie.TryDelete([]byte("123456")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) @@ -196,7 +197,7 @@ func TestGet(t *testing.T) { } root, nodes, _ := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) - trie, _ = New(common.Hash{}, root, db) + trie, _ = New(TrieID(root), db) } } @@ -273,7 +274,7 @@ func TestReplication(t *testing.T) { triedb.Update(NewWithNodeSet(nodes)) // create a new trie on top of the database and check that lookups work. - trie2, err := New(common.Hash{}, exp, triedb) + trie2, err := New(TrieID(exp), triedb) if err != nil { t.Fatalf("can't recreate trie at %x: %v", exp, err) } @@ -294,7 +295,7 @@ func TestReplication(t *testing.T) { if nodes != nil { triedb.Update(NewWithNodeSet(nodes)) } - trie2, err = New(common.Hash{}, hash, triedb) + trie2, err = New(TrieID(hash), triedb) if err != nil { t.Fatalf("can't recreate trie at %x: %v", exp, err) } @@ -377,6 +378,7 @@ const ( opCommit opItercheckhash opNodeDiff + opProve opMax // boundary value, not an actual op ) @@ -402,7 +404,7 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value { step.key = genKey() step.value = make([]byte, 8) binary.BigEndian.PutUint64(step.value, uint64(i)) - case opGet, opDelete: + case opGet, opDelete, opProve: step.key = genKey() } steps = append(steps, step) @@ -436,24 +438,60 @@ func runRandTest(rt randTest) bool { if string(v) != want { rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) } + case opProve: + hash := tr.Hash() + if hash == emptyRoot { + continue + } + proofDb := rawdb.NewMemoryDatabase() + err := tr.Prove(step.key, 0, proofDb) + if err != nil { + rt[i].err = fmt.Errorf("failed for proving key %#x, %v", step.key, err) + } + _, err = VerifyProof(hash, step.key, proofDb) + if err != nil { + rt[i].err = fmt.Errorf("failed for verifying key %#x, %v", step.key, err) + } case opHash: tr.Hash() case opCommit: - hash, nodes, err := tr.Commit(false) + root, nodes, err := tr.Commit(true) if err != nil { rt[i].err = err return false } + // Validity the returned nodeset + if nodes != nil { + for path, node := range nodes.updates.nodes { + blob, _, _ := origTrie.TryGetNode(hexToCompact([]byte(path))) + got := node.prev + if !bytes.Equal(blob, got) { + rt[i].err = fmt.Errorf("prevalue mismatch for 0x%x, got 0x%x want 0x%x", path, got, blob) + panic(rt[i].err) + } + } + for path, prev := range nodes.deletes { + blob, _, _ := origTrie.TryGetNode(hexToCompact([]byte(path))) + if !bytes.Equal(blob, prev) { + rt[i].err = fmt.Errorf("prevalue mismatch for 0x%x, got 0x%x want 0x%x", path, prev, blob) + return false + } + } + } if nodes != nil { triedb.Update(NewWithNodeSet(nodes)) } - newtr, err := New(common.Hash{}, hash, triedb) + newtr, err := New(TrieID(root), triedb) if err != nil { rt[i].err = err return false } tr = newtr + + // Enable node tracing. Resolve the root node again explicitly + // since it's not captured at the beginning. tr.tracer = newTracer() + tr.resolveAndTrack(root.Bytes(), nil) origTrie = tr.Copy() case opItercheckhash: diff --git a/trie/util_test.go b/trie/util_test.go index cf6758e63d4a..e0e314205035 100644 --- a/trie/util_test.go +++ b/trie/util_test.go @@ -17,6 +17,7 @@ package trie import ( + "bytes" "testing" "github.com/ethereum/go-ethereum/common" @@ -72,7 +73,7 @@ func TestTrieTracer(t *testing.T) { if err := db.Update(NewWithNodeSet(nodes)); err != nil { t.Fatal(err) } - trie, _ = New(common.Hash{}, root, db) + trie, _ = New(TrieID(root), db) trie.tracer = newTracer() // Delete all the elements, check deletion set @@ -124,3 +125,120 @@ func TestTrieTracerNoop(t *testing.T) { t.Fatalf("Unexpected deleted node tracked %d", len(trie.tracer.deleteList())) } } + +func TestTrieTracePrevValue(t *testing.T) { + db := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(db) + trie.tracer = newTracer() + + paths, blobs := trie.tracer.prevList() + if len(paths) != 0 || len(blobs) != 0 { + t.Fatalf("Nothing should be tracked") + } + // Insert a batch of entries, all the nodes should be marked as inserted + vals := []struct{ k, v string }{ + {"do", "verb"}, + {"ether", "wookiedoo"}, + {"horse", "stallion"}, + {"shaman", "horse"}, + {"doge", "coin"}, + {"dog", "puppy"}, + {"somethingveryoddindeedthis is", "myothernodedata"}, + } + for _, val := range vals { + trie.Update([]byte(val.k), []byte(val.v)) + } + paths, blobs = trie.tracer.prevList() + if len(paths) != 0 || len(blobs) != 0 { + t.Fatalf("Nothing should be tracked") + } + + // Commit the changes and re-create with new root + root, nodes, _ := trie.Commit(false) + if err := db.Update(NewWithNodeSet(nodes)); err != nil { + t.Fatal(err) + } + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + trie.resolveAndTrack(root.Bytes(), nil) + + // Load all nodes in trie + for _, val := range vals { + trie.TryGet([]byte(val.k)) + } + + // Ensure all nodes are tracked by tracer with correct prev-values + iter := trie.NodeIterator(nil) + seen := make(map[string][]byte) + for iter.Next(true) { + // Embedded nodes are ignored since they are not present in + // database. + if iter.Hash() == (common.Hash{}) { + continue + } + seen[string(iter.Path())] = common.CopyBytes(iter.NodeBlob()) + } + + paths, blobs = trie.tracer.prevList() + if len(paths) != len(seen) || len(blobs) != len(seen) { + t.Fatalf("Unexpected tracked values") + } + for i, path := range paths { + blob := blobs[i] + prev, ok := seen[string(path)] + if !ok { + t.Fatalf("Missing node %v", path) + } + if !bytes.Equal(blob, prev) { + t.Fatalf("Unexpected value path: %v, want: %v, got: %v", path, prev, blob) + } + } + + // Re-open the trie and iterate the trie, ensure nothing will be tracked. + // Iterator will not link any loaded nodes to trie. + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + + iter = trie.NodeIterator(nil) + for iter.Next(true) { + } + paths, blobs = trie.tracer.prevList() + if len(paths) != 0 || len(blobs) != 0 { + t.Fatalf("Nothing should be tracked") + } + + // Re-open the trie and generate proof for entries, ensure nothing will + // be tracked. Prover will not link any loaded nodes to trie. + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + for _, val := range vals { + trie.Prove([]byte(val.k), 0, rawdb.NewMemoryDatabase()) + } + paths, blobs = trie.tracer.prevList() + if len(paths) != 0 || len(blobs) != 0 { + t.Fatalf("Nothing should be tracked") + } + + // Delete entries from trie, ensure all previous values are correct. + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + trie.resolveAndTrack(root.Bytes(), nil) + + for _, val := range vals { + trie.TryDelete([]byte(val.k)) + } + paths, blobs = trie.tracer.prevList() + if len(paths) != len(seen) || len(blobs) != len(seen) { + t.Fatalf("Unexpected tracked values") + } + for i, path := range paths { + blob := blobs[i] + prev, ok := seen[string(path)] + if !ok { + t.Fatalf("Missing node %v", path) + } + if !bytes.Equal(blob, prev) { + t.Fatalf("Unexpected value path: %v, want: %v, got: %v", path, prev, blob) + } + } +} diff --git a/trie/utils.go b/trie/utils.go index 7e26915041ef..d462b31bd205 100644 --- a/trie/utils.go +++ b/trie/utils.go @@ -50,45 +50,43 @@ func newTracer() *tracer { } } -/* // 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(key []byte, val []byte) { +func (t *tracer) onRead(path []byte, val []byte) { // Tracer isn't used right now, remove this check later. if t == nil { return } - t.origin[string(key)] = val + t.origin[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 the "untouched". -func (t *tracer) onInsert(key []byte) { +func (t *tracer) onInsert(path []byte) { // Tracer isn't used right now, remove this check later. if t == nil { return } - if _, present := t.delete[string(key)]; present { - delete(t.delete, string(key)) + if _, present := t.delete[string(path)]; present { + delete(t.delete, string(path)) return } - t.insert[string(key)] = struct{}{} + t.insert[string(path)] = struct{}{} } // 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(key []byte) { +func (t *tracer) onDelete(path []byte) { // Tracer isn't used right now, remove this check later. if t == nil { return } - if _, present := t.insert[string(key)]; present { - delete(t.insert, string(key)) + if _, present := t.insert[string(path)]; present { + delete(t.insert, string(path)) return } - t.delete[string(key)] = struct{}{} + t.delete[string(path)] = struct{}{} } // insertList returns the tracked inserted trie nodes in list format. @@ -98,8 +96,8 @@ func (t *tracer) insertList() [][]byte { return nil } var ret [][]byte - for key := range t.insert { - ret = append(ret, []byte(key)) + for path := range t.insert { + ret = append(ret, []byte(path)) } return ret } @@ -111,22 +109,37 @@ func (t *tracer) deleteList() [][]byte { return nil } var ret [][]byte - for key := range t.delete { - ret = append(ret, []byte(key)) + for path := range t.delete { + ret = append(ret, []byte(path)) } return ret } -/* +// prevList returns the tracked node blobs in list format. +func (t *tracer) prevList() ([][]byte, [][]byte) { + // Tracer isn't used right now, remove this check later. + if t == nil { + return nil, nil + } + var ( + paths [][]byte + blobs [][]byte + ) + for path, blob := range t.origin { + paths = append(paths, []byte(path)) + blobs = append(blobs, blob) + } + return paths, blobs +} + // getPrev returns the cached original value of the specified node. -func (t *tracer) getPrev(key []byte) []byte { - // Don't panic on uninitialized tracer, it's possible in testing. +func (t *tracer) getPrev(path []byte) []byte { + // Tracer isn't used right now, remove this check later. if t == nil { return nil } - return t.origin[string(key)] + return t.origin[string(path)] } -*/ // reset clears the content tracked by tracer. func (t *tracer) reset() { From 13e698592917a1d8a793af56d1f0a4bbec269fbb Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 27 Sep 2022 19:16:54 +0800 Subject: [PATCH 271/715] eth: return state error via GetEVM (#25876) * make vmError more useful * fix for review * Update api.go * revert calling site Co-authored-by: rjl493456442 --- eth/api_backend.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index 97c22c8fbbe9..ccc0966f00a5 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -214,13 +214,12 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { } func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { - vmError := func() error { return nil } if vmConfig == nil { vmConfig = b.eth.blockchain.GetVMConfig() } txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) - return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), vmError, nil + return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error, nil } func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { From 80cc34ac3c6857cdb702c76a53ea963aac6c795f Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 27 Sep 2022 15:49:52 +0200 Subject: [PATCH 272/715] eth/downloader: make flakey test less flakey (#25879) --- eth/downloader/skeleton_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index 6bcbac3a89fe..41373d33a861 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -803,7 +803,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) { } waitStart := time.Now() - for waitTime := 20 * time.Millisecond; time.Since(waitStart) < time.Second; waitTime = waitTime * 2 { + for waitTime := 20 * time.Millisecond; time.Since(waitStart) < 2*time.Second; waitTime = waitTime * 2 { time.Sleep(waitTime) // Check the post-init end state if it matches the required results json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) @@ -855,7 +855,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) { return nil } waitStart = time.Now() - for waitTime := 20 * time.Millisecond; time.Since(waitStart) < time.Second; waitTime = waitTime * 2 { + for waitTime := 20 * time.Millisecond; time.Since(waitStart) < 2*time.Second; waitTime = waitTime * 2 { time.Sleep(waitTime) // Check the post-init end state if it matches the required results json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) From 1a63a76fcc8c8055d3361f3d9c4b0a5bc9c0da6d Mon Sep 17 00:00:00 2001 From: Janko Simonovic Date: Tue, 27 Sep 2022 19:23:53 +0200 Subject: [PATCH 273/715] ethclient/gethclient: fix bugs in override object encoding (#25616) This fixes a bug where contract code would be overridden to empty code ("0x") when the Code field of OverrideAccount was left nil. The change also cleans up the encoding of overrides to only send necessary fields, and improves documentation. Fixes #25615 Co-authored-by: Felix Lange Co-authored-by: Martin Holst Swende --- ethclient/gethclient/gethclient.go | 78 +++++++++++++++---------- ethclient/gethclient/gethclient_test.go | 51 ++++++++++++++++ 2 files changed, 97 insertions(+), 32 deletions(-) diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index edc441bd1ee9..e182911aa5de 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -19,6 +19,7 @@ package gethclient import ( "context" + "encoding/json" "math/big" "runtime" "runtime/debug" @@ -118,15 +119,6 @@ func (ec *Client) GetProof(ctx context.Context, account common.Address, keys []s return &result, err } -// OverrideAccount specifies the state of an account to be overridden. -type OverrideAccount struct { - Nonce uint64 `json:"nonce"` - Code []byte `json:"code"` - Balance *big.Int `json:"balance"` - State map[common.Hash]common.Hash `json:"state"` - StateDiff map[common.Hash]common.Hash `json:"stateDiff"` -} - // CallContract executes a message call transaction, which is directly executed in the VM // of the node, but never mined into the blockchain. // @@ -141,7 +133,7 @@ func (ec *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockN var hex hexutil.Bytes err := ec.c.CallContext( ctx, &hex, "eth_call", toCallArg(msg), - toBlockNumArg(blockNumber), toOverrideMap(overrides), + toBlockNumArg(blockNumber), overrides, ) return hex, err } @@ -218,26 +210,48 @@ func toCallArg(msg ethereum.CallMsg) interface{} { return arg } -func toOverrideMap(overrides *map[common.Address]OverrideAccount) interface{} { - if overrides == nil { - return nil - } - type overrideAccount struct { - Nonce hexutil.Uint64 `json:"nonce"` - Code hexutil.Bytes `json:"code"` - Balance *hexutil.Big `json:"balance"` - State map[common.Hash]common.Hash `json:"state"` - StateDiff map[common.Hash]common.Hash `json:"stateDiff"` - } - result := make(map[common.Address]overrideAccount) - for addr, override := range *overrides { - result[addr] = overrideAccount{ - Nonce: hexutil.Uint64(override.Nonce), - Code: override.Code, - Balance: (*hexutil.Big)(override.Balance), - State: override.State, - StateDiff: override.StateDiff, - } - } - return &result +// OverrideAccount specifies the state of an account to be overridden. +type OverrideAccount struct { + // Nonce sets nonce of the account. Note: the nonce override will only + // be applied when it is set to a non-zero value. + Nonce uint64 + + // Code sets the contract code. The override will be applied + // when the code is non-nil, i.e. setting empty code is possible + // using an empty slice. + Code []byte + + // Balance sets the account balance. + Balance *big.Int + + // State sets the complete storage. The override will be applied + // when the given map is non-nil. Using an empty map wipes the + // entire contract storage during the call. + State map[common.Hash]common.Hash + + // StateDiff allows overriding individual storage slots. + StateDiff map[common.Hash]common.Hash +} + +func (a OverrideAccount) MarshalJSON() ([]byte, error) { + type acc struct { + Nonce hexutil.Uint64 `json:"nonce,omitempty"` + Code string `json:"code,omitempty"` + Balance *hexutil.Big `json:"balance,omitempty"` + State interface{} `json:"state,omitempty"` + StateDiff map[common.Hash]common.Hash `json:"stateDiff,omitempty"` + } + + output := acc{ + Nonce: hexutil.Uint64(a.Nonce), + Balance: (*hexutil.Big)(a.Balance), + StateDiff: a.StateDiff, + } + if a.Code != nil { + output.Code = hexutil.Encode(a.Code) + } + if a.State != nil { + output.State = a.State + } + return json.Marshal(output) } diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index e77c6015a215..0e2f7e57b69a 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -19,6 +19,7 @@ package gethclient import ( "bytes" "context" + "encoding/json" "math/big" "testing" @@ -322,3 +323,53 @@ func testCallContract(t *testing.T, client *rpc.Client) { t.Fatalf("unexpected error: %v", err) } } + +func TestOverrideAccountMarshal(t *testing.T) { + om := map[common.Address]OverrideAccount{ + common.Address{0x11}: OverrideAccount{ + // Zero-valued nonce is not overriddden, but simply dropped by the encoder. + Nonce: 0, + }, + common.Address{0xaa}: OverrideAccount{ + Nonce: 5, + }, + common.Address{0xbb}: OverrideAccount{ + Code: []byte{1}, + }, + common.Address{0xcc}: OverrideAccount{ + // 'code', 'balance', 'state' should be set when input is + // a non-nil but empty value. + Code: []byte{}, + Balance: big.NewInt(0), + State: map[common.Hash]common.Hash{}, + // For 'stateDiff' the behavior is different, empty map + // is ignored because it makes no difference. + StateDiff: map[common.Hash]common.Hash{}, + }, + } + + marshalled, err := json.MarshalIndent(&om, "", " ") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + expected := `{ + "0x1100000000000000000000000000000000000000": {}, + "0xaa00000000000000000000000000000000000000": { + "nonce": "0x5" + }, + "0xbb00000000000000000000000000000000000000": { + "code": "0x01" + }, + "0xcc00000000000000000000000000000000000000": { + "code": "0x", + "balance": "0x0", + "state": {} + } +}` + + if string(marshalled) != expected { + t.Error("wrong output:", string(marshalled)) + t.Error("want:", expected) + } +} From 456b1878928c75aae3f42e9f9c98a7ccd1a25666 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 28 Sep 2022 08:08:18 +0200 Subject: [PATCH 274/715] trie, eth/protocols/snap: less tiny db-writes during trie-healing (#25681) This PR prevent making tiny writes during state healing, by only performing the batch-write if the accumulated data is large enough to be meaningful. --- eth/protocols/snap/sync.go | 34 ++++++++++++++++++---------------- trie/sync.go | 12 +++++++++++- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index e23693789723..f262824f9adf 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -615,6 +615,8 @@ func (s *Syncer) Sync(root common.Hash, cancel chan struct{}) error { } }() defer s.report(true) + // commit any trie- and bytecode-healing data. + defer s.commitHealer(true) // Whether sync completed or not, disregard any future packets defer func() { @@ -2154,14 +2156,7 @@ func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) { log.Error("Invalid trienode processed", "hash", hash, "err", err) } } - batch := s.db.NewBatch() - if err := s.healer.scheduler.Commit(batch); err != nil { - log.Error("Failed to commit healing data", "err", err) - } - if err := batch.Write(); err != nil { - log.Crit("Failed to persist healing data", "err", err) - } - log.Debug("Persisted set of healing data", "type", "trienodes", "bytes", common.StorageSize(batch.ValueSize())) + s.commitHealer(false) // Calculate the processing rate of one filled trie node rate := float64(fills) / (float64(time.Since(start)) / float64(time.Second)) @@ -2208,6 +2203,20 @@ func (s *Syncer) processTrienodeHealResponse(res *trienodeHealResponse) { } } +func (s *Syncer) commitHealer(force bool) { + if !force && s.healer.scheduler.MemSize() < ethdb.IdealBatchSize { + return + } + batch := s.db.NewBatch() + if err := s.healer.scheduler.Commit(batch); err != nil { + log.Error("Failed to commit healing data", "err", err) + } + if err := batch.Write(); err != nil { + log.Crit("Failed to persist healing data", "err", err) + } + log.Debug("Persisted set of healing data", "type", "trienodes", "bytes", common.StorageSize(batch.ValueSize())) +} + // processBytecodeHealResponse integrates an already validated bytecode response // into the healer tasks. func (s *Syncer) processBytecodeHealResponse(res *bytecodeHealResponse) { @@ -2234,14 +2243,7 @@ func (s *Syncer) processBytecodeHealResponse(res *bytecodeHealResponse) { log.Error("Invalid bytecode processed", "hash", hash, "err", err) } } - batch := s.db.NewBatch() - if err := s.healer.scheduler.Commit(batch); err != nil { - log.Error("Failed to commit healing data", "err", err) - } - if err := batch.Write(); err != nil { - log.Crit("Failed to persist healing data", "err", err) - } - log.Debug("Persisted set of healing data", "type", "bytecode", "bytes", common.StorageSize(batch.ValueSize())) + s.commitHealer(false) } // forwardAccountTask takes a filled account task and persists anything available diff --git a/trie/sync.go b/trie/sync.go index 862ce7e16e6c..31d3cbe91b9e 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -111,6 +111,7 @@ type syncMemBatch struct { nodes map[string][]byte // In-memory membatch of recently completed nodes hashes map[string]common.Hash // Hashes of recently completed nodes codes map[common.Hash][]byte // In-memory membatch of recently completed codes + size uint64 // Estimated batch-size of in-memory data. } // newSyncMemBatch allocates a new memory-buffer for not-yet persisted trie nodes. @@ -338,6 +339,11 @@ func (s *Sync) Commit(dbw ethdb.Batch) error { return nil } +// MemSize returns an estimated size (in bytes) of the data held in the membatch. +func (s *Sync) MemSize() uint64 { + return s.membatch.size +} + // Pending returns the number of state entries currently pending for download. func (s *Sync) Pending() int { return len(s.nodeReqs) + len(s.codeReqs) @@ -479,7 +485,10 @@ func (s *Sync) commitNodeRequest(req *nodeRequest) error { // Write the node content to the membatch s.membatch.nodes[string(req.path)] = req.data s.membatch.hashes[string(req.path)] = req.hash - + // The size tracking refers to the db-batch, not the in-memory data. + // Therefore, we ignore the req.path, and account only for the hash+data + // which eventually is written to db. + s.membatch.size += common.HashLength + uint64(len(req.data)) delete(s.nodeReqs, string(req.path)) s.fetches[len(req.path)]-- @@ -501,6 +510,7 @@ func (s *Sync) commitNodeRequest(req *nodeRequest) error { func (s *Sync) commitCodeRequest(req *codeRequest) error { // Write the node content to the membatch s.membatch.codes[req.hash] = req.data + s.membatch.size += common.HashLength + uint64(len(req.data)) delete(s.codeReqs, req.hash) s.fetches[len(req.path)]-- From 1743e611301f54fc11f4fed8ebd74339715082a2 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Wed, 28 Sep 2022 01:55:07 -0600 Subject: [PATCH 275/715] accounts/abi/bind/backends: fix AdjustTime to respect Fork (#25225) --- accounts/abi/bind/backends/simulated.go | 7 ++++++- accounts/abi/bind/backends/simulated_test.go | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 7cd03d14e465..21c94d7e17e1 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -793,8 +793,13 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { if len(b.pendingBlock.Transactions()) != 0 { return errors.New("Could not adjust time on non-empty block") } + // Get the last block + block := b.blockchain.GetBlockByHash(b.pendingBlock.ParentHash()) + if block == nil { + return fmt.Errorf("could not find parent") + } - blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { + blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { block.OffsetTime(int64(adjustment.Seconds())) }) stateDB, _ := b.blockchain.State() diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index bb19b5455b03..40699e011636 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -1377,3 +1377,23 @@ func TestCommitReturnValue(t *testing.T) { t.Error("Could not retrieve the just created block (side-chain)") } } + +// TestAdjustTimeAfterFork ensures that after a fork, AdjustTime uses the pending fork +// block's parent rather than the canonical head's parent. +func TestAdjustTimeAfterFork(t *testing.T) { + testAddr := crypto.PubkeyToAddress(testKey.PublicKey) + sim := simTestBackend(testAddr) + defer sim.Close() + + sim.Commit() // h1 + h1 := sim.blockchain.CurrentHeader().Hash() + sim.Commit() // h2 + sim.Fork(context.Background(), h1) + sim.AdjustTime(1 * time.Second) + sim.Commit() + + head := sim.blockchain.CurrentHeader() + if head.Number == common.Big2 && head.ParentHash != h1 { + t.Errorf("failed to build block on fork") + } +} From 53d68feea8fcd0fcfbb575e9f9b55d5c2edff9f5 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 28 Sep 2022 10:39:20 +0200 Subject: [PATCH 276/715] tests: report mgas/s metric in evm benchmarks (#25700) * test(state): report mgas/s metric in EVM benchmark * revert testdata submodule update * aggregate mgas/s results * calculate elapsed time better * tests: benchmarks - handle access list + take refund into account Co-authored-by: Martin Holst Swende --- tests/state_test.go | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/state_test.go b/tests/state_test.go index cd287413bdc5..5c605f6722b1 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -26,6 +26,7 @@ import ( "reflect" "strings" "testing" + "time" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -184,12 +185,14 @@ func runBenchmark(b *testing.B, t *StateTest) { b.Error(err) return } + var rules = config.Rules(new(big.Int), false) + vmconfig.ExtraEips = eips block := t.genesis(config).ToBlock() _, statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, false) var baseFee *big.Int - if config.IsLondon(new(big.Int)) { + if rules.IsLondon { baseFee = t.json.Env.BaseFee if baseFee == nil { // Retesteth uses `0x10` for genesis baseFee. Therefore, it defaults to @@ -230,17 +233,40 @@ func runBenchmark(b *testing.B, t *StateTest) { sender := vm.NewContract(vm.AccountRef(msg.From()), vm.AccountRef(msg.From()), nil, 0) + var ( + gasUsed uint64 + elapsed uint64 + refund uint64 + ) b.ResetTimer() for n := 0; n < b.N; n++ { - // Execute the message. snapshot := statedb.Snapshot() - _, _, err = evm.Call(sender, *msg.To(), msg.Data(), msg.Gas(), msg.Value()) + if rules.IsBerlin { + statedb.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) + } + b.StartTimer() + start := time.Now() + + // Execute the message. + _, leftOverGas, err := evm.Call(sender, *msg.To(), msg.Data(), msg.Gas(), msg.Value()) if err != nil { b.Error(err) return } + + b.StopTimer() + elapsed += uint64(time.Since(start)) + refund += statedb.GetRefund() + gasUsed += msg.Gas() - leftOverGas + statedb.RevertToSnapshot(snapshot) } + if elapsed < 1 { + elapsed = 1 + } + // Keep it as uint64, multiply 100 to get two digit float later + mgasps := (100 * 1000 * (gasUsed - refund)) / elapsed + b.ReportMetric(float64(mgasps)/100, "mgas/s") }) } } From 2b1299b1c006077c56ecbad32e79fc16febe3dd6 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Wed, 28 Sep 2022 13:21:54 +0200 Subject: [PATCH 277/715] core/vm: minor trivial clean up (#25880) * dropped `vm.keccakState` for `crypto.KeccakState` * cleaned up `OpCode.IsPush()` --- core/vm/instructions.go | 4 ++-- core/vm/interpreter.go | 15 +++------------ core/vm/opcodes.go | 6 +----- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 12490025f511..22d459233b3d 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -21,9 +21,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" - "golang.org/x/crypto/sha3" ) func opAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { @@ -238,7 +238,7 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( data := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) if interpreter.hasher == nil { - interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState) + interpreter.hasher = crypto.NewKeccakState() } else { interpreter.hasher.Reset() } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 04256bb4bdbe..312977b75588 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -17,10 +17,9 @@ package vm import ( - "hash" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" ) @@ -44,21 +43,13 @@ type ScopeContext struct { Contract *Contract } -// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports -// Read to get a variable amount of data from the hash state. Read is faster than Sum -// because it doesn't copy the internal state, but also modifies the internal state. -type keccakState interface { - hash.Hash - Read([]byte) (int, error) -} - // EVMInterpreter represents an EVM interpreter type EVMInterpreter struct { evm *EVM cfg Config - hasher keccakState // Keccak256 hasher instance shared across opcodes - hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes + hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes + hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes readOnly bool // Whether to throw on stateful modifications returnData []byte // Last CALL's return data for subsequent reuse diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 70d854f15e9f..fa7de5049ace 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -25,11 +25,7 @@ type OpCode byte // IsPush specifies if an opcode is a PUSH opcode. func (op OpCode) IsPush() bool { - switch op { - case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: - return true - } - return false + return PUSH1 <= op && op <= PUSH32 } // 0x0 range - arithmetic ops. From 85aafcfb2b82f695f6fbae8db966e213df4ce8ae Mon Sep 17 00:00:00 2001 From: Delweng Date: Wed, 28 Sep 2022 23:52:39 +0800 Subject: [PATCH 278/715] eth/tracers: fix a bug in prestateTracer (#25884) --- eth/tracers/native/prestate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 918143a334e8..a40f84952a4c 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -79,7 +79,7 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo // The sender balance is after reducing: value and gasLimit. // We need to re-add them to get the pre-tx balance. - fromBal := t.prestate[from].Balance + fromBal := new(big.Int).Set(t.prestate[from].Balance) gasPrice := env.TxContext.GasPrice consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit)) fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) From 88132afc3f42d4f8ef05cdcaf0e59d68a8f4d599 Mon Sep 17 00:00:00 2001 From: TY <45994721+tylerK1294@users.noreply.github.com> Date: Thu, 29 Sep 2022 01:55:44 +0900 Subject: [PATCH 279/715] internal/ethapi: handle odd length hex in decodeHash (#25883) This change adds zero-padding (prefix) of odd nibbles in the decodeHash function. Co-authored-by: ty --- internal/ethapi/api.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 2e410605222c..64b389612aba 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -714,6 +714,9 @@ func decodeHash(s string) (common.Hash, error) { if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") { s = s[2:] } + if (len(s) & 1) > 0 { + s = "0" + s + } b, err := hex.DecodeString(s) if err != nil { return common.Hash{}, fmt.Errorf("hex string invalid") From 052c634917127b76e9089088860df27598c7ebad Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 29 Sep 2022 15:50:24 +0800 Subject: [PATCH 280/715] core: rework tx indexer (#25723) This PR reworks tx indexer a bit. Compared to the original version, one scenario is no longer handled - upgrading from legacy geth without indexer support. The tx indexer was introduced in 2020 and have been present through hardforks, so it can be assumed that all Geth nodes have tx indexer already. So we can simplify the tx indexer logic a bit: - If the tail flag is not present, it means node is just initialized may or may not with an ancient store attached. In this case all blocks are regarded as unindexed - If the tail flag is present, it means blocks below tail are unindexed, blocks above tail are indexed This change also address some weird cornercases that could make the indexer not work after a crash. --- core/blockchain.go | 131 +++++++---------- core/blockchain_test.go | 267 ++++++++++++++++++++++++++++------ core/rawdb/accessors_chain.go | 3 +- 3 files changed, 280 insertions(+), 121 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 2d77ecf01b85..2821fedb0f34 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -292,22 +292,16 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis bc.currentFinalizedBlock.Store(nilBlock) bc.currentSafeBlock.Store(nilBlock) - // Initialize the chain with ancient data if it isn't empty. - var txIndexBlock uint64 - + // If Geth is initialized with an external ancient store, re-initialize the + // missing chain indexes and chain flags. This procedure can survive crash + // and can be resumed in next restart since chain flags are updated in last step. if bc.empty() { rawdb.InitDatabaseFromFreezer(bc.db) - // If ancient database is not empty, reconstruct all missing - // indices in the background. - frozen, _ := bc.db.Ancients() - if frozen > 0 { - txIndexBlock = frozen - } } + // Load blockchain states from disk if err := bc.loadLastState(); err != nil { return nil, err } - // Make sure the state associated with the block is available head := bc.CurrentBlock() if _, err := state.New(head.Root(), bc.stateCache, bc.snaps); err != nil { @@ -415,14 +409,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis bc.wg.Add(1) go bc.updateFutureBlocks() - // Start tx indexer/unindexer. - if txLookupLimit != nil { - bc.txLookupLimit = *txLookupLimit - - bc.wg.Add(1) - go bc.maintainTxIndex(txIndexBlock) - } - // If periodic cache journal is required, spin it up. if bc.cacheConfig.TrieCleanRejournal > 0 { if bc.cacheConfig.TrieCleanRejournal < time.Minute { @@ -442,6 +428,13 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis bc.SetHead(compat.RewindTo) rawdb.WriteChainConfig(db, genesisHash, chainConfig) } + // Start tx indexer/unindexer if required. + if txLookupLimit != nil { + bc.txLookupLimit = *txLookupLimit + + bc.wg.Add(1) + go bc.maintainTxIndex() + } return bc, nil } @@ -2289,6 +2282,44 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool { return false } +// indexBlocks reindexes or unindexes transactions depending on user configuration +func (bc *BlockChain) indexBlocks(tail *uint64, head uint64, done chan struct{}) { + defer func() { close(done) }() + + // The tail flag is not existent, it means the node is just initialized + // and all blocks(may from ancient store) are not indexed yet. + if tail == nil { + from := uint64(0) + if bc.txLookupLimit != 0 && head >= bc.txLookupLimit { + from = head - bc.txLookupLimit + 1 + } + rawdb.IndexTransactions(bc.db, from, head+1, bc.quit) + return + } + // The tail flag is existent, but the whole chain is required to be indexed. + if bc.txLookupLimit == 0 || head < bc.txLookupLimit { + if *tail > 0 { + // It can happen when chain is rewound to a historical point which + // is even lower than the indexes tail, recap the indexing target + // to new head to avoid reading non-existent block bodies. + end := *tail + if end > head+1 { + end = head + 1 + } + rawdb.IndexTransactions(bc.db, 0, end, bc.quit) + } + return + } + // Update the transaction index to the new chain state + if head-bc.txLookupLimit+1 < *tail { + // Reindex a part of missing indices and rewind index tail to HEAD-limit + rawdb.IndexTransactions(bc.db, head-bc.txLookupLimit+1, *tail, bc.quit) + } else { + // Unindex a part of stale indices and forward index tail to HEAD-limit + rawdb.UnindexTransactions(bc.db, *tail, head-bc.txLookupLimit+1, bc.quit) + } +} + // maintainTxIndex is responsible for the construction and deletion of the // transaction index. // @@ -2296,65 +2327,13 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool { // which ancient tx indices get deleted. If `txlookuplimit` is 0, it means // all tx indices will be reserved. // -// The user can adjust the txlookuplimit value for each launch after fast -// sync, Geth will automatically construct the missing indices and delete -// the extra indices. -func (bc *BlockChain) maintainTxIndex(ancients uint64) { +// The user can adjust the txlookuplimit value for each launch after sync, +// Geth will automatically construct the missing indices or delete the extra +// indices. +func (bc *BlockChain) maintainTxIndex() { defer bc.wg.Done() - // Before starting the actual maintenance, we need to handle a special case, - // where user might init Geth with an external ancient database. If so, we - // need to reindex all necessary transactions before starting to process any - // pruning requests. - if ancients > 0 { - var from = uint64(0) - if bc.txLookupLimit != 0 && ancients > bc.txLookupLimit { - from = ancients - bc.txLookupLimit - } - rawdb.IndexTransactions(bc.db, from, ancients, bc.quit) - } - - // indexBlocks reindexes or unindexes transactions depending on user configuration - indexBlocks := func(tail *uint64, head uint64, done chan struct{}) { - defer func() { done <- struct{}{} }() - - // If the user just upgraded Geth to a new version which supports transaction - // index pruning, write the new tail and remove anything older. - if tail == nil { - if bc.txLookupLimit == 0 || head < bc.txLookupLimit { - // Nothing to delete, write the tail and return - rawdb.WriteTxIndexTail(bc.db, 0) - } else { - // Prune all stale tx indices and record the tx index tail - rawdb.UnindexTransactions(bc.db, 0, head-bc.txLookupLimit+1, bc.quit) - } - return - } - // If a previous indexing existed, make sure that we fill in any missing entries - if bc.txLookupLimit == 0 || head < bc.txLookupLimit { - if *tail > 0 { - // It can happen when chain is rewound to a historical point which - // is even lower than the indexes tail, recap the indexing target - // to new head to avoid reading non-existent block bodies. - end := *tail - if end > head+1 { - end = head + 1 - } - rawdb.IndexTransactions(bc.db, 0, end, bc.quit) - } - return - } - // Update the transaction index to the new chain state - if head-bc.txLookupLimit+1 < *tail { - // Reindex a part of missing indices and rewind index tail to HEAD-limit - rawdb.IndexTransactions(bc.db, head-bc.txLookupLimit+1, *tail, bc.quit) - } else { - // Unindex a part of stale indices and forward index tail to HEAD-limit - rawdb.UnindexTransactions(bc.db, *tail, head-bc.txLookupLimit+1, bc.quit) - } - } - - // Any reindexing done, start listening to chain events and moving the index window + // Listening to chain events and manipulate the transaction indexes. var ( done chan struct{} // Non-nil if background unindexing or reindexing routine is active. headCh = make(chan ChainHeadEvent, 1) // Buffered to avoid locking up the event feed @@ -2370,7 +2349,7 @@ func (bc *BlockChain) maintainTxIndex(ancients uint64) { case head := <-headCh: if done == nil { done = make(chan struct{}) - go indexBlocks(rawdb.ReadTxIndexTail(bc.db), head.Block.NumberU64(), done) + go bc.indexBlocks(rawdb.ReadTxIndexTail(bc.db), head.Block.NumberU64(), done) } case <-done: done = nil diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 08061bc2498a..aba50c8627c9 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2479,15 +2479,13 @@ func TestTransactionIndices(t *testing.T) { } signer = types.LatestSigner(gspec.Config) ) - height := uint64(128) - genDb, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), func(i int, block *BlockGen) { + _, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 128, func(i int, block *BlockGen) { tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key) if err != nil { panic(err) } block.AddTx(tx) }) - blocks2, _ := GenerateChain(gspec.Config, blocks[len(blocks)-1], ethash.NewFaker(), genDb, 10, nil) check := func(tail *uint64, chain *BlockChain) { stored := rawdb.ReadTxIndexTail(chain.db) @@ -2522,43 +2520,20 @@ func TestTransactionIndices(t *testing.T) { } } } - frdir := t.TempDir() - ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) - if err != nil { - t.Fatalf("failed to create temp freezer db: %v", err) - } - // Import all blocks into ancient db - l := uint64(0) - chain, err := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) - if err != nil { - t.Fatalf("failed to create tester chain: %v", err) - } - headers := make([]*types.Header, len(blocks)) - for i, block := range blocks { - headers[i] = block.Header() - } - if n, err := chain.InsertHeaderChain(headers, 0); err != nil { - t.Fatalf("failed to insert header %d: %v", n, err) - } - if n, err := chain.InsertReceiptChain(blocks, receipts, 128); err != nil { - t.Fatalf("block %d: failed to insert into chain: %v", n, err) - } - chain.Stop() - ancientDb.Close() - // Init block chain with external ancients, check all needed indices has been indexed. limit := []uint64{0, 32, 64, 128} for _, l := range limit { - ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) - if err != nil { - t.Fatalf("failed to create temp freezer db: %v", err) - } + frdir := t.TempDir() + ancientDb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + rawdb.WriteAncientBlocks(ancientDb, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0)) + l := l - chain, err = NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } - time.Sleep(50 * time.Millisecond) // Wait for indices initialisation + chain.indexBlocks(rawdb.ReadTxIndexTail(ancientDb), 128, make(chan struct{})) + var tail uint64 if l != 0 { tail = uint64(128) - l + 1 @@ -2566,26 +2541,27 @@ func TestTransactionIndices(t *testing.T) { check(&tail, chain) chain.Stop() ancientDb.Close() + os.RemoveAll(frdir) } // Reconstruct a block chain which only reserves HEAD-64 tx indices - ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) - if err != nil { - t.Fatalf("failed to create temp freezer db: %v", err) - } + ancientDb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) defer ancientDb.Close() + rawdb.WriteAncientBlocks(ancientDb, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0)) limit = []uint64{0, 64 /* drop stale */, 32 /* shorten history */, 64 /* extend history */, 0 /* restore all */} - tails := []uint64{0, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */, 69 /* 132 - 64 + 1 */, 0} - for i, l := range limit { + for _, l := range limit { l := l - chain, err = NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } - chain.InsertChain(blocks2[i : i+1]) // Feed chain a higher block to trigger indices updater. - time.Sleep(50 * time.Millisecond) // Wait for indices initialisation - check(&tails[i], chain) + var tail uint64 + if l != 0 { + tail = uint64(128) - l + 1 + } + chain.indexBlocks(rawdb.ReadTxIndexTail(ancientDb), 128, make(chan struct{})) + check(&tail, chain) chain.Stop() } } @@ -3784,3 +3760,208 @@ func TestCanonicalHashMarker(t *testing.T) { } } } + +// TestTxIndexer tests the tx indexes are updated correctly. +func TestTxIndexer(t *testing.T) { + var ( + testBankKey, _ = crypto.GenerateKey() + testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) + testBankFunds = big.NewInt(1000000000000000000) + + gspec = &Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, + BaseFee: big.NewInt(params.InitialBaseFee), + } + engine = ethash.NewFaker() + nonce = uint64(0) + ) + _, blocks, receipts := GenerateChainWithGenesis(gspec, engine, 128, func(i int, gen *BlockGen) { + tx, _ := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("0xdeadbeef"), big.NewInt(1000), params.TxGas, big.NewInt(10*params.InitialBaseFee), nil), types.HomesteadSigner{}, testBankKey) + gen.AddTx(tx) + nonce += 1 + }) + + // verifyIndexes checks if the transaction indexes are present or not + // of the specified block. + verifyIndexes := func(db ethdb.Database, number uint64, exist bool) { + if number == 0 { + return + } + block := blocks[number-1] + for _, tx := range block.Transactions() { + lookup := rawdb.ReadTxLookupEntry(db, tx.Hash()) + if exist && lookup == nil { + t.Fatalf("missing %d %x", number, tx.Hash().Hex()) + } + if !exist && lookup != nil { + t.Fatalf("unexpected %d %x", number, tx.Hash().Hex()) + } + } + } + // verifyRange runs verifyIndexes for a range of blocks, from and to are included. + verifyRange := func(db ethdb.Database, from, to uint64, exist bool) { + for number := from; number <= to; number += 1 { + verifyIndexes(db, number, exist) + } + } + verify := func(db ethdb.Database, expTail uint64) { + tail := rawdb.ReadTxIndexTail(db) + if tail == nil { + t.Fatal("Failed to write tx index tail") + } + if *tail != expTail { + t.Fatalf("Unexpected tx index tail, want %v, got %d", expTail, *tail) + } + if *tail != 0 { + verifyRange(db, 0, *tail-1, false) + } + verifyRange(db, *tail, 128, true) + } + + var cases = []struct { + limitA uint64 + tailA uint64 + limitB uint64 + tailB uint64 + limitC uint64 + tailC uint64 + }{ + { + // LimitA: 0 + // TailA: 0 + // + // all blocks are indexed + limitA: 0, + tailA: 0, + + // LimitB: 1 + // TailB: 128 + // + // block-128 is indexed + limitB: 1, + tailB: 128, + + // LimitB: 64 + // TailB: 65 + // + // block [65, 128] are indexed + limitC: 64, + tailC: 65, + }, + { + // LimitA: 64 + // TailA: 65 + // + // block [65, 128] are indexed + limitA: 64, + tailA: 65, + + // LimitB: 1 + // TailB: 128 + // + // block-128 is indexed + limitB: 1, + tailB: 128, + + // LimitB: 64 + // TailB: 65 + // + // block [65, 128] are indexed + limitC: 64, + tailC: 65, + }, + { + // LimitA: 127 + // TailA: 2 + // + // block [2, 128] are indexed + limitA: 127, + tailA: 2, + + // LimitB: 1 + // TailB: 128 + // + // block-128 is indexed + limitB: 1, + tailB: 128, + + // LimitB: 64 + // TailB: 65 + // + // block [65, 128] are indexed + limitC: 64, + tailC: 65, + }, + { + // LimitA: 128 + // TailA: 1 + // + // block [2, 128] are indexed + limitA: 128, + tailA: 1, + + // LimitB: 1 + // TailB: 128 + // + // block-128 is indexed + limitB: 1, + tailB: 128, + + // LimitB: 64 + // TailB: 65 + // + // block [65, 128] are indexed + limitC: 64, + tailC: 65, + }, + { + // LimitA: 129 + // TailA: 0 + // + // block [0, 128] are indexed + limitA: 129, + tailA: 0, + + // LimitB: 1 + // TailB: 128 + // + // block-128 is indexed + limitB: 1, + tailB: 128, + + // LimitB: 64 + // TailB: 65 + // + // block [65, 128] are indexed + limitC: 64, + tailC: 65, + }, + } + for _, c := range cases { + frdir := t.TempDir() + db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false) + rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0)) + + // Index the initial blocks from ancient store + chain, _ := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, &c.limitA) + chain.indexBlocks(nil, 128, make(chan struct{})) + verify(db, c.tailA) + + chain.SetTxLookupLimit(c.limitB) + chain.indexBlocks(rawdb.ReadTxIndexTail(db), 128, make(chan struct{})) + verify(db, c.tailB) + + chain.SetTxLookupLimit(c.limitC) + chain.indexBlocks(rawdb.ReadTxIndexTail(db), 128, make(chan struct{})) + verify(db, c.tailC) + + // Recover all indexes + chain.SetTxLookupLimit(0) + chain.indexBlocks(rawdb.ReadTxIndexTail(db), 128, make(chan struct{})) + verify(db, 0) + + db.Close() + os.RemoveAll(frdir) + } +} diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index aeba3690d228..881660aa8e8f 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -259,8 +259,7 @@ func WriteLastPivotNumber(db ethdb.KeyValueWriter, pivot uint64) { } // ReadTxIndexTail retrieves the number of oldest indexed block -// whose transaction indices has been indexed. If the corresponding entry -// is non-existent in database it means the indexing has been finished. +// whose transaction indices has been indexed. func ReadTxIndexTail(db ethdb.KeyValueReader) *uint64 { data, _ := db.Get(txIndexTailKey) if len(data) != 8 { From c2918c2f475e03521028e11c5e2cbe4fecb71350 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Thu, 29 Sep 2022 11:47:12 +0300 Subject: [PATCH 281/715] accounts/abi: return toGoType error immediately (#25565) --- accounts/abi/argument.go | 6 +++--- accounts/abi/unpack.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index ed204e0a81dd..2e48d539e0dc 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -187,6 +187,9 @@ func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { virtualArgs := 0 for index, arg := range nonIndexedArgs { marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) + if err != nil { + return nil, err + } if arg.Type.T == ArrayTy && !isDynamicType(arg.Type) { // If we have a static array, like [3]uint256, these are coded as // just like uint256,uint256,uint256. @@ -204,9 +207,6 @@ func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { // coded as just like uint256,bool,uint256 virtualArgs += getTypeSize(arg.Type)/32 - 1 } - if err != nil { - return nil, err - } retval = append(retval, marshalledValue) } return retval, nil diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index 0de99cd2b68c..b6ca0a038480 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -162,6 +162,9 @@ func forTupleUnpack(t Type, output []byte) (interface{}, error) { virtualArgs := 0 for index, elem := range t.TupleElems { marshalledValue, err := toGoType((index+virtualArgs)*32, *elem, output) + if err != nil { + return nil, err + } if elem.T == ArrayTy && !isDynamicType(*elem) { // If we have a static array, like [3]uint256, these are coded as // just like uint256,uint256,uint256. @@ -179,9 +182,6 @@ func forTupleUnpack(t Type, output []byte) (interface{}, error) { // coded as just like uint256,bool,uint256 virtualArgs += getTypeSize(*elem)/32 - 1 } - if err != nil { - return nil, err - } retval.Field(index).Set(reflect.ValueOf(marshalledValue)) } return retval.Interface(), nil From ff1f49245d641a7268ade38cf512bdc7b26f9b7c Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Thu, 29 Sep 2022 04:36:07 -0500 Subject: [PATCH 282/715] eth/tracers: remove revertReasonTracer, add revert reason to callTracer (#25508) * eth/tracers: add revertReason to callTracer * update callframe gen json * add revertal to calltrace test --- .../internal/tracetest/calltrace_test.go | 21 ++-- .../testdata/call_tracer/revert_reason.json | 3 +- eth/tracers/native/call.go | 39 ++++--- eth/tracers/native/gen_callframe_json.go | 36 +++--- eth/tracers/native/revertreason.go | 108 ------------------ 5 files changed, 58 insertions(+), 149 deletions(-) delete mode 100644 eth/tracers/native/revertreason.go diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index d2c50656d9a8..90f25e65bb7e 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -104,16 +104,17 @@ type callContext struct { // callTrace is the result of a callTracer run. type callTrace struct { - Type string `json:"type"` - From common.Address `json:"from"` - To common.Address `json:"to"` - Input hexutil.Bytes `json:"input"` - Output hexutil.Bytes `json:"output"` - Gas *hexutil.Uint64 `json:"gas,omitempty"` - GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"` - Value *hexutil.Big `json:"value,omitempty"` - Error string `json:"error,omitempty"` - Calls []callTrace `json:"calls,omitempty"` + Type string `json:"type"` + From common.Address `json:"from"` + To common.Address `json:"to"` + Input hexutil.Bytes `json:"input"` + Output hexutil.Bytes `json:"output"` + Gas *hexutil.Uint64 `json:"gas,omitempty"` + GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"` + Value *hexutil.Big `json:"value,omitempty"` + Error string `json:"error,omitempty"` + Revertal string `json:"revertReason,omitempty"` + Calls []callTrace `json:"calls,omitempty"` } // callTracerTest defines a single test to check the call tracer against. diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json index 094b0446779f..e0b2a9c6f181 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json @@ -59,6 +59,7 @@ "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", "type": "CALL", "value": "0x0", - "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e53656c662d64656c65676174696f6e20697320646973616c6c6f7765642e0000" + "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e53656c662d64656c65676174696f6e20697320646973616c6c6f7765642e0000", + "revertReason": "Self-delegation is disallowed." } } diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 54ae6dc8ab99..26fdd0008d2a 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -23,6 +23,7 @@ import ( "sync/atomic" "time" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/vm" @@ -36,15 +37,16 @@ func init() { } type callFrame struct { - Type vm.OpCode `json:"-"` - From common.Address `json:"from"` - Gas uint64 `json:"gas"` - GasUsed uint64 `json:"gasUsed"` - To common.Address `json:"to,omitempty" rlp:"optional"` - Input []byte `json:"input" rlp:"optional"` - Output []byte `json:"output,omitempty" rlp:"optional"` - Error string `json:"error,omitempty" rlp:"optional"` - Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Type vm.OpCode `json:"-"` + From common.Address `json:"from"` + Gas uint64 `json:"gas"` + GasUsed uint64 `json:"gasUsed"` + To common.Address `json:"to,omitempty" rlp:"optional"` + Input []byte `json:"input" rlp:"optional"` + Output []byte `json:"output,omitempty" rlp:"optional"` + Error string `json:"error,omitempty" rlp:"optional"` + Revertal string `json:"revertReason,omitempty"` + Calls []callFrame `json:"calls,omitempty" rlp:"optional"` // Placed at end on purpose. The RLP will be decoded to 0 instead of // nil if there are non-empty elements after in the struct. Value *big.Int `json:"value,omitempty" rlp:"optional"` @@ -109,13 +111,20 @@ func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { t.callstack[0].GasUsed = gasUsed output = common.CopyBytes(output) - if err != nil { - t.callstack[0].Error = err.Error() - if err.Error() == "execution reverted" && len(output) > 0 { - t.callstack[0].Output = output - } - } else { + if err == nil { t.callstack[0].Output = output + return + } + t.callstack[0].Error = err.Error() + if !errors.Is(err, vm.ErrExecutionReverted) || len(output) == 0 { + return + } + t.callstack[0].Output = output + if len(output) < 4 { + return + } + if unpacked, err := abi.UnpackRevert(output); err == nil { + t.callstack[0].Revertal = unpacked } } diff --git a/eth/tracers/native/gen_callframe_json.go b/eth/tracers/native/gen_callframe_json.go index baf0e32e6c68..bb7658a76ad3 100644 --- a/eth/tracers/native/gen_callframe_json.go +++ b/eth/tracers/native/gen_callframe_json.go @@ -18,12 +18,13 @@ func (c callFrame) MarshalJSON() ([]byte, error) { type callFrame0 struct { Type vm.OpCode `json:"-"` From common.Address `json:"from"` - To common.Address `json:"to,omitempty" rlp:"optional"` Gas hexutil.Uint64 `json:"gas"` GasUsed hexutil.Uint64 `json:"gasUsed"` + To common.Address `json:"to,omitempty" rlp:"optional"` Input hexutil.Bytes `json:"input" rlp:"optional"` Output hexutil.Bytes `json:"output,omitempty" rlp:"optional"` Error string `json:"error,omitempty" rlp:"optional"` + Revertal string `json:"revertReason,omitempty"` Calls []callFrame `json:"calls,omitempty" rlp:"optional"` Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` TypeString string `json:"type"` @@ -31,12 +32,13 @@ func (c callFrame) MarshalJSON() ([]byte, error) { var enc callFrame0 enc.Type = c.Type enc.From = c.From - enc.To = c.To enc.Gas = hexutil.Uint64(c.Gas) enc.GasUsed = hexutil.Uint64(c.GasUsed) + enc.To = c.To enc.Input = c.Input enc.Output = c.Output enc.Error = c.Error + enc.Revertal = c.Revertal enc.Calls = c.Calls enc.Value = (*hexutil.Big)(c.Value) enc.TypeString = c.TypeString() @@ -46,16 +48,17 @@ func (c callFrame) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (c *callFrame) UnmarshalJSON(input []byte) error { type callFrame0 struct { - Type *vm.OpCode `json:"-"` - From *common.Address `json:"from"` - To *common.Address `json:"to,omitempty" rlp:"optional"` - Gas *hexutil.Uint64 `json:"gas"` - GasUsed *hexutil.Uint64 `json:"gasUsed"` - Input *hexutil.Bytes `json:"input" rlp:"optional"` - Output *hexutil.Bytes `json:"output,omitempty" rlp:"optional"` - Error *string `json:"error,omitempty" rlp:"optional"` - Calls []callFrame `json:"calls,omitempty" rlp:"optional"` - Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` + Type *vm.OpCode `json:"-"` + From *common.Address `json:"from"` + Gas *hexutil.Uint64 `json:"gas"` + GasUsed *hexutil.Uint64 `json:"gasUsed"` + To *common.Address `json:"to,omitempty" rlp:"optional"` + Input *hexutil.Bytes `json:"input" rlp:"optional"` + Output *hexutil.Bytes `json:"output,omitempty" rlp:"optional"` + Error *string `json:"error,omitempty" rlp:"optional"` + Revertal *string `json:"revertReason,omitempty"` + Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` } var dec callFrame0 if err := json.Unmarshal(input, &dec); err != nil { @@ -67,15 +70,15 @@ func (c *callFrame) UnmarshalJSON(input []byte) error { if dec.From != nil { c.From = *dec.From } - if dec.To != nil { - c.To = *dec.To - } if dec.Gas != nil { c.Gas = uint64(*dec.Gas) } if dec.GasUsed != nil { c.GasUsed = uint64(*dec.GasUsed) } + if dec.To != nil { + c.To = *dec.To + } if dec.Input != nil { c.Input = *dec.Input } @@ -85,6 +88,9 @@ func (c *callFrame) UnmarshalJSON(input []byte) error { if dec.Error != nil { c.Error = *dec.Error } + if dec.Revertal != nil { + c.Revertal = *dec.Revertal + } if dec.Calls != nil { c.Calls = dec.Calls } diff --git a/eth/tracers/native/revertreason.go b/eth/tracers/native/revertreason.go deleted file mode 100644 index d09b86100901..000000000000 --- a/eth/tracers/native/revertreason.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2022 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 native - -import ( - "bytes" - "encoding/json" - "math/big" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers" -) - -func init() { - register("revertReasonTracer", newRevertReasonTracer) -} - -var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4] - -// revertReasonTracer is a go implementation of the Tracer interface which -// track the error message or revert reason return by the contract. -type revertReasonTracer struct { - env *vm.EVM - revertReason string // The revert reason return from the tx, if tx success, empty string return - interrupt uint32 // Atomic flag to signal execution interruption - reason error // Textual reason for the interruption -} - -// newRevertReasonTracer returns a new revert reason tracer. -func newRevertReasonTracer(_ *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { - return &revertReasonTracer{}, nil -} - -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *revertReasonTracer) CaptureStart(env *vm.EVM, _ common.Address, _ common.Address, _ bool, _ []byte, _ uint64, _ *big.Int) { - t.env = env -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *revertReasonTracer) CaptureEnd(output []byte, _ uint64, _ time.Duration, err error) { - if err != nil { - if err == vm.ErrExecutionReverted && len(output) > 4 && bytes.Equal(output[:4], revertSelector) { - errMsg, _ := abi.UnpackRevert(output) - t.revertReason = err.Error() + ": " + errMsg - } else { - t.revertReason = err.Error() - } - } -} - -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *revertReasonTracer) CaptureState(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ []byte, _ int, _ error) { -} - -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *revertReasonTracer) CaptureFault(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ int, _ error) { -} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *revertReasonTracer) CaptureEnter(_ vm.OpCode, _ common.Address, _ common.Address, _ []byte, _ uint64, _ *big.Int) { - // Skip if tracing was interrupted - if atomic.LoadUint32(&t.interrupt) > 0 { - t.env.Cancel() - return - } -} - -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (t *revertReasonTracer) CaptureExit(_ []byte, _ uint64, _ error) {} - -func (t *revertReasonTracer) CaptureTxStart(_ uint64) {} - -func (t *revertReasonTracer) CaptureTxEnd(_ uint64) {} - -// GetResult returns an error message json object. -func (t *revertReasonTracer) GetResult() (json.RawMessage, error) { - res, err := json.Marshal(t.revertReason) - if err != nil { - return nil, err - } - return res, t.reason -} - -// Stop terminates execution of the tracer at the first opportune moment. -func (t *revertReasonTracer) Stop(err error) { - t.reason = err - atomic.StoreUint32(&t.interrupt, 1) -} From f651d6d56b4e7cc706f43074baf598813eb28644 Mon Sep 17 00:00:00 2001 From: Mikhail Vazhnov Date: Thu, 29 Sep 2022 13:44:22 +0400 Subject: [PATCH 283/715] accounts/abi/bind: parse ABI only once on bind (#25574) * accounts/abi/bind: parse ABI once on bind * accounts/abi/bind: suppress 'imported and not used' error for abi package --- accounts/abi/bind/template.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/accounts/abi/bind/template.go b/accounts/abi/bind/template.go index c9b001133dd5..855c8ead87ca 100644 --- a/accounts/abi/bind/template.go +++ b/accounts/abi/bind/template.go @@ -110,6 +110,7 @@ var ( _ = common.Big1 _ = types.BloomLookup _ = event.NewSubscription + _ = abi.ConvertType ) {{$structs := .Structs}} @@ -268,11 +269,11 @@ var ( // bind{{.Type}} binds a generic wrapper to an already deployed contract. func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader({{.Type}}ABI)) + parsed, err := {{.Type}}MetaData.GetAbi() if err != nil { return nil, err } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil } // Call invokes the (constant) contract method with params as input values and From 07e0704ca9d430195a6f519b7e5cee4bfea77c19 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 29 Sep 2022 20:16:36 +0200 Subject: [PATCH 284/715] internal/flags: fix issue with stringslice migration (#25830) This fixes a cornercase bug where the flag migration would mess up the value of StringSlice flags. --- internal/flags/helpers.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index 46409f4dfdb0..3be0a5807290 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -94,10 +94,34 @@ func MigrateGlobalFlags(ctx *cli.Context) { } func doMigrateFlags(ctx *cli.Context) { + // Figure out if there are any aliases of commands. If there are, we want + // to ignore them when iterating over the flags. + var aliases = make(map[string]bool) + for _, fl := range ctx.Command.Flags { + for _, alias := range fl.Names()[1:] { + aliases[alias] = true + } + } for _, name := range ctx.FlagNames() { for _, parent := range ctx.Lineage()[1:] { if parent.IsSet(name) { - ctx.Set(name, parent.String(name)) + // When iterating across the lineage, we will be served both + // the 'canon' and alias formats of all commmands. In most cases, + // it's fine to set it in the ctx multiple times (one for each + // name), however, the Slice-flags are not fine. + // The slice-flags accumulate, so if we set it once as + // "foo" and once as alias "F", then both will be present in the slice. + if _, isAlias := aliases[name]; isAlias { + continue + } + // If it is a string-slice, we need to set it as + // "alfa, beta, gamma" instead of "[alfa beta gamma]", in order + // for the backing StringSlice to parse it properly. + if result := parent.StringSlice(name); len(result) > 0 { + ctx.Set(name, strings.Join(result, ",")) + } else { + ctx.Set(name, parent.String(name)) + } break } } From ea26fc8a6c44ebb48223f991048f41b2ec0a6414 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 30 Sep 2022 13:50:25 +0200 Subject: [PATCH 285/715] cmd/geth, cmd/utils: geth attach with custom headers (#25829) This PR makes it possible to set custom headers, in particular for two scenarios: - geth attach - geth commands which can use --remotedb, e..g geth db inspect The ability to use custom headers is typically useful for connecting to cloud-apis, e.g. providing an infura- or alchemy key, or for that matter access-keys for environments behind cloudflare. Co-authored-by: Felix Lange --- cmd/geth/attach_test.go | 83 ++++++++++++++++++++++++++++++++++++++ cmd/geth/consolecmd.go | 21 +--------- cmd/utils/flags.go | 43 +++++++++++++++++++- ethdb/remotedb/remotedb.go | 23 +---------- 4 files changed, 128 insertions(+), 42 deletions(-) create mode 100644 cmd/geth/attach_test.go diff --git a/cmd/geth/attach_test.go b/cmd/geth/attach_test.go new file mode 100644 index 000000000000..7c5f951750fb --- /dev/null +++ b/cmd/geth/attach_test.go @@ -0,0 +1,83 @@ +// Copyright 2022 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 main + +import ( + "fmt" + "net" + "net/http" + "sync/atomic" + "testing" +) + +type testHandler struct { + body func(http.ResponseWriter, *http.Request) +} + +func (t *testHandler) ServeHTTP(out http.ResponseWriter, in *http.Request) { + t.body(out, in) +} + +// TestAttachWithHeaders tests that 'geth attach' with custom headers works, i.e +// that custom headers are forwarded to the target. +func TestAttachWithHeaders(t *testing.T) { + t.Parallel() + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatal(err) + } + port := ln.Addr().(*net.TCPAddr).Port + testReceiveHeaders(t, ln, "attach", "-H", "first: one", "-H", "second: two", fmt.Sprintf("http://localhost:%d", port)) + // This way to do it fails due to flag ordering: + // + // testReceiveHeaders(t, ln, "-H", "first: one", "-H", "second: two", "attach", fmt.Sprintf("http://localhost:%d", port)) + // This is fixed in a follow-up PR. +} + +// TestAttachWithHeaders tests that 'geth db --remotedb' with custom headers works, i.e +// that custom headers are forwarded to the target. +func TestRemoteDbWithHeaders(t *testing.T) { + t.Parallel() + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatal(err) + } + port := ln.Addr().(*net.TCPAddr).Port + testReceiveHeaders(t, ln, "db", "metadata", "--remotedb", fmt.Sprintf("http://localhost:%d", port), "-H", "first: one", "-H", "second: two") +} + +func testReceiveHeaders(t *testing.T, ln net.Listener, gethArgs ...string) { + var ok uint32 + server := &http.Server{ + Addr: "localhost:0", + Handler: &testHandler{func(w http.ResponseWriter, r *http.Request) { + // We expect two headers + if have, want := r.Header.Get("first"), "one"; have != want { + t.Fatalf("missing header, have %v want %v", have, want) + } + if have, want := r.Header.Get("second"), "two"; have != want { + t.Fatalf("missing header, have %v want %v", have, want) + } + atomic.StoreUint32(&ok, 1) + }}} + go server.Serve(ln) + defer server.Close() + runGeth(t, gethArgs...).WaitExit() + if atomic.LoadUint32(&ok) != 1 { + t.Fatal("Test fail, expected invocation to succeed") + } +} diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index 87bbe24b977a..83c6b66a8a60 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -23,8 +23,6 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/internal/flags" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/rpc" "github.com/urfave/cli/v2" ) @@ -47,7 +45,7 @@ See https://geth.ethereum.org/docs/interface/javascript-console.`, Name: "attach", Usage: "Start an interactive JavaScript environment (connect to node)", ArgsUsage: "[endpoint]", - Flags: flags.Merge([]cli.Flag{utils.DataDirFlag}, consoleFlags), + Flags: flags.Merge([]cli.Flag{utils.DataDirFlag, utils.HttpHeaderFlag}, consoleFlags), Description: ` The Geth console is an interactive shell for the JavaScript runtime environment which exposes a node admin interface as well as the Ðapp JavaScript API. @@ -118,14 +116,13 @@ func remoteConsole(ctx *cli.Context) error { if ctx.Args().Len() > 1 { utils.Fatalf("invalid command-line: too many arguments") } - endpoint := ctx.Args().First() if endpoint == "" { cfg := defaultNodeConfig() utils.SetDataDir(ctx, &cfg) endpoint = cfg.IPCEndpoint() } - client, err := dialRPC(endpoint) + client, err := utils.DialRPCWithHeaders(endpoint, ctx.StringSlice(utils.HttpHeaderFlag.Name)) if err != nil { utils.Fatalf("Unable to attach to remote geth: %v", err) } @@ -164,17 +161,3 @@ func ephemeralConsole(ctx *cli.Context) error { geth --exec "%s" console`, b.String()) return nil } - -// dialRPC returns a RPC client which connects to the given endpoint. -// The check for empty endpoint implements the defaulting logic -// for "geth attach" with no argument. -func dialRPC(endpoint string) (*rpc.Client, error) { - if endpoint == "" { - endpoint = node.DefaultIPCEndpoint(clientIdentifier) - } else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { - // Backwards compatibility with geth < 1.5 which required - // these prefixes. - endpoint = endpoint[4:] - } - return rpc.Dial(endpoint) -} diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 745b9f088eb3..ca6ded475668 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -18,10 +18,13 @@ package utils import ( + "context" "crypto/ecdsa" + "errors" "fmt" "math" "math/big" + "net/http" "os" "path/filepath" godebug "runtime/debug" @@ -976,6 +979,13 @@ var ( Value: metrics.DefaultConfig.InfluxDBOrganization, Category: flags.MetricsCategory, } + + HttpHeaderFlag = &cli.StringSliceFlag{ + Name: "header", + Aliases: []string{"H"}, + Usage: "Pass custom headers to the RPC server wheng using --" + RemoteDBFlag.Name + " or the geth attach console.", + Category: flags.NetworkingCategory, + } ) var ( @@ -995,6 +1005,7 @@ var ( DataDirFlag, AncientFlag, RemoteDBFlag, + HttpHeaderFlag, } ) @@ -2125,8 +2136,12 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. ) switch { case ctx.IsSet(RemoteDBFlag.Name): - log.Info("Using remote db", "url", ctx.String(RemoteDBFlag.Name)) - chainDb, err = remotedb.New(ctx.String(RemoteDBFlag.Name)) + log.Info("Using remote db", "url", ctx.String(RemoteDBFlag.Name), "headers", len(ctx.StringSlice(HttpHeaderFlag.Name))) + client, err := DialRPCWithHeaders(ctx.String(RemoteDBFlag.Name), ctx.StringSlice(HttpHeaderFlag.Name)) + if err != nil { + break + } + chainDb = remotedb.New(client) case ctx.String(SyncModeFlag.Name) == "light": chainDb, err = stack.OpenDatabase("lightchaindata", cache, handles, "", readonly) default: @@ -2148,6 +2163,30 @@ func IsNetworkPreset(ctx *cli.Context) bool { return false } +func DialRPCWithHeaders(endpoint string, headers []string) (*rpc.Client, error) { + if endpoint == "" { + return nil, errors.New("endpoint must be specified") + } + if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { + // Backwards compatibility with geth < 1.5 which required + // these prefixes. + endpoint = endpoint[4:] + } + var opts []rpc.ClientOption + if len(headers) > 0 { + var customHeaders = make(http.Header) + for _, h := range headers { + kv := strings.Split(h, ":") + if len(kv) != 2 { + return nil, fmt.Errorf("invalid http header directive: %q", h) + } + customHeaders.Add(kv[0], kv[1]) + } + opts = append(opts, rpc.WithHeaders(customHeaders)) + } + return rpc.DialOptions(context.Background(), endpoint, opts...) +} + func MakeGenesis(ctx *cli.Context) *core.Genesis { var genesis *core.Genesis switch { diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index 59a570bb5e96..9ce657d78026 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -22,9 +22,6 @@ package remotedb import ( - "errors" - "strings" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rpc" @@ -150,24 +147,8 @@ func (db *Database) Close() error { return nil } -func dialRPC(endpoint string) (*rpc.Client, error) { - if endpoint == "" { - return nil, errors.New("endpoint must be specified") - } - if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { - // Backwards compatibility with geth < 1.5 which required - // these prefixes. - endpoint = endpoint[4:] - } - return rpc.Dial(endpoint) -} - -func New(endpoint string) (ethdb.Database, error) { - client, err := dialRPC(endpoint) - if err != nil { - return nil, err - } +func New(client *rpc.Client) ethdb.Database { return &Database{ remote: client, - }, nil + } } From a724163e59756ef6f8cd92adec039bb046a8a82f Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Mon, 3 Oct 2022 18:56:21 +0800 Subject: [PATCH 286/715] core/types: add a testcase to TestLegacyReceiptDecoding (#25909) add a testcase to TestLegacyReceiptDecoding --- core/types/receipt_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index bba18d2a7bf3..6f0953bdec7d 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -96,6 +96,10 @@ func TestLegacyReceiptDecoding(t *testing.T) { name string encode func(*Receipt) ([]byte, error) }{ + { + "ReceiptForStorage", + encodeAsReceiptForStorage, + }, { "StoredReceiptRLP", encodeAsStoredReceiptRLP, @@ -170,6 +174,10 @@ func TestLegacyReceiptDecoding(t *testing.T) { } } +func encodeAsReceiptForStorage(want *Receipt) ([]byte, error) { + return rlp.EncodeToBytes((*ReceiptForStorage)(want)) +} + func encodeAsStoredReceiptRLP(want *Receipt) ([]byte, error) { stored := &storedReceiptRLP{ PostStateOrStatus: want.statusEncoding(), From f61b50b1e85ebf4a81f7ba52131858b8c6476bd3 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 3 Oct 2022 13:37:17 +0200 Subject: [PATCH 287/715] eth/protocols/snap: serve snap requests when possible (#25644) This PR makes it so that the snap server responds to trie heal requests when possible, even if the snapshot does not exist. The idea being that it might prolong the lifetime of a state root, so we don't have to pivot quite as often. --- cmd/devp2p/internal/ethtest/snap.go | 36 ++++++++++++++++++++++++++--- eth/protocols/snap/handler.go | 31 +++++++++++++++---------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/snap.go b/cmd/devp2p/internal/ethtest/snap.go index 032afeafcdad..7ecbcef6f587 100644 --- a/cmd/devp2p/internal/ethtest/snap.go +++ b/cmd/devp2p/internal/ethtest/snap.go @@ -406,8 +406,10 @@ func (s *Suite) TestSnapTrieNodes(t *utesting.T) { {[]byte{0}}, {[]byte{1}, []byte{0}}, }, - nBytes: 5000, - expHashes: []common.Hash{}, + nBytes: 5000, + expHashes: []common.Hash{ + common.HexToHash("0x1ee1bb2fbac4d46eab331f3e8551e18a0805d084ed54647883aa552809ca968d"), + }, }, { // The leaf is only a couple of levels down, so the continued trie traversal causes lookup failures. @@ -437,7 +439,35 @@ func (s *Suite) TestSnapTrieNodes(t *utesting.T) { common.HexToHash("0xbcefee69b37cca1f5bf3a48aebe08b35f2ea1864fa958bb0723d909a0e0d28d8"), }, }, - } { + { + /* + A test against this account, requesting trie nodes for the storage trie + { + "balance": "0", + "nonce": 1, + "root": "0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790", + "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "storage": { + "0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": "02", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "01", + "0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": "03" + }, + "key": "0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844" + } + */ + root: s.chain.RootAt(999), + paths: []snap.TrieNodePathSet{ + { + common.FromHex("0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844"), + []byte{0}, + }, + }, + nBytes: 5000, + expHashes: []common.Hash{ + common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790"), + }, + }, + }[7:] { tc := tc if err := s.snapGetTrieNodes(t, &tc); err != nil { t.Errorf("test %d \n #hashes %x\n root: %#x\n bytes: %d\nfailed: %v", i, len(tc.expHashes), tc.root, tc.nBytes, err) diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index aa245ab7e62d..e001a3883e37 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -493,14 +493,8 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s // We don't have the requested state available, bail out return nil, nil } + // The 'snap' might be nil, in which case we cannot serve storage slots. snap := chain.Snapshots().Snapshot(req.Root) - if snap == nil { - // We don't have the requested state snapshotted yet, bail out. - // In reality we could still serve using the account and storage - // tries only, but let's protect the node a bit while it's doing - // snapshot generation. - return nil, nil - } // Retrieve trie nodes until the packet size limit is reached var ( nodes [][]byte @@ -524,13 +518,26 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s bytes += uint64(len(blob)) default: + var stRoot common.Hash // Storage slots requested, open the storage trie and retrieve from there - account, err := snap.Account(common.BytesToHash(pathset[0])) - loads++ // always account database reads, even for failures - if err != nil || account == nil { - break + if snap == nil { + // We don't have the requested state snapshotted yet (or it is stale), + // but can look up the account via the trie instead. + account, err := accTrie.TryGetAccountWithPreHashedKey(pathset[0]) + loads += 8 // We don't know the exact cost of lookup, this is an estimate + if err != nil || account == nil { + break + } + stRoot = account.Root + } else { + account, err := snap.Account(common.BytesToHash(pathset[0])) + loads++ // always account database reads, even for failures + if err != nil || account == nil { + break + } + stRoot = common.BytesToHash(account.Root) } - id := trie.StorageTrieID(req.Root, common.BytesToHash(pathset[0]), common.BytesToHash(account.Root)) + id := trie.StorageTrieID(req.Root, common.BytesToHash(pathset[0]), stRoot) stTrie, err := trie.NewStateTrie(id, triedb) loads++ // always account database reads, even for failures if err != nil { From 1913b50111bd30dda5b43171c1f880f0127d40e1 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 3 Oct 2022 20:10:00 +0800 Subject: [PATCH 288/715] eth, miner: add timeout for building sealing block (#25407) * eth, miner: add timeout for building sealing block * eth, cmd, miner: add newpayloadtimeout flag * eth, miner, cmd: address comments * eth, miner: minor fixes Co-authored-by: Martin Holst Swende --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 9 +++ eth/catalyst/api_test.go | 7 +-- eth/ethconfig/config.go | 16 ++---- miner/miner.go | 10 ++++ miner/worker.go | 116 +++++++++++++++++++++++++++------------ miner/worker_test.go | 8 +-- 7 files changed, 112 insertions(+), 55 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 5d54ee41ca2f..e6d1128ba9b5 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -127,6 +127,7 @@ var ( utils.MinerExtraDataFlag, utils.MinerRecommitIntervalFlag, utils.MinerNoVerifyFlag, + utils.MinerNewPayloadTimeout, utils.NATFlag, utils.NoDiscoverFlag, utils.DiscoveryV5Flag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ca6ded475668..5ce244080ff2 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -563,6 +563,12 @@ var ( Usage: "Disable remote sealing verification", Category: flags.MinerCategory, } + MinerNewPayloadTimeout = &cli.DurationFlag{ + Name: "miner.newpayload-timeout", + Usage: "Specify the maximum time allowance for creating a new payload", + Value: ethconfig.Defaults.Miner.NewPayloadTimeout, + Category: flags.MinerCategory, + } // Account settings UnlockedAccountFlag = &cli.StringFlag{ @@ -1658,6 +1664,9 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) { if ctx.IsSet(MinerNoVerifyFlag.Name) { cfg.Noverify = ctx.Bool(MinerNoVerifyFlag.Name) } + if ctx.IsSet(MinerNewPayloadTimeout.Name) { + cfg.NewPayloadTimeout = ctx.Duration(MinerNewPayloadTimeout.Name) + } } func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) { diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 480a30b52dc5..c98a48ea4769 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -476,10 +476,9 @@ func TestExchangeTransitionConfig(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(10) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() - var ( - api = NewConsensusAPI(ethservice) - ) + // invalid ttd + api := NewConsensusAPI(ethservice) config := beacon.TransitionConfigurationV1{ TerminalTotalDifficulty: (*hexutil.Big)(big.NewInt(0)), TerminalBlockHash: common.Hash{}, @@ -812,10 +811,8 @@ func TestInvalidBloom(t *testing.T) { func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(100) - fmt.Println(genesis.Config.TerminalTotalDifficulty) genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty()) - fmt.Println(genesis.Config.TerminalTotalDifficulty) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index a897294175ea..b5a7837ffda3 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -84,16 +84,12 @@ var Defaults = Config{ TrieTimeout: 60 * time.Minute, SnapshotCache: 102, FilterLogCacheSize: 32, - Miner: miner.Config{ - GasCeil: 30000000, - GasPrice: big.NewInt(params.GWei), - Recommit: 3 * time.Second, - }, - TxPool: core.DefaultTxPoolConfig, - RPCGasCap: 50000000, - RPCEVMTimeout: 5 * time.Second, - GPO: FullNodeGPO, - RPCTxFeeCap: 1, // 1 ether + Miner: miner.DefaultConfig, + TxPool: core.DefaultTxPoolConfig, + RPCGasCap: 50000000, + RPCEVMTimeout: 5 * time.Second, + GPO: FullNodeGPO, + RPCTxFeeCap: 1, // 1 ether } func init() { diff --git a/miner/miner.go b/miner/miner.go index 1e9607a76ad9..0f644b200bcf 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -53,6 +53,16 @@ type Config struct { GasPrice *big.Int // Minimum gas price for mining a transaction Recommit time.Duration // The time interval for miner to re-create mining work. Noverify bool // Disable remote mining solution verification(only useful in ethash). + + NewPayloadTimeout time.Duration // The maximum time allowance for creating a new payload +} + +// DefaultConfig contains default settings for miner. +var DefaultConfig = Config{ + GasCeil: 30000000, + GasPrice: big.NewInt(params.GWei), + Recommit: 3 * time.Second, + NewPayloadTimeout: 2 * time.Second, } // Miner creates blocks and searches for proof-of-work values. diff --git a/miner/worker.go b/miner/worker.go index 93fb6288bb45..bf9434eefe70 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -80,6 +80,7 @@ const ( var ( errBlockInterruptedByNewHead = errors.New("new head arrived while building block") errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block") + errBlockInterruptedByTimeout = errors.New("timeout while building block") ) // environment is the worker's current environment and holds all @@ -158,6 +159,7 @@ const ( commitInterruptNone int32 = iota commitInterruptNewHead commitInterruptResubmit + commitInterruptTimeout ) // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. @@ -241,6 +243,13 @@ type worker struct { // non-stop and no real transaction will be included. noempty uint32 + // newpayloadTimeout is the maximum timeout allowance for creating payload. + // The default value is 2 seconds but node operator can set it to arbitrary + // large value. A large timeout allowance may cause Geth to fail creating + // a non-empty payload within the specified time and eventually miss the slot + // in case there are some computation expensive transactions in txpool. + newpayloadTimeout time.Duration + // External functions isLocalBlock func(header *types.Header) bool // Function used to determine whether the specified block is mined by local miner. @@ -288,6 +297,16 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus log.Warn("Sanitizing miner recommit interval", "provided", recommit, "updated", minRecommitInterval) recommit = minRecommitInterval } + // Sanitize the timeout config for creating payload. + newpayloadTimeout := worker.config.NewPayloadTimeout + if newpayloadTimeout == 0 { + log.Warn("Sanitizing new payload timeout to default", "provided", newpayloadTimeout, "updated", DefaultConfig.NewPayloadTimeout) + newpayloadTimeout = DefaultConfig.NewPayloadTimeout + } + if newpayloadTimeout < time.Millisecond*100 { + log.Warn("Low payload timeout may cause high amount of non-full blocks", "provided", newpayloadTimeout, "default", DefaultConfig.NewPayloadTimeout) + } + worker.newpayloadTimeout = newpayloadTimeout worker.wg.Add(4) go worker.mainLoop() @@ -844,42 +863,26 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP var coalescedLogs []*types.Log for { - // In the following three cases, we will interrupt the execution of the transaction. - // (1) new head block event arrival, the interrupt signal is 1 - // (2) worker start or restart, the interrupt signal is 1 - // (3) worker recreate the sealing block with any newly arrived transactions, the interrupt signal is 2. - // For the first two cases, the semi-finished work will be discarded. - // For the third case, the semi-finished work will be submitted to the consensus engine. - if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { - // Notify resubmit loop to increase resubmitting interval due to too frequent commits. - if atomic.LoadInt32(interrupt) == commitInterruptResubmit { - ratio := float64(gasLimit-env.gasPool.Gas()) / float64(gasLimit) - if ratio < 0.1 { - ratio = 0.1 - } - w.resubmitAdjustCh <- &intervalAdjust{ - ratio: ratio, - inc: true, - } - return errBlockInterruptedByRecommit + // Check interruption signal and abort building if it's fired. + if interrupt != nil { + if signal := atomic.LoadInt32(interrupt); signal != commitInterruptNone { + return signalToErr(signal) } - return errBlockInterruptedByNewHead } - // If we don't have enough gas for any further transactions then we're done + // If we don't have enough gas for any further transactions then we're done. if env.gasPool.Gas() < params.TxGas { log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas) break } - // Retrieve the next transaction and abort if all done + // Retrieve the next transaction and abort if all done. tx := txs.Peek() if tx == nil { break } // Error may be ignored here. The error has already been checked // during transaction acceptance is the transaction pool. - // - // We use the eip155 signer regardless of the current hf. from, _ := types.Sender(env.signer, tx) + // Check whether the tx is replay protected. If we're not in the EIP155 hf // phase, start ignoring the sender until we do. if tx.Protected() && !w.chainConfig.IsEIP155(env.header.Number) { @@ -926,7 +929,6 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP txs.Shift() } } - if !w.isRunning() && len(coalescedLogs) > 0 { // We don't push the pendingLogsEvent while we are sealing. The reason is that // when we are sealing, the worker will regenerate a sealing block every 3 seconds. @@ -942,11 +944,6 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP } w.pendingLogsFeed.Send(cpy) } - // Notify resubmit loop to decrease resubmitting interval if current interval is larger - // than the user-specified one. - if interrupt != nil { - w.resubmitAdjustCh <- &intervalAdjust{inc: false} - } return nil } @@ -986,15 +983,15 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { } timestamp = parent.Time() + 1 } - // Construct the sealing block header, set the extra field if it's allowed - num := parent.Number() + // Construct the sealing block header. header := &types.Header{ ParentHash: parent.Hash(), - Number: num.Add(num, common.Big1), + Number: new(big.Int).Add(parent.Number(), common.Big1), GasLimit: core.CalcGasLimit(parent.GasLimit(), w.config.GasCeil), Time: timestamp, Coinbase: genParams.coinbase, } + // Set the extra field if it's allowed. if !genParams.noExtra && len(w.extra) != 0 { header.Extra = w.extra } @@ -1082,7 +1079,16 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, error) { defer work.discard() if !params.noTxs { - w.fillTransactions(nil, work) + interrupt := new(int32) + timer := time.AfterFunc(w.newpayloadTimeout, func() { + atomic.StoreInt32(interrupt, commitInterruptTimeout) + }) + defer timer.Stop() + + err := w.fillTransactions(interrupt, work) + if errors.Is(err, errBlockInterruptedByTimeout) { + log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.newpayloadTimeout)) + } } return w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts) } @@ -1113,13 +1119,36 @@ func (w *worker) commitWork(interrupt *int32, noempty bool, timestamp int64) { if !noempty && atomic.LoadUint32(&w.noempty) == 0 { w.commit(work.copy(), nil, false, start) } - - // Fill pending transactions from the txpool + // Fill pending transactions from the txpool into the block. err = w.fillTransactions(interrupt, work) - if errors.Is(err, errBlockInterruptedByNewHead) { + switch { + case err == nil: + // The entire block is filled, decrease resubmit interval in case + // of current interval is larger than the user-specified one. + w.resubmitAdjustCh <- &intervalAdjust{inc: false} + + case errors.Is(err, errBlockInterruptedByRecommit): + // Notify resubmit loop to increase resubmitting interval if the + // interruption is due to frequent commits. + gaslimit := work.header.GasLimit + ratio := float64(gaslimit-work.gasPool.Gas()) / float64(gaslimit) + if ratio < 0.1 { + ratio = 0.1 + } + w.resubmitAdjustCh <- &intervalAdjust{ + ratio: ratio, + inc: true, + } + + case errors.Is(err, errBlockInterruptedByNewHead): + // If the block building is interrupted by newhead event, discard it + // totally. Committing the interrupted block introduces unnecessary + // delay, and possibly causes miner to mine on the previous head, + // which could result in higher uncle rate. work.discard() return } + // Submit the generated block for consensus sealing. w.commit(work.copy(), w.fullTaskHook, true, start) // Swap out the old work with the new one, terminating any leftover @@ -1231,3 +1260,18 @@ func totalFees(block *types.Block, receipts []*types.Receipt) *big.Float { } return new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether))) } + +// signalToErr converts the interruption signal to a concrete error type for return. +// The given signal must be a valid interruption signal. +func signalToErr(signal int32) error { + switch signal { + case commitInterruptNewHead: + return errBlockInterruptedByNewHead + case commitInterruptResubmit: + return errBlockInterruptedByRecommit + case commitInterruptTimeout: + return errBlockInterruptedByTimeout + default: + panic(fmt.Errorf("undefined signal %d", signal)) + } +} diff --git a/miner/worker_test.go b/miner/worker_test.go index 2f1939f75981..0cba7ff9955f 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -523,21 +523,21 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co } func TestGetSealingWorkEthash(t *testing.T) { - testGetSealingWork(t, ethashChainConfig, ethash.NewFaker(), false) + testGetSealingWork(t, ethashChainConfig, ethash.NewFaker()) } func TestGetSealingWorkClique(t *testing.T) { - testGetSealingWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase()), false) + testGetSealingWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) } func TestGetSealingWorkPostMerge(t *testing.T) { local := new(params.ChainConfig) *local = *ethashChainConfig local.TerminalTotalDifficulty = big.NewInt(0) - testGetSealingWork(t, local, ethash.NewFaker(), true) + testGetSealingWork(t, local, ethash.NewFaker()) } -func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, postMerge bool) { +func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { defer engine.Close() w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) From ee301c750bd179b9f9a8b219a5fd9a0472ec28f1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 4 Oct 2022 08:44:05 +0200 Subject: [PATCH 289/715] all: fix docstrings --- cmd/devp2p/internal/ethtest/snap.go | 2 +- cmd/devp2p/internal/v4test/discv4tests.go | 12 +++++----- cmd/devp2p/internal/v5test/discv5tests.go | 14 +++++------ core/rawdb/schema.go | 4 +++- core/state/snapshot/snapshot.go | 2 +- core/state/state_object.go | 4 ++-- core/state_transition.go | 2 ++ core/tx_pool.go | 2 +- core/types/transaction_signing.go | 4 +++- core/vm/interface.go | 8 +++---- eth/downloader/resultstore.go | 2 +- eth/filters/filter_system.go | 2 +- eth/protocols/snap/peer.go | 2 +- eth/tracers/js/goja.go | 2 +- les/api.go | 2 +- les/downloader/downloader.go | 2 +- les/downloader/resultstore.go | 2 +- les/fetcher/block_fetcher.go | 2 +- les/flowcontrol/manager.go | 2 +- les/odr_requests.go | 18 +++++++------- les/protocol.go | 2 +- les/utils/expiredvalue.go | 20 ++++++++-------- les/vflux/client/serverpool.go | 6 ++--- les/vflux/client/valuetracker.go | 2 +- les/vflux/requests.go | 2 +- light/lightchain.go | 2 +- light/txpool.go | 2 +- p2p/discover/v4wire/v4wire.go | 5 ++-- p2p/discover/v5_udp.go | 2 +- p2p/discover/v5wire/encoding.go | 1 + p2p/discover/v5wire/msg.go | 24 +++++++++---------- p2p/enode/idscheme.go | 5 ++-- p2p/enode/node.go | 2 +- p2p/enode/nodedb.go | 2 +- p2p/enr/entries.go | 4 ++-- p2p/nat/nat.go | 6 ++--- p2p/nodestate/nodestate.go | 2 +- p2p/simulations/http.go | 2 +- p2p/simulations/mocker.go | 4 ++-- p2p/simulations/network.go | 4 ++-- rlp/encbuffer.go | 2 +- rlp/encode.go | 5 +++- rlp/internal/rlpstruct/rlpstruct.go | 2 +- tests/fuzzers/difficulty/difficulty-fuzz.go | 2 +- tests/fuzzers/rangeproof/rangeproof-fuzzer.go | 1 + tests/fuzzers/stacktrie/trie_fuzzer.go | 1 + tests/fuzzers/trie/trie-fuzzer.go | 1 + tests/init.go | 2 +- 48 files changed, 110 insertions(+), 95 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/snap.go b/cmd/devp2p/internal/ethtest/snap.go index 032afeafcdad..5db3cd2093f4 100644 --- a/cmd/devp2p/internal/ethtest/snap.go +++ b/cmd/devp2p/internal/ethtest/snap.go @@ -121,7 +121,7 @@ type stRangesTest struct { expSlots int } -// TestSnapGetStorageRange various forms of GetStorageRanges requests. +// TestSnapGetStorageRanges various forms of GetStorageRanges requests. func (s *Suite) TestSnapGetStorageRanges(t *utesting.T) { var ( ffHash = common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") diff --git a/cmd/devp2p/internal/v4test/discv4tests.go b/cmd/devp2p/internal/v4test/discv4tests.go index 5f340ed94c24..cf727dcf8713 100644 --- a/cmd/devp2p/internal/v4test/discv4tests.go +++ b/cmd/devp2p/internal/v4test/discv4tests.go @@ -37,9 +37,9 @@ const ( var ( // Remote node under test Remote string - // IP where the first tester is listening, port will be assigned + // Listen1 is the IP where the first tester is listening, port will be assigned Listen1 string = "127.0.0.1" - // IP where the second tester is listening, port will be assigned + // Listen2 is the IP where the second tester is listening, port will be assigned // Before running the test, you may have to `sudo ifconfig lo0 add 127.0.0.2` (on MacOS at least) Listen2 string = "127.0.0.2" ) @@ -68,7 +68,7 @@ func futureExpiration() uint64 { return uint64(time.Now().Add(expiration).Unix()) } -// This test just sends a PING packet and expects a response. +// BasicPing just sends a PING packet and expects a response. func BasicPing(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) defer te.close() @@ -137,7 +137,7 @@ func (te *testenv) checkPong(reply v4wire.Packet, pingHash []byte) error { return nil } -// This test sends a PING packet with wrong 'to' field and expects a PONG response. +// PingWrongTo sends a PING packet with wrong 'to' field and expects a PONG response. func PingWrongTo(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) defer te.close() @@ -154,7 +154,7 @@ func PingWrongTo(t *utesting.T) { } } -// This test sends a PING packet with wrong 'from' field and expects a PONG response. +// PingWrongFrom sends a PING packet with wrong 'from' field and expects a PONG response. func PingWrongFrom(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) defer te.close() @@ -172,7 +172,7 @@ func PingWrongFrom(t *utesting.T) { } } -// This test sends a PING packet with additional data at the end and expects a PONG +// PingExtraData This test sends a PING packet with additional data at the end and expects a PONG // response. The remote node should respond because EIP-8 mandates ignoring additional // trailing data. func PingExtraData(t *utesting.T) { diff --git a/cmd/devp2p/internal/v5test/discv5tests.go b/cmd/devp2p/internal/v5test/discv5tests.go index 7866498f7376..a7cd352763fe 100644 --- a/cmd/devp2p/internal/v5test/discv5tests.go +++ b/cmd/devp2p/internal/v5test/discv5tests.go @@ -58,7 +58,7 @@ func (s *Suite) AllTests() []utesting.Test { } } -// This test sends PING and expects a PONG response. +// TestPing sends PING and expects a PONG response. func (s *Suite) TestPing(t *utesting.T) { conn, l1 := s.listen1(t) defer conn.close() @@ -84,7 +84,7 @@ func checkPong(t *utesting.T, pong *v5wire.Pong, ping *v5wire.Ping, c net.Packet } } -// This test sends PING with a 9-byte request ID, which isn't allowed by the spec. +// TestPingLargeRequestID sends PING with a 9-byte request ID, which isn't allowed by the spec. // The remote node should not respond. func (s *Suite) TestPingLargeRequestID(t *utesting.T) { conn, l1 := s.listen1(t) @@ -103,7 +103,7 @@ func (s *Suite) TestPingLargeRequestID(t *utesting.T) { } } -// In this test, a session is established from one IP as usual. The session is then reused +// TestPingMultiIP establishes a session from one IP as usual. The session is then reused // on another IP, which shouldn't work. The remote node should respond with WHOAREYOU for // the attempt from a different IP. func (s *Suite) TestPingMultiIP(t *utesting.T) { @@ -153,7 +153,7 @@ func (s *Suite) TestPingMultiIP(t *utesting.T) { } } -// This test starts a handshake, but doesn't finish it and sends a second ordinary message +// TestPingHandshakeInterrupted starts a handshake, but doesn't finish it and sends a second ordinary message // packet instead of a handshake message packet. The remote node should respond with // another WHOAREYOU challenge for the second packet. func (s *Suite) TestPingHandshakeInterrupted(t *utesting.T) { @@ -180,7 +180,7 @@ func (s *Suite) TestPingHandshakeInterrupted(t *utesting.T) { } } -// This test sends TALKREQ and expects an empty TALKRESP response. +// TestTalkRequest sends TALKREQ and expects an empty TALKRESP response. func (s *Suite) TestTalkRequest(t *utesting.T) { conn, l1 := s.listen1(t) defer conn.close() @@ -215,7 +215,7 @@ func (s *Suite) TestTalkRequest(t *utesting.T) { } } -// This test checks that the remote node returns itself for FINDNODE with distance zero. +// TestFindnodeZeroDistance checks that the remote node returns itself for FINDNODE with distance zero. func (s *Suite) TestFindnodeZeroDistance(t *utesting.T) { conn, l1 := s.listen1(t) defer conn.close() @@ -232,7 +232,7 @@ func (s *Suite) TestFindnodeZeroDistance(t *utesting.T) { } } -// In this test, multiple nodes ping the node under test. After waiting for them to be +// TestFindnodeResults pings the node under test from multiple nodes. After waiting for them to be // accepted into the remote table, the test checks that they are returned by FINDNODE. func (s *Suite) TestFindnodeResults(t *utesting.T) { // Create bystanders. diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index d5f751da3a13..0fdb445ebb80 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -105,7 +105,9 @@ var ( genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db // Chain index prefixes (use `i` + single byte to avoid mixing data types). - BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress + + // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress + BloomBitsIndexPrefix = []byte("iB") preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index ee18f4bcdcf6..a73649a1fe11 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -844,7 +844,7 @@ func (t *Tree) generating() (bool, error) { return layer.genMarker != nil, nil } -// diskRoot is a external helper function to return the disk layer root. +// DiskRoot is a external helper function to return the disk layer root. func (t *Tree) DiskRoot() common.Hash { t.lock.Lock() defer t.lock.Unlock() diff --git a/core/state/state_object.go b/core/state/state_object.go index 178b93059317..5eb053e83095 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -449,7 +449,7 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject { // Attribute accessors // -// Returns the address of the contract/account +// Address returns the address of the contract/account func (s *stateObject) Address() common.Address { return s.address } @@ -527,7 +527,7 @@ func (s *stateObject) Nonce() uint64 { return s.data.Nonce } -// Never called, but must be present to allow stateObject to be used +// Value is never called, but must be present to allow stateObject to be used // as a vm.Account interface that also satisfies the vm.ContractRef // interface. Interfaces are awesome. func (s *stateObject) Value() *big.Int { diff --git a/core/state_transition.go b/core/state_transition.go index 4048c02507a9..58c5756cec6f 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -31,6 +31,8 @@ import ( var emptyCodeHash = crypto.Keccak256Hash(nil) +// StateTransition represents a state transition. +// // The State Transitioning Model // // A state transition is a change made when a transaction is applied to the current world diff --git a/core/tx_pool.go b/core/tx_pool.go index ee8b9f7a43f0..940678d9b1d3 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -865,7 +865,7 @@ func (pool *TxPool) AddRemotes(txs []*types.Transaction) []error { return pool.addTxs(txs, false, false) } -// This is like AddRemotes, but waits for pool reorganization. Tests use this method. +// AddRemotesSync is like AddRemotes, but waits for pool reorganization. Tests use this method. func (pool *TxPool) AddRemotesSync(txs []*types.Transaction) []error { return pool.addTxs(txs, false, true) } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 1d0d2a4c75e7..5f8048493577 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -400,7 +400,7 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash { }) } -// HomesteadTransaction implements TransactionInterface using the +// HomesteadSigner implements Signer interface using the // homestead rules. type HomesteadSigner struct{ FrontierSigner } @@ -427,6 +427,8 @@ func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) { return recoverPlain(hs.Hash(tx), r, s, v, true) } +// FrontierSigner implements Signer interface using the +// frontier rules. type FrontierSigner struct{} func (s FrontierSigner) ChainID() *big.Int { diff --git a/core/vm/interface.go b/core/vm/interface.go index ad9b05d666a8..88e57a2e5e1e 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -79,12 +79,12 @@ type StateDB interface { // CallContext provides a basic interface for the EVM calling conventions. The EVM // depends on this context being implemented for doing subcalls and initialising new EVM contracts. type CallContext interface { - // Call another contract + // Call calls another contract. Call(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) - // Take another's contract code and execute within our own context + // CallCode takes another contracts code and execute within our own context CallCode(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) - // Same as CallCode except sender and value is propagated from parent to child scope + // DelegateCall is same as CallCode except sender and value is propagated from parent to child scope DelegateCall(env *EVM, me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) - // Create a new contract + // Create creates a new contract Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) } diff --git a/eth/downloader/resultstore.go b/eth/downloader/resultstore.go index 2dcbbe16c916..a550f8c10933 100644 --- a/eth/downloader/resultstore.go +++ b/eth/downloader/resultstore.go @@ -124,7 +124,7 @@ func (r *resultStore) getFetchResult(headerNumber uint64) (item *fetchResult, in return item, index, stale, throttle, nil } -// hasCompletedItems returns true if there are processable items available +// HasCompletedItems returns true if there are processable items available // this method is cheaper than countCompleted func (r *resultStore) HasCompletedItems() bool { r.lock.RLock() diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 79a9b089f422..ab9858f45495 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -129,7 +129,7 @@ const ( PendingTransactionsSubscription // BlocksSubscription queries hashes for blocks that are imported BlocksSubscription - // LastSubscription keeps track of the last index + // LastIndexSubscription keeps track of the last index LastIndexSubscription ) diff --git a/eth/protocols/snap/peer.go b/eth/protocols/snap/peer.go index 235d499ffdc9..3db6e22cbd92 100644 --- a/eth/protocols/snap/peer.go +++ b/eth/protocols/snap/peer.go @@ -86,7 +86,7 @@ func (p *Peer) RequestAccountRange(id uint64, root common.Hash, origin, limit co }) } -// RequestStorageRange fetches a batch of storage slots belonging to one or more +// RequestStorageRanges fetches a batch of storage slots belonging to one or more // accounts. If slots from only one account is requested, an origin marker may also // be used to retrieve from there. func (p *Peer) RequestStorageRanges(id uint64, root common.Hash, accounts []common.Hash, origin, limit []byte, bytes uint64) error { diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 7bb323f6985c..3510360410c2 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -214,7 +214,7 @@ func (t *jsTracer) CaptureTxStart(gasLimit uint64) { t.gasLimit = gasLimit } -// CaptureTxStart implements the Tracer interface and is invoked at the end of +// CaptureTxEnd implements the Tracer interface and is invoked at the end of // transaction processing. func (t *jsTracer) CaptureTxEnd(restGas uint64) {} diff --git a/les/api.go b/les/api.go index 76714baef086..3b21b635ace6 100644 --- a/les/api.go +++ b/les/api.go @@ -382,7 +382,7 @@ func (api *LightAPI) LatestCheckpoint() ([4]string, error) { return res, nil } -// GetLocalCheckpoint returns the specific local checkpoint package. +// GetCheckpoint returns the specific local checkpoint package. // // The checkpoint package consists of 3 strings: // diff --git a/les/downloader/downloader.go b/les/downloader/downloader.go index 740fdbdad1a3..9eb7be715cdb 100644 --- a/les/downloader/downloader.go +++ b/les/downloader/downloader.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// This is a temporary package whilst working on the eth/66 blocking refactors. +// Package downloader is a temporary package whilst working on the eth/66 blocking refactors. // After that work is done, les needs to be refactored to use the new package, // or alternatively use a stripped down version of it. Either way, we need to // keep the changes scoped so duplicating temporarily seems the sanest. diff --git a/les/downloader/resultstore.go b/les/downloader/resultstore.go index 2dcbbe16c916..a550f8c10933 100644 --- a/les/downloader/resultstore.go +++ b/les/downloader/resultstore.go @@ -124,7 +124,7 @@ func (r *resultStore) getFetchResult(headerNumber uint64) (item *fetchResult, in return item, index, stale, throttle, nil } -// hasCompletedItems returns true if there are processable items available +// HasCompletedItems returns true if there are processable items available // this method is cheaper than countCompleted func (r *resultStore) HasCompletedItems() bool { r.lock.RLock() diff --git a/les/fetcher/block_fetcher.go b/les/fetcher/block_fetcher.go index 86b3c552ce27..42cf9500a2ae 100644 --- a/les/fetcher/block_fetcher.go +++ b/les/fetcher/block_fetcher.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// This is a temporary package whilst working on the eth/66 blocking refactors. +// Package fetcher is a temporary package whilst working on the eth/66 blocking refactors. // After that work is done, les needs to be refactored to use the new package, // or alternatively use a stripped down version of it. Either way, we need to // keep the changes scoped so duplicating temporarily seems the sanest. diff --git a/les/flowcontrol/manager.go b/les/flowcontrol/manager.go index 4367974d632e..10b6615e0431 100644 --- a/les/flowcontrol/manager.go +++ b/les/flowcontrol/manager.go @@ -153,7 +153,7 @@ func (cm *ClientManager) SetRechargeCurve(curve PieceWiseLinear) { } } -// SetCapacityRaiseThreshold sets a threshold value used for raising capFactor. +// SetCapacityLimits sets a threshold value used for raising capFactor. // Either if the difference between total allowed and connected capacity is less // than this threshold or if their ratio is less than capacityRaiseThresholdRatio // then capFactor is allowed to slowly raise. diff --git a/les/odr_requests.go b/les/odr_requests.go index d548fb1ee01c..d8b094b72781 100644 --- a/les/odr_requests.go +++ b/les/odr_requests.go @@ -93,7 +93,7 @@ func (r *BlockRequest) Request(reqID uint64, peer *serverPeer) error { return peer.requestBodies(reqID, []common.Hash{r.Hash}) } -// Valid processes an ODR request reply message from the LES network +// Validate processes an ODR request reply message from the LES network // returns true and stores results in memory if the message was a valid reply // to the request (implementation of LesOdrRequest) func (r *BlockRequest) Validate(db ethdb.Database, msg *Msg) error { @@ -151,7 +151,7 @@ func (r *ReceiptsRequest) Request(reqID uint64, peer *serverPeer) error { return peer.requestReceipts(reqID, []common.Hash{r.Hash}) } -// Valid processes an ODR request reply message from the LES network +// Validate processes an ODR request reply message from the LES network // returns true and stores results in memory if the message was a valid reply // to the request (implementation of LesOdrRequest) func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error { @@ -213,7 +213,7 @@ func (r *TrieRequest) Request(reqID uint64, peer *serverPeer) error { return peer.requestProofs(reqID, []ProofReq{req}) } -// Valid processes an ODR request reply message from the LES network +// Validate processes an ODR request reply message from the LES network // returns true and stores results in memory if the message was a valid reply // to the request (implementation of LesOdrRequest) func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error { @@ -242,7 +242,7 @@ type CodeReq struct { AccKey []byte } -// ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface +// CodeRequest is the ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface type CodeRequest light.CodeRequest // GetCost returns the cost of the given ODR request according to the serving @@ -266,7 +266,7 @@ func (r *CodeRequest) Request(reqID uint64, peer *serverPeer) error { return peer.requestCode(reqID, []CodeReq{req}) } -// Valid processes an ODR request reply message from the LES network +// Validate processes an ODR request reply message from the LES network // returns true and stores results in memory if the message was a valid reply // to the request (implementation of LesOdrRequest) func (r *CodeRequest) Validate(db ethdb.Database, msg *Msg) error { @@ -312,7 +312,7 @@ type HelperTrieResps struct { // describes all responses, not just a single one AuxData [][]byte } -// ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface +// ChtRequest is the ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface type ChtRequest light.ChtRequest // GetCost returns the cost of the given ODR request according to the serving @@ -343,7 +343,7 @@ func (r *ChtRequest) Request(reqID uint64, peer *serverPeer) error { return peer.requestHelperTrieProofs(reqID, []HelperTrieReq{req}) } -// Valid processes an ODR request reply message from the LES network +// Validate processes an ODR request reply message from the LES network // returns true and stores results in memory if the message was a valid reply // to the request (implementation of LesOdrRequest) func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error { @@ -400,7 +400,7 @@ type BloomReq struct { BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64 } -// ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface +// BloomRequest is the ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface type BloomRequest light.BloomRequest // GetCost returns the cost of the given ODR request according to the serving @@ -439,7 +439,7 @@ func (r *BloomRequest) Request(reqID uint64, peer *serverPeer) error { return peer.requestHelperTrieProofs(reqID, reqs) } -// Valid processes an ODR request reply message from the LES network +// Validate processes an ODR request reply message from the LES network // returns true and stores results in memory if the message was a valid reply // to the request (implementation of LesOdrRequest) func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { diff --git a/les/protocol.go b/les/protocol.go index 06db9024eb8b..dced7039e402 100644 --- a/les/protocol.go +++ b/les/protocol.go @@ -45,7 +45,7 @@ var ( AdvertiseProtocolVersions = []uint{lpv2} // clients are searching for the first advertised protocol in the list ) -// Number of implemented message corresponding to different protocol versions. +// ProtocolLengths is the number of implemented message corresponding to different protocol versions. var ProtocolLengths = map[uint]uint64{lpv2: 22, lpv3: 24, lpv4: 24} const ( diff --git a/les/utils/expiredvalue.go b/les/utils/expiredvalue.go index 3fd52616fac5..099b61d0536d 100644 --- a/les/utils/expiredvalue.go +++ b/les/utils/expiredvalue.go @@ -67,13 +67,13 @@ func (e ExpirationFactor) Value(base float64, exp uint64) float64 { return base / e.Factor * math.Pow(2, float64(int64(exp-e.Exp))) } -// value calculates the value at the given moment. +// Value calculates the value at the given moment. func (e ExpiredValue) Value(logOffset Fixed64) uint64 { offset := Uint64ToFixed64(e.Exp) - logOffset return uint64(float64(e.Base) * offset.Pow2()) } -// add adds a signed value at the given moment +// Add adds a signed value at the given moment func (e *ExpiredValue) Add(amount int64, logOffset Fixed64) int64 { integer, frac := logOffset.ToUint64(), logOffset.Fraction() factor := frac.Pow2() @@ -102,7 +102,7 @@ func (e *ExpiredValue) Add(amount int64, logOffset Fixed64) int64 { return net } -// addExp adds another ExpiredValue +// AddExp adds another ExpiredValue func (e *ExpiredValue) AddExp(a ExpiredValue) { if e.Exp > a.Exp { a.Base >>= (e.Exp - a.Exp) @@ -114,7 +114,7 @@ func (e *ExpiredValue) AddExp(a ExpiredValue) { e.Base += a.Base } -// subExp subtracts another ExpiredValue +// SubExp subtracts another ExpiredValue func (e *ExpiredValue) SubExp(a ExpiredValue) { if e.Exp > a.Exp { a.Base >>= (e.Exp - a.Exp) @@ -143,7 +143,7 @@ type LinearExpiredValue struct { Rate mclock.AbsTime `rlp:"-"` // Expiration rate(by nanosecond), will ignored by RLP } -// value calculates the value at the given moment. This function always has the +// Value calculates the value at the given moment. This function always has the // assumption that the given timestamp shouldn't less than the recorded one. func (e LinearExpiredValue) Value(now mclock.AbsTime) uint64 { offset := uint64(now / e.Rate) @@ -158,7 +158,7 @@ func (e LinearExpiredValue) Value(now mclock.AbsTime) uint64 { return e.Val } -// add adds a signed value at the given moment. This function always has the +// Add adds a signed value at the given moment. This function always has the // assumption that the given timestamp shouldn't less than the recorded one. func (e *LinearExpiredValue) Add(amount int64, now mclock.AbsTime) uint64 { offset := uint64(now / e.Rate) @@ -244,17 +244,17 @@ func Uint64ToFixed64(f uint64) Fixed64 { return Fixed64(f * fixedFactor) } -// float64ToFixed64 converts float64 to Fixed64 format. +// Float64ToFixed64 converts float64 to Fixed64 format. func Float64ToFixed64(f float64) Fixed64 { return Fixed64(f * fixedFactor) } -// toUint64 converts Fixed64 format to uint64. +// ToUint64 converts Fixed64 format to uint64. func (f64 Fixed64) ToUint64() uint64 { return uint64(f64) / fixedFactor } -// fraction returns the fractional part of a Fixed64 value. +// Fraction returns the fractional part of a Fixed64 value. func (f64 Fixed64) Fraction() Fixed64 { return f64 % fixedFactor } @@ -264,7 +264,7 @@ var ( fixedToLogFactor = math.Log(2) / float64(fixedFactor) ) -// pow2Fixed returns the base 2 power of the fixed point value. +// Pow2 returns the base 2 power of the fixed point value. func (f64 Fixed64) Pow2() float64 { return math.Exp(float64(f64) * fixedToLogFactor) } diff --git a/les/vflux/client/serverpool.go b/les/vflux/client/serverpool.go index cf96f0ee3a23..271d6e022447 100644 --- a/les/vflux/client/serverpool.go +++ b/les/vflux/client/serverpool.go @@ -89,7 +89,7 @@ type nodeHistoryEnc struct { RedialWaitStart, RedialWaitEnd uint64 } -// queryFunc sends a pre-negotiation query and blocks until a response arrives or timeout occurs. +// QueryFunc sends a pre-negotiation query and blocks until a response arrives or timeout occurs. // It returns 1 if the remote node has confirmed that connection is possible, 0 if not // possible and -1 if no response arrived (timeout). type QueryFunc func(*enode.Node) int @@ -302,7 +302,7 @@ func (s *ServerPool) addPreNegFilter(input enode.Iterator, query QueryFunc) enod }) } -// start starts the server pool. Note that NodeStateMachine should be started first. +// Start starts the server pool. Note that NodeStateMachine should be started first. func (s *ServerPool) Start() { s.ns.Start() for _, iter := range s.mixSources { @@ -336,7 +336,7 @@ func (s *ServerPool) Start() { atomic.StoreUint32(&s.started, 1) } -// stop stops the server pool +// Stop stops the server pool func (s *ServerPool) Stop() { if s.fillSet != nil { s.fillSet.Close() diff --git a/les/vflux/client/valuetracker.go b/les/vflux/client/valuetracker.go index dcd2fcdfd97e..806d0c7d7543 100644 --- a/les/vflux/client/valuetracker.go +++ b/les/vflux/client/valuetracker.go @@ -233,7 +233,7 @@ func (vt *ValueTracker) StatsExpirer() *utils.Expirer { return &vt.statsExpirer } -// StatsExpirer returns the current expiration factor so that other values can be expired +// StatsExpFactor returns the current expiration factor so that other values can be expired // with the same rate as the service value statistics. func (vt *ValueTracker) StatsExpFactor() utils.ExpirationFactor { vt.statsExpLock.RLock() diff --git a/les/vflux/requests.go b/les/vflux/requests.go index 7d4bafc18886..5abae2f537c2 100644 --- a/les/vflux/requests.go +++ b/les/vflux/requests.go @@ -50,7 +50,7 @@ type ( Bias uint64 // seconds AddTokens []IntOrInf } - // CapacityQueryReq is the encoding format of the response to the capacity query + // CapacityQueryReply is the encoding format of the response to the capacity query CapacityQueryReply []uint64 ) diff --git a/light/lightchain.go b/light/lightchain.go index dca97ce45ce6..84eee8ecaf8c 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -453,7 +453,7 @@ func (lc *LightChain) GetTd(hash common.Hash, number uint64) *big.Int { return lc.hc.GetTd(hash, number) } -// GetHeaderByNumberOdr retrieves the total difficult from the database or +// GetTdOdr retrieves the total difficult from the database or // network by hash and number, caching it (associated with its hash) if found. func (lc *LightChain) GetTdOdr(ctx context.Context, hash common.Hash, number uint64) *big.Int { td := lc.GetTd(hash, number) diff --git a/light/txpool.go b/light/txpool.go index 0f24fe1bc515..1daeea0ad695 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -447,7 +447,7 @@ func (pool *TxPool) Add(ctx context.Context, tx *types.Transaction) error { return nil } -// AddTransactions adds all valid transactions to the pool and passes them to +// AddBatch adds all valid transactions to the pool and passes them to // the tx relay backend func (pool *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) { pool.mu.Lock() diff --git a/p2p/discover/v4wire/v4wire.go b/p2p/discover/v4wire/v4wire.go index 02ee459d1479..3935068cd9db 100644 --- a/p2p/discover/v4wire/v4wire.go +++ b/p2p/discover/v4wire/v4wire.go @@ -102,7 +102,7 @@ type ( } ) -// This number is the maximum number of neighbor nodes in a Neighbors packet. +// MaxNeighbors is the maximum number of neighbor nodes in a Neighbors packet. const MaxNeighbors = 12 // This code computes the MaxNeighbors constant value. @@ -161,8 +161,9 @@ func NewEndpoint(addr *net.UDPAddr, tcpPort uint16) Endpoint { } type Packet interface { - // packet name and type for logging purposes. + // Name is the name of the package, for logging purposes. Name() string + // Kind is the packet type, for logging purposes. Kind() byte } diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 071ed65adc7f..757a3587dc7d 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -54,7 +54,7 @@ type codecV5 interface { // Encode encodes a packet. Encode(enode.ID, string, v5wire.Packet, *v5wire.Whoareyou) ([]byte, v5wire.Nonce, error) - // decode decodes a packet. It returns a *v5wire.Unknown packet if decryption fails. + // Decode decodes a packet. It returns a *v5wire.Unknown packet if decryption fails. // The *enode.Node return value is non-nil when the input contains a handshake response. Decode([]byte, string) (enode.ID, *enode.Node, v5wire.Packet, error) } diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index d605d7080332..6f8f3466e9de 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -118,6 +118,7 @@ var ( // Public errors. var ( + // ErrInvalidReqID represents error when the ID is invalid. ErrInvalidReqID = errors.New("request ID larger than 8 bytes") ) diff --git a/p2p/discover/v5wire/msg.go b/p2p/discover/v5wire/msg.go index 2f387b4025d6..1316598a4722 100644 --- a/p2p/discover/v5wire/msg.go +++ b/p2p/discover/v5wire/msg.go @@ -59,7 +59,7 @@ type ( Nonce Nonce } - // WHOAREYOU contains the handshake challenge. + // Whoareyou contains the handshake challenge. Whoareyou struct { ChallengeData []byte // Encoded challenge Nonce Nonce // Nonce of request packet @@ -73,13 +73,13 @@ type ( sent mclock.AbsTime // for handshake GC. } - // PING is sent during liveness checks. + // Ping is sent during liveness checks. Ping struct { ReqID []byte ENRSeq uint64 } - // PONG is the reply to PING. + // Pong is the reply to Ping. Pong struct { ReqID []byte ENRSeq uint64 @@ -87,58 +87,58 @@ type ( ToPort uint16 // packet, which provides a way to discover the external address (after NAT). } - // FINDNODE is a query for nodes in the given bucket. + // Findnode is a query for nodes in the given bucket. Findnode struct { ReqID []byte Distances []uint } - // NODES is the reply to FINDNODE and TOPICQUERY. + // Nodes is the reply to Findnode and Topicquery. Nodes struct { ReqID []byte Total uint8 Nodes []*enr.Record } - // TALKREQ is an application-level request. + // TalkRequest is an application-level request. TalkRequest struct { ReqID []byte Protocol string Message []byte } - // TALKRESP is the reply to TALKREQ. + // TalkResponse is the reply to TalkRequest. TalkResponse struct { ReqID []byte Message []byte } - // REQUESTTICKET requests a ticket for a topic queue. + // RequestTicket requests a ticket for a topic queue. RequestTicket struct { ReqID []byte Topic []byte } - // TICKET is the response to REQUESTTICKET. + // Ticket is the response to RequestTicket. Ticket struct { ReqID []byte Ticket []byte } - // REGTOPIC registers the sender in a topic queue using a ticket. + // Regtopic registers the sender in a topic queue using a ticket. Regtopic struct { ReqID []byte Ticket []byte ENR *enr.Record } - // REGCONFIRMATION is the reply to REGTOPIC. + // Regconfirmation is the reply to Regtopic. Regconfirmation struct { ReqID []byte Registered bool } - // TOPICQUERY asks for nodes with the given topic. + // TopicQuery asks for nodes with the given topic. TopicQuery struct { ReqID []byte Topic []byte diff --git a/p2p/enode/idscheme.go b/p2p/enode/idscheme.go index c1834f06995c..fd5d868b761d 100644 --- a/p2p/enode/idscheme.go +++ b/p2p/enode/idscheme.go @@ -28,17 +28,18 @@ import ( "golang.org/x/crypto/sha3" ) -// List of known secure identity schemes. +// ValidSchemes is a List of known secure identity schemes. var ValidSchemes = enr.SchemeMap{ "v4": V4ID{}, } +// ValidSchemesForTesting is a List of identity schemes for testing. var ValidSchemesForTesting = enr.SchemeMap{ "v4": V4ID{}, "null": NullID{}, } -// v4ID is the "v4" identity scheme. +// V4ID is the "v4" identity scheme. type V4ID struct{} // SignV4 signs a record using the v4 scheme. diff --git a/p2p/enode/node.go b/p2p/enode/node.go index d747ca331377..d7a1a9a1561c 100644 --- a/p2p/enode/node.go +++ b/p2p/enode/node.go @@ -199,7 +199,7 @@ func (n ID) String() string { return fmt.Sprintf("%x", n[:]) } -// The Go syntax representation of a ID is a call to HexID. +// GoString returns the Go syntax representation of a ID is a call to HexID. func (n ID) GoString() string { return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) } diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go index d1712f75974a..7e7fb69b293a 100644 --- a/p2p/enode/nodedb.go +++ b/p2p/enode/nodedb.go @@ -494,7 +494,7 @@ func nextNode(it iterator.Iterator) *Node { return nil } -// close flushes and closes the database files. +// Close flushes and closes the database files. func (db *DB) Close() { close(db.quit) db.lvl.Close() diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go index a8b0a3839bda..9945a436c9f8 100644 --- a/p2p/enr/entries.go +++ b/p2p/enr/entries.go @@ -61,7 +61,7 @@ type TCP uint16 func (v TCP) ENRKey() string { return "tcp" } -// UDP is the "udp" key, which holds the IPv6-specific UDP port of the node. +// TCP6 is the "tcp6" key, which holds the IPv6-specific tcp6 port of the node. type TCP6 uint16 func (v TCP6) ENRKey() string { return "tcp6" } @@ -71,7 +71,7 @@ type UDP uint16 func (v UDP) ENRKey() string { return "udp" } -// UDP is the "udp" key, which holds the IPv6-specific UDP port of the node. +// UDP6 is the "udp6" key, which holds the IPv6-specific UDP port of the node. type UDP6 uint16 func (v UDP6) ENRKey() string { return "udp6" } diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go index b7c840bc5aee..ad4c36582ae7 100644 --- a/p2p/nat/nat.go +++ b/p2p/nat/nat.go @@ -29,7 +29,7 @@ import ( natpmp "github.com/jackpal/go-nat-pmp" ) -// An implementation of nat.Interface can map local ports to ports +// Interface An implementation of nat.Interface can map local ports to ports // accessible from the Internet. type Interface interface { // These methods manage a mapping between a port on the local @@ -41,11 +41,11 @@ type Interface interface { AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error DeleteMapping(protocol string, extport, intport int) error - // This method should return the external (Internet-facing) + // ExternalIP should return the external (Internet-facing) // address of the gateway device. ExternalIP() (net.IP, error) - // Should return name of the method. This is used for logging. + // String should return name of the method. This is used for logging. String() string } diff --git a/p2p/nodestate/nodestate.go b/p2p/nodestate/nodestate.go index 2af0d0a6bd40..3adcd6c463dc 100644 --- a/p2p/nodestate/nodestate.go +++ b/p2p/nodestate/nodestate.go @@ -117,7 +117,7 @@ type ( decode func([]byte) (interface{}, error) } - // stateSetup contains the list of flags and fields used by the application + // Setup contains the list of flags and fields used by the application Setup struct { Version uint flags []flagDefinition diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go index b221a0597fc4..f3ea87930858 100644 --- a/p2p/simulations/http.go +++ b/p2p/simulations/http.go @@ -365,7 +365,7 @@ func (s *Server) StopMocker(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusOK) } -// GetMockerList returns a list of available mockers +// GetMockers returns a list of available mockers func (s *Server) GetMockers(w http.ResponseWriter, req *http.Request) { list := GetMockerList() s.JSON(w, http.StatusOK, list) diff --git a/p2p/simulations/mocker.go b/p2p/simulations/mocker.go index 47193d83ccb8..0dc04e65f921 100644 --- a/p2p/simulations/mocker.go +++ b/p2p/simulations/mocker.go @@ -36,12 +36,12 @@ var mockerList = map[string]func(net *Network, quit chan struct{}, nodeCount int "boot": boot, } -// Lookup a mocker by its name, returns the mockerFn +// LookupMocker looks a mocker by its name, returns the mockerFn func LookupMocker(mockerType string) func(net *Network, quit chan struct{}, nodeCount int) { return mockerList[mockerType] } -// Get a list of mockers (keys of the map) +// GetMockerList returns a list of mockers (keys of the map) // Useful for frontend to build available mocker selection func GetMockerList() []string { list := make([]string, 0, len(mockerList)) diff --git a/p2p/simulations/network.go b/p2p/simulations/network.go index d6c5aca73c5c..4735e5cfa6cf 100644 --- a/p2p/simulations/network.go +++ b/p2p/simulations/network.go @@ -646,8 +646,8 @@ func (net *Network) getConn(oneID, otherID enode.ID) *Conn { return net.Conns[i] } -// InitConn(one, other) retrieves the connection model for the connection between -// peers one and other, or creates a new one if it does not exist +// InitConn retrieves the connection model for the connection between +// peers 'oneID' and 'otherID', or creates a new one if it does not exist // the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i) // it checks if the connection is already up, and if the nodes are running // NOTE: diff --git a/rlp/encbuffer.go b/rlp/encbuffer.go index 687949c04442..d2c6d93bcaea 100644 --- a/rlp/encbuffer.go +++ b/rlp/encbuffer.go @@ -381,7 +381,7 @@ func (w EncoderBuffer) WriteBytes(b []byte) { w.buf.writeBytes(b) } -// WriteBytes encodes s as an RLP string. +// WriteString encodes s as an RLP string. func (w EncoderBuffer) WriteString(s string) { w.buf.writeString(s) } diff --git a/rlp/encode.go b/rlp/encode.go index b96505f56dfe..a377a1ef4c99 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -29,8 +29,11 @@ import ( var ( // Common encoded values. // These are useful when implementing EncodeRLP. + + // EmptyString is the encoding of an empty string. EmptyString = []byte{0x80} - EmptyList = []byte{0xC0} + // EmptyList is the encoding of an empty list. + EmptyList = []byte{0xC0} ) var ErrNegativeBigInt = errors.New("rlp: cannot encode negative big.Int") diff --git a/rlp/internal/rlpstruct/rlpstruct.go b/rlp/internal/rlpstruct/rlpstruct.go index 1edead96ce99..2e3eeb688193 100644 --- a/rlp/internal/rlpstruct/rlpstruct.go +++ b/rlp/internal/rlpstruct/rlpstruct.go @@ -44,7 +44,7 @@ type Type struct { Elem *Type // non-nil for Kind values of Ptr, Slice, Array } -// defaultNilValue determines whether a nil pointer to t encodes/decodes +// DefaultNilValue determines whether a nil pointer to t encodes/decodes // as an empty string or empty list. func (t Type) DefaultNilValue() NilKind { k := t.Kind diff --git a/tests/fuzzers/difficulty/difficulty-fuzz.go b/tests/fuzzers/difficulty/difficulty-fuzz.go index 5612a4e70660..e8753bb62349 100644 --- a/tests/fuzzers/difficulty/difficulty-fuzz.go +++ b/tests/fuzzers/difficulty/difficulty-fuzz.go @@ -66,7 +66,7 @@ func (f *fuzzer) readBool() bool { return f.read(1)[0]&0x1 == 0 } -// The function must return +// Fuzz function must return // // - 1 if the fuzzer should increase priority of the // given input during subsequent fuzzing (for example, the input is lexically diff --git a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go index 16242a66ec6e..70f26be7193f 100644 --- a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go +++ b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go @@ -179,6 +179,7 @@ func (f *fuzzer) fuzz() int { return ok } +// Fuzz is the fuzzing entryy-point. // The function must return // // - 1 if the fuzzer should increase priority of the diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 95a1fc464e07..6a95a1804c81 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -113,6 +113,7 @@ func (k kvs) Swap(i, j int) { k[j], k[i] = k[i], k[j] } +// Fuzz is the fuzzing entry-point. // The function must return // // - 1 if the fuzzer should increase priority of the diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index 8467bdafa6b6..3cb07dff98e9 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -117,6 +117,7 @@ func Generate(input []byte) randTest { return steps } +// Fuzz is the fuzzing entry-point. // The function must return // // - 1 if the fuzzer should increase priority of the diff --git a/tests/init.go b/tests/init.go index 87ffc65a677c..ef5ea4bb9a9a 100644 --- a/tests/init.go +++ b/tests/init.go @@ -232,7 +232,7 @@ var Forks = map[string]*params.ChainConfig{ }, } -// Returns the set of defined fork names +// AvailableForks returns the set of defined fork names func AvailableForks() []string { var availableForks []string for k := range Forks { From e14164d516600e9ac66f9060892e078f5c076229 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 4 Oct 2022 18:09:05 +0200 Subject: [PATCH 290/715] core: fix linter complaint (#25927) --- core/state_transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state_transition.go b/core/state_transition.go index 58c5756cec6f..e6a15a3c1c2e 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -33,7 +33,7 @@ var emptyCodeHash = crypto.Keccak256Hash(nil) // StateTransition represents a state transition. // -// The State Transitioning Model +// == The State Transitioning Model // // A state transition is a change made when a transaction is applied to the current world // state. The state transitioning model does all the necessary work to work out a valid new From 5d52a35931bba10f438ce4f41410442dd9cd396c Mon Sep 17 00:00:00 2001 From: Delweng Date: Thu, 6 Oct 2022 08:05:43 +0800 Subject: [PATCH 291/715] eth/tracers: add diffMode to prestateTracer (#25422) Backwards compatibility warning: The result will from now on omit empty fields instead of including a zero value (e.g. no more `balance: '0x'`). The prestateTracer will now take an option `diffMode: bool`. In this mode the tracer will output the pre state and post data for the modified parts of state. Read-only accesses will be completely omitted. Creations (be it account or slot) will be signified by omission in the `pre` list and inclusion in `post`. Whereas deletion (be it account or slot) will be signified by inclusion in `pre` and omission in `post` list. Signed-off-by: Delweng --- .../internal/tracetest/calltrace_test.go | 86 +--- .../internal/tracetest/prestate_test.go | 144 +++++++ .../testdata/prestate_tracer/simple.json | 84 ++++ .../create.json | 102 +++++ .../create_suicide.json | 104 +++++ .../inner_create.json | 374 ++++++++++++++++++ .../simple.json | 106 +++++ .../suicide.json | 107 +++++ eth/tracers/internal/tracetest/util.go | 90 +++++ eth/tracers/native/gen_account_json.go | 8 +- eth/tracers/native/prestate.go | 154 ++++++-- 11 files changed, 1245 insertions(+), 114 deletions(-) create mode 100644 eth/tracers/internal/tracetest/prestate_test.go create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create.json create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_suicide.json create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create.json create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple.json create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/suicide.json create mode 100644 eth/tracers/internal/tracetest/util.go diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 90f25e65bb7e..08b93591821b 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -21,10 +21,8 @@ import ( "math/big" "os" "path/filepath" - "reflect" "strings" "testing" - "unicode" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -38,62 +36,8 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" - - // Force-load native and js packages, to trigger registration - _ "github.com/ethereum/go-ethereum/eth/tracers/js" - _ "github.com/ethereum/go-ethereum/eth/tracers/native" ) -// To generate a new callTracer test, copy paste the makeTest method below into -// a Geth console and call it with a transaction hash you which to export. - -/* -// makeTest generates a callTracer test by running a prestate reassembled and a -// call trace run, assembling all the gathered information into a test case. -var makeTest = function(tx, rewind) { - // Generate the genesis block from the block, transaction and prestate data - var block = eth.getBlock(eth.getTransaction(tx).blockHash); - var genesis = eth.getBlock(block.parentHash); - - delete genesis.gasUsed; - delete genesis.logsBloom; - delete genesis.parentHash; - delete genesis.receiptsRoot; - delete genesis.sha3Uncles; - delete genesis.size; - delete genesis.transactions; - delete genesis.transactionsRoot; - delete genesis.uncles; - - genesis.gasLimit = genesis.gasLimit.toString(); - genesis.number = genesis.number.toString(); - genesis.timestamp = genesis.timestamp.toString(); - - genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer", rewind: rewind}); - for (var key in genesis.alloc) { - genesis.alloc[key].nonce = genesis.alloc[key].nonce.toString(); - } - genesis.config = admin.nodeInfo.protocols.eth.config; - - // Generate the call trace and produce the test input - var result = debug.traceTransaction(tx, {tracer: "callTracer", rewind: rewind}); - delete result.time; - - console.log(JSON.stringify({ - genesis: genesis, - context: { - number: block.number.toString(), - difficulty: block.difficulty, - timestamp: block.timestamp.toString(), - gasLimit: block.gasLimit.toString(), - miner: block.miner, - }, - input: eth.getRawTransaction(tx), - result: result, - }, null, 2)); -} -*/ - type callContext struct { Number math.HexOrDecimal64 `json:"number"` Difficulty *math.HexOrDecimal256 `json:"difficulty"` @@ -204,7 +148,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to unmarshal trace result: %v", err) } - if !jsonEqual(ret, test.Result) { + if !jsonEqual(ret, test.Result, new(callTrace), new(callTrace)) { // uncomment this for easier debugging //have, _ := json.MarshalIndent(ret, "", " ") //want, _ := json.MarshalIndent(test.Result, "", " ") @@ -215,32 +159,6 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { } } -// jsonEqual is similar to reflect.DeepEqual, but does a 'bounce' via json prior to -// comparison -func jsonEqual(x, y interface{}) bool { - xTrace := new(callTrace) - yTrace := new(callTrace) - if xj, err := json.Marshal(x); err == nil { - json.Unmarshal(xj, xTrace) - } else { - return false - } - if yj, err := json.Marshal(y); err == nil { - json.Unmarshal(yj, yTrace) - } else { - return false - } - return reflect.DeepEqual(xTrace, yTrace) -} - -// camel converts a snake cased input string into a camel cased output. -func camel(str string) string { - pieces := strings.Split(str, "_") - for i := 1; i < len(pieces); i++ { - pieces[i] = string(unicode.ToUpper(rune(pieces[i][0]))) + pieces[i][1:] - } - return strings.Join(pieces, "") -} func BenchmarkTracers(b *testing.B) { files, err := os.ReadDir(filepath.Join("testdata", "call_tracer")) if err != nil { @@ -386,7 +304,7 @@ func TestZeroValueToNotExitCall(t *testing.T) { wantStr := `{"type":"CALL","from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","to":"0x00000000000000000000000000000000deadbeef","value":"0x0","gas":"0x7148","gasUsed":"0x2d0","input":"0x","output":"0x","calls":[{"type":"CALL","from":"0x00000000000000000000000000000000deadbeef","to":"0x00000000000000000000000000000000000000ff","value":"0x0","gas":"0x6cbf","gasUsed":"0x0","input":"0x","output":"0x"}]}` want := new(callTrace) json.Unmarshal([]byte(wantStr), want) - if !jsonEqual(have, want) { + if !jsonEqual(have, want, new(callTrace), new(callTrace)) { t.Error("have != want") } } diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go new file mode 100644 index 000000000000..2873dfb23b3c --- /dev/null +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -0,0 +1,144 @@ +// 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 . + +package tracetest + +import ( + "encoding/json" + "math/big" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/tests" +) + +// prestateTrace is the result of a prestateTrace run. +type prestateTrace = map[common.Address]*account +type account struct { + Balance string `json:"balance,omitempty"` + Nonce uint64 `json:"nonce,omitempty"` + Code string `json:"code,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` +} +type prePostStateTrace struct { + Pre prestateTrace `json:"pre"` + Post prestateTrace `json:"post"` +} + +// prestateTraceTest defines a single test to check the stateDiff tracer against. +type prestateTraceTest struct { + Genesis *core.Genesis `json:"genesis"` + Context *callContext `json:"context"` + Input string `json:"input"` + TracerConfig json.RawMessage `json:"tracerConfig"` + Result interface{} `json:"result"` +} + +func TestPrestateTracer(t *testing.T) { + testPrestateDiffTracer("prestateTracer", "prestate_tracer", t, func() interface{} { return new(prestateTrace) }) +} + +func TestPrestateWithDiffModeTracer(t *testing.T) { + testPrestateDiffTracer("prestateTracer", "prestate_tracer_with_diff_mode", t, func() interface{} { return new(prePostStateTrace) }) +} + +func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typeBuilder func() interface{}) { + files, err := os.ReadDir(filepath.Join("testdata", dirPath)) + if err != nil { + t.Fatalf("failed to retrieve tracer test suite: %v", err) + } + for _, file := range files { + if !strings.HasSuffix(file.Name(), ".json") { + continue + } + file := file // capture range variable + t.Run(camel(strings.TrimSuffix(file.Name(), ".json")), func(t *testing.T) { + t.Parallel() + + var ( + test = new(prestateTraceTest) + tx = new(types.Transaction) + ) + // Call tracer test found, read if from disk + if blob, err := os.ReadFile(filepath.Join("testdata", dirPath, file.Name())); err != nil { + t.Fatalf("failed to read testcase: %v", err) + } else if err := json.Unmarshal(blob, test); err != nil { + t.Fatalf("failed to parse testcase: %v", err) + } + if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { + t.Fatalf("failed to parse testcase input: %v", err) + } + // Configure a blockchain with the given prestate + var ( + signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) + origin, _ = signer.Sender(tx) + txContext = vm.TxContext{ + Origin: origin, + GasPrice: tx.GasPrice(), + } + context = vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + Coinbase: test.Context.Miner, + BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), + Time: new(big.Int).SetUint64(uint64(test.Context.Time)), + Difficulty: (*big.Int)(test.Context.Difficulty), + GasLimit: uint64(test.Context.GasLimit), + } + _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) + ) + tracer, err := tracers.New(tracerName, new(tracers.Context), test.TracerConfig) + if err != nil { + t.Fatalf("failed to create call tracer: %v", err) + } + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + msg, err := tx.AsMessage(signer, nil) + if err != nil { + t.Fatalf("failed to prepare transaction for tracing: %v", err) + } + st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + if _, err = st.TransitionDb(); err != nil { + t.Fatalf("failed to execute transaction: %v", err) + } + // Retrieve the trace result and compare against the etalon + res, err := tracer.GetResult() + if err != nil { + t.Fatalf("failed to retrieve trace result: %v", err) + } + ret := typeBuilder() + if err := json.Unmarshal(res, ret); err != nil { + t.Fatalf("failed to unmarshal trace result: %v", err) + } + + if !jsonEqual(ret, test.Result, typeBuilder(), typeBuilder()) { + // uncomment this for easier debugging + // have, _ := json.MarshalIndent(ret, "", " ") + // want, _ := json.MarshalIndent(test.Result, "", " ") + // t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", string(have), string(want)) + t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result) + } + }) + } +} diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json new file mode 100644 index 000000000000..3ed27dc434cd --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json @@ -0,0 +1,84 @@ +{ + "context": { + "difficulty": "3502894804", + "gasLimit": "4722976", + "miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724", + "number": "2289806", + "timestamp": "1513601314" + }, + "genesis": { + "alloc": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "code": "0x", + "nonce": "22", + "storage": {} + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "code": "0x", + "nonce": "29072", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3509749784", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "4727564", + "hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada", + "nonce": "0x4eb12e19c16d43da", + "number": "2289805", + "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", + "timestamp": "1513601261", + "totalDifficulty": "7143276353481064" + }, + "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", + "result": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "nonce": 22 + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "nonce": 1, + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "nonce": 29072 + }, + "0x1585936b53834b021f68cc13eeefdec2efc8e724": { + "balance": "0x0", + "nonce": 0 + } + } +} 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 new file mode 100644 index 000000000000..1b09622474ef --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create.json @@ -0,0 +1,102 @@ +{ + "genesis": { + "difficulty": "13756228101629", + "extraData": "0xd983010302844765746887676f312e342e328777696e646f7773", + "gasLimit": "3141592", + "hash": "0x58b7a87b6ba10b46b4e251d64ebc3d9822dd82218eaf24dff6796f6f1f687251", + "miner": "0xf8b483dba2c3b7176a3da549ad41a48bb3121069", + "mixHash": "0x5984b9a316116bd890e6e5f4c52d655184b0d7aa74821e1382d7760f9803c1dd", + "nonce": "0xea4bb4997242c681", + "number": "1061221", + "stateRoot": "0x5402c04d481414248d824c3b61e924e0c9307adbc9fbaae774a74cce30a4163d", + "timestamp": "1456458069", + "totalDifficulty": "7930751135586064334", + "alloc": { + "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { + "balance": "0x9fb6b81e112638b886", + "nonce": "217865", + "code": "0x" + }, + "0xf0c5cef39b17c213cfe090a46b8c7760ffb7928a": { + "balance": "0x15b6828e22bb12188", + "nonce": "747", + "code": "0x" + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "ethash": {} + } + }, + "context": { + "number": "1061222", + "difficulty": "13749511193633", + "timestamp": "1456458097", + "gasLimit": "3141592", + "miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226" + }, + "input": "0xf905498202eb850ba43b7400830f42408080b904f460606040526040516102b43803806102b48339016040526060805160600190602001505b5b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b806001600050908051906020019082805482825590600052602060002090601f01602090048101928215609e579182015b82811115609d5782518260005055916020019190600101906081565b5b50905060c5919060a9565b8082111560c1576000818150600090555060010160a9565b5090565b50505b506101dc806100d86000396000f30060606040526000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514610044578063cfae32171461005157610042565b005b61004f6004506100ca565b005b61005c60045061015e565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156100bc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561015b57600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b565b60206040519081016040528060008152602001506001600050805480601f016020809104026020016040519081016040528092919081815260200182805480156101cd57820191906000526020600020905b8154815290600101906020018083116101b057829003601f168201915b505050505090506101d9565b9056000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001ee7b225f6964223a225a473466784a7245323639384866623839222c22666f726d5f736f75726365223a22434c54523031222c22636f6d6d69746d656e745f64617465223a22222c22626f72726f7765725f6e616d65223a22222c22626f72726f7765725f616464726573735f6c696e6531223a22222c22626f72726f7765725f616464726573735f6c696e6532223a22222c22626f72726f7765725f636f6e74616374223a22222c22626f72726f7765725f7374617465223a22222c22626f72726f7765725f74797065223a22222c2270726f70657274795f61646472657373223a22222c226c6f616e5f616d6f756e745f7772697474656e223a22222c226c6f616e5f616d6f756e74223a22222c224c54565f7772697474656e223a22222c224c5456223a22222c2244534352223a22222c2270726f70657274795f74797065223a22222c2270726f70657274795f6465736372697074696f6e223a22222c226c656e646572223a22222c2267756172616e746f7273223a22222c226c696d69746564223a22222c226361705f616d6f756e74223a22222c226361705f70657263656e745f7772697474656e223a22222c226361705f70657263656e74616765223a22222c227465726d5f7772697474656e223a22222c227465726d223a22222c22657874656e64223a22227d0000000000000000000000000000000000001ba027d54712289af34f0ec0f06092745104d68e5801cd17097bc1104111f855258da070ec9f1c942d9bedf89f9660a684d3bb8cd9c2ac7f6dd883cb3e26a193180244", + "tracerConfig": { + "diffMode": true + }, + "result": { + "pre": { + "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { + "balance": "0x9fb6b81e112638b886", + "nonce": 217865 + }, + "0xf0c5cef39b17c213cfe090a46b8c7760ffb7928a": { + "balance": "0x15b6828e22bb12188", + "nonce": 747 + } + }, + "post": { + "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { + "balance": "0x9fb71abdd2621d8886" + }, + "0x40f2f445da6c9047554683fb382fba6769717116": { + "code": "0x60606040526000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514610044578063cfae32171461005157610042565b005b61004f6004506100ca565b005b61005c60045061015e565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156100bc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561015b57600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b565b60206040519081016040528060008152602001506001600050805480601f016020809104026020016040519081016040528092919081815260200182805480156101cd57820191906000526020600020905b8154815290600101906020018083116101b057829003601f168201915b505050505090506101d9565b9056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f0c5cef39b17c213cfe090a46b8c7760ffb7928a", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000000000000000001ee", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "0x7b225f6964223a225a473466784a7245323639384866623839222c22666f726d", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7": "0x5f736f75726365223a22434c54523031222c22636f6d6d69746d656e745f6461", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf8": "0x7465223a22222c22626f72726f7765725f6e616d65223a22222c22626f72726f", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf9": "0x7765725f616464726573735f6c696e6531223a22222c22626f72726f7765725f", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfa": "0x616464726573735f6c696e6532223a22222c22626f72726f7765725f636f6e74", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfb": "0x616374223a22222c22626f72726f7765725f7374617465223a22222c22626f72", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfc": "0x726f7765725f74797065223a22222c2270726f70657274795f61646472657373", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfd": "0x223a22222c226c6f616e5f616d6f756e745f7772697474656e223a22222c226c", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cfe": "0x6f616e5f616d6f756e74223a22222c224c54565f7772697474656e223a22222c", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cff": "0x224c5456223a22222c2244534352223a22222c2270726f70657274795f747970", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d00": "0x65223a22222c2270726f70657274795f6465736372697074696f6e223a22222c", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d01": "0x226c656e646572223a22222c2267756172616e746f7273223a22222c226c696d", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d02": "0x69746564223a22222c226361705f616d6f756e74223a22222c226361705f7065", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d03": "0x7263656e745f7772697474656e223a22222c226361705f70657263656e746167", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d04": "0x65223a22222c227465726d5f7772697474656e223a22222c227465726d223a22", + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0d05": "0x222c22657874656e64223a22227d000000000000000000000000000000000000" + } + }, + "0xf0c5cef39b17c213cfe090a46b8c7760ffb7928a": { + "balance": "0x15b058920efcc5188", + "nonce": 748 + } + } + } +} diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_suicide.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_suicide.json new file mode 100644 index 000000000000..fdeb0e50673c --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_suicide.json @@ -0,0 +1,104 @@ +{ + "genesis": { + "difficulty": "6217248151198", + "extraData": "0xd783010103844765746887676f312e342e32856c696e7578", + "gasLimit": "3141592", + "hash": "0xe8bff55fe3e61936ef321cf3afaeb1ba2f7234e1e89535fa8ae39963caebe9c3", + "miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5", + "mixHash": "0x03da00d5a15a064e5ebddf53cd0aaeb9a8aff0f40c0fb031a74f463d11ec83b8", + "nonce": "0x6575fe08c4167044", + "number": "243825", + "stateRoot": "0x47182fe2e6e740b8a76f82fe5c527d6ad548f805274f21792cf4047235b24fbf", + "timestamp": "1442424328", + "totalDifficulty": "1035061827427752845", + "alloc": { + "0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": { + "balance": "0xc820f93200f4000", + "nonce": "0x5E", + "code": "0x" + }, + "0x332b656504f4eabb44c8617a42af37461a34e9dc": { + "balance": "0x11faea4f35e5af80000", + "code": "0x", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": { + "balance": "0xbf681825be002ac452", + "nonce": "0x70FA", + "code": "0x" + }, + "0x82effbaaaf28614e55b2ba440fb198e0e5789b0f": { + "balance": "0xb3d0ac5cb94df6f6b0", + "nonce": "0x1", + "code": "0x" + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "ethash": {} + } + }, + "context": { + "number": "243826", + "difficulty": "6214212385501", + "timestamp": "1442424353", + "gasLimit": "3141592", + "miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5" + }, + "input": "0xf8e85e850ba43b7400830f42408080b89660606040527382effbaaaf28614e55b2ba440fb198e0e5789b0f600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600a80608c6000396000f30060606040526008565b001ca0340b21661e5bb85a46319a15f33a362e5c0f02faa7cdbf9c5808b2134da968eaa0226e6788f8c20e211d436ab7f6298ef32fa4c23a509eeeaac0880d115c17bc3f", + "tracerConfig": { + "diffMode": true + }, + "result": { + "pre": { + "0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": { + "balance": "0xc820f93200f4000", + "nonce": 94 + }, + "0x332b656504f4eabb44c8617a42af37461a34e9dc": { + "balance": "0x11faea4f35e5af80000", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": { + "balance": "0xbf681825be002ac452", + "nonce": 28922 + }, + "0x82effbaaaf28614e55b2ba440fb198e0e5789b0f": { + "balance": "0xb3d0ac5cb94df6f6b0", + "nonce": 1 + } + }, + "post": { + "0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": { + "balance": "0xc7d4d88af8b4c00", + "nonce": 95 + }, + "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": { + "balance": "0xbf681ce7c870aeb852" + }, + "0x82effbaaaf28614e55b2ba440fb198e0e5789b0f": { + "balance": "0x1d37f515017a8eef6b0" + } + } + } +} 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 new file mode 100644 index 000000000000..5bcf5121f12e --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/inner_create.json @@ -0,0 +1,374 @@ +{ + "genesis": { + "difficulty": "13707196986889", + "extraData": "0xd983010302844765746887676f312e342e328777696e646f7773", + "gasLimit": "3141592", + "hash": "0x607b38fe7e94427ee8f3b9a62375c67f953f8d49e05dbfd0145f9d3bac142193", + "miner": "0xf8b483dba2c3b7176a3da549ad41a48bb3121069", + "mixHash": "0x98c74c9e76fd0078157e1696e4334a7e787396459693a84536d8b96414dafd5d", + "nonce": "0x77a5a0a73ad8745e", + "number": "1062502", + "stateRoot": "0x1df615df5fdbc8d5397bf3574f462f6d9696428eb8796d8e9252bccc8e3a8996", + "timestamp": "1456480432", + "totalDifficulty": "7948153536501153741", + "alloc": { + "0x0000000000000000000000000000000000000004": { + "balance": "0x0", + "code": "0x" + }, + "0x1deeda36e15ec9e80f3d7414d67a4803ae45fc80": { + "balance": "0x0", + "code": "0x650200d2f18c7350606060405236156100c15760e060020a60003504630bd295e681146100c65780630fd1f94e1461017d5780630fee183d1461018c578063349501b7146101ad5780635054d98a146101c75780637c0278fc146101ef5780637e92656214610287578063a0943154146102f6578063a1873db61461030e578063a9d2293d14610355578063b5d0f16e146103ad578063c17e6817146103ce578063cc3471af1461046a578063da46be0a1461047a578063f55627531461052a575b610007565b6105d36004356024356044355b60006000600030915081600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515191505080841080610173575081600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050506040518051906020015060ff16810184115b1561100d57610007565b6105d3600060f0610f6d61046e565b6105d3600435602435604435606435600081600202831015610ff657610fee565b6105d36004355b600081600014156109115750600161098f565b6105d36004355b6008810154600090819062010000900460ff16156105f257600691506105ec565b60408051602060248035600481810135601f81018590048502860185019096528585526105e5958135959194604494929390920191819084018382808284375094965050505050505060006004825103836001016000508181546001816001161561010002031660029004825481601f106108005782601f1061083a575b826008026101000360020a80910402828001178355610851565b6105e5600435602435604051600090600160a060020a038316907f398bd6b21ae4164ec322fb0eb8c2eb6277f36fd41903fbbed594dfe125591281908390a26007830154819010610e415760078301546005840154610e3f9162010000909104600160a060020a0316906103d8565b6105d3600435602435600060006000611064856101ce565b6105d36004356024356044356004830154600090819030908410156110e4577f4e4f545f454e4f5547485f47415300000000000000000000000000000000000091506112dd565b6105d35b60006000309050600a81600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515160091901935050505b5090565b6105d36004356024355b60008282111561099e578183606402049050610998565b6105d36004356024355b600030600160a060020a0316318211156103fa57600160a060020a0330163191505b6000821115610994577389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc84846040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f2156100075750839250610998915050565b6105d35b6000600f610f6d610359565b6105e560043560243560443560643560843560088501805461ff00191661010017905584543090600090819081908190819060a060020a900460e060020a02811480156104db575060018b8101546002918116156101000260001901160481145b156109b3578a5460028c0154600160a060020a039190911690895a60405191900391906000818181858888f193505050508b60080160006101000a81548160ff02191690830217905550610bfa565b6105d36004355b6000600060006000309250600a83600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151600919019350505081851115610eb05782600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051519450610ea89050565b60408051918252519081900360200190f35b005b600291505b50919050565b6008830154610100900460ff161561060d57600591506105ec565b30905080600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515143610109011015905061066457600091506105ec565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515143600a01101590506106d3576005830154620100009004600160a060020a0316600014156105e757600191506105ec565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151431015905061072357600391506105ec565b80600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050506040518051906020015060ff1681600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051519190910143101590506107bf57600491506105ec565b600791506105ec565b5081800160010183558181151161085157601f016020900481601f016020900483600052602060002091820191016108519190610826565b82601f106107c8575082600052602060002080549082601f016020900481019061090691905b808211156103a95760008155600101610826565b60ff19168360005260206000205581800160010183555b5050505060048251111561090c575060005b6001838101546002918116156101000260001901160481101561090c57818160040181518110156100075790602001015160f860020a900460f860020a02836001016000508281546001816001161561010002031660029004811015610007578154600116156108e25790600052602060002090602091828204019190065b601f036101000a81548160ff0219169060f860020a84040217905550600101610863565b5061026d565b505050565b604080517f5f5f6469672875696e74323536290000000000000000000000000000000000008152815190819003600e01812060e060020a9081900481028190049081028252600019850160048301529151600160a060020a03301692916102bc86029160248281019260009291908290030181838887f19450505050505b919050565b5060005b92915050565b818360020203836064020460c8039050610998565b8a5460a060020a900460e060020a0260001415610a23578a5460028c0154600160a060020a039190911690895a03908d6001016000506040518082805460018160011615610100020316600290048015610ae55780601f10610aba57610100808354040283529160200191610ae5565b60018b8101546002918116156101000260001901160460001415610b1a578a5460028c0154600160a060020a039190911690895a03908d60000160149054906101000a900460e060020a0260e060020a900491906040518360e060020a028152600401809050600060405180830381858988f19450505050508b60080160006101000a81548160ff02191690830217905550610bfa565b820191906000526020600020905b815481529060010190602001808311610ac857829003601f168201915b5050915050600060405180830381858888f193505050508b60080160006101000a81548160ff02191690830217905550610bfa565b8a5460028c0154600160a060020a039190911690895a03908d60000160149054906101000a900460e060020a0260e060020a900491908e6001016000506040518460e060020a0281526004018082805460018160011615610100020316600290048015610bc85780601f10610b9d57610100808354040283529160200191610bc8565b820191906000526020600020905b815481529060010190602001808311610bab57829003601f168201915b5050915050600060405180830381858988f19450505050508b60080160006101000a81548160ff021916908302179055505b85600160a060020a031663938b5f326040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750505060405180519060200150600160a060020a031660405180807f75706461746544656661756c745061796d656e742829000000000000000000008152602001506016019050604051809103902060e060020a8091040260e060020a90046040518160e060020a0281526004018090506000604051808303816000876161da5a03f15050505060038b0154610cc8903a6103b7565b60058c0154909550620100009004600160a060020a03908116908a161415610cf65760068b01549350610d38565b85600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051519450505b6064858502048b6007016000505401925060648587600160a060020a031663625cc4656040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505050604051805190602001500204915060008b60070160005081905550865a8b03013a029050610db7898285016103d8565b9250610dd773d3cda913deb6f67967b99d67acdfa1712c293601836103d8565b6040805160088e01548482526020820187905281830184905260ff1660608201529051919350600160a060020a038b16917f4538b7ec91dae8fada01e66a052482086d3e690c3db5a80457fbcd55457b4ae19181900360800190a25050505050505050505050565b505b309050610e8c81600160a060020a031663ae45850b6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040515190316103d8565b505050600801805462ff0000191662010000179055565b600093505b505050919050565b600e19919091019081851115610f075782600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051519450610ea89050565b60ef19919091019081851115610ea357818503905060f08184600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050506040518051906020015002049350610ea8565b03905090565b6006860181905560058601805475ffffffffffffffffffffffffffffffffffffffff000019166201000087021790556007860184905560408051600160a060020a0387168152602081019290925280517fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9281900390910190a15b949350505050565b610f7343610531565b600192505b50509392505050565b60108185031015610fff576005860154620100009004600160a060020a03166000148061105057506005860154620100009004600160a060020a03908116908616145b9250611004565b600092505b505092915050565b91503090506000821480156110c4575080600160a060020a031663ae45850b6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505060405151600160a060020a039081169086161490505b156110d2576001925061105c565b6007821415611057576001925061105c565b6008860154610100900460ff161561111e577f414c52454144595f43414c4c454400000000000000000000000000000000000091506112dd565b80600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610007575050604051514310905080611206575080600160a060020a031663a06db7dc6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100075750506040805180517f0a16697a000000000000000000000000000000000000000000000000000000008252915160ff9092169291630a16697a9160048181019260209290919082900301816000876161da5a03f1156100075750506040515191909101431190505b15611233577f4e4f545f494e5f43414c4c5f57494e444f57000000000000000000000000000091506112dd565b61123e8686436100d3565b151561126c577f4e4f545f415554484f52495a454400000000000000000000000000000000000091506112dd565b6005860154600061ffff91909116118015611299575032600160a060020a031685600160a060020a031614155b80156112b4575060058601546112b29061ffff166101b4565b155b156112dd577f535441434b5f544f4f5f4445455000000000000000000000000000000000000091505b60008214610fff5760408051600160a060020a03871681526020810184905281517fdcb278834ca505ad219cf8e4b5d11f026080abef6ec68e249ea5e4d9bb3dc7b2929181900390910190a16000925061100456" + }, + "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { + "balance": "0x98e1c608601c2496b2", + "nonce": "218916", + "code": "0x" + }, + "0x651913977e8140c323997fce5e03c19e0015eebf": { + "balance": "0x0", + "code": "0x", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000007": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000008": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000000000c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000000000d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000000000e": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x6c8f2a135f6ed072de4503bd7c4999a1a17f824b": { + "balance": "0x0", + "nonce": "237", + "code": "0x6060604052361561027c5760e060020a600035046301991313811461027e57806303d22885146102ca5780630450991814610323578063049ae734146103705780630ce46c43146103c35780630e85023914610602578063112e39a8146106755780631b4fa6ab146106c25780631e74a2d3146106d057806326a7985a146106fd5780633017fe2414610753578063346cabbc1461075c578063373a1bc3146107d55780633a9e74331461081e5780633c2c21a01461086e5780633d9ce89b146108ba578063480b70bd1461092f578063481078431461097e57806348f0518714610a0e5780634c471cde14610a865780634db3da8314610b09578063523ccfa814610b4f578063586a69fa14610be05780635a9f2def14610c3657806364ee49fe14610caf57806367beaccb14610d055780636840246014610d74578063795b9a6f14610dca5780637b55c8b514610e415780637c73f84614610ee15780638c0e156d14610f145780638c1d01c814610f605780638e46afa914610f69578063938c430714610fc0578063971c803f146111555780639772c982146111ac57806398c9cdf41461122857806398e00e541461127f5780639f927be7146112d5578063a00aede914611383578063a1c0539d146113d3578063aff21c6514611449578063b152f19e14611474578063b549793d146114cb578063b5b33eda1461154b578063bbc6eb1f1461159b578063c0f68859146115ab578063c3a2c0c314611601578063c43d05751461164b578063d8e5c04814611694578063dbfef71014611228578063e29fb547146116e7578063e6470fbe1461173a578063ea27a8811461174c578063ee77fe86146117d1578063f158458c14611851575b005b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387876020604051908101604052806000815260200150612225610f6d565b61188260043560243560443560643560843560a43560c435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338b8a6020604051908101604052806000815260200150896125196106c6565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503385600060e060020a026020604051908101604052806000815260200150611e4a610f6d565b611882600435602435604435606435608435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503389896020604051908101604052806000815260200150886124e86106c6565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750506040805160a08082019092529597963596608435969095506101449450925060a491506005908390839080828437509095505050505050604080518082018252600160a060020a03338116825288166020820152815160c0810190925260009173e54d323f9ef17c1f0dede47ecc86a9718fe5ea349163e3042c0f91600191908a908a9089908b90808b8b9090602002015181526020018b60016005811015610002579090602002015181526020018b60026005811015610002579090602002015181526020018b60036005811015610002579090602002015181526020018b6004600581101561000257909060200201518152602001348152602001506040518860e060020a02815260040180888152602001876002602002808383829060006004602084601f0104600f02600301f150905001868152602001806020018560ff1681526020018461ffff168152602001836006602002808383829060006004602084601f0104600f02600301f1509050018281038252868181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156105d25780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038160008760325a03f2156100025750506040515191506124cd9050565b60408051602060248035600481810135601f81018590048502860185019096528585526118829581359591946044949293909201918190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808787611e64610f6d565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611d28610f6d565b61189f5b6000611bf8611159565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881600060005054611a9561159f565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346326a7985a6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b6118b760075b90565b604080516020606435600481810135601f8101849004840285018401909552848452611882948135946024803595604435956084949201919081908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160013389898861224b610f6d565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503386866020604051908101604052806000815260200150611e64610f6d565b611882600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333896020604051908101604052806000815260200150886123bc6106c6565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387866020604051908101604052806000815260200150611f8d610f6d565b60408051602060248035600481810135601f810185900485028601850190965285855261188295813595919460449492939092019181908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808888612225610f6d565b611882600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503388886020604051908101604052806000815260200150612388610f6d565b611882600435604080517fc4144b2600000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a03831660248201529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163c4144b26916044818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b604080516020604435600481810135601f81018490048402850184019095528484526118829481359460248035959394606494929391019181908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133888888612238610f6d565b604080516020604435600481810135601f810184900484028501840190955284845261188294813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a43560c435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338b8b8b896126536106c6565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333866020604051908101604052806000815260200150611e4a610f6d565b6118b76004355b604080517fed5bd7ea00000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a03831660248201529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163ed5bd7ea916044818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b61189f600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463586a69fa6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f81018590048502860185019096528585526118829581359591946044949293909201918190840183828082843750949650509335935050606435915050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808989612388610f6d565b61188260043560243560443560643560843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338a896020604051908101604052806000815260200150886124d76106c6565b6040805160206004803580820135601f8101849004840285018401909552848452611882949193602493909291840191908190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808587611e4a610f6d565b61188260043560243560443560643560843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338a8a60206040519081016040528060008152602001508961262d6106c6565b604080516020606435600481810135601f810184900484028501840190955284845261188294813594602480359560443595608494920191908190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338888876120c7610f6d565b604080516020604435600481810135601f81018490048402850184019095528484526118829481359460248035959394606494929391019181908401838280828437505060408051608080820190925295979635969561010495509350608492508591508390839080828437509095505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338989898961263a6106c6565b6118b7600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881858585611ba361122c565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050333388602060405190810160405280600081526020015061236e610f6d565b6118b760005481565b6118c95b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea34638e46afa96040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f8101859004850286018501909652858552611882958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a43560c43560e43561010435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600160005033338e8e8d8f8e8e8e8e8e346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156111195780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519b9a5050505050505050505050565b61189f5b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463971c803f6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750949650509335935050608435915050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338989896123a2610f6d565b6118b75b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346398c9cdf46040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346398e00e546040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b611882600435604080517fe6ce3a6a000000000000000000000000000000000000000000000000000000008152600160048201527f3e3d0000000000000000000000000000000000000000000000000000000000006024820152604481018390529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163e6ce3a6a916064818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503385600060e060020a0260206040519081016040528060008152602001506121ef610f6d565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338787876120b5610f6d565b6118b7600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a88183611b4561159f565b6118b75b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463b152f19e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f8101859004850286018501909652858552611882958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808b8b8961262d6106c6565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503386600060e060020a026020604051908101604052806000815260200150612200610f6d565b6118b75b60005460649004610759565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463c0f688596040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b611882600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611bff610f6d565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333876020604051908101604052806000815260200150612200610f6d565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387600060e060020a026020604051908101604052806000815260200150612213610f6d565b611882600435602435604435606435608435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600160005033338a60206040519081016040528060008152602001508961250c6106c6565b61027c6000600060006118e033610b56565b6118b7600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881868686866040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b949350505050565b604080516020604435600481810135601f810184900484028501840190955284845261188294813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338a8a8a886124fa6106c6565b6118b7600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a88184846000611b4f61122c565b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b60408051918252519081900360200190f35b6040805160ff929092168252519081900360200190f35b15611a905733925082600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fc6803622000000000000000000000000000000000000000000000000000000008252915191945063c680362291600482810192602092919082900301816000876161da5a03f11561000257505060405151905080156119d1575082600160a060020a031663d379be236040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151600160a060020a03166000141590505b80156119dd5750600082115b80156119ec5750600054600190115b15611a90578183600160a060020a031663830953ab6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040515160640291909104915050604281118015611a4d5750600054829011155b15611a675760008054612710612711909102049055611a90565b602181108015611a7a5750600054829010155b15611a90576000805461271061270f9091020490555b505050565b6000611a9f61122c565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f2156100025750506040515191506107599050565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b919050565b6000611af261122c565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b9392505050565b9050610759565b611c076106c6565b6000611c11611478565b611c1961122c565b600054611c2461159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611cf25780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f2156100025750506040515191506107599050565b611d306106c6565b60008b611d3b61122c565b600054611d4661159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611e145780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611b409050565b611e526106c6565b6000611e5c611478565b611d3b61122c565b611e6c6106c6565b6000611e76611478565b611e7e61122c565b600054611e8961159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611f575780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611b9d9050565b611f956106c6565b8b611f9e611478565b611fa661122c565b600054611fb161159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561207f5780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611bf19050565b6120bd6106c6565b6000611f9e611478565b6120cf6106c6565b8b6120d8611478565b6120e061122c565b6000546120eb61159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156121b95780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f2156100025750506040515191506117c99050565b6121f76106c6565b8b611e76611478565b6122086106c6565b60008b611e7e61122c565b61221b6106c6565b8a8c611fa661122c565b61222d6106c6565b60008b611fa661122c565b6122406106c6565b60008b6120e061122c565b6122536106c6565b8c8b61225d61122c565b60005461226861159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156123365780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f21561000257505060405151979650505050505050565b6123766106c6565b60008c8c600060005054611fb161159f565b6123906106c6565b60008c8c6000600050546120eb61159f565b6123aa6106c6565b60008c8c60006000505461226861159f565b60008d8d6000600050546120eb61159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561249c5780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150505b9695505050505050565b8e8d8d6000600050546123ce61159f565b60008d8d60006000505461226861159f565b60008d8d6000600050546123ce61159f565b60008e8e8d61226861159f565b8f8e8e8d61252561159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156125f35780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519998505050505050505050565b60008e8e8d6123ce61159f565b8a5160208c015160408d015160608e015161226861159f565b60008e8e8d61252561159f56", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000011f8119429ed3a", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000f5d861791e76fa01433e0d7421aee565290e4afe", + "0x031b9ec274101cc3ccff4d6d98ef4513742dadbaadba538bff48b88403253234": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x20ef51bb8ea9e8e8d5e2c17d28e47285698893c1017db4b4e40b792358a3dbc7": "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8abd": "0x000000000000000000000000c9a2bfd279fe57e7651e5d9f29bb1793c9a1cf01", + "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8abf": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", + "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8ac2": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dfb": "0x000000000000000000000000f5d861791e76fa01433e0d7421aee565290e4afe", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dfc": "0x00000000000000000000000000000000000000000000000000000000000f6897", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dfd": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dfe": "0x0000000000000000000000002859ddf2877c46d54e67b6becdb1cafb8ef4a458", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dff": "0x000000000000000000000000b7df3c43a8b13ecf45777c267404e15c7cdb04c9", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794e00": "0x0000000000000000000000000000000000000000000000000000000000000008", + "0x3b20a4b931bc4ae9450774ee52b8f5da1b248d23e61cd20c09b25662f73894fd": "0x0000000000000000000000000000000000000000000000000000000000000006", + "0x3b99aee1e3090227401ac2055c861246ca6ec62f426b4b4d74df88510f841b89": "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef711": "0x000000000000000000000000a4d91b341f0e9a7000be916a668408b463f4c38c", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef712": "0x0000000000000000000000000000000000000000000000000000000000102ce9", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef713": "0x000000000000000000000000fd97a0d81cc92eecd52452831930b27889925ef0", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef714": "0x00000000000000000000000016917c151bb1399852a0741eb7b317b443e2cfa3", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef715": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef716": "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a3fe": "0x000000000000000000000000c5ef24ec3bf0e3522cfc8e53f3e076b043547ce1", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a3ff": "0x00000000000000000000000000000000000000000000000000000000000fff67", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a400": "0x000000000000000000000000b7df3c43a8b13ecf45777c267404e15c7cdb04c9", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a401": "0x00000000000000000000000010fc2e8ba5f40336c3576ffaa25177f1cdedf836", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a402": "0x000000000000000000000000fd97a0d81cc92eecd52452831930b27889925ef0", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a403": "0x0000000000000000000000000000000000000000000000000000000000000006", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5ba": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bb": "0x000000000000000000000000000000000000000000000000000000000010347b", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bc": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bd": "0x000000000000000000000000c9a2bfd279fe57e7651e5d9f29bb1793c9a1cf01", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5be": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bf": "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x99d5294a34e2d6d560a223237786adc8b5651c09094b9ecd56e6ae7abc2a2751": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x99d5294a34e2d6d560a223237786adc8b5651c09094b9ecd56e6ae7abc2a2752": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x99d5294a34e2d6d560a223237786adc8b5651c09094b9ecd56e6ae7abc2a2753": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x99d5294a34e2d6d560a223237786adc8b5651c09094b9ecd56e6ae7abc2a2754": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x99d5294a34e2d6d560a223237786adc8b5651c09094b9ecd56e6ae7abc2a2755": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x99d5294a34e2d6d560a223237786adc8b5651c09094b9ecd56e6ae7abc2a2756": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826a7": "0x000000000000000000000000b7df3c43a8b13ecf45777c267404e15c7cdb04c9", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826a8": "0x00000000000000000000000000000000000000000000000000000000000fe13d", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826a9": "0x000000000000000000000000f5d861791e76fa01433e0d7421aee565290e4afe", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826aa": "0x00000000000000000000000063110531142fb314118164ff579ba52746504408", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826ab": "0x000000000000000000000000c5ef24ec3bf0e3522cfc8e53f3e076b043547ce1", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826ac": "0x0000000000000000000000000000000000000000000000000000000000000007", + "0xac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c890780": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xccd2cbc946692be8ade97db99353304e3af0fa6202f93649d4e185ad8b1f385c": "0x0000000000000000000000000000000000000000000000000000000000000004", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4ef": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f0": "0x00000000000000000000000000000000000000000000000000000000001030b3", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f1": "0x000000000000000000000000a4d91b341f0e9a7000be916a668408b463f4c38c", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f2": "0x000000000000000000000000dd87a67740c2acf48a31829783a095a81c3628d9", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f3": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f4": "0x0000000000000000000000000000000000000000000000000000000000000003", + "0xdabde47554d6a6cfcff3c968abb145f298585fafa9e24c10fc526269794bd626": "0x0000000000000000000000000000000000000000000000000000000000000003", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64db7": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64db8": "0x000000000000000000000000000000000000000000000000000000000010365c", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64db9": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64dba": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64dbb": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64dbc": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdec": "0x000000000000000000000000fd97a0d81cc92eecd52452831930b27889925ef0", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bded": "0x0000000000000000000000000000000000000000000000000000000000101dc2", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdee": "0x000000000000000000000000c5ef24ec3bf0e3522cfc8e53f3e076b043547ce1", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdef": "0x000000000000000000000000173243e117a6382211b1ac91eeb262f4a7021c16", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdf0": "0x000000000000000000000000a4d91b341f0e9a7000be916a668408b463f4c38c", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdf1": "0x0000000000000000000000000000000000000000000000000000000000000005" + } + }, + "0x741467b251fca923d6229c4b439078b55dca233b": { + "balance": "0x29c613529e8218f8", + "code": "0x606060405236156101a05760e060020a60003504630924120081146101c25780630a16697a146101cf5780630fd1f94e146101d8578063137c638b1461022e57806321835af61461023b57806324032866146102545780632f95b833146102d65780633017fe24146102e55780633233c686146102ef57806337f4c00e146102fa5780634500054f146103055780634e417a98146103785780634e71d92d146103e15780634f059a43146103f35780636146195414610451578063625cc4651461046157806367ce940d1461046a5780637d298ee314610477578063830953ab146104f9578063938b5f321461050457806395ee122114610516578063974654f41461052a578063a06db7dc14610535578063a9d2293d14610541578063ae45850b14610597578063b0f07e44146105a9578063c19d93fb146105cb578063c6502da81461062e578063c680362214610637578063ca94692d1461064a578063cc3471af14610673578063d379be23146106c9578063d62457f6146106e3578063ea8a1af0146106ee578063f5562753146107f3578063f6b4dfb414610854575b610868600080548190600160a060020a03908116339091161461087a57610994565b610868600b5460ff165b90565b610868600d5481565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630fd1f94e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6108685b62012cc86101cc565b61086860043560008160001415610dc65750600161084f565b6108686004356024356000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b61099860085461ffff166101cc565b61086860026101cc565b610868600a546101cc565b6108686006546101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6109af60408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610a7d5780601f10610a5257610100808354040283529160200191610a7d565b61086860006000600180610b7b6105cf565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753436040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1d6000600480610c986105cf565b61086860025481565b6108685b620186a06101cc565b6108686004356024355b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506102d09050565b6108686009546101cc565b610a1f600c54600160a060020a031681565b610868600b5462010000900460ff166101cc565b6108686007546101cc565b610a3c600e5460ff1681565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a9d2293d6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600054600160a060020a031681565b610868600080548190600160a060020a039081163390911614610a8957610994565b6108685b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc80635054d98a60036000506040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b61086860015481565b610868600b54610100900460ff166101cc565b61086860035474010000000000000000000000000000000000000000900460e060020a026101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063cc3471af6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600854620100009004600160a060020a03166101cc565b6108686005546101cc565b610a1d604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc809163a0943154916044808301926020929190829003018160008760325a03f215610002575050604051511590506107f157604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091637e9265629160448083019260009291908290030181838760325a03f215610002575050505b565b6108686004356000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753836040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f215610002575050604051519150505b919050565b610a1f600354600160a060020a03166101cc565b60408051918252519081900360200190f35b60045460006002600183161561010002600019019092169190910411156108a45760009150610994565b6108ac6105cf565b9050600081141580156108c0575060018114155b80156108cd575060028114155b156108db5760009150610994565b600480546000828152602060026001841615610100026000190190931692909204601f908101929092047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9081019236929083901061095d5782800160ff198235161785555b5061098d9291505b808211156109945760008155600101610949565b82800160010185558215610941579182015b8281111561094157823582600050559160200191906001019061096f565b5050600191505b5090565b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610a0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311610a6057829003601f168201915b505050505090506101cc565b6004546000600260018316156101000260001901909216919091041115610ab35760009150610994565b610abb6105cf565b905060008114158015610acf575060018114155b8015610adc575060028114155b15610aea5760009150610994565b604080517f7c0278fc000000000000000000000000000000000000000000000000000000008152600360048201818152602483019384523660448401819052731deeda36e15ec9e80f3d7414d67a4803ae45fc8094637c0278fc946000939190606401848480828437820191505094505050505060006040518083038160008760325a03f215610002575050505090565b1415610c8557604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a0316602483015234604483015260648201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091630fee183d916084828101926020929190829003018160008760325a03f21561000257505060405151925050811515610c8a577389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc33346040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515115159050610c8a57610002565b505090565b81925050610994565b505b50565b1415610c93575a9150610cab3383610481565b1515610cb75750610c95565b731deeda36e15ec9e80f3d7414d67a4803ae45fc8063da46be0a60038433610cdd61046e565b610ce5610232565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a031681526020018381526020018281526020019550505050505060006040518083038160008760325a03f21561000257505050610c933360408051600080547fc17e6817000000000000000000000000000000000000000000000000000000008352600160a060020a03908116600484015230163160248301529151731deeda36e15ec9e80f3d7414d67a4803ae45fc809263c17e68179260448082019360209390928390039091019082908760325a03f2156100025750505050565b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a8091040260e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f292505050151561084f5761000256", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000007dd677b54fc954824a7bc49bd26cbdfa12c75adf", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000011f79bd42b0c7c", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000002dfeff8fca5d", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x00000000000000003defb9627dd677b54fc954824a7bc49bd26cbdfa12c75adf", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000000000000000000000000000ba43b7400", + "0x0000000000000000000000000000000000000000000000000000000000000007": "0x00000000000000000000000000000000000000000000000000000000001e8480", + "0x0000000000000000000000000000000000000000000000000000000000000008": "0x000000000000000000000000000000000000000000000000000000000000000a", + "0x000000000000000000000000000000000000000000000000000000000000000a": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000000000b": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000000000c": "0x0000000000000000000000006c8f2a135f6ed072de4503bd7c4999a1a17f824b", + "0x000000000000000000000000000000000000000000000000000000000000000d": "0x000000000000000000000000000000000000000000000000000000000010365c", + "0x000000000000000000000000000000000000000000000000000000000000000e": "0x00000000000000000000000000000000000000000000000000000000000000ff" + } + }, + "0x7c1eb207c07e7ab13cf245585bd03d0fa478d034": { + "balance": "0x0", + "code": "0x650200d2f18c7350606060405236156100a05760e060020a60003504630e9f1a3c81146100a55780632b4096b4146100c95780636ec13982146100eb578063a3119e571461010d578063a749f19b1461012f578063ab7366f714610151578063bacd69581461017f578063bfdf87c0146101c2578063c4144b26146101e1578063caa46c9c1461023c578063e6ce3a6a14610297578063ed5bd7ea146102b6575b610007565b6102d960043560243560008181526001830160205260409020600401545b92915050565b6102d960043560243560008181526001830160205260409020600301546100c3565b6102d960043560243560008181526001830160205260409020600201546100c3565b6102d960043560243560008181526001838101602052604090912001546100c3565b6102d960043560243560008181526001830160205260409020600501546100c3565b6102eb6004356024355b600081815260018301602052604081208054829182918291908614610790576101b9565b6102eb600435602435604435600082815260018401602052604081205481908190819086141561068a576040812060010154851415610680575b50505050505050565b6102d960043560243560008181526001830160205260409020546100c3565b6102d96004356024355b6040805160c08101825260008082526020828101829052828401829052606083018290526080830182905260a08301829052848252600186019052918220805490919083908114156102fb576102f2565b6102d96004356024355b6040805160c08101825260008082526020828101829052828401829052606083018290526080830182905260a08301829052848252600186019052918220805490919083908114156104c0576102f2565b6102d960043560243560443582546000908181811415610a6557610a8c565b6102d96004356024356000818152600183016020526040812060050154116100c3565b60408051918252519081900360200190f35b005b815193505b50505092915050565b60048301546000146103d257600483810154600090815260018881016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015460608201529181015460808301526005015460a082015291505b60608201516000146102ed57606091820151600090815260018781016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015493810193909352600481015460808401526005015460a0830152610364565b600283015460001461045b5750506002810154600081815260018681016020908152604092839020835160c081018552865481529286015491830191909152918101929092526003830154606083015260048301546080830152600583015460a08301525b81516003820154141561044d57805493506102f2565b600281015460001415610464575b600093506102f2565b6040805160c08101825282548152600183810154602083810191909152600285015483850181905260038601546060850152600486015460808501526005959095015460a0840152600094855290890190529120909150610437565b600383015460001461059757600383810154600090815260018881016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252918101546060830152600481015460808301526005015460a082015291505b60808201516000146102ed57608091820151600090815260018781016020908152604092839020835160c081018552815481529281015491830191909152600281015492820192909252600382015460608201526004820154938101939093526005015460a0830152610529565b600283015460001461045b5750506002810154600081815260018681016020908152604092839020835160c081018552865481529286015491830191909152918101929092526003830154606083015260048301546080830152600583015460a08301525b81516004820154141561061257805493506102f2565b6002810154600014156106245761045b565b6040805160c08101825282548152600183810154602083810191909152600285015483850181905260038601546060850152600486015460808501526005959095015460a08401526000948552908901905291209091506105fc565b61068a878761015b565b86546000925082141561069b578587555b508554600090815260018701602052604090205b8054600014156107255785815560028101829055600181018590556101b987875b60008181526001830160205260408120905b8154610d8e9085905b60008181526001830160205260408082206004810154835281832060059081015460038301548552929093209092015403905b5092915050565b60018101548154925085126107625760048101546000141561074957600481018690555b60040154600090815260018701602052604090206106af565b60038101546000141561077757600381018690555b60030154600090815260018701602052604090206106af565b600381015460001415806107a957506004810154600014155b156107cf576003810154600014610826578054600188019060009061083b908a90610246565b6002810154600014610a285760028101546000908152600188016020526040902060038101548254919550141561080857600060038501555b60048401548154141561081d57600060048501555b83549150610a2d565b80546001880190600090610852908a906101eb565b815260208101919091526040016000209450610865565b8152602081019190915260400160002094505b600285015460009081526001880160205260409020600381015486549195509092508214156108b9576004850154600385018190556000146108b95760048501546000908152604090208454600282015592505b60048401548554141561091357600385015460048501819055600014610913578660010160005060008660030160005054815260200190815260200160002060005092508250836000016000505483600201600050819055505b60028082015490860181905560001461098457866001016000506000826002016000505481526020019081526020016000206000509350835080600001600050548460030160005054141561096a57845460038501555b60048401548154141561097f57845460048501555b610989565b845487555b6003818101549086018190556000146109d6578660010160005060008260030160005054815260200190815260200160002060005092508250846000016000505483600201600050819055505b600481810154908601819055600014610a23578660010160005060008260040160005054815260200190815260200160002060005092508250846000016000505483600201600050819055505b610a2d565b600087555b6000808255600182018190556002820181905560038201819055600482018190556005820181905582146101b9576101b987836106d0565b50600081815260018601602052604090205b6001810154610a95908686610ad4565b805492505b50509392505050565b15610b915760fa60020a600f02851480610ab6575060f060020a613c3d0285145b15610af157600481015460001415610b3a5780549250610a8c565b86865b600060f960020a601f02831415610ce357508083135b9392505050565b60f960020a601f02851480610b0d575060f060020a613e3d0285145b80610b1f575060f060020a613d3d0285145b15610b9157600381015460001415610bc85780549250610a8c565b610b73610ad1878360040160005054600081815260018301602052604081205b600381015460001415610d61576001810154915061071e565b15610a87576004015460009081526001860160205260409020610a77565b60fa60020a600f02851480610bad575060f060020a613c3d0285145b15610c1f57600381015460001415610c565760009250610a8c565b610c01610ad1878360030160005054600081815260018301602052604081205b600481015460001415610d48576001810154915061071e565b15610a87576003015460009081526001860160205260409020610a77565b60f960020a601f02851480610c3b575060f060020a613e3d0285145b15610c6f57600481015460001415610ca25760009250610a8c565b6003015460009081526001860160205260409020610a77565b60f060020a613d3d02851415610cde57600181015484901215610cbb57600481015460001415610ca25760009250610a8c565b6004015460009081526001860160205260409020610a77565b600181015484901315610cde57600381015460001415610c565760009250610a8c565b610a77565b60fa60020a600f02831415610cfb5750808312610aea565b60f060020a613e3d02831415610d15575080831215610aea565b60f060020a613c3d02831415610d2f575080831315610aea565b60f060020a613d3d028314156100a05750828114610aea565b6004015460009081526001840160205260409020610be8565b6003015460009081526001840160205260409020610b5a565b600282015460001415610fbd575b50505050565b90508060021415610e2657610daa8483600301600050546106eb565b6000191415610dc457610dc4848360030160005054610dfe565b8154610e269085905b60008181526001830160205260408120600381015490919081908190811415610ffb57610007565b8154610e5a9085905b60008181526001830160205260408120600481015490919081908190811415610e7f57610007565b806001191415610e5a57610e418483600401600050546106eb565b60011415610df557610df5848360040160005054610dcd565b8060001913158015610e6d575060018113155b15610d7a578154610d7a908590610f7a565b6004840180546000908152600188016020526040812060028088015490820181905592829055945014610f0f57856001016000506000856002016000505481526020019081526020016000206000509150836000016000505482600301600050541415610efa57826000016000505482600301600050819055505b835460048301541415610f0f57825460048301555b6003830154600014610f40575060038201546000908152600186016020526040902080546004850155835460028201555b82546002808601919091558454600385015583015460001415610f7157826000016000505486600001600050819055505b8354610fe69087905b6000818152600183016020526040808220600381015483528183206005908101546004830154855292842001549092610fd99291908183106110fa5750816100c3565b60029091015460009081526001840160205260409020906106e2565b6001016005820155505050565b8254610ff3908790610f7a565b505050505050565b600384018054600090815260018801602052604081206002808801549082018190559282905594501461108b5785600101600050600085600201600050548152602001908152602001600020600050915083600001600050548260030160005054141561107657826000016000505482600301600050819055505b83546004830154141561108b57825460048301555b60048301546000146110bd57506004820154600081815260018701602052604090206003850191909155835460028201555b82546002808601919091558454600485015583015460001415610f7157826000016000505486600001600050819055508354610fe6908790610f7a565b50806100c356" + }, + "0x7dd677b54fc954824a7bc49bd26cbdfa12c75adf": { + "balance": "0xd7a58f5b73b4b6c4", + "code": "0x606060405236156100985760e060020a60003504633896002781146100e15780633defb962146100ea5780633f4be8891461010c5780634136aa351461011f5780634a420138146101a057806369c1a7121461028c5780638129fc1c146102955780638da5cb5b146102a6578063ae45850b146102b8578063af3309d8146102cc578063ea8a1af0146102d5578063ead50da3146102f4575b610308671bc16d674ec8000030600160a060020a03163110156100df57600554604051600160a060020a03918216916000913091909116319082818181858883f150505050505b565b61030a60005481565b610308671bc16d674ec8000030600160a060020a031631101561040f576100df565b61031c600454600160a060020a03165b90565b61030a5b600080548190118015610199575060408051600480547f0a16697a0000000000000000000000000000000000000000000000000000000083529251600160a060020a039390931692630a16697a928083019260209291829003018187876161da5a03f1156100025750506040515160ff01431090505b905061011c565b6103085b600354600554604080517f8c0e156d0000000000000000000000000000000000000000000000000000000081527f3defb96200000000000000000000000000000000000000000000000000000000600482015260a060020a90920461ffff1643016024830152621e8480604483015251600092600160a060020a031691638c0e156d916729a2241af62c000091606481810192602092909190829003018185886185025a03f1156100025750506040515192600160a060020a0384161491506102899050576004805473ffffffffffffffffffffffffffffffffffffffff1916821790555b50565b61030a60015481565b61030860008054146103f2576100df565b61031c600554600160a060020a031681565b61031c600354600160a060020a031661011c565b61030a60025481565b610308600554600160a060020a03908116339091161461035157610002565b61033960055460a060020a900461ffff1681565b005b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b6004546000600160a060020a03919091163111156103c75760408051600480547fea8a1af00000000000000000000000000000000000000000000000000000000083529251600160a060020a03939093169263ea8a1af0928083019260009291829003018183876161da5a03f115610002575050505b600554604051600160a060020a03918216916000913091909116319082818181858883f15050505050565b426000556100df6101a4565b600280546001908101909155429055565b600454600160a060020a03908116339091161461042b576100df565b610433610123565b151561043e576100df565b6103fe6101a456", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000056be5b99", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000056d0009b", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000008b", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000006c8f2a135f6ed072de4503bd7c4999a1a17f824b", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000001e0d3cda913deb6f67967b99d67acdfa1712c293601" + } + }, + "0x89efe605e9ecbe22849cd85d5449cc946c26f8f3": { + "balance": "0x0", + "code": "0x650200d2f18c73506060604052361561007f5760e060020a600035046312c82bcc81146100845780635548c837146100a55780635c54305e146101015780636b103966146101555780637fcf532c14610189578063b1df3d80146101d5578063b5bc6dbb146101ee578063c6ab451414610225578063e62af6c114610293575b610007565b6102c56004356024356000620186a05a10156103855761030083835a610232565b6102d760043560243560443581600160a060020a031683600160a060020a03167f47a08955ce2b7f21ea62ff0024e1ea0ad87430953554a87e6bc65d777f18e639836040518082815260200191505060405180910390a3505050565b6102d760043560243560443560408051838152602081018390528151600160a060020a038616927f9b24879829bed3003de08d5c5d7e18dcbb8dc76faebd95cafc5d4dec8c61a3a5928290030190a2505050565b6102d76004356024356044355b600160a060020a03821660009081526020849052604090205480820110156102d957610007565b6102d7600435602435604080518281529051600160a060020a038416917fd0c5cf41ee8ebf084ad0bce53de7cbc6e4693d9b53a4019ca36a2f91cdc20b3a919081900360200190a25050565b6102c560043560243560443560006102fc848484610162565b6102c5600435602435604435600160a060020a03821660009081526020849052604081205482901061032b576103338484846102a0565b6102c56004356024356044355b60006000831180156102605750604051600160a060020a038516908290859082818181858883f19350505050155b156102fc57604051600160a060020a03851690839085906000818181858888f1935050505015156102fc57506000610300565b6102d76004356024356044355b600160a060020a03821660009081526020849052604090205481111561030757610007565b60408051918252519081900360200190f35b005b600160a060020a0382166000908152602084905260409020805482019055505050565b5060015b9392505050565b600160a060020a038216600090815260208490526040902080548290039055505050565b506000610300565b604051600160a060020a03841690600090849082818181858883f1935050505015156102fc57604051600160a060020a038416908390600081818185876185025a03f19250505015156102fc57610007565b6103008383620186a061023256" + }, + "0xb834e3edfc1a927bdcecb67a9d0eccbd752a5bb3": { + "balance": "0xffe9b09a5c474dca", + "nonce": "975", + "code": "0x" + }, + "0xd3cda913deb6f67967b99d67acdfa1712c293601": { + "balance": "0x4f5807198e238f13e", + "nonce": "283", + "code": "0x" + }, + "0xe54d323f9ef17c1f0dede47ecc86a9718fe5ea34": { + "balance": "0x0", + "code": "0x650200d2f18c7350606060405236156100ab5760e060020a600035046326a7985a81146100b057806350d4e411146100be57806354fd4d501461023d578063586a69fa1461025d5780638e46afa91461026857806396cff3df14610272578063971c803f1461029657806398c9cdf4146102a157806398e00e54146102ae578063b152f19e146102b8578063c0f68859146102c4578063e3042c0f146102cf578063ea27a88114610461575b610007565b6102845b60006104cb6102a5565b604080516020601f60843560048181013592830184900484028501840190955281845261047f948035946024803595604435956064359560a494930191819084018382808284375094965050933593505060c43591505060e435610104356101243561014435610164356101843560006101806040519081016040528060008152602001600081526020016000815260200160206040519081016040528060008152602001508152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200150610180604051908101604052808f81526020018e81526020018d81526020018c81526020018981526020018b81526020018a81526020018881526020018781526020018681526020018581526020018481526020015090506104d48f825b600060006000600a43018460e0015110156105de577f544f4f5f534f4f4e0000000000000000000000000000000000000000000000009150610524565b604080516000808252600760208301528183015290519081900360600190f35b61049c5b6103e85b90565b6104b460ff610265565b62030d403a0260026024356004350102015b60408051918252519081900360200190f35b61049c5b600a610265565b6102845b62030d40610265565b6102846010610265565b61028443600a01610265565b6102845b6020610265565b60408051808201825261047f916004803592909160649190602490600290839083908082843780516020601f608435808c01359182018390048302840183019094528083529499983598975060a49650909450910191908190840183828082843750506040805160c0818101909252959796359660c435969095506101a49450925060e491506006908390839080828437509095505050505050604080516101808181018352600080835260208381018290528385018290528451908101855281815260608401526080830181905260a0830181905260c0830181905260e0830181905261010083018190526101208301819052610140830181905261016083018190528351918201909352808984505181526020018960015060209081015182528101899052604081018890526060018484505181526020810187905260408101869052606001846001506020908101518252018460025060400151815260200184600350606001518152602001846004506080015181526020018460055060a00151905290506104e78982610200565b6102846004356024356044356064355b3a0291909201600202010190565b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b6040805160ff929092168252519081900360200190f35b45039050610265565b9f9e505050505050505050505050505050565b9998505050505050505050565b8461016001511015610524577f494e53554646494349454e545f46554e4453000000000000000000000000000091505b600082146106ed576040805185518482529151600160a060020a0392909216917f513485fc54ef019ef1bc1ea683ef7d5d522f2865224ae10871ff992749c0ba4f9181900360200190a27389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc85600001518661016001516040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f215610007575050505b505092915050565b8360c0015161ffff166105ef61029a565b61ffff1611806106115750610602610261565b61ffff168460c0015161ffff16115b1561063e577f535441434b5f434845434b5f4f55545f4f465f52414e474500000000000000009150610524565b6106466102c8565b8460a0015160ff16101561067c577f47524143455f544f4f5f53484f525400000000000000000000000000000000009150610524565b6106846102a5565b84610100015110806106a157506106996100b4565b846101000151115b156106ce577f52455155495245445f4741535f4f55545f4f465f52414e4745000000000000009150610524565b6104f48461012001518561014001518660800151876101000151610471565b83610160015184600001518560e001518660a001518760200151886040015189606001518a608001518b61010001518c60c001518d61012001518e6101400151604051611078806108fa833901808c600160a060020a031681526020018b81526020018a60ff16815260200189600160a060020a03168152602001888152602001806020018781526020018681526020018561ffff1681526020018481526020018381526020018281038252888181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156107ec5780820380516001836020036101000a031916815260200191505b509c505050505050505050505050506040518091039082f090509050737c1eb207c07e7ab13cf245585bd03d0fa478d03463bacd69588683600160a060020a031660010284600160a060020a0316630a16697a6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000757505050604051805190602001506040518460e060020a02815260040180848152602001838152602001828152602001935050505060006040518083038160008760325a03f21561000757505060408051600160a060020a038416815290517f2b05d346f0b0b9fd470024751c52d3b5dac5c37796f077c1a66241f2eada44b792509081900360200190a18092506105d656606060405260405161107838038061107883398101604052805160805160a05160c05160e05161010051610120516101405161016051610180516101a051999a98999798969795969490940194929391929091908a84848a8a8a8a88886101008051600c8054600160a060020a031990811633179091556000805482168d1781556001868155600286815560078e90556008805461ffff19168e1790553a600655600380547c01000000000000000000000000000000000000000000000000000000008d04740100000000000000000000000000000000000000000260a060020a63ffffffff0219919096168e17169490941790935588516004805493819052956020601f9385161590910260001901909316939093048101919091047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b908101939091608091909101908390106101ee57805160ff19168380011785555b5061017a9291505b8082111561021e5760008155600101610166565b5050826003600050600201600050819055505050505050505050508a600060006101000a815481600160a060020a030219169083021790555089600d6000508190555088600e60006101000a81548160ff021916908302179055505050505050505050505050610e56806102226000396000f35b8280016001018555821561015e579182015b8281111561015e578251826000505591602001919060010190610200565b509056606060405236156101a05760e060020a60003504630924120081146101c25780630a16697a146101cf5780630fd1f94e146101d8578063137c638b1461022e57806321835af61461023b57806324032866146102545780632f95b833146102d65780633017fe24146102e55780633233c686146102ef57806337f4c00e146102fa5780634500054f146103055780634e417a98146103785780634e71d92d146103e15780634f059a43146103f35780636146195414610451578063625cc4651461046157806367ce940d1461046a5780637d298ee314610477578063830953ab146104f9578063938b5f321461050457806395ee122114610516578063974654f41461052a578063a06db7dc14610535578063a9d2293d14610541578063ae45850b14610597578063b0f07e44146105a9578063c19d93fb146105cb578063c6502da81461062e578063c680362214610637578063ca94692d1461064a578063cc3471af14610673578063d379be23146106c9578063d62457f6146106e3578063ea8a1af0146106ee578063f5562753146107f3578063f6b4dfb414610854575b610868600080548190600160a060020a03908116339091161461087a57610994565b610868600b5460ff165b90565b610868600d5481565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630fd1f94e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6108685b62012cc86101cc565b61086860043560008160001415610dc65750600161084f565b6108686004356024356000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b61099860085461ffff166101cc565b61086860026101cc565b610868600a546101cc565b6108686006546101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6109af60408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610a7d5780601f10610a5257610100808354040283529160200191610a7d565b61086860006000600180610b7b6105cf565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753436040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1d6000600480610c986105cf565b61086860025481565b6108685b620186a06101cc565b6108686004356024355b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506102d09050565b6108686009546101cc565b610a1f600c54600160a060020a031681565b610868600b5462010000900460ff166101cc565b6108686007546101cc565b610a3c600e5460ff1681565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a9d2293d6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600054600160a060020a031681565b610868600080548190600160a060020a039081163390911614610a8957610994565b6108685b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc80635054d98a60036000506040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b61086860015481565b610868600b54610100900460ff166101cc565b61086860035474010000000000000000000000000000000000000000900460e060020a026101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063cc3471af6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600854620100009004600160a060020a03166101cc565b6108686005546101cc565b610a1d604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc809163a0943154916044808301926020929190829003018160008760325a03f215610002575050604051511590506107f157604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091637e9265629160448083019260009291908290030181838760325a03f215610002575050505b565b6108686004356000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753836040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f215610002575050604051519150505b919050565b610a1f600354600160a060020a03166101cc565b60408051918252519081900360200190f35b60045460006002600183161561010002600019019092169190910411156108a45760009150610994565b6108ac6105cf565b9050600081141580156108c0575060018114155b80156108cd575060028114155b156108db5760009150610994565b600480546000828152602060026001841615610100026000190190931692909204601f908101929092047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9081019236929083901061095d5782800160ff198235161785555b5061098d9291505b808211156109945760008155600101610949565b82800160010185558215610941579182015b8281111561094157823582600050559160200191906001019061096f565b5050600191505b5090565b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610a0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311610a6057829003601f168201915b505050505090506101cc565b6004546000600260018316156101000260001901909216919091041115610ab35760009150610994565b610abb6105cf565b905060008114158015610acf575060018114155b8015610adc575060028114155b15610aea5760009150610994565b604080517f7c0278fc000000000000000000000000000000000000000000000000000000008152600360048201818152602483019384523660448401819052731deeda36e15ec9e80f3d7414d67a4803ae45fc8094637c0278fc946000939190606401848480828437820191505094505050505060006040518083038160008760325a03f215610002575050505090565b1415610c8557604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a0316602483015234604483015260648201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091630fee183d916084828101926020929190829003018160008760325a03f21561000257505060405151925050811515610c8a577389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc33346040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515115159050610c8a57610002565b505090565b81925050610994565b505b50565b1415610c93575a9150610cab3383610481565b1515610cb75750610c95565b731deeda36e15ec9e80f3d7414d67a4803ae45fc8063da46be0a60038433610cdd61046e565b610ce5610232565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a031681526020018381526020018281526020019550505050505060006040518083038160008760325a03f21561000257505050610c933360408051600080547fc17e6817000000000000000000000000000000000000000000000000000000008352600160a060020a03908116600484015230163160248301529151731deeda36e15ec9e80f3d7414d67a4803ae45fc809263c17e68179260448082019360209390928390039091019082908760325a03f2156100025750505050565b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a8091040260e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f292505050151561084f5761000256" + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "ethash": {} + } + }, + "context": { + "number": "1062503", + "difficulty": "13700504019867", + "timestamp": "1456480446", + "gasLimit": "3141592", + "miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226" + }, + "input": "0xf86b8203cf850ba43b740083200b2094741467b251fca923d6229c4b439078b55dca233b8084614619541ca078293714f69a810356f1ee29dc686ec2ca3a0e5448e1ef6322c77369ebdd26c2a01c3836fa363548959554ee5360361be9db4aea9eb7c31f61550f0e9a10138adf", + "tracerConfig": { + "diffMode": true + }, + "result": { + "pre": { + "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { + "balance": "0x98e1c608601c2496b2", + "nonce": 218916 + }, + "0x6c8f2a135f6ed072de4503bd7c4999a1a17f824b": { + "balance": "0x0", + "nonce": 237, + "code": "0x6060604052361561027c5760e060020a600035046301991313811461027e57806303d22885146102ca5780630450991814610323578063049ae734146103705780630ce46c43146103c35780630e85023914610602578063112e39a8146106755780631b4fa6ab146106c25780631e74a2d3146106d057806326a7985a146106fd5780633017fe2414610753578063346cabbc1461075c578063373a1bc3146107d55780633a9e74331461081e5780633c2c21a01461086e5780633d9ce89b146108ba578063480b70bd1461092f578063481078431461097e57806348f0518714610a0e5780634c471cde14610a865780634db3da8314610b09578063523ccfa814610b4f578063586a69fa14610be05780635a9f2def14610c3657806364ee49fe14610caf57806367beaccb14610d055780636840246014610d74578063795b9a6f14610dca5780637b55c8b514610e415780637c73f84614610ee15780638c0e156d14610f145780638c1d01c814610f605780638e46afa914610f69578063938c430714610fc0578063971c803f146111555780639772c982146111ac57806398c9cdf41461122857806398e00e541461127f5780639f927be7146112d5578063a00aede914611383578063a1c0539d146113d3578063aff21c6514611449578063b152f19e14611474578063b549793d146114cb578063b5b33eda1461154b578063bbc6eb1f1461159b578063c0f68859146115ab578063c3a2c0c314611601578063c43d05751461164b578063d8e5c04814611694578063dbfef71014611228578063e29fb547146116e7578063e6470fbe1461173a578063ea27a8811461174c578063ee77fe86146117d1578063f158458c14611851575b005b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387876020604051908101604052806000815260200150612225610f6d565b61188260043560243560443560643560843560a43560c435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338b8a6020604051908101604052806000815260200150896125196106c6565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503385600060e060020a026020604051908101604052806000815260200150611e4a610f6d565b611882600435602435604435606435608435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503389896020604051908101604052806000815260200150886124e86106c6565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750506040805160a08082019092529597963596608435969095506101449450925060a491506005908390839080828437509095505050505050604080518082018252600160a060020a03338116825288166020820152815160c0810190925260009173e54d323f9ef17c1f0dede47ecc86a9718fe5ea349163e3042c0f91600191908a908a9089908b90808b8b9090602002015181526020018b60016005811015610002579090602002015181526020018b60026005811015610002579090602002015181526020018b60036005811015610002579090602002015181526020018b6004600581101561000257909060200201518152602001348152602001506040518860e060020a02815260040180888152602001876002602002808383829060006004602084601f0104600f02600301f150905001868152602001806020018560ff1681526020018461ffff168152602001836006602002808383829060006004602084601f0104600f02600301f1509050018281038252868181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156105d25780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038160008760325a03f2156100025750506040515191506124cd9050565b60408051602060248035600481810135601f81018590048502860185019096528585526118829581359591946044949293909201918190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808787611e64610f6d565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611d28610f6d565b61189f5b6000611bf8611159565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881600060005054611a9561159f565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346326a7985a6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b6118b760075b90565b604080516020606435600481810135601f8101849004840285018401909552848452611882948135946024803595604435956084949201919081908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160013389898861224b610f6d565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503386866020604051908101604052806000815260200150611e64610f6d565b611882600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333896020604051908101604052806000815260200150886123bc6106c6565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387866020604051908101604052806000815260200150611f8d610f6d565b60408051602060248035600481810135601f810185900485028601850190965285855261188295813595919460449492939092019181908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808888612225610f6d565b611882600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503388886020604051908101604052806000815260200150612388610f6d565b611882600435604080517fc4144b2600000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a03831660248201529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163c4144b26916044818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b604080516020604435600481810135601f81018490048402850184019095528484526118829481359460248035959394606494929391019181908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133888888612238610f6d565b604080516020604435600481810135601f810184900484028501840190955284845261188294813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a43560c435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338b8b8b896126536106c6565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333866020604051908101604052806000815260200150611e4a610f6d565b6118b76004355b604080517fed5bd7ea00000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a03831660248201529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163ed5bd7ea916044818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b61189f600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463586a69fa6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f81018590048502860185019096528585526118829581359591946044949293909201918190840183828082843750949650509335935050606435915050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808989612388610f6d565b61188260043560243560443560643560843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338a896020604051908101604052806000815260200150886124d76106c6565b6040805160206004803580820135601f8101849004840285018401909552848452611882949193602493909291840191908190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808587611e4a610f6d565b61188260043560243560443560643560843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338a8a60206040519081016040528060008152602001508961262d6106c6565b604080516020606435600481810135601f810184900484028501840190955284845261188294813594602480359560443595608494920191908190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338888876120c7610f6d565b604080516020604435600481810135601f81018490048402850184019095528484526118829481359460248035959394606494929391019181908401838280828437505060408051608080820190925295979635969561010495509350608492508591508390839080828437509095505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338989898961263a6106c6565b6118b7600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881858585611ba361122c565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050333388602060405190810160405280600081526020015061236e610f6d565b6118b760005481565b6118c95b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea34638e46afa96040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f8101859004850286018501909652858552611882958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a43560c43560e43561010435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600160005033338e8e8d8f8e8e8e8e8e346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156111195780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519b9a5050505050505050505050565b61189f5b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463971c803f6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750949650509335935050608435915050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338989896123a2610f6d565b6118b75b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346398c9cdf46040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346398e00e546040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b611882600435604080517fe6ce3a6a000000000000000000000000000000000000000000000000000000008152600160048201527f3e3d0000000000000000000000000000000000000000000000000000000000006024820152604481018390529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163e6ce3a6a916064818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503385600060e060020a0260206040519081016040528060008152602001506121ef610f6d565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338787876120b5610f6d565b6118b7600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a88183611b4561159f565b6118b75b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463b152f19e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f8101859004850286018501909652858552611882958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808b8b8961262d6106c6565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503386600060e060020a026020604051908101604052806000815260200150612200610f6d565b6118b75b60005460649004610759565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463c0f688596040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b611882600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611bff610f6d565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333876020604051908101604052806000815260200150612200610f6d565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387600060e060020a026020604051908101604052806000815260200150612213610f6d565b611882600435602435604435606435608435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600160005033338a60206040519081016040528060008152602001508961250c6106c6565b61027c6000600060006118e033610b56565b6118b7600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881868686866040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b949350505050565b604080516020604435600481810135601f810184900484028501840190955284845261188294813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338a8a8a886124fa6106c6565b6118b7600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a88184846000611b4f61122c565b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b60408051918252519081900360200190f35b6040805160ff929092168252519081900360200190f35b15611a905733925082600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fc6803622000000000000000000000000000000000000000000000000000000008252915191945063c680362291600482810192602092919082900301816000876161da5a03f11561000257505060405151905080156119d1575082600160a060020a031663d379be236040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151600160a060020a03166000141590505b80156119dd5750600082115b80156119ec5750600054600190115b15611a90578183600160a060020a031663830953ab6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040515160640291909104915050604281118015611a4d5750600054829011155b15611a675760008054612710612711909102049055611a90565b602181108015611a7a5750600054829010155b15611a90576000805461271061270f9091020490555b505050565b6000611a9f61122c565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f2156100025750506040515191506107599050565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b919050565b6000611af261122c565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b9392505050565b9050610759565b611c076106c6565b6000611c11611478565b611c1961122c565b600054611c2461159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611cf25780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f2156100025750506040515191506107599050565b611d306106c6565b60008b611d3b61122c565b600054611d4661159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611e145780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611b409050565b611e526106c6565b6000611e5c611478565b611d3b61122c565b611e6c6106c6565b6000611e76611478565b611e7e61122c565b600054611e8961159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611f575780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611b9d9050565b611f956106c6565b8b611f9e611478565b611fa661122c565b600054611fb161159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561207f5780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611bf19050565b6120bd6106c6565b6000611f9e611478565b6120cf6106c6565b8b6120d8611478565b6120e061122c565b6000546120eb61159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156121b95780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f2156100025750506040515191506117c99050565b6121f76106c6565b8b611e76611478565b6122086106c6565b60008b611e7e61122c565b61221b6106c6565b8a8c611fa661122c565b61222d6106c6565b60008b611fa661122c565b6122406106c6565b60008b6120e061122c565b6122536106c6565b8c8b61225d61122c565b60005461226861159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156123365780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f21561000257505060405151979650505050505050565b6123766106c6565b60008c8c600060005054611fb161159f565b6123906106c6565b60008c8c6000600050546120eb61159f565b6123aa6106c6565b60008c8c60006000505461226861159f565b60008d8d6000600050546120eb61159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561249c5780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150505b9695505050505050565b8e8d8d6000600050546123ce61159f565b60008d8d60006000505461226861159f565b60008d8d6000600050546123ce61159f565b60008e8e8d61226861159f565b8f8e8e8d61252561159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156125f35780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519998505050505050505050565b60008e8e8d6123ce61159f565b8a5160208c015160408d015160608e015161226861159f565b60008e8e8d61252561159f56", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000011f8119429ed3a", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000f5d861791e76fa01433e0d7421aee565290e4afe", + "0x031b9ec274101cc3ccff4d6d98ef4513742dadbaadba538bff48b88403253234": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x20ef51bb8ea9e8e8d5e2c17d28e47285698893c1017db4b4e40b792358a3dbc7": "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8abd": "0x000000000000000000000000c9a2bfd279fe57e7651e5d9f29bb1793c9a1cf01", + "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8abf": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", + "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8ac2": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dfb": "0x000000000000000000000000f5d861791e76fa01433e0d7421aee565290e4afe", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dfc": "0x00000000000000000000000000000000000000000000000000000000000f6897", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dfe": "0x0000000000000000000000002859ddf2877c46d54e67b6becdb1cafb8ef4a458", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dff": "0x000000000000000000000000b7df3c43a8b13ecf45777c267404e15c7cdb04c9", + "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794e00": "0x0000000000000000000000000000000000000000000000000000000000000008", + "0x3b20a4b931bc4ae9450774ee52b8f5da1b248d23e61cd20c09b25662f73894fd": "0x0000000000000000000000000000000000000000000000000000000000000006", + "0x3b99aee1e3090227401ac2055c861246ca6ec62f426b4b4d74df88510f841b89": "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef711": "0x000000000000000000000000a4d91b341f0e9a7000be916a668408b463f4c38c", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef712": "0x0000000000000000000000000000000000000000000000000000000000102ce9", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef713": "0x000000000000000000000000fd97a0d81cc92eecd52452831930b27889925ef0", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef714": "0x00000000000000000000000016917c151bb1399852a0741eb7b317b443e2cfa3", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef715": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef716": "0x0000000000000000000000000000000000000000000000000000000000000004", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a3fe": "0x000000000000000000000000c5ef24ec3bf0e3522cfc8e53f3e076b043547ce1", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a3ff": "0x00000000000000000000000000000000000000000000000000000000000fff67", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a400": "0x000000000000000000000000b7df3c43a8b13ecf45777c267404e15c7cdb04c9", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a401": "0x00000000000000000000000010fc2e8ba5f40336c3576ffaa25177f1cdedf836", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a402": "0x000000000000000000000000fd97a0d81cc92eecd52452831930b27889925ef0", + "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a403": "0x0000000000000000000000000000000000000000000000000000000000000006", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5ba": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bb": "0x000000000000000000000000000000000000000000000000000000000010347b", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bc": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bd": "0x000000000000000000000000c9a2bfd279fe57e7651e5d9f29bb1793c9a1cf01", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5be": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bf": "0x0000000000000000000000000000000000000000000000000000000000000002", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826a7": "0x000000000000000000000000b7df3c43a8b13ecf45777c267404e15c7cdb04c9", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826a8": "0x00000000000000000000000000000000000000000000000000000000000fe13d", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826a9": "0x000000000000000000000000f5d861791e76fa01433e0d7421aee565290e4afe", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826aa": "0x00000000000000000000000063110531142fb314118164ff579ba52746504408", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826ab": "0x000000000000000000000000c5ef24ec3bf0e3522cfc8e53f3e076b043547ce1", + "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826ac": "0x0000000000000000000000000000000000000000000000000000000000000007", + "0xccd2cbc946692be8ade97db99353304e3af0fa6202f93649d4e185ad8b1f385c": "0x0000000000000000000000000000000000000000000000000000000000000004", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4ef": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f0": "0x00000000000000000000000000000000000000000000000000000000001030b3", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f1": "0x000000000000000000000000a4d91b341f0e9a7000be916a668408b463f4c38c", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f2": "0x000000000000000000000000dd87a67740c2acf48a31829783a095a81c3628d9", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f3": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f4": "0x0000000000000000000000000000000000000000000000000000000000000003", + "0xdabde47554d6a6cfcff3c968abb145f298585fafa9e24c10fc526269794bd626": "0x0000000000000000000000000000000000000000000000000000000000000003", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64db7": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64db8": "0x000000000000000000000000000000000000000000000000000000000010365c", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64db9": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64dbc": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdec": "0x000000000000000000000000fd97a0d81cc92eecd52452831930b27889925ef0", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bded": "0x0000000000000000000000000000000000000000000000000000000000101dc2", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdee": "0x000000000000000000000000c5ef24ec3bf0e3522cfc8e53f3e076b043547ce1", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdef": "0x000000000000000000000000173243e117a6382211b1ac91eeb262f4a7021c16", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdf0": "0x000000000000000000000000a4d91b341f0e9a7000be916a668408b463f4c38c", + "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdf1": "0x0000000000000000000000000000000000000000000000000000000000000005" + } + }, + "0x741467b251fca923d6229c4b439078b55dca233b": { + "balance": "0x29c613529e8218f8", + "code": "0x606060405236156101a05760e060020a60003504630924120081146101c25780630a16697a146101cf5780630fd1f94e146101d8578063137c638b1461022e57806321835af61461023b57806324032866146102545780632f95b833146102d65780633017fe24146102e55780633233c686146102ef57806337f4c00e146102fa5780634500054f146103055780634e417a98146103785780634e71d92d146103e15780634f059a43146103f35780636146195414610451578063625cc4651461046157806367ce940d1461046a5780637d298ee314610477578063830953ab146104f9578063938b5f321461050457806395ee122114610516578063974654f41461052a578063a06db7dc14610535578063a9d2293d14610541578063ae45850b14610597578063b0f07e44146105a9578063c19d93fb146105cb578063c6502da81461062e578063c680362214610637578063ca94692d1461064a578063cc3471af14610673578063d379be23146106c9578063d62457f6146106e3578063ea8a1af0146106ee578063f5562753146107f3578063f6b4dfb414610854575b610868600080548190600160a060020a03908116339091161461087a57610994565b610868600b5460ff165b90565b610868600d5481565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630fd1f94e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6108685b62012cc86101cc565b61086860043560008160001415610dc65750600161084f565b6108686004356024356000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b61099860085461ffff166101cc565b61086860026101cc565b610868600a546101cc565b6108686006546101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6109af60408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610a7d5780601f10610a5257610100808354040283529160200191610a7d565b61086860006000600180610b7b6105cf565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753436040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1d6000600480610c986105cf565b61086860025481565b6108685b620186a06101cc565b6108686004356024355b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506102d09050565b6108686009546101cc565b610a1f600c54600160a060020a031681565b610868600b5462010000900460ff166101cc565b6108686007546101cc565b610a3c600e5460ff1681565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a9d2293d6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600054600160a060020a031681565b610868600080548190600160a060020a039081163390911614610a8957610994565b6108685b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc80635054d98a60036000506040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b61086860015481565b610868600b54610100900460ff166101cc565b61086860035474010000000000000000000000000000000000000000900460e060020a026101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063cc3471af6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600854620100009004600160a060020a03166101cc565b6108686005546101cc565b610a1d604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc809163a0943154916044808301926020929190829003018160008760325a03f215610002575050604051511590506107f157604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091637e9265629160448083019260009291908290030181838760325a03f215610002575050505b565b6108686004356000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753836040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f215610002575050604051519150505b919050565b610a1f600354600160a060020a03166101cc565b60408051918252519081900360200190f35b60045460006002600183161561010002600019019092169190910411156108a45760009150610994565b6108ac6105cf565b9050600081141580156108c0575060018114155b80156108cd575060028114155b156108db5760009150610994565b600480546000828152602060026001841615610100026000190190931692909204601f908101929092047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9081019236929083901061095d5782800160ff198235161785555b5061098d9291505b808211156109945760008155600101610949565b82800160010185558215610941579182015b8281111561094157823582600050559160200191906001019061096f565b5050600191505b5090565b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610a0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311610a6057829003601f168201915b505050505090506101cc565b6004546000600260018316156101000260001901909216919091041115610ab35760009150610994565b610abb6105cf565b905060008114158015610acf575060018114155b8015610adc575060028114155b15610aea5760009150610994565b604080517f7c0278fc000000000000000000000000000000000000000000000000000000008152600360048201818152602483019384523660448401819052731deeda36e15ec9e80f3d7414d67a4803ae45fc8094637c0278fc946000939190606401848480828437820191505094505050505060006040518083038160008760325a03f215610002575050505090565b1415610c8557604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a0316602483015234604483015260648201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091630fee183d916084828101926020929190829003018160008760325a03f21561000257505060405151925050811515610c8a577389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc33346040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515115159050610c8a57610002565b505090565b81925050610994565b505b50565b1415610c93575a9150610cab3383610481565b1515610cb75750610c95565b731deeda36e15ec9e80f3d7414d67a4803ae45fc8063da46be0a60038433610cdd61046e565b610ce5610232565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a031681526020018381526020018281526020019550505050505060006040518083038160008760325a03f21561000257505050610c933360408051600080547fc17e6817000000000000000000000000000000000000000000000000000000008352600160a060020a03908116600484015230163160248301529151731deeda36e15ec9e80f3d7414d67a4803ae45fc809263c17e68179260448082019360209390928390039091019082908760325a03f2156100025750505050565b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a8091040260e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f292505050151561084f5761000256", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000007dd677b54fc954824a7bc49bd26cbdfa12c75adf", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000011f79bd42b0c7c", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000002dfeff8fca5d", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x00000000000000003defb9627dd677b54fc954824a7bc49bd26cbdfa12c75adf", + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000000000000000000000000000ba43b7400", + "0x0000000000000000000000000000000000000000000000000000000000000007": "0x00000000000000000000000000000000000000000000000000000000001e8480", + "0x0000000000000000000000000000000000000000000000000000000000000008": "0x000000000000000000000000000000000000000000000000000000000000000a", + "0x000000000000000000000000000000000000000000000000000000000000000c": "0x0000000000000000000000006c8f2a135f6ed072de4503bd7c4999a1a17f824b", + "0x000000000000000000000000000000000000000000000000000000000000000d": "0x000000000000000000000000000000000000000000000000000000000010365c", + "0x000000000000000000000000000000000000000000000000000000000000000e": "0x00000000000000000000000000000000000000000000000000000000000000ff" + } + }, + "0x7dd677b54fc954824a7bc49bd26cbdfa12c75adf": { + "balance": "0xd7a58f5b73b4b6c4", + "code": "0x606060405236156100985760e060020a60003504633896002781146100e15780633defb962146100ea5780633f4be8891461010c5780634136aa351461011f5780634a420138146101a057806369c1a7121461028c5780638129fc1c146102955780638da5cb5b146102a6578063ae45850b146102b8578063af3309d8146102cc578063ea8a1af0146102d5578063ead50da3146102f4575b610308671bc16d674ec8000030600160a060020a03163110156100df57600554604051600160a060020a03918216916000913091909116319082818181858883f150505050505b565b61030a60005481565b610308671bc16d674ec8000030600160a060020a031631101561040f576100df565b61031c600454600160a060020a03165b90565b61030a5b600080548190118015610199575060408051600480547f0a16697a0000000000000000000000000000000000000000000000000000000083529251600160a060020a039390931692630a16697a928083019260209291829003018187876161da5a03f1156100025750506040515160ff01431090505b905061011c565b6103085b600354600554604080517f8c0e156d0000000000000000000000000000000000000000000000000000000081527f3defb96200000000000000000000000000000000000000000000000000000000600482015260a060020a90920461ffff1643016024830152621e8480604483015251600092600160a060020a031691638c0e156d916729a2241af62c000091606481810192602092909190829003018185886185025a03f1156100025750506040515192600160a060020a0384161491506102899050576004805473ffffffffffffffffffffffffffffffffffffffff1916821790555b50565b61030a60015481565b61030860008054146103f2576100df565b61031c600554600160a060020a031681565b61031c600354600160a060020a031661011c565b61030a60025481565b610308600554600160a060020a03908116339091161461035157610002565b61033960055460a060020a900461ffff1681565b005b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b6004546000600160a060020a03919091163111156103c75760408051600480547fea8a1af00000000000000000000000000000000000000000000000000000000083529251600160a060020a03939093169263ea8a1af0928083019260009291829003018183876161da5a03f115610002575050505b600554604051600160a060020a03918216916000913091909116319082818181858883f15050505050565b426000556100df6101a4565b600280546001908101909155429055565b600454600160a060020a03908116339091161461042b576100df565b610433610123565b151561043e576100df565b6103fe6101a456", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000056be5b99", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000056d0009b", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000008b", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000006c8f2a135f6ed072de4503bd7c4999a1a17f824b", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000001e0d3cda913deb6f67967b99d67acdfa1712c293601" + } + }, + "0xb834e3edfc1a927bdcecb67a9d0eccbd752a5bb3": { + "balance": "0xffe9b09a5c474dca", + "nonce": 975 + }, + "0xd3cda913deb6f67967b99d67acdfa1712c293601": { + "balance": "0x4f5807198e238f13e", + "nonce": 283 + } + }, + "post": { + "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { + "balance": "0x98e2b02f14529b1eb2" + }, + "0x651913977e8140c323997fce5e03c19e0015eebf": { + "balance": "0x29a2241af62c0000", + "code": "0x606060405236156101a05760e060020a60003504630924120081146101c25780630a16697a146101cf5780630fd1f94e146101d8578063137c638b1461022e57806321835af61461023b57806324032866146102545780632f95b833146102d65780633017fe24146102e55780633233c686146102ef57806337f4c00e146102fa5780634500054f146103055780634e417a98146103785780634e71d92d146103e15780634f059a43146103f35780636146195414610451578063625cc4651461046157806367ce940d1461046a5780637d298ee314610477578063830953ab146104f9578063938b5f321461050457806395ee122114610516578063974654f41461052a578063a06db7dc14610535578063a9d2293d14610541578063ae45850b14610597578063b0f07e44146105a9578063c19d93fb146105cb578063c6502da81461062e578063c680362214610637578063ca94692d1461064a578063cc3471af14610673578063d379be23146106c9578063d62457f6146106e3578063ea8a1af0146106ee578063f5562753146107f3578063f6b4dfb414610854575b610868600080548190600160a060020a03908116339091161461087a57610994565b610868600b5460ff165b90565b610868600d5481565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630fd1f94e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6108685b62012cc86101cc565b61086860043560008160001415610dc65750600161084f565b6108686004356024356000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b61099860085461ffff166101cc565b61086860026101cc565b610868600a546101cc565b6108686006546101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6109af60408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610a7d5780601f10610a5257610100808354040283529160200191610a7d565b61086860006000600180610b7b6105cf565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753436040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1d6000600480610c986105cf565b61086860025481565b6108685b620186a06101cc565b6108686004356024355b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506102d09050565b6108686009546101cc565b610a1f600c54600160a060020a031681565b610868600b5462010000900460ff166101cc565b6108686007546101cc565b610a3c600e5460ff1681565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a9d2293d6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600054600160a060020a031681565b610868600080548190600160a060020a039081163390911614610a8957610994565b6108685b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc80635054d98a60036000506040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b61086860015481565b610868600b54610100900460ff166101cc565b61086860035474010000000000000000000000000000000000000000900460e060020a026101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063cc3471af6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600854620100009004600160a060020a03166101cc565b6108686005546101cc565b610a1d604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc809163a0943154916044808301926020929190829003018160008760325a03f215610002575050604051511590506107f157604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091637e9265629160448083019260009291908290030181838760325a03f215610002575050505b565b6108686004356000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753836040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f215610002575050604051519150505b919050565b610a1f600354600160a060020a03166101cc565b60408051918252519081900360200190f35b60045460006002600183161561010002600019019092169190910411156108a45760009150610994565b6108ac6105cf565b9050600081141580156108c0575060018114155b80156108cd575060028114155b156108db5760009150610994565b600480546000828152602060026001841615610100026000190190931692909204601f908101929092047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9081019236929083901061095d5782800160ff198235161785555b5061098d9291505b808211156109945760008155600101610949565b82800160010185558215610941579182015b8281111561094157823582600050559160200191906001019061096f565b5050600191505b5090565b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610a0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311610a6057829003601f168201915b505050505090506101cc565b6004546000600260018316156101000260001901909216919091041115610ab35760009150610994565b610abb6105cf565b905060008114158015610acf575060018114155b8015610adc575060028114155b15610aea5760009150610994565b604080517f7c0278fc000000000000000000000000000000000000000000000000000000008152600360048201818152602483019384523660448401819052731deeda36e15ec9e80f3d7414d67a4803ae45fc8094637c0278fc946000939190606401848480828437820191505094505050505060006040518083038160008760325a03f215610002575050505090565b1415610c8557604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a0316602483015234604483015260648201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091630fee183d916084828101926020929190829003018160008760325a03f21561000257505060405151925050811515610c8a577389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc33346040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515115159050610c8a57610002565b505090565b81925050610994565b505b50565b1415610c93575a9150610cab3383610481565b1515610cb75750610c95565b731deeda36e15ec9e80f3d7414d67a4803ae45fc8063da46be0a60038433610cdd61046e565b610ce5610232565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a031681526020018381526020018281526020019550505050505060006040518083038160008760325a03f21561000257505050610c933360408051600080547fc17e6817000000000000000000000000000000000000000000000000000000008352600160a060020a03908116600484015230163160248301529151731deeda36e15ec9e80f3d7414d67a4803ae45fc809263c17e68179260448082019360209390928390039091019082908760325a03f2156100025750505050565b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a8091040260e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f292505050151561084f5761000256", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000007dd677b54fc954824a7bc49bd26cbdfa12c75adf", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000011f8119429ed3a", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000002e002d006b55", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x00000000000000003defb9627dd677b54fc954824a7bc49bd26cbdfa12c75adf", + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000000000000000000000000000ba43b7400", + "0x0000000000000000000000000000000000000000000000000000000000000007": "0x00000000000000000000000000000000000000000000000000000000001e8480", + "0x0000000000000000000000000000000000000000000000000000000000000008": "0x000000000000000000000000000000000000000000000000000000000000000a", + "0x000000000000000000000000000000000000000000000000000000000000000c": "0x0000000000000000000000006c8f2a135f6ed072de4503bd7c4999a1a17f824b", + "0x000000000000000000000000000000000000000000000000000000000000000d": "0x0000000000000000000000000000000000000000000000000000000000103847", + "0x000000000000000000000000000000000000000000000000000000000000000e": "0x00000000000000000000000000000000000000000000000000000000000000ff" + } + }, + "0x6c8f2a135f6ed072de4503bd7c4999a1a17f824b": { + "nonce": 238, + "storage": { + "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8abf": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", + "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef715": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bc": "0x000000000000000000000000a4d91b341f0e9a7000be916a668408b463f4c38c", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bd": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", + "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bf": "0x0000000000000000000000000000000000000000000000000000000000000003", + "0x99d5294a34e2d6d560a223237786adc8b5651c09094b9ecd56e6ae7abc2a2751": "0x000000000000000000000000651913977e8140c323997fce5e03c19e0015eebf", + "0x99d5294a34e2d6d560a223237786adc8b5651c09094b9ecd56e6ae7abc2a2752": "0x0000000000000000000000000000000000000000000000000000000000103847", + "0x99d5294a34e2d6d560a223237786adc8b5651c09094b9ecd56e6ae7abc2a2753": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b", + "0x99d5294a34e2d6d560a223237786adc8b5651c09094b9ecd56e6ae7abc2a2756": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f1": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f3": "0x000000000000000000000000c9a2bfd279fe57e7651e5d9f29bb1793c9a1cf01", + "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f4": "0x0000000000000000000000000000000000000000000000000000000000000002", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64dbb": "0x000000000000000000000000651913977e8140c323997fce5e03c19e0015eebf", + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64dbc": "0x0000000000000000000000000000000000000000000000000000000000000002" + } + }, + "0x741467b251fca923d6229c4b439078b55dca233b": { + "balance": "0x0", + "storage": { + "0x000000000000000000000000000000000000000000000000000000000000000b": "0x0000000000000000000000000000000000000000000000000000000000000101" + } + }, + "0x7dd677b54fc954824a7bc49bd26cbdfa12c75adf": { + "balance": "0xd6c5f42b8502a0e3", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000056d020be", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000008c", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x000000000000000000000000651913977e8140c323997fce5e03c19e0015eebf" + } + }, + "0xb834e3edfc1a927bdcecb67a9d0eccbd752a5bb3": { + "balance": "0x10002e64ebd492a46", + "nonce": 976 + }, + "0xd3cda913deb6f67967b99d67acdfa1712c293601": { + "balance": "0x4f5809f97e1c8bb9b" + } + } + } +} 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 new file mode 100644 index 000000000000..4fd7df37a9b4 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/simple.json @@ -0,0 +1,106 @@ +{ + "context": { + "difficulty": "3502894804", + "gasLimit": "4722976", + "miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724", + "number": "2289806", + "timestamp": "1513601314" + }, + "genesis": { + "alloc": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "code": "0x", + "nonce": "22", + "storage": {} + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "code": "0x", + "nonce": "29072", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3509749784", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "4727564", + "hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada", + "nonce": "0x4eb12e19c16d43da", + "number": "2289805", + "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", + "timestamp": "1513601261", + "totalDifficulty": "7143276353481064" + }, + "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", + "tracerConfig": { + "diffMode": true + }, + "result": { + "pre": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "nonce": 22 + }, + "0x1585936b53834b021f68cc13eeefdec2efc8e724": { + "balance": "0x0" + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "nonce": 1, + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "nonce": 29072 + } + }, + "post": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x6f05b59d3b20000" + }, + "0x1585936b53834b021f68cc13eeefdec2efc8e724": { + "balance": "0x420eed1bd6c00" + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d869a3b70062eb9bd5", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b95e" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d7725724a9044b75", + "nonce": 29073 + } + } + } +} 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 new file mode 100644 index 000000000000..5021bda192cb --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/suicide.json @@ -0,0 +1,107 @@ +{ + "genesis": { + "difficulty": "5697691613344", + "extraData": "0xd783010202844765746887676f312e342e32856c696e7578", + "gasLimit": "3141592", + "hash": "0x2004021ae3545cf8abba1ec97a7e401157cee9e847131e2f4c75ce38610040cc", + "miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5", + "mixHash": "0x651f01d13fb801c602e1544ab80b3bc32888ea40ef298efa52ec3df983b558ee", + "nonce": "0xdf23f0da925518a6", + "number": "422908", + "stateRoot": "0xd914c6440edf9f4a6f997a9b3ecb6e1a9ca2310f74b0b6890c0d0d4a3c28e4d3", + "timestamp": "1445530335", + "totalDifficulty": "2148894717741690476", + "alloc": { + "0x2861bf89b6c640c79040d357c1e9513693ef5d3f": { + "balance": "0x0", + "code": "0x606060405236156100825760e060020a600035046312055e8f8114610084578063185061da146100b157806322beb9b9146100d5578063245a03ec146101865780633fa4f245146102a657806341c0e1b5146102af578063890eba68146102cb578063b29f0835146102de578063d6b4485914610308578063dd012a15146103b9575b005b6001805474ff0000000000000000000000000000000000000000191660a060020a60043502179055610082565b6100826001805475ff00000000000000000000000000000000000000000019169055565b61008260043560015460e060020a6352afbc3302606090815230600160a060020a039081166064527fb29f0835000000000000000000000000000000000000000000000000000000006084527fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060a45243840160c490815260ff60a060020a85041660e452600061010481905291909316926352afbc339261012492918183876161da5a03f1156100025750505050565b6100826004356024356001547fb0f07e440000000000000000000000000000000000000000000000000000000060609081526064839052600160a060020a039091169063b0f07e449060849060009060248183876161da5a03f150604080516001547f73657449742875696e74323536290000000000000000000000000000000000008252825191829003600e018220878352835192839003602001832060e060020a6352afbc33028452600160a060020a03308116600486015260e060020a9283900490920260248501526044840152438901606484015260a060020a820460ff1694830194909452600060a483018190529251931694506352afbc33935060c48181019391829003018183876161da5a03f115610002575050505050565b6103c460025481565b61008260005433600160a060020a039081169116146103ce575b565b6103c460015460a860020a900460ff1681565b6100826001805475ff000000000000000000000000000000000000000000191660a860020a179055565b61008260043560015460e060020a6352afbc3302606090815230600160a060020a039081166064527f185061da000000000000000000000000000000000000000000000000000000006084527fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060a45243840160c490815260ff60a060020a85041660e452600061010481905291909316926352afbc339261012492918183876161da5a03f1156100025750505050565b600435600255610082565b6060908152602090f35b6001547f6ff96d17000000000000000000000000000000000000000000000000000000006060908152600160a060020a0330811660645290911690632e1a7d4d908290636ff96d17906084906020906024816000876161da5a03f1156100025750506040805180517f2e1a7d4d0000000000000000000000000000000000000000000000000000000082526004820152905160248281019350600092829003018183876161da5a03f115610002575050600054600160a060020a03169050ff", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000d3cda913deb6f67967b99d67acdfa1712c293601", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000ff30c9e568f133adce1f1ea91e189613223fc461b9" + } + }, + "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { + "balance": "0x326601cc6cf364f6b9", + "nonce": "12122", + "code": "0x" + }, + "0x30c9e568f133adce1f1ea91e189613223fc461b9": { + "balance": "0x8b83c417dd78000", + "nonce": "2", + "code": "0x606060405236156102ea5760e060020a6000350463022bc71f81146102f757806303d6d7b61461037f578063086ae9e4146103ec57806309c975df146104595780631145a20f146104c657806312d67c5f146104e75780631302188c146104f15780631ae460e5146104fc57806323306ed614610573578063234917d4146105ca57806329917954146106375780632a472ae81461071d5780632e1a7d4d1461078a578063306b031d1461087f57806333613cbe1461089d57806334c19b93146108c257806335b281531461092f5780633664a0ea146109b85780633c941423146109c35780633cbfed7414610a3b57806350a3bd3914610a4957806352afbc3314610a735780635539d40014610c2a5780635a5383ac14610c3e57806360b831e514610cb55780636164947214610d7f578063685c234a14610d8a5780636ffc089614610de0578063741b3c3914610e4d5780637542861514610ed25780637772a38014610f5557806377b19cd514610ff057806378bc64601461105d5780638b37e656146110ca5780638baced64146111375780638dd5e298146111b157806393423e9c146111de57806394d2b21b1461120257806394f3f81d1461121657806398e00e54146112665780639f927be7146112bc578063a502aae81461136a578063a6c01cfd146113e8578063a9743c68146113fa578063aa4cc01f14611467578063b010d94a146114d4578063b0171fa41461154e578063b0ac4c8c146115cc578063b0f07e4414611635578063b35594601461171c578063c0f6885914611739578063c3daab961461178f578063c630f92b146117bb578063c831391d146117e5578063cd062734146117f0578063d0e30db01461185d578063db681e5414611865578063e40986551461190c578063e850f3ae14611979578063ed2b8e0b146119e6578063f340fa01146119f1578063f828c3fa14611ae8578063f8b1185314611b07578063f9f447eb14611b24578063fc30052214611b91578063fcf3691814611bfe575b6112645b611c86336119f8565b611c88600435604080517fc4144b260000000000000000000000000000000000000000000000000000000081526010600482015260248101839052905160009173ce642b6a82e72147ceade0e72c786ba8eaeb31d79163c4144b26916044818101926020929091908290030181878760325a03f2156100025750506040515191506108989050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b637d613b346000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63da40fd616000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611c9a60043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63c68efc486000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b61126460043560243560443560643560843561200185858585856000610a89565b611c886004545b90565b611c886005546104ee565b611c886040805160e160020a6333f8a36702815260066004820152600160a060020a0333166024820152905160009173c895c144d0b0f88417cf9e14e03e6abc82c0af3f916367f146ce916044818101926020929091908290030181878760325a03f2156100025750506040515191506104ee9050565b611c885b60007327b1b436e4699a012cc8698e33c8f3e1c035c28b6323306ed66040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506104ee9050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63e99a66856000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611264604080517f317c152d00000000000000000000000000000000000000000000000000000000815260066004820152600160a060020a0333166024820152905160009173c895c144d0b0f88417cf9e14e03e6abc82c0af3f9163317c152d916044818101926020929091908290030181878760325a03f2156100025750506040805180517ff1173928000000000000000000000000000000000000000000000000000000008252600160a060020a0333166004830152602482018190529151919363f1173928926044838101938290030181838760325a03f2156100025750505050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63707378396000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611264600435604080517fb5bc6dbb00000000000000000000000000000000000000000000000000000000815260126004820152600160a060020a033316602482015260448101839052905173d3cb18959b0435864ff33010fa83be60afc04b229163b5bc6dbb916064828101926020929190829003018160008760325a03f21561000257505060405151159050611d255773d3cb18959b0435864ff33010fa83be60afc04b22637fcf532c33836040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060006040518083038160008760325a03f21561000257505050611ae5565b611c886004356000818152600e60205260409020600201545b919050565b611c886004355b600160a060020a0381166000908152600f6020526040902054610898565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63fc4730126000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611264600435604080517fa95d3e76000000000000000000000000000000000000000000000000000000008152600060048201819052600160a060020a0384811660248401523316604483015291517327b1b436e4699a012cc8698e33c8f3e1c035c28b9263a95d3e7692606481810193918290030181838760325a03f2156100025750505050565b611c886002546104ee565b611c9a60043560243560007327b1b436e4699a012cc8698e33c8f3e1c035c28b6398213db6600060005085856040518460e060020a02815260040180848152602001838152602001828152602001935050505060206040518083038160008760325a03f215610002575050604051519150610dda9050565b611c886000611e0a336108a4565b611264600073c895c144d0b0f88417cf9e14e03e6abc82c0af3f635748147e600633611ec2610577565b61126460043560243560443560643560843560a4355b604080517ff1924efb000000000000000000000000000000000000000000000000000000008152600060048201819052600160a060020a03338116602484015289166044830152606482018890526084820187905260a4820186905260ff851660c483015260e48201849052915182917327b1b436e4699a012cc8698e33c8f3e1c035c28b9163f1924efb91610104818101926020929091908290030181878760325a03f2156100025750506040805180517f5a1230bf000000000000000000000000000000000000000000000000000000008252600160a060020a0333811660048401528c166024830152604482018b9052606482018a90526084820189905260ff881660a483015260c482018790529151919450635a1230bf9160e48083019260209291908290030181878760325a03f215610002575050604051519183149050612008577327b1b436e4699a012cc8698e33c8f3e1c035c28b6318b753ab82846040518360e060020a028152600401808381526020018281526020019250505060006040518083038160008760325a03f21561000257505050612056565b611c9a600154600160a060020a03166104ee565b611c886040805160e560020a6304b47bb902815260066004820152600160a060020a0333166024820152905160009173c895c144d0b0f88417cf9e14e03e6abc82c0af3f9163968f7720916044818101926020929091908290030181878760325a03f2156100025750506040515191506104ee9050565b6112646004357327b1b436e4699a012cc8698e33c8f3e1c035c28b637e853f3d600060005083336040518460e060020a0281526004018084815260200183815260200182600160a060020a03168152602001935050505060206040518083038160008760325a03f21561000257505060405151159050611ae5577327b1b436e4699a012cc8698e33c8f3e1c035c28b63ab2af349826040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f2156100025750505050565b611c886008546104ee565b611c88600435602435604080516c01000000000000000000000000600160a060020a03858116820283528416026014820152815160289181900391909101902060009081526015602052205460ff165b92915050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63b506054f6000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611264604080517f068e3ef100000000000000000000000000000000000000000000000000000000815260066004820152600160a060020a0333166024820152346044820152905173c895c144d0b0f88417cf9e14e03e6abc82c0af3f9163068e3ef19160648281019260009291908290030181838760325a03f21561000257505050565b611cb76004356040805160208181018352600080835284815260138252838120600d0154815260148252835190849020805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015611fb85780601f10611f8d57610100808354040283529160200191611fb8565b611c886004356024355b604080517fa163a32500000000000000000000000000000000000000000000000000000000815260066004820152600160a060020a038416602482015260448101839052905160009173c895c144d0b0f88417cf9e14e03e6abc82c0af3f9163a163a325916064818101926020929091908290030181878760325a03f215610002575050604051519150610dda9050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63775f20f96000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b637517a7c96000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611c9a60043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63250687836000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611c886004356040805160e160020a6333f8a36702815260066004820152600160a060020a0383166024820152905160009173c895c144d0b0f88417cf9e14e03e6abc82c0af3f916367f146ce916044818101926020929091908290030181878760325a03f2156100025750506040515191506108989050565b611c88600435600073c895c144d0b0f88417cf9e14e03e6abc82c0af3f6354e37911600684611e6d610577565b611c88600435600160a060020a038116600090815260126020526040902054610898565b611c9a600054600160a060020a03166104ee565b604080516c01000000000000000000000000600435600160a060020a0390811682028352331602601482015281516028918190039190910190206000908152601560205220805460ff191690555b005b611c8860007327b1b436e4699a012cc8698e33c8f3e1c035c28b6398e00e546040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506104ee9050565b611c88600435604080517fe6ce3a6a000000000000000000000000000000000000000000000000000000008152601060048201527f3e3d000000000000000000000000000000000000000000000000000000000000602482015260448101839052905160009173ce642b6a82e72147ceade0e72c786ba8eaeb31d79163e6ce3a6a916064818101926020929091908290030181878760325a03f2156100025750506040515191506108989050565b611c88604080517f8f00e61a00000000000000000000000000000000000000000000000000000000815260066004820152905160009173c895c144d0b0f88417cf9e14e03e6abc82c0af3f91638f00e61a916024818101926020929091908290030181878760325a03f2156100025750506040515191506104ee9050565b611c886004356000611e113383610f5f565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63dd382dd36000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63aebd65476000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611c886004356040805160e560020a6304b47bb902815260066004820152600160a060020a0383166024820152905160009173c895c144d0b0f88417cf9e14e03e6abc82c0af3f9163968f7720916044818101926020929091908290030181878760325a03f2156100025750506040515191506108989050565b611c88604080517fc75e8f8800000000000000000000000000000000000000000000000000000000815260066004820152905160009173c895c144d0b0f88417cf9e14e03e6abc82c0af3f9163c75e8f88916024818101926020929091908290030181878760325a03f2156100025750506040515191506104ee9050565b611cb760408051602081810183526000825282516003805460026000196001831615610100020190911604601f81018490048402830184019095528482529293909291830182828015611fef5780601f10611fc457610100808354040283529160200191611fef565b611264604080517fa89713750000000000000000000000000000000000000000000000000000000081526000600482018181526024830193845236604484018190527327b1b436e4699a012cc8698e33c8f3e1c035c28b9463a89713759484939190606401848480828437820191505094505050505060006040518083038160008760325a03f215610002575050604080516005547f321f45840000000000000000000000000000000000000000000000000000000082526004820152905163321f4584916024818101926000929091908290030181838760325a03f21561000257505050565b611c886004356000818152600e6020526040902060030154610898565b611c8860007327b1b436e4699a012cc8698e33c8f3e1c035c28b63c0f688596040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506104ee9050565b61126460043573c895c144d0b0f88417cf9e14e03e6abc82c0af3f63dd8abb6c60063384611db7610577565b611c88600073c895c144d0b0f88417cf9e14e03e6abc82c0af3f6354e37911600633611e18610577565b611c886007546104ee565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63125935846000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b6112646102ee565b611c886004356000818152601360209081526040805181842060038101546004828101547f38f4c9eb0000000000000000000000000000000000000000000000000000000085526006918501919091526024840182905260ff160160448301529151919273c895c144d0b0f88417cf9e14e03e6abc82c0af3f926338f4c9eb9260648181019392918290030181888760325a03f21561000257505060405151949350505050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63fae644646000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63b3a5e2556000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611c886006546104ee565b6112646004355b604080517fb1df3d8000000000000000000000000000000000000000000000000000000000815260126004820152600160a060020a0383166024820152346044820152905173d3cb18959b0435864ff33010fa83be60afc04b229163b1df3d80916064828101926020929190829003018160008760325a03f215610002575050604080517f5548c837000000000000000000000000000000000000000000000000000000008152600160a060020a033381166004830152841660248201523460448201529051635548c837916064818101926000929091908290030181838760325a03f215610002575050505b50565b611264600435602435604435606435611ffb8484848460ff6000610a89565b611c886004356000818152600e6020526040902060010154610898565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b63c9abdb7c6000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611c8860043560007327b1b436e4699a012cc8698e33c8f3e1c035c28b6386b0aac96000600050846040518360e060020a028152600401808381526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515191506108989050565b611264600435604080517f25fea09900000000000000000000000000000000000000000000000000000000815260006004820181905260248201849052600160a060020a033316604483015291517327b1b436e4699a012cc8698e33c8f3e1c035c28b926325fea09992606481810193918290030181838760325a03f2156100025750505050565b565b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611d175780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600160a060020a0333166000818152601260205260408051818320547f5c54305e00000000000000000000000000000000000000000000000000000000825260048201949094526024810185905260448101939093525173d3cb18959b0435864ff33010fa83be60afc04b2292635c54305e9260648281019391928290030181838760325a03f2156100025750505050565b6040518560e060020a0281526004018085815260200184600160a060020a0316815260200183815260200182815260200194505050505060006040518083038160008760325a03f2156100025750505050565b90506104ee565b9050610898565b6040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506104ee9050565b6040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506108989050565b6040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040805180517f6a704d7b000000000000000000000000000000000000000000000000000000008252600160a060020a033316600483015260248201819052915191935073c895c144d0b0f88417cf9e14e03e6abc82c0af3f9250636a704d7b9160448281019260009291908290030181838760325a03f2156100025750505050565b820191906000526020600020905b815481529060010190602001808311611f9b57829003601f168201915b50505050509050610898565b820191906000526020600020905b815481529060010190602001808311611fd257829003601f168201915b505050505090506104ee565b50505050565b5050505050565b7327b1b436e4699a012cc8698e33c8f3e1c035c28b635ca1bad5826040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f215610002575050505b505050505050505056", + "storage": { + "0x18b039f13c5f33908f0960616cb3e44029c716366508c54d555096d6e1fa5145": "0x00000000000000000000000000000000000000000000000008b83c417dd78000" + } + }, + "0xd3cb18959b0435864ff33010fa83be60afc04b22": { + "balance": "0x0", + "code": "0x650105e11e10f850606060405236156100695760e060020a60003504635548c837811461006e5780635c54305e146100ca5780636b1039661461011e5780637fcf532c14610152578063b1df3d801461019e578063b5bc6dbb146101b7578063e62af6c1146101ee575b610007565b61022060043560243560443581600160a060020a031683600160a060020a03167f47a08955ce2b7f21ea62ff0024e1ea0ad87430953554a87e6bc65d777f18e639836040518082815260200191505060405180910390a3505050565b61022060043560243560443560408051838152602081018390528151600160a060020a038616927f9b24879829bed3003de08d5c5d7e18dcbb8dc76faebd95cafc5d4dec8c61a3a5928290030190a2505050565b6102206004356024356044355b600160a060020a038216600090815260208490526040902054808201101561023457610007565b610220600435602435604080518281529051600160a060020a038416917fd0c5cf41ee8ebf084ad0bce53de7cbc6e4693d9b53a4019ca36a2f91cdc20b3a919081900360200190a25050565b610222600435602435604435600061025784848461012b565b610222600435602435604435600160a060020a0382166000908152602084905260408120548290106102865761028e8484846101fb565b6102206004356024356044355b600160a060020a03821660009081526020849052604090205481111561026257610007565b005b60408051918252519081900360200190f35b600160a060020a0382166000908152602084905260409020805482019055505050565b5060015b9392505050565b600160a060020a038216600090815260208490526040902080548290039055505050565b50600061025b565b604051600160a060020a03841690600090849082818181858883f19350505050151561025757604051600160a060020a038416908390600081818185876185025a03f19250505015156102575761000756" + }, + "0xd3cda913deb6f67967b99d67acdfa1712c293601": { + "balance": "0x1ff0509d9d6821e26", + "nonce": "138", + "code": "0x" + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "ethash": {} + } + }, + "context": { + "number": "422909", + "difficulty": "5694909537365", + "timestamp": "1445530357", + "gasLimit": "3141592", + "miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226" + }, + "input": "0xf86a818a850ba43b7400832d8a40942861bf89b6c640c79040d357c1e9513693ef5d3f808441c0e1b51ca0b8de64a9a04d699f5938efa5431ca7c80500f6accb329da43aadabd4eab84f17a035b969c198f694be991a2a5b287250e19e852efd0ccba30bd50707277bfbc9aa", + "tracerConfig": { + "diffMode": true + }, + "result": { + "pre": { + "0x2861bf89b6c640c79040d357c1e9513693ef5d3f": { + "balance": "0x0", + "code": "0x606060405236156100825760e060020a600035046312055e8f8114610084578063185061da146100b157806322beb9b9146100d5578063245a03ec146101865780633fa4f245146102a657806341c0e1b5146102af578063890eba68146102cb578063b29f0835146102de578063d6b4485914610308578063dd012a15146103b9575b005b6001805474ff0000000000000000000000000000000000000000191660a060020a60043502179055610082565b6100826001805475ff00000000000000000000000000000000000000000019169055565b61008260043560015460e060020a6352afbc3302606090815230600160a060020a039081166064527fb29f0835000000000000000000000000000000000000000000000000000000006084527fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060a45243840160c490815260ff60a060020a85041660e452600061010481905291909316926352afbc339261012492918183876161da5a03f1156100025750505050565b6100826004356024356001547fb0f07e440000000000000000000000000000000000000000000000000000000060609081526064839052600160a060020a039091169063b0f07e449060849060009060248183876161da5a03f150604080516001547f73657449742875696e74323536290000000000000000000000000000000000008252825191829003600e018220878352835192839003602001832060e060020a6352afbc33028452600160a060020a03308116600486015260e060020a9283900490920260248501526044840152438901606484015260a060020a820460ff1694830194909452600060a483018190529251931694506352afbc33935060c48181019391829003018183876161da5a03f115610002575050505050565b6103c460025481565b61008260005433600160a060020a039081169116146103ce575b565b6103c460015460a860020a900460ff1681565b6100826001805475ff000000000000000000000000000000000000000000191660a860020a179055565b61008260043560015460e060020a6352afbc3302606090815230600160a060020a039081166064527f185061da000000000000000000000000000000000000000000000000000000006084527fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060a45243840160c490815260ff60a060020a85041660e452600061010481905291909316926352afbc339261012492918183876161da5a03f1156100025750505050565b600435600255610082565b6060908152602090f35b6001547f6ff96d17000000000000000000000000000000000000000000000000000000006060908152600160a060020a0330811660645290911690632e1a7d4d908290636ff96d17906084906020906024816000876161da5a03f1156100025750506040805180517f2e1a7d4d0000000000000000000000000000000000000000000000000000000082526004820152905160248281019350600092829003018183876161da5a03f115610002575050600054600160a060020a03169050ff", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000d3cda913deb6f67967b99d67acdfa1712c293601", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000ff30c9e568f133adce1f1ea91e189613223fc461b9" + } + }, + "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { + "balance": "0x326601cc6cf364f6b9", + "nonce": 12122 + }, + "0xd3cda913deb6f67967b99d67acdfa1712c293601": { + "balance": "0x1ff0509d9d6821e26", + "nonce": 138 + } + }, + "post": { + "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { + "balance": "0x326604ee5f5eecd2b9" + }, + "0xd3cda913deb6f67967b99d67acdfa1712c293601": { + "balance": "0x1ff01e7e76afa4226", + "nonce": 139 + } + } + } +} diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go new file mode 100644 index 000000000000..b75d785a0ef7 --- /dev/null +++ b/eth/tracers/internal/tracetest/util.go @@ -0,0 +1,90 @@ +package tracetest + +import ( + "encoding/json" + "reflect" + "strings" + "unicode" + + // Force-load native and js pacakges, to trigger registration + _ "github.com/ethereum/go-ethereum/eth/tracers/js" + _ "github.com/ethereum/go-ethereum/eth/tracers/native" +) + +// To generate a new callTracer test, copy paste the makeTest method below into +// a Geth console and call it with a transaction hash you which to export. + +/* +// makeTest generates a callTracer test by running a prestate reassembled and a +// call trace run, assembling all the gathered information into a test case. +var makeTest = function(tx, rewind) { + // Generate the genesis block from the block, transaction and prestate data + var block = eth.getBlock(eth.getTransaction(tx).blockHash); + var genesis = eth.getBlock(block.parentHash); + + delete genesis.gasUsed; + delete genesis.logsBloom; + delete genesis.parentHash; + delete genesis.receiptsRoot; + delete genesis.sha3Uncles; + delete genesis.size; + delete genesis.transactions; + delete genesis.transactionsRoot; + delete genesis.uncles; + + genesis.gasLimit = genesis.gasLimit.toString(); + genesis.number = genesis.number.toString(); + genesis.timestamp = genesis.timestamp.toString(); + + genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer", rewind: rewind}); + for (var key in genesis.alloc) { + var nonce = genesis.alloc[key].nonce; + if (nonce) { + genesis.alloc[key].nonce = nonce.toString(); + } + } + genesis.config = admin.nodeInfo.protocols.eth.config; + + // Generate the call trace and produce the test input + var result = debug.traceTransaction(tx, {tracer: "callTracer", rewind: rewind}); + delete result.time; + + console.log(JSON.stringify({ + genesis: genesis, + context: { + number: block.number.toString(), + difficulty: block.difficulty, + timestamp: block.timestamp.toString(), + gasLimit: block.gasLimit.toString(), + miner: block.miner, + }, + input: eth.getRawTransaction(tx), + result: result, + }, null, 2)); +} +*/ + +// jsonEqual is similar to reflect.DeepEqual, but does a 'bounce' via json prior to +// comparison +func jsonEqual(xi, yi, xt, yt interface{}) bool { + if xj, err := json.Marshal(xi); err == nil { + json.Unmarshal(xj, xt) + } else { + return false + } + if yj, err := json.Marshal(yi); err == nil { + json.Unmarshal(yj, yt) + } else { + return false + } + return reflect.DeepEqual(xt, yt) +} + +// camel converts a snake cased input string into a camel cased output. +func camel(str string) string { + pieces := strings.Split(str, "_") + for i := 1; i < len(pieces); i++ { + pieces[i] = string(unicode.ToUpper(rune(pieces[i][0]))) + pieces[i][1:] + } + return strings.Join(pieces, "") +} diff --git a/eth/tracers/native/gen_account_json.go b/eth/tracers/native/gen_account_json.go index 25dc77dc7455..070fd7d93ea5 100644 --- a/eth/tracers/native/gen_account_json.go +++ b/eth/tracers/native/gen_account_json.go @@ -15,10 +15,10 @@ var _ = (*accountMarshaling)(nil) // MarshalJSON marshals as JSON. func (a account) MarshalJSON() ([]byte, error) { type account struct { - Balance *hexutil.Big `json:"balance"` - Nonce uint64 `json:"nonce"` - Code hexutil.Bytes `json:"code"` - Storage map[common.Hash]common.Hash `json:"storage"` + Balance *hexutil.Big `json:"balance,omitempty"` + Nonce uint64 `json:"nonce,omitempty"` + Code hexutil.Bytes `json:"code,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` } var enc account enc.Balance = (*hexutil.Big)(a.Balance) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index a40f84952a4c..ff14baaf9c50 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -17,6 +17,7 @@ package native import ( + "bytes" "encoding/json" "math/big" "sync/atomic" @@ -35,12 +36,13 @@ func init() { register("prestateTracer", newPrestateTracer) } -type prestate = map[common.Address]*account +type state = map[common.Address]*account + type account struct { - Balance *big.Int `json:"balance"` - Nonce uint64 `json:"nonce"` - Code []byte `json:"code"` - Storage map[common.Hash]common.Hash `json:"storage"` + Balance *big.Int `json:"balance,omitempty"` + Nonce uint64 `json:"nonce,omitempty"` + Code []byte `json:"code,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` } type accountMarshaling struct { @@ -50,18 +52,38 @@ type accountMarshaling struct { type prestateTracer struct { env *vm.EVM - prestate prestate + pre state + post state create bool to common.Address gasLimit uint64 // Amount of gas bought for the whole tx + config prestateTracerConfig interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption + created map[common.Address]bool + deleted map[common.Address]bool +} + +type prestateTracerConfig struct { + DiffMode bool `json:"diffMode"` // If true, this tracer will return all diff states } -func newPrestateTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { +func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { // First callframe contains tx context info // and is populated on start and end. - return &prestateTracer{prestate: prestate{}}, nil + var config prestateTracerConfig + if cfg != nil { + if err := json.Unmarshal(cfg, &config); err != nil { + return nil, err + } + } + return &prestateTracer{ + pre: state{}, + post: state{}, + config: config, + created: make(map[common.Address]bool), + deleted: make(map[common.Address]bool), + }, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. @@ -72,26 +94,31 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo t.lookupAccount(from) t.lookupAccount(to) + t.lookupAccount(env.Context.Coinbase) // The recipient balance includes the value transferred. - toBal := new(big.Int).Sub(t.prestate[to].Balance, value) - t.prestate[to].Balance = toBal + toBal := new(big.Int).Sub(t.pre[to].Balance, value) + t.pre[to].Balance = toBal // The sender balance is after reducing: value and gasLimit. // We need to re-add them to get the pre-tx balance. - fromBal := new(big.Int).Set(t.prestate[from].Balance) + fromBal := new(big.Int).Set(t.pre[from].Balance) gasPrice := env.TxContext.GasPrice consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit)) fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) - t.prestate[from].Balance = fromBal - t.prestate[from].Nonce-- + t.pre[from].Balance = fromBal + t.pre[from].Nonce-- + + if create && t.config.DiffMode { + t.created[to] = true + } } // CaptureEnd is called after the call finishes to finalize the tracing. func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { - if t.create { + if t.create && !t.config.DiffMode { // Exclude created contract. - delete(t.prestate, t.to) + delete(t.pre, t.to) } } @@ -100,27 +127,34 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, stack := scope.Stack stackData := stack.Data() stackLen := len(stackData) + caller := scope.Contract.Address() switch { case stackLen >= 1 && (op == vm.SLOAD || op == vm.SSTORE): slot := common.Hash(stackData[stackLen-1].Bytes32()) - t.lookupStorage(scope.Contract.Address(), slot) + t.lookupStorage(caller, slot) case stackLen >= 1 && (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT): addr := common.Address(stackData[stackLen-1].Bytes20()) t.lookupAccount(addr) + if op == vm.SELFDESTRUCT { + t.deleted[caller] = true + } case stackLen >= 5 && (op == vm.DELEGATECALL || op == vm.CALL || op == vm.STATICCALL || op == vm.CALLCODE): addr := common.Address(stackData[stackLen-2].Bytes20()) t.lookupAccount(addr) case op == vm.CREATE: - addr := scope.Contract.Address() - nonce := t.env.StateDB.GetNonce(addr) - t.lookupAccount(crypto.CreateAddress(addr, nonce)) + nonce := t.env.StateDB.GetNonce(caller) + addr := crypto.CreateAddress(caller, nonce) + t.lookupAccount(addr) + t.created[addr] = true case stackLen >= 4 && op == vm.CREATE2: offset := stackData[stackLen-2] size := stackData[stackLen-3] init := scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) inithash := crypto.Keccak256(init) salt := stackData[stackLen-4] - t.lookupAccount(crypto.CreateAddress2(scope.Contract.Address(), salt.Bytes32(), inithash)) + addr := crypto.CreateAddress2(caller, salt.Bytes32(), inithash) + t.lookupAccount(addr) + t.created[addr] = true } } @@ -141,12 +175,79 @@ func (t *prestateTracer) CaptureTxStart(gasLimit uint64) { t.gasLimit = gasLimit } -func (t *prestateTracer) CaptureTxEnd(restGas uint64) {} +func (t *prestateTracer) CaptureTxEnd(restGas uint64) { + if !t.config.DiffMode { + return + } + + for addr, state := range t.pre { + // the deleted account's state is pruned + if _, ok := t.deleted[addr]; ok { + continue + } + modified := false + postAccount := &account{Storage: make(map[common.Hash]common.Hash)} + newBalance := t.env.StateDB.GetBalance(addr) + newNonce := t.env.StateDB.GetNonce(addr) + newCode := t.env.StateDB.GetCode(addr) + + if newBalance.Cmp(t.pre[addr].Balance) != 0 { + modified = true + postAccount.Balance = newBalance + } + if newNonce != t.pre[addr].Nonce { + modified = true + postAccount.Nonce = newNonce + } + if !bytes.Equal(newCode, t.pre[addr].Code) { + modified = true + postAccount.Code = newCode + } + + for key, val := range state.Storage { + // don't include the empty slot + if val == (common.Hash{}) { + delete(t.pre[addr].Storage, key) + } + + newVal := t.env.StateDB.GetState(addr, key) + if val != newVal { + modified = true + if newVal != (common.Hash{}) { + postAccount.Storage[key] = newVal + } + } + } + + if modified { + t.post[addr] = postAccount + } else { + // if state is not modified, then no need to include into the pre state + delete(t.pre, addr) + } + } + // the new created contracts' prestate were empty, so delete them + for a := range t.created { + // the created contract maybe exists in statedb before the creating tx + if s := t.pre[a]; s.Balance.Cmp(big.NewInt(0)) == 0 && len(s.Storage) == 0 && len(s.Code) == 0 { + delete(t.pre, a) + } + } +} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). func (t *prestateTracer) GetResult() (json.RawMessage, error) { - res, err := json.Marshal(t.prestate) + var res []byte + var err error + if t.config.DiffMode { + res, err = json.Marshal(struct { + Pre state `json:"pre"` + Post state `json:"post"` + }{t.pre, t.post}) + } else { + res, err = json.Marshal(t.pre) + } if err != nil { return nil, err } @@ -162,10 +263,11 @@ func (t *prestateTracer) Stop(err error) { // lookupAccount fetches details of an account and adds it to the prestate // if it doesn't exist there. func (t *prestateTracer) lookupAccount(addr common.Address) { - if _, ok := t.prestate[addr]; ok { + if _, ok := t.pre[addr]; ok { return } - t.prestate[addr] = &account{ + + t.pre[addr] = &account{ Balance: t.env.StateDB.GetBalance(addr), Nonce: t.env.StateDB.GetNonce(addr), Code: t.env.StateDB.GetCode(addr), @@ -177,8 +279,8 @@ func (t *prestateTracer) lookupAccount(addr common.Address) { // it to the prestate of the given contract. It assumes `lookupAccount` // has been performed on the contract before. func (t *prestateTracer) lookupStorage(addr common.Address, key common.Hash) { - if _, ok := t.prestate[addr].Storage[key]; ok { + if _, ok := t.pre[addr].Storage[key]; ok { return } - t.prestate[addr].Storage[key] = t.env.StateDB.GetState(addr, key) + t.pre[addr].Storage[key] = t.env.StateDB.GetState(addr, key) } From e50aeac4d0904c830dcb3d7439c75e9e8ae56b31 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 6 Oct 2022 16:48:04 +0800 Subject: [PATCH 292/715] eth/traces: add state limit (#25812) This PR introduces a new mechanism in chain tracer for preventing creating too many trace states. The workflow of chain tracer can be divided into several parts: - state creator generates trace state in a thread - state tracer retrieves the trace state and applies the tracing on top in another thread - state collector gathers all result from state tracer and stream to users It's basically a producer-consumer model here, while if we imagine that the state producer generates states too fast, then it will lead to accumulate lots of unused states in memory. Even worse, in path-based state scheme it will only keep the latest 128 states in memory, and the newly generated state will invalidate the oldest one by marking it as stale. The solution for fixing it is to limit the speed of state generation. If there are over 128 states un-consumed in memory, then the creation will be paused until the states are be consumed properly. --- eth/tracers/api.go | 68 ++++++-------- eth/tracers/tracker.go | 109 +++++++++++++++++++++++ eth/tracers/tracker_test.go | 171 ++++++++++++++++++++++++++++++++++++ 3 files changed, 309 insertions(+), 39 deletions(-) create mode 100644 eth/tracers/tracker.go create mode 100644 eth/tracers/tracker_test.go diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 1e04bea411f3..c0d9dfb061f2 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -61,6 +61,11 @@ const ( // For non-archive nodes, this limit _will_ be overblown, as disk-backed tries // will only be found every ~15K blocks or so. defaultTracechainMemLimit = common.StorageSize(500 * 1024 * 1024) + + // maximumPendingTraceStates is the maximum number of states allowed waiting + // for tracing. The creation of trace state will be paused if the unused + // trace states exceed this limit. + maximumPendingTraceStates = 128 ) // StateReleaseFunc is used to deallocate resources held by constructing a @@ -251,30 +256,6 @@ func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, conf return sub, nil } -// releaser is a helper tool responsible for caching the release -// callbacks of tracing state. -type releaser struct { - releases []StateReleaseFunc - lock sync.Mutex -} - -func (r *releaser) add(release StateReleaseFunc) { - r.lock.Lock() - defer r.lock.Unlock() - - r.releases = append(r.releases, release) -} - -func (r *releaser) call() { - r.lock.Lock() - defer r.lock.Unlock() - - for _, release := range r.releases { - release() - } - r.releases = r.releases[:0] -} - // traceChain configures a new tracer according to the provided configuration, and // executes all the transactions contained within. The tracing chain range includes // the end block but excludes the start one. The return value will be one item per @@ -291,11 +272,11 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed threads = blocks } var ( - pend = new(sync.WaitGroup) - ctx = context.Background() - taskCh = make(chan *blockTraceTask, threads) - resCh = make(chan *blockTraceTask, threads) - reler = new(releaser) + pend = new(sync.WaitGroup) + ctx = context.Background() + taskCh = make(chan *blockTraceTask, threads) + resCh = make(chan *blockTraceTask, threads) + tracker = newStateTracker(maximumPendingTraceStates, start.NumberU64()) ) for th := 0; th < threads; th++ { pend.Add(1) @@ -326,8 +307,10 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number())) task.results[i] = &txTraceResult{Result: res} } - // Tracing state is used up, queue it for de-referencing - reler.add(task.release) + // Tracing state is used up, queue it for de-referencing. Note the + // state is the parent state of trace block, use block.number-1 as + // the state number. + tracker.releaseState(task.block.NumberU64()-1, task.release) // Stream the result back to the result catcher or abort on teardown select { @@ -354,8 +337,8 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed close(taskCh) pend.Wait() - // Clean out any pending derefs. - reler.call() + // Clean out any pending release functions of trace states. + tracker.callReleases() // Log the chain result switch { @@ -392,6 +375,13 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed failed = err break } + // Make sure the state creator doesn't go too far. Too many unprocessed + // trace state may cause the oldest state to become stale(e.g. in + // path-based scheme). + if err = tracker.wait(number); err != nil { + failed = err + break + } // Prepare the statedb for tracing. Don't use the live database for // tracing to avoid persisting state junks into the database. Switch // over to `preferDisk` mode only if the memory usage exceeds the @@ -407,18 +397,18 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed failed = err break } - // Clean out any pending derefs. Note this step must be done after - // constructing tracing state, because the tracing state of block - // next depends on the parent state and construction may fail if - // we release too early. - reler.call() + // Clean out any pending release functions of trace state. Note this + // step must be done after constructing tracing state, because the + // tracing state of block next depends on the parent state and construction + // may fail if we release too early. + tracker.callReleases() // Send the block over to the concurrent tracers (if not in the fast-forward phase) txs := next.Transactions() select { case taskCh <- &blockTraceTask{statedb: statedb.Copy(), block: next, release: release, results: make([]*txTraceResult, len(txs))}: case <-closed: - reler.add(release) + tracker.releaseState(number, release) return } traced += uint64(len(txs)) diff --git a/eth/tracers/tracker.go b/eth/tracers/tracker.go new file mode 100644 index 000000000000..136be37f5c09 --- /dev/null +++ b/eth/tracers/tracker.go @@ -0,0 +1,109 @@ +// Copyright 2022 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 tracers + +import ( + "fmt" + "sync" +) + +// stateTracker is an auxiliary tool used to cache the release functions of all +// used trace states, and to determine whether the creation of trace state needs +// to be paused in case there are too many states waiting for tracing. +type stateTracker struct { + limit int // Maximum number of states allowed waiting for tracing + oldest uint64 // The number of the oldest state which is still using for trace + used []bool // List of flags indicating whether the trace state has been used up + releases []StateReleaseFunc // List of trace state release functions waiting to be called + cond *sync.Cond + lock *sync.RWMutex +} + +// newStateTracker initializes the tracker with provided state limits and +// the number of the first state that will be used. +func newStateTracker(limit int, oldest uint64) *stateTracker { + lock := new(sync.RWMutex) + return &stateTracker{ + limit: limit, + oldest: oldest, + used: make([]bool, limit), + cond: sync.NewCond(lock), + lock: lock, + } +} + +// releaseState marks the state specified by the number as released and caches +// the corresponding release functions internally. +func (t *stateTracker) releaseState(number uint64, release StateReleaseFunc) { + t.lock.Lock() + defer t.lock.Unlock() + + // Set the state as used, the corresponding flag is indexed by + // the distance between the specified state and the oldest state + // which is still using for trace. + t.used[int(number-t.oldest)] = true + + // If the oldest state is used up, update the oldest marker by moving + // it to the next state which is not used up. + if number == t.oldest { + var count int + for _, used := range t.used { + if !used { + break + } + count += 1 + } + t.oldest += uint64(count) + copy(t.used, t.used[count:]) + + // Clean up the array tail since they are useless now. + for i := t.limit - count; i < t.limit; i++ { + t.used[i] = false + } + // Fire the signal to all waiters that oldest marker is updated. + t.cond.Broadcast() + } + t.releases = append(t.releases, release) +} + +// callReleases invokes all cached release functions. +func (t *stateTracker) callReleases() { + t.lock.Lock() + defer t.lock.Unlock() + + for _, release := range t.releases { + release() + } + t.releases = t.releases[:0] +} + +// wait blocks until the accumulated trace states are less than the limit. +func (t *stateTracker) wait(number uint64) error { + t.lock.Lock() + defer t.lock.Unlock() + + for { + if number < t.oldest { + return fmt.Errorf("invalid state number %d head %d", number, t.oldest) + } + if number < t.oldest+uint64(t.limit) { + // number is now within limit, wait over + return nil + } + t.cond.Wait() + } +} diff --git a/eth/tracers/tracker_test.go b/eth/tracers/tracker_test.go new file mode 100644 index 000000000000..46f6ac8e5185 --- /dev/null +++ b/eth/tracers/tracker_test.go @@ -0,0 +1,171 @@ +// Copyright 2022 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 tracers + +import ( + "reflect" + "testing" + "time" +) + +func TestTracker(t *testing.T) { + var cases = []struct { + limit int + calls []uint64 + expHead uint64 + }{ + // Release in order + { + limit: 3, + calls: []uint64{0, 1, 2}, + expHead: 3, + }, + { + limit: 3, + calls: []uint64{0, 1, 2, 3, 4, 5}, + expHead: 6, + }, + + // Release out of order + { + limit: 3, + calls: []uint64{1, 2, 0}, + expHead: 3, + }, + { + limit: 3, + calls: []uint64{1, 2, 0, 5, 4, 3}, + expHead: 6, + }, + } + for _, c := range cases { + tracker := newStateTracker(c.limit, 0) + for _, call := range c.calls { + tracker.releaseState(call, func() {}) + } + tracker.lock.RLock() + head := tracker.oldest + tracker.lock.RUnlock() + + if head != c.expHead { + t.Fatalf("Unexpected head want %d got %d", c.expHead, head) + } + } + + var calls = []struct { + number uint64 + expUsed []bool + expHead uint64 + }{ + // Release the first one, update the oldest flag + { + number: 0, + expUsed: []bool{false, false, false, false, false}, + expHead: 1, + }, + // Release the second one, oldest shouldn't be updated + { + number: 2, + expUsed: []bool{false, true, false, false, false}, + expHead: 1, + }, + // Release the forth one, oldest shouldn't be updated + { + number: 4, + expUsed: []bool{false, true, false, true, false}, + expHead: 1, + }, + // Release the first one, the first two should all be cleaned, + // and the remaining flags should all be left-shifted. + { + number: 1, + expUsed: []bool{false, true, false, false, false}, + expHead: 3, + }, + // Release the first one, the first two should all be cleaned + { + number: 3, + expUsed: []bool{false, false, false, false, false}, + expHead: 5, + }, + } + tracker := newStateTracker(5, 0) // limit = 5, oldest = 0 + for _, call := range calls { + tracker.releaseState(call.number, nil) + tracker.lock.RLock() + if !reflect.DeepEqual(tracker.used, call.expUsed) { + t.Fatalf("Unexpected used array") + } + if tracker.oldest != call.expHead { + t.Fatalf("Unexpected head") + } + tracker.lock.RUnlock() + } +} + +func TestTrackerWait(t *testing.T) { + var ( + tracker = newStateTracker(5, 0) // limit = 5, oldest = 0 + result = make(chan error, 1) + doCall = func(number uint64) { + go func() { + result <- tracker.wait(number) + }() + } + checkNoWait = func() { + select { + case <-result: + return + case <-time.NewTimer(time.Second).C: + t.Fatal("No signal fired") + } + } + checkWait = func() { + select { + case <-result: + t.Fatal("Unexpected signal") + case <-time.NewTimer(time.Millisecond * 100).C: + } + } + ) + // States [0, 5) should all be available + doCall(0) + checkNoWait() + + doCall(4) + checkNoWait() + + // State 5 is not available + doCall(5) + checkWait() + + // States [1, 6) are available + tracker.releaseState(0, nil) + checkNoWait() + + // States [1, 6) are available + doCall(7) + checkWait() + + // States [2, 7) are available + tracker.releaseState(1, nil) + checkWait() + + // States [3, 8) are available + tracker.releaseState(2, nil) + checkNoWait() +} From deead99731f325442154e99e5ee15a7d50df1cff Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 6 Oct 2022 11:41:07 +0200 Subject: [PATCH 293/715] core/bloombits: speed up windows-test (#25844) core/bloombits: remove micro-sleep --- core/bloombits/scheduler_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/bloombits/scheduler_test.go b/core/bloombits/scheduler_test.go index 707e8ea11d04..49e113c117ba 100644 --- a/core/bloombits/scheduler_test.go +++ b/core/bloombits/scheduler_test.go @@ -19,11 +19,9 @@ package bloombits import ( "bytes" "math/big" - "math/rand" "sync" "sync/atomic" "testing" - "time" ) // Tests that the scheduler can deduplicate and forward retrieval requests to @@ -53,7 +51,6 @@ func testScheduler(t *testing.T, clients int, fetchers int, requests int) { defer fetchPend.Done() for req := range fetch { - time.Sleep(time.Duration(rand.Intn(int(100 * time.Microsecond)))) atomic.AddUint32(&delivered, 1) f.deliver([]uint64{ From 067bac3f2409aec16994163e7a635d36bdb9b956 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 6 Oct 2022 13:39:20 +0200 Subject: [PATCH 294/715] core, ethclient/gethclient: improve flaky tests (#25918) * ethclient/gethclient: improve time-sensitive flaky test * eth/catalyst: fix (?) flaky test * core: stop blockchains in tests after use * core: fix dangling blockchain instances * core: rm whitespace * eth/gasprice, eth/tracers, consensus/clique: stop dangling blockchains in tests * all: address review concerns * core: goimports * eth/catalyst: fix another time-sensitive test * consensus/clique: add snapshot test run function * core: rename stop() to stopWithoutSaving() Co-authored-by: Felix Lange --- consensus/clique/snapshot_test.go | 231 ++++++++++++------------ core/blockchain.go | 16 +- core/blockchain_repair_test.go | 2 + core/blockchain_sethead_test.go | 2 + core/blockchain_snapshot_test.go | 7 +- core/blockchain_test.go | 48 ++++- core/dao_test.go | 4 +- eth/catalyst/api_test.go | 42 +++-- eth/gasprice/feehistory_test.go | 2 +- eth/gasprice/gasprice_test.go | 7 + eth/tracers/api_test.go | 31 +++- ethclient/gethclient/gethclient_test.go | 13 +- 12 files changed, 256 insertions(+), 149 deletions(-) diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 4f9222d0927a..1a39557108ed 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -19,6 +19,7 @@ package clique import ( "bytes" "crypto/ecdsa" + "fmt" "math/big" "sort" "testing" @@ -95,17 +96,19 @@ type testerVote struct { newbatch bool } +type cliqueTest struct { + epoch uint64 + signers []string + votes []testerVote + results []string + failure error +} + // Tests that Clique signer voting is evaluated correctly for various simple and // complex scenarios, as well as that a few special corner cases fail correctly. func TestClique(t *testing.T) { // Define the various voting scenarios to test - tests := []struct { - epoch uint64 - signers []string - votes []testerVote - results []string - failure error - }{ + tests := []cliqueTest{ { // Single signer, no votes cast signers: []string{"A"}, @@ -377,129 +380,129 @@ func TestClique(t *testing.T) { failure: errRecentlySigned, }, } + // Run through the scenarios and test them for i, tt := range tests { - // Create the account pool and generate the initial set of signers - accounts := newTesterAccountPool() + t.Run(fmt.Sprint(i), tt.run) + } +} - signers := make([]common.Address, len(tt.signers)) - for j, signer := range tt.signers { - signers[j] = accounts.address(signer) - } - for j := 0; j < len(signers); j++ { - for k := j + 1; k < len(signers); k++ { - if bytes.Compare(signers[j][:], signers[k][:]) > 0 { - signers[j], signers[k] = signers[k], signers[j] - } - } - } - // Create the genesis block with the initial set of signers - genesis := &core.Genesis{ - ExtraData: make([]byte, extraVanity+common.AddressLength*len(signers)+extraSeal), - BaseFee: big.NewInt(params.InitialBaseFee), - } - for j, signer := range signers { - copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:]) - } +func (tt *cliqueTest) run(t *testing.T) { + // Create the account pool and generate the initial set of signers + accounts := newTesterAccountPool() - // Assemble a chain of headers from the cast votes - config := *params.TestChainConfig - config.Clique = ¶ms.CliqueConfig{ - Period: 1, - Epoch: tt.epoch, + signers := make([]common.Address, len(tt.signers)) + for j, signer := range tt.signers { + signers[j] = accounts.address(signer) + } + for j := 0; j < len(signers); j++ { + for k := j + 1; k < len(signers); k++ { + if bytes.Compare(signers[j][:], signers[k][:]) > 0 { + signers[j], signers[k] = signers[k], signers[j] + } } - genesis.Config = &config + } + // Create the genesis block with the initial set of signers + genesis := &core.Genesis{ + ExtraData: make([]byte, extraVanity+common.AddressLength*len(signers)+extraSeal), + BaseFee: big.NewInt(params.InitialBaseFee), + } + for j, signer := range signers { + copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:]) + } - engine := New(config.Clique, rawdb.NewMemoryDatabase()) - engine.fakeDiff = true + // Assemble a chain of headers from the cast votes + config := *params.TestChainConfig + config.Clique = ¶ms.CliqueConfig{ + Period: 1, + Epoch: tt.epoch, + } + genesis.Config = &config - _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, len(tt.votes), func(j int, gen *core.BlockGen) { - // Cast the vote contained in this block - gen.SetCoinbase(accounts.address(tt.votes[j].voted)) - if tt.votes[j].auth { - var nonce types.BlockNonce - copy(nonce[:], nonceAuthVote) - gen.SetNonce(nonce) - } - }) - // Iterate through the blocks and seal them individually - for j, block := range blocks { - // Get the header and prepare it for signing - header := block.Header() - if j > 0 { - header.ParentHash = blocks[j-1].Hash() - } - header.Extra = make([]byte, extraVanity+extraSeal) - if auths := tt.votes[j].checkpoint; auths != nil { - header.Extra = make([]byte, extraVanity+len(auths)*common.AddressLength+extraSeal) - accounts.checkpoint(header, auths) - } - header.Difficulty = diffInTurn // Ignored, we just need a valid number + engine := New(config.Clique, rawdb.NewMemoryDatabase()) + engine.fakeDiff = true - // Generate the signature, embed it into the header and the block - accounts.sign(header, tt.votes[j].signer) - blocks[j] = block.WithSeal(header) - } - // Split the blocks up into individual import batches (cornercase testing) - batches := [][]*types.Block{nil} - for j, block := range blocks { - if tt.votes[j].newbatch { - batches = append(batches, nil) - } - batches[len(batches)-1] = append(batches[len(batches)-1], block) - } - // Pass all the headers through clique and ensure tallying succeeds - chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) - if err != nil { - t.Errorf("test %d: failed to create test chain: %v", i, err) - continue - } - failed := false - for j := 0; j < len(batches)-1; j++ { - if k, err := chain.InsertChain(batches[j]); err != nil { - t.Errorf("test %d: failed to import batch %d, block %d: %v", i, j, k, err) - failed = true - break - } - } - if failed { - continue + _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, len(tt.votes), func(j int, gen *core.BlockGen) { + // Cast the vote contained in this block + gen.SetCoinbase(accounts.address(tt.votes[j].voted)) + if tt.votes[j].auth { + var nonce types.BlockNonce + copy(nonce[:], nonceAuthVote) + gen.SetNonce(nonce) } - if _, err = chain.InsertChain(batches[len(batches)-1]); err != tt.failure { - t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) + }) + // Iterate through the blocks and seal them individually + for j, block := range blocks { + // Get the header and prepare it for signing + header := block.Header() + if j > 0 { + header.ParentHash = blocks[j-1].Hash() } - if tt.failure != nil { - continue + header.Extra = make([]byte, extraVanity+extraSeal) + if auths := tt.votes[j].checkpoint; auths != nil { + header.Extra = make([]byte, extraVanity+len(auths)*common.AddressLength+extraSeal) + accounts.checkpoint(header, auths) } - // No failure was produced or requested, generate the final voting snapshot - head := blocks[len(blocks)-1] + header.Difficulty = diffInTurn // Ignored, we just need a valid number - snap, err := engine.snapshot(chain, head.NumberU64(), head.Hash(), nil) - if err != nil { - t.Errorf("test %d: failed to retrieve voting snapshot: %v", i, err) - continue + // Generate the signature, embed it into the header and the block + accounts.sign(header, tt.votes[j].signer) + blocks[j] = block.WithSeal(header) + } + // Split the blocks up into individual import batches (cornercase testing) + batches := [][]*types.Block{nil} + for j, block := range blocks { + if tt.votes[j].newbatch { + batches = append(batches, nil) } - // Verify the final list of signers against the expected ones - signers = make([]common.Address, len(tt.results)) - for j, signer := range tt.results { - signers[j] = accounts.address(signer) + batches[len(batches)-1] = append(batches[len(batches)-1], block) + } + // Pass all the headers through clique and ensure tallying succeeds + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("failed to create test chain: %v", err) + } + defer chain.Stop() + + for j := 0; j < len(batches)-1; j++ { + if k, err := chain.InsertChain(batches[j]); err != nil { + t.Fatalf("failed to import batch %d, block %d: %v", j, k, err) + break } - for j := 0; j < len(signers); j++ { - for k := j + 1; k < len(signers); k++ { - if bytes.Compare(signers[j][:], signers[k][:]) > 0 { - signers[j], signers[k] = signers[k], signers[j] - } + } + if _, err = chain.InsertChain(batches[len(batches)-1]); err != tt.failure { + t.Errorf("failure mismatch: have %v, want %v", err, tt.failure) + } + if tt.failure != nil { + return + } + + // No failure was produced or requested, generate the final voting snapshot + head := blocks[len(blocks)-1] + + snap, err := engine.snapshot(chain, head.NumberU64(), head.Hash(), nil) + if err != nil { + t.Fatalf("failed to retrieve voting snapshot: %v", err) + } + // Verify the final list of signers against the expected ones + signers = make([]common.Address, len(tt.results)) + for j, signer := range tt.results { + signers[j] = accounts.address(signer) + } + for j := 0; j < len(signers); j++ { + for k := j + 1; k < len(signers); k++ { + if bytes.Compare(signers[j][:], signers[k][:]) > 0 { + signers[j], signers[k] = signers[k], signers[j] } } - result := snap.signers() - if len(result) != len(signers) { - t.Errorf("test %d: signers mismatch: have %x, want %x", i, result, signers) - continue - } - for j := 0; j < len(result); j++ { - if !bytes.Equal(result[j][:], signers[j][:]) { - t.Errorf("test %d, signer %d: signer mismatch: have %x, want %x", i, j, result[j], signers[j]) - } + } + result := snap.signers() + if len(result) != len(signers) { + t.Fatalf("signers mismatch: have %x, want %x", result, signers) + } + for j := 0; j < len(result); j++ { + if !bytes.Equal(result[j][:], signers[j][:]) { + t.Fatalf("signer %d: signer mismatch: have %x, want %x", j, result[j], signers[j]) } } } diff --git a/core/blockchain.go b/core/blockchain.go index 2821fedb0f34..9766f28eda9c 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -856,9 +856,13 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) { headBlockGauge.Update(int64(block.NumberU64())) } -// Stop stops the blockchain service. If any imports are currently in progress -// it will abort them using the procInterrupt. -func (bc *BlockChain) Stop() { +// stop stops the blockchain service. If any imports are currently in progress +// it will abort them using the procInterrupt. This method stops all running +// goroutines, but does not do all the post-stop work of persisting data. +// OBS! It is generally recommended to use the Stop method! +// This method has been exposed to allow tests to stop the blockchain while simulating +// a crash. +func (bc *BlockChain) stopWithoutSaving() { if !atomic.CompareAndSwapInt32(&bc.running, 0, 1) { return } @@ -878,6 +882,12 @@ func (bc *BlockChain) Stop() { // returned. bc.chainmu.Close() bc.wg.Wait() +} + +// Stop stops the blockchain service. If any imports are currently in progress +// it will abort them using the procInterrupt. +func (bc *BlockChain) Stop() { + bc.stopWithoutSaving() // Ensure that the entirety of the state snapshot is journalled to disk. var snapBase common.Hash diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 6e61f89c3b14..1b3f1b718782 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1826,6 +1826,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { } // Pull the plug on the database, simulating a hard crash db.Close() + chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us db, err = rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) @@ -1940,6 +1941,7 @@ func TestIssue23496(t *testing.T) { // Pull the plug on the database, simulating a hard crash db.Close() + chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us db, err = rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index 1eb588d02fd1..1750cb4e63dc 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -1984,6 +1984,8 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { if err != nil { t.Fatalf("Failed to create chain: %v", err) } + defer chain.Stop() + // If sidechain blocks are needed, make a light chain and import it var sideblocks types.Blocks if tt.sidechainBlocks > 0 { diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index 1b38ad51e985..e55431c914fa 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -247,6 +247,7 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { // Pull the plug on the database, simulating a hard crash db := chain.db db.Close() + chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us newdb, err := rawdb.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "", false) @@ -388,15 +389,19 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { SnapshotLimit: 256, SnapshotWait: false, // Don't wait rebuild } - _, err = NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } + // Simulate the blockchain crash. + tmp.stopWithoutSaving() + newchain, err = NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } + defer newchain.Stop() snaptest.verify(t, newchain, blocks) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index aba50c8627c9..418844cdf502 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -681,7 +681,7 @@ func TestHeadersInsertNonceError(t *testing.T) { testInsertNonceError(t, false) func TestBlocksInsertNonceError(t *testing.T) { testInsertNonceError(t, true) } func testInsertNonceError(t *testing.T, full bool) { - for i := 1; i < 25 && !t.Failed(); i++ { + doTest := func(i int) { // Create a pristine chain and database genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) if err != nil { @@ -730,6 +730,9 @@ func testInsertNonceError(t *testing.T, full bool) { } } } + for i := 1; i < 25 && !t.Failed(); i++ { + doTest(i) + } } // Tests that fast importing a block chain produces the same chain data as the @@ -1639,6 +1642,8 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + for i := 0; i < len(blocks); i++ { if _, err := chain.InsertChain(blocks[i : i+1]); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", i, err) @@ -1681,6 +1686,8 @@ func TestTrieForkGC(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + for i := 0; i < len(blocks); i++ { if _, err := chain.InsertChain(blocks[i : i+1]); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", i, err) @@ -1717,6 +1724,8 @@ func TestLargeReorgTrieGC(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + if _, err := chain.InsertChain(shared); err != nil { t.Fatalf("failed to insert shared chain: %v", err) } @@ -1896,6 +1905,8 @@ func TestLowDiffLongChain(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.stopWithoutSaving() + if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } @@ -1955,6 +1966,8 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + // Activate the transition since genesis if required if mergePoint == 0 { merger.ReachTTD() @@ -2092,6 +2105,7 @@ func testInsertKnownChainData(t *testing.T, typ string) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() var ( inserter func(blocks []*types.Block, receipts []types.Receipts) error @@ -2242,6 +2256,8 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + var ( inserter func(blocks []*types.Block, receipts []types.Receipts) error asserter func(t *testing.T, block *types.Block) @@ -2394,6 +2410,8 @@ func TestReorgToShorterRemovesCanonMapping(t *testing.T) { if err != nil { t.Fatal(err) } + defer chain.Stop() + if n, err := chain.InsertChain(canonblocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } @@ -2430,6 +2448,8 @@ func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) { if err != nil { t.Fatal(err) } + defer chain.Stop() + // Convert into headers canonHeaders := make([]*types.Header, len(canonblocks)) for i, block := range canonblocks { @@ -2629,6 +2649,8 @@ func TestSkipStaleTxIndicesInSnapSync(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + headers := make([]*types.Header, len(blocks)) for i, block := range blocks { headers[i] = block.Header() @@ -2769,6 +2791,8 @@ func TestSideImportPrunedBlocks(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } @@ -2857,6 +2881,8 @@ func TestDeleteCreateRevert(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } @@ -2966,6 +2992,8 @@ func TestDeleteRecreateSlots(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } @@ -3042,6 +3070,8 @@ func TestDeleteRecreateAccount(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } @@ -3163,7 +3193,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { e.exist = false e.values = nil } - t.Logf("block %d; adding destruct\n", e.blocknum) + //t.Logf("block %d; adding destruct\n", e.blocknum) return tx } var newResurrect = func(e *expectation, b *BlockGen) *types.Transaction { @@ -3174,7 +3204,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { e.exist = true e.values = map[int]int{3: e.blocknum + 1, 4: 4} } - t.Logf("block %d; adding resurrect\n", e.blocknum) + //t.Logf("block %d; adding resurrect\n", e.blocknum) return tx } @@ -3211,6 +3241,8 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + var asHash = func(num int) common.Hash { return common.BytesToHash([]byte{byte(num)}) } @@ -3340,6 +3372,8 @@ func TestInitThenFailCreateContract(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + statedb, _ := chain.State() if got, exp := statedb.GetBalance(aa), big.NewInt(100000); got.Cmp(exp) != 0 { t.Fatalf("Genesis err, got %v exp %v", got, exp) @@ -3420,6 +3454,8 @@ func TestEIP2718Transition(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } @@ -3506,6 +3542,8 @@ func TestEIP1559Transition(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } @@ -3608,6 +3646,8 @@ func TestSetCanonical(t *testing.T) { if err != nil { t.Fatalf("failed to create tester chain: %v", err) } + defer chain.Stop() + if n, err := chain.InsertChain(canon); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } @@ -3758,6 +3798,7 @@ func TestCanonicalHashMarker(t *testing.T) { } } } + chain.Stop() } } @@ -3961,6 +4002,7 @@ func TestTxIndexer(t *testing.T) { chain.indexBlocks(rawdb.ReadTxIndexTail(db), 128, make(chan struct{})) verify(db, 0) + chain.Stop() db.Close() os.RemoveAll(frdir) } diff --git a/core/dao_test.go b/core/dao_test.go index 44405447deaa..632eafe4d5c8 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -75,7 +75,6 @@ func TestDAOForkRangeExtradata(t *testing.T) { for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { // Create a pro-fork block, and try to feed into the no-fork chain bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) for j := 0; j < len(blocks)/2; j++ { @@ -87,6 +86,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true, nil); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } + bc.Stop() blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err == nil { t.Fatalf("contra-fork chain accepted pro-fork block: %v", blocks[0]) @@ -98,7 +98,6 @@ func TestDAOForkRangeExtradata(t *testing.T) { } // Create a no-fork block, and try to feed into the pro-fork chain bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) for j := 0; j < len(blocks)/2; j++ { @@ -110,6 +109,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true, nil); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } + bc.Stop() blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err == nil { t.Fatalf("pro-fork chain accepted contra-fork block: %v", blocks[0]) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index c98a48ea4769..e195145b73ad 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -92,12 +92,21 @@ func TestEth2AssembleBlock(t *testing.T) { blockParams := beacon.PayloadAttributesV1{ Timestamp: blocks[9].Time() + 5, } - execData, err := assembleBlock(api, blocks[9].Hash(), &blockParams) - if err != nil { - t.Fatalf("error producing block, err=%v", err) - } - if len(execData.Transactions) != 1 { - t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions)) + // This test is a bit time-sensitive, the miner needs to pick up on the + // txs in the pool. Therefore, we retry once if it fails on the first attempt. + var testErr error + for retries := 2; retries > 0; retries-- { + if execData, err := assembleBlock(api, blocks[9].Hash(), &blockParams); err != nil { + t.Fatalf("error producing block, err=%v", err) + } else if have, want := len(execData.Transactions), 1; have != want { + testErr = fmt.Errorf("invalid number of transactions, have %d want %d", have, want) + } else { + testErr = nil + break + } + } + if testErr != nil { + t.Fatal(testErr) } } @@ -113,12 +122,21 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { blockParams := beacon.PayloadAttributesV1{ Timestamp: blocks[8].Time() + 5, } - execData, err := assembleBlock(api, blocks[8].Hash(), &blockParams) - if err != nil { - t.Fatalf("error producing block, err=%v", err) - } - if len(execData.Transactions) != blocks[9].Transactions().Len() { - t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions)) + // This test is a bit time-sensitive, the miner needs to pick up on the + // txs in the pool. Therefore, we retry once if it fails on the first attempt. + var testErr error + for retries := 2; retries > 0; retries-- { + if execData, err := assembleBlock(api, blocks[8].Hash(), &blockParams); err != nil { + t.Fatalf("error producing block, err=%v", err) + } else if have, want := len(execData.Transactions), blocks[9].Transactions().Len(); have != want { + testErr = fmt.Errorf("invalid number of transactions, have %d want %d", have, want) + } else { + testErr = nil + break + } + } + if testErr != nil { + t.Fatal(testErr) } } diff --git a/eth/gasprice/feehistory_test.go b/eth/gasprice/feehistory_test.go index deece7f46150..b54874d68847 100644 --- a/eth/gasprice/feehistory_test.go +++ b/eth/gasprice/feehistory_test.go @@ -62,7 +62,7 @@ func TestFeeHistory(t *testing.T) { oracle := NewOracle(backend, config) first, reward, baseFee, ratio, err := oracle.FeeHistory(context.Background(), c.count, c.last, c.percent) - + backend.teardown() expReward := c.expCount if len(c.percent) == 0 { expReward = 0 diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index a4399661fcf0..a987d46458e4 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -113,6 +113,12 @@ func (b *testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) eve return nil } +func (b *testBackend) teardown() { + b.chain.Stop() +} + +// newTestBackend creates a test backend. OBS: don't forget to invoke tearDown +// after use, otherwise the blockchain instance will mem-leak via goroutines. func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBackend { var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -198,6 +204,7 @@ func TestSuggestTipCap(t *testing.T) { // The gas price sampled is: 32G, 31G, 30G, 29G, 28G, 27G got, err := oracle.SuggestTipCap(context.Background()) + backend.teardown() if err != nil { t.Fatalf("Failed to retrieve recommended gas price: %v", err) } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 346813ae2c77..adf65d33fb4f 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -63,6 +63,8 @@ type testBackend struct { relHook func() // Hook is invoked when the requested state is released } +// testBackend creates a new test backend. OBS: After test is done, teardown must be +// invoked in order to release associated resources. func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend { backend := &testBackend{ chainConfig: gspec.Config, @@ -137,6 +139,11 @@ func (b *testBackend) ChainDb() ethdb.Database { return b.chaindb } +// teardown releases the associated resources. +func (b *testBackend) teardown() { + b.chain.Stop() +} + func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) { statedb, err := b.chain.StateAt(block.Root()) if err != nil { @@ -198,13 +205,15 @@ func TestTraceCall(t *testing.T) { } genBlocks := 10 signer := types.HomesteadSigner{} - api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { + backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { // Transfer from account[0] to account[1] // value: 1000 wei // fee: 0 wei tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) b.AddTx(tx) - })) + }) + defer backend.teardown() + api := NewAPI(backend) var testSuite = []struct { blockNumber rpc.BlockNumber call ethapi.TransactionArgs @@ -330,14 +339,16 @@ func TestTraceTransaction(t *testing.T) { } target := common.Hash{} signer := types.HomesteadSigner{} - api := NewAPI(newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) { + backend := newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) { // Transfer from account[0] to account[1] // value: 1000 wei // fee: 0 wei tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) b.AddTx(tx) target = tx.Hash() - })) + }) + defer backend.chain.Stop() + api := NewAPI(backend) result, err := api.TraceTransaction(context.Background(), target, nil) if err != nil { t.Errorf("Failed to trace transaction %v", err) @@ -371,13 +382,15 @@ func TestTraceBlock(t *testing.T) { } genBlocks := 10 signer := types.HomesteadSigner{} - api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { + backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { // Transfer from account[0] to account[1] // value: 1000 wei // fee: 0 wei tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) b.AddTx(tx) - })) + }) + defer backend.chain.Stop() + api := NewAPI(backend) var testSuite = []struct { blockNumber rpc.BlockNumber @@ -449,13 +462,15 @@ func TestTracingWithOverrides(t *testing.T) { } genBlocks := 10 signer := types.HomesteadSigner{} - api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { + backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { // Transfer from account[0] to account[1] // value: 1000 wei // fee: 0 wei tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) b.AddTx(tx) - })) + }) + defer backend.chain.Stop() + api := NewAPI(backend) randomAccounts := newAccounts(3) type res struct { Gas int diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index 0e2f7e57b69a..da0118887b26 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -106,10 +106,6 @@ func TestGethClient(t *testing.T) { name string test func(t *testing.T) }{ - { - "TestAccessList", - func(t *testing.T) { testAccessList(t, client) }, - }, { "TestGetProof", func(t *testing.T) { testGetProof(t, client) }, @@ -132,8 +128,15 @@ func TestGethClient(t *testing.T) { "TestCallContract", func(t *testing.T) { testCallContract(t, client) }, }, + // The testaccesslist is a bit time-sensitive: the newTestBackend imports + // one block. The `testAcessList` fails if the miner has not yet created a + // new pending-block after the import event. + // Hence: this test should be last, execute the tests serially. + { + "TestAccessList", + func(t *testing.T) { testAccessList(t, client) }, + }, } - t.Parallel() for _, tt := range tests { t.Run(tt.name, tt.test) } From 9cddfe92a38138a8eb88011954ca9b6a1ae4405e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 6 Oct 2022 14:01:04 +0200 Subject: [PATCH 295/715] node: prevent exposing engine API on unauthenticated endpoint (#25939) * node: prevent exposing engine API on unauthenticated endpoint * node: improve RPC setup --- node/api.go | 2 +- node/node.go | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/node/api.go b/node/api.go index 67953a812e9d..15892a270b66 100644 --- a/node/api.go +++ b/node/api.go @@ -269,7 +269,7 @@ func (api *adminAPI) StartWS(host *string, port *int, allowedOrigins *string, ap if err := server.setListenAddr(*host, *port); err != nil { return false, err } - openApis, _ := api.node.GetAPIs() + openApis, _ := api.node.getAPIs() if err := server.enableWS(openApis, config); err != nil { return false, err } diff --git a/node/node.go b/node/node.go index 3cbefef022e5..c8fda1fe3c61 100644 --- a/node/node.go +++ b/node/node.go @@ -392,15 +392,15 @@ func (n *Node) startRPC() error { } } var ( - servers []*httpServer - open, all = n.GetAPIs() + servers []*httpServer + openAPIs, allAPIs = n.getAPIs() ) - initHttp := func(server *httpServer, apis []rpc.API, port int) error { + initHttp := func(server *httpServer, port int) error { if err := server.setListenAddr(n.config.HTTPHost, port); err != nil { return err } - if err := server.enableRPC(apis, httpConfig{ + if err := server.enableRPC(openAPIs, httpConfig{ CorsAllowedOrigins: n.config.HTTPCors, Vhosts: n.config.HTTPVirtualHosts, Modules: n.config.HTTPModules, @@ -412,12 +412,12 @@ func (n *Node) startRPC() error { return nil } - initWS := func(apis []rpc.API, port int) error { + initWS := func(port int) error { server := n.wsServerForPort(port, false) if err := server.setListenAddr(n.config.WSHost, port); err != nil { return err } - if err := server.enableWS(n.rpcAPIs, wsConfig{ + if err := server.enableWS(openAPIs, wsConfig{ Modules: n.config.WSModules, Origins: n.config.WSOrigins, prefix: n.config.WSPathPrefix, @@ -428,13 +428,13 @@ func (n *Node) startRPC() error { return nil } - initAuth := func(apis []rpc.API, port int, secret []byte) error { + initAuth := func(port int, secret []byte) error { // Enable auth via HTTP server := n.httpAuth if err := server.setListenAddr(n.config.AuthAddr, port); err != nil { return err } - if err := server.enableRPC(apis, httpConfig{ + if err := server.enableRPC(allAPIs, httpConfig{ CorsAllowedOrigins: DefaultAuthCors, Vhosts: n.config.AuthVirtualHosts, Modules: DefaultAuthModules, @@ -449,7 +449,7 @@ func (n *Node) startRPC() error { if err := server.setListenAddr(n.config.AuthAddr, port); err != nil { return err } - if err := server.enableWS(apis, wsConfig{ + if err := server.enableWS(allAPIs, wsConfig{ Modules: DefaultAuthModules, Origins: DefaultAuthOrigins, prefix: DefaultAuthPrefix, @@ -464,24 +464,24 @@ func (n *Node) startRPC() error { // Set up HTTP. if n.config.HTTPHost != "" { // Configure legacy unauthenticated HTTP. - if err := initHttp(n.http, open, n.config.HTTPPort); err != nil { + if err := initHttp(n.http, n.config.HTTPPort); err != nil { return err } } // Configure WebSocket. if n.config.WSHost != "" { // legacy unauthenticated - if err := initWS(open, n.config.WSPort); err != nil { + if err := initWS(n.config.WSPort); err != nil { return err } } // Configure authenticated API - if len(open) != len(all) { + if len(openAPIs) != len(allAPIs) { jwtSecret, err := n.obtainJWTSecret(n.config.JWTSecret) if err != nil { return err } - if err := initAuth(all, n.config.AuthPort, jwtSecret); err != nil { + if err := initAuth(n.config.AuthPort, jwtSecret); err != nil { return err } } @@ -570,9 +570,9 @@ func (n *Node) RegisterAPIs(apis []rpc.API) { n.rpcAPIs = append(n.rpcAPIs, apis...) } -// GetAPIs return two sets of APIs, both the ones that do not require +// getAPIs return two sets of APIs, both the ones that do not require // authentication, and the complete set -func (n *Node) GetAPIs() (unauthenticated, all []rpc.API) { +func (n *Node) getAPIs() (unauthenticated, all []rpc.API) { for _, api := range n.rpcAPIs { if !api.Authenticated { unauthenticated = append(unauthenticated, api) From df2b3cd2bd6781098a4bba12fba104a5e3a63f36 Mon Sep 17 00:00:00 2001 From: Ryan Schneider Date: Thu, 6 Oct 2022 05:43:55 -0700 Subject: [PATCH 296/715] eth/filters: fix for eth_getLogs failing with finalized- and safe tag (#25922) Prior to this change, f.begin (and possibly end) stay negative, leading to strange results later in the code. With this change, filters using "safe" and "finalized" block produce results consistent w/ the overall behavior of this RPC method. Co-authored-by: Martin Holst Swende --- accounts/abi/bind/backends/simulated.go | 23 +++++- eth/filters/filter.go | 38 +++++++-- eth/filters/filter_system_test.go | 15 +++- eth/filters/filter_test.go | 103 +++++++++++++----------- 4 files changed, 120 insertions(+), 59 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 21c94d7e17e1..277850e3b57c 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -844,11 +844,28 @@ func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db } func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") } -func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) { - if block == rpc.LatestBlockNumber { +func (fb *filterBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { + switch number { + case rpc.PendingBlockNumber: + if block := fb.backend.pendingBlock; block != nil { + return block.Header(), nil + } + return nil, nil + case rpc.LatestBlockNumber: return fb.bc.CurrentHeader(), nil + case rpc.FinalizedBlockNumber: + if block := fb.bc.CurrentFinalizedBlock(); block != nil { + return block.Header(), nil + } + return nil, errors.New("finalized block not found") + case rpc.SafeBlockNumber: + if block := fb.bc.CurrentSafeBlock(); block != nil { + return block.Header(), nil + } + return nil, errors.New("safe block not found") + default: + return fb.bc.GetHeaderByNumber(uint64(number.Int64())), nil } - return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil } func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 0a70c9ece1db..fbbb4a7aab8f 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -119,20 +119,44 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { return nil, nil } var ( - head = header.Number.Uint64() - end = uint64(f.end) + err error + head = header.Number.Int64() pending = f.end == rpc.PendingBlockNumber.Int64() ) - if f.begin == rpc.LatestBlockNumber.Int64() { - f.begin = int64(head) + resolveSpecial := func(number int64) (int64, error) { + var hdr *types.Header + switch number { + case rpc.LatestBlockNumber.Int64(): + return head, nil + case rpc.PendingBlockNumber.Int64(): + // we should return head here since we've already captured + // that we need to get the pending logs in the pending boolean above + return head, nil + case rpc.FinalizedBlockNumber.Int64(): + hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber) + if hdr == nil { + return 0, errors.New("finalized header not found") + } + case rpc.SafeBlockNumber.Int64(): + hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.SafeBlockNumber) + if hdr == nil { + return 0, errors.New("safe header not found") + } + default: + return number, nil + } + return hdr.Number.Int64(), nil } - if f.end == rpc.LatestBlockNumber.Int64() || f.end == rpc.PendingBlockNumber.Int64() { - end = head + if f.begin, err = resolveSpecial(f.begin); err != nil { + return nil, err + } + if f.end, err = resolveSpecial(f.end); err != nil { + return nil, err } // Gather all indexed logs, and finish with non indexed ones var ( logs []*types.Log - err error + end = uint64(f.end) size, sections = f.sys.backend.BloomStatus() ) if indexed := sections * size; indexed > uint64(f.begin) { diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 73a4ab2d4fca..4386f0e5bde6 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -18,6 +18,7 @@ package filters import ( "context" + "errors" "fmt" "math/big" "math/rand" @@ -58,14 +59,24 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumbe hash common.Hash num uint64 ) - if blockNr == rpc.LatestBlockNumber { + switch blockNr { + case rpc.LatestBlockNumber: hash = rawdb.ReadHeadBlockHash(b.db) number := rawdb.ReadHeaderNumber(b.db, hash) if number == nil { return nil, nil } num = *number - } else { + case rpc.FinalizedBlockNumber: + hash = rawdb.ReadFinalizedBlockHash(b.db) + number := rawdb.ReadHeaderNumber(b.db, hash) + if number == nil { + return nil, nil + } + num = *number + case rpc.SafeBlockNumber: + return nil, errors.New("safe block not found") + default: num = uint64(blockNr) hash = rawdb.ReadCanonicalHash(b.db, num) } diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 39ed46cec761..2a4dfd90ad80 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -19,6 +19,7 @@ package filters import ( "context" "math/big" + "reflect" "testing" "github.com/ethereum/go-ethereum/common" @@ -170,58 +171,66 @@ func TestFilters(t *testing.T) { rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i]) } - filter := sys.NewRangeFilter(0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) + // Set block 998 as Finalized (-3) + rawdb.WriteFinalizedBlockHash(db, chain[998].Hash()) + filter := sys.NewRangeFilter(0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) logs, _ := filter.Logs(context.Background()) if len(logs) != 4 { t.Error("expected 4 log, got", len(logs)) } - filter = sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}) - logs, _ = filter.Logs(context.Background()) - if len(logs) != 1 { - t.Error("expected 1 log, got", len(logs)) - } - if len(logs) > 0 && logs[0].Topics[0] != hash3 { - t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) - } - - filter = sys.NewRangeFilter(990, -1, []common.Address{addr}, [][]common.Hash{{hash3}}) - logs, _ = filter.Logs(context.Background()) - if len(logs) != 1 { - t.Error("expected 1 log, got", len(logs)) - } - if len(logs) > 0 && logs[0].Topics[0] != hash3 { - t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) - } - - filter = sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}) - - logs, _ = filter.Logs(context.Background()) - if len(logs) != 2 { - t.Error("expected 2 log, got", len(logs)) - } - - failHash := common.BytesToHash([]byte("fail")) - filter = sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{failHash}}) - - logs, _ = filter.Logs(context.Background()) - if len(logs) != 0 { - t.Error("expected 0 log, got", len(logs)) - } - - failAddr := common.BytesToAddress([]byte("failmenow")) - filter = sys.NewRangeFilter(0, -1, []common.Address{failAddr}, nil) - - logs, _ = filter.Logs(context.Background()) - if len(logs) != 0 { - t.Error("expected 0 log, got", len(logs)) - } - - filter = sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{failHash}, {hash1}}) - - logs, _ = filter.Logs(context.Background()) - if len(logs) != 0 { - t.Error("expected 0 log, got", len(logs)) + for i, tc := range []struct { + f *Filter + wantHashes []common.Hash + }{ + { + sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}), + []common.Hash{hash3}, + }, { + sys.NewRangeFilter(990, -1, []common.Address{addr}, [][]common.Hash{{hash3}}), + []common.Hash{hash3}, + }, { + sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}), + []common.Hash{hash1, hash2}, + }, { + sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}), + nil, + }, { + sys.NewRangeFilter(0, -1, []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil), + nil, + }, { + sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}), + nil, + }, { + sys.NewRangeFilter(-1, -1, nil, nil), []common.Hash{hash4}, + }, { + sys.NewRangeFilter(-3, -1, nil, nil), []common.Hash{hash3, hash4}, + }, { + sys.NewRangeFilter(-3, -3, nil, nil), []common.Hash{hash3}, + }, { + sys.NewRangeFilter(-1, -3, nil, nil), nil, + }, { + sys.NewRangeFilter(-4, -1, nil, nil), nil, + }, { + sys.NewRangeFilter(-4, -4, nil, nil), nil, + }, { + sys.NewRangeFilter(-1, -4, nil, nil), nil, + }, + } { + logs, _ := tc.f.Logs(context.Background()) + var haveHashes []common.Hash + for _, l := range logs { + haveHashes = append(haveHashes, l.Topics[0]) + } + if have, want := len(haveHashes), len(tc.wantHashes); have != want { + t.Fatalf("test %d, have %d logs, want %d", i, have, want) + } + if len(haveHashes) == 0 { + continue + } + if !reflect.DeepEqual(tc.wantHashes, haveHashes) { + t.Fatalf("test %d, have %v want %v", i, haveHashes, tc.wantHashes) + } } } From 564751668aa01f55d39851cbf4673500ec2d4718 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 6 Oct 2022 19:59:23 +0200 Subject: [PATCH 297/715] cmd/geth: fix help output issues (#25941) This update resolves an issue where StringSliceFlag would not be rendered correctly in help output + mention that -H can be used multiple times Co-authored-by: Martin Holst Swende --- cmd/geth/verkle.go | 1 - cmd/utils/flags.go | 13 ++++++------- go.mod | 6 ++---- go.sum | 39 +++++++-------------------------------- 4 files changed, 15 insertions(+), 44 deletions(-) diff --git a/cmd/geth/verkle.go b/cmd/geth/verkle.go index f85ec37ea924..a5756ceab003 100644 --- a/cmd/geth/verkle.go +++ b/cmd/geth/verkle.go @@ -38,7 +38,6 @@ var ( verkleCommand = &cli.Command{ Name: "verkle", Usage: "A set of experimental verkle tree management commands", - Category: "MISCELLANEOUS COMMANDS", Description: "", Subcommands: []*cli.Command{ { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5ce244080ff2..4c4dc9df1be7 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -864,6 +864,12 @@ var ( Value: flags.DirectoryString("."), Category: flags.APICategory, } + HttpHeaderFlag = &cli.StringSliceFlag{ + Name: "header", + Aliases: []string{"H"}, + Usage: "Pass custom headers to the RPC server when using --" + RemoteDBFlag.Name + " or the geth attach console. This flag can be given multiple times.", + Category: flags.APICategory, + } // Gas price oracle settings GpoBlocksFlag = &cli.IntFlag{ @@ -985,13 +991,6 @@ var ( Value: metrics.DefaultConfig.InfluxDBOrganization, Category: flags.MetricsCategory, } - - HttpHeaderFlag = &cli.StringSliceFlag{ - Name: "header", - Aliases: []string{"H"}, - Usage: "Pass custom headers to the RPC server wheng using --" + RemoteDBFlag.Name + " or the geth attach console.", - Category: flags.NetworkingCategory, - } ) var ( diff --git a/go.mod b/go.mod index 72613343948e..1f88ef7c6f6d 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff + github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 github.com/go-stack/stack v1.8.0 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.5.2 @@ -55,7 +56,7 @@ require ( github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef - github.com/urfave/cli/v2 v2.10.2 + github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c @@ -83,12 +84,9 @@ require ( github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect - github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 // indirect - github.com/go-logfmt/logfmt v0.4.0 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect - github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect diff --git a/go.sum b/go.sum index 72d9b25e2021..3b1b58a12168 100644 --- a/go.sum +++ b/go.sum @@ -129,9 +129,8 @@ github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlK github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgxrzK5E1fW7RQGeDwE8F/ZZnUYc= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= @@ -160,7 +159,6 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -208,7 +206,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -235,7 +232,6 @@ github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= github.com/influxdata/influxdb v1.8.3 h1:WEypI1BQFTT4teLM+1qkEcvUi0dAvopAI/ir0vAiBg8= @@ -324,29 +320,19 @@ github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hz github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= @@ -412,14 +398,8 @@ github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= -github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= @@ -428,8 +408,8 @@ github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZF github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y= -github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= +github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= +github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= @@ -513,11 +493,9 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -564,7 +542,6 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -574,8 +551,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -623,7 +599,6 @@ golang.org/x/tools v0.0.0-20191126055441-b0650ceb63d9/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= From 7eafbec741d124bc53896f6bfc2408b70ab9a82a Mon Sep 17 00:00:00 2001 From: jin <35813306+lochjin@users.noreply.github.com> Date: Tue, 11 Oct 2022 15:31:32 +0800 Subject: [PATCH 298/715] accounts/usbwallet: support Ledger Nano S Plus and FTS (#25933) * usbwallet support Ledger Nano S Plus * accounts/usbwallet: add definitions + ref to ledger docs Co-authored-by: Martin Holst Swende --- accounts/usbwallet/hub.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index 23be98a08483..2139967228f5 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -71,18 +71,28 @@ type Hub struct { // NewLedgerHub creates a new hardware wallet manager for Ledger devices. func NewLedgerHub() (*Hub, error) { return newHub(LedgerScheme, 0x2c97, []uint16{ + + // Device definitions taken from + // https://github.com/LedgerHQ/ledger-live/blob/38012bc8899e0f07149ea9cfe7e64b2c146bc92b/libs/ledgerjs/packages/devices/src/index.ts + // Original product IDs 0x0000, /* Ledger Blue */ 0x0001, /* Ledger Nano S */ 0x0004, /* Ledger Nano X */ + 0x0005, /* Ledger Nano S Plus */ + 0x0006, /* Ledger Nano FTS */ - // Upcoming product IDs: https://www.ledger.com/2019/05/17/windows-10-update-sunsetting-u2f-tunnel-transport-for-ledger-devices/ 0x0015, /* HID + U2F + WebUSB Ledger Blue */ 0x1015, /* HID + U2F + WebUSB Ledger Nano S */ 0x4015, /* HID + U2F + WebUSB Ledger Nano X */ + 0x5015, /* HID + U2F + WebUSB Ledger Nano S Plus */ + 0x6015, /* HID + U2F + WebUSB Ledger Nano FTS */ + 0x0011, /* HID + WebUSB Ledger Blue */ 0x1011, /* HID + WebUSB Ledger Nano S */ 0x4011, /* HID + WebUSB Ledger Nano X */ + 0x5011, /* HID + WebUSB Ledger Nano S Plus */ + 0x6011, /* HID + WebUSB Ledger Nano FTS */ }, 0xffa0, 0, newLedgerDriver) } From 5a02b2d6d0a8d5c8ebf170505c681f7b19df7ed9 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 11 Oct 2022 09:37:00 +0200 Subject: [PATCH 299/715] all: fix spelling mistakes (#25961) --- accounts/manager.go | 2 +- cmd/devp2p/internal/ethtest/snap.go | 2 +- cmd/evm/internal/t8ntool/transition.go | 2 +- consensus/clique/snapshot_test.go | 2 +- core/bloombits/matcher.go | 2 +- core/state/dump.go | 2 +- core/state/snapshot/conversion.go | 2 +- core/state/snapshot/iterator_fast.go | 2 +- core/state/snapshot/iterator_test.go | 2 +- core/state/snapshot/metrics.go | 2 +- core/state/snapshot/snapshot_test.go | 4 ++-- core/state/statedb.go | 6 +++--- core/tx_list.go | 2 +- core/tx_pool.go | 4 ++-- core/tx_pool_test.go | 2 +- core/vm/contracts.go | 2 +- crypto/signature_cgo.go | 2 +- eth/catalyst/api.go | 2 +- eth/downloader/queue.go | 2 +- eth/downloader/skeleton.go | 2 +- eth/fetcher/tx_fetcher.go | 4 ++-- eth/protocols/eth/dispatcher.go | 2 +- eth/protocols/eth/handler_test.go | 2 +- eth/protocols/eth/peer.go | 2 +- eth/protocols/snap/handler.go | 4 ++-- eth/protocols/snap/range_test.go | 2 +- eth/protocols/snap/sync.go | 6 +++--- eth/tracers/internal/tracetest/calltrace_test.go | 2 +- eth/tracers/internal/tracetest/prestate_test.go | 2 +- eth/tracers/internal/tracetest/util.go | 2 +- ethclient/ethclient_test.go | 2 +- internal/ethapi/api.go | 4 ++-- internal/version/version.go | 2 +- les/downloader/resultstore.go | 2 +- les/fetcher_test.go | 2 +- les/flowcontrol/manager.go | 2 +- les/odr.go | 2 +- les/server_requests.go | 2 +- les/vflux/server/clientpool.go | 2 +- light/txpool.go | 2 +- miner/stress/1559/main.go | 2 +- mobile/interface.go | 2 +- p2p/msgrate/msgrate.go | 10 +++++----- signer/core/api.go | 4 ++-- tests/fuzzers/rangeproof/rangeproof-fuzzer.go | 2 +- tests/fuzzers/runtime/runtime_fuzz.go | 2 +- trie/proof.go | 2 +- trie/stacktrie.go | 2 +- trie/trie_test.go | 4 ++-- 49 files changed, 64 insertions(+), 64 deletions(-) diff --git a/accounts/manager.go b/accounts/manager.go index 1e111d19487b..a0b5c329cdb8 100644 --- a/accounts/manager.go +++ b/accounts/manager.go @@ -257,7 +257,7 @@ func merge(slice []Wallet, wallets ...Wallet) []Wallet { return slice } -// drop is the couterpart of merge, which looks up wallets from within the sorted +// drop is the counterpart of merge, which looks up wallets from within the sorted // cache and removes the ones specified. func drop(slice []Wallet, wallets ...Wallet) []Wallet { for _, wallet := range wallets { diff --git a/cmd/devp2p/internal/ethtest/snap.go b/cmd/devp2p/internal/ethtest/snap.go index 6d5a5c17a194..754d7850d530 100644 --- a/cmd/devp2p/internal/ethtest/snap.go +++ b/cmd/devp2p/internal/ethtest/snap.go @@ -90,7 +90,7 @@ func (s *Suite) TestSnapGetAccountRange(t *utesting.T) { {4000, s.chain.RootAt(0), zero, ffHash, 0, zero, zero}, // A 127 block old stateroot, expected to be served {4000, s.chain.RootAt(999 - 127), zero, ffHash, 77, firstKey, common.HexToHash("0xe4c6fdef5dd4e789a2612390806ee840b8ec0fe52548f8b4efe41abb20c37aac")}, - // A root which is not actually an account root, but a storage orot + // A root which is not actually an account root, but a storage root {4000, storageRoot, zero, ffHash, 0, zero, zero}, // And some non-sensical requests diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index e2d9cced2255..0a0ba4ea51fa 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -394,7 +394,7 @@ func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) { g[addr] = genesisAccount } -// saveFile marshalls the object to the given file +// saveFile marshals the object to the given file func saveFile(baseDir, filename string, data interface{}) error { b, err := json.MarshalIndent(data, "", " ") if err != nil { diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 1a39557108ed..66e667276ff8 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -86,7 +86,7 @@ func (ap *testerAccountPool) sign(header *types.Header, signer string) { copy(header.Extra[len(header.Extra)-extraSeal:], sig) } -// testerVote represents a single block signed by a parcitular account, where +// testerVote represents a single block signed by a particular account, where // the account may or may not have cast a Clique vote. type testerVote struct { signer string diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go index f2a8bda17c55..0d2f6f950d86 100644 --- a/core/bloombits/matcher.go +++ b/core/bloombits/matcher.go @@ -612,7 +612,7 @@ func (s *MatcherSession) Multiplex(batch int, wait time.Duration, mux chan chan return case <-time.After(wait): - // Throttling up, fetch whatever's available + // Throttling up, fetch whatever is available } } // Allocate as much as we can handle and request servicing diff --git a/core/state/dump.go b/core/state/dump.go index bfcc03543516..d97520f08ee7 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -29,7 +29,7 @@ import ( "github.com/ethereum/go-ethereum/trie" ) -// DumpConfig is a set of options to control what portions of the statewill be +// DumpConfig is a set of options to control what portions of the state will be // iterated and collected. type DumpConfig struct { SkipCode bool diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index 0f3934cb423b..c15b17aa87e4 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -136,7 +136,7 @@ func (stat *generateStats) progressAccounts(account common.Hash, done uint64) { stat.head = account } -// finishAccounts updates the gemerator stats for the finished account range. +// finishAccounts updates the generator stats for the finished account range. func (stat *generateStats) finishAccounts(done uint64) { stat.lock.Lock() defer stat.lock.Unlock() diff --git a/core/state/snapshot/iterator_fast.go b/core/state/snapshot/iterator_fast.go index 435c28e96f9e..1a042c7cd3c0 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -276,7 +276,7 @@ func (fi *fastIterator) next(idx int) bool { return false } // The elem we're placing it next to has the same value, - // so whichever winds up on n+1 will need further iteraton + // so whichever winds up on n+1 will need further iteration clash = n + 1 return cur.priority < fi.iterators[n+1].priority diff --git a/core/state/snapshot/iterator_test.go b/core/state/snapshot/iterator_test.go index 2c7e876e0851..7420a2dc22ed 100644 --- a/core/state/snapshot/iterator_test.go +++ b/core/state/snapshot/iterator_test.go @@ -819,7 +819,7 @@ func TestStorageIteratorDeletions(t *testing.T) { // only spit out 200 values eventually. // // The value-fetching benchmark is easy on the binary iterator, since it never has to reach -// down at any depth for retrieving the values -- all are on the toppmost layer +// down at any depth for retrieving the values -- all are on the topmost layer // // BenchmarkAccountIteratorTraversal/binary_iterator_keys-6 2239 483674 ns/op // BenchmarkAccountIteratorTraversal/binary_iterator_values-6 2403 501810 ns/op diff --git a/core/state/snapshot/metrics.go b/core/state/snapshot/metrics.go index 43f417a0ded6..b2e884588b5d 100644 --- a/core/state/snapshot/metrics.go +++ b/core/state/snapshot/metrics.go @@ -36,7 +36,7 @@ var ( snapAccountProveCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/account/prove", nil) // snapAccountTrieReadCounter measures time spent on the account trie iteration snapAccountTrieReadCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/account/trieread", nil) - // snapAccountSnapReadCounter measues time spent on the snapshot account iteration + // snapAccountSnapReadCounter measures time spent on the snapshot account iteration snapAccountSnapReadCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/account/snapread", nil) // snapAccountWriteCounter measures time spent on writing/updating/deleting accounts snapAccountWriteCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/account/write", nil) diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index 7c8077b652ed..bbb2650aafc2 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -166,7 +166,7 @@ func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) { if err := snaps.Cap(common.HexToHash("0x03"), 1); err != nil { t.Fatalf("failed to merge accumulator onto disk: %v", err) } - // Since the base layer was modified, ensure that data retrievald on the external reference fail + // Since the base layer was modified, ensure that data retrievals on the external reference fail if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale { t.Errorf("stale reference returned account: %#x (err: %v)", acc, err) } @@ -224,7 +224,7 @@ func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) { if err := snaps.Cap(common.HexToHash("0x04"), 1); err != nil { t.Fatalf("failed to flatten diff layer into accumulator: %v", err) } - // Since the accumulator diff layer was modified, ensure that data retrievald on the external reference fail + // Since the accumulator diff layer was modified, ensure that data retrievals on the external reference fail if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale { t.Errorf("stale reference returned account: %#x (err: %v)", acc, err) } diff --git a/core/state/statedb.go b/core/state/statedb.go index 29a1ccf2d737..72c2aede1389 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -667,7 +667,7 @@ func (s *StateDB) Copy() *StateDB { // nil if object, exist := s.stateObjects[addr]; exist { // Even though the original object is dirty, we are not copying the journal, - // so we need to make sure that anyside effect the journal would have caused + // so we need to make sure that any side-effect the journal would have caused // during a commit (or similar op) is already applied to the copy. state.stateObjects[addr] = object.deepCopy(state) @@ -796,8 +796,8 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // resurrect an account; but the snapshotter needs both events. if s.snap != nil { s.snapDestructs[obj.addrHash] = struct{}{} // We need to maintain account deletions explicitly (will remain set indefinitely) - delete(s.snapAccounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a ressurrect) - delete(s.snapStorage, obj.addrHash) // Clear out any previously updated storage data (may be recreated via a ressurrect) + delete(s.snapAccounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a resurrect) + delete(s.snapStorage, obj.addrHash) // Clear out any previously updated storage data (may be recreated via a resurrect) } } else { obj.finalise(true) // Prefetch slots in the background diff --git a/core/tx_list.go b/core/tx_list.go index f141a03bbd96..274061c59173 100644 --- a/core/tx_list.go +++ b/core/tx_list.go @@ -469,7 +469,7 @@ func (h *priceHeap) Pop() interface{} { } // txPricedList is a price-sorted heap to allow operating on transactions pool -// contents in a price-incrementing way. It's built opon the all transactions +// contents in a price-incrementing way. It's built upon the all transactions // in txpool but only interested in the remote part. It means only remote transactions // will be considered for tracking, sorting, eviction, etc. // diff --git a/core/tx_pool.go b/core/tx_pool.go index 940678d9b1d3..a7142978ceec 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -65,7 +65,7 @@ var ( // configured for the transaction pool. ErrUnderpriced = errors.New("transaction underpriced") - // ErrTxPoolOverflow is returned if the transaction pool is full and can't accpet + // ErrTxPoolOverflow is returned if the transaction pool is full and can't accept // another remote transaction. ErrTxPoolOverflow = errors.New("txpool is full") @@ -850,7 +850,7 @@ func (pool *TxPool) AddLocals(txs []*types.Transaction) []error { } // AddLocal enqueues a single local transaction into the pool if it is valid. This is -// a convenience wrapper aroundd AddLocals. +// a convenience wrapper around AddLocals. func (pool *TxPool) AddLocal(tx *types.Transaction) error { errs := pool.AddLocals([]*types.Transaction{tx}) return errs[0] diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 2fd0f529f8f2..adc7e4fe1468 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -2158,7 +2158,7 @@ func TestTransactionReplacementDynamicFee(t *testing.T) { stages := []string{"pending", "queued"} for _, stage := range stages { // Since state is empty, 0 nonce txs are "executable" and can go - // into pending immediately. 2 nonce txs are "happed + // into pending immediately. 2 nonce txs are "gapped" nonce := uint64(0) if stage == "queued" { nonce = 2 diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 44aa930d47a3..054c3b66e7ba 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -935,7 +935,7 @@ func (c *bls12381Pairing) Run(input []byte) ([]byte, error) { return nil, errBLS12381G2PointSubgroup } - // Update pairing engine with G1 and G2 ponits + // Update pairing engine with G1 and G2 points e.AddPair(p1, p2) } // Prepare 32 byte output diff --git a/crypto/signature_cgo.go b/crypto/signature_cgo.go index bd72d97d3b62..3a32755f5e48 100644 --- a/crypto/signature_cgo.go +++ b/crypto/signature_cgo.go @@ -48,7 +48,7 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { // // This function is susceptible to chosen plaintext attacks that can leak // information about the private key that is used for signing. Callers must -// be aware that the given digest cannot be chosen by an adversery. Common +// be aware that the given digest cannot be chosen by an adversary. Common // solution is to hash any input before calculating the signature. // // The produced signature is in the [R || S || V] format where V is 0 or 1. diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 2756a02e2f6d..6653f719fc3c 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -105,7 +105,7 @@ type ConsensusAPI struct { // problematic, so we will only track the head chain segment of a bad // chain to allow discarding progressing bad chains and side chains, // without tracking too much bad data. - invalidBlocksHits map[common.Hash]int // Emhemeral cache to track invalid blocks and their hit count + invalidBlocksHits map[common.Hash]int // Ephemeral cache to track invalid blocks and their hit count invalidTipsets map[common.Hash]*types.Header // Ephemeral cache to track invalid tipsets and their bad ancestor invalidLock sync.Mutex // Protects the invalid maps from concurrent access diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index ab3ae3d77d0a..0b500484b860 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -632,7 +632,7 @@ func (q *queue) ExpireReceipts(peer string) int { // lock is not obtained in here is that the parameters already need to access // the queue, so they already need a lock anyway. func (q *queue) expire(peer string, pendPool map[string]*fetchRequest, taskQueue *prque.Prque) int { - // Retrieve the request being expired and log an error if it's non-existnet, + // Retrieve the request being expired and log an error if it's non-existent, // as there's no order of events that should lead to such expirations. req := pendPool[peer] if req == nil { diff --git a/eth/downloader/skeleton.go b/eth/downloader/skeleton.go index 517b8378c518..8dcec2292b49 100644 --- a/eth/downloader/skeleton.go +++ b/eth/downloader/skeleton.go @@ -35,7 +35,7 @@ import ( // scratchHeaders is the number of headers to store in a scratch space to allow // concurrent downloads. A header is about 0.5KB in size, so there is no worry // about using too much memory. The only catch is that we can only validate gaps -// afer they're linked to the head, so the bigger the scratch space, the larger +// after they're linked to the head, so the bigger the scratch space, the larger // potential for invalid headers. // // The current scratch space of 131072 headers is expected to use 64MB RAM. diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index 677a6422b011..d1d62eb6ef70 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -154,7 +154,7 @@ type TxFetcher struct { // broadcast without needing explicit request/reply round trips. waitlist map[common.Hash]map[string]struct{} // Transactions waiting for an potential broadcast waittime map[common.Hash]mclock.AbsTime // Timestamps when transactions were added to the waitlist - waitslots map[string]map[common.Hash]struct{} // Waiting announcement sgroupped by peer (DoS protection) + waitslots map[string]map[common.Hash]struct{} // Waiting announcements grouped by peer (DoS protection) // Stage 2: Queue of transactions that waiting to be allocated to some peer // to be retrieved directly. @@ -218,7 +218,7 @@ func (f *TxFetcher) Notify(peer string, hashes []common.Hash) error { txAnnounceInMeter.Mark(int64(len(hashes))) // Skip any transaction announcements that we already know of, or that we've - // previously marked as cheap and discarded. This check is of course racey, + // previously marked as cheap and discarded. This check is of course racy, // because multiple concurrent notifies will still manage to pass it, but it's // still valuable to check here because it runs concurrent to the internal // loop, so anything caught here is time saved internally. diff --git a/eth/protocols/eth/dispatcher.go b/eth/protocols/eth/dispatcher.go index 65a935d55548..3f81e045bae9 100644 --- a/eth/protocols/eth/dispatcher.go +++ b/eth/protocols/eth/dispatcher.go @@ -203,7 +203,7 @@ func (p *Peer) dispatcher() { } case cancelOp := <-p.reqCancel: - // Retrieve the pendign request to cancel and short circuit if it + // Retrieve the pending request to cancel and short circuit if it // has already been serviced and is not available anymore req := pending[cancelOp.id] if req == nil { diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index ef534ba37697..8c0c59ba3dc6 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -335,7 +335,7 @@ func testGetBlockBodies(t *testing.T, protocol uint) { } // Run each of the tests and verify the results against the chain for i, tt := range tests { - // Collect the hashes to request, and the response to expectva + // Collect the hashes to request, and the response to expect var ( hashes []common.Hash bodies []*BlockBody diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index a23726384d70..0a3b7bd56e1b 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -188,7 +188,7 @@ func (p *Peer) markTransaction(hash common.Hash) { // not be managed directly. // // The reasons this is public is to allow packages using this protocol to write -// tests that directly send messages without having to do the asyn queueing. +// tests that directly send messages without having to do the async queueing. func (p *Peer) SendTransactions(txs types.Transactions) error { // Mark all the transactions as known, but ensure we don't overflow our limits for _, tx := range txs { diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index e001a3883e37..60f9898f406b 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -139,7 +139,7 @@ func HandleMessage(backend Backend, peer *Peer) error { } defer msg.Discard() start := time.Now() - // Track the emount of time it takes to serve the request and run the handler + // Track the amount of time it takes to serve the request and run the handler if metrics.Enabled { h := fmt.Sprintf("%s/%s/%d/%#02x", p2p.HandleHistName, ProtocolName, peer.Version(), msg.Code) defer func(start time.Time) { @@ -343,7 +343,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP req.Bytes = softResponseLimit } // TODO(karalabe): Do we want to enforce > 0 accounts and 1 account if origin is set? - // TODO(karalabe): - Logging locally is not ideal as remote faulst annoy the local user + // TODO(karalabe): - Logging locally is not ideal as remote faults annoy the local user // TODO(karalabe): - Dropping the remote peer is less flexible wrt client bugs (slow is better than non-functional) // Calculate the hard limit at which to abort, even if mid storage trie diff --git a/eth/protocols/snap/range_test.go b/eth/protocols/snap/range_test.go index c6dc8fb718ae..3461439e54bd 100644 --- a/eth/protocols/snap/range_test.go +++ b/eth/protocols/snap/range_test.go @@ -95,7 +95,7 @@ func TestHashRanges(t *testing.T) { // meaningful space size for manual verification. // - The head being 0xff...f0, we have 14 hashes left in the space // - Chunking up 14 into 3 pieces is 4.(6), but we need the ceil of 5 to avoid a micro-last-chunk - // - Since the range is not divisible, the last interval will be shrter, capped at 0xff...f + // - Since the range is not divisible, the last interval will be shorter, capped at 0xff...f // - The chunk ranges thus needs to be [..0, ..5], [..6, ..b], [..c, ..f] { head: common.HexToHash("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0"), diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index f262824f9adf..6e8c450f51c3 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -70,7 +70,7 @@ const ( // and waste round trip times. If it's too high, we're capping responses and // waste bandwidth. // - // Depoyed bytecodes are currently capped at 24KB, so the minimum request + // Deployed bytecodes are currently capped at 24KB, so the minimum request // size should be maxRequestSize / 24K. Assuming that most contracts do not // come close to that, requesting 4x should be a good approximation. maxCodeRequestCount = maxRequestSize / (24 * 1024) * 4 @@ -87,8 +87,8 @@ const ( trienodeHealRateMeasurementImpact = 0.005 // minTrienodeHealThrottle is the minimum divisor for throttling trie node - // heal requests to avoid overloading the local node and exessively expanding - // the state trie bedth wise. + // heal requests to avoid overloading the local node and excessively expanding + // the state trie breadth wise. minTrienodeHealThrottle = 1 // maxTrienodeHealThrottle is the maximum divisor for throttling trie node diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 08b93591821b..ca93ad95cd3a 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -138,7 +138,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if _, err = st.TransitionDb(); err != nil { t.Fatalf("failed to execute transaction: %v", err) } - // Retrieve the trace result and compare against the etalon + // Retrieve the trace result and compare against the expected. res, err := tracer.GetResult() if err != nil { t.Fatalf("failed to retrieve trace result: %v", err) diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 2873dfb23b3c..084bcb8ed401 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -122,7 +122,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typ if _, err = st.TransitionDb(); err != nil { t.Fatalf("failed to execute transaction: %v", err) } - // Retrieve the trace result and compare against the etalon + // Retrieve the trace result and compare against the expected res, err := tracer.GetResult() if err != nil { t.Fatalf("failed to retrieve trace result: %v", err) diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index b75d785a0ef7..f56d9246b882 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -6,7 +6,7 @@ import ( "strings" "unicode" - // Force-load native and js pacakges, to trigger registration + // Force-load native and js packages, to trigger registration _ "github.com/ethereum/go-ethereum/eth/tracers/js" _ "github.com/ethereum/go-ethereum/eth/tracers/native" ) diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 67b1fde7569c..8bd8b0614c2d 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -392,7 +392,7 @@ func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) { t.Fatalf("unexpected error: %v", err) } - // Test tx in block interupted. + // Test tx in block interrupted. ctx, cancel := context.WithCancel(context.Background()) cancel() tx, err := ec.TransactionInBlock(ctx, block.Hash(), 0) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 64b389612aba..1a2f8bdd5e77 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -456,7 +456,7 @@ func (s *PersonalAccountAPI) signTransaction(ctx context.Context, args *Transact // passwd isn't able to decrypt the key it fails. func (s *PersonalAccountAPI) SendTransaction(ctx context.Context, args TransactionArgs, passwd string) (common.Hash, error) { if args.Nonce == nil { - // Hold the addresse's mutex around signing to prevent concurrent assignment of + // Hold the mutex around signing to prevent concurrent assignment of // the same nonce to multiple accounts. s.nonceLock.LockAddr(args.from()) defer s.nonceLock.UnlockAddr(args.from()) @@ -1719,7 +1719,7 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr } if args.Nonce == nil { - // Hold the addresse's mutex around signing to prevent concurrent assignment of + // Hold the mutex around signing to prevent concurrent assignment of // the same nonce to multiple accounts. s.nonceLock.LockAddr(args.from()) defer s.nonceLock.UnlockAddr(args.from()) diff --git a/internal/version/version.go b/internal/version/version.go index 4959102f7d84..0daea02b57e5 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -95,7 +95,7 @@ func Info() (version, vcs string) { // versionInfo returns version information for the currently executing // implementation. // -// Depending on how the code is instansiated, it returns different amounts of +// Depending on how the code is instantiated, it returns different amounts of // information. If it is unable to determine which module is related to our // package it falls back to the hardcoded values in the params package. func versionInfo(info *debug.BuildInfo) string { diff --git a/les/downloader/resultstore.go b/les/downloader/resultstore.go index a550f8c10933..7fcade294660 100644 --- a/les/downloader/resultstore.go +++ b/les/downloader/resultstore.go @@ -142,7 +142,7 @@ func (r *resultStore) HasCompletedItems() bool { // countCompleted returns the number of items ready for delivery, stopping at // the first non-complete item. // -// The mthod assumes (at least) rlock is held. +// The method assumes (at least) rlock is held. func (r *resultStore) countCompleted() int { // We iterate from the already known complete point, and see // if any more has completed since last count diff --git a/les/fetcher_test.go b/les/fetcher_test.go index 6a17e73757a5..2f3a80aa5ba3 100644 --- a/les/fetcher_test.go +++ b/les/fetcher_test.go @@ -282,7 +282,7 @@ func testInvalidAnnounces(t *testing.T, protocol int) { peer.cpeer.sendAnnounce(announce) <-done // Wait syncing - // Ensure the bad peer is evicited + // Ensure the bad peer is evicted if c.handler.backend.peers.len() != 0 { t.Fatalf("Failed to evict invalid peer") } diff --git a/les/flowcontrol/manager.go b/les/flowcontrol/manager.go index 10b6615e0431..497f91eeda79 100644 --- a/les/flowcontrol/manager.go +++ b/les/flowcontrol/manager.go @@ -223,7 +223,7 @@ func (cm *ClientManager) processed(node *ClientNode, maxCost, realCost uint64, n cm.updateBuffer(node, int64(maxCost-realCost), now) } -// updateBuffer recalulates the corrected buffer value, adds the given value to it +// updateBuffer recalculates the corrected buffer value, adds the given value to it // and updates the node's actual buffer value if possible func (cm *ClientManager) updateBuffer(node *ClientNode, add int64, now mclock.AbsTime) { cm.lock.Lock() diff --git a/les/odr.go b/les/odr.go index 2643a534787f..da2121fc5fc1 100644 --- a/les/odr.go +++ b/les/odr.go @@ -119,7 +119,7 @@ func (h peerByTxHistory) Less(i, j int) bool { func (h peerByTxHistory) Swap(i, j int) { h[i], h[j] = h[j], h[i] } const ( - maxTxStatusRetry = 3 // The maximum retrys will be made for tx status request. + maxTxStatusRetry = 3 // The maximum retries will be made for tx status request. maxTxStatusCandidates = 5 // The maximum les servers the tx status requests will be sent to. ) diff --git a/les/server_requests.go b/les/server_requests.go index b0eb2371e028..aa9b70899152 100644 --- a/les/server_requests.go +++ b/les/server_requests.go @@ -434,7 +434,7 @@ func handleGetProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) { continue } } - // Prove the user's request from the account or stroage trie + // Prove the user's request from the account or storage trie if err := trie.Prove(request.Key, request.FromLevel, nodes); err != nil { p.Log().Warn("Failed to prove state request", "block", header.Number, "hash", header.Hash(), "err", err) continue diff --git a/les/vflux/server/clientpool.go b/les/vflux/server/clientpool.go index 734d74f453c9..a525f86368d2 100644 --- a/les/vflux/server/clientpool.go +++ b/les/vflux/server/clientpool.go @@ -53,7 +53,7 @@ var ( // each client can have several minutes of connection time. // // Balances of disconnected clients are stored in nodeDB including positive balance -// and negative banalce. Boeth positive balance and negative balance will decrease +// and negative balance. Both positive balance and negative balance will decrease // exponentially. If the balance is low enough, then the record will be dropped. type ClientPool struct { *priorityPool diff --git a/light/txpool.go b/light/txpool.go index 1daeea0ad695..0de1327886fb 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -182,7 +182,7 @@ func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, number } // If some transactions have been mined, write the needed data to disk and update if list != nil { - // Retrieve all the receipts belonging to this block and write the loopup table + // Retrieve all the receipts belonging to this block and write the lookup table if _, err := GetBlockReceipts(ctx, pool.odr, hash, number); err != nil { // ODR caches, ignore results return err } diff --git a/miner/stress/1559/main.go b/miner/stress/1559/main.go index 9c1ab0f4a1fd..2e0a4f6c7328 100644 --- a/miner/stress/1559/main.go +++ b/miner/stress/1559/main.go @@ -169,7 +169,7 @@ func makeTransaction(nonce uint64, privKey *ecdsa.PrivateKey, signer types.Signe if baseFee == nil { baseFee = new(big.Int).SetInt64(int64(rand.Int31())) } - // Generate the feecap, 75% valid feecap and 25% unguaranted. + // Generate the feecap, 75% valid feecap and 25% unguaranteed. var gasFeeCap *big.Int if rand.Intn(4) == 0 { rand.Read(buf) diff --git a/mobile/interface.go b/mobile/interface.go index d5200d5b1b82..132f7ac9a5a0 100644 --- a/mobile/interface.go +++ b/mobile/interface.go @@ -31,7 +31,7 @@ import ( // Since it's impossible to get the arbitrary-ness converted between Go and mobile // platforms, we're using explicit getters and setters for the conversions. There // is of course no point in enumerating everything, just enough to support the -// contract bindins requiring client side generated code. +// contract bindings requiring client side generated code. type Interface struct { object interface{} } diff --git a/p2p/msgrate/msgrate.go b/p2p/msgrate/msgrate.go index adc3758f5b71..ff29c9620a46 100644 --- a/p2p/msgrate/msgrate.go +++ b/p2p/msgrate/msgrate.go @@ -73,7 +73,7 @@ const rttMinConfidence = 0.1 const ttlScaling = 3 // ttlLimit is the maximum timeout allowance to prevent reaching crazy numbers -// if some unforeseen network events shappen. As much as we try to hone in on +// if some unforeseen network events happen. As much as we try to hone in on // the most optimal values, it doesn't make any sense to go above a threshold, // even if everything is slow and screwy. const ttlLimit = time.Minute @@ -92,9 +92,9 @@ const tuningImpact = 0.25 // Tracker estimates the throughput capacity of a peer with regard to each data // type it can deliver. The goal is to dynamically adjust request sizes to max -// out network throughput without overloading either the peer or th elocal node. +// out network throughput without overloading either the peer or the local node. // -// By tracking in real time the latencies and bandiwdths peers exhibit for each +// By tracking in real time the latencies and bandwidths peers exhibit for each // packet type, it's possible to prevent overloading by detecting a slowdown on // one type when another type is pushed too hard. // @@ -214,7 +214,7 @@ type Trackers struct { // confidence represents the probability that the estimated roundtrip value // is the real one across all our peers. The confidence value is used as an // impact factor of new measurements on old estimates. As our connectivity - // stabilizes, this value gravitates towards 1, new measurements havinng + // stabilizes, this value gravitates towards 1, new measurements having // almost no impact. If there's a large peer churn and few peers, then new // measurements will impact it more. The confidence is increased with every // packet and dropped with every new connection. @@ -316,7 +316,7 @@ func (t *Trackers) medianRoundTrip() time.Duration { } // MeanCapacities returns the capacities averaged across all the added trackers. -// The purpos of the mean capacities are to initialize a new peer with some sane +// The purpose of the mean capacities are to initialize a new peer with some sane // starting values that it will hopefully outperform. If the mean overshoots, the // peer will be cut back to minimal capacity and given another chance. func (t *Trackers) MeanCapacities() map[uint64]float64 { diff --git a/signer/core/api.go b/signer/core/api.go index f10f03d83ac1..61793a0e51c3 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -409,7 +409,7 @@ func (api *SignerAPI) List(ctx context.Context) ([]common.Address, error) { // New creates a new password protected Account. The private key is protected with // the given password. Users are responsible to backup the private key that is stored -// in the keystore location thas was specified when this API was created. +// in the keystore location that was specified when this API was created. func (api *SignerAPI) New(ctx context.Context) (common.Address, error) { if be := api.am.Backends(keystore.KeyStoreType); len(be) == 0 { return common.Address{}, errors.New("password based accounts not supported") @@ -635,7 +635,7 @@ func (api *SignerAPI) SignGnosisSafeTx(ctx context.Context, signerAddress common gnosisTx.Signature = signature gnosisTx.SafeTxHash = common.BytesToHash(preimage) - gnosisTx.Sender = *checkSummedSender // Must be checksumed to be accepted by relay + gnosisTx.Sender = *checkSummedSender // Must be checksummed to be accepted by relay return &gnosisTx, nil } diff --git a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go index 70f26be7193f..bca93bbe19c7 100644 --- a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go +++ b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go @@ -179,7 +179,7 @@ func (f *fuzzer) fuzz() int { return ok } -// Fuzz is the fuzzing entryy-point. +// Fuzz is the fuzzing entry-point. // The function must return // // - 1 if the fuzzer should increase priority of the diff --git a/tests/fuzzers/runtime/runtime_fuzz.go b/tests/fuzzers/runtime/runtime_fuzz.go index 9b9604575279..b30e9243d89d 100644 --- a/tests/fuzzers/runtime/runtime_fuzz.go +++ b/tests/fuzzers/runtime/runtime_fuzz.go @@ -22,7 +22,7 @@ import ( // Fuzz is the basic entry point for the go-fuzz tool // -// This returns 1 for valid parsable/runable code, 0 +// This returns 1 for valid parse:able/runnable code, 0 // for invalid opcode. func Fuzz(input []byte) int { _, _, err := runtime.Execute(input, input, &runtime.Config{ diff --git a/trie/proof.go b/trie/proof.go index 8e706f886b59..af49ce36b36c 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -373,7 +373,7 @@ func unset(parent node, child node, key []byte, pos int, removeLeft bool) error if removeLeft { if bytes.Compare(cld.Key, key[pos:]) < 0 { // The key of fork shortnode is less than the path - // (it belongs to the range), unset the entrie + // (it belongs to the range), unset the entire // branch. The parent must be a fullnode. fn := parent.(*fullNode) fn.Children[key[pos-1]] = nil diff --git a/trie/stacktrie.go b/trie/stacktrie.go index d37375d35d52..2df2cd6ed016 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -494,7 +494,7 @@ func (st *StackTrie) Hash() (h common.Hash) { return h } -// Commit will firstly hash the entrie trie if it's still not hashed +// Commit will firstly hash the entire trie if it's still not hashed // and then commit all nodes to the associated database. Actually most // of the trie nodes MAY have been committed already. The main purpose // here is to commit the root node. diff --git a/trie/trie_test.go b/trie/trie_test.go index d2a599ffdd64..832546b1e344 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -609,7 +609,7 @@ func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { } // Benchmarks the trie hashing. Since the trie caches the result of any operation, -// we cannot use b.N as the number of hashing rouns, since all rounds apart from +// we cannot use b.N as the number of hashing rounds, since all rounds apart from // the first one will be NOOP. As such, we'll use b.N as the number of account to // insert into the trie before measuring the hashing. // BenchmarkHash-6 288680 4561 ns/op 682 B/op 9 allocs/op @@ -644,7 +644,7 @@ func BenchmarkHash(b *testing.B) { } // Benchmarks the trie Commit following a Hash. Since the trie caches the result of any operation, -// we cannot use b.N as the number of hashing rouns, since all rounds apart from +// we cannot use b.N as the number of hashing rounds, since all rounds apart from // the first one will be NOOP. As such, we'll use b.N as the number of account to // insert into the trie before measuring the hashing. func BenchmarkCommitAfterHash(b *testing.B) { From 1c737e8b6da2b14111f8224ef3f385b1fe0cd8b9 Mon Sep 17 00:00:00 2001 From: Paul <41552663+molecula451@users.noreply.github.com> Date: Tue, 11 Oct 2022 02:37:33 -0500 Subject: [PATCH 300/715] cmd/geth, core: fix typo in comment (#25954) * fix typo on comment * typo "can't accept" --- cmd/geth/consolecmd_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index 442b82df0b3c..a5a23ccdfd65 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -120,7 +120,7 @@ func TestAttachWelcome(t *testing.T) { } func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { - // Attach to a running geth note and terminate immediately + // Attach to a running geth node and terminate immediately attach := runGeth(t, "attach", endpoint) defer attach.ExpectExit() attach.CloseStdin() From 28d076d37e667f26e1f60b97484bed0b5d3cbec2 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 12 Oct 2022 09:35:09 +0200 Subject: [PATCH 301/715] core/rawdb: provide more info on 'gap in the chain' error (#25938) --- core/rawdb/database.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 1eaf033bbefa..2cc3a7c85c21 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -240,8 +240,8 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st if kvhash, _ := db.Get(headerHashKey(frozen)); len(kvhash) == 0 { // Subsequent header after the freezer limit is missing from the database. // Reject startup if the database has a more recent head. - if *ReadHeaderNumber(db, ReadHeadHeaderHash(db)) > frozen-1 { - return nil, fmt.Errorf("gap (#%d) in the chain between ancients and leveldb", frozen) + if ldbNum := *ReadHeaderNumber(db, ReadHeadHeaderHash(db)); ldbNum > frozen-1 { + return nil, fmt.Errorf("gap in the chain between ancients (#%d) and leveldb (#%d) ", frozen, ldbNum) } // Database contains only older data than the freezer, this happens if the // state was wiped and reinited from an existing freezer. From a007ab786cc0feaf304d767af9f4e3fc4eb79d72 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 12 Oct 2022 10:27:39 +0200 Subject: [PATCH 302/715] core/types: add more context around ErrInvalidChainID (#25367) This changes the error message for mismatching chain ID to show the given and expected value. Callers expecting this error must be changed to use errors.Is. --- core/types/transaction_signing.go | 10 +++++----- core/types/transaction_signing_test.go | 5 +++-- core/types/transaction_test.go | 5 +++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 5f8048493577..87f0390a6f9c 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -190,7 +190,7 @@ func (s londonSigner) Sender(tx *Transaction) (common.Address, error) { // id, add 27 to become equivalent to unprotected Homestead signatures. V = new(big.Int).Add(V, big.NewInt(27)) if tx.ChainId().Cmp(s.chainId) != 0 { - return common.Address{}, ErrInvalidChainId + return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId) } return recoverPlain(s.Hash(tx), R, S, V, true) } @@ -208,7 +208,7 @@ func (s londonSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big // Check that chain ID of tx matches the signer. We also accept ID zero here, // because it indicates that the chain ID was not specified in the tx. if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 { - return nil, nil, nil, ErrInvalidChainId + return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) } R, S, _ = decodeSignature(sig) V = big.NewInt(int64(sig[64])) @@ -270,7 +270,7 @@ func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) { return common.Address{}, ErrTxTypeNotSupported } if tx.ChainId().Cmp(s.chainId) != 0 { - return common.Address{}, ErrInvalidChainId + return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId) } return recoverPlain(s.Hash(tx), R, S, V, true) } @@ -283,7 +283,7 @@ func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *bi // Check that chain ID of tx matches the signer. We also accept ID zero here, // because it indicates that the chain ID was not specified in the tx. if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 { - return nil, nil, nil, ErrInvalidChainId + return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) } R, S, _ = decodeSignature(sig) V = big.NewInt(int64(sig[64])) @@ -364,7 +364,7 @@ func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) { return HomesteadSigner{}.Sender(tx) } if tx.ChainId().Cmp(s.chainId) != 0 { - return common.Address{}, ErrInvalidChainId + return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId) } V, R, S := tx.RawSignatureValues() V = new(big.Int).Sub(V, s.chainIdMul) diff --git a/core/types/transaction_signing_test.go b/core/types/transaction_signing_test.go index 1c775f129d65..2a9ceb09529f 100644 --- a/core/types/transaction_signing_test.go +++ b/core/types/transaction_signing_test.go @@ -17,6 +17,7 @@ package types import ( + "errors" "math/big" "testing" @@ -126,8 +127,8 @@ func TestChainId(t *testing.T) { } _, err = Sender(NewEIP155Signer(big.NewInt(2)), tx) - if err != ErrInvalidChainId { - t.Error("expected error:", ErrInvalidChainId) + if !errors.Is(err, ErrInvalidChainId) { + t.Error("expected error:", ErrInvalidChainId, err) } _, err = Sender(NewEIP155Signer(big.NewInt(1)), tx) diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 67e5b3cce3f5..8e8ee595c971 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -20,6 +20,7 @@ import ( "bytes" "crypto/ecdsa" "encoding/json" + "errors" "fmt" "math/big" "math/rand" @@ -170,14 +171,14 @@ func TestEIP2930Signer(t *testing.T) { t.Errorf("test %d: wrong sig hash: got %x, want %x", i, sigHash, test.wantSignerHash) } sender, err := Sender(test.signer, test.tx) - if err != test.wantSenderErr { + if !errors.Is(err, test.wantSenderErr) { t.Errorf("test %d: wrong Sender error %q", i, err) } if err == nil && sender != keyAddr { t.Errorf("test %d: wrong sender address %x", i, sender) } signedTx, err := SignTx(test.tx, test.signer, key) - if err != test.wantSignErr { + if !errors.Is(err, test.wantSignErr) { t.Fatalf("test %d: wrong SignTx error %q", i, err) } if signedTx != nil { From bed3b100867daab55a8e3c639ead8da9cda89a3c Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 12 Oct 2022 10:34:52 +0200 Subject: [PATCH 303/715] common/math: optimized modexp (+ fuzzer) (#25525) This adds a * core/vm, tests: optimized modexp + fuzzer * common/math: modexp optimizations * core/vm: special case base 1 in big modexp * core/vm: disable fastexp --- common/math/modexp.go | 82 ++++++++++++++++++++++++++ core/vm/contracts.go | 15 ++++- oss-fuzz.sh | 2 + tests/fuzzers/modexp/modexp-fuzzer.go | 84 +++++++++++++++++++++++++++ 4 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 common/math/modexp.go create mode 100644 tests/fuzzers/modexp/modexp-fuzzer.go diff --git a/common/math/modexp.go b/common/math/modexp.go new file mode 100644 index 000000000000..b0a32e8c2739 --- /dev/null +++ b/common/math/modexp.go @@ -0,0 +1,82 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package math + +import ( + "math/big" + "math/bits" + + "github.com/ethereum/go-ethereum/common" +) + +// FastExp is semantically equivalent to x.Exp(x,y, m), but is faster for even +// modulus. +func FastExp(x, y, m *big.Int) *big.Int { + // Split m = m1 × m2 where m1 = 2ⁿ + n := m.TrailingZeroBits() + m1 := new(big.Int).Lsh(common.Big1, n) + mask := new(big.Int).Sub(m1, common.Big1) + m2 := new(big.Int).Rsh(m, n) + + // We want z = x**y mod m. + // z1 = x**y mod m1 = (x**y mod m) mod m1 = z mod m1 + // z2 = x**y mod m2 = (x**y mod m) mod m2 = z mod m2 + z1 := fastExpPow2(x, y, mask) + z2 := new(big.Int).Exp(x, y, m2) + + // Reconstruct z from z1, z2 using CRT, using algorithm from paper, + // which uses only a single modInverse. + // p = (z1 - z2) * m2⁻¹ (mod m1) + // z = z2 + p * m2 + z := new(big.Int).Set(z2) + + // Compute (z1 - z2) mod m1 [m1 == 2**n] into z1. + z1 = z1.And(z1, mask) + z2 = z2.And(z2, mask) + z1 = z1.Sub(z1, z2) + if z1.Sign() < 0 { + z1 = z1.Add(z1, m1) + } + + // Reuse z2 for p = z1 * m2inv. + m2inv := new(big.Int).ModInverse(m2, m1) + z2 = z2.Mul(z1, m2inv) + z2 = z2.And(z2, mask) + + // Reuse z1 for m2 * p. + z = z.Add(z, z1.Mul(z2, m2)) + z = z.Rem(z, m) + + return z +} + +func fastExpPow2(x, y *big.Int, mask *big.Int) *big.Int { + z := big.NewInt(1) + if y.Sign() == 0 { + return z + } + p := new(big.Int).Set(x) + p = p.And(p, mask) + if p.Cmp(z) <= 0 { // p <= 1 + return p + } + if y.Cmp(mask) > 0 { + y = new(big.Int).And(y, mask) + } + t := new(big.Int) + + for _, b := range y.Bits() { + for i := 0; i < bits.UintSize; i++ { + if b&1 != 0 { + z, t = t.Mul(z, p), z + z = z.And(z, mask) + } + p, t = t.Mul(p, p), p + p = p.And(p, mask) + b >>= 1 + } + } + return z +} diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 054c3b66e7ba..d0e3e6913917 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -380,12 +380,23 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) { base = new(big.Int).SetBytes(getData(input, 0, baseLen)) exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + v []byte ) - if mod.BitLen() == 0 { + switch { + case mod.BitLen() == 0: // Modulo 0 is undefined, return zero return common.LeftPadBytes([]byte{}, int(modLen)), nil + case base.Cmp(common.Big1) == 0: + //If base == 1, then we can just return base % mod (if mod >= 1, which it is) + v = base.Mod(base, mod).Bytes() + //case mod.Bit(0) == 0: + // // Modulo is even + // v = math.FastExp(base, exp, mod).Bytes() + default: + // Modulo is odd + v = base.Exp(base, exp, mod).Bytes() } - return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), int(modLen)), nil + return common.LeftPadBytes(v, int(modLen)), nil } // newCurvePoint unmarshals a binary blob into a bn256 elliptic curve point, diff --git a/oss-fuzz.sh b/oss-fuzz.sh index 745a5ba7c7c0..7f454ff307b4 100644 --- a/oss-fuzz.sh +++ b/oss-fuzz.sh @@ -125,5 +125,7 @@ compile_fuzzer tests/fuzzers/snap FuzzSRange fuzz_storage_range compile_fuzzer tests/fuzzers/snap FuzzByteCodes fuzz_byte_codes compile_fuzzer tests/fuzzers/snap FuzzTrieNodes fuzz_trie_nodes +compile_fuzzer tests/fuzzers/modexp Fuzz fuzzModexp + #TODO: move this to tests/fuzzers, if possible compile_fuzzer crypto/blake2b Fuzz fuzzBlake2b diff --git a/tests/fuzzers/modexp/modexp-fuzzer.go b/tests/fuzzers/modexp/modexp-fuzzer.go new file mode 100644 index 000000000000..0068c5030259 --- /dev/null +++ b/tests/fuzzers/modexp/modexp-fuzzer.go @@ -0,0 +1,84 @@ +// Copyright 2022 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 modexp + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/vm" +) + +// The function must return +// 1 if the fuzzer should increase priority of the +// given input during subsequent fuzzing (for example, the input is lexically +// correct and was parsed successfully); +// -1 if the input must not be added to corpus even if gives new coverage; and +// 0 otherwise +// other values are reserved for future use. +func Fuzz(input []byte) int { + if len(input) <= 96 { + return -1 + } + // Abort on too expensive inputs + precomp := vm.PrecompiledContractsBerlin[common.BytesToAddress([]byte{5})] + if gas := precomp.RequiredGas(input); gas > 40_000_000 { + return 0 + } + 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() + ) + // Handle a special case when both the base and mod length is zero + if baseLen == 0 && modLen == 0 { + return -1 + } + input = input[96:] + // Retrieve the operands and execute the exponentiation + var ( + base = new(big.Int).SetBytes(getData(input, 0, baseLen)) + exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) + mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + ) + if mod.BitLen() == 0 { + // Modulo 0 is undefined, return zero + return -1 + } + var a = math.FastExp(new(big.Int).Set(base), new(big.Int).Set(exp), new(big.Int).Set(mod)) + var b = base.Exp(base, exp, mod) + if a.Cmp(b) != 0 { + panic(fmt.Sprintf("Inequality %x != %x", a, b)) + } + return 1 +} + +// getData returns a slice from the data based on the start and size and pads +// up to size with zero's. This function is overflow safe. +func getData(data []byte, start uint64, size uint64) []byte { + length := uint64(len(data)) + if start > length { + start = length + } + end := start + size + if end > length { + end = length + } + return common.RightPadBytes(data[start:end], int(size)) +} From e257b3add767da078921b65f9e6d7608145f9f9f Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 12 Oct 2022 10:39:21 +0200 Subject: [PATCH 304/715] tests/fuzzers/modexp: gofmt (#25972) --- tests/fuzzers/modexp/modexp-fuzzer.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/fuzzers/modexp/modexp-fuzzer.go b/tests/fuzzers/modexp/modexp-fuzzer.go index 0068c5030259..a28840494292 100644 --- a/tests/fuzzers/modexp/modexp-fuzzer.go +++ b/tests/fuzzers/modexp/modexp-fuzzer.go @@ -25,12 +25,15 @@ import ( "github.com/ethereum/go-ethereum/core/vm" ) +// Fuzz is the fuzzing entry-point. // The function must return -// 1 if the fuzzer should increase priority of the -// given input during subsequent fuzzing (for example, the input is lexically -// correct and was parsed successfully); -// -1 if the input must not be added to corpus even if gives new coverage; and -// 0 otherwise +// +// - 1 if the fuzzer should increase priority of the +// given input during subsequent fuzzing (for example, the input is lexically +// correct and was parsed successfully); +// - -1 if the input must not be added to corpus even if gives new coverage; and +// - 0 otherwise +// // other values are reserved for future use. func Fuzz(input []byte) int { if len(input) <= 96 { From 3630cafb34f7c48b9cc78cf736309275cbd70f74 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Wed, 12 Oct 2022 03:50:12 -0500 Subject: [PATCH 305/715] node: drop support for static & trusted node list files (#25610) This changes the node setup to ignore datadir files static-nodes.json trusted-nodes.json When these files are present, it an error will be printed to the log. --- node/config.go | 79 +++++++++++++++----------------------------------- node/node.go | 7 +---- 2 files changed, 24 insertions(+), 62 deletions(-) diff --git a/node/config.go b/node/config.go index 49959d5ec5de..e2099ee0f6ab 100644 --- a/node/config.go +++ b/node/config.go @@ -23,13 +23,11 @@ import ( "path/filepath" "runtime" "strings" - "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" ) @@ -194,8 +192,6 @@ type Config struct { // Logger is a custom logger to use with the p2p.Server. Logger log.Logger `toml:",omitempty"` - staticNodesWarning bool - trustedNodesWarning bool oldGethResourceWarning bool // AllowUnprotectedTxs allows non EIP-155 protected transactions to be send over RPC. @@ -340,8 +336,9 @@ func (c *Config) ResolvePath(path string) string { oldpath = filepath.Join(c.DataDir, path) } if oldpath != "" && common.FileExist(oldpath) { - if warn { - c.warnOnce(&c.oldGethResourceWarning, "Using deprecated resource file %s, please move this file to the 'geth' subdirectory of datadir.", oldpath) + if warn && !c.oldGethResourceWarning { + c.oldGethResourceWarning = true + log.Warn("Using deprecated resource file, please move this file to the 'geth' subdirectory of datadir.", "file", oldpath) } return oldpath } @@ -394,48 +391,35 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey { return key } -// StaticNodes returns a list of node enode URLs configured as static nodes. -func (c *Config) StaticNodes() []*enode.Node { - return c.parsePersistentNodes(&c.staticNodesWarning, c.ResolvePath(datadirStaticNodes)) +// CheckLegacyFiles inspects the datadir for signs of legacy static-nodes +// and trusted-nodes files. If they exist it raises an error. +func (c *Config) checkLegacyFiles() { + c.checkLegacyFile(c.ResolvePath(datadirStaticNodes)) + c.checkLegacyFile(c.ResolvePath(datadirTrustedNodes)) } -// TrustedNodes returns a list of node enode URLs configured as trusted nodes. -func (c *Config) TrustedNodes() []*enode.Node { - return c.parsePersistentNodes(&c.trustedNodesWarning, c.ResolvePath(datadirTrustedNodes)) -} - -// parsePersistentNodes parses a list of discovery node URLs loaded from a .json -// file from within the data directory. -func (c *Config) parsePersistentNodes(w *bool, path string) []*enode.Node { +// checkLegacyFile will only raise an error if a file at the given path exists. +func (c *Config) checkLegacyFile(path string) { // Short circuit if no node config is present if c.DataDir == "" { - return nil + return } if _, err := os.Stat(path); err != nil { - return nil + return } - c.warnOnce(w, "Found deprecated node list file %s, please use the TOML config file instead.", path) - - // Load the nodes from the config file. - var nodelist []string - if err := common.LoadJSON(path, &nodelist); err != nil { - log.Error(fmt.Sprintf("Can't load node list file: %v", err)) - return nil + logger := c.Logger + if logger == nil { + logger = log.Root() } - // Interpret the list as a discovery node array - var nodes []*enode.Node - for _, url := range nodelist { - if url == "" { - continue - } - node, err := enode.Parse(enode.ValidSchemes, url) - if err != nil { - log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err)) - continue - } - nodes = append(nodes, node) + switch fname := filepath.Base(path); fname { + case "static-nodes.json": + logger.Error("The static-nodes.json file is deprecated and ignored. Use P2P.StaticNodes in config.toml instead.") + case "trusted-nodes.json": + logger.Error("The trusted-nodes.json file is deprecated and ignored. Use P2P.TrustedNodes in config.toml instead.") + default: + // We shouldn't wind up here, but better print something just in case. + logger.Error("Ignoring deprecated file.", "file", path) } - return nodes } // KeyDirConfig determines the settings for keydirectory @@ -482,20 +466,3 @@ func getKeyStoreDir(conf *Config) (string, bool, error) { return keydir, isEphemeral, nil } - -var warnLock sync.Mutex - -func (c *Config) warnOnce(w *bool, format string, args ...interface{}) { - warnLock.Lock() - defer warnLock.Unlock() - - if *w { - return - } - l := c.Logger - if l == nil { - l = log.Root() - } - l.Warn(fmt.Sprintf(format, args...)) - *w = true -} diff --git a/node/node.go b/node/node.go index c8fda1fe3c61..4d9072e2c96b 100644 --- a/node/node.go +++ b/node/node.go @@ -133,12 +133,7 @@ func New(conf *Config) (*Node, error) { node.server.Config.PrivateKey = node.config.NodeKey() node.server.Config.Name = node.config.NodeName() node.server.Config.Logger = node.log - if node.server.Config.StaticNodes == nil { - node.server.Config.StaticNodes = node.config.StaticNodes() - } - if node.server.Config.TrustedNodes == nil { - node.server.Config.TrustedNodes = node.config.TrustedNodes() - } + node.config.checkLegacyFiles() if node.server.Config.NodeDatabase == "" { node.server.Config.NodeDatabase = node.config.NodeDB() } From eaf095ccd412aae3da7ca8635cf5fde0b9ebb124 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 12 Oct 2022 10:53:01 +0200 Subject: [PATCH 306/715] accounts/keystore: faster tests (#25827) This PR removes some optimistic tests -- a'la "do something, wait a while, and hope it has trickled through and continue" -- and instead uses some introspection to ensure that prerequisites are met. --- accounts/keystore/account_cache.go | 8 +++ accounts/keystore/account_cache_test.go | 91 +++++++++++++------------ accounts/keystore/keystore.go | 8 +++ accounts/keystore/keystore_test.go | 63 +++++++++-------- accounts/keystore/watch.go | 9 ++- accounts/keystore/watch_fallback.go | 8 ++- 6 files changed, 111 insertions(+), 76 deletions(-) diff --git a/accounts/keystore/account_cache.go b/accounts/keystore/account_cache.go index a3ec6e9c5606..db49ec349942 100644 --- a/accounts/keystore/account_cache.go +++ b/accounts/keystore/account_cache.go @@ -146,6 +146,14 @@ func (ac *accountCache) deleteByFile(path string) { } } +// watcherStarted returns true if the watcher loop started running (even if it +// has since also ended). +func (ac *accountCache) watcherStarted() bool { + ac.mu.Lock() + defer ac.mu.Unlock() + return ac.watcher.running || ac.watcher.runEnded +} + func removeAccount(slice []accounts.Account, elem accounts.Account) []accounts.Account { for i := range slice { if slice[i] == elem { diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index daea497d1ae7..01db587d1599 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -50,6 +50,38 @@ var ( } ) +// waitWatcherStarts waits up to 1s for the keystore watcher to start. +func waitWatcherStart(ks *KeyStore) bool { + // On systems where file watch is not supported, just return "ok". + if !ks.cache.watcher.enabled() { + return true + } + // The watcher should start, and then exit. + for t0 := time.Now(); time.Since(t0) < 1*time.Second; time.Sleep(100 * time.Millisecond) { + if ks.cache.watcherStarted() { + return true + } + } + return false +} + +func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error { + var list []accounts.Account + for t0 := time.Now(); time.Since(t0) < 5*time.Second; time.Sleep(200 * time.Millisecond) { + list = ks.Accounts() + if reflect.DeepEqual(list, wantAccounts) { + // ks should have also received change notifications + select { + case <-ks.changes: + default: + return fmt.Errorf("wasn't notified of new accounts") + } + return nil + } + } + return fmt.Errorf("\ngot %v\nwant %v", list, wantAccounts) +} + func TestWatchNewFile(t *testing.T) { t.Parallel() @@ -57,8 +89,9 @@ func TestWatchNewFile(t *testing.T) { // Ensure the watcher is started before adding any files. ks.Accounts() - time.Sleep(1000 * time.Millisecond) - + if !waitWatcherStart(ks) { + t.Fatal("keystore watcher didn't start in time") + } // Move in the files. wantAccounts := make([]accounts.Account, len(cachetestAccounts)) for i := range cachetestAccounts { @@ -72,37 +105,25 @@ func TestWatchNewFile(t *testing.T) { } // ks should see the accounts. - var list []accounts.Account - for d := 200 * time.Millisecond; d < 5*time.Second; d *= 2 { - list = ks.Accounts() - if reflect.DeepEqual(list, wantAccounts) { - // ks should have also received change notifications - select { - case <-ks.changes: - default: - t.Fatalf("wasn't notified of new accounts") - } - return - } - time.Sleep(d) + if err := waitForAccounts(wantAccounts, ks); err != nil { + t.Error(err) } - t.Errorf("got %s, want %s", spew.Sdump(list), spew.Sdump(wantAccounts)) } func TestWatchNoDir(t *testing.T) { t.Parallel() - // Create ks but not the directory that it watches. rand.Seed(time.Now().UnixNano()) dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int())) ks := NewKeyStore(dir, LightScryptN, LightScryptP) - list := ks.Accounts() if len(list) > 0 { t.Error("initial account list not empty:", list) } - time.Sleep(100 * time.Millisecond) - + // The watcher should start, and then exit. + if !waitWatcherStart(ks) { + t.Fatal("keystore watcher didn't start in time") + } // Create the directory and copy a key file into it. os.MkdirAll(dir, 0700) defer os.RemoveAll(dir) @@ -295,24 +316,6 @@ func TestCacheFind(t *testing.T) { } } -func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error { - var list []accounts.Account - for d := 200 * time.Millisecond; d < 8*time.Second; d *= 2 { - list = ks.Accounts() - if reflect.DeepEqual(list, wantAccounts) { - // ks should have also received change notifications - select { - case <-ks.changes: - default: - return fmt.Errorf("wasn't notified of new accounts") - } - return nil - } - time.Sleep(d) - } - return fmt.Errorf("\ngot %v\nwant %v", list, wantAccounts) -} - // TestUpdatedKeyfileContents tests that updating the contents of a keystore file // is noticed by the watcher, and the account cache is updated accordingly func TestUpdatedKeyfileContents(t *testing.T) { @@ -327,8 +330,9 @@ func TestUpdatedKeyfileContents(t *testing.T) { if len(list) > 0 { t.Error("initial account list not empty:", list) } - time.Sleep(100 * time.Millisecond) - + if !waitWatcherStart(ks) { + t.Fatal("keystore watcher didn't start in time") + } // Create the directory and copy a key file into it. os.MkdirAll(dir, 0700) defer os.RemoveAll(dir) @@ -346,9 +350,8 @@ func TestUpdatedKeyfileContents(t *testing.T) { t.Error(err) return } - // needed so that modTime of `file` is different to its current value after forceCopyFile - time.Sleep(1000 * time.Millisecond) + time.Sleep(time.Second) // Now replace file contents if err := forceCopyFile(file, cachetestAccounts[1].URL.Path); err != nil { @@ -364,7 +367,7 @@ func TestUpdatedKeyfileContents(t *testing.T) { } // needed so that modTime of `file` is different to its current value after forceCopyFile - time.Sleep(1000 * time.Millisecond) + time.Sleep(time.Second) // Now replace file contents again if err := forceCopyFile(file, cachetestAccounts[2].URL.Path); err != nil { @@ -380,7 +383,7 @@ func TestUpdatedKeyfileContents(t *testing.T) { } // needed so that modTime of `file` is different to its current value after os.WriteFile - time.Sleep(1000 * time.Millisecond) + time.Sleep(time.Second) // Now replace file contents with crap if err := os.WriteFile(file, []byte("foo"), 0600); err != nil { diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 88dcfbeb69e0..0ffcf376a5fd 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -498,6 +498,14 @@ func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (account return a, nil } +// isUpdating returns whether the event notification loop is running. +// This method is mainly meant for tests. +func (ks *KeyStore) isUpdating() bool { + ks.mu.RLock() + defer ks.mu.RUnlock() + return ks.updating +} + // zeroKey zeroes a private key in memory. func zeroKey(k *ecdsa.PrivateKey) { b := k.D.Bits() diff --git a/accounts/keystore/keystore_test.go b/accounts/keystore/keystore_test.go index 4cdf0b1ed6ce..f90d809b55f4 100644 --- a/accounts/keystore/keystore_test.go +++ b/accounts/keystore/keystore_test.go @@ -113,6 +113,7 @@ func TestSignWithPassphrase(t *testing.T) { } func TestTimedUnlock(t *testing.T) { + t.Parallel() _, ks := tmpKeyStore(t, true) pass := "foo" @@ -147,6 +148,7 @@ func TestTimedUnlock(t *testing.T) { } func TestOverrideUnlock(t *testing.T) { + t.Parallel() _, ks := tmpKeyStore(t, false) pass := "foo" @@ -187,6 +189,7 @@ func TestOverrideUnlock(t *testing.T) { // This test should fail under -race if signing races the expiration goroutine. func TestSignRace(t *testing.T) { + t.Parallel() _, ks := tmpKeyStore(t, false) // Create a test account. @@ -211,19 +214,33 @@ func TestSignRace(t *testing.T) { t.Errorf("Account did not lock within the timeout") } +// waitForKsUpdating waits until the updating-status of the ks reaches the +// desired wantStatus. +// It waits for a maximum time of maxTime, and returns false if it does not +// finish in time +func waitForKsUpdating(t *testing.T, ks *KeyStore, wantStatus bool, maxTime time.Duration) bool { + t.Helper() + // Wait max 250 ms, then return false + for t0 := time.Now(); time.Since(t0) < maxTime; { + if ks.isUpdating() == wantStatus { + return true + } + time.Sleep(25 * time.Millisecond) + } + return false +} + // Tests that the wallet notifier loop starts and stops correctly based on the // addition and removal of wallet event subscriptions. func TestWalletNotifierLifecycle(t *testing.T) { + t.Parallel() // Create a temporary keystore to test with _, ks := tmpKeyStore(t, false) // Ensure that the notification updater is not running yet time.Sleep(250 * time.Millisecond) - ks.mu.RLock() - updating := ks.updating - ks.mu.RUnlock() - if updating { + if ks.isUpdating() { t.Errorf("wallet notifier running without subscribers") } // Subscribe to the wallet feed and ensure the updater boots up @@ -233,38 +250,26 @@ func TestWalletNotifierLifecycle(t *testing.T) { for i := 0; i < len(subs); i++ { // Create a new subscription subs[i] = ks.Subscribe(updates) - - // Ensure the notifier comes online - time.Sleep(250 * time.Millisecond) - ks.mu.RLock() - updating = ks.updating - ks.mu.RUnlock() - - if !updating { + if !waitForKsUpdating(t, ks, true, 250*time.Millisecond) { t.Errorf("sub %d: wallet notifier not running after subscription", i) } } - // Unsubscribe and ensure the updater terminates eventually - for i := 0; i < len(subs); i++ { + // Close all but one sub + for i := 0; i < len(subs)-1; i++ { // Close an existing subscription subs[i].Unsubscribe() + } + // Check that it is still running + time.Sleep(250 * time.Millisecond) - // Ensure the notifier shuts down at and only at the last close - for k := 0; k < int(walletRefreshCycle/(250*time.Millisecond))+2; k++ { - ks.mu.RLock() - updating = ks.updating - ks.mu.RUnlock() - - if i < len(subs)-1 && !updating { - t.Fatalf("sub %d: event notifier stopped prematurely", i) - } - if i == len(subs)-1 && !updating { - return - } - time.Sleep(250 * time.Millisecond) - } + if !ks.isUpdating() { + t.Fatal("event notifier stopped prematurely") + } + // Unsubscribe the last one and ensure the updater terminates eventually. + subs[len(subs)-1].Unsubscribe() + if !waitForKsUpdating(t, ks, false, 4*time.Second) { + t.Errorf("wallet notifier didn't terminate after unsubscribe") } - t.Errorf("wallet notifier didn't terminate after unsubscribe") } type walletEvent struct { diff --git a/accounts/keystore/watch.go b/accounts/keystore/watch.go index ad176040d68c..ae72a1ccd666 100644 --- a/accounts/keystore/watch.go +++ b/accounts/keystore/watch.go @@ -28,8 +28,9 @@ import ( type watcher struct { ac *accountCache - starting bool - running bool + running bool // set to true when runloop begins + runEnded bool // set to true when runloop ends + starting bool // set to true prior to runloop starting ev chan notify.EventInfo quit chan struct{} } @@ -42,6 +43,9 @@ func newWatcher(ac *accountCache) *watcher { } } +// enabled returns false on systems not supported. +func (*watcher) enabled() bool { return true } + // starts the watcher loop in the background. // Start a watcher in the background if that's not already in progress. // The caller must hold w.ac.mu. @@ -62,6 +66,7 @@ func (w *watcher) loop() { w.ac.mu.Lock() w.running = false w.starting = false + w.runEnded = true w.ac.mu.Unlock() }() logger := log.New("path", w.ac.keydir) diff --git a/accounts/keystore/watch_fallback.go b/accounts/keystore/watch_fallback.go index e40eca42fe75..e3c133b3f6ad 100644 --- a/accounts/keystore/watch_fallback.go +++ b/accounts/keystore/watch_fallback.go @@ -22,8 +22,14 @@ package keystore -type watcher struct{ running bool } +type watcher struct { + running bool + runEnded bool +} func newWatcher(*accountCache) *watcher { return new(watcher) } func (*watcher) start() {} func (*watcher) close() {} + +// enabled returns false on systems not supported. +func (*watcher) enabled() bool { return false } From 010f47f76ac355caa7ec44ff87a1d5e0a7accf63 Mon Sep 17 00:00:00 2001 From: Jens W <8270201+DragonDev1906@users.noreply.github.com> Date: Wed, 12 Oct 2022 11:15:19 +0200 Subject: [PATCH 307/715] eth/protocols/eth: fix typo in log message (#25969) --- eth/protocols/eth/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index c8585dfdf8f2..d454b3407f3c 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -84,7 +84,7 @@ func serviceNonContiguousBlockHeaderQuery(chain *core.BlockChain, query *GetBloc break } if rlpData, err := rlp.EncodeToBytes(origin); err != nil { - log.Crit("Unable to decode our own headers", "err", err) + log.Crit("Unable to encode our own headers", "err", err) } else { headers = append(headers, rlp.RawValue(rlpData)) bytes += common.StorageSize(len(rlpData)) From 5b1a04b9c749d804b51159fe12246c56de8515c1 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Wed, 12 Oct 2022 11:54:52 +0200 Subject: [PATCH 308/715] eth/filters, ethclient/gethclient: add fullTx option to pending tx filter (#25186) This PR adds a way to subscribe to the _full_ pending transactions, as opposed to just being notified about hashes. In use cases where client subscribes to newPendingTransactions and gets txhashes only to then request the actual transaction, the caller can now shortcut that flow and obtain the transactions directly. Co-authored-by: Felix Lange --- eth/filters/api.go | 38 +++++++++++++++--------- eth/filters/filter_system.go | 28 ++++++++---------- eth/filters/filter_system_test.go | 22 +++++++------- ethclient/gethclient/gethclient.go | 7 ++++- ethclient/gethclient/gethclient_test.go | 39 ++++++++++++++++++++++++- 5 files changed, 91 insertions(+), 43 deletions(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index 43e63d5ba98a..f52bff6f3c32 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -38,6 +38,7 @@ type filter struct { typ Type deadline *time.Timer // filter is inactive when deadline triggers hashes []common.Hash + txs []*types.Transaction crit FilterCriteria logs []*types.Log s *Subscription // associated subscription in event system @@ -96,28 +97,28 @@ func (api *FilterAPI) timeoutLoop(timeout time.Duration) { } } -// NewPendingTransactionFilter creates a filter that fetches pending transaction hashes +// NewPendingTransactionFilter creates a filter that fetches pending transactions // as transactions enter the pending state. // // It is part of the filter package because this filter can be used through the // `eth_getFilterChanges` polling method that is also used for log filters. func (api *FilterAPI) NewPendingTransactionFilter() rpc.ID { var ( - pendingTxs = make(chan []common.Hash) + pendingTxs = make(chan []*types.Transaction) pendingTxSub = api.events.SubscribePendingTxs(pendingTxs) ) api.filtersMu.Lock() - api.filters[pendingTxSub.ID] = &filter{typ: PendingTransactionsSubscription, deadline: time.NewTimer(api.timeout), hashes: make([]common.Hash, 0), s: pendingTxSub} + api.filters[pendingTxSub.ID] = &filter{typ: PendingTransactionsSubscription, deadline: time.NewTimer(api.timeout), txs: make([]*types.Transaction, 0), s: pendingTxSub} api.filtersMu.Unlock() go func() { for { select { - case ph := <-pendingTxs: + case pTx := <-pendingTxs: api.filtersMu.Lock() if f, found := api.filters[pendingTxSub.ID]; found { - f.hashes = append(f.hashes, ph...) + f.txs = append(f.txs, pTx...) } api.filtersMu.Unlock() case <-pendingTxSub.Err(): @@ -132,9 +133,10 @@ func (api *FilterAPI) NewPendingTransactionFilter() rpc.ID { return pendingTxSub.ID } -// NewPendingTransactions creates a subscription that is triggered each time a transaction -// enters the transaction pool and was signed from one of the transactions this nodes manages. -func (api *FilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Subscription, error) { +// NewPendingTransactions creates a subscription that is triggered each time a +// transaction enters the transaction pool. If fullTx is true the full tx is +// sent to the client, otherwise the hash is sent. +func (api *FilterAPI) NewPendingTransactions(ctx context.Context, fullTx *bool) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported @@ -143,16 +145,20 @@ func (api *FilterAPI) NewPendingTransactions(ctx context.Context) (*rpc.Subscrip rpcSub := notifier.CreateSubscription() go func() { - txHashes := make(chan []common.Hash, 128) - pendingTxSub := api.events.SubscribePendingTxs(txHashes) + txs := make(chan []*types.Transaction, 128) + pendingTxSub := api.events.SubscribePendingTxs(txs) for { select { - case hashes := <-txHashes: + case txs := <-txs: // To keep the original behaviour, send a single tx hash in one notification. // TODO(rjl493456442) Send a batch of tx hashes in one notification - for _, h := range hashes { - notifier.Notify(rpcSub.ID, h) + for _, tx := range txs { + if fullTx != nil && *fullTx { + notifier.Notify(rpcSub.ID, tx) + } else { + notifier.Notify(rpcSub.ID, tx.Hash()) + } } case <-rpcSub.Err(): pendingTxSub.Unsubscribe() @@ -411,10 +417,14 @@ func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { f.deadline.Reset(api.timeout) switch f.typ { - case PendingTransactionsSubscription, BlocksSubscription: + case BlocksSubscription: hashes := f.hashes f.hashes = nil return returnHashes(hashes), nil + case PendingTransactionsSubscription: + txs := f.txs + f.txs = nil + return txs, nil case LogsSubscription, MinedAndPendingLogsSubscription: logs := f.logs f.logs = nil diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index ab9858f45495..e86a67abfda3 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -124,8 +124,8 @@ const ( PendingLogsSubscription // MinedAndPendingLogsSubscription queries for logs in mined and pending blocks. MinedAndPendingLogsSubscription - // PendingTransactionsSubscription queries tx hashes for pending - // transactions entering the pending state + // PendingTransactionsSubscription queries for pending transactions entering + // the pending state PendingTransactionsSubscription // BlocksSubscription queries hashes for blocks that are imported BlocksSubscription @@ -151,7 +151,7 @@ type subscription struct { created time.Time logsCrit ethereum.FilterQuery logs chan []*types.Log - hashes chan []common.Hash + txs chan []*types.Transaction headers chan *types.Header installed chan struct{} // closed when the filter is installed err chan error // closed when the filter is uninstalled @@ -244,7 +244,7 @@ func (sub *Subscription) Unsubscribe() { case sub.es.uninstall <- sub.f: break uninstallLoop case <-sub.f.logs: - case <-sub.f.hashes: + case <-sub.f.txs: case <-sub.f.headers: } } @@ -311,7 +311,7 @@ func (es *EventSystem) subscribeMinedPendingLogs(crit ethereum.FilterQuery, logs logsCrit: crit, created: time.Now(), logs: logs, - hashes: make(chan []common.Hash), + txs: make(chan []*types.Transaction), headers: make(chan *types.Header), installed: make(chan struct{}), err: make(chan error), @@ -328,7 +328,7 @@ func (es *EventSystem) subscribeLogs(crit ethereum.FilterQuery, logs chan []*typ logsCrit: crit, created: time.Now(), logs: logs, - hashes: make(chan []common.Hash), + txs: make(chan []*types.Transaction), headers: make(chan *types.Header), installed: make(chan struct{}), err: make(chan error), @@ -345,7 +345,7 @@ func (es *EventSystem) subscribePendingLogs(crit ethereum.FilterQuery, logs chan logsCrit: crit, created: time.Now(), logs: logs, - hashes: make(chan []common.Hash), + txs: make(chan []*types.Transaction), headers: make(chan *types.Header), installed: make(chan struct{}), err: make(chan error), @@ -361,7 +361,7 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti typ: BlocksSubscription, created: time.Now(), logs: make(chan []*types.Log), - hashes: make(chan []common.Hash), + txs: make(chan []*types.Transaction), headers: headers, installed: make(chan struct{}), err: make(chan error), @@ -369,15 +369,15 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti return es.subscribe(sub) } -// SubscribePendingTxs creates a subscription that writes transaction hashes for +// SubscribePendingTxs creates a subscription that writes transactions for // transactions that enter the transaction pool. -func (es *EventSystem) SubscribePendingTxs(hashes chan []common.Hash) *Subscription { +func (es *EventSystem) SubscribePendingTxs(txs chan []*types.Transaction) *Subscription { sub := &subscription{ id: rpc.NewID(), typ: PendingTransactionsSubscription, created: time.Now(), logs: make(chan []*types.Log), - hashes: hashes, + txs: txs, headers: make(chan *types.Header), installed: make(chan struct{}), err: make(chan error), @@ -421,12 +421,8 @@ func (es *EventSystem) handleRemovedLogs(filters filterIndex, ev core.RemovedLog } func (es *EventSystem) handleTxsEvent(filters filterIndex, ev core.NewTxsEvent) { - hashes := make([]common.Hash, 0, len(ev.Txs)) - for _, tx := range ev.Txs { - hashes = append(hashes, tx.Hash()) - } for _, f := range filters[PendingTransactionsSubscription] { - f.hashes <- hashes + f.txs <- ev.Txs } } diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 4386f0e5bde6..a41271f7b843 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -240,7 +240,7 @@ func TestPendingTxFilter(t *testing.T) { types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), } - hashes []common.Hash + txs []*types.Transaction ) fid0 := api.NewPendingTransactionFilter() @@ -255,9 +255,9 @@ func TestPendingTxFilter(t *testing.T) { t.Fatalf("Unable to retrieve logs: %v", err) } - h := results.([]common.Hash) - hashes = append(hashes, h...) - if len(hashes) >= len(transactions) { + tx := results.([]*types.Transaction) + txs = append(txs, tx...) + if len(txs) >= len(transactions) { break } // check timeout @@ -268,13 +268,13 @@ func TestPendingTxFilter(t *testing.T) { time.Sleep(100 * time.Millisecond) } - if len(hashes) != len(transactions) { - t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(hashes)) + if len(txs) != len(transactions) { + t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(txs)) return } - for i := range hashes { - if hashes[i] != transactions[i].Hash() { - t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), hashes[i]) + for i := range txs { + if txs[i].Hash() != transactions[i].Hash() { + t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), txs[i].Hash()) } } } @@ -705,11 +705,11 @@ func TestPendingTxFilterDeadlock(t *testing.T) { fids[i] = fid // Wait for at least one tx to arrive in filter for { - hashes, err := api.GetFilterChanges(fid) + txs, err := api.GetFilterChanges(fid) if err != nil { t.Fatalf("Filter should exist: %v\n", err) } - if len(hashes.([]common.Hash)) > 0 { + if len(txs.([]*types.Transaction)) > 0 { break } runtime.Gosched() diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index e182911aa5de..8211ee75ae01 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -166,7 +166,12 @@ func (ec *Client) GetNodeInfo(ctx context.Context) (*p2p.NodeInfo, error) { return &result, err } -// SubscribePendingTransactions subscribes to new pending transactions. +// SubscribeFullPendingTransactions subscribes to new pending transactions. +func (ec *Client) SubscribeFullPendingTransactions(ctx context.Context, ch chan<- *types.Transaction) (*rpc.ClientSubscription, error) { + return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions", true) +} + +// SubscribePendingTransactions subscribes to new pending transaction hashes. func (ec *Client) SubscribePendingTransactions(ctx context.Context, ch chan<- common.Hash) (*rpc.ClientSubscription, error) { return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions") } diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index da0118887b26..e60490c61646 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -122,8 +122,11 @@ func TestGethClient(t *testing.T) { "TestSetHead", func(t *testing.T) { testSetHead(t, client) }, }, { - "TestSubscribePendingTxs", + "TestSubscribePendingTxHashes", func(t *testing.T) { testSubscribePendingTransactions(t, client) }, + }, { + "TestSubscribePendingTxs", + func(t *testing.T) { testSubscribeFullPendingTransactions(t, client) }, }, { "TestCallContract", func(t *testing.T) { testCallContract(t, client) }, @@ -303,6 +306,40 @@ func testSubscribePendingTransactions(t *testing.T, client *rpc.Client) { } } +func testSubscribeFullPendingTransactions(t *testing.T, client *rpc.Client) { + ec := New(client) + ethcl := ethclient.NewClient(client) + // Subscribe to Transactions + ch := make(chan *types.Transaction) + ec.SubscribeFullPendingTransactions(context.Background(), ch) + // Send a transaction + chainID, err := ethcl.ChainID(context.Background()) + if err != nil { + t.Fatal(err) + } + // Create transaction + tx := types.NewTransaction(1, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil) + signer := types.LatestSignerForChainID(chainID) + signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) + if err != nil { + t.Fatal(err) + } + signedTx, err := tx.WithSignature(signer, signature) + if err != nil { + t.Fatal(err) + } + // Send transaction + err = ethcl.SendTransaction(context.Background(), signedTx) + if err != nil { + t.Fatal(err) + } + // Check that the transaction was send over the channel + tx = <-ch + if tx.Hash() != signedTx.Hash() { + t.Fatalf("Invalid tx hash received, got %v, want %v", tx.Hash(), signedTx.Hash()) + } +} + func testCallContract(t *testing.T, client *rpc.Client) { ec := New(client) msg := ethereum.CallMsg{ From 9207e348f0d3c2bd2b65f6c52b20a37de76350ae Mon Sep 17 00:00:00 2001 From: ucwong Date: Wed, 12 Oct 2022 18:03:45 +0800 Subject: [PATCH 309/715] go.mod: upgrade github.com/dop251/goja (#25955) This upgrade pulls in a fix to handling of 'continue' in loops. --- go.mod | 4 ++-- go.sum | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 1f88ef7c6f6d..d154b467b4cf 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v1.8.0 github.com/docker/docker v1.6.2 - github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf + github.com/dop251/goja v0.0.0-20221003171542-5ea1285e6c91 github.com/edsrzf/mmap-go v1.0.0 github.com/fatih/color v1.7.0 github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c @@ -82,7 +82,7 @@ require ( github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect - github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect + github.com/dlclark/regexp2 v1.7.0 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect diff --git a/go.sum b/go.sum index 3b1b58a12168..2b744cf7a473 100644 --- a/go.sum +++ b/go.sum @@ -106,16 +106,19 @@ github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRk github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/docker v1.6.2 h1:HlFGsy+9/xrgMmhmN+NGhCc5SHGJ7I+kHosRR1xc/aI= github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= -github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20221003171542-5ea1285e6c91 h1:1PfaQuGdeJVnHHQ0tg0Jw7MXagyqaAupJyk35/QM3I4= +github.com/dop251/goja v0.0.0-20221003171542-5ea1285e6c91/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -274,8 +277,9 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -366,6 +370,8 @@ github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1 github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= From c776a98c83ee0a8ab8d5eeb256884b14693f903d Mon Sep 17 00:00:00 2001 From: Delweng Date: Wed, 12 Oct 2022 18:50:01 +0800 Subject: [PATCH 310/715] eth/tracers: fix the issue of panic in prestate with diffmode (#25957) In some cases, inner contract creation may not be successful, and an inner contract was not created. This PR fixes a crash that could occur when doing tracing in such situations. --- .../internal/tracetest/calltrace_test.go | 3 +- .../internal/tracetest/prestate_test.go | 4 +- .../create_failed.json | 94 +++++++++++++++++++ eth/tracers/native/prestate.go | 6 +- 4 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index ca93ad95cd3a..215b657c2f27 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -103,7 +103,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { } else if err := json.Unmarshal(blob, test); err != nil { t.Fatalf("failed to parse testcase: %v", err) } - if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { + if err := tx.UnmarshalBinary(common.FromHex(test.Input)); err != nil { t.Fatalf("failed to parse testcase input: %v", err) } // Configure a blockchain with the given prestate @@ -122,6 +122,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { Time: new(big.Int).SetUint64(uint64(test.Context.Time)), Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), + BaseFee: test.Genesis.BaseFee, } _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) ) diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 084bcb8ed401..446c7925447d 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests" ) @@ -87,7 +86,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typ } else if err := json.Unmarshal(blob, test); err != nil { t.Fatalf("failed to parse testcase: %v", err) } - if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { + if err := tx.UnmarshalBinary(common.FromHex(test.Input)); err != nil { t.Fatalf("failed to parse testcase input: %v", err) } // Configure a blockchain with the given prestate @@ -106,6 +105,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typ Time: new(big.Int).SetUint64(uint64(test.Context.Time)), Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), + BaseFee: test.Genesis.BaseFee, } _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) ) diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json new file mode 100644 index 000000000000..e80dad5667ef --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_with_diff_mode/create_failed.json @@ -0,0 +1,94 @@ +{ + "genesis": { + "baseFeePerGas": "51088069741", + "difficulty": "14315558652874667", + "extraData": "0xd883010a10846765746888676f312e31362e35856c696e7578", + "gasLimit": "30058590", + "hash": "0xdf6b95183f99054fb6541e3b482c0109c9f6be40553cff24efa3ac76736adbf5", + "miner": "0xb7e390864a90b7b923c9f9310c6f98aafe43f707", + "mixHash": "0x8d76b0d32e42ab277dbf00836eabef76674cd70ae2bb53718175069ad6b6147e", + "nonce": "0x8d3a1c010ad2c687", + "number": "14707767", + "stateRoot": "0x8a50c896a6f7eb1f3479337db981fa10ce316281cb4dd2f07487be9ca27dae6b", + "timestamp": "1651623275", + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x268fd0b894b8c4f6d1f" + }, + "0x13b152c9f50878ffaf3de41e192653bda545d889": { + "balance": "0x0", + "nonce": "1", + "code": "0x363d3d373d3d3d363d73059ffafdc6ef594230de44f824e2bd0a51ca5ded5af43d82803e903d91602b57fd5bf3" + }, + "0x808b4da0be6c9512e948521452227efc619bea52": { + "balance": "0x2cdb96c56db040b43", + "nonce": "1223932" + }, + "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": { + "balance": "0x38079b28689d40240e", + "nonce": "44" + }, + "0xffa397285ce46fb78c588a9e993286aac68c37cd": { + "balance": "0x0", + "nonce": "747319", + "code": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063b97a23191461003b578063fb90b3201461006f575b600080fd5b6100436100bd565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100bb6004803603604081101561008557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506100e1565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008282604051602001808373ffffffffffffffffffffffffffffffffffffffff1660601b815260140182815260200192505050604051602081830303815290604052805190602001209050600061015960008054906101000a900473ffffffffffffffffffffffffffffffffffffffff168361024d565b90508073ffffffffffffffffffffffffffffffffffffffff166319ab453c856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b1580156101c457600080fd5b505af11580156101d8573d6000803e3d6000fd5b505050507fa35ea2cc726861482a50a162c72aad60965cc64641d419cd4d675036238b52048185604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a150505050565b6000808360601b90506040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528160148201527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006028820152836037826000f5925050509291505056fea2646970667358221220c87b2492828fdd7dad3175a32a98ff07fc0eedf106536f2eddd9a016971c56a764736f6c63430007050033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000059ffafdc6ef594230de44f824e2bd0a51ca5ded" + } + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "14707768", + "difficulty": "14322823549655084", + "timestamp": "1651623279", + "gasLimit": "30029237", + "miner": "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7" + }, + "input": "0x02f8b4018312acfc8459682f00851a46bcf47a8302b1a194ffa397285ce46fb78c588a9e993286aac68c37cd80b844fb90b3200000000000000000000000002a549b4af9ec39b03142da6dc32221fc390b553300000000000000000000000000000000000000000000000000000000000cb3d5c001a03002079d2873f7963c4278200c43aa71efad262b2150bc8524480acfc38b5faaa077d44aa09d56b9cf99443c7f55aaad1bbae9cfb5bbb9de31eaf7a8f9e623e980", + "tracerConfig": { + "diffMode": true + }, + "result": { + "pre": { + "0x808b4da0be6c9512e948521452227efc619bea52": { + "balance": "0x2cdb96c56db040b43", + "nonce": 1223932 + }, + "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": { + "balance": "0x38079b28689d40240e", + "nonce": 44 + } + }, + "post": { + "0x808b4da0be6c9512e948521452227efc619bea52": { + "balance": "0x2cd72a36dd031f089", + "nonce": 1223933 + }, + "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": { + "balance": "0x38079c19423e44b30e" + } + } + } +} diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index ff14baaf9c50..b22f6181b944 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -229,8 +229,10 @@ func (t *prestateTracer) CaptureTxEnd(restGas uint64) { // the new created contracts' prestate were empty, so delete them for a := range t.created { // the created contract maybe exists in statedb before the creating tx - if s := t.pre[a]; s.Balance.Cmp(big.NewInt(0)) == 0 && len(s.Storage) == 0 && len(s.Code) == 0 { - delete(t.pre, a) + if s := t.pre[a]; s != nil { + if s.Balance.Sign() == 0 && len(s.Storage) == 0 && len(s.Code) == 0 { + delete(t.pre, a) + } } } } From fb75f11e87420ec25ff72f7eeeb741fa8974e87e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 12 Oct 2022 20:08:36 +0200 Subject: [PATCH 311/715] Revert "go.mod: upgrade github.com/dop251/goja" (#25975) Revert "go.mod: upgrade github.com/dop251/goja (#25955)" This reverts commit 9207e348f0d3c2bd2b65f6c52b20a37de76350ae. --- go.mod | 4 ++-- go.sum | 14 ++++---------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index d154b467b4cf..1f88ef7c6f6d 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v1.8.0 github.com/docker/docker v1.6.2 - github.com/dop251/goja v0.0.0-20221003171542-5ea1285e6c91 + github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf github.com/edsrzf/mmap-go v1.0.0 github.com/fatih/color v1.7.0 github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c @@ -82,7 +82,7 @@ require ( github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect - github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect diff --git a/go.sum b/go.sum index 2b744cf7a473..3b1b58a12168 100644 --- a/go.sum +++ b/go.sum @@ -106,19 +106,16 @@ github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRk github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= -github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/docker v1.6.2 h1:HlFGsy+9/xrgMmhmN+NGhCc5SHGJ7I+kHosRR1xc/aI= github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja v0.0.0-20221003171542-5ea1285e6c91 h1:1PfaQuGdeJVnHHQ0tg0Jw7MXagyqaAupJyk35/QM3I4= -github.com/dop251/goja v0.0.0-20221003171542-5ea1285e6c91/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= +github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= +github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= -github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -277,9 +274,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -370,8 +366,6 @@ github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1 github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= From 15b7e0b25459786f4914590cc980039a7ea564f1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 18 Oct 2022 15:42:16 +0200 Subject: [PATCH 312/715] common/math, tests/fuzzers: use big.Int clone (#26006) * common/math, tests/fuzzers: use big.Int clone * common/math: license --- common/math/modexp.go | 82 --------------------------- common/math/modexp_test.go | 53 +++++++++++++++++ go.mod | 3 +- go.sum | 5 +- tests/fuzzers/modexp/debug/main.go | 40 +++++++++++++ tests/fuzzers/modexp/modexp-fuzzer.go | 19 ++++--- 6 files changed, 110 insertions(+), 92 deletions(-) delete mode 100644 common/math/modexp.go create mode 100644 common/math/modexp_test.go create mode 100644 tests/fuzzers/modexp/debug/main.go diff --git a/common/math/modexp.go b/common/math/modexp.go deleted file mode 100644 index b0a32e8c2739..000000000000 --- a/common/math/modexp.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import ( - "math/big" - "math/bits" - - "github.com/ethereum/go-ethereum/common" -) - -// FastExp is semantically equivalent to x.Exp(x,y, m), but is faster for even -// modulus. -func FastExp(x, y, m *big.Int) *big.Int { - // Split m = m1 × m2 where m1 = 2ⁿ - n := m.TrailingZeroBits() - m1 := new(big.Int).Lsh(common.Big1, n) - mask := new(big.Int).Sub(m1, common.Big1) - m2 := new(big.Int).Rsh(m, n) - - // We want z = x**y mod m. - // z1 = x**y mod m1 = (x**y mod m) mod m1 = z mod m1 - // z2 = x**y mod m2 = (x**y mod m) mod m2 = z mod m2 - z1 := fastExpPow2(x, y, mask) - z2 := new(big.Int).Exp(x, y, m2) - - // Reconstruct z from z1, z2 using CRT, using algorithm from paper, - // which uses only a single modInverse. - // p = (z1 - z2) * m2⁻¹ (mod m1) - // z = z2 + p * m2 - z := new(big.Int).Set(z2) - - // Compute (z1 - z2) mod m1 [m1 == 2**n] into z1. - z1 = z1.And(z1, mask) - z2 = z2.And(z2, mask) - z1 = z1.Sub(z1, z2) - if z1.Sign() < 0 { - z1 = z1.Add(z1, m1) - } - - // Reuse z2 for p = z1 * m2inv. - m2inv := new(big.Int).ModInverse(m2, m1) - z2 = z2.Mul(z1, m2inv) - z2 = z2.And(z2, mask) - - // Reuse z1 for m2 * p. - z = z.Add(z, z1.Mul(z2, m2)) - z = z.Rem(z, m) - - return z -} - -func fastExpPow2(x, y *big.Int, mask *big.Int) *big.Int { - z := big.NewInt(1) - if y.Sign() == 0 { - return z - } - p := new(big.Int).Set(x) - p = p.And(p, mask) - if p.Cmp(z) <= 0 { // p <= 1 - return p - } - if y.Cmp(mask) > 0 { - y = new(big.Int).And(y, mask) - } - t := new(big.Int) - - for _, b := range y.Bits() { - for i := 0; i < bits.UintSize; i++ { - if b&1 != 0 { - z, t = t.Mul(z, p), z - z = z.And(z, mask) - } - p, t = t.Mul(p, p), p - p = p.And(p, mask) - b >>= 1 - } - } - return z -} diff --git a/common/math/modexp_test.go b/common/math/modexp_test.go new file mode 100644 index 000000000000..bd90076f84f6 --- /dev/null +++ b/common/math/modexp_test.go @@ -0,0 +1,53 @@ +// Copyright 2022 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 math + +import ( + "math/big" + "testing" + + big2 "github.com/holiman/big" +) + +// TestFastModexp tests some cases found during fuzzing. +func TestFastModexp(t *testing.T) { + for i, tc := range []struct { + base string + exp string + mod string + }{ + {"0xeffffff900002f00", "0x40000000000000", "0x200"}, + {"0xf000", "0x4f900b400080000", "0x400000d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9ffffff005aeffd310000000000000000000000000000000000009f9f9f9f0000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000befffa5a5a5fff900002f000040000000000000000000000000000000029d9d9d000000000000009f9f9f00000000000000009f9f9f000000f3a080ab00000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f0000000000002900009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000cf000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000befffff0000c0800000000800000000000000000000000000000002000000000000009f9f9f0000000000000000008000ff000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000befffa5a5a5fff900002f000040000000000000000000000000000000029d9d9d000000000000009f9f9f00000000000000009f9f9f000000f3a080ab00000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f0000000000002900009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000beffffff900002f0000400000c100000000000000000000000000000000000000006160600000000000000000008000ff0000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f0000"}, + {"5", "1435700818", "72"}, + {"0xffff", "0x300030003000300030003000300030003000302a3000300030003000300030003000300030003000300030003000300030003030623066307f3030783062303430383064303630343036", "0x300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, + {"0x3133", "0x667f00000000000000000000000000ff002a000000000000000000000000000000000000000000000000000000000000667fff30783362773057ee756a6c266134643831646230313630", "0x3030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, + } { + var ( + base, _ = new(big.Int).SetString(tc.base, 0) + exp, _ = new(big.Int).SetString(tc.exp, 0) + mod, _ = new(big.Int).SetString(tc.mod, 0) + base2, _ = new(big2.Int).SetString(tc.base, 0) + exp2, _ = new(big2.Int).SetString(tc.exp, 0) + mod2, _ = new(big2.Int).SetString(tc.mod, 0) + ) + var a = new(big2.Int).Exp(base2, exp2, mod2).String() + var b = new(big.Int).Exp(base, exp, mod).String() + if a != b { + t.Errorf("test %d: %#x ^ %#x mod %#x \n have %x\n want %x", i, base, exp, mod, a, b) + } + } +} diff --git a/go.mod b/go.mod index 1f88ef7c6f6d..eda8e663c6bb 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d + github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e github.com/holiman/bloomfilter/v2 v2.0.3 github.com/holiman/uint256 v1.2.0 github.com/huin/goupnp v1.0.3 @@ -60,7 +61,7 @@ require ( golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a + golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 golang.org/x/text v0.3.7 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba diff --git a/go.sum b/go.sum index 3b1b58a12168..50c27386cbae 100644 --- a/go.sum +++ b/go.sum @@ -223,6 +223,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw= +github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= @@ -552,8 +554,9 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4= +golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= diff --git a/tests/fuzzers/modexp/debug/main.go b/tests/fuzzers/modexp/debug/main.go new file mode 100644 index 000000000000..22002bd3f807 --- /dev/null +++ b/tests/fuzzers/modexp/debug/main.go @@ -0,0 +1,40 @@ +// Copyright 2020 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 main + +import ( + "fmt" + "os" + + "github.com/ethereum/go-ethereum/tests/fuzzers/modexp" +) + +func main() { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "Usage: debug \n") + fmt.Fprintf(os.Stderr, "Example\n") + fmt.Fprintf(os.Stderr, " $ debug ../crashers/4bbef6857c733a87ecf6fd8b9e7238f65eb9862a\n") + os.Exit(1) + } + crasher := os.Args[1] + data, err := os.ReadFile(crasher) + if err != nil { + fmt.Fprintf(os.Stderr, "error loading crasher %v: %v", crasher, err) + os.Exit(1) + } + modexp.Fuzz(data) +} diff --git a/tests/fuzzers/modexp/modexp-fuzzer.go b/tests/fuzzers/modexp/modexp-fuzzer.go index a28840494292..086d9e115310 100644 --- a/tests/fuzzers/modexp/modexp-fuzzer.go +++ b/tests/fuzzers/modexp/modexp-fuzzer.go @@ -21,8 +21,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/vm" + big2 "github.com/holiman/big" ) // Fuzz is the fuzzing entry-point. @@ -56,18 +56,21 @@ func Fuzz(input []byte) int { input = input[96:] // Retrieve the operands and execute the exponentiation var ( - base = new(big.Int).SetBytes(getData(input, 0, baseLen)) - exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) - mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + base = new(big.Int).SetBytes(getData(input, 0, baseLen)) + exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) + mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + base2 = new(big2.Int).SetBytes(getData(input, 0, baseLen)) + exp2 = new(big2.Int).SetBytes(getData(input, baseLen, expLen)) + mod2 = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen)) ) if mod.BitLen() == 0 { // Modulo 0 is undefined, return zero return -1 } - var a = math.FastExp(new(big.Int).Set(base), new(big.Int).Set(exp), new(big.Int).Set(mod)) - var b = base.Exp(base, exp, mod) - if a.Cmp(b) != 0 { - panic(fmt.Sprintf("Inequality %x != %x", a, b)) + var a = new(big2.Int).Exp(base2, exp2, mod2).String() + var b = new(big.Int).Exp(base, exp, mod).String() + if a != b { + panic(fmt.Sprintf("Inequality %#x ^ %#x mod %#x \n have %s\n want %s", base, exp, mod, a, b)) } return 1 } From 6069d8294e2e52d6a18c8e9661302e15ddaaf9f8 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 19 Oct 2022 08:20:39 +0200 Subject: [PATCH 313/715] cmd/utils: enable snapshot generation in import-mode (#25990) This PR fixes a regression causing snapshots not to be generated in "geth --import" mode. It also fixes the geth export command to be truly readonly, and adds a new test for geth export. --- cmd/geth/chaincmd.go | 4 ++-- cmd/geth/exportcmd_test.go | 45 ++++++++++++++++++++++++++++++++++++++ cmd/utils/flags.go | 10 +++++---- core/genesis.go | 6 ++++- 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 cmd/geth/exportcmd_test.go diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index c89f736169ef..48b21ddbf7a5 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -252,7 +252,7 @@ func importChain(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - chain, db := utils.MakeChain(ctx, stack) + chain, db := utils.MakeChain(ctx, stack, false) defer db.Close() // Start periodically gathering memory profiles @@ -327,7 +327,7 @@ func exportChain(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - chain, _ := utils.MakeChain(ctx, stack) + chain, _ := utils.MakeChain(ctx, stack, true) start := time.Now() var err error diff --git a/cmd/geth/exportcmd_test.go b/cmd/geth/exportcmd_test.go new file mode 100644 index 000000000000..bbf08d820eb6 --- /dev/null +++ b/cmd/geth/exportcmd_test.go @@ -0,0 +1,45 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "bytes" + "fmt" + "os" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +// TestExport does a basic test of "geth export", exporting the test-genesis. +func TestExport(t *testing.T) { + outfile := fmt.Sprintf("%v/testExport.out", os.TempDir()) + defer os.Remove(outfile) + geth := runGeth(t, "--datadir", initGeth(t), "export", outfile) + geth.WaitExit() + if have, want := geth.ExitStatus(), 0; have != want { + t.Errorf("exit error, have %d want %d", have, want) + } + have, err := os.ReadFile(outfile) + if err != nil { + t.Fatal(err) + } + want := common.FromHex("0xf9026bf90266a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a08758259b018f7bce3d2be2ddb62f325eaeea0a0c188cf96623eab468a4413e03a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180837a12008080b875000000000000000000000000000000000000000000000000000000000000000002f0d131f1f97aef08aec6e3291b957d9efe71050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0") + if !bytes.Equal(have, want) { + t.Fatalf("wrong content exported") + } +} diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 4c4dc9df1be7..dafa2dd801df 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2217,10 +2217,10 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { } // MakeChain creates a chain manager from set command line flags. -func MakeChain(ctx *cli.Context, stack *node.Node) (*core.BlockChain, ethdb.Database) { +func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockChain, ethdb.Database) { var ( gspec = MakeGenesis(ctx) - chainDb = MakeChainDatabase(ctx, stack, false) // TODO(rjl493456442) support read-only database + chainDb = MakeChainDatabase(ctx, stack, readonly) ) cliqueConfig, err := core.LoadCliqueConfig(chainDb, gspec) if err != nil { @@ -2250,8 +2250,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (*core.BlockChain, ethdb.Data if !ctx.Bool(SnapshotFlag.Name) { cache.SnapshotLimit = 0 // Disabled } - // Disable snapshot generation/wiping by default - cache.SnapshotNoBuild = true + // If we're in readonly, do not bother generating snapshot data. + if readonly { + cache.SnapshotNoBuild = true + } if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) { cache.TrieCleanLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 diff --git a/core/genesis.go b/core/genesis.go index 8b855147972d..b5f844724741 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -358,6 +358,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override rawdb.WriteChainConfig(db, stored, newcfg) return newcfg, stored, nil } + storedData, _ := json.Marshal(storedcfg) // Special case: if a private network is being used (no genesis and also no // mainnet hash in the database), we must not apply the `configOrDefault` // chain config as that would be AllProtocolChanges (applying any new fork @@ -377,7 +378,10 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override if compatErr != nil && *height != 0 && compatErr.RewindTo != 0 { return newcfg, stored, compatErr } - rawdb.WriteChainConfig(db, stored, newcfg) + // Don't overwrite if the old is identical to the new + if newData, _ := json.Marshal(newcfg); !bytes.Equal(storedData, newData) { + rawdb.WriteChainConfig(db, stored, newcfg) + } return newcfg, stored, nil } From d86fe26f67d8ad17d8b66da9a8908101fb4c11cb Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Wed, 19 Oct 2022 15:53:09 +0800 Subject: [PATCH 314/715] core/rawdb: refactor db key prefix (#26000) Co-authored-by: seven --- consensus/clique/snapshot.go | 5 +++-- core/rawdb/database.go | 14 +++++++------- core/rawdb/schema.go | 10 ++++++++++ les/handler_test.go | 4 ++-- les/server_handler.go | 4 ++-- light/postprocess.go | 27 ++++++++++----------------- 6 files changed, 34 insertions(+), 30 deletions(-) diff --git a/consensus/clique/snapshot.go b/consensus/clique/snapshot.go index 4ee731a90821..35eaf1eb774a 100644 --- a/consensus/clique/snapshot.go +++ b/consensus/clique/snapshot.go @@ -23,6 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" @@ -87,7 +88,7 @@ func newSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, number uin // loadSnapshot loads an existing snapshot from the database. func loadSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) { - blob, err := db.Get(append([]byte("clique-"), hash[:]...)) + blob, err := db.Get(append(rawdb.CliqueSnapshotPrefix, hash[:]...)) if err != nil { return nil, err } @@ -107,7 +108,7 @@ func (s *Snapshot) store(db ethdb.Database) error { if err != nil { return err } - return db.Put(append([]byte("clique-"), s.Hash[:]...), blob) + return db.Put(append(rawdb.CliqueSnapshotPrefix, s.Hash[:]...), blob) } // copy creates a deep copy of the snapshot, though not the individual votes. diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 2cc3a7c85c21..9e1bdbfac399 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -439,15 +439,15 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { bloomBits.Add(size) case bytes.HasPrefix(key, skeletonHeaderPrefix) && len(key) == (len(skeletonHeaderPrefix)+8): beaconHeaders.Add(size) - case bytes.HasPrefix(key, []byte("clique-")) && len(key) == 7+common.HashLength: + case bytes.HasPrefix(key, CliqueSnapshotPrefix) && len(key) == 7+common.HashLength: cliqueSnaps.Add(size) - case bytes.HasPrefix(key, []byte("cht-")) || - bytes.HasPrefix(key, []byte("chtIndexV2-")) || - bytes.HasPrefix(key, []byte("chtRootV2-")): // Canonical hash trie + case bytes.HasPrefix(key, ChtTablePrefix) || + bytes.HasPrefix(key, ChtIndexTablePrefix) || + bytes.HasPrefix(key, ChtPrefix): // Canonical hash trie chtTrieNodes.Add(size) - case bytes.HasPrefix(key, []byte("blt-")) || - bytes.HasPrefix(key, []byte("bltIndex-")) || - bytes.HasPrefix(key, []byte("bltRoot-")): // Bloomtrie sub + case bytes.HasPrefix(key, BloomTrieTablePrefix) || + bytes.HasPrefix(key, BloomTrieIndexPrefix) || + bytes.HasPrefix(key, BloomTriePrefix): // Bloomtrie sub bloomTrieNodes.Add(size) default: var accounted bool diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 0fdb445ebb80..5a670b408694 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -109,6 +109,16 @@ var ( // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress BloomBitsIndexPrefix = []byte("iB") + ChtPrefix = []byte("chtRootV2-") // ChtPrefix + chtNum (uint64 big endian) -> trie root hash + ChtTablePrefix = []byte("cht-") + ChtIndexTablePrefix = []byte("chtIndexV2-") + + BloomTriePrefix = []byte("bltRoot-") // BloomTriePrefix + bloomTrieNum (uint64 big endian) -> trie root hash + BloomTrieTablePrefix = []byte("blt-") + BloomTrieIndexPrefix = []byte("bltIndex-") + + CliqueSnapshotPrefix = []byte("clique-") + preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil) preimageHitCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil) ) diff --git a/les/handler_test.go b/les/handler_test.go index ecf97bf9d109..bd48d7eb4394 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -512,7 +512,7 @@ func testGetCHTProofs(t *testing.T, protocol int) { AuxData: [][]byte{rlp}, } root := light.GetChtRoot(server.db, 0, bc.GetHeaderByNumber(config.ChtSize-1).Hash()) - trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, light.ChtTablePrefix))) + trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, string(rawdb.ChtTablePrefix)))) trie.Prove(key, 0, &proofsV2.Proofs) // Assemble the requests for the different protocols requestsV2 := []HelperTrieReq{{ @@ -577,7 +577,7 @@ func testGetBloombitsProofs(t *testing.T, protocol int) { var proofs HelperTrieResps root := light.GetBloomTrieRoot(server.db, 0, bc.GetHeaderByNumber(config.BloomTrieSize-1).Hash()) - trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, light.BloomTrieTablePrefix))) + trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, string(rawdb.BloomTrieTablePrefix)))) trie.Prove(key, 0, &proofs.Proofs) // Send the proof request and verify the response diff --git a/les/server_handler.go b/les/server_handler.go index 32a38f64cc44..2dac80cd434e 100644 --- a/les/server_handler.go +++ b/les/server_handler.go @@ -383,10 +383,10 @@ func (h *serverHandler) GetHelperTrie(typ uint, index uint64) *trie.Trie { switch typ { case htCanonical: sectionHead := rawdb.ReadCanonicalHash(h.chainDb, (index+1)*h.server.iConfig.ChtSize-1) - root, prefix = light.GetChtRoot(h.chainDb, index, sectionHead), light.ChtTablePrefix + root, prefix = light.GetChtRoot(h.chainDb, index, sectionHead), string(rawdb.ChtTablePrefix) case htBloomBits: sectionHead := rawdb.ReadCanonicalHash(h.chainDb, (index+1)*h.server.iConfig.BloomTrieSize-1) - root, prefix = light.GetBloomTrieRoot(h.chainDb, index, sectionHead), light.BloomTrieTablePrefix + root, prefix = light.GetBloomTrieRoot(h.chainDb, index, sectionHead), string(rawdb.BloomTrieTablePrefix) } if root == (common.Hash{}) { return nil diff --git a/light/postprocess.go b/light/postprocess.go index bd17eca8a3d2..181916deb9a3 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -102,8 +102,6 @@ var ( errNoTrustedCht = errors.New("no trusted canonical hash trie") errNoTrustedBloomTrie = errors.New("no trusted bloom trie") errNoHeader = errors.New("header not found") - chtPrefix = []byte("chtRootV2-") // chtPrefix + chtNum (uint64 big endian) -> trie root hash - ChtTablePrefix = "cht-" ) // ChtNode structures are stored in the Canonical Hash Trie in an RLP encoded format @@ -116,7 +114,7 @@ type ChtNode struct { func GetChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], sectionIdx) - data, _ := db.Get(append(append(chtPrefix, encNumber[:]...), sectionHead.Bytes()...)) + data, _ := db.Get(append(append(rawdb.ChtPrefix, encNumber[:]...), sectionHead.Bytes()...)) return common.BytesToHash(data) } @@ -124,7 +122,7 @@ func GetChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) c func StoreChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root common.Hash) { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], sectionIdx) - db.Put(append(append(chtPrefix, encNumber[:]...), sectionHead.Bytes()...), root.Bytes()) + db.Put(append(append(rawdb.ChtPrefix, encNumber[:]...), sectionHead.Bytes()...), root.Bytes()) } // ChtIndexerBackend implements core.ChainIndexerBackend. @@ -140,7 +138,7 @@ type ChtIndexerBackend struct { // NewChtIndexer creates a Cht chain indexer func NewChtIndexer(db ethdb.Database, odr OdrBackend, size, confirms uint64, disablePruning bool) *core.ChainIndexer { - trieTable := rawdb.NewTable(db, ChtTablePrefix) + trieTable := rawdb.NewTable(db, string(rawdb.ChtTablePrefix)) backend := &ChtIndexerBackend{ diskdb: db, odr: odr, @@ -149,7 +147,7 @@ func NewChtIndexer(db ethdb.Database, odr OdrBackend, size, confirms uint64, dis sectionSize: size, disablePruning: disablePruning, } - return core.NewChainIndexer(db, rawdb.NewTable(db, "chtIndexV2-"), backend, size, confirms, time.Millisecond*100, "cht") + return core.NewChainIndexer(db, rawdb.NewTable(db, string(rawdb.ChtIndexTablePrefix)), backend, size, confirms, time.Millisecond*100, "cht") } // fetchMissingNodes tries to retrieve the last entry of the latest trusted CHT from the @@ -249,7 +247,7 @@ func (c *ChtIndexerBackend) Commit() error { } } for it.Next() { - trimmed := bytes.TrimPrefix(it.Key(), []byte(ChtTablePrefix)) + trimmed := bytes.TrimPrefix(it.Key(), rawdb.ChtTablePrefix) if len(trimmed) == common.HashLength { if _, ok := hashes[common.BytesToHash(trimmed)]; !ok { batch.Delete(trimmed) @@ -311,16 +309,11 @@ func (c *ChtIndexerBackend) Prune(threshold uint64) error { return nil } -var ( - bloomTriePrefix = []byte("bltRoot-") // bloomTriePrefix + bloomTrieNum (uint64 big endian) -> trie root hash - BloomTrieTablePrefix = "blt-" -) - // GetBloomTrieRoot reads the BloomTrie root associated to the given section from the database func GetBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], sectionIdx) - data, _ := db.Get(append(append(bloomTriePrefix, encNumber[:]...), sectionHead.Bytes()...)) + data, _ := db.Get(append(append(rawdb.BloomTriePrefix, encNumber[:]...), sectionHead.Bytes()...)) return common.BytesToHash(data) } @@ -328,7 +321,7 @@ func GetBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.H func StoreBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root common.Hash) { var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], sectionIdx) - db.Put(append(append(bloomTriePrefix, encNumber[:]...), sectionHead.Bytes()...), root.Bytes()) + db.Put(append(append(rawdb.BloomTriePrefix, encNumber[:]...), sectionHead.Bytes()...), root.Bytes()) } // BloomTrieIndexerBackend implements core.ChainIndexerBackend @@ -347,7 +340,7 @@ type BloomTrieIndexerBackend struct { // NewBloomTrieIndexer creates a BloomTrie chain indexer func NewBloomTrieIndexer(db ethdb.Database, odr OdrBackend, parentSize, size uint64, disablePruning bool) *core.ChainIndexer { - trieTable := rawdb.NewTable(db, BloomTrieTablePrefix) + trieTable := rawdb.NewTable(db, string(rawdb.BloomTrieTablePrefix)) backend := &BloomTrieIndexerBackend{ diskdb: db, odr: odr, @@ -359,7 +352,7 @@ func NewBloomTrieIndexer(db ethdb.Database, odr OdrBackend, parentSize, size uin } backend.bloomTrieRatio = size / parentSize backend.sectionHeads = make([]common.Hash, backend.bloomTrieRatio) - return core.NewChainIndexer(db, rawdb.NewTable(db, "bltIndex-"), backend, size, 0, time.Millisecond*100, "bloomtrie") + return core.NewChainIndexer(db, rawdb.NewTable(db, string(rawdb.BloomTrieIndexPrefix)), backend, size, 0, time.Millisecond*100, "bloomtrie") } // fetchMissingNodes tries to retrieve the last entries of the latest trusted bloom trie from the @@ -500,7 +493,7 @@ func (b *BloomTrieIndexerBackend) Commit() error { } } for it.Next() { - trimmed := bytes.TrimPrefix(it.Key(), []byte(BloomTrieTablePrefix)) + trimmed := bytes.TrimPrefix(it.Key(), rawdb.BloomTrieTablePrefix) if len(trimmed) == common.HashLength { if _, ok := hashes[common.BytesToHash(trimmed)]; !ok { batch.Delete(trimmed) From b9ba6f6e4d86d0ee86c63e8f4552e233fe0450aa Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 20 Oct 2022 03:15:43 +0800 Subject: [PATCH 315/715] core/rawdb: open meta file in read only mode (#26009) --- core/rawdb/freezer_table.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 3fe691cf6d2a..746f825e4038 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -148,20 +148,12 @@ func newTable(path string, name string, readMeter metrics.Meter, writeMeter metr meta *os.File ) if readonly { - // Will fail if table doesn't exist + // Will fail if table index file or meta file is not existent index, err = openFreezerFileForReadOnly(filepath.Join(path, idxName)) if err != nil { return nil, err } - // TODO(rjl493456442) change it to read-only mode. Open the metadata file - // in rw mode. It's a temporary solution for now and should be changed - // whenever the tail deletion is actually used. The reason for this hack is - // the additional meta file for each freezer table is added in order to support - // tail deletion, but for most legacy nodes this file is missing. This check - // will suddenly break lots of database relevant commands. So the metadata file - // is always opened for mutation and nothing else will be written except - // the initialization. - meta, err = openFreezerFileForAppend(filepath.Join(path, fmt.Sprintf("%s.meta", name))) + meta, err = openFreezerFileForReadOnly(filepath.Join(path, fmt.Sprintf("%s.meta", name))) if err != nil { return nil, err } From 9b9a1b677d894db951dc4714ea1a46a2e7b74ffc Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Thu, 20 Oct 2022 18:56:12 +0800 Subject: [PATCH 316/715] internal/ethapi, accounts/abi/backends: use error defined in core (#26012) Co-authored-by: seven --- accounts/abi/bind/backends/simulated.go | 2 +- internal/ethapi/api.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 277850e3b57c..4c259e03c93c 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -527,7 +527,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs available := new(big.Int).Set(balance) if call.Value != nil { if call.Value.Cmp(available) >= 0 { - return 0, errors.New("insufficient funds for transfer") + return 0, core.ErrInsufficientFundsForTransfer } available.Sub(available, call.Value) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1a2f8bdd5e77..538644908ba0 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1098,7 +1098,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr available := new(big.Int).Set(balance) if args.Value != nil { if args.Value.ToInt().Cmp(available) >= 0 { - return 0, errors.New("insufficient funds for transfer") + return 0, core.ErrInsufficientFundsForTransfer } available.Sub(available, args.Value.ToInt()) } From a404195c7bad5cd0d526abb22f97e4ee790430d9 Mon Sep 17 00:00:00 2001 From: Delweng Date: Fri, 21 Oct 2022 17:48:53 +0800 Subject: [PATCH 317/715] eth/tracers: fix the issue prestate missing existing contract state (#25996) The prestate tracer did not report accounts that existed at a given address prior to a contract being created at that address. Signed-off-by: Delweng Co-authored-by: Sina Mahmoodi --- .../create_existing_contract.json | 85 +++++++++++++++++++ eth/tracers/native/prestate.go | 23 +++-- 2 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer/create_existing_contract.json diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_existing_contract.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_existing_contract.json new file mode 100644 index 000000000000..a34d3b759ee1 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_existing_contract.json @@ -0,0 +1,85 @@ +{ + "genesis": { + "difficulty": "6217248151198", + "extraData": "0xd783010103844765746887676f312e342e32856c696e7578", + "gasLimit": "3141592", + "hash": "0xe8bff55fe3e61936ef321cf3afaeb1ba2f7234e1e89535fa8ae39963caebe9c3", + "miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5", + "mixHash": "0x03da00d5a15a064e5ebddf53cd0aaeb9a8aff0f40c0fb031a74f463d11ec83b8", + "nonce": "0x6575fe08c4167044", + "number": "243825", + "stateRoot": "0x47182fe2e6e740b8a76f82fe5c527d6ad548f805274f21792cf4047235b24fbf", + "timestamp": "1442424328", + "totalDifficulty": "1035061827427752845", + "alloc": { + "0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": { + "balance": "0xc820f93200f4000", + "nonce": "0x5E", + "code": "0x" + }, + "0x332b656504f4eabb44c8617a42af37461a34e9dc": { + "balance": "0x11faea4f35e5af80000", + "code": "0x" + }, + "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": { + "balance": "0xbf681825be002ac452", + "nonce": "0x70FA", + "code": "0x" + }, + "0x82effbaaaf28614e55b2ba440fb198e0e5789b0f": { + "balance": "0xb3d0ac5cb94df6f6b0", + "nonce": "0x1", + "code": "0x" + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "243826", + "difficulty": "6214212385501", + "timestamp": "1442424353", + "gasLimit": "3141592", + "miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5" + }, + "input": "0xf8e85e850ba43b7400830f42408080b89660606040527382effbaaaf28614e55b2ba440fb198e0e5789b0f600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600a80608c6000396000f30060606040526008565b001ca0340b21661e5bb85a46319a15f33a362e5c0f02faa7cdbf9c5808b2134da968eaa0226e6788f8c20e211d436ab7f6298ef32fa4c23a509eeeaac0880d115c17bc3f", + "result": { + "0x082d4cdf07f386ffa9258f52a5c49db4ac321ec6": { + "balance": "0xc820f93200f4000", + "nonce": 94 + }, + "0x332b656504f4eabb44c8617a42af37461a34e9dc": { + "balance": "0x11faea4f35e5af80000", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5": { + "balance": "0xbf681825be002ac452", + "nonce": 28922 + }, + "0x82effbaaaf28614e55b2ba440fb198e0e5789b0f": { + "balance": "0xb3d0ac5cb94df6f6b0", + "nonce": 1 + } + } +} diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index b22f6181b944..d50d00c6f7c9 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -45,6 +45,10 @@ type account struct { Storage map[common.Hash]common.Hash `json:"storage,omitempty"` } +func (a *account) exists() bool { + return a.Balance.Sign() != 0 || a.Nonce > 0 || len(a.Code) > 0 || len(a.Storage) > 0 +} + type accountMarshaling struct { Balance *hexutil.Big Code hexutil.Bytes @@ -116,9 +120,16 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo // CaptureEnd is called after the call finishes to finalize the tracing. func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { - if t.create && !t.config.DiffMode { - // Exclude created contract. - delete(t.pre, t.to) + if t.config.DiffMode { + return + } + + if t.create { + // Keep existing account prior to contract creation at that address + if s := t.pre[t.to]; s != nil && !s.exists() { + // Exclude newly created contract. + delete(t.pre, t.to) + } } } @@ -229,10 +240,8 @@ func (t *prestateTracer) CaptureTxEnd(restGas uint64) { // the new created contracts' prestate were empty, so delete them for a := range t.created { // the created contract maybe exists in statedb before the creating tx - if s := t.pre[a]; s != nil { - if s.Balance.Sign() == 0 && len(s.Storage) == 0 && len(s.Code) == 0 { - delete(t.pre, a) - } + if s := t.pre[a]; s != nil && !s.exists() { + delete(t.pre, a) } } } From 5f70f9fd37b14c6c8021cd277f9d620dbef7583b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 21 Oct 2022 17:55:15 +0200 Subject: [PATCH 318/715] eth/tracers: simplify test framework (#25973) Co-authored-by: Sina Mahmoodi --- .../internal/tracetest/calltrace_test.go | 49 ++++++----- .../internal/tracetest/prestate_test.go | 53 ++++++------ .../testdata/prestate_tracer/simple.json | 3 +- .../prestate_tracer_legacy/simple.json | 84 +++++++++++++++++++ eth/tracers/internal/tracetest/util.go | 18 ---- .../js/internal/tracers/call_tracer_legacy.js | 1 - eth/tracers/native/gen_account_json.go | 18 ++-- eth/tracers/native/prestate.go | 6 +- 8 files changed, 150 insertions(+), 82 deletions(-) create mode 100644 eth/tracers/internal/tracetest/testdata/prestate_tracer_legacy/simple.json diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 215b657c2f27..de6b3f9bfd1c 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -48,17 +48,18 @@ type callContext struct { // callTrace is the result of a callTracer run. type callTrace struct { - Type string `json:"type"` From common.Address `json:"from"` - To common.Address `json:"to"` + Gas *hexutil.Uint64 `json:"gas"` + GasUsed *hexutil.Uint64 `json:"gasUsed"` + To common.Address `json:"to,omitempty"` Input hexutil.Bytes `json:"input"` - Output hexutil.Bytes `json:"output"` - Gas *hexutil.Uint64 `json:"gas,omitempty"` - GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"` - Value *hexutil.Big `json:"value,omitempty"` + Output hexutil.Bytes `json:"output,omitempty"` Error string `json:"error,omitempty"` Revertal string `json:"revertReason,omitempty"` Calls []callTrace `json:"calls,omitempty"` + Value *hexutil.Big `json:"value,omitempty"` + // Gencodec adds overridden fields at the end + Type string `json:"type"` } // callTracerTest defines a single test to check the call tracer against. @@ -144,17 +145,21 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to retrieve trace result: %v", err) } - ret := new(callTrace) - if err := json.Unmarshal(res, ret); err != nil { - t.Fatalf("failed to unmarshal trace result: %v", err) + // The legacy javascript calltracer marshals json in js, which + // is not deterministic (as opposed to the golang json encoder). + if strings.HasSuffix(dirPath, "_legacy") { + // This is a tweak to make it deterministic. Can be removed when + // we remove the legacy tracer. + var x callTrace + json.Unmarshal(res, &x) + res, _ = json.Marshal(x) } - - if !jsonEqual(ret, test.Result, new(callTrace), new(callTrace)) { - // uncomment this for easier debugging - //have, _ := json.MarshalIndent(ret, "", " ") - //want, _ := json.MarshalIndent(test.Result, "", " ") - //t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", string(have), string(want)) - t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result) + want, err := json.Marshal(test.Result) + if err != nil { + t.Fatalf("failed to marshal test: %v", err) + } + if string(want) != string(res) { + t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), string(want)) } }) } @@ -298,14 +303,8 @@ func TestZeroValueToNotExitCall(t *testing.T) { if err != nil { t.Fatalf("failed to retrieve trace result: %v", err) } - have := new(callTrace) - if err := json.Unmarshal(res, have); err != nil { - t.Fatalf("failed to unmarshal trace result: %v", err) - } - wantStr := `{"type":"CALL","from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","to":"0x00000000000000000000000000000000deadbeef","value":"0x0","gas":"0x7148","gasUsed":"0x2d0","input":"0x","output":"0x","calls":[{"type":"CALL","from":"0x00000000000000000000000000000000deadbeef","to":"0x00000000000000000000000000000000000000ff","value":"0x0","gas":"0x6cbf","gasUsed":"0x0","input":"0x","output":"0x"}]}` - want := new(callTrace) - json.Unmarshal([]byte(wantStr), want) - if !jsonEqual(have, want, new(callTrace), new(callTrace)) { - t.Error("have != want") + wantStr := `{"from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","gas":"0x7148","gasUsed":"0x2d0","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}` + if string(res) != wantStr { + t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), wantStr) } } diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 446c7925447d..9227aff9453d 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -35,19 +35,16 @@ import ( // prestateTrace is the result of a prestateTrace run. type prestateTrace = map[common.Address]*account + type account struct { - Balance string `json:"balance,omitempty"` - Nonce uint64 `json:"nonce,omitempty"` - Code string `json:"code,omitempty"` - Storage map[common.Hash]common.Hash `json:"storage,omitempty"` -} -type prePostStateTrace struct { - Pre prestateTrace `json:"pre"` - Post prestateTrace `json:"post"` + Balance string `json:"balance"` + Code string `json:"code"` + Nonce uint64 `json:"nonce"` + Storage map[common.Hash]common.Hash `json:"storage"` } -// prestateTraceTest defines a single test to check the stateDiff tracer against. -type prestateTraceTest struct { +// testcase defines a single test to check the stateDiff tracer against. +type testcase struct { Genesis *core.Genesis `json:"genesis"` Context *callContext `json:"context"` Input string `json:"input"` @@ -55,15 +52,19 @@ type prestateTraceTest struct { Result interface{} `json:"result"` } +func TestPrestateTracerLegacy(t *testing.T) { + testPrestateDiffTracer("prestateTracerLegacy", "prestate_tracer_legacy", t) +} + func TestPrestateTracer(t *testing.T) { - testPrestateDiffTracer("prestateTracer", "prestate_tracer", t, func() interface{} { return new(prestateTrace) }) + testPrestateDiffTracer("prestateTracer", "prestate_tracer", t) } func TestPrestateWithDiffModeTracer(t *testing.T) { - testPrestateDiffTracer("prestateTracer", "prestate_tracer_with_diff_mode", t, func() interface{} { return new(prePostStateTrace) }) + testPrestateDiffTracer("prestateTracer", "prestate_tracer_with_diff_mode", t) } -func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typeBuilder func() interface{}) { +func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { files, err := os.ReadDir(filepath.Join("testdata", dirPath)) if err != nil { t.Fatalf("failed to retrieve tracer test suite: %v", err) @@ -77,7 +78,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typ t.Parallel() var ( - test = new(prestateTraceTest) + test = new(testcase) tx = new(types.Transaction) ) // Call tracer test found, read if from disk @@ -127,17 +128,21 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T, typ if err != nil { t.Fatalf("failed to retrieve trace result: %v", err) } - ret := typeBuilder() - if err := json.Unmarshal(res, ret); err != nil { - t.Fatalf("failed to unmarshal trace result: %v", err) + // The legacy javascript calltracer marshals json in js, which + // is not deterministic (as opposed to the golang json encoder). + if strings.HasSuffix(dirPath, "_legacy") { + // This is a tweak to make it deterministic. Can be removed when + // we remove the legacy tracer. + var x prestateTrace + json.Unmarshal(res, &x) + res, _ = json.Marshal(x) } - - if !jsonEqual(ret, test.Result, typeBuilder(), typeBuilder()) { - // uncomment this for easier debugging - // have, _ := json.MarshalIndent(ret, "", " ") - // want, _ := json.MarshalIndent(test.Result, "", " ") - // t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", string(have), string(want)) - t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result) + want, err := json.Marshal(test.Result) + if err != nil { + t.Fatalf("failed to marshal test: %v", err) + } + if string(want) != string(res) { + t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), string(want)) } }) } diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json index 3ed27dc434cd..7204bfcbfeae 100644 --- a/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/simple.json @@ -77,8 +77,7 @@ "nonce": 29072 }, "0x1585936b53834b021f68cc13eeefdec2efc8e724": { - "balance": "0x0", - "nonce": 0 + "balance": "0x0" } } } diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer_legacy/simple.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer_legacy/simple.json new file mode 100644 index 000000000000..44b1f08dd337 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer_legacy/simple.json @@ -0,0 +1,84 @@ +{ + "context": { + "difficulty": "3502894804", + "gasLimit": "4722976", + "miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724", + "number": "2289806", + "timestamp": "1513601314" + }, + "genesis": { + "alloc": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "code": "0x", + "nonce": "22", + "storage": {} + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "code": "0x", + "nonce": "29072", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3509749784", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "4727564", + "hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada", + "nonce": "0x4eb12e19c16d43da", + "number": "2289805", + "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", + "timestamp": "1513601261", + "totalDifficulty": "7143276353481064" + }, + "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", + "result": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "code": "0x", + "nonce": 22, + "storage": {} + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "nonce": 1, + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "code": "0x", + "nonce": 29072, + "storage": {} + } + } +} diff --git a/eth/tracers/internal/tracetest/util.go b/eth/tracers/internal/tracetest/util.go index f56d9246b882..95d292c9240b 100644 --- a/eth/tracers/internal/tracetest/util.go +++ b/eth/tracers/internal/tracetest/util.go @@ -1,8 +1,6 @@ package tracetest import ( - "encoding/json" - "reflect" "strings" "unicode" @@ -64,22 +62,6 @@ var makeTest = function(tx, rewind) { } */ -// jsonEqual is similar to reflect.DeepEqual, but does a 'bounce' via json prior to -// comparison -func jsonEqual(xi, yi, xt, yt interface{}) bool { - if xj, err := json.Marshal(xi); err == nil { - json.Unmarshal(xj, xt) - } else { - return false - } - if yj, err := json.Marshal(yi); err == nil { - json.Unmarshal(yj, yt) - } else { - return false - } - return reflect.DeepEqual(xt, yt) -} - // camel converts a snake cased input string into a camel cased output. func camel(str string) string { pieces := strings.Split(str, "_") diff --git a/eth/tracers/js/internal/tracers/call_tracer_legacy.js b/eth/tracers/js/internal/tracers/call_tracer_legacy.js index 3ca7377738b7..b9e555df8746 100644 --- a/eth/tracers/js/internal/tracers/call_tracer_legacy.js +++ b/eth/tracers/js/internal/tracers/call_tracer_legacy.js @@ -204,7 +204,6 @@ gasUsed: '0x' + bigInt(ctx.gasUsed).toString(16), input: toHex(ctx.input), output: toHex(ctx.output), - time: ctx.time, }; if (this.callstack[0].calls !== undefined) { result.calls = this.callstack[0].calls; diff --git a/eth/tracers/native/gen_account_json.go b/eth/tracers/native/gen_account_json.go index 070fd7d93ea5..4c39cbc38cd4 100644 --- a/eth/tracers/native/gen_account_json.go +++ b/eth/tracers/native/gen_account_json.go @@ -16,14 +16,14 @@ var _ = (*accountMarshaling)(nil) func (a account) MarshalJSON() ([]byte, error) { type account struct { Balance *hexutil.Big `json:"balance,omitempty"` - Nonce uint64 `json:"nonce,omitempty"` Code hexutil.Bytes `json:"code,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.Nonce = a.Nonce enc.Code = a.Code + enc.Nonce = a.Nonce enc.Storage = a.Storage return json.Marshal(&enc) } @@ -31,10 +31,10 @@ 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"` - Nonce *uint64 `json:"nonce"` - Code *hexutil.Bytes `json:"code"` - Storage map[common.Hash]common.Hash `json:"storage"` + 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"` } var dec account if err := json.Unmarshal(input, &dec); err != nil { @@ -43,12 +43,12 @@ func (a *account) UnmarshalJSON(input []byte) error { if dec.Balance != nil { a.Balance = (*big.Int)(dec.Balance) } - if dec.Nonce != nil { - a.Nonce = *dec.Nonce - } if dec.Code != nil { a.Code = *dec.Code } + if dec.Nonce != nil { + a.Nonce = *dec.Nonce + } if dec.Storage != nil { a.Storage = dec.Storage } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index d50d00c6f7c9..f06ca8059880 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -40,8 +40,8 @@ type state = map[common.Address]*account type account struct { Balance *big.Int `json:"balance,omitempty"` - Nonce uint64 `json:"nonce,omitempty"` Code []byte `json:"code,omitempty"` + Nonce uint64 `json:"nonce,omitempty"` Storage map[common.Hash]common.Hash `json:"storage,omitempty"` } @@ -253,9 +253,9 @@ func (t *prestateTracer) GetResult() (json.RawMessage, error) { var err error if t.config.DiffMode { res, err = json.Marshal(struct { - Pre state `json:"pre"` Post state `json:"post"` - }{t.pre, t.post}) + Pre state `json:"pre"` + }{t.post, t.pre}) } else { res, err = json.Marshal(t.pre) } From a6dda036446bf2ca7fab07bd72b04d51de684b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 24 Oct 2022 16:13:55 +0300 Subject: [PATCH 319/715] all: refactor txpool into it's own package in prep for 4844 --- cmd/utils/flags.go | 7 +- core/blockchain.go | 9 +- core/{tx_cacher.go => sender_cacher.go} | 14 +- core/{tx_journal.go => txpool/journal.go} | 18 +- core/{tx_list.go => txpool/list.go} | 102 +++--- core/{tx_list_test.go => txpool/list_test.go} | 18 +- core/{tx_noncer.go => txpool/noncer.go} | 20 +- core/{tx_pool.go => txpool/txpool.go} | 150 ++++----- .../txpool_test.go} | 295 +++++++++--------- eth/api_backend.go | 3 +- eth/backend.go | 7 +- eth/ethconfig/config.go | 5 +- eth/ethconfig/gen_config.go | 5 +- eth/fetcher/tx_fetcher.go | 8 +- eth/fetcher/tx_fetcher_test.go | 8 +- eth/protocols/eth/handler_test.go | 7 +- les/handler_test.go | 23 +- les/odr.go | 5 +- les/odr_test.go | 5 +- les/server.go | 3 +- les/server_handler.go | 7 +- les/server_requests.go | 9 +- les/test_helper.go | 5 +- light/odr.go | 3 +- light/odr_util.go | 4 +- light/txpool.go | 7 +- miner/miner.go | 3 +- miner/miner_test.go | 9 +- miner/stress/1559/main.go | 3 +- miner/stress/beacon/main.go | 5 +- miner/stress/clique/main.go | 3 +- miner/stress/ethash/main.go | 3 +- miner/worker.go | 2 +- miner/worker_test.go | 11 +- tests/fuzzers/les/les-fuzzer.go | 7 +- 35 files changed, 408 insertions(+), 385 deletions(-) rename core/{tx_cacher.go => sender_cacher.go} (88%) rename core/{tx_journal.go => txpool/journal.go} (91%) rename core/{tx_list.go => txpool/list.go} (87%) rename core/{tx_list_test.go => txpool/list_test.go} (84%) rename core/{tx_noncer.go => txpool/noncer.go} (81%) rename core/{tx_pool.go => txpool/txpool.go} (94%) rename core/{tx_pool_test.go => txpool/txpool_test.go} (91%) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index dafa2dd801df..d705d7a16306 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -390,13 +391,13 @@ var ( TxPoolJournalFlag = &cli.StringFlag{ Name: "txpool.journal", Usage: "Disk journal for local transaction to survive node restarts", - Value: core.DefaultTxPoolConfig.Journal, + Value: txpool.DefaultConfig.Journal, Category: flags.TxPoolCategory, } TxPoolRejournalFlag = &cli.DurationFlag{ Name: "txpool.rejournal", Usage: "Time interval to regenerate the local transaction journal", - Value: core.DefaultTxPoolConfig.Rejournal, + Value: txpool.DefaultConfig.Rejournal, Category: flags.TxPoolCategory, } TxPoolPriceLimitFlag = &cli.Uint64Flag{ @@ -1573,7 +1574,7 @@ func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) { } } -func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { +func setTxPool(ctx *cli.Context, cfg *txpool.Config) { if ctx.IsSet(TxPoolLocalsFlag.Name) { locals := strings.Split(ctx.String(TxPoolLocalsFlag.Name), ",") for _, account := range locals { diff --git a/core/blockchain.go b/core/blockchain.go index 9766f28eda9c..4965eeef35b4 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -77,10 +77,9 @@ var ( blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil) blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil) - blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil) - blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil) - blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil) - blockReorgInvalidatedTx = metrics.NewRegisteredMeter("chain/reorg/invalidTx", nil) + blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil) + blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil) + blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil) blockPrefetchExecuteTimer = metrics.NewRegisteredTimer("chain/prefetch/executes", nil) blockPrefetchInterruptMeter = metrics.NewRegisteredMeter("chain/prefetch/interrupts", nil) @@ -1492,7 +1491,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) } // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) - senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain) + SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain) var ( stats = insertStats{startTime: mclock.Now()} diff --git a/core/tx_cacher.go b/core/sender_cacher.go similarity index 88% rename from core/tx_cacher.go rename to core/sender_cacher.go index b1e5d676a2b1..4be53619ebec 100644 --- a/core/tx_cacher.go +++ b/core/sender_cacher.go @@ -22,8 +22,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) -// senderCacher is a concurrent transaction sender recoverer and cacher. -var senderCacher = newTxSenderCacher(runtime.NumCPU()) +// SenderCacher is a concurrent transaction sender recoverer and cacher. +var SenderCacher = newTxSenderCacher(runtime.NumCPU()) // txSenderCacherRequest is a request for recovering transaction senders with a // specific signature scheme and caching it into the transactions themselves. @@ -67,10 +67,10 @@ func (cacher *txSenderCacher) cache() { } } -// recover recovers the senders from a batch of transactions and caches them +// Recover recovers the senders from a batch of transactions and caches them // back into the same data structures. There is no validation being done, nor // any reaction to invalid signatures. That is up to calling code later. -func (cacher *txSenderCacher) recover(signer types.Signer, txs []*types.Transaction) { +func (cacher *txSenderCacher) Recover(signer types.Signer, txs []*types.Transaction) { // If there's nothing to recover, abort if len(txs) == 0 { return @@ -89,10 +89,10 @@ func (cacher *txSenderCacher) recover(signer types.Signer, txs []*types.Transact } } -// recoverFromBlocks recovers the senders from a batch of blocks and caches them +// RecoverFromBlocks recovers the senders from a batch of blocks and caches them // back into the same data structures. There is no validation being done, nor // any reaction to invalid signatures. That is up to calling code later. -func (cacher *txSenderCacher) recoverFromBlocks(signer types.Signer, blocks []*types.Block) { +func (cacher *txSenderCacher) RecoverFromBlocks(signer types.Signer, blocks []*types.Block) { count := 0 for _, block := range blocks { count += len(block.Transactions()) @@ -101,5 +101,5 @@ func (cacher *txSenderCacher) recoverFromBlocks(signer types.Signer, blocks []*t for _, block := range blocks { txs = append(txs, block.Transactions()...) } - cacher.recover(signer, txs) + cacher.Recover(signer, txs) } diff --git a/core/tx_journal.go b/core/txpool/journal.go similarity index 91% rename from core/tx_journal.go rename to core/txpool/journal.go index 62344f564676..1b330b0c3cab 100644 --- a/core/tx_journal.go +++ b/core/txpool/journal.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package core +package txpool import ( "errors" @@ -41,23 +41,23 @@ type devNull struct{} func (*devNull) Write(p []byte) (n int, err error) { return len(p), nil } func (*devNull) Close() error { return nil } -// txJournal is a rotating log of transactions with the aim of storing locally +// journal is a rotating log of transactions with the aim of storing locally // created transactions to allow non-executed ones to survive node restarts. -type txJournal struct { +type journal struct { path string // Filesystem path to store the transactions at writer io.WriteCloser // Output stream to write new transactions into } // newTxJournal creates a new transaction journal to -func newTxJournal(path string) *txJournal { - return &txJournal{ +func newTxJournal(path string) *journal { + return &journal{ path: path, } } // load parses a transaction journal dump from disk, loading its contents into // the specified pool. -func (journal *txJournal) load(add func([]*types.Transaction) []error) error { +func (journal *journal) load(add func([]*types.Transaction) []error) error { // Open the journal for loading any past transactions input, err := os.Open(journal.path) if errors.Is(err, fs.ErrNotExist) { @@ -118,7 +118,7 @@ func (journal *txJournal) load(add func([]*types.Transaction) []error) error { } // insert adds the specified transaction to the local disk journal. -func (journal *txJournal) insert(tx *types.Transaction) error { +func (journal *journal) insert(tx *types.Transaction) error { if journal.writer == nil { return errNoActiveJournal } @@ -130,7 +130,7 @@ func (journal *txJournal) insert(tx *types.Transaction) error { // rotate regenerates the transaction journal based on the current contents of // the transaction pool. -func (journal *txJournal) rotate(all map[common.Address]types.Transactions) error { +func (journal *journal) rotate(all map[common.Address]types.Transactions) error { // Close the current journal (if any is open) if journal.writer != nil { if err := journal.writer.Close(); err != nil { @@ -170,7 +170,7 @@ func (journal *txJournal) rotate(all map[common.Address]types.Transactions) erro } // close flushes the transaction journal contents to disk and closes the file. -func (journal *txJournal) close() error { +func (journal *journal) close() error { var err error if journal.writer != nil { diff --git a/core/tx_list.go b/core/txpool/list.go similarity index 87% rename from core/tx_list.go rename to core/txpool/list.go index 274061c59173..eb0c753f21e9 100644 --- a/core/tx_list.go +++ b/core/txpool/list.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package core +package txpool import ( "container/heap" @@ -49,30 +49,30 @@ func (h *nonceHeap) Pop() interface{} { return x } -// txSortedMap is a nonce->transaction hash map with a heap based index to allow +// sortedMap is a nonce->transaction hash map with a heap based index to allow // iterating over the contents in a nonce-incrementing way. -type txSortedMap struct { +type sortedMap struct { items map[uint64]*types.Transaction // Hash map storing the transaction data index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode) cache types.Transactions // Cache of the transactions already sorted } -// newTxSortedMap creates a new nonce-sorted transaction map. -func newTxSortedMap() *txSortedMap { - return &txSortedMap{ +// newSortedMap creates a new nonce-sorted transaction map. +func newSortedMap() *sortedMap { + return &sortedMap{ items: make(map[uint64]*types.Transaction), index: new(nonceHeap), } } // Get retrieves the current transactions associated with the given nonce. -func (m *txSortedMap) Get(nonce uint64) *types.Transaction { +func (m *sortedMap) Get(nonce uint64) *types.Transaction { return m.items[nonce] } // Put inserts a new transaction into the map, also updating the map's nonce // index. If a transaction already exists with the same nonce, it's overwritten. -func (m *txSortedMap) Put(tx *types.Transaction) { +func (m *sortedMap) Put(tx *types.Transaction) { nonce := tx.Nonce() if m.items[nonce] == nil { heap.Push(m.index, nonce) @@ -83,7 +83,7 @@ func (m *txSortedMap) Put(tx *types.Transaction) { // Forward removes all transactions from the map with a nonce lower than the // provided threshold. Every removed transaction is returned for any post-removal // maintenance. -func (m *txSortedMap) Forward(threshold uint64) types.Transactions { +func (m *sortedMap) Forward(threshold uint64) types.Transactions { var removed types.Transactions // Pop off heap items until the threshold is reached @@ -104,7 +104,7 @@ func (m *txSortedMap) Forward(threshold uint64) types.Transactions { // Filter, as opposed to 'filter', re-initialises the heap after the operation is done. // If you want to do several consecutive filterings, it's therefore better to first // do a .filter(func1) followed by .Filter(func2) or reheap() -func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { +func (m *sortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { removed := m.filter(filter) // If transactions were removed, the heap and cache are ruined if len(removed) > 0 { @@ -113,7 +113,7 @@ func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transac return removed } -func (m *txSortedMap) reheap() { +func (m *sortedMap) reheap() { *m.index = make([]uint64, 0, len(m.items)) for nonce := range m.items { *m.index = append(*m.index, nonce) @@ -124,7 +124,7 @@ func (m *txSortedMap) reheap() { // filter is identical to Filter, but **does not** regenerate the heap. This method // should only be used if followed immediately by a call to Filter or reheap() -func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transactions { +func (m *sortedMap) filter(filter func(*types.Transaction) bool) types.Transactions { var removed types.Transactions // Collect all the transactions to filter out @@ -142,7 +142,7 @@ func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transac // Cap places a hard limit on the number of items, returning all transactions // exceeding that limit. -func (m *txSortedMap) Cap(threshold int) types.Transactions { +func (m *sortedMap) Cap(threshold int) types.Transactions { // Short circuit if the number of items is under the limit if len(m.items) <= threshold { return nil @@ -167,7 +167,7 @@ func (m *txSortedMap) Cap(threshold int) types.Transactions { // Remove deletes a transaction from the maintained map, returning whether the // transaction was found. -func (m *txSortedMap) Remove(nonce uint64) bool { +func (m *sortedMap) Remove(nonce uint64) bool { // Short circuit if no transaction is present _, ok := m.items[nonce] if !ok { @@ -193,7 +193,7 @@ func (m *txSortedMap) Remove(nonce uint64) bool { // Note, all transactions with nonces lower than start will also be returned to // prevent getting into and invalid state. This is not something that should ever // happen but better to be self correcting than failing! -func (m *txSortedMap) Ready(start uint64) types.Transactions { +func (m *sortedMap) Ready(start uint64) types.Transactions { // Short circuit if no transactions are available if m.index.Len() == 0 || (*m.index)[0] > start { return nil @@ -211,11 +211,11 @@ func (m *txSortedMap) Ready(start uint64) types.Transactions { } // Len returns the length of the transaction map. -func (m *txSortedMap) Len() int { +func (m *sortedMap) Len() int { return len(m.items) } -func (m *txSortedMap) flatten() types.Transactions { +func (m *sortedMap) flatten() types.Transactions { // If the sorting was not cached yet, create and cache it if m.cache == nil { m.cache = make(types.Transactions, 0, len(m.items)) @@ -230,7 +230,7 @@ func (m *txSortedMap) flatten() types.Transactions { // Flatten creates a nonce-sorted slice of transactions based on the loosely // sorted internal representation. The result of the sorting is cached in case // it's requested again before any modifications are made to the contents. -func (m *txSortedMap) Flatten() types.Transactions { +func (m *sortedMap) Flatten() types.Transactions { // Copy the cache to prevent accidental modifications cache := m.flatten() txs := make(types.Transactions, len(cache)) @@ -240,36 +240,36 @@ func (m *txSortedMap) Flatten() types.Transactions { // LastElement returns the last element of a flattened list, thus, the // transaction with the highest nonce -func (m *txSortedMap) LastElement() *types.Transaction { +func (m *sortedMap) LastElement() *types.Transaction { cache := m.flatten() return cache[len(cache)-1] } -// txList is a "list" of transactions belonging to an account, sorted by account +// list is a "list" of transactions belonging to an account, sorted by account // nonce. The same type can be used both for storing contiguous transactions for // the executable/pending queue; and for storing gapped transactions for the non- // executable/future queue, with minor behavioral changes. -type txList struct { - strict bool // Whether nonces are strictly continuous or not - txs *txSortedMap // Heap indexed sorted hash map of the transactions +type list struct { + strict bool // Whether nonces are strictly continuous or not + txs *sortedMap // Heap indexed sorted hash map of the transactions costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance) gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) } -// newTxList create a new transaction list for maintaining nonce-indexable fast, +// newList create a new transaction list for maintaining nonce-indexable fast, // gapped, sortable transaction lists. -func newTxList(strict bool) *txList { - return &txList{ +func newList(strict bool) *list { + return &list{ strict: strict, - txs: newTxSortedMap(), + txs: newSortedMap(), costcap: new(big.Int), } } // Overlaps returns whether the transaction specified has the same nonce as one // already contained within the list. -func (l *txList) Overlaps(tx *types.Transaction) bool { +func (l *list) Overlaps(tx *types.Transaction) bool { return l.txs.Get(tx.Nonce()) != nil } @@ -278,7 +278,7 @@ func (l *txList) Overlaps(tx *types.Transaction) bool { // // If the new transaction is accepted into the list, the lists' cost and gas // thresholds are also potentially updated. -func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) { +func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) { // If there's an older better transaction, abort old := l.txs.Get(tx.Nonce()) if old != nil { @@ -316,7 +316,7 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran // Forward removes all transactions from the list with a nonce lower than the // provided threshold. Every removed transaction is returned for any post-removal // maintenance. -func (l *txList) Forward(threshold uint64) types.Transactions { +func (l *list) Forward(threshold uint64) types.Transactions { return l.txs.Forward(threshold) } @@ -329,7 +329,7 @@ func (l *txList) Forward(threshold uint64) types.Transactions { // a point in calculating all the costs or if the balance covers all. If the threshold // is lower than the costgas cap, the caps will be reset to a new high after removing // the newly invalidated transactions. -func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions, types.Transactions) { +func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions, types.Transactions) { // If all transactions are below the threshold, short circuit if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit { return nil, nil @@ -362,14 +362,14 @@ func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions // Cap places a hard limit on the number of items, returning all transactions // exceeding that limit. -func (l *txList) Cap(threshold int) types.Transactions { +func (l *list) Cap(threshold int) types.Transactions { return l.txs.Cap(threshold) } // Remove deletes a transaction from the maintained list, returning whether the // transaction was found, and also returning any transaction invalidated due to // the deletion (strict mode only). -func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) { +func (l *list) Remove(tx *types.Transaction) (bool, types.Transactions) { // Remove the transaction from the set nonce := tx.Nonce() if removed := l.txs.Remove(nonce); !removed { @@ -389,30 +389,30 @@ func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) { // Note, all transactions with nonces lower than start will also be returned to // prevent getting into and invalid state. This is not something that should ever // happen but better to be self correcting than failing! -func (l *txList) Ready(start uint64) types.Transactions { +func (l *list) Ready(start uint64) types.Transactions { return l.txs.Ready(start) } // Len returns the length of the transaction list. -func (l *txList) Len() int { +func (l *list) Len() int { return l.txs.Len() } // Empty returns whether the list of transactions is empty or not. -func (l *txList) Empty() bool { +func (l *list) Empty() bool { return l.Len() == 0 } // Flatten creates a nonce-sorted slice of transactions based on the loosely // sorted internal representation. The result of the sorting is cached in case // it's requested again before any modifications are made to the contents. -func (l *txList) Flatten() types.Transactions { +func (l *list) Flatten() types.Transactions { return l.txs.Flatten() } // LastElement returns the last element of a flattened list, thus, the // transaction with the highest nonce -func (l *txList) LastElement() *types.Transaction { +func (l *list) LastElement() *types.Transaction { return l.txs.LastElement() } @@ -468,7 +468,7 @@ func (h *priceHeap) Pop() interface{} { return x } -// txPricedList is a price-sorted heap to allow operating on transactions pool +// pricedList is a price-sorted heap to allow operating on transactions pool // contents in a price-incrementing way. It's built upon the all transactions // in txpool but only interested in the remote part. It means only remote transactions // will be considered for tracking, sorting, eviction, etc. @@ -479,14 +479,14 @@ func (h *priceHeap) Pop() interface{} { // In some cases (during a congestion, when blocks are full) the urgent heap can provide // better candidates for inclusion while in other cases (at the top of the baseFee peak) // the floating heap is better. When baseFee is decreasing they behave similarly. -type txPricedList struct { +type pricedList struct { // Number of stale price points to (re-heap trigger). // This field is accessed atomically, and must be the first field // to ensure it has correct alignment for atomic.AddInt64. // See https://golang.org/pkg/sync/atomic/#pkg-note-BUG. stales int64 - all *txLookup // Pointer to the map of all transactions + all *lookup // Pointer to the map of all transactions urgent, floating priceHeap // Heaps of prices of all the stored **remote** transactions reheapMu sync.Mutex // Mutex asserts that only one routine is reheaping the list } @@ -497,15 +497,15 @@ const ( floatingRatio = 1 ) -// newTxPricedList creates a new price-sorted transaction heap. -func newTxPricedList(all *txLookup) *txPricedList { - return &txPricedList{ +// newPricedList creates a new price-sorted transaction heap. +func newPricedList(all *lookup) *pricedList { + return &pricedList{ all: all, } } // Put inserts a new transaction into the heap. -func (l *txPricedList) Put(tx *types.Transaction, local bool) { +func (l *pricedList) Put(tx *types.Transaction, local bool) { if local { return } @@ -516,7 +516,7 @@ func (l *txPricedList) Put(tx *types.Transaction, local bool) { // Removed notifies the prices transaction list that an old transaction dropped // from the pool. The list will just keep a counter of stale objects and update // the heap if a large enough ratio of transactions go stale. -func (l *txPricedList) Removed(count int) { +func (l *pricedList) Removed(count int) { // Bump the stale counter, but exit if still too low (< 25%) stales := atomic.AddInt64(&l.stales, int64(count)) if int(stales) <= (len(l.urgent.list)+len(l.floating.list))/4 { @@ -528,7 +528,7 @@ func (l *txPricedList) Removed(count int) { // Underpriced checks whether a transaction is cheaper than (or as cheap as) the // lowest priced (remote) transaction currently being tracked. -func (l *txPricedList) Underpriced(tx *types.Transaction) bool { +func (l *pricedList) Underpriced(tx *types.Transaction) bool { // Note: with two queues, being underpriced is defined as being worse than the worst item // in all non-empty queues if there is any. If both queues are empty then nothing is underpriced. return (l.underpricedFor(&l.urgent, tx) || len(l.urgent.list) == 0) && @@ -538,7 +538,7 @@ func (l *txPricedList) Underpriced(tx *types.Transaction) bool { // underpricedFor checks whether a transaction is cheaper than (or as cheap as) the // lowest priced (remote) transaction in the given heap. -func (l *txPricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool { +func (l *pricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool { // Discard stale price points if found at the heap start for len(h.list) > 0 { head := h.list[0] @@ -562,7 +562,7 @@ func (l *txPricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool // priced list and returns them for further removal from the entire pool. // // Note local transaction won't be considered for eviction. -func (l *txPricedList) Discard(slots int, force bool) (types.Transactions, bool) { +func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) { drop := make(types.Transactions, 0, slots) // Remote underpriced transactions to drop for slots > 0 { if len(l.urgent.list)*floatingRatio > len(l.floating.list)*urgentRatio || floatingRatio == 0 { @@ -601,7 +601,7 @@ func (l *txPricedList) Discard(slots int, force bool) (types.Transactions, bool) } // Reheap forcibly rebuilds the heap based on the current remote transaction set. -func (l *txPricedList) Reheap() { +func (l *pricedList) Reheap() { l.reheapMu.Lock() defer l.reheapMu.Unlock() start := time.Now() @@ -629,7 +629,7 @@ func (l *txPricedList) 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 *txPricedList) SetBaseFee(baseFee *big.Int) { +func (l *pricedList) SetBaseFee(baseFee *big.Int) { l.urgent.baseFee = baseFee l.Reheap() } diff --git a/core/tx_list_test.go b/core/txpool/list_test.go similarity index 84% rename from core/tx_list_test.go rename to core/txpool/list_test.go index ef49cae1dd1c..4e1a5d5e832a 100644 --- a/core/tx_list_test.go +++ b/core/txpool/list_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package core +package txpool import ( "math/big" @@ -27,7 +27,7 @@ import ( // Tests that transactions can be added to strict lists and list contents and // nonce boundaries are correctly maintained. -func TestStrictTxListAdd(t *testing.T) { +func TestStrictListAdd(t *testing.T) { // Generate a list of transactions to insert key, _ := crypto.GenerateKey() @@ -36,9 +36,9 @@ func TestStrictTxListAdd(t *testing.T) { txs[i] = transaction(uint64(i), 0, key) } // Insert the transactions in a random order - list := newTxList(true) + list := newList(true) for _, v := range rand.Perm(len(txs)) { - list.Add(txs[v], DefaultTxPoolConfig.PriceBump) + list.Add(txs[v], DefaultConfig.PriceBump) } // Verify internal state if len(list.txs.items) != len(txs) { @@ -51,7 +51,7 @@ func TestStrictTxListAdd(t *testing.T) { } } -func BenchmarkTxListAdd(b *testing.B) { +func BenchmarkListAdd(b *testing.B) { // Generate a list of transactions to insert key, _ := crypto.GenerateKey() @@ -60,13 +60,13 @@ func BenchmarkTxListAdd(b *testing.B) { txs[i] = transaction(uint64(i), 0, key) } // Insert the transactions in a random order - priceLimit := big.NewInt(int64(DefaultTxPoolConfig.PriceLimit)) + priceLimit := big.NewInt(int64(DefaultConfig.PriceLimit)) b.ResetTimer() for i := 0; i < b.N; i++ { - list := newTxList(true) + list := newList(true) for _, v := range rand.Perm(len(txs)) { - list.Add(txs[v], DefaultTxPoolConfig.PriceBump) - list.Filter(priceLimit, DefaultTxPoolConfig.PriceBump) + list.Add(txs[v], DefaultConfig.PriceBump) + list.Filter(priceLimit, DefaultConfig.PriceBump) } } } diff --git a/core/tx_noncer.go b/core/txpool/noncer.go similarity index 81% rename from core/tx_noncer.go rename to core/txpool/noncer.go index 257beffa06c6..ba7fbedad568 100644 --- a/core/tx_noncer.go +++ b/core/txpool/noncer.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package core +package txpool import ( "sync" @@ -23,18 +23,18 @@ import ( "github.com/ethereum/go-ethereum/core/state" ) -// txNoncer is a tiny virtual state database to manage the executable nonces of +// noncer is a tiny virtual state database to manage the executable nonces of // accounts in the pool, falling back to reading from a real state database if // an account is unknown. -type txNoncer struct { +type noncer struct { fallback *state.StateDB nonces map[common.Address]uint64 lock sync.Mutex } -// newTxNoncer creates a new virtual state database to track the pool nonces. -func newTxNoncer(statedb *state.StateDB) *txNoncer { - return &txNoncer{ +// newNoncer creates a new virtual state database to track the pool nonces. +func newNoncer(statedb *state.StateDB) *noncer { + return &noncer{ fallback: statedb.Copy(), nonces: make(map[common.Address]uint64), } @@ -42,7 +42,7 @@ func newTxNoncer(statedb *state.StateDB) *txNoncer { // get returns the current nonce of an account, falling back to a real state // database if the account is unknown. -func (txn *txNoncer) get(addr common.Address) uint64 { +func (txn *noncer) get(addr common.Address) uint64 { // We use mutex for get operation is the underlying // state will mutate db even for read access. txn.lock.Lock() @@ -58,7 +58,7 @@ func (txn *txNoncer) get(addr common.Address) uint64 { // set inserts a new virtual nonce into the virtual state database to be returned // whenever the pool requests it instead of reaching into the real state database. -func (txn *txNoncer) set(addr common.Address, nonce uint64) { +func (txn *noncer) set(addr common.Address, nonce uint64) { txn.lock.Lock() defer txn.lock.Unlock() @@ -67,7 +67,7 @@ func (txn *txNoncer) set(addr common.Address, nonce uint64) { // setIfLower updates a new virtual nonce into the virtual state database if the // new one is lower. -func (txn *txNoncer) setIfLower(addr common.Address, nonce uint64) { +func (txn *noncer) setIfLower(addr common.Address, nonce uint64) { txn.lock.Lock() defer txn.lock.Unlock() @@ -83,7 +83,7 @@ func (txn *txNoncer) setIfLower(addr common.Address, nonce uint64) { } // setAll sets the nonces for all accounts to the given map. -func (txn *txNoncer) setAll(all map[common.Address]uint64) { +func (txn *noncer) setAll(all map[common.Address]uint64) { txn.lock.Lock() defer txn.lock.Unlock() diff --git a/core/tx_pool.go b/core/txpool/txpool.go similarity index 94% rename from core/tx_pool.go rename to core/txpool/txpool.go index a7142978ceec..2e02c46101da 100644 --- a/core/tx_pool.go +++ b/core/txpool/txpool.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package core +package txpool import ( "errors" @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" @@ -112,6 +113,7 @@ var ( invalidTxMeter = metrics.NewRegisteredMeter("txpool/invalid", nil) underpricedTxMeter = metrics.NewRegisteredMeter("txpool/underpriced", nil) overflowedTxMeter = metrics.NewRegisteredMeter("txpool/overflowed", nil) + // throttleTxMeter counts how many transactions are rejected due to too-many-changes between // txpool reorgs. throttleTxMeter = metrics.NewRegisteredMeter("txpool/throttle", nil) @@ -146,11 +148,11 @@ type blockChain interface { GetBlock(hash common.Hash, number uint64) *types.Block StateAt(root common.Hash) (*state.StateDB, error) - SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription + SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription } -// TxPoolConfig are the configuration parameters of the transaction pool. -type TxPoolConfig struct { +// Config are the configuration parameters of the transaction pool. +type Config struct { Locals []common.Address // Addresses that should be treated by default as local NoLocals bool // Whether local transaction handling should be disabled Journal string // Journal of local transactions to survive node restarts @@ -167,9 +169,9 @@ type TxPoolConfig struct { Lifetime time.Duration // Maximum amount of time non-executable transaction are queued } -// DefaultTxPoolConfig contains the default configurations for the transaction +// DefaultConfig contains the default configurations for the transaction // pool. -var DefaultTxPoolConfig = TxPoolConfig{ +var DefaultConfig = Config{ Journal: "transactions.rlp", Rejournal: time.Hour, @@ -186,39 +188,39 @@ var DefaultTxPoolConfig = TxPoolConfig{ // sanitize checks the provided user configurations and changes anything that's // unreasonable or unworkable. -func (config *TxPoolConfig) sanitize() TxPoolConfig { +func (config *Config) sanitize() Config { conf := *config if conf.Rejournal < time.Second { log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second) conf.Rejournal = time.Second } if conf.PriceLimit < 1 { - log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultTxPoolConfig.PriceLimit) - conf.PriceLimit = DefaultTxPoolConfig.PriceLimit + log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultConfig.PriceLimit) + conf.PriceLimit = DefaultConfig.PriceLimit } if conf.PriceBump < 1 { - log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump) - conf.PriceBump = DefaultTxPoolConfig.PriceBump + log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultConfig.PriceBump) + conf.PriceBump = DefaultConfig.PriceBump } if conf.AccountSlots < 1 { - log.Warn("Sanitizing invalid txpool account slots", "provided", conf.AccountSlots, "updated", DefaultTxPoolConfig.AccountSlots) - conf.AccountSlots = DefaultTxPoolConfig.AccountSlots + log.Warn("Sanitizing invalid txpool account slots", "provided", conf.AccountSlots, "updated", DefaultConfig.AccountSlots) + conf.AccountSlots = DefaultConfig.AccountSlots } if conf.GlobalSlots < 1 { - log.Warn("Sanitizing invalid txpool global slots", "provided", conf.GlobalSlots, "updated", DefaultTxPoolConfig.GlobalSlots) - conf.GlobalSlots = DefaultTxPoolConfig.GlobalSlots + log.Warn("Sanitizing invalid txpool global slots", "provided", conf.GlobalSlots, "updated", DefaultConfig.GlobalSlots) + conf.GlobalSlots = DefaultConfig.GlobalSlots } if conf.AccountQueue < 1 { - log.Warn("Sanitizing invalid txpool account queue", "provided", conf.AccountQueue, "updated", DefaultTxPoolConfig.AccountQueue) - conf.AccountQueue = DefaultTxPoolConfig.AccountQueue + log.Warn("Sanitizing invalid txpool account queue", "provided", conf.AccountQueue, "updated", DefaultConfig.AccountQueue) + conf.AccountQueue = DefaultConfig.AccountQueue } if conf.GlobalQueue < 1 { - log.Warn("Sanitizing invalid txpool global queue", "provided", conf.GlobalQueue, "updated", DefaultTxPoolConfig.GlobalQueue) - conf.GlobalQueue = DefaultTxPoolConfig.GlobalQueue + log.Warn("Sanitizing invalid txpool global queue", "provided", conf.GlobalQueue, "updated", DefaultConfig.GlobalQueue) + conf.GlobalQueue = DefaultConfig.GlobalQueue } if conf.Lifetime < 1 { - log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultTxPoolConfig.Lifetime) - conf.Lifetime = DefaultTxPoolConfig.Lifetime + log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultConfig.Lifetime) + conf.Lifetime = DefaultConfig.Lifetime } return conf } @@ -231,7 +233,7 @@ func (config *TxPoolConfig) sanitize() TxPoolConfig { // current state) and future transactions. Transactions move between those // two states over time as they are received and processed. type TxPool struct { - config TxPoolConfig + config Config chainconfig *params.ChainConfig chain blockChain gasPrice *big.Int @@ -245,19 +247,19 @@ type TxPool struct { eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions. currentState *state.StateDB // Current state in the blockchain head - pendingNonces *txNoncer // Pending state tracking virtual nonces + pendingNonces *noncer // Pending state tracking virtual nonces currentMaxGas uint64 // Current gas limit for transaction caps locals *accountSet // Set of local transaction to exempt from eviction rules - journal *txJournal // Journal of local transaction to back up to disk + journal *journal // Journal of local transaction to back up to disk - pending map[common.Address]*txList // All currently processable transactions - queue map[common.Address]*txList // Queued but non-processable transactions + pending map[common.Address]*list // All currently processable transactions + queue map[common.Address]*list // Queued but non-processable transactions beats map[common.Address]time.Time // Last heartbeat from each known account - all *txLookup // All transactions to allow lookups - priced *txPricedList // All transactions sorted by price + all *lookup // All transactions to allow lookups + priced *pricedList // All transactions sorted by price - chainHeadCh chan ChainHeadEvent + chainHeadCh chan core.ChainHeadEvent chainHeadSub event.Subscription reqResetCh chan *txpoolResetRequest reqPromoteCh chan *accountSet @@ -276,7 +278,7 @@ type txpoolResetRequest struct { // NewTxPool creates a new transaction pool to gather, sort and filter inbound // transactions from the network. -func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain) *TxPool { +func NewTxPool(config Config, chainconfig *params.ChainConfig, chain blockChain) *TxPool { // Sanitize the input to ensure no vulnerable gas prices are set config = (&config).sanitize() @@ -286,11 +288,11 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block chainconfig: chainconfig, chain: chain, signer: types.LatestSigner(chainconfig), - pending: make(map[common.Address]*txList), - queue: make(map[common.Address]*txList), + pending: make(map[common.Address]*list), + queue: make(map[common.Address]*list), beats: make(map[common.Address]time.Time), - all: newTxLookup(), - chainHeadCh: make(chan ChainHeadEvent, chainHeadChanSize), + all: newLookup(), + chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), reqResetCh: make(chan *txpoolResetRequest), reqPromoteCh: make(chan *accountSet), queueTxEventCh: make(chan *types.Transaction), @@ -304,7 +306,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block log.Info("Setting new local account", "address", addr) pool.locals.add(addr) } - pool.priced = newTxPricedList(pool.all) + pool.priced = newPricedList(pool.all) pool.reset(nil, chain.CurrentBlock().Header()) // Start the reorg loop early so it can handle requests generated during journal loading. @@ -427,7 +429,7 @@ func (pool *TxPool) Stop() { // SubscribeNewTxsEvent registers a subscription of NewTxsEvent and // starts sending event to the given channel. -func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- NewTxsEvent) event.Subscription { +func (pool *TxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { return pool.scope.Track(pool.txFeed.Subscribe(ch)) } @@ -586,11 +588,11 @@ func (pool *TxPool) local() map[common.Address]types.Transactions { func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { // Accept only legacy transactions until EIP-2718/2930 activates. if !pool.eip2718 && tx.Type() != types.LegacyTxType { - return ErrTxTypeNotSupported + return core.ErrTxTypeNotSupported } // Reject dynamic fee transactions until EIP-1559 activates. if !pool.eip1559 && tx.Type() == types.DynamicFeeTxType { - return ErrTxTypeNotSupported + return core.ErrTxTypeNotSupported } // Reject transactions over defined size to prevent DOS attacks if uint64(tx.Size()) > txMaxSize { @@ -607,14 +609,14 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { } // Sanity check for extremely large numbers if tx.GasFeeCap().BitLen() > 256 { - return ErrFeeCapVeryHigh + return core.ErrFeeCapVeryHigh } if tx.GasTipCap().BitLen() > 256 { - return ErrTipVeryHigh + return core.ErrTipVeryHigh } // Ensure gasFeeCap is greater than or equal to gasTipCap. if tx.GasFeeCapIntCmp(tx.GasTipCap()) < 0 { - return ErrTipAboveFeeCap + return core.ErrTipAboveFeeCap } // Make sure the transaction is signed properly. from, err := types.Sender(pool.signer, tx) @@ -627,20 +629,20 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { } // Ensure the transaction adheres to nonce ordering if pool.currentState.GetNonce(from) > tx.Nonce() { - return ErrNonceTooLow + return core.ErrNonceTooLow } // Transactor should have enough funds to cover the costs // cost == V + GP * GL if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { - return ErrInsufficientFunds + return core.ErrInsufficientFunds } // Ensure the transaction has more gas than the basic tx fee. - intrGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul) + intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul) if err != nil { return err } if tx.Gas() < intrGas { - return ErrIntrinsicGas + return core.ErrIntrinsicGas } return nil } @@ -759,7 +761,7 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction, local boo // Try to insert the transaction into the future queue from, _ := types.Sender(pool.signer, tx) // already validated if pool.queue[from] == nil { - pool.queue[from] = newTxList(false) + pool.queue[from] = newList(false) } inserted, old := pool.queue[from].Add(tx, pool.config.PriceBump) if !inserted { @@ -811,7 +813,7 @@ func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) { func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool { // Try to insert the transaction into the pending queue if pool.pending[addr] == nil { - pool.pending[addr] = newTxList(true) + pool.pending[addr] = newList(true) } list := pool.pending[addr] @@ -1078,7 +1080,7 @@ func (pool *TxPool) scheduleReorgLoop() { launchNextRun bool reset *txpoolResetRequest dirtyAccounts *accountSet - queuedEvents = make(map[common.Address]*txSortedMap) + queuedEvents = make(map[common.Address]*sortedMap) ) for { // Launch next background reorg if needed @@ -1091,7 +1093,7 @@ func (pool *TxPool) scheduleReorgLoop() { launchNextRun = false reset, dirtyAccounts = nil, nil - queuedEvents = make(map[common.Address]*txSortedMap) + queuedEvents = make(map[common.Address]*sortedMap) } select { @@ -1120,7 +1122,7 @@ func (pool *TxPool) scheduleReorgLoop() { // request one later if they want the events sent. addr, _ := types.Sender(pool.signer, tx) if _, ok := queuedEvents[addr]; !ok { - queuedEvents[addr] = newTxSortedMap() + queuedEvents[addr] = newSortedMap() } queuedEvents[addr].Put(tx) @@ -1139,7 +1141,7 @@ func (pool *TxPool) scheduleReorgLoop() { } // runReorg runs reset and promoteExecutables on behalf of scheduleReorgLoop. -func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirtyAccounts *accountSet, events map[common.Address]*txSortedMap) { +func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirtyAccounts *accountSet, events map[common.Address]*sortedMap) { defer func(t0 time.Time) { reorgDurationTimer.Update(time.Since(t0)) }(time.Now()) @@ -1202,7 +1204,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt for _, tx := range promoted { addr, _ := types.Sender(pool.signer, tx) if _, ok := events[addr]; !ok { - events[addr] = newTxSortedMap() + events[addr] = newSortedMap() } events[addr].Put(tx) } @@ -1211,7 +1213,7 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt for _, set := range events { txs = append(txs, set.Flatten()...) } - pool.txFeed.Send(NewTxsEvent{txs}) + pool.txFeed.Send(core.NewTxsEvent{Txs: txs}) } } @@ -1238,7 +1240,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { if rem == nil { // This can happen if a setHead is performed, where we simply discard the old // head from the chain. - // If that is the case, we don't have the lost transactions any more, and + // If that is the case, we don't have the lost transactions anymore, and // there's nothing to add if newNum >= oldNum { // If we reorged to a same or higher number, then it's not a case of setHead @@ -1291,12 +1293,12 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { return } pool.currentState = statedb - pool.pendingNonces = newTxNoncer(statedb) + pool.pendingNonces = newNoncer(statedb) pool.currentMaxGas = newHead.GasLimit // Inject any transactions discarded due to reorgs log.Debug("Reinjecting stale transactions", "count", len(reinject)) - senderCacher.recover(pool.signer, reinject) + core.SenderCacher.Recover(pool.signer, reinject) pool.addTxsLocked(reinject, false) // Update all fork indicator by next pending block number. @@ -1554,8 +1556,6 @@ func (pool *TxPool) demoteUnexecutables() { pool.enqueueTx(hash, tx, false, false) } pendingGauge.Dec(int64(len(gapped))) - // This might happen in a reorg, so log it to the metering - blockReorgInvalidatedTx.Mark(int64(len(gapped))) } // Delete the entire pending entry if it became empty. if list.Empty() { @@ -1646,7 +1646,7 @@ func (as *accountSet) merge(other *accountSet) { as.cache = nil } -// txLookup is used internally by TxPool to track transactions while allowing +// lookup is used internally by TxPool to track transactions while allowing // lookup without mutex contention. // // Note, although this type is properly protected against concurrent access, it @@ -1658,16 +1658,16 @@ func (as *accountSet) merge(other *accountSet) { // // This lookup set combines the notion of "local transactions", which is useful // to build upper-level structure. -type txLookup struct { +type lookup struct { slots int lock sync.RWMutex locals map[common.Hash]*types.Transaction remotes map[common.Hash]*types.Transaction } -// newTxLookup returns a new txLookup structure. -func newTxLookup() *txLookup { - return &txLookup{ +// newLookup returns a new lookup structure. +func newLookup() *lookup { + return &lookup{ locals: make(map[common.Hash]*types.Transaction), remotes: make(map[common.Hash]*types.Transaction), } @@ -1676,7 +1676,7 @@ func newTxLookup() *txLookup { // Range calls f on each key and value present in the map. The callback passed // should return the indicator whether the iteration needs to be continued. // Callers need to specify which set (or both) to be iterated. -func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction, local bool) bool, local bool, remote bool) { +func (t *lookup) Range(f func(hash common.Hash, tx *types.Transaction, local bool) bool, local bool, remote bool) { t.lock.RLock() defer t.lock.RUnlock() @@ -1697,7 +1697,7 @@ func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction, local b } // Get returns a transaction if it exists in the lookup, or nil if not found. -func (t *txLookup) Get(hash common.Hash) *types.Transaction { +func (t *lookup) Get(hash common.Hash) *types.Transaction { t.lock.RLock() defer t.lock.RUnlock() @@ -1708,7 +1708,7 @@ func (t *txLookup) Get(hash common.Hash) *types.Transaction { } // GetLocal returns a transaction if it exists in the lookup, or nil if not found. -func (t *txLookup) GetLocal(hash common.Hash) *types.Transaction { +func (t *lookup) GetLocal(hash common.Hash) *types.Transaction { t.lock.RLock() defer t.lock.RUnlock() @@ -1716,7 +1716,7 @@ func (t *txLookup) GetLocal(hash common.Hash) *types.Transaction { } // GetRemote returns a transaction if it exists in the lookup, or nil if not found. -func (t *txLookup) GetRemote(hash common.Hash) *types.Transaction { +func (t *lookup) GetRemote(hash common.Hash) *types.Transaction { t.lock.RLock() defer t.lock.RUnlock() @@ -1724,7 +1724,7 @@ func (t *txLookup) GetRemote(hash common.Hash) *types.Transaction { } // Count returns the current number of transactions in the lookup. -func (t *txLookup) Count() int { +func (t *lookup) Count() int { t.lock.RLock() defer t.lock.RUnlock() @@ -1732,7 +1732,7 @@ func (t *txLookup) Count() int { } // LocalCount returns the current number of local transactions in the lookup. -func (t *txLookup) LocalCount() int { +func (t *lookup) LocalCount() int { t.lock.RLock() defer t.lock.RUnlock() @@ -1740,7 +1740,7 @@ func (t *txLookup) LocalCount() int { } // RemoteCount returns the current number of remote transactions in the lookup. -func (t *txLookup) RemoteCount() int { +func (t *lookup) RemoteCount() int { t.lock.RLock() defer t.lock.RUnlock() @@ -1748,7 +1748,7 @@ func (t *txLookup) RemoteCount() int { } // Slots returns the current number of slots used in the lookup. -func (t *txLookup) Slots() int { +func (t *lookup) Slots() int { t.lock.RLock() defer t.lock.RUnlock() @@ -1756,7 +1756,7 @@ func (t *txLookup) Slots() int { } // Add adds a transaction to the lookup. -func (t *txLookup) Add(tx *types.Transaction, local bool) { +func (t *lookup) Add(tx *types.Transaction, local bool) { t.lock.Lock() defer t.lock.Unlock() @@ -1771,7 +1771,7 @@ func (t *txLookup) Add(tx *types.Transaction, local bool) { } // Remove removes a transaction from the lookup. -func (t *txLookup) Remove(hash common.Hash) { +func (t *lookup) Remove(hash common.Hash) { t.lock.Lock() defer t.lock.Unlock() @@ -1792,7 +1792,7 @@ func (t *txLookup) Remove(hash common.Hash) { // RemoteToLocals migrates the transactions belongs to the given locals to locals // set. The assumption is held the locals set is thread-safe to be used. -func (t *txLookup) RemoteToLocals(locals *accountSet) int { +func (t *lookup) RemoteToLocals(locals *accountSet) int { t.lock.Lock() defer t.lock.Unlock() @@ -1808,7 +1808,7 @@ func (t *txLookup) RemoteToLocals(locals *accountSet) int { } // RemotesBelowTip finds all remote transactions below the given tip threshold. -func (t *txLookup) RemotesBelowTip(threshold *big.Int) types.Transactions { +func (t *lookup) RemotesBelowTip(threshold *big.Int) types.Transactions { found := make(types.Transactions, 0, 128) t.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool { if tx.GasTipCapIntCmp(threshold) < 0 { diff --git a/core/tx_pool_test.go b/core/txpool/txpool_test.go similarity index 91% rename from core/tx_pool_test.go rename to core/txpool/txpool_test.go index adc7e4fe1468..7aa016ab4192 100644 --- a/core/tx_pool_test.go +++ b/core/txpool/txpool_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package core +package txpool import ( "crypto/ecdsa" @@ -28,6 +28,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -40,14 +41,14 @@ import ( var ( // testTxPoolConfig is a transaction pool configuration without stateful disk // sideeffects used during testing. - testTxPoolConfig TxPoolConfig + testTxPoolConfig Config // eip1559Config is a chain config with EIP-1559 enabled at block 0. eip1559Config *params.ChainConfig ) func init() { - testTxPoolConfig = DefaultTxPoolConfig + testTxPoolConfig = DefaultConfig testTxPoolConfig.Journal = "" cpy := *params.TestChainConfig @@ -76,7 +77,7 @@ func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { return bc.statedb, nil } -func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription { +func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { return bc.chainHeadFeed.Subscribe(ch) } @@ -112,11 +113,11 @@ func dynamicFeeTx(nonce uint64, gaslimit uint64, gasFee *big.Int, tip *big.Int, return tx } -func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { - return setupTxPoolWithConfig(params.TestChainConfig) +func setupPool() (*TxPool, *ecdsa.PrivateKey) { + return setupPoolWithConfig(params.TestChainConfig) } -func setupTxPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateKey) { +func setupPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateKey) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) blockchain := &testBlockChain{10000000, statedb, new(event.Feed)} @@ -128,8 +129,8 @@ func setupTxPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateK return pool, key } -// validateTxPoolInternals checks various consistency invariants within the pool. -func validateTxPoolInternals(pool *TxPool) error { +// validatePoolInternals checks various consistency invariants within the pool. +func validatePoolInternals(pool *TxPool) error { pool.mu.RLock() defer pool.mu.RUnlock() @@ -161,7 +162,7 @@ func validateTxPoolInternals(pool *TxPool) error { // validateEvents checks that the correct number of transaction addition events // were fired on the pool's event feed. -func validateEvents(events chan NewTxsEvent, count int) error { +func validateEvents(events chan core.NewTxsEvent, count int) error { var received []*types.Transaction for len(received) < count { @@ -218,7 +219,7 @@ func (c *testChain) State() (*state.StateDB, error) { // This test simulates a scenario where a new block is imported during a // state reset and tests whether the pending state is in sync with the // block head event that initiated the resetState(). -func TestStateChangeDuringTransactionPoolReset(t *testing.T) { +func TestStateChangeDuringReset(t *testing.T) { t.Parallel() var ( @@ -275,28 +276,28 @@ func testSetNonce(pool *TxPool, addr common.Address, nonce uint64) { func TestInvalidTransactions(t *testing.T) { t.Parallel() - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() tx := transaction(0, 100, key) from, _ := deriveSender(tx) testAddBalance(pool, from, big.NewInt(1)) - if err := pool.AddRemote(tx); !errors.Is(err, ErrInsufficientFunds) { - t.Error("expected", ErrInsufficientFunds) + if err := pool.AddRemote(tx); !errors.Is(err, core.ErrInsufficientFunds) { + t.Error("expected", core.ErrInsufficientFunds) } balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())) testAddBalance(pool, from, balance) - if err := pool.AddRemote(tx); !errors.Is(err, ErrIntrinsicGas) { - t.Error("expected", ErrIntrinsicGas, "got", err) + if err := pool.AddRemote(tx); !errors.Is(err, core.ErrIntrinsicGas) { + t.Error("expected", core.ErrIntrinsicGas, "got", err) } testSetNonce(pool, from, 1) testAddBalance(pool, from, big.NewInt(0xffffffffffffff)) tx = transaction(0, 100000, key) - if err := pool.AddRemote(tx); !errors.Is(err, ErrNonceTooLow) { - t.Error("expected", ErrNonceTooLow) + if err := pool.AddRemote(tx); !errors.Is(err, core.ErrNonceTooLow) { + t.Error("expected", core.ErrNonceTooLow) } tx = transaction(1, 100000, key) @@ -309,10 +310,10 @@ func TestInvalidTransactions(t *testing.T) { } } -func TestTransactionQueue(t *testing.T) { +func TestQueue(t *testing.T) { t.Parallel() - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() tx := transaction(0, 100, key) @@ -340,10 +341,10 @@ func TestTransactionQueue(t *testing.T) { } } -func TestTransactionQueue2(t *testing.T) { +func TestQueue2(t *testing.T) { t.Parallel() - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() tx1 := transaction(0, 100, key) @@ -366,10 +367,10 @@ func TestTransactionQueue2(t *testing.T) { } } -func TestTransactionNegativeValue(t *testing.T) { +func TestNegativeValue(t *testing.T) { t.Parallel() - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key) @@ -380,43 +381,43 @@ func TestTransactionNegativeValue(t *testing.T) { } } -func TestTransactionTipAboveFeeCap(t *testing.T) { +func TestTipAboveFeeCap(t *testing.T) { t.Parallel() - pool, key := setupTxPoolWithConfig(eip1559Config) + pool, key := setupPoolWithConfig(eip1559Config) defer pool.Stop() tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key) - if err := pool.AddRemote(tx); err != ErrTipAboveFeeCap { - t.Error("expected", ErrTipAboveFeeCap, "got", err) + if err := pool.AddRemote(tx); err != core.ErrTipAboveFeeCap { + t.Error("expected", core.ErrTipAboveFeeCap, "got", err) } } -func TestTransactionVeryHighValues(t *testing.T) { +func TestVeryHighValues(t *testing.T) { t.Parallel() - pool, key := setupTxPoolWithConfig(eip1559Config) + pool, key := setupPoolWithConfig(eip1559Config) defer pool.Stop() veryBigNumber := big.NewInt(1) veryBigNumber.Lsh(veryBigNumber, 300) tx := dynamicFeeTx(0, 100, big.NewInt(1), veryBigNumber, key) - if err := pool.AddRemote(tx); err != ErrTipVeryHigh { - t.Error("expected", ErrTipVeryHigh, "got", err) + if err := pool.AddRemote(tx); err != core.ErrTipVeryHigh { + t.Error("expected", core.ErrTipVeryHigh, "got", err) } tx2 := dynamicFeeTx(0, 100, veryBigNumber, big.NewInt(1), key) - if err := pool.AddRemote(tx2); err != ErrFeeCapVeryHigh { - t.Error("expected", ErrFeeCapVeryHigh, "got", err) + if err := pool.AddRemote(tx2); err != core.ErrFeeCapVeryHigh { + t.Error("expected", core.ErrFeeCapVeryHigh, "got", err) } } -func TestTransactionChainFork(t *testing.T) { +func TestChainFork(t *testing.T) { t.Parallel() - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() addr := crypto.PubkeyToAddress(key.PublicKey) @@ -442,10 +443,10 @@ func TestTransactionChainFork(t *testing.T) { } } -func TestTransactionDoubleNonce(t *testing.T) { +func TestDoubleNonce(t *testing.T) { t.Parallel() - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() addr := crypto.PubkeyToAddress(key.PublicKey) @@ -493,10 +494,10 @@ func TestTransactionDoubleNonce(t *testing.T) { } } -func TestTransactionMissingNonce(t *testing.T) { +func TestMissingNonce(t *testing.T) { t.Parallel() - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() addr := crypto.PubkeyToAddress(key.PublicKey) @@ -516,11 +517,11 @@ func TestTransactionMissingNonce(t *testing.T) { } } -func TestTransactionNonceRecovery(t *testing.T) { +func TestNonceRecovery(t *testing.T) { t.Parallel() const n = 10 - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() addr := crypto.PubkeyToAddress(key.PublicKey) @@ -542,11 +543,11 @@ func TestTransactionNonceRecovery(t *testing.T) { // Tests that if an account runs out of funds, any pending and queued transactions // are dropped. -func TestTransactionDropping(t *testing.T) { +func TestDropping(t *testing.T) { t.Parallel() // Create a test account and fund it - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() account := crypto.PubkeyToAddress(key.PublicKey) @@ -646,7 +647,7 @@ func TestTransactionDropping(t *testing.T) { // Tests that if a transaction is dropped from the current pending pool (e.g. out // of fund), all consecutive (still valid, but not executable) transactions are // postponed back into the future queue to prevent broadcasting them. -func TestTransactionPostponing(t *testing.T) { +func TestPostponing(t *testing.T) { t.Parallel() // Create the pool to test the postponing with @@ -759,18 +760,18 @@ func TestTransactionPostponing(t *testing.T) { // Tests that if the transaction pool has both executable and non-executable // transactions from an origin account, filling the nonce gap moves all queued // ones into the pending pool. -func TestTransactionGapFilling(t *testing.T) { +func TestGapFilling(t *testing.T) { t.Parallel() // Create a test account and fund it - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000)) // Keep track of transaction events to ensure all executables get announced - events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue+5) + events := make(chan core.NewTxsEvent, testTxPoolConfig.AccountQueue+5) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -789,7 +790,7 @@ func TestTransactionGapFilling(t *testing.T) { if err := validateEvents(events, 1); err != nil { t.Fatalf("original event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Fill the nonce gap and ensure all transactions become pending @@ -806,18 +807,18 @@ func TestTransactionGapFilling(t *testing.T) { if err := validateEvents(events, 2); err != nil { t.Fatalf("gap-filling event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } // Tests that if the transaction count belonging to a single account goes above // some threshold, the higher transactions are dropped to prevent DOS attacks. -func TestTransactionQueueAccountLimiting(t *testing.T) { +func TestQueueAccountLimiting(t *testing.T) { t.Parallel() // Create a test account and fund it - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() account := crypto.PubkeyToAddress(key.PublicKey) @@ -851,14 +852,14 @@ func TestTransactionQueueAccountLimiting(t *testing.T) { // // This logic should not hold for local transactions, unless the local tracking // mechanism is disabled. -func TestTransactionQueueGlobalLimiting(t *testing.T) { - testTransactionQueueGlobalLimiting(t, false) +func TestQueueGlobalLimiting(t *testing.T) { + testQueueGlobalLimiting(t, false) } -func TestTransactionQueueGlobalLimitingNoLocals(t *testing.T) { - testTransactionQueueGlobalLimiting(t, true) +func TestQueueGlobalLimitingNoLocals(t *testing.T) { + testQueueGlobalLimiting(t, true) } -func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { +func testQueueGlobalLimiting(t *testing.T, nolocals bool) { t.Parallel() // Create the pool to test the limit enforcement with @@ -941,14 +942,14 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { // // This logic should not hold for local transactions, unless the local tracking // mechanism is disabled. -func TestTransactionQueueTimeLimiting(t *testing.T) { - testTransactionQueueTimeLimiting(t, false) +func TestQueueTimeLimiting(t *testing.T) { + testQueueTimeLimiting(t, false) } -func TestTransactionQueueTimeLimitingNoLocals(t *testing.T) { - testTransactionQueueTimeLimiting(t, true) +func TestQueueTimeLimitingNoLocals(t *testing.T) { + testQueueTimeLimiting(t, true) } -func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { +func testQueueTimeLimiting(t *testing.T, nolocals bool) { // Reduce the eviction interval to a testable amount defer func(old time.Duration) { evictionInterval = old }(evictionInterval) evictionInterval = time.Millisecond * 100 @@ -985,7 +986,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { if queued != 2 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1000,7 +1001,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { if queued != 2 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1020,7 +1021,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) } } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1037,7 +1038,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { if queued != 0 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1067,7 +1068,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { if queued != 2 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1086,7 +1087,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) } } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } @@ -1094,18 +1095,18 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { // Tests that even if the transaction count belonging to a single account goes // above some threshold, as long as the transactions are executable, they are // accepted. -func TestTransactionPendingLimiting(t *testing.T) { +func TestPendingLimiting(t *testing.T) { t.Parallel() // Create a test account and fund it - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000)) // Keep track of transaction events to ensure all executables get announced - events := make(chan NewTxsEvent, testTxPoolConfig.AccountQueue+5) + events := make(chan core.NewTxsEvent, testTxPoolConfig.AccountQueue+5) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -1127,7 +1128,7 @@ func TestTransactionPendingLimiting(t *testing.T) { if err := validateEvents(events, int(testTxPoolConfig.AccountQueue+5)); err != nil { t.Fatalf("event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } @@ -1135,7 +1136,7 @@ func TestTransactionPendingLimiting(t *testing.T) { // Tests that if the transaction count belonging to multiple accounts go above // some hard threshold, the higher transactions are dropped to prevent DOS // attacks. -func TestTransactionPendingGlobalLimiting(t *testing.T) { +func TestPendingGlobalLimiting(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with @@ -1175,7 +1176,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { if pending > int(config.GlobalSlots) { t.Fatalf("total pending transactions overflow allowance: %d > %d", pending, config.GlobalSlots) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } @@ -1183,11 +1184,11 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { // Test the limit on transaction size is enforced correctly. // This test verifies every transaction having allowed size // is added to the pool, and longer transactions are rejected. -func TestTransactionAllowedTxSize(t *testing.T) { +func TestAllowedTxSize(t *testing.T) { t.Parallel() // Create a test account and fund it - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() account := crypto.PubkeyToAddress(key.PublicKey) @@ -1231,13 +1232,13 @@ func TestTransactionAllowedTxSize(t *testing.T) { if queued != 0 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } // Tests that if transactions start being capped, transactions are also removed from 'all' -func TestTransactionCapClearsFromAll(t *testing.T) { +func TestCapClearsFromAll(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with @@ -1263,7 +1264,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) { } // Import the batch and verify that limits have been enforced pool.AddRemotes(txs) - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } @@ -1271,7 +1272,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) { // Tests that if the transaction count belonging to multiple accounts go above // some hard threshold, if they are under the minimum guaranteed slot count then // the transactions are still kept. -func TestTransactionPendingMinimumAllowance(t *testing.T) { +func TestPendingMinimumAllowance(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with @@ -1309,7 +1310,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { t.Errorf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), config.AccountSlots) } } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } @@ -1319,7 +1320,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { // from the pending pool to the queue. // // Note, local transactions are never allowed to be dropped. -func TestTransactionPoolRepricing(t *testing.T) { +func TestRepricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with @@ -1330,7 +1331,7 @@ func TestTransactionPoolRepricing(t *testing.T) { defer pool.Stop() // Keep track of transaction events to ensure all executables get announced - events := make(chan NewTxsEvent, 32) + events := make(chan core.NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -1371,7 +1372,7 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateEvents(events, 7); err != nil { t.Fatalf("original event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Reprice the pool and check that underpriced transactions get dropped @@ -1387,7 +1388,7 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateEvents(events, 0); err != nil { t.Fatalf("reprice event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Check that we can't add the old transactions back @@ -1403,7 +1404,7 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateEvents(events, 0); err != nil { t.Fatalf("post-reprice event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // However we can add local underpriced transactions @@ -1417,7 +1418,7 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateEvents(events, 1); err != nil { t.Fatalf("post-reprice local event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // And we can fill gaps with properly priced transactions @@ -1433,7 +1434,7 @@ func TestTransactionPoolRepricing(t *testing.T) { if err := validateEvents(events, 5); err != nil { t.Fatalf("post-reprice event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } @@ -1443,15 +1444,15 @@ func TestTransactionPoolRepricing(t *testing.T) { // gapped transactions back from the pending pool to the queue. // // Note, local transactions are never allowed to be dropped. -func TestTransactionPoolRepricingDynamicFee(t *testing.T) { +func TestRepricingDynamicFee(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - pool, _ := setupTxPoolWithConfig(eip1559Config) + pool, _ := setupPoolWithConfig(eip1559Config) defer pool.Stop() // Keep track of transaction events to ensure all executables get announced - events := make(chan NewTxsEvent, 32) + events := make(chan core.NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -1492,7 +1493,7 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) { if err := validateEvents(events, 7); err != nil { t.Fatalf("original event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Reprice the pool and check that underpriced transactions get dropped @@ -1508,7 +1509,7 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) { if err := validateEvents(events, 0); err != nil { t.Fatalf("reprice event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Check that we can't add the old transactions back @@ -1527,7 +1528,7 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) { if err := validateEvents(events, 0); err != nil { t.Fatalf("post-reprice event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // However we can add local underpriced transactions @@ -1541,7 +1542,7 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) { if err := validateEvents(events, 1); err != nil { t.Fatalf("post-reprice local event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // And we can fill gaps with properly priced transactions @@ -1560,14 +1561,14 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) { if err := validateEvents(events, 5); err != nil { t.Fatalf("post-reprice event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } // Tests that setting the transaction pool gas price to a higher value does not // remove local transactions (legacy & dynamic fee). -func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { +func TestRepricingKeepsLocals(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with @@ -1618,7 +1619,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, expQueued) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } @@ -1640,7 +1641,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { // pending transactions are moved into the queue. // // Note, local transactions are never allowed to be dropped. -func TestTransactionPoolUnderpricing(t *testing.T) { +func TestUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with @@ -1655,7 +1656,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { defer pool.Stop() // Keep track of transaction events to ensure all executables get announced - events := make(chan NewTxsEvent, 32) + events := make(chan core.NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -1689,7 +1690,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { if err := validateEvents(events, 3); err != nil { t.Fatalf("original event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Ensure that adding an underpriced transaction on block limit fails @@ -1716,7 +1717,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { if err := validateEvents(events, 1); err != nil { t.Fatalf("additional event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Ensure that adding local transactions can push out even higher priced ones @@ -1738,7 +1739,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { if err := validateEvents(events, 2); err != nil { t.Fatalf("local event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } @@ -1746,7 +1747,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { // Tests that more expensive transactions push out cheap ones from the pool, but // without producing instability by creating gaps that start jumping transactions // back and forth between queued/pending. -func TestTransactionPoolStableUnderpricing(t *testing.T) { +func TestStableUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with @@ -1761,7 +1762,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) { defer pool.Stop() // Keep track of transaction events to ensure all executables get announced - events := make(chan NewTxsEvent, 32) + events := make(chan core.NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -1788,7 +1789,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) { if err := validateEvents(events, int(config.GlobalSlots)); err != nil { t.Fatalf("original event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Ensure that adding high priced transactions drops a cheap, but doesn't produce a gap @@ -1805,7 +1806,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) { if err := validateEvents(events, 1); err != nil { t.Fatalf("additional event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } @@ -1815,17 +1816,17 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) { // expensive ones and any gapped pending transactions are moved into the queue. // // Note, local transactions are never allowed to be dropped. -func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) { +func TestUnderpricingDynamicFee(t *testing.T) { t.Parallel() - pool, _ := setupTxPoolWithConfig(eip1559Config) + pool, _ := setupPoolWithConfig(eip1559Config) defer pool.Stop() pool.config.GlobalSlots = 2 pool.config.GlobalQueue = 2 // Keep track of transaction events to ensure all executables get announced - events := make(chan NewTxsEvent, 32) + events := make(chan core.NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -1859,7 +1860,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) { if err := validateEvents(events, 3); err != nil { t.Fatalf("original event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } @@ -1893,7 +1894,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) { if err := validateEvents(events, 1); err != nil { t.Fatalf("additional event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Ensure that adding local transactions can push out even higher priced ones @@ -1915,7 +1916,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) { if err := validateEvents(events, 2); err != nil { t.Fatalf("local event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } @@ -1925,7 +1926,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) { func TestDualHeapEviction(t *testing.T) { t.Parallel() - pool, _ := setupTxPoolWithConfig(eip1559Config) + pool, _ := setupPoolWithConfig(eip1559Config) defer pool.Stop() pool.config.GlobalSlots = 10 @@ -1972,13 +1973,13 @@ func TestDualHeapEviction(t *testing.T) { check(highTip, "effective tip") } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } // Tests that the pool rejects duplicate transactions. -func TestTransactionDeduplication(t *testing.T) { +func TestDeduplication(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with @@ -2037,14 +2038,14 @@ func TestTransactionDeduplication(t *testing.T) { if queued != 0 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } // Tests that the pool rejects replacement transactions that don't meet the minimum // price bump required. -func TestTransactionReplacement(t *testing.T) { +func TestReplacement(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with @@ -2055,7 +2056,7 @@ func TestTransactionReplacement(t *testing.T) { defer pool.Stop() // Keep track of transaction events to ensure all executables get announced - events := make(chan NewTxsEvent, 32) + events := make(chan core.NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -2117,23 +2118,23 @@ func TestTransactionReplacement(t *testing.T) { if err := validateEvents(events, 0); err != nil { t.Fatalf("queued replacement event firing failed: %v", err) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } // Tests that the pool rejects replacement dynamic fee transactions that don't // meet the minimum price bump required. -func TestTransactionReplacementDynamicFee(t *testing.T) { +func TestReplacementDynamicFee(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - pool, key := setupTxPoolWithConfig(eip1559Config) + pool, key := setupPoolWithConfig(eip1559Config) defer pool.Stop() testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000)) // Keep track of transaction events to ensure all executables get announced - events := make(chan NewTxsEvent, 32) + events := make(chan core.NewTxsEvent, 32) sub := pool.txFeed.Subscribe(events) defer sub.Unsubscribe() @@ -2227,17 +2228,17 @@ func TestTransactionReplacementDynamicFee(t *testing.T) { } } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } } // Tests that local transactions are journaled to disk, but remote transactions // get discarded between restarts. -func TestTransactionJournaling(t *testing.T) { testTransactionJournaling(t, false) } -func TestTransactionJournalingNoLocals(t *testing.T) { testTransactionJournaling(t, true) } +func TestJournaling(t *testing.T) { testJournaling(t, false) } +func TestJournalingNoLocals(t *testing.T) { testJournaling(t, true) } -func testTransactionJournaling(t *testing.T, nolocals bool) { +func testJournaling(t *testing.T, nolocals bool) { t.Parallel() // Create a temporary file for the journal @@ -2290,7 +2291,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { if queued != 0 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Terminate the old pool, bump the local nonce, create a new pool and ensure relevant transaction survive @@ -2313,7 +2314,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) } } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Bump the nonce temporarily and ensure the newly invalidated transaction is removed @@ -2339,15 +2340,15 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1) } } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } pool.Stop() } -// TestTransactionStatusCheck tests that the pool can correctly retrieve the +// TestStatusCheck tests that the pool can correctly retrieve the // pending status of individual transactions. -func TestTransactionStatusCheck(t *testing.T) { +func TestStatusCheck(t *testing.T) { t.Parallel() // Create the pool to test the status retrievals with @@ -2381,7 +2382,7 @@ func TestTransactionStatusCheck(t *testing.T) { if queued != 2 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) } - if err := validateTxPoolInternals(pool); err != nil { + if err := validatePoolInternals(pool); err != nil { t.Fatalf("pool internal state corrupted: %v", err) } // Retrieve the status of each transaction and validate them @@ -2402,7 +2403,7 @@ func TestTransactionStatusCheck(t *testing.T) { } // Test the transaction slots consumption is computed correctly -func TestTransactionSlotCount(t *testing.T) { +func TestSlotCount(t *testing.T) { t.Parallel() key, _ := crypto.GenerateKey() @@ -2427,7 +2428,7 @@ func BenchmarkPendingDemotion10000(b *testing.B) { benchmarkPendingDemotion(b, 1 func benchmarkPendingDemotion(b *testing.B, size int) { // Add a batch of transactions to a pool one by one - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() account := crypto.PubkeyToAddress(key.PublicKey) @@ -2452,7 +2453,7 @@ func BenchmarkFuturePromotion10000(b *testing.B) { benchmarkFuturePromotion(b, 1 func benchmarkFuturePromotion(b *testing.B, size int) { // Add a batch of transactions to a pool one by one - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() account := crypto.PubkeyToAddress(key.PublicKey) @@ -2470,17 +2471,17 @@ func benchmarkFuturePromotion(b *testing.B, size int) { } // Benchmarks the speed of batched transaction insertion. -func BenchmarkPoolBatchInsert100(b *testing.B) { benchmarkPoolBatchInsert(b, 100, false) } -func BenchmarkPoolBatchInsert1000(b *testing.B) { benchmarkPoolBatchInsert(b, 1000, false) } -func BenchmarkPoolBatchInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 10000, false) } +func BenchmarkBatchInsert100(b *testing.B) { benchmarkBatchInsert(b, 100, false) } +func BenchmarkBatchInsert1000(b *testing.B) { benchmarkBatchInsert(b, 1000, false) } +func BenchmarkBatchInsert10000(b *testing.B) { benchmarkBatchInsert(b, 10000, false) } -func BenchmarkPoolBatchLocalInsert100(b *testing.B) { benchmarkPoolBatchInsert(b, 100, true) } -func BenchmarkPoolBatchLocalInsert1000(b *testing.B) { benchmarkPoolBatchInsert(b, 1000, true) } -func BenchmarkPoolBatchLocalInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 10000, true) } +func BenchmarkBatchLocalInsert100(b *testing.B) { benchmarkBatchInsert(b, 100, true) } +func BenchmarkBatchLocalInsert1000(b *testing.B) { benchmarkBatchInsert(b, 1000, true) } +func BenchmarkBatchLocalInsert10000(b *testing.B) { benchmarkBatchInsert(b, 10000, true) } -func benchmarkPoolBatchInsert(b *testing.B, size int, local bool) { +func benchmarkBatchInsert(b *testing.B, size int, local bool) { // Generate a batch of transactions to enqueue into the pool - pool, key := setupTxPool() + pool, key := setupPool() defer pool.Stop() account := crypto.PubkeyToAddress(key.PublicKey) @@ -2524,7 +2525,7 @@ func BenchmarkInsertRemoteWithAllLocals(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { b.StopTimer() - pool, _ := setupTxPool() + pool, _ := setupPool() testAddBalance(pool, account, big.NewInt(100000000)) for _, local := range locals { pool.AddLocal(local) @@ -2540,9 +2541,9 @@ func BenchmarkInsertRemoteWithAllLocals(b *testing.B) { } // Benchmarks the speed of batch transaction insertion in case of multiple accounts. -func BenchmarkPoolMultiAccountBatchInsert(b *testing.B) { +func BenchmarkMultiAccountBatchInsert(b *testing.B) { // Generate a batch of transactions to enqueue into the pool - pool, _ := setupTxPool() + pool, _ := setupPool() defer pool.Stop() b.ReportAllocs() batches := make(types.Transactions, b.N) diff --git a/eth/api_backend.go b/eth/api_backend.go index ccc0966f00a5..fad88e801865 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/gasprice" @@ -284,7 +285,7 @@ func (b *EthAPIBackend) TxPoolContentFrom(addr common.Address) (types.Transactio return b.eth.TxPool().ContentFrom(addr) } -func (b *EthAPIBackend) TxPool() *core.TxPool { +func (b *EthAPIBackend) TxPool() *txpool.TxPool { return b.eth.TxPool() } diff --git a/eth/backend.go b/eth/backend.go index dca96e4f9d6c..ab2aaf7b6b12 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/pruner" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" @@ -66,7 +67,7 @@ type Ethereum struct { config *ethconfig.Config // Handlers - txPool *core.TxPool + txPool *txpool.TxPool blockchain *core.BlockChain handler *handler ethDialCandidates enode.Iterator @@ -209,7 +210,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.TxPool.Journal != "" { config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) } - eth.txPool = core.NewTxPool(config.TxPool, eth.blockchain.Config(), eth.blockchain) + eth.txPool = txpool.NewTxPool(config.TxPool, eth.blockchain.Config(), eth.blockchain) // Permit the downloader to use the trie cache allowance during fast sync cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit @@ -482,7 +483,7 @@ func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } -func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } +func (s *Ethereum) TxPool() *txpool.TxPool { return s.txPool } func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } func (s *Ethereum) Engine() consensus.Engine { return s.engine } func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index b5a7837ffda3..75606339323a 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/ethdb" @@ -85,7 +86,7 @@ var Defaults = Config{ SnapshotCache: 102, FilterLogCacheSize: 32, Miner: miner.DefaultConfig, - TxPool: core.DefaultTxPoolConfig, + TxPool: txpool.DefaultConfig, RPCGasCap: 50000000, RPCEVMTimeout: 5 * time.Second, GPO: FullNodeGPO, @@ -178,7 +179,7 @@ type Config struct { Ethash ethash.Config // Transaction pool options - TxPool core.TxPoolConfig + TxPool txpool.Config // Gas Price Oracle options GPO gasprice.Config diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 9c7a04364d20..514facde0a8b 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/miner" @@ -51,7 +52,7 @@ func (c Config) MarshalTOML() (interface{}, error) { FilterLogCacheSize int Miner miner.Config Ethash ethash.Config - TxPool core.TxPoolConfig + TxPool txpool.Config GPO gasprice.Config EnablePreimageRecording bool DocRoot string `toml:"-"` @@ -147,7 +148,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { FilterLogCacheSize *int Miner *miner.Config Ethash *ethash.Config - TxPool *core.TxPoolConfig + TxPool *txpool.Config GPO *gasprice.Config EnablePreimageRecording *bool DocRoot *string `toml:"-"` diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index d1d62eb6ef70..a9e994a8c778 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -27,7 +27,7 @@ import ( mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" - "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -298,7 +298,7 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) // Track the transaction hash if the price is too low for us. // Avoid re-request this transaction when we receive another // announcement. - if errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced) { + if errors.Is(err, txpool.ErrUnderpriced) || errors.Is(err, txpool.ErrReplaceUnderpriced) { for f.underpriced.Cardinality() >= maxTxUnderpricedSetSize { f.underpriced.Pop() } @@ -308,10 +308,10 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) switch { case err == nil: // Noop, but need to handle to not count these - case errors.Is(err, core.ErrAlreadyKnown): + case errors.Is(err, txpool.ErrAlreadyKnown): duplicate++ - case errors.Is(err, core.ErrUnderpriced) || errors.Is(err, core.ErrReplaceUnderpriced): + case errors.Is(err, txpool.ErrUnderpriced) || errors.Is(err, txpool.ErrReplaceUnderpriced): underpriced++ default: diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index 4c06712f7759..1715def99c00 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -25,7 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" - "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" ) @@ -869,9 +869,9 @@ func TestTransactionFetcherUnderpricedDedup(t *testing.T) { errs := make([]error, len(txs)) for i := 0; i < len(errs); i++ { if i%2 == 0 { - errs[i] = core.ErrUnderpriced + errs[i] = txpool.ErrUnderpriced } else { - errs[i] = core.ErrReplaceUnderpriced + errs[i] = txpool.ErrReplaceUnderpriced } } return errs @@ -941,7 +941,7 @@ func TestTransactionFetcherUnderpricedDoSProtection(t *testing.T) { func(txs []*types.Transaction) []error { errs := make([]error, len(txs)) for i := 0; i < len(errs); i++ { - errs[i] = core.ErrUnderpriced + errs[i] = txpool.ErrUnderpriced } return errs }, diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 8c0c59ba3dc6..faea081be539 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -50,7 +51,7 @@ var ( type testBackend struct { db ethdb.Database chain *core.BlockChain - txpool *core.TxPool + txpool *txpool.TxPool } // newTestBackend creates an empty chain and wraps it into a mock backend. @@ -76,13 +77,13 @@ func newTestBackendWithGenerator(blocks int, generator func(int, *core.BlockGen) for _, block := range bs { chain.StateCache().TrieDB().Commit(block.Root(), false, nil) } - txconfig := core.DefaultTxPoolConfig + txconfig := txpool.DefaultConfig txconfig.Journal = "" // Don't litter the disk with test journals return &testBackend{ db: db, chain: chain, - txpool: core.NewTxPool(txconfig, params.TestChainConfig, chain), + txpool: txpool.NewTxPool(txconfig, params.TestChainConfig, chain), } } diff --git a/les/handler_test.go b/les/handler_test.go index bd48d7eb4394..b7be29b862ab 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/les/downloader" @@ -624,20 +625,20 @@ func testTransactionStatus(t *testing.T, protocol int) { // test error status by sending an underpriced transaction tx0, _ := types.SignTx(types.NewTransaction(0, userAddr1, big.NewInt(10000), params.TxGas, nil, nil), signer, bankKey) - test(tx0, true, light.TxStatus{Status: core.TxStatusUnknown, Error: core.ErrUnderpriced.Error()}) + test(tx0, true, light.TxStatus{Status: txpool.TxStatusUnknown, Error: txpool.ErrUnderpriced.Error()}) tx1, _ := types.SignTx(types.NewTransaction(0, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, bankKey) - test(tx1, false, light.TxStatus{Status: core.TxStatusUnknown}) // query before sending, should be unknown - test(tx1, true, light.TxStatus{Status: core.TxStatusPending}) // send valid processable tx, should return pending - test(tx1, true, light.TxStatus{Status: core.TxStatusPending}) // adding it again should not return an error + test(tx1, false, light.TxStatus{Status: txpool.TxStatusUnknown}) // query before sending, should be unknown + test(tx1, true, light.TxStatus{Status: txpool.TxStatusPending}) // send valid processable tx, should return pending + test(tx1, true, light.TxStatus{Status: txpool.TxStatusPending}) // adding it again should not return an error tx2, _ := types.SignTx(types.NewTransaction(1, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, bankKey) tx3, _ := types.SignTx(types.NewTransaction(2, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, bankKey) // send transactions in the wrong order, tx3 should be queued - test(tx3, true, light.TxStatus{Status: core.TxStatusQueued}) - test(tx2, true, light.TxStatus{Status: core.TxStatusPending}) + test(tx3, true, light.TxStatus{Status: txpool.TxStatusQueued}) + test(tx2, true, light.TxStatus{Status: txpool.TxStatusPending}) // query again, now tx3 should be pending too - test(tx3, false, light.TxStatus{Status: core.TxStatusPending}) + test(tx3, false, light.TxStatus{Status: txpool.TxStatusPending}) // generate and add a block with tx1 and tx2 included gchain, _ := core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), server.db, 1, func(i int, block *core.BlockGen) { @@ -663,9 +664,9 @@ func testTransactionStatus(t *testing.T, protocol int) { // check if their status is included now block1hash := rawdb.ReadCanonicalHash(server.db, 1) - test(tx1, false, light.TxStatus{Status: core.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}}) + test(tx1, false, light.TxStatus{Status: txpool.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}}) - test(tx2, false, light.TxStatus{Status: core.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}}) + test(tx2, false, light.TxStatus{Status: txpool.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}}) // create a reorg that rolls them back gchain, _ = core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), server.db, 2, func(i int, block *core.BlockGen) {}) @@ -687,8 +688,8 @@ func testTransactionStatus(t *testing.T, protocol int) { msg.Discard() // check if their status is pending again - test(tx1, false, light.TxStatus{Status: core.TxStatusPending}) - test(tx2, false, light.TxStatus{Status: core.TxStatusPending}) + test(tx1, false, light.TxStatus{Status: txpool.TxStatusPending}) + test(tx2, false, light.TxStatus{Status: txpool.TxStatusPending}) } func TestStopResumeLES3(t *testing.T) { testStopResume(t, lpv3) } diff --git a/les/odr.go b/les/odr.go index da2121fc5fc1..943b05fdfc6e 100644 --- a/les/odr.go +++ b/les/odr.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/light" ) @@ -176,10 +177,10 @@ func (odr *LesOdr) RetrieveTxStatus(ctx context.Context, req *light.TxStatusRequ // All the response is not verifiable, so always pick the first // one we get. for index, status := range req.Status { - if result[index].Status != core.TxStatusUnknown { + if result[index].Status != txpool.TxStatusUnknown { continue } - if status.Status == core.TxStatusUnknown { + if status.Status == txpool.TxStatusUnknown { continue } result[index], missing = status, missing-1 diff --git a/les/odr_test.go b/les/odr_test.go index 48fd9f95e394..e028d35e639c 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" @@ -294,7 +295,7 @@ func testGetTxStatusFromUnindexedPeers(t *testing.T, protocol int) { if testHash == (common.Hash{}) { testHash = tx.Hash() testStatus = light.TxStatus{ - Status: core.TxStatusIncluded, + Status: txpool.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{ BlockHash: block.Hash(), BlockIndex: block.NumberU64(), @@ -327,7 +328,7 @@ func testGetTxStatusFromUnindexedPeers(t *testing.T, protocol int) { if txLookup != txIndexUnlimited && (txLookup == txIndexDisabled || number < min) { continue // Filter out unindexed transactions } - stats[i].Status = core.TxStatusIncluded + stats[i].Status = txpool.TxStatusIncluded stats[i].Lookup = &rawdb.LegacyTxLookupEntry{ BlockHash: blockHashes[hash], BlockIndex: number, diff --git a/les/server.go b/les/server.go index df453b4819a2..06bbc30fb0da 100644 --- a/les/server.go +++ b/les/server.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/les/flowcontrol" @@ -49,7 +50,7 @@ type ethBackend interface { BloomIndexer() *core.ChainIndexer ChainDb() ethdb.Database Synced() bool - TxPool() *core.TxPool + TxPool() *txpool.TxPool } type LesServer struct { diff --git a/les/server_handler.go b/les/server_handler.go index 2dac80cd434e..28815c3d85ef 100644 --- a/les/server_handler.go +++ b/les/server_handler.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/forkid" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/les/flowcontrol" @@ -62,7 +63,7 @@ type serverHandler struct { forkFilter forkid.Filter blockchain *core.BlockChain chainDb ethdb.Database - txpool *core.TxPool + txpool *txpool.TxPool server *LesServer closeCh chan struct{} // Channel used to exit all background routines of handler. @@ -73,7 +74,7 @@ type serverHandler struct { addTxsSync bool } -func newServerHandler(server *LesServer, blockchain *core.BlockChain, chainDb ethdb.Database, txpool *core.TxPool, synced func() bool) *serverHandler { +func newServerHandler(server *LesServer, blockchain *core.BlockChain, chainDb ethdb.Database, txpool *txpool.TxPool, synced func() bool) *serverHandler { handler := &serverHandler{ forkFilter: forkid.NewFilter(blockchain), server: server, @@ -343,7 +344,7 @@ func (h *serverHandler) BlockChain() *core.BlockChain { } // TxPool implements serverBackend -func (h *serverHandler) TxPool() *core.TxPool { +func (h *serverHandler) TxPool() *txpool.TxPool { return h.txpool } diff --git a/les/server_requests.go b/les/server_requests.go index aa9b70899152..3563bf93c63a 100644 --- a/les/server_requests.go +++ b/les/server_requests.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" @@ -36,7 +37,7 @@ type serverBackend interface { ArchiveMode() bool AddTxsSync() bool BlockChain() *core.BlockChain - TxPool() *core.TxPool + TxPool() *txpool.TxPool GetHelperTrie(typ uint, index uint64) *trie.Trie } @@ -516,7 +517,7 @@ func handleSendTx(msg Decoder) (serveRequestFn, uint64, uint64, error) { } hash := tx.Hash() stats[i] = txStatus(backend, hash) - if stats[i].Status == core.TxStatusUnknown { + if stats[i].Status == txpool.TxStatusUnknown { addFn := backend.TxPool().AddRemotes // Add txs synchronously for testing purpose if backend.AddTxsSync() { @@ -558,10 +559,10 @@ func txStatus(b serverBackend, hash common.Hash) light.TxStatus { stat.Status = b.TxPool().Status([]common.Hash{hash})[0] // If the transaction is unknown to the pool, try looking it up locally. - if stat.Status == core.TxStatusUnknown { + if stat.Status == txpool.TxStatusUnknown { lookup := b.BlockChain().GetTransactionLookup(hash) if lookup != nil { - stat.Status = core.TxStatusIncluded + stat.Status = txpool.TxStatusIncluded stat.Lookup = lookup } } diff --git a/les/test_helper.go b/les/test_helper.go index 8335e2c39ac5..33a76252bf05 100644 --- a/les/test_helper.go +++ b/les/test_helper.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/forkid" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" @@ -269,9 +270,9 @@ func newTestServerHandler(blocks int, indexers []*core.ChainIndexer, db ethdb.Da simulation := backends.NewSimulatedBackendWithDatabase(db, gspec.Alloc, 100000000) prepare(blocks, simulation) - txpoolConfig := core.DefaultTxPoolConfig + txpoolConfig := txpool.DefaultConfig txpoolConfig.Journal = "" - txpool := core.NewTxPool(txpoolConfig, gspec.Config, simulation.Blockchain()) + txpool := txpool.NewTxPool(txpoolConfig, gspec.Config, simulation.Blockchain()) if indexers != nil { checkpointConfig := ¶ms.CheckpointOracleConfig{ Address: crypto.CreateAddress(bankAddr, 0), diff --git a/light/odr.go b/light/odr.go index 7cebe010d41f..f998dbe58445 100644 --- a/light/odr.go +++ b/light/odr.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" ) @@ -182,7 +183,7 @@ func (req *BloomRequest) StoreResult(db ethdb.Database) { // TxStatus describes the status of a transaction type TxStatus struct { - Status core.TxStatus + Status txpool.TxStatus Lookup *rawdb.LegacyTxLookupEntry `rlp:"nil"` Error string } diff --git a/light/odr_util.go b/light/odr_util.go index 48631139b488..ea941ec32133 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -23,8 +23,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) @@ -277,7 +277,7 @@ func GetBloomBits(ctx context.Context, odr OdrBackend, bit uint, sections []uint // number of retries, thus giving a weak guarantee. func GetTransaction(ctx context.Context, odr OdrBackend, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { r := &TxStatusRequest{Hashes: []common.Hash{txHash}} - if err := odr.RetrieveTxStatus(ctx, r); err != nil || r.Status[0].Status != core.TxStatusIncluded { + if err := odr.RetrieveTxStatus(ctx, r); err != nil || r.Status[0].Status != txpool.TxStatusIncluded { return nil, common.Hash{}, 0, 0, err } pos := r.Status[0].Lookup diff --git a/light/txpool.go b/light/txpool.go index 0de1327886fb..3e3572faaf11 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -354,7 +355,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error // Validate the transaction sender and it's sig. Throw // if the from fields is invalid. if from, err = types.Sender(pool.signer, tx); err != nil { - return core.ErrInvalidSender + return txpool.ErrInvalidSender } // Last but not least check for nonce errors currentState := pool.currentState(ctx) @@ -366,14 +367,14 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error // block limit gas. header := pool.chain.GetHeaderByHash(pool.head) if header.GasLimit < tx.Gas() { - return core.ErrGasLimit + return txpool.ErrGasLimit } // Transactions can't be negative. This may never happen // using RLP decoded transactions but may occur if you create // a transaction using the RPC for example. if tx.Value().Sign() < 0 { - return core.ErrNegativeValue + return txpool.ErrNegativeValue } // Transactor should have enough funds to cover the costs diff --git a/miner/miner.go b/miner/miner.go index 0f644b200bcf..2b81b8464214 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/event" @@ -39,7 +40,7 @@ import ( // to offer all the functions here. type Backend interface { BlockChain() *core.BlockChain - TxPool() *core.TxPool + TxPool() *txpool.TxPool } // Config is the configuration parameters of mining. diff --git a/miner/miner_test.go b/miner/miner_test.go index d49c07d964ca..7c07b21dd82f 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" @@ -37,10 +38,10 @@ import ( type mockBackend struct { bc *core.BlockChain - txPool *core.TxPool + txPool *txpool.TxPool } -func NewMockBackend(bc *core.BlockChain, txPool *core.TxPool) *mockBackend { +func NewMockBackend(bc *core.BlockChain, txPool *txpool.TxPool) *mockBackend { return &mockBackend{ bc: bc, txPool: txPool, @@ -51,7 +52,7 @@ func (m *mockBackend) BlockChain() *core.BlockChain { return m.bc } -func (m *mockBackend) TxPool() *core.TxPool { +func (m *mockBackend) TxPool() *txpool.TxPool { return m.txPool } @@ -263,7 +264,7 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(chainDB), nil) blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)} - pool := core.NewTxPool(testTxPoolConfig, chainConfig, blockchain) + pool := txpool.NewTxPool(testTxPoolConfig, chainConfig, blockchain) backend := NewMockBackend(bc, pool) // Create event Mux mux := new(event.TypeMux) diff --git a/miner/stress/1559/main.go b/miner/stress/1559/main.go index 2e0a4f6c7328..b4ce2a14f287 100644 --- a/miner/stress/1559/main.go +++ b/miner/stress/1559/main.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -245,7 +246,7 @@ func makeMiner(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) { SyncMode: downloader.FullSync, DatabaseCache: 256, DatabaseHandles: 256, - TxPool: core.DefaultTxPoolConfig, + TxPool: txpool.DefaultConfig, GPO: ethconfig.Defaults.GPO, Ethash: ethconfig.Defaults.Ethash, Miner: miner.Config{ diff --git a/miner/stress/beacon/main.go b/miner/stress/beacon/main.go index 88af84c7fcd3..a4764be0ada4 100644 --- a/miner/stress/beacon/main.go +++ b/miner/stress/beacon/main.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/beacon" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -484,7 +485,7 @@ func makeFullNode(genesis *core.Genesis) (*node.Node, *eth.Ethereum, *ethcatalys SyncMode: downloader.FullSync, DatabaseCache: 256, DatabaseHandles: 256, - TxPool: core.DefaultTxPoolConfig, + TxPool: txpool.DefaultConfig, GPO: ethconfig.Defaults.GPO, Ethash: ethconfig.Defaults.Ethash, Miner: miner.Config{ @@ -535,7 +536,7 @@ func makeLightNode(genesis *core.Genesis) (*node.Node, *les.LightEthereum, *lesc SyncMode: downloader.LightSync, DatabaseCache: 256, DatabaseHandles: 256, - TxPool: core.DefaultTxPoolConfig, + TxPool: txpool.DefaultConfig, GPO: ethconfig.Defaults.GPO, Ethash: ethconfig.Defaults.Ethash, LightPeers: 10, diff --git a/miner/stress/clique/main.go b/miner/stress/clique/main.go index 070a6ed60eee..688c2b698409 100644 --- a/miner/stress/clique/main.go +++ b/miner/stress/clique/main.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -206,7 +207,7 @@ func makeSealer(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) { SyncMode: downloader.FullSync, DatabaseCache: 256, DatabaseHandles: 256, - TxPool: core.DefaultTxPoolConfig, + TxPool: txpool.DefaultConfig, GPO: ethconfig.Defaults.GPO, Miner: miner.Config{ GasCeil: genesis.GasLimit * 11 / 10, diff --git a/miner/stress/ethash/main.go b/miner/stress/ethash/main.go index 56a6e5817365..4fe5429e6d7e 100644 --- a/miner/stress/ethash/main.go +++ b/miner/stress/ethash/main.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -175,7 +176,7 @@ func makeMiner(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) { SyncMode: downloader.FullSync, DatabaseCache: 256, DatabaseHandles: 256, - TxPool: core.DefaultTxPoolConfig, + TxPool: txpool.DefaultConfig, GPO: ethconfig.Defaults.GPO, Ethash: ethconfig.Defaults.Ethash, Miner: miner.Config{ diff --git a/miner/worker.go b/miner/worker.go index bf9434eefe70..c3fca2159452 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -917,7 +917,7 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP env.tcount++ txs.Shift() - case errors.Is(err, core.ErrTxTypeNotSupported): + case errors.Is(err, types.ErrTxTypeNotSupported): // Pop the unsupported transaction without shifting in the next from the account log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type()) txs.Pop() diff --git a/miner/worker_test.go b/miner/worker_test.go index 0cba7ff9955f..fcbe5529c1d0 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -51,7 +52,7 @@ const ( var ( // Test chain configurations - testTxPoolConfig core.TxPoolConfig + testTxPoolConfig txpool.Config ethashChainConfig *params.ChainConfig cliqueChainConfig *params.ChainConfig @@ -74,7 +75,7 @@ var ( ) func init() { - testTxPoolConfig = core.DefaultTxPoolConfig + testTxPoolConfig = txpool.DefaultConfig testTxPoolConfig.Journal = "" ethashChainConfig = new(params.ChainConfig) *ethashChainConfig = *params.TestChainConfig @@ -111,7 +112,7 @@ func init() { // testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. type testWorkerBackend struct { db ethdb.Database - txPool *core.TxPool + txPool *txpool.TxPool chain *core.BlockChain genesis *core.Genesis uncleBlock *types.Block @@ -134,7 +135,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine t.Fatalf("unexpected consensus engine type: %T", engine) } chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil, nil) - txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) + txpool := txpool.NewTxPool(testTxPoolConfig, chainConfig, chain) // Generate a small n-block chain and an uncle block for it var uncle *types.Block @@ -166,7 +167,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine } func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } -func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool } +func (b *testWorkerBackend) TxPool() *txpool.TxPool { return b.txPool } func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { return nil, errors.New("not supported") } diff --git a/tests/fuzzers/les/les-fuzzer.go b/tests/fuzzers/les/les-fuzzer.go index d3a25a31c084..924a749e5832 100644 --- a/tests/fuzzers/les/les-fuzzer.go +++ b/tests/fuzzers/les/les-fuzzer.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -111,7 +112,7 @@ func init() { type fuzzer struct { chain *core.BlockChain - pool *core.TxPool + pool *txpool.TxPool chainLen int addr, txs []common.Hash @@ -137,7 +138,7 @@ func newFuzzer(input []byte) *fuzzer { chtKeys: chtKeys, bloomKeys: bloomKeys, nonce: uint64(len(txHashes)), - pool: core.NewTxPool(core.DefaultTxPoolConfig, params.TestChainConfig, chain), + pool: txpool.NewTxPool(txpool.DefaultConfig, params.TestChainConfig, chain), input: bytes.NewReader(input), } } @@ -229,7 +230,7 @@ func (f *fuzzer) BlockChain() *core.BlockChain { return f.chain } -func (f *fuzzer) TxPool() *core.TxPool { +func (f *fuzzer) TxPool() *txpool.TxPool { return f.pool } From 68ba845bb5cebb60495b70113e9a5657956877e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 26 Oct 2022 13:30:51 +0300 Subject: [PATCH 320/715] core/types: rename tx files to group them better together --- core/types/{access_list_tx.go => tx_access_list.go} | 0 core/types/{dynamic_fee_tx.go => tx_dynamic_fee.go} | 0 core/types/{legacy_tx.go => tx_legacy.go} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename core/types/{access_list_tx.go => tx_access_list.go} (100%) rename core/types/{dynamic_fee_tx.go => tx_dynamic_fee.go} (100%) rename core/types/{legacy_tx.go => tx_legacy.go} (100%) diff --git a/core/types/access_list_tx.go b/core/types/tx_access_list.go similarity index 100% rename from core/types/access_list_tx.go rename to core/types/tx_access_list.go diff --git a/core/types/dynamic_fee_tx.go b/core/types/tx_dynamic_fee.go similarity index 100% rename from core/types/dynamic_fee_tx.go rename to core/types/tx_dynamic_fee.go diff --git a/core/types/legacy_tx.go b/core/types/tx_legacy.go similarity index 100% rename from core/types/legacy_tx.go rename to core/types/tx_legacy.go From c4a662176ec11b9d5718904ccefee753637ab377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 26 Oct 2022 15:23:07 +0300 Subject: [PATCH 321/715] core, eth: for types with accurate size calcs, return uint64, not float (#26046) * core, eth: for types with accurate size calcs, return uint64, not float * core/types: proper tx size tests * core/types: extend tx size test with decoded sizes, fix error * core/txpool: fix linter Co-authored-by: Martin Holst Swende --- core/blockchain.go | 2 +- core/txpool/txpool.go | 2 +- core/types/block.go | 12 ++--- core/types/block_test.go | 6 +-- core/types/transaction.go | 29 +++++----- core/types/transaction_marshalling.go | 76 +++++++++++++-------------- core/types/transaction_test.go | 68 ++++++++++++++++++++++++ eth/downloader/queue.go | 2 +- eth/protocols/eth/broadcast.go | 2 +- les/downloader/queue.go | 2 +- 10 files changed, 137 insertions(+), 64 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 4965eeef35b4..a1d402517dad 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1913,7 +1913,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i // Import all the pruned blocks to make the state available var ( blocks []*types.Block - memory common.StorageSize + memory uint64 ) for i := len(hashes) - 1; i >= 0; i-- { // Append the next block to our batch diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 2e02c46101da..8905140fdb69 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -595,7 +595,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return core.ErrTxTypeNotSupported } // Reject transactions over defined size to prevent DOS attacks - if uint64(tx.Size()) > txMaxSize { + if tx.Size() > txMaxSize { return ErrOversizedData } // Transactions can't be negative. This may never happen using RLP decoded diff --git a/core/types/block.go b/core/types/block.go index 8942082b6e48..603a3f771208 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -263,7 +263,7 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error { return err } b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, eb.Txs - b.size.Store(common.StorageSize(rlp.ListSize(size))) + b.size.Store(rlp.ListSize(size)) return nil } @@ -322,14 +322,14 @@ func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles} } // Size returns the true RLP encoded storage size of the block, either by encoding // and returning it, or returning a previously cached value. -func (b *Block) Size() common.StorageSize { +func (b *Block) Size() uint64 { if size := b.size.Load(); size != nil { - return size.(common.StorageSize) + return size.(uint64) } c := writeCounter(0) rlp.Encode(&c, b) - b.size.Store(common.StorageSize(c)) - return common.StorageSize(c) + b.size.Store(uint64(c)) + return uint64(c) } // SanityCheck can be used to prevent that unbounded fields are @@ -338,7 +338,7 @@ func (b *Block) SanityCheck() error { return b.header.SanityCheck() } -type writeCounter common.StorageSize +type writeCounter uint64 func (c *writeCounter) Write(b []byte) (int, error) { *c += writeCounter(len(b)) diff --git a/core/types/block_test.go b/core/types/block_test.go index 9e7f581b1dc4..49197c923764 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -53,7 +53,7 @@ func TestBlockEncoding(t *testing.T) { check("Hash", block.Hash(), common.HexToHash("0a5843ac1cb04865017cb35a57b50b07084e5fcee39b5acadade33149f4fff9e")) check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) check("Time", block.Time(), uint64(1426516743)) - check("Size", block.Size(), common.StorageSize(len(blockEnc))) + check("Size", block.Size(), uint64(len(blockEnc))) tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil) tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) @@ -90,7 +90,7 @@ func TestEIP1559BlockEncoding(t *testing.T) { check("Hash", block.Hash(), common.HexToHash("c7252048cd273fe0dac09650027d07f0e3da4ee0675ebbb26627cea92729c372")) check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) check("Time", block.Time(), uint64(1426516743)) - check("Size", block.Size(), common.StorageSize(len(blockEnc))) + check("Size", block.Size(), uint64(len(blockEnc))) check("BaseFee", block.BaseFee(), new(big.Int).SetUint64(params.InitialBaseFee)) tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil) @@ -153,7 +153,7 @@ func TestEIP2718BlockEncoding(t *testing.T) { check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017")) check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4)) check("Time", block.Time(), uint64(1426516743)) - check("Size", block.Size(), common.StorageSize(len(blockEnc))) + check("Size", block.Size(), uint64(len(blockEnc))) // Create legacy tx. to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") diff --git a/core/types/transaction.go b/core/types/transaction.go index 715ede15db2e..910c68aea363 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -131,7 +131,7 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error { var inner LegacyTx err := s.Decode(&inner) if err == nil { - tx.setDecoded(&inner, int(rlp.ListSize(size))) + tx.setDecoded(&inner, rlp.ListSize(size)) } return err default: @@ -142,7 +142,7 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error { } inner, err := tx.decodeTyped(b) if err == nil { - tx.setDecoded(inner, len(b)) + tx.setDecoded(inner, uint64(len(b))) } return err } @@ -158,7 +158,7 @@ func (tx *Transaction) UnmarshalBinary(b []byte) error { if err != nil { return err } - tx.setDecoded(&data, len(b)) + tx.setDecoded(&data, uint64(len(b))) return nil } // It's an EIP2718 typed transaction envelope. @@ -166,7 +166,7 @@ func (tx *Transaction) UnmarshalBinary(b []byte) error { if err != nil { return err } - tx.setDecoded(inner, len(b)) + tx.setDecoded(inner, uint64(len(b))) return nil } @@ -190,11 +190,11 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { } // setDecoded sets the inner transaction and size after decoding. -func (tx *Transaction) setDecoded(inner TxData, size int) { +func (tx *Transaction) setDecoded(inner TxData, size uint64) { tx.inner = inner tx.time = time.Now() if size > 0 { - tx.size.Store(common.StorageSize(size)) + tx.size.Store(size) } } @@ -372,16 +372,21 @@ func (tx *Transaction) Hash() common.Hash { return h } -// Size returns the true RLP encoded storage size of the transaction, either by -// encoding and returning it, or returning a previously cached value. -func (tx *Transaction) Size() common.StorageSize { +// Size returns the true encoded storage size of the transaction, either by encoding +// and returning it, or returning a previously cached value. +func (tx *Transaction) Size() uint64 { if size := tx.size.Load(); size != nil { - return size.(common.StorageSize) + return size.(uint64) } c := writeCounter(0) rlp.Encode(&c, &tx.inner) - tx.size.Store(common.StorageSize(c)) - return common.StorageSize(c) + + size := uint64(c) + if tx.Type() != LegacyTxType { + size += 1 // type byte + } + tx.size.Store(size) + return size } // WithSignature returns a new transaction with the given signature. diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index aad31a5a97e2..2566d0b8d656 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -51,55 +51,55 @@ type txJSON struct { } // MarshalJSON marshals as JSON with a hash. -func (t *Transaction) MarshalJSON() ([]byte, error) { +func (tx *Transaction) MarshalJSON() ([]byte, error) { var enc txJSON // These are set for all tx types. - enc.Hash = t.Hash() - enc.Type = hexutil.Uint64(t.Type()) + enc.Hash = tx.Hash() + enc.Type = hexutil.Uint64(tx.Type()) // Other fields are set conditionally depending on tx type. - switch tx := t.inner.(type) { + switch itx := tx.inner.(type) { case *LegacyTx: - enc.Nonce = (*hexutil.Uint64)(&tx.Nonce) - enc.Gas = (*hexutil.Uint64)(&tx.Gas) - enc.GasPrice = (*hexutil.Big)(tx.GasPrice) - enc.Value = (*hexutil.Big)(tx.Value) - enc.Data = (*hexutil.Bytes)(&tx.Data) - enc.To = t.To() - enc.V = (*hexutil.Big)(tx.V) - enc.R = (*hexutil.Big)(tx.R) - enc.S = (*hexutil.Big)(tx.S) + enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) + enc.Gas = (*hexutil.Uint64)(&itx.Gas) + enc.GasPrice = (*hexutil.Big)(itx.GasPrice) + enc.Value = (*hexutil.Big)(itx.Value) + enc.Data = (*hexutil.Bytes)(&itx.Data) + enc.To = tx.To() + enc.V = (*hexutil.Big)(itx.V) + enc.R = (*hexutil.Big)(itx.R) + enc.S = (*hexutil.Big)(itx.S) case *AccessListTx: - enc.ChainID = (*hexutil.Big)(tx.ChainID) - enc.AccessList = &tx.AccessList - enc.Nonce = (*hexutil.Uint64)(&tx.Nonce) - enc.Gas = (*hexutil.Uint64)(&tx.Gas) - enc.GasPrice = (*hexutil.Big)(tx.GasPrice) - enc.Value = (*hexutil.Big)(tx.Value) - enc.Data = (*hexutil.Bytes)(&tx.Data) - enc.To = t.To() - enc.V = (*hexutil.Big)(tx.V) - enc.R = (*hexutil.Big)(tx.R) - enc.S = (*hexutil.Big)(tx.S) + enc.ChainID = (*hexutil.Big)(itx.ChainID) + enc.AccessList = &itx.AccessList + enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) + enc.Gas = (*hexutil.Uint64)(&itx.Gas) + enc.GasPrice = (*hexutil.Big)(itx.GasPrice) + enc.Value = (*hexutil.Big)(itx.Value) + enc.Data = (*hexutil.Bytes)(&itx.Data) + enc.To = tx.To() + enc.V = (*hexutil.Big)(itx.V) + enc.R = (*hexutil.Big)(itx.R) + enc.S = (*hexutil.Big)(itx.S) case *DynamicFeeTx: - enc.ChainID = (*hexutil.Big)(tx.ChainID) - enc.AccessList = &tx.AccessList - enc.Nonce = (*hexutil.Uint64)(&tx.Nonce) - enc.Gas = (*hexutil.Uint64)(&tx.Gas) - enc.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap) - enc.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap) - enc.Value = (*hexutil.Big)(tx.Value) - enc.Data = (*hexutil.Bytes)(&tx.Data) - enc.To = t.To() - enc.V = (*hexutil.Big)(tx.V) - enc.R = (*hexutil.Big)(tx.R) - enc.S = (*hexutil.Big)(tx.S) + enc.ChainID = (*hexutil.Big)(itx.ChainID) + enc.AccessList = &itx.AccessList + enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) + enc.Gas = (*hexutil.Uint64)(&itx.Gas) + enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap) + enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap) + enc.Value = (*hexutil.Big)(itx.Value) + enc.Data = (*hexutil.Bytes)(&itx.Data) + enc.To = tx.To() + enc.V = (*hexutil.Big)(itx.V) + enc.R = (*hexutil.Big)(itx.R) + enc.S = (*hexutil.Big)(itx.S) } return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. -func (t *Transaction) UnmarshalJSON(input []byte) error { +func (tx *Transaction) UnmarshalJSON(input []byte) error { var dec txJSON if err := json.Unmarshal(input, &dec); err != nil { return err @@ -268,7 +268,7 @@ func (t *Transaction) UnmarshalJSON(input []byte) error { } // Now set the inner transaction. - t.setDecoded(inner, 0) + tx.setDecoded(inner, 0) // TODO: check hash here? return nil diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 8e8ee595c971..4b96c6b91a01 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -531,3 +531,71 @@ func assertEqual(orig *Transaction, cpy *Transaction) error { } return nil } + +func TestTransactionSizes(t *testing.T) { + signer := NewLondonSigner(big.NewInt(123)) + key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + to := common.HexToAddress("0x01") + for i, txdata := range []TxData{ + &AccessListTx{ + ChainID: big.NewInt(123), + Nonce: 0, + To: nil, + Value: big.NewInt(1000), + Gas: 21000, + GasPrice: big.NewInt(100000), + }, + &LegacyTx{ + Nonce: 1, + GasPrice: big.NewInt(500), + Gas: 1000000, + To: &to, + Value: big.NewInt(1), + }, + &AccessListTx{ + ChainID: big.NewInt(123), + Nonce: 1, + GasPrice: big.NewInt(500), + Gas: 1000000, + To: &to, + Value: big.NewInt(1), + AccessList: AccessList{ + AccessTuple{ + Address: common.HexToAddress("0x01"), + StorageKeys: []common.Hash{common.HexToHash("0x01")}, + }}, + }, + &DynamicFeeTx{ + ChainID: big.NewInt(123), + Nonce: 1, + Gas: 1000000, + To: &to, + Value: big.NewInt(1), + GasTipCap: big.NewInt(500), + GasFeeCap: big.NewInt(500), + }, + } { + tx, err := SignNewTx(key, signer, txdata) + if err != nil { + t.Fatalf("test %d: %v", i, err) + } + bin, _ := tx.MarshalBinary() + + // Check initial calc + if have, want := int(tx.Size()), len(bin); have != want { + t.Errorf("test %d: size wrong, have %d want %d", i, have, want) + } + // Check cached version too + if have, want := int(tx.Size()), len(bin); have != want { + t.Errorf("test %d: (cached) size wrong, have %d want %d", i, have, want) + } + // Check unmarshalled version too + utx := new(Transaction) + if err := utx.UnmarshalBinary(bin); err != nil { + t.Fatalf("test %d: failed to unmarshal tx: %v", i, err) + } + if have, want := int(utx.Size()), len(bin); have != want { + t.Errorf("test %d: (unmarshalled) size wrong, have %d want %d", i, have, want) + } + } +} diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 0b500484b860..60a83a7fb0d9 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -369,7 +369,7 @@ func (q *queue) Results(block bool) []*fetchResult { size += receipt.Size() } for _, tx := range result.Transactions { - size += tx.Size() + size += common.StorageSize(tx.Size()) } q.resultSize = common.StorageSize(blockCacheSizeWeight)*size + (1-common.StorageSize(blockCacheSizeWeight))*q.resultSize diff --git a/eth/protocols/eth/broadcast.go b/eth/protocols/eth/broadcast.go index 6fc15f136bff..0afe01b1ce15 100644 --- a/eth/protocols/eth/broadcast.go +++ b/eth/protocols/eth/broadcast.go @@ -82,7 +82,7 @@ func (p *Peer) broadcastTransactions() { for i := 0; i < len(queue) && size < maxTxPacketSize; i++ { if tx := p.txpool.Get(queue[i]); tx != nil { txs = append(txs, tx) - size += tx.Size() + size += common.StorageSize(tx.Size()) } hashesCount++ } diff --git a/les/downloader/queue.go b/les/downloader/queue.go index fe08c810a11f..5b7054cf35cb 100644 --- a/les/downloader/queue.go +++ b/les/downloader/queue.go @@ -373,7 +373,7 @@ func (q *queue) Results(block bool) []*fetchResult { size += receipt.Size() } for _, tx := range result.Transactions { - size += tx.Size() + size += common.StorageSize(tx.Size()) } q.resultSize = common.StorageSize(blockCacheSizeWeight)*size + (1-common.StorageSize(blockCacheSizeWeight))*q.resultSize From 1d0c4e27bf8fec6de45849993ddc38653404cd9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Wed, 26 Oct 2022 14:49:12 +0200 Subject: [PATCH 322/715] build: upgrade -dlgo version to Go 1.19.2 --- build/checksums.txt | 28 ++++++++++++++-------------- build/ci.go | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 2725329fbc09..bd11b218dcbd 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,19 +1,19 @@ # This file contains sha256 checksums of optional build dependencies. -27871baa490f3401414ad793fba49086f6c855b1c584385ed7771e1204c7e179 go1.19.1.src.tar.gz -b2828a2b05f0d2169afc74c11ed010775bf7cf0061822b275697b2f470495fb7 go1.19.1.darwin-amd64.tar.gz -e46aecce83a9289be16ce4ba9b8478a5b89b8aa0230171d5c6adbc0c66640548 go1.19.1.darwin-arm64.tar.gz -cfaca8c1d5784d2bc21e12d8893cfd2dc885a60db4c1a9a95e4ffc694d0925ce go1.19.1.freebsd-386.tar.gz -db5b8f232e12c655cc6cde6af1adf4d27d842541807802d747c86161e89efa0a go1.19.1.freebsd-amd64.tar.gz -9acc57342400c5b0c2da07b5b01b50da239dd4a7fad41a1fb56af8363ef4133f go1.19.1.linux-386.tar.gz -acc512fbab4f716a8f97a8b3fbaa9ddd39606a28be6c2515ef7c6c6311acffde go1.19.1.linux-amd64.tar.gz -49960821948b9c6b14041430890eccee58c76b52e2dbaafce971c3c38d43df9f go1.19.1.linux-arm64.tar.gz -efe93f5671621ee84ce5e262e1e21acbc72acefbaba360f21778abd083d4ad16 go1.19.1.linux-armv6l.tar.gz -4137984aa353de9c5ec1bd8fb3cd00a0624b75eafa3d4ec13d2f3f48261dba2e go1.19.1.linux-ppc64le.tar.gz -ca1005cc80a3dd726536b4c6ea5fef0318939351ff273eff420bd66a377c74eb go1.19.1.linux-s390x.tar.gz -bc7043e7a9a8d34aacd06f8c2f70e166d1d148f6800814cff790c45b9ab31cee go1.19.1.windows-386.zip -b33584c1d93b0e9c783de876b7aa99d3018bdeccd396aeb6d516a74e9d88d55f go1.19.1.windows-amd64.zip -d8cf3f04762fa7d5d9c82dfa15b5adaae2404463af3bc8dcd7f89837512501fe go1.19.1.windows-arm64.zip +2ce930d70a931de660fdaf271d70192793b1b240272645bf0275779f6704df6b go1.19.2.src.tar.gz +16f8047d7b627699b3773680098fbaf7cc962b7db02b3e02726f78c4db26dfde go1.19.2.darwin-amd64.tar.gz +35d819df25197c0be45f36ce849b994bba3b0559b76d4538b910d28f6395c00d go1.19.2.darwin-arm64.tar.gz +7831a406447a14d964212d07f68e77cf7fe7fb7286bade6eeb9fbea39b192984 go1.19.2.freebsd-386.tar.gz +d74c88430484d14826ec21161e3b9336bd021f502b6594c4dd00e9ec730ee51d go1.19.2.freebsd-amd64.tar.gz +ba8c97965e0856c69c9ca2c86f96bec5bb21de43e6533e25494bb211d85cda1b go1.19.2.linux-386.tar.gz +5e8c5a74fe6470dd7e055a461acda8bb4050ead8c2df70f227e3ff7d8eb7eeb6 go1.19.2.linux-amd64.tar.gz +b62a8d9654436c67c14a0c91e931d50440541f09eb991a987536cb982903126d go1.19.2.linux-arm64.tar.gz +f3ccec7816ecd704ebafd130b08b8ad97c55402a8193a107b63e9de12ab90118 go1.19.2.linux-armv6l.tar.gz +37e1d4342f7103aeb9babeabe8c71ef3dba23db28db525071119e94b2aa21d7d go1.19.2.linux-ppc64le.tar.gz +51b45dec41295215df17f78e67d1a373b9dda97a5e539bed440974da5ffc97de go1.19.2.linux-s390x.tar.gz +9355b09b23e9db33945a7ba45bb75981ab0bb6006713099732167722cf081b53 go1.19.2.windows-386.zip +e132d4f0518b0d417eb6cc5f182c3385f6d24bb2eebee2566cd1a7ab6097e3f2 go1.19.2.windows-amd64.zip +4049435f77fb2a0642fd8740c588aadbcc446056e637e835a8e223fdb897cb3e go1.19.2.windows-arm64.zip 20cd1215e0420db8cfa94a6cd3c9d325f7b39c07f2415a02d111568d8bc9e271 golangci-lint-1.49.0-darwin-amd64.tar.gz cabb1a4c35fe1dadbe5a81550a00871281a331e7660cd85ae16e936a7f0f6cfc golangci-lint-1.49.0-darwin-arm64.tar.gz diff --git a/build/ci.go b/build/ci.go index 043c13b76e3c..8e020b5697be 100644 --- a/build/ci.go +++ b/build/ci.go @@ -148,7 +148,7 @@ var ( // This is the version of go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.19.1" + dlgoVersion = "1.19.2" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) From 0c66d971e7f3557df297cbe450fe7fc7826017be Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 27 Oct 2022 10:06:28 +0200 Subject: [PATCH 323/715] accounts/scwallet: fix keycard data signing error (#25331) accounts/scwallet: fix keycard data signing --- accounts/scwallet/wallet.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index e66717c3b1ad..6a40e28ae670 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -99,8 +99,8 @@ const ( P1DeriveKeyFromCurrent = uint8(0x10) statusP1WalletStatus = uint8(0x00) statusP1Path = uint8(0x01) - signP1PrecomputedHash = uint8(0x01) - signP2OnlyBlock = uint8(0x81) + signP1PrecomputedHash = uint8(0x00) + signP2OnlyBlock = uint8(0x00) exportP1Any = uint8(0x00) exportP2Pubkey = uint8(0x01) ) From 4984c4e63f0311d90ff2ac05398149e6d9f60ff1 Mon Sep 17 00:00:00 2001 From: Jakub Freebit <49676311+jakub-freebit@users.noreply.github.com> Date: Thu, 27 Oct 2022 17:23:11 +0900 Subject: [PATCH 324/715] build: make ios work again (#26052) --- build/ci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ci.go b/build/ci.go index 8e020b5697be..572519b9698e 100644 --- a/build/ci.go +++ b/build/ci.go @@ -1150,7 +1150,7 @@ func doXCodeFramework(cmdline []string) { tc := new(build.GoToolchain) // Build gomobile. - build.MustRun(tc.Install(GOBIN, "golang.org/x/mobile/cmd/gomobile", "golang.org/x/mobile/cmd/gobind")) + build.MustRun(tc.Install(GOBIN, "golang.org/x/mobile/cmd/gomobile@latest", "golang.org/x/mobile/cmd/gobind@latest")) // Build the iOS XCode framework bind := gomobileTool("bind", "-ldflags", "-s -w", "--target", "ios", "-v", "github.com/ethereum/go-ethereum/mobile") From 9d795d0836cb67ac42035c29839500b364ecc64b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 27 Oct 2022 10:39:01 +0200 Subject: [PATCH 325/715] core/vm: use optimized bigint (#26021) --- core/vm/contracts.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index d0e3e6913917..9a52616657bb 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/bls12381" "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/params" + big2 "github.com/holiman/big" "golang.org/x/crypto/ripemd160" ) @@ -377,23 +378,19 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) { } // Retrieve the operands and execute the exponentiation var ( - base = new(big.Int).SetBytes(getData(input, 0, baseLen)) - exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) - mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + base = new(big2.Int).SetBytes(getData(input, 0, baseLen)) + exp = new(big2.Int).SetBytes(getData(input, baseLen, expLen)) + mod = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen)) v []byte ) switch { case mod.BitLen() == 0: // Modulo 0 is undefined, return zero return common.LeftPadBytes([]byte{}, int(modLen)), nil - case base.Cmp(common.Big1) == 0: + case base.BitLen() == 1: // a bit length of 1 means it's 1 (or -1). //If base == 1, then we can just return base % mod (if mod >= 1, which it is) v = base.Mod(base, mod).Bytes() - //case mod.Bit(0) == 0: - // // Modulo is even - // v = math.FastExp(base, exp, mod).Bytes() default: - // Modulo is odd v = base.Exp(base, exp, mod).Bytes() } return common.LeftPadBytes(v, int(modLen)), nil From a1fc0d8144c0204314d4551d2bbd3af0130ea73e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 27 Oct 2022 15:25:01 +0200 Subject: [PATCH 326/715] eth/filters: change filter block to be by-ref (#26054) This PR changes the block field in the filter to be a pointer, to disambiguate between empty hash and no hash --- eth/filters/filter.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eth/filters/filter.go b/eth/filters/filter.go index fbbb4a7aab8f..26e85a6f1a42 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -34,8 +34,8 @@ type Filter struct { addresses []common.Address topics [][]common.Hash - block common.Hash // Block hash if filtering a single block - begin, end int64 // Range interval if filtering multiple blocks + block *common.Hash // Block hash if filtering a single block + begin, end int64 // Range interval if filtering multiple blocks matcher *bloombits.Matcher } @@ -78,7 +78,7 @@ func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Add func (sys *FilterSystem) NewBlockFilter(block common.Hash, addresses []common.Address, topics [][]common.Hash) *Filter { // Create a generic filter and convert it into a block filter filter := newFilter(sys, addresses, topics) - filter.block = block + filter.block = &block return filter } @@ -96,8 +96,8 @@ func newFilter(sys *FilterSystem, addresses []common.Address, topics [][]common. // first block that contains matches, updating the start of the filter accordingly. func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { // If we're doing singleton block filtering, execute and return - if f.block != (common.Hash{}) { - header, err := f.sys.backend.HeaderByHash(ctx, f.block) + if f.block != nil { + header, err := f.sys.backend.HeaderByHash(ctx, *f.block) if err != nil { return nil, err } From 60e30a940bbba2c0d26de040195a5ccdb14d8c10 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 28 Oct 2022 16:23:49 +0800 Subject: [PATCH 327/715] core/rawdb: refactor db inspector for extending multiple ancient store (#25896) This PR ports a few changes from PBSS: - Fix the snapshot generator waiter in case the generation is not even initialized - Refactor db inspector for ancient store --- core/blockchain.go | 4 +- core/blockchain_test.go | 86 +++++++++++++++++++++++ core/rawdb/ancient_scheme.go | 33 --------- core/rawdb/ancient_utils.go | 121 ++++++++++++++++++++++++++++++++ core/rawdb/database.go | 45 +++++------- core/state/snapshot/snapshot.go | 13 ++-- core/state/state_object.go | 8 +-- core/state/statedb.go | 8 ++- trie/nodeset.go | 2 + 9 files changed, 247 insertions(+), 73 deletions(-) create mode 100644 core/rawdb/ancient_utils.go diff --git a/core/blockchain.go b/core/blockchain.go index a1d402517dad..80f8ba76f121 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -123,7 +123,7 @@ const ( BlockChainVersion uint64 = 8 ) -// CacheConfig contains the configuration values for the trie caching/pruning +// CacheConfig contains the configuration values for the trie database // that's resident in a blockchain. type CacheConfig struct { TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory @@ -1408,7 +1408,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types if len(logs) > 0 { bc.logsFeed.Send(logs) } - // In theory we should fire a ChainHeadEvent when we inject + // In theory, we should fire a ChainHeadEvent when we inject // a canonical block, but sometimes we can insert a batch of // canonical blocks. Avoid firing too many ChainHeadEvents, // we will fire an accumulated ChainHeadEvent and disable fire diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 418844cdf502..85e0d5980a74 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4007,3 +4007,89 @@ func TestTxIndexer(t *testing.T) { os.RemoveAll(frdir) } } + +func TestCreateThenDeletePreByzantium(t *testing.T) { + // We use Ropsten chain config instead of Testchain config, this is + // deliberate: we want to use pre-byz rules where we have intermediate state roots + // between transactions. + testCreateThenDelete(t, params.RopstenChainConfig) +} +func TestCreateThenDeletePostByzantium(t *testing.T) { + testCreateThenDelete(t, params.TestChainConfig) +} + +// testCreateThenDelete tests a creation and subsequent deletion of a contract, happening +// within the same block. +func testCreateThenDelete(t *testing.T, config *params.ChainConfig) { + var ( + engine = ethash.NewFaker() + // A sender who makes transactions, has some funds + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + destAddress = crypto.CreateAddress(address, 0) + funds = big.NewInt(1000000000000000) + ) + + // runtime code is 0x60ffff : PUSH1 0xFF SELFDESTRUCT, a.k.a SELFDESTRUCT(0xFF) + code := append([]byte{0x60, 0xff, 0xff}, make([]byte, 32-3)...) + initCode := []byte{ + // SSTORE 1:1 + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x1, + byte(vm.SSTORE), + // Get the runtime-code on the stack + byte(vm.PUSH32)} + initCode = append(initCode, code...) + initCode = append(initCode, []byte{ + byte(vm.PUSH1), 0x0, // offset + byte(vm.MSTORE), + byte(vm.PUSH1), 0x3, // size + byte(vm.PUSH1), 0x0, // offset + byte(vm.RETURN), // return 3 bytes of zero-code + }...) + gspec := &Genesis{ + Config: config, + Alloc: GenesisAlloc{ + address: {Balance: funds}, + }, + } + nonce := uint64(0) + signer := types.HomesteadSigner{} + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2, func(i int, b *BlockGen) { + fee := big.NewInt(1) + if b.header.BaseFee != nil { + fee = b.header.BaseFee + } + b.SetCoinbase(common.Address{1}) + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: nonce, + GasPrice: new(big.Int).Set(fee), + Gas: 100000, + Data: initCode, + }) + nonce++ + b.AddTx(tx) + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: nonce, + GasPrice: new(big.Int).Set(fee), + Gas: 100000, + To: &destAddress, + }) + b.AddTx(tx) + nonce++ + }) + // Import the canonical chain + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ + //Debug: true, + //Tracer: logger.NewJSONLogger(nil, os.Stdout), + }, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + // Import the blocks + for _, block := range blocks { + if _, err := chain.InsertChain([]*types.Block{block}); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", block.NumberU64(), err) + } + } +} diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index 3da061cbd977..047b504a24bc 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -16,8 +16,6 @@ package rawdb -import "fmt" - // The list of table names of chain freezer. const ( // chainFreezerHeaderTable indicates the name of the freezer header table. @@ -53,34 +51,3 @@ var ( // freezers the collections of all builtin freezers. var freezers = []string{chainFreezerName} - -// InspectFreezerTable dumps out the index of a specific freezer table. The passed -// ancient indicates the path of root ancient directory where the chain freezer can -// be opened. Start and end specify the range for dumping out indexes. -// Note this function can only be used for debugging purposes. -func InspectFreezerTable(ancient string, freezerName string, tableName string, start, end int64) error { - var ( - path string - tables map[string]bool - ) - switch freezerName { - case chainFreezerName: - path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy - default: - return fmt.Errorf("unknown freezer, supported ones: %v", freezers) - } - noSnappy, exist := tables[tableName] - if !exist { - var names []string - for name := range tables { - names = append(names, name) - } - return fmt.Errorf("unknown table, supported ones: %v", names) - } - table, err := newFreezerTable(path, tableName, noSnappy, true) - if err != nil { - return err - } - table.dumpIndexStdout(start, end) - return nil -} diff --git a/core/rawdb/ancient_utils.go b/core/rawdb/ancient_utils.go new file mode 100644 index 000000000000..363a911aeea7 --- /dev/null +++ b/core/rawdb/ancient_utils.go @@ -0,0 +1,121 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rawdb + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" +) + +type tableSize struct { + name string + size common.StorageSize +} + +// freezerInfo contains the basic information of the freezer. +type freezerInfo struct { + name string // The identifier of freezer + head uint64 // The number of last stored item in the freezer + tail uint64 // The number of first stored item in the freezer + sizes []tableSize // The storage size per table +} + +// count returns the number of stored items in the freezer. +func (info *freezerInfo) count() uint64 { + return info.head - info.tail + 1 +} + +// size returns the storage size of the entire freezer. +func (info *freezerInfo) size() common.StorageSize { + var total common.StorageSize + for _, table := range info.sizes { + total += table.size + } + return total +} + +// inspectFreezers inspects all freezers registered in the system. +func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) { + var infos []freezerInfo + for _, freezer := range freezers { + switch freezer { + case chainFreezerName: + // Chain ancient store is a bit special. It's always opened along + // with the key-value store, inspect the chain store directly. + info := freezerInfo{name: freezer} + // Retrieve storage size of every contained table. + for table := range chainFreezerNoSnappy { + size, err := db.AncientSize(table) + if err != nil { + return nil, err + } + info.sizes = append(info.sizes, tableSize{name: table, size: common.StorageSize(size)}) + } + // Retrieve the number of last stored item + ancients, err := db.Ancients() + if err != nil { + return nil, err + } + info.head = ancients - 1 + + // Retrieve the number of first stored item + tail, err := db.Tail() + if err != nil { + return nil, err + } + info.tail = tail + infos = append(infos, info) + + default: + return nil, fmt.Errorf("unknown freezer, supported ones: %v", freezers) + } + } + return infos, nil +} + +// InspectFreezerTable dumps out the index of a specific freezer table. The passed +// ancient indicates the path of root ancient directory where the chain freezer can +// be opened. Start and end specify the range for dumping out indexes. +// Note this function can only be used for debugging purposes. +func InspectFreezerTable(ancient string, freezerName string, tableName string, start, end int64) error { + var ( + path string + tables map[string]bool + ) + switch freezerName { + case chainFreezerName: + path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy + default: + return fmt.Errorf("unknown freezer, supported ones: %v", freezers) + } + noSnappy, exist := tables[tableName] + if !exist { + var names []string + for name := range tables { + names = append(names, name) + } + return fmt.Errorf("unknown table, supported ones: %v", names) + } + table, err := newFreezerTable(path, tableName, noSnappy, true) + if err != nil { + return err + } + table.dumpIndexStdout(start, end) + return nil +} diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 9e1bdbfac399..cc4799792cfa 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -22,6 +22,7 @@ import ( "fmt" "os" "path" + "strings" "sync/atomic" "time" @@ -379,13 +380,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { beaconHeaders stat cliqueSnaps stat - // Ancient store statistics - ancientHeadersSize common.StorageSize - ancientBodiesSize common.StorageSize - ancientReceiptsSize common.StorageSize - ancientTdsSize common.StorageSize - ancientHashesSize common.StorageSize - // Les statistic chtTrieNodes stat bloomTrieNodes stat @@ -473,20 +467,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { logged = time.Now() } } - // Inspect append-only file store then. - ancientSizes := []*common.StorageSize{&ancientHeadersSize, &ancientBodiesSize, &ancientReceiptsSize, &ancientHashesSize, &ancientTdsSize} - for i, category := range []string{chainFreezerHeaderTable, chainFreezerBodiesTable, chainFreezerReceiptTable, chainFreezerHashTable, chainFreezerDifficultyTable} { - if size, err := db.AncientSize(category); err == nil { - *ancientSizes[i] += common.StorageSize(size) - total += common.StorageSize(size) - } - } - // Get number of ancient rows inside the freezer - ancients := counter(0) - if count, err := db.Ancients(); err == nil { - ancients = counter(count) - } - // Display the database statistic. + // Display the database statistic of key-value store. stats := [][]string{ {"Key-Value store", "Headers", headers.Size(), headers.Count()}, {"Key-Value store", "Bodies", bodies.Size(), bodies.Count()}, @@ -504,14 +485,25 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Beacon sync headers", beaconHeaders.Size(), beaconHeaders.Count()}, {"Key-Value store", "Clique snapshots", cliqueSnaps.Size(), cliqueSnaps.Count()}, {"Key-Value store", "Singleton metadata", metadata.Size(), metadata.Count()}, - {"Ancient store", "Headers", ancientHeadersSize.String(), ancients.String()}, - {"Ancient store", "Bodies", ancientBodiesSize.String(), ancients.String()}, - {"Ancient store", "Receipt lists", ancientReceiptsSize.String(), ancients.String()}, - {"Ancient store", "Difficulties", ancientTdsSize.String(), ancients.String()}, - {"Ancient store", "Block number->hash", ancientHashesSize.String(), ancients.String()}, {"Light client", "CHT trie nodes", chtTrieNodes.Size(), chtTrieNodes.Count()}, {"Light client", "Bloom trie nodes", bloomTrieNodes.Size(), bloomTrieNodes.Count()}, } + // Inspect all registered append-only file store then. + ancients, err := inspectFreezers(db) + if err != nil { + return err + } + for _, ancient := range ancients { + for _, table := range ancient.sizes { + stats = append(stats, []string{ + fmt.Sprintf("Ancient store (%s)", strings.Title(ancient.name)), + strings.Title(table.name), + table.size.String(), + fmt.Sprintf("%d", ancient.count()), + }) + } + total += ancient.size() + } table := tablewriter.NewWriter(os.Stdout) table.SetHeader([]string{"Database", "Category", "Size", "Items"}) table.SetFooter([]string{"", "Total", total.String(), " "}) @@ -521,6 +513,5 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { if unaccounted.size > 0 { log.Error("Database contains unaccounted data", "size", unaccounted.size, "count", unaccounted.count) } - return nil } diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index a73649a1fe11..f07f8d8e31ef 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -187,8 +187,9 @@ type Tree struct { // If the memory layers in the journal do not match the disk layer (e.g. there is // a gap) or the journal is missing, there are two repair cases: // -// - if the 'recovery' parameter is true, all memory diff-layers will be discarded. -// This case happens when the snapshot is 'ahead' of the state trie. +// - if the 'recovery' parameter is true, memory diff-layers and the disk-layer +// will all be kept. This case happens when the snapshot is 'ahead' of the +// state trie. // - otherwise, the entire snapshot is considered invalid and will be recreated on // a background thread. func New(config Config, diskdb ethdb.KeyValueStore, triedb *trie.Database, root common.Hash) (*Tree, error) { @@ -199,16 +200,16 @@ func New(config Config, diskdb ethdb.KeyValueStore, triedb *trie.Database, root triedb: triedb, layers: make(map[common.Hash]snapshot), } - // Create the building waiter iff the background generation is allowed - if !config.NoBuild && !config.AsyncBuild { - defer snap.waitBuild() - } // Attempt to load a previously persisted snapshot and rebuild one if failed head, disabled, err := loadSnapshot(diskdb, triedb, root, config.CacheSize, config.Recovery, config.NoBuild) if disabled { log.Warn("Snapshot maintenance disabled (syncing)") return snap, nil } + // Create the building waiter iff the background generation is allowed + if !config.NoBuild && !config.AsyncBuild { + defer snap.waitBuild() + } if err != nil { log.Warn("Failed to load snapshot", "err", err) if !config.NoBuild { diff --git a/core/state/state_object.go b/core/state/state_object.go index 5eb053e83095..d2693b0c02d8 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -63,7 +63,7 @@ func (s Storage) Copy() Storage { // The usage pattern is as follows: // First you need to obtain a state object. // Account values can be accessed and modified through the object. -// Finally, call CommitTrie to write the modified storage trie into a database. +// Finally, call commitTrie to write the modified storage trie into a database. type stateObject struct { address common.Address addrHash common.Hash // hash of ethereum address of the account @@ -374,9 +374,9 @@ func (s *stateObject) updateRoot(db Database) { s.data.Root = s.trie.Hash() } -// CommitTrie the storage trie of the object to db. -// This updates the trie root. -func (s *stateObject) CommitTrie(db Database) (*trie.NodeSet, error) { +// commitTrie submits the storage changes into the storage trie and re-computes +// the root. Besides, all trie changes will be collected in a nodeset and returned. +func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) { // If nothing changed, don't bother with hashing anything if s.updateTrie(db) == nil { return nil, nil diff --git a/core/state/statedb.go b/core/state/statedb.go index 72c2aede1389..02ced7b785c5 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -920,7 +920,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { obj.dirtyCode = false } // Write any storage changes in the state object to its storage trie - set, err := obj.CommitTrie(s.db) + set, err := obj.commitTrie(s.db) if err != nil { return common.Hash{}, err } @@ -934,6 +934,12 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { storageTrieNodesDeleted += deleted } } + // If the contract is destructed, the storage is still left in the + // database as dangling data. Theoretically it's should be wiped from + // database as well, but in hash-based-scheme it's extremely hard to + // determine that if the trie nodes are also referenced by other storage, + // and in path-based-scheme some technical challenges are still unsolved. + // Although it won't affect the correctness but please fix it TODO(rjl493456442). } if len(s.stateObjectsDirty) > 0 { s.stateObjectsDirty = make(map[common.Address]struct{}) diff --git a/trie/nodeset.go b/trie/nodeset.go index 0f9d4ea01570..928172350171 100644 --- a/trie/nodeset.go +++ b/trie/nodeset.go @@ -113,6 +113,7 @@ func NewNodeSet(owner common.Hash) *NodeSet { } } +/* // NewNodeSetWithDeletion initializes the nodeset with provided deletion set. func NewNodeSetWithDeletion(owner common.Hash, paths [][]byte, prev [][]byte) *NodeSet { set := NewNodeSet(owner) @@ -121,6 +122,7 @@ func NewNodeSetWithDeletion(owner common.Hash, paths [][]byte, prev [][]byte) *N } return set } +*/ // markUpdated marks the node as dirty(newly-inserted or updated) with provided // node path, node object along with its previous value. From fbdeff99cec568b4078d9df96170fc122cfd138d Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Fri, 28 Oct 2022 04:25:37 -0600 Subject: [PATCH 328/715] cmd/evm: calc base fee if parent data is present (#26051) Currently, in order to chain together sequential valid t8n transitions the caller must manually calculate the block base fee. This PR adds support for the necessary parent fee market data to calculate the base fee for the current transition. Concretely, env is extended to accept the following: parentBaseFee parentGasUsed parentGasLimit Example usage can be found in ./cmd/evm/testdata/25. Co-authored-by: Martin Holst Swende --- cmd/evm/internal/t8ntool/execution.go | 8 +++++ cmd/evm/internal/t8ntool/gen_stenv.go | 18 +++++++++++ cmd/evm/internal/t8ntool/transition.go | 13 +++++++- cmd/evm/t8n_test.go | 8 +++++ cmd/evm/testdata/13/exp2.json | 3 +- cmd/evm/testdata/14/exp.json | 3 +- cmd/evm/testdata/14/exp2.json | 3 +- cmd/evm/testdata/14/exp_berlin.json | 3 +- cmd/evm/testdata/19/exp_arrowglacier.json | 3 +- cmd/evm/testdata/19/exp_grayglacier.json | 3 +- cmd/evm/testdata/19/exp_london.json | 3 +- cmd/evm/testdata/24/exp.json | 3 +- cmd/evm/testdata/25/alloc.json | 8 +++++ cmd/evm/testdata/25/env.json | 11 +++++++ cmd/evm/testdata/25/exp.json | 38 +++++++++++++++++++++++ cmd/evm/testdata/25/txs.json | 15 +++++++++ 16 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 cmd/evm/testdata/25/alloc.json create mode 100644 cmd/evm/testdata/25/env.json create mode 100644 cmd/evm/testdata/25/exp.json create mode 100644 cmd/evm/testdata/25/txs.json diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 77f6ec37158b..a27c6f6b4f4b 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -56,6 +56,7 @@ type ExecutionResult struct { Rejected []*rejectedTx `json:"rejected,omitempty"` Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` GasUsed math.HexOrDecimal64 `json:"gasUsed"` + BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` } type ommer struct { @@ -69,6 +70,9 @@ type stEnv struct { Difficulty *big.Int `json:"currentDifficulty"` Random *big.Int `json:"currentRandom"` ParentDifficulty *big.Int `json:"parentDifficulty"` + ParentBaseFee *big.Int `json:"parentBaseFee,omitempty"` + ParentGasUsed uint64 `json:"parentGasUsed,omitempty"` + ParentGasLimit uint64 `json:"parentGasLimit,omitempty"` GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` Number uint64 `json:"currentNumber" gencodec:"required"` Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` @@ -84,6 +88,9 @@ type stEnvMarshaling struct { Difficulty *math.HexOrDecimal256 Random *math.HexOrDecimal256 ParentDifficulty *math.HexOrDecimal256 + ParentBaseFee *math.HexOrDecimal256 + ParentGasUsed math.HexOrDecimal64 + ParentGasLimit math.HexOrDecimal64 GasLimit math.HexOrDecimal64 Number math.HexOrDecimal64 Timestamp math.HexOrDecimal64 @@ -263,6 +270,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, Rejected: rejectedTxs, Difficulty: (*math.HexOrDecimal256)(vmContext.Difficulty), GasUsed: (math.HexOrDecimal64)(gasUsed), + BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee), } return statedb, execRs, nil } diff --git a/cmd/evm/internal/t8ntool/gen_stenv.go b/cmd/evm/internal/t8ntool/gen_stenv.go index a6d774cdabcf..da449e659dca 100644 --- a/cmd/evm/internal/t8ntool/gen_stenv.go +++ b/cmd/evm/internal/t8ntool/gen_stenv.go @@ -20,6 +20,9 @@ func (s stEnv) MarshalJSON() ([]byte, error) { Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"` Random *math.HexOrDecimal256 `json:"currentRandom"` ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"` + ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"` + ParentGasUsed math.HexOrDecimal64 `json:"parentGasUsed,omitempty"` + ParentGasLimit math.HexOrDecimal64 `json:"parentGasLimit,omitempty"` GasLimit math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"` Number math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"` Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"` @@ -34,6 +37,9 @@ func (s stEnv) MarshalJSON() ([]byte, error) { enc.Difficulty = (*math.HexOrDecimal256)(s.Difficulty) enc.Random = (*math.HexOrDecimal256)(s.Random) enc.ParentDifficulty = (*math.HexOrDecimal256)(s.ParentDifficulty) + enc.ParentBaseFee = (*math.HexOrDecimal256)(s.ParentBaseFee) + enc.ParentGasUsed = math.HexOrDecimal64(s.ParentGasUsed) + enc.ParentGasLimit = math.HexOrDecimal64(s.ParentGasLimit) enc.GasLimit = math.HexOrDecimal64(s.GasLimit) enc.Number = math.HexOrDecimal64(s.Number) enc.Timestamp = math.HexOrDecimal64(s.Timestamp) @@ -52,6 +58,9 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"` Random *math.HexOrDecimal256 `json:"currentRandom"` ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"` + ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"` + ParentGasUsed *math.HexOrDecimal64 `json:"parentGasUsed,omitempty"` + ParentGasLimit *math.HexOrDecimal64 `json:"parentGasLimit,omitempty"` GasLimit *math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"` Number *math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"` Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"` @@ -78,6 +87,15 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { if dec.ParentDifficulty != nil { s.ParentDifficulty = (*big.Int)(dec.ParentDifficulty) } + if dec.ParentBaseFee != nil { + s.ParentBaseFee = (*big.Int)(dec.ParentBaseFee) + } + if dec.ParentGasUsed != nil { + s.ParentGasUsed = uint64(*dec.ParentGasUsed) + } + if dec.ParentGasLimit != nil { + s.ParentGasLimit = uint64(*dec.ParentGasLimit) + } if dec.GasLimit == nil { return errors.New("missing required field 'currentGasLimit' for stEnv") } diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 0a0ba4ea51fa..8b05f1def9db 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -247,7 +248,17 @@ func Transition(ctx *cli.Context) error { } // Sanity check, to not `panic` in state_transition if chainConfig.IsLondon(big.NewInt(int64(prestate.Env.Number))) { - if prestate.Env.BaseFee == nil { + if prestate.Env.BaseFee != nil { + // Already set, base fee has precedent over parent base fee. + } else if prestate.Env.ParentBaseFee != nil { + parent := &types.Header{ + Number: new(big.Int).SetUint64(prestate.Env.Number), + BaseFee: prestate.Env.ParentBaseFee, + GasUsed: prestate.Env.ParentGasUsed, + GasLimit: prestate.Env.ParentGasLimit, + } + prestate.Env.BaseFee = misc.CalcBaseFee(chainConfig, parent) + } else { return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) } } diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 72c062e8d923..031def0211b1 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -243,6 +243,14 @@ func TestT8n(t *testing.T) { output: t8nOutput{alloc: false, result: false}, expExitCode: 3, }, + { // Test base fee calculation + base: "./testdata/25", + input: t8nInput{ + "alloc.json", "txs.json", "env.json", "Merged", "", + }, + output: t8nOutput{alloc: true, result: true}, + expOut: "exp.json", + }, } { args := []string{"t8n"} args = append(args, tc.output.get()...) diff --git a/cmd/evm/testdata/13/exp2.json b/cmd/evm/testdata/13/exp2.json index ba8c9f865b7e..cbad6552c17c 100644 --- a/cmd/evm/testdata/13/exp2.json +++ b/cmd/evm/testdata/13/exp2.json @@ -34,6 +34,7 @@ } ], "currentDifficulty": "0x20000", - "gasUsed": "0x109a0" + "gasUsed": "0x109a0", + "currentBaseFee": "0x36b" } } diff --git a/cmd/evm/testdata/14/exp.json b/cmd/evm/testdata/14/exp.json index 9bf5635f5ba3..26d49173ce6d 100644 --- a/cmd/evm/testdata/14/exp.json +++ b/cmd/evm/testdata/14/exp.json @@ -7,6 +7,7 @@ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "currentDifficulty": "0x2000020000000", "receipts": [], - "gasUsed": "0x0" + "gasUsed": "0x0", + "currentBaseFee": "0x500" } } diff --git a/cmd/evm/testdata/14/exp2.json b/cmd/evm/testdata/14/exp2.json index 9c9025381f16..cd75b47d5a50 100644 --- a/cmd/evm/testdata/14/exp2.json +++ b/cmd/evm/testdata/14/exp2.json @@ -7,6 +7,7 @@ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "receipts": [], "currentDifficulty": "0x1ff8020000000", - "gasUsed": "0x0" + "gasUsed": "0x0", + "currentBaseFee": "0x500" } } diff --git a/cmd/evm/testdata/14/exp_berlin.json b/cmd/evm/testdata/14/exp_berlin.json index c2bf9531197b..5c00ef130a9b 100644 --- a/cmd/evm/testdata/14/exp_berlin.json +++ b/cmd/evm/testdata/14/exp_berlin.json @@ -7,6 +7,7 @@ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "receipts": [], "currentDifficulty": "0x1ff9000000000", - "gasUsed": "0x0" + "gasUsed": "0x0", + "currentBaseFee": "0x500" } } diff --git a/cmd/evm/testdata/19/exp_arrowglacier.json b/cmd/evm/testdata/19/exp_arrowglacier.json index 9cf56ffafc33..dd49f7d02ea2 100644 --- a/cmd/evm/testdata/19/exp_arrowglacier.json +++ b/cmd/evm/testdata/19/exp_arrowglacier.json @@ -7,6 +7,7 @@ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "currentDifficulty": "0x2000000200000", "receipts": [], - "gasUsed": "0x0" + "gasUsed": "0x0", + "currentBaseFee": "0x500" } } diff --git a/cmd/evm/testdata/19/exp_grayglacier.json b/cmd/evm/testdata/19/exp_grayglacier.json index 95a3cb1685cf..86fd8e6c137e 100644 --- a/cmd/evm/testdata/19/exp_grayglacier.json +++ b/cmd/evm/testdata/19/exp_grayglacier.json @@ -7,6 +7,7 @@ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "receipts": [], "currentDifficulty": "0x2000000004000", - "gasUsed": "0x0" + "gasUsed": "0x0", + "currentBaseFee": "0x500" } } \ No newline at end of file diff --git a/cmd/evm/testdata/19/exp_london.json b/cmd/evm/testdata/19/exp_london.json index a06bc8ca69f0..9e9a17da9004 100644 --- a/cmd/evm/testdata/19/exp_london.json +++ b/cmd/evm/testdata/19/exp_london.json @@ -7,6 +7,7 @@ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "currentDifficulty": "0x2000080000000", "receipts": [], - "gasUsed": "0x0" + "gasUsed": "0x0", + "currentBaseFee": "0x500" } } diff --git a/cmd/evm/testdata/24/exp.json b/cmd/evm/testdata/24/exp.json index 05d8c7a03b81..d8cec59d6abc 100644 --- a/cmd/evm/testdata/24/exp.json +++ b/cmd/evm/testdata/24/exp.json @@ -48,6 +48,7 @@ } ], "currentDifficulty": null, - "gasUsed": "0x10306" + "gasUsed": "0x10306", + "currentBaseFee": "0x500" } } diff --git a/cmd/evm/testdata/25/alloc.json b/cmd/evm/testdata/25/alloc.json new file mode 100644 index 000000000000..d66366718e5c --- /dev/null +++ b/cmd/evm/testdata/25/alloc.json @@ -0,0 +1,8 @@ +{ + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x5ffd4878be161d74", + "code": "0x", + "nonce": "0xac", + "storage": {} + } +} diff --git a/cmd/evm/testdata/25/env.json b/cmd/evm/testdata/25/env.json new file mode 100644 index 000000000000..bb2c9e0d7d68 --- /dev/null +++ b/cmd/evm/testdata/25/env.json @@ -0,0 +1,11 @@ +{ + "currentCoinbase": "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty": null, + "currentRandom": "0xdeadc0de", + "currentGasLimit": "0x750a163df65e8a", + "parentBaseFee": "0x500", + "parentGasUsed": "0x0", + "parentGasLimit": "0x750a163df65e8a", + "currentNumber": "1", + "currentTimestamp": "1000" +} diff --git a/cmd/evm/testdata/25/exp.json b/cmd/evm/testdata/25/exp.json new file mode 100644 index 000000000000..a9c310a1e136 --- /dev/null +++ b/cmd/evm/testdata/25/exp.json @@ -0,0 +1,38 @@ +{ + "alloc": { + "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": { + "balance": "0x1" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x5ffd4878bc29ed73", + "nonce": "0xad" + }, + "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x854d00" + } + }, + "result": { + "stateRoot": "0x5139609e39f4d158a7d1ad1800908eb0349cea9b500a8273a6cf0a7e4392639b", + "txRoot": "0x572690baf4898c2972446e56ecf0aa2a027c08a863927d2dce34472f0c5496fe", + "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [ + { + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x5208", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x5208", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "currentDifficulty": null, + "gasUsed": "0x5208", + "currentBaseFee": "0x460" + } +} diff --git a/cmd/evm/testdata/25/txs.json b/cmd/evm/testdata/25/txs.json new file mode 100644 index 000000000000..acb4035fd1ee --- /dev/null +++ b/cmd/evm/testdata/25/txs.json @@ -0,0 +1,15 @@ +[ + { + "gas": "0x186a0", + "gasPrice": "0x600", + "hash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673", + "input": "0x", + "nonce": "0xac", + "to": "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192", + "value": "0x1", + "v" : "0x0", + "r" : "0x0", + "s" : "0x0", + "secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + } +] From 0f4942214d76385c52c7917212331c9bad8b3566 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Fri, 28 Oct 2022 13:58:29 +0330 Subject: [PATCH 329/715] eth/tracers: fix gasUsed for native and JS tracers (#26048) * eth/tracers: fix gasUsed in call tracer * fix js tracers gasUsed * fix legacy prestate tracer * fix restGas in test * drop intrinsicGas field from js tracers --- .../internal/tracetest/calltrace_test.go | 20 +++++++++++++++---- .../testdata/call_tracer/create.json | 2 +- .../testdata/call_tracer/deep_calls.json | 2 +- .../testdata/call_tracer/delegatecall.json | 2 +- .../inner_create_oog_outer_throw.json | 2 +- .../testdata/call_tracer/inner_instafail.json | 2 +- .../call_tracer/inner_throw_outer_revert.json | 2 +- .../tracetest/testdata/call_tracer/oog.json | 2 +- .../testdata/call_tracer/revert.json | 2 +- .../testdata/call_tracer/revert_reason.json | 2 +- .../testdata/call_tracer/selfdestruct.json | 2 +- .../testdata/call_tracer/simple.json | 2 +- .../testdata/call_tracer/simple_onlytop.json | 2 +- .../tracetest/testdata/call_tracer/throw.json | 2 +- .../testdata/call_tracer_legacy/create.json | 2 +- .../call_tracer_legacy/deep_calls.json | 2 +- .../call_tracer_legacy/delegatecall.json | 2 +- .../inner_create_oog_outer_throw.json | 2 +- .../call_tracer_legacy/inner_instafail.json | 2 +- .../inner_throw_outer_revert.json | 2 +- .../testdata/call_tracer_legacy/oog.json | 2 +- .../testdata/call_tracer_legacy/revert.json | 2 +- .../call_tracer_legacy/revert_reason.json | 2 +- .../call_tracer_legacy/selfdestruct.json | 2 +- .../testdata/call_tracer_legacy/simple.json | 2 +- .../testdata/call_tracer_legacy/throw.json | 2 +- eth/tracers/js/goja.go | 6 +++--- .../tracers/prestate_tracer_legacy.js | 2 +- eth/tracers/js/tracer_test.go | 8 ++++---- eth/tracers/native/call.go | 10 +++++++--- 30 files changed, 56 insertions(+), 40 deletions(-) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index de6b3f9bfd1c..6bb8dae9b622 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -82,6 +82,7 @@ func TestCallTracerNative(t *testing.T) { } func testCallTracer(tracerName string, dirPath string, t *testing.T) { + isLegacy := strings.HasSuffix(dirPath, "_legacy") files, err := os.ReadDir(filepath.Join("testdata", dirPath)) if err != nil { t.Fatalf("failed to retrieve tracer test suite: %v", err) @@ -136,8 +137,8 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - if _, err = st.TransitionDb(); err != nil { + vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + if err != nil { t.Fatalf("failed to execute transaction: %v", err) } // Retrieve the trace result and compare against the expected. @@ -147,7 +148,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { } // The legacy javascript calltracer marshals json in js, which // is not deterministic (as opposed to the golang json encoder). - if strings.HasSuffix(dirPath, "_legacy") { + if isLegacy { // This is a tweak to make it deterministic. Can be removed when // we remove the legacy tracer. var x callTrace @@ -161,6 +162,17 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if string(want) != string(res) { t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), string(want)) } + // Sanity check: compare top call's gas used against vm result + type simpleResult struct { + GasUsed hexutil.Uint64 + } + var topCall simpleResult + if err := json.Unmarshal(res, &topCall); err != nil { + t.Fatalf("failed to unmarshal top calls gasUsed: %v", err) + } + if uint64(topCall.GasUsed) != vmRet.UsedGas { + t.Fatalf("top call has invalid gasUsed. have: %d want: %d", topCall.GasUsed, vmRet.UsedGas) + } }) } } @@ -303,7 +315,7 @@ func TestZeroValueToNotExitCall(t *testing.T) { if err != nil { t.Fatalf("failed to retrieve trace result: %v", err) } - wantStr := `{"from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","gas":"0x7148","gasUsed":"0x2d0","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}` + wantStr := `{"from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","gas":"0x7148","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}` if string(res) != wantStr { t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), wantStr) } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer/create.json index 8699bf3e7e9c..8557f8efd69b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/create.json @@ -48,7 +48,7 @@ "result": { "from": "0x13e4acefe6a6700604929946e70e6443e4e73447", "gas": "0x5e106", - "gasUsed": "0x5e106", + "gasUsed": "0x897be", "input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", "output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029", "to": "0x7dc9c9730689ff0b0fd506c67db815f12d90a448", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json index 0353d4cfa9ac..ef28a930b3bc 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json @@ -405,7 +405,7 @@ ], "from": "0x70c9217d814985faef62b124420f8dfbddd96433", "gas": "0x37b38", - "gasUsed": "0x12bb3", + "gasUsed": "0x1810b", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", "output": "0x", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json index f7ad6df5f526..c4c1390fa257 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json @@ -87,7 +87,7 @@ ], "from": "0xa529806c67cc6486d4d62024471772f47f6fd672", "gas": "0x2d6e28", - "gasUsed": "0x64bd", + "gasUsed": "0xbd55", "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", "output": "0x", "to": "0x269296dddce321a6bcbaa2f0181127593d732cba", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json index 9395eb401c2a..95c5889269fc 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json @@ -68,7 +68,7 @@ "error": "invalid jump destination", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", "gas": "0x435c8", - "gasUsed": "0x435c8", + "gasUsed": "0x493e0", "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json index 6e221b3c079b..50adecadc31f 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json @@ -55,7 +55,7 @@ "to": "0x6c06b16512b332e6cd8293a2974872674716ce18", "value": "0x0", "gas": "0x1a466", - "gasUsed": "0x1dc6", + "gasUsed": "0x72de", "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", "output": "0x", "calls": [] diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json index ec2ceb426fda..2be2dee23f26 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json @@ -72,7 +72,7 @@ "error": "execution reverted", "from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826", "gas": "0x78d9e", - "gasUsed": "0x76fc0", + "gasUsed": "0x7c1c8", "input": "0x", "to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json index de4fed6ab1fb..8022f53a992d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json @@ -51,7 +51,7 @@ "error": "out of gas", "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", "gas": "0x7045", - "gasUsed": "0x7045", + "gasUsed": "0xca1d", "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json index 059040a1c811..aee894d11fde 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json @@ -49,7 +49,7 @@ "error": "execution reverted", "from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9", "gas": "0x2d55e8", - "gasUsed": "0xc3", + "gasUsed": "0x719b", "input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000", "to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json index e0b2a9c6f181..8c8abd4d6d24 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json @@ -54,7 +54,7 @@ "error": "execution reverted", "from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", "gas": "0x2d7308", - "gasUsed": "0x588", + "gasUsed": "0x5940", "input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json index dd717906bc03..8a6262776b3f 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json @@ -65,7 +65,7 @@ ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", "gas": "0x10738", - "gasUsed": "0x7533", + "gasUsed": "0x6fcb", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x", "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json index 08cb7b2d00c0..0a6d66a5c4ca 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json @@ -70,7 +70,7 @@ ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", "gas": "0x10738", - "gasUsed": "0x3ef9", + "gasUsed": "0x9751", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x0000000000000000000000000000000000000000000000000000000000000001", "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json index ac1fef44098e..5e25a01cef2d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json @@ -62,7 +62,7 @@ "result": { "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", "gas": "0x10738", - "gasUsed": "0x3ef9", + "gasUsed": "0x9751", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x0000000000000000000000000000000000000000000000000000000000000001", "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json index 09cf449776fb..76fae3c392b3 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json @@ -53,7 +53,7 @@ "error": "invalid jump destination", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", "gas": "0x37b38", - "gasUsed": "0x37b38", + "gasUsed": "0x3d090", "input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json index 8699bf3e7e9c..8557f8efd69b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json @@ -48,7 +48,7 @@ "result": { "from": "0x13e4acefe6a6700604929946e70e6443e4e73447", "gas": "0x5e106", - "gasUsed": "0x5e106", + "gasUsed": "0x897be", "input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", "output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029", "to": "0x7dc9c9730689ff0b0fd506c67db815f12d90a448", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json index 0353d4cfa9ac..ef28a930b3bc 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json @@ -405,7 +405,7 @@ ], "from": "0x70c9217d814985faef62b124420f8dfbddd96433", "gas": "0x37b38", - "gasUsed": "0x12bb3", + "gasUsed": "0x1810b", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", "output": "0x", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json index f7ad6df5f526..c4c1390fa257 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json @@ -87,7 +87,7 @@ ], "from": "0xa529806c67cc6486d4d62024471772f47f6fd672", "gas": "0x2d6e28", - "gasUsed": "0x64bd", + "gasUsed": "0xbd55", "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", "output": "0x", "to": "0x269296dddce321a6bcbaa2f0181127593d732cba", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json index 72152e27e7f7..0b60e34d0e11 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json @@ -68,7 +68,7 @@ "error": "invalid jump destination", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", "gas": "0x435c8", - "gasUsed": "0x435c8", + "gasUsed": "0x493e0", "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json index 86070d130857..c1ed766ef902 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json @@ -55,7 +55,7 @@ "to": "0x6c06b16512b332e6cd8293a2974872674716ce18", "value": "0x0", "gas": "0x1a466", - "gasUsed": "0x1dc6", + "gasUsed": "0x72de", "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", "output": "0x", "calls": [ diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json index ec2ceb426fda..2be2dee23f26 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json @@ -72,7 +72,7 @@ "error": "execution reverted", "from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826", "gas": "0x78d9e", - "gasUsed": "0x76fc0", + "gasUsed": "0x7c1c8", "input": "0x", "to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json index de4fed6ab1fb..8022f53a992d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json @@ -51,7 +51,7 @@ "error": "out of gas", "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", "gas": "0x7045", - "gasUsed": "0x7045", + "gasUsed": "0xca1d", "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json index 059040a1c811..aee894d11fde 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json @@ -49,7 +49,7 @@ "error": "execution reverted", "from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9", "gas": "0x2d55e8", - "gasUsed": "0xc3", + "gasUsed": "0x719b", "input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000", "to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json index 094b0446779f..4f7fee97d930 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json @@ -54,7 +54,7 @@ "error": "execution reverted", "from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", "gas": "0x2d7308", - "gasUsed": "0x588", + "gasUsed": "0x5940", "input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", "type": "CALL", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json index 132cefa1681a..55b63dbdb6c9 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json @@ -63,7 +63,7 @@ ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", "gas": "0x10738", - "gasUsed": "0x7533", + "gasUsed": "0x6fcb", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x", "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json index b46432122dd0..c9192a19f923 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json @@ -68,7 +68,7 @@ ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", "gas": "0x10738", - "gasUsed": "0x3ef9", + "gasUsed": "0x9751", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x0000000000000000000000000000000000000000000000000000000000000001", "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json index 09cf449776fb..76fae3c392b3 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json @@ -53,7 +53,7 @@ "error": "invalid jump destination", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", "gas": "0x37b38", - "gasUsed": "0x37b38", + "gasUsed": "0x3d090", "input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", "type": "CALL", diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 3510360410c2..ceb591a79afe 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -216,7 +216,9 @@ func (t *jsTracer) CaptureTxStart(gasLimit uint64) { // CaptureTxEnd implements the Tracer interface and is invoked at the end of // transaction processing. -func (t *jsTracer) CaptureTxEnd(restGas uint64) {} +func (t *jsTracer) CaptureTxEnd(restGas uint64) { + t.ctx["gasUsed"] = t.vm.ToValue(t.gasLimit - restGas) +} // CaptureStart implements the Tracer interface to initialize the tracing operation. func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { @@ -243,7 +245,6 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr // Update list of precompiles based on current block rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) t.activePrecompiles = vm.ActivePrecompiles(rules) - t.ctx["intrinsicGas"] = t.vm.ToValue(t.gasLimit - gas) } // CaptureState implements the Tracer interface to trace a single step of VM execution. @@ -287,7 +288,6 @@ func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, duration time.Duration, err error) { t.ctx["output"] = t.vm.ToValue(output) t.ctx["time"] = t.vm.ToValue(duration.String()) - t.ctx["gasUsed"] = t.vm.ToValue(gasUsed) if err != nil { t.ctx["error"] = t.vm.ToValue(err.Error()) } diff --git a/eth/tracers/js/internal/tracers/prestate_tracer_legacy.js b/eth/tracers/js/internal/tracers/prestate_tracer_legacy.js index 77f25209cd9e..2757b8b1419a 100644 --- a/eth/tracers/js/internal/tracers/prestate_tracer_legacy.js +++ b/eth/tracers/js/internal/tracers/prestate_tracer_legacy.js @@ -62,7 +62,7 @@ var toBal = bigInt(this.prestate[toHex(ctx.to)].balance.slice(2), 16); this.prestate[toHex(ctx.to)].balance = '0x'+toBal.subtract(ctx.value).toString(16); - this.prestate[toHex(ctx.from)].balance = '0x'+fromBal.add(ctx.value).add((ctx.gasUsed + ctx.intrinsicGas) * ctx.gasPrice).toString(16); + this.prestate[toHex(ctx.from)].balance = '0x'+fromBal.add(ctx.value).add(ctx.gasUsed * ctx.gasPrice).toString(16); // Decrement the caller's nonce, and remove empty create targets this.prestate[toHex(ctx.from)].nonce--; diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 02789d6713ed..6a916f55b2a7 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -78,7 +78,7 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon ret, err := env.Interpreter().Run(contract, []byte{}, false) tracer.CaptureEnd(ret, startGas-contract.Gas, 1, err) // Rest gas assumes no refund - tracer.CaptureTxEnd(startGas - contract.Gas) + tracer.CaptureTxEnd(contract.Gas) if err != nil { return nil, err } @@ -128,9 +128,9 @@ func TestTracer(t *testing.T) { }, { // tests to-string of opcodes code: "{opcodes: [], step: function(log) { this.opcodes.push(log.op.toString()); }, fault: function() {}, result: function() { return this.opcodes; }}", want: `["PUSH1","PUSH1","STOP"]`, - }, { // tests intrinsic gas - code: "{depths: [], step: function() {}, fault: function() {}, result: function(ctx) { return ctx.gasPrice+'.'+ctx.gasUsed+'.'+ctx.intrinsicGas; }}", - want: `"100000.6.21000"`, + }, { // tests gasUsed + code: "{depths: [], step: function() {}, fault: function() {}, result: function(ctx) { return ctx.gasPrice+'.'+ctx.gasUsed; }}", + want: `"100000.21006"`, }, { code: "{res: null, step: function(log) {}, fault: function() {}, result: function() { return toWord('0xffaa') }}", want: `{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":255,"31":170}`, diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 26fdd0008d2a..536906e312f9 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -69,6 +69,7 @@ type callTracer struct { env *vm.EVM callstack []callFrame config callTracerConfig + gasLimit uint64 interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption } @@ -109,7 +110,6 @@ func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad // CaptureEnd is called after the call finishes to finalize the tracing. func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { - t.callstack[0].GasUsed = gasUsed output = common.CopyBytes(output) if err == nil { t.callstack[0].Output = output @@ -185,9 +185,13 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } -func (*callTracer) CaptureTxStart(gasLimit uint64) {} +func (t *callTracer) CaptureTxStart(gasLimit uint64) { + t.gasLimit = gasLimit +} -func (*callTracer) CaptureTxEnd(restGas uint64) {} +func (t *callTracer) CaptureTxEnd(restGas uint64) { + t.callstack[0].GasUsed = t.gasLimit - restGas +} // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). From 2c1af8b1ec38675b86bdb520b679dc7f6605f065 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 28 Oct 2022 20:48:08 +0800 Subject: [PATCH 330/715] cmd, eth: implement full-sync tester (#26035) This PR adds a parameter to startup, --synctarget. The synctarget flag is a developer-flag, that can be useful in some scenarios as a replacement for a CL node. It defines a fixed block sync target: geth --syncmode=full --synctarget=./block_15816882.hex_rlp The --synctarget is only made available during syncmode=full --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 37 +++++++++++++ eth/catalyst/tester.go | 100 ++++++++++++++++++++++++++++++++++++ eth/ethconfig/config.go | 5 ++ eth/ethconfig/gen_config.go | 7 +++ 5 files changed, 150 insertions(+) create mode 100644 eth/catalyst/tester.go diff --git a/cmd/geth/main.go b/cmd/geth/main.go index e6d1128ba9b5..a94c0c17db3b 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -86,6 +86,7 @@ var ( utils.TxPoolGlobalQueueFlag, utils.TxPoolLifetimeFlag, utils.SyncModeFlag, + utils.SyncTargetFlag, utils.ExitWhenSyncedFlag, utils.GCModeFlag, utils.SnapshotFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index d705d7a16306..974c03579507 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -18,6 +18,7 @@ package utils import ( + "bytes" "context" "crypto/ecdsa" "errors" @@ -36,10 +37,12 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -68,6 +71,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" pcsclite "github.com/gballet/go-libpcsclite" gopsutil "github.com/shirou/gopsutil/mem" @@ -664,11 +668,18 @@ var ( Category: flags.LoggingCategory, } + // MISC settings IgnoreLegacyReceiptsFlag = &cli.BoolFlag{ Name: "ignore-legacy-receipts", Usage: "Geth will start up even if there are legacy receipts in freezer", Category: flags.MiscCategory, } + SyncTargetFlag = &cli.PathFlag{ + Name: "synctarget", + Usage: `File for containing the hex-encoded block-rlp as sync target(dev feature)`, + TakesFile: true, + Category: flags.MiscCategory, + } // RPC settings IPCDisabledFlag = &cli.BoolFlag{ @@ -1874,6 +1885,25 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.EthDiscoveryURLs = SplitAndTrim(urls) } } + if ctx.IsSet(SyncTargetFlag.Name) { + path := ctx.Path(SyncTargetFlag.Name) + if path == "" { + Fatalf("Failed to resolve file path") + } + blob, err := os.ReadFile(path) + if err != nil { + Fatalf("Failed to read block file: %v", err) + } + rlpBlob, err := hexutil.Decode(string(bytes.TrimRight(blob, "\r\n"))) + if err != nil { + Fatalf("Failed to decode block blob: %v", err) + } + var block types.Block + if err := rlp.DecodeBytes(rlpBlob, &block); err != nil { + Fatalf("Failed to decode block: %v", err) + } + cfg.SyncTarget = &block + } // Override any default configs for hard coded networks. switch { case ctx.Bool(MainnetFlag.Name): @@ -2027,6 +2057,13 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend Fatalf("Failed to register the Engine API service: %v", err) } stack.RegisterAPIs(tracers.APIs(backend.APIBackend)) + + // Register the auxiliary full-sync tester service in case the sync + // target is configured. + if cfg.SyncTarget != nil && cfg.SyncMode == downloader.FullSync { + ethcatalyst.RegisterFullSyncTester(stack, backend, cfg.SyncTarget) + log.Info("Registered full-sync tester", "number", cfg.SyncTarget.NumberU64(), "hash", cfg.SyncTarget.Hash()) + } return backend.APIBackend, backend } diff --git a/eth/catalyst/tester.go b/eth/catalyst/tester.go new file mode 100644 index 000000000000..63ee5feb26be --- /dev/null +++ b/eth/catalyst/tester.go @@ -0,0 +1,100 @@ +// Copyright 2022 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 catalyst + +import ( + "sync" + "time" + + "github.com/ethereum/go-ethereum/core/beacon" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" +) + +// FullSyncTester is an auxiliary service that allows Geth to perform full sync +// alone without consensus-layer attached. Users must specify a valid block as +// the sync target. This tester can be applied to different networks, no matter +// it's pre-merge or post-merge, but only for full-sync. +type FullSyncTester struct { + api *ConsensusAPI + block *types.Block + closed chan struct{} + wg sync.WaitGroup +} + +// RegisterFullSyncTester registers the full-sync tester service into the node +// stack for launching and stopping the service controlled by node. +func RegisterFullSyncTester(stack *node.Node, backend *eth.Ethereum, block *types.Block) (*FullSyncTester, error) { + cl := &FullSyncTester{ + api: NewConsensusAPI(backend), + block: block, + closed: make(chan struct{}), + } + stack.RegisterLifecycle(cl) + return cl, nil +} + +// Start launches the full-sync tester by spinning up a background thread +// for keeping firing NewPayload-UpdateForkChoice combos with the provided +// target block, it may or may not trigger the beacon sync depends on if +// there are protocol peers connected. +func (tester *FullSyncTester) Start() error { + tester.wg.Add(1) + go func() { + defer tester.wg.Done() + + ticker := time.NewTicker(time.Second * 5) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + // Don't bother downloader in case it's already syncing. + if tester.api.eth.Downloader().Synchronising() { + continue + } + // Short circuit in case the target block is already stored + // locally. + if tester.api.eth.BlockChain().HasBlock(tester.block.Hash(), tester.block.NumberU64()) { + log.Info("Full-sync target reached", "number", tester.block.NumberU64(), "hash", tester.block.Hash()) + return + } + // Shoot out consensus events in order to trigger syncing. + data := beacon.BlockToExecutableData(tester.block) + tester.api.NewPayloadV1(*data) + tester.api.ForkchoiceUpdatedV1(beacon.ForkchoiceStateV1{ + HeadBlockHash: tester.block.Hash(), + SafeBlockHash: tester.block.Hash(), + FinalizedBlockHash: tester.block.Hash(), + }, nil) + case <-tester.closed: + return + } + } + }() + return nil +} + +// Stop stops the full-sync tester to stop all background activities. +// This function can only be called for one time. +func (tester *FullSyncTester) Stop() error { + close(tester.closed) + tester.wg.Wait() + return nil +} diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 75606339323a..e9651d041c3c 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/ethdb" @@ -211,6 +212,10 @@ type Config struct { // OverrideTerminalTotalDifficultyPassed (TODO: remove after the fork) OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` + + // SyncTarget defines the target block of sync. It's only used for + // development purposes. + SyncTarget *types.Block } // CreateConsensusEngine creates a consensus engine for the given chain configuration. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 514facde0a8b..a3dcf5a12f6f 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/miner" @@ -63,6 +64,7 @@ func (c Config) MarshalTOML() (interface{}, error) { CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` + FullSyncTarget *types.Block } var enc Config enc.Genesis = c.Genesis @@ -109,6 +111,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.CheckpointOracle = c.CheckpointOracle enc.OverrideTerminalTotalDifficulty = c.OverrideTerminalTotalDifficulty enc.OverrideTerminalTotalDifficultyPassed = c.OverrideTerminalTotalDifficultyPassed + enc.FullSyncTarget = c.SyncTarget return &enc, nil } @@ -159,6 +162,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` + FullSyncTarget *types.Block } var dec Config if err := unmarshal(&dec); err != nil { @@ -296,5 +300,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.OverrideTerminalTotalDifficultyPassed != nil { c.OverrideTerminalTotalDifficultyPassed = dec.OverrideTerminalTotalDifficultyPassed } + if dec.FullSyncTarget != nil { + c.SyncTarget = dec.FullSyncTarget + } return nil } From fb4a97f33f3dadf1b2ee3eeaee7fa84d6f68b42e Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Mon, 31 Oct 2022 16:42:25 +0800 Subject: [PATCH 331/715] rpc: update docstring (#26072) Co-authored-by: seven --- rpc/types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/types.go b/rpc/types.go index e3d1a4896821..e7158796ead0 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -69,7 +69,7 @@ const ( ) // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: -// - "latest", "earliest" or "pending" as string arguments +// - "safe", "finalized", "latest", "earliest" or "pending" as string arguments // - the block number // Returned errors: // - an invalid block number error when the given argument isn't a known strings @@ -110,7 +110,7 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { } // MarshalText implements encoding.TextMarshaler. It marshals: -// - "latest", "earliest" or "pending" as strings +// - "safe", "finalized", "latest", "earliest" or "pending" as strings // - other numbers as hex func (bn BlockNumber) MarshalText() ([]byte, error) { switch bn { From 5329aa3786ee654d093ef7ed46cad9d1b3e948c9 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 31 Oct 2022 04:50:21 -0400 Subject: [PATCH 332/715] Fix trace call for inner reverts (#25971) Inner call reverts will now return the reason similar to the top-level call. Separately, if top-level call is of type CREATE and it fails, its `to` field will now be cleared to `0x00...00` instead of being set to the created address. --- .../testdata/call_tracer/deep_calls.json | 6 -- .../testdata/call_tracer/delegatecall.json | 1 - .../inner_create_oog_outer_throw.json | 1 + .../testdata/call_tracer/inner_instafail.json | 4 +- .../call_tracer/inner_revert_reason.json | 86 +++++++++++++++++++ .../call_tracer/inner_throw_outer_revert.md | 19 ++++ .../testdata/call_tracer/selfdestruct.json | 3 +- eth/tracers/native/call.go | 48 +++++------ 8 files changed, 132 insertions(+), 36 deletions(-) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.md diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json index ef28a930b3bc..174f23fc456c 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json @@ -263,7 +263,6 @@ "gas": "0x20ee1", "gasUsed": "0x5374", "input": "0x581d5d60000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b0000000000000000000000000000000000000000000000280faf689c35ac0000", - "output": "0x", "to": "0xcf00ffd997ad14939736f026006498e3f099baaf", "type": "CALL", "value": "0x0" @@ -305,7 +304,6 @@ "gas": "0x1a91d", "gasUsed": "0x12fa", "input": "0x0accce0600000000000000000000000000000000000000000000000000000000000000025842545553440000000000000000000000000000000000000000000000000000000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "output": "0x", "to": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38", "type": "CALL", "value": "0x0" @@ -377,7 +375,6 @@ "gas": "0x16e62", "gasUsed": "0xebb", "input": "0x645a3b72584254555344000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002816d180e30c390000", - "output": "0x", "to": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38", "type": "CALL", "value": "0x0" @@ -387,7 +384,6 @@ "gas": "0x283b9", "gasUsed": "0xc51c", "input": "0x949ae479000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b0000000000000000000000000000000000000000000000280faf689c35ac0000", - "output": "0x", "to": "0x3e9286eafa2db8101246c2131c09b49080d00690", "type": "CALL", "value": "0x0" @@ -397,7 +393,6 @@ "gas": "0x30b4a", "gasUsed": "0xedb7", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", - "output": "0x", "to": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", "type": "CALL", "value": "0x0" @@ -407,7 +402,6 @@ "gas": "0x37b38", "gasUsed": "0x1810b", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", - "output": "0x", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", "type": "CALL", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json index c4c1390fa257..3e7b5f436528 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json @@ -89,7 +89,6 @@ "gas": "0x2d6e28", "gasUsed": "0xbd55", "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", - "output": "0x", "to": "0x269296dddce321a6bcbaa2f0181127593d732cba", "type": "CALL", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json index 95c5889269fc..40d240e4b82b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json @@ -58,6 +58,7 @@ { "error": "contract creation code storage out of gas", "from": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", + "to": "0x0000000000000000000000000000000000000000", "gas": "0x39ff0", "gasUsed": "0x39ff0", "input": "0x606060405234620000005760405160208062001fd283398101604052515b805b600a8054600160a060020a031916600160a060020a0383161790555b506001600d819055600e81905560408051808201909152600c8082527f566f74696e672053746f636b00000000000000000000000000000000000000006020928301908152600b805460008290528251601860ff1990911617825590947f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9600291831615610100026000190190921604601f0193909304830192906200010c565b828001600101855582156200010c579182015b828111156200010c578251825591602001919060010190620000ef565b5b50620001309291505b808211156200012c576000815560010162000116565b5090565b50506040805180820190915260038082527f43565300000000000000000000000000000000000000000000000000000000006020928301908152600c805460008290528251600660ff1990911617825590937fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c760026001841615610100026000190190931692909204601f010481019291620001f7565b82800160010185558215620001f7579182015b82811115620001f7578251825591602001919060010190620001da565b5b506200021b9291505b808211156200012c576000815560010162000116565b5090565b50505b505b611da280620002306000396000f3006060604052361561019a5763ffffffff60e060020a600035041662e1986d811461019f57806302a72a4c146101d657806306eb4e421461020157806306fdde0314610220578063095ea7b3146102ad578063158ccb99146102dd57806318160ddd146102f85780631cf65a781461031757806323b872dd146103365780632c71e60a1461036c57806333148fd6146103ca578063435ebc2c146103f55780635eeb6e451461041e578063600e85b71461043c5780636103d70b146104a157806362c1e46a146104b05780636c182e99146104ba578063706dc87c146104f057806370a082311461052557806377174f851461055057806395d89b411461056f578063a7771ee3146105fc578063a9059cbb14610629578063ab377daa14610659578063b25dbb5e14610685578063b89a73cb14610699578063ca5eb5e1146106c6578063cbcf2e5a146106e1578063d21f05ba1461070e578063d347c2051461072d578063d96831e114610765578063dd62ed3e14610777578063df3c211b146107a8578063e2982c21146107d6578063eb944e4c14610801575b610000565b34610000576101d4600160a060020a036004351660243567ffffffffffffffff6044358116906064358116906084351661081f565b005b34610000576101ef600160a060020a0360043516610a30565b60408051918252519081900360200190f35b34610000576101ef610a4f565b60408051918252519081900360200190f35b346100005761022d610a55565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516602435610ae3565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516610b4e565b005b34610000576101ef610b89565b60408051918252519081900360200190f35b34610000576101ef610b8f565b60408051918252519081900360200190f35b34610000576102c9600160a060020a0360043581169060243516604435610b95565b604080519115158252519081900360200190f35b3461000057610388600160a060020a0360043516602435610bb7565b60408051600160a060020a039096168652602086019490945267ffffffffffffffff928316858501529082166060850152166080830152519081900360a00190f35b34610000576101ef600160a060020a0360043516610c21565b60408051918252519081900360200190f35b3461000057610402610c40565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d4600160a060020a0360043516602435610c4f565b005b3461000057610458600160a060020a0360043516602435610cc9565b60408051600160a060020a03909716875260208701959095528585019390935267ffffffffffffffff9182166060860152811660808501521660a0830152519081900360c00190f35b34610000576101d4610d9e565b005b6101d4610e1e565b005b34610000576104d3600160a060020a0360043516610e21565b6040805167ffffffffffffffff9092168252519081900360200190f35b3461000057610402600160a060020a0360043516610ead565b60408051600160a060020a039092168252519081900360200190f35b34610000576101ef600160a060020a0360043516610ef9565b60408051918252519081900360200190f35b34610000576101ef610f18565b60408051918252519081900360200190f35b346100005761022d610f1e565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516610fac565b604080519115158252519081900360200190f35b34610000576102c9600160a060020a0360043516602435610fc2565b604080519115158252519081900360200190f35b3461000057610402600435610fe2565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d46004351515610ffd565b005b34610000576102c9600160a060020a036004351661104c565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516611062565b005b34610000576102c9600160a060020a0360043516611070565b604080519115158252519081900360200190f35b34610000576101ef6110f4565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351667ffffffffffffffff602435166110fa565b60408051918252519081900360200190f35b34610000576101d4600435611121565b005b34610000576101ef600160a060020a03600435811690602435166111c6565b60408051918252519081900360200190f35b34610000576101ef6004356024356044356064356084356111f3565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351661128c565b60408051918252519081900360200190f35b34610000576101d4600160a060020a036004351660243561129e565b005b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff848116908416101561086457610000565b8367ffffffffffffffff168267ffffffffffffffff16101561088557610000565b8267ffffffffffffffff168267ffffffffffffffff1610156108a657610000565b506040805160a081018252600160a060020a033381168252602080830188905267ffffffffffffffff80871684860152858116606085015287166080840152908816600090815260039091529190912080546001810180835582818380158290116109615760030281600302836000526020600020918201910161096191905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050916000526020600020906003020160005b5082518154600160a060020a031916600160a060020a03909116178155602083015160018201556040830151600290910180546060850151608086015167ffffffffffffffff1990921667ffffffffffffffff948516176fffffffffffffffff00000000000000001916604060020a918516919091021777ffffffffffffffff000000000000000000000000000000001916608060020a939091169290920291909117905550610a268686610fc2565b505b505050505050565b600160a060020a0381166000908152600360205260409020545b919050565b60055481565b600b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b600a5433600160a060020a03908116911614610b6957610000565b600a8054600160a060020a031916600160a060020a0383161790555b5b50565b60005481565b60005b90565b6000610ba2848484611600565b610bad8484846116e2565b90505b9392505050565b600360205281600052604060002081815481101561000057906000526020600020906003020160005b5080546001820154600290920154600160a060020a03909116935090915067ffffffffffffffff80821691604060020a8104821691608060020a9091041685565b600160a060020a0381166000908152600860205260409020545b919050565b600a54600160a060020a031681565b600a5433600160a060020a03908116911614610c6a57610000565b610c7660005482611714565b6000908155600160a060020a038316815260016020526040902054610c9b9082611714565b600160a060020a038316600090815260016020526040812091909155610cc390839083611600565b5b5b5050565b6000600060006000600060006000600360008a600160a060020a0316600160a060020a0316815260200190815260200160002088815481101561000057906000526020600020906003020160005b508054600182015460028301546040805160a081018252600160a060020a039094168085526020850184905267ffffffffffffffff808416928601839052604060020a8404811660608701819052608060020a9094041660808601819052909c50929a509197509095509350909150610d90904261172d565b94505b509295509295509295565b33600160a060020a038116600090815260066020526040902054801515610dc457610000565b8030600160a060020a0316311015610ddb57610000565b600160a060020a0382166000818152600660205260408082208290555183156108fc0291849190818181858888f193505050501515610cc357610000565b5b5050565b5b565b600160a060020a03811660009081526003602052604081205442915b81811015610ea557600160a060020a03841660009081526003602052604090208054610e9a9190839081101561000057906000526020600020906003020160005b5060020154604060020a900467ffffffffffffffff168461177d565b92505b600101610e3d565b5b5050919050565b600160a060020a0380821660009081526007602052604081205490911615610eef57600160a060020a0380831660009081526007602052604090205416610ef1565b815b90505b919050565b600160a060020a0381166000908152600160205260409020545b919050565b600d5481565b600c805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b60006000610fb983610c21565b1190505b919050565b6000610fcf338484611600565b610fd983836117ac565b90505b92915050565b600460205260009081526040902054600160a060020a031681565b8015801561101a575061100f33610ef9565b61101833610c21565b115b1561102457610000565b33600160a060020a03166000908152600960205260409020805460ff19168215151790555b50565b60006000610fb983610ef9565b1190505b919050565b610b8533826117dc565b5b50565b600a54604080516000602091820181905282517fcbcf2e5a000000000000000000000000000000000000000000000000000000008152600160a060020a03868116600483015293519194939093169263cbcf2e5a92602480830193919282900301818787803b156100005760325a03f115610000575050604051519150505b919050565b600e5481565b6000610fd961110984846118b2565b61111385856119b6565b611a05565b90505b92915050565b600a5433600160a060020a0390811691161461113c57610000565b61114860005482611a1f565b600055600554600190101561116c57600a5461116c90600160a060020a0316611a47565b5b600a54600160a060020a03166000908152600160205260409020546111929082611a1f565b600a8054600160a060020a039081166000908152600160205260408120939093559054610b8592911683611600565b5b5b50565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b92915050565b6000600060008487101561120a5760009250611281565b8387111561121a57879250611281565b61123f6112308961122b888a611714565b611a90565b61123a8689611714565b611abc565b915081925061124e8883611714565b905061127e8361127961126a8461122b8c8b611714565b611a90565b61123a888b611714565b611abc565b611a1f565b92505b505095945050505050565b60066020526000908152604090205481565b600160a060020a03821660009081526003602052604081208054829190849081101561000057906000526020600020906003020160005b50805490925033600160a060020a039081169116146112f357610000565b6040805160a0810182528354600160a060020a0316815260018401546020820152600284015467ffffffffffffffff80821693830193909352604060020a810483166060830152608060020a900490911660808201526113539042611af9565b600160a060020a0385166000908152600360205260409020805491925090849081101561000057906000526020600020906003020160005b508054600160a060020a031916815560006001820181905560029091018054600160c060020a0319169055600160a060020a0385168152600360205260409020805460001981019081101561000057906000526020600020906003020160005b50600160a060020a03851660009081526003602052604090208054859081101561000057906000526020600020906003020160005b5081548154600160a060020a031916600160a060020a03918216178255600180840154908301556002928301805493909201805467ffffffffffffffff191667ffffffffffffffff948516178082558354604060020a908190048616026fffffffffffffffff000000000000000019909116178082559254608060020a9081900490941690930277ffffffffffffffff00000000000000000000000000000000199092169190911790915584166000908152600360205260409020805460001981018083559190829080158290116115485760030281600302836000526020600020918201910161154891905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050600160a060020a033316600090815260016020526040902054611570915082611a1f565b600160a060020a03338116600090815260016020526040808220939093559086168152205461159f9082611714565b600160a060020a038086166000818152600160209081526040918290209490945580518581529051339093169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35b50505050565b600160a060020a0383161561166e576116466008600061161f86610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611714565b6008600061165386610ead565b600160a060020a031681526020810191909152604001600020555b600160a060020a038216156116dc576116b46008600061168d85610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611a1f565b600860006116c185610ead565b600160a060020a031681526020810191909152604001600020555b5b505050565b600083826116f082426110fa565b8111156116fc57610000565b611707868686611b1b565b92505b5b50509392505050565b600061172283831115611b4d565b508082035b92915050565b6000610fd983602001518367ffffffffffffffff16856080015167ffffffffffffffff16866040015167ffffffffffffffff16876060015167ffffffffffffffff166111f3565b90505b92915050565b60008167ffffffffffffffff168367ffffffffffffffff1610156117a15781610fd9565b825b90505b92915050565b600033826117ba82426110fa565b8111156117c657610000565b6117d08585611b5d565b92505b5b505092915050565b6117e582610ef9565b6117ee83610c21565b11156117f957610000565b600160a060020a03811660009081526009602052604090205460ff16158015611834575081600160a060020a031681600160a060020a031614155b1561183e57610000565b61184782611070565b1561185157610000565b611864828261185f85610ef9565b611600565b600160a060020a0382811660009081526007602052604090208054600160a060020a031916918316918217905561189a82610ead565b600160a060020a031614610cc357610000565b5b5050565b600160a060020a038216600090815260036020526040812054815b818110156119885761197d836112796003600089600160a060020a0316600160a060020a0316815260200190815260200160002084815481101561000057906000526020600020906003020160005b506040805160a0810182528254600160a060020a031681526001830154602082015260029092015467ffffffffffffffff80821692840192909252604060020a810482166060840152608060020a900416608082015287611af9565b611a1f565b92505b6001016118cd565b600160a060020a0385166000908152600160205260409020546117d09084611714565b92505b505092915050565b600060006119c384611070565b80156119d157506000600d54115b90506119fb816119e9576119e485610ef9565b6119ec565b60005b6111138686611b7b565b611a05565b91505b5092915050565b60008183106117a15781610fd9565b825b90505b92915050565b6000828201611a3c848210801590611a375750838210155b611b4d565b8091505b5092915050565b611a508161104c565b15611a5a57610b85565b6005805460009081526004602052604090208054600160a060020a031916600160a060020a038416179055805460010190555b50565b6000828202611a3c841580611a37575083858381156100005704145b611b4d565b8091505b5092915050565b60006000611acc60008411611b4d565b8284811561000057049050611a3c838581156100005706828502018514611b4d565b8091505b5092915050565b6000610fd98360200151611b0d858561172d565b611714565b90505b92915050565b60008382611b2982426110fa565b811115611b3557610000565b611707868686611b8f565b92505b5b50509392505050565b801515610b8557610000565b5b50565b6000611b6883611a47565b610fd98383611c92565b90505b92915050565b6000610fd983610ef9565b90505b92915050565b600160a060020a038084166000908152600260209081526040808320338516845282528083205493861683526001909152812054909190611bd09084611a1f565b600160a060020a038086166000908152600160205260408082209390935590871681522054611bff9084611714565b600160a060020a038616600090815260016020526040902055611c228184611714565b600160a060020a038087166000818152600260209081526040808320338616845282529182902094909455805187815290519288169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600191505b509392505050565b60003382611ca082426110fa565b811115611cac57610000565b6117d08585611cc2565b92505b5b505092915050565b600160a060020a033316600090815260016020526040812054611ce59083611714565b600160a060020a033381166000908152600160205260408082209390935590851681522054611d149083611a1f565b600160a060020a038085166000818152600160209081526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b929150505600a165627a7a72305820bfa5ddd3fecf3f43aed25385ec7ec3ef79638c2e58d99f85d9a3cc494183bf160029000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json index 50adecadc31f..4d7305a15479 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json @@ -56,8 +56,6 @@ "value": "0x0", "gas": "0x1a466", "gasUsed": "0x72de", - "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", - "output": "0x", - "calls": [] + "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000" } } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json new file mode 100644 index 000000000000..ec10902b284b --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json @@ -0,0 +1,86 @@ +{ + "genesis": { + "baseFeePerGas": "1000000000", + "difficulty": "1", + "extraData": "0x00000000000000000000000000000000000000000000000000000000000000003623191d4ccfbbdf09e8ebf6382a1f8257417bc10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "11500000", + "hash": "0x2af138b8a06e65b8dd0999df70b9e87609e9fc91ea201f08b1cc4f25ef01fcf6", + "miner": "0x0000000000000000000000000000000000000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "number": "0", + "stateRoot": "0xa775801d572e9b79585eb131d18d79f8a0f71895455ab9a5b656911428e11708", + "timestamp": "0", + "totalDifficulty": "1", + "alloc": { + "0x3623191d4ccfbbdf09e8ebf6382a1f8257417bc1": { + "balance": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7" + }, + "0xd15abca351f79181dedfb6d019e382db90f3628a": { + "balance": "0x0" + } + }, + "config": { + "chainId": 1337, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "clique": { + "period": 0, + "epoch": 30000 + } + } + }, + "context": { + "number": "1", + "difficulty": "2", + "timestamp": "1665537018", + "gasLimit": "11511229", + "miner": "0x0000000000000000000000000000000000000000" + }, + "input": "0x02f9029d82053980849502f90085010c388d00832dc6c08080b90241608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033c001a07566181071cabaf58b70fc41557eb813bfc7a24f5c58554e7fed0bf7c031f169a0420af50b5fe791a4d839e181a676db5250b415dfb35cb85d544db7a1475ae2cc", + "result": { + "from": "0x3623191d4ccfbbdf09e8ebf6382a1f8257417bc1", + "to": "0x0000000000000000000000000000000000000000", + "gas": "0x2cd774", + "gasUsed": "0x25590", + "input": "0x608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033", + "output": "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012546869732063616c6c6564206661696c65640000000000000000000000000000", + "error": "execution reverted", + "revertReason": "This called failed", + "calls": [ + { + "from": "0xdebfb4b387033eac57af7b3de5116dd60056803b", + "gas": "0x2ba851", + "gasUsed": "0xe557", + "to": "0xd15abca351f79181dedfb6d019e382db90f3628a", + "input": "0x608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033", + "output": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033", + "value": "0x0", + "type": "CREATE" + }, + { + "from": "0xdebfb4b387033eac57af7b3de5116dd60056803b", + "gas": "0x2ac548", + "gasUsed": "0x1b2", + "to": "0xd15abca351f79181dedfb6d019e382db90f3628a", + "input": "0xc0406226", + "output": "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012546869732063616c6c6564206661696c65640000000000000000000000000000", + "error": "execution reverted", + "revertReason": "This called failed", + "type": "STATICCALL" + } + ], + "value": "0x0", + "type": "CREATE" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.md b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.md new file mode 100644 index 000000000000..2700578bd062 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.md @@ -0,0 +1,19 @@ +This test tests out the trace generated by the deployment of this contract: + +```solidity +contract Revertor { + function run() public pure { + require(2 > 3, "This called failed"); + } +} + +contract Contract { + constructor() { + Revertor r = new Revertor(); + r.run(); + } +} +``` + +The trace should show a revert, with the revert reason for both the top-call as well +as the inner call. diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json index 8a6262776b3f..a89d4dc7456b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json @@ -58,7 +58,7 @@ "gas": "0x0", "gasUsed": "0x0", "input": "0x", - "to": "0x000000000000000000000000000000000000dEaD", + "to": "0x000000000000000000000000000000000000dead", "type": "SELFDESTRUCT", "value": "0x4d87094125a369d9bd5" } @@ -67,7 +67,6 @@ "gas": "0x10738", "gasUsed": "0x6fcb", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", - "output": "0x", "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", "type": "CALL", "value": "0x0" diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 536906e312f9..68fe3bac3407 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -56,6 +56,28 @@ func (f callFrame) TypeString() string { return f.Type.String() } +func (f *callFrame) capture(output []byte, err error) { + output = common.CopyBytes(output) + if err == nil { + f.Output = output + return + } + f.Error = err.Error() + if f.Type == vm.CREATE || f.Type == vm.CREATE2 { + f.To = common.Address{} + } + if !errors.Is(err, vm.ErrExecutionReverted) || len(output) == 0 { + return + } + f.Output = output + if len(output) < 4 { + return + } + if unpacked, err := abi.UnpackRevert(output); err == nil { + f.Revertal = unpacked + } +} + type callFrameMarshaling struct { TypeString string `json:"type"` Gas hexutil.Uint64 @@ -110,22 +132,7 @@ func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad // CaptureEnd is called after the call finishes to finalize the tracing. func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { - output = common.CopyBytes(output) - if err == nil { - t.callstack[0].Output = output - return - } - t.callstack[0].Error = err.Error() - if !errors.Is(err, vm.ErrExecutionReverted) || len(output) == 0 { - return - } - t.callstack[0].Output = output - if len(output) < 4 { - return - } - if unpacked, err := abi.UnpackRevert(output); err == nil { - t.callstack[0].Revertal = unpacked - } + t.callstack[0].capture(output, err) } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. @@ -174,14 +181,7 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { size -= 1 call.GasUsed = gasUsed - if err == nil { - call.Output = common.CopyBytes(output) - } else { - call.Error = err.Error() - if call.Type == vm.CREATE || call.Type == vm.CREATE2 { - call.To = common.Address{} - } - } + call.capture(output, err) t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } From b0d44338bbcefee044f1f635a84487cbbd8f0538 Mon Sep 17 00:00:00 2001 From: vdwijden <115323661+vdwijden@users.noreply.github.com> Date: Mon, 31 Oct 2022 15:23:26 +0100 Subject: [PATCH 333/715] eth: implement eth/68 (#25980) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * eth: implement eth/68 * eth/protocols/eth: added tx size to announcement * eth/protocols/eth: check equal lengths on receiving announcement * eth/protocols/eth: add +1 to tx size because of the type byte * eth: happy lint, add eth68 tests, enable eth68 * eth: various nitpick fixes on eth/68 * eth/protocols/eth: fix announced tx size wrt type byte Co-authored-by: MariusVanDerWijden Co-authored-by: Péter Szilágyi --- cmd/devp2p/internal/ethtest/types.go | 2 +- eth/handler_eth.go | 5 ++++- eth/handler_eth_test.go | 18 ++++++++++++++++-- eth/protocols/eth/broadcast.go | 25 ++++++++++++++++++------- eth/protocols/eth/handler.go | 24 +++++++++++++++++++++--- eth/protocols/eth/handler_test.go | 23 +++++++++++++++++++---- eth/protocols/eth/handlers.go | 24 ++++++++++++++++++++++-- eth/protocols/eth/peer.go | 19 ++++++++++++++++--- eth/protocols/eth/peer_test.go | 2 ++ eth/protocols/eth/protocol.go | 23 +++++++++++++++++------ 10 files changed, 136 insertions(+), 29 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/types.go b/cmd/devp2p/internal/ethtest/types.go index 2c5cb94c699f..fd5251d161f3 100644 --- a/cmd/devp2p/internal/ethtest/types.go +++ b/cmd/devp2p/internal/ethtest/types.go @@ -127,7 +127,7 @@ func (msg NewBlock) Code() int { return 23 } func (msg NewBlock) ReqID() uint64 { return 0 } // NewPooledTransactionHashes is the network packet for the tx hash propagation message. -type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket +type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket66 func (msg NewPooledTransactionHashes) Code() int { return 24 } func (msg NewPooledTransactionHashes) ReqID() uint64 { return 0 } diff --git a/eth/handler_eth.go b/eth/handler_eth.go index 12e91ec7f534..4ed6335769cf 100644 --- a/eth/handler_eth.go +++ b/eth/handler_eth.go @@ -67,9 +67,12 @@ func (h *ethHandler) Handle(peer *eth.Peer, packet eth.Packet) error { case *eth.NewBlockPacket: return h.handleBlockBroadcast(peer, packet.Block, packet.TD) - case *eth.NewPooledTransactionHashesPacket: + case *eth.NewPooledTransactionHashesPacket66: return h.txFetcher.Notify(peer.ID(), *packet) + case *eth.NewPooledTransactionHashesPacket68: + return h.txFetcher.Notify(peer.ID(), packet.Hashes) + case *eth.TransactionsPacket: return h.txFetcher.Enqueue(peer.ID(), *packet, false) diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 9f0c36f950c5..885c2a971505 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -61,10 +61,14 @@ func (h *testEthHandler) Handle(peer *eth.Peer, packet eth.Packet) error { h.blockBroadcasts.Send(packet.Block) return nil - case *eth.NewPooledTransactionHashesPacket: + case *eth.NewPooledTransactionHashesPacket66: h.txAnnounces.Send(([]common.Hash)(*packet)) return nil + case *eth.NewPooledTransactionHashesPacket68: + h.txAnnounces.Send(packet.Hashes) + return nil + case *eth.TransactionsPacket: h.txBroadcasts.Send(([]*types.Transaction)(*packet)) return nil @@ -81,6 +85,8 @@ func (h *testEthHandler) Handle(peer *eth.Peer, packet eth.Packet) error { // Tests that peers are correctly accepted (or rejected) based on the advertised // fork IDs in the protocol handshake. func TestForkIDSplit66(t *testing.T) { testForkIDSplit(t, eth.ETH66) } +func TestForkIDSplit67(t *testing.T) { testForkIDSplit(t, eth.ETH67) } +func TestForkIDSplit68(t *testing.T) { testForkIDSplit(t, eth.ETH68) } func testForkIDSplit(t *testing.T, protocol uint) { t.Parallel() @@ -235,6 +241,8 @@ func testForkIDSplit(t *testing.T, protocol uint) { // Tests that received transactions are added to the local pool. func TestRecvTransactions66(t *testing.T) { testRecvTransactions(t, eth.ETH66) } +func TestRecvTransactions67(t *testing.T) { testRecvTransactions(t, eth.ETH67) } +func TestRecvTransactions68(t *testing.T) { testRecvTransactions(t, eth.ETH68) } func testRecvTransactions(t *testing.T, protocol uint) { t.Parallel() @@ -292,6 +300,8 @@ func testRecvTransactions(t *testing.T, protocol uint) { // This test checks that pending transactions are sent. func TestSendTransactions66(t *testing.T) { testSendTransactions(t, eth.ETH66) } +func TestSendTransactions67(t *testing.T) { testSendTransactions(t, eth.ETH67) } +func TestSendTransactions68(t *testing.T) { testSendTransactions(t, eth.ETH68) } func testSendTransactions(t *testing.T, protocol uint) { t.Parallel() @@ -350,7 +360,7 @@ func testSendTransactions(t *testing.T, protocol uint) { seen := make(map[common.Hash]struct{}) for len(seen) < len(insert) { switch protocol { - case 66: + case 66, 67, 68: select { case hashes := <-anns: for _, hash := range hashes { @@ -377,6 +387,8 @@ func testSendTransactions(t *testing.T, protocol uint) { // Tests that transactions get propagated to all attached peers, either via direct // broadcasts or via announcements/retrievals. func TestTransactionPropagation66(t *testing.T) { testTransactionPropagation(t, eth.ETH66) } +func TestTransactionPropagation67(t *testing.T) { testTransactionPropagation(t, eth.ETH67) } +func TestTransactionPropagation68(t *testing.T) { testTransactionPropagation(t, eth.ETH68) } func testTransactionPropagation(t *testing.T, protocol uint) { t.Parallel() @@ -678,6 +690,8 @@ func testBroadcastBlock(t *testing.T, peers, bcasts int) { // Tests that a propagated malformed block (uncles or transactions don't match // with the hashes in the header) gets discarded and not broadcast forward. func TestBroadcastMalformedBlock66(t *testing.T) { testBroadcastMalformedBlock(t, eth.ETH66) } +func TestBroadcastMalformedBlock67(t *testing.T) { testBroadcastMalformedBlock(t, eth.ETH67) } +func TestBroadcastMalformedBlock68(t *testing.T) { testBroadcastMalformedBlock(t, eth.ETH68) } func testBroadcastMalformedBlock(t *testing.T, protocol uint) { t.Parallel() diff --git a/eth/protocols/eth/broadcast.go b/eth/protocols/eth/broadcast.go index 0afe01b1ce15..3045303f222e 100644 --- a/eth/protocols/eth/broadcast.go +++ b/eth/protocols/eth/broadcast.go @@ -142,13 +142,17 @@ func (p *Peer) announceTransactions() { if done == nil && len(queue) > 0 { // Pile transaction hashes until we reach our allowed network limit var ( - count int - pending []common.Hash - size common.StorageSize + count int + pending []common.Hash + pendingTypes []byte + pendingSizes []uint32 + size common.StorageSize ) for count = 0; count < len(queue) && size < maxTxPacketSize; count++ { - if p.txpool.Get(queue[count]) != nil { + if tx := p.txpool.Get(queue[count]); tx != nil { pending = append(pending, queue[count]) + pendingTypes = append(pendingTypes, tx.Type()) + pendingSizes = append(pendingSizes, uint32(tx.Size())) size += common.HashLength } } @@ -159,9 +163,16 @@ func (p *Peer) announceTransactions() { if len(pending) > 0 { done = make(chan struct{}) go func() { - if err := p.sendPooledTransactionHashes(pending); err != nil { - fail <- err - return + if p.version >= ETH68 { + if err := p.sendPooledTransactionHashes68(pending, pendingTypes, pendingSizes); err != nil { + fail <- err + return + } + } else { + if err := p.sendPooledTransactionHashes66(pending); err != nil { + fail <- err + return + } } close(done) p.Log().Trace("Sent transaction announcements", "count", len(pending)) diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 87b1f20a2dc2..60654b803051 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -168,7 +168,7 @@ var eth66 = map[uint64]msgHandler{ NewBlockHashesMsg: handleNewBlockhashes, NewBlockMsg: handleNewBlock, TransactionsMsg: handleTransactions, - NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes, + NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes66, GetBlockHeadersMsg: handleGetBlockHeaders66, BlockHeadersMsg: handleBlockHeaders66, GetBlockBodiesMsg: handleGetBlockBodies66, @@ -185,7 +185,22 @@ var eth67 = map[uint64]msgHandler{ NewBlockHashesMsg: handleNewBlockhashes, NewBlockMsg: handleNewBlock, TransactionsMsg: handleTransactions, - NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes, + NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes66, + GetBlockHeadersMsg: handleGetBlockHeaders66, + BlockHeadersMsg: handleBlockHeaders66, + GetBlockBodiesMsg: handleGetBlockBodies66, + BlockBodiesMsg: handleBlockBodies66, + GetReceiptsMsg: handleGetReceipts66, + ReceiptsMsg: handleReceipts66, + GetPooledTransactionsMsg: handleGetPooledTransactions66, + PooledTransactionsMsg: handlePooledTransactions66, +} + +var eth68 = map[uint64]msgHandler{ + NewBlockHashesMsg: handleNewBlockhashes, + NewBlockMsg: handleNewBlock, + TransactionsMsg: handleTransactions, + NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes68, GetBlockHeadersMsg: handleGetBlockHeaders66, BlockHeadersMsg: handleBlockHeaders66, GetBlockBodiesMsg: handleGetBlockBodies66, @@ -210,9 +225,12 @@ func handleMessage(backend Backend, peer *Peer) error { defer msg.Discard() var handlers = eth66 - if peer.Version() >= ETH67 { + if peer.Version() == ETH67 { handlers = eth67 } + if peer.Version() >= ETH68 { + handlers = eth68 + } // Track the amount of time it takes to serve the request and run the handler if metrics.Enabled { diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index faea081be539..5c3d1be0a123 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -112,6 +112,8 @@ func (b *testBackend) Handle(*Peer, Packet) error { // Tests that block headers can be retrieved from a remote chain based on user queries. func TestGetBlockHeaders66(t *testing.T) { testGetBlockHeaders(t, ETH66) } +func TestGetBlockHeaders67(t *testing.T) { testGetBlockHeaders(t, ETH67) } +func TestGetBlockHeaders68(t *testing.T) { testGetBlockHeaders(t, ETH68) } func testGetBlockHeaders(t *testing.T, protocol uint) { t.Parallel() @@ -297,6 +299,8 @@ func testGetBlockHeaders(t *testing.T, protocol uint) { // Tests that block contents can be retrieved from a remote chain based on their hashes. func TestGetBlockBodies66(t *testing.T) { testGetBlockBodies(t, ETH66) } +func TestGetBlockBodies67(t *testing.T) { testGetBlockBodies(t, ETH67) } +func TestGetBlockBodies68(t *testing.T) { testGetBlockBodies(t, ETH68) } func testGetBlockBodies(t *testing.T, protocol uint) { t.Parallel() @@ -379,9 +383,11 @@ func testGetBlockBodies(t *testing.T, protocol uint) { } // Tests that the state trie nodes can be retrieved based on hashes. -func TestGetNodeData66(t *testing.T) { testGetNodeData(t, ETH66) } +func TestGetNodeData66(t *testing.T) { testGetNodeData(t, ETH66, false) } +func TestGetNodeData67(t *testing.T) { testGetNodeData(t, ETH67, true) } +func TestGetNodeData68(t *testing.T) { testGetNodeData(t, ETH68, true) } -func testGetNodeData(t *testing.T, protocol uint) { +func testGetNodeData(t *testing.T, protocol uint, drop bool) { t.Parallel() // Define three accounts to simulate transactions with @@ -442,8 +448,15 @@ func testGetNodeData(t *testing.T, protocol uint) { GetNodeDataPacket: hashes, }) msg, err := peer.app.ReadMsg() - if err != nil { - t.Fatalf("failed to read node data response: %v", err) + if !drop { + if err != nil { + t.Fatalf("failed to read node data response: %v", err) + } + } else { + if err != nil { + return + } + t.Fatalf("succeeded to read node data response on non-supporting protocol: %v", msg) } if msg.Code != NodeDataMsg { t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, NodeDataMsg) @@ -489,6 +502,8 @@ func testGetNodeData(t *testing.T, protocol uint) { // Tests that the transaction receipts can be retrieved based on hashes. func TestGetBlockReceipts66(t *testing.T) { testGetBlockReceipts(t, ETH66) } +func TestGetBlockReceipts67(t *testing.T) { testGetBlockReceipts(t, ETH67) } +func TestGetBlockReceipts68(t *testing.T) { testGetBlockReceipts(t, ETH68) } func testGetBlockReceipts(t *testing.T, protocol uint) { t.Parallel() diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index d454b3407f3c..85a59969ebf8 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -430,13 +430,13 @@ func handleReceipts66(backend Backend, msg Decoder, peer *Peer) error { }, metadata) } -func handleNewPooledTransactionHashes(backend Backend, msg Decoder, peer *Peer) error { +func handleNewPooledTransactionHashes66(backend Backend, msg Decoder, peer *Peer) error { // New transaction announcement arrived, make sure we have // a valid and fresh chain to handle them if !backend.AcceptTxs() { return nil } - ann := new(NewPooledTransactionHashesPacket) + ann := new(NewPooledTransactionHashesPacket66) if err := msg.Decode(ann); err != nil { return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) } @@ -447,6 +447,26 @@ func handleNewPooledTransactionHashes(backend Backend, msg Decoder, peer *Peer) return backend.Handle(peer, ann) } +func handleNewPooledTransactionHashes68(backend Backend, msg Decoder, peer *Peer) error { + // New transaction announcement arrived, make sure we have + // a valid and fresh chain to handle them + if !backend.AcceptTxs() { + return nil + } + ann := new(NewPooledTransactionHashesPacket68) + if err := msg.Decode(ann); err != nil { + return fmt.Errorf("%w: message %v: %v", errDecode, msg, err) + } + if len(ann.Hashes) != len(ann.Types) || len(ann.Hashes) != len(ann.Sizes) { + return fmt.Errorf("%w: message %v: invalid len of fields: %v %v %v", errDecode, msg, len(ann.Hashes), len(ann.Types), len(ann.Sizes)) + } + // Schedule all the unknown hashes for retrieval + for _, hash := range ann.Hashes { + peer.markTransaction(hash) + } + return backend.Handle(peer, ann) +} + func handleGetPooledTransactions66(backend Backend, msg Decoder, peer *Peer) error { // Decode the pooled transactions retrieval message var query GetPooledTransactionsPacket66 diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index 0a3b7bd56e1b..070ce0825f9a 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -210,16 +210,29 @@ func (p *Peer) AsyncSendTransactions(hashes []common.Hash) { } } -// sendPooledTransactionHashes sends transaction hashes to the peer and includes +// sendPooledTransactionHashes66 sends transaction hashes to the peer and includes // them in its transaction hash set for future reference. // // This method is a helper used by the async transaction announcer. Don't call it // directly as the queueing (memory) and transmission (bandwidth) costs should // not be managed directly. -func (p *Peer) sendPooledTransactionHashes(hashes []common.Hash) error { +func (p *Peer) sendPooledTransactionHashes66(hashes []common.Hash) error { // Mark all the transactions as known, but ensure we don't overflow our limits p.knownTxs.Add(hashes...) - return p2p.Send(p.rw, NewPooledTransactionHashesMsg, NewPooledTransactionHashesPacket(hashes)) + return p2p.Send(p.rw, NewPooledTransactionHashesMsg, NewPooledTransactionHashesPacket66(hashes)) +} + +// sendPooledTransactionHashes68 sends transaction hashes (tagged with their type +// and size) to the peer and includes them in its transaction hash set for future +// reference. +// +// This method is a helper used by the async transaction announcer. Don't call it +// directly as the queueing (memory) and transmission (bandwidth) costs should +// not be managed directly. +func (p *Peer) sendPooledTransactionHashes68(hashes []common.Hash, types []byte, sizes []uint32) error { + // Mark all the transactions as known, but ensure we don't overflow our limits + p.knownTxs.Add(hashes...) + return p2p.Send(p.rw, NewPooledTransactionHashesMsg, NewPooledTransactionHashesPacket68{Types: types, Sizes: sizes, Hashes: hashes}) } // AsyncSendPooledTransactionHashes queues a list of transactions hashes to eventually diff --git a/eth/protocols/eth/peer_test.go b/eth/protocols/eth/peer_test.go index 0916ebee5d45..efbbbc6fff88 100644 --- a/eth/protocols/eth/peer_test.go +++ b/eth/protocols/eth/peer_test.go @@ -48,6 +48,8 @@ func newTestPeer(name string, version uint, backend Backend) (*testPeer, <-chan peer := NewPeer(version, p2p.NewPeer(id, name, nil), net, backend.TxPool()) errc := make(chan error, 1) go func() { + defer app.Close() + errc <- backend.RunPeer(peer, func(peer *Peer) error { return Handle(backend, peer) }) diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index f6fac4278080..6c59fcae655a 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -32,6 +32,7 @@ import ( const ( ETH66 = 66 ETH67 = 67 + ETH68 = 68 ) // ProtocolName is the official short name of the `eth` protocol used during @@ -40,11 +41,11 @@ const ProtocolName = "eth" // ProtocolVersions are the supported versions of the `eth` protocol (first // is primary). -var ProtocolVersions = []uint{ETH67, ETH66} +var ProtocolVersions = []uint{ETH68, ETH67, ETH66} // protocolLengths are the number of implemented message corresponding to // different protocol versions. -var protocolLengths = map[uint]uint64{ETH67: 17, ETH66: 17} +var protocolLengths = map[uint]uint64{ETH68: 17, ETH67: 17, ETH66: 17} // maxMessageSize is the maximum cap on the size of a protocol message. const maxMessageSize = 10 * 1024 * 1024 @@ -298,8 +299,15 @@ type ReceiptsRLPPacket66 struct { ReceiptsRLPPacket } -// NewPooledTransactionHashesPacket represents a transaction announcement packet. -type NewPooledTransactionHashesPacket []common.Hash +// NewPooledTransactionHashesPacket66 represents a transaction announcement packet on eth/66 and eth/67. +type NewPooledTransactionHashesPacket66 []common.Hash + +// NewPooledTransactionHashesPacket68 represents a transaction announcement packet on eth/68 and newer. +type NewPooledTransactionHashesPacket68 struct { + Types []byte + Sizes []uint32 + Hashes []common.Hash +} // GetPooledTransactionsPacket represents a transaction query. type GetPooledTransactionsPacket []common.Hash @@ -364,8 +372,11 @@ func (*GetReceiptsPacket) Kind() byte { return GetReceiptsMsg } func (*ReceiptsPacket) Name() string { return "Receipts" } func (*ReceiptsPacket) Kind() byte { return ReceiptsMsg } -func (*NewPooledTransactionHashesPacket) Name() string { return "NewPooledTransactionHashes" } -func (*NewPooledTransactionHashesPacket) Kind() byte { return NewPooledTransactionHashesMsg } +func (*NewPooledTransactionHashesPacket66) Name() string { return "NewPooledTransactionHashes" } +func (*NewPooledTransactionHashesPacket66) Kind() byte { return NewPooledTransactionHashesMsg } + +func (*NewPooledTransactionHashesPacket68) Name() string { return "NewPooledTransactionHashes" } +func (*NewPooledTransactionHashesPacket68) Kind() byte { return NewPooledTransactionHashesMsg } func (*GetPooledTransactionsPacket) Name() string { return "GetPooledTransactions" } func (*GetPooledTransactionsPacket) Kind() byte { return GetPooledTransactionsMsg } From 8e69622c6894ebf99ff30ab0ed6f76a71cc1dc5e Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 1 Nov 2022 19:03:26 +0800 Subject: [PATCH 334/715] eth/tracers: add withLog to callTracer (#25991) In some cases, it is desirable to capture what is triggered by each trace, when using the `callTracer`. For example: call `USDT.transfer` will trigger a `Transfer(from, to, value)` event. This PR adds the option to capture logs to the call tracer, by specifying `{"withLog": true}` in the tracerconfig. Any logs belonging to failed/reverted call-scopes are removed from the output, to prevent interpretation mistakes. Signed-off-by: Delweng Co-authored-by: Sina Mahmoodi --- .../internal/tracetest/calltrace_test.go | 12 + .../call_tracer_withLog/calldata.json | 115 + .../call_tracer_withLog/delegatecall.json | 400 +++ .../call_tracer_withLog/multi_contracts.json | 2295 +++++++++++++++++ .../call_tracer_withLog/multilogs.json | 530 ++++ .../testdata/call_tracer_withLog/notopic.json | 286 ++ .../testdata/call_tracer_withLog/simple.json | 84 + .../call_tracer_withLog/tx_failed.json | 244 ++ .../tx_partial_failed.json | 107 + .../call_tracer_withLog/with_onlyTopCall.json | 89 + eth/tracers/native/call.go | 59 +- eth/tracers/native/gen_callframe_json.go | 6 + 12 files changed, 4226 insertions(+), 1 deletion(-) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 6bb8dae9b622..0827d3b40e41 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -46,6 +46,13 @@ type callContext struct { Miner common.Address `json:"miner"` } +// callLog is the result of LOG opCode +type callLog struct { + Address common.Address `json:"address"` + Topics []common.Hash `json:"topics"` + Data hexutil.Bytes `json:"data"` +} + // callTrace is the result of a callTracer run. type callTrace struct { From common.Address `json:"from"` @@ -57,6 +64,7 @@ type callTrace struct { Error string `json:"error,omitempty"` Revertal string `json:"revertReason,omitempty"` Calls []callTrace `json:"calls,omitempty"` + Logs []callLog `json:"logs,omitempty"` Value *hexutil.Big `json:"value,omitempty"` // Gencodec adds overridden fields at the end Type string `json:"type"` @@ -81,6 +89,10 @@ func TestCallTracerNative(t *testing.T) { testCallTracer("callTracer", "call_tracer", t) } +func TestCallTracerNativeWithLog(t *testing.T) { + testCallTracer("callTracer", "call_tracer_withLog", t) +} + func testCallTracer(tracerName string, dirPath string, t *testing.T) { isLegacy := strings.HasSuffix(dirPath, "_legacy") files, err := os.ReadDir(filepath.Join("testdata", dirPath)) diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json new file mode 100644 index 000000000000..b18c80e58ec5 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json @@ -0,0 +1,115 @@ +{ + "genesis": { + "difficulty": "11934798510088", + "extraData": "0xd983010302844765746887676f312e342e328777696e646f7773", + "gasLimit": "3141592", + "hash": "0xfc543a4a551afbd4a6c5d6d49041371e6bb58b1108c12aaec7f487ce656bb97f", + "miner": "0xf8b483dba2c3b7176a3da549ad41a48bb3121069", + "mixHash": "0xa6a1e67fc68da76b8d9cc3ce1c45d5e1f4bbd96b5dcfddbe0017d7fa99903ead", + "nonce": "0x5f00c600268b4659", + "number": "995200", + "stateRoot": "0x3579328470dd2aef5b9da69f5480cbe0d375e653b530ab3c1aee0da5e1ff4c94", + "timestamp": "1455322761", + "totalDifficulty": "7077231809278509672", + "alloc": { + "0x200edd17f30485a8735878661960cd7a9a95733f": { + "balance": "0x0", + "code": "0x3660008037602060003660003473273930d21e01ee25e4c219b63259d214872220a261235a5a03f21560015760206000f3", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000000000000000000000000000104": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x4c0be60200faa20559308cb7b5a1bb3255c16cb1cab91f525b5ae7a03d02fabe": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8ba1097eb3abe3dc1b51faa48445d593bf968f722e20b67bb62a87495836bf04": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8ba1097eb3abe3dc1b51faa48445d593bf968f722e20b67bb62a87495836bf05": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8ba1097eb3abe3dc1b51faa48445d593bf968f722e20b67bb62a87495836bf06": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xa611e7c895a426c0477bc9e280db9c3b1e456dc6310ffcf23926ef5186c1facc": "0x0000000000000000000000000000000000000000000000000000000000000002", + "0xac682d343707aadf06c2c4c3692831d9e7ba711099ef36f9efb8bb29be8c410e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xac682d343707aadf06c2c4c3692831d9e7ba711099ef36f9efb8bb29be8c410f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xac682d343707aadf06c2c4c3692831d9e7ba711099ef36f9efb8bb29be8c4110": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x273930d21e01ee25e4c219b63259d214872220a2": { + "balance": "0x0", + "code": "0x606060405236156100da5760e060020a6000350463173825d9811461012c5780632f54bf6e146101875780634123cb6b146101af57806352375093146101b857806354fd4d50146101c25780635c52c2f5146101cc578063659010e7146101fd5780637065cb4814610207578063746c91711461023b578063797af62714610244578063b20d30a914610257578063b61d27f61461028b578063b75c7dc6146102ac578063ba51a6df146102db578063c2cf73261461030f578063cbf0b0c01461034d578063f00d4b5d14610381578063f1736d86146103ba575b6103c4600034111561012a5760408051600160a060020a033216815234602082015281517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c929181900390910190a15b565b6103c46004356000600036436040518084848082843750505090910190815260405190819003602001902090506106c9815b600160a060020a03321660009081526101026020526040812054818082811415610c3f57610d97565b6103c66004355b600160a060020a03811660009081526101026020526040812054115b919050565b6103c660015481565b6103c66101075481565b6103c66101085481565b6103c46000364360405180848480828437505050909101908152604051908190036020019020905061081a8161015e565b6103c66101065481565b6103c4600435600036436040518084848082843750505090910190815260405190819003602001902090506106418161015e565b6103c660005481565b6103c66004355b600081610a7d8161015e565b6103c46004356000364360405180848480828437505050909101908152604051908190036020019020905061080e8161015e565b6103c66004803590602480359160443591820191013560006108393261018e565b6103c4600435600160a060020a033216600090815261010260205260408120549080828114156103d857610457565b6103c4600435600036436040518084848082843750505090910190815260405190819003602001902090506107888161015e565b6103c6600435602435600082815261010360209081526040808320600160a060020a038516845261010290925282205482818114156107e157610805565b6103c4600435600036436040518084848082843750505090910190815260405190819003602001902090506108288161015e565b6103c46004356024356000600036436040518084848082843750505090910190815260405190819003602001902090506104e28161015e565b6103c66101055481565b005b60408051918252519081900360200190f35b50506000828152610103602052604081206001810154600284900a9290831611156104575780546001828101805492909101835590839003905560408051600160a060020a03321681526020810186905281517fc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b929181900390910190a15b50505050565b600160a060020a03831660028361010081101561000257508301819055600160a060020a03851660008181526101026020908152604080832083905584835291829020869055815192835282019290925281517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c929181900390910190a1505b505050565b15610457576104f08361018e565b156104fb57506104dd565b600160a060020a03841660009081526101026020526040812054925082141561052457506104dd565b61045d5b6101045460005b81811015610ee457610104805461010991600091849081101561000257600080516020610f9f83398151915201548252506020918252604081208054600160a060020a0319168155600181018290556002810180548382559083528383209193610f6992601f9290920104810190610a65565b60018054810190819055600160a060020a038316906002906101008110156100025790900160005081905550600160005054610102600050600084600160a060020a03168152602001908152602001600020600050819055507f994a936646fe87ffe4f1e469d3d6aa417d6b855598397f323de5b449f765f0c3826040518082600160a060020a0316815260200191505060405180910390a15b505b50565b1561063c5761064f8261018e565b1561065a575061063e565b610662610528565b60015460fa90106106775761067561068c565b505b60015460fa90106105a2575061063e565b6107465b600060015b600154811015610a79575b600154811080156106bc5750600281610100811015610002570154600014155b15610d9f5760010161069c565b156104dd57600160a060020a0383166000908152610102602052604081205492508214156106f7575061063c565b6001600160005054036000600050541115610712575061063c565b600060028361010081101561000257508301819055600160a060020a03841681526101026020526040812055610688610528565b5060408051600160a060020a038516815290517f58619076adf5bb0943d100ef88d52d7c3fd691b19d3a9071b555b651fbf418da9181900360200190a1505050565b1561063c5760015482111561079d575061063e565b60008290556107aa610528565b6040805183815290517facbdb084c721332ac59f9b8e392196c9eb0e4932862da8eb9beaf0dad4f550da9181900360200190a15050565b506001820154600282900a908116600014156108005760009350610805565b600193505b50505092915050565b1561063c575061010555565b1561063e5760006101065550565b1561063c5781600160a060020a0316ff5b15610a555761084d846000610e793261018e565b15610909577f92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd00432858786866040518086600160a060020a0316815260200185815260200184600160a060020a031681526020018060200182810382528484828181526020019250808284378201915050965050505050505060405180910390a184600160a060020a03168484846040518083838082843750505090810191506000908083038185876185025a03f15060009350610a5592505050565b6000364360405180848480828437505050909101908152604051908190036020019020915061093990508161024b565b15801561095c575060008181526101096020526040812054600160a060020a0316145b15610a555760008181526101096020908152604082208054600160a060020a03191688178155600181018790556002018054858255818452928290209092601f01919091048101908490868215610a5d579182015b82811115610a5d5782358260005055916020019190600101906109b1565b50507f1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf328132868887876040518087815260200186600160a060020a0316815260200185815260200184600160a060020a03168152602001806020018281038252848482818152602001925080828437820191505097505050505050505060405180910390a15b949350505050565b506109cf9291505b80821115610a795760008155600101610a65565b5090565b15610c2c5760008381526101096020526040812054600160a060020a031614610c2c5760408051600091909120805460018201546002929092018054600160a060020a0392909216939091819083908015610afd57820191906000526020600020905b815481529060010190602001808311610ae057829003601f168201915b505091505060006040518083038185876185025a03f150505060008481526101096020908152604080519281902080546001820154600160a060020a033281811688529587018b905293860181905292166060850181905260a06080860181815260029390930180549187018290527fe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a975094958a959293909160c083019084908015610bcf57820191906000526020600020905b815481529060010190602001808311610bb257829003601f168201915b5050965050505050505060405180910390a160008381526101096020908152604082208054600160a060020a031916815560018101839055600281018054848255908452828420919392610c3292601f9290920104810190610a65565b50919050565b50505060019150506101aa565b60008581526101036020526040812080549093501415610cc7576000805483556001838101919091556101048054918201808255828015829011610c9657818360005260206000209182019101610c969190610a65565b50505060028301819055610104805487929081101561000257600091909152600080516020610f9f83398151915201555b506001810154600283900a90811660001415610d975760408051600160a060020a03321681526020810187905281517fe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda929181900390910190a1815460019011610d84576000858152610103602052604090206002015461010480549091908110156100025760406000908120600080516020610f9f8339815191529290920181905580825560018083018290556002909201559450610d979050565b8154600019018255600182018054821790555b505050919050565b5b60018054118015610dc257506001546002906101008110156100025701546000145b15610dd65760018054600019019055610da0565b60015481108015610df95750600154600290610100811015610002570154600014155b8015610e1357506002816101008110156100025701546000145b15610e7457600154600290610100811015610002578101549082610100811015610002578101919091558190610102906000908361010081101561000257810154825260209290925260408120929092556001546101008110156100025701555b610691565b156101aa5761010754610e8f5b62015180420490565b1115610ea857600061010655610ea3610e86565b610107555b6101065480830110801590610ec65750610106546101055490830111155b15610edc575061010680548201905560016101aa565b5060006101aa565b61063c6101045460005b81811015610f745761010480548290811015610002576000918252600080516020610f9f833981519152015414610f6157610104805461010391600091849081101561000257600080516020610f9f83398151915201548252506020919091526040812081815560018101829055600201555b600101610eee565b50505060010161052f565b61010480546000808355919091526104dd90600080516020610f9f83398151915290810190610a6556004c0be60200faa20559308cb7b5a1bb3255c16cb1cab91f525b5ae7a03d02fabe" + }, + "0x4f5777744b500616697cb655dcb02ee6cd51deb5": { + "balance": "0xb0983f1b83eec290", + "nonce": "2" + }, + "0xf8b483dba2c3b7176a3da549ad41a48bb3121069": { + "balance": "0x16969a0ba2c2d384d07", + "nonce": "67521" + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "995201", + "difficulty": "11940626048551", + "timestamp": "1455322773", + "gasLimit": "3141592", + "miner": "0xf8b483dba2c3b7176a3da549ad41a48bb3121069" + }, + "input": "0xf89102850a954d522e8303308594200edd17f30485a8735878661960cd7a9a95733f888ac7230489e80000a4ba51a6df00000000000000000000000000000000000000000000000000000000000000001ca04f2cc45b96f965296382b2e9b657e90808301d5179035a5d91a2de7b912def20a056e19271ea4e19e4e034f38e925e312beed4d300c267160eeb2f565c42deb578", + "tracerConfig": { + "withLog": true + }, + "result": { + "from": "0x4f5777744b500616697cb655dcb02ee6cd51deb5", + "gas": "0x2dced", + "gasUsed": "0x1a9e5", + "to": "0x200edd17f30485a8735878661960cd7a9a95733f", + "input": "0xba51a6df0000000000000000000000000000000000000000000000000000000000000000", + "output": "0xba51a6df00000000000000000000000000000000000000000000000000000000", + "calls": [ + { + "from": "0x200edd17f30485a8735878661960cd7a9a95733f", + "gas": "0x2c263", + "gasUsed": "0x1b0e4", + "to": "0x273930d21e01ee25e4c219b63259d214872220a2", + "input": "0xba51a6df0000000000000000000000000000000000000000000000000000000000000000", + "logs": [ + { + "address": "0x200edd17f30485a8735878661960cd7a9a95733f", + "topics": [ + "0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda" + ], + "data": "0x0000000000000000000000004f5777744b500616697cb655dcb02ee6cd51deb5be96016bb57376da7a6d296e0a405ee1501778227dfa604df0a81cb1ae018598" + }, + { + "address": "0x200edd17f30485a8735878661960cd7a9a95733f", + "topics": [ + "0xacbdb084c721332ac59f9b8e392196c9eb0e4932862da8eb9beaf0dad4f550da" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x8ac7230489e80000", + "type": "CALLCODE" + } + ], + "value": "0x8ac7230489e80000", + "type": "CALL" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json new file mode 100644 index 000000000000..d5d0d072f2a1 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json @@ -0,0 +1,400 @@ +{ + "genesis": { + "difficulty": "80344740444880", + "extraData": "0x7777772e62772e636f6d", + "gasLimit": "1498600", + "hash": "0xf5d85a80bdbc5d28a16b8eb0d1b9dd18316ddc3655c7d5c901b67acdb7700037", + "miner": "0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1", + "mixHash": "0x433ae590edf0e7ba9aac698bb7d3be2300e3e79d175db13528ff3e79a3f93910", + "nonce": "0x084adce0020c6fd8", + "number": "2340152", + "stateRoot": "0x38295a2634c9c62d48bcbf2ef2ae83768b9055c1f5e6469d17a5d1bcb052072e", + "timestamp": "1475034708", + "totalDifficulty": "66488249547380413902", + "alloc": { + "0x01e60b511fced1eb2b5b40991eb1dfd171a6df42": { + "balance": "0x0", + "code": "0x6060604052361561008d5760e060020a600035046306fdde03811461008f578063095ea7b3146100a557806318160ddd1461012457806323b872dd1461012f578063313ce567146101dc578063475a9fa9146101f057806370a0823114610215578063721a37d21461024357806395d89b411461008f578063a9059cbb14610268578063dd62ed3e146102e7575b005b61031d6040805160208101909152600081525b90565b61038b60043560243560007319ee743d2e356d5f0e4d97cc09b96d06e933d0db63c6605267600160005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506103179050565b6102316003546100a2565b61038b60043560243560443560008054604080517fa00bfa1100000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a038781166024830152868116604483015260648201869052929092166084830152517319ee743d2e356d5f0e4d97cc09b96d06e933d0db9163a00bfa119160a482810192602092919082900301818660325a03f4156100025750506040515195945050505050565b604080516000815290519081900360200190f35b61038b6004356024356000805433600160a060020a0390811691161461039f57610002565b600160a060020a03600435166000908152600160205260409020545b60408051918252519081900360200190f35b61038b6004356024356000805433600160a060020a039081169116146103ce57610002565b61038b60043560243560007319ee743d2e356d5f0e4d97cc09b96d06e933d0db6388d5fecb600160005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506103179050565b610231600435602435600160a060020a038281166000908152600260209081526040808320938516835292905220545b92915050565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561037d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080519115158252519081900360200190f35b50600160a060020a03821660009081526001602081905260409091208054830190556003805483019055610317565b600160a060020a038316600090815260016020526040902054821161040a57506040600020805482900390556003805482900390556001610317565b50600061031756", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000012098a4651fb262f7", + "0xfae22198212900725daa5db635d1fda7b0fa195adaabdc806a7267959c3d8ae4": "0x00000000000000000000000000000000000000000000000026cbcbc35aaa62f7" + } + }, + "0x19ee743d2e356d5f0e4d97cc09b96d06e933d0db": { + "balance": "0x0", + "code": "0x6503060000000050606060405260e060020a600035046388d5fecb811461003c578063a00bfa11146100e3578063c6605267146102dc575b610007565b610356600435602435604435600160a060020a0333166000908152602084905260408120548290108015906100715750600082115b1561036a57600160a060020a0333811660008181526020878152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a350600161034f565b610356600435602435604435606435608435600160a060020a03841660009081526020869052604081205483901080159061011e5750600083115b80156101bb5750600160a060020a0385811660009081526001880160209081526040808320339094168352929052205483901015806101bb575081600160a060020a0316631934d55a86336040518360e060020a0281526004018083600160a060020a0316815260200182600160a060020a03168152602001925050506020604051808303816000876161da5a03f1156100075750506040515190505b1561037257600160a060020a038481166000908152602088815260408083208054880190558884168084528184208054899003905581517f1934d55a00000000000000000000000000000000000000000000000000000000815260048101919091523385166024820152905193861693631934d55a936044838101949383900301908290876161da5a03f115610007575050604051511515905061028957600160a060020a038581166000908152600188016020908152604080832033909416835292905220805484900390555b83600160a060020a031685600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3506001610376565b610356600435602435604435600160a060020a033381166000818152600186016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b9392505050565b604080519115158252519081900360200190f35b50600061034f565b5060005b9594505050505056" + }, + "0x3de712784baf97260455ae25fb74f574ec9c1add": { + "balance": "0x23c8352f33854625", + "nonce": "80" + }, + "0x5aae5c59d642e5fd45b427df6ed478b49d55fefd": { + "balance": "0x0", + "nonce": "29", + "code": "0x606060405236156100cf5760e060020a600035046307d5b82681146100d157806315e812ad146101775780631934d55a1461018d5780631d007f5f146101c65780631f0c1e0c146101ee5780633983d5c41461022b5780634025b29314610243578063428d64bd1461030f578063481b659d146104b557806357bcccb6146104f45780638c172fa21461052f5780639ba5b4e9146105ea578063a4a7cf5c146106ca578063b11e3b82146106ed578063c51cf179146107a6578063d6911046146107c2578063eff6be2f146109cb575b005b6109f2600435602435600082815260016020908152604080832060049081015482517f23b872dd00000000000000000000000000000000000000000000000000000000815233600160a060020a0390811693820193909352308316602482015260448101879052925185948594859493909316926323b872dd9260648281019392829003018187876161da5a03f1156100025750506040515115159050610a6d57610002565b6004545b60408051918252519081900360200190f35b6109f2600435602435600160a060020a0382811660009081526003602090815260408083209385168352929052205460ff165b92915050565b6109f2600435600080546101009004600160a060020a039081163390911614610be757610002565b610a066004356024356000828152600160205260408120600901805483908110156100025750815260209020810154600160a060020a03166101c0565b61017b6004355b600454620f4240908202045b919050565b6109f26004356024356000805b600084815260016020526040902060090154811015610c13576040600090812090859052600160205260090180548290811015610002576000918252604080516020808520909301547f721a37d2000000000000000000000000000000000000000000000000000000008252600160a060020a03338116600484015260248301899052925192169363721a37d293604483810194919391929183900301908290876161da5a03f1156100025750506040515115159050610c8d57610002565b604080516024803560048181013560208181028087018201909752818652610a2396833596939560449501929182919085019084908082843750949650505050505050604080516020818101835260008083528351918201909352828152909190819081905b8551831015610c9f57600091505b600160005060008785815181101561000257602090810290910181015182528101919091526040016000206009015460ff831610156104a957600060016000506000888681518110156100025760209081029091018101518252810191909152604001600020600901805460ff85169081101561000257906000526020600020900160009054906101000a9004600160a060020a0316600160a060020a03166370a08231896040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515191909111159050610f59576001600050600087858151811015610002576020908102909101810151825281019190915260400160002060090154909301600201925b60019290920191610375565b6109f260043533600160a060020a039081166000908152600360209081526040808320938516835292905220805460ff1916600190811790915561023e565b6109f260043533600160a060020a039081166000908152600360209081526040808320938516835292905220805460ff19169055600161023e565b60048035600090815260016020818152604092839020600981015481548551968301546002840154600385015460088601546005870154600688015499880154600790980154958c52600160a060020a03888116998d019990995260a060020a90970460ff90811615158c8c015260608c019390935260808b019190915260a08a019490945290851660c08901529290931660e087015261010086019390935216151561012084015261014083015251908190036101600190f35b60408051600480358082013560208181028086018201909652818552610a23959394602494909385019291829190850190849080828437509496505050505050506040805160208181018352600080835283519182019093528281529091908190815b8551831015610f93576000600260005060008886815181101561000257602090810290910181015182528101919091526040016000205411156106be576002600050600087858151811015610002576020908102909101810151825281019190915260400160002054909301600201925b6001929092019161064d565b61017b6004356000805481908190819081908190819060ff161561115757610002565b6040805160e4356004818101356020818102808601820190965281855261017b95833595602480359660443596606435966084359660a4359660c4359693956101049501929182919085019084908082843750949650505050505050600080808080808d81148061076657508c801561076657508a8c12155b80610774575060028a60ff16105b80610788575087600160a060020a03166000145b8061079c575088600160a060020a03166000145b1561177157611760565b61017b600435600454620f42409081039082020481900361023e565b60408051600480358082013560208181028086018201909652818552610a23959394602494909385019291829190850190849080828437509496505093359350506044359150506064356040805160208181018352600080835283519182019093528281529091908190815b8851831015611cee576000600102600160005060008b8681518110156100025760209081029091018101518252810191909152604001600020541180156108c7575087600160a060020a0316600014806108c7575087600160a060020a0316600160005060008b868151811015610002576020908102909101810151825281019190915260400160002060050154600160a060020a0316145b8015610925575086600160a060020a031660001480610925575086600160a060020a0316600160005060008b868151811015610002576020908102909101810151825281019190915260400160002060040154600160a060020a0316145b8015610983575085600160a060020a031660001480610983575085600160a060020a0316600160005060008b868151811015610002576020908102909101810151825281019190915260400160002060010154600160a060020a0316145b156109bf57600160005060008a858151811015610002576020908102909101810151825281019190915260400160002060090154909301600c01925b6001929092019161082e565b6109f26004356000805433600160a060020a03908116610100909204161461234c57610002565b604080519115158252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050019250505060405180910390f35b610a7685610232565b92508285039150600083118015610b00575060008681526001602090815260408083206004908101548251855460e060020a63a9059cbb0282526101009004600160a060020a039081169382019390935260248101899052925191169363a9059cbb936044848101949193929183900301908290876161da5a03f115610002575050604051511590505b15610b0a57610002565b5060005b60008681526001602052604090206009015460ff82161015610bd35760406000908120908790526001602052600901805460ff831690811015610002576000918252604080516020808520909301547f475a9fa9000000000000000000000000000000000000000000000000000000008252600160a060020a03338116600484015260248301889052925192169363475a9fa993604483810194919391929183900301908290876161da5a03f1156100025750506040515115159050610bdf57610002565b50600195945050505050565b600101610b0e565b506000805474ffffffffffffffffffffffffffffffffffffffff0019166101008302179055600161023e565b6000848152600160209081526040808320600490810154825160e060020a63a9059cbb028152600160a060020a033381169382019390935260248101899052925191169363a9059cbb936044848101949193929183900301908290876161da5a03f1156100025750506040515115159050610c9557610002565b600101610250565b5060019392505050565b83604051805910610cad5750595b908082528060200260200182016040528015610cc4575b506000945084935090505b8551831015610f6557600091505b600160005060008785815181101561000257602090810290910181015182528101919091526040016000206009015460ff83161015610f7b57600060016000506000888681518110156100025760209081029091018101518252810191909152604001600020600901805460ff85169081101561000257906000526020600020900160009054906101000a9004600160a060020a0316600160a060020a03166370a08231896040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515191909111159050610f8757858381518110156100025790602001906020020151600190048185815181101561000257602090810290910101528551600190600090889086908110156100025760209081029091018101518252810191909152604001600020600901548151829060018701908110156100025760209081029091010152600091505b600160005060008785815181101561000257602090810290910181015182528101919091526040016000206009015460ff83161015610f6f5760016000506000878581518110156100025760209081029091018101518252810191909152604001600020600901805460ff84169081101561000257906000526020600020900160009054906101000a9004600160a060020a0316600160a060020a03166370a08231886040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f115610002575050604051518251909150829060ff8516870160020190811015610002576020908102909101015260019190910190610e49565b60019190910190610383565b9695505050505050565b6002820160ff16909301925b60019290920191610ccf565b60019190910190610cdd565b83604051805910610fa15750595b908082528060200260200182016040528015610fb8575b506000945084935091505b85518310156111125760006002600050600088868151811015610002576020908102909101810151825281019190915260400160002054111561114b578583815181101561000257906020019060200201516001900482858151811015610002576020908102909101015285516002906000908890869081101561000257602090810290910181015182528101919091526040016000205482518390600187019081101561000257602090810290910101525060005b600260005060008785815181101561000257602090810290910181015182528101919091526040016000205481101561111b5760026000506000878581518110156100025760209081029091018101518252810191909152604001600020805482908110156100025760009182526020909120015482518390868401600201908110156100025760209081029091010152600101611079565b50949350505050565b60026000506000878581518110156100025750506020858102890181015182528290526040902054909401909301925b60019290920191610fc3565b6000805460ff191660019081178255898252602052604090206007015460ff1615156112e85760406000818120600581015483516006909201547f5101770200000000000000000000000000000000000000000000000000000000835260048301529251600160a060020a0393909316926351017702926024838101936020939290839003909101908290876161da5a03f115610002575050604051511515905061120457611338611347565b6000888152600160209081526040808320815160058201546006909201547f5d1a3b8200000000000000000000000000000000000000000000000000000000825260048201529151600160a060020a039190911693635d1a3b82936024808501949193929183900301908290876161da5a03f1156100025750505060405180519060200150600160005060008a600019168152602001908152602001600020600050600801600050819055506001600160005060008a60001916815260200190815260200160002060005060070160006101000a81548160ff021916908302179055505b6000888152600160208190526040909120015460a060020a900460ff16156113535760406000908120908990526001602052600281015460089091015412156115435760009450611598565b8596505b505050505050919050565b6113345b6000805460ff19169055565b6000888152600160205260409020600981018054600890920154909181101561000257600091825260208083206040805193909101547f70a08231000000000000000000000000000000000000000000000000000000008452600160a060020a03338116600486015291519116936370a082319360248181019493929183900301908290876161da5a03f115610002575050604051519650505b600091505b60008881526001602052604090206009015460ff831610156116d65760406000908120908990526001602052600901805460ff84169081101561000257906000526020600020900160009054906101000a9004600160a060020a0316600160a060020a03166370a08231336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f115610002575050604080515160008b81526001602052919091206009018054919350915060ff84169081101561000257906000526020600020900160009054906101000a9004600160a060020a0316600160a060020a031663721a37d233836040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511515905061175057610002565b60008881526001602052604090206003810154600890910154131561156c576127109450611598565b600088815260016020526040902060028101546003820154600890920154918190039103612710020594505b6000888152600160208190526040909120600901805461271088810361ffff16975087810396509286929181101561000257906000526020600020900160009054906101000a9004600160a060020a0316600160a060020a03166370a08231336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f115610002575050604080515160008d815260016020529182206009018054919094029389935091908110156100025790815260208120909054906101000a9004600160a060020a0316600160a060020a03166370a08231336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750505060405180519060200150020104955085506113ed565b6000888152600160209081526040808320600490810154825160e060020a63a9059cbb028152600160a060020a0333811693820193909352602481018c9052925191169363a9059cbb936044848101949193929183900301908290876161da5a03f115610002575050604051511515905061134357610002565b600191909101906113f2565b8495505b505050505098975050505050505050565b8d8d8d8d8d8d8d8d604051808960001916815260200188151560f860020a0281526001018781526020018681526020018560ff1660f860020a02815260010184600160a060020a03166c0100000000000000000000000002815260140183600160a060020a03166c010000000000000000000000000281526014018280519060200190602002808383829060006004602084601f0104600302600f01f1509050019850505050505050505060405180910390209450600060010260016000506000876000191681526020019081526020016000206000506000016000505460001916111561185e57611760565b87600160a060020a031663c91d7e9c886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f150905001925050506040604051808303816000876161da5a03f1156100025750506040518051602091909101519095509350506000841180156119bd575082600160a060020a03166323b872dd3330876040518460e060020a0281526004018084600160a060020a0316815260200183600160a060020a0316815260200182815260200193505050506020604051808303816000876161da5a03f11561000257505060405151159050806119bd575082600160a060020a031663095ea7b389866040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511590505b156119c757610002565b87600160a060020a031663c1b06513886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f150905001925050506020604051808303816000876161da5a03f115610002575050604051519250506000821415611a5257610002565b60008e81526002602052604090208054600181018083558281838015829011611a9e57818360005260206000209182019101611a9e91905b80821115611c975760008155600101611a8a565b50505091909060005260206000209001600087909190915055508d60016000506000876000191681526020019081526020016000206000506000016000508190555087600160005060008760001916815260200190815260200160002060005060050160006101000a815481600160a060020a0302191690830217905550816001600050600087600019168152602001908152602001600020600050600601600050819055508c600160005060008760001916815260200190815260200160002060005060010160146101000a81548160ff021916908302179055508b6001600050600087600019168152602001908152602001600020600050600201600050819055508a60016000506000876000191681526020019081526020016000206000506003016000508190555088600160005060008760001916815260200190815260200160002060005060040160006101000a815481600160a060020a030219169083021790555033600160005060008760001916815260200190815260200160002060005060010160006101000a815481600160a060020a0302191690830217905550600090505b8960ff168160ff16101561175c57600085815260016020819052604090912060090180549182018082559091908281838015829011611c9b57600083815260209020611c9b918101908301611a8a565b5090565b5050509190906000526020600020900160006040516104368061236c833901809050604051809103906000f0825473ffffffffffffffffffffffffffffffffffffffff1916179091555050600101611c47565b83604051805910611cfc5750595b908082528060200260200182016040528015611d13575b506000945084935091505b8851831015611fa2576000600102600160005060008b868151811015610002576020908102909101810151825281019190915260400160002054118015611db7575087600160a060020a031660001480611db7575087600160a060020a0316600160005060008b868151811015610002576020908102909101810151825281019190915260400160002060050154600160a060020a0316145b8015611e15575086600160a060020a031660001480611e15575086600160a060020a0316600160005060008b868151811015610002576020908102909101810151825281019190915260400160002060040154600160a060020a0316145b8015611e73575085600160a060020a031660001480611e73575085600160a060020a0316600160005060008b868151811015610002576020908102909101810151825281019190915260400160002060010154600160a060020a0316145b15611fe5578883815181101561000257906020019060200201516001900482858151811015610002576020908102909101015288516001906000908b908690811015610002576020908102909101810151825281019190915260400160002054825183906001870190811015610002576020908102909101015288516001906000908b9086908110156100025760209081029091018101518252810191909152604001600020600101548251600160a060020a03919091169083906002870190811015610002576020908102909101015288516001906000908b90869081101561000257602090810290910181015182528101919091526040016000206001015460a060020a900460ff1615611ff157600182856003018151811015610002576020908102909101015261200c565b50979650505050505050565b600160005060008a858151811015610002576020908102909101810151825281019190915260400160002060090154909301600c01925b60019290920191611d1e565b60008285600301815181101561000257602090810290910101525b600160005060008a858151811015610002576020908102909101810151825281019190915260400160002060020154825183906004870190811015610002576020908102909101015288516001906000908b908690811015610002576020908102909101810151825281019190915260400160002060030154825183906005870190811015610002576020908102909101015288516001906000908b9086908110156100025760209081029091018101518252810191909152604001600020600401548251600160a060020a03919091169083906006870190811015610002576020908102909101015288516001906000908b9086908110156100025760209081029091018101518252810191909152604001600020600501548251600160a060020a03919091169083906007870190811015610002576020908102909101015288516001906000908b908690811015610002576020908102909101810151825281019190915260400160002060060154825183906008870190811015610002576020908102909101015288516001906000908b90869081101561000257602090810290910181015182528101919091526040016000206007015460ff16156121ee576001828560090181518110156100025760209081029091010152612209565b60008285600901815181101561000257602090810290910101525b600160005060008a85815181101561000257602090810290910181015182528101919091526040016000206008015482518390600a870190811015610002576020908102909101015288516001906000908b90869081101561000257602090810290910181015182528101919091526040016000206009015482518390600b87019081101561000257602090810290910101525060005b600160005060008a858151811015610002576020908102909101810151825281019190915260400160002060090154811015611fae57600160005060008a858151811015610002576020908102909101810151825281019190915260400160002060090180548290811015610002576000918252602090912001548251600160a060020a0391909116908390868401600c019081101561000257602090810290910101526001016122a0565b620f424082101561236457506004819055600161023e565b50600061023e56606060405260008054600160a060020a03191633179055610412806100246000396000f36060604052361561008d5760e060020a600035046306fdde03811461008f578063095ea7b3146100a557806318160ddd1461012457806323b872dd1461012f578063313ce567146101dc578063475a9fa9146101f057806370a0823114610215578063721a37d21461024357806395d89b411461008f578063a9059cbb14610268578063dd62ed3e146102e7575b005b61031d6040805160208101909152600081525b90565b61038b60043560243560007319ee743d2e356d5f0e4d97cc09b96d06e933d0db63c6605267600160005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506103179050565b6102316003546100a2565b61038b60043560243560443560008054604080517fa00bfa1100000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a038781166024830152868116604483015260648201869052929092166084830152517319ee743d2e356d5f0e4d97cc09b96d06e933d0db9163a00bfa119160a482810192602092919082900301818660325a03f4156100025750506040515195945050505050565b604080516000815290519081900360200190f35b61038b6004356024356000805433600160a060020a0390811691161461039f57610002565b600160a060020a03600435166000908152600160205260409020545b60408051918252519081900360200190f35b61038b6004356024356000805433600160a060020a039081169116146103ce57610002565b61038b60043560243560007319ee743d2e356d5f0e4d97cc09b96d06e933d0db6388d5fecb600160005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506103179050565b610231600435602435600160a060020a038281166000908152600260209081526040808320938516835292905220545b92915050565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561037d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080519115158252519081900360200190f35b50600160a060020a03821660009081526001602081905260409091208054830190556003805483019055610317565b600160a060020a038316600090815260016020526040902054821161040a57506040600020805482900390556003805482900390556001610317565b50600061031756", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000950ca4a06c78934a148b7a3ff3ea8fc366f77a0600", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x00000000000000000000000000000000000000000000000000000000000007d0", + "0x6b8ad191d0fa8204d4eafca22ce4ec42425fde2eecf25ce484ecc76765b9a937": "0x00000000000000000000000001e60b511fced1eb2b5b40991eb1dfd171a6df42", + "0x6b8ad191d0fa8204d4eafca22ce4ec42425fde2eecf25ce484ecc76765b9a938": "0x000000000000000000000000f4cbd7e037b80c2e67b80512d482685f15b1fb28", + "0x71dbd1e5cfc57324881ede454ea48ef3502c5c0b0454ccd622624a7061c2e854": "0x446374989d279847d0dbc6708a9c76a419fe9831d42c78bc89473f559a00d915", + "0x71dbd1e5cfc57324881ede454ea48ef3502c5c0b0454ccd622624a7061c2e855": "0x00000000000000000000000061d76c05cd2aa9ed5135e21e52fff188b02089d4", + "0x71dbd1e5cfc57324881ede454ea48ef3502c5c0b0454ccd622624a7061c2e856": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x71dbd1e5cfc57324881ede454ea48ef3502c5c0b0454ccd622624a7061c2e857": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x71dbd1e5cfc57324881ede454ea48ef3502c5c0b0454ccd622624a7061c2e858": "0x00000000000000000000000092f1dbea03ce08225e31e95cc926ddbe0198e6f2", + "0x71dbd1e5cfc57324881ede454ea48ef3502c5c0b0454ccd622624a7061c2e859": "0x000000000000000000000000529c4cb814029b8bb32acb516ea3a4b07fdae350", + "0x71dbd1e5cfc57324881ede454ea48ef3502c5c0b0454ccd622624a7061c2e85a": "0x846fd373887ade3ab7703750294876afa61cf56303f5f014a4d80d04f508a1f1", + "0x71dbd1e5cfc57324881ede454ea48ef3502c5c0b0454ccd622624a7061c2e85b": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x71dbd1e5cfc57324881ede454ea48ef3502c5c0b0454ccd622624a7061c2e85c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x71dbd1e5cfc57324881ede454ea48ef3502c5c0b0454ccd622624a7061c2e85d": "0x0000000000000000000000000000000000000000000000000000000000000002" + } + }, + "0x61c808d82a3ac53231750dadc13c777b59310bd9": { + "balance": "0x90a7af5d4755984561", + "nonce": "197408" + }, + "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5": { + "balance": "0x0", + "code": "0x606060405236156100a35760e060020a6000350463031d973e81146100a557806316181bb7146100da5780635aa97eeb146103b1578063674cc1f5146104f75780636da84ec0146105d7578063929e626e146105fe578063a0bde7e8146106ac578063bbd4f8541461078b578063c1fd43391461098e578063c3c95c7b14610a88578063db833e3a14610afe578063df6c13c314610cfe578063ebb7119414610d13575b005b610d4960043560008181526020819052604081206004015481908390600160a060020a039081163390911614610dcb57610002565b610d0160043560243560443560643560008481526020819052604080822054815160e160020a63460b97d1028152600481018290529151909183918291829182916000805160206123dd83398151915291638c172fa29160248181019261016092909190829003018187876161da5a03f1156100025750506040805160a081015160c08201517fc51cf179000000000000000000000000000000000000000000000000000000008352600483018d90529251909750919550600160a060020a038616926323b872dd92339230929163c51cf1799160248181019260209290919082900301818b876161da5a03f11561000257505060408051805160e060020a6323b872dd028252600160a060020a039586166004830152939094166024850152918d01604484015250516064828101926020929190829003018187876161da5a03f11561000257505060405151159050806102e8575082600160a060020a031663095ea7b36000805160206123dd8339815191526000805160206123dd833981519152600160a060020a031663c51cf1798c6040518260e060020a028152600401808281526020019150506020604051808303816000876161da5a03f11561000257505060408051805160e060020a63095ea7b30282526004820193909352918d0160248301525160448281019350602092829003018187876161da5a03f115610002575050604051511590505b806103a757506000805160206123dd833981519152600160a060020a03166307d5b826866000805160206123dd833981519152600160a060020a031663c51cf1798c6040518260e060020a028152600401808281526020019150506020604051808303816000876161da5a03f11561000257505060408051805160e160020a6303eadc130282526004820194909452928d016024840152516044838101936020935082900301816000876161da5a03f115610002575050604051511590505b15610fcd57610002565b60408051600480358082013560208181028086018201909652818552610d5d9593946024949093850192918291908501908490808284375094965050933593505050506040805160208181018352600080835283519182019093528281529091908190815b86518310156112c757600060010260006000506000898681518110156100025760209081029091018101518252810191909152604001600020541180156104af575085600160a060020a0316600014806104af575085600160a060020a03166000600050600089868151811015610002576020908102909101810151825281019190915260400160002060040154600160a060020a0316145b156104eb576000600050600088858151811015610002576020908102909101810151825281019190915260400160002060070154909301600901925b60019290920191610416565b60408051600480358082013560208181028086018201909652818552610d5d959394602494909385019291829190850190849080828437509496505050505050506040805160208181018352600080835283519182019093528281529091908190815b8551831015611713576000600160005060008886815181101561000257602090810290910181015182528101919091526040016000205411156105cb576001600050600087858151811015610002576020908102909101810151825281019190915260400160002054909301600201925b6001929092019161055a565b610d016004356024355b60009182526020829052604090912060010154620f424091020490565b610da760043561200060405190810160405280610100905b6000815260200190600190039081610616575050604080516120008101909152610100815b600081526020019060019003908161063b5750600090505b60008481526020819052604090206007015460ff821610156118d8576040600020600701805460ff8316908110156100025760009182526020909120810154908390610100811015610002576020020152600101610653565b610d5d600435604080516020818101835260008083528351808301855281815285825291819052835193812060070154929391929091600191909101908059106106f35750595b90808252806020026020018201604052801561070a575b509150428260008151811015610002576020919091019190915290505b60008481526020819052604090206007015460ff821610156118d8576040600020600701805460ff83169081101561000257906000526020600020900160005054828260010160ff1681518110156100025760209081029091010152600101610727565b610d0160043560243560443560643560008481526020819052604080822054815160e160020a63460b97d102815260048101919091529051829182918291829182916000805160206123dd83398151915291638c172fa29160248181019261016092909190829003018187876161da5a03f1156100025750505060405180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200150505050509a50505050505050600060005060008b60001916815260200190815260200160002060005060050160009054906101000a9004600160a060020a0316600160a060020a0316630439978d8b600060005060008e60001916815260200190815260200160002060005060030160005054600060005060008f6000191681526020019081526020016000206000506007016000508d8d6040518660e060020a0281526004018086600019168152602001858152602001806020018460ff168152602001838152602001828103825285818154815260200191508054801561095657602002820191906000526020600020905b81600050548152602001906001019080831161093f575b505096505050505050506020604051808303816000876161da5a03f1156100025750506040515194505060008414156118e357610fc0565b610d01600435602435604435606435600060006000600060006000805160206123dd833981519152600160a060020a0316638c172fa28a6040518260e060020a0281526004018082600019168152602001915050610160604051808303816000876161da5a03f1156100025750506040805160a081015160c08201518d83526c01000000000000000000000000600160a060020a033381168202602086810191909152908d16909102603485015284516048948190039490940190932080875292869052928520600301549097509195509350821415905080610a7357506207a12088115b80610a7e5750836000145b15611cc857611cbc565b60048035600090815260208181526040918290206002810154815484516001840154600385015497850154600586015460069096015493835295820152808601929092526060820195909552600160a060020a039283166080820152911660a082015260c0810192909252519081900360e00190f35b610d0160043560243560443560643560008481526020819052604080822054815160e160020a63460b97d10281526004810191909152905182918291829182916000805160206123dd83398151915291638c172fa291602482810192610160929190829003018187876161da5a03f1156100025750505060405180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200180519060200150505050509950505050505050600060005060008a60001916815260200190815260200160002060005060050160009054906101000a9004600160a060020a0316600160a060020a031663f47cd6718a600060005060008d60001916815260200190815260200160002060005060030160005054600060005060008e6000191681526020019081526020016000206000506007016000508c8c6040518660e060020a0281526004018086600019168152602001858152602001806020018460ff1681526020018381526020018281038252858181548152602001915080548015610cc657602002820191906000526020600020905b816000505481526020019060010190808311610caf575b505096505050505050506020604051808303816000876161da5a03f11561000257505060405151935050600083141561201957611cbc565b60005b60408051918252519081900360200190f35b610d0160043560008181526020819052604081206004015481908190849033600160a060020a039081169116146122df57610002565b604080519115158252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050019250505060405180910390f35b6040518082612000808381846000600461030ff15090500191505060405180910390f35b600091505b60008481526020819052604090206007015460ff83161015610eed576040600081812086825260208281528351915460e260020a6307c30783028352600483015260ff8616602483015292516000805160206123dd83398151915293631f0c1e0c9360448481019492939283900301908290876161da5a03f115610002575050604080515160008781526020819052919091206007018054600160a060020a0392909216925063a9059cbb9133919060ff871690811015610002579060005260206000209001600050546040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f1156100025750506040515115159050610f7357610002565b60406000908120602082815282825560018201839055600282018390556003820183905560048201805473ffffffffffffffffffffffffffffffffffffffff19908116909155600583018054909116905560068201839055600782018054848255908452908320919291610fa7918101905b80821115610fb45760008155600101610f5f565b6000848152602081905260408120600701805460ff8516908110156100025790825260208220015560019190910190610dd0565b5060019695505050505050565b5090565b818385010195505b5050505050949350505050565b6040805160e260020a6307c307830281526004810187905260ff8b16602482015290516000805160206123dd83398151915291631f0c1e0c91604482810192602092919082900301816000876161da5a03f11561000257505060408051805160e060020a63095ea7b302825230600160a060020a039081166004840152602483018d905292519216925063095ea7b391604482810192602092919082900301816000876161da5a03f115610002575050604051511515905061108e57610002565b604080517fdb833e3a000000000000000000000000000000000000000000000000000000008152600481018c905260ff8b166024820152604481018a905260648101899052905130600160a060020a03169163db833e3a91608482810192602092919082900301816000876161da5a03f11561000257505060405151925050600082141561111b57610002565b5060005b838160ff1610156111f75760ff808a169082161461125b576040805160e260020a6307c307830281526004810187905260ff8316602482015290516000805160206123dd83398151915291631f0c1e0c91604482810192602092919082900301816000876161da5a03f11561000257505060408051805160e060020a63a9059cbb028252600160a060020a033381166004840152602483018d905292519216925063a9059cbb91604482810192602092919082900301816000876161da5a03f115610002575050604051511515905061125b57610002565b82600160a060020a031663a9059cbb33846040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511515905061126357610002565b60010161111f565b816000805160206123dd833981519152600160a060020a031663c51cf1798a6040518260e060020a028152600401808281526020019150506020604051808303816000876161da5a03f115610002575050604051518a01919091039650610fc09050565b836040518059106112d55750595b9080825280602002602001820160405280156112ec575b506000945084935091505b86518310156116c65760006001026000600050600089868151811015610002576020908102909101810151825281019190915260400160002054118015611390575085600160a060020a031660001480611390575085600160a060020a03166000600050600089868151811015610002576020908102909101810151825281019190915260400160002060040154600160a060020a0316145b1561170757868381518110156100025790602001906020020151600190048285815181101561000257602090810290910101528651600090819089908690811015610002576020908102909101810151825281019190915260400160002054825183906001870190811015610002576020908102909101015286516000908190899086908110156100025760209081029091018101518252810191909152604001600020600101548251839060028701908110156100025760209081029091010152865160009081908990869081101561000257602090810290910181015182528101919091526040016000206002015482518390600387019081101561000257602090810290910101528651600090819089908690811015610002576020908102909101810151825281019190915260400160002060030154825183906004870190811015610002576020908102909101015286516000908190899086908110156100025760209081029091018101518252810191909152604001600020600401548251600160a060020a03919091169083906005870190811015610002576020908102909101015286516000908190899086908110156100025760209081029091018101518252810191909152604001600020600501548251600160a060020a03919091169083906006870190811015610002576020908102909101015286516000908190899086908110156100025760209081029091018101518252810191909152604001600020600601548251839060078701908110156100025760209081029091010152865160009081908990869081101561000257602090810290910181015182528101919091526040016000206007015482518390600887019081101561000257602090810290910101525060005b60006000506000888581518110156100025760209081029091018101518252810191909152604001600020600701548110156116d0576000600050600088858151811015610002576020908102909101810151825281019190915260400160002060070180548290811015610002579060005260206000209001600050548282866009010181518110156100025760209081029091010152600101611626565b5095945050505050565b6000600050600088858151811015610002576020908102909101810151825281019190915260400160002060070154909301600901925b600192909201916112f7565b836040518059106117215750595b908082528060200260200182016040528015611738575b506000945084935091505b8551831015611892576000600160005060008886815181101561000257602090810290910181015182528101919091526040016000205411156118cc578583815181101561000257906020019060200201516001900482858151811015610002576020908102909101015285516001906000908890869081101561000257602090810290910181015182528101919091526040016000205482518390600187019081101561000257602090810290910101525060005b600160005060008785815181101561000257602090810290910181015182528101919091526040016000205481101561189b57600160005060008785815181101561000257602090810290910181015182528101919091526040016000208054829081101561000257600091825260209091200154825183908684016002019081101561000257602090810290910101526001016117f9565b50949350505050565b6001600050600087858151811015610002575050602085810289018101518252919091526040902054909301600201925b60019290920191611743565b8192505b5050919050565b6118ed8a856105e1565b92506000805160206123dd833981519152600160a060020a031663c51cf179896040518260e060020a028152600401808281526020019150506020604051808303816000876161da5a03f1156100025750506040515192505083830182018790111561195857610fc0565b84600160a060020a03166323b872dd333085878901016040518460e060020a0281526004018084600160a060020a0316815260200183600160a060020a0316815260200182815260200193505050506020604051808303816000876161da5a03f1156100025750506040515115905080611a3557506040805160e060020a63095ea7b30281526000805160206123dd833981519152600482015285840160248201529051600160a060020a0387169163095ea7b391604482810192602092919082900301816000876161da5a03f115610002575050604051511590505b80611aa9575060008a81526020818152604080832054815160e160020a6303eadc130281526004810191909152878601602482015290516000805160206123dd833981519152936307d5b826936044848101949193929183900301908290876161da5a03f115610002575050604051511590505b15611ab357610002565b5060005b60008a81526020819052604090206007015460ff82161015611b06576040600020600701805485919060ff84169081101561000257600091825260209091200180549091019055600101611ab7565b604060009081208b8252602091909152600701805460ff8b169081101561000257600091825260209091200154881115611b3f57610002565b60008a815260208190526040902060028101805485019055600701805489919060ff8c1690811015610002579060005260206000209001600050805491909103905560008a81526020818152604080832054815160e260020a6307c30783028152600481019190915260ff8d16602482015290516000805160206123dd83398151915293631f0c1e0c936044848101949193929183900301908290876161da5a03f11561000257505060408051805160e060020a63a9059cbb028252600160a060020a033381166004840152602483018d905292519216925063a9059cbb91604482810192602092919082900301816000876161da5a03f1156100025750506040515115159050610fb857610002565b505050600092835250602080832090910184905583825281905260409020600181018990556003810188905589815560048101805473ffffffffffffffffffffffffffffffffffffffff199081163317909155600582018054909116881790554360069091015590935083905b50505050949350505050565b82600160a060020a03166323b872dd33306000805160206123dd833981519152600160a060020a031663c51cf1798c6040518260e060020a028152600401808281526020019150506020604051808303816000876161da5a03f11561000257505060408051805160e060020a6323b872dd028252600160a060020a039586166004830152939094166024850152918c0160448401525051606482810192602092919082900301816000876161da5a03f1156100025750506040515115905080611e45575082600160a060020a031663095ea7b36000805160206123dd8339815191526000805160206123dd833981519152600160a060020a031663c51cf1798b6040518260e060020a028152600401808281526020019150506020604051808303816000876161da5a03f11561000257505060408051805160e060020a63095ea7b30282526004820193909352918c016024830152516044828101935060209282900301816000876161da5a03f115610002575050604051511590505b80611f0457506000805160206123dd833981519152600160a060020a03166307d5b8268a6000805160206123dd833981519152600160a060020a031663c51cf1798b6040518260e060020a028152600401808281526020019150506020604051808303816000876161da5a03f11561000257505060408051805160e160020a6303eadc130282526004820194909452928c016024840152516044838101936020935082900301816000876161da5a03f115610002575050604051511590505b15611f0e57610002565b83604051805910611f1c5750595b908082528060200260200182016040528015611f33575b506000838152602081815260408220600701805484518083558285529383902091949082019392018215611f86579160200282015b82811115611f86578251826000505591602001919060010190611f68565b50611f92929150610f5f565b5050600090505b838160ff161015611fda576000828152602081905260409020600701805488919060ff84169081101561000257600091825260209091200155600101611f99565b600089815260016020819052604090912080549182018082559091908281838015829011611c4f57600083815260209020611c4f918101908301610f5f565b61202389846105e1565b915085828403101561203457611cbc565b60008981526020818152604080832054815160e260020a6307c30783028152600481019190915260ff8c16602482015290516000805160206123dd83398151915293631f0c1e0c936044848101949193929183900301908290876161da5a03f11561000257505060408051805160e060020a6323b872dd028252600160a060020a0333811660048401523081166024840152604483018c90529251921692506323b872dd91606482810192602092919082900301816000876161da5a03f115610002575050604051511590508061218d57506000805160206123dd833981519152600160a060020a0316634025b293600060005060008c60001916815260200190815260200160002060005060000160005054856040518360e060020a0281526004018083600019168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511590505b1561219757610002565b6000898152602081905260409020600701805488919060ff8b16908110156100025760009182526020822001805490920190915590505b60008981526020819052604090206007015460ff82161015612254576040600020600701805484919060ff84169081101561000257600091825260209091200154106122d0576000898152602081905260409020600701805484919060ff84169081101561000257906000526020600020900160005080549190910390556001016121ce565b600089815260208181526040808320600201805486019055805160e060020a63a9059cbb028152600160a060020a033381166004830152868803602483015291519188169363a9059cbb93604483810194919391929183900301908290876161da5a03f11561000257505060405151151590506122d557610002565b610002565b8183039450611cbc565b60008581526020819052604080822054815160e160020a63460b97d1028152600481019190915290516000805160206123dd83398151915292638c172fa292602481810193610160939092839003909101908290876161da5a03f1156100025750506040805160c001516000888152602081905291822060020180549083905590955093508311905080156123ca575082600160a060020a031663a9059cbb33846040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511590505b156123d457610002565b819350506118dc560000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd", + "storage": { + "0x50ff25f5e9a51687bca1c50f3544d5eef8202f228d3de791691a137aecb6b360": "0x00000000000000000000000000000000000000000000000026566ea1ec2f6a9b", + "0x50ff25f5e9a51687bca1c50f3544d5eef8202f228d3de791691a137aecb6b361": "0x00000000000000000000000000000000000000000000000072aa5b7e04d56a9b", + "0x642f3c12d3cd25d9b946d8c2ec97f080f4efcff18301a6dcade5a6be0c5ed86c": "0xd9a4ffe21d19763887176173d08241e8393c1dfd208f29193dfecdf854b664ac", + "0x642f3c12d3cd25d9b946d8c2ec97f080f4efcff18301a6dcade5a6be0c5ed86d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x642f3c12d3cd25d9b946d8c2ec97f080f4efcff18301a6dcade5a6be0c5ed86e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x642f3c12d3cd25d9b946d8c2ec97f080f4efcff18301a6dcade5a6be0c5ed86f": "0x0000000000000000000000000000000000000000000000004563918244f40000", + "0x642f3c12d3cd25d9b946d8c2ec97f080f4efcff18301a6dcade5a6be0c5ed871": "0x0000000000000000000000008695e5e79dab06fbbb05f445316fa4edb0da30f0", + "0x642f3c12d3cd25d9b946d8c2ec97f080f4efcff18301a6dcade5a6be0c5ed873": "0x0000000000000000000000000000000000000000000000000000000000000002" + } + }, + "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0": { + "balance": "0x0", + "code": "0x606060405260e060020a60003504630439978d811461003157806308f028d514610115578063f47cd6711461026e575b005b60408051604435600481810135602081810285810182019096528185526103509583359560248035966064959294910192829185019084908082843750949650509335935050608435915050600060006040604051908101604052806002905b60008152602001906001900390816100915790505060006000600061271073ef3487d24a0702703e04a26cef479e313c8fc7ae6324d4e90a604060020a8c51026040518260e060020a028152600401808281526020019150506020604051808303818660325a03f41561000257505060405151919091049550610398905089610157565b60408051600480358082013560208181028086018201909652818552610362959394602494909385019291829190850190849080828437509496505050505050505b6040604051908101604052806002905b6000815260200190600190039081610167575050604080518082019091526002815b600081526020019060019003908161018957905050600083600081518110156100025760209081029091010151825283518490600090811015610002576020908102909101810151908301525060005b83518160ff1610156104a7578351825190859060ff8416908110156100025790602001906020020151101561022357838160ff168151811015610002576020908102909101015182525b60208201518451859060ff8416908110156100025790602001906020020151111561026657838160ff168151811015610002576020908102909101810151908301525b6001016101d9565b60408051604435600481810135602081810285810182019096528185526103509583359560248035966064959294910192829185019084908082843750949650509335935050608435915050600060006040604051908101604052806002905b60008152602001906001900390816102ce579050506000600061271073ef3487d24a0702703e04a26cef479e313c8fc7ae6324d4e90a604060020a8b51026040518260e060020a028152600401808281526020019150506020604051808303818660325a03f415610002575050604051519190910494506104ae905088610157565b60408051918252519081900360200190f35b60408051908190839080838184600060046015f15090500191505060405180910390f35b8095505b505050505095945050505050565b935061044d85858b8d5b6000806127108304815b85518160ff16101561051d5773ef3487d24a0702703e04a26cef479e313c8fc7ae63872fb2b589848a6000909060200201518a8660ff1681518110156100025760209081029091010151038b600060200201518c600190906020020151030304026040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515190930192506001016103ac565b925086898960ff16815181101561000257602090810290910101805191909103905261047b85858b8d6103a2565b915050604060020a620186a0620186a28484036127108d0402020404868111156103865786955061038a565b5092915050565b6020810180518801905292506104c684848a8c6103a2565b915085888860ff16815181101561000257602090810290910101805190910190526104f384848a8c6103a2565b9050604060020a620186a06127108b04838503026201869e02040494505050505095945050505050565b87604060020a73ef3487d24a0702703e04a26cef479e313c8fc7ae6324d4e90a866040518260e060020a028152600401808281526020019150506020604051808303818660325a03f4156100025750506040515190910291909104999850505050505050505056" + }, + "0x92f1dbea03ce08225e31e95cc926ddbe0198e6f2": { + "balance": "0xa6e361612cc228000", + "code": "0x6060604052361561008d5760e060020a600035046306fdde03811461008f578063095ea7b3146100ed57806318160ddd1461016257806323b872dd1461016b578063313ce567146102565780636c11bcd31461026257806370a08231146102d057806395d89b41146102f5578063a9059cbb14610353578063d0febe4c146103f8578063dd62ed3e14610439575b005b6040805160038054602060026001831615610100026000190190921691909104601f810182900482028401820190945283835261046d939083018282801561052e5780601f106105035761010080835404028352916020019161052e565b61042560043560243533600160a060020a03908116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b6104db60025481565b610425600435602435604435600160a060020a0383166000908152602081905260408120548290108015906101be575060016020908152604080832033600160a060020a03168452909152812054829010155b80156101ca5750600082115b1561053657600160a060020a0383811660008181526020818152604080832080548801905588851680845281842080548990039055600183528184203390961684529482529182902080548790039055815186815291519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a350600161053a565b6104ed60055460ff1681565b61042560043533600160a060020a0316600090815260208190526040812054821161054157604081208054839003905560028054839003905580821180156102c6575060405133600160a060020a0316908290849082818181858883f19350505050155b1561054957610002565b6104db600435600160a060020a0381166000908152602081905260409020545b919050565b61046d6004805460408051602060026000196101006001871615020190941693909304601f8101849004840282018401909252818152929183018282801561052e5780601f106105035761010080835404028352916020019161052e565b61042560043560243533600160a060020a03166000908152602081905260408120548290108015906103855750600082115b156105515733600160a060020a0390811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a350600161015c565b33600160a060020a0316600090815260208190526040902080543490810190915560028054909101905560015b604080519115158252519081900360200190f35b6104db600435602435600160a060020a0382811660009081526001602090815260408083209385168352929052205461015c565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156104cd5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051918252519081900360200190f35b6040805160ff9092168252519081900360200190f35b820191906000526020600020905b81548152906001019060200180831161051157829003601f168201915b505050505081565b5060005b9392505050565b5060006102f0565b5060016102f0565b50600061015c56", + "storage": { + "0x3830062b39ca7888048a385f112e36aef7258a27d84eb6e31312c298e5954da3": "0x0000000000000000000000000000000000000000000000035fe3763f1973ab3b", + "0x527b1dd758d53f706730e0fb37a8de5c38d8b4cd17fbe1cfa285480a00f55bf4": "0x000000000000000000000000000000000000000000000003ab97b2fc29ad66c6", + "0x52cb6de4baff82acfb6977b64d52b9ac011f8af34631d933997b7649a84d716f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8f0cfa08792bcd3de052a3bb7bd54f8a62c44b02ba16ff336e9a881c348cca21": "0x000000000000000000000000000000000000000000046ba103abb9d1301f1b2e", + "0xa29249eda6f9f8d0c67b7a4f954f6ba7a9f1bb3f216b2fedc6db8def03c47746": "0x00000000000000000000000000000000000000000000000007a93ebd870d6684", + "0xbe1e23f4b08159a01ee61379749e9b484f5947aaeeb008ce7c97d1c56d3eeb8b": "0x0000000000000000000000000000000000000000000000000dfecc50c6f7d5cd" + } + }, + "0xef3487d24a0702703e04a26cef479e313c8fc7ae": { + "balance": "0x0", + "code": "0x6503060000000050606060405260e060020a600035046324d4e90a8114610031578063872fb2b514610078575b610007565b61013c6004356000680171547652b82fe177818080808061014e886000604060020a82048160bf605f5b6001830182146103c4578060020a8410156103ce579050806103d2565b61013c600435604060020a67b17217f7d1cf79ac81830281900482810460020a680100000016aee6e8ef67b172182739bc0e46858406908102869004673d7f78a624cfb9b582800288900490810288900491909101670e359bcfeb6e45319183028890049182028890040167027601df2fc048dc91830288900491820288900401665808a728816ee89183028890049182028890040166095dedef350bc991830288900491820297909704969096019190910182810295905b505050505050919050565b60408051918252519081900360200190f35b94508460020a88049350604060020a9250604060020a600a029150819050604060020a83680443b9c5adb08cc45f0204810390508050604060020a8484020492508250604060020a83680f0a52590f17c71a3f0204810190508050604060020a8484020492508250604060020a83682478f22e787502b0230204810390508050604060020a8484020492508250604060020a836848c6de1480526b8d4c0204810190508050604060020a8484020492508250604060020a836870c18cae824656408c0204810390508050604060020a8484020492508250604060020a8368883c81ec0ce7abebb20204810190508050604060020a8484020492508250604060020a836881814da94fe52ca9f50204810390508050604060020a8484020492508250604060020a8368616361924625d1acf50204810190508050604060020a8484020492508250604060020a836839f9a16fb9292a608d0204810390508050604060020a8484020492508250604060020a83681b3049a5740b21d65f0204810190508050604060020a8484020492508250604060020a836809ee1408bd5ad96f3e0204810390508050604060020a8484020492508250604060020a836802c465c91703b7a7f40204810190508050604060020a8484020492508250604060020a8367918d2d5f045a4d630204810390508050604060020a8484020492508250604060020a836714ca095145f44f780204810190508050604060020a8484020492508250604060020a836701d806fc412c1b990204810390508050604060020a8484020492508250604060020a836613950b4e1e89cc020481019050805085604060020a8383604060020a8902010302049650610131565b5090949350505050565b9150815b5060028282010461005b56" + }, + "0xf4cbd7e037b80c2e67b80512d482685f15b1fb28": { + "balance": "0x0", + "code": "0x6060604052361561008d5760e060020a600035046306fdde03811461008f578063095ea7b3146100a557806318160ddd1461012457806323b872dd1461012f578063313ce567146101dc578063475a9fa9146101f057806370a0823114610215578063721a37d21461024357806395d89b411461008f578063a9059cbb14610268578063dd62ed3e146102e7575b005b61031d6040805160208101909152600081525b90565b61038b60043560243560007319ee743d2e356d5f0e4d97cc09b96d06e933d0db63c6605267600160005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506103179050565b6102316003546100a2565b61038b60043560243560443560008054604080517fa00bfa1100000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a038781166024830152868116604483015260648201869052929092166084830152517319ee743d2e356d5f0e4d97cc09b96d06e933d0db9163a00bfa119160a482810192602092919082900301818660325a03f4156100025750506040515195945050505050565b604080516000815290519081900360200190f35b61038b6004356024356000805433600160a060020a0390811691161461039f57610002565b600160a060020a03600435166000908152600160205260409020545b60408051918252519081900360200190f35b61038b6004356024356000805433600160a060020a039081169116146103ce57610002565b61038b60043560243560007319ee743d2e356d5f0e4d97cc09b96d06e933d0db6388d5fecb600160005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506103179050565b610231600435602435600160a060020a038281166000908152600260209081526040808320938516835292905220545b92915050565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561037d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080519115158252519081900360200190f35b50600160a060020a03821660009081526001602081905260409091208054830190556003805483019055610317565b600160a060020a038316600090815260016020526040902054821161040a57506040600020805482900390556003805482900390556001610317565b50600061031756", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000012098a4651fb262f7", + "0xfae22198212900725daa5db635d1fda7b0fa195adaabdc806a7267959c3d8ae4": "0x000000000000000000000000000000000000000000000000731fb89f735062f7", + "0xfd73dc2251dc113619c6fcc1c142e797f06e77a178cc37fe300a56823b741ef7": "0x0000000000000000000000000000000000000000000000008ac7230489e80000" + } + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "2340153", + "difficulty": "80383973372327", + "timestamp": "1475034716", + "gasLimit": "1500062", + "miner": "0x61c808d82a3ac53231750dadc13c777b59310bd9" + }, + "input": "0xf8ea508504a817c80083084398946ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba580b884bbd4f854e9efd3ab89acad6a3edf9828c3b00ed1c4a74e974d05d32d3b2fb15aa16fc3770000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000080d29fa5cccfadac1ba0690ce7a4cf8590c636a1799ebf2cc52229714c47da72ee406fb9bd7d29e52440a017b6ce39e8876965afa2a1c579a592eb1af146506ccdbfc2c9ea422b13dca438", + "tracerConfig": { + "withLog": true + }, + "result": { + "from": "0x3de712784baf97260455ae25fb74f574ec9c1add", + "gas": "0x7e2c0", + "gasUsed": "0x27ec3", + "to": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "input": "0xbbd4f854e9efd3ab89acad6a3edf9828c3b00ed1c4a74e974d05d32d3b2fb15aa16fc3770000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000080d29fa5cccfadac", + "output": "0x00000000000000000000000000000000000000000000000080d29fa5cccfadac", + "calls": [ + { + "from": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "gas": "0x77e82", + "gasUsed": "0x54c", + "to": "0x5aae5c59d642e5fd45b427df6ed478b49d55fefd", + "input": "0x8c172fa2d9a4ffe21d19763887176173d08241e8393c1dfd208f29193dfecdf854b664ac", + "output": "0x446374989d279847d0dbc6708a9c76a419fe9831d42c78bc89473f559a00d91500000000000000000000000061d76c05cd2aa9ed5135e21e52fff188b02089d4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000092f1dbea03ce08225e31e95cc926ddbe0198e6f2000000000000000000000000529c4cb814029b8bb32acb516ea3a4b07fdae350846fd373887ade3ab7703750294876afa61cf56303f5f014a4d80d04f508a1f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "gas": "0x7737b", + "gasUsed": "0x3fe1", + "to": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", + "input": "0x0439978de9efd3ab89acad6a3edf9828c3b00ed1c4a74e974d05d32d3b2fb15aa16fc3770000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000026566ea1ec2f6a9b00000000000000000000000000000000000000000000000072aa5b7e04d56a9b", + "output": "0x0000000000000000000000000000000000000000000000008060b57e2e0c99aa", + "calls": [ + { + "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", + "gas": "0x770ef", + "gasUsed": "0xc24", + "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", + "input": "0x24d4e90a0000000000000000000000000000000000000000000000020000000000000000", + "output": "0x000000000000000000000000000000000000000000000000b17217f7d1cf79ab", + "type": "DELEGATECALL" + }, + { + "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", + "gas": "0x75eb2", + "gasUsed": "0x265", + "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", + "input": "0x872fb2b5000000000000000000000000000000000000000000000000c330b3f7006420b8", + "output": "0x00000000000000000000000000000000000000000000000224bf7df2c80f0878", + "type": "DELEGATECALL" + }, + { + "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", + "gas": "0x75aad", + "gasUsed": "0x25b", + "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", + "input": "0x872fb2b50000000000000000000000000000000000000000000000000000000000000000", + "output": "0x00000000000000000000000000000000000000000000000100000016aee6e8ef", + "type": "DELEGATECALL" + }, + { + "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", + "gas": "0x75737", + "gasUsed": "0xc24", + "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", + "input": "0x24d4e90a00000000000000000000000000000000000000000000000324bf7e0976f5f167", + "output": "0x0000000000000000000000000000000000000000000000012535c5e5f87ee0d2", + "type": "DELEGATECALL" + }, + { + "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", + "gas": "0x748c7", + "gasUsed": "0x265", + "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", + "input": "0x872fb2b5000000000000000000000000000000000000000000000000c330b3f7006420b8", + "output": "0x00000000000000000000000000000000000000000000000224bf7df2c80f0878", + "type": "DELEGATECALL" + }, + { + "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", + "gas": "0x744c2", + "gasUsed": "0x265", + "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", + "input": "0x872fb2b500000000000000000000000000000000000000000000000237d37fe5d297a500", + "output": "0x0000000000000000000000000000000000000000000000093088c407fcbbce38", + "type": "DELEGATECALL" + }, + { + "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", + "gas": "0x74142", + "gasUsed": "0xc99", + "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", + "input": "0x24d4e90a00000000000000000000000000000000000000000000000b554841fac4cad6b0", + "output": "0x0000000000000000000000000000000000000000000000026d7fc130d6a74cbe", + "type": "DELEGATECALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "gas": "0x731be", + "gasUsed": "0x241", + "to": "0x5aae5c59d642e5fd45b427df6ed478b49d55fefd", + "input": "0xc51cf179000000000000000000000000000000000000000000000000de0b6b3a76400000", + "output": "0x0000000000000000000000000000000000000000000000000071ea279ec31402", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "gas": "0x72df4", + "gasUsed": "0x468b", + "to": "0x92f1dbea03ce08225e31e95cc926ddbe0198e6f2", + "input": "0x23b872dd0000000000000000000000003de712784baf97260455ae25fb74f574ec9c1add0000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba500000000000000000000000000000000000000000000000080d29fa5cccfadac", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x92f1dbea03ce08225e31e95cc926ddbe0198e6f2", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000003de712784baf97260455ae25fb74f574ec9c1add", + "0x0000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5" + ], + "data": "0x00000000000000000000000000000000000000000000000080d29fa5cccfadac" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "gas": "0x6e627", + "gasUsed": "0x56d6", + "to": "0x92f1dbea03ce08225e31e95cc926ddbe0198e6f2", + "input": "0x095ea7b30000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd00000000000000000000000000000000000000000000000080d29fa5cccfadac", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x92f1dbea03ce08225e31e95cc926ddbe0198e6f2", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x0000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "0x0000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd" + ], + "data": "0x00000000000000000000000000000000000000000000000080d29fa5cccfadac" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "gas": "0x68dae", + "gasUsed": "0xd6f0", + "to": "0x5aae5c59d642e5fd45b427df6ed478b49d55fefd", + "input": "0x07d5b826d9a4ffe21d19763887176173d08241e8393c1dfd208f29193dfecdf854b664ac00000000000000000000000000000000000000000000000080d29fa5cccfadac", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0x5aae5c59d642e5fd45b427df6ed478b49d55fefd", + "gas": "0x629ff", + "gasUsed": "0x468b", + "to": "0x92f1dbea03ce08225e31e95cc926ddbe0198e6f2", + "input": "0x23b872dd0000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba50000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd00000000000000000000000000000000000000000000000080d29fa5cccfadac", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x92f1dbea03ce08225e31e95cc926ddbe0198e6f2", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "0x0000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd" + ], + "data": "0x00000000000000000000000000000000000000000000000080d29fa5cccfadac" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x5aae5c59d642e5fd45b427df6ed478b49d55fefd", + "gas": "0x5e0df", + "gasUsed": "0x31af", + "to": "0x92f1dbea03ce08225e31e95cc926ddbe0198e6f2", + "input": "0xa9059cbb000000000000000000000000950ca4a06c78934a148b7a3ff3ea8fc366f77a060000000000000000000000000000000000000000000000000041f50e27d56848", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x92f1dbea03ce08225e31e95cc926ddbe0198e6f2", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd", + "0x000000000000000000000000950ca4a06c78934a148b7a3ff3ea8fc366f77a06" + ], + "data": "0x0000000000000000000000000000000000000000000000000041f50e27d56848" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x5aae5c59d642e5fd45b427df6ed478b49d55fefd", + "gas": "0x5ac6b", + "gasUsed": "0x29ae", + "to": "0x01e60b511fced1eb2b5b40991eb1dfd171a6df42", + "input": "0x475a9fa90000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba50000000000000000000000000000000000000000000000008090aa97a4fa4564", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x5aae5c59d642e5fd45b427df6ed478b49d55fefd", + "gas": "0x57fed", + "gasUsed": "0x29ae", + "to": "0xf4cbd7e037b80c2e67b80512d482685f15b1fb28", + "input": "0x475a9fa90000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba50000000000000000000000000000000000000000000000008090aa97a4fa4564", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "gas": "0x56030", + "gasUsed": "0x265", + "to": "0x5aae5c59d642e5fd45b427df6ed478b49d55fefd", + "input": "0x1f0c1e0cd9a4ffe21d19763887176173d08241e8393c1dfd208f29193dfecdf854b664ac0000000000000000000000000000000000000000000000000000000000000001", + "output": "0x000000000000000000000000f4cbd7e037b80c2e67b80512d482685f15b1fb28", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "gas": "0x55cc3", + "gasUsed": "0x339f", + "to": "0xf4cbd7e037b80c2e67b80512d482685f15b1fb28", + "input": "0xa9059cbb0000000000000000000000003de712784baf97260455ae25fb74f574ec9c1add000000000000000000000000000000000000000000000000de0b6b3a76400000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0xf4cbd7e037b80c2e67b80512d482685f15b1fb28", + "gas": "0x55a8a", + "gasUsed": "0x30f7", + "to": "0x19ee743d2e356d5f0e4d97cc09b96d06e933d0db", + "input": "0x88d5fecb00000000000000000000000000000000000000000000000000000000000000010000000000000000000000003de712784baf97260455ae25fb74f574ec9c1add000000000000000000000000000000000000000000000000de0b6b3a76400000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0xf4cbd7e037b80c2e67b80512d482685f15b1fb28", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", + "0x0000000000000000000000003de712784baf97260455ae25fb74f574ec9c1add" + ], + "data": "0x000000000000000000000000000000000000000000000000de0b6b3a76400000" + } + ], + "type": "DELEGATECALL" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json new file mode 100644 index 000000000000..649a5b1b566d --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json @@ -0,0 +1,2295 @@ +{ + "genesis": { + "difficulty": "59917798787272", + "extraData": "0xe4b883e5bda9e7a59ee4bb99e9b1bc", + "gasLimit": "4712380", + "hash": "0xae82afe3630b001a34ad4c51695dacb17872ebee4dadd2de88b1a16671871da4", + "miner": "0x61c808d82a3ac53231750dadc13c777b59310bd9", + "mixHash": "0x23c2289cdee8a397cf36db9ffa3419503bed54eb09e988b3c7a3587a090e6fc1", + "nonce": "0x94dc83e0044f49c8", + "number": "1881283", + "stateRoot": "0x6e3832bc2e4e66170a1e716449083e08fbb70e7b2a9f1f34e0c57e66ce40c50f", + "timestamp": "1468467284", + "totalDifficulty": "37186898441932102239", + "alloc": { + "0x0000000000000000000000000000000000000004": { + "balance": "0x0" + }, + "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e": { + "balance": "0x0", + "code": "0x606060405236156100f05760e060020a600035046303afc23581146100f257806313af4035146101145780631838e26614610136578063186ef9621461014d57806327df8c501461016f578063295d5866146101915780634162169f146101b35780634dfc3db6146101c55780636637b882146101e8578063839d3f7f1461020a57806386c9b5361461021d5780638da5cb5b1461022f5780639093a5e714610241578063b199efb514610263578063b262b9ae14610275578063b9f34aa114610297578063be9a6555146102a9578063d1c3c84a146102c7578063e26fc92b146102d9578063e8d9f074146102eb575b005b6100f0600435600054600160a060020a03908116339091161461034057610002565b6100f0600435600054600160a060020a03908116339091161461035557610002565b6102fd60006000600060006000600061036a6101c9565b6100f0600435600054600160a060020a0390811633909116146108a157610002565b6100f0600435600054600160a060020a0390811633909116146108b657610002565b6100f0600435600054600160a060020a0390811633909116146108cb57610002565b61030f600154600160a060020a031681565b6102fd5b60008054600160a060020a0390811633909116146108e0575060015b90565b6100f0600435600054600160a060020a03908116339091161461098857610002565b61032c60075460a060020a900460ff1681565b61030f600454600160a060020a031681565b61030f600054600160a060020a031681565b6100f0600435600054600160a060020a03908116339091161461099d57610002565b61030f600254600160a060020a031681565b6100f0600435600054600160a060020a0390811633909116146109b257610002565b61030f600754600160a060020a031681565b6100f060005433600160a060020a03908116911614610a1a57610002565b61030f600354600160a060020a031681565b61030f600554600160a060020a031681565b61030f600654600160a060020a031681565b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b604080519115158252519081900360200190f35b60048054600160a060020a0319168217905550565b60008054600160a060020a0319168217905550565b945060008514610380578495505b505050505090565b6002546040805160015460e060020a634162169f0282529151600160a060020a039283169390921691634162169f9160048181019260209290919082900301816000876161da5a03f11561000257505060405151600160a060020a031690911490506103ef5760649550610378565b600260009054906101000a9004600160a060020a0316600160a060020a0316634dfc3db66040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051519450506000841461045857836064019550610378565b6040805160015460035460e060020a634162169f0283529251600160a060020a039182169390911691634162169f91600482810192602092919082900301816000876161da5a03f11561000257505060405151600160a060020a031690911490506104c65760c89550610378565b600360009054906101000a9004600160a060020a0316600160a060020a0316634dfc3db66040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051519350506000831461052f578260c8019550610378565b604080516001546004805460e060020a634162169f0284529351600160a060020a039283169490921692634162169f928183019260209282900301816000876161da5a03f11561000257505060405151600160a060020a0316909114905061059b5761012c9550610378565b60408051600480547f4dfc3db60000000000000000000000000000000000000000000000000000000083529251600160a060020a039390931692634dfc3db692808301926020929182900301816000876161da5a03f1156100025750506040515192505060008214610613578161012c019550610378565b6040805160015460055460e060020a634162169f0283529251600160a060020a039182169390911691634162169f91600482810192602092919082900301816000876161da5a03f11561000257505060405151600160a060020a03169091149050610682576101909550610378565b600560009054906101000a9004600160a060020a0316600160a060020a0316634dfc3db66040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151915050600081146106ec5780610190019550610378565b6040805160015460065460e060020a634162169f0283529251600160a060020a039182169390911691634162169f91600482810192602092919082900301816000876161da5a03f11561000257505060405151600160a060020a0316909114905061075b576101f49550610378565b6040805160065460e060020a638da5cb5b028252915130600160a060020a03908116931691638da5cb5b91600482810192602092919082900301816000876161da5a03f11561000257505060405151600160a060020a031690911490506107c6576101f59550610378565b6040805160075460015460e060020a634162169f0283529251600160a060020a03938416939190911691634162169f91600482810192602092919082900301816000876161da5a03f11561000257505060405151600160a060020a03169091149050610836576102589550610378565b6040805160075460e060020a638da5cb5b028252915130600160a060020a03908116931691638da5cb5b91600482810192602092919082900301816000876161da5a03f11561000257505060405151600160a060020a03169091149050610378576102599550610378565b60038054600160a060020a0319168217905550565b60058054600160a060020a0319168217905550565b60068054600160a060020a0319168217905550565b600154600160a060020a0316600014156108fc575060026101e5565b600654600160a060020a031660001415610918575060036101e5565b600754600160a060020a031660001415610934575060046101e5565b600254600160a060020a031660001415610950575060056101e5565b600354600160a060020a03166000141561096c575060066101e5565b600454600160a060020a0316600014156101e5575060076101e5565b60018054600160a060020a0319168217905550565b60078054600160a060020a0319168217905550565b60028054600160a060020a0319168217905550565b600260009054906101000a9004600160a060020a0316600160a060020a031663975057e76040518160e060020a0281526004018090506000604051808303816000876161da5a03f115610002575050505b565b610a8a600154604080517f4b6753bc0000000000000000000000000000000000000000000000000000000081529051600092600160a060020a031691634b6753bc916004828101926020929190829003018187876161da5a03f11561000257505060405151421191506101e59050565b1515610a9557610a18565b60075460a060020a900460ff1615610e93576111556040805160015460065460e060020a6370a08231028352600160a060020a039081166004840152925160009384939216916370a08231916024808301926020929190829003018187876161da5a03f1156100025750506040515191909111159050610c61576040805160065460025460015460e060020a6370a08231028452600160a060020a0392831660048501819052945163a9059cbb949284169391909116916370a0823191602482810192602092919082900301818a876161da5a03f11561000257505060408051805160e060020a63a9059cbb028252600482019490945260248101939093525160448084019360209350829003018187876161da5a03f1156100025750506040805160025460e060020a63a8618f71028252600160a060020a031660048201819052915191925063a8618f71916024828101926020929190829003018187876161da5a03f11561000257505060405151159050610c6157600260009054906101000a9004600160a060020a0316600160a060020a031663975057e76040518160e060020a0281526004018090506000604051808303816000876161da5a03f11561000257506001925050505b6001546007546040805160e060020a6370a08231028152600160a060020a0392831660048201529051600093909216916370a0823191602481810192602092909190829003018187876161da5a03f1156100025750506040515191909111159050610e1b576040805160075460025460015460e060020a6370a08231028452600160a060020a0392831660048501819052945163a9059cbb949284169391909116916370a0823191602482810192602092919082900301816000876161da5a03f11561000257505060408051805160e060020a63a9059cbb02825260048201949094526024810193909352516044838101936020935082900301816000876161da5a03f1156100025750506040805160025460e060020a63a8618f71028252600160a060020a031660048201819052915191925063a8618f7191602482810192602092919082900301816000876161da5a03f11561000257505060405151159050610e1b57600260009054906101000a9004600160a060020a0316600160a060020a031663975057e76040518160e060020a0281526004018090506000604051808303816000876161da5a03f11561000257506001925050505b8015610e7257600260009054906101000a9004600160a060020a0316600160a060020a0316632e64cec16040518160e060020a0281526004018090506000604051808303816000876161da5a03f115610002575050505b6007805474ff00000000000000000000000000000000000000001916905550565b600260009054906101000a9004600160a060020a0316600160a060020a0316632e64cec16040518160e060020a0281526004018090506000604051808303816000876161da5a03f115610002575050505b60048054604080517ffc3407160000000000000000000000000000000000000000000000000000000081529051600160a060020a03929092169263fc340716928282019260009290829003018183876161da5a03f115610002575050600354604080517fd95f98ce0000000000000000000000000000000000000000000000000000000081529051600160a060020a0392909216925063d95f98ce916004828101926000929190829003018183876161da5a03f11561000257505050620f42405a11156109c7576109c76001546005546040805160e060020a6370a08231028152600160a060020a039283166004820152905192909116916370a082319160248181019260209290919082900301816000876161da5a03f1156100025750506040515160001415905061108357604080516002546005547fd0679d34000000000000000000000000000000000000000000000000000000008352600160a060020a03908116600484015260016024840152925192169163d0679d349160448181019260209290919082900301816000876161da5a03f115610002575050505b5b600554604080517f400e39490000000000000000000000000000000000000000000000000000000081529051600a92600160a060020a03169163400e394991600482810192602092919082900301816000876161da5a03f1156100025750506040515191909110905080156110fb5750620aae605a115b15610a1857600560009054906101000a9004600160a060020a0316600160a060020a031663ff2f4bd26040518160e060020a0281526004018090506000604051808303816000876161da5a03f11561000257505050611084565b610ee456", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000304a554a310c7e546dfe434669c62820b7d83490", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89", + "0x0000000000000000000000000000000000000000000000000000000000000007": "0x000000000000000000000001f835a0247b0063c04ef22006ebe57c5f11977cc4" + } + }, + "0x304a554a310c7e546dfe434669c62820b7d83490": { + "balance": "0x3034f5ca7d45e17df1d83", + "nonce": "3", + "code": "0x6060604052361561020e5760e060020a6000350463013cf08b8114610247578063095ea7b3146102d05780630c3b7b96146103455780630e7082031461034e578063149acf9a1461036057806318160ddd146103725780631f2dc5ef1461037b57806321b5b8dd1461039b578063237e9492146103ad57806323b872dd1461040e5780632632bf2014610441578063341458081461047257806339d1f9081461047b5780634b6753bc146104935780634df6d6cc1461049c5780634e10c3ee146104b7578063590e1ae3146104ca578063612e45a3146104db578063643f7cdd1461057a578063674ed066146105925780636837ff1e1461059b57806370a08231146105e5578063749f98891461060b57806378524b2e1461062457806381f03fcb1461067e57806382661dc41461069657806382bf6464146106b75780638b15a605146106c95780638d7af473146106d257806396d7f3f5146106e1578063a1da2fb9146106ea578063a3912ec814610704578063a9059cbb1461070f578063b7bc2c841461073f578063baac53001461074b578063be7c29c1146107b1578063c9d27afe14610817578063cc9ae3f61461082d578063cdef91d014610841578063dbde198814610859578063dd62ed3e1461087e578063e33734fd146108b2578063e5962195146108c6578063e66f53b7146108de578063eceb2945146108f0578063f8c80d261461094f575b610966600f546000906234bc000142108015610239575060125433600160a060020a03908116911614155b156109785761098033610752565b6109866004356000805482908110156100025750808052600e8202600080516020612a3683398151915201905060038101546004820154600683015460018401548454600786015460058701546009880154600a890154600d8a0154600160a060020a039586169b509599600201989760ff81811698610100909204811697949691951693168c565b61096660043560243533600160a060020a03908116600081815260156020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b61096660105481565b610a7d600754600160a060020a031681565b610a7d600e54600160a060020a031681565b61096660165481565b6109665b60004262127500600f60005054031115610de557506014610983565b610a7d601254600160a060020a031681565b60408051602060248035600481810135601f810185900485028601850190965285855261096695813595919460449492939092019181908401838280828437509496505050505050506000600060006000600060003411156116a857610002565b6109666004356024356044355b60115460009060ff1680156104315750600f5442115b80156124e957506124e78461044b565b6109666000610980335b600160a060020a0381166000908152600b602052604081205481908114156129cb57610b99565b61096660065481565b6109665b600d5430600160a060020a03163103610983565b610966600f5481565b61096660043560046020526000908152604090205460ff1681565b61096660043560243560006124cb610831565b610a9a6000341115610ba457610002565b604080516020604435600481810135601f8101849004840285018401909552848452610966948135946024803595939460649492939101918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050933593505060a435915050600060006110c1336105ec565b61096660043560096020526000908152604090205481565b61096660015481565b610a9a60043530600160a060020a031633600160a060020a03161415806105db5750600160a060020a03811660009081526004602052604090205460ff16155b156121cb576121c8565b6109666004355b600160a060020a0381166000908152601460205260409020545b919050565b6109666004356024356000600034111561259957610002565b610966600062e6b680420360026000505410806106505750600354600160a060020a0390811633909116145b80156106645750600254621274ff19420190105b156126145750426002908155600180549091028155610983565b610966600435600a6020526000908152604090205481565b610966600435602435600060006000600060006000341115611ba157610002565b610a7d600854600160a060020a031681565b610966600c5481565b61096660005460001901610983565b61096660025481565b61096660043560006000600060003411156121fc57610002565b6109665b6001610983565b6109666004356024355b60115460009060ff16801561072f5750600f5442115b801561248757506124853361044b565b61096660115460ff1681565b6109666004355b60006000600f600050544210801561076a5750600034115b80156107a457506011546101009004600160a060020a0316600014806107a457506011546101009004600160a060020a0390811633909116145b15610b9f57610a9c61037f565b610a7d600435600060006000508281548110156100025750508080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56b600e83020180548290811015610002575081526020902060030154600160a060020a0316610606565b61096660043560243560006000610e1b336105ec565b6109665b6000600034111561247c57610002565b61096660043560056020526000908152604090205481565b610966600435602435604435600061252f845b6000600060003411156127ac57610002565b610966600435602435600160a060020a0382811660009081526015602090815260408083209385168352929052205461033f565b610a9a600435600034111561254557610002565b610966600435600b6020526000908152604090205481565b610a7d600354600160a060020a031681565b604080516020606435600481810135601f81018490048402850184019095528484526109669481359460248035956044359560849492019190819084018382808284375094965050505050505060006000600034111561103257610002565b610a7d6011546101009004600160a060020a031681565b60408051918252519081900360200190f35b610980610708565b90505b90565b604051808d600160a060020a031681526020018c8152602001806020018b81526020018a815260200189815260200188815260200187815260200186815260200185815260200184815260200183600160a060020a0316815260200182810382528c818154600181600116156101000203166002900481526020019150805460018160011615610100020316600290048015610a635780601f10610a3857610100808354040283529160200191610a63565b820191906000526020600020905b815481529060010190602001808311610a4657829003601f168201915b50509d505050505050505050505050505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b005b604051601254601434908102939093049350600160a060020a03169183900390600081818185876185025a03f150505050600160a060020a038316600081815260146020908152604080832080548601905560168054860190556013825291829020805434019055815184815291517fdbccb92686efceafb9bb7e0394df7f58f71b954061b81afb57109bf247d3d75a9281900390910190a260105460165410801590610b4c575060115460ff16155b15610b94576011805460ff1916600117905560165460408051918252517ff381a3e2428fdda36615919e8d9c35878d9eb0cf85ac6edf575088e80e4c147e9181900360200190a15b600191505b50919050565b610002565b600f5442118015610bb8575060115460ff16155b15610de357601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040516012549051600160a060020a039190911631109050610cc9576040805160125460e060020a63d2cc718f0282529151600160a060020a039290921691630221038a913091849163d2cc718f91600482810192602092919082900301816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a039490941660048201526024810193909352516044838101936020935082900301816000876161da5a03f115610002575050505b33600160a060020a0316600081815260136020526040808220549051909181818185876185025a03f19250505015610de35733600160a060020a03167fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d6013600050600033600160a060020a03168152602001908152602001600020600050546040518082815260200191505060405180910390a26014600050600033600160a060020a0316815260200190815260200160002060005054601660008282825054039250508190555060006014600050600033600160a060020a031681526020019081526020016000206000508190555060006013600050600033600160a060020a03168152602001908152602001600020600050819055505b565b4262054600600f60005054031115610e13576201518062127500600f60005054034203046014019050610983565b50601e610983565b60001415610e2857610002565b6000341115610e3657610002565b6000805485908110156100025750600160a060020a03331681527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56e600e8602908101602052604090912054600080516020612a3683398151915291909101915060ff1680610eb05750600c810160205260406000205460ff165b80610ebf575060038101544210155b15610ec957610002565b8215610f0f5733600160a060020a03166000908152601460209081526040808320546009850180549091019055600b84019091529020805460ff19166001179055610f4b565b33600160a060020a0316600090815260146020908152604080832054600a850180549091019055600c84019091529020805460ff191660011790555b33600160a060020a03166000908152600b60205260408120541415610f77576040600020849055610feb565b33600160a060020a03166000908152600b60205260408120548154811015610002579080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566600e909102015460038201541115610feb5733600160a060020a03166000908152600b602052604090208490555b60408051848152905133600160a060020a03169186917f86abfce99b7dd908bec0169288797f85049ec73cbe046ed9de818fab3a497ae09181900360200190a35092915050565b6000805487908110156100025750808052600e8702600080516020612a3683398151915201905090508484846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020816005016000505414915050949350505050565b600014156110ce57610002565b82801561111857508660001415806110e857508451600014155b806111005750600354600160a060020a038981169116145b8061110b5750600034115b80611118575062093a8084105b1561112257610002565b8215801561114257506111348861115c565b158061114257506212750084105b156111fe57610002565b83546118e590600160a060020a03165b600160a060020a03811660009081526004602052604081205460ff16806111f15750601254600160a060020a039081169083161480156111f15750601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051516006541190505b156129a157506001610606565b6249d40084111561120e57610002565b60115460ff1615806112215750600f5442105b806112365750600c5434108015611236575082155b1561124057610002565b42844201101561124f57610002565b30600160a060020a031633600160a060020a0316141561126e57610002565b60008054600181018083559091908280158290116112a557600e0281600e0283600052602060002091820191016112a5919061136a565b505060008054929450918491508110156100025750808052600e8302600080516020612a368339815191520190508054600160a060020a031916891781556001818101899055875160028084018054600082815260209081902096975091959481161561010002600019011691909104601f908101829004840193918b019083901061146257805160ff19168380011785555b5061149292915061144a565b5050600060098201819055600a820155600d81018054600160a060020a03191690556001015b8082111561145e578054600160a060020a03191681556000600182810182905560028084018054848255909281161561010002600019011604601f81901061143057505b506000600383018190556004808401805461ffff19169055600584018290556006840182905560078401805460ff191690556008840180548382559083526020909220611344929091028101905b8082111561145e57600080825560018201818155600283019190915560039091018054600160a060020a03191690556113fc565b601f0160209004906000526020600020908101906113ae91905b8082111561145e576000815560010161144a565b5090565b82800160010185558215611338579182015b82811115611338578251826000505591602001919060010190611474565b50508787866040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160050160005081905550834201816003016000508190555060018160040160006101000a81548160ff02191690830217905550828160070160006101000a81548160ff02191690830217905550821561157857600881018054600181018083559091908280158290116115735760040281600402836000526020600020918201910161157391906113fc565b505050505b600d8082018054600160a060020a031916331790553460068301819055815401905560408051600160a060020a038a16815260208181018a9052918101859052608060608201818152895191830191909152885185937f5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f938d938d938a938e93929160a084019185810191908190849082908590600090600490601f850104600f02600301f150905090810190601f1680156116485780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a2509695505050505050565b6040805186815260208101839052815189927fdfc78bdca8e3e0b18c16c5c99323c6cb9eb5e00afde190b4e7273f5158702b07928290030190a25b5050505092915050565b6000805488908110156100025750808052600e8802600080516020612a36833981519152019050600781015490945060ff166116e757620d2f006116ec565b622398805b600485015490935060ff16801561170857506003840154830142115b15611716576117b887611890565b600384015442108061172d5750600484015460ff16155b806117ae57508360000160009054906101000a9004600160a060020a03168460010160005054876040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020846005016000505414155b1561114c57610002565b61169e565b60048401805461ff001916610100179055835460019550600160a060020a03908116309091161480159061180157508354600754600160a060020a03908116911614155b801561181d57506008548454600160a060020a03908116911614155b801561183957508354601254600160a060020a03908116911614155b801561185557506003548454600160a060020a03908116911614155b1561188b5760018401805430600160a060020a031660009081526005602052604090208054919091019055546006805490910190555b611663875b6000600060005082815481101561000257908052600e02600080516020612a36833981519152018150600481015490915060ff16156118d757600d80546006830154900390555b600401805460ff1916905550565b15156118f45761190087611890565b6001915061193161047f565b604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050505061169e565b6001850154111561194157600091505b50600a8301546009840154865191019060049010801590611986575085600081518110156100025790602001015160f860020a900460f860020a02606860f860020a02145b80156119b6575085600181518110156100025790602001015160f860020a900460f860020a02603760f860020a02145b80156119e6575085600281518110156100025790602001015160f860020a900460f860020a0260ff60f860020a02145b8015611a16575085600381518110156100025790602001015160f860020a900460f860020a02601e60f860020a02145b8015611a45575030600160a060020a0316600090815260056020526040902054611a4290611a5d61047f565b81105b15611a4f57600091505b6001840154611a8090611a5f565b015b30600160a060020a03166000908152600560205260408120546129a961047f565b8110611ad457604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050501515611abc57610002565b4260025560165460059004811115611ad45760056001555b6001840154611ae290611a5f565b8110158015611af85750600a8401546009850154115b8015611b015750815b1561188b578360000160009054906101000a9004600160a060020a0316600160a060020a0316846001016000505487604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611b7d5780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f19250505015156117bd57610002565b611baa336105ec565b60001415611bb757610002565b60008054889081101561000257508052600e87027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566810154600080516020612a36833981519152919091019450421080611c1957506003840154622398800142115b80611c3257508354600160a060020a0390811690871614155b80611c425750600784015460ff16155b80611c68575033600160a060020a03166000908152600b8501602052604090205460ff16155b80611c9c575033600160a060020a03166000908152600b60205260409020548714801590611c9c5750604060009081205414155b15611ca657610002565b600884018054600090811015610002579081526020812060030154600160a060020a03161415611e1257611efc86604051600090600160a060020a038316907f9046fefd66f538ab35263248a44217dcb70e2eb2cd136629e141b8b8f9f03b60908390a260408051600e547fe2faf044000000000000000000000000000000000000000000000000000000008252600160a060020a03858116600484015260248301859052604483018590526223988042016064840152925192169163e2faf04491608480820192602092909190829003018187876161da5a03f1156100025750506040515191506106069050565b6008850180546000908110156100025781815260208082209390935530600160a060020a031681526005909252604082205481549092908110156100025790815260208120905060020155601654600885018054600090811015610002579081526020812090506001015560048401805461ff0019166101001790555b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090505433600160a060020a031660009081526014602052604081205460088801805493909102939093049550908110156100025790815260208120905060030154604080517fbaac530000000000000000000000000000000000000000000000000000000000815233600160a060020a0390811660048301529151929091169163baac53009186916024808301926020929190829003018185886185025a03f11561000257505060405151600014159150611f78905057610002565b60088501805460009081101561000257818152602081206003018054600160a060020a03191690931790925580549091908110156100025790815260208120905060030154600160a060020a031660001415611f5757610002565b600d5430600160a060020a0316311015611f7057610002565b611d9561047f565b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090506002015433600160a060020a0390811660009081526014602090815260408083205430909416835260058083528184205460099093529083205460088b018054969095029690960497509487020494508593929091908290811015610002575260208120815060030154600160a060020a0390811682526020828101939093526040918201600090812080549095019094553016835260059091529020548290101561205357610002565b30600160a060020a031660009081526005602052604081208054849003905560088501805483926009929091829081101561000257508152602080822060030154600160a060020a039081168352929052604080822080549094019093553090911681522054819010156120c657610002565b30600160a060020a0390811660009081526009602090815260408083208054869003905533909316808352601482528383205484519081529351929390927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a36121383361086c565b5033600160a060020a03166000908152601460209081526040808320805460168054919091039055839055600a9091528120556001945061169e565b30600160a060020a0390811660008181526005602090815260408083208054958716808552828520805490970190965584845283905560099091528082208054948352908220805490940190935590815290555b50565b604051600160a060020a0382811691309091163190600081818185876185025a03f192505050151561217457610002565b33600160a060020a03818116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f028352935197995091969195929092169363d2cc718f936004848101949193929183900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a03168152602001908152602001600020600050540204101561229d57610002565b600160a060020a03338116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f02835293519296909593169363d2cc718f93600483810194929383900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a0316815260200190815260200160002060005054020403905083156123ec57600860009054906101000a9004600160a060020a0316600160a060020a0316630221038a83600160a060020a0316630e7082036040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a031660048201526024810186905290516044808301935060209282900301816000876161da5a03f115610002575050604051511515905061245457610002565b6040805160085460e160020a63011081c5028252600160a060020a038581166004840152602483018590529251921691630221038a9160448082019260209290919082900301816000876161da5a03f115610002575050604051511515905061245457610002565b600160a060020a03331660009081526009602052604090208054909101905550600192915050565b6109803361086c565b155b80156124a257506124a23384845b6000600061293a856105ec565b80156124be57506124be83836000600034111561261c57610002565b15610b9f5750600161033f565b15156124d657610002565b6124e08383610719565b905061033f565b155b80156124fb57506124fb848484612495565b80156125185750612518848484600060003411156126c157610002565b15610b9f57506001612528565b90505b9392505050565b151561253a57610002565b61252584848461041b565b30600160a060020a031633600160a060020a031614158061258a575030600160a060020a031660009081526005602052604090205460649061258561047f565b010481115b1561259457610002565b600c55565b600354600160a060020a0390811633909116146125b557610002565b600160a060020a038316600081815260046020908152604091829020805460ff191686179055815185815291517f73ad2a153c8b67991df9459024950b318a609782cee8c7eeda47b905f9baa91f9281900390910190a250600161033f565b506000610983565b33600160a060020a03166000908152601460205260409020548290108015906126455750600082115b156126b957600160a060020a03338116600081815260146020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a350600161033f565b50600061033f565b600160a060020a03841660009081526014602052604090205482901080159061270a5750601560209081526040600081812033600160a060020a03168252909252902054829010155b80156127165750600082115b156127a457600160a060020a03838116600081815260146020908152604080832080548801905588851680845281842080548990039055601583528184203390961684529482529182902080548790039055815186815291519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001612528565b506000612528565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f11561000257505060405151905061281a866105ec565b0204101561282757610002565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f115610002575050604051519050612895866105ec565b0204039050600760009054906101000a9004600160a060020a0316600160a060020a0316630221038a84836040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511515905061291357610002565b600160a060020a0383166000908152600a6020526040902080548201905560019150610b99565b600160a060020a0386166000908152600a602052604090205480850291909104915081111561296857610002565b600160a060020a038581166000908152600a60205260408082208054859003905591861681522080548201905560019150509392505050565b506000610606565b0160030260166000505483020460016000505460166000505404019050610606565b600160a060020a0383166000908152600b6020526040812054815481101561000257818052600e02600080516020612a368339815191520190506003810154909150421115610b9457600160a060020a0383166000908152600b602052604081208190559150610b9956290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a", + "0x0000000000000000000000000000000000000000000000000000000000000007": "0x000000000000000000000000ad3ecf23c0c8983b07163708be6d763b5f056193", + "0x000000000000000000000000000000000000000000000000000000000000000c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000000000d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000000000f": "0x0000000000000000000000000000000000000000000000000000000057870858", + "0x0000000000000000000000000000000000000000000000000000000000000011": "0x0000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c18941301", + "0x0000000000000000000000000000000000000000000000000000000000000016": "0x00000000000000000000000000000000000000000003034f5ca7d45e17df199b", + "0x0421a2c4dbea98e8df669bb77238b62677daa210c5fbc46600627f90c03d0f08": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e571": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e572": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e573": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e574": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e575": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e576": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e577": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e578": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e579": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e57e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e57f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e580": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e581": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e582": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e583": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e584": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e585": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e586": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e587": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e590": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e591": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e592": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e593": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e594": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e595": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59a": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59b": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e59f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a1": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a2": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a3": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a8": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5a9": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5aa": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ab": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ac": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ad": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ae": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5af": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b1": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b6": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b7": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b8": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5b9": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ba": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5bb": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5bc": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5bd": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5be": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5bf": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c4": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c5": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c6": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c7": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c8": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5c9": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ca": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5cb": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5cc": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5cd": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5d2": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5d3": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5d4": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5d5": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5d6": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5d7": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5d8": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5d9": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5da": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5db": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5e0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5e1": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5e2": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5e3": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5e4": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5e5": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5e6": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5e7": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5e8": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5e9": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ee": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5ef": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5f0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5f1": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5f2": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5f3": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5f4": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5f5": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5f6": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5f7": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5fc": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x330b9432081afd3b64172d5df1f72ca72fc17e7e729ceb8b7529f91eee8b3f23": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x33f9bdb745e7edb1789dd1d68f40f693940aa8313b4f6bdc543be443dbc85e63": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x4830270ad35536baba417a92ea24656430586a37c90999b53c4d72ef1090cc9d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x4b16ba88f291613070529c10c8bdc41e973e2e2aa412ed92254cdca71ccfbc89": "0x00000000000000000000000000000000000000000001819451f999d617dafa76", + "0x6546a4760869a51d07a75a31f00531836c32152c06dc88ac342da52fac5d939e": "0x000000000000000000000000000000000000000000000026b8b4a0b1e8292492", + "0x6796d25b854f17a11b940a9ff2822335f7d9bd1b85fbcd9d1f5cf742099d477a": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x711886c99bc7a6e316551823dca012bd5b4381b57cec388f72c4b8105c1ed4ad": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x74024021ec74dc59b0fa1b66e9f430163a5e1128785ec9495f9686628ca7cc2b": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x79a0e9ff42282e7cbcb539e164f024ab90021633de05f600fff6d16305888d26": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x81ffe0a69ee20c37e3f3ba834da8b20475846fcde1f4a39fdfc628a2560076aa": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8f85b96a91f601f62149f5dd6a35d6168f6de5bc047a18e3cf7b97a3843c6ffd": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x946f68a04a200ebe87f2f896f7f6c08f4e22813db910c8a6d6abf17611ce3ffb": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x9c1ad2f16775f94ffd360e8bc716f86016a3fcf90992b5b4f3312353efd1bd61": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xa66ae63934365a757bf33d70ca0a28352da4c2fe6cb147bf29d69fbea3a706e0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xa7653edcf1403f7ce2f75784d5f34ca5f57ff110bd0c3abbdcc5a84f101dc83a": "0x00000000000000000000000000000000000000000001819451f999d617dafa93", + "0xa87317e3ffd5ed16f357bd31427bd97cbb35fc51ad1e00feec89bdfe82c5dba4": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xaa535eb427f7963e49601f9032ee6b62a9f72b6b3c610a5f11faf8dc68a97e2a": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xaade287f2b81ac58dcc6ee0c381cde85b6aa7a9a769be73605f1af9453a340a0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xb56a086d82c3921c13c13d1d53f18bbbe36d9d1c4862be8339a5171feb94c164": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xb6ab9f1541f42dc4feba15ccd18bc3af7c8f99cafb184ab65539883a68c7a1a9": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xbad9e5f7dc3001078ea6433993a2f145c2ef9af1c5137a35e9c173c208990249": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xc319152db8781ef1f12090aad94325d650e39c8a20285c7e02959817118f3f28": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xde65b6d76ea4a5547af9707e6e099bba6f16dbc7b5cf97fb8fedc82583b38de0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xdf71c8506c3cf85e2e677b60ec28fe60eb820775001bdce289e3253f304f22e8": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x4fd27b205895e698fa350f7ea57cec8a21927fcd": { + "balance": "0x0", + "nonce": "11", + "code": "0x606060405236156100f05760e060020a600035046303afc23581146100f257806313af403514610114578063186ef962146101365780632e64cec11461015857806331962cdc146101d2578063365a86fc146101f45780634162169f146102065780634dfc3db61461021857806365f13792146102585780636637b88214610441578063715d832f146104625780637452c2e61461048457806386c9b536146105005780638da5cb5b14610512578063975057e714610524578063a8618f711461059f578063d0679d341461061b578063d1c3c84a14610698578063d9d35966146106aa578063f3273907146106c9575b005b6100f0600435600054600160a060020a03908116339091161461072e57610002565b6100f0600435600054600160a060020a03908116339091161461074457610002565b6100f0600435600054600160a060020a03908116339091161461075957610002565b6100f06000805481908190600160a060020a0390811633909116148015906101905750600154600160a060020a039081163390911614155b80156101ac5750600254600160a060020a039081163390911614155b80156101c85750600354600160a060020a039081163390911614155b1561076e57610002565b6100f0600435600054600160a060020a039081163390911614610a5d57610002565b6106eb600154600160a060020a031681565b6106eb600454600160a060020a031681565b61070860008054600160a060020a03908116339091161480159061024c5750600154600160a060020a039081163390911614155b15610a72575060015b90565b6107086004355b600060006000600060006000600460009054906101000a9004600160a060020a0316600160a060020a0316630e7082036040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150945084600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051600480547f81f03fcb000000000000000000000000000000000000000000000000000000008452600160a060020a038d81169285019290925293519198509290921692506381f03fcb916024828101926020929190829003018187876161da5a03f115610002575050604080518051600480547f18160ddd0000000000000000000000000000000000000000000000000000000084529351919750600160a060020a039390931693506318160ddd92828101926020929190829003018187876161da5a03f1156100025750506040805180516004805460e060020a6370a08231028452600160a060020a038d81169285019290925293519196509290921692506370a08231916024828101926020929190829003018187876161da5a03f11561000257505060405151909402919091049695505050505050565b6100f060043560005433600160a060020a03908116911614610ad957610002565b6100f06004356000805433600160a060020a03908116911614610aff57610002565b61071a600435600080548190819033600160a060020a039081169116148015906104be5750600154600160a060020a039081163390911614155b80156104da5750600254600160a060020a039081163390911614155b80156104f65750600354600160a060020a039081163390911614155b15610be657610002565b6106eb600354600160a060020a031681565b6106eb600054600160a060020a031681565b6100f06000805481908190819033600160a060020a0390811691161480159061055d5750600154600160a060020a039081163390911614155b80156105795750600254600160a060020a039081163390911614155b80156105955750600354600160a060020a039081163390911614155b15610c4457610002565b61071a6004355b60006000600460009054906101000a9004600160a060020a0316600160a060020a03166381f03fcb846040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f115610002575050604051519150610da490508361025f565b61071a60043560243560008054819033600160a060020a039081169116148015906106565750600154600160a060020a039081163390911614155b80156106725750600254600160a060020a039081163390911614155b801561068e5750600354600160a060020a039081163390911614155b15610dac57610002565b6106eb600254600160a060020a031681565b6100f06000805433600160a060020a03908116911614610ec457610002565b6106eb6004356000805433600160a060020a03908116911614610fd357610002565b60408051600160a060020a03929092168252519081900360200190f35b60408051918252519081900360200190f35b604080519115158252519081900360200190f35b60038054600160a060020a031916821790555b50565b60008054600160a060020a0319168217905550565b60028054600160a060020a0319168217905550565b30925061077a836105a6565b1561082557600480546006546040805160e060020a6370a08231028152600160a060020a038881169582019590955290519284169363a9059cbb9392169184916370a0823191602482810192602092919082900301816000876161da5a03f11561000257505060408051805160e060020a63a9059cbb02825260048201949094526024810193909352516044838101936020935082900301816000876161da5a03f115610002575050505b600091505b6005548210156108f45760058054600454600160a060020a0316916370a0823191859081101561000257600091825260408051600080516020611089833981519152929092015460e060020a6370a08231028352600160a060020a0316600483015251602482810193602093839003909101908290876161da5a03f115610002575050604051519150506000811115610a51576108f96005600050838154811015610002576000919091526000805160206110898339815191520154600160a060020a03166105a6565b505050565b15156109c25760058054600454600160a060020a0316916323b872dd918590811015610002575060009081526040805160008051602061108983398151915287015460e060020a6323b872dd028252600160a060020a03908116600483015230166024820152604481018690529051606482810193602093839003909101908290876161da5a03f1156100025750506040805183815290517f92da44f6982cd1ca7a9c851f8c39b26c80c235d7bb9fd59bce334fa634a1728b92509081900360200190a1610a51565b60058054600454600160a060020a0316916323b872dd918590811015610002575060009081526006546040805160008051602061108983398151915288015460e060020a6323b872dd028252600160a060020a0390811660048301529290921660248301526044820186905251606482810193602093839003909101908290876161da5a03f115610002575050505b6001919091019061082a565b60018054600160a060020a0319168217905550565b600454600160a060020a031660001415610a8e57506002610255565b600354600160a060020a031660001415610aaa57506003610255565b600254600160a060020a031660001415610ac657506004610255565b6005546000141561025557506005610255565b6005546000901115610aea57610002565b60048054600160a060020a0319168217905550565b5060005b81811015610b5a57600580546001818101808455930192909190828015829011610b5e576000839052610b5e906000805160206110898339815191529081019083015b80821115610bd65760008155600101610b46565b5050565b5050604051600454600160a060020a0316925090506082806110078339018082600160a060020a03168152602001915050604051809103906000f06005805460001981019081101561000257600091909152600080516020611089833981519152018054600160a060020a0319169091179055610b03565b5090565b600092505b5050919050565b600091505b600554821015610bda57600580548390811015610002576000919091526000805160206110898339815191520154600160a060020a0390811691508416811415610c385760019250610bdf565b60019190910190610beb565b600460009054906101000a9004600160a060020a0316600160a060020a03166370a08231306040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f115610002575050604051519450506000841415610cbb575b50505050565b600554600093506004900460010191505b81831015610cb557506005805460045442850182900692600160a060020a03919091169163a9059cbb9190849081101561000257600091825260408051600080516020611089833981519152929092015460e060020a63a9059cbb028352600160a060020a03166004830152868904602483015251604482810193602093839003909101908290876161da5a03f11561000257505060408051848704815290517fc6d8c0af6d21f291e7c359603aa97e0ed500f04db6e983b9fce75a91c6b8da6b92509081900360200190a160019290920191610ccc565b901192915050565b600460009054906101000a9004600160a060020a0316600160a060020a03166370a08231306040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515191505082811015610e5f57604080516020810185905281517f703690365b2d63b5b9ec4471a919cdd5924f745170399a5d24927fd07d81a04d929181900390910190a1600091505b5092915050565b604080516004805460e060020a63a9059cbb028352600160a060020a038881169284019290925260248301879052925192169163a9059cbb9160448082019260209290919082900301816000876161da5a03f115610002575060019350610e58915050565b600480546006546040805160e060020a6370a08231028152600160a060020a0392831694810194909452519116916370a0823191602482810192602092919082900301816000876161da5a03f11561000257505060405151915050600081111561074157604080516004805460065460e060020a6323b872dd028452600160a060020a039081169284019290925230821660248401526044830185905292519216916323b872dd9160648181019260209290919082900301816000876161da5a03f1156100025750505060405180519060200150507f32e95f921f72e9e736ccad1cc1c0ef6e3c3c08204eb74e9ee4ae8f98e195e3f0816040518082815260200191505060405180910390a150565b600580548390811015610002576000919091526000805160206110898339815191520154600160a060020a03169291505056006060604052604051602080608283396080604081905291517f095ea7b3000000000000000000000000000000000000000000000000000000008352600160a060020a0333811660845260001960a4819052919384939184169163095ea7b39160c491906044816000876161da5a03f115600257505033600160a060020a03169050ff036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000003e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x000000000000000000000000304a554a310c7e546dfe434669c62820b7d83490", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x000000000000000000000000000000000000000000000000000000000000000a", + "0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db6": "0x0000000000000000000000007ccbc69292c7a6d7b538c91f3b283de97906cf30", + "0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db7": "0x0000000000000000000000001b9ec8ba24630b75a7a958153ffff56dd6d4b6a2", + "0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db8": "0x000000000000000000000000c3a2c744ad1f5253c736875b93bacce5b01b060b" + } + }, + "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f": { + "balance": "0x0", + "code": "0x606060405236156100da5760e060020a600035046303afc23581146100dc57806309f180f9146100fe5780630a39ce021461016c57806310aa1caa146101a057806313af40351461021e57806331962cdc14610240578063365a86fc146102625780634162169f146102745780634dfc3db6146102865780636637b882146102c65780636de45dee146102e85780638da5cb5b146103285780639137c1a71461033a578063b199efb51461035c578063b3a69f861461036e578063d5d7ff3c1461040b578063d95f98ce1461044b578063fe39084c146104b5575b005b6100da600435600054600160a060020a0390811633909116146104f657610002565b6104c76004355b6002546040805160e060020a6381f03fcb028152600160a060020a0384811660048301529151600093849384939116916381f03fcb91602481810192602092909190829003018187876161da5a03f1156100025750506040515192506105199050846101a7565b6104d960043560068054829081101561000257506000526000805160206110cf8339815191520154600160a060020a031681565b6104c76004355b604080516003547f65f13792000000000000000000000000000000000000000000000000000000008252600160a060020a038481166004840152925160009391909116916365f13792916024828101926020929190829003018187876161da5a03f115610002575050604051516001019392505050565b6100da600435600054600160a060020a03908116339091161461052c57610002565b6100da600435600054600160a060020a03908116339091161461054157610002565b6104d9600154600160a060020a031681565b6104d9600254600160a060020a031681565b6104c760008054600160a060020a0390811633909116148015906102ba5750600154600160a060020a039081163390911614155b15610556575060015b90565b6100da600435600054600160a060020a03908116339091161461063c57610002565b6100da600435600054600160a060020a03908116339091161480159061031e5750600154600160a060020a039081163390911614155b1561065157610002565b6104d9600054600160a060020a031681565b6100da600435600054600160a060020a03908116339091161461081b57610002565b6104d9600354600160a060020a031681565b6104c75b6000805b6006548110156108175760068054600254600160a060020a0316916370a08231918490811015610002576000918252604080516000805160206110cf833981519152929092015460e060020a6370a08231028352600160a060020a0316600483015251602482810193602093839003909101908290876161da5a03f11561000257505060405151929092019150600101610376565b6100da6004356000805433600160a060020a039081169116148015906104415750600154600160a060020a039081163390911614155b1561083057610002565b6100da60006000600060006000600060006000600060006000600060009054906101000a9004600160a060020a0316600160a060020a031633600160a060020a0316141580156104ab5750600154600160a060020a039081163390911614155b1561092d57610002565b6104d9600454600160a060020a031681565b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b60048054600160a060020a031916821790555b50565b81810392505b5050919050565b90508082111561050c5760009250610512565b60008054600160a060020a0319168217905550565b60018054600160a060020a0319168217905550565b600254600160a060020a031660001415610572575060026102c3565b600354600160a060020a03166000141561058e575060036102c3565b600354604080517fd1c3c84a000000000000000000000000000000000000000000000000000000008152905130600160a060020a0390811693169163d1c3c84a91600482810192602092919082900301816000876161da5a03f11561000257505060405151600160a060020a0316909114905061060d575060046102c3565b60065460001415610620575060056102c3565b600454600160a060020a0316600014156102c3575060066102c3565b60028054600160a060020a0319168217905550565b6106ab816000805b6006548110156110bc5782600160a060020a03166006600050828154811015610002576000919091526000805160206110cf8339815191520154600160a060020a031614156110c757600191506110c1565b156106b557610509565b600354604080517f7452c2e6000000000000000000000000000000000000000000000000000000008152600160a060020a03848116600483015291519290911691637452c2e69160248181019260209290919082900301816000876161da5a03f1156100025750506040515115905061072d57610509565b30600160a060020a031681600160a060020a0316148061075b5750600354600160a060020a03908116908216145b806107745750600154600160a060020a03908116908216145b1561077e57610509565b60068054600181018083559091908280158290116107bf578183600052602060002091820191016107bf91905b8082111561081757600081556001016107ab565b505060068054849350909150600019810190811015610002575080546000919091527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3e018054600160a060020a031916909117905550565b5090565b60038054600160a060020a0319168217905550565b5060005b6006548110156109215781600160a060020a03166006600050828154811015610002576000919091526000805160206110cf8339815191520154600160a060020a0316141561092557600680546000198101908110156100025760009182526000805160206110cf83398151915201909054906101000a9004600160a060020a03166006600050828154811015610002576000805160206110cf833981519152018054600160a060020a0319169092179091558054600019810180835590919082801582901161091c5761091c906000805160206110cf8339815191529081019083016107ab565b505050505b5050565b600101610834565b6002546040805160e060020a6381f03fcb02815230600160a060020a0381811660048401529251909e5092909116916381f03fcb9160248181019260209290919082900301816000876161da5a03f115610002575050604051519a505060008a14156109c1576040517f044c61dab36644651a1f82d87d6494a3a6450a6edde20b9baf45e374fb2d0bb990600090a1610e04565b6109c9610372565b6040805160025460e060020a6370a08231028252600160a060020a038f811660048401529251939c50909116916370a082319160248181019260209290919082900301816000876161da5a03f115610002575050604051519850606497505086881015610ade57604080516003547fd0679d34000000000000000000000000000000000000000000000000000000008252600160a060020a038e811660048401528b8b036024840152925192169163d0679d349160448082019260209290919082900301816000876161da5a03f1156100025750506040515115159050610ad8576040517f044c61dab36644651a1f82d87d6494a3a6450a6edde20b9baf45e374fb2d0bb990600090a1610e04565b86975087505b600095505b600654861015610b2457610d8e6006600050878154811015610002576000919091526000805160206110cf8339815191520154600160a060020a0316610105565b6040805160025460e060020a6381f03fcb028252600160a060020a038e8116600484015292519216916381f03fcb9160248181019260209290919082900301816000876161da5a03f11561000257505050604051805190602001509250600260009054906101000a9004600160a060020a0316600160a060020a03166370a082318c6040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f11561000257505060405151600097509250505b600654861015610e045760068054600254600160a060020a0316916370a082319189908110156100025760009182526000805160206110cf83398151915201546040805160e060020a6370a08231028152600160a060020a0392909216600483015251602482810193602093839003909101908290876161da5a03f115610002575050604051518084028b900495509150506000841115610d82577ff340c079d598119636d42046c6a2d2faf7a68c04aecee516f0e0b8a9e79b86666006600050878154811015610002576000919091526000805160206110cf833981519152015460408051600160a060020a03929092168252602082018790528386048c900482820152519081900360600190a160025460068054600160a060020a03929092169163a9059cbb919089908110156100025760009182526000805160206110cf83398151915201546040805160e060020a63a9059cbb028152600160a060020a039290921660048301526024820189905251604482810193602093839003909101908290876161da5a03f115610002575050505b60019590950194610bed565b9450898589020493508760001415610e11577fdb0f19c627ca59a2db73b1e1e8c4853f34a58afa92b29331e56c75144fa0c84c6006600050878154811015610002576000919091526000805160206110cf833981519152015460408051600160a060020a03929092168252519081900360200190a15b5050505050505050505050565b87841115610e84577f211d59fc569e166e12f7ca82135d85b1f178f636fefe40d168f0113cf07f818f6006600050878154811015610002576000919091526000805160206110cf833981519152015460408051600160a060020a03929092168252519081900360200190a1879350610ee8565b7f4b0bc4f25f8d0b92d2e12b686ba96cd75e4e69325e6cf7b1f3119d14eaf2cbdf6006600050878154811015610002576000919091526000805160206110cf833981519152015460408051600160a060020a03929092168252519081900360200190a15b60008411156110b05760068054998501997ff340c079d598119636d42046c6a2d2faf7a68c04aecee516f0e0b8a9e79b86669190889081101561000257600091909152604080516000805160206110cf8339815191529290920154600160a060020a0316825260208201879052818101889052519081900360600190a160025460068054600160a060020a03929092169163a9059cbb91908990811015610002576000918252604080516000805160206110cf833981519152929092015460e060020a63a9059cbb028352600160a060020a031660048301526024820189905251604482810193602093839003909101908290876161da5a03f1156100025750506040805160025460e060020a6370a08231028252600160a060020a038f811660048401529251921692506370a0823191602482810192602092919082900301816000876161da5a03f115610002575050506040518051906020015097508750600260009054906101000a9004600160a060020a0316600160a060020a03166381f03fcb8c6040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f115610002575050604051519a50505b60019590950194610ae3565b600091505b50919050565b60010161065956f652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000003e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000304a554a310c7e546dfe434669c62820b7d83490", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f": "0x000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526" + } + }, + "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc": { + "balance": "0x4563918244f400000", + "code": "0x606060405236156100da5760e060020a600035046313af40358114610145578063186ef9621461016757806331962cdc14610189578063365a86fc146101ab5780634162169f146101bd57806348c981e2146101cf5780634dfc3db61461020f57806361bc221a146102505780636637b882146102595780636c0e29601461027b5780638da5cb5b146104795780638f2b29a71461048b5780639137c1a714610602578063b199efb514610624578063b826c4fd14610636578063d1c3c84a1461063f578063d2f0ad9214610651578063fc340716146106bf575b6107236002546040805160e060020a630e7082030281529051600092600160a060020a031691630e708203916004828101926020929190829003018187876161da5a03f1156100025750506040515133600160a060020a039081169116149050610737575060015b90565b610861600435600054600160a060020a03908116339091161461089257610002565b610861600435600054600160a060020a0390811633909116146108a757610002565b610861600435600054600160a060020a0390811633909116146108bc57610002565b610863600154600160a060020a031681565b610863600254600160a060020a031681565b610861600435600054600160a060020a0390811633909116148015906102055750600154600160a060020a039081163390911614155b156108d157610002565b61088060008054600160a060020a0390811633909116148015906102435750600154600160a060020a039081163390911614155b156108fa57506001610142565b61088060055481565b610861600435600054600160a060020a0390811633909116146109e857610002565b6108805b6000600060006000600060006000600060006000600260009054906101000a9004600160a060020a0316600160a060020a0316630e7082036040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150985088600160a060020a03163130600160a060020a03163101975088600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160025460035460e060020a6381f03fcb028452600160a060020a0390811660048501529351919b5090921692506381f03fcb916024828101926020929190829003018187876161da5a03f11561000257505060408051805160025460e060020a6318160ddd0283529251909950600160a060020a039290921692506318160ddd916004828101926020929190829003018187876161da5a03f11561000257505060408051805160025460035460e060020a6370a08231028452600160a060020a039081166004850152935191995090921692506370a08231916024828101926020929190829003018187876161da5a03f115610002575050506040518051906020015093508784860202925088600160a060020a03163188880103840291508585029050808210156109fd57610a05565b610863600054600160a060020a031681565b61088060043560006000600060006000600260009054906101000a9004600160a060020a0316600160a060020a0316630e7082036040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150935083600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051600254815160035460e060020a6381f03fcb028452600160a060020a0390811660048501529351909750921692506381f03fcb916024808301926020929190829003018187876161da5a03f11561000257505060408051805160025460e060020a6318160ddd0283529251909550600160a060020a039290921692506318160ddd916004828101926020929190829003018187876161da5a03f115610002575050506040518051906020015090508581038183020486820387850204039450845084945050505050919050565b610861600435600054600160a060020a039081163390911614610a1157610002565b610863600354600160a060020a031681565b61088060065481565b610863600454600160a060020a031681565b6108806004355b6040805160025460035460e060020a6370a08231028352600160a060020a039081166004840152925160009384939216916370a08231916024828101926020929190829003018187876161da5a03f115610002575050604051519093046001019392505050565b61086160006000600060006000600060006000600060009054906101000a9004600160a060020a0316600160a060020a031633600160a060020a0316141580156107195750600154600160a060020a039081163390911614155b15610cbc57610002565b604080519115158252519081900360200190f35b600654600554600019909101901115610803576040805160025460035460e060020a6370a0823102835230600160a060020a03908116600485015293519184169363a9059cbb9391169160019185916370a082319160248082019260209290919082900301816000876161da5a03f11561000257505060408051805160e060020a63a9059cbb028252600482019590955260001994909401602485015251604480850194602094509192509082900301816000876161da5a03f115610002575060019250610142915050565b6005805460010190556040805160025460e160020a63664d71fb0282529151600160a060020a03929092169163cc9ae3f69160048181019260209290919082900301816000876161da5a03f115610002575060019250610142915050565b005b60408051600160a060020a03929092168252519081900360200190f35b60408051918252519081900360200190f35b60008054600160a060020a0319168217905550565b60048054600160a060020a0319168217905550565b60018054600160a060020a0319168217905550565b604051600160a060020a0382811691309091163190600081818185876185025a03f15050505050565b600254600160a060020a03166000141561091657506002610142565b600354600160a060020a03166000141561093257506003610142565b600454600160a060020a03166000141561094e57506004610142565b600354604080517f86c9b536000000000000000000000000000000000000000000000000000000008152905130600160a060020a039081169316916386c9b53691600482810192602092919082900301816000876161da5a03f11561000257505060405151600160a060020a031690911490506109cd57506005610142565b30600160a060020a0316316000141561014257506006610142565b60028054600160a060020a0319168217905550565b808203830499505b50505050505050505090565b60038054600160a060020a0319168217905550565b6006819055600354604080517fd0679d34000000000000000000000000000000000000000000000000000000008152600160a060020a038981166004830152938b04602482018190529151919750919092169163d0679d349160448181019260209290919082900301816000876161da5a03f11561000257505060408051600160055530600160a060020a031631815290517f7027eecbd2a688fc1fa281702b311ed7168571514adfd17014a55d828cb4338292509081900360200190a1604051600160a060020a0389811691309091163190600081818185876185025a03f15050604080517fd2cc718f000000000000000000000000000000000000000000000000000000008152905163d2cc718f9250600482810192602092919082900301816000876161da5a03f11561000257505060408051805160025460e060020a6370a08231028352600160a060020a038a81166004850152935191975090921692506370a0823191602482810192602092919082900301816000876161da5a03f11561000257505060408051805160025460e060020a6381f03fcb028352600160a060020a038a81166004850152935191965090921692506381f03fcb91602482810192602092919082900301816000876161da5a03f11561000257505060408051805160025460e160020a63664d71fb0283529251909450600160a060020a0392909216925063cc9ae3f691600482810192602092919082900301816000876161da5a03f115610002575050604080516002546004805460e060020a63a9059cbb028452600160a060020a03908116918401919091526001602484015292519216925063a9059cbb91604482810192602092919082900301816000876161da5a03f115610002575050505b5050505050505050565b6002546040805160e060020a630e7082030281529051600160a060020a0390921691630e7082039160048181019260209290919082900301816000876161da5a03f115610002575050604051519850610d15905061027f565b60408051600160a060020a038b1631815290519198507f07cf7e805770612a8b2ee8e0bcbba8aa908df5f85fbc4f9e2ef384cf75315038919081900360200190a187600160a060020a03163130600160a060020a0316310195508660001480610d7e5750856000145b15610db1576040517f30090d86c52e12fbc1213c1ecf7e193d6ce4a5c838c8c41d06c1a9daea8a2cec90600090a1610cb2565b309450610a268761065856", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000003e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000304a554a310c7e546dfe434669c62820b7d83490", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b": { + "balance": "0x0", + "code": "0x606060405236156100985760e060020a6000350463013cf08b811461009a57806313af4035146100d757806331962cdc146100f9578063365a86fc1461011b578063400e39491461012d5780634162169f146101375780634dfc3db6146101495780636637b8821461018a5780638da5cb5b146101ac578063e66f53b7146101be578063e90956cf146101d0578063ff2f4bd2146101f2575b005b61024460043560048054829081101561000257506000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b015481565b610098600435600054600160a060020a03908116339091161461026157610002565b610098600435600054600160a060020a03908116339091161461027657610002565b61024e600154600160a060020a031681565b6102446004545b90565b61024e600254600160a060020a031681565b61024460008054600160a060020a03908116339091161480159061017d5750600154600160a060020a039081163390911614155b1561028b57506001610134565b610098600435600054600160a060020a0390811633909116146102c157610002565b61024e600054600160a060020a031681565b61024e600354600160a060020a031681565b610098600435600054600160a060020a0390811633909116146102d657610002565b6100986000606081815260a06040526080828152825491929091819033600160a060020a0390811691161480159061023a5750600154600160a060020a039081163390911614155b1561031857610002565b6060908152602090f35b600160a060020a03166060908152602090f35b60008054600160a060020a0319168217905550565b60018054600160a060020a0319168217905550565b600254600160a060020a03168114156102a657506002610134565b600354600160a060020a031681141561013457506003610134565b60028054600160a060020a0319168217905550565b60038054600160a060020a0319168217905550565b50508054839250600019810190811015610002579060005260206000209001600050819055505b50505050565b6002547f70a082310000000000000000000000000000000000000000000000000000000060a090815230600160a060020a0390811660a45291909116906370a082319060c49060209060248187876161da5a03f11561000257505060405151821415905061038557610312565b60006040518059106103945750595b9080825280602002602001820160405250935062093a809150600260009054906101000a9004600160a060020a0316600160a060020a031663612e45a3600360009054906101000a9004600160a060020a0316600086888760016040518760e060020a0281526004018087600160a060020a03168152602001868152602001806020018060200185815260200184151581526020018381038352878181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156104815780820380516001836020036101000a031916815260200191505b508381038252868181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156104da5780820380516001836020036101000a031916815260200191505b50985050505050505050506020604051808303816000876161da5a03f1156100025750506040515160048054600181018083559294509250908280158290116102eb578183600052602060002091820191016102eb91905b808211156105465760008155600101610532565b509056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000003e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000304a554a310c7e546dfe434669c62820b7d83490", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd1a0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd1a1": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd1a2": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd1a3": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd1a4": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0xad3ecf23c0c8983b07163708be6d763b5f056193": { + "balance": "0x0", + "code": "0x606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b9291505056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000304a554a310c7e546dfe434669c62820b7d83490", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0xbe3ae5cb97c253dda67181c6e34e43f5c275e08b": { + "balance": "0x167d285b38143c04f", + "nonce": "68" + }, + "0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89": { + "balance": "0x9651c71936", + "code": "0x606060405236156100b95760e060020a600035046313af4035811461019e57806326f5a8c9146101c1578063371fa854146101ca5780634162169f146101d35780634c8fe526146101e55780635970c915146101f757806361bc221a14610209578063625e847d146102125780636637b882146102325780637f9f519f146102555780638da5cb5b14610278578063a9059cbb1461028a578063c4463c80146102b0578063c9d27afe146102df578063e66f53b714610305575b6103176002547f0e708203000000000000000000000000000000000000000000000000000000006060908152600091600160a060020a031690630e7082039060649060209060048187876161da5a03f1156100025750506040515133600160a060020a039081169116149050610329576040805133600160a060020a03166020820152818152600f818301527f636f6e73747563746f72206661696c0000000000000000000000000000000000606082015290517fa6af7265d7ede5fbf0ee375956b52b362800d4f92e268809bef5fdf2a57924b89181900360800190a15060015b90565b61031760043560008054600160a060020a03908116339091161461049257610002565b61047560055481565b61047560045481565b61047f600254600160a060020a031681565b61047f600654600160a060020a031681565b61047f600754600160a060020a031681565b61047560035481565b61031760008054600160a060020a0390811633909116146104ef57610002565b61031760043560008054600160a060020a03908116339091161461057a57610002565b61031760043560008054600160a060020a0390811633909116146105d757610002565b61047f600054600160a060020a031681565b61031760043560243560008054600160a060020a03908116339091161461060f57610002565b61031760043560243560443560643560843560008054600160a060020a0390811633909116146106a657610002565b61031760043560243560008054600160a060020a0390811633909116146107bb57610002565b61047f600154600160a060020a031681565b60408051918252519081900360200190f35b60055460035460001990910190111561040257604080516002546006547f70a0823100000000000000000000000000000000000000000000000000000000835230600160a060020a03908116600485015293519184169363a9059cbb9391169184916370a0823191602480830192602092919082900301818a876161da5a03f11561000257505060408051805160e060020a63a9059cbb028252600482019490945260248101939093525160448084019360209350829003018187876161da5a03f11561000257505060016003819055915061019b9050565b6040805160038054600190810190915560025460048054925460e260020a632099877102855290840192909252600160a060020a03918216602484015292519216916382661dc491604480820192602092909190829003018187876161da5a03f11561000257506001925061019b915050565b6060908152602090f35b600160a060020a03166060908152602090f35b600160a060020a03821660609081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc90602090a181600060006101000a815481600160a060020a0302191690830217905550600190505b919050565b6001600355600754600160a060020a03908116908290301631606082818181858883f15050604080516002546001546004805460e260020a632099877102855290840152600160a060020a0390811660248401529251921694506382661dc493506044808201935060209291829003018187876161da5a03f11561000257506001925061019b915050565b6002805473ffffffffffffffffffffffffffffffffffffffff1916831790819055600160a060020a031660609081527fce6a5015a40a2ec38ce912a63bca374d85386207c6927d284292449f1431082290602090a15060016104ea565b600582905560608281527fbab6859bc098da798dbdc4860f0fee7467d703dadd975799e8c258b46a37d3de90602090a15060016104ea565b60025460e060020a63a9059cbb026060908152600160a060020a0385811660645260848590529091169063a9059cbb9060a49060209060448187876161da5a03f11561000257505060408051600160a060020a03861681526020810185905281517f69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de293509081900390910190a15060015b92915050565b6006805473ffffffffffffffffffffffffffffffffffffffff1990811686179091556001600381905580548216871790556004879055600584905560078054909116831790819055600160a060020a03908116908290301631606082818181858883f15050604080516002546004805460015460e260020a632099877102855291840152600160a060020a0390811660248401529251921694506382661dc493506044808201935060209291829003018187876161da5a03f11561000257505060408051600454600654908252600160a060020a0316602082015281517fa1ab731770d71027cd294cc0af5c8f5ec3c2ff5dbe6b75d68963d17192f8377b93509081900390910190a150600195945050505050565b6002547fc9d27afe0000000000000000000000000000000000000000000000000000000060609081526064859052831515608452600160a060020a039091169063c9d27afe9060a49060209060448187876161da5a03f11561000257505060408051858152841515602082015281517f8bfa1f40665434b48e7becc865cc0586ce3d6d2388521c05d4db87536ac8279993509081900390910190a15060016106a056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000003e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000304a554a310c7e546dfe434669c62820b7d83490" + } + }, + "0xea674fdde714fd979de3edf0f56aa9716b898ec8": { + "balance": "0x4ab3566739e7b24371", + "nonce": "286339" + }, + "0xf835a0247b0063c04ef22006ebe57c5f11977cc4": { + "balance": "0x9645db5736", + "code": "0x606060405236156100b95760e060020a600035046313af4035811461019e57806326f5a8c9146101c1578063371fa854146101ca5780634162169f146101d35780634c8fe526146101e55780635970c915146101f757806361bc221a14610209578063625e847d146102125780636637b882146102325780637f9f519f146102555780638da5cb5b14610278578063a9059cbb1461028a578063c4463c80146102b0578063c9d27afe146102df578063e66f53b714610305575b6103176002547f0e708203000000000000000000000000000000000000000000000000000000006060908152600091600160a060020a031690630e7082039060649060209060048187876161da5a03f1156100025750506040515133600160a060020a039081169116149050610329576040805133600160a060020a03166020820152818152600f818301527f636f6e73747563746f72206661696c0000000000000000000000000000000000606082015290517fa6af7265d7ede5fbf0ee375956b52b362800d4f92e268809bef5fdf2a57924b89181900360800190a15060015b90565b61031760043560008054600160a060020a03908116339091161461049257610002565b61047560055481565b61047560045481565b61047f600254600160a060020a031681565b61047f600654600160a060020a031681565b61047f600754600160a060020a031681565b61047560035481565b61031760008054600160a060020a0390811633909116146104ef57610002565b61031760043560008054600160a060020a03908116339091161461057a57610002565b61031760043560008054600160a060020a0390811633909116146105d757610002565b61047f600054600160a060020a031681565b61031760043560243560008054600160a060020a03908116339091161461060f57610002565b61031760043560243560443560643560843560008054600160a060020a0390811633909116146106a657610002565b61031760043560243560008054600160a060020a0390811633909116146107bb57610002565b61047f600154600160a060020a031681565b60408051918252519081900360200190f35b60055460035460001990910190111561040257604080516002546006547f70a0823100000000000000000000000000000000000000000000000000000000835230600160a060020a03908116600485015293519184169363a9059cbb9391169184916370a0823191602480830192602092919082900301818a876161da5a03f11561000257505060408051805160e060020a63a9059cbb028252600482019490945260248101939093525160448084019360209350829003018187876161da5a03f11561000257505060016003819055915061019b9050565b6040805160038054600190810190915560025460048054925460e260020a632099877102855290840192909252600160a060020a03918216602484015292519216916382661dc491604480820192602092909190829003018187876161da5a03f11561000257506001925061019b915050565b6060908152602090f35b600160a060020a03166060908152602090f35b600160a060020a03821660609081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc90602090a181600060006101000a815481600160a060020a0302191690830217905550600190505b919050565b6001600355600754600160a060020a03908116908290301631606082818181858883f15050604080516002546001546004805460e260020a632099877102855290840152600160a060020a0390811660248401529251921694506382661dc493506044808201935060209291829003018187876161da5a03f11561000257506001925061019b915050565b6002805473ffffffffffffffffffffffffffffffffffffffff1916831790819055600160a060020a031660609081527fce6a5015a40a2ec38ce912a63bca374d85386207c6927d284292449f1431082290602090a15060016104ea565b600582905560608281527fbab6859bc098da798dbdc4860f0fee7467d703dadd975799e8c258b46a37d3de90602090a15060016104ea565b60025460e060020a63a9059cbb026060908152600160a060020a0385811660645260848590529091169063a9059cbb9060a49060209060448187876161da5a03f11561000257505060408051600160a060020a03861681526020810185905281517f69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de293509081900390910190a15060015b92915050565b6006805473ffffffffffffffffffffffffffffffffffffffff1990811686179091556001600381905580548216871790556004879055600584905560078054909116831790819055600160a060020a03908116908290301631606082818181858883f15050604080516002546004805460015460e260020a632099877102855291840152600160a060020a0390811660248401529251921694506382661dc493506044808201935060209291829003018187876161da5a03f11561000257505060408051600454600654908252600160a060020a0316602082015281517fa1ab731770d71027cd294cc0af5c8f5ec3c2ff5dbe6b75d68963d17192f8377b93509081900390910190a150600195945050505050565b6002547fc9d27afe0000000000000000000000000000000000000000000000000000000060609081526064859052831515608452600160a060020a039091169063c9d27afe9060a49060209060448187876161da5a03f11561000257505060408051858152841515602082015281517f8bfa1f40665434b48e7becc865cc0586ce3d6d2388521c05d4db87536ac8279993509081900390910190a15060016106a056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000003e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000304a554a310c7e546dfe434669c62820b7d83490" + } + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "1881284", + "difficulty": "59917798852808", + "timestamp": "1468467296", + "gasLimit": "4712388", + "miner": "0xea674fdde714fd979de3edf0f56aa9716b898ec8" + }, + "input": "0xf869448505d21dba00833567e09403e3d4561a8f8e975fdcd798d32857a20cf25e7e8084be9a65551ba0d4dd5fff30e83fbe630bb0fd67eeefe9e3aad0c3ee870a2b6e80fc40191bc7d4a074f93b546bfad60f3cae8e4aafef835237095d6618334154a24df4b4d49d9359", + "tracerConfig": { + "withLog": true + }, + "result": { + "from": "0xbe3ae5cb97c253dda67181c6e34e43f5c275e08b", + "gas": "0x3514c8", + "gasUsed": "0x26e1ef", + "to": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "input": "0xbe9a6555", + "calls": [ + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x34affa", + "gasUsed": "0x1ef", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x4b6753bc", + "output": "0x0000000000000000000000000000000000000000000000000000000057870858", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x34abef", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a08231000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89", + "output": "0x00000000000000000000000000000000000000000001819451f999d617dafa93", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x34a705", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a08231000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89", + "output": "0x00000000000000000000000000000000000000000001819451f999d617dafa93", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x34a31a", + "gasUsed": "0xa2f3", + "to": "0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89", + "input": "0xa9059cbb0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd00000000000000000000000000000000000000000001819451f999d617dafa93", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89", + "gas": "0x343e8c", + "gasUsed": "0x9a62", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd00000000000000000000000000000000000000000001819451f999d617dafa93", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89", + "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd" + ], + "data": "0x00000000000000000000000000000000000000000001819451f999d617dafa93" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89", + "topics": [ + "0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2" + ], + "data": "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd00000000000000000000000000000000000000000001819451f999d617dafa93" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x33ff04", + "gasUsed": "0x168e", + "to": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "input": "0xa8618f710000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "calls": [ + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x339a3b", + "gasUsed": "0x329", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x81f03fcb0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x3395a4", + "gasUsed": "0x15f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x0e708203", + "output": "0x000000000000000000000000ad3ecf23c0c8983b07163708be6d763b5f056193", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x339363", + "gasUsed": "0x113", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0xd2cc718f", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x339129", + "gasUsed": "0x329", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x81f03fcb0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x338cfa", + "gasUsed": "0x13f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x18160ddd", + "output": "0x00000000000000000000000000000000000000000003034f5ca7d45e17df199b", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x338a75", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x00000000000000000000000000000000000000000001819451f999d617dafa93", + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x33e6f2", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a08231000000000000000000000000f835a0247b0063c04ef22006ebe57c5f11977cc4", + "output": "0x00000000000000000000000000000000000000000001819451f999d617dafa76", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x33e208", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a08231000000000000000000000000f835a0247b0063c04ef22006ebe57c5f11977cc4", + "output": "0x00000000000000000000000000000000000000000001819451f999d617dafa76", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x33de20", + "gasUsed": "0x685b", + "to": "0xf835a0247b0063c04ef22006ebe57c5f11977cc4", + "input": "0xa9059cbb0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd00000000000000000000000000000000000000000001819451f999d617dafa76", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0xf835a0247b0063c04ef22006ebe57c5f11977cc4", + "gas": "0x337992", + "gasUsed": "0x5fca", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd00000000000000000000000000000000000000000001819451f999d617dafa76", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000f835a0247b0063c04ef22006ebe57c5f11977cc4", + "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd" + ], + "data": "0x00000000000000000000000000000000000000000001819451f999d617dafa76" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0xf835a0247b0063c04ef22006ebe57c5f11977cc4", + "topics": [ + "0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2" + ], + "data": "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd00000000000000000000000000000000000000000001819451f999d617dafa76" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x3374a2", + "gasUsed": "0x168e", + "to": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "input": "0xa8618f710000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "calls": [ + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x330fd9", + "gasUsed": "0x329", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x81f03fcb0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x330b42", + "gasUsed": "0x15f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x0e708203", + "output": "0x000000000000000000000000ad3ecf23c0c8983b07163708be6d763b5f056193", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x330901", + "gasUsed": "0x113", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0xd2cc718f", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x3306c7", + "gasUsed": "0x329", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x81f03fcb0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x330298", + "gasUsed": "0x13f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x18160ddd", + "output": "0x00000000000000000000000000000000000000000003034f5ca7d45e17df199b", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x330013", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x000000000000000000000000000000000000000000030328a3f333ac2fb5f509", + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x33490b", + "gasUsed": "0x3f781", + "to": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "input": "0xfc340716", + "calls": [ + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x32e30d", + "gasUsed": "0x15f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x0e708203", + "output": "0x000000000000000000000000ad3ecf23c0c8983b07163708be6d763b5f056193", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x32e037", + "gasUsed": "0x15f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x0e708203", + "output": "0x000000000000000000000000ad3ecf23c0c8983b07163708be6d763b5f056193", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x32dd7b", + "gasUsed": "0x113", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0xd2cc718f", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x32daf9", + "gasUsed": "0x329", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x81f03fcb0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x32d6ab", + "gasUsed": "0x13f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x18160ddd", + "output": "0x00000000000000000000000000000000000000000003034f5ca7d45e17df199b", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x32d400", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x000000000000000000000000000000000000000000030328a3f333ac2fb5f509", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x32c975", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x000000000000000000000000000000000000000000030328a3f333ac2fb5f509", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x3276d3", + "gasUsed": "0xa49d", + "to": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "input": "0xd0679d340000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccd", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x320fe1", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x000000000000000000000000000000000000000000030328a3f333ac2fb5f509", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x320b5b", + "gasUsed": "0x9a62", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccd", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc" + ], + "data": "0x0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccd" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x3164e1", + "gasUsed": "0x4e91", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0x", + "value": "0x4563918244f400000", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x3115cc", + "gasUsed": "0x113", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0xd2cc718f", + "output": "0x000000000000000000000000000000000000000000000004563918244f400000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x311382", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc", + "output": "0x0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccd", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x310f37", + "gasUsed": "0x329", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x81f03fcb0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x310ae9", + "gasUsed": "0x1446e", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xcc9ae3f6", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x30a397", + "gasUsed": "0x113", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0xd2cc718f", + "output": "0x000000000000000000000000000000000000000000000004563918244f400000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x309fc1", + "gasUsed": "0x113", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0xd2cc718f", + "output": "0x000000000000000000000000000000000000000000000004563918244f400000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x309c45", + "gasUsed": "0x122af", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0x0221038a0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc0000000000000000000000000000000000000000000000022b1c8c12279fffff", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "gas": "0x301e6f", + "gasUsed": "0x10068", + "to": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "input": "0x", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x2fbb97", + "gasUsed": "0x15f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x0e708203", + "output": "0x000000000000000000000000ad3ecf23c0c8983b07163708be6d763b5f056193", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x2fa477", + "gasUsed": "0xe7b6", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xcc9ae3f6", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x2f3d25", + "gasUsed": "0x113", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0xd2cc718f", + "output": "0x000000000000000000000000000000000000000000000004563918244f400000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x2f394f", + "gasUsed": "0x113", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0xd2cc718f", + "output": "0x000000000000000000000000000000000000000000000004563918244f400000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x2f35d3", + "gasUsed": "0x8b5f", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0x0221038a0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc0000000000000000000000000000000000000000000000022b1c8c12279fffff", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "gas": "0x2eb7fd", + "gasUsed": "0x6918", + "to": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "input": "0x", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x2e5525", + "gasUsed": "0x15f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x0e708203", + "output": "0x000000000000000000000000ad3ecf23c0c8983b07163708be6d763b5f056193", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x2e5168", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc", + "output": "0x0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccd", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x2e4d69", + "gasUsed": "0x5fca", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccc", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc", + "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd" + ], + "data": "0x0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccc" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x22b1c8c12279fffff", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "topics": [ + "0x9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc", + "0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc" + ], + "data": "0x0000000000000000000000000000000000000000000000022b1c8c12279fffff" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x22b1c8c12279fffff", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "topics": [ + "0x9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc", + "0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc" + ], + "data": "0x0000000000000000000000000000000000000000000000022b1c8c12279fffff" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "gas": "0x2fc505", + "gasUsed": "0xd4fa", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f0000000000000000000000000000000000000000000000000000000000000001", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc", + "0x0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "topics": [ + "0x07cf7e805770612a8b2ee8e0bcbba8aa908df5f85fbc4f9e2ef384cf75315038" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "address": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc", + "topics": [ + "0x7027eecbd2a688fc1fa281702b311ed7168571514adfd17014a55d828cb43382" + ], + "data": "0x000000000000000000000000000000000000000000000004563918244f400000" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x2f5092", + "gasUsed": "0x14e37", + "to": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "input": "0xd95f98ce", + "calls": [ + { + "from": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "gas": "0x2eea7c", + "gasUsed": "0x329", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x81f03fcb0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f", + "output": "0x000000000000000000000000000000000000000000000004563918244f3ffffe", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "gas": "0x2ee4cb", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a08231000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526", + "output": "0x000000000000000000000000000000000000000000000026b8b4a0b1e8292492", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "gas": "0x2edfff", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "gas": "0x2edb9a", + "gasUsed": "0x6994", + "to": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "input": "0xd0679d340000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f0000000000000000000000000000000000000000000000000000000000000063", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x2e7519", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x000000000000000000000000000000000000000000030328a3f333ac2fb5f508", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x2e7093", + "gasUsed": "0x5fca", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f0000000000000000000000000000000000000000000000000000000000000063", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "0x0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000063" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "gas": "0x2e6f59", + "gasUsed": "0x329", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x81f03fcb000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "gas": "0x2e6afa", + "gasUsed": "0x1113", + "to": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "input": "0x65f13792000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526", + "output": "0x0000000000000000000000000000000000000000000000000037bc5737aa7ba8", + "calls": [ + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x2e06f9", + "gasUsed": "0x15f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x0e708203", + "output": "0x000000000000000000000000ad3ecf23c0c8983b07163708be6d763b5f056193", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x2e04b8", + "gasUsed": "0x113", + "to": "0xad3ecf23c0c8983b07163708be6d763b5f056193", + "input": "0xd2cc718f", + "output": "0x000000000000000000000000000000000000000000000004563918244f400000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x2e027b", + "gasUsed": "0x329", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x81f03fcb000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x2dfe4c", + "gasUsed": "0x13f", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x18160ddd", + "output": "0x00000000000000000000000000000000000000000003034f5ca7d45e17df199b", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x2dfbc7", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a08231000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526", + "output": "0x000000000000000000000000000000000000000000000026b8b4a0b1e8292492", + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "gas": "0x2e5281", + "gasUsed": "0x329", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x81f03fcb0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f", + "output": "0x000000000000000000000000000000000000000000000004563918244f3ffffe", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "gas": "0x2e4dcc", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f", + "output": "0x0000000000000000000000000000000000000000000000000000000000000064", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "gas": "0x2e4857", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a08231000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526", + "output": "0x000000000000000000000000000000000000000000000026b8b4a0b1e8292492", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "gas": "0x2e3bae", + "gasUsed": "0x9a62", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb000000000000000000000000da4a4626d3e16e094de3225a751aab7128e965260000000000000000000000000000000000000000000000000000000000000064", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f", + "0x000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000064" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "topics": [ + "0x4b0bc4f25f8d0b92d2e12b686ba96cd75e4e69325e6cf7b1f3119d14eaf2cbdf" + ], + "data": "0x000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526" + }, + { + "address": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f", + "topics": [ + "0xf340c079d598119636d42046c6a2d2faf7a68c04aecee516f0e0b8a9e79b8666" + ], + "data": "0x000000000000000000000000da4a4626d3e16e094de3225a751aab7128e9652600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x2e00dc", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x2dfc58", + "gasUsed": "0xa3bb", + "to": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "input": "0xd0679d340000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b0000000000000000000000000000000000000000000000000000000000000001", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x2d9648", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x000000000000000000000000000000000000000000030328a3f333ac2fb5f4a5", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0x2d91c2", + "gasUsed": "0x9a62", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb0000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b0000000000000000000000000000000000000000000000000000000000000001", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "0x0000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x2d57a6", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x2d5515", + "gasUsed": "0x3478d", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0xff2f4bd2", + "calls": [ + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x2ceffb", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x2ce86e", + "gasUsed": "0x29e8d", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x612e45a3000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f", + "0x0000000000000000000000000000000000000000000000000000000000000001" + ], + "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x2a0c87", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x2a09f6", + "gasUsed": "0x30cf5", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0xff2f4bd2", + "calls": [ + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x29a4dc", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x299d4f", + "gasUsed": "0x29e8d", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x612e45a3000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000002", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f", + "0x0000000000000000000000000000000000000000000000000000000000000002" + ], + "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x26fc00", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x0000000000000000000000000000000000000000000000000000000000000002", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x26f96f", + "gasUsed": "0x30cf5", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0xff2f4bd2", + "calls": [ + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x269455", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x268cc8", + "gasUsed": "0x29e8d", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x612e45a3000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000003", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f", + "0x0000000000000000000000000000000000000000000000000000000000000003" + ], + "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x23eb79", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x0000000000000000000000000000000000000000000000000000000000000003", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x23e8e8", + "gasUsed": "0x30cf5", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0xff2f4bd2", + "calls": [ + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x2383ce", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x237c41", + "gasUsed": "0x29e8d", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x612e45a3000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000004", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f", + "0x0000000000000000000000000000000000000000000000000000000000000004" + ], + "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x20daf2", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x0000000000000000000000000000000000000000000000000000000000000004", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x20d861", + "gasUsed": "0x30cf5", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0xff2f4bd2", + "calls": [ + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x207347", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x206bba", + "gasUsed": "0x29e8d", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x612e45a3000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000005", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f", + "0x0000000000000000000000000000000000000000000000000000000000000005" + ], + "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x1dca6b", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x0000000000000000000000000000000000000000000000000000000000000005", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x1dc7da", + "gasUsed": "0x30cf5", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0xff2f4bd2", + "calls": [ + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x1d62c0", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x1d5b33", + "gasUsed": "0x29e8d", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x612e45a3000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000006", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f", + "0x0000000000000000000000000000000000000000000000000000000000000006" + ], + "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x1ab9e4", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x0000000000000000000000000000000000000000000000000000000000000006", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x1ab753", + "gasUsed": "0x30cf5", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0xff2f4bd2", + "calls": [ + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x1a5239", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x1a4aac", + "gasUsed": "0x29e8d", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x612e45a3000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000007", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f", + "0x0000000000000000000000000000000000000000000000000000000000000007" + ], + "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x17a95d", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x0000000000000000000000000000000000000000000000000000000000000007", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x17a6cc", + "gasUsed": "0x30cf5", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0xff2f4bd2", + "calls": [ + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x1741b2", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x173a25", + "gasUsed": "0x29e8d", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x612e45a3000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000008", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f", + "0x0000000000000000000000000000000000000000000000000000000000000008" + ], + "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x1498d6", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x0000000000000000000000000000000000000000000000000000000000000008", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x149645", + "gasUsed": "0x30cf5", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0xff2f4bd2", + "calls": [ + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x14312b", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x14299e", + "gasUsed": "0x29e8d", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x612e45a3000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000009", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f", + "0x0000000000000000000000000000000000000000000000000000000000000009" + ], + "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x11884f", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x0000000000000000000000000000000000000000000000000000000000000009", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0x1185be", + "gasUsed": "0x30cf5", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0xff2f4bd2", + "calls": [ + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x1120a4", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "gas": "0x111917", + "gasUsed": "0x29e8d", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x612e45a3000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000093a80000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "output": "0x000000000000000000000000000000000000000000000000000000000000000a", + "calls": [ + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x304a554a310c7e546dfe434669c62820b7d83490", + "gas": "0x3", + "gasUsed": "0x3", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x", + "error": "out of gas", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f", + "0x000000000000000000000000000000000000000000000000000000000000000a" + ], + "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0xe77c8", + "gasUsed": "0x112", + "to": "0x7498bb5749c9801f1f7e490baf5f966dbfe4e97b", + "input": "0x400e3949", + "output": "0x000000000000000000000000000000000000000000000000000000000000000a", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", + "gas": "0xe7537", + "gasUsed": "0x1eafd", + "to": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "input": "0x975057e7", + "calls": [ + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0xe0f53", + "gasUsed": "0x314", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0x70a082310000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "output": "0x000000000000000000000000000000000000000000030328a3f333ac2fb5f4a4", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0xe096d", + "gasUsed": "0x9a62", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb0000000000000000000000007ccbc69292c7a6d7b538c91f3b283de97906cf3000000000000000000000000000000000000000000001010d8bfbbbe40fe7518c", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "0x0000000000000000000000007ccbc69292c7a6d7b538c91f3b283de97906cf30" + ], + "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0xd6871", + "gasUsed": "0x9a62", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb0000000000000000000000001b9ec8ba24630b75a7a958153ffff56dd6d4b6a200000000000000000000000000000000000000000001010d8bfbbbe40fe7518c", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "0x0000000000000000000000001b9ec8ba24630b75a7a958153ffff56dd6d4b6a2" + ], + "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "gas": "0xcc775", + "gasUsed": "0x9a62", + "to": "0x304a554a310c7e546dfe434669c62820b7d83490", + "input": "0xa9059cbb000000000000000000000000c3a2c744ad1f5253c736875b93bacce5b01b060b00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x304a554a310c7e546dfe434669c62820b7d83490", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd", + "0x000000000000000000000000c3a2c744ad1f5253c736875b93bacce5b01b060b" + ], + "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "topics": [ + "0xc6d8c0af6d21f291e7c359603aa97e0ed500f04db6e983b9fce75a91c6b8da6b" + ], + "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c" + }, + { + "address": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "topics": [ + "0xc6d8c0af6d21f291e7c359603aa97e0ed500f04db6e983b9fce75a91c6b8da6b" + ], + "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c" + }, + { + "address": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd", + "topics": [ + "0xc6d8c0af6d21f291e7c359603aa97e0ed500f04db6e983b9fce75a91c6b8da6b" + ], + "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json new file mode 100644 index 000000000000..858931558a99 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json @@ -0,0 +1,530 @@ +{ + "genesis": { + "difficulty": "7507253814130", + "extraData": "0xd783010400844765746887676f312e352e31856c696e7578", + "gasLimit": "3141592", + "hash": "0x3d9d19618f67bbb7708403fe9bda131fbade0449d2ac12bf3b140b4269112826", + "miner": "0x63a9975ba31b0b9626b34300f7f627147df1f526", + "mixHash": "0x50aaa8973eadd4bbfc7f5b59d5be52f6a1be2d38f40b5a0786a24b90257520da", + "nonce": "0x3547956c62c256b9", + "number": "595531", + "stateRoot": "0x79d00dd270bffc48d89fa55842f63f840981121378da8c6de4d479535f25ed6a", + "timestamp": "1448471472", + "totalDifficulty": "3448100174991667199", + "alloc": { + "0x2a65aca4d5fc5b5c859090a6c34d164135398226": { + "balance": "0x44dc051cccdfd2e132", + "nonce": "39602" + }, + "0x350e0ffc780a6a75b44cc52e1ff9092870668945": { + "balance": "0xe37111b7c79406c0", + "code": "0x606060405236156100f05760e060020a60003504631ff6c70581146100f257806347980c0d146100fd57806353ba9c2f146101085780635ea8cd12146101c957806369d640fd146101f05780637ce3489b146102405780637d1bb97a1461026b5780637fd6f15c146103e55780638bf50628146103f057806390a248f814610411578063a8f37bb214610438578063b019e0171461046a578063b4c70cea1461059b578063cf955f34146106a1578063d229b54b146106bd578063d54b4a04146106e4578063e021fadb146106f1578063e45be8eb14610858578063eddfa7c814610863578063f2a75fe41461095d575b005b6109a5621e84845481565b6109a5621e84865481565b6109b76004356024356000808080806003876103e881101561000257506107d0880201866103e8811015610002579090600202016000505461ffff168152602081019190915260400160002054600160a060020a031692506003856103e881101561000257506107d0860201846103e88110156100025790906002020160005054620100009004600390810b9250856103e881101561000257506107d0860201846103e8811015610002579090600202016000506001015490509250925092565b6100f0600435621e848354600160a060020a0390811633909116141561026857621e848755565b6109e36004356024356003826103e881101561000257506107d0830201816103e88110156100025790906002020160005080546001919091015461ffff821693506201000090910460030b915083565b6100f0600435621e848354600160a060020a0390811633909116141561026857621e84858190555b50565b610a0a600435617d00604051908101604052806103e8905b600081526020019060019003908161028357505060408051617d0081019091526103e8815b60008152602001906001900390816102a857505060408051617d0081019091526103e8815b60008152602001906001900390816102cd5750600090505b6103e861ffff82161015610d09576000806003836103e8811015610002576107d002018150876103e881101561000257600202016000505461ffff168152602081019190915260400160002054600160a060020a031684826103e8811015610002575050602082028501526003816103e8811015610002576107d00201600050856103e8811015610002579090600202016000505462010000900460030b83826103e8811015610002575050600390810b60208302850152816103e8811015610002576107d00201600050856103e8811015610002579090600202016000506001015482826103e8811015610002575050602082028301526001016102e5565b6109a5621e84855481565b610a59600435600060208190529081526040902054600160a060020a031681565b6100f0600435621e848354600160a060020a0390811633909116141561026857621e848655565b6100f060043560243560443560643560843560a435610a8e868684866101000288620100000286607f02010101610870565b604080516004803580820135602081810280860182019096528185526100f09593946024949093850192918291908501908490808284375050604080518735808a013560208181028085018201909552818452989a996044999398509190910195509350839250850190849080828437505060408051606435808a013560208181028085018201909552818452989a9935999860849850929650602491909101945092508291908501908490808284375050604080519635808901356020818102808b018201909452818a5297999860a4989097506024929092019550935083925085019084908082843750949650505050505050621e848354600090600160a060020a03908116339091161415610a8e575b8551811015610a8e57606060405190810160405280610d1186610ebc565b60408051602060248035600481810135601f81018590048502860185019096528585526109a5958135959194604494929390920191819084018382808284375094965050933593505050505b6000831515610699577ffd33e90d0eac940755277aa91045b95664988beeeafc4ed7d1281a6d83afbc003384846040518084600160a060020a03168152602001806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106895780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a15b509192915050565b610a7660043560016020526000908152604090205461ffff1681565b6100f0600435621e848354600160a060020a0390811633909116141561026857621e848455565b610a7660025461ffff1681565b604080516004803580820135602081810280860182019096528185526109a59593946024949093850192918291908501908490808284375050604080518735808a013560208181028085018201909552818452989a9960449993985091909101955093508392508501908490808284375050604080519635808901356020818102808b018201909452818a529799986064989097506024929092019550935083925085019084908082843750506040805196358089013560208181028a81018201909452818a5297999860849890975060249290920195509350839250850190849080828437509496505050505050506000600060006000610ad68751895114606060405190810160405280602381526020017f446966666572656e74206e756d626572206f66207856616c732061732079566181526020017f6c732e00000000000000000000000000000000000000000000000000000000008152602001508a516105e7565b6109a5621e84875481565b6100f06004356024356044355b6000610a96848484345b6000808080808060038a6103e8811015610002576107d00201896103e88110156100025760020201805461ffff16825260208290526040822054621e8484546001830154621e848654939850600160a060020a03928316975060649181028290049650929092029190910492503316841415610f4d57610fbc82341015606060405190810160405280602e81526020017f4368616e67696e6720796f7572206f776e20706978656c20636f73747320313081526020017f25206f66206974732076616c7565000000000000000000000000000000000000815260200150846105e7565b6100f0621e848354600160a060020a039081163390911614156109a357604051621e848354600160a060020a03908116916000913016319082818181858883f150505050505b565b60408051918252519081900360200190f35b60408051600160a060020a0394909416845260039290920b602084015282820152519081900360600190f35b6040805161ffff94909416845260039290920b602084015282820152519081900360600190f35b6040518084617d008083818460006004610bc7f150918201918591508083818460006004610bc7f15061fa00840192508491508083818460006004610bc7f15062017700965092945050505050f35b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b505050505050565b90506000811115610ac25760405133600160a060020a031690600090839082818181858883f150505050505b50505050565b93505b505050949350505050565b1580610b4e5750610b4c8651895114606060405190810160405280602481526020017f446966666572656e74206e756d626572206f66207856616c7320617320636f6c81526020017f6f72732e000000000000000000000000000000000000000000000000000000008152602001508a516105e7565b155b80610bc55750610bc38551895114606060405190810160405280602481526020017f446966666572656e74206e756d626572206f66207856616c732061732070726981526020017f6365732e000000000000000000000000000000000000000000000000000000008152602001508a516105e7565b155b15610bd35760009350610acb565b5034915060009050805b8751811015610c63578481815181101561000257602090810290910101519092039160008310610d0157610cfb88828151811015610002579060200190602002015188838151811015610002579060200190602002015188848151811015610002579060200190602002015188858151811015610002579060200190602002015161087a565b6000821115610c8d5760405133600160a060020a031690600090849082818181858883f150505050505b610ac86000841015606060405190810160405280602181526020017f56616c756520776173206c657373207468616e2073756d206f6620707269636581526020017f7300000000000000000000000000000000000000000000000000000000000000815260200150856105e7565b91909101905b600101610bdd565b509193909250565b8152602001848381518110156100025790602001906020020151815260200183838151811015610002579060200190602002015181526020015060036000508783815181101561000257906020019060200201516103e8811015610002576107d002016000508683815181101561000257906020019060200201516103e8811015610002576002020160005081518154602084015160e060020a90810204620100000261ffff199190911690911765ffffffff00001916178155604091909101516001919091015560010161057d565b8454600061ffff919091161115610e225750604051621e84855460649088020490600160a060020a03851690600090838a039082818181858883f150505050505b845460018601546040805161ffff8e811682528d166020820152600160a060020a038881168284015262010000909404600390810b810b606083015260808201939093523390931660a0840152908a900b60c083015260e08201899052517fcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42918190036101000190a1606060405190810160405280611143335b600160a060020a03811660009081526001602052604081205461ffff1690811415610f485750604060008181206002805461ffff1981811661ffff928316600190810191821790945591821685526020858152958520805473ffffffffffffffffffffffffffffffffffffffff191688179055600160a060020a03871690945293528054909116821790555b919050565b60408051621e848754606082018352602182527f4d696e696d756d20706978656c2070726963652069732035302066696e6e657960208301527f2e00000000000000000000000000000000000000000000000000000000000000928201929092526110c29134101590896105e7565b1515610fca578695506110b5565b33600160a060020a031684600160a060020a03161415610de157604080518654600188015461ffff8e811684528d166020840152600160a060020a03881683850181905262010000909204600390810b810b60608501526080840182905260a0840192909252908b900b60c083015260e082015290517fcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42918190036101000190a18760038b6103e8811015610002576107d002018a6103e88110156100025760020201805465ffffffff0000191660e060020a92830292909204620100000291909117905581870395505b5050505050949350505050565b15806111365750610fbc83341015606060405190810160405280603281526020017f56616c7565206d7573742062652031302520686967686572207468616e20637581526020017f7272656e7420706978656c2070726963652e0000000000000000000000000000815260200150856105e7565b15610fca578695506110b5565b8152602081018a905260400188905260038b6103e8811015610002576107d002018a6103e8811015610002576002020160005081518154602084015160e060020a90810204620100000261ffff199190911690911765ffffffff000019161781556040919091015160019190910155600095506110b556", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000175901": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000175902": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000175903": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000175904": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760c7": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760c8": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760c9": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760ca": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760cb": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760cc": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760cd": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760ce": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760cf": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760d0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760d1": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760d2": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760d3": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760d4": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760d5": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760d6": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760d7": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760d8": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760d9": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760da": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760db": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760dc": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760dd": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760de": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760df": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001760e0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000176897": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000176898": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000176899": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000017689a": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000017689b": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000017689c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000017689d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000017689e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000017689f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768a0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768a7": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768a8": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768a9": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768aa": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768ab": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768ac": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768ad": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768ae": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768af": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001768b0": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c37": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c38": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c39": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c3a": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c3b": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c3c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c3d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c3e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c3f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c40": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c45": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c46": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c47": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c48": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c49": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c4a": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c4b": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c4c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c4d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c4e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c4f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000196c50": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197407": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197408": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197409": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019740a": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019740b": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019740c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019740d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019740e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019740f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197410": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197411": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197412": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197413": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197414": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197415": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197416": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197417": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197418": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197419": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019741a": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019741b": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019741c": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019741d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019741e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000000000000000000000000000000000000019741f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197420": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197be3": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000197be4": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000001e8484": "0x000000000000000000000000000000000000000000000000000000000000006e", + "0x00000000000000000000000000000000000000000000000000000000001e8486": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000001e8487": "0x0000000000000000000000000000000000000000000000000011c37937e08000", + "0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xe1723559c995b1804c0512df6fe6d061eeb47aff37a3ced3b93f0c1bef247540": "0x0000000000000000000000000000000000000000000000000000000000000007" + } + }, + "0x3fcb0342353c541e210013aaddc2e740b9a33d08": { + "balance": "0x6a0e4be198f18400", + "nonce": "17" + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "595532", + "difficulty": "7503588162862", + "timestamp": "1448471495", + "gasLimit": "3141592", + "miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226" + }, + "input": "0xf91a7311850ba43b7400832dc6c094350e0ffc780a6a75b44cc52e1ff90928706689458803782dace9d90000b91a04e021fadb000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000006e00000000000000000000000000000000000000000000000000000000000000d4000000000000000000000000000000000000000000000000000000000000013a00000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fd000000000000000000000000000000000000000000000000000000000000034300000000000000000000000000000000000000000000000000000000000002fd0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003900000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003900000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000032fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebebebffffffffffffffffffffffffffffffffffffffffffffffffffffffffff888888ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3b3b3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3e3e3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e3e3effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbdbdbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f4f4fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0b0b0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0a0a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b5b5bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9a9a9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb9b9b9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababaffffffffffffffffffffffffffffffffffffffffffffffffffffffffff636363fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9c9cfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4d4e53ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f494b00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080001ca0e8a879dd98a39d735b866ff64d84e9c144a17bcab106cf2f1327b1272db06aaca02ab279a2459b5e30dfea0bc8a888c7d2a190740090352b4a7aded30c45490af9", + "tracerConfig": { + "withLog": true + }, + "result": { + "from": "0x3fcb0342353c541e210013aaddc2e740b9a33d08", + "gas": "0x2b0868", + "gasUsed": "0x2570bf", + "to": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "input": "0xe021fadb000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000006e00000000000000000000000000000000000000000000000000000000000000d4000000000000000000000000000000000000000000000000000000000000013a00000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fd000000000000000000000000000000000000000000000000000000000000034300000000000000000000000000000000000000000000000000000000000002fd0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003900000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003900000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000032fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebebebffffffffffffffffffffffffffffffffffffffffffffffffffffffffff888888ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3b3b3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3e3e3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e3e3effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbdbdbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f4f4fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0b0b0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0a0a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b5b5bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9a9a9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb9b9b9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababaffffffffffffffffffffffffffffffffffffffffffffffffffffffffff636363fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9c9cfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4d4e53ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f494b00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e08000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logs": [ + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfd0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebebeb0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8888880000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3b3b30000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfc0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3e3e30000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e3e3e0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbdbdb0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f4f40000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfb0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0b0b00000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0a0a00000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b5b5b0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababa0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaea0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9a9a90000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb9b9b90000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfb0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababa0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6363630000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f9f90000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaea0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9c9c0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f80000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfd0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfc0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfd0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4d4e530000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000034300000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000" + }, + { + "address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", + "topics": [ + "0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f494b0000000000000000000000000000000000000000000000000011c37937e08000" + } + ], + "value": "0x3782dace9d90000", + "type": "CALL" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json new file mode 100644 index 000000000000..09aa7af461e0 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json @@ -0,0 +1,286 @@ +{ + "genesis": { + "difficulty": "45944156141275", + "extraData": "0xd783010406844765746887676f312e342e32856c696e7578", + "gasLimit": "4714680", + "hash": "0x3c41811ab60f232565db6cfafb939d96255b9f678a203181c6f537d6c22d7e6f", + "miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5", + "mixHash": "0x8b736c63e05d381ae593d584b63fef5c31b04a3cea72bd5a3c92f95f4f7040e8", + "nonce": "0xce8ffb5c1ad942ec", + "number": "1725115", + "stateRoot": "0xca08a341c1f95fcba0821c4a27662ef162d39e1f9f5722717531f510d54112b0", + "timestamp": "1466232982", + "totalDifficulty": "28554024908214037524", + "alloc": { + "0x0000000000000000000000000000000000000004": { + "balance": "0x0" + }, + "0x1d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed": { + "balance": "0x0", + "code": "0x606060405260e060020a600035046338cc483181146038578063767800de14604f578063a6f9dae1146060578063d1d80fdf14607e575b005b600054600160a060020a03165b6060908152602090f35b6045600054600160a060020a031681565b603660043560015433600160a060020a03908116911614609c576002565b603660043560015433600160a060020a0390811691161460be576002565b6001805473ffffffffffffffffffffffffffffffffffffffff19168217905550565b6000805473ffffffffffffffffffffffffffffffffffffffff1916821790555056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x00000000000000000000000088e1315687aec48a72786c6b3b3f075208b62713" + } + }, + "0x50739060a2c32dc076e507ae1a893aab28ecfe68": { + "balance": "0x6a8ecefb09f7c4141", + "code": "0x606060405236156101745760e060020a6000350463058aace1811461017f578063061e494f146101905780630d1fce421461021e57806311610c251461029157806312253a6c146102b5578063132ae5e9146102d357806316d190e3146102dc57806329e206bd146102e5578063337b68ba1461030a57806338bbfa50146103135780633f683b6a146104115780634dc6b523146104245780634e69d5601461042d57806366d16cc31461044a578063724ae9d014610453578063758971e81461046f5780637cf0ffcb146104965780638ca17995146104a35780639619367d146104b7578063a96a5a5b146104c0578063adc2c98a146104c9578063b70d0b3b146104d2578063bc99cc37146104db578063c4bc5da5146104e4578063cafb220214610502578063d28442ef1461050b578063d4c80edf14610514578063df06f9061461051d578063e8b5e51f14610527578063f738e5ca14610546578063f8b2cb4f14610553578063fa968eea14610594575b610661610663610295565b6106616000341115610eab57610002565b61066560043560006000600060006000600f6000508054905086101561021657600f8054879081101561000257505050507f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac80284015490819052600e602052604090912080546001820154600283015460039390930154600160a060020a03929092169450925b509193509193565b6106965b601254601354601154600c5460009391019091010330600160a060020a0316318190101561028957604080517f62616e6b726f6c6c5f6d69736d61746368000000000000000000000000000000815290519081900360110190a05030600160a060020a0316315b8091505b5090565b6106615b600060006000600d60149054906101000a900460ff16156106ef57610002565b610661600d5433600160a060020a03908116911614610fd657610002565b610696600a5481565b61069660045481565b6106616004355b600d5460009033600160a060020a0390811691161461101c57610002565b61069660125481565b60408051602060248035600481810135601f81018590048502860185019096528585526106619581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760649791965060249190910194509092508291508401838280828437509496505050505050506000600060006000610a18600080546040805160e060020a6338cc483102815290518392600160a060020a0316916338cc4831916004828101926020929190829003018187876161da5a03f11561000257505060405151915050600160a060020a0381168214156114635761140b6000610939565b610696600d5460a060020a900460ff1681565b61069660085481565b6106a8600060006000600060006000600060006000610f8d610222565b61069660115481565b6106965b600a54600654600091829182911015610ef857610f33565b6106616004355b600d54600090819033600160a060020a0390811691161461108657610002565b61066161066360006102ec565b6106616004356000341115610e7957610002565b61069660055481565b61069660025481565b61069660035481565b61069660075481565b61069660065481565b610661600d5433600160a060020a03908116911614610ffc57610002565b610696600c5481565b61069660135481565b61069660105481565b610696600f545b90565b610661600d54600090819060a060020a900460ff1615610c8057610002565b6106616106636000610476565b6106966004355b600160a060020a0381166000908152600b602052604081205481901180156105845750600c548190115b15610ebd57600c54610ec6610222565b610696600080546040805160e060020a6338cc483102815290518392600160a060020a0316916338cc4831916004828101926020929190829003018187876161da5a03f11561000257505060408051805160e260020a630bbceb33028252620249f06024830152600482018390526003604483015260ea60020a621554930260648301529151600160a060020a03929092169250632ef3accc916084828101926020929190829003018187876161da5a03f1156100025750506040515160055481019350915061028d9050565b005b565b60408051600160a060020a039590951685526020850193909352838301919091526060830152519081900360800190f35b60408051918252519081900360200190f35b60408051998a5260208a0198909852888801969096526060880194909452608087019290925260a086015260c085015260e084015261010083015251908190036101200190f35b600060009054906101000a9004600160a060020a0316600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e260020a630bbceb33028252620249f06024830152600482018390526003604483015260ea60020a621554930260648301529151600160a060020a03929092169250632ef3accc91608480830192602092919082900301816000876161da5a03f1156100025750506040515193505034839010156107c257610002565b82340391506127106107d2610222565b600460005054020460026000505460026000505460036000505461271003038402041115801561080457506005548210155b1561095a576040805180820182526003815260ea60020a62155493026020828101919091528251608081018452604381527f6a736f6e2868747470733a2f2f6170692e72616e646f6d2e6f72672f6a736f6e818301527f2d7270632f312f696e766f6b65292e726573756c742e72616e646f6d2e646174818501527f612e30000000000000000000000000000000000000000000000000000000000060608201528351610160810190945261012c80855261095f94919261175690830139620249f0600060006000600060009054906101000a9004600160a060020a0316600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151915050600160a060020a03811682141561118c5761113460005b600060006115ef731d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed5b3b90565b610002565b6040805160808101825233815260208181018681526000838501818152606085018a8152878352600e90945293519490208054600160a060020a031916909417845551600184810191909155915160028401555160039290920191909155600f8054918201808255929350918281838015829011610a0057818360005260206000209182019101610a0091905b8082111561028d57600081556001016109ec565b5050506000928352506020909120018190555b505050565b600160a060020a031633600160a060020a0316141515610a3757610002565b6000878152600e6020526040812060018101549095501115610c5257600d5460a060020a900460ff166000148015610aa15750612710610a75610222565b600460005054020460026000505460026000505460036000505461271003038660010160005054020411155b15610b4957610b968660006114e28260006040805160208101909152600090819052828180805b8351811015610b3e57603060f860020a02848281518110156100025790602001015160f860020a900460f860020a0210158015610b295750603960f860020a02848281518110156100025790602001015160f860020a900460f860020a0211155b156116cb578115611722578560001415611719575b509095945050505050565b60018401548454610c5291600160a060020a0391909116905b604051600160a060020a038316906161a89083906000818181858888f193505050501515610d005760138054820190555050565b92506001831080610ba8575061271083115b15610bc75783546001850154610c5291600160a060020a031690610b62565b6000878152600e6020526040902060029081018490555460001984011015610c5b57506002546003546001850154855461271092909203029190910490610c7190600160a060020a031682610b62565b60018401546000190191505b601380546007546127109085020590810190915560118054918403909101905560018401546010805490910190555b50505050505050565b8354610c1790600160a060020a03166001610b62565b60018401548190039150610c23565b33600160a060020a03166000908152600b60205260408120541115610ca757610cc5610cab565b610d045b6011546012546000918291829114610a13576114e9610222565b33600160a060020a03166000908152600b6020908152604080832054835260099091529020600101805434908101909155600c805490910190555b5050565b600a5460065460009350901015610d6557600a80546001019081905591505b600082111561095a576000828152600960205260408120600101541115610deb576040600020805460019190910154610dc591600160a060020a031690610e7f565b5060015b600a548111610d23576000818152600960205260409020600101543490108015610db457508160001480610db457506040600081812060019081015485835292822001549083905290105b15610dbd579050805b600101610d69565b600082815260096020908152604080832054600160a060020a03168352600b9091528120555b600082815260096020526040812060010154148015610e2357506040600081812054600160a060020a03168152600b60205290812054145b1561095a5760008281526009602090815260408083208054600160a060020a03191633908117825534600192909201829055600c8054909201909155600160a060020a03168352600b9091529020829055610d00565b610ea833825b600160a060020a0382166000908152600b602052604081205481901115610a1357611578610cab565b50565b61066333610eb83361055a565b610e7f565b5060005b919050565b600160a060020a0384166000908152600b60209081526040808320548352600990915290206001015402049050610ec1565b5060015b600a548111610f38578160001480610f5b5750600082815260096020526040902054610f6c90600160a060020a031661055a565b92505b505090565b600082815260096020526040902054610f3090600160a060020a031661055a565b105b15610f64579050805b600101610efc565b600082815260096020526040902054610f5990600160a060020a031661055a565b601154600254600354600454600554601054939492939192909190610fb0610457565b600f60005080549050985098509850985098509850985098509850909192939495969798565b600d805474ff0000000000000000000000000000000000000000191660a060020a179055565b600d805474ff000000000000000000000000000000000000000019169055565b5060015b600a54811161104e5760008181526009602052604090205461107e90600160a060020a0316610eb88161055a565b8115610d0057604051600d54600160a060020a03908116916000913016319082818181858883f150505050505050565b600101611020565b82156110bb57506000905060015b600a5481116110e55760008181526009602052604090206001015490910190600101611094565b601354604051600d54600160a060020a03169160009182818181858883f150505060135550505050565b816000148015611101575060135430600160a060020a03163114155b1561112f57604051600d54600160a060020a03908116916000913016319082818181858883f1505050601355505b610a13565b50600060009054906101000a9004600160a060020a0316600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051519150505b60018054600160a060020a0319168217908190556040805160e260020a630bbceb330281526024810187905260048181019283528a5160448301528a51600160a060020a039490941693632ef3accc938c938a939192839260649290920191602087810192918291859183918691600091601f850104600f02600301f150905090810190601f1680156112335780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050604051519250503a8402670de0b6b3a76400000182111561127c5750600091505b50949350505050565b600160009054906101000a9004600160a060020a0316600160a060020a03166385dee34c8360008a8a8a8a6040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156113275780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156113805780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156113d95780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f11561000257505060405151945061127392505050565b50600060009054906101000a9004600160a060020a0316600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051519150505b60018054600160a060020a031916821790819055604080517fc281d19e0000000000000000000000000000000000000000000000000000000081529051600160a060020a03929092169163c281d19e9160048181019260209290919082900301816000876161da5a03f115610002575050604051519250610524915050565b9050610ec1565b9150600190505b600a54811161151a5760008181526009602052604090205461155990600160a060020a031661055a565b600c8390558282148015906115325750600a54600090115b1561154e5760138054848403908101909155600c805490910190555b601154601255505050565b60008281526009602052604090206001908101829055930192016114f0565b6115818361055a565b821115611594576115918361055a565b91505b50600160a060020a0382166000908152600b602090815260408083205483526009909152902060010180548290039055600c8054829003905560085460138054612710928402929092049182019055610a1383828403610b62565b1115611623575060008054600160a060020a031916731d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed1790556001610ec1565b6000611642739efbea6358bed926b293d2ce63a730d6d98d43dd610956565b1115611678575060008054739efbea6358bed926b293d2ce63a730d6d98d43dd600160a060020a03199091161790556001610ec1565b60006116977320e12a1f859b3feae5fb2a0a32c18f5a65555bbf610956565b1115610ebd575060008054600160a060020a0319167320e12a1f859b3feae5fb2a0a32c18f5a65555bbf1790556001610ec1565b8381815181101561000257016020015160f860020a90819004027f2e00000000000000000000000000000000000000000000000000000000000000141561171157600191505b600101610ac8565b60001995909501945b600a83029250825060308482815181101561000257016020015160f860020a90819004810204909301602f19019250611711564244584a68725670424a35336f3243786c4a526c51745a4a4b5a714c5974354951652b37335944533448744e6a5335486f64624942337476666f773755717579416b303835566b4c6e4c3945704b67777157517a375a4c64477673516c526432734b78496f6c4e673944626e6650737047714c684c62625953566e4e38437776736a7041586353536f33632b34634e774339307946346f4e69626b764433797461706f5a37676f5453796f5559546677536a6e773374692b484a5648374e332b633069774f43715a6a4464734751556358336d33532f494857624f4f5151356f734f344c626a33476730783155644e7466557a5943465937396e7a596757495145464375524249306e364e42764251573732372b4f73445259304a2f392f676a74387563696248576963303d", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000001d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000088e1315687aec48a72786c6b3b3f075208b62713", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000000000000009c4", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x00000000000000000000000000000000000000000000000000000000000000be", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000000000000000000000000000000000000000000064", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x00000000000000000000000000000000000000000000000002c68af0bb140000", + "0x000000000000000000000000000000000000000000000000000000000000000c": "0x000000000000000000000000000000000000000000000006ad2ff8ba84afdcdc", + "0x000000000000000000000000000000000000000000000000000000000000000d": "0x000000000000000000000000a1b5f95be71ffa2f86adefcaa0028c46fe825161", + "0x000000000000000000000000000000000000000000000000000000000000000f": "0x0000000000000000000000000000000000000000000000000000000000000022", + "0x0000000000000000000000000000000000000000000000000000000000000011": "0xffffffffffffffffffffffffffffffffffffffffffffffffd14ae0a37b4cc1d4", + "0x0000000000000000000000000000000000000000000000000000000000000012": "0xffffffffffffffffffffffffffffffffffffffffffffffffd5ab72be30cb5f50", + "0x0000000000000000000000000000000000000000000000000000000000000013": "0xffffffffffffffffd5bbd8ce9d1eb44232ca20eb5b4319ac5e1982d2c94bc3cb", + "0x8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac824": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xe950f1be9a49788ef79ea4e854ed56155a7f60661724f41e3af5f799203a1eb9": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xe950f1be9a49788ef79ea4e854ed56155a7f60661724f41e3af5f799203a1eba": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xe950f1be9a49788ef79ea4e854ed56155a7f60661724f41e3af5f799203a1ebb": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xe950f1be9a49788ef79ea4e854ed56155a7f60661724f41e3af5f799203a1ebc": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x61c808d82a3ac53231750dadc13c777b59310bd9": { + "balance": "0x12f621ea72fef44f848", + "nonce": "51830" + }, + "0x6412becf35cc7e2a9e7e47966e443f295e1e4f4a": { + "balance": "0xfb5dbfc0d448e70", + "nonce": "6" + }, + "0x88e1315687aec48a72786c6b3b3f075208b62713": { + "balance": "0x24b9f2c5dc266dc6", + "code": "0x606060405236156101535760e060020a60003504630f825673811461018f57806323dc42e7146102135780632ef3accc146102ad578063453629781461033b578063480a434d146103d5578063524f3889146103de5780635c242c591461043f57806360f66701146104de57806362b3b8331461056757806368742da6146105eb578063688dcfd71461062b578063757004371461065857806377228659146106f25780637d242ae5146107cd5780637e1c42051461085357806381ade3071461033b57806385dee34c14610932578063a2ec191a14610a0c578063adf59f9914610213578063ae81584314610658578063b5bfdd7314610a64578063bf1fe42014610af2578063c281d19e14610b32578063c51be90f14610b44578063ca6ad1e414610bdd578063d959701614610bff578063db37e42f14610cb6578063de4b326214610d6d578063e839e65e14610daf575b61065660025433600160a060020a039081169116148015906101855750600154600160a060020a039081163390911614155b15610e8a57610002565b6106566004808035906020019082018035906020019191908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650505050505050600254600160a060020a0390811633909116148015906102095750600154600160a060020a039081163390911614155b15610ebb57610002565b60408051602060248035600481810135601f8101859004850286018501909652858552610e8c9581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760649791965060249190910194509092508291508401838280828437509496505050505050506000610f2084848462030d406104cb565b610e8c6004808035906020019082018035906020019191908080601f0160208091040260200160405190810160405280939291908181526020018383808284375094965050933593505050506000610f288383335b6000600062030d40841115801561032d5750600160a060020a03831681526020819052604081205481145b1561184e5760009150611846565b610e8c6004808035906020019082018035906020019191908080601f01602080910402602001604051908101604052809392919081815260200183838082843750506040805160208835808b0135601f81018390048302840183019094528383529799986044989297509190910194509092508291508401838280828437509496505050505050506000610f286000848462030d406104cb565b610e8c60085481565b610e8c6004808035906020019082018035906020019191908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496505050505050506000610f2f82336000610f288362030d4084610302565b60408051602060248035600481810135601f8101859004850286018501909652858552610e8c9581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050505b600083826000600061113d848433610302565b6106566004808035906020019082018035906020019191908080601f0160208091040260200160405190810160405280939291908181526020018383808284375094965050505050505080604051808280519060200190808383829060006004602084601f0104600f02600301f150905001915050604051809103902060046000508190555050565b6106566004808035906020019082018035906020019191908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650505050505050600254600160a060020a0390811633909116148015906105e15750600154600160a060020a039081163390911614155b1561119757610002565b610656600435600254600160a060020a0390811633909116148015906106215750600154600160a060020a039081163390911614155b156111f957610002565b600160a060020a0333166000908152600660205260409020805460ff191660f860020a600435041790555b005b60408051602060248035600481810135601f8101859004850286018501909652858552610e8c9581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050505b6000610f1d858585856104cb565b60408051602060248035600481810135601f8101859004850286018501909652858552610e8c9581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760849791965060249190910194509092508291508401838280828437509496505050505050506000610f1d8585858562030d4061091f565b60408051602060248035600481810135601f81018590048502860185019096528585526106569581359591946044949293909201918190840183828082843750949650505050505050600254600090600160a060020a0390811633909116148015906108495750600154600160a060020a039081163390911614155b1561121f57610002565b60408051602060248035600481810135601f8101859004850286018501909652858552610e8c9581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050933593505050505b6000848260006000611516848433610302565b60408051602060248035600481810135601f8101859004850286018501909652858552610e8c9581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760849791965060249190910194509092508291508401838280828437509496505093359350505050600061156b868686868661091f565b6106566004808035906020019082018035906020019191908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650509335935050505061157282600083610ab5565b6106566004808035906020019082018035906020019191908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496505093359350506044359150505b600254600090600160a060020a039081163390911614801590610ae85750600154600160a060020a039081163390911614155b1561157657610002565b610656600435600254600160a060020a039081163390911614801590610b285750600154600160a060020a039081163390911614155b1561162f57610002565b610e9e600154600160a060020a031681565b60408051602060248035600481810135601f8101859004850286018501909652858552610e8c9581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050506000610f1d858585856106e4565b600160a060020a03331660009081526007602052604090206004359055610656565b604080516004803580820135602081810285810182019096528185526106569593946024949093850192918291908501908490808284375050604080518735808a013560208181028085018201909552818452989a99604499939850919091019550935083925085019084908082843750949650505050505050600254600090600160a060020a039081163390911614801590610cac5750600154600160a060020a039081163390911614155b1561163457610002565b604080516004803580820135602081810285810182019096528185526106569593946024949093850192918291908501908490808284375050604080518735808a013560208181028085018201909552818452989a99604499939850919091019550935083925085019084908082843750949650505050505050600254600090600160a060020a039081163390911614801590610d635750600154600160a060020a039081163390911614155b1561168f57610002565b61065660043560025460009033600160a060020a03908116911614801590610da55750600154600160a060020a039081163390911614155b1561170557610002565b610e8c6004808035906020019082018035906020019191908080601f01602080910402602001604051908101604052809392919081815260200183838082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760649791965060249190910194509092508291508401838280828437509496505050505050506000610f20600085858562030d4061091f565b565b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b60006003600050600083604051808280519060200190808383829060006004602084601f0104600f02600301f1509050019150506040518091039020815260200190815260200160002060006101000a81548160ff0219169083021790555050565b90505b949350505050565b9392505050565b92915050565b6000600050600033600160a060020a031681526020019081526020016000206000505433600160a060020a031630600160a060020a03160101604051808281526020019150506040518091039020945084506000600050600033600160a060020a031681526020019081526020016000206000818150548092919060010191905055507fb76d0edd90c6a07aa3ff7a222d7f5933e29c6acc660c059c97837f05c4ca1a8433868b8b8b8b6006600050600033600160a060020a0316815260200190815260200160002060009054906101000a900460f860020a026007600050600033600160a060020a03168152602001908152602001600020600050546040518089600160a060020a0316815260200188815260200187815260200180602001806020018681526020018581526020018481526020018381038352888181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156110c35780820380516001836020036101000a031916815260200191505b508381038252878181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561111c5780820380516001836020036101000a031916815260200191505b509a505050505050505050505060405180910390a150505050949350505050565b91503482901061119257813403905060008111156111765760405133600160a060020a031690600090839082818181858883f150505050505b42624f1a000189118061118857504586115b15610f3557610002565b610002565b60016003600050600083604051808280519060200190808383829060006004602084601f0104600f02600301f1509050019150506040518091039020815260200190815260200160002060006101000a81548160ff0219169083021790555050565b604051600160a060020a03828116916000913016319082818181858883f1505050505050565b50600882905560005b600b548110156112a757600b8054600a91600091849081101561000257508054600080516020611883833981519152850154835260209390935260408220548602926009929190859081101561000257908252600080516020611883833981519152018150548152602081019190915260400160002055600101611228565b505050565b6000600050600033600160a060020a031681526020019081526020016000206000505433600160a060020a031630600160a060020a03160101604051808281526020019150506040518091039020945084506000600050600033600160a060020a031681526020019081526020016000206000818150548092919060010191905055507faf30e4d66b2f1f23e63ef4591058a897f67e6867233e33ca3508b982dcc4129b33868c8c8c8c8c6006600050600033600160a060020a0316815260200190815260200160002060009054906101000a900460f860020a026007600050600033600160a060020a0316815260200190815260200160002060005054604051808a600160a060020a0316815260200189815260200188815260200180602001806020018060200187815260200186815260200185815260200184810384528a8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561143f5780820380516001836020036101000a031916815260200191505b508481038352898181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156114985780820380516001836020036101000a031916815260200191505b508481038252888181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156114f15780820380516001836020036101000a031916815260200191505b509c5050505050505050505050505060405180910390a1505050505b95945050505050565b915034829010611192578134039050600081111561154f5760405133600160a060020a031690600090839082818181858883f150505050505b42624f1a00018a118061156157504586115b156112ac57610002565b905061150d565b5050565b8383604051808380519060200190808383829060006004602084601f0104600f02600301f150905001828152600101925050506040518091039020905080600b600050600b600050805480919060010190908154818355818115116115fe578183600052602060002091820191016115fe91905b8082111561162b57600081556001016115ea565b5050508154811015610002576000918252602080832090910192909255918252600a905260409020555050565b5090565b600555565b5060005b81518110156112a7578281815181101561000257906020019060200201516007600050600084848151811015610002576020908102909101810151600160a060020a03168252919091526040902055600101611638565b5060005b81518110156112a75782818151811015610002579060200190602002015160f860020a026006600050600084848151811015610002576020908102909101810151600160a060020a031682529190915260409020805460f860020a90920460ff19909216919091179055600101611693565b50600881905560005b600b5481101561157257600b8054600a91600091849081101561000257600080516020611883833981519152015482526020929092526040812054825490850292600992918590811015610002576000805160206118838339815191520154825250602091909152604090205560010161170e565b60096000506000866006600050600087600160a060020a0316815260200190815260200160002060009054906101000a900460f860020a02604051808380519060200190808383829060006004602084601f0104600f02600301f150905001828152600101925050506040518091039020815260200190815260200160002060005054915081506007600050600084600160a060020a03168152602001908152602001600020600050549050806000141561183d57506005545b83810291909101905b509392505050565b600454600014801590611875575060045460009081526003602052604090205460ff166001145b156117835760009150611846560175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000004": "0xbb130806898f085471286ecb4f3966fcbe090ba29e4f9d194ee9e9062f6b61ae", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x00000000000000000000000000000000000000000000000000000004a817c800", + "0x797fdd0f6c82412493cfa2aacdc9999c10e5d0c9aa3f05a8a289b1b3918c6db8": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8d90a37db271d62339ebfe84641d1ebdaf56fd5d50861d795eacb410dbb57630": "0x000000000000000000000000000000000000000000000000000cf4e712e8d654", + "0x9864048b6d6c99ecd7fcaecf663fbe1036a6e1fc00cec0a3eb25684dd08184c2": "0x0000000000000000000000000000000000000000000000000000000000000011", + "0xca9ea8077ddc97a21c029df4b19819e51903e11d4bfc7564a622a192cefd6356": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xf34e44a0672ef76b852374cc47d9772eb4e5e41fa79fba61dcfc9cf7d50418d5": "0x0000000000000000000000000000000000000000000000000000000000000022" + } + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "1725116", + "difficulty": "45966589844033", + "timestamp": "1466232988", + "gasLimit": "4716972", + "miner": "0x61c808d82a3ac53231750dadc13c777b59310bd9" + }, + "input": "0xf86d068504e3b2920083030d409450739060a2c32dc076e507ae1a893aab28ecfe68880429d069189e0000801ca04e403b46022c2098e41d3a0e561881ac368cd330637239da85759c1b4f44ab24a072a88235d98959283c00af411bd663b0da8703e05a94d3673aca37d0a39b7e07", + "tracerConfig": { + "withLog": true + }, + "result": { + "from": "0x6412becf35cc7e2a9e7e47966e443f295e1e4f4a", + "gas": "0x2bb38", + "gasUsed": "0x249eb", + "to": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "input": "0x", + "calls": [ + { + "from": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "gas": "0x257af", + "gasUsed": "0xbc", + "to": "0x1d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed", + "input": "0x38cc4831", + "output": "0x00000000000000000000000088e1315687aec48a72786c6b3b3f075208b62713", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "gas": "0x255a1", + "gasUsed": "0x73a", + "to": "0x88e1315687aec48a72786c6b3b3f075208b62713", + "input": "0x2ef3accc000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000249f0000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000", + "output": "0x00000000000000000000000000000000000000000000000000179d63013c5654", + "calls": [ + { + "from": "0x88e1315687aec48a72786c6b3b3f075208b62713", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "gas": "0x24680", + "gasUsed": "0xbc", + "to": "0x1d3b2638a7cc9f2cb3d298a3da7a90b67e5506ed", + "input": "0x38cc4831", + "output": "0x00000000000000000000000088e1315687aec48a72786c6b3b3f075208b62713", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "gas": "0x22f3b", + "gasUsed": "0x73a", + "to": "0x88e1315687aec48a72786c6b3b3f075208b62713", + "input": "0x2ef3accc000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000249f0000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000", + "output": "0x00000000000000000000000000000000000000000000000000179d63013c5654", + "calls": [ + { + "from": "0x88e1315687aec48a72786c6b3b3f075208b62713", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "gas": "0x30", + "gasUsed": "0x18", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x6a736f6e2868747470733a2f2f6170692e72616e646f6d2e6f72672f6a736f6e2d7270632f312f696e766f6b65292e726573756c742e72616e646f6d2e646174612e30", + "output": "0x6a736f6e2868747470733a2f2f6170692e72616e646f6d2e6f72672f6a736f6e2d7270632f312f696e766f6b65292e726573756c742e72616e646f6d2e646174612e30", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "gas": "0x99", + "gasUsed": "0x2d", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x4244584a68725670424a35336f3243786c4a526c51745a4a4b5a714c5974354951652b37335944533448744e6a5335486f64624942337476666f773755717579416b303835566b4c6e4c3945704b67777157517a375a4c64477673516c526432734b78496f6c4e673944626e6650737047714c684c62625953566e4e38437776736a7041586353536f33632b34634e774339307946346f4e69626b764433797461706f5a37676f5453796f5559546677536a6e773374692b484a5648374e332b633069774f43715a6a4464734751556358336d33532f494857624f4f5151356f734f344c626a33476730783155644e7466557a5943465937396e7a596757495145464375524249306e364e42764251573732372b4f73445259304a2f392f676a74387563696248576963303d", + "output": "0x4244584a68725670424a35336f3243786c4a526c51745a4a4b5a714c5974354951652b37335944533448744e6a5335486f64624942337476666f773755717579416b303835566b4c6e4c3945704b67777157517a375a4c64477673516c526432734b78496f6c4e673944626e6650737047714c684c62625953566e4e38437776736a7041586353536f33632b34634e774339307946346f4e69626b764433797461706f5a37676f5453796f5559546677536a6e773374692b484a5648374e332b633069774f43715a6a4464734751556358336d33532f494857624f4f5151356f734f344c626a33476730783155644e7466557a5943465937396e7a596757495145464375524249306e364e42764251573732372b4f73445259304a2f392f676a74387563696248576963303d", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "gas": "0x2083e", + "gasUsed": "0x4417", + "to": "0x88e1315687aec48a72786c6b3b3f075208b62713", + "input": "0x85dee34c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000249f0000000000000000000000000000000000000000000000000000000000000000355524c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000436a736f6e2868747470733a2f2f6170692e72616e646f6d2e6f72672f6a736f6e2d7270632f312f696e766f6b65292e726573756c742e72616e646f6d2e646174612e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012c4244584a68725670424a35336f3243786c4a526c51745a4a4b5a714c5974354951652b37335944533448744e6a5335486f64624942337476666f773755717579416b303835566b4c6e4c3945704b67777157517a375a4c64477673516c526432734b78496f6c4e673944626e6650737047714c684c62625953566e4e38437776736a7041586353536f33632b34634e774339307946346f4e69626b764433797461706f5a37676f5453796f5559546677536a6e773374692b484a5648374e332b633069774f43715a6a4464734751556358336d33532f494857624f4f5151356f734f344c626a33476730783155644e7466557a5943465937396e7a596757495145464375524249306e364e42764251573732372b4f73445259304a2f392f676a74387563696248576963303d0000000000000000000000000000000000000000", + "output": "0xd1b13c1538a940417bf0e73b2498634436753c854c7fb971224d971bd2ae3e88", + "calls": [ + { + "from": "0x88e1315687aec48a72786c6b3b3f075208b62713", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x88e1315687aec48a72786c6b3b3f075208b62713", + "gas": "0x12", + "gasUsed": "0x12", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x55524c", + "output": "0x55524c", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x88e1315687aec48a72786c6b3b3f075208b62713", + "gas": "0x30", + "gasUsed": "0x18", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x6a736f6e2868747470733a2f2f6170692e72616e646f6d2e6f72672f6a736f6e2d7270632f312f696e766f6b65292e726573756c742e72616e646f6d2e646174612e30", + "output": "0x6a736f6e2868747470733a2f2f6170692e72616e646f6d2e6f72672f6a736f6e2d7270632f312f696e766f6b65292e726573756c742e72616e646f6d2e646174612e30", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x88e1315687aec48a72786c6b3b3f075208b62713", + "gas": "0x99", + "gasUsed": "0x2d", + "to": "0x0000000000000000000000000000000000000004", + "input": "0x4244584a68725670424a35336f3243786c4a526c51745a4a4b5a714c5974354951652b37335944533448744e6a5335486f64624942337476666f773755717579416b303835566b4c6e4c3945704b67777157517a375a4c64477673516c526432734b78496f6c4e673944626e6650737047714c684c62625953566e4e38437776736a7041586353536f33632b34634e774339307946346f4e69626b764433797461706f5a37676f5453796f5559546677536a6e773374692b484a5648374e332b633069774f43715a6a4464734751556358336d33532f494857624f4f5151356f734f344c626a33476730783155644e7466557a5943465937396e7a596757495145464375524249306e364e42764251573732372b4f73445259304a2f392f676a74387563696248576963303d", + "output": "0x4244584a68725670424a35336f3243786c4a526c51745a4a4b5a714c5974354951652b37335944533448744e6a5335486f64624942337476666f773755717579416b303835566b4c6e4c3945704b67777157517a375a4c64477673516c526432734b78496f6c4e673944626e6650737047714c684c62625953566e4e38437776736a7041586353536f33632b34634e774339307946346f4e69626b764433797461706f5a37676f5453796f5559546677536a6e773374692b484a5648374e332b633069774f43715a6a4464734751556358336d33532f494857624f4f5151356f734f344c626a33476730783155644e7466557a5943465937396e7a596757495145464375524249306e364e42764251573732372b4f73445259304a2f392f676a74387563696248576963303d", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x88e1315687aec48a72786c6b3b3f075208b62713", + "topics": [ + "0xaf30e4d66b2f1f23e63ef4591058a897f67e6867233e33ca3508b982dcc4129b" + ], + "data": "0x00000000000000000000000050739060a2c32dc076e507ae1a893aab28ecfe68d1b13c1538a940417bf0e73b2498634436753c854c7fb971224d971bd2ae3e8800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000249f011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000355524c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000436a736f6e2868747470733a2f2f6170692e72616e646f6d2e6f72672f6a736f6e2d7270632f312f696e766f6b65292e726573756c742e72616e646f6d2e646174612e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012c4244584a68725670424a35336f3243786c4a526c51745a4a4b5a714c5974354951652b37335944533448744e6a5335486f64624942337476666f773755717579416b303835566b4c6e4c3945704b67777157517a375a4c64477673516c526432734b78496f6c4e673944626e6650737047714c684c62625953566e4e38437776736a7041586353536f33632b34634e774339307946346f4e69626b764433797461706f5a37676f5453796f5559546677536a6e773374692b484a5648374e332b633069774f43715a6a4464734751556358336d33532f494857624f4f5151356f734f344c626a33476730783155644e7466557a5943465937396e7a596757495145464375524249306e364e42764251573732372b4f73445259304a2f392f676a74387563696248576963303d0000000000000000000000000000000000000000" + } + ], + "value": "0x179d63013c5654", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", + "topics": [], + "data": "0x62616e6b726f6c6c5f6d69736d61746368" + } + ], + "value": "0x429d069189e0000", + "type": "CALL" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json new file mode 100644 index 000000000000..1a03f0e7fb28 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json @@ -0,0 +1,84 @@ +{ + "genesis": { + "difficulty": "8430028481555", + "extraData": "0xd783010302844765746887676f312e352e31856c696e7578", + "gasLimit": "3141592", + "hash": "0xde66937783697293f2e529d2034887c531535d78afa8c9051511ae12ba48fbea", + "miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226", + "mixHash": "0xba28a43bfbca4a2effbb76bb70d03482a8a0c92e2883ff36cbac3d7c6dbb7df5", + "nonce": "0xa3827ec0a82fe823", + "number": "765824", + "stateRoot": "0x8d96cb027a29f8ca0ccd6d31f9ea0656136ec8030ecda70bb9231849ed6f41a2", + "timestamp": "1451389443", + "totalDifficulty": "4838314986494741271", + "alloc": { + "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb": { + "balance": "0x14203bee2ea6fbe8c", + "nonce": "34" + }, + "0xe2fe6b13287f28e193333fdfe7fedf2f6df6124a": { + "balance": "0x2717a9c870a286f4350" + }, + "0xf4eced2f682ce333f96f2d8966c613ded8fc95dd": { + "balance": "0x0", + "code": "0x606060405260e060020a600035046306fdde038114610047578063313ce567146100a457806370a08231146100b057806395d89b41146100c8578063a9059cbb14610123575b005b61015260008054602060026001831615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156101f55780601f106101ca576101008083540402835291602001916101f5565b6101c060025460ff1681565b6101c060043560036020526000908152604090205481565b610152600180546020601f6002600019610100858716150201909316929092049182018190040260809081016040526060828152929190828280156101f55780601f106101ca576101008083540402835291602001916101f5565b610045600435602435600160a060020a033316600090815260036020526040902054819010156101fd57610002565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156101b25780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6060908152602090f35b820191906000526020600020905b8154815290600101906020018083116101d857829003601f168201915b505050505081565b600160a060020a03821660009081526040902054808201101561021f57610002565b806003600050600033600160a060020a03168152602001908152602001600020600082828250540392505081905550806003600050600084600160a060020a0316815260200190815260200160002060008282825054019250508190555081600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505056", + "storage": { + "0x1dae8253445d3a5edbe8200da9fc39bc4f11db9362181dc1b640d08c3c2fb4d6": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8ba52aac7f255d80a49abcf003d6af4752aba5a9531cae94fde7ac8d72191d67": "0x000000000000000000000000000000000000000000000000000000000178e460" + } + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "765825", + "difficulty": "8425912256743", + "timestamp": "1451389488", + "gasLimit": "3141592", + "miner": "0xe2fe6b13287f28e193333fdfe7fedf2f6df6124a" + }, + "input": "0xf8aa22850ba43b740083024d4594f4eced2f682ce333f96f2d8966c613ded8fc95dd80b844a9059cbb000000000000000000000000dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb00000000000000000000000000000000000000000000000000000000009896801ca067da548a2e0f381a957b9b51f086073375d6bfc7312cbc9540b3647ccab7db11a042c6e5b34bc7ba821e9c25b166fa13d82ad4b0d044d16174d5587d4f04ecfcd1", + "tracerConfig": { + "withLog": true + }, + "result": { + "from": "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb", + "gas": "0x1f36d", + "gasUsed": "0xc6a5", + "to": "0xf4eced2f682ce333f96f2d8966c613ded8fc95dd", + "input": "0xa9059cbb000000000000000000000000dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb0000000000000000000000000000000000000000000000000000000000989680", + "logs": [ + { + "address": "0xf4eced2f682ce333f96f2d8966c613ded8fc95dd", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000d1220a0cf47c7b9be7a2e6ba89f429762e7b9adb", + "0x000000000000000000000000dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000989680" + } + ], + "value": "0x0", + "type": "CALL" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json new file mode 100644 index 000000000000..4e0aec529f0a --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json @@ -0,0 +1,244 @@ +{ + "genesis": { + "difficulty": "56311715121637", + "extraData": "0x7777772e62772e636f6d", + "gasLimit": "4712388", + "hash": "0x20d3b8daa046f2f10564d84ccbe6d0a8842d8d52bc6d623e23c38050a8f73776", + "miner": "0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1", + "mixHash": "0x75029f90d7de3f9e3d5eac4a25019f9ac5d0041641d1ef17e7759e45699d4224", + "nonce": "0x54ff3b34fa1d9c97", + "number": "1968179", + "stateRoot": "0x6420003b1779cca3bcdab698c239bbc63623c0a7e4deeedbdb8190b9e7fd7520", + "timestamp": "1469713675", + "totalDifficulty": "42284028928878034360", + "alloc": { + "0x10abb5efecdc09581f8b7cb95791fe2936790b4e": { + "balance": "0x81f158e2814b4ab624c", + "code": "0x6060604052361561020e5760e060020a6000350463013cf08b8114610247578063095ea7b3146102d05780630c3b7b96146103455780630e7082031461034e578063149acf9a1461036057806318160ddd146103725780631f2dc5ef1461037b57806321b5b8dd1461039b578063237e9492146103ad57806323b872dd1461040e5780632632bf2014610441578063341458081461047257806339d1f9081461047b5780634b6753bc146104935780634df6d6cc1461049c5780634e10c3ee146104b7578063590e1ae3146104ca578063612e45a3146104db578063643f7cdd1461057a578063674ed066146105925780636837ff1e1461059b57806370a08231146105e5578063749f98891461060b57806378524b2e1461062457806381f03fcb1461067e57806382661dc41461069657806382bf6464146106b75780638b15a605146106c95780638d7af473146106d257806396d7f3f5146106e1578063a1da2fb9146106ea578063a3912ec814610704578063a9059cbb1461070f578063b7bc2c841461073f578063baac53001461074b578063be7c29c1146107b1578063c9d27afe14610817578063cc9ae3f61461082d578063cdef91d014610841578063dbde198814610859578063dd62ed3e1461087e578063e33734fd146108b2578063e5962195146108c6578063e66f53b7146108de578063eceb2945146108f0578063f8c80d261461094f575b610966600f546000906234bc000142108015610239575060125433600160a060020a03908116911614155b156109785761098033610752565b6109866004356000805482908110156100025750808052600e8202600080516020612a3683398151915201905060038101546004820154600683015460018401548454600786015460058701546009880154600a890154600d8a0154600160a060020a039586169b509599600201989760ff81811698610100909204811697949691951693168c565b61096660043560243533600160a060020a03908116600081815260156020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b61096660105481565b610a7d600754600160a060020a031681565b610a7d600e54600160a060020a031681565b61096660165481565b6109665b60004262127500600f60005054031115610de557506014610983565b610a7d601254600160a060020a031681565b60408051602060248035600481810135601f810185900485028601850190965285855261096695813595919460449492939092019181908401838280828437509496505050505050506000600060006000600060003411156116a857610002565b6109666004356024356044355b60115460009060ff1680156104315750600f5442115b80156124e957506124e78461044b565b6109666000610980335b600160a060020a0381166000908152600b602052604081205481908114156129cb57610b99565b61096660065481565b6109665b600d5430600160a060020a03163103610983565b610966600f5481565b61096660043560046020526000908152604090205460ff1681565b61096660043560243560006124cb610831565b610a9a6000341115610ba457610002565b604080516020604435600481810135601f8101849004840285018401909552848452610966948135946024803595939460649492939101918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050933593505060a435915050600060006110c1336105ec565b61096660043560096020526000908152604090205481565b61096660015481565b610a9a60043530600160a060020a031633600160a060020a03161415806105db5750600160a060020a03811660009081526004602052604090205460ff16155b156121cb576121c8565b6109666004355b600160a060020a0381166000908152601460205260409020545b919050565b6109666004356024356000600034111561259957610002565b610966600062e6b680420360026000505410806106505750600354600160a060020a0390811633909116145b80156106645750600254621274ff19420190105b156126145750426002908155600180549091028155610983565b610966600435600a6020526000908152604090205481565b610966600435602435600060006000600060006000341115611ba157610002565b610a7d600854600160a060020a031681565b610966600c5481565b61096660005460001901610983565b61096660025481565b61096660043560006000600060003411156121fc57610002565b6109665b6001610983565b6109666004356024355b60115460009060ff16801561072f5750600f5442115b801561248757506124853361044b565b61096660115460ff1681565b6109666004355b60006000600f600050544210801561076a5750600034115b80156107a457506011546101009004600160a060020a0316600014806107a457506011546101009004600160a060020a0390811633909116145b15610b9f57610a9c61037f565b610a7d600435600060006000508281548110156100025750508080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56b600e83020180548290811015610002575081526020902060030154600160a060020a0316610606565b61096660043560243560006000610e1b336105ec565b6109665b6000600034111561247c57610002565b61096660043560056020526000908152604090205481565b610966600435602435604435600061252f845b6000600060003411156127ac57610002565b610966600435602435600160a060020a0382811660009081526015602090815260408083209385168352929052205461033f565b610a9a600435600034111561254557610002565b610966600435600b6020526000908152604090205481565b610a7d600354600160a060020a031681565b604080516020606435600481810135601f81018490048402850184019095528484526109669481359460248035956044359560849492019190819084018382808284375094965050505050505060006000600034111561103257610002565b610a7d6011546101009004600160a060020a031681565b60408051918252519081900360200190f35b610980610708565b90505b90565b604051808d600160a060020a031681526020018c8152602001806020018b81526020018a815260200189815260200188815260200187815260200186815260200185815260200184815260200183600160a060020a0316815260200182810382528c818154600181600116156101000203166002900481526020019150805460018160011615610100020316600290048015610a635780601f10610a3857610100808354040283529160200191610a63565b820191906000526020600020905b815481529060010190602001808311610a4657829003601f168201915b50509d505050505050505050505050505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b005b604051601254601434908102939093049350600160a060020a03169183900390600081818185876185025a03f150505050600160a060020a038316600081815260146020908152604080832080548601905560168054860190556013825291829020805434019055815184815291517fdbccb92686efceafb9bb7e0394df7f58f71b954061b81afb57109bf247d3d75a9281900390910190a260105460165410801590610b4c575060115460ff16155b15610b94576011805460ff1916600117905560165460408051918252517ff381a3e2428fdda36615919e8d9c35878d9eb0cf85ac6edf575088e80e4c147e9181900360200190a15b600191505b50919050565b610002565b600f5442118015610bb8575060115460ff16155b15610de357601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040516012549051600160a060020a039190911631109050610cc9576040805160125460e060020a63d2cc718f0282529151600160a060020a039290921691630221038a913091849163d2cc718f91600482810192602092919082900301816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a039490941660048201526024810193909352516044838101936020935082900301816000876161da5a03f115610002575050505b33600160a060020a0316600081815260136020526040808220549051909181818185876185025a03f19250505015610de35733600160a060020a03167fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d6013600050600033600160a060020a03168152602001908152602001600020600050546040518082815260200191505060405180910390a26014600050600033600160a060020a0316815260200190815260200160002060005054601660008282825054039250508190555060006014600050600033600160a060020a031681526020019081526020016000206000508190555060006013600050600033600160a060020a03168152602001908152602001600020600050819055505b565b4262054600600f60005054031115610e13576201518062127500600f60005054034203046014019050610983565b50601e610983565b60001415610e2857610002565b6000341115610e3657610002565b6000805485908110156100025750600160a060020a03331681527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56e600e8602908101602052604090912054600080516020612a3683398151915291909101915060ff1680610eb05750600c810160205260406000205460ff165b80610ebf575060038101544210155b15610ec957610002565b8215610f0f5733600160a060020a03166000908152601460209081526040808320546009850180549091019055600b84019091529020805460ff19166001179055610f4b565b33600160a060020a0316600090815260146020908152604080832054600a850180549091019055600c84019091529020805460ff191660011790555b33600160a060020a03166000908152600b60205260408120541415610f77576040600020849055610feb565b33600160a060020a03166000908152600b60205260408120548154811015610002579080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566600e909102015460038201541115610feb5733600160a060020a03166000908152600b602052604090208490555b60408051848152905133600160a060020a03169186917f86abfce99b7dd908bec0169288797f85049ec73cbe046ed9de818fab3a497ae09181900360200190a35092915050565b6000805487908110156100025750808052600e8702600080516020612a3683398151915201905090508484846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020816005016000505414915050949350505050565b600014156110ce57610002565b82801561111857508660001415806110e857508451600014155b806111005750600354600160a060020a038981169116145b8061110b5750600034115b80611118575062093a8084105b1561112257610002565b8215801561114257506111348861115c565b158061114257506212750084105b156111fe57610002565b83546118e590600160a060020a03165b600160a060020a03811660009081526004602052604081205460ff16806111f15750601254600160a060020a039081169083161480156111f15750601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051516006541190505b156129a157506001610606565b6249d40084111561120e57610002565b60115460ff1615806112215750600f5442105b806112365750600c5434108015611236575082155b1561124057610002565b42844201101561124f57610002565b30600160a060020a031633600160a060020a0316141561126e57610002565b60008054600181018083559091908280158290116112a557600e0281600e0283600052602060002091820191016112a5919061136a565b505060008054929450918491508110156100025750808052600e8302600080516020612a368339815191520190508054600160a060020a031916891781556001818101899055875160028084018054600082815260209081902096975091959481161561010002600019011691909104601f908101829004840193918b019083901061146257805160ff19168380011785555b5061149292915061144a565b5050600060098201819055600a820155600d81018054600160a060020a03191690556001015b8082111561145e578054600160a060020a03191681556000600182810182905560028084018054848255909281161561010002600019011604601f81901061143057505b506000600383018190556004808401805461ffff19169055600584018290556006840182905560078401805460ff191690556008840180548382559083526020909220611344929091028101905b8082111561145e57600080825560018201818155600283019190915560039091018054600160a060020a03191690556113fc565b601f0160209004906000526020600020908101906113ae91905b8082111561145e576000815560010161144a565b5090565b82800160010185558215611338579182015b82811115611338578251826000505591602001919060010190611474565b50508787866040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160050160005081905550834201816003016000508190555060018160040160006101000a81548160ff02191690830217905550828160070160006101000a81548160ff02191690830217905550821561157857600881018054600181018083559091908280158290116115735760040281600402836000526020600020918201910161157391906113fc565b505050505b600d8082018054600160a060020a031916331790553460068301819055815401905560408051600160a060020a038a16815260208181018a9052918101859052608060608201818152895191830191909152885185937f5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f938d938d938a938e93929160a084019185810191908190849082908590600090600490601f850104600f02600301f150905090810190601f1680156116485780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a2509695505050505050565b6040805186815260208101839052815189927fdfc78bdca8e3e0b18c16c5c99323c6cb9eb5e00afde190b4e7273f5158702b07928290030190a25b5050505092915050565b6000805488908110156100025750808052600e8802600080516020612a36833981519152019050600781015490945060ff166116e757620d2f006116ec565b622398805b600485015490935060ff16801561170857506003840154830142115b15611716576117b887611890565b600384015442108061172d5750600484015460ff16155b806117ae57508360000160009054906101000a9004600160a060020a03168460010160005054876040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020846005016000505414155b1561114c57610002565b61169e565b60048401805461ff001916610100179055835460019550600160a060020a03908116309091161480159061180157508354600754600160a060020a03908116911614155b801561181d57506008548454600160a060020a03908116911614155b801561183957508354601254600160a060020a03908116911614155b801561185557506003548454600160a060020a03908116911614155b1561188b5760018401805430600160a060020a031660009081526005602052604090208054919091019055546006805490910190555b611663875b6000600060005082815481101561000257908052600e02600080516020612a36833981519152018150600481015490915060ff16156118d757600d80546006830154900390555b600401805460ff1916905550565b15156118f45761190087611890565b6001915061193161047f565b604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050505061169e565b6001850154111561194157600091505b50600a8301546009840154865191019060049010801590611986575085600081518110156100025790602001015160f860020a900460f860020a02606860f860020a02145b80156119b6575085600181518110156100025790602001015160f860020a900460f860020a02603760f860020a02145b80156119e6575085600281518110156100025790602001015160f860020a900460f860020a0260ff60f860020a02145b8015611a16575085600381518110156100025790602001015160f860020a900460f860020a02601e60f860020a02145b8015611a45575030600160a060020a0316600090815260056020526040902054611a4290611a5d61047f565b81105b15611a4f57600091505b6001840154611a8090611a5f565b015b30600160a060020a03166000908152600560205260408120546129a961047f565b8110611ad457604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050501515611abc57610002565b4260025560165460059004811115611ad45760056001555b6001840154611ae290611a5f565b8110158015611af85750600a8401546009850154115b8015611b015750815b1561188b578360000160009054906101000a9004600160a060020a0316600160a060020a0316846001016000505487604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611b7d5780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f19250505015156117bd57610002565b611baa336105ec565b60001415611bb757610002565b60008054889081101561000257508052600e87027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566810154600080516020612a36833981519152919091019450421080611c1957506003840154622398800142115b80611c3257508354600160a060020a0390811690871614155b80611c425750600784015460ff16155b80611c68575033600160a060020a03166000908152600b8501602052604090205460ff16155b80611c9c575033600160a060020a03166000908152600b60205260409020548714801590611c9c5750604060009081205414155b15611ca657610002565b600884018054600090811015610002579081526020812060030154600160a060020a03161415611e1257611efc86604051600090600160a060020a038316907f9046fefd66f538ab35263248a44217dcb70e2eb2cd136629e141b8b8f9f03b60908390a260408051600e547fe2faf044000000000000000000000000000000000000000000000000000000008252600160a060020a03858116600484015260248301859052604483018590526223988042016064840152925192169163e2faf04491608480820192602092909190829003018187876161da5a03f1156100025750506040515191506106069050565b6008850180546000908110156100025781815260208082209390935530600160a060020a031681526005909252604082205481549092908110156100025790815260208120905060020155601654600885018054600090811015610002579081526020812090506001015560048401805461ff0019166101001790555b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090505433600160a060020a031660009081526014602052604081205460088801805493909102939093049550908110156100025790815260208120905060030154604080517fbaac530000000000000000000000000000000000000000000000000000000000815233600160a060020a0390811660048301529151929091169163baac53009186916024808301926020929190829003018185886185025a03f11561000257505060405151600014159150611f78905057610002565b60088501805460009081101561000257818152602081206003018054600160a060020a03191690931790925580549091908110156100025790815260208120905060030154600160a060020a031660001415611f5757610002565b600d5430600160a060020a0316311015611f7057610002565b611d9561047f565b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090506002015433600160a060020a0390811660009081526014602090815260408083205430909416835260058083528184205460099093529083205460088b018054969095029690960497509487020494508593929091908290811015610002575260208120815060030154600160a060020a0390811682526020828101939093526040918201600090812080549095019094553016835260059091529020548290101561205357610002565b30600160a060020a031660009081526005602052604081208054849003905560088501805483926009929091829081101561000257508152602080822060030154600160a060020a039081168352929052604080822080549094019093553090911681522054819010156120c657610002565b30600160a060020a0390811660009081526009602090815260408083208054869003905533909316808352601482528383205484519081529351929390927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a36121383361086c565b5033600160a060020a03166000908152601460209081526040808320805460168054919091039055839055600a9091528120556001945061169e565b30600160a060020a0390811660008181526005602090815260408083208054958716808552828520805490970190965584845283905560099091528082208054948352908220805490940190935590815290555b50565b604051600160a060020a0382811691309091163190600081818185876185025a03f192505050151561217457610002565b33600160a060020a03818116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f028352935197995091969195929092169363d2cc718f936004848101949193929183900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a03168152602001908152602001600020600050540204101561229d57610002565b600160a060020a03338116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f02835293519296909593169363d2cc718f93600483810194929383900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a0316815260200190815260200160002060005054020403905083156123ec57600860009054906101000a9004600160a060020a0316600160a060020a0316630221038a83600160a060020a0316630e7082036040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a031660048201526024810186905290516044808301935060209282900301816000876161da5a03f115610002575050604051511515905061245457610002565b6040805160085460e160020a63011081c5028252600160a060020a038581166004840152602483018590529251921691630221038a9160448082019260209290919082900301816000876161da5a03f115610002575050604051511515905061245457610002565b600160a060020a03331660009081526009602052604090208054909101905550600192915050565b6109803361086c565b155b80156124a257506124a23384845b6000600061293a856105ec565b80156124be57506124be83836000600034111561261c57610002565b15610b9f5750600161033f565b15156124d657610002565b6124e08383610719565b905061033f565b155b80156124fb57506124fb848484612495565b80156125185750612518848484600060003411156126c157610002565b15610b9f57506001612528565b90505b9392505050565b151561253a57610002565b61252584848461041b565b30600160a060020a031633600160a060020a031614158061258a575030600160a060020a031660009081526005602052604090205460649061258561047f565b010481115b1561259457610002565b600c55565b600354600160a060020a0390811633909116146125b557610002565b600160a060020a038316600081815260046020908152604091829020805460ff191686179055815185815291517f73ad2a153c8b67991df9459024950b318a609782cee8c7eeda47b905f9baa91f9281900390910190a250600161033f565b506000610983565b33600160a060020a03166000908152601460205260409020548290108015906126455750600082115b156126b957600160a060020a03338116600081815260146020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a350600161033f565b50600061033f565b600160a060020a03841660009081526014602052604090205482901080159061270a5750601560209081526040600081812033600160a060020a03168252909252902054829010155b80156127165750600082115b156127a457600160a060020a03838116600081815260146020908152604080832080548801905588851680845281842080548990039055601583528184203390961684529482529182902080548790039055815186815291519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001612528565b506000612528565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f11561000257505060405151905061281a866105ec565b0204101561282757610002565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f115610002575050604051519050612895866105ec565b0204039050600760009054906101000a9004600160a060020a0316600160a060020a0316630221038a84836040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511515905061291357610002565b600160a060020a0383166000908152600a6020526040902080548201905560019150610b99565b600160a060020a0386166000908152600a602052604090205480850291909104915081111561296857610002565b600160a060020a038581166000908152600a60205260408082208054859003905591861681522080548201905560019150509392505050565b506000610606565b0160030260166000505483020460016000505460166000505404019050610606565b600160a060020a0383166000908152600b6020526040812054815481101561000257818052600e02600080516020612a368339815191520190506003810154909150421115610b9457600160a060020a0383166000908152600b602052604081208190559150610b9956290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563", + "nonce": "3", + "storage": { + "0x000000000000000000000000000000000000000000000000000000000000000f": "0x0000000000000000000000000000000000000000000000000000000057bda071", + "0x0000000000000000000000000000000000000000000000000000000000000010": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000011": "0x0000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c18941301", + "0x0000000000000000000000000000000000000000000000000000000000000012": "0x000000000000000000000000fde8d5f77ef48bb7bf5766c7404691b9ee1dfca7", + "0x0000000000000000000000000000000000000000000000000000000000000016": "0x00000000000000000000000000000000000000000000081f158e2814b4ab624c", + "0x7ffc832d0c7f56b16d03bf3ff14bc4dd6a6cb1ec75841f7397362f4a9be4d392": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xaccfa2662c944e8eae80b7720d9d232eb6809c18f6c8da65189acbb38069d869": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x630a0cd35d5bd57e61410fda76fea850225cda18": { + "balance": "0x0", + "code": "0x6060604052361561006c5760e060020a60003504630121b93f81146100e15780636637b882146101615780636dbf2fa0146101935780638da5cb5b1461026a578063a6f9dae11461027c578063beabacc8146102ae578063d979f5aa14610322578063e1fa763814610354575b61050b600060006000600460005054111561051d576004805460001901905560015460035460055460e260020a6320998771026060908152606492909252600160a060020a03908116608452909116906382661dc49060a49060209060448187876161da5a03f11561000257506105c3915050565b6105cb60043560005433600160a060020a039081169116141561015e57600180547fc9d27afe0000000000000000000000000000000000000000000000000000000060609081526064849052608492909252600160a060020a03169063c9d27afe9060a4906020906044816000876161da5a03f115610002575050505b50565b6105cb60043560005433600160a060020a039081169116141561015e5760018054600160a060020a0319168217905550565b60806020604435600481810135601f8101849004909302840160405260608381526105cb9482359460248035956064949391019190819083828082843750949650505050505050600054600160a060020a039081163390911614156102655782600160a060020a03168282604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561024b5780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f1505050505b505050565b6105cd600054600160a060020a031681565b6105cb60043560005433600160a060020a039081169116141561015e5760008054600160a060020a0319168217905550565b6105cb6004356024356044356000805433600160a060020a039081169116141561031c5760e060020a63a9059cbb026060908152600160a060020a03848116606452608484905285929083169163a9059cbb9160a4916020916044908290876161da5a03f115610002575050505b50505050565b6105cb60043560005433600160a060020a039081169116141561015e5760028054600160a060020a0319168217905550565b6105cb60043560243560005433600160a060020a03908116911614156105075760015460e060020a6370a0823102606090815230600160a060020a0390811660645291909116906370a08231906084906020906024816000876161da5a03f1156100025750506040805180516006556002546001547f1a695230000000000000000000000000000000000000000000000000000000008352600160a060020a039081166004840152925192169250631a695230916024828101926000929190829003018183876161da5a03f1156100025750505060048181556003839055600154604080517f013cf08b00000000000000000000000000000000000000000000000000000000815292830185905251600160a060020a03919091169163013cf08b91602482810192602092919082900301816000876161da5a03f11561000257505060408051805160058054600160a060020a0319169091179081905560015460035460e260020a63209987710284526004840152600160a060020a0391821660248401529251921692506382661dc491604482810192602092919082900301816000876161da5a03f115610002575050505b5050565b60408051918252519081900360200190f35b60015460e060020a6370a0823102606090815230600160a060020a0390811660645291909116906370a082319060849060209060248187876161da5a03f11561000257505060408051805160015460025460e060020a63a9059cbb028452600160a060020a039081166004850152602484018390529351919550909216925063a9059cbb916044828101926020929190829003018188876161da5a03f115610002575050505b600191505090565b005b6060908152602090f3", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000e6002189a74b43e6868b20c1311bc108e38aac57", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c189413", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000006e073c0e1bd5af550239025dffcfb37175acedd3", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x6e073c0e1bd5af550239025dffcfb37175acedd3": { + "balance": "0x0", + "code": "0x606060405260e060020a60003504631a69523081146100475780636dbf2fa01461006d5780638da5cb5b14610144578063a6f9dae114610156578063beabacc814610196575b005b610045600435600080548190819032600160a060020a0390811691161461022957610002565b60806020604435600481810135601f8101849004909302840160405260608381526100459482359460248035956064949391019190819083828082843750949650505050505050600054600160a060020a0390811633909116141561013f5782600160a060020a03168282604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156101255780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f1505050505b505050565b61021f600054600160a060020a031681565b61004560043560005433600160a060020a0390811691161415610193576000805473ffffffffffffffffffffffffffffffffffffffff1916821790555b50565b6100456004356024356044356000805433600160a060020a0390811691161415610343577fa9059cbb000000000000000000000000000000000000000000000000000000006060908152600160a060020a03808516606452608484905285929083169163a9059cbb9160a4916020916044908290876161da5a03f1156100025750505050505050565b6060908152602090f35b7f70a0823100000000000000000000000000000000000000000000000000000000606090815230600160a060020a039081166064528594508416906370a082319060849060209060248187876161da5a03f1156100025750506040805180517f18160ddd00000000000000000000000000000000000000000000000000000000825291519194506318160ddd916004828101926020929190829003018187876161da5a03f11561000257505050604051805190602001509050808211156102ee579050805b82600160a060020a031663a9059cbb33846040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050505b5050505056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000e6002189a74b43e6868b20c1311bc108e38aac57" + } + }, + "0xbb9bc244d798123fde783fcc1c72d3bb8c189413": { + "balance": "0x53d2c8df046dd3db5", + "code": "0x6060604052361561020e5760e060020a6000350463013cf08b8114610247578063095ea7b3146102d05780630c3b7b96146103455780630e7082031461034e578063149acf9a1461036057806318160ddd146103725780631f2dc5ef1461037b57806321b5b8dd1461039b578063237e9492146103ad57806323b872dd1461040e5780632632bf2014610441578063341458081461047257806339d1f9081461047b5780634b6753bc146104935780634df6d6cc1461049c5780634e10c3ee146104b7578063590e1ae3146104ca578063612e45a3146104db578063643f7cdd1461057a578063674ed066146105925780636837ff1e1461059b57806370a08231146105e5578063749f98891461060b57806378524b2e1461062457806381f03fcb1461067e57806382661dc41461069657806382bf6464146106b75780638b15a605146106c95780638d7af473146106d257806396d7f3f5146106e1578063a1da2fb9146106ea578063a3912ec814610704578063a9059cbb1461070f578063b7bc2c841461073f578063baac53001461074b578063be7c29c1146107b1578063c9d27afe14610817578063cc9ae3f61461082d578063cdef91d014610841578063dbde198814610859578063dd62ed3e1461087e578063e33734fd146108b2578063e5962195146108c6578063e66f53b7146108de578063eceb2945146108f0578063f8c80d261461094f575b610966600f546000906234bc000142108015610239575060125433600160a060020a03908116911614155b156109785761098033610752565b6109866004356000805482908110156100025750808052600e8202600080516020612a3683398151915201905060038101546004820154600683015460018401548454600786015460058701546009880154600a890154600d8a0154600160a060020a039586169b509599600201989760ff81811698610100909204811697949691951693168c565b61096660043560243533600160a060020a03908116600081815260156020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b61096660105481565b610a7d600754600160a060020a031681565b610a7d600e54600160a060020a031681565b61096660165481565b6109665b60004262127500600f60005054031115610de557506014610983565b610a7d601254600160a060020a031681565b60408051602060248035600481810135601f810185900485028601850190965285855261096695813595919460449492939092019181908401838280828437509496505050505050506000600060006000600060003411156116a857610002565b6109666004356024356044355b60115460009060ff1680156104315750600f5442115b80156124e957506124e78461044b565b6109666000610980335b600160a060020a0381166000908152600b602052604081205481908114156129cb57610b99565b61096660065481565b6109665b600d5430600160a060020a03163103610983565b610966600f5481565b61096660043560046020526000908152604090205460ff1681565b61096660043560243560006124cb610831565b610a9a6000341115610ba457610002565b604080516020604435600481810135601f8101849004840285018401909552848452610966948135946024803595939460649492939101918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050933593505060a435915050600060006110c1336105ec565b61096660043560096020526000908152604090205481565b61096660015481565b610a9a60043530600160a060020a031633600160a060020a03161415806105db5750600160a060020a03811660009081526004602052604090205460ff16155b156121cb576121c8565b6109666004355b600160a060020a0381166000908152601460205260409020545b919050565b6109666004356024356000600034111561259957610002565b610966600062e6b680420360026000505410806106505750600354600160a060020a0390811633909116145b80156106645750600254621274ff19420190105b156126145750426002908155600180549091028155610983565b610966600435600a6020526000908152604090205481565b610966600435602435600060006000600060006000341115611ba157610002565b610a7d600854600160a060020a031681565b610966600c5481565b61096660005460001901610983565b61096660025481565b61096660043560006000600060003411156121fc57610002565b6109665b6001610983565b6109666004356024355b60115460009060ff16801561072f5750600f5442115b801561248757506124853361044b565b61096660115460ff1681565b6109666004355b60006000600f600050544210801561076a5750600034115b80156107a457506011546101009004600160a060020a0316600014806107a457506011546101009004600160a060020a0390811633909116145b15610b9f57610a9c61037f565b610a7d600435600060006000508281548110156100025750508080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56b600e83020180548290811015610002575081526020902060030154600160a060020a0316610606565b61096660043560243560006000610e1b336105ec565b6109665b6000600034111561247c57610002565b61096660043560056020526000908152604090205481565b610966600435602435604435600061252f845b6000600060003411156127ac57610002565b610966600435602435600160a060020a0382811660009081526015602090815260408083209385168352929052205461033f565b610a9a600435600034111561254557610002565b610966600435600b6020526000908152604090205481565b610a7d600354600160a060020a031681565b604080516020606435600481810135601f81018490048402850184019095528484526109669481359460248035956044359560849492019190819084018382808284375094965050505050505060006000600034111561103257610002565b610a7d6011546101009004600160a060020a031681565b60408051918252519081900360200190f35b610980610708565b90505b90565b604051808d600160a060020a031681526020018c8152602001806020018b81526020018a815260200189815260200188815260200187815260200186815260200185815260200184815260200183600160a060020a0316815260200182810382528c818154600181600116156101000203166002900481526020019150805460018160011615610100020316600290048015610a635780601f10610a3857610100808354040283529160200191610a63565b820191906000526020600020905b815481529060010190602001808311610a4657829003601f168201915b50509d505050505050505050505050505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b005b604051601254601434908102939093049350600160a060020a03169183900390600081818185876185025a03f150505050600160a060020a038316600081815260146020908152604080832080548601905560168054860190556013825291829020805434019055815184815291517fdbccb92686efceafb9bb7e0394df7f58f71b954061b81afb57109bf247d3d75a9281900390910190a260105460165410801590610b4c575060115460ff16155b15610b94576011805460ff1916600117905560165460408051918252517ff381a3e2428fdda36615919e8d9c35878d9eb0cf85ac6edf575088e80e4c147e9181900360200190a15b600191505b50919050565b610002565b600f5442118015610bb8575060115460ff16155b15610de357601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040516012549051600160a060020a039190911631109050610cc9576040805160125460e060020a63d2cc718f0282529151600160a060020a039290921691630221038a913091849163d2cc718f91600482810192602092919082900301816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a039490941660048201526024810193909352516044838101936020935082900301816000876161da5a03f115610002575050505b33600160a060020a0316600081815260136020526040808220549051909181818185876185025a03f19250505015610de35733600160a060020a03167fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d6013600050600033600160a060020a03168152602001908152602001600020600050546040518082815260200191505060405180910390a26014600050600033600160a060020a0316815260200190815260200160002060005054601660008282825054039250508190555060006014600050600033600160a060020a031681526020019081526020016000206000508190555060006013600050600033600160a060020a03168152602001908152602001600020600050819055505b565b4262054600600f60005054031115610e13576201518062127500600f60005054034203046014019050610983565b50601e610983565b60001415610e2857610002565b6000341115610e3657610002565b6000805485908110156100025750600160a060020a03331681527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56e600e8602908101602052604090912054600080516020612a3683398151915291909101915060ff1680610eb05750600c810160205260406000205460ff165b80610ebf575060038101544210155b15610ec957610002565b8215610f0f5733600160a060020a03166000908152601460209081526040808320546009850180549091019055600b84019091529020805460ff19166001179055610f4b565b33600160a060020a0316600090815260146020908152604080832054600a850180549091019055600c84019091529020805460ff191660011790555b33600160a060020a03166000908152600b60205260408120541415610f77576040600020849055610feb565b33600160a060020a03166000908152600b60205260408120548154811015610002579080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566600e909102015460038201541115610feb5733600160a060020a03166000908152600b602052604090208490555b60408051848152905133600160a060020a03169186917f86abfce99b7dd908bec0169288797f85049ec73cbe046ed9de818fab3a497ae09181900360200190a35092915050565b6000805487908110156100025750808052600e8702600080516020612a3683398151915201905090508484846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020816005016000505414915050949350505050565b600014156110ce57610002565b82801561111857508660001415806110e857508451600014155b806111005750600354600160a060020a038981169116145b8061110b5750600034115b80611118575062093a8084105b1561112257610002565b8215801561114257506111348861115c565b158061114257506212750084105b156111fe57610002565b83546118e590600160a060020a03165b600160a060020a03811660009081526004602052604081205460ff16806111f15750601254600160a060020a039081169083161480156111f15750601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051516006541190505b156129a157506001610606565b6249d40084111561120e57610002565b60115460ff1615806112215750600f5442105b806112365750600c5434108015611236575082155b1561124057610002565b42844201101561124f57610002565b30600160a060020a031633600160a060020a0316141561126e57610002565b60008054600181018083559091908280158290116112a557600e0281600e0283600052602060002091820191016112a5919061136a565b505060008054929450918491508110156100025750808052600e8302600080516020612a368339815191520190508054600160a060020a031916891781556001818101899055875160028084018054600082815260209081902096975091959481161561010002600019011691909104601f908101829004840193918b019083901061146257805160ff19168380011785555b5061149292915061144a565b5050600060098201819055600a820155600d81018054600160a060020a03191690556001015b8082111561145e578054600160a060020a03191681556000600182810182905560028084018054848255909281161561010002600019011604601f81901061143057505b506000600383018190556004808401805461ffff19169055600584018290556006840182905560078401805460ff191690556008840180548382559083526020909220611344929091028101905b8082111561145e57600080825560018201818155600283019190915560039091018054600160a060020a03191690556113fc565b601f0160209004906000526020600020908101906113ae91905b8082111561145e576000815560010161144a565b5090565b82800160010185558215611338579182015b82811115611338578251826000505591602001919060010190611474565b50508787866040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160050160005081905550834201816003016000508190555060018160040160006101000a81548160ff02191690830217905550828160070160006101000a81548160ff02191690830217905550821561157857600881018054600181018083559091908280158290116115735760040281600402836000526020600020918201910161157391906113fc565b505050505b600d8082018054600160a060020a031916331790553460068301819055815401905560408051600160a060020a038a16815260208181018a9052918101859052608060608201818152895191830191909152885185937f5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f938d938d938a938e93929160a084019185810191908190849082908590600090600490601f850104600f02600301f150905090810190601f1680156116485780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a2509695505050505050565b6040805186815260208101839052815189927fdfc78bdca8e3e0b18c16c5c99323c6cb9eb5e00afde190b4e7273f5158702b07928290030190a25b5050505092915050565b6000805488908110156100025750808052600e8802600080516020612a36833981519152019050600781015490945060ff166116e757620d2f006116ec565b622398805b600485015490935060ff16801561170857506003840154830142115b15611716576117b887611890565b600384015442108061172d5750600484015460ff16155b806117ae57508360000160009054906101000a9004600160a060020a03168460010160005054876040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020846005016000505414155b1561114c57610002565b61169e565b60048401805461ff001916610100179055835460019550600160a060020a03908116309091161480159061180157508354600754600160a060020a03908116911614155b801561181d57506008548454600160a060020a03908116911614155b801561183957508354601254600160a060020a03908116911614155b801561185557506003548454600160a060020a03908116911614155b1561188b5760018401805430600160a060020a031660009081526005602052604090208054919091019055546006805490910190555b611663875b6000600060005082815481101561000257908052600e02600080516020612a36833981519152018150600481015490915060ff16156118d757600d80546006830154900390555b600401805460ff1916905550565b15156118f45761190087611890565b6001915061193161047f565b604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050505061169e565b6001850154111561194157600091505b50600a8301546009840154865191019060049010801590611986575085600081518110156100025790602001015160f860020a900460f860020a02606860f860020a02145b80156119b6575085600181518110156100025790602001015160f860020a900460f860020a02603760f860020a02145b80156119e6575085600281518110156100025790602001015160f860020a900460f860020a0260ff60f860020a02145b8015611a16575085600381518110156100025790602001015160f860020a900460f860020a02601e60f860020a02145b8015611a45575030600160a060020a0316600090815260056020526040902054611a4290611a5d61047f565b81105b15611a4f57600091505b6001840154611a8090611a5f565b015b30600160a060020a03166000908152600560205260408120546129a961047f565b8110611ad457604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050501515611abc57610002565b4260025560165460059004811115611ad45760056001555b6001840154611ae290611a5f565b8110158015611af85750600a8401546009850154115b8015611b015750815b1561188b578360000160009054906101000a9004600160a060020a0316600160a060020a0316846001016000505487604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611b7d5780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f19250505015156117bd57610002565b611baa336105ec565b60001415611bb757610002565b60008054889081101561000257508052600e87027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566810154600080516020612a36833981519152919091019450421080611c1957506003840154622398800142115b80611c3257508354600160a060020a0390811690871614155b80611c425750600784015460ff16155b80611c68575033600160a060020a03166000908152600b8501602052604090205460ff16155b80611c9c575033600160a060020a03166000908152600b60205260409020548714801590611c9c5750604060009081205414155b15611ca657610002565b600884018054600090811015610002579081526020812060030154600160a060020a03161415611e1257611efc86604051600090600160a060020a038316907f9046fefd66f538ab35263248a44217dcb70e2eb2cd136629e141b8b8f9f03b60908390a260408051600e547fe2faf044000000000000000000000000000000000000000000000000000000008252600160a060020a03858116600484015260248301859052604483018590526223988042016064840152925192169163e2faf04491608480820192602092909190829003018187876161da5a03f1156100025750506040515191506106069050565b6008850180546000908110156100025781815260208082209390935530600160a060020a031681526005909252604082205481549092908110156100025790815260208120905060020155601654600885018054600090811015610002579081526020812090506001015560048401805461ff0019166101001790555b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090505433600160a060020a031660009081526014602052604081205460088801805493909102939093049550908110156100025790815260208120905060030154604080517fbaac530000000000000000000000000000000000000000000000000000000000815233600160a060020a0390811660048301529151929091169163baac53009186916024808301926020929190829003018185886185025a03f11561000257505060405151600014159150611f78905057610002565b60088501805460009081101561000257818152602081206003018054600160a060020a03191690931790925580549091908110156100025790815260208120905060030154600160a060020a031660001415611f5757610002565b600d5430600160a060020a0316311015611f7057610002565b611d9561047f565b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090506002015433600160a060020a0390811660009081526014602090815260408083205430909416835260058083528184205460099093529083205460088b018054969095029690960497509487020494508593929091908290811015610002575260208120815060030154600160a060020a0390811682526020828101939093526040918201600090812080549095019094553016835260059091529020548290101561205357610002565b30600160a060020a031660009081526005602052604081208054849003905560088501805483926009929091829081101561000257508152602080822060030154600160a060020a039081168352929052604080822080549094019093553090911681522054819010156120c657610002565b30600160a060020a0390811660009081526009602090815260408083208054869003905533909316808352601482528383205484519081529351929390927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a36121383361086c565b5033600160a060020a03166000908152601460209081526040808320805460168054919091039055839055600a9091528120556001945061169e565b30600160a060020a0390811660008181526005602090815260408083208054958716808552828520805490970190965584845283905560099091528082208054948352908220805490940190935590815290555b50565b604051600160a060020a0382811691309091163190600081818185876185025a03f192505050151561217457610002565b33600160a060020a03818116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f028352935197995091969195929092169363d2cc718f936004848101949193929183900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a03168152602001908152602001600020600050540204101561229d57610002565b600160a060020a03338116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f02835293519296909593169363d2cc718f93600483810194929383900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a0316815260200190815260200160002060005054020403905083156123ec57600860009054906101000a9004600160a060020a0316600160a060020a0316630221038a83600160a060020a0316630e7082036040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a031660048201526024810186905290516044808301935060209282900301816000876161da5a03f115610002575050604051511515905061245457610002565b6040805160085460e160020a63011081c5028252600160a060020a038581166004840152602483018590529251921691630221038a9160448082019260209290919082900301816000876161da5a03f115610002575050604051511515905061245457610002565b600160a060020a03331660009081526009602052604090208054909101905550600192915050565b6109803361086c565b155b80156124a257506124a23384845b6000600061293a856105ec565b80156124be57506124be83836000600034111561261c57610002565b15610b9f5750600161033f565b15156124d657610002565b6124e08383610719565b905061033f565b155b80156124fb57506124fb848484612495565b80156125185750612518848484600060003411156126c157610002565b15610b9f57506001612528565b90505b9392505050565b151561253a57610002565b61252584848461041b565b30600160a060020a031633600160a060020a031614158061258a575030600160a060020a031660009081526005602052604090205460649061258561047f565b010481115b1561259457610002565b600c55565b600354600160a060020a0390811633909116146125b557610002565b600160a060020a038316600081815260046020908152604091829020805460ff191686179055815185815291517f73ad2a153c8b67991df9459024950b318a609782cee8c7eeda47b905f9baa91f9281900390910190a250600161033f565b506000610983565b33600160a060020a03166000908152601460205260409020548290108015906126455750600082115b156126b957600160a060020a03338116600081815260146020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a350600161033f565b50600061033f565b600160a060020a03841660009081526014602052604090205482901080159061270a5750601560209081526040600081812033600160a060020a03168252909252902054829010155b80156127165750600082115b156127a457600160a060020a03838116600081815260146020908152604080832080548801905588851680845281842080548990039055601583528184203390961684529482529182902080548790039055815186815291519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001612528565b506000612528565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f11561000257505060405151905061281a866105ec565b0204101561282757610002565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f115610002575050604051519050612895866105ec565b0204039050600760009054906101000a9004600160a060020a0316600160a060020a0316630221038a84836040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511515905061291357610002565b600160a060020a0383166000908152600a6020526040902080548201905560019150610b99565b600160a060020a0386166000908152600a602052604090205480850291909104915081111561296857610002565b600160a060020a038581166000908152600a60205260408082208054859003905591861681522080548201905560019150509392505050565b506000610606565b0160030260166000505483020460016000505460166000505404019050610606565b600160a060020a0383166000908152600b6020526040812054815481101561000257818052600e02600080516020612a368339815191520190506003810154909150421115610b9457600160a060020a0383166000908152600b602052604081208190559150610b9956290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563", + "nonce": "3", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000120", + "0x000000000000000000000000000000000000000000000000000000000000000f": "0x0000000000000000000000000000000000000000000000000000000057495e10", + "0x0000000000000000000000000000000000000000000000000000000000000011": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000016": "0x000000000000000000000000000000000000000000098b4d3b425f8c368391b2", + "0x29066f14bd0b438bb3db8771a65febf0be7574be7528f87e7ae11aafc2b2c3ac": "0x000000000000000000000000000000000000000000000025d57ab057892050fc", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f443": "0x000000000000000000000000b3b10eff47b9c0b3e5579bf1c25872111667e650", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f444": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f445": "0x0000000000000000000000000000000000000000000000000000000000000093", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f446": "0x00000000000000000000000000000000000000000000000000000000579a07ea", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f447": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f448": "0x63c103e1feea47a9bf6c0dce1349da1a95b96532661d43063ab8e52b3e2a844b", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f449": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f44a": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f44b": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f44c": "0x00000000000000000000000000000000000000000000000001620725a3de2009", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f44d": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3f450": "0x000000000000000000000000b3b10eff47b9c0b3e5579bf1c25872111667e650", + "0x3987ba2457a57cc6778cce06d8c58970029977d834f0de345c7a495612cbb060": "0x00000000000000000000000000000000000000000000081f2acc2a62590de041", + "0x3987ba2457a57cc6778cce06d8c58970029977d834f0de345c7a495612cbb061": "0x000000000000000000000000000000000000000000098b4d3b425f8c368391b2", + "0x3987ba2457a57cc6778cce06d8c58970029977d834f0de345c7a495612cbb062": "0x00000000000000000000000000000000000000000000003635c9adc5dea00000", + "0x3987ba2457a57cc6778cce06d8c58970029977d834f0de345c7a495612cbb063": "0x00000000000000000000000010abb5efecdc09581f8b7cb95791fe2936790b4e", + "0x6f125332c6f598e8798f0c277f4b1052ac80cd02ff2eebe0c7f362d63b6959ef": "0x000000000000000000000000000000000000000000000000008dc9007b27b5a9", + "0x793bebaf0ea12c858c08547e9aa88b849bba94bb6933c7bdb0fecbb707ecf5c7": "0x00000000000000000000000000000000000000000000076d52eebfbfbfc172e5", + "0xaccfa2662c944e8eae80b7720d9d232eb6809c18f6c8da65189acbb38069d869": "0x000000000000000000000000000000000000000000000000000289739e60e3e2", + "0xb6e4d5c52e0c64fb49c5a97cacdbcf8bd94b5bd4d490590326a19d27eaf543ae": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xbe273e24e8bd646e29d1fb5a924a12a8585095b9f45a317fc708165a127fdd70": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xc34fc4bc1a730d3f836c9ac5124865056e88f3776b63662e34976bdb47549077": "0x000000000000000000000000000000000000000000000036353be4c563784a57", + "0xe2112d92b8a1d00a569b85fbe7a384a5c9f74f5ff8478647397cb58dde254ffa": "0x53706c697420666f722070656f706c652077686f2073656e74206d6f6e657920", + "0xe2112d92b8a1d00a569b85fbe7a384a5c9f74f5ff8478647397cb58dde254ffb": "0x746f207468652044414f20616674657220746865204861726420466f726b2062", + "0xe2112d92b8a1d00a569b85fbe7a384a5c9f74f5ff8478647397cb58dde254ffc": "0x79206d697374616b650000000000000000000000000000000000000000000000", + "0xf60322aa1a2e769d412b36e4a9def4300f7540bf1bc9e0f4691786a9100145fa": "0x0000000000000000000000000000000000000000000000000000000062188dd2", + "0xf735edeea40e4ec771f49da7f7b854b398a1ad43f8a9617d43e53d3093e9fdc0": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xf7905fa5d54027d5d59f4678dda481331babad2d3d0fdefd552afbce2e74c07e": "0x0000000000000000000000000000000000000000000000000000000000000110" + } + }, + "0xe6002189a74b43e6868b20c1311bc108e38aac57": { + "balance": "0x29129264d1ae4848b", + "nonce": "45" + }, + "0xea674fdde714fd979de3edf0f56aa9716b898ec8": { + "balance": "0x1601bbe4c58ec73210", + "nonce": "337736" + }, + "0xfde8d5f77ef48bb7bf5766c7404691b9ee1dfca7": { + "balance": "0x0", + "code": "0x606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b9291505056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "1968180", + "difficulty": "56311715252709", + "timestamp": "1469713694", + "gasLimit": "4712388", + "miner": "0xea674fdde714fd979de3edf0f56aa9716b898ec8" + }, + "input": "0xf8aa2d850c2b6f9f7e830aae6094630a0cd35d5bd57e61410fda76fea850225cda1880b844e1fa7638000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000000001ba0563f81ca66b2c618bf4be9470fab88fff1b44eb5c33a9c73a68e8b26fbaa7c8da041464789c49fee77d2e053ff0705bc845fe2a78a35e478132371f294bb594021", + "tracerConfig": { + "withLog": true + }, + "result": { + "from": "0xe6002189a74b43e6868b20c1311bc108e38aac57", + "gas": "0xa59c8", + "gasUsed": "0xaae60", + "to": "0x630a0cd35d5bd57e61410fda76fea850225cda18", + "input": "0xe1fa763800000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000000", + "error": "invalid jump destination", + "calls": [ + { + "from": "0x630a0cd35d5bd57e61410fda76fea850225cda18", + "gas": "0x9f5a0", + "gasUsed": "0x314", + "to": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", + "input": "0x70a08231000000000000000000000000630a0cd35d5bd57e61410fda76fea850225cda18", + "output": "0x000000000000000000000000000000000000000000000000000289739e60e3e2", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x630a0cd35d5bd57e61410fda76fea850225cda18", + "gas": "0x9a327", + "gasUsed": "0x67b0", + "to": "0x6e073c0e1bd5af550239025dffcfb37175acedd3", + "input": "0x1a695230000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c189413", + "calls": [ + { + "from": "0x6e073c0e1bd5af550239025dffcfb37175acedd3", + "gas": "0x93ff6", + "gasUsed": "0x314", + "to": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", + "input": "0x70a082310000000000000000000000006e073c0e1bd5af550239025dffcfb37175acedd3", + "output": "0x000000000000000000000000000000000000000000000025d57ab057892050fc", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e073c0e1bd5af550239025dffcfb37175acedd3", + "gas": "0x93c42", + "gasUsed": "0x13f", + "to": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", + "input": "0x18160ddd", + "output": "0x000000000000000000000000000000000000000000098b4d3b425f8c368391b2", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x6e073c0e1bd5af550239025dffcfb37175acedd3", + "gas": "0x939ba", + "gasUsed": "0x5fca", + "to": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", + "input": "0xa9059cbb000000000000000000000000630a0cd35d5bd57e61410fda76fea850225cda18000000000000000000000000000000000000000000000025d57ab057892050fc", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x630a0cd35d5bd57e61410fda76fea850225cda18", + "gas": "0x8d8b6", + "gasUsed": "0x7be", + "to": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", + "input": "0x013cf08b0000000000000000000000000000000000000000000000000000000000000110", + "output": "0x000000000000000000000000b3b10eff47b9c0b3e5579bf1c25872111667e6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000579a07ea0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000163c103e1feea47a9bf6c0dce1349da1a95b96532661d43063ab8e52b3e2a844b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000001620725a3de20090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b3b10eff47b9c0b3e5579bf1c25872111667e650000000000000000000000000000000000000000000000000000000000000004953706c697420666f722070656f706c652077686f2073656e74206d6f6e657920746f207468652044414f20616674657220746865204861726420466f726b206279206d697374616b650000000000000000000000000000000000000000000000", + "value": "0x0", + "type": "CALL" + }, + { + "from": "0x630a0cd35d5bd57e61410fda76fea850225cda18", + "gas": "0x880f8", + "gasUsed": "0x880f8", + "to": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", + "input": "0x82661dc40000000000000000000000000000000000000000000000000000000000000110000000000000000000000000b3b10eff47b9c0b3e5579bf1c25872111667e650", + "error": "invalid jump destination", + "calls": [ + { + "from": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", + "gas": "0x7f910", + "gasUsed": "0xd20f", + "to": "0x10abb5efecdc09581f8b7cb95791fe2936790b4e", + "input": "0xbaac5300000000000000000000000000630a0cd35d5bd57e61410fda76fea850225cda18", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "calls": [ + { + "from": "0x10abb5efecdc09581f8b7cb95791fe2936790b4e", + "gas": "0x76e12", + "gasUsed": "0x13f9", + "to": "0xfde8d5f77ef48bb7bf5766c7404691b9ee1dfca7", + "input": "0x", + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x20320625e3126cb0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + } + ], + "value": "0x0", + "type": "CALL" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json new file mode 100644 index 000000000000..8df52db23c85 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json @@ -0,0 +1,107 @@ +{ + "genesis": { + "difficulty": "45372803248884", + "extraData": "0x65746865726d696e652e6f7267202855533129", + "gasLimit": "4712388", + "hash": "0xa2b18cc64ec062676680f2bb2d880205dcd372f4396722f2294d3fceece96193", + "miner": "0xea674fdde714fd979de3edf0f56aa9716b898ec8", + "mixHash": "0xce7c26a9238b249edcdcd51f0ea1ad0e632e872daf9a09f039d918bcaeb7194f", + "nonce": "0x849d49e634e93bb5", + "number": "1646451", + "stateRoot": "0x2bd193b9911caf43204960cc7661ce864bf0bac7f9b60191aa02bbff24f061fb", + "timestamp": "1465103859", + "totalDifficulty": "24813742796574158431", + "alloc": { + "0x01115b41bd2731353dd3e6abf44818fdc035aaf1": { + "balance": "0x16d99e16e809000", + "nonce": "23" + }, + "0x61c808d82a3ac53231750dadc13c777b59310bd9": { + "balance": "0x6a636960e34bd696f4", + "nonce": "36888" + }, + "0xbb9bc244d798123fde783fcc1c72d3bb8c189413": { + "balance": "0x9b37460cdbcba74181f81", + "code": "0x6060604052361561020e5760e060020a6000350463013cf08b8114610247578063095ea7b3146102d05780630c3b7b96146103455780630e7082031461034e578063149acf9a1461036057806318160ddd146103725780631f2dc5ef1461037b57806321b5b8dd1461039b578063237e9492146103ad57806323b872dd1461040e5780632632bf2014610441578063341458081461047257806339d1f9081461047b5780634b6753bc146104935780634df6d6cc1461049c5780634e10c3ee146104b7578063590e1ae3146104ca578063612e45a3146104db578063643f7cdd1461057a578063674ed066146105925780636837ff1e1461059b57806370a08231146105e5578063749f98891461060b57806378524b2e1461062457806381f03fcb1461067e57806382661dc41461069657806382bf6464146106b75780638b15a605146106c95780638d7af473146106d257806396d7f3f5146106e1578063a1da2fb9146106ea578063a3912ec814610704578063a9059cbb1461070f578063b7bc2c841461073f578063baac53001461074b578063be7c29c1146107b1578063c9d27afe14610817578063cc9ae3f61461082d578063cdef91d014610841578063dbde198814610859578063dd62ed3e1461087e578063e33734fd146108b2578063e5962195146108c6578063e66f53b7146108de578063eceb2945146108f0578063f8c80d261461094f575b610966600f546000906234bc000142108015610239575060125433600160a060020a03908116911614155b156109785761098033610752565b6109866004356000805482908110156100025750808052600e8202600080516020612a3683398151915201905060038101546004820154600683015460018401548454600786015460058701546009880154600a890154600d8a0154600160a060020a039586169b509599600201989760ff81811698610100909204811697949691951693168c565b61096660043560243533600160a060020a03908116600081815260156020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b61096660105481565b610a7d600754600160a060020a031681565b610a7d600e54600160a060020a031681565b61096660165481565b6109665b60004262127500600f60005054031115610de557506014610983565b610a7d601254600160a060020a031681565b60408051602060248035600481810135601f810185900485028601850190965285855261096695813595919460449492939092019181908401838280828437509496505050505050506000600060006000600060003411156116a857610002565b6109666004356024356044355b60115460009060ff1680156104315750600f5442115b80156124e957506124e78461044b565b6109666000610980335b600160a060020a0381166000908152600b602052604081205481908114156129cb57610b99565b61096660065481565b6109665b600d5430600160a060020a03163103610983565b610966600f5481565b61096660043560046020526000908152604090205460ff1681565b61096660043560243560006124cb610831565b610a9a6000341115610ba457610002565b604080516020604435600481810135601f8101849004840285018401909552848452610966948135946024803595939460649492939101918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050933593505060a435915050600060006110c1336105ec565b61096660043560096020526000908152604090205481565b61096660015481565b610a9a60043530600160a060020a031633600160a060020a03161415806105db5750600160a060020a03811660009081526004602052604090205460ff16155b156121cb576121c8565b6109666004355b600160a060020a0381166000908152601460205260409020545b919050565b6109666004356024356000600034111561259957610002565b610966600062e6b680420360026000505410806106505750600354600160a060020a0390811633909116145b80156106645750600254621274ff19420190105b156126145750426002908155600180549091028155610983565b610966600435600a6020526000908152604090205481565b610966600435602435600060006000600060006000341115611ba157610002565b610a7d600854600160a060020a031681565b610966600c5481565b61096660005460001901610983565b61096660025481565b61096660043560006000600060003411156121fc57610002565b6109665b6001610983565b6109666004356024355b60115460009060ff16801561072f5750600f5442115b801561248757506124853361044b565b61096660115460ff1681565b6109666004355b60006000600f600050544210801561076a5750600034115b80156107a457506011546101009004600160a060020a0316600014806107a457506011546101009004600160a060020a0390811633909116145b15610b9f57610a9c61037f565b610a7d600435600060006000508281548110156100025750508080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56b600e83020180548290811015610002575081526020902060030154600160a060020a0316610606565b61096660043560243560006000610e1b336105ec565b6109665b6000600034111561247c57610002565b61096660043560056020526000908152604090205481565b610966600435602435604435600061252f845b6000600060003411156127ac57610002565b610966600435602435600160a060020a0382811660009081526015602090815260408083209385168352929052205461033f565b610a9a600435600034111561254557610002565b610966600435600b6020526000908152604090205481565b610a7d600354600160a060020a031681565b604080516020606435600481810135601f81018490048402850184019095528484526109669481359460248035956044359560849492019190819084018382808284375094965050505050505060006000600034111561103257610002565b610a7d6011546101009004600160a060020a031681565b60408051918252519081900360200190f35b610980610708565b90505b90565b604051808d600160a060020a031681526020018c8152602001806020018b81526020018a815260200189815260200188815260200187815260200186815260200185815260200184815260200183600160a060020a0316815260200182810382528c818154600181600116156101000203166002900481526020019150805460018160011615610100020316600290048015610a635780601f10610a3857610100808354040283529160200191610a63565b820191906000526020600020905b815481529060010190602001808311610a4657829003601f168201915b50509d505050505050505050505050505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b005b604051601254601434908102939093049350600160a060020a03169183900390600081818185876185025a03f150505050600160a060020a038316600081815260146020908152604080832080548601905560168054860190556013825291829020805434019055815184815291517fdbccb92686efceafb9bb7e0394df7f58f71b954061b81afb57109bf247d3d75a9281900390910190a260105460165410801590610b4c575060115460ff16155b15610b94576011805460ff1916600117905560165460408051918252517ff381a3e2428fdda36615919e8d9c35878d9eb0cf85ac6edf575088e80e4c147e9181900360200190a15b600191505b50919050565b610002565b600f5442118015610bb8575060115460ff16155b15610de357601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040516012549051600160a060020a039190911631109050610cc9576040805160125460e060020a63d2cc718f0282529151600160a060020a039290921691630221038a913091849163d2cc718f91600482810192602092919082900301816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a039490941660048201526024810193909352516044838101936020935082900301816000876161da5a03f115610002575050505b33600160a060020a0316600081815260136020526040808220549051909181818185876185025a03f19250505015610de35733600160a060020a03167fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d6013600050600033600160a060020a03168152602001908152602001600020600050546040518082815260200191505060405180910390a26014600050600033600160a060020a0316815260200190815260200160002060005054601660008282825054039250508190555060006014600050600033600160a060020a031681526020019081526020016000206000508190555060006013600050600033600160a060020a03168152602001908152602001600020600050819055505b565b4262054600600f60005054031115610e13576201518062127500600f60005054034203046014019050610983565b50601e610983565b60001415610e2857610002565b6000341115610e3657610002565b6000805485908110156100025750600160a060020a03331681527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56e600e8602908101602052604090912054600080516020612a3683398151915291909101915060ff1680610eb05750600c810160205260406000205460ff165b80610ebf575060038101544210155b15610ec957610002565b8215610f0f5733600160a060020a03166000908152601460209081526040808320546009850180549091019055600b84019091529020805460ff19166001179055610f4b565b33600160a060020a0316600090815260146020908152604080832054600a850180549091019055600c84019091529020805460ff191660011790555b33600160a060020a03166000908152600b60205260408120541415610f77576040600020849055610feb565b33600160a060020a03166000908152600b60205260408120548154811015610002579080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566600e909102015460038201541115610feb5733600160a060020a03166000908152600b602052604090208490555b60408051848152905133600160a060020a03169186917f86abfce99b7dd908bec0169288797f85049ec73cbe046ed9de818fab3a497ae09181900360200190a35092915050565b6000805487908110156100025750808052600e8702600080516020612a3683398151915201905090508484846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020816005016000505414915050949350505050565b600014156110ce57610002565b82801561111857508660001415806110e857508451600014155b806111005750600354600160a060020a038981169116145b8061110b5750600034115b80611118575062093a8084105b1561112257610002565b8215801561114257506111348861115c565b158061114257506212750084105b156111fe57610002565b83546118e590600160a060020a03165b600160a060020a03811660009081526004602052604081205460ff16806111f15750601254600160a060020a039081169083161480156111f15750601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051516006541190505b156129a157506001610606565b6249d40084111561120e57610002565b60115460ff1615806112215750600f5442105b806112365750600c5434108015611236575082155b1561124057610002565b42844201101561124f57610002565b30600160a060020a031633600160a060020a0316141561126e57610002565b60008054600181018083559091908280158290116112a557600e0281600e0283600052602060002091820191016112a5919061136a565b505060008054929450918491508110156100025750808052600e8302600080516020612a368339815191520190508054600160a060020a031916891781556001818101899055875160028084018054600082815260209081902096975091959481161561010002600019011691909104601f908101829004840193918b019083901061146257805160ff19168380011785555b5061149292915061144a565b5050600060098201819055600a820155600d81018054600160a060020a03191690556001015b8082111561145e578054600160a060020a03191681556000600182810182905560028084018054848255909281161561010002600019011604601f81901061143057505b506000600383018190556004808401805461ffff19169055600584018290556006840182905560078401805460ff191690556008840180548382559083526020909220611344929091028101905b8082111561145e57600080825560018201818155600283019190915560039091018054600160a060020a03191690556113fc565b601f0160209004906000526020600020908101906113ae91905b8082111561145e576000815560010161144a565b5090565b82800160010185558215611338579182015b82811115611338578251826000505591602001919060010190611474565b50508787866040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160050160005081905550834201816003016000508190555060018160040160006101000a81548160ff02191690830217905550828160070160006101000a81548160ff02191690830217905550821561157857600881018054600181018083559091908280158290116115735760040281600402836000526020600020918201910161157391906113fc565b505050505b600d8082018054600160a060020a031916331790553460068301819055815401905560408051600160a060020a038a16815260208181018a9052918101859052608060608201818152895191830191909152885185937f5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f938d938d938a938e93929160a084019185810191908190849082908590600090600490601f850104600f02600301f150905090810190601f1680156116485780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a2509695505050505050565b6040805186815260208101839052815189927fdfc78bdca8e3e0b18c16c5c99323c6cb9eb5e00afde190b4e7273f5158702b07928290030190a25b5050505092915050565b6000805488908110156100025750808052600e8802600080516020612a36833981519152019050600781015490945060ff166116e757620d2f006116ec565b622398805b600485015490935060ff16801561170857506003840154830142115b15611716576117b887611890565b600384015442108061172d5750600484015460ff16155b806117ae57508360000160009054906101000a9004600160a060020a03168460010160005054876040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020846005016000505414155b1561114c57610002565b61169e565b60048401805461ff001916610100179055835460019550600160a060020a03908116309091161480159061180157508354600754600160a060020a03908116911614155b801561181d57506008548454600160a060020a03908116911614155b801561183957508354601254600160a060020a03908116911614155b801561185557506003548454600160a060020a03908116911614155b1561188b5760018401805430600160a060020a031660009081526005602052604090208054919091019055546006805490910190555b611663875b6000600060005082815481101561000257908052600e02600080516020612a36833981519152018150600481015490915060ff16156118d757600d80546006830154900390555b600401805460ff1916905550565b15156118f45761190087611890565b6001915061193161047f565b604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050505061169e565b6001850154111561194157600091505b50600a8301546009840154865191019060049010801590611986575085600081518110156100025790602001015160f860020a900460f860020a02606860f860020a02145b80156119b6575085600181518110156100025790602001015160f860020a900460f860020a02603760f860020a02145b80156119e6575085600281518110156100025790602001015160f860020a900460f860020a0260ff60f860020a02145b8015611a16575085600381518110156100025790602001015160f860020a900460f860020a02601e60f860020a02145b8015611a45575030600160a060020a0316600090815260056020526040902054611a4290611a5d61047f565b81105b15611a4f57600091505b6001840154611a8090611a5f565b015b30600160a060020a03166000908152600560205260408120546129a961047f565b8110611ad457604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050501515611abc57610002565b4260025560165460059004811115611ad45760056001555b6001840154611ae290611a5f565b8110158015611af85750600a8401546009850154115b8015611b015750815b1561188b578360000160009054906101000a9004600160a060020a0316600160a060020a0316846001016000505487604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611b7d5780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f19250505015156117bd57610002565b611baa336105ec565b60001415611bb757610002565b60008054889081101561000257508052600e87027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566810154600080516020612a36833981519152919091019450421080611c1957506003840154622398800142115b80611c3257508354600160a060020a0390811690871614155b80611c425750600784015460ff16155b80611c68575033600160a060020a03166000908152600b8501602052604090205460ff16155b80611c9c575033600160a060020a03166000908152600b60205260409020548714801590611c9c5750604060009081205414155b15611ca657610002565b600884018054600090811015610002579081526020812060030154600160a060020a03161415611e1257611efc86604051600090600160a060020a038316907f9046fefd66f538ab35263248a44217dcb70e2eb2cd136629e141b8b8f9f03b60908390a260408051600e547fe2faf044000000000000000000000000000000000000000000000000000000008252600160a060020a03858116600484015260248301859052604483018590526223988042016064840152925192169163e2faf04491608480820192602092909190829003018187876161da5a03f1156100025750506040515191506106069050565b6008850180546000908110156100025781815260208082209390935530600160a060020a031681526005909252604082205481549092908110156100025790815260208120905060020155601654600885018054600090811015610002579081526020812090506001015560048401805461ff0019166101001790555b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090505433600160a060020a031660009081526014602052604081205460088801805493909102939093049550908110156100025790815260208120905060030154604080517fbaac530000000000000000000000000000000000000000000000000000000000815233600160a060020a0390811660048301529151929091169163baac53009186916024808301926020929190829003018185886185025a03f11561000257505060405151600014159150611f78905057610002565b60088501805460009081101561000257818152602081206003018054600160a060020a03191690931790925580549091908110156100025790815260208120905060030154600160a060020a031660001415611f5757610002565b600d5430600160a060020a0316311015611f7057610002565b611d9561047f565b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090506002015433600160a060020a0390811660009081526014602090815260408083205430909416835260058083528184205460099093529083205460088b018054969095029690960497509487020494508593929091908290811015610002575260208120815060030154600160a060020a0390811682526020828101939093526040918201600090812080549095019094553016835260059091529020548290101561205357610002565b30600160a060020a031660009081526005602052604081208054849003905560088501805483926009929091829081101561000257508152602080822060030154600160a060020a039081168352929052604080822080549094019093553090911681522054819010156120c657610002565b30600160a060020a0390811660009081526009602090815260408083208054869003905533909316808352601482528383205484519081529351929390927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a36121383361086c565b5033600160a060020a03166000908152601460209081526040808320805460168054919091039055839055600a9091528120556001945061169e565b30600160a060020a0390811660008181526005602090815260408083208054958716808552828520805490970190965584845283905560099091528082208054948352908220805490940190935590815290555b50565b604051600160a060020a0382811691309091163190600081818185876185025a03f192505050151561217457610002565b33600160a060020a03818116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f028352935197995091969195929092169363d2cc718f936004848101949193929183900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a03168152602001908152602001600020600050540204101561229d57610002565b600160a060020a03338116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f02835293519296909593169363d2cc718f93600483810194929383900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a0316815260200190815260200160002060005054020403905083156123ec57600860009054906101000a9004600160a060020a0316600160a060020a0316630221038a83600160a060020a0316630e7082036040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a031660048201526024810186905290516044808301935060209282900301816000876161da5a03f115610002575050604051511515905061245457610002565b6040805160085460e160020a63011081c5028252600160a060020a038581166004840152602483018590529251921691630221038a9160448082019260209290919082900301816000876161da5a03f115610002575050604051511515905061245457610002565b600160a060020a03331660009081526009602052604090208054909101905550600192915050565b6109803361086c565b155b80156124a257506124a23384845b6000600061293a856105ec565b80156124be57506124be83836000600034111561261c57610002565b15610b9f5750600161033f565b15156124d657610002565b6124e08383610719565b905061033f565b155b80156124fb57506124fb848484612495565b80156125185750612518848484600060003411156126c157610002565b15610b9f57506001612528565b90505b9392505050565b151561253a57610002565b61252584848461041b565b30600160a060020a031633600160a060020a031614158061258a575030600160a060020a031660009081526005602052604090205460649061258561047f565b010481115b1561259457610002565b600c55565b600354600160a060020a0390811633909116146125b557610002565b600160a060020a038316600081815260046020908152604091829020805460ff191686179055815185815291517f73ad2a153c8b67991df9459024950b318a609782cee8c7eeda47b905f9baa91f9281900390910190a250600161033f565b506000610983565b33600160a060020a03166000908152601460205260409020548290108015906126455750600082115b156126b957600160a060020a03338116600081815260146020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a350600161033f565b50600061033f565b600160a060020a03841660009081526014602052604090205482901080159061270a5750601560209081526040600081812033600160a060020a03168252909252902054829010155b80156127165750600082115b156127a457600160a060020a03838116600081815260146020908152604080832080548801905588851680845281842080548990039055601583528184203390961684529482529182902080548790039055815186815291519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001612528565b506000612528565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f11561000257505060405151905061281a866105ec565b0204101561282757610002565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f115610002575050604051519050612895866105ec565b0204039050600760009054906101000a9004600160a060020a0316600160a060020a0316630221038a84836040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511515905061291357610002565b600160a060020a0383166000908152600a6020526040902080548201905560019150610b99565b600160a060020a0386166000908152600a602052604090205480850291909104915081111561296857610002565b600160a060020a038581166000908152600a60205260408082208054859003905591861681522080548201905560019150509392505050565b506000610606565b0160030260166000505483020460016000505460166000505404019050610606565b600160a060020a0383166000908152600b6020526040812054815481101561000257818052600e02600080516020612a368339815191520190506003810154909150421115610b9457600160a060020a0383166000908152600b602052604081208190559150610b9956290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563", + "nonce": "3", + "storage": { + "0x000000000000000000000000000000000000000000000000000000000000000f": "0x0000000000000000000000000000000000000000000000000000000057495e10", + "0x0000000000000000000000000000000000000000000000000000000000000012": "0x000000000000000000000000807640a13483f8ac783c557fcdf27be11ea4ac7a" + } + }, + "0xcf1476387d780169410d4e936d75a206fda2a68c": { + "balance": "0x15fd0ad66ea7000", + "code": "0x606060405236156100b95760e060020a6000350463173825d9811461010b5780632f54bf6e1461015f5780634123cb6b146101875780635c52c2f5146101905780637065cb48146101ba578063746c9171146101e7578063797af627146101f0578063b20d30a914610203578063b61d27f614610230578063b75c7dc614610251578063ba51a6df14610280578063c2cf7326146102ad578063cbf0b0c0146102eb578063f00d4b5d14610318578063f1736d861461034a575b61035460003411156101095760408051600160a060020a033316815234602082015281517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c929181900390910190a15b565b610354600435600060003660405180838380828437820191505092505050604051809103902061064a815b600160a060020a03331660009081526101026020526040812054818082811415610c6657610dbf565b6103566004355b600160a060020a03811660009081526101026020526040812054115b919050565b61035660015481565b61035460003660405180838380828437820191505092505050604051809103902061078b81610136565b6103546004356000366040518083838082843782019150509250505060405180910390206105c681610136565b61035660005481565b6103566004355b600081610a2781610136565b61035460043560003660405180838380828437820191505092505050604051809103902061077f81610136565b6103566004803590602480359160443591820191013560006107aa33610166565b610354600435600160a060020a03331660009081526101026020526040812054908082811415610368576103e7565b61035460043560003660405180838380828437820191505092505050604051809103902061070881610136565b610356600435602435600082815261010360209081526040808320600160a060020a0385168452610102909252822054828181141561076157610776565b61035460043560003660405180838380828437820191505092505050604051809103902061079981610136565b610354600435602435600060003660405180838380828437820191505092505050604051809103902061047281610136565b6103566101055481565b005b60408051918252519081900360200190f35b50506000828152610103602052604081206001810154600284900a9290831611156103e75780546001828101805492909101835590839003905560408051600160a060020a03331681526020810186905281517fc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b929181900390910190a15b50505050565b600160a060020a03831660028361010081101561000257508301819055600160a060020a03851660008181526101026020908152604080832083905584835291829020869055815192835282019290925281517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c929181900390910190a1505b505050565b156103e75761048083610166565b1561048b575061046d565b600160a060020a0384166000908152610102602052604081205492508214156104b4575061046d565b6103ed5b6101045460005b81811015610f0b57610104805461010891600091849081101561000257600080516020610fd88339815191520154825250602091909152604081208054600160a060020a0319168155600181810183905560028281018054858255939493909281161561010002600019011604601f819010610f9057505b5050506001016104bf565b60018054810190819055600160a060020a038316906002906101008110156100025790900160005055600154600160a060020a03831660008181526101026020908152604091829020939093558051918252517f994a936646fe87ffe4f1e469d3d6aa417d6b855598397f323de5b449f765f0c3929181900390910190a15b505b50565b156105c1576105d482610166565b156105df57506105c3565b6105e76104b8565b60015460fa90106105fa576105fa61060f565b60015460fa901061054257506105c3565b6106c75b60015b6001548110156105c3575b6001548110801561063d5750600281610100811015610002570154600014155b15610dc75760010161061d565b1561046d57600160a060020a03831660009081526101026020526040812054925082141561067857506105c1565b600160016000505403600060005054111561069357506105c1565b600060028361010081101561000257508301819055600160a060020a0384168152610102602052604081205561060b6104b8565b60408051600160a060020a038516815290517f58619076adf5bb0943d100ef88d52d7c3fd691b19d3a9071b555b651fbf418da9181900360200190a1505050565b156105c15760015482111561071d57506105c3565b600082905561072a6104b8565b6040805183815290517facbdb084c721332ac59f9b8e392196c9eb0e4932862da8eb9beaf0dad4f550da9181900360200190a15050565b506001820154600282900a9081166000141593505b50505092915050565b156105c1575061010555565b156105c35760006101065550565b156105c15781600160a060020a0316ff5b156109eb576107be846000610ea133610166565b1561087d577f92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd00433858786866040518086600160a060020a0316815260200185815260200184600160a060020a031681526020018060200182810382528484828181526020019250808284378201915050965050505050505060405180910390a184600160a060020a03168484846040518083838082843782019150509250505060006040518083038185876185025a03f150600093506109eb92505050565b6000364360405180848480828437820191505082815260200193505050506040518091039020905080506108b0816101f7565b1580156108d3575060008181526101086020526040812054600160a060020a0316145b156109eb5760008181526101086020908152604082208054600160a060020a0319168817815560018181018890556002918201805481865294849020909491821615610100026000190190911691909104601f9081019290920481019185919087908390106109f35760ff198135168380011785555b506109659291505b80821115610a235760008155600101610951565b50507f1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf328133868887876040518087815260200186600160a060020a0316815260200185815260200184600160a060020a03168152602001806020018281038252848482818152602001925080828437820191505097505050505050505060405180910390a15b949350505050565b82800160010185558215610949579182015b82811115610949578235826000505591602001919060010190610a05565b5090565b15610aaa5760008381526101086020526040812054600160a060020a031614610aaa5760408051600091909120805460018281015460029384018054600160a060020a0394909416959194909391928392859291811615610100026000190116048015610adb5780601f10610ab057610100808354040283529160200191610adb565b50919050565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505091505060006040518083038185876185025a03f1505050600084815261010860209081526040918290208054600180830154855133600160a060020a0381811683529682018c9052968101829052929094166060830181905260a06080840181815260029586018054948516156101000260001901909416959095049084018190527fe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a97508a95949193919060c083019084908015610bdd5780601f10610bb257610100808354040283529160200191610bdd565b820191906000526020600020905b815481529060010190602001808311610bc057829003601f168201915b5050965050505050505060405180910390a16000838152610108602052604081208054600160a060020a0319168155600181810183905560028281018054858255939493909281161561010002600019011604601f819010610c4857505b5050506001915050610182565b601f016020900490600052602060002090810190610c3b9190610951565b60008581526101036020526040812080549093501415610cee576000805483556001838101919091556101048054918201808255828015829011610cbd57818360005260206000209182019101610cbd9190610951565b50505060028301819055610104805487929081101561000257600091909152600080516020610fd883398151915201555b506001810154600283900a90811660001415610dbf5760408051600160a060020a03331681526020810187905281517fe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda929181900390910190a1815460019011610dac576000858152610103602052604090206002015461010480549091908110156100025760406000908120600080516020610fd8833981519152929092018190558082556001828101829055600292909201559450610dbf9050565b8154600019018255600182018054821790555b505050919050565b5b60018054118015610dea57506001546002906101008110156100025701546000145b15610dfe5760018054600019019055610dc8565b60015481108015610e215750600154600290610100811015610002570154600014155b8015610e3b57506002816101008110156100025701546000145b15610e9c57600154600290610100811015610002578101549082610100811015610002579090016000505580610102600060028361010081101561000257810154825260209290925260408120929092556001546101008110156100025701555b610612565b156101825761010754610eb75b62015180420490565b1115610ed057600061010655610ecb610eae565b610107555b6101065480830110801590610eed57506101055461010654830111155b15610f0357506101068054820190556001610182565b506000610182565b6105c16101045460005b81811015610fae5761010480548290811015610002576000918252600080516020610fd8833981519152015414610f8857610104805461010391600091849081101561000257600080516020610fd883398151915201548252506020919091526040812081815560018101829055600201555b600101610f15565b601f0160209004906000526020600020908101906105379190610951565b610104805460008083559190915261046d90600080516020610fd883398151915290810190610951564c0be60200faa20559308cb7b5a1bb3255c16cb1cab91f525b5ae7a03d02fabe", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000105": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000106": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000107": "0x000000000000000000000000000000000000000000000000000000000000423d", + "0xcabd288dcb1ace4f49c34e8ac2d843772952b4226b3c832bdb4ac1ddca0f7c05": "0x0000000000000000000000000000000000000000000000000000000000000002" + } + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "1646452", + "difficulty": "45328493887096", + "timestamp": "1465103894", + "gasLimit": "4712388", + "miner": "0x61c808d82a3ac53231750dadc13c777b59310bd9" + }, + "input": "0xf9018b178504a817c80083030d4094cf1476387d780169410d4e936d75a206fda2a68c80b90124b61d27f6000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c189413000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000088613930353963626230303030303030303030303030303030303030303030303039306433633138313264653236363962663830376264373735386365623165333439376163376534303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030316336626635323633343030300000000000000000000000000000000000000000000000001ca0f1ae5ea07b1d00eb5e06fc854124ee0234ec61c8b393147f9d030804a75c98daa01d045d7633012cca74e30e975c3d00d11b4243dd8648f2e78d652f3a8aaafceb", + "tracerConfig": { + "withLog": true + }, + "result": { + "from": "0x01115b41bd2731353dd3e6abf44818fdc035aaf1", + "gas": "0x28e28", + "gasUsed": "0x288c9", + "to": "0xcf1476387d780169410d4e936d75a206fda2a68c", + "input": "0xb61d27f6000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c18941300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008861393035396362623030303030303030303030303030303030303030303030303930643363313831326465323636396266383037626437373538636562316533343937616337653430303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303031633662663532363334303030000000000000000000000000000000000000000000000000", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000", + "calls": [ + { + "from": "0xcf1476387d780169410d4e936d75a206fda2a68c", + "gas": "0x1e30b", + "gasUsed": "0x1e30b", + "to": "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", + "input": "0x61393035396362623030303030303030303030303030303030303030303030303930643363313831326465323636396266383037626437373538636562316533343937616337653430303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303031633662663532363334303030", + "error": "invalid jump destination", + "value": "0x0", + "type": "CALL" + } + ], + "logs": [ + { + "address": "0xcf1476387d780169410d4e936d75a206fda2a68c", + "topics": [ + "0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004" + ], + "data": "0x00000000000000000000000001115b41bd2731353dd3e6abf44818fdc035aaf10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c1894130000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008861393035396362623030303030303030303030303030303030303030303030303930643363313831326465323636396266383037626437373538636562316533343937616337653430303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303031633662663532363334303030" + } + ], + "value": "0x0", + "type": "CALL" + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json new file mode 100644 index 000000000000..c805296adb02 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json @@ -0,0 +1,89 @@ +{ + "genesis": { + "difficulty": "11934798510088", + "extraData": "0xd983010302844765746887676f312e342e328777696e646f7773", + "gasLimit": "3141592", + "hash": "0xfc543a4a551afbd4a6c5d6d49041371e6bb58b1108c12aaec7f487ce656bb97f", + "miner": "0xf8b483dba2c3b7176a3da549ad41a48bb3121069", + "mixHash": "0xa6a1e67fc68da76b8d9cc3ce1c45d5e1f4bbd96b5dcfddbe0017d7fa99903ead", + "nonce": "0x5f00c600268b4659", + "number": "995200", + "stateRoot": "0x3579328470dd2aef5b9da69f5480cbe0d375e653b530ab3c1aee0da5e1ff4c94", + "timestamp": "1455322761", + "totalDifficulty": "7077231809278509672", + "alloc": { + "0x200edd17f30485a8735878661960cd7a9a95733f": { + "balance": "0x0", + "code": "0x3660008037602060003660003473273930d21e01ee25e4c219b63259d214872220a261235a5a03f21560015760206000f3", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000000000000000000000000000104": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x4c0be60200faa20559308cb7b5a1bb3255c16cb1cab91f525b5ae7a03d02fabe": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8ba1097eb3abe3dc1b51faa48445d593bf968f722e20b67bb62a87495836bf04": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8ba1097eb3abe3dc1b51faa48445d593bf968f722e20b67bb62a87495836bf05": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x8ba1097eb3abe3dc1b51faa48445d593bf968f722e20b67bb62a87495836bf06": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xa611e7c895a426c0477bc9e280db9c3b1e456dc6310ffcf23926ef5186c1facc": "0x0000000000000000000000000000000000000000000000000000000000000002", + "0xac682d343707aadf06c2c4c3692831d9e7ba711099ef36f9efb8bb29be8c410e": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xac682d343707aadf06c2c4c3692831d9e7ba711099ef36f9efb8bb29be8c410f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xac682d343707aadf06c2c4c3692831d9e7ba711099ef36f9efb8bb29be8c4110": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x273930d21e01ee25e4c219b63259d214872220a2": { + "balance": "0x0", + "code": "0x606060405236156100da5760e060020a6000350463173825d9811461012c5780632f54bf6e146101875780634123cb6b146101af57806352375093146101b857806354fd4d50146101c25780635c52c2f5146101cc578063659010e7146101fd5780637065cb4814610207578063746c91711461023b578063797af62714610244578063b20d30a914610257578063b61d27f61461028b578063b75c7dc6146102ac578063ba51a6df146102db578063c2cf73261461030f578063cbf0b0c01461034d578063f00d4b5d14610381578063f1736d86146103ba575b6103c4600034111561012a5760408051600160a060020a033216815234602082015281517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c929181900390910190a15b565b6103c46004356000600036436040518084848082843750505090910190815260405190819003602001902090506106c9815b600160a060020a03321660009081526101026020526040812054818082811415610c3f57610d97565b6103c66004355b600160a060020a03811660009081526101026020526040812054115b919050565b6103c660015481565b6103c66101075481565b6103c66101085481565b6103c46000364360405180848480828437505050909101908152604051908190036020019020905061081a8161015e565b6103c66101065481565b6103c4600435600036436040518084848082843750505090910190815260405190819003602001902090506106418161015e565b6103c660005481565b6103c66004355b600081610a7d8161015e565b6103c46004356000364360405180848480828437505050909101908152604051908190036020019020905061080e8161015e565b6103c66004803590602480359160443591820191013560006108393261018e565b6103c4600435600160a060020a033216600090815261010260205260408120549080828114156103d857610457565b6103c4600435600036436040518084848082843750505090910190815260405190819003602001902090506107888161015e565b6103c6600435602435600082815261010360209081526040808320600160a060020a038516845261010290925282205482818114156107e157610805565b6103c4600435600036436040518084848082843750505090910190815260405190819003602001902090506108288161015e565b6103c46004356024356000600036436040518084848082843750505090910190815260405190819003602001902090506104e28161015e565b6103c66101055481565b005b60408051918252519081900360200190f35b50506000828152610103602052604081206001810154600284900a9290831611156104575780546001828101805492909101835590839003905560408051600160a060020a03321681526020810186905281517fc7fb647e59b18047309aa15aad418e5d7ca96d173ad704f1031a2c3d7591734b929181900390910190a15b50505050565b600160a060020a03831660028361010081101561000257508301819055600160a060020a03851660008181526101026020908152604080832083905584835291829020869055815192835282019290925281517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c929181900390910190a1505b505050565b15610457576104f08361018e565b156104fb57506104dd565b600160a060020a03841660009081526101026020526040812054925082141561052457506104dd565b61045d5b6101045460005b81811015610ee457610104805461010991600091849081101561000257600080516020610f9f83398151915201548252506020918252604081208054600160a060020a0319168155600181018290556002810180548382559083528383209193610f6992601f9290920104810190610a65565b60018054810190819055600160a060020a038316906002906101008110156100025790900160005081905550600160005054610102600050600084600160a060020a03168152602001908152602001600020600050819055507f994a936646fe87ffe4f1e469d3d6aa417d6b855598397f323de5b449f765f0c3826040518082600160a060020a0316815260200191505060405180910390a15b505b50565b1561063c5761064f8261018e565b1561065a575061063e565b610662610528565b60015460fa90106106775761067561068c565b505b60015460fa90106105a2575061063e565b6107465b600060015b600154811015610a79575b600154811080156106bc5750600281610100811015610002570154600014155b15610d9f5760010161069c565b156104dd57600160a060020a0383166000908152610102602052604081205492508214156106f7575061063c565b6001600160005054036000600050541115610712575061063c565b600060028361010081101561000257508301819055600160a060020a03841681526101026020526040812055610688610528565b5060408051600160a060020a038516815290517f58619076adf5bb0943d100ef88d52d7c3fd691b19d3a9071b555b651fbf418da9181900360200190a1505050565b1561063c5760015482111561079d575061063e565b60008290556107aa610528565b6040805183815290517facbdb084c721332ac59f9b8e392196c9eb0e4932862da8eb9beaf0dad4f550da9181900360200190a15050565b506001820154600282900a908116600014156108005760009350610805565b600193505b50505092915050565b1561063c575061010555565b1561063e5760006101065550565b1561063c5781600160a060020a0316ff5b15610a555761084d846000610e793261018e565b15610909577f92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd00432858786866040518086600160a060020a0316815260200185815260200184600160a060020a031681526020018060200182810382528484828181526020019250808284378201915050965050505050505060405180910390a184600160a060020a03168484846040518083838082843750505090810191506000908083038185876185025a03f15060009350610a5592505050565b6000364360405180848480828437505050909101908152604051908190036020019020915061093990508161024b565b15801561095c575060008181526101096020526040812054600160a060020a0316145b15610a555760008181526101096020908152604082208054600160a060020a03191688178155600181018790556002018054858255818452928290209092601f01919091048101908490868215610a5d579182015b82811115610a5d5782358260005055916020019190600101906109b1565b50507f1733cbb53659d713b79580f79f3f9ff215f78a7c7aa45890f3b89fc5cddfbf328132868887876040518087815260200186600160a060020a0316815260200185815260200184600160a060020a03168152602001806020018281038252848482818152602001925080828437820191505097505050505050505060405180910390a15b949350505050565b506109cf9291505b80821115610a795760008155600101610a65565b5090565b15610c2c5760008381526101096020526040812054600160a060020a031614610c2c5760408051600091909120805460018201546002929092018054600160a060020a0392909216939091819083908015610afd57820191906000526020600020905b815481529060010190602001808311610ae057829003601f168201915b505091505060006040518083038185876185025a03f150505060008481526101096020908152604080519281902080546001820154600160a060020a033281811688529587018b905293860181905292166060850181905260a06080860181815260029390930180549187018290527fe7c957c06e9a662c1a6c77366179f5b702b97651dc28eee7d5bf1dff6e40bb4a975094958a959293909160c083019084908015610bcf57820191906000526020600020905b815481529060010190602001808311610bb257829003601f168201915b5050965050505050505060405180910390a160008381526101096020908152604082208054600160a060020a031916815560018101839055600281018054848255908452828420919392610c3292601f9290920104810190610a65565b50919050565b50505060019150506101aa565b60008581526101036020526040812080549093501415610cc7576000805483556001838101919091556101048054918201808255828015829011610c9657818360005260206000209182019101610c969190610a65565b50505060028301819055610104805487929081101561000257600091909152600080516020610f9f83398151915201555b506001810154600283900a90811660001415610d975760408051600160a060020a03321681526020810187905281517fe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda929181900390910190a1815460019011610d84576000858152610103602052604090206002015461010480549091908110156100025760406000908120600080516020610f9f8339815191529290920181905580825560018083018290556002909201559450610d979050565b8154600019018255600182018054821790555b505050919050565b5b60018054118015610dc257506001546002906101008110156100025701546000145b15610dd65760018054600019019055610da0565b60015481108015610df95750600154600290610100811015610002570154600014155b8015610e1357506002816101008110156100025701546000145b15610e7457600154600290610100811015610002578101549082610100811015610002578101919091558190610102906000908361010081101561000257810154825260209290925260408120929092556001546101008110156100025701555b610691565b156101aa5761010754610e8f5b62015180420490565b1115610ea857600061010655610ea3610e86565b610107555b6101065480830110801590610ec65750610106546101055490830111155b15610edc575061010680548201905560016101aa565b5060006101aa565b61063c6101045460005b81811015610f745761010480548290811015610002576000918252600080516020610f9f833981519152015414610f6157610104805461010391600091849081101561000257600080516020610f9f83398151915201548252506020919091526040812081815560018101829055600201555b600101610eee565b50505060010161052f565b61010480546000808355919091526104dd90600080516020610f9f83398151915290810190610a6556004c0be60200faa20559308cb7b5a1bb3255c16cb1cab91f525b5ae7a03d02fabe" + }, + "0x4f5777744b500616697cb655dcb02ee6cd51deb5": { + "balance": "0xb0983f1b83eec290", + "nonce": "2" + }, + "0xf8b483dba2c3b7176a3da549ad41a48bb3121069": { + "balance": "0x16969a0ba2c2d384d07", + "nonce": "67521" + } + }, + "config": { + "chainId": 1, + "homesteadBlock": 1150000, + "daoForkBlock": 1920000, + "daoForkSupport": true, + "eip150Block": 2463000, + "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0", + "eip155Block": 2675000, + "eip158Block": 2675000, + "byzantiumBlock": 4370000, + "constantinopleBlock": 7280000, + "petersburgBlock": 7280000, + "istanbulBlock": 9069000, + "muirGlacierBlock": 9200000, + "berlinBlock": 12244000, + "londonBlock": 12965000, + "arrowGlacierBlock": 13773000, + "grayGlacierBlock": 15050000, + "terminalTotalDifficultyPassed": true, + "ethash": {} + } + }, + "context": { + "number": "995201", + "difficulty": "11940626048551", + "timestamp": "1455322773", + "gasLimit": "3141592", + "miner": "0xf8b483dba2c3b7176a3da549ad41a48bb3121069" + }, + "input": "0xf89102850a954d522e8303308594200edd17f30485a8735878661960cd7a9a95733f888ac7230489e80000a4ba51a6df00000000000000000000000000000000000000000000000000000000000000001ca04f2cc45b96f965296382b2e9b657e90808301d5179035a5d91a2de7b912def20a056e19271ea4e19e4e034f38e925e312beed4d300c267160eeb2f565c42deb578", + "tracerConfig": { + "withLog": true, + "onlyTopCall": true + }, + "result": { + "from": "0x4f5777744b500616697cb655dcb02ee6cd51deb5", + "gas": "0x2dced", + "gasUsed": "0x1a9e5", + "to": "0x200edd17f30485a8735878661960cd7a9a95733f", + "input": "0xba51a6df0000000000000000000000000000000000000000000000000000000000000000", + "output": "0xba51a6df00000000000000000000000000000000000000000000000000000000", + "value": "0x8ac7230489e80000", + "type": "CALL" + } +} diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 68fe3bac3407..34f88126bad4 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -36,6 +36,12 @@ func init() { register("callTracer", newCallTracer) } +type callLog struct { + Address common.Address `json:"address"` + Topics []common.Hash `json:"topics"` + Data hexutil.Bytes `json:"data"` +} + type callFrame struct { Type vm.OpCode `json:"-"` From common.Address `json:"from"` @@ -47,6 +53,7 @@ type callFrame struct { Error string `json:"error,omitempty" rlp:"optional"` Revertal string `json:"revertReason,omitempty"` Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Logs []callLog `json:"logs,omitempty" rlp:"optional"` // Placed at end on purpose. The RLP will be decoded to 0 instead of // nil if there are non-empty elements after in the struct. Value *big.Int `json:"value,omitempty" rlp:"optional"` @@ -56,6 +63,10 @@ func (f callFrame) TypeString() string { return f.Type.String() } +func (f callFrame) failed() bool { + return len(f.Error) > 0 +} + func (f *callFrame) capture(output []byte, err error) { output = common.CopyBytes(output) if err == nil { @@ -98,6 +109,7 @@ type callTracer struct { type callTracerConfig struct { OnlyTopCall bool `json:"onlyTopCall"` // If true, call tracer won't collect any subcalls + WithLog bool `json:"withLog"` // If true, call tracer will collect event logs } // newCallTracer returns a native go tracer which tracks @@ -137,10 +149,38 @@ func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, // CaptureState implements the EVMLogger interface to trace a single step of VM execution. func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + // Only logs need to be captured via opcode processing + if !t.config.WithLog { + return + } + // Avoid processing nested calls when only caring about top call + if t.config.OnlyTopCall && depth > 0 { + return + } + switch op { + case vm.LOG0, vm.LOG1, vm.LOG2, vm.LOG3, vm.LOG4: + size := int(op - vm.LOG0) + + stack := scope.Stack + stackData := stack.Data() + + // Don't modify the stack + mStart := stackData[len(stackData)-1] + mSize := stackData[len(stackData)-2] + topics := make([]common.Hash, size) + for i := 0; i < size; i++ { + topic := stackData[len(stackData)-2-(i+1)] + topics[i] = common.Hash(topic.Bytes32()) + } + + data := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64())) + log := callLog{Address: scope.Contract.Address(), Topics: topics, Data: hexutil.Bytes(data)} + t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, log) + } } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *callTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { +func (t *callTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). @@ -191,6 +231,10 @@ func (t *callTracer) CaptureTxStart(gasLimit uint64) { func (t *callTracer) CaptureTxEnd(restGas uint64) { t.callstack[0].GasUsed = t.gasLimit - restGas + if t.config.WithLog { + // Logs are not emitted when the call fails + clearFailedLogs(&t.callstack[0], false) + } } // GetResult returns the json-encoded nested list of call traces, and any @@ -211,3 +255,16 @@ func (t *callTracer) Stop(err error) { t.reason = err atomic.StoreUint32(&t.interrupt, 1) } + +// clearFailedLogs clears the logs of a callframe and all its children +// in case of execution failure. +func clearFailedLogs(cf *callFrame, parentFailed bool) { + failed := cf.failed() || parentFailed + // Clear own logs + if failed { + cf.Logs = nil + } + for i := range cf.Calls { + clearFailedLogs(&cf.Calls[i], failed) + } +} diff --git a/eth/tracers/native/gen_callframe_json.go b/eth/tracers/native/gen_callframe_json.go index bb7658a76ad3..f6b48366fe80 100644 --- a/eth/tracers/native/gen_callframe_json.go +++ b/eth/tracers/native/gen_callframe_json.go @@ -26,6 +26,7 @@ func (c callFrame) MarshalJSON() ([]byte, error) { Error string `json:"error,omitempty" rlp:"optional"` Revertal string `json:"revertReason,omitempty"` Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Logs []callLog `json:"logs,omitempty" rlp:"optional"` Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` TypeString string `json:"type"` } @@ -40,6 +41,7 @@ func (c callFrame) MarshalJSON() ([]byte, error) { enc.Error = c.Error enc.Revertal = c.Revertal enc.Calls = c.Calls + enc.Logs = c.Logs enc.Value = (*hexutil.Big)(c.Value) enc.TypeString = c.TypeString() return json.Marshal(&enc) @@ -58,6 +60,7 @@ func (c *callFrame) UnmarshalJSON(input []byte) error { Error *string `json:"error,omitempty" rlp:"optional"` Revertal *string `json:"revertReason,omitempty"` Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Logs []callLog `json:"logs,omitempty" rlp:"optional"` Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` } var dec callFrame0 @@ -94,6 +97,9 @@ func (c *callFrame) UnmarshalJSON(input []byte) error { if dec.Calls != nil { c.Calls = dec.Calls } + if dec.Logs != nil { + c.Logs = dec.Logs + } if dec.Value != nil { c.Value = (*big.Int)(dec.Value) } From 0c40df5f28b70b4aafee526bed7575520f3b827b Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 1 Nov 2022 16:55:44 +0330 Subject: [PATCH 335/715] eth/tracers: prestateTracer - exclude unchanged storage slots in diffMode (#25944) Fixes #25943 --- .../inner_create.json | 68 +------------------ .../simple.json | 3 - eth/tracers/native/prestate.go | 11 +-- 3 files changed, 9 insertions(+), 73 deletions(-) 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 5bcf5121f12e..9c0030a0a8d1 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 @@ -214,90 +214,28 @@ "nonce": 237, "code": "0x6060604052361561027c5760e060020a600035046301991313811461027e57806303d22885146102ca5780630450991814610323578063049ae734146103705780630ce46c43146103c35780630e85023914610602578063112e39a8146106755780631b4fa6ab146106c25780631e74a2d3146106d057806326a7985a146106fd5780633017fe2414610753578063346cabbc1461075c578063373a1bc3146107d55780633a9e74331461081e5780633c2c21a01461086e5780633d9ce89b146108ba578063480b70bd1461092f578063481078431461097e57806348f0518714610a0e5780634c471cde14610a865780634db3da8314610b09578063523ccfa814610b4f578063586a69fa14610be05780635a9f2def14610c3657806364ee49fe14610caf57806367beaccb14610d055780636840246014610d74578063795b9a6f14610dca5780637b55c8b514610e415780637c73f84614610ee15780638c0e156d14610f145780638c1d01c814610f605780638e46afa914610f69578063938c430714610fc0578063971c803f146111555780639772c982146111ac57806398c9cdf41461122857806398e00e541461127f5780639f927be7146112d5578063a00aede914611383578063a1c0539d146113d3578063aff21c6514611449578063b152f19e14611474578063b549793d146114cb578063b5b33eda1461154b578063bbc6eb1f1461159b578063c0f68859146115ab578063c3a2c0c314611601578063c43d05751461164b578063d8e5c04814611694578063dbfef71014611228578063e29fb547146116e7578063e6470fbe1461173a578063ea27a8811461174c578063ee77fe86146117d1578063f158458c14611851575b005b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387876020604051908101604052806000815260200150612225610f6d565b61188260043560243560443560643560843560a43560c435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338b8a6020604051908101604052806000815260200150896125196106c6565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503385600060e060020a026020604051908101604052806000815260200150611e4a610f6d565b611882600435602435604435606435608435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503389896020604051908101604052806000815260200150886124e86106c6565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750506040805160a08082019092529597963596608435969095506101449450925060a491506005908390839080828437509095505050505050604080518082018252600160a060020a03338116825288166020820152815160c0810190925260009173e54d323f9ef17c1f0dede47ecc86a9718fe5ea349163e3042c0f91600191908a908a9089908b90808b8b9090602002015181526020018b60016005811015610002579090602002015181526020018b60026005811015610002579090602002015181526020018b60036005811015610002579090602002015181526020018b6004600581101561000257909060200201518152602001348152602001506040518860e060020a02815260040180888152602001876002602002808383829060006004602084601f0104600f02600301f150905001868152602001806020018560ff1681526020018461ffff168152602001836006602002808383829060006004602084601f0104600f02600301f1509050018281038252868181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156105d25780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038160008760325a03f2156100025750506040515191506124cd9050565b60408051602060248035600481810135601f81018590048502860185019096528585526118829581359591946044949293909201918190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808787611e64610f6d565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611d28610f6d565b61189f5b6000611bf8611159565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881600060005054611a9561159f565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346326a7985a6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b6118b760075b90565b604080516020606435600481810135601f8101849004840285018401909552848452611882948135946024803595604435956084949201919081908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160013389898861224b610f6d565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503386866020604051908101604052806000815260200150611e64610f6d565b611882600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333896020604051908101604052806000815260200150886123bc6106c6565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387866020604051908101604052806000815260200150611f8d610f6d565b60408051602060248035600481810135601f810185900485028601850190965285855261188295813595919460449492939092019181908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808888612225610f6d565b611882600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503388886020604051908101604052806000815260200150612388610f6d565b611882600435604080517fc4144b2600000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a03831660248201529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163c4144b26916044818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b604080516020604435600481810135601f81018490048402850184019095528484526118829481359460248035959394606494929391019181908401838280828437509496505093359350505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133888888612238610f6d565b604080516020604435600481810135601f810184900484028501840190955284845261188294813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a43560c435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338b8b8b896126536106c6565b611882600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333866020604051908101604052806000815260200150611e4a610f6d565b6118b76004355b604080517fed5bd7ea00000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a03831660248201529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163ed5bd7ea916044818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b61189f600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463586a69fa6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f81018590048502860185019096528585526118829581359591946044949293909201918190840183828082843750949650509335935050606435915050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808989612388610f6d565b61188260043560243560443560643560843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338a896020604051908101604052806000815260200150886124d76106c6565b6040805160206004803580820135601f8101849004840285018401909552848452611882949193602493909291840191908190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808587611e4a610f6d565b61188260043560243560443560643560843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050338a8a60206040519081016040528060008152602001508961262d6106c6565b604080516020606435600481810135601f810184900484028501840190955284845261188294813594602480359560443595608494920191908190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338888876120c7610f6d565b604080516020604435600481810135601f81018490048402850184019095528484526118829481359460248035959394606494929391019181908401838280828437505060408051608080820190925295979635969561010495509350608492508591508390839080828437509095505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338989898961263a6106c6565b6118b7600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881858585611ba361122c565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001600050333388602060405190810160405280600081526020015061236e610f6d565b6118b760005481565b6118c95b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea34638e46afa96040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f8101859004850286018501909652858552611882958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a43560c43560e43561010435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600160005033338e8e8d8f8e8e8e8e8e346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156111195780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519b9a5050505050505050505050565b61189f5b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463971c803f6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750949650509335935050608435915050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338989896123a2610f6d565b6118b75b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346398c9cdf46040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346398e00e546040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b611882600435604080517fe6ce3a6a000000000000000000000000000000000000000000000000000000008152600160048201527f3e3d0000000000000000000000000000000000000000000000000000000000006024820152604481018390529051600091737c1eb207c07e7ab13cf245585bd03d0fa478d0349163e6ce3a6a916064818101926020929091908290030181878760325a03f215610002575050604051519150611b409050565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503385600060e060020a0260206040519081016040528060008152602001506121ef610f6d565b604080516020604435600481810135601f8101849004840285018401909552848452611882948135946024803595939460649492939101918190840183828082843750949650505050505050600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338787876120b5610f6d565b6118b7600435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a88183611b4561159f565b6118b75b600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463b152f19e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b60408051602060248035600481810135601f8101859004850286018501909652858552611882958135959194604494929390920191819084018382808284375094965050933593505060643591505060843560a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600133808b8b8961262d6106c6565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503386600060e060020a026020604051908101604052806000815260200150612200610f6d565b6118b75b60005460649004610759565b6118b7600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463c0f688596040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506107599050565b611882600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333600060e060020a026020604051908101604052806000815260200150611bff610f6d565b611882600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503333876020604051908101604052806000815260200150612200610f6d565b611882600435602435604435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e41160016000503387600060e060020a026020604051908101604052806000815260200150612213610f6d565b611882600435602435604435606435608435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e411600160005033338a60206040519081016040528060008152602001508961250c6106c6565b61027c6000600060006118e033610b56565b6118b7600435602435604435606435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a881868686866040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b949350505050565b604080516020604435600481810135601f810184900484028501840190955284845261188294813594602480359593946064949293910191819084018382808284375094965050933593505060843591505060a435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea346350d4e4116001338a8a8a886124fa6106c6565b6118b7600435602435600073e54d323f9ef17c1f0dede47ecc86a9718fe5ea3463ea27a88184846000611b4f61122c565b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b60408051918252519081900360200190f35b6040805160ff929092168252519081900360200190f35b15611a905733925082600160a060020a031663c6502da86040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fc6803622000000000000000000000000000000000000000000000000000000008252915191945063c680362291600482810192602092919082900301816000876161da5a03f11561000257505060405151905080156119d1575082600160a060020a031663d379be236040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151600160a060020a03166000141590505b80156119dd5750600082115b80156119ec5750600054600190115b15611a90578183600160a060020a031663830953ab6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040515160640291909104915050604281118015611a4d5750600054829011155b15611a675760008054612710612711909102049055611a90565b602181108015611a7a5750600054829010155b15611a90576000805461271061270f9091020490555b505050565b6000611a9f61122c565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f2156100025750506040515191506107599050565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b919050565b6000611af261122c565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b6040518560e060020a0281526004018085815260200184815260200183815260200182815260200194505050505060206040518083038160008760325a03f215610002575050604051519150505b9392505050565b9050610759565b611c076106c6565b6000611c11611478565b611c1961122c565b600054611c2461159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611cf25780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f2156100025750506040515191506107599050565b611d306106c6565b60008b611d3b61122c565b600054611d4661159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611e145780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611b409050565b611e526106c6565b6000611e5c611478565b611d3b61122c565b611e6c6106c6565b6000611e76611478565b611e7e61122c565b600054611e8961159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611f575780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611b9d9050565b611f956106c6565b8b611f9e611478565b611fa661122c565b600054611fb161159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561207f5780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150611bf19050565b6120bd6106c6565b6000611f9e611478565b6120cf6106c6565b8b6120d8611478565b6120e061122c565b6000546120eb61159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156121b95780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f2156100025750506040515191506117c99050565b6121f76106c6565b8b611e76611478565b6122086106c6565b60008b611e7e61122c565b61221b6106c6565b8a8c611fa661122c565b61222d6106c6565b60008b611fa661122c565b6122406106c6565b60008b6120e061122c565b6122536106c6565b8c8b61225d61122c565b60005461226861159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156123365780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f21561000257505060405151979650505050505050565b6123766106c6565b60008c8c600060005054611fb161159f565b6123906106c6565b60008c8c6000600050546120eb61159f565b6123aa6106c6565b60008c8c60006000505461226861159f565b60008d8d6000600050546120eb61159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561249c5780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519150505b9695505050505050565b8e8d8d6000600050546123ce61159f565b60008d8d60006000505461226861159f565b60008d8d6000600050546123ce61159f565b60008e8e8d61226861159f565b8f8e8e8d61252561159f565b346040518e60e060020a028152600401808e81526020018d600160a060020a031681526020018c600160a060020a031681526020018b8152602001806020018a60ff1681526020018961ffff16815260200188815260200187815260200186815260200185815260200184815260200183815260200182810382528b8181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156125f35780820380516001836020036101000a031916815260200191505b509e50505050505050505050505050505060206040518083038160008760325a03f215610002575050604051519998505050505050505050565b60008e8e8d6123ce61159f565b8a5160208c015160408d015160608e015161226861159f565b60008e8e8d61252561159f56", "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000011f8119429ed3a", - "0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000f5d861791e76fa01433e0d7421aee565290e4afe", - "0x031b9ec274101cc3ccff4d6d98ef4513742dadbaadba538bff48b88403253234": "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x20ef51bb8ea9e8e8d5e2c17d28e47285698893c1017db4b4e40b792358a3dbc7": "0x0000000000000000000000000000000000000000000000000000000000000004", - "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8abd": "0x000000000000000000000000c9a2bfd279fe57e7651e5d9f29bb1793c9a1cf01", "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8abf": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", - "0x26cba0705aade77fa0f9275b68d01fb71206a44abd3a4f5a838f7241efbc8ac2": "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dfb": "0x000000000000000000000000f5d861791e76fa01433e0d7421aee565290e4afe", - "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dfc": "0x00000000000000000000000000000000000000000000000000000000000f6897", - "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dfe": "0x0000000000000000000000002859ddf2877c46d54e67b6becdb1cafb8ef4a458", - "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794dff": "0x000000000000000000000000b7df3c43a8b13ecf45777c267404e15c7cdb04c9", - "0x37a551428681c06e6f97b79bb6c8c325935dc1a51b31a982594f40f2dd794e00": "0x0000000000000000000000000000000000000000000000000000000000000008", - "0x3b20a4b931bc4ae9450774ee52b8f5da1b248d23e61cd20c09b25662f73894fd": "0x0000000000000000000000000000000000000000000000000000000000000006", - "0x3b99aee1e3090227401ac2055c861246ca6ec62f426b4b4d74df88510f841b89": "0x0000000000000000000000000000000000000000000000000000000000000007", - "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef711": "0x000000000000000000000000a4d91b341f0e9a7000be916a668408b463f4c38c", - "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef712": "0x0000000000000000000000000000000000000000000000000000000000102ce9", - "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef713": "0x000000000000000000000000fd97a0d81cc92eecd52452831930b27889925ef0", - "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef714": "0x00000000000000000000000016917c151bb1399852a0741eb7b317b443e2cfa3", "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef715": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", - "0x49f03a2c2f4fd666a32141fb324283b6f84a1d07b5fa435669fdb55766aef716": "0x0000000000000000000000000000000000000000000000000000000000000004", - "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a3fe": "0x000000000000000000000000c5ef24ec3bf0e3522cfc8e53f3e076b043547ce1", - "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a3ff": "0x00000000000000000000000000000000000000000000000000000000000fff67", - "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a400": "0x000000000000000000000000b7df3c43a8b13ecf45777c267404e15c7cdb04c9", - "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a401": "0x00000000000000000000000010fc2e8ba5f40336c3576ffaa25177f1cdedf836", - "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a402": "0x000000000000000000000000fd97a0d81cc92eecd52452831930b27889925ef0", - "0x5d866e5ddc53cb4c50f232302c51f03204d70c867baf663c9211cc229676a403": "0x0000000000000000000000000000000000000000000000000000000000000006", - "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5ba": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", - "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bb": "0x000000000000000000000000000000000000000000000000000000000010347b", "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bc": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bd": "0x000000000000000000000000c9a2bfd279fe57e7651e5d9f29bb1793c9a1cf01", - "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5be": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b", "0x95e05d02b91af970cb4998107e8613455258880676e00b819c12d675e60de5bf": "0x0000000000000000000000000000000000000000000000000000000000000002", - "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826a7": "0x000000000000000000000000b7df3c43a8b13ecf45777c267404e15c7cdb04c9", - "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826a8": "0x00000000000000000000000000000000000000000000000000000000000fe13d", - "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826a9": "0x000000000000000000000000f5d861791e76fa01433e0d7421aee565290e4afe", - "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826aa": "0x00000000000000000000000063110531142fb314118164ff579ba52746504408", - "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826ab": "0x000000000000000000000000c5ef24ec3bf0e3522cfc8e53f3e076b043547ce1", - "0xa9e249fecbfa0518be95c32972ad551c71206081844335006bb2a349490826ac": "0x0000000000000000000000000000000000000000000000000000000000000007", - "0xccd2cbc946692be8ade97db99353304e3af0fa6202f93649d4e185ad8b1f385c": "0x0000000000000000000000000000000000000000000000000000000000000004", - "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4ef": "0x000000000000000000000000d7b0e93fa8386b17fb5d1cf934076203dcc122f3", - "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f0": "0x00000000000000000000000000000000000000000000000000000000001030b3", "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f1": "0x000000000000000000000000a4d91b341f0e9a7000be916a668408b463f4c38c", - "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f2": "0x000000000000000000000000dd87a67740c2acf48a31829783a095a81c3628d9", "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f3": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", "0xd3a5582b3eff6ef8ee90f3962e9d598a3f4b7d07840356c9b8fd7b494879b4f4": "0x0000000000000000000000000000000000000000000000000000000000000003", - "0xdabde47554d6a6cfcff3c968abb145f298585fafa9e24c10fc526269794bd626": "0x0000000000000000000000000000000000000000000000000000000000000003", - "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64db7": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b", - "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64db8": "0x000000000000000000000000000000000000000000000000000000000010365c", - "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64db9": "0x00000000000000000000000042e69cd0a17ae9992f9ad93d136c4bb0d95e3230", - "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64dbc": "0x0000000000000000000000000000000000000000000000000000000000000001", - "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdec": "0x000000000000000000000000fd97a0d81cc92eecd52452831930b27889925ef0", - "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bded": "0x0000000000000000000000000000000000000000000000000000000000101dc2", - "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdee": "0x000000000000000000000000c5ef24ec3bf0e3522cfc8e53f3e076b043547ce1", - "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdef": "0x000000000000000000000000173243e117a6382211b1ac91eeb262f4a7021c16", - "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdf0": "0x000000000000000000000000a4d91b341f0e9a7000be916a668408b463f4c38c", - "0xfbba286dd5525a6ed3322411df4f261c98e43b123fef71777adc2b44d705bdf1": "0x0000000000000000000000000000000000000000000000000000000000000005" + "0xf7518490c515b9fc8e7fe713b647fe88eacefc92d616fa9454e61fe9aab64dbc": "0x0000000000000000000000000000000000000000000000000000000000000001" } }, "0x741467b251fca923d6229c4b439078b55dca233b": { "balance": "0x29c613529e8218f8", - "code": "0x606060405236156101a05760e060020a60003504630924120081146101c25780630a16697a146101cf5780630fd1f94e146101d8578063137c638b1461022e57806321835af61461023b57806324032866146102545780632f95b833146102d65780633017fe24146102e55780633233c686146102ef57806337f4c00e146102fa5780634500054f146103055780634e417a98146103785780634e71d92d146103e15780634f059a43146103f35780636146195414610451578063625cc4651461046157806367ce940d1461046a5780637d298ee314610477578063830953ab146104f9578063938b5f321461050457806395ee122114610516578063974654f41461052a578063a06db7dc14610535578063a9d2293d14610541578063ae45850b14610597578063b0f07e44146105a9578063c19d93fb146105cb578063c6502da81461062e578063c680362214610637578063ca94692d1461064a578063cc3471af14610673578063d379be23146106c9578063d62457f6146106e3578063ea8a1af0146106ee578063f5562753146107f3578063f6b4dfb414610854575b610868600080548190600160a060020a03908116339091161461087a57610994565b610868600b5460ff165b90565b610868600d5481565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630fd1f94e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6108685b62012cc86101cc565b61086860043560008160001415610dc65750600161084f565b6108686004356024356000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b61099860085461ffff166101cc565b61086860026101cc565b610868600a546101cc565b6108686006546101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6109af60408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610a7d5780601f10610a5257610100808354040283529160200191610a7d565b61086860006000600180610b7b6105cf565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753436040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1d6000600480610c986105cf565b61086860025481565b6108685b620186a06101cc565b6108686004356024355b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506102d09050565b6108686009546101cc565b610a1f600c54600160a060020a031681565b610868600b5462010000900460ff166101cc565b6108686007546101cc565b610a3c600e5460ff1681565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a9d2293d6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600054600160a060020a031681565b610868600080548190600160a060020a039081163390911614610a8957610994565b6108685b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc80635054d98a60036000506040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b61086860015481565b610868600b54610100900460ff166101cc565b61086860035474010000000000000000000000000000000000000000900460e060020a026101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063cc3471af6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600854620100009004600160a060020a03166101cc565b6108686005546101cc565b610a1d604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc809163a0943154916044808301926020929190829003018160008760325a03f215610002575050604051511590506107f157604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091637e9265629160448083019260009291908290030181838760325a03f215610002575050505b565b6108686004356000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753836040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f215610002575050604051519150505b919050565b610a1f600354600160a060020a03166101cc565b60408051918252519081900360200190f35b60045460006002600183161561010002600019019092169190910411156108a45760009150610994565b6108ac6105cf565b9050600081141580156108c0575060018114155b80156108cd575060028114155b156108db5760009150610994565b600480546000828152602060026001841615610100026000190190931692909204601f908101929092047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9081019236929083901061095d5782800160ff198235161785555b5061098d9291505b808211156109945760008155600101610949565b82800160010185558215610941579182015b8281111561094157823582600050559160200191906001019061096f565b5050600191505b5090565b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610a0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311610a6057829003601f168201915b505050505090506101cc565b6004546000600260018316156101000260001901909216919091041115610ab35760009150610994565b610abb6105cf565b905060008114158015610acf575060018114155b8015610adc575060028114155b15610aea5760009150610994565b604080517f7c0278fc000000000000000000000000000000000000000000000000000000008152600360048201818152602483019384523660448401819052731deeda36e15ec9e80f3d7414d67a4803ae45fc8094637c0278fc946000939190606401848480828437820191505094505050505060006040518083038160008760325a03f215610002575050505090565b1415610c8557604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a0316602483015234604483015260648201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091630fee183d916084828101926020929190829003018160008760325a03f21561000257505060405151925050811515610c8a577389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc33346040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515115159050610c8a57610002565b505090565b81925050610994565b505b50565b1415610c93575a9150610cab3383610481565b1515610cb75750610c95565b731deeda36e15ec9e80f3d7414d67a4803ae45fc8063da46be0a60038433610cdd61046e565b610ce5610232565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a031681526020018381526020018281526020019550505050505060006040518083038160008760325a03f21561000257505050610c933360408051600080547fc17e6817000000000000000000000000000000000000000000000000000000008352600160a060020a03908116600484015230163160248301529151731deeda36e15ec9e80f3d7414d67a4803ae45fc809263c17e68179260448082019360209390928390039091019082908760325a03f2156100025750505050565b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a8091040260e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f292505050151561084f5761000256", - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000007dd677b54fc954824a7bc49bd26cbdfa12c75adf", - "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000011f79bd42b0c7c", - "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000002dfeff8fca5d", - "0x0000000000000000000000000000000000000000000000000000000000000003": "0x00000000000000003defb9627dd677b54fc954824a7bc49bd26cbdfa12c75adf", - "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000000000000000000000000000ba43b7400", - "0x0000000000000000000000000000000000000000000000000000000000000007": "0x00000000000000000000000000000000000000000000000000000000001e8480", - "0x0000000000000000000000000000000000000000000000000000000000000008": "0x000000000000000000000000000000000000000000000000000000000000000a", - "0x000000000000000000000000000000000000000000000000000000000000000c": "0x0000000000000000000000006c8f2a135f6ed072de4503bd7c4999a1a17f824b", - "0x000000000000000000000000000000000000000000000000000000000000000d": "0x000000000000000000000000000000000000000000000000000000000010365c", - "0x000000000000000000000000000000000000000000000000000000000000000e": "0x00000000000000000000000000000000000000000000000000000000000000ff" - } + "code": "0x606060405236156101a05760e060020a60003504630924120081146101c25780630a16697a146101cf5780630fd1f94e146101d8578063137c638b1461022e57806321835af61461023b57806324032866146102545780632f95b833146102d65780633017fe24146102e55780633233c686146102ef57806337f4c00e146102fa5780634500054f146103055780634e417a98146103785780634e71d92d146103e15780634f059a43146103f35780636146195414610451578063625cc4651461046157806367ce940d1461046a5780637d298ee314610477578063830953ab146104f9578063938b5f321461050457806395ee122114610516578063974654f41461052a578063a06db7dc14610535578063a9d2293d14610541578063ae45850b14610597578063b0f07e44146105a9578063c19d93fb146105cb578063c6502da81461062e578063c680362214610637578063ca94692d1461064a578063cc3471af14610673578063d379be23146106c9578063d62457f6146106e3578063ea8a1af0146106ee578063f5562753146107f3578063f6b4dfb414610854575b610868600080548190600160a060020a03908116339091161461087a57610994565b610868600b5460ff165b90565b610868600d5481565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630fd1f94e6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6108685b62012cc86101cc565b61086860043560008160001415610dc65750600161084f565b6108686004356024356000731deeda36e15ec9e80f3d7414d67a4803ae45fc80630bd295e6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f215610002575050604051519150505b92915050565b61099860085461ffff166101cc565b61086860026101cc565b610868600a546101cc565b6108686006546101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a09431546003600050336040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b6109af60408051602081810183526000825282516004805460026001821615610100026000190190911604601f81018490048402830184019095528482529293909291830182828015610a7d5780601f10610a5257610100808354040283529160200191610a7d565b61086860006000600180610b7b6105cf565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753436040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1d6000600480610c986105cf565b61086860025481565b6108685b620186a06101cc565b6108686004356024355b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a1873db6600360005085856040518460e060020a0281526004018084815260200183600160a060020a03168152602001828152602001935050505060206040518083038160008760325a03f2156100025750506040515191506102d09050565b6108686009546101cc565b610a1f600c54600160a060020a031681565b610868600b5462010000900460ff166101cc565b6108686007546101cc565b610a3c600e5460ff1681565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063a9d2293d6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600054600160a060020a031681565b610868600080548190600160a060020a039081163390911614610a8957610994565b6108685b6000731deeda36e15ec9e80f3d7414d67a4803ae45fc80635054d98a60036000506040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b61086860015481565b610868600b54610100900460ff166101cc565b61086860035474010000000000000000000000000000000000000000900460e060020a026101cc565b6108686000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063cc3471af6040518160e060020a02815260040180905060206040518083038160008760325a03f2156100025750506040515191506101cc9050565b610a1f600854620100009004600160a060020a03166101cc565b6108686005546101cc565b610a1d604080517fa09431540000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc809163a0943154916044808301926020929190829003018160008760325a03f215610002575050604051511590506107f157604080517f7e9265620000000000000000000000000000000000000000000000000000000081526003600482015233600160a060020a031660248201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091637e9265629160448083019260009291908290030181838760325a03f215610002575050505b565b6108686004356000731deeda36e15ec9e80f3d7414d67a4803ae45fc8063f5562753836040518260e060020a0281526004018082815260200191505060206040518083038160008760325a03f215610002575050604051519150505b919050565b610a1f600354600160a060020a03166101cc565b60408051918252519081900360200190f35b60045460006002600183161561010002600019019092169190910411156108a45760009150610994565b6108ac6105cf565b9050600081141580156108c0575060018114155b80156108cd575060028114155b156108db5760009150610994565b600480546000828152602060026001841615610100026000190190931692909204601f908101929092047f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9081019236929083901061095d5782800160ff198235161785555b5061098d9291505b808211156109945760008155600101610949565b82800160010185558215610941579182015b8281111561094157823582600050559160200191906001019061096f565b5050600191505b5090565b6040805161ffff9092168252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610a0f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b005b60408051600160a060020a03929092168252519081900360200190f35b6040805160ff9092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311610a6057829003601f168201915b505050505090506101cc565b6004546000600260018316156101000260001901909216919091041115610ab35760009150610994565b610abb6105cf565b905060008114158015610acf575060018114155b8015610adc575060028114155b15610aea5760009150610994565b604080517f7c0278fc000000000000000000000000000000000000000000000000000000008152600360048201818152602483019384523660448401819052731deeda36e15ec9e80f3d7414d67a4803ae45fc8094637c0278fc946000939190606401848480828437820191505094505050505060006040518083038160008760325a03f215610002575050505090565b1415610c8557604080516001547f0fee183d0000000000000000000000000000000000000000000000000000000082526003600483015233600160a060020a0316602483015234604483015260648201529051731deeda36e15ec9e80f3d7414d67a4803ae45fc8091630fee183d916084828101926020929190829003018160008760325a03f21561000257505060405151925050811515610c8a577389efe605e9ecbe22849cd85d5449cc946c26f8f36312c82bcc33346040518360e060020a0281526004018083600160a060020a031681526020018281526020019250505060206040518083038160008760325a03f2156100025750506040515115159050610c8a57610002565b505090565b81925050610994565b505b50565b1415610c93575a9150610cab3383610481565b1515610cb75750610c95565b731deeda36e15ec9e80f3d7414d67a4803ae45fc8063da46be0a60038433610cdd61046e565b610ce5610232565b6040518660e060020a0281526004018086815260200185815260200184600160a060020a031681526020018381526020018281526020019550505050505060006040518083038160008760325a03f21561000257505050610c933360408051600080547fc17e6817000000000000000000000000000000000000000000000000000000008352600160a060020a03908116600484015230163160248301529151731deeda36e15ec9e80f3d7414d67a4803ae45fc809263c17e68179260448082019360209390928390039091019082908760325a03f2156100025750505050565b30600160a060020a031660405180807f5f5f6469672875696e7432353629000000000000000000000000000000000000815260200150600e019050604051809103902060e060020a8091040260e060020a9004600184036040518260e060020a0281526004018082815260200191505060006040518083038160008760325a03f292505050151561084f5761000256" }, "0x7dd677b54fc954824a7bc49bd26cbdfa12c75adf": { "balance": "0xd7a58f5b73b4b6c4", "code": "0x606060405236156100985760e060020a60003504633896002781146100e15780633defb962146100ea5780633f4be8891461010c5780634136aa351461011f5780634a420138146101a057806369c1a7121461028c5780638129fc1c146102955780638da5cb5b146102a6578063ae45850b146102b8578063af3309d8146102cc578063ea8a1af0146102d5578063ead50da3146102f4575b610308671bc16d674ec8000030600160a060020a03163110156100df57600554604051600160a060020a03918216916000913091909116319082818181858883f150505050505b565b61030a60005481565b610308671bc16d674ec8000030600160a060020a031631101561040f576100df565b61031c600454600160a060020a03165b90565b61030a5b600080548190118015610199575060408051600480547f0a16697a0000000000000000000000000000000000000000000000000000000083529251600160a060020a039390931692630a16697a928083019260209291829003018187876161da5a03f1156100025750506040515160ff01431090505b905061011c565b6103085b600354600554604080517f8c0e156d0000000000000000000000000000000000000000000000000000000081527f3defb96200000000000000000000000000000000000000000000000000000000600482015260a060020a90920461ffff1643016024830152621e8480604483015251600092600160a060020a031691638c0e156d916729a2241af62c000091606481810192602092909190829003018185886185025a03f1156100025750506040515192600160a060020a0384161491506102899050576004805473ffffffffffffffffffffffffffffffffffffffff1916821790555b50565b61030a60015481565b61030860008054146103f2576100df565b61031c600554600160a060020a031681565b61031c600354600160a060020a031661011c565b61030a60025481565b610308600554600160a060020a03908116339091161461035157610002565b61033960055460a060020a900461ffff1681565b005b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b6040805161ffff929092168252519081900360200190f35b6004546000600160a060020a03919091163111156103c75760408051600480547fea8a1af00000000000000000000000000000000000000000000000000000000083529251600160a060020a03939093169263ea8a1af0928083019260009291829003018183876161da5a03f115610002575050505b600554604051600160a060020a03918216916000913091909116319082818181858883f15050505050565b426000556100df6101a4565b600280546001908101909155429055565b600454600160a060020a03908116339091161461042b576100df565b610433610123565b151561043e576100df565b6103fe6101a456", "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000056be5b99", "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000056d0009b", "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000008b", - "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000006c8f2a135f6ed072de4503bd7c4999a1a17f824b", - "0x0000000000000000000000000000000000000000000000000000000000000004": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b", - "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000001e0d3cda913deb6f67967b99d67acdfa1712c293601" + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x000000000000000000000000741467b251fca923d6229c4b439078b55dca233b" } }, "0xb834e3edfc1a927bdcecb67a9d0eccbd752a5bb3": { 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 4fd7df37a9b4..01cc3c50582f 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 @@ -73,9 +73,6 @@ "nonce": 1, "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", - "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", - "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" } }, diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index f06ca8059880..9562bb01caa7 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -69,12 +69,10 @@ type prestateTracer struct { } type prestateTracerConfig struct { - DiffMode bool `json:"diffMode"` // If true, this tracer will return all diff states + DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications } func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { - // First callframe contains tx context info - // and is populated on start and end. var config prestateTracerConfig if cfg != nil { if err := json.Unmarshal(cfg, &config); err != nil { @@ -192,7 +190,7 @@ func (t *prestateTracer) CaptureTxEnd(restGas uint64) { } for addr, state := range t.pre { - // the deleted account's state is pruned + // The deleted account's state is pruned from `post` but kept in `pre` if _, ok := t.deleted[addr]; ok { continue } @@ -222,7 +220,10 @@ func (t *prestateTracer) CaptureTxEnd(restGas uint64) { } newVal := t.env.StateDB.GetState(addr, key) - if val != newVal { + if val == newVal { + // Omit unchanged slots + delete(t.pre[addr].Storage, key) + } else { modified = true if newVal != (common.Hash{}) { postAccount.Storage[key] = newVal From 8578eb2fe1071c70eeee1a76b14d87e93ba129ca Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 1 Nov 2022 21:28:40 +0800 Subject: [PATCH 336/715] accounts/abi: return error on fixed bytes with size larger than 32 bytes (#26075) * fixed bytes with size larger than 32 bytes is not allowed * add testcase --- accounts/abi/type.go | 3 +++ accounts/abi/type_test.go | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 008b665b1aee..7f74907a8479 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -154,6 +154,9 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty if varSize == 0 { typ.T = BytesTy } else { + if varSize > 32 { + return Type{}, fmt.Errorf("unsupported arg type: %s", t) + } typ.T = FixedBytesTy typ.Size = varSize } diff --git a/accounts/abi/type_test.go b/accounts/abi/type_test.go index 8c3aedca6a4d..a72531ba2797 100644 --- a/accounts/abi/type_test.go +++ b/accounts/abi/type_test.go @@ -366,3 +366,10 @@ func TestGetTypeSize(t *testing.T) { } } } + +func TestNewFixedBytesOver32(t *testing.T) { + _, err := NewType("bytes4096", "", nil) + if err == nil { + t.Errorf("fixed bytes with size over 32 is not spec'd") + } +} From 2b65219550e258f1fe5200c8221a9f780824c5ee Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 1 Nov 2022 21:39:39 +0800 Subject: [PATCH 337/715] consensus/ethash: fix typo (#26016) fix typo --- consensus/ethash/algorithm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/ethash/algorithm.go b/consensus/ethash/algorithm.go index 065e60b90b21..d53918382283 100644 --- a/consensus/ethash/algorithm.go +++ b/consensus/ethash/algorithm.go @@ -339,7 +339,7 @@ func hashimoto(hash []byte, nonce uint64, size uint64, lookup func(index uint32) // Calculate the number of theoretical rows (we use one buffer nonetheless) rows := uint32(size / mixBytes) - // Combine header+nonce into a 64 byte seed + // Combine header+nonce into a 40 byte seed seed := make([]byte, 40) copy(seed, hash) binary.LittleEndian.PutUint64(seed[32:], nonce) From 2415911f5366059d739a36b24e79e99d3b5901ed Mon Sep 17 00:00:00 2001 From: Sebastian Supreme <106926150+SebastianSupreme@users.noreply.github.com> Date: Tue, 1 Nov 2022 14:50:03 +0100 Subject: [PATCH 338/715] docs/postmortems: remove wrong parentheses (#26066) Removed parentheses in line 71 because line 80 doesn't have them either. --- docs/postmortems/2021-08-22-split-postmortem.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/postmortems/2021-08-22-split-postmortem.md b/docs/postmortems/2021-08-22-split-postmortem.md index 2004f0f2870d..962aa51f644b 100644 --- a/docs/postmortems/2021-08-22-split-postmortem.md +++ b/docs/postmortems/2021-08-22-split-postmortem.md @@ -68,7 +68,7 @@ Since we had merged the removal of `ETH65`, if the entire network were to upgrad ## Exploit -At block [13107518](https://etherscan.io/block/13107518), mined at (Aug-27-2021 12:50:07 PM +UTC), a minority chain split occurred. The discord user @AlexSSD7 notified the allcoredevs-channel on the Eth R&D discord, on Aug 27 13:09 UTC. +At block [13107518](https://etherscan.io/block/13107518), mined at Aug-27-2021 12:50:07 PM +UTC, a minority chain split occurred. The discord user @AlexSSD7 notified the allcoredevs-channel on the Eth R&D discord, on Aug 27 13:09 UTC. At 14:09 UTC, it was confirmed that the transaction `0x1cb6fb36633d270edefc04d048145b4298e67b8aa82a9e5ec4aa1435dd770ce4` had triggered the bug, leading to a minority-split of the chain. The term 'minority split' means that the majority of miners continued to mine on the correct chain. From a2a144c593a75b674e46b426850757afc29a2ba5 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 2 Nov 2022 17:32:20 +0800 Subject: [PATCH 339/715] miner, eth: implement recommit mechanism for payload building (#25836) * miner, eth: implement recommit for payload building * miner: address comments from marius --- eth/catalyst/api.go | 21 ++--- eth/catalyst/api_test.go | 30 ++++-- eth/catalyst/queue.go | 55 ++--------- miner/miner.go | 25 +---- miner/payload_building.go | 168 +++++++++++++++++++++++++++++++++ miner/payload_building_test.go | 80 ++++++++++++++++ miner/stress/beacon/main.go | 18 ++-- miner/worker.go | 64 ++++++++----- miner/worker_test.go | 8 +- 9 files changed, 338 insertions(+), 131 deletions(-) create mode 100644 miner/payload_building.go create mode 100644 miner/payload_building_test.go diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 6653f719fc3c..030a39837472 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" ) @@ -279,23 +280,21 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa } // If payload generation was requested, create a new block to be potentially // sealed by the beacon client. The payload will be requested later, and we - // might replace it arbitrarily many times in between. + // will replace it arbitrarily many times in between. if payloadAttributes != nil { - // Create an empty block first which can be used as a fallback - empty, err := api.eth.Miner().GetSealingBlockSync(update.HeadBlockHash, payloadAttributes.Timestamp, payloadAttributes.SuggestedFeeRecipient, payloadAttributes.Random, true) - if err != nil { - log.Error("Failed to create empty sealing payload", "err", err) - return valid(nil), beacon.InvalidPayloadAttributes.With(err) + args := &miner.BuildPayloadArgs{ + Parent: update.HeadBlockHash, + Timestamp: payloadAttributes.Timestamp, + FeeRecipient: payloadAttributes.SuggestedFeeRecipient, + Random: payloadAttributes.Random, } - // Send a request to generate a full block in the background. - // The result can be obtained via the returned channel. - resCh, err := api.eth.Miner().GetSealingBlockAsync(update.HeadBlockHash, payloadAttributes.Timestamp, payloadAttributes.SuggestedFeeRecipient, payloadAttributes.Random, false) + payload, err := api.eth.Miner().BuildPayload(args) if err != nil { - log.Error("Failed to create async sealing payload", "err", err) + log.Error("Failed to build payload", "err", err) return valid(nil), beacon.InvalidPayloadAttributes.With(err) } id := computePayloadId(update.HeadBlockHash, payloadAttributes) - api.localBlocks.put(id, &payload{empty: empty, result: resCh}) + api.localBlocks.put(id, payload) return valid(&id), nil } return valid(nil), nil diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index e195145b73ad..18750d6a0323 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" @@ -181,6 +182,8 @@ func TestEth2PrepareAndGetPayload(t *testing.T) { if err != nil { t.Fatalf("error preparing payload, err=%v", err) } + // give the payload some time to be built + time.Sleep(100 * time.Millisecond) payloadID := computePayloadId(fcState.HeadBlockHash, &blockParams) execData, err := api.GetPayloadV1(payloadID) if err != nil { @@ -586,12 +589,12 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { if resp.PayloadStatus.Status != beacon.VALID { t.Fatalf("error preparing payload, invalid status: %v", resp.PayloadStatus.Status) } + // give the payload some time to be built + time.Sleep(100 * time.Millisecond) payload, err := api.GetPayloadV1(*resp.PayloadID) if err != nil { t.Fatalf("can't get payload: %v", err) } - // TODO(493456442, marius) this test can be flaky since we rely on a 100ms - // allowance for block generation internally. if len(payload.Transactions) == 0 { t.Fatalf("payload should not be empty") } @@ -618,11 +621,17 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { } func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributesV1) (*beacon.ExecutableDataV1, error) { - block, err := api.eth.Miner().GetSealingBlockSync(parentHash, params.Timestamp, params.SuggestedFeeRecipient, params.Random, false) + args := &miner.BuildPayloadArgs{ + Parent: parentHash, + Timestamp: params.Timestamp, + FeeRecipient: params.SuggestedFeeRecipient, + Random: params.Random, + } + payload, err := api.eth.Miner().BuildPayload(args) if err != nil { return nil, err } - return beacon.BlockToExecutableData(block), nil + return payload.ResolveFull(), nil } func TestEmptyBlocks(t *testing.T) { @@ -854,16 +863,17 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { } // Test parent already post TTD in NewPayload - params := beacon.PayloadAttributesV1{ - Timestamp: parent.Time() + 1, - Random: crypto.Keccak256Hash([]byte{byte(1)}), - SuggestedFeeRecipient: parent.Coinbase(), + args := &miner.BuildPayloadArgs{ + Parent: parent.Hash(), + Timestamp: parent.Time() + 1, + Random: crypto.Keccak256Hash([]byte{byte(1)}), + FeeRecipient: parent.Coinbase(), } - empty, err := api.eth.Miner().GetSealingBlockSync(parent.Hash(), params.Timestamp, params.SuggestedFeeRecipient, params.Random, true) + payload, err := api.eth.Miner().BuildPayload(args) if err != nil { t.Fatalf("error preparing payload, err=%v", err) } - data := *beacon.BlockToExecutableData(empty) + data := *payload.Resolve() resp2, err := api.NewPayloadV1(data) if err != nil { t.Fatalf("error sending NewPayload, err=%v", err) diff --git a/eth/catalyst/queue.go b/eth/catalyst/queue.go index ff8edc1201c4..6863edfad1ae 100644 --- a/eth/catalyst/queue.go +++ b/eth/catalyst/queue.go @@ -18,11 +18,11 @@ package catalyst import ( "sync" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/miner" ) // maxTrackedPayloads is the maximum number of prepared payloads the execution @@ -35,52 +35,11 @@ const maxTrackedPayloads = 10 // latest one; but have a slight wiggle room for non-ideal conditions. const maxTrackedHeaders = 10 -// payload wraps the miner's block production channel, allowing the mined block -// to be retrieved later upon the GetPayload engine API call. -type payload struct { - lock sync.Mutex - done bool - empty *types.Block - block *types.Block - result chan *types.Block -} - -// resolve extracts the generated full block from the given channel if possible -// or fallback to empty block as an alternative. -func (req *payload) resolve() *beacon.ExecutableDataV1 { - // this function can be called concurrently, prevent any - // concurrency issue in the first place. - req.lock.Lock() - defer req.lock.Unlock() - - // Try to resolve the full block first if it's not obtained - // yet. The returned block can be nil if the generation fails. - - if !req.done { - timeout := time.NewTimer(500 * time.Millisecond) - defer timeout.Stop() - - select { - case req.block = <-req.result: - req.done = true - case <-timeout.C: - // TODO(rjl49345642, Marius), should we keep this - // 100ms timeout allowance? Why not just use the - // default and then fallback to empty directly? - } - } - - if req.block != nil { - return beacon.BlockToExecutableData(req.block) - } - return beacon.BlockToExecutableData(req.empty) -} - // payloadQueueItem represents an id->payload tuple to store until it's retrieved // or evicted. type payloadQueueItem struct { - id beacon.PayloadID - data *payload + id beacon.PayloadID + payload *miner.Payload } // payloadQueue tracks the latest handful of constructed payloads to be retrieved @@ -99,14 +58,14 @@ func newPayloadQueue() *payloadQueue { } // put inserts a new payload into the queue at the given id. -func (q *payloadQueue) put(id beacon.PayloadID, data *payload) { +func (q *payloadQueue) put(id beacon.PayloadID, payload *miner.Payload) { q.lock.Lock() defer q.lock.Unlock() copy(q.payloads[1:], q.payloads) q.payloads[0] = &payloadQueueItem{ - id: id, - data: data, + id: id, + payload: payload, } } @@ -120,7 +79,7 @@ func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutableDataV1 { return nil // no more items } if item.id == id { - return item.data.resolve() + return item.payload.Resolve() } } return nil diff --git a/miner/miner.go b/miner/miner.go index 2b81b8464214..c2a9e07d0499 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -251,26 +251,7 @@ func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscript return miner.worker.pendingLogsFeed.Subscribe(ch) } -// GetSealingBlockAsync requests to generate a sealing block according to the -// given parameters. Regardless of whether the generation is successful or not, -// there is always a result that will be returned through the result channel. -// The difference is that if the execution fails, the returned result is nil -// and the concrete error is dropped silently. -func (miner *Miner) GetSealingBlockAsync(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, noTxs bool) (chan *types.Block, error) { - resCh, _, err := miner.worker.getSealingBlock(parent, timestamp, coinbase, random, noTxs) - if err != nil { - return nil, err - } - return resCh, nil -} - -// GetSealingBlockSync creates a sealing block according to the given parameters. -// If the generation is failed or the underlying work is already closed, an error -// will be returned. -func (miner *Miner) GetSealingBlockSync(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, noTxs bool) (*types.Block, error) { - resCh, errCh, err := miner.worker.getSealingBlock(parent, timestamp, coinbase, random, noTxs) - if err != nil { - return nil, err - } - return <-resCh, <-errCh +// BuildPayload builds the payload according to the provided parameters. +func (miner *Miner) BuildPayload(args *BuildPayloadArgs) (*Payload, error) { + return miner.worker.buildPayload(args) } diff --git a/miner/payload_building.go b/miner/payload_building.go new file mode 100644 index 000000000000..18a74ceae3ce --- /dev/null +++ b/miner/payload_building.go @@ -0,0 +1,168 @@ +// Copyright 2022 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 miner + +import ( + "math/big" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/beacon" + "github.com/ethereum/go-ethereum/core/types" +) + +// BuildPayloadArgs contains the provided parameters for building payload. +// Check engine-api specification for more details. +// https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#payloadattributesv1 +type BuildPayloadArgs struct { + Parent common.Hash // The parent block to build payload on top + Timestamp uint64 // The provided timestamp of generated payload + FeeRecipient common.Address // The provided recipient address for collecting transaction fee + Random common.Hash // The provided randomness value +} + +// Payload wraps the built payload(block waiting for sealing). According to the +// engine-api specification, EL should build the initial version of the payload +// which has an empty transaction set and then keep update it in order to maximize +// the revenue. Therefore, the empty-block here is always available and full-block +// will be set/updated afterwards. +type Payload struct { + empty *types.Block + full *types.Block + fullFees *big.Int + stop chan struct{} + lock *sync.Mutex + cond *sync.Cond +} + +// newPayload initializes the payload object. +func newPayload(empty *types.Block) *Payload { + lock := new(sync.Mutex) + return &Payload{ + empty: empty, + stop: make(chan struct{}), + lock: lock, + cond: sync.NewCond(lock), + } +} + +// update updates the full-block with latest built version. +func (payload *Payload) update(block *types.Block, fees *big.Int) { + payload.lock.Lock() + defer payload.lock.Unlock() + + select { + case <-payload.stop: + return // reject stale update + default: + } + // Ensure the newly provided full block has a higher transaction fee. + // In post-merge stage, there is no uncle reward anymore and transaction + // fee(apart from the mev revenue) is the only indicator for comparison. + if payload.full == nil || fees.Cmp(payload.fullFees) > 0 { + payload.full = block + payload.fullFees = fees + } + payload.cond.Broadcast() // fire signal for notifying full block +} + +// Resolve returns the latest built payload and also terminates the background +// thread for updating payload. It's safe to be called multiple times. +func (payload *Payload) Resolve() *beacon.ExecutableDataV1 { + payload.lock.Lock() + defer payload.lock.Unlock() + + select { + case <-payload.stop: + default: + close(payload.stop) + } + if payload.full != nil { + return beacon.BlockToExecutableData(payload.full) + } + return beacon.BlockToExecutableData(payload.empty) +} + +// ResolveEmpty is basically identical to Resolve, but it expects empty block only. +// It's only used in tests. +func (payload *Payload) ResolveEmpty() *beacon.ExecutableDataV1 { + payload.lock.Lock() + defer payload.lock.Unlock() + + return beacon.BlockToExecutableData(payload.empty) +} + +// ResolveFull is basically identical to Resolve, but it expects full block only. +// It's only used in tests. +func (payload *Payload) ResolveFull() *beacon.ExecutableDataV1 { + payload.lock.Lock() + defer payload.lock.Unlock() + + if payload.full == nil { + select { + case <-payload.stop: + return nil + default: + } + payload.cond.Wait() + } + return beacon.BlockToExecutableData(payload.full) +} + +// buildPayload builds the payload according to the provided parameters. +func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { + // Build the initial version with no transaction included. It should be fast + // enough to run. The empty payload can at least make sure there is something + // to deliver for not missing slot. + empty, _, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, true) + if err != nil { + return nil, err + } + // Construct a payload object for return. + payload := newPayload(empty) + + // Spin up a routine for updating the payload in background. This strategy + // can maximum the revenue for including transactions with highest fee. + go func() { + // Setup the timer for re-building the payload. The initial clock is kept + // for triggering process immediately. + timer := time.NewTimer(0) + defer timer.Stop() + + // Setup the timer for terminating the process if SECONDS_PER_SLOT (12s in + // the Mainnet configuration) have passed since the point in time identified + // by the timestamp parameter. + endTimer := time.NewTimer(time.Second * 12) + + for { + select { + case <-timer.C: + block, fees, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, false) + if err == nil { + payload.update(block, fees) + } + timer.Reset(w.recommit) + case <-payload.stop: + return + case <-endTimer.C: + return + } + } + }() + return payload, nil +} diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go new file mode 100644 index 000000000000..226ae71b4add --- /dev/null +++ b/miner/payload_building_test.go @@ -0,0 +1,80 @@ +// Copyright 2022 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 miner + +import ( + "reflect" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/beacon" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/params" +) + +func TestBuildPayload(t *testing.T) { + var ( + db = rawdb.NewMemoryDatabase() + recipient = common.HexToAddress("0xdeadbeef") + ) + w, b := newTestWorker(t, params.TestChainConfig, ethash.NewFaker(), db, 0) + defer w.close() + + timestamp := uint64(time.Now().Unix()) + args := &BuildPayloadArgs{ + Parent: b.chain.CurrentBlock().Hash(), + Timestamp: timestamp, + Random: common.Hash{}, + FeeRecipient: recipient, + } + payload, err := w.buildPayload(args) + if err != nil { + t.Fatalf("Failed to build payload %v", err) + } + verify := func(data *beacon.ExecutableDataV1, txs int) { + if data.ParentHash != b.chain.CurrentBlock().Hash() { + t.Fatal("Unexpect parent hash") + } + if data.Random != (common.Hash{}) { + t.Fatal("Unexpect random value") + } + if data.Timestamp != timestamp { + t.Fatal("Unexpect timestamp") + } + if data.FeeRecipient != recipient { + t.Fatal("Unexpect fee recipient") + } + if len(data.Transactions) != txs { + t.Fatal("Unexpect transaction set") + } + } + empty := payload.ResolveEmpty() + verify(empty, 0) + + full := payload.ResolveFull() + verify(full, len(pendingTxs)) + + // Ensure resolve can be called multiple times and the + // result should be unchanged + dataOne := payload.Resolve() + dataTwo := payload.Resolve() + if !reflect.DeepEqual(dataOne, dataTwo) { + t.Fatal("Unexpected payload data") + } +} diff --git a/miner/stress/beacon/main.go b/miner/stress/beacon/main.go index a4764be0ada4..7dabc97c003f 100644 --- a/miner/stress/beacon/main.go +++ b/miner/stress/beacon/main.go @@ -81,8 +81,8 @@ var ( transitionDifficulty = new(big.Int).Mul(big.NewInt(20), params.MinimumDifficulty) // blockInterval is the time interval for creating a new eth2 block - blockInterval = time.Second * 3 blockIntervalInt = 3 + blockInterval = time.Second * time.Duration(blockIntervalInt) // finalizationDist is the block distance for finalizing block finalizationDist = 10 @@ -164,6 +164,7 @@ func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) if err != nil { return nil, err } + time.Sleep(time.Second * 5) // give enough time for block creation return n.api.GetPayloadV1(*payload.PayloadID) } @@ -316,17 +317,14 @@ func (mgr *nodeManager) run() { } nodes := mgr.getNodes(eth2MiningNode) nodes = append(nodes, mgr.getNodes(eth2NormalNode)...) - nodes = append(nodes, mgr.getNodes(eth2LightClient)...) + //nodes = append(nodes, mgr.getNodes(eth2LightClient)...) for _, node := range nodes { fcState := beacon.ForkchoiceStateV1{ - HeadBlockHash: oldest.Hash(), - SafeBlockHash: common.Hash{}, + HeadBlockHash: parentBlock.Hash(), + SafeBlockHash: oldest.Hash(), FinalizedBlockHash: oldest.Hash(), } - // TODO(rjl493456442) finalization doesn't work properly, FIX IT - _ = fcState - _ = node - //node.api.ForkchoiceUpdatedV1(fcState, nil) + node.api.ForkchoiceUpdatedV1(fcState, nil) } log.Info("Finalised eth2 block", "number", oldest.NumberU64(), "hash", oldest.Hash()) waitFinalise = waitFinalise[1:] @@ -423,7 +421,7 @@ func main() { node := nodes[index%len(nodes)] // Create a self transaction and inject into the pool - tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000+rand.Int63n(65536)), nil), types.HomesteadSigner{}, faucets[index]) + tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(10_000_000_000+rand.Int63n(6_553_600_000)), nil), types.HomesteadSigner{}, faucets[index]) if err != nil { panic(err) } @@ -492,7 +490,7 @@ func makeFullNode(genesis *core.Genesis) (*node.Node, *eth.Ethereum, *ethcatalys GasFloor: genesis.GasLimit * 9 / 10, GasCeil: genesis.GasLimit * 11 / 10, GasPrice: big.NewInt(1), - Recommit: 10 * time.Second, // Disable the recommit + Recommit: 1 * time.Second, }, LightServ: 100, LightPeers: 10, diff --git a/miner/worker.go b/miner/worker.go index c3fca2159452..720613cb2e7e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -169,11 +169,17 @@ type newWorkReq struct { timestamp int64 } +// newPayloadResult represents a result struct corresponds to payload generation. +type newPayloadResult struct { + err error + block *types.Block + fees *big.Int +} + // getWorkReq represents a request for getting a new sealing work with provided parameters. type getWorkReq struct { params *generateParams - result chan *types.Block // non-blocking channel - err chan error + result chan *newPayloadResult // non-blocking channel } // intervalAdjust represents a resubmitting interval adjustment. @@ -250,6 +256,10 @@ type worker struct { // in case there are some computation expensive transactions in txpool. newpayloadTimeout time.Duration + // recommit is the time interval to re-create sealing work or to re-build + // payload in proof-of-stake stage. + recommit time.Duration + // External functions isLocalBlock func(header *types.Header) bool // Function used to determine whether the specified block is mined by local miner. @@ -297,6 +307,8 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus log.Warn("Sanitizing miner recommit interval", "provided", recommit, "updated", minRecommitInterval) recommit = minRecommitInterval } + worker.recommit = recommit + // Sanitize the timeout config for creating payload. newpayloadTimeout := worker.config.NewPayloadTimeout if newpayloadTimeout == 0 { @@ -553,13 +565,11 @@ func (w *worker) mainLoop() { w.commitWork(req.interrupt, req.noempty, req.timestamp) case req := <-w.getWorkCh: - block, err := w.generateWork(req.params) - if err != nil { - req.err <- err - req.result <- nil - } else { - req.err <- nil - req.result <- block + block, fees, err := w.generateWork(req.params) + req.result <- &newPayloadResult{ + err: err, + block: block, + fees: fees, } case ev := <-w.chainSideCh: // Short circuit for duplicate side blocks @@ -1071,10 +1081,10 @@ func (w *worker) fillTransactions(interrupt *int32, env *environment) error { } // generateWork generates a sealing block based on the given parameters. -func (w *worker) generateWork(params *generateParams) (*types.Block, error) { +func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, error) { work, err := w.prepareWork(params) if err != nil { - return nil, err + return nil, nil, err } defer work.discard() @@ -1090,7 +1100,11 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, error) { log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.newpayloadTimeout)) } } - return w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts) + block, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts) + if err != nil { + return nil, nil, err + } + return block, totalFees(block, work.receipts), nil } // commitWork generates several new sealing tasks based on the parent block @@ -1180,9 +1194,12 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti select { case w.taskCh <- &task{receipts: env.receipts, state: env.state, block: block, createdAt: time.Now()}: w.unconfirmed.Shift(block.NumberU64() - 1) + + fees := totalFees(block, env.receipts) + feesInEther := new(big.Float).Quo(new(big.Float).SetInt(fees), new(big.Float).SetInt(big.NewInt(params.Ether))) log.Info("Commit new sealing work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), "uncles", len(env.uncles), "txs", env.tcount, - "gas", block.GasUsed(), "fees", totalFees(block, env.receipts), + "gas", block.GasUsed(), "fees", feesInEther, "elapsed", common.PrettyDuration(time.Since(start))) case <-w.exitCh: @@ -1199,11 +1216,7 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti // getSealingBlock generates the sealing block based on the given parameters. // The generation result will be passed back via the given channel no matter // the generation itself succeeds or not. -func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, noTxs bool) (chan *types.Block, chan error, error) { - var ( - resCh = make(chan *types.Block, 1) - errCh = make(chan error, 1) - ) +func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, noTxs bool) (*types.Block, *big.Int, error) { req := &getWorkReq{ params: &generateParams{ timestamp: timestamp, @@ -1215,12 +1228,15 @@ func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase noExtra: true, noTxs: noTxs, }, - result: resCh, - err: errCh, + result: make(chan *newPayloadResult, 1), } select { case w.getWorkCh <- req: - return resCh, errCh, nil + result := <-req.result + if result.err != nil { + return nil, nil, result.err + } + return result.block, result.fees, nil case <-w.exitCh: return nil, nil, errors.New("miner closed") } @@ -1251,14 +1267,14 @@ func (w *worker) postSideBlock(event core.ChainSideEvent) { } } -// totalFees computes total consumed miner fees in ETH. Block transactions and receipts have to have the same order. -func totalFees(block *types.Block, receipts []*types.Receipt) *big.Float { +// totalFees computes total consumed miner fees in Wei. Block transactions and receipts have to have the same order. +func totalFees(block *types.Block, receipts []*types.Receipt) *big.Int { feesWei := new(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)) } - return new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether))) + return feesWei } // signalToErr converts the interruption signal to a concrete error type for return. diff --git a/miner/worker_test.go b/miner/worker_test.go index fcbe5529c1d0..104417c34158 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -634,9 +634,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co // This API should work even when the automatic sealing is not enabled for _, c := range cases { - resChan, errChan, _ := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, false) - block := <-resChan - err := <-errChan + block, _, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, false) if c.expectErr { if err == nil { t.Error("Expect error but get nil") @@ -652,9 +650,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co // This API should work even when the automatic sealing is enabled w.start() for _, c := range cases { - resChan, errChan, _ := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, false) - block := <-resChan - err := <-errChan + block, _, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, false) if c.expectErr { if err == nil { t.Error("Expect error but get nil") From 24f08ece621f3257bd9e24080a3c5d798a9ea7ad Mon Sep 17 00:00:00 2001 From: Roberto Bayardo Date: Wed, 2 Nov 2022 04:57:09 -0700 Subject: [PATCH 340/715] miner: fail early if core.NewBlockChain fails (#26079) don't ignore errors returned by core.NewBlockChain when initializing tests --- miner/worker_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/miner/worker_test.go b/miner/worker_test.go index 104417c34158..859495d7bf16 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -134,7 +134,10 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine default: t.Fatalf("unexpected consensus engine type: %T", engine) } - chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("core.NewBlockChain failed: %v", err) + } txpool := txpool.NewTxPool(testTxPoolConfig, chainConfig, chain) // Generate a small n-block chain and an uncle block for it From 621b423ac1b61d6bac1651cf1481fb8220080d40 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Wed, 2 Nov 2022 08:50:07 -0500 Subject: [PATCH 341/715] p2p/discover: fix handling of distance 256 in lookupDistances (#26087) Noticed that lookupDistances for FINDNODE requests didn't consider 256 a valid distance. This is actually part of the example in the comment above the function, surprised that wasn't tested before. --- p2p/discover/v5_udp.go | 2 +- p2p/discover/v5_udp_test.go | 37 +++++++++++++++++++++++++++++++++ p2p/discover/v5wire/encoding.go | 4 ++-- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 757a3587dc7d..1c66602f8791 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -323,7 +323,7 @@ func lookupDistances(target, dest enode.ID) (dists []uint) { td := enode.LogDist(target, dest) dists = append(dists, uint(td)) for i := 1; len(dists) < lookupRequestLimit; i++ { - if td+i < 256 { + if td+i <= 256 { dists = append(dists, uint(td+i)) } if td-i > 0 { diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 30d610a4dd8c..ca63688afa13 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rlp" + "github.com/stretchr/testify/require" ) // Real sockets, real crypto: this test checks end-to-end connectivity for UDPv5. @@ -519,6 +520,42 @@ func TestUDPv5_talkRequest(t *testing.T) { } } +// This test checks that lookupDistances works. +func TestUDPv5_lookupDistances(t *testing.T) { + test := newUDPV5Test(t) + lnID := test.table.self().ID() + + t.Run("target distance of 1", func(t *testing.T) { + node := nodeAtDistance(lnID, 1, intIP(0)) + dists := lookupDistances(lnID, node.ID()) + require.Equal(t, []uint{1, 2, 3}, dists) + }) + + t.Run("target distance of 2", func(t *testing.T) { + node := nodeAtDistance(lnID, 2, intIP(0)) + dists := lookupDistances(lnID, node.ID()) + require.Equal(t, []uint{2, 3, 1}, dists) + }) + + t.Run("target distance of 128", func(t *testing.T) { + node := nodeAtDistance(lnID, 128, intIP(0)) + dists := lookupDistances(lnID, node.ID()) + require.Equal(t, []uint{128, 129, 127}, dists) + }) + + t.Run("target distance of 255", func(t *testing.T) { + node := nodeAtDistance(lnID, 255, intIP(0)) + dists := lookupDistances(lnID, node.ID()) + require.Equal(t, []uint{255, 256, 254}, dists) + }) + + t.Run("target distance of 256", func(t *testing.T) { + node := nodeAtDistance(lnID, 256, intIP(0)) + dists := lookupDistances(lnID, node.ID()) + require.Equal(t, []uint{256, 255, 254}, dists) + }) +} + // This test checks that lookup works. func TestUDPv5_lookup(t *testing.T) { t.Parallel() diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index 6f8f3466e9de..e41d7f4c451e 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -65,7 +65,7 @@ type ( handshakeAuthData struct { h struct { SrcID enode.ID - SigSize byte // ignature data + SigSize byte // signature data PubkeySize byte // offset of } // Trailing variable-size data. @@ -529,7 +529,7 @@ func (c *Codec) decodeHandshake(fromAddr string, head *Header) (n *enode.Node, a if err != nil { return nil, auth, nil, errInvalidAuthKey } - // Derive sesssion keys. + // Derive session keys. session := deriveKeys(sha256.New, c.privkey, ephkey, auth.h.SrcID, c.localnode.ID(), cdata) session = session.keysFlipped() return n, auth, session, nil From 4a81e5afea2f82e04764aadabd18115250bce785 Mon Sep 17 00:00:00 2001 From: Roberto Bayardo Date: Wed, 2 Nov 2022 06:50:48 -0700 Subject: [PATCH 342/715] rlp: add more tests for nil pointer / optional field encoding (#26077) --- rlp/decode_test.go | 34 ++++++++++++++++++++++++++++++++++ rlp/encode_test.go | 4 ++++ 2 files changed, 38 insertions(+) diff --git a/rlp/decode_test.go b/rlp/decode_test.go index 00722f847bbb..dbcfcffed1a1 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -439,6 +439,16 @@ type optionalPtrField struct { B *[3]byte `rlp:"optional"` } +type nonOptionalPtrField struct { + A uint + B *[3]byte +} + +type multipleOptionalFields struct { + A *[3]byte `rlp:"optional"` + B *[3]byte `rlp:"optional"` +} + type optionalPtrFieldNil struct { A uint B *[3]byte `rlp:"optional,nil"` @@ -744,6 +754,30 @@ var decodeTests = []decodeTest{ ptr: new(optionalPtrField), value: optionalPtrField{A: 1, B: &[3]byte{1, 2, 3}}, }, + { + // all optional fields nil + input: "C0", + ptr: new(multipleOptionalFields), + value: multipleOptionalFields{A: nil, B: nil}, + }, + { + // all optional fields set + input: "C88301020383010203", + ptr: new(multipleOptionalFields), + value: multipleOptionalFields{A: &[3]byte{1, 2, 3}, B: &[3]byte{1, 2, 3}}, + }, + { + // nil optional field appears before a non-nil one + input: "C58083010203", + ptr: new(multipleOptionalFields), + error: "rlp: input string too short for [3]uint8, decoding into (rlp.multipleOptionalFields).A", + }, + { + // decode a nil ptr into a ptr that is not nil or not optional + input: "C20180", + ptr: new(nonOptionalPtrField), + error: "rlp: input string too short for [3]uint8, decoding into (rlp.nonOptionalPtrField).B", + }, { input: "C101", ptr: new(optionalPtrFieldNil), diff --git a/rlp/encode_test.go b/rlp/encode_test.go index 58ddc0d120f0..82c490a80275 100644 --- a/rlp/encode_test.go +++ b/rlp/encode_test.go @@ -290,6 +290,10 @@ var encTests = []encTest{ {val: &optionalBigIntField{A: 1}, output: "C101"}, {val: &optionalPtrField{A: 1}, output: "C101"}, {val: &optionalPtrFieldNil{A: 1}, output: "C101"}, + {val: &multipleOptionalFields{A: nil, B: nil}, output: "C0"}, + {val: &multipleOptionalFields{A: &[3]byte{1, 2, 3}, B: &[3]byte{1, 2, 3}}, output: "C88301020383010203"}, + {val: &multipleOptionalFields{A: nil, B: &[3]byte{1, 2, 3}}, output: "C58083010203"}, // encodes without error but decode will fail + {val: &nonOptionalPtrField{A: 1}, output: "C20180"}, // encodes without error but decode will fail // nil {val: (*uint)(nil), output: "80"}, From 05037eaffc1ddc3170117ea82d09f4fc1d3888fc Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 2 Nov 2022 09:29:33 -0500 Subject: [PATCH 343/715] rpc: handle wrong HTTP batch response length (#26064) --- rpc/client.go | 1 + rpc/client_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++ rpc/http.go | 3 +++ 3 files changed, 52 insertions(+) diff --git a/rpc/client.go b/rpc/client.go index 8288f976ebeb..d89aa69277c7 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -32,6 +32,7 @@ import ( ) var ( + ErrBadResult = errors.New("bad result in JSON-RPC response") ErrClientQuit = errors.New("client is closed") ErrNoResult = errors.New("no result in JSON-RPC response") ErrSubscriptionQueueOverflow = errors.New("subscription queue overflow") diff --git a/rpc/client_test.go b/rpc/client_test.go index 51df76f7fe44..0a88ce40b2a8 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -19,6 +19,7 @@ package rpc import ( "context" "encoding/json" + "errors" "fmt" "math/rand" "net" @@ -148,6 +149,53 @@ func TestClientBatchRequest(t *testing.T) { } } +func TestClientBatchRequest_len(t *testing.T) { + b, err := json.Marshal([]jsonrpcMessage{ + {Version: "2.0", ID: json.RawMessage("1"), Method: "foo", Result: json.RawMessage(`"0x1"`)}, + {Version: "2.0", ID: json.RawMessage("2"), Method: "bar", Result: json.RawMessage(`"0x2"`)}, + }) + if err != nil { + t.Fatal("failed to encode jsonrpc message:", err) + } + s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + _, err := rw.Write(b) + if err != nil { + t.Error("failed to write response:", err) + } + })) + t.Cleanup(s.Close) + + client, err := Dial(s.URL) + if err != nil { + t.Fatal("failed to dial test server:", err) + } + defer client.Close() + + t.Run("too-few", func(t *testing.T) { + batch := []BatchElem{ + {Method: "foo"}, + {Method: "bar"}, + {Method: "baz"}, + } + ctx, cancelFn := context.WithTimeout(context.Background(), time.Second) + defer cancelFn() + if err := client.BatchCallContext(ctx, batch); !errors.Is(err, ErrBadResult) { + t.Errorf("expected %q but got: %v", ErrBadResult, err) + } + }) + + t.Run("too-many", func(t *testing.T) { + batch := []BatchElem{ + {Method: "foo"}, + } + ctx, cancelFn := context.WithTimeout(context.Background(), time.Second) + defer cancelFn() + if err := client.BatchCallContext(ctx, batch); !errors.Is(err, ErrBadResult) { + t.Errorf("expected %q but got: %v", ErrBadResult, err) + } + }) +} + func TestClientNotify(t *testing.T) { server := newTestServer() defer server.Stop() diff --git a/rpc/http.go b/rpc/http.go index 8595959afb66..e806ce98b09d 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -192,6 +192,9 @@ func (c *Client) sendBatchHTTP(ctx context.Context, op *requestOp, msgs []*jsonr if err := json.NewDecoder(respBody).Decode(&respmsgs); err != nil { return err } + if len(respmsgs) != len(msgs) { + return fmt.Errorf("batch has %d requests but response has %d: %w", len(msgs), len(respmsgs), ErrBadResult) + } for i := 0; i < len(respmsgs); i++ { op.resp <- &respmsgs[i] } From f3a005f176372ff291dfa7c02ee1c87d18e9c788 Mon Sep 17 00:00:00 2001 From: Joseph Cook <33655003+jmcook1186@users.noreply.github.com> Date: Wed, 2 Nov 2022 18:02:32 +0000 Subject: [PATCH 344/715] cmd/clef: add `list-accounts` and `list-wallets` to CLI (#26080) This commit adds support for two new commands to clef, making it possible to list accounts / wallets from the command-line-interface. Co-authored-by: Martin Holst Swende --- cmd/clef/main.go | 125 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 28 deletions(-) diff --git a/cmd/clef/main.go b/cmd/clef/main.go index a3e4815ed5fa..188a11500004 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -203,9 +203,8 @@ The delpw command removes a password for a given address (keyfile). }, Description: ` The newaccount command creates a new keystore-backed account. It is a convenience-method -which can be used in lieu of an external UI.`, - } - +which can be used in lieu of an external UI. +`} gendocCommand = &cli.Command{ Action: GenDoc, Name: "gendoc", @@ -213,6 +212,32 @@ which can be used in lieu of an external UI.`, Description: ` The gendoc generates example structures of the json-rpc communication types. `} + listAccountsCommand = &cli.Command{ + Action: listAccounts, + Name: "list-accounts", + Usage: "List accounts in the keystore", + Flags: []cli.Flag{ + logLevelFlag, + keystoreFlag, + utils.LightKDFFlag, + acceptFlag, + }, + Description: ` + Lists the accounts in the keystore. + `} + listWalletsCommand = &cli.Command{ + Action: listWallets, + Name: "list-wallets", + Usage: "List wallets known to Clef", + Flags: []cli.Flag{ + logLevelFlag, + keystoreFlag, + utils.LightKDFFlag, + acceptFlag, + }, + Description: ` + Lists the wallets known to Clef. + `} ) var app = flags.NewApp("Manage Ethereum account operations") @@ -249,6 +274,8 @@ func init() { delCredentialCommand, newAccountCommand, gendocCommand, + listAccountsCommand, + listWalletsCommand, } } @@ -351,6 +378,22 @@ func attestFile(ctx *cli.Context) error { return nil } +func initInternalApi(c *cli.Context) (*core.UIServerAPI, error) { + if err := initialize(c); err != nil { + return nil, err + } + var ( + ui = core.NewCommandlineUI() + pwStorage storage.Storage = &storage.NoStorage{} + ksLoc = c.String(keystoreFlag.Name) + lightKdf = c.Bool(utils.LightKDFFlag.Name) + ) + am := core.StartClefAccountManager(ksLoc, true, lightKdf, "") + api := core.NewSignerAPI(am, 0, true, ui, nil, false, pwStorage) + internalApi := core.NewUIServerAPI(api) + return internalApi, nil +} + func setCredential(ctx *cli.Context) error { if ctx.NArg() < 1 { utils.Fatalf("This command requires an address to be passed as an argument") @@ -409,31 +452,6 @@ func removeCredential(ctx *cli.Context) error { return nil } -func newAccount(c *cli.Context) error { - if err := initialize(c); err != nil { - return err - } - // The newaccount is meant for users using the CLI, since 'real' external - // UIs can use the UI-api instead. So we'll just use the native CLI UI here. - var ( - ui = core.NewCommandlineUI() - pwStorage storage.Storage = &storage.NoStorage{} - ksLoc = c.String(keystoreFlag.Name) - lightKdf = c.Bool(utils.LightKDFFlag.Name) - ) - log.Info("Starting clef", "keystore", ksLoc, "light-kdf", lightKdf) - am := core.StartClefAccountManager(ksLoc, true, lightKdf, "") - // This gives is us access to the external API - apiImpl := core.NewSignerAPI(am, 0, true, ui, nil, false, pwStorage) - // This gives us access to the internal API - internalApi := core.NewUIServerAPI(apiImpl) - addr, err := internalApi.New(context.Background()) - if err == nil { - fmt.Printf("Generated account %v\n", addr.String()) - } - return err -} - func initialize(c *cli.Context) error { // Set up the logger to print everything logOutput := os.Stdout @@ -459,6 +477,57 @@ func initialize(c *cli.Context) error { return nil } +func newAccount(c *cli.Context) error { + internalApi, err := initInternalApi(c) + if err != nil { + return err + } + addr, err := internalApi.New(context.Background()) + if err == nil { + fmt.Printf("Generated account %v\n", addr.String()) + } + return err +} + +func listAccounts(c *cli.Context) error { + internalApi, err := initInternalApi(c) + if err != nil { + return err + } + accs, err := internalApi.ListAccounts(context.Background()) + if err != nil { + return err + } + if len(accs) == 0 { + fmt.Println("\nThe keystore is empty.") + } + fmt.Println() + for _, account := range accs { + fmt.Printf("%v (%v)\n", account.Address, account.URL) + } + return err +} + +func listWallets(c *cli.Context) error { + internalApi, err := initInternalApi(c) + if err != nil { + return err + } + wallets := internalApi.ListWallets() + if len(wallets) == 0 { + fmt.Println("\nThere are no wallets.") + } + fmt.Println() + for i, wallet := range wallets { + fmt.Printf("- Wallet %d at %v (%v %v)\n", i, wallet.URL, wallet.Status, wallet.Failure) + for j, acc := range wallet.Accounts { + fmt.Printf(" -Account %d: %v (%v)\n", j, acc.Address, acc.URL) + } + fmt.Println() + } + return nil +} + // ipcEndpoint resolves an IPC endpoint based on a configured value, taking into // account the set data folders as well as the designated platform we're currently // running on. From 9a4e8e222e1a793a46800f1e2db5aed86344e33e Mon Sep 17 00:00:00 2001 From: jwasinger Date: Thu, 3 Nov 2022 00:48:13 -0700 Subject: [PATCH 345/715] crypto/bls12381: docs - fix broken links to references (#26095) --- crypto/bls12381/g1.go | 4 ++-- crypto/bls12381/g2.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crypto/bls12381/g1.go b/crypto/bls12381/g1.go index 52e12cc3a259..bcb898027ad8 100644 --- a/crypto/bls12381/g1.go +++ b/crypto/bls12381/g1.go @@ -247,7 +247,7 @@ func (g *G1) Affine(p *PointG1) *PointG1 { // Add adds two G1 points p1, p2 and assigns the result to point at first argument. func (g *G1) Add(r, p1, p2 *PointG1) *PointG1 { - // http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#addition-add-2007-bl + // www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl if g.IsZero(p1) { return r.Set(p2) } @@ -295,7 +295,7 @@ func (g *G1) Add(r, p1, p2 *PointG1) *PointG1 { // Double doubles a G1 point p and assigns the result to the point at first argument. func (g *G1) Double(r, p *PointG1) *PointG1 { - // http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l if g.IsZero(p) { return r.Set(p) } diff --git a/crypto/bls12381/g2.go b/crypto/bls12381/g2.go index c2ca959bcca1..4d6f1ff11de8 100644 --- a/crypto/bls12381/g2.go +++ b/crypto/bls12381/g2.go @@ -267,7 +267,7 @@ func (g *G2) Affine(p *PointG2) *PointG2 { // Add adds two G2 points p1, p2 and assigns the result to point at first argument. func (g *G2) Add(r, p1, p2 *PointG2) *PointG2 { - // http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#addition-add-2007-bl + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl if g.IsZero(p1) { return r.Set(p2) } @@ -315,7 +315,7 @@ func (g *G2) Add(r, p1, p2 *PointG2) *PointG2 { // Double doubles a G2 point p and assigns the result to the point at first argument. func (g *G2) Double(r, p *PointG2) *PointG2 { - // http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l if g.IsZero(p) { return r.Set(p) } From 08fb1aade6f8053f7b929d154db2a3c824779ac5 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 3 Nov 2022 22:18:28 +0800 Subject: [PATCH 346/715] miner: display change in fees, change recommit period (#26097) * miner: add logs for displaying fees change * miner: simplify feesInEther calculation * miner: fix lock * miner: change to default recommit to 2 seconds --- miner/miner.go | 11 ++++++++--- miner/payload_building.go | 20 +++++++++++++------- miner/worker.go | 2 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index c2a9e07d0499..5102cb523c39 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -60,9 +60,14 @@ type Config struct { // DefaultConfig contains default settings for miner. var DefaultConfig = Config{ - GasCeil: 30000000, - GasPrice: big.NewInt(params.GWei), - Recommit: 3 * time.Second, + GasCeil: 30000000, + GasPrice: big.NewInt(params.GWei), + + // The default recommit time is chosen as two seconds since + // consensus-layer usually will wait a half slot of time(6s) + // for payload generation. It should be enough for Geth to + // run 3 rounds. + Recommit: 2 * time.Second, NewPayloadTimeout: 2 * time.Second, } diff --git a/miner/payload_building.go b/miner/payload_building.go index 18a74ceae3ce..cdea6a3cc368 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -24,6 +24,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" ) // BuildPayloadArgs contains the provided parameters for building payload. @@ -46,23 +48,22 @@ type Payload struct { full *types.Block fullFees *big.Int stop chan struct{} - lock *sync.Mutex + lock sync.Mutex cond *sync.Cond } // newPayload initializes the payload object. func newPayload(empty *types.Block) *Payload { - lock := new(sync.Mutex) - return &Payload{ + payload := &Payload{ empty: empty, stop: make(chan struct{}), - lock: lock, - cond: sync.NewCond(lock), } + payload.cond = sync.NewCond(&payload.lock) + return payload } // update updates the full-block with latest built version. -func (payload *Payload) update(block *types.Block, fees *big.Int) { +func (payload *Payload) update(block *types.Block, fees *big.Int, elapsed time.Duration) { payload.lock.Lock() defer payload.lock.Unlock() @@ -77,6 +78,10 @@ func (payload *Payload) update(block *types.Block, fees *big.Int) { if payload.full == nil || fees.Cmp(payload.fullFees) > 0 { payload.full = block payload.fullFees = fees + + feesInEther := new(big.Float).Quo(new(big.Float).SetInt(fees), big.NewFloat(params.Ether)) + log.Info("Updated payload", "number", block.NumberU64(), "hash", block.Hash(), + "txs", len(block.Transactions()), "gas", block.GasUsed(), "fees", feesInEther, "elapsed", common.PrettyDuration(elapsed)) } payload.cond.Broadcast() // fire signal for notifying full block } @@ -152,9 +157,10 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { for { select { case <-timer.C: + start := time.Now() block, fees, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, false) if err == nil { - payload.update(block, fees) + payload.update(block, fees, time.Since(start)) } timer.Reset(w.recommit) case <-payload.stop: diff --git a/miner/worker.go b/miner/worker.go index 720613cb2e7e..5e3c3f22b557 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1196,7 +1196,7 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti w.unconfirmed.Shift(block.NumberU64() - 1) fees := totalFees(block, env.receipts) - feesInEther := new(big.Float).Quo(new(big.Float).SetInt(fees), new(big.Float).SetInt(big.NewInt(params.Ether))) + feesInEther := new(big.Float).Quo(new(big.Float).SetInt(fees), big.NewFloat(params.Ether)) log.Info("Commit new sealing work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), "uncles", len(env.uncles), "txs", env.tcount, "gas", block.GasUsed(), "fees", feesInEther, From a51188a163ff4e22deb880d424bb27902e63be03 Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 4 Nov 2022 16:27:15 +0100 Subject: [PATCH 347/715] params: make eip1559 params non-global (#25994) This PR changes geth to read the eip1559 params from the chain config instead of the globals. This way the parameters may be changed by forking the chain config code, without creating a large diff throughout the past and future usages of the parameters. Co-authored-by: Martin Holst Swende --- consensus/misc/eip1559.go | 8 ++++---- core/chain_makers.go | 4 ++-- miner/worker.go | 2 +- params/config.go | 10 ++++++++++ params/protocol_params.go | 6 +++--- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go index e0216243f057..4521b47b36e6 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559.go @@ -33,7 +33,7 @@ func VerifyEip1559Header(config *params.ChainConfig, parent, header *types.Heade // Verify that the gas limit remains within allowed bounds parentGasLimit := parent.GasLimit if !config.IsLondon(parent.Number) { - parentGasLimit = parent.GasLimit * params.ElasticityMultiplier + parentGasLimit = parent.GasLimit * config.ElasticityMultiplier() } if err := VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil { return err @@ -58,7 +58,7 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { return new(big.Int).SetUint64(params.InitialBaseFee) } - parentGasTarget := parent.GasLimit / params.ElasticityMultiplier + parentGasTarget := parent.GasLimit / config.ElasticityMultiplier() // If the parent gasUsed is the same as the target, the baseFee remains unchanged. if parent.GasUsed == parentGasTarget { return new(big.Int).Set(parent.BaseFee) @@ -75,7 +75,7 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { num.SetUint64(parent.GasUsed - parentGasTarget) num.Mul(num, parent.BaseFee) num.Div(num, denom.SetUint64(parentGasTarget)) - num.Div(num, denom.SetUint64(params.BaseFeeChangeDenominator)) + num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator())) baseFeeDelta := math.BigMax(num, common.Big1) return num.Add(parent.BaseFee, baseFeeDelta) @@ -85,7 +85,7 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { num.SetUint64(parentGasTarget - parent.GasUsed) num.Mul(num, parent.BaseFee) num.Div(num, denom.SetUint64(parentGasTarget)) - num.Div(num, denom.SetUint64(params.BaseFeeChangeDenominator)) + num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator())) baseFee := num.Sub(parent.BaseFee, num) return math.BigMax(baseFee, common.Big0) diff --git a/core/chain_makers.go b/core/chain_makers.go index 88a1c4e87024..2ed87e0a9e3a 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -174,7 +174,7 @@ func (b *BlockGen) AddUncle(h *types.Header) { if b.config.IsLondon(h.Number) { h.BaseFee = misc.CalcBaseFee(b.config, parent) if !b.config.IsLondon(parent.Number) { - parentGasLimit := parent.GasLimit * params.ElasticityMultiplier + parentGasLimit := parent.GasLimit * b.config.ElasticityMultiplier() h.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit) } } @@ -322,7 +322,7 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S if chain.Config().IsLondon(header.Number) { header.BaseFee = misc.CalcBaseFee(chain.Config(), parent.Header()) if !chain.Config().IsLondon(parent.Number()) { - parentGasLimit := parent.GasLimit() * params.ElasticityMultiplier + parentGasLimit := parent.GasLimit() * chain.Config().ElasticityMultiplier() header.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit) } } diff --git a/miner/worker.go b/miner/worker.go index 5e3c3f22b557..b38d68e7ea0c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1013,7 +1013,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { if w.chainConfig.IsLondon(header.Number) { header.BaseFee = misc.CalcBaseFee(w.chainConfig, parent.Header()) if !w.chainConfig.IsLondon(parent.Number()) { - parentGasLimit := parent.GasLimit() * params.ElasticityMultiplier + parentGasLimit := parent.GasLimit() * w.chainConfig.ElasticityMultiplier() header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) } } diff --git a/params/config.go b/params/config.go index 22b36b7d68e3..e3e48f9c2597 100644 --- a/params/config.go +++ b/params/config.go @@ -709,6 +709,16 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi return nil } +// BaseFeeChangeDenominator bounds the amount the base fee can change between blocks. +func (c *ChainConfig) BaseFeeChangeDenominator() uint64 { + return DefaultBaseFeeChangeDenominator +} + +// ElasticityMultiplier bounds the maximum gas limit an EIP-1559 block may have. +func (c *ChainConfig) ElasticityMultiplier() uint64 { + return DefaultElasticityMultiplier +} + // isForkIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to // block s2 because head is already past the fork. func isForkIncompatible(s1, s2, head *big.Int) bool { diff --git a/params/protocol_params.go b/params/protocol_params.go index 5f154597a7fa..b0037fd471c4 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -119,9 +119,9 @@ const ( // Introduced in Tangerine Whistle (Eip 150) CreateBySelfdestructGas uint64 = 25000 - BaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks. - ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. - InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. + DefaultBaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks. + DefaultElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. + InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. MaxCodeSize = 24576 // Maximum bytecode to permit for a contract From 6d55908347cac7463dd6a2cb236f30ec26c9a121 Mon Sep 17 00:00:00 2001 From: Obtuse7772 <117080049+Obtuse7772@users.noreply.github.com> Date: Fri, 4 Nov 2022 20:58:12 +0530 Subject: [PATCH 348/715] signer/core/apitypes: support more input types for eip-712 encoding (#26074) * apitypes: synchronize handling of types * signer/core/apitypes: improve array check * apitypes: add a test for big.Int -> int32 * signer/core/apitypes: Add a test for parsing addresses from [20]byte, []byte and string * signer/core/apitypes: add some testcases Co-authored-by: Felix Lange Co-authored-by: Martin Holst Swende --- .../apitypes/signed_data_internal_test.go | 54 +++++++++++++++++++ signer/core/apitypes/types.go | 32 ++++++++--- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/signer/core/apitypes/signed_data_internal_test.go b/signer/core/apitypes/signed_data_internal_test.go index 121cc00dec85..8379c0a7f075 100644 --- a/signer/core/apitypes/signed_data_internal_test.go +++ b/signer/core/apitypes/signed_data_internal_test.go @@ -21,6 +21,7 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -84,6 +85,55 @@ func TestBytesPadding(t *testing.T) { } } +func TestParseAddress(t *testing.T) { + tests := []struct { + Input interface{} + Output []byte // nil => error + }{ + { + Input: [20]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14}, + Output: common.FromHex("0x0000000000000000000000000102030405060708090A0B0C0D0E0F1011121314"), + }, + { + Input: "0x0102030405060708090A0B0C0D0E0F1011121314", + Output: common.FromHex("0x0000000000000000000000000102030405060708090A0B0C0D0E0F1011121314"), + }, + { + Input: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14}, + Output: common.FromHex("0x0000000000000000000000000102030405060708090A0B0C0D0E0F1011121314"), + }, + // Various error-cases: + {Input: "0x000102030405060708090A0B0C0D0E0F1011121314"}, // too long string + {Input: "0x01"}, // too short string + {Input: ""}, + {Input: [32]byte{}}, // too long fixed-size array + {Input: [21]byte{}}, // too long fixed-size array + {Input: make([]byte, 19)}, // too short slice + {Input: make([]byte, 21)}, // too long slice + {Input: nil}, + } + + d := TypedData{} + for i, test := range tests { + val, err := d.EncodePrimitiveValue("address", test.Input, 1) + if test.Output == nil { + if err == nil { + t.Errorf("test %d: expected error, got no error (result %x)", i, val) + } + continue + } + if err != nil { + t.Errorf("test %d: expected no error, got %v", i, err) + } + if have, want := len(val), 32; have != want { + t.Errorf("test %d: have len %d, want %d", i, have, want) + } + if !bytes.Equal(val, test.Output) { + t.Errorf("test %d: want %x, have %x", i, test.Output, val) + } + } +} + func TestParseBytes(t *testing.T) { for i, tt := range []struct { v interface{} @@ -98,6 +148,9 @@ func TestParseBytes(t *testing.T) { {"not a hex string", nil}, {15, nil}, {nil, nil}, + {[2]byte{12, 34}, []byte{12, 34}}, + {[8]byte{12, 34, 56, 78, 90, 12, 34, 56}, []byte{12, 34, 56, 78, 90, 12, 34, 56}}, + {[16]byte{12, 34, 56, 78, 90, 12, 34, 56, 12, 34, 56, 78, 90, 12, 34, 56}, []byte{12, 34, 56, 78, 90, 12, 34, 56, 12, 34, 56, 78, 90, 12, 34, 56}}, } { out, ok := parseBytes(tt.v) if tt.exp == nil { @@ -123,6 +176,7 @@ func TestParseInteger(t *testing.T) { }{ {"uint32", "-123", nil}, {"int32", "-123", big.NewInt(-123)}, + {"int32", big.NewInt(-124), big.NewInt(-124)}, {"uint32", "0xff", big.NewInt(0xff)}, {"int8", "0xffff", nil}, } { diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 2c8907ac822e..6e883b27c847 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -418,6 +418,14 @@ func (typedData *TypedData) EncodeData(primaryType string, data map[string]inter // Attempt to parse bytes in different formats: byte array, hex string, hexutil.Bytes. 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()) + reflect.Copy(v, val) + return v.Bytes(), true + } + switch v := encType.(type) { case []byte: return v, true @@ -458,6 +466,8 @@ func parseInteger(encType string, encValue interface{}) (*big.Int, error) { switch v := encValue.(type) { case *math.HexOrDecimal256: b = (*big.Int)(v) + case *big.Int: + b = v case string: var hexIntValue math.HexOrDecimal256 if err := hexIntValue.UnmarshalText([]byte(v)); err != nil { @@ -490,13 +500,23 @@ func parseInteger(encType string, encValue interface{}) (*big.Int, error) { func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interface{}, depth int) ([]byte, error) { switch encType { case "address": - stringValue, ok := encValue.(string) - if !ok || !common.IsHexAddress(stringValue) { - return nil, dataMismatchError(encType, encValue) - } retval := make([]byte, 32) - copy(retval[12:], common.HexToAddress(stringValue).Bytes()) - return retval, nil + switch val := encValue.(type) { + case string: + if common.IsHexAddress(val) { + copy(retval[12:], common.HexToAddress(val).Bytes()) + return retval, nil + } + case []byte: + if len(val) == 20 { + copy(retval[12:], val) + return retval, nil + } + case [20]byte: + copy(retval[12:], val[:]) + return retval, nil + } + return nil, dataMismatchError(encType, encValue) case "bool": boolValue, ok := encValue.(bool) if !ok { From 33e23ee37d181bff41692a6b3b826a8053ffd1cd Mon Sep 17 00:00:00 2001 From: "Saman H. Pasha" <51169592+saman-pasha@users.noreply.github.com> Date: Sat, 5 Nov 2022 00:33:34 +0330 Subject: [PATCH 349/715] accounts/abi.bind: don't fetch head in transact unless required (#25988) If GasFeeCap and GasTipCap are specified, we don't need to retrieve the head block for constructing a transaction --- accounts/abi/bind/base.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 88b997684a40..df3f52a403e7 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -373,6 +373,8 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i ) if opts.GasPrice != nil { rawTx, err = c.createLegacyTx(opts, contract, input) + } else if opts.GasFeeCap != nil && opts.GasTipCap != nil { + rawTx, err = c.createDynamicTx(opts, contract, input, nil) } else { // Only query for basefee if gasPrice not specified if head, errHead := c.transactor.HeaderByNumber(ensureContext(opts.Context), nil); errHead != nil { From 17744639dafc5a54f21e220660bd39d765a09051 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 6 Nov 2022 13:02:49 +0100 Subject: [PATCH 350/715] cmd/clef: add importraw feature to clef (#26058) This adds a subcommand that imports a raw secp256k1 key into the keystore managed by clef. --- cmd/clef/consolecmd_test.go | 117 ++++++++++++++++++++++++++++++++++++ cmd/clef/main.go | 84 +++++++++++++++++++++++--- cmd/clef/run_test.go | 109 +++++++++++++++++++++++++++++++++ 3 files changed, 303 insertions(+), 7 deletions(-) create mode 100644 cmd/clef/consolecmd_test.go create mode 100644 cmd/clef/run_test.go diff --git a/cmd/clef/consolecmd_test.go b/cmd/clef/consolecmd_test.go new file mode 100644 index 000000000000..283d7e8def3f --- /dev/null +++ b/cmd/clef/consolecmd_test.go @@ -0,0 +1,117 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "testing" +) + +// TestImportRaw tests clef --importraw +func TestImportRaw(t *testing.T) { + keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) + os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) + t.Cleanup(func() { os.Remove(keyPath) }) + + t.Parallel() + t.Run("happy-path", func(t *testing.T) { + // Run clef importraw + clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath) + clef.input("myverylongpassword").input("myverylongpassword") + if out := string(clef.Output()); !strings.Contains(out, + "Key imported:\n Address 0x9160DC9105f7De5dC5E7f3d97ef11DA47269BdA6") { + t.Logf("Output\n%v", out) + t.Error("Failure") + } + }) + // tests clef --importraw with mismatched passwords. + t.Run("pw-mismatch", func(t *testing.T) { + // Run clef importraw + clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath) + clef.input("myverylongpassword1").input("myverylongpassword2").WaitExit() + if have, want := clef.StderrText(), "Passwords do not match\n"; have != want { + t.Errorf("have %q, want %q", have, want) + } + }) + // tests clef --importraw with a too short password. + t.Run("short-pw", func(t *testing.T) { + // Run clef importraw + clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath) + clef.input("shorty").input("shorty").WaitExit() + if have, want := clef.StderrText(), + "password requirements not met: password too short (<10 characters)\n"; have != want { + t.Errorf("have %q, want %q", have, want) + } + }) +} + +// TestListAccounts tests clef --list-accounts +func TestListAccounts(t *testing.T) { + keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) + os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) + t.Cleanup(func() { os.Remove(keyPath) }) + + t.Parallel() + t.Run("no-accounts", func(t *testing.T) { + clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "list-accounts") + if out := string(clef.Output()); !strings.Contains(out, "The keystore is empty.") { + t.Logf("Output\n%v", out) + t.Error("Failure") + } + }) + t.Run("one-account", func(t *testing.T) { + // First, we need to import + clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath) + clef.input("myverylongpassword").input("myverylongpassword").WaitExit() + // Secondly, do a listing, using the same datadir + clef = runWithKeystore(t, clef.Datadir, "--suppress-bootwarn", "--lightkdf", "list-accounts") + if out := string(clef.Output()); !strings.Contains(out, "0x9160DC9105f7De5dC5E7f3d97ef11DA47269BdA6 (keystore:") { + t.Logf("Output\n%v", out) + t.Error("Failure") + } + }) +} + +// TestListWallets tests clef --list-wallets +func TestListWallets(t *testing.T) { + keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) + os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) + t.Cleanup(func() { os.Remove(keyPath) }) + + t.Parallel() + t.Run("no-accounts", func(t *testing.T) { + clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "list-wallets") + if out := string(clef.Output()); !strings.Contains(out, "There are no wallets.") { + t.Logf("Output\n%v", out) + t.Error("Failure") + } + }) + t.Run("one-account", func(t *testing.T) { + // First, we need to import + clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath) + clef.input("myverylongpassword").input("myverylongpassword").WaitExit() + // Secondly, do a listing, using the same datadir + clef = runWithKeystore(t, clef.Datadir, "--suppress-bootwarn", "--lightkdf", "list-wallets") + if out := string(clef.Output()); !strings.Contains(out, "Account 0: 0x9160DC9105f7De5dC5E7f3d97ef11DA47269BdA6") { + t.Logf("Output\n%v", out) + t.Error("Failure") + } + }) +} diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 188a11500004..be7089ce449e 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -23,6 +23,7 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + "errors" "fmt" "io" "math/big" @@ -74,7 +75,7 @@ PURPOSE. See the GNU General Public License for more details. var ( logLevelFlag = &cli.IntFlag{ Name: "loglevel", - Value: 4, + Value: 3, Usage: "log level to emit to the screen", } advancedMode = &cli.BoolFlag{ @@ -238,6 +239,23 @@ The gendoc generates example structures of the json-rpc communication types. Description: ` Lists the wallets known to Clef. `} + importRawCommand = &cli.Command{ + Action: accountImport, + Name: "importraw", + Usage: "Import a hex-encoded private key.", + ArgsUsage: "", + Flags: []cli.Flag{ + logLevelFlag, + keystoreFlag, + utils.LightKDFFlag, + acceptFlag, + }, + Description: ` +Imports an unencrypted private key from and creates a new account. +Prints the address. +The keyfile is assumed to contain an unencrypted private key in hexadecimal format. +The account is saved in encrypted format, you are prompted for a password. +`} ) var app = flags.NewApp("Manage Ethereum account operations") @@ -273,6 +291,7 @@ func init() { setCredentialCommand, delCredentialCommand, newAccountCommand, + importRawCommand, gendocCommand, listAccountsCommand, listWalletsCommand, @@ -378,9 +397,9 @@ func attestFile(ctx *cli.Context) error { return nil } -func initInternalApi(c *cli.Context) (*core.UIServerAPI, error) { +func initInternalApi(c *cli.Context) (*core.UIServerAPI, core.UIClientAPI, error) { if err := initialize(c); err != nil { - return nil, err + return nil, nil, err } var ( ui = core.NewCommandlineUI() @@ -391,7 +410,7 @@ func initInternalApi(c *cli.Context) (*core.UIServerAPI, error) { am := core.StartClefAccountManager(ksLoc, true, lightKdf, "") api := core.NewSignerAPI(am, 0, true, ui, nil, false, pwStorage) internalApi := core.NewUIServerAPI(api) - return internalApi, nil + return internalApi, ui, nil } func setCredential(ctx *cli.Context) error { @@ -478,7 +497,7 @@ func initialize(c *cli.Context) error { } func newAccount(c *cli.Context) error { - internalApi, err := initInternalApi(c) + internalApi, _, err := initInternalApi(c) if err != nil { return err } @@ -490,7 +509,7 @@ func newAccount(c *cli.Context) error { } func listAccounts(c *cli.Context) error { - internalApi, err := initInternalApi(c) + internalApi, _, err := initInternalApi(c) if err != nil { return err } @@ -509,7 +528,7 @@ func listAccounts(c *cli.Context) error { } func listWallets(c *cli.Context) error { - internalApi, err := initInternalApi(c) + internalApi, _, err := initInternalApi(c) if err != nil { return err } @@ -528,6 +547,57 @@ func listWallets(c *cli.Context) error { return nil } +// accountImport imports a raw hexadecimal private key via CLI. +func accountImport(c *cli.Context) error { + if c.Args().Len() != 1 { + return errors.New(" must be given as first argument.") + } + internalApi, ui, err := initInternalApi(c) + if err != nil { + return err + } + pKey, err := crypto.LoadECDSA(c.Args().First()) + if err != nil { + return err + } + readPw := func(prompt string) (string, error) { + resp, err := ui.OnInputRequired(core.UserInputRequest{ + Title: "Password", + Prompt: prompt, + IsPassword: true, + }) + if err != nil { + return "", err + } + return resp.Text, nil + } + first, err := readPw("Please enter a password for the imported account") + if err != nil { + return err + } + second, err := readPw("Please repeat the password you just entered") + if err != nil { + return err + } + if first != second { + return errors.New("Passwords do not match") + } + acc, err := internalApi.ImportRawKey(hex.EncodeToString(crypto.FromECDSA(pKey)), first) + if err != nil { + return err + } + ui.ShowInfo(fmt.Sprintf(`Key imported: + Address %v + Keystore file: %v + +The key is now encrypted; losing the password will result in permanently losing +access to the key and all associated funds! + +Make sure to backup keystore and passwords in a safe location.`, + acc.Address, acc.URL.Path)) + return nil +} + // ipcEndpoint resolves an IPC endpoint based on a configured value, taking into // account the set data folders as well as the designated platform we're currently // running on. diff --git a/cmd/clef/run_test.go b/cmd/clef/run_test.go new file mode 100644 index 000000000000..fc3145b1e0cd --- /dev/null +++ b/cmd/clef/run_test.go @@ -0,0 +1,109 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "fmt" + "os" + "testing" + + "github.com/docker/docker/pkg/reexec" + "github.com/ethereum/go-ethereum/internal/cmdtest" +) + +const registeredName = "clef-test" + +type testproc struct { + *cmdtest.TestCmd + + // template variables for expect + Datadir string + Etherbase string +} + +func init() { + reexec.Register(registeredName, func() { + if err := app.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + os.Exit(0) + }) +} + +func TestMain(m *testing.M) { + // check if we have been reexec'd + if reexec.Init() { + return + } + os.Exit(m.Run()) +} + +// runClef spawns clef with the given command line args and adds keystore arg. +// This method creates a temporary keystore folder which will be removed after +// the test exits. +func runClef(t *testing.T, args ...string) *testproc { + ddir, err := os.MkdirTemp("", "cleftest-*") + if err != nil { + return nil + } + t.Cleanup(func() { + os.RemoveAll(ddir) + }) + return runWithKeystore(t, ddir, args...) +} + +// runWithKeystore spawns clef with the given command line args and adds keystore arg. +// This method does _not_ create the keystore folder, but it _does_ add the arg +// to the args. +func runWithKeystore(t *testing.T, keystore string, args ...string) *testproc { + args = append([]string{"--keystore", keystore}, args...) + tt := &testproc{Datadir: keystore} + tt.TestCmd = cmdtest.NewTestCmd(t, tt) + // Boot "clef". This actually runs the test binary but the TestMain + // function will prevent any tests from running. + tt.Run(registeredName, args...) + return tt +} + +func (proc *testproc) input(text string) *testproc { + proc.TestCmd.InputLine(text) + return proc +} + +/* +// waitForEndpoint waits for the rpc endpoint to appear, or +// aborts after 3 seconds. +func (proc *testproc) waitForEndpoint(t *testing.T) *testproc { + t.Helper() + timeout := 3 * time.Second + ipc := filepath.Join(proc.Datadir, "clef.ipc") + + start := time.Now() + for time.Since(start) < timeout { + if _, err := os.Stat(ipc); !errors.Is(err, os.ErrNotExist) { + t.Logf("endpoint %v opened", ipc) + return proc + } + time.Sleep(200 * time.Millisecond) + } + t.Logf("stderr: \n%v", proc.StderrText()) + t.Logf("stdout: \n%v", proc.Output()) + t.Fatal("endpoint", ipc, "did not open within", timeout) + return proc +} +*/ From 111ed1af1b2fbd936e5fb4b0d685f509b2e6f6a6 Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Mon, 7 Nov 2022 07:58:00 -0500 Subject: [PATCH 351/715] accounts/abi: properly quote untrusted data in error message (#26110) * abi: Format data as hex-string instead of string(data) * Update accounts/abi/abi.go Co-authored-by: Martin Holst Swende --- accounts/abi/abi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 81bbee2f2b4a..841d3c6cb676 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -87,7 +87,7 @@ func (abi ABI) getArguments(name string, data []byte) (Arguments, error) { var args Arguments if method, ok := abi.Methods[name]; ok { if len(data)%32 != 0 { - return nil, fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(data), data) + return nil, fmt.Errorf("abi: improperly formatted output: %q - Bytes: %+v", data, data) } args = method.Outputs } From ca948b85790b25c710a0f7e93677a5d9ef059477 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 7 Nov 2022 15:30:54 +0100 Subject: [PATCH 352/715] eth/catalyst, miner: deduplicate work + show payload id (#26115) This PR now also includes a fix to the problem of mult-routines building blocks on the same input. This PR works as before with regards to stopping the work, but it just will not spin up a second routine if one is already building. So if the CL does N calls to FCU+buildblock, and N calls to GetPayload, only the first of each will do something, the other calls will be mostly no-ops. This PR also adds printout of the payload id into the logs. --- eth/catalyst/api.go | 22 ++++++---------------- eth/catalyst/api_test.go | 7 ++++++- eth/catalyst/queue.go | 16 ++++++++++++++++ miner/payload_building.go | 29 +++++++++++++++++++++++++---- 4 files changed, 53 insertions(+), 21 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 030a39837472..8dd71f48a7f8 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -18,8 +18,6 @@ package catalyst import ( - "crypto/sha256" - "encoding/binary" "errors" "fmt" "math/big" @@ -288,12 +286,17 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa FeeRecipient: payloadAttributes.SuggestedFeeRecipient, Random: payloadAttributes.Random, } + id := args.Id() + // If we already are busy generating this work, then we do not need + // to start a second process. + if api.localBlocks.has(id) { + return valid(&id), nil + } payload, err := api.eth.Miner().BuildPayload(args) if err != nil { log.Error("Failed to build payload", "err", err) return valid(nil), beacon.InvalidPayloadAttributes.With(err) } - id := computePayloadId(update.HeadBlockHash, payloadAttributes) api.localBlocks.put(id, payload) return valid(&id), nil } @@ -443,19 +446,6 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa return beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &hash}, nil } -// computePayloadId computes a pseudo-random payloadid, based on the parameters. -func computePayloadId(headBlockHash common.Hash, params *beacon.PayloadAttributesV1) beacon.PayloadID { - // Hash - hasher := sha256.New() - hasher.Write(headBlockHash[:]) - binary.Write(hasher, binary.BigEndian, params.Timestamp) - hasher.Write(params.Random[:]) - hasher.Write(params.SuggestedFeeRecipient[:]) - var out beacon.PayloadID - copy(out[:], hasher.Sum(nil)[:8]) - return out -} - // delayPayloadImport stashes the given block away for import at a later time, // either via a forkchoice update or a sync extension. This method is meant to // be called by the newpayload command when the block seems to be ok, but some diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 18750d6a0323..63f5d19cb9fc 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -184,7 +184,12 @@ func TestEth2PrepareAndGetPayload(t *testing.T) { } // give the payload some time to be built time.Sleep(100 * time.Millisecond) - payloadID := computePayloadId(fcState.HeadBlockHash, &blockParams) + payloadID := (&miner.BuildPayloadArgs{ + Parent: fcState.HeadBlockHash, + Timestamp: blockParams.Timestamp, + FeeRecipient: blockParams.SuggestedFeeRecipient, + Random: blockParams.Random, + }).Id() execData, err := api.GetPayloadV1(payloadID) if err != nil { t.Fatalf("error getting payload, err=%v", err) diff --git a/eth/catalyst/queue.go b/eth/catalyst/queue.go index 6863edfad1ae..c15799487f20 100644 --- a/eth/catalyst/queue.go +++ b/eth/catalyst/queue.go @@ -85,6 +85,22 @@ func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutableDataV1 { return nil } +// has checks if a particular payload is already tracked. +func (q *payloadQueue) has(id beacon.PayloadID) bool { + q.lock.RLock() + defer q.lock.RUnlock() + + for _, item := range q.payloads { + if item == nil { + return false + } + if item.id == id { + return true + } + } + return false +} + // headerQueueItem represents an hash->header tuple to store until it's retrieved // or evicted. type headerQueueItem struct { diff --git a/miner/payload_building.go b/miner/payload_building.go index cdea6a3cc368..2e3ebe356c59 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -17,6 +17,8 @@ package miner import ( + "crypto/sha256" + "encoding/binary" "math/big" "sync" "time" @@ -38,12 +40,26 @@ type BuildPayloadArgs struct { Random common.Hash // The provided randomness value } +// Id computes an 8-byte identifier by hashing the components of the payload arguments. +func (args *BuildPayloadArgs) Id() beacon.PayloadID { + // Hash + hasher := sha256.New() + hasher.Write(args.Parent[:]) + binary.Write(hasher, binary.BigEndian, args.Timestamp) + hasher.Write(args.Random[:]) + hasher.Write(args.FeeRecipient[:]) + var out beacon.PayloadID + copy(out[:], hasher.Sum(nil)[:8]) + return out +} + // Payload wraps the built payload(block waiting for sealing). According to the // engine-api specification, EL should build the initial version of the payload // which has an empty transaction set and then keep update it in order to maximize // the revenue. Therefore, the empty-block here is always available and full-block // will be set/updated afterwards. type Payload struct { + id beacon.PayloadID empty *types.Block full *types.Block fullFees *big.Int @@ -53,11 +69,13 @@ type Payload struct { } // newPayload initializes the payload object. -func newPayload(empty *types.Block) *Payload { +func newPayload(empty *types.Block, id beacon.PayloadID) *Payload { payload := &Payload{ + id: id, empty: empty, stop: make(chan struct{}), } + log.Info("Starting work on payload", "id", payload.id) payload.cond = sync.NewCond(&payload.lock) return payload } @@ -80,8 +98,9 @@ func (payload *Payload) update(block *types.Block, fees *big.Int, elapsed time.D payload.fullFees = fees feesInEther := new(big.Float).Quo(new(big.Float).SetInt(fees), big.NewFloat(params.Ether)) - log.Info("Updated payload", "number", block.NumberU64(), "hash", block.Hash(), - "txs", len(block.Transactions()), "gas", block.GasUsed(), "fees", feesInEther, "elapsed", common.PrettyDuration(elapsed)) + log.Info("Updated payload", "id", payload.id, "number", block.NumberU64(), "hash", block.Hash(), + "txs", len(block.Transactions()), "gas", block.GasUsed(), "fees", feesInEther, + "root", block.Root(), "elapsed", common.PrettyDuration(elapsed)) } payload.cond.Broadcast() // fire signal for notifying full block } @@ -139,7 +158,7 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { return nil, err } // Construct a payload object for return. - payload := newPayload(empty) + payload := newPayload(empty, args.Id()) // Spin up a routine for updating the payload in background. This strategy // can maximum the revenue for including transactions with highest fee. @@ -164,8 +183,10 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { } timer.Reset(w.recommit) case <-payload.stop: + log.Info("Stopping work on payload", "id", payload.id, "reason", "delivery") return case <-endTimer.C: + log.Info("Stopping work on payload", "id", payload.id, "reason", "timeout") return } } From 55a92fa0a4570ac2bd1774c7f7d8c52311863e32 Mon Sep 17 00:00:00 2001 From: Joseph Cook <33655003+jmcook1186@users.noreply.github.com> Date: Mon, 7 Nov 2022 15:41:36 +0000 Subject: [PATCH 353/715] cmd/clef: list accounts at startup (#26082) Reports accounts known to Clef during startup, after master seed is provided by the user. --- cmd/clef/main.go | 5 ++--- signer/core/cliui.go | 29 +++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/cmd/clef/main.go b/cmd/clef/main.go index be7089ce449e..7dc12a14ac61 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -707,6 +707,7 @@ func signer(c *cli.Context) error { // it with the UI. ui.RegisterUIServer(core.NewUIServerAPI(apiImpl)) api = apiImpl + // Audit logging if logfile := c.String(auditLogFlag.Name); logfile != "" { api, err = core.NewAuditLogger(logfile, api) @@ -768,7 +769,6 @@ func signer(c *cli.Context) error { log.Info("IPC endpoint closed", "url", ipcapiURL) }() } - if c.Bool(testFlag.Name) { log.Info("Performing UI test") go testExternalUI(apiImpl) @@ -779,8 +779,7 @@ func signer(c *cli.Context) error { "extapi_version": core.ExternalAPIVersion, "extapi_http": extapiURL, "extapi_ipc": ipcapiURL, - }, - }) + }}) abortChan := make(chan os.Signal, 1) signal.Notify(abortChan, os.Interrupt) diff --git a/signer/core/cliui.go b/signer/core/cliui.go index 187eb1390af7..6278e53c08a0 100644 --- a/signer/core/cliui.go +++ b/signer/core/cliui.go @@ -18,6 +18,7 @@ package core import ( "bufio" + "context" "encoding/json" "fmt" "os" @@ -31,8 +32,9 @@ import ( ) type CommandlineUI struct { - in *bufio.Reader - mu sync.Mutex + in *bufio.Reader + mu sync.Mutex + api *UIServerAPI } func NewCommandlineUI() *CommandlineUI { @@ -40,7 +42,7 @@ func NewCommandlineUI() *CommandlineUI { } func (ui *CommandlineUI) RegisterUIServer(api *UIServerAPI) { - // noop + ui.api = api } // readString reads a single line from stdin, trimming if from spaces, enforcing @@ -241,9 +243,28 @@ func (ui *CommandlineUI) OnApprovedTx(tx ethapi.SignTransactionResult) { } } +func (ui *CommandlineUI) showAccounts() { + accounts, err := ui.api.ListAccounts(context.Background()) + if err != nil { + log.Error("Error listing accounts", "err", err) + return + } + if len(accounts) == 0 { + fmt.Print("No accounts found\n") + return + } + var out = new(strings.Builder) + fmt.Fprint(out, "\n------- Available accounts -------\n") + for i, account := range accounts { + fmt.Fprintf(out, "%d. %s at %s\n", i, account.Address, account.URL) + } + fmt.Print(out.String()) +} + func (ui *CommandlineUI) OnSignerStartup(info StartupInfo) { - fmt.Printf("------- Signer info -------\n") + fmt.Print("\n------- Signer info -------\n") for k, v := range info.Info { fmt.Printf("* %v : %v\n", k, v) } + go ui.showAccounts() } From 9027ee0b45f14aae1f3a98f62f5353bf6807ad68 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 7 Nov 2022 19:19:02 +0100 Subject: [PATCH 354/715] p2p/discover: improve discv5 NODES response packing (#26033) Instead of using a limit of three nodes per message, we can pack more nodes into each message based on ENR size. In my testing, this halves the number of sent NODES messages, because ENR size is usually < 300 bytes. This also adds RLP helper functions that compute the encoded size of []byte and string. Co-authored-by: Martin Holst Swende --- p2p/discover/v5_udp.go | 26 ++++++++++++++++++-------- p2p/discover/v5_udp_test.go | 9 +++------ p2p/enr/enr.go | 18 ++++++++++++++++++ p2p/enr/enr_test.go | 31 ++++++++++++++++++++++++++++++- rlp/raw.go | 35 ++++++++++++++++++++++++++++++++++- rlp/raw_test.go | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 136 insertions(+), 16 deletions(-) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 1c66602f8791..321c5bd2a818 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -24,7 +24,6 @@ import ( "errors" "fmt" "io" - "math" "net" "sync" "time" @@ -41,7 +40,6 @@ const ( lookupRequestLimit = 3 // max requests against a single node during lookup findnodeResultLimit = 16 // applies in FINDNODE handler totalNodesResponseLimit = 5 // applies in waitForNodes - nodesResponseItemLimit = 3 // applies in sendNodes respTimeoutV5 = 700 * time.Millisecond ) @@ -832,17 +830,29 @@ func packNodes(reqid []byte, nodes []*enode.Node) []*v5wire.Nodes { return []*v5wire.Nodes{{ReqID: reqid, Total: 1}} } - total := uint8(math.Ceil(float64(len(nodes)) / 3)) + // This limit represents the available space for nodes in output packets. Maximum + // packet size is 1280, and out of this ~80 bytes will be taken up by the packet + // frame. So limiting to 1000 bytes here leaves 200 bytes for other fields of the + // NODES message, which is a lot. + const sizeLimit = 1000 + var resp []*v5wire.Nodes for len(nodes) > 0 { - p := &v5wire.Nodes{ReqID: reqid, Total: total} - items := min(nodesResponseItemLimit, len(nodes)) - for i := 0; i < items; i++ { - p.Nodes = append(p.Nodes, nodes[i].Record()) + p := &v5wire.Nodes{ReqID: reqid} + size := uint64(0) + for len(nodes) > 0 { + r := nodes[0].Record() + if size += r.Size(); size > sizeLimit { + break + } + p.Nodes = append(p.Nodes, r) + nodes = nodes[1:] } - nodes = nodes[items:] resp = append(resp, p) } + for _, msg := range resp { + msg.Total = uint8(len(resp)) + } return resp } diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index ca63688afa13..ab0cb9a8211c 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -161,7 +161,7 @@ func TestUDPv5_findnodeHandling(t *testing.T) { defer test.close() // Create test nodes and insert them into the table. - nodes253 := nodesAtDistance(test.table.self().ID(), 253, 10) + nodes253 := nodesAtDistance(test.table.self().ID(), 253, 16) nodes249 := nodesAtDistance(test.table.self().ID(), 249, 4) nodes248 := nodesAtDistance(test.table.self().ID(), 248, 10) fillTable(test.table, wrapNodes(nodes253)) @@ -186,7 +186,7 @@ func TestUDPv5_findnodeHandling(t *testing.T) { // This request gets all the distance-253 nodes. test.packetIn(&v5wire.Findnode{ReqID: []byte{4}, Distances: []uint{253}}) - test.expectNodes([]byte{4}, 4, nodes253) + test.expectNodes([]byte{4}, 1, nodes253) // This request gets all the distance-249 nodes and some more at 248 because // the bucket at 249 is not full. @@ -194,7 +194,7 @@ func TestUDPv5_findnodeHandling(t *testing.T) { var nodes []*enode.Node nodes = append(nodes, nodes249...) nodes = append(nodes, nodes248[:10]...) - test.expectNodes([]byte{5}, 5, nodes) + test.expectNodes([]byte{5}, 1, nodes) } func (test *udpV5Test) expectNodes(wantReqID []byte, wantTotal uint8, wantNodes []*enode.Node) { @@ -208,9 +208,6 @@ func (test *udpV5Test) expectNodes(wantReqID []byte, wantTotal uint8, wantNodes if !bytes.Equal(p.ReqID, wantReqID) { test.t.Fatalf("wrong request ID %v in response, want %v", p.ReqID, wantReqID) } - if len(p.Nodes) > 3 { - test.t.Fatalf("too many nodes in response") - } if p.Total != wantTotal { test.t.Fatalf("wrong total response count %d, want %d", p.Total, wantTotal) } diff --git a/p2p/enr/enr.go b/p2p/enr/enr.go index 438c7b8a3b36..2b093b2f1ab1 100644 --- a/p2p/enr/enr.go +++ b/p2p/enr/enr.go @@ -96,6 +96,24 @@ type pair struct { v rlp.RawValue } +// Size returns the encoded size of the record. +func (r *Record) Size() uint64 { + if r.raw != nil { + return uint64(len(r.raw)) + } + return computeSize(r) +} + +func computeSize(r *Record) uint64 { + size := uint64(rlp.IntSize(r.seq)) + size += rlp.BytesSize(r.signature) + for _, p := range r.pairs { + size += rlp.StringSize(p.k) + size += uint64(len(p.v)) + } + return rlp.ListSize(size) +} + // Seq returns the sequence number. func (r *Record) Seq() uint64 { return r.seq diff --git a/p2p/enr/enr_test.go b/p2p/enr/enr_test.go index bf3f1047440e..b85ee209d591 100644 --- a/p2p/enr/enr_test.go +++ b/p2p/enr/enr_test.go @@ -169,6 +169,32 @@ func TestDirty(t *testing.T) { } } +func TestSize(t *testing.T) { + var r Record + + // Empty record size is 3 bytes. + // Unsigned records cannot be encoded, but they could, the encoding + // would be [ 0, 0 ] -> 0xC28080. + assert.Equal(t, uint64(3), r.Size()) + + // Add one attribute. The size increases to 5, the encoding + // would be [ 0, 0, "k", "v" ] -> 0xC58080C26B76. + r.Set(WithEntry("k", "v")) + assert.Equal(t, uint64(5), r.Size()) + + // Now add a signature. + nodeid := []byte{1, 2, 3, 4, 5, 6, 7, 8} + signTest(nodeid, &r) + assert.Equal(t, uint64(45), r.Size()) + enc, _ := rlp.EncodeToBytes(&r) + if r.Size() != uint64(len(enc)) { + t.Error("Size() not equal encoded length", len(enc)) + } + if r.Size() != computeSize(&r) { + t.Error("Size() not equal computed size", computeSize(&r)) + } +} + func TestSeq(t *testing.T) { var r Record @@ -268,8 +294,11 @@ func TestSignEncodeAndDecodeRandom(t *testing.T) { } require.NoError(t, signTest([]byte{5}, &r)) - _, err := rlp.EncodeToBytes(r) + + enc, err := rlp.EncodeToBytes(r) require.NoError(t, err) + require.Equal(t, uint64(len(enc)), r.Size()) + require.Equal(t, uint64(len(enc)), computeSize(&r)) for k, v := range pairs { desc := fmt.Sprintf("key %q", k) diff --git a/rlp/raw.go b/rlp/raw.go index f355efc144df..773aa7e614e8 100644 --- a/rlp/raw.go +++ b/rlp/raw.go @@ -28,13 +28,46 @@ type RawValue []byte var rawValueType = reflect.TypeOf(RawValue{}) +// StringSize returns the encoded size of a string. +func StringSize(s string) uint64 { + switch { + case len(s) == 0: + return 1 + case len(s) == 1: + if s[0] <= 0x7f { + return 1 + } else { + return 2 + } + default: + return uint64(headsize(uint64(len(s))) + len(s)) + } +} + +// BytesSize returns the encoded size of a byte slice. +func BytesSize(b []byte) uint64 { + switch { + case len(b) == 0: + return 1 + case len(b) == 1: + if b[0] <= 0x7f { + return 1 + } else { + return 2 + } + default: + return uint64(headsize(uint64(len(b))) + len(b)) + } +} + // ListSize returns the encoded size of an RLP list with the given // content size. func ListSize(contentSize uint64) uint64 { return uint64(headsize(contentSize)) + contentSize } -// IntSize returns the encoded size of the integer x. +// IntSize returns the encoded size of the integer x. Note: The return type of this +// function is 'int' for backwards-compatibility reasons. The result is always positive. func IntSize(x uint64) int { if x < 0x80 { return 1 diff --git a/rlp/raw_test.go b/rlp/raw_test.go index 46adff22c5da..2812ef74c622 100644 --- a/rlp/raw_test.go +++ b/rlp/raw_test.go @@ -283,3 +283,36 @@ func TestAppendUint64Random(t *testing.T) { t.Fatal(err) } } + +func TestBytesSize(t *testing.T) { + tests := []struct { + v []byte + size uint64 + }{ + {v: []byte{}, size: 1}, + {v: []byte{0x1}, size: 1}, + {v: []byte{0x7E}, size: 1}, + {v: []byte{0x7F}, size: 1}, + {v: []byte{0x80}, size: 2}, + {v: []byte{0xFF}, size: 2}, + {v: []byte{0xFF, 0xF0}, size: 3}, + {v: make([]byte, 55), size: 56}, + {v: make([]byte, 56), size: 58}, + } + + for _, test := range tests { + s := BytesSize(test.v) + if s != test.size { + t.Errorf("BytesSize(%#x) -> %d, want %d", test.v, s, test.size) + } + s = StringSize(string(test.v)) + if s != test.size { + t.Errorf("StringSize(%#x) -> %d, want %d", test.v, s, test.size) + } + // Sanity check: + enc, _ := EncodeToBytes(test.v) + if uint64(len(enc)) != test.size { + t.Errorf("len(EncodeToBytes(%#x)) -> %d, test says %d", test.v, len(enc), test.size) + } + } +} From 055528ae05723b075ecb0665c4305283817656b9 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 7 Nov 2022 20:47:04 +0100 Subject: [PATCH 355/715] cmd/devp2p/internal/ethtest: add support for eth/68 (#26078) Co-authored-by: Felix Lange --- cmd/devp2p/internal/ethtest/helpers.go | 5 ++- cmd/devp2p/internal/ethtest/suite.go | 25 ++++++++----- cmd/devp2p/internal/ethtest/transaction.go | 41 ++++++++++++++++++++-- cmd/devp2p/internal/ethtest/types.go | 17 +++++++-- 4 files changed, 73 insertions(+), 15 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/helpers.go b/cmd/devp2p/internal/ethtest/helpers.go index b57649ade99d..70ed2d2106dd 100644 --- a/cmd/devp2p/internal/ethtest/helpers.go +++ b/cmd/devp2p/internal/ethtest/helpers.go @@ -63,8 +63,9 @@ func (s *Suite) dial() (*Conn, error) { conn.caps = []p2p.Cap{ {Name: "eth", Version: 66}, {Name: "eth", Version: 67}, + {Name: "eth", Version: 68}, } - conn.ourHighestProtoVersion = 67 + conn.ourHighestProtoVersion = 68 return &conn, nil } @@ -359,6 +360,8 @@ func (s *Suite) waitAnnounce(conn *Conn, blockAnnouncement *NewBlock) error { return nil // ignore tx announcements from previous tests + case *NewPooledTransactionHashes66: + continue case *NewPooledTransactionHashes: continue case *Transactions: diff --git a/cmd/devp2p/internal/ethtest/suite.go b/cmd/devp2p/internal/ethtest/suite.go index 4497478d72d6..815353be7265 100644 --- a/cmd/devp2p/internal/ethtest/suite.go +++ b/cmd/devp2p/internal/ethtest/suite.go @@ -510,17 +510,18 @@ func (s *Suite) TestNewPooledTxs(t *utesting.T) { } // generate 50 txs - hashMap, _, err := generateTxs(s, 50) + _, txs, err := generateTxs(s, 50) if err != nil { t.Fatalf("failed to generate transactions: %v", err) } - - // create new pooled tx hashes announcement - hashes := make([]common.Hash, 0) - for _, hash := range hashMap { - hashes = append(hashes, hash) + hashes := make([]common.Hash, len(txs)) + types := make([]byte, len(txs)) + sizes := make([]uint32, len(txs)) + for i, tx := range txs { + hashes[i] = tx.Hash() + types[i] = tx.Type() + sizes[i] = uint32(tx.Size()) } - announce := NewPooledTransactionHashes(hashes) // send announcement conn, err := s.dial() @@ -531,7 +532,13 @@ func (s *Suite) TestNewPooledTxs(t *utesting.T) { if err = conn.peer(s.chain, nil); err != nil { t.Fatalf("peering failed: %v", err) } - if err = conn.Write(announce); err != nil { + + var ann Message = NewPooledTransactionHashes{Types: types, Sizes: sizes, Hashes: hashes} + if conn.negotiatedProtoVersion < eth.ETH68 { + ann = NewPooledTransactionHashes66(hashes) + } + err = conn.Write(ann) + if err != nil { t.Fatalf("failed to write to connection: %v", err) } @@ -546,6 +553,8 @@ func (s *Suite) TestNewPooledTxs(t *utesting.T) { return // ignore propagated txs from previous tests + case *NewPooledTransactionHashes66: + continue case *NewPooledTransactionHashes: continue case *Transactions: diff --git a/cmd/devp2p/internal/ethtest/transaction.go b/cmd/devp2p/internal/ethtest/transaction.go index baa55bd49268..bf3a4b7f063f 100644 --- a/cmd/devp2p/internal/ethtest/transaction.go +++ b/cmd/devp2p/internal/ethtest/transaction.go @@ -95,7 +95,7 @@ func sendSuccessfulTx(s *Suite, tx *types.Transaction, prevTx *types.Transaction } } return fmt.Errorf("missing transaction: got %v missing %v", recTxs, tx.Hash()) - case *NewPooledTransactionHashes: + case *NewPooledTransactionHashes66: txHashes := *msg // if you receive an old tx propagation, read from connection again if len(txHashes) == 1 && prevTx != nil { @@ -110,6 +110,34 @@ func sendSuccessfulTx(s *Suite, tx *types.Transaction, prevTx *types.Transaction } } return fmt.Errorf("missing transaction announcement: got %v missing %v", txHashes, tx.Hash()) + case *NewPooledTransactionHashes: + txHashes := msg.Hashes + if len(txHashes) != len(msg.Sizes) { + return fmt.Errorf("invalid msg size lengths: hashes: %v sizes: %v", len(txHashes), len(msg.Sizes)) + } + if len(txHashes) != len(msg.Types) { + return fmt.Errorf("invalid msg type lengths: hashes: %v types: %v", len(txHashes), len(msg.Types)) + } + // if you receive an old tx propagation, read from connection again + if len(txHashes) == 1 && prevTx != nil { + if txHashes[0] == prevTx.Hash() { + continue + } + } + for index, gotHash := range txHashes { + if gotHash == tx.Hash() { + if msg.Sizes[index] != uint32(tx.Size()) { + return fmt.Errorf("invalid tx size: got %v want %v", msg.Sizes[index], tx.Size()) + } + if msg.Types[index] != tx.Type() { + return fmt.Errorf("invalid tx type: got %v want %v", msg.Types[index], tx.Type()) + } + // Ok + return nil + } + } + return fmt.Errorf("missing transaction announcement: got %v missing %v", txHashes, tx.Hash()) + default: return fmt.Errorf("unexpected message in sendSuccessfulTx: %s", pretty.Sdump(msg)) } @@ -201,8 +229,10 @@ func sendMultipleSuccessfulTxs(t *utesting.T, s *Suite, txs []*types.Transaction for _, tx := range *msg { recvHashes = append(recvHashes, tx.Hash()) } - case *NewPooledTransactionHashes: + case *NewPooledTransactionHashes66: recvHashes = append(recvHashes, *msg...) + case *NewPooledTransactionHashes: + recvHashes = append(recvHashes, msg.Hashes...) default: if !strings.Contains(pretty.Sdump(msg), "i/o timeout") { return fmt.Errorf("unexpected message while waiting to receive txs: %s", pretty.Sdump(msg)) @@ -246,11 +276,16 @@ func checkMaliciousTxPropagation(s *Suite, txs []*types.Transaction, conn *Conn) if len(badTxs) > 0 { return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs) } - case *NewPooledTransactionHashes: + case *NewPooledTransactionHashes66: badTxs, _ := compareReceivedTxs(*msg, txs) if len(badTxs) > 0 { return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs) } + case *NewPooledTransactionHashes: + badTxs, _ := compareReceivedTxs(msg.Hashes, txs) + if len(badTxs) > 0 { + return fmt.Errorf("received %d bad txs: \n%v", len(badTxs), badTxs) + } case *Error: // Transaction should not be announced -> wait for timeout return nil diff --git a/cmd/devp2p/internal/ethtest/types.go b/cmd/devp2p/internal/ethtest/types.go index fd5251d161f3..3c7b6dbcf1b6 100644 --- a/cmd/devp2p/internal/ethtest/types.go +++ b/cmd/devp2p/internal/ethtest/types.go @@ -126,8 +126,14 @@ type NewBlock eth.NewBlockPacket func (msg NewBlock) Code() int { return 23 } func (msg NewBlock) ReqID() uint64 { return 0 } +// NewPooledTransactionHashes66 is the network packet for the tx hash propagation message. +type NewPooledTransactionHashes66 eth.NewPooledTransactionHashesPacket66 + +func (msg NewPooledTransactionHashes66) Code() int { return 24 } +func (msg NewPooledTransactionHashes66) ReqID() uint64 { return 0 } + // NewPooledTransactionHashes is the network packet for the tx hash propagation message. -type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket66 +type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket68 func (msg NewPooledTransactionHashes) Code() int { return 24 } func (msg NewPooledTransactionHashes) ReqID() uint64 { return 0 } @@ -202,8 +208,13 @@ func (c *Conn) Read() Message { msg = new(NewBlockHashes) case (Transactions{}).Code(): msg = new(Transactions) - case (NewPooledTransactionHashes{}).Code(): - msg = new(NewPooledTransactionHashes) + case (NewPooledTransactionHashes66{}).Code(): + // Try decoding to eth68 + ethMsg := new(NewPooledTransactionHashes) + if err := rlp.DecodeBytes(rawData, ethMsg); err == nil { + return ethMsg + } + msg = new(NewPooledTransactionHashes66) case (GetPooledTransactions{}.Code()): ethMsg := new(eth.GetPooledTransactionsPacket66) if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { From d629e0204799f2f7109fd52aa245e852c2e4f921 Mon Sep 17 00:00:00 2001 From: Marcin Sobczak <77129288+marcindsobczak@users.noreply.github.com> Date: Mon, 7 Nov 2022 22:46:21 +0100 Subject: [PATCH 356/715] cmd/devp2p/internal/v4test: ignore FINDNODE in BondThenPingWithWrongFrom (#26085) This fixes a race in the test. Co-authored-by: Felix Lange --- cmd/devp2p/internal/v4test/discv4tests.go | 24 +++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/cmd/devp2p/internal/v4test/discv4tests.go b/cmd/devp2p/internal/v4test/discv4tests.go index cf727dcf8713..7b818a52f9c5 100644 --- a/cmd/devp2p/internal/v4test/discv4tests.go +++ b/cmd/devp2p/internal/v4test/discv4tests.go @@ -256,6 +256,7 @@ func WrongPacketType(t *utesting.T) { func BondThenPingWithWrongFrom(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) defer te.close() + bond(t, te) wrongEndpoint := v4wire.Endpoint{IP: net.ParseIP("192.0.2.0")} @@ -265,10 +266,25 @@ func BondThenPingWithWrongFrom(t *utesting.T) { To: te.remoteEndpoint(), Expiration: futureExpiration(), }) - if reply, _, err := te.read(te.l1); err != nil { - t.Fatal(err) - } else if err := te.checkPong(reply, pingHash); err != nil { - t.Fatal(err) + +waitForPong: + for { + reply, _, err := te.read(te.l1) + if err != nil { + t.Fatal(err) + } + switch reply.Kind() { + case v4wire.PongPacket: + if err := te.checkPong(reply, pingHash); err != nil { + t.Fatal(err) + } + break waitForPong + case v4wire.FindnodePacket: + // FINDNODE from the node is acceptable here since the endpoint + // verification was performed earlier. + default: + t.Fatalf("Expected PONG, got %v %v", reply.Name(), reply) + } } } From 53b624b56d4f36c90ebf8046bd1ca78c87a3b6df Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 8 Nov 2022 12:46:52 +0330 Subject: [PATCH 357/715] eth/tracers: add multiplexing tracer (#26086) * eth/tracers: add native multiplexing tracer * minor improv callTracer * mv evm cancellation to api --- eth/tracers/api.go | 6 +- eth/tracers/logger/logger.go | 1 - eth/tracers/native/4byte.go | 4 - eth/tracers/native/call.go | 13 ++-- eth/tracers/native/mux.go | 139 +++++++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 eth/tracers/native/mux.go diff --git a/eth/tracers/api.go b/eth/tracers/api.go index c0d9dfb061f2..eb24760afd4a 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -911,6 +911,8 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex return nil, err } } + vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) + // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { if timeout, err = time.ParseDuration(*config.Timeout); err != nil { @@ -922,12 +924,12 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex <-deadlineCtx.Done() if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) { tracer.Stop(errors.New("execution timeout")) + // Stop evm execution. Note cancellation is not necessarily immediate. + vmenv.Cancel() } }() defer cancel() - // Run the transaction with tracing enabled. - vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) // Call Prepare to clear out the statedb access list statedb.Prepare(txctx.TxHash, txctx.TxIndex) if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())); err != nil { diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 07aa2f2b4301..ce774270e127 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -151,7 +151,6 @@ func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common. func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { // If tracing was interrupted, set the error and stop if atomic.LoadUint32(&l.interrupt) > 0 { - l.env.Cancel() return } // check if already accumulated the specified number of logs diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 29f3bccb1a56..d9b52b184c72 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -47,7 +47,6 @@ func init() { // 0xc281d19e-0: 1 // } type fourByteTracer struct { - env *vm.EVM ids map[string]int // ids aggregates the 4byte ids found interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption @@ -81,8 +80,6 @@ func (t *fourByteTracer) store(id []byte, size int) { // CaptureStart implements the EVMLogger interface to initialize the tracing operation. func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.env = env - // Update list of precompiles based on current block rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) t.activePrecompiles = vm.ActivePrecompiles(rules) @@ -101,7 +98,6 @@ func (t *fourByteTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { // Skip if tracing was interrupted if atomic.LoadUint32(&t.interrupt) > 0 { - t.env.Cancel() return } if len(input) < 4 { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 34f88126bad4..2d19c6fdb8dc 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -67,7 +67,7 @@ func (f callFrame) failed() bool { return len(f.Error) > 0 } -func (f *callFrame) capture(output []byte, err error) { +func (f *callFrame) processOutput(output []byte, err error) { output = common.CopyBytes(output) if err == nil { f.Output = output @@ -99,7 +99,6 @@ type callFrameMarshaling struct { } type callTracer struct { - env *vm.EVM callstack []callFrame config callTracerConfig gasLimit uint64 @@ -128,7 +127,6 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, e // CaptureStart implements the EVMLogger interface to initialize the tracing operation. func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - t.env = env t.callstack[0] = callFrame{ Type: vm.CALL, From: from, @@ -144,7 +142,7 @@ func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad // CaptureEnd is called after the call finishes to finalize the tracing. func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { - t.callstack[0].capture(output, err) + t.callstack[0].processOutput(output, err) } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. @@ -157,6 +155,10 @@ func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco if t.config.OnlyTopCall && depth > 0 { return } + // Skip if tracing was interrupted + if atomic.LoadUint32(&t.interrupt) > 0 { + return + } switch op { case vm.LOG0, vm.LOG1, vm.LOG2, vm.LOG3, vm.LOG4: size := int(op - vm.LOG0) @@ -190,7 +192,6 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. } // Skip if tracing was interrupted if atomic.LoadUint32(&t.interrupt) > 0 { - t.env.Cancel() return } @@ -221,7 +222,7 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { size -= 1 call.GasUsed = gasUsed - call.capture(output, err) + call.processOutput(output, err) t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go new file mode 100644 index 000000000000..05b5e3d808b6 --- /dev/null +++ b/eth/tracers/native/mux.go @@ -0,0 +1,139 @@ +// Copyright 2022 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 native + +import ( + "encoding/json" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" +) + +func init() { + register("muxTracer", newMuxTracer) +} + +// muxTracer is a go implementation of the Tracer interface which +// runs multiple tracers in one go. +type muxTracer struct { + names []string + tracers []tracers.Tracer +} + +// newMuxTracer returns a new mux tracer. +func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { + var config map[string]json.RawMessage + if cfg != nil { + if err := json.Unmarshal(cfg, &config); err != nil { + return nil, err + } + } + objects := make([]tracers.Tracer, 0, len(config)) + names := make([]string, 0, len(config)) + for k, v := range config { + t, err := tracers.New(k, ctx, v) + if err != nil { + return nil, err + } + objects = append(objects, t) + names = append(names, k) + } + + return &muxTracer{names: names, tracers: objects}, nil +} + +// CaptureStart implements the EVMLogger interface to initialize the tracing operation. +func (t *muxTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { + for _, t := range t.tracers { + t.CaptureStart(env, from, to, create, input, gas, value) + } +} + +// CaptureEnd is called after the call finishes to finalize the tracing. +func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, elapsed time.Duration, err error) { + for _, t := range t.tracers { + t.CaptureEnd(output, gasUsed, elapsed, err) + } +} + +// CaptureState implements the EVMLogger interface to trace a single step of VM execution. +func (t *muxTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + for _, t := range t.tracers { + t.CaptureState(pc, op, gas, cost, scope, rData, depth, err) + } +} + +// CaptureFault implements the EVMLogger interface to trace an execution fault. +func (t *muxTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { + for _, t := range t.tracers { + t.CaptureFault(pc, op, gas, cost, scope, depth, err) + } +} + +// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + for _, t := range t.tracers { + t.CaptureEnter(typ, from, to, input, gas, value) + } +} + +// CaptureExit is called when EVM exits a scope, even if the scope didn't +// execute any code. +func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error) { + for _, t := range t.tracers { + t.CaptureExit(output, gasUsed, err) + } +} + +func (t *muxTracer) CaptureTxStart(gasLimit uint64) { + for _, t := range t.tracers { + t.CaptureTxStart(gasLimit) + } +} + +func (t *muxTracer) CaptureTxEnd(restGas uint64) { + for _, t := range t.tracers { + t.CaptureTxEnd(restGas) + } +} + +// GetResult returns an empty json object. +func (t *muxTracer) GetResult() (json.RawMessage, error) { + resObject := make(map[string]json.RawMessage) + for i, tt := range t.tracers { + r, err := tt.GetResult() + if err != nil { + return nil, err + } + resObject[t.names[i]] = r + } + res, err := json.Marshal(resObject) + if err != nil { + return nil, err + } + return res, nil +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (t *muxTracer) Stop(err error) { + for _, t := range t.tracers { + t.Stop(err) + } +} From 4cb1fca43d6b49c879a6f82280df1766eceace4c Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 8 Nov 2022 19:12:36 +0800 Subject: [PATCH 358/715] p2p/enode: implement per-source timeout in FairMix (#25962) Co-authored-by: Felix Lange --- p2p/enode/iter.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/p2p/enode/iter.go b/p2p/enode/iter.go index 664964f53406..b8ab4a758aee 100644 --- a/p2p/enode/iter.go +++ b/p2p/enode/iter.go @@ -203,27 +203,34 @@ func (m *FairMix) Close() { func (m *FairMix) Next() bool { m.cur = nil - var timeout <-chan time.Time - if m.timeout >= 0 { - timer := time.NewTimer(m.timeout) - timeout = timer.C - defer timer.Stop() - } for { source := m.pickSource() if source == nil { return m.nextFromAny() } + + var timeout <-chan time.Time + if source.timeout >= 0 { + timer := time.NewTimer(source.timeout) + timeout = timer.C + defer timer.Stop() + } + select { case n, ok := <-source.next: if ok { - m.cur = n + // Here, the timeout is reset to the configured value + // because the source delivered a node. source.timeout = m.timeout + m.cur = n return true } // This source has ended. m.deleteSource(source) case <-timeout: + // The selected source did not deliver a node within the timeout, so the + // timeout duration is halved for next time. This is supposed to improve + // latency with stuck sources. source.timeout /= 2 return m.nextFromAny() } From a609e7b81fbf360745b06a35227da52cc50c2d1b Mon Sep 17 00:00:00 2001 From: Mark Tyneway Date: Tue, 8 Nov 2022 03:14:11 -0800 Subject: [PATCH 359/715] common/types: add `Address.Big` (#26132) Many of the other types have a function to convert the type to a big.Int, but Address was missing this function. It is useful to be able to turn an Address into a big.Int when doing EVM-like computations natively in Go. Sometimes a Solidity address type is casted to a uint256 and having a Big method on the Address type makes this easy. --- common/types.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/types.go b/common/types.go index 2205835cb5d0..218ca0be4c44 100644 --- a/common/types.go +++ b/common/types.go @@ -231,6 +231,9 @@ func (a Address) Bytes() []byte { return a[:] } // Hash converts an address to a hash by left-padding it with zeros. func (a Address) Hash() Hash { return BytesToHash(a[:]) } +// Big converts an address to a big integer. +func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) } + // Hex returns an EIP55-compliant hex string representation of the address. func (a Address) Hex() string { return string(a.checksumHex()) From 913973436bb88b652faffc10d8f97e4c19722883 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 8 Nov 2022 12:15:32 +0100 Subject: [PATCH 360/715] cmd/devp2p: add more nodekey commands (#26129) This adds new commands to turn a node key file into signed ENR / node ID. --- cmd/devp2p/keycmd.go | 73 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/cmd/devp2p/keycmd.go b/cmd/devp2p/keycmd.go index e824abe653e2..f409057fe043 100644 --- a/cmd/devp2p/keycmd.go +++ b/cmd/devp2p/keycmd.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" "github.com/urfave/cli/v2" ) @@ -31,7 +32,9 @@ var ( Usage: "Operations on node keys", Subcommands: []*cli.Command{ keyGenerateCommand, + keyToIDCommand, keyToNodeCommand, + keyToRecordCommand, }, } keyGenerateCommand = &cli.Command{ @@ -40,6 +43,13 @@ var ( ArgsUsage: "keyfile", Action: genkey, } + keyToIDCommand = &cli.Command{ + Name: "to-id", + Usage: "Creates a node ID from a node key file", + ArgsUsage: "keyfile", + Action: keyToID, + Flags: []cli.Flag{}, + } keyToNodeCommand = &cli.Command{ Name: "to-enode", Usage: "Creates an enode URL from a node key file", @@ -47,6 +57,13 @@ var ( Action: keyToURL, Flags: []cli.Flag{hostFlag, tcpPortFlag, udpPortFlag}, } + keyToRecordCommand = &cli.Command{ + Name: "to-enr", + Usage: "Creates an ENR from a node key file", + ArgsUsage: "keyfile", + Action: keyToRecord, + Flags: []cli.Flag{hostFlag, tcpPortFlag, udpPortFlag}, + } ) var ( @@ -80,9 +97,36 @@ func genkey(ctx *cli.Context) error { return crypto.SaveECDSA(file, key) } +func keyToID(ctx *cli.Context) error { + n, err := makeRecord(ctx) + if err != nil { + return err + } + fmt.Println(n.ID()) + return nil +} + func keyToURL(ctx *cli.Context) error { + n, err := makeRecord(ctx) + if err != nil { + return err + } + fmt.Println(n.URLv4()) + return nil +} + +func keyToRecord(ctx *cli.Context) error { + n, err := makeRecord(ctx) + if err != nil { + return err + } + fmt.Println(n.String()) + return nil +} + +func makeRecord(ctx *cli.Context) (*enode.Node, error) { if ctx.NArg() != 1 { - return fmt.Errorf("need key file as argument") + return nil, fmt.Errorf("need key file as argument") } var ( @@ -93,13 +137,26 @@ func keyToURL(ctx *cli.Context) error { ) key, err := crypto.LoadECDSA(file) if err != nil { - return err + return nil, err + } + + var r enr.Record + if host != "" { + ip := net.ParseIP(host) + if ip == nil { + return nil, fmt.Errorf("invalid IP address %q", host) + } + r.Set(enr.IP(ip)) } - ip := net.ParseIP(host) - if ip == nil { - return fmt.Errorf("invalid IP address %q", host) + if udp != 0 { + r.Set(enr.UDP(udp)) } - node := enode.NewV4(&key.PublicKey, ip, tcp, udp) - fmt.Println(node.URLv4()) - return nil + if tcp != 0 { + r.Set(enr.TCP(tcp)) + } + + if err := enode.SignV4(&r, key); err != nil { + return nil, err + } + return enode.New(enode.ValidSchemes, &r) } From ee9ff064694c445a3a6972001ccbce2cc5b9c3f2 Mon Sep 17 00:00:00 2001 From: Ahmet Avci Date: Tue, 8 Nov 2022 15:14:14 +0300 Subject: [PATCH 361/715] graphql: add query timeout (#26116) This PR adds a 60 second timeout to graphql queries. --- graphql/service.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/graphql/service.go b/graphql/service.go index 6f6e58335991..684fdc71268d 100644 --- a/graphql/service.go +++ b/graphql/service.go @@ -17,8 +17,10 @@ package graphql import ( + "context" "encoding/json" "net/http" + "time" "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/internal/ethapi" @@ -41,7 +43,10 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - response := h.Schema.Exec(r.Context(), params.Query, params.OperationName, params.Variables) + ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second) + defer cancel() + + response := h.Schema.Exec(ctx, params.Query, params.OperationName, params.Variables) responseJSON, err := json.Marshal(response) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) From 6685f8845583cfc2edddab7618af4ad0fe88e220 Mon Sep 17 00:00:00 2001 From: Joseph Cook <33655003+jmcook1186@users.noreply.github.com> Date: Tue, 8 Nov 2022 20:17:12 +0000 Subject: [PATCH 362/715] cmd/clef: only print first N accounts on startup (#26128) PR #26082 added account listing to OnSignerStartup but did not consider the case where a user has a large number of accounts which would be annoying to display. This PR updates showAccounts() so that if there are more than 20 accounts available the user sees the first 20 displayed in the console followed by: First 20 accounts listed (N more available). Co-authored-by: Martin Holst Swende --- signer/core/cliui.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/signer/core/cliui.go b/signer/core/cliui.go index 6278e53c08a0..b1bd3206ed3f 100644 --- a/signer/core/cliui.go +++ b/signer/core/cliui.go @@ -253,12 +253,17 @@ func (ui *CommandlineUI) showAccounts() { fmt.Print("No accounts found\n") return } + var msg string var out = new(strings.Builder) + if limit := 20; len(accounts) > limit { + msg = fmt.Sprintf("\nFirst %d accounts listed (%d more available).\n", limit, len(accounts)-limit) + accounts = accounts[:limit] + } fmt.Fprint(out, "\n------- Available accounts -------\n") for i, account := range accounts { fmt.Fprintf(out, "%d. %s at %s\n", i, account.Address, account.URL) } - fmt.Print(out.String()) + fmt.Print(out.String(), msg) } func (ui *CommandlineUI) OnSignerStartup(info StartupInfo) { From 7dc5e785a8fda2485515203c302fdd113dd5313e Mon Sep 17 00:00:00 2001 From: yihuang Date: Wed, 9 Nov 2022 14:52:13 +0800 Subject: [PATCH 363/715] core/vm: deepcopy jumptable when enabling extra eips (#26137) When the interpreter is configured to use extra-eips, this change makes it so that all the opcodes are deep-copied, to prevent accidental modification of the 'base' jumptable. Closes: #26136 Co-authored-by: Martin Holst Swende --- core/vm/interpreter.go | 8 +++++--- core/vm/jump_table.go | 11 +++++++++++ core/vm/jump_table_test.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 core/vm/jump_table_test.go diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 312977b75588..c99e54b76dc0 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -82,15 +82,17 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { cfg.JumpTable = &frontierInstructionSet } var extraEips []int + if len(cfg.ExtraEips) > 0 { + // Deep-copy jumptable to prevent modification of opcodes in other tables + cfg.JumpTable = copyJumpTable(cfg.JumpTable) + } for _, eip := range cfg.ExtraEips { - copy := *cfg.JumpTable - if err := EnableEIP(eip, ©); err != nil { + if err := EnableEIP(eip, cfg.JumpTable); 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) } - cfg.JumpTable = © } cfg.ExtraEips = extraEips } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 94229436d23c..7cbcc56c5adc 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -1043,3 +1043,14 @@ func newFrontierInstructionSet() JumpTable { return validate(tbl) } + +func copyJumpTable(source *JumpTable) *JumpTable { + dest := *source + for i, op := range source { + if op != nil { + opCopy := *op + dest[i] = &opCopy + } + } + return &dest +} diff --git a/core/vm/jump_table_test.go b/core/vm/jump_table_test.go new file mode 100644 index 000000000000..f67915fff3d8 --- /dev/null +++ b/core/vm/jump_table_test.go @@ -0,0 +1,35 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// TestJumpTableCopy tests that deep copy is necessery to prevent modify shared jump table +func TestJumpTableCopy(t *testing.T) { + tbl := newMergeInstructionSet() + require.Equal(t, uint64(0), tbl[SLOAD].constantGas) + + // a deep copy won't modify the shared jump table + deepCopy := copyJumpTable(&tbl) + deepCopy[SLOAD].constantGas = 100 + require.Equal(t, uint64(100), deepCopy[SLOAD].constantGas) + require.Equal(t, uint64(0), tbl[SLOAD].constantGas) +} From 5fded040372784985265f83f33f15cb6a51bebdb Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 9 Nov 2022 08:06:02 +0100 Subject: [PATCH 364/715] core/state: replace fastcache code cache with gc-friendly structure (#26092) This PR replaces fastcache with a pretty simple LRU which does not require explicit closing. --- common/lru/blob_lru.go | 88 ++++++++++++++++++++++++++ common/lru/blob_lru_test.go | 122 ++++++++++++++++++++++++++++++++++++ core/state/database.go | 14 ++--- 3 files changed, 217 insertions(+), 7 deletions(-) create mode 100644 common/lru/blob_lru.go create mode 100644 common/lru/blob_lru_test.go diff --git a/common/lru/blob_lru.go b/common/lru/blob_lru.go new file mode 100644 index 000000000000..3138f422ccfa --- /dev/null +++ b/common/lru/blob_lru.go @@ -0,0 +1,88 @@ +// Copyright 2022 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 lru + +import ( + "math" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/hashicorp/golang-lru/simplelru" +) + +// SizeConstrainedLRU is a wrapper around simplelru.LRU. The simplelru.LRU is capable +// of item-count constraints, but is not capable of enforcing a byte-size constraint, +// hence this wrapper. +// OBS: This cache assumes that items are content-addressed: keys are unique per content. +// In other words: two Add(..) with the same key K, will always have the same value V. +type SizeConstrainedLRU struct { + size uint64 + maxSize uint64 + lru *simplelru.LRU + lock sync.RWMutex +} + +// NewSizeConstrainedLRU creates a new SizeConstrainedLRU. +func NewSizeConstrainedLRU(max uint64) *SizeConstrainedLRU { + lru, err := simplelru.NewLRU(math.MaxInt, nil) + if err != nil { + panic(err) + } + return &SizeConstrainedLRU{ + size: 0, + maxSize: max, + lru: lru, + } +} + +// Add adds a value to the cache. Returns true if an eviction occurred. +// OBS: This cache assumes that items are content-addressed: keys are unique per content. +// In other words: two Add(..) with the same key K, will always have the same value V. +// OBS: The value is _not_ copied on Add, so the caller must not modify it afterwards. +func (c *SizeConstrainedLRU) Add(key common.Hash, value []byte) (evicted bool) { + c.lock.Lock() + defer c.lock.Unlock() + + // Unless it is already present, might need to evict something. + // OBS: If it is present, we still call Add internally to bump the recentness. + if !c.lru.Contains(key) { + targetSize := c.size + uint64(len(value)) + for targetSize > c.maxSize { + evicted = true + _, v, ok := c.lru.RemoveOldest() + if !ok { + // list is now empty. Break + break + } + targetSize -= uint64(len(v.([]byte))) + } + c.size = targetSize + } + c.lru.Add(key, value) + return evicted +} + +// Get looks up a key's value from the cache. +func (c *SizeConstrainedLRU) Get(key common.Hash) []byte { + c.lock.RLock() + defer c.lock.RUnlock() + + if v, ok := c.lru.Get(key); ok { + return v.([]byte) + } + return nil +} diff --git a/common/lru/blob_lru_test.go b/common/lru/blob_lru_test.go new file mode 100644 index 000000000000..4b5e69340222 --- /dev/null +++ b/common/lru/blob_lru_test.go @@ -0,0 +1,122 @@ +// Copyright 2022 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 lru + +import ( + "encoding/binary" + "fmt" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +func mkHash(i int) common.Hash { + h := make([]byte, 32) + binary.LittleEndian.PutUint64(h, uint64(i)) + return common.BytesToHash(h) +} + +func TestBlobLru(t *testing.T) { + lru := NewSizeConstrainedLRU(100) + var want uint64 + // Add 11 items of 10 byte each. First item should be swapped out + for i := 0; i < 11; i++ { + k := mkHash(i) + v := fmt.Sprintf("value-%04d", i) + lru.Add(k, []byte(v)) + want += uint64(len(v)) + if want > 100 { + want = 100 + } + if have := lru.size; have != want { + t.Fatalf("size wrong, have %d want %d", have, want) + } + } + // Zero:th should be evicted + { + k := mkHash(0) + if val := lru.Get(k); val != nil { + t.Fatalf("should be evicted: %v", k) + } + } + // Elems 1-11 should be present + for i := 1; i < 11; i++ { + k := mkHash(i) + want := fmt.Sprintf("value-%04d", i) + have := lru.Get(k) + if have == nil { + t.Fatalf("missing key %v", k) + } + if string(have) != want { + t.Fatalf("wrong value, have %v want %v", have, want) + } + } +} + +// TestBlobLruOverflow tests what happens when inserting an element exceeding +// the max size +func TestBlobLruOverflow(t *testing.T) { + lru := NewSizeConstrainedLRU(100) + // Add 10 items of 10 byte each, filling the cache + for i := 0; i < 10; i++ { + k := mkHash(i) + v := fmt.Sprintf("value-%04d", i) + lru.Add(k, []byte(v)) + } + // Add one single large elem. We expect it to swap out all entries. + { + k := mkHash(1337) + v := make([]byte, 200) + lru.Add(k, v) + } + // Elems 0-9 should be missing + for i := 1; i < 10; i++ { + k := mkHash(i) + if val := lru.Get(k); val != nil { + t.Fatalf("should be evicted: %v", k) + } + } + // The size should be accurate + if have, want := lru.size, uint64(200); have != want { + t.Fatalf("size wrong, have %d want %d", have, want) + } + // Adding one small item should swap out the large one + { + i := 0 + k := mkHash(i) + v := fmt.Sprintf("value-%04d", i) + lru.Add(k, []byte(v)) + if have, want := lru.size, uint64(10); have != want { + t.Fatalf("size wrong, have %d want %d", have, want) + } + } +} + +// TestBlobLruSameItem tests what happens when inserting the same k/v multiple times. +func TestBlobLruSameItem(t *testing.T) { + lru := NewSizeConstrainedLRU(100) + // Add one 10 byte-item 10 times + k := mkHash(0) + v := fmt.Sprintf("value-%04d", 0) + for i := 0; i < 10; i++ { + lru.Add(k, []byte(v)) + } + // The size should be accurate + if have, want := lru.size, uint64(10); have != want { + t.Fatalf("size wrong, have %d want %d", have, want) + } +} diff --git a/core/state/database.go b/core/state/database.go index 5e3d9a9d388a..9f270bf0f98d 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -20,8 +20,8 @@ import ( "errors" "fmt" - "github.com/VictoriaMetrics/fastcache" "github.com/ethereum/go-ethereum/common" + lru2 "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" @@ -135,7 +135,7 @@ func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { db: trie.NewDatabaseWithConfig(db, config), disk: db, codeSizeCache: csc, - codeCache: fastcache.New(codeCacheSize), + codeCache: lru2.NewSizeConstrainedLRU(codeCacheSize), } } @@ -143,7 +143,7 @@ type cachingDB struct { db *trie.Database disk ethdb.KeyValueStore codeSizeCache *lru.Cache - codeCache *fastcache.Cache + codeCache *lru2.SizeConstrainedLRU } // OpenTrie opens the main account trie at a specific root hash. @@ -176,12 +176,12 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { // ContractCode retrieves a particular contract's code. func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { - if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 { + if code := db.codeCache.Get(codeHash); len(code) > 0 { return code, nil } code := rawdb.ReadCode(db.disk, codeHash) if len(code) > 0 { - db.codeCache.Set(codeHash.Bytes(), code) + db.codeCache.Add(codeHash, code) db.codeSizeCache.Add(codeHash, len(code)) return code, nil } @@ -192,12 +192,12 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error // code can't be found in the cache, then check the existence with **new** // db scheme. func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error) { - if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 { + if code := db.codeCache.Get(codeHash); len(code) > 0 { return code, nil } code := rawdb.ReadCodeWithPrefix(db.disk, codeHash) if len(code) > 0 { - db.codeCache.Set(codeHash.Bytes(), code) + db.codeCache.Add(codeHash, code) db.codeSizeCache.Add(codeHash, len(code)) return code, nil } From dffd93b4758e7027aadbe5611794df9eac4d7ab5 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 9 Nov 2022 09:34:42 +0100 Subject: [PATCH 365/715] cmd/evm: slight change in how t8n handles coinbase pre eip-158 (#26139) This PR fixes a subtle bug in t8n. After this PR, t8n behaves like our state-test runner in certain pre-EIP-158 scenarios --- cmd/evm/internal/t8ntool/execution.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index a27c6f6b4f4b..adbf56f70c95 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -230,8 +230,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txIndex++ } statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)) - // Add mining reward? - if miningReward > 0 { + // Add mining reward? (-1 means rewards are disabled) + if miningReward >= 0 { // Add mining reward. The mining reward may be `0`, which only makes a difference in the cases // where // - the coinbase suicided, or From 093b2ac32ac96fdf89cd80ca8fe40cb9c9fc8f49 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 9 Nov 2022 09:49:42 +0100 Subject: [PATCH 366/715] eth/filters: fix failing benchmark-test (#26144) --- eth/filters/filter_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 2a4dfd90ad80..d10e0f1d9482 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -53,10 +53,10 @@ func BenchmarkFilters(b *testing.B) { gspec = &core.Genesis{ Alloc: core.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.TestChainConfig, } ) defer db.Close() - _, chain, receipts := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 100010, func(i int, gen *core.BlockGen) { switch i { case 2403: @@ -77,6 +77,11 @@ func BenchmarkFilters(b *testing.B) { gen.AddUncheckedTx(types.NewTransaction(999, common.HexToAddress("0x999"), big.NewInt(999), 999, gen.BaseFee(), nil)) } }) + // The test txs are not properly signed, can't simply create a chain + // and then import blocks. TODO(rjl493456442) try to get rid of the + // manual database writes. + gspec.MustCommit(db) + for i, block := range chain { rawdb.WriteBlock(db, block) rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) From 0ad20140265072d9b34900e0d18863c48b73d6c3 Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 10 Nov 2022 01:32:02 +0100 Subject: [PATCH 367/715] go.mod: update status-im/keycard-go (#26141) --- go.mod | 20 ++++++++++---------- go.sum | 36 ++++++++++++++++++++++++++---------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index eda8e663c6bb..0eaa65c0bfa5 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 - github.com/go-stack/stack v1.8.0 + github.com/go-stack/stack v1.8.1 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.4 @@ -52,20 +52,20 @@ require ( github.com/rjeczalik/notify v0.9.1 github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible - github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 + github.com/status-im/keycard-go v0.2.0 github.com/stretchr/testify v1.7.2 github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 + golang.org/x/crypto v0.1.0 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 - golang.org/x/text v0.3.7 + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 + golang.org/x/sys v0.2.0 + golang.org/x/term v0.1.0 + golang.org/x/text v0.4.0 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba - golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 + golang.org/x/tools v0.1.12 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce ) @@ -100,8 +100,8 @@ require ( github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect - golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.1.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/protobuf v1.26.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 50c27386cbae..05324488c29c 100644 --- a/go.sum +++ b/go.sum @@ -121,6 +121,7 @@ github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0= @@ -157,8 +158,9 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -386,8 +388,9 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= +github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -410,6 +413,7 @@ github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZF github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -421,6 +425,7 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRT github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -437,8 +442,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -470,8 +476,9 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4= golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -498,8 +505,10 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -512,8 +521,9 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -555,12 +565,16 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43 h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -568,8 +582,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -603,8 +618,9 @@ golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 5b4c149f97408ecefc7f440e86c12a30c4342620 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 11 Nov 2022 11:33:18 +0100 Subject: [PATCH 368/715] internal/debug: add --log.file option (#26149) This adds an option to direct log output to a file. This feature has been requested a lot. It's sometimes useful to have this available when running geth in an environment that doesn't easily allow redirecting the output. Notably, there is no support for log rotation with this change. The --log.file option opens the file once on startup and then keeps writing to the file handle. This can become an issue when external log rotation tools are involved, so it's best not to use them with this option for now. --- internal/debug/flags.go | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 2082d60df51c..e014a85d7fc8 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -54,6 +54,11 @@ var ( Usage: "Format logs with JSON", Category: flags.LoggingCategory, } + logFileFlag = &cli.StringFlag{ + Name: "log.file", + Usage: "Write logs to a file", + Category: flags.LoggingCategory, + } backtraceAtFlag = &cli.StringFlag{ Name: "log.backtrace", Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", @@ -110,6 +115,7 @@ var Flags = []cli.Flag{ verbosityFlag, vmoduleFlag, logjsonFlag, + logFileFlag, backtraceAtFlag, debugFlag, pprofFlag, @@ -121,7 +127,10 @@ var Flags = []cli.Flag{ traceFlag, } -var glogger *log.GlogHandler +var ( + glogger *log.GlogHandler + logOutputStream log.Handler +) func init() { glogger = log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) @@ -132,18 +141,30 @@ func init() { // Setup initializes profiling and logging based on the CLI flags. // It should be called as early as possible in the program. func Setup(ctx *cli.Context) error { - var ostream log.Handler - output := io.Writer(os.Stderr) + logFile := ctx.String(logFileFlag.Name) + useColor := logFile == "" && os.Getenv("TERM") != "dumb" && (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) + + var logfmt log.Format if ctx.Bool(logjsonFlag.Name) { - ostream = log.StreamHandler(output, log.JSONFormat()) + logfmt = log.JSONFormat() } else { - usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" - if usecolor { + logfmt = log.TerminalFormat(useColor) + } + + if logFile != "" { + var err error + logOutputStream, err = log.FileHandler(logFile, logfmt) + if err != nil { + return err + } + } else { + output := io.Writer(os.Stderr) + if useColor { output = colorable.NewColorableStderr() } - ostream = log.StreamHandler(output, log.TerminalFormat(usecolor)) + logOutputStream = log.StreamHandler(output, logfmt) } - glogger.SetHandler(ostream) + glogger.SetHandler(logOutputStream) // logging verbosity := ctx.Int(verbosityFlag.Name) @@ -217,4 +238,7 @@ func StartPProf(address string, withMetrics bool) { func Exit() { Handler.StopCPUProfile() Handler.StopGoTrace() + if closer, ok := logOutputStream.(io.Closer); ok { + closer.Close() + } } From 62c973eba664ad1daf6ba843e28b3c14f787a9b8 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 11 Nov 2022 13:11:24 +0100 Subject: [PATCH 369/715] go.mod: minimum Go version 1.18 (#26160) This will allow use of generics and other new standard library APIs such as package net/netip. --- README.md | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5506001287fe..59fcd4a12eb7 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ archives are published at https://geth.ethereum.org/downloads/. For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/install-and-build/installing-geth). -Building `geth` requires both a Go (version 1.16 or later) and a C compiler. You can install +Building `geth` requires both a Go (version 1.18 or later) and a C compiler. You can install them using your favourite package manager. Once the dependencies are installed, run ```shell diff --git a/go.mod b/go.mod index 0eaa65c0bfa5..01c5e07bbe2a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ethereum/go-ethereum -go 1.17 +go 1.18 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 From c539bda166bb0b04e0558d46799bb5e691b8fdbd Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 11 Nov 2022 13:16:13 +0100 Subject: [PATCH 370/715] metrics: improve reading Go runtime metrics (#25886) This changes how we read performance metrics from the Go runtime. Instead of using runtime.ReadMemStats, we now rely on the API provided by package runtime/metrics. runtime/metrics provides more accurate information. For example, the new interface has better reporting of memory use. In my testing, the reported value of held memory more accurately reflects the usage reported by the OS. The semantics of metrics system/memory/allocs and system/memory/frees have changed to report amounts in bytes. ReadMemStats only reported the count of allocations in number-of-objects. This is imprecise: 'tiny objects' are not counted because the runtime allocates them in batches; and certain improvements in allocation behavior, such as struct size optimizations, will be less visible when the number of allocs doesn't change. Changing allocation reports to be in bytes makes it appear in graphs that lots more is being allocated. I don't think that's a problem because this metric is primarily interesting for geth developers. The metric system/memory/pauses has been changed to report statistical values from the histogram provided by the runtime. Its name in influxdb has changed from geth.system/memory/pauses.meter to geth.system/memory/pauses.histogram. We also have a new histogram metric, system/cpu/schedlatency, reporting the Go scheduler latency. --- metrics/influxdb/influxdb.go | 35 +-- metrics/metrics.go | 176 ++++++++++----- metrics/metrics_test.go | 32 +-- metrics/runtime.go | 212 ------------------ metrics/runtime_cgo.go | 10 - metrics/runtime_gccpufraction.go | 10 - metrics/runtime_no_cgo.go | 8 - metrics/runtime_no_gccpufraction.go | 10 - metrics/runtime_test.go | 88 -------- metrics/runtimehistogram.go | 319 ++++++++++++++++++++++++++++ metrics/runtimehistogram_test.go | 133 ++++++++++++ 11 files changed, 602 insertions(+), 431 deletions(-) delete mode 100644 metrics/runtime.go delete mode 100644 metrics/runtime_cgo.go delete mode 100644 metrics/runtime_gccpufraction.go delete mode 100644 metrics/runtime_no_cgo.go delete mode 100644 metrics/runtime_no_gccpufraction.go delete mode 100644 metrics/runtime_test.go create mode 100644 metrics/runtimehistogram.go create mode 100644 metrics/runtimehistogram_test.go diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go index e99717aeebf9..1bf0c355edfe 100644 --- a/metrics/influxdb/influxdb.go +++ b/metrics/influxdb/influxdb.go @@ -160,27 +160,28 @@ func (r *reporter) send() error { }) case metrics.Histogram: ms := metric.Snapshot() - if ms.Count() > 0 { - ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) + ps := ms.Percentiles([]float64{0.25, 0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) + fields := map[string]interface{}{ + "count": ms.Count(), + "max": ms.Max(), + "mean": ms.Mean(), + "min": ms.Min(), + "stddev": ms.StdDev(), + "variance": ms.Variance(), + "p25": ps[0], + "p50": ps[1], + "p75": ps[2], + "p95": ps[3], + "p99": ps[4], + "p999": ps[5], + "p9999": ps[6], + } pts = append(pts, client.Point{ Measurement: fmt.Sprintf("%s%s.histogram", namespace, name), Tags: r.tags, - Fields: map[string]interface{}{ - "count": ms.Count(), - "max": ms.Max(), - "mean": ms.Mean(), - "min": ms.Min(), - "stddev": ms.StdDev(), - "variance": ms.Variance(), - "p50": ps[0], - "p75": ps[1], - "p95": ps[2], - "p99": ps[3], - "p999": ps[4], - "p9999": ps[5], - }, - Time: now, + Fields: fields, + Time: now, }) } case metrics.Meter: diff --git a/metrics/metrics.go b/metrics/metrics.go index 747d6471a764..2edf8e35f151 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -7,7 +7,8 @@ package metrics import ( "os" - "runtime" + "runtime/metrics" + "runtime/pprof" "strings" "time" @@ -54,38 +55,106 @@ func init() { } } -// CollectProcessMetrics periodically collects various metrics about the running -// process. +var threadCreateProfile = pprof.Lookup("threadcreate") + +type runtimeStats struct { + GCPauses *metrics.Float64Histogram + GCAllocBytes uint64 + GCFreedBytes uint64 + + MemTotal uint64 + HeapObjects uint64 + HeapFree uint64 + HeapReleased uint64 + HeapUnused uint64 + + Goroutines uint64 + SchedLatency *metrics.Float64Histogram +} + +var runtimeSamples = []metrics.Sample{ + {Name: "/gc/pauses:seconds"}, // histogram + {Name: "/gc/heap/allocs:bytes"}, + {Name: "/gc/heap/frees:bytes"}, + {Name: "/memory/classes/total:bytes"}, + {Name: "/memory/classes/heap/objects:bytes"}, + {Name: "/memory/classes/heap/free:bytes"}, + {Name: "/memory/classes/heap/released:bytes"}, + {Name: "/memory/classes/heap/unused:bytes"}, + {Name: "/sched/goroutines:goroutines"}, + {Name: "/sched/latencies:seconds"}, // histogram +} + +func readRuntimeStats(v *runtimeStats) { + metrics.Read(runtimeSamples) + for _, s := range runtimeSamples { + // Skip invalid/unknown metrics. This is needed because some metrics + // are unavailable in older Go versions, and attempting to read a 'bad' + // metric panics. + if s.Value.Kind() == metrics.KindBad { + continue + } + + switch s.Name { + case "/gc/pauses:seconds": + v.GCPauses = s.Value.Float64Histogram() + case "/gc/heap/allocs:bytes": + v.GCAllocBytes = s.Value.Uint64() + case "/gc/heap/frees:bytes": + v.GCFreedBytes = s.Value.Uint64() + case "/memory/classes/total:bytes": + v.MemTotal = s.Value.Uint64() + case "/memory/classes/heap/objects:bytes": + v.HeapObjects = s.Value.Uint64() + case "/memory/classes/heap/free:bytes": + v.HeapFree = s.Value.Uint64() + case "/memory/classes/heap/released:bytes": + v.HeapReleased = s.Value.Uint64() + case "/memory/classes/heap/unused:bytes": + v.HeapUnused = s.Value.Uint64() + case "/sched/goroutines:goroutines": + v.Goroutines = s.Value.Uint64() + case "/sched/latencies:seconds": + v.SchedLatency = s.Value.Float64Histogram() + } + } +} + +// CollectProcessMetrics periodically collects various metrics about the running process. func CollectProcessMetrics(refresh time.Duration) { // Short circuit if the metrics system is disabled if !Enabled { return } + refreshFreq := int64(refresh / time.Second) // Create the various data collectors - cpuStats := make([]*CPUStats, 2) - memstats := make([]*runtime.MemStats, 2) - diskstats := make([]*DiskStats, 2) - for i := 0; i < len(memstats); i++ { - cpuStats[i] = new(CPUStats) - memstats[i] = new(runtime.MemStats) - diskstats[i] = new(DiskStats) - } - // Define the various metrics to collect var ( - cpuSysLoad = GetOrRegisterGauge("system/cpu/sysload", DefaultRegistry) - cpuSysWait = GetOrRegisterGauge("system/cpu/syswait", DefaultRegistry) - cpuProcLoad = GetOrRegisterGauge("system/cpu/procload", DefaultRegistry) - cpuThreads = GetOrRegisterGauge("system/cpu/threads", DefaultRegistry) - cpuGoroutines = GetOrRegisterGauge("system/cpu/goroutines", DefaultRegistry) - - memPauses = GetOrRegisterMeter("system/memory/pauses", DefaultRegistry) - memAllocs = GetOrRegisterMeter("system/memory/allocs", DefaultRegistry) - memFrees = GetOrRegisterMeter("system/memory/frees", DefaultRegistry) - memHeld = GetOrRegisterGauge("system/memory/held", DefaultRegistry) - memUsed = GetOrRegisterGauge("system/memory/used", DefaultRegistry) + cpustats = make([]CPUStats, 2) + diskstats = make([]DiskStats, 2) + rstats = make([]runtimeStats, 2) + ) + + // This scale factor is used for the runtime's time metrics. It's useful to convert to + // ns here because the runtime gives times in float seconds, but runtimeHistogram can + // only provide integers for the minimum and maximum values. + const secondsToNs = float64(time.Second) + // Define the various metrics to collect + var ( + cpuSysLoad = GetOrRegisterGauge("system/cpu/sysload", DefaultRegistry) + cpuSysWait = GetOrRegisterGauge("system/cpu/syswait", DefaultRegistry) + cpuProcLoad = GetOrRegisterGauge("system/cpu/procload", DefaultRegistry) + cpuThreads = GetOrRegisterGauge("system/cpu/threads", DefaultRegistry) + cpuGoroutines = GetOrRegisterGauge("system/cpu/goroutines", DefaultRegistry) + cpuSchedLatency = getOrRegisterRuntimeHistogram("system/cpu/schedlatency", secondsToNs, nil) + memPauses = getOrRegisterRuntimeHistogram("system/memory/pauses", secondsToNs, nil) + memAllocs = GetOrRegisterMeter("system/memory/allocs", DefaultRegistry) + memFrees = GetOrRegisterMeter("system/memory/frees", DefaultRegistry) + memTotal = GetOrRegisterGauge("system/memory/held", DefaultRegistry) + heapUsed = GetOrRegisterGauge("system/memory/used", DefaultRegistry) + heapObjects = GetOrRegisterGauge("system/memory/objects", DefaultRegistry) diskReads = GetOrRegisterMeter("system/disk/readcount", DefaultRegistry) diskReadBytes = GetOrRegisterMeter("system/disk/readdata", DefaultRegistry) diskReadBytesCounter = GetOrRegisterCounter("system/disk/readbytes", DefaultRegistry) @@ -93,34 +162,43 @@ func CollectProcessMetrics(refresh time.Duration) { diskWriteBytes = GetOrRegisterMeter("system/disk/writedata", DefaultRegistry) diskWriteBytesCounter = GetOrRegisterCounter("system/disk/writebytes", DefaultRegistry) ) - // Iterate loading the different stats and updating the meters - for i := 1; ; i++ { - location1 := i % 2 - location2 := (i - 1) % 2 - - ReadCPUStats(cpuStats[location1]) - cpuSysLoad.Update((cpuStats[location1].GlobalTime - cpuStats[location2].GlobalTime) / refreshFreq) - cpuSysWait.Update((cpuStats[location1].GlobalWait - cpuStats[location2].GlobalWait) / refreshFreq) - cpuProcLoad.Update((cpuStats[location1].LocalTime - cpuStats[location2].LocalTime) / refreshFreq) + + // Iterate loading the different stats and updating the meters. + now, prev := 0, 1 + for ; ; now, prev = prev, now { + // CPU + ReadCPUStats(&cpustats[now]) + cpuSysLoad.Update((cpustats[now].GlobalTime - cpustats[prev].GlobalTime) / refreshFreq) + cpuSysWait.Update((cpustats[now].GlobalWait - cpustats[prev].GlobalWait) / refreshFreq) + cpuProcLoad.Update((cpustats[now].LocalTime - cpustats[prev].LocalTime) / refreshFreq) + + // Threads cpuThreads.Update(int64(threadCreateProfile.Count())) - cpuGoroutines.Update(int64(runtime.NumGoroutine())) - - runtime.ReadMemStats(memstats[location1]) - memPauses.Mark(int64(memstats[location1].PauseTotalNs - memstats[location2].PauseTotalNs)) - memAllocs.Mark(int64(memstats[location1].Mallocs - memstats[location2].Mallocs)) - memFrees.Mark(int64(memstats[location1].Frees - memstats[location2].Frees)) - memHeld.Update(int64(memstats[location1].HeapSys - memstats[location1].HeapReleased)) - memUsed.Update(int64(memstats[location1].Alloc)) - - if ReadDiskStats(diskstats[location1]) == nil { - diskReads.Mark(diskstats[location1].ReadCount - diskstats[location2].ReadCount) - diskReadBytes.Mark(diskstats[location1].ReadBytes - diskstats[location2].ReadBytes) - diskWrites.Mark(diskstats[location1].WriteCount - diskstats[location2].WriteCount) - diskWriteBytes.Mark(diskstats[location1].WriteBytes - diskstats[location2].WriteBytes) - - diskReadBytesCounter.Inc(diskstats[location1].ReadBytes - diskstats[location2].ReadBytes) - diskWriteBytesCounter.Inc(diskstats[location1].WriteBytes - diskstats[location2].WriteBytes) + + // Go runtime metrics + readRuntimeStats(&rstats[now]) + + cpuGoroutines.Update(int64(rstats[now].Goroutines)) + cpuSchedLatency.update(rstats[now].SchedLatency) + memPauses.update(rstats[now].GCPauses) + + memAllocs.Mark(int64(rstats[now].GCAllocBytes - rstats[prev].GCAllocBytes)) + memFrees.Mark(int64(rstats[now].GCFreedBytes - rstats[prev].GCFreedBytes)) + + memTotal.Update(int64(rstats[now].MemTotal)) + heapUsed.Update(int64(rstats[now].MemTotal - rstats[now].HeapUnused - rstats[now].HeapFree - rstats[now].HeapReleased)) + heapObjects.Update(int64(rstats[now].HeapObjects)) + + // Disk + if ReadDiskStats(&diskstats[now]) == nil { + diskReads.Mark(diskstats[now].ReadCount - diskstats[prev].ReadCount) + diskReadBytes.Mark(diskstats[now].ReadBytes - diskstats[prev].ReadBytes) + diskWrites.Mark(diskstats[now].WriteCount - diskstats[prev].WriteCount) + diskWriteBytes.Mark(diskstats[now].WriteBytes - diskstats[prev].WriteBytes) + diskReadBytesCounter.Inc(diskstats[now].ReadBytes - diskstats[prev].ReadBytes) + diskWriteBytesCounter.Inc(diskstats[now].WriteBytes - diskstats[prev].WriteBytes) } + time.Sleep(refresh) } } diff --git a/metrics/metrics_test.go b/metrics/metrics_test.go index 029c99870eba..e3fde1ea62ce 100644 --- a/metrics/metrics_test.go +++ b/metrics/metrics_test.go @@ -2,8 +2,6 @@ package metrics import ( "fmt" - "io" - "log" "sync" "testing" "time" @@ -11,11 +9,11 @@ import ( const FANOUT = 128 -// Stop the compiler from complaining during debugging. -var ( - _ = io.Discard - _ = log.LstdFlags -) +func TestReadRuntimeValues(t *testing.T) { + var v runtimeStats + readRuntimeStats(&v) + t.Logf("%+v", v) +} func BenchmarkMetrics(b *testing.B) { r := NewRegistry() @@ -26,7 +24,6 @@ func BenchmarkMetrics(b *testing.B) { m := NewRegisteredMeter("meter", r) t := NewRegisteredTimer("timer", r) RegisterDebugGCStats(r) - RegisterRuntimeMemStats(r) b.ResetTimer() ch := make(chan bool) @@ -48,24 +45,6 @@ func BenchmarkMetrics(b *testing.B) { }() //*/ - wgR := &sync.WaitGroup{} - //* - wgR.Add(1) - go func() { - defer wgR.Done() - //log.Println("go CaptureRuntimeMemStats") - for { - select { - case <-ch: - //log.Println("done CaptureRuntimeMemStats") - return - default: - CaptureRuntimeMemStatsOnce(r) - } - } - }() - //*/ - wgW := &sync.WaitGroup{} /* wgW.Add(1) @@ -104,7 +83,6 @@ func BenchmarkMetrics(b *testing.B) { wg.Wait() close(ch) wgD.Wait() - wgR.Wait() wgW.Wait() } diff --git a/metrics/runtime.go b/metrics/runtime.go deleted file mode 100644 index 9450c479bad7..000000000000 --- a/metrics/runtime.go +++ /dev/null @@ -1,212 +0,0 @@ -package metrics - -import ( - "runtime" - "runtime/pprof" - "time" -) - -var ( - memStats runtime.MemStats - runtimeMetrics struct { - MemStats struct { - Alloc Gauge - BuckHashSys Gauge - DebugGC Gauge - EnableGC Gauge - Frees Gauge - HeapAlloc Gauge - HeapIdle Gauge - HeapInuse Gauge - HeapObjects Gauge - HeapReleased Gauge - HeapSys Gauge - LastGC Gauge - Lookups Gauge - Mallocs Gauge - MCacheInuse Gauge - MCacheSys Gauge - MSpanInuse Gauge - MSpanSys Gauge - NextGC Gauge - NumGC Gauge - GCCPUFraction GaugeFloat64 - PauseNs Histogram - PauseTotalNs Gauge - StackInuse Gauge - StackSys Gauge - Sys Gauge - TotalAlloc Gauge - } - NumCgoCall Gauge - NumGoroutine Gauge - NumThread Gauge - ReadMemStats Timer - } - frees uint64 - lookups uint64 - mallocs uint64 - numGC uint32 - numCgoCalls int64 - - threadCreateProfile = pprof.Lookup("threadcreate") -) - -// Capture new values for the Go runtime statistics exported in -// runtime.MemStats. This is designed to be called as a goroutine. -func CaptureRuntimeMemStats(r Registry, d time.Duration) { - for range time.Tick(d) { - CaptureRuntimeMemStatsOnce(r) - } -} - -// Capture new values for the Go runtime statistics exported in -// runtime.MemStats. This is designed to be called in a background -// goroutine. Giving a registry which has not been given to -// RegisterRuntimeMemStats will panic. -// -// Be very careful with this because runtime.ReadMemStats calls the C -// functions runtime·semacquire(&runtime·worldsema) and runtime·stoptheworld() -// and that last one does what it says on the tin. -func CaptureRuntimeMemStatsOnce(r Registry) { - t := time.Now() - runtime.ReadMemStats(&memStats) // This takes 50-200us. - runtimeMetrics.ReadMemStats.UpdateSince(t) - - runtimeMetrics.MemStats.Alloc.Update(int64(memStats.Alloc)) - runtimeMetrics.MemStats.BuckHashSys.Update(int64(memStats.BuckHashSys)) - if memStats.DebugGC { - runtimeMetrics.MemStats.DebugGC.Update(1) - } else { - runtimeMetrics.MemStats.DebugGC.Update(0) - } - if memStats.EnableGC { - runtimeMetrics.MemStats.EnableGC.Update(1) - } else { - runtimeMetrics.MemStats.EnableGC.Update(0) - } - - runtimeMetrics.MemStats.Frees.Update(int64(memStats.Frees - frees)) - runtimeMetrics.MemStats.HeapAlloc.Update(int64(memStats.HeapAlloc)) - runtimeMetrics.MemStats.HeapIdle.Update(int64(memStats.HeapIdle)) - runtimeMetrics.MemStats.HeapInuse.Update(int64(memStats.HeapInuse)) - runtimeMetrics.MemStats.HeapObjects.Update(int64(memStats.HeapObjects)) - runtimeMetrics.MemStats.HeapReleased.Update(int64(memStats.HeapReleased)) - runtimeMetrics.MemStats.HeapSys.Update(int64(memStats.HeapSys)) - runtimeMetrics.MemStats.LastGC.Update(int64(memStats.LastGC)) - runtimeMetrics.MemStats.Lookups.Update(int64(memStats.Lookups - lookups)) - runtimeMetrics.MemStats.Mallocs.Update(int64(memStats.Mallocs - mallocs)) - runtimeMetrics.MemStats.MCacheInuse.Update(int64(memStats.MCacheInuse)) - runtimeMetrics.MemStats.MCacheSys.Update(int64(memStats.MCacheSys)) - runtimeMetrics.MemStats.MSpanInuse.Update(int64(memStats.MSpanInuse)) - runtimeMetrics.MemStats.MSpanSys.Update(int64(memStats.MSpanSys)) - runtimeMetrics.MemStats.NextGC.Update(int64(memStats.NextGC)) - runtimeMetrics.MemStats.NumGC.Update(int64(memStats.NumGC - numGC)) - runtimeMetrics.MemStats.GCCPUFraction.Update(gcCPUFraction(&memStats)) - - // - i := numGC % uint32(len(memStats.PauseNs)) - ii := memStats.NumGC % uint32(len(memStats.PauseNs)) - if memStats.NumGC-numGC >= uint32(len(memStats.PauseNs)) { - for i = 0; i < uint32(len(memStats.PauseNs)); i++ { - runtimeMetrics.MemStats.PauseNs.Update(int64(memStats.PauseNs[i])) - } - } else { - if i > ii { - for ; i < uint32(len(memStats.PauseNs)); i++ { - runtimeMetrics.MemStats.PauseNs.Update(int64(memStats.PauseNs[i])) - } - i = 0 - } - for ; i < ii; i++ { - runtimeMetrics.MemStats.PauseNs.Update(int64(memStats.PauseNs[i])) - } - } - frees = memStats.Frees - lookups = memStats.Lookups - mallocs = memStats.Mallocs - numGC = memStats.NumGC - - runtimeMetrics.MemStats.PauseTotalNs.Update(int64(memStats.PauseTotalNs)) - runtimeMetrics.MemStats.StackInuse.Update(int64(memStats.StackInuse)) - runtimeMetrics.MemStats.StackSys.Update(int64(memStats.StackSys)) - runtimeMetrics.MemStats.Sys.Update(int64(memStats.Sys)) - runtimeMetrics.MemStats.TotalAlloc.Update(int64(memStats.TotalAlloc)) - - currentNumCgoCalls := numCgoCall() - runtimeMetrics.NumCgoCall.Update(currentNumCgoCalls - numCgoCalls) - numCgoCalls = currentNumCgoCalls - - runtimeMetrics.NumGoroutine.Update(int64(runtime.NumGoroutine())) - - runtimeMetrics.NumThread.Update(int64(threadCreateProfile.Count())) -} - -// Register runtimeMetrics for the Go runtime statistics exported in runtime and -// specifically runtime.MemStats. The runtimeMetrics are named by their -// fully-qualified Go symbols, i.e. runtime.MemStats.Alloc. -func RegisterRuntimeMemStats(r Registry) { - runtimeMetrics.MemStats.Alloc = NewGauge() - runtimeMetrics.MemStats.BuckHashSys = NewGauge() - runtimeMetrics.MemStats.DebugGC = NewGauge() - runtimeMetrics.MemStats.EnableGC = NewGauge() - runtimeMetrics.MemStats.Frees = NewGauge() - runtimeMetrics.MemStats.HeapAlloc = NewGauge() - runtimeMetrics.MemStats.HeapIdle = NewGauge() - runtimeMetrics.MemStats.HeapInuse = NewGauge() - runtimeMetrics.MemStats.HeapObjects = NewGauge() - runtimeMetrics.MemStats.HeapReleased = NewGauge() - runtimeMetrics.MemStats.HeapSys = NewGauge() - runtimeMetrics.MemStats.LastGC = NewGauge() - runtimeMetrics.MemStats.Lookups = NewGauge() - runtimeMetrics.MemStats.Mallocs = NewGauge() - runtimeMetrics.MemStats.MCacheInuse = NewGauge() - runtimeMetrics.MemStats.MCacheSys = NewGauge() - runtimeMetrics.MemStats.MSpanInuse = NewGauge() - runtimeMetrics.MemStats.MSpanSys = NewGauge() - runtimeMetrics.MemStats.NextGC = NewGauge() - runtimeMetrics.MemStats.NumGC = NewGauge() - runtimeMetrics.MemStats.GCCPUFraction = NewGaugeFloat64() - runtimeMetrics.MemStats.PauseNs = NewHistogram(NewExpDecaySample(1028, 0.015)) - runtimeMetrics.MemStats.PauseTotalNs = NewGauge() - runtimeMetrics.MemStats.StackInuse = NewGauge() - runtimeMetrics.MemStats.StackSys = NewGauge() - runtimeMetrics.MemStats.Sys = NewGauge() - runtimeMetrics.MemStats.TotalAlloc = NewGauge() - runtimeMetrics.NumCgoCall = NewGauge() - runtimeMetrics.NumGoroutine = NewGauge() - runtimeMetrics.NumThread = NewGauge() - runtimeMetrics.ReadMemStats = NewTimer() - - r.Register("runtime.MemStats.Alloc", runtimeMetrics.MemStats.Alloc) - r.Register("runtime.MemStats.BuckHashSys", runtimeMetrics.MemStats.BuckHashSys) - r.Register("runtime.MemStats.DebugGC", runtimeMetrics.MemStats.DebugGC) - r.Register("runtime.MemStats.EnableGC", runtimeMetrics.MemStats.EnableGC) - r.Register("runtime.MemStats.Frees", runtimeMetrics.MemStats.Frees) - r.Register("runtime.MemStats.HeapAlloc", runtimeMetrics.MemStats.HeapAlloc) - r.Register("runtime.MemStats.HeapIdle", runtimeMetrics.MemStats.HeapIdle) - r.Register("runtime.MemStats.HeapInuse", runtimeMetrics.MemStats.HeapInuse) - r.Register("runtime.MemStats.HeapObjects", runtimeMetrics.MemStats.HeapObjects) - r.Register("runtime.MemStats.HeapReleased", runtimeMetrics.MemStats.HeapReleased) - r.Register("runtime.MemStats.HeapSys", runtimeMetrics.MemStats.HeapSys) - r.Register("runtime.MemStats.LastGC", runtimeMetrics.MemStats.LastGC) - r.Register("runtime.MemStats.Lookups", runtimeMetrics.MemStats.Lookups) - r.Register("runtime.MemStats.Mallocs", runtimeMetrics.MemStats.Mallocs) - r.Register("runtime.MemStats.MCacheInuse", runtimeMetrics.MemStats.MCacheInuse) - r.Register("runtime.MemStats.MCacheSys", runtimeMetrics.MemStats.MCacheSys) - r.Register("runtime.MemStats.MSpanInuse", runtimeMetrics.MemStats.MSpanInuse) - r.Register("runtime.MemStats.MSpanSys", runtimeMetrics.MemStats.MSpanSys) - r.Register("runtime.MemStats.NextGC", runtimeMetrics.MemStats.NextGC) - r.Register("runtime.MemStats.NumGC", runtimeMetrics.MemStats.NumGC) - r.Register("runtime.MemStats.GCCPUFraction", runtimeMetrics.MemStats.GCCPUFraction) - r.Register("runtime.MemStats.PauseNs", runtimeMetrics.MemStats.PauseNs) - r.Register("runtime.MemStats.PauseTotalNs", runtimeMetrics.MemStats.PauseTotalNs) - r.Register("runtime.MemStats.StackInuse", runtimeMetrics.MemStats.StackInuse) - r.Register("runtime.MemStats.StackSys", runtimeMetrics.MemStats.StackSys) - r.Register("runtime.MemStats.Sys", runtimeMetrics.MemStats.Sys) - r.Register("runtime.MemStats.TotalAlloc", runtimeMetrics.MemStats.TotalAlloc) - r.Register("runtime.NumCgoCall", runtimeMetrics.NumCgoCall) - r.Register("runtime.NumGoroutine", runtimeMetrics.NumGoroutine) - r.Register("runtime.NumThread", runtimeMetrics.NumThread) - r.Register("runtime.ReadMemStats", runtimeMetrics.ReadMemStats) -} diff --git a/metrics/runtime_cgo.go b/metrics/runtime_cgo.go deleted file mode 100644 index 4307ebdba689..000000000000 --- a/metrics/runtime_cgo.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build cgo && !appengine && !js -// +build cgo,!appengine,!js - -package metrics - -import "runtime" - -func numCgoCall() int64 { - return runtime.NumCgoCall() -} diff --git a/metrics/runtime_gccpufraction.go b/metrics/runtime_gccpufraction.go deleted file mode 100644 index 28cd44752b45..000000000000 --- a/metrics/runtime_gccpufraction.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build go1.5 -// +build go1.5 - -package metrics - -import "runtime" - -func gcCPUFraction(memStats *runtime.MemStats) float64 { - return memStats.GCCPUFraction -} diff --git a/metrics/runtime_no_cgo.go b/metrics/runtime_no_cgo.go deleted file mode 100644 index 1799bef63bfb..000000000000 --- a/metrics/runtime_no_cgo.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build !cgo || appengine || js -// +build !cgo appengine js - -package metrics - -func numCgoCall() int64 { - return 0 -} diff --git a/metrics/runtime_no_gccpufraction.go b/metrics/runtime_no_gccpufraction.go deleted file mode 100644 index af1a4b63c809..000000000000 --- a/metrics/runtime_no_gccpufraction.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !go1.5 -// +build !go1.5 - -package metrics - -import "runtime" - -func gcCPUFraction(memStats *runtime.MemStats) float64 { - return 0 -} diff --git a/metrics/runtime_test.go b/metrics/runtime_test.go deleted file mode 100644 index f85f7868f71a..000000000000 --- a/metrics/runtime_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package metrics - -import ( - "runtime" - "testing" - "time" -) - -func BenchmarkRuntimeMemStats(b *testing.B) { - r := NewRegistry() - RegisterRuntimeMemStats(r) - b.ResetTimer() - for i := 0; i < b.N; i++ { - CaptureRuntimeMemStatsOnce(r) - } -} - -func TestRuntimeMemStats(t *testing.T) { - r := NewRegistry() - RegisterRuntimeMemStats(r) - CaptureRuntimeMemStatsOnce(r) - zero := runtimeMetrics.MemStats.PauseNs.Count() // Get a "zero" since GC may have run before these tests. - runtime.GC() - CaptureRuntimeMemStatsOnce(r) - if count := runtimeMetrics.MemStats.PauseNs.Count(); count-zero != 1 { - t.Fatal(count - zero) - } - runtime.GC() - runtime.GC() - CaptureRuntimeMemStatsOnce(r) - if count := runtimeMetrics.MemStats.PauseNs.Count(); count-zero != 3 { - t.Fatal(count - zero) - } - for i := 0; i < 256; i++ { - runtime.GC() - } - CaptureRuntimeMemStatsOnce(r) - if count := runtimeMetrics.MemStats.PauseNs.Count(); count-zero != 259 { - t.Fatal(count - zero) - } - for i := 0; i < 257; i++ { - runtime.GC() - } - CaptureRuntimeMemStatsOnce(r) - if count := runtimeMetrics.MemStats.PauseNs.Count(); count-zero != 515 { // We lost one because there were too many GCs between captures. - t.Fatal(count - zero) - } -} - -func TestRuntimeMemStatsNumThread(t *testing.T) { - r := NewRegistry() - RegisterRuntimeMemStats(r) - CaptureRuntimeMemStatsOnce(r) - - if value := runtimeMetrics.NumThread.Value(); value < 1 { - t.Fatalf("got NumThread: %d, wanted at least 1", value) - } -} - -func TestRuntimeMemStatsBlocking(t *testing.T) { - if g := runtime.GOMAXPROCS(0); g < 2 { - t.Skipf("skipping TestRuntimeMemStatsBlocking with GOMAXPROCS=%d\n", g) - } - ch := make(chan int) - go testRuntimeMemStatsBlocking(ch) - var memStats runtime.MemStats - t0 := time.Now() - runtime.ReadMemStats(&memStats) - t1 := time.Now() - t.Log("i++ during runtime.ReadMemStats:", <-ch) - go testRuntimeMemStatsBlocking(ch) - d := t1.Sub(t0) - t.Log(d) - time.Sleep(d) - t.Log("i++ during time.Sleep:", <-ch) -} - -func testRuntimeMemStatsBlocking(ch chan int) { - i := 0 - for { - select { - case ch <- i: - return - default: - i++ - } - } -} diff --git a/metrics/runtimehistogram.go b/metrics/runtimehistogram.go new file mode 100644 index 000000000000..c68939af1ef7 --- /dev/null +++ b/metrics/runtimehistogram.go @@ -0,0 +1,319 @@ +package metrics + +import ( + "math" + "runtime/metrics" + "sort" + "sync/atomic" +) + +func getOrRegisterRuntimeHistogram(name string, scale float64, r Registry) *runtimeHistogram { + if r == nil { + r = DefaultRegistry + } + constructor := func() Histogram { return newRuntimeHistogram(scale) } + return r.GetOrRegister(name, constructor).(*runtimeHistogram) +} + +// runtimeHistogram wraps a runtime/metrics histogram. +type runtimeHistogram struct { + v atomic.Value + scaleFactor float64 +} + +func newRuntimeHistogram(scale float64) *runtimeHistogram { + h := &runtimeHistogram{scaleFactor: scale} + h.update(&metrics.Float64Histogram{}) + return h +} + +func (h *runtimeHistogram) update(mh *metrics.Float64Histogram) { + if mh == nil { + // The update value can be nil if the current Go version doesn't support a + // requested metric. It's just easier to handle nil here than putting + // conditionals everywhere. + return + } + + s := runtimeHistogramSnapshot{ + Counts: make([]uint64, len(mh.Counts)), + Buckets: make([]float64, len(mh.Buckets)), + } + copy(s.Counts, mh.Counts) + copy(s.Buckets, mh.Buckets) + for i, b := range s.Buckets { + s.Buckets[i] = b * h.scaleFactor + } + h.v.Store(&s) +} + +func (h *runtimeHistogram) load() *runtimeHistogramSnapshot { + return h.v.Load().(*runtimeHistogramSnapshot) +} + +func (h *runtimeHistogram) Clear() { + panic("runtimeHistogram does not support Clear") +} +func (h *runtimeHistogram) Update(int64) { + panic("runtimeHistogram does not support Update") +} +func (h *runtimeHistogram) Sample() Sample { + return NilSample{} +} + +// Snapshot returns a non-changing cop of the histogram. +func (h *runtimeHistogram) Snapshot() Histogram { + return h.load() +} + +// Count returns the sample count. +func (h *runtimeHistogram) Count() int64 { + return h.load().Count() +} + +// Mean returns an approximation of the mean. +func (h *runtimeHistogram) Mean() float64 { + return h.load().Mean() +} + +// StdDev approximates the standard deviation of the histogram. +func (h *runtimeHistogram) StdDev() float64 { + return h.load().StdDev() +} + +// Variance approximates the variance of the histogram. +func (h *runtimeHistogram) Variance() float64 { + return h.load().Variance() +} + +// Percentile computes the p'th percentile value. +func (h *runtimeHistogram) Percentile(p float64) float64 { + return h.load().Percentile(p) +} + +// Percentiles computes all requested percentile values. +func (h *runtimeHistogram) Percentiles(ps []float64) []float64 { + return h.load().Percentiles(ps) +} + +// Max returns the highest sample value. +func (h *runtimeHistogram) Max() int64 { + return h.load().Max() +} + +// Min returns the lowest sample value. +func (h *runtimeHistogram) Min() int64 { + return h.load().Min() +} + +// Sum returns the sum of all sample values. +func (h *runtimeHistogram) Sum() int64 { + return h.load().Sum() +} + +type runtimeHistogramSnapshot metrics.Float64Histogram + +func (h *runtimeHistogramSnapshot) Clear() { + panic("runtimeHistogram does not support Clear") +} +func (h *runtimeHistogramSnapshot) Update(int64) { + panic("runtimeHistogram does not support Update") +} +func (h *runtimeHistogramSnapshot) Sample() Sample { + return NilSample{} +} + +func (h *runtimeHistogramSnapshot) Snapshot() Histogram { + return h +} + +// Count returns the sample count. +func (h *runtimeHistogramSnapshot) Count() int64 { + var count int64 + for _, c := range h.Counts { + count += int64(c) + } + return count +} + +// Mean returns an approximation of the mean. +func (h *runtimeHistogramSnapshot) Mean() float64 { + if len(h.Counts) == 0 { + return 0 + } + mean, _ := h.mean() + return mean +} + +// mean computes the mean and also the total sample count. +func (h *runtimeHistogramSnapshot) mean() (mean, totalCount float64) { + var sum float64 + for i, c := range h.Counts { + midpoint := h.midpoint(i) + sum += midpoint * float64(c) + totalCount += float64(c) + } + return sum / totalCount, totalCount +} + +func (h *runtimeHistogramSnapshot) midpoint(bucket int) float64 { + high := h.Buckets[bucket+1] + low := h.Buckets[bucket] + if math.IsInf(high, 1) { + // The edge of the highest bucket can be +Inf, and it's supposed to mean that this + // bucket contains all remaining samples > low. We can't get the middle of an + // infinite range, so just return the lower bound of this bucket instead. + return low + } + if math.IsInf(low, -1) { + // Similarly, we can get -Inf in the left edge of the lowest bucket, + // and it means the bucket contains all remaining values < high. + return high + } + return (low + high) / 2 +} + +// StdDev approximates the standard deviation of the histogram. +func (h *runtimeHistogramSnapshot) StdDev() float64 { + return math.Sqrt(h.Variance()) +} + +// Variance approximates the variance of the histogram. +func (h *runtimeHistogramSnapshot) Variance() float64 { + if len(h.Counts) == 0 { + return 0 + } + + mean, totalCount := h.mean() + if totalCount <= 1 { + // There is no variance when there are zero or one items. + return 0 + } + + var sum float64 + for i, c := range h.Counts { + midpoint := h.midpoint(i) + d := midpoint - mean + sum += float64(c) * (d * d) + } + return sum / (totalCount - 1) +} + +// Percentile computes the p'th percentile value. +func (h *runtimeHistogramSnapshot) Percentile(p float64) float64 { + threshold := float64(h.Count()) * p + values := [1]float64{threshold} + h.computePercentiles(values[:]) + return values[0] +} + +// Percentiles computes all requested percentile values. +func (h *runtimeHistogramSnapshot) Percentiles(ps []float64) []float64 { + // Compute threshold values. We need these to be sorted + // for the percentile computation, but restore the original + // order later, so keep the indexes as well. + count := float64(h.Count()) + thresholds := make([]float64, len(ps)) + indexes := make([]int, len(ps)) + for i, percentile := range ps { + thresholds[i] = count * math.Max(0, math.Min(1.0, percentile)) + indexes[i] = i + } + sort.Sort(floatsAscendingKeepingIndex{thresholds, indexes}) + + // Now compute. The result is stored back into the thresholds slice. + h.computePercentiles(thresholds) + + // Put the result back into the requested order. + sort.Sort(floatsByIndex{thresholds, indexes}) + return thresholds +} + +func (h *runtimeHistogramSnapshot) computePercentiles(thresh []float64) { + var totalCount float64 + for i, count := range h.Counts { + totalCount += float64(count) + + for len(thresh) > 0 && thresh[0] < totalCount { + thresh[0] = h.Buckets[i] + thresh = thresh[1:] + } + if len(thresh) == 0 { + return + } + } +} + +// Note: runtime/metrics.Float64Histogram is a collection of float64s, but the methods +// below need to return int64 to satisfy the interface. The histogram provided by runtime +// also doesn't keep track of individual samples, so results are approximated. + +// Max returns the highest sample value. +func (h *runtimeHistogramSnapshot) Max() int64 { + for i := len(h.Counts) - 1; i >= 0; i-- { + count := h.Counts[i] + if count > 0 { + edge := h.Buckets[i+1] + if math.IsInf(edge, 1) { + edge = h.Buckets[i] + } + return int64(math.Ceil(edge)) + } + } + return 0 +} + +// Min returns the lowest sample value. +func (h *runtimeHistogramSnapshot) Min() int64 { + for i, count := range h.Counts { + if count > 0 { + return int64(math.Floor(h.Buckets[i])) + } + } + return 0 +} + +// Sum returns the sum of all sample values. +func (h *runtimeHistogramSnapshot) Sum() int64 { + var sum float64 + for i := range h.Counts { + sum += h.Buckets[i] * float64(h.Counts[i]) + } + return int64(math.Ceil(sum)) +} + +type floatsAscendingKeepingIndex struct { + values []float64 + indexes []int +} + +func (s floatsAscendingKeepingIndex) Len() int { + return len(s.values) +} + +func (s floatsAscendingKeepingIndex) Less(i, j int) bool { + return s.values[i] < s.values[j] +} + +func (s floatsAscendingKeepingIndex) Swap(i, j int) { + s.values[i], s.values[j] = s.values[j], s.values[i] + s.indexes[i], s.indexes[j] = s.indexes[j], s.indexes[i] +} + +type floatsByIndex struct { + values []float64 + indexes []int +} + +func (s floatsByIndex) Len() int { + return len(s.values) +} + +func (s floatsByIndex) Less(i, j int) bool { + return s.indexes[i] < s.indexes[j] +} + +func (s floatsByIndex) Swap(i, j int) { + s.values[i], s.values[j] = s.values[j], s.values[i] + s.indexes[i], s.indexes[j] = s.indexes[j], s.indexes[i] +} diff --git a/metrics/runtimehistogram_test.go b/metrics/runtimehistogram_test.go new file mode 100644 index 000000000000..d53a01438311 --- /dev/null +++ b/metrics/runtimehistogram_test.go @@ -0,0 +1,133 @@ +package metrics + +import ( + "fmt" + "math" + "reflect" + "runtime/metrics" + "testing" +) + +var _ Histogram = (*runtimeHistogram)(nil) + +type runtimeHistogramTest struct { + h metrics.Float64Histogram + + Count int64 + Min int64 + Max int64 + Sum int64 + Mean float64 + Variance float64 + StdDev float64 + Percentiles []float64 // .5 .8 .9 .99 .995 +} + +// This test checks the results of statistical functions implemented +// by runtimeHistogramSnapshot. +func TestRuntimeHistogramStats(t *testing.T) { + tests := []runtimeHistogramTest{ + 0: { + h: metrics.Float64Histogram{ + Counts: []uint64{}, + Buckets: []float64{}, + }, + Count: 0, + Max: 0, + Min: 0, + Sum: 0, + Mean: 0, + Variance: 0, + StdDev: 0, + Percentiles: []float64{0, 0, 0, 0, 0}, + }, + 1: { + // This checks the case where the highest bucket is +Inf. + h: metrics.Float64Histogram{ + Counts: []uint64{0, 1, 2}, + Buckets: []float64{0, 0.5, 1, math.Inf(1)}, + }, + Count: 3, + Max: 1, + Min: 0, + Sum: 3, + Mean: 0.9166666, + Percentiles: []float64{1, 1, 1, 1, 1}, + Variance: 0.020833, + StdDev: 0.144433, + }, + 2: { + h: metrics.Float64Histogram{ + Counts: []uint64{8, 6, 3, 1}, + Buckets: []float64{12, 16, 18, 24, 25}, + }, + Count: 18, + Max: 25, + Min: 12, + Sum: 270, + Mean: 16.75, + Variance: 10.3015, + StdDev: 3.2096, + Percentiles: []float64{16, 18, 18, 24, 24}, + }, + } + + for i, test := range tests { + t.Run(fmt.Sprint(i), func(t *testing.T) { + s := runtimeHistogramSnapshot(test.h) + + if v := s.Count(); v != test.Count { + t.Errorf("Count() = %v, want %v", v, test.Count) + } + if v := s.Min(); v != test.Min { + t.Errorf("Min() = %v, want %v", v, test.Min) + } + if v := s.Max(); v != test.Max { + t.Errorf("Max() = %v, want %v", v, test.Max) + } + if v := s.Sum(); v != test.Sum { + t.Errorf("Sum() = %v, want %v", v, test.Sum) + } + if v := s.Mean(); !approxEqual(v, test.Mean, 0.0001) { + t.Errorf("Mean() = %v, want %v", v, test.Mean) + } + if v := s.Variance(); !approxEqual(v, test.Variance, 0.0001) { + t.Errorf("Variance() = %v, want %v", v, test.Variance) + } + if v := s.StdDev(); !approxEqual(v, test.StdDev, 0.0001) { + t.Errorf("StdDev() = %v, want %v", v, test.StdDev) + } + ps := []float64{.5, .8, .9, .99, .995} + if v := s.Percentiles(ps); !reflect.DeepEqual(v, test.Percentiles) { + t.Errorf("Percentiles(%v) = %v, want %v", ps, v, test.Percentiles) + } + }) + } +} + +func approxEqual(x, y, ε float64) bool { + if math.IsInf(x, -1) && math.IsInf(y, -1) { + return true + } + if math.IsInf(x, 1) && math.IsInf(y, 1) { + return true + } + if math.IsNaN(x) && math.IsNaN(y) { + return true + } + return math.Abs(x-y) < ε +} + +// This test verifies that requesting Percentiles in unsorted order +// returns them in the requested order. +func TestRuntimeHistogramStatsPercentileOrder(t *testing.T) { + p := runtimeHistogramSnapshot{ + Counts: []uint64{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + Buckets: []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + } + result := p.Percentiles([]float64{1, 0.2, 0.5, 0.1, 0.2}) + expected := []float64{10, 2, 5, 1, 2} + if !reflect.DeepEqual(result, expected) { + t.Fatal("wrong result:", result) + } +} From ea65edaa28286dad533df1b6defa73ecab2538b4 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 11 Nov 2022 13:22:54 +0100 Subject: [PATCH 371/715] eth, catalyst: fix flaky tests (#26153) * eth/catalyst: fix time-dependent (flaky) test * eth: increase timeout on TestTransactionPropagation --- eth/catalyst/api_test.go | 74 ++++++++++++++++++++++++---------------- eth/handler_eth_test.go | 2 +- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 63f5d19cb9fc..7abca5a9a090 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -567,41 +567,55 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { var ( api = NewConsensusAPI(ethservice) parent = ethservice.BlockChain().CurrentBlock() + signer = types.LatestSigner(ethservice.BlockChain().Config()) // This EVM code generates a log when the contract is created. logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") ) for i := 0; i < 10; i++ { statedb, _ := ethservice.BlockChain().StateAt(parent.Root()) - nonce := statedb.GetNonce(testAddr) - tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) - ethservice.TxPool().AddLocal(tx) - - params := beacon.PayloadAttributesV1{ - Timestamp: parent.Time() + 1, - Random: crypto.Keccak256Hash([]byte{byte(i)}), - SuggestedFeeRecipient: parent.Coinbase(), - } - - fcState := beacon.ForkchoiceStateV1{ - HeadBlockHash: parent.Hash(), - SafeBlockHash: common.Hash{}, - FinalizedBlockHash: common.Hash{}, - } - resp, err := api.ForkchoiceUpdatedV1(fcState, ¶ms) - if err != nil { - t.Fatalf("error preparing payload, err=%v", err) - } - if resp.PayloadStatus.Status != beacon.VALID { - t.Fatalf("error preparing payload, invalid status: %v", resp.PayloadStatus.Status) - } - // give the payload some time to be built - time.Sleep(100 * time.Millisecond) - payload, err := api.GetPayloadV1(*resp.PayloadID) - if err != nil { - t.Fatalf("can't get payload: %v", err) - } - if len(payload.Transactions) == 0 { - t.Fatalf("payload should not be empty") + tx := types.MustSignNewTx(testKey, signer, &types.LegacyTx{ + Nonce: statedb.GetNonce(testAddr), + Value: new(big.Int), + Gas: 1000000, + GasPrice: big.NewInt(2 * params.InitialBaseFee), + Data: logCode, + }) + ethservice.TxPool().AddRemotesSync([]*types.Transaction{tx}) + var ( + params = beacon.PayloadAttributesV1{ + Timestamp: parent.Time() + 1, + Random: crypto.Keccak256Hash([]byte{byte(i)}), + SuggestedFeeRecipient: parent.Coinbase(), + } + fcState = beacon.ForkchoiceStateV1{ + HeadBlockHash: parent.Hash(), + SafeBlockHash: common.Hash{}, + FinalizedBlockHash: common.Hash{}, + } + payload *beacon.ExecutableDataV1 + resp beacon.ForkChoiceResponse + err error + ) + for i := 0; ; i++ { + if resp, err = api.ForkchoiceUpdatedV1(fcState, ¶ms); err != nil { + t.Fatalf("error preparing payload, err=%v", err) + } + if resp.PayloadStatus.Status != beacon.VALID { + t.Fatalf("error preparing payload, invalid status: %v", resp.PayloadStatus.Status) + } + // give the payload some time to be built + time.Sleep(50 * time.Millisecond) + if payload, err = api.GetPayloadV1(*resp.PayloadID); err != nil { + t.Fatalf("can't get payload: %v", err) + } + if len(payload.Transactions) > 0 { + break + } + // No luck this time we need to update the params and try again. + params.Timestamp = params.Timestamp + 1 + if i > 10 { + t.Fatalf("payload should not be empty") + } } execResp, err := api.NewPayloadV1(*payload) if err != nil { diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 885c2a971505..502cc8e6a9f6 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -451,7 +451,7 @@ func testTransactionPropagation(t *testing.T, protocol uint) { select { case event := <-txChs[i]: arrived += len(event.Txs) - case <-time.After(time.Second): + case <-time.After(2 * time.Second): t.Errorf("sink %d: transaction propagation timed out: have %d, want %d", i, arrived, len(txs)) timeout = true } From 8334b5f51a16b72cf2b3ebdc9e131a442c5289d7 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 11 Nov 2022 19:48:36 +0100 Subject: [PATCH 372/715] common/lru: fix race in lru (#26164) This fixes a problem in the SizeConstrainedLRU. The SCLRU uses an underlying simple lru which is not thread safe. During the Get operation, the recentness of the accessed item is updated, so it is not a pure read-operation. Therefore, the mutex we need is a full mutex, not RLock. This PR changes the mutex to be a regular Mutex, instead of RWMutex, so a reviewer can at a glance see that all affected locations are fixed. --- common/lru/blob_lru.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/lru/blob_lru.go b/common/lru/blob_lru.go index 3138f422ccfa..b24684256c88 100644 --- a/common/lru/blob_lru.go +++ b/common/lru/blob_lru.go @@ -33,7 +33,7 @@ type SizeConstrainedLRU struct { size uint64 maxSize uint64 lru *simplelru.LRU - lock sync.RWMutex + lock sync.Mutex } // NewSizeConstrainedLRU creates a new SizeConstrainedLRU. @@ -78,8 +78,8 @@ func (c *SizeConstrainedLRU) Add(key common.Hash, value []byte) (evicted bool) { // Get looks up a key's value from the cache. func (c *SizeConstrainedLRU) Get(key common.Hash) []byte { - c.lock.RLock() - defer c.lock.RUnlock() + c.lock.Lock() + defer c.lock.Unlock() if v, ok := c.lru.Get(key); ok { return v.([]byte) From e34e540e4c6cfaae67543427f7c36bff1408fcaf Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 14 Nov 2022 12:38:10 +0100 Subject: [PATCH 373/715] accounts/keystore: replace inotify with fsnotify (#26176) --- accounts/keystore/watch.go | 33 +++++++++++++++++++++++++-------- go.mod | 2 +- go.sum | 33 +++------------------------------ 3 files changed, 29 insertions(+), 39 deletions(-) diff --git a/accounts/keystore/watch.go b/accounts/keystore/watch.go index ae72a1ccd666..3f64b89c585e 100644 --- a/accounts/keystore/watch.go +++ b/accounts/keystore/watch.go @@ -23,7 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/log" - "github.com/rjeczalik/notify" + "github.com/fsnotify/fsnotify" ) type watcher struct { @@ -31,14 +31,12 @@ type watcher struct { running bool // set to true when runloop begins runEnded bool // set to true when runloop ends starting bool // set to true prior to runloop starting - ev chan notify.EventInfo quit chan struct{} } func newWatcher(ac *accountCache) *watcher { return &watcher{ ac: ac, - ev: make(chan notify.EventInfo, 10), quit: make(chan struct{}), } } @@ -71,12 +69,19 @@ func (w *watcher) loop() { }() logger := log.New("path", w.ac.keydir) - if err := notify.Watch(w.ac.keydir, w.ev, notify.All); err != nil { - logger.Trace("Failed to watch keystore folder", "err", err) + // Create new watcher. + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Error("Failed to start filesystem watcher", "err", err) return } - defer notify.Stop(w.ev) - logger.Trace("Started watching keystore folder") + defer watcher.Close() + if err := watcher.Add(w.ac.keydir); err != nil { + logger.Warn("Failed to watch keystore folder", "err", err) + return + } + + logger.Trace("Started watching keystore folder", "folder", w.ac.keydir) defer logger.Trace("Stopped watching keystore folder") w.ac.mu.Lock() @@ -100,12 +105,24 @@ func (w *watcher) loop() { select { case <-w.quit: return - case <-w.ev: + case _, ok := <-watcher.Events: + if !ok { + return + } // Trigger the scan (with delay), if not already triggered if !rescanTriggered { debounce.Reset(debounceDuration) rescanTriggered = true } + // The fsnotify library does provide more granular event-info, it + // would be possible to refresh individual affected files instead + // of scheduling a full rescan. For most cases though, the + // full rescan is quick and obviously simplest. + case err, ok := <-watcher.Errors: + if !ok { + return + } + log.Info("Filsystem watcher error", "err", err) case <-debounce.C: w.ac.scanAccounts() rescanTriggered = false diff --git a/go.mod b/go.mod index 01c5e07bbe2a..96353b9aaf0a 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/fatih/color v1.7.0 github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 + github.com/fsnotify/fsnotify v1.6.0 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 github.com/go-stack/stack v1.8.1 @@ -49,7 +50,6 @@ require ( github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 github.com/prometheus/tsdb v0.7.1 - github.com/rjeczalik/notify v0.9.1 github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 diff --git a/go.sum b/go.sum index 05324488c29c..1c4f16ae2ded 100644 --- a/go.sum +++ b/go.sum @@ -25,7 +25,6 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -65,12 +64,10 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2 github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -121,7 +118,6 @@ github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0= @@ -130,8 +126,9 @@ github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlK github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgxrzK5E1fW7RQGeDwE8F/ZZnUYc= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= @@ -284,7 +281,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= @@ -330,7 +326,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= @@ -367,8 +362,6 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= -github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= -github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -388,7 +381,6 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -413,7 +405,6 @@ github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZF github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -424,8 +415,6 @@ github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6Ut github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -442,7 +431,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -455,7 +443,6 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -475,8 +462,6 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -504,9 +489,6 @@ golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -560,19 +542,12 @@ golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -613,12 +588,10 @@ golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191126055441-b0650ceb63d9/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 8c5ce1107b3110c7cb735d8dfa91c9c701393c85 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 14 Nov 2022 14:48:01 +0100 Subject: [PATCH 374/715] eth/filters: send rpctransactions in pending-subscription (#26126) This PR changes the pending tx subscription to return RPCTransaction types instead of normal Transaction objects. This will fix the inconsistencies with other tx returning API methods (i.e. getTransactionByHash), and also fill in the sender value for the tx. co-authored by @s1na --- accounts/abi/bind/backends/simulated.go | 8 ++++++++ eth/filters/api.go | 6 +++++- eth/filters/filter_system.go | 3 +++ eth/filters/filter_system_test.go | 8 ++++++++ internal/ethapi/api.go | 16 ++++++++-------- internal/ethapi/backend.go | 10 ++++++++-- 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 4c259e03c93c..0224488ddd0d 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -915,6 +915,14 @@ func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.Matche panic("not supported") } +func (fb *filterBackend) ChainConfig() *params.ChainConfig { + panic("not supported") +} + +func (fb *filterBackend) CurrentHeader() *types.Header { + panic("not supported") +} + func nullSubscription() event.Subscription { return event.NewSubscription(func(quit <-chan struct{}) error { <-quit diff --git a/eth/filters/api.go b/eth/filters/api.go index f52bff6f3c32..0b4e9a91a885 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/rpc" ) @@ -147,15 +148,18 @@ func (api *FilterAPI) NewPendingTransactions(ctx context.Context, fullTx *bool) go func() { txs := make(chan []*types.Transaction, 128) pendingTxSub := api.events.SubscribePendingTxs(txs) + chainConfig := api.sys.backend.ChainConfig() for { select { case txs := <-txs: // To keep the original behaviour, send a single tx hash in one notification. // TODO(rjl493456442) Send a batch of tx hashes in one notification + latest := api.sys.backend.CurrentHeader() for _, tx := range txs { if fullTx != nil && *fullTx { - notifier.Notify(rpcSub.ID, tx) + rpcTx := ethapi.NewRPCPendingTransaction(tx, latest, chainConfig) + notifier.Notify(rpcSub.ID, rpcTx) } else { notifier.Notify(rpcSub.ID, tx.Hash()) } diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index e86a67abfda3..ea0233dd0829 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" lru "github.com/hashicorp/golang-lru" ) @@ -61,6 +62,8 @@ type Backend interface { GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) PendingBlockAndReceipts() (*types.Block, types.Receipts) + CurrentHeader() *types.Header + ChainConfig() *params.ChainConfig SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index a41271f7b843..0609acc42861 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -50,6 +50,14 @@ type testBackend struct { chainFeed event.Feed } +func (b *testBackend) ChainConfig() *params.ChainConfig { + panic("implement me") +} + +func (b *testBackend) CurrentHeader() *types.Header { + panic("implement me") +} + func (b *testBackend) ChainDb() ethdb.Database { return b.db } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 538644908ba0..ea0cbfe867aa 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -171,7 +171,7 @@ func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { for account, txs := range pending { dump := make(map[string]*RPCTransaction) for _, tx := range txs { - dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) } content["pending"][account.Hex()] = dump } @@ -179,7 +179,7 @@ func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { for account, txs := range queue { dump := make(map[string]*RPCTransaction) for _, tx := range txs { - dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) } content["queued"][account.Hex()] = dump } @@ -195,14 +195,14 @@ func (s *TxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCT // Build the pending transactions dump := make(map[string]*RPCTransaction, len(pending)) for _, tx := range pending { - dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) } content["pending"] = dump // Build the queued transactions dump = make(map[string]*RPCTransaction, len(queue)) for _, tx := range queue { - dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) } content["queued"] = dump @@ -1344,8 +1344,8 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber return result } -// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation -func newRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig) *RPCTransaction { +// NewRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation +func NewRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig) *RPCTransaction { var baseFee *big.Int blockNumber := uint64(0) if current != nil { @@ -1577,7 +1577,7 @@ func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.H } // No finalized transaction, try to retrieve it from the pool if tx := s.b.GetPoolTransaction(hash); tx != nil { - return newRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil + return NewRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil } // Transaction unknown, return as such @@ -1847,7 +1847,7 @@ func (s *TransactionAPI) PendingTransactions() ([]*RPCTransaction, error) { for _, tx := range pending { from, _ := types.Sender(s.signer, tx) if _, exists := accounts[from]; exists { - transactions = append(transactions, newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())) + transactions = append(transactions, NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())) } } return transactions, nil diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 5b4ceb631069..3bc7819a7d51 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -27,10 +27,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" @@ -87,9 +87,15 @@ type Backend interface { ChainConfig() *params.ChainConfig Engine() consensus.Engine + // This is copied from filters.Backend // eth/filters needs to be initialized from this backend type, so methods needed by // it must also be included here. - filters.Backend + GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) + SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription + SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription + SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription + BloomStatus() (uint64, uint64) + ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) } func GetAPIs(apiBackend Backend) []rpc.API { From f58ebd9696326082b10cb19ee5e071952e872e9e Mon Sep 17 00:00:00 2001 From: Jolly Zhao Date: Mon, 14 Nov 2022 22:16:52 +0800 Subject: [PATCH 375/715] all: use github.com/deckarep/golang-set/v2 (generic set) (#26159) Co-authored-by: Felix Lange --- accounts/keystore/account_cache.go | 15 +++++++-------- accounts/keystore/file_cache.go | 12 ++++++------ consensus/ethash/consensus.go | 4 ++-- eth/fetcher/tx_fetcher.go | 6 +++--- eth/protocols/eth/peer.go | 6 +++--- go.mod | 2 +- go.sum | 30 ++++++++++++++++++++++++++++++ miner/worker.go | 16 ++++++++-------- rpc/server.go | 14 +++++++------- rpc/websocket.go | 8 ++++---- 10 files changed, 71 insertions(+), 42 deletions(-) diff --git a/accounts/keystore/account_cache.go b/accounts/keystore/account_cache.go index db49ec349942..12f92d261951 100644 --- a/accounts/keystore/account_cache.go +++ b/accounts/keystore/account_cache.go @@ -27,7 +27,7 @@ import ( "sync" "time" - mapset "github.com/deckarep/golang-set" + mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" @@ -79,7 +79,7 @@ func newAccountCache(keydir string) (*accountCache, chan struct{}) { keydir: keydir, byAddr: make(map[common.Address][]accounts.Account), notify: make(chan struct{}, 1), - fileC: fileCache{all: mapset.NewThreadUnsafeSet()}, + fileC: fileCache{all: mapset.NewThreadUnsafeSet[string]()}, } ac.watcher = newWatcher(ac) return ac, ac.notify @@ -283,16 +283,15 @@ func (ac *accountCache) scanAccounts() error { // Process all the file diffs start := time.Now() - for _, p := range creates.ToSlice() { - if a := readAccount(p.(string)); a != nil { + for _, path := range creates.ToSlice() { + if a := readAccount(path); a != nil { ac.add(*a) } } - for _, p := range deletes.ToSlice() { - ac.deleteByFile(p.(string)) + for _, path := range deletes.ToSlice() { + ac.deleteByFile(path) } - for _, p := range updates.ToSlice() { - path := p.(string) + for _, path := range updates.ToSlice() { ac.deleteByFile(path) if a := readAccount(path); a != nil { ac.add(*a) diff --git a/accounts/keystore/file_cache.go b/accounts/keystore/file_cache.go index 79f9a2963743..63eb8503744f 100644 --- a/accounts/keystore/file_cache.go +++ b/accounts/keystore/file_cache.go @@ -23,20 +23,20 @@ import ( "sync" "time" - mapset "github.com/deckarep/golang-set" + mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/log" ) // fileCache is a cache of files seen during scan of keystore. type fileCache struct { - all mapset.Set // Set of all files from the keystore folder - lastMod time.Time // Last time instance when a file was modified + all mapset.Set[string] // Set of all files from the keystore folder + lastMod time.Time // Last time instance when a file was modified mu sync.Mutex } // scan performs a new scan on the given directory, compares against the already // cached filenames, and returns file sets: creates, deletes, updates. -func (fc *fileCache) scan(keyDir string) (mapset.Set, mapset.Set, mapset.Set, error) { +func (fc *fileCache) scan(keyDir string) (mapset.Set[string], mapset.Set[string], mapset.Set[string], error) { t0 := time.Now() // List all the files from the keystore folder @@ -50,8 +50,8 @@ func (fc *fileCache) scan(keyDir string) (mapset.Set, mapset.Set, mapset.Set, er defer fc.mu.Unlock() // Iterate all the files and gather their metadata - all := mapset.NewThreadUnsafeSet() - mods := mapset.NewThreadUnsafeSet() + all := mapset.NewThreadUnsafeSet[string]() + mods := mapset.NewThreadUnsafeSet[string]() var newLastMod time.Time for _, fi := range files { diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 1c38b80ea59b..b49fcf0ce5a7 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -24,7 +24,7 @@ import ( "runtime" "time" - mapset "github.com/deckarep/golang-set" + mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" @@ -214,7 +214,7 @@ func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Blo return nil } // Gather the set of past uncles and ancestors - uncles, ancestors := mapset.NewSet(), make(map[common.Hash]*types.Header) + uncles, ancestors := mapset.NewSet[common.Hash](), make(map[common.Hash]*types.Header) number, parent := block.NumberU64()-1, block.ParentHash() for i := 0; i < 7; i++ { diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index a9e994a8c778..39727e0079d7 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -24,7 +24,7 @@ import ( "sort" "time" - mapset "github.com/deckarep/golang-set" + mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/core/txpool" @@ -148,7 +148,7 @@ type TxFetcher struct { drop chan *txDrop quit chan struct{} - underpriced mapset.Set // Transactions discarded as too cheap (don't re-fetch) + underpriced mapset.Set[common.Hash] // Transactions discarded as too cheap (don't re-fetch) // Stage 1: Waiting lists for newly discovered transactions that might be // broadcast without needing explicit request/reply round trips. @@ -202,7 +202,7 @@ func NewTxFetcherForTests( fetching: make(map[common.Hash]string), requests: make(map[string]*txRequest), alternates: make(map[common.Hash]map[string]struct{}), - underpriced: mapset.NewSet(), + underpriced: mapset.NewSet[common.Hash](), hasTx: hasTx, addTxs: addTxs, fetchTxs: fetchTxs, diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index 070ce0825f9a..219f486c8e6f 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -21,7 +21,7 @@ import ( "math/rand" "sync" - mapset "github.com/deckarep/golang-set" + mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/p2p" @@ -502,7 +502,7 @@ func (p *Peer) RequestTxs(hashes []common.Hash) error { // knownCache is a cache for known hashes. type knownCache struct { - hashes mapset.Set + hashes mapset.Set[common.Hash] max int } @@ -510,7 +510,7 @@ type knownCache struct { func newKnownCache(max int) *knownCache { return &knownCache{ max: max, - hashes: mapset.NewSet(), + hashes: mapset.NewSet[common.Hash](), } } diff --git a/go.mod b/go.mod index 96353b9aaf0a..60afbfffb965 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/cloudflare/cloudflare-go v0.14.0 github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f github.com/davecgh/go-spew v1.1.1 - github.com/deckarep/golang-set v1.8.0 + github.com/deckarep/golang-set/v2 v2.1.0 github.com/docker/docker v1.6.2 github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf github.com/edsrzf/mmap-go v1.0.0 diff --git a/go.sum b/go.sum index 1c4f16ae2ded..82818291cb60 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,7 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -64,10 +65,12 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2 github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -93,6 +96,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= +github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= +github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= @@ -118,6 +123,7 @@ github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0= @@ -281,6 +287,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= @@ -326,6 +333,7 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= @@ -362,6 +370,7 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -381,6 +390,7 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -405,6 +415,7 @@ github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZF github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -415,6 +426,8 @@ github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6Ut github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -431,6 +444,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -443,6 +457,7 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -462,6 +477,8 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -489,6 +506,9 @@ golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -542,12 +562,20 @@ golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -588,10 +616,12 @@ golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191126055441-b0650ceb63d9/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/miner/worker.go b/miner/worker.go index b38d68e7ea0c..57c1fc7b9f53 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -24,7 +24,7 @@ import ( "sync/atomic" "time" - mapset "github.com/deckarep/golang-set" + mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" @@ -88,11 +88,11 @@ var ( type environment struct { signer types.Signer - state *state.StateDB // apply state changes here - ancestors mapset.Set // ancestor set (used for checking uncle parent validity) - family mapset.Set // family set (used for checking uncle invalidity) - tcount int // tx count in cycle - gasPool *core.GasPool // available gas used to pack transactions + state *state.StateDB // apply state changes here + ancestors mapset.Set[common.Hash] // ancestor set (used for checking uncle parent validity) + family mapset.Set[common.Hash] // family set (used for checking uncle invalidity) + tcount int // tx count in cycle + gasPool *core.GasPool // available gas used to pack transactions coinbase common.Address header *types.Header @@ -795,8 +795,8 @@ func (w *worker) makeEnv(parent *types.Block, header *types.Header, coinbase com signer: types.MakeSigner(w.chainConfig, header.Number), state: state, coinbase: coinbase, - ancestors: mapset.NewSet(), - family: mapset.NewSet(), + ancestors: mapset.NewSet[common.Hash](), + family: mapset.NewSet[common.Hash](), header: header, uncles: make(map[common.Hash]*types.Header), } diff --git a/rpc/server.go b/rpc/server.go index bf1f71a28e26..4f23c93bae46 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -21,7 +21,7 @@ import ( "io" "sync/atomic" - mapset "github.com/deckarep/golang-set" + mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/log" ) @@ -46,12 +46,12 @@ type Server struct { services serviceRegistry idgen func() ID run int32 - codecs mapset.Set + codecs mapset.Set[*ServerCodec] } // NewServer creates a new server instance with no registered handlers. func NewServer() *Server { - server := &Server{idgen: randomIDGenerator(), codecs: mapset.NewSet(), run: 1} + server := &Server{idgen: randomIDGenerator(), codecs: mapset.NewSet[*ServerCodec](), run: 1} // Register the default service providing meta information about the RPC service such // as the services and methods it offers. rpcService := &RPCService{server} @@ -81,8 +81,8 @@ func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { } // Add the codec to the set so it can be closed by Stop. - s.codecs.Add(codec) - defer s.codecs.Remove(codec) + s.codecs.Add(&codec) + defer s.codecs.Remove(&codec) c := initClient(codec, s.idgen, &s.services) <-codec.closed() @@ -122,8 +122,8 @@ func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { func (s *Server) Stop() { if atomic.CompareAndSwapInt32(&s.run, 1, 0) { log.Debug("RPC server shutting down") - s.codecs.Each(func(c interface{}) bool { - c.(ServerCodec).close() + s.codecs.Each(func(c *ServerCodec) bool { + (*c).close() return true }) } diff --git a/rpc/websocket.go b/rpc/websocket.go index f2a923446cac..f6d09288590c 100644 --- a/rpc/websocket.go +++ b/rpc/websocket.go @@ -27,7 +27,7 @@ import ( "sync" "time" - mapset "github.com/deckarep/golang-set" + mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/log" "github.com/gorilla/websocket" ) @@ -69,7 +69,7 @@ func (s *Server) WebsocketHandler(allowedOrigins []string) http.Handler { // websocket upgrade process. When a '*' is specified as an allowed origins all // connections are accepted. func wsHandshakeValidator(allowedOrigins []string) func(*http.Request) bool { - origins := mapset.NewSet() + origins := mapset.NewSet[string]() allowAllOrigins := false for _, origin := range allowedOrigins { @@ -122,10 +122,10 @@ func (e wsHandshakeError) Error() string { return s } -func originIsAllowed(allowedOrigins mapset.Set, browserOrigin string) bool { +func originIsAllowed(allowedOrigins mapset.Set[string], browserOrigin string) bool { it := allowedOrigins.Iterator() for origin := range it.C { - if ruleAllowsOrigin(origin.(string), browserOrigin) { + if ruleAllowsOrigin(origin, browserOrigin) { return true } } From 9afc6816d2301b52e01e0a1c84a933a879115571 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 14 Nov 2022 15:41:56 +0100 Subject: [PATCH 376/715] common/lru: add generic LRU implementation (#26162) It seems there is no fully typed library implementation of an LRU cache. So I wrote one. Method names are the same as github.com/hashicorp/golang-lru, and the new type can be used as a drop-in replacement. Two reasons to do this: - It's much easier to understand what a cache is for when the types are right there. - Performance: the new implementation is slightly faster and performs zero memory allocations in Add when the cache is at capacity. Overall, memory usage of the cache is much reduced because keys are values are no longer wrapped in interface. --- common/lru/basiclru.go | 223 ++++++++++++++++++++++++++++++ common/lru/basiclru_test.go | 240 +++++++++++++++++++++++++++++++++ common/lru/blob_lru.go | 44 +++--- common/lru/blob_lru_test.go | 91 +++++++++---- common/lru/lru.go | 95 +++++++++++++ core/blockchain.go | 37 +++-- core/blockchain_reader.go | 11 +- core/headerchain.go | 30 ++--- core/state/database.go | 24 ++-- eth/filters/filter_system.go | 13 +- eth/gasprice/feehistory.go | 14 +- eth/gasprice/gasprice.go | 7 +- p2p/discover/v5wire/session.go | 17 +-- p2p/dnsdisc/client.go | 12 +- 14 files changed, 711 insertions(+), 147 deletions(-) create mode 100644 common/lru/basiclru.go create mode 100644 common/lru/basiclru_test.go create mode 100644 common/lru/lru.go diff --git a/common/lru/basiclru.go b/common/lru/basiclru.go new file mode 100644 index 000000000000..b3369cf1f252 --- /dev/null +++ b/common/lru/basiclru.go @@ -0,0 +1,223 @@ +// Copyright 2022 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 lru implements generically-typed LRU caches. +package lru + +// BasicLRU is a simple LRU cache. +// +// This type is not safe for concurrent use. +// The zero value is not valid, instances must be created using NewCache. +type BasicLRU[K comparable, V any] struct { + list *list[K] + items map[K]cacheItem[K, V] + cap int +} + +type cacheItem[K any, V any] struct { + elem *listElem[K] + value V +} + +// NewBasicLRU creates a new LRU cache. +func NewBasicLRU[K comparable, V any](capacity int) BasicLRU[K, V] { + if capacity < 0 { + capacity = 1 + } + c := BasicLRU[K, V]{ + items: make(map[K]cacheItem[K, V]), + list: newList[K](), + cap: capacity, + } + return c +} + +// Add adds a value to the cache. Returns true if an item was evicted to store the new item. +func (c *BasicLRU[K, V]) Add(key K, value V) (evicted bool) { + item, ok := c.items[key] + if ok { + // Already exists in cache. + item.value = value + c.items[key] = item + c.list.moveToFront(item.elem) + return false + } + + var elem *listElem[K] + if c.Len() >= c.cap { + elem = c.list.removeLast() + delete(c.items, elem.v) + evicted = true + } else { + elem = new(listElem[K]) + } + + // Store the new item. + // Note that, if another item was evicted, we re-use its list element here. + elem.v = key + c.items[key] = cacheItem[K, V]{elem, value} + c.list.pushElem(elem) + return evicted +} + +// Contains reports whether the given key exists in the cache. +func (c *BasicLRU[K, V]) Contains(key K) bool { + _, ok := c.items[key] + return ok +} + +// Get retrieves a value from the cache. This marks the key as recently used. +func (c *BasicLRU[K, V]) Get(key K) (value V, ok bool) { + item, ok := c.items[key] + if !ok { + return value, false + } + c.list.moveToFront(item.elem) + return item.value, true +} + +// GetOldest retrieves the least-recently-used item. +// Note that this does not update the item's recency. +func (c *BasicLRU[K, V]) GetOldest() (key K, value V, ok bool) { + lastElem := c.list.last() + if lastElem == nil { + return key, value, false + } + key = lastElem.v + item := c.items[key] + return key, item.value, true +} + +// Len returns the current number of items in the cache. +func (c *BasicLRU[K, V]) Len() int { + return len(c.items) +} + +// Peek retrieves a value from the cache, but does not mark the key as recently used. +func (c *BasicLRU[K, V]) Peek(key K) (value V, ok bool) { + item, ok := c.items[key] + return item.value, ok +} + +// Purge empties the cache. +func (c *BasicLRU[K, V]) Purge() { + c.list.init() + for k := range c.items { + delete(c.items, k) + } +} + +// Remove drops an item from the cache. Returns true if the key was present in cache. +func (c *BasicLRU[K, V]) Remove(key K) bool { + item, ok := c.items[key] + if ok { + delete(c.items, key) + c.list.remove(item.elem) + } + return ok +} + +// RemoveOldest drops the least recently used item. +func (c *BasicLRU[K, V]) RemoveOldest() (key K, value V, ok bool) { + lastElem := c.list.last() + if lastElem == nil { + return key, value, false + } + + key = lastElem.v + item := c.items[key] + delete(c.items, key) + c.list.remove(lastElem) + return key, item.value, true +} + +// Keys returns all keys in the cache. +func (c *BasicLRU[K, V]) Keys() []K { + keys := make([]K, 0, len(c.items)) + return c.list.appendTo(keys) +} + +// list is a doubly-linked list holding items of type he. +// The zero value is not valid, use newList to create lists. +type list[T any] struct { + root listElem[T] +} + +type listElem[T any] struct { + next *listElem[T] + prev *listElem[T] + v T +} + +func newList[T any]() *list[T] { + l := new(list[T]) + l.init() + return l +} + +// init reinitializes the list, making it empty. +func (l *list[T]) init() { + l.root.next = &l.root + l.root.prev = &l.root +} + +// push adds an element to the front of the list. +func (l *list[T]) pushElem(e *listElem[T]) { + e.prev = &l.root + e.next = l.root.next + l.root.next = e + e.next.prev = e +} + +// moveToFront makes 'node' the head of the list. +func (l *list[T]) moveToFront(e *listElem[T]) { + e.prev.next = e.next + e.next.prev = e.prev + l.pushElem(e) +} + +// remove removes an element from the list. +func (l *list[T]) remove(e *listElem[T]) { + e.prev.next = e.next + e.next.prev = e.prev + e.next, e.prev = nil, nil +} + +// removeLast removes the last element of the list. +func (l *list[T]) removeLast() *listElem[T] { + last := l.last() + if last != nil { + l.remove(last) + } + return last +} + +// last returns the last element of the list, or nil if the list is empty. +func (l *list[T]) last() *listElem[T] { + e := l.root.prev + if e == &l.root { + return nil + } + return e +} + +// appendTo appends all list elements to a slice. +func (l *list[T]) appendTo(slice []T) []T { + for e := l.root.prev; e != &l.root; e = e.prev { + slice = append(slice, e.v) + } + return slice +} diff --git a/common/lru/basiclru_test.go b/common/lru/basiclru_test.go new file mode 100644 index 000000000000..68e13bfc92ec --- /dev/null +++ b/common/lru/basiclru_test.go @@ -0,0 +1,240 @@ +// Copyright 2022 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 lru + +import ( + "fmt" + "io" + "math/rand" + "testing" +) + +// Some of these test cases were adapted +// from https://github.com/hashicorp/golang-lru/blob/master/simplelru/lru_test.go + +func TestBasicLRU(t *testing.T) { + cache := NewBasicLRU[int, int](128) + + for i := 0; i < 256; i++ { + cache.Add(i, i) + } + if cache.Len() != 128 { + t.Fatalf("bad len: %v", cache.Len()) + } + + // Check that Keys returns least-recent key first. + keys := cache.Keys() + if len(keys) != 128 { + t.Fatal("wrong Keys() length", len(keys)) + } + for i, k := range keys { + v, ok := cache.Peek(k) + if !ok { + t.Fatalf("expected key %d be present", i) + } + if v != k { + t.Fatalf("expected %d == %d", k, v) + } + if v != i+128 { + t.Fatalf("wrong value at key %d: %d, want %d", i, v, i+128) + } + } + + for i := 0; i < 128; i++ { + _, ok := cache.Get(i) + if ok { + t.Fatalf("%d should be evicted", i) + } + } + for i := 128; i < 256; i++ { + _, ok := cache.Get(i) + if !ok { + t.Fatalf("%d should not be evicted", i) + } + } + + for i := 128; i < 192; i++ { + ok := cache.Remove(i) + if !ok { + t.Fatalf("%d should be in cache", i) + } + ok = cache.Remove(i) + if ok { + t.Fatalf("%d should not be in cache", i) + } + _, ok = cache.Get(i) + if ok { + t.Fatalf("%d should be deleted", i) + } + } + + // Request item 192. + cache.Get(192) + // It should be the last item returned by Keys(). + for i, k := range cache.Keys() { + if (i < 63 && k != i+193) || (i == 63 && k != 192) { + t.Fatalf("out of order key: %v", k) + } + } + + cache.Purge() + if cache.Len() != 0 { + t.Fatalf("bad len: %v", cache.Len()) + } + if _, ok := cache.Get(200); ok { + t.Fatalf("should contain nothing") + } +} + +func TestBasicLRUAddExistingKey(t *testing.T) { + cache := NewBasicLRU[int, int](1) + + cache.Add(1, 1) + cache.Add(1, 2) + + v, _ := cache.Get(1) + if v != 2 { + t.Fatal("wrong value:", v) + } +} + +// This test checks GetOldest and RemoveOldest. +func TestBasicLRUGetOldest(t *testing.T) { + cache := NewBasicLRU[int, int](128) + for i := 0; i < 256; i++ { + cache.Add(i, i) + } + + k, _, ok := cache.GetOldest() + if !ok { + t.Fatalf("missing") + } + if k != 128 { + t.Fatalf("bad: %v", k) + } + + k, _, ok = cache.RemoveOldest() + if !ok { + t.Fatalf("missing") + } + if k != 128 { + t.Fatalf("bad: %v", k) + } + + k, _, ok = cache.RemoveOldest() + if !ok { + t.Fatalf("missing oldest item") + } + if k != 129 { + t.Fatalf("wrong oldest item: %v", k) + } +} + +// Test that Add returns true/false if an eviction occurred +func TestBasicLRUAddReturnValue(t *testing.T) { + cache := NewBasicLRU[int, int](1) + if cache.Add(1, 1) { + t.Errorf("first add shouldn't have evicted") + } + if !cache.Add(2, 2) { + t.Errorf("second add should have evicted") + } +} + +// This test verifies that Contains doesn't change item recency. +func TestBasicLRUContains(t *testing.T) { + cache := NewBasicLRU[int, int](2) + cache.Add(1, 1) + cache.Add(2, 2) + if !cache.Contains(1) { + t.Errorf("1 should be in the cache") + } + cache.Add(3, 3) + if cache.Contains(1) { + t.Errorf("Contains should not have updated recency of 1") + } +} + +func BenchmarkLRU(b *testing.B) { + var ( + capacity = 1000 + indexes = make([]int, capacity*20) + keys = make([]string, capacity) + values = make([][]byte, capacity) + ) + for i := range indexes { + indexes[i] = rand.Intn(capacity) + } + for i := range keys { + b := make([]byte, 32) + rand.Read(b) + keys[i] = string(b) + rand.Read(b) + values[i] = b + } + + var sink []byte + + b.Run("Add/BasicLRU", func(b *testing.B) { + cache := NewBasicLRU[int, int](capacity) + for i := 0; i < b.N; i++ { + cache.Add(i, i) + } + }) + b.Run("Get/BasicLRU", func(b *testing.B) { + cache := NewBasicLRU[string, []byte](capacity) + for i := 0; i < capacity; i++ { + index := indexes[i] + cache.Add(keys[index], values[index]) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + k := keys[indexes[i%len(indexes)]] + v, ok := cache.Get(k) + if ok { + sink = v + } + } + }) + + // // vs. github.com/hashicorp/golang-lru/simplelru + // b.Run("Add/simplelru.LRU", func(b *testing.B) { + // cache, _ := simplelru.NewLRU(capacity, nil) + // for i := 0; i < b.N; i++ { + // cache.Add(i, i) + // } + // }) + // b.Run("Get/simplelru.LRU", func(b *testing.B) { + // cache, _ := simplelru.NewLRU(capacity, nil) + // for i := 0; i < capacity; i++ { + // index := indexes[i] + // cache.Add(keys[index], values[index]) + // } + // + // b.ResetTimer() + // for i := 0; i < b.N; i++ { + // k := keys[indexes[i%len(indexes)]] + // v, ok := cache.Get(k) + // if ok { + // sink = v.([]byte) + // } + // } + // }) + + fmt.Fprintln(io.Discard, sink) +} diff --git a/common/lru/blob_lru.go b/common/lru/blob_lru.go index b24684256c88..c9b33985032c 100644 --- a/common/lru/blob_lru.go +++ b/common/lru/blob_lru.go @@ -19,33 +19,32 @@ package lru import ( "math" "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/hashicorp/golang-lru/simplelru" ) -// SizeConstrainedLRU is a wrapper around simplelru.LRU. The simplelru.LRU is capable -// of item-count constraints, but is not capable of enforcing a byte-size constraint, -// hence this wrapper. +// blobType is the type constraint for values stored in SizeConstrainedCache. +type blobType interface { + ~[]byte | ~string +} + +// SizeConstrainedCache is a cache where capacity is in bytes (instead of item count). When the cache +// is at capacity, and a new item is added, older items are evicted until the size +// constraint is met. +// // OBS: This cache assumes that items are content-addressed: keys are unique per content. // In other words: two Add(..) with the same key K, will always have the same value V. -type SizeConstrainedLRU struct { +type SizeConstrainedCache[K comparable, V blobType] struct { size uint64 maxSize uint64 - lru *simplelru.LRU + lru BasicLRU[K, V] lock sync.Mutex } -// NewSizeConstrainedLRU creates a new SizeConstrainedLRU. -func NewSizeConstrainedLRU(max uint64) *SizeConstrainedLRU { - lru, err := simplelru.NewLRU(math.MaxInt, nil) - if err != nil { - panic(err) - } - return &SizeConstrainedLRU{ +// NewSizeConstrainedCache creates a new size-constrained LRU cache. +func NewSizeConstrainedCache[K comparable, V blobType](maxSize uint64) *SizeConstrainedCache[K, V] { + return &SizeConstrainedCache[K, V]{ size: 0, - maxSize: max, - lru: lru, + maxSize: maxSize, + lru: NewBasicLRU[K, V](math.MaxInt), } } @@ -53,7 +52,7 @@ func NewSizeConstrainedLRU(max uint64) *SizeConstrainedLRU { // OBS: This cache assumes that items are content-addressed: keys are unique per content. // In other words: two Add(..) with the same key K, will always have the same value V. // OBS: The value is _not_ copied on Add, so the caller must not modify it afterwards. -func (c *SizeConstrainedLRU) Add(key common.Hash, value []byte) (evicted bool) { +func (c *SizeConstrainedCache[K, V]) Add(key K, value V) (evicted bool) { c.lock.Lock() defer c.lock.Unlock() @@ -68,7 +67,7 @@ func (c *SizeConstrainedLRU) Add(key common.Hash, value []byte) (evicted bool) { // list is now empty. Break break } - targetSize -= uint64(len(v.([]byte))) + targetSize -= uint64(len(v)) } c.size = targetSize } @@ -77,12 +76,9 @@ func (c *SizeConstrainedLRU) Add(key common.Hash, value []byte) (evicted bool) { } // Get looks up a key's value from the cache. -func (c *SizeConstrainedLRU) Get(key common.Hash) []byte { +func (c *SizeConstrainedCache[K, V]) Get(key K) (V, bool) { c.lock.Lock() defer c.lock.Unlock() - if v, ok := c.lru.Get(key); ok { - return v.([]byte) - } - return nil + return c.lru.Get(key) } diff --git a/common/lru/blob_lru_test.go b/common/lru/blob_lru_test.go index 4b5e69340222..ca1b0ddd742a 100644 --- a/common/lru/blob_lru_test.go +++ b/common/lru/blob_lru_test.go @@ -20,22 +20,21 @@ import ( "encoding/binary" "fmt" "testing" - - "github.com/ethereum/go-ethereum/common" ) -func mkHash(i int) common.Hash { - h := make([]byte, 32) - binary.LittleEndian.PutUint64(h, uint64(i)) - return common.BytesToHash(h) +type testKey [8]byte + +func mkKey(i int) (key testKey) { + binary.LittleEndian.PutUint64(key[:], uint64(i)) + return key } -func TestBlobLru(t *testing.T) { - lru := NewSizeConstrainedLRU(100) +func TestSizeConstrainedCache(t *testing.T) { + lru := NewSizeConstrainedCache[testKey, []byte](100) var want uint64 // Add 11 items of 10 byte each. First item should be swapped out for i := 0; i < 11; i++ { - k := mkHash(i) + k := mkKey(i) v := fmt.Sprintf("value-%04d", i) lru.Add(k, []byte(v)) want += uint64(len(v)) @@ -48,17 +47,17 @@ func TestBlobLru(t *testing.T) { } // Zero:th should be evicted { - k := mkHash(0) - if val := lru.Get(k); val != nil { + k := mkKey(0) + if _, ok := lru.Get(k); ok { t.Fatalf("should be evicted: %v", k) } } // Elems 1-11 should be present for i := 1; i < 11; i++ { - k := mkHash(i) + k := mkKey(i) want := fmt.Sprintf("value-%04d", i) - have := lru.Get(k) - if have == nil { + have, ok := lru.Get(k) + if !ok { t.Fatalf("missing key %v", k) } if string(have) != want { @@ -67,26 +66,26 @@ func TestBlobLru(t *testing.T) { } } -// TestBlobLruOverflow tests what happens when inserting an element exceeding -// the max size -func TestBlobLruOverflow(t *testing.T) { - lru := NewSizeConstrainedLRU(100) +// This test adds inserting an element exceeding the max size. +func TestSizeConstrainedCacheOverflow(t *testing.T) { + lru := NewSizeConstrainedCache[testKey, []byte](100) + // Add 10 items of 10 byte each, filling the cache for i := 0; i < 10; i++ { - k := mkHash(i) + k := mkKey(i) v := fmt.Sprintf("value-%04d", i) lru.Add(k, []byte(v)) } // Add one single large elem. We expect it to swap out all entries. { - k := mkHash(1337) + k := mkKey(1337) v := make([]byte, 200) lru.Add(k, v) } // Elems 0-9 should be missing for i := 1; i < 10; i++ { - k := mkHash(i) - if val := lru.Get(k); val != nil { + k := mkKey(i) + if _, ok := lru.Get(k); ok { t.Fatalf("should be evicted: %v", k) } } @@ -97,7 +96,7 @@ func TestBlobLruOverflow(t *testing.T) { // Adding one small item should swap out the large one { i := 0 - k := mkHash(i) + k := mkKey(i) v := fmt.Sprintf("value-%04d", i) lru.Add(k, []byte(v)) if have, want := lru.size, uint64(10); have != want { @@ -106,17 +105,51 @@ func TestBlobLruOverflow(t *testing.T) { } } -// TestBlobLruSameItem tests what happens when inserting the same k/v multiple times. -func TestBlobLruSameItem(t *testing.T) { - lru := NewSizeConstrainedLRU(100) - // Add one 10 byte-item 10 times - k := mkHash(0) +// This checks what happens when inserting the same k/v multiple times. +func TestSizeConstrainedCacheSameItem(t *testing.T) { + lru := NewSizeConstrainedCache[testKey, []byte](100) + + // Add one 10 byte-item 10 times. + k := mkKey(0) v := fmt.Sprintf("value-%04d", 0) for i := 0; i < 10; i++ { lru.Add(k, []byte(v)) } - // The size should be accurate + + // The size should be accurate. if have, want := lru.size, uint64(10); have != want { t.Fatalf("size wrong, have %d want %d", have, want) } } + +// This tests that empty/nil values are handled correctly. +func TestSizeConstrainedCacheEmpties(t *testing.T) { + lru := NewSizeConstrainedCache[testKey, []byte](100) + + // This test abuses the lru a bit, using different keys for identical value(s). + for i := 0; i < 10; i++ { + lru.Add(testKey{byte(i)}, []byte{}) + lru.Add(testKey{byte(255 - i)}, nil) + } + + // The size should not count, only the values count. So this could be a DoS + // since it basically has no cap, and it is intentionally overloaded with + // different-keyed 0-length values. + if have, want := lru.size, uint64(0); have != want { + t.Fatalf("size wrong, have %d want %d", have, want) + } + + for i := 0; i < 10; i++ { + if v, ok := lru.Get(testKey{byte(i)}); !ok { + t.Fatalf("test %d: expected presence", i) + } else if v == nil { + t.Fatalf("test %d, v is nil", i) + } + + if v, ok := lru.Get(testKey{byte(255 - i)}); !ok { + t.Fatalf("test %d: expected presence", i) + } else if v != nil { + t.Fatalf("test %d, v is not nil", i) + } + } +} diff --git a/common/lru/lru.go b/common/lru/lru.go new file mode 100644 index 000000000000..45965adb0dfc --- /dev/null +++ b/common/lru/lru.go @@ -0,0 +1,95 @@ +// Copyright 2022 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 lru + +import "sync" + +// Cache is a LRU cache. +// This type is safe for concurrent use. +type Cache[K comparable, V any] struct { + cache BasicLRU[K, V] + mu sync.Mutex +} + +// NewCache creates an LRU cache. +func NewCache[K comparable, V any](capacity int) *Cache[K, V] { + return &Cache[K, V]{cache: NewBasicLRU[K, V](capacity)} +} + +// Add adds a value to the cache. Returns true if an item was evicted to store the new item. +func (c *Cache[K, V]) Add(key K, value V) (evicted bool) { + c.mu.Lock() + defer c.mu.Unlock() + + return c.cache.Add(key, value) +} + +// Contains reports whether the given key exists in the cache. +func (c *Cache[K, V]) Contains(key K) bool { + c.mu.Lock() + defer c.mu.Unlock() + + return c.cache.Contains(key) +} + +// Get retrieves a value from the cache. This marks the key as recently used. +func (c *Cache[K, V]) Get(key K) (value V, ok bool) { + c.mu.Lock() + defer c.mu.Unlock() + + return c.cache.Get(key) +} + +// Len returns the current number of items in the cache. +func (c *Cache[K, V]) Len() int { + c.mu.Lock() + defer c.mu.Unlock() + + return c.cache.Len() +} + +// Peek retrieves a value from the cache, but does not mark the key as recently used. +func (c *Cache[K, V]) Peek(key K) (value V, ok bool) { + c.mu.Lock() + defer c.mu.Unlock() + + return c.cache.Peek(key) +} + +// Purge empties the cache. +func (c *Cache[K, V]) Purge() { + c.mu.Lock() + defer c.mu.Unlock() + + c.cache.Purge() +} + +// Remove drops an item from the cache. Returns true if the key was present in cache. +func (c *Cache[K, V]) Remove(key K) bool { + c.mu.Lock() + defer c.mu.Unlock() + + return c.cache.Remove(key) +} + +// Keys returns all keys of items currently in the LRU. +func (c *Cache[K, V]) Keys() []K { + c.mu.Lock() + defer c.mu.Unlock() + + return c.cache.Keys() +} diff --git a/core/blockchain.go b/core/blockchain.go index 80f8ba76f121..863e9424259e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -30,6 +30,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/consensus" @@ -45,8 +46,8 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - lru "github.com/hashicorp/golang-lru" ) var ( @@ -200,12 +201,14 @@ type BlockChain struct { currentSafeBlock atomic.Value // Current safe head stateCache state.Database // State database to reuse between imports (contains state cache) - bodyCache *lru.Cache // Cache for the most recent block bodies - bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format - receiptsCache *lru.Cache // Cache for the most recent receipts per block - blockCache *lru.Cache // Cache for the most recent entire blocks - txLookupCache *lru.Cache // Cache for the most recent transaction lookup data. - futureBlocks *lru.Cache // future blocks are blocks added for later processing + bodyCache *lru.Cache[common.Hash, *types.Body] + bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] + receiptsCache *lru.Cache[common.Hash, []*types.Receipt] + blockCache *lru.Cache[common.Hash, *types.Block] + txLookupCache *lru.Cache[common.Hash, *rawdb.LegacyTxLookupEntry] + + // future blocks are blocks added for later processing + futureBlocks *lru.Cache[common.Hash, *types.Block] wg sync.WaitGroup // quit chan struct{} // shutdown signal, closed in Stop. @@ -227,12 +230,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis if cacheConfig == nil { cacheConfig = defaultCacheConfig } - bodyCache, _ := lru.New(bodyCacheLimit) - bodyRLPCache, _ := lru.New(bodyCacheLimit) - receiptsCache, _ := lru.New(receiptsCacheLimit) - blockCache, _ := lru.New(blockCacheLimit) - txLookupCache, _ := lru.New(txLookupCacheLimit) - futureBlocks, _ := lru.New(maxFutureBlocks) // Setup the genesis block, commit the provided genesis specification // to database if the genesis block is not present yet, or load the @@ -261,12 +258,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis }), quit: make(chan struct{}), chainmu: syncx.NewClosableMutex(), - bodyCache: bodyCache, - bodyRLPCache: bodyRLPCache, - receiptsCache: receiptsCache, - blockCache: blockCache, - txLookupCache: txLookupCache, - futureBlocks: futureBlocks, + bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit), + bodyRLPCache: lru.NewCache[common.Hash, rlp.RawValue](bodyCacheLimit), + receiptsCache: lru.NewCache[common.Hash, []*types.Receipt](receiptsCacheLimit), + blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit), + txLookupCache: lru.NewCache[common.Hash, *rawdb.LegacyTxLookupEntry](txLookupCacheLimit), + futureBlocks: lru.NewCache[common.Hash, *types.Block](maxFutureBlocks), engine: engine, vmConfig: vmConfig, } @@ -957,7 +954,7 @@ func (bc *BlockChain) procFutureBlocks() { blocks := make([]*types.Block, 0, bc.futureBlocks.Len()) for _, hash := range bc.futureBlocks.Keys() { if block, exist := bc.futureBlocks.Peek(hash); exist { - blocks = append(blocks, block.(*types.Block)) + blocks = append(blocks, block) } } if len(blocks) > 0 { diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 5814c8a0daee..da948029a13e 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -96,8 +96,7 @@ func (bc *BlockChain) GetHeadersFrom(number, count uint64) []rlp.RawValue { func (bc *BlockChain) GetBody(hash common.Hash) *types.Body { // Short circuit if the body's already in the cache, retrieve otherwise if cached, ok := bc.bodyCache.Get(hash); ok { - body := cached.(*types.Body) - return body + return cached } number := bc.hc.GetBlockNumber(hash) if number == nil { @@ -117,7 +116,7 @@ func (bc *BlockChain) GetBody(hash common.Hash) *types.Body { func (bc *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue { // Short circuit if the body's already in the cache, retrieve otherwise if cached, ok := bc.bodyRLPCache.Get(hash); ok { - return cached.(rlp.RawValue) + return cached } number := bc.hc.GetBlockNumber(hash) if number == nil { @@ -159,7 +158,7 @@ func (bc *BlockChain) HasFastBlock(hash common.Hash, number uint64) bool { func (bc *BlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { // Short circuit if the block's already in the cache, retrieve otherwise if block, ok := bc.blockCache.Get(hash); ok { - return block.(*types.Block) + return block } block := rawdb.ReadBlock(bc.db, hash, number) if block == nil { @@ -211,7 +210,7 @@ func (bc *BlockChain) GetBlocksFromHash(hash common.Hash, n int) (blocks []*type // GetReceiptsByHash retrieves the receipts for all transactions in a given block. func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts { if receipts, ok := bc.receiptsCache.Get(hash); ok { - return receipts.(types.Receipts) + return receipts } number := rawdb.ReadHeaderNumber(bc.db, hash) if number == nil { @@ -255,7 +254,7 @@ func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, max func (bc *BlockChain) GetTransactionLookup(hash common.Hash) *rawdb.LegacyTxLookupEntry { // Short circuit if the txlookup already in the cache, retrieve otherwise if lookup, exist := bc.txLookupCache.Get(hash); exist { - return lookup.(*rawdb.LegacyTxLookupEntry) + return lookup } tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(bc.db, hash) if tx == nil { diff --git a/core/headerchain.go b/core/headerchain.go index d8c415f336b8..482b5f6fbe91 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -27,6 +27,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" @@ -34,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - lru "github.com/hashicorp/golang-lru" ) const ( @@ -64,9 +64,9 @@ type HeaderChain struct { currentHeader atomic.Value // Current head of the header chain (may be above the block chain!) currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time) - headerCache *lru.Cache // Cache for the most recent block headers - tdCache *lru.Cache // Cache for the most recent block total difficulties - numberCache *lru.Cache // Cache for the most recent block numbers + headerCache *lru.Cache[common.Hash, *types.Header] + tdCache *lru.Cache[common.Hash, *big.Int] // most recent total difficulties + numberCache *lru.Cache[common.Hash, uint64] // most recent block numbers procInterrupt func() bool @@ -77,10 +77,6 @@ type HeaderChain struct { // NewHeaderChain creates a new HeaderChain structure. ProcInterrupt points // to the parent's interrupt semaphore. func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) { - headerCache, _ := lru.New(headerCacheLimit) - tdCache, _ := lru.New(tdCacheLimit) - numberCache, _ := lru.New(numberCacheLimit) - // Seed a fast but crypto originating random generator seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) if err != nil { @@ -89,9 +85,9 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c hc := &HeaderChain{ config: config, chainDb: chainDb, - headerCache: headerCache, - tdCache: tdCache, - numberCache: numberCache, + headerCache: lru.NewCache[common.Hash, *types.Header](headerCacheLimit), + tdCache: lru.NewCache[common.Hash, *big.Int](tdCacheLimit), + numberCache: lru.NewCache[common.Hash, uint64](numberCacheLimit), procInterrupt: procInterrupt, rand: mrand.New(mrand.NewSource(seed.Int64())), engine: engine, @@ -115,8 +111,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c // from the cache or database func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 { if cached, ok := hc.numberCache.Get(hash); ok { - number := cached.(uint64) - return &number + return &cached } number := rawdb.ReadHeaderNumber(hc.chainDb, hash) if number != nil { @@ -442,7 +437,7 @@ func (hc *HeaderChain) GetAncestor(hash common.Hash, number, ancestor uint64, ma func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { // Short circuit if the td's already in the cache, retrieve otherwise if cached, ok := hc.tdCache.Get(hash); ok { - return cached.(*big.Int) + return cached } td := rawdb.ReadTd(hc.chainDb, hash, number) if td == nil { @@ -458,7 +453,7 @@ func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header { // Short circuit if the header's already in the cache, retrieve otherwise if header, ok := hc.headerCache.Get(hash); ok { - return header.(*types.Header) + return header } header := rawdb.ReadHeader(hc.chainDb, hash, number) if header == nil { @@ -525,10 +520,9 @@ func (hc *HeaderChain) GetHeadersFrom(number, count uint64) []rlp.RawValue { if !ok { break } - h := header.(*types.Header) - rlpData, _ := rlp.EncodeToBytes(h) + rlpData, _ := rlp.EncodeToBytes(header) headers = append(headers, rlpData) - hash = h.ParentHash + hash = header.ParentHash count-- number-- } diff --git a/core/state/database.go b/core/state/database.go index 9f270bf0f98d..2de0650df892 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -21,12 +21,11 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" - lru2 "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" - lru "github.com/hashicorp/golang-lru" ) const ( @@ -130,20 +129,19 @@ func NewDatabase(db ethdb.Database) Database { // is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a // large memory cache. func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { - csc, _ := lru.New(codeSizeCacheSize) return &cachingDB{ db: trie.NewDatabaseWithConfig(db, config), disk: db, - codeSizeCache: csc, - codeCache: lru2.NewSizeConstrainedLRU(codeCacheSize), + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), + codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), } } type cachingDB struct { db *trie.Database disk ethdb.KeyValueStore - codeSizeCache *lru.Cache - codeCache *lru2.SizeConstrainedLRU + codeSizeCache *lru.Cache[common.Hash, int] + codeCache *lru.SizeConstrainedCache[common.Hash, []byte] } // OpenTrie opens the main account trie at a specific root hash. @@ -176,10 +174,11 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { // ContractCode retrieves a particular contract's code. func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { - if code := db.codeCache.Get(codeHash); len(code) > 0 { + code, _ := db.codeCache.Get(codeHash) + if len(code) > 0 { return code, nil } - code := rawdb.ReadCode(db.disk, codeHash) + code = rawdb.ReadCode(db.disk, codeHash) if len(code) > 0 { db.codeCache.Add(codeHash, code) db.codeSizeCache.Add(codeHash, len(code)) @@ -192,10 +191,11 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error // code can't be found in the cache, then check the existence with **new** // db scheme. func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error) { - if code := db.codeCache.Get(codeHash); len(code) > 0 { + code, _ := db.codeCache.Get(codeHash) + if len(code) > 0 { return code, nil } - code := rawdb.ReadCodeWithPrefix(db.disk, codeHash) + code = rawdb.ReadCodeWithPrefix(db.disk, codeHash) if len(code) > 0 { db.codeCache.Add(codeHash, code) db.codeSizeCache.Add(codeHash, len(code)) @@ -207,7 +207,7 @@ func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]b // ContractCodeSize retrieves a particular contracts code's size. func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) { if cached, ok := db.codeSizeCache.Get(codeHash); ok { - return cached.(int), nil + return cached, nil } code, err := db.ContractCode(addrHash, codeHash) return len(code), err diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index ea0233dd0829..c424dd2946e7 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" @@ -35,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - lru "github.com/hashicorp/golang-lru" ) // Config represents the configuration of the filter system. @@ -77,21 +77,16 @@ type Backend interface { // FilterSystem holds resources shared by all filters. type FilterSystem struct { backend Backend - logsCache *lru.Cache + logsCache *lru.Cache[common.Hash, [][]*types.Log] cfg *Config } // NewFilterSystem creates a filter system. func NewFilterSystem(backend Backend, config Config) *FilterSystem { config = config.withDefaults() - - cache, err := lru.New(config.LogCacheSize) - if err != nil { - panic(err) - } return &FilterSystem{ backend: backend, - logsCache: cache, + logsCache: lru.NewCache[common.Hash, [][]*types.Log](config.LogCacheSize), cfg: &config, } } @@ -100,7 +95,7 @@ func NewFilterSystem(backend Backend, config Config) *FilterSystem { func (sys *FilterSystem) cachedGetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { cached, ok := sys.logsCache.Get(blockHash) if ok { - return cached.([][]*types.Log), nil + return cached, nil } logs, err := sys.backend.GetLogs(ctx, blockHash, number) diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 6028ef03cf15..47cc31999e01 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -56,7 +56,12 @@ type blockFees struct { err error } -// processedFees contains the results of a processed block and is also used for caching +type cacheKey struct { + number uint64 + percentiles string +} + +// processedFees contains the results of a processed block. type processedFees struct { reward []*big.Int baseFee, nextBaseFee *big.Int @@ -270,13 +275,10 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast oracle.processBlock(fees, rewardPercentiles) results <- fees } else { - cacheKey := struct { - number uint64 - percentiles string - }{blockNumber, string(percentileKey)} + cacheKey := cacheKey{number: blockNumber, percentiles: string(percentileKey)} if p, ok := oracle.historyCache.Get(cacheKey); ok { - fees.results = p.(processedFees) + fees.results = p results <- fees } else { if len(rewardPercentiles) != 0 { diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 00128a5dc852..604ad5e10432 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -23,13 +23,13 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - lru "github.com/hashicorp/golang-lru" ) const sampleNumber = 3 // Number of transactions sampled in a block @@ -72,7 +72,8 @@ type Oracle struct { checkBlocks, percentile int maxHeaderHistory, maxBlockHistory int - historyCache *lru.Cache + + historyCache *lru.Cache[cacheKey, processedFees] } // NewOracle returns a new gasprice oracle which can recommend suitable @@ -114,7 +115,7 @@ func NewOracle(backend OracleBackend, params Config) *Oracle { log.Warn("Sanitizing invalid gasprice oracle max block history", "provided", params.MaxBlockHistory, "updated", maxBlockHistory) } - cache, _ := lru.New(2048) + cache := lru.NewCache[cacheKey, processedFees](2048) headEvent := make(chan core.ChainHeadEvent, 1) backend.SubscribeChainHeadEvent(headEvent) go func() { diff --git a/p2p/discover/v5wire/session.go b/p2p/discover/v5wire/session.go index d52b5c118101..862c21fcee9f 100644 --- a/p2p/discover/v5wire/session.go +++ b/p2p/discover/v5wire/session.go @@ -22,10 +22,10 @@ import ( "encoding/binary" "time" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/hashicorp/golang-lru/simplelru" ) const handshakeTimeout = time.Second @@ -33,7 +33,7 @@ const handshakeTimeout = time.Second // The SessionCache keeps negotiated encryption keys and // state for in-progress handshakes in the Discovery v5 wire protocol. type SessionCache struct { - sessions *simplelru.LRU + sessions lru.BasicLRU[sessionID, *session] handshakes map[sessionID]*Whoareyou clock mclock.Clock @@ -62,12 +62,8 @@ func (s *session) keysFlipped() *session { } func NewSessionCache(maxItems int, clock mclock.Clock) *SessionCache { - cache, err := simplelru.NewLRU(maxItems, nil) - if err != nil { - panic("can't create session cache") - } return &SessionCache{ - sessions: cache, + sessions: lru.NewBasicLRU[sessionID, *session](maxItems), handshakes: make(map[sessionID]*Whoareyou), clock: clock, nonceGen: generateNonce, @@ -95,11 +91,8 @@ func (sc *SessionCache) nextNonce(s *session) (Nonce, error) { // session returns the current session for the given node, if any. func (sc *SessionCache) session(id enode.ID, addr string) *session { - item, ok := sc.sessions.Get(sessionID{id, addr}) - if !ok { - return nil - } - return item.(*session) + item, _ := sc.sessions.Get(sessionID{id, addr}) + return item } // readKey returns the current read key for the given node. diff --git a/p2p/dnsdisc/client.go b/p2p/dnsdisc/client.go index 3f914d6e9416..8f1c221b8038 100644 --- a/p2p/dnsdisc/client.go +++ b/p2p/dnsdisc/client.go @@ -27,12 +27,12 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" - lru "github.com/hashicorp/golang-lru" "golang.org/x/sync/singleflight" "golang.org/x/time/rate" ) @@ -41,7 +41,7 @@ import ( type Client struct { cfg Config clock mclock.Clock - entries *lru.Cache + entries *lru.Cache[string, entry] ratelimit *rate.Limiter singleflight singleflight.Group } @@ -96,14 +96,10 @@ func (cfg Config) withDefaults() Config { // NewClient creates a client. func NewClient(cfg Config) *Client { cfg = cfg.withDefaults() - cache, err := lru.New(cfg.CacheLimit) - if err != nil { - panic(err) - } rlimit := rate.NewLimiter(rate.Limit(cfg.RateLimit), 10) return &Client{ cfg: cfg, - entries: cache, + entries: lru.NewCache[string, entry](cfg.CacheLimit), clock: mclock.System{}, ratelimit: rlimit, } @@ -176,7 +172,7 @@ func (c *Client) resolveEntry(ctx context.Context, domain, hash string) (entry, } cacheKey := truncateHash(hash) if e, ok := c.entries.Get(cacheKey); ok { - return e.(entry), nil + return e, nil } ei, err, _ := c.singleflight.Do(cacheKey, func() (interface{}, error) { From ae42148093fdfd72749ff3dda2b986cef543510f Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 15 Nov 2022 14:05:16 +0100 Subject: [PATCH 377/715] rpc: fix connection tracking set in Server (#26180) rpc: fix connection tracking in Server When upgrading to mapset/v2 with generics, the set element type used in rpc.Server had to be changed to *ServerCodec because ServerCodec is not 'comparable'. While the distinction is technically correct, we know all possible ServerCodec types, and all of them are comparable. So just use a map instead. --- rpc/server.go | 50 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/rpc/server.go b/rpc/server.go index 4f23c93bae46..fe162d5a428e 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -19,9 +19,9 @@ package rpc import ( "context" "io" + "sync" "sync/atomic" - mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/log" ) @@ -45,13 +45,19 @@ const ( type Server struct { services serviceRegistry idgen func() ID - run int32 - codecs mapset.Set[*ServerCodec] + + mutex sync.Mutex + codecs map[ServerCodec]struct{} + run int32 } // NewServer creates a new server instance with no registered handlers. func NewServer() *Server { - server := &Server{idgen: randomIDGenerator(), codecs: mapset.NewSet[*ServerCodec](), run: 1} + server := &Server{ + idgen: randomIDGenerator(), + codecs: make(map[ServerCodec]struct{}), + run: 1, + } // Register the default service providing meta information about the RPC service such // as the services and methods it offers. rpcService := &RPCService{server} @@ -75,20 +81,34 @@ func (s *Server) RegisterName(name string, receiver interface{}) error { func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { defer codec.close() - // Don't serve if server is stopped. - if atomic.LoadInt32(&s.run) == 0 { + if !s.trackCodec(codec) { return } - - // Add the codec to the set so it can be closed by Stop. - s.codecs.Add(&codec) - defer s.codecs.Remove(&codec) + defer s.untrackCodec(codec) c := initClient(codec, s.idgen, &s.services) <-codec.closed() c.Close() } +func (s *Server) trackCodec(codec ServerCodec) bool { + s.mutex.Lock() + defer s.mutex.Unlock() + + if atomic.LoadInt32(&s.run) == 0 { + return false // Don't serve if server is stopped. + } + s.codecs[codec] = struct{}{} + return true +} + +func (s *Server) untrackCodec(codec ServerCodec) { + s.mutex.Lock() + defer s.mutex.Unlock() + + delete(s.codecs, codec) +} + // serveSingleRequest reads and processes a single RPC request from the given codec. This // is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in // this mode. @@ -120,12 +140,14 @@ func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { // requests to finish, then closes all codecs which will cancel pending requests and // subscriptions. func (s *Server) Stop() { + s.mutex.Lock() + defer s.mutex.Unlock() + if atomic.CompareAndSwapInt32(&s.run, 1, 0) { log.Debug("RPC server shutting down") - s.codecs.Each(func(c *ServerCodec) bool { - (*c).close() - return true - }) + for codec := range s.codecs { + codec.close() + } } } From bc90a882633e7a61fd5d18ec266a0c51bd71a888 Mon Sep 17 00:00:00 2001 From: ligi Date: Wed, 16 Nov 2022 08:44:54 +0100 Subject: [PATCH 378/715] ethclient: docs, fix misleading comment (#26189) closes #26188 --- ethclient/ethclient.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 766efcf57140..1d2df5466ede 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -320,7 +320,7 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) // State Access -// NetworkID returns the network ID (also known as the chain ID) for this chain. +// NetworkID returns the network ID for this client. func (ec *Client) NetworkID(ctx context.Context) (*big.Int, error) { version := new(big.Int) var ver string From b4ea2bf7dda9def5374ed3ab16a3dfd872eaa40a Mon Sep 17 00:00:00 2001 From: Mark Tyneway Date: Wed, 16 Nov 2022 01:18:52 -0800 Subject: [PATCH 379/715] all: implement EIP-1153 transient storage (#26003) Implements TSTORE and TLOAD as specified by the following EIP: https://eips.ethereum.org/EIPS/eip-1153 https://ethereum-magicians.org/t/eip-1153-transient-storage-opcodes/553 Co-authored-by: Sara Reynolds Co-authored-by: Martin Holst Swende Co-authored-by: Gary Rong --- cmd/evm/internal/t8ntool/execution.go | 2 +- core/blockchain_test.go | 94 +++++++++++++++++++++++++++ core/chain_makers.go | 40 ++++++++---- core/state/journal.go | 13 ++++ core/state/statedb.go | 87 ++++++++++++++++++------- core/state/statedb_test.go | 44 +++++++++++++ core/state/transient_storage.go | 55 ++++++++++++++++ core/state_prefetcher.go | 2 +- core/state_processor.go | 2 +- core/state_transition.go | 9 +-- core/vm/eips.go | 41 ++++++++++++ core/vm/instructions.go | 3 +- core/vm/instructions_test.go | 53 +++++++++++++++ core/vm/interface.go | 6 +- core/vm/opcodes.go | 12 ++++ core/vm/runtime/runtime.go | 36 ++++++---- eth/state_accessor.go | 2 +- eth/tracers/api.go | 8 +-- les/state_accessor.go | 2 +- miner/worker.go | 2 +- tests/state_test.go | 4 +- 21 files changed, 450 insertions(+), 67 deletions(-) create mode 100644 core/state/transient_storage.go diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index adbf56f70c95..a05dbedea700 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -173,7 +173,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } vmConfig.Tracer = tracer vmConfig.Debug = (tracer != nil) - statedb.Prepare(tx.Hash(), txIndex) + statedb.SetTxContext(tx.Hash(), txIndex) txContext := core.NewEVMTxContext(msg) snapshot := statedb.Snapshot() evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 85e0d5980a74..c476d4596296 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4093,3 +4093,97 @@ func testCreateThenDelete(t *testing.T, config *params.ChainConfig) { } } } + +// TestTransientStorageReset ensures the transient storage is wiped correctly +// between transactions. +func TestTransientStorageReset(t *testing.T) { + var ( + engine = ethash.NewFaker() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + destAddress = crypto.CreateAddress(address, 0) + funds = big.NewInt(1000000000000000) + vmConfig = vm.Config{ + ExtraEips: []int{1153}, // Enable transient storage EIP + } + ) + code := append([]byte{ + // TLoad value with location 1 + byte(vm.PUSH1), 0x1, + byte(vm.TLOAD), + + // PUSH location + byte(vm.PUSH1), 0x1, + + // SStore location:value + byte(vm.SSTORE), + }, make([]byte, 32-6)...) + initCode := []byte{ + // TSTORE 1:1 + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x1, + byte(vm.TSTORE), + + // Get the runtime-code on the stack + byte(vm.PUSH32)} + initCode = append(initCode, code...) + initCode = append(initCode, []byte{ + byte(vm.PUSH1), 0x0, // offset + byte(vm.MSTORE), + byte(vm.PUSH1), 0x6, // size + byte(vm.PUSH1), 0x0, // offset + byte(vm.RETURN), // return 6 bytes of zero-code + }...) + gspec := &Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{ + address: {Balance: funds}, + }, + } + nonce := uint64(0) + signer := types.HomesteadSigner{} + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { + fee := big.NewInt(1) + if b.header.BaseFee != nil { + fee = b.header.BaseFee + } + b.SetCoinbase(common.Address{1}) + tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: nonce, + GasPrice: new(big.Int).Set(fee), + Gas: 100000, + Data: initCode, + }) + nonce++ + b.AddTxWithVMConfig(tx, vmConfig) + + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ + Nonce: nonce, + GasPrice: new(big.Int).Set(fee), + Gas: 100000, + To: &destAddress, + }) + b.AddTxWithVMConfig(tx, vmConfig) + nonce++ + }) + + // Initialize the blockchain with 1153 enabled. + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vmConfig, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + // Import the blocks + if _, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("failed to insert into chain: %v", err) + } + // Check the storage + state, err := chain.StateAt(chain.CurrentHeader().Root) + if err != nil { + t.Fatalf("Failed to load state %v", err) + } + loc := common.BytesToHash([]byte{1}) + slot := state.GetState(destAddress, loc) + if slot != (common.Hash{}) { + t.Fatalf("Unexpected dirty storage slot") + } +} diff --git a/core/chain_makers.go b/core/chain_makers.go index 2ed87e0a9e3a..48a5fa162a81 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -79,6 +79,26 @@ func (b *BlockGen) SetDifficulty(diff *big.Int) { b.header.Difficulty = diff } +// addTx adds a transaction to the generated block. If no coinbase has +// been set, the block's coinbase is set to the zero address. +// +// There are a few options can be passed as well in order to run some +// customized rules. +// - bc: enables the ability to query historical block hashes for BLOCKHASH +// - vmConfig: extends the flexibility for customizing evm rules, e.g. enable extra EIPs +func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transaction) { + if b.gasPool == nil { + b.SetCoinbase(common.Address{}) + } + b.statedb.SetTxContext(tx.Hash(), len(b.txs)) + receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig) + if err != nil { + panic(err) + } + b.txs = append(b.txs, tx) + b.receipts = append(b.receipts, receipt) +} + // AddTx adds a transaction to the generated block. If no coinbase has // been set, the block's coinbase is set to the zero address. // @@ -88,7 +108,7 @@ func (b *BlockGen) SetDifficulty(diff *big.Int) { // added. Notably, contract code relying on the BLOCKHASH instruction // will panic during execution. func (b *BlockGen) AddTx(tx *types.Transaction) { - b.AddTxWithChain(nil, tx) + b.addTx(nil, vm.Config{}, tx) } // AddTxWithChain adds a transaction to the generated block. If no coinbase has @@ -100,16 +120,14 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { // added. If contract code relies on the BLOCKHASH instruction, // the block in chain will be returned. func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { - if b.gasPool == nil { - b.SetCoinbase(common.Address{}) - } - b.statedb.Prepare(tx.Hash(), len(b.txs)) - receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) - if err != nil { - panic(err) - } - b.txs = append(b.txs, tx) - b.receipts = append(b.receipts, receipt) + b.addTx(bc, vm.Config{}, tx) +} + +// AddTxWithVMConfig adds a transaction to the generated block. If no coinbase has +// been set, the block's coinbase is set to the zero address. +// The evm interpreter can be customized with the provided vm config. +func (b *BlockGen) AddTxWithVMConfig(tx *types.Transaction, config vm.Config) { + b.addTx(nil, config, tx) } // GetBalance returns the balance of the given address at the generated block. diff --git a/core/state/journal.go b/core/state/journal.go index 57a692dc7ffa..dabc1cf7d768 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -138,6 +138,11 @@ type ( address *common.Address slot *common.Hash } + + transientStorageChange struct { + account *common.Address + key, prevalue common.Hash + } ) func (ch createObjectChange) revert(s *StateDB) { @@ -213,6 +218,14 @@ func (ch storageChange) dirtied() *common.Address { return ch.account } +func (ch transientStorageChange) revert(s *StateDB) { + s.setTransientState(*ch.account, ch.key, ch.prevalue) +} + +func (ch transientStorageChange) dirtied() *common.Address { + return nil +} + func (ch refundChange) revert(s *StateDB) { s.refund = ch.prev } diff --git a/core/state/statedb.go b/core/state/statedb.go index 02ced7b785c5..559f7fa51898 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" ) @@ -102,6 +103,9 @@ type StateDB struct { // Per-transaction access list accessList *accessList + // Transient storage + transientStorage transientStorage + // Journal of state modifications. This is the backbone of // Snapshot and RevertToSnapshot. journal *journal @@ -146,6 +150,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) preimages: make(map[common.Hash][]byte), journal: newJournal(), accessList: newAccessList(), + transientStorage: newTransientStorage(), hasher: crypto.NewKeccakState(), } if sdb.snaps != nil { @@ -452,6 +457,35 @@ func (s *StateDB) Suicide(addr common.Address) bool { return true } +// SetTransientState sets transient storage for a given account. It +// adds the change to the journal so that it can be rolled back +// to its previous value if there is a revert. +func (s *StateDB) SetTransientState(addr common.Address, key, value common.Hash) { + prev := s.GetTransientState(addr, key) + if prev == value { + return + } + + s.journal.append(transientStorageChange{ + account: &addr, + key: key, + prevalue: prev, + }) + + s.setTransientState(addr, key, value) +} + +// setTransientState is a lower level setter for transient storage. It +// is called during a revert to prevent modifications to the journal. +func (s *StateDB) setTransientState(addr common.Address, key, value common.Hash) { + s.transientStorage.Set(addr, key, value) +} + +// GetTransientState gets transient storage for a given account. +func (s *StateDB) GetTransientState(addr common.Address, key common.Hash) common.Hash { + return s.transientStorage.Get(addr, key) +} + // // Setting, updating & deleting state object methods. // @@ -708,6 +742,8 @@ func (s *StateDB) Copy() *StateDB { // to not blow up if we ever decide copy it in the middle of a transaction state.accessList = s.accessList.Copy() + state.transientStorage = s.transientStorage.Copy() + // If there's a prefetcher running, make an inactive copy of it that can // only access data but does not actively preload (since the user will not // know that they need to explicitly terminate an active copy). @@ -880,9 +916,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { return s.trie.Hash() } -// Prepare sets the current transaction hash and index which are -// used when the EVM emits new state logs. -func (s *StateDB) Prepare(thash common.Hash, ti int) { +// SetTxContext sets the current transaction hash and index which are +// used when the EVM emits new state logs. It should be invoked before +// transaction execution. +func (s *StateDB) SetTxContext(thash common.Hash, ti int) { s.thash = thash s.txIndex = ti } @@ -1020,33 +1057,39 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { return root, nil } -// PrepareAccessList handles the preparatory steps for executing a state transition with -// regards to both EIP-2929 and EIP-2930: +// Prepare handles the preparatory steps for executing a state transition with. +// This method must be invoked before state transition. // +// Berlin fork: // - Add sender to access list (2929) // - Add destination to access list (2929) // - Add precompiles to access list (2929) // - Add the contents of the optional tx access list (2930) // -// This method should only be called if Berlin/2929+2930 is applicable at the current number. -func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) { - // Clear out any leftover from previous executions - s.accessList = newAccessList() - - s.AddAddressToAccessList(sender) - if dst != nil { - s.AddAddressToAccessList(*dst) - // If it's a create-tx, the destination will be added inside evm.create - } - for _, addr := range precompiles { - s.AddAddressToAccessList(addr) - } - for _, el := range list { - s.AddAddressToAccessList(el.Address) - for _, key := range el.StorageKeys { - s.AddSlotToAccessList(el.Address, key) +// Potential EIPs: +// - Reset transient storage(1153) +func (s *StateDB) Prepare(rules params.Rules, sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) { + if rules.IsBerlin { + // Clear out any leftover from previous executions + s.accessList = newAccessList() + + s.AddAddressToAccessList(sender) + if dst != nil { + s.AddAddressToAccessList(*dst) + // If it's a create-tx, the destination will be added inside evm.create + } + for _, addr := range precompiles { + s.AddAddressToAccessList(addr) + } + for _, el := range list { + s.AddAddressToAccessList(el.Address) + for _, key := range el.StorageKeys { + s.AddSlotToAccessList(el.Address, key) + } } } + // Reset transient storage at the beginning of transaction execution + s.transientStorage = newTransientStorage() } // AddAddressToAccessList adds the given address to the access list diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 6fe36a7ecffd..5e134043d243 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -342,6 +342,16 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { }, args: make([]int64, 1), }, + { + name: "SetTransientState", + fn: func(a testAction, s *StateDB) { + var key, val common.Hash + binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) + binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) + s.SetTransientState(addr, key, val) + }, + args: make([]int64, 2), + }, } action := actions[r.Intn(len(actions))] var nameargs []string @@ -954,3 +964,37 @@ func TestFlushOrderDataLoss(t *testing.T) { } } } + +func TestStateDBTransientStorage(t *testing.T) { + memDb := rawdb.NewMemoryDatabase() + db := NewDatabase(memDb) + state, _ := New(common.Hash{}, db, nil) + + key := common.Hash{0x01} + value := common.Hash{0x02} + addr := common.Address{} + + state.SetTransientState(addr, key, value) + if exp, got := 1, state.journal.length(); exp != got { + t.Fatalf("journal length mismatch: have %d, want %d", got, exp) + } + // the retrieved value should equal what was set + if got := state.GetTransientState(addr, key); got != value { + t.Fatalf("transient storage mismatch: have %x, want %x", got, value) + } + + // revert the transient state being set and then check that the + // value is now the empty hash + state.journal.revert(state, 0) + if got, exp := state.GetTransientState(addr, key), (common.Hash{}); exp != got { + t.Fatalf("transient storage mismatch: have %x, want %x", got, exp) + } + + // set transient state and then copy the statedb and ensure that + // the transient state is copied + state.SetTransientState(addr, key, value) + cpy := state.Copy() + if got := cpy.GetTransientState(addr, key); got != value { + t.Fatalf("transient storage mismatch: have %x, want %x", got, value) + } +} diff --git a/core/state/transient_storage.go b/core/state/transient_storage.go new file mode 100644 index 000000000000..66e563efa732 --- /dev/null +++ b/core/state/transient_storage.go @@ -0,0 +1,55 @@ +// Copyright 2022 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 state + +import ( + "github.com/ethereum/go-ethereum/common" +) + +// transientStorage is a representation of EIP-1153 "Transient Storage". +type transientStorage map[common.Address]Storage + +// newTransientStorage creates a new instance of a transientStorage. +func newTransientStorage() transientStorage { + return make(transientStorage) +} + +// Set sets the transient-storage `value` for `key` at the given `addr`. +func (t transientStorage) Set(addr common.Address, key, value common.Hash) { + if _, ok := t[addr]; !ok { + t[addr] = make(Storage) + } + t[addr][key] = value +} + +// Get gets the transient storage for `key` at the given `addr`. +func (t transientStorage) Get(addr common.Address, key common.Hash) common.Hash { + val, ok := t[addr] + if !ok { + return common.Hash{} + } + return val[key] +} + +// Copy does a deep copy of the transientStorage +func (t transientStorage) Copy() transientStorage { + storage := make(transientStorage) + for key, value := range t { + storage[key] = value.Copy() + } + return storage +} diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 10a1722940b0..867b47db5319 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -67,7 +67,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c if err != nil { return // Also invalid block, bail out } - statedb.Prepare(tx.Hash(), i) + statedb.SetTxContext(tx.Hash(), i) if err := precacheTransaction(msg, p.config, gaspool, statedb, header, evm); err != nil { return // Ugh, something went horribly wrong, bail out } diff --git a/core/state_processor.go b/core/state_processor.go index e511697c5f6a..db17481804ab 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -78,7 +78,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } - statedb.Prepare(tx.Hash(), i) + statedb.SetTxContext(tx.Hash(), i) receipt, err := applyTransaction(msg, p.config, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) diff --git a/core/state_transition.go b/core/state_transition.go index e6a15a3c1c2e..7387acf3539b 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -319,10 +319,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex()) } - // Set up the initial access list. - if rules.IsBerlin { - st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) - } + // Execute the preparatory steps for state transition which includes: + // - prepare accessList(post-berlin) + // - reset transient storage(eip 1153) + st.state.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) + var ( ret []byte vmerr error // vm errors do not effect consensus and are therefore not assigned to err diff --git a/core/vm/eips.go b/core/vm/eips.go index 93f5c399a668..26c450905662 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -20,6 +20,7 @@ import ( "fmt" "sort" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -32,6 +33,7 @@ var activators = map[int]func(*JumpTable){ 2200: enable2200, 1884: enable1884, 1344: enable1344, + 1153: enable1153, } // EnableEIP enables the given EIP on the config. @@ -169,6 +171,45 @@ func enable3198(jt *JumpTable) { } } +// enable1153 applies EIP-1153 "Transient Storage" +// - Adds TLOAD that reads from transient storage +// - Adds TSTORE that writes to transient storage +func enable1153(jt *JumpTable) { + jt[TLOAD] = &operation{ + execute: opTload, + constantGas: params.WarmStorageReadCostEIP2929, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + } + + jt[TSTORE] = &operation{ + execute: opTstore, + constantGas: params.WarmStorageReadCostEIP2929, + minStack: minStack(2, 0), + maxStack: maxStack(2, 0), + } +} + +// opTload implements TLOAD opcode +func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + loc := scope.Stack.peek() + hash := common.Hash(loc.Bytes32()) + val := interpreter.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 { + return nil, ErrWriteProtection + } + loc := scope.Stack.pop() + val := scope.Stack.pop() + interpreter.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) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 22d459233b3d..22c72c10a491 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -527,8 +527,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b } loc := scope.Stack.pop() val := scope.Stack.pop() - interpreter.evm.StateDB.SetState(scope.Contract.Address(), - loc.Bytes32(), val.Bytes32()) + interpreter.evm.StateDB.SetState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32()) return nil, nil } diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 602cde51015e..b4144a66fae9 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -25,6 +25,8 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -45,6 +47,14 @@ var alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffff var commonParams []*twoOperandParams var twoOpMethods map[string]executionFunc +type contractRef struct { + addr common.Address +} + +func (c contractRef) Address() common.Address { + return c.addr +} + func init() { // Params is a list of common edgecases that should be used for some common tests params := []string{ @@ -567,6 +577,49 @@ func BenchmarkOpMstore(bench *testing.B) { } } +func TestOpTstore(t *testing.T) { + var ( + statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + env = NewEVM(BlockContext{}, TxContext{}, statedb, params.TestChainConfig, Config{}) + stack = newstack() + mem = NewMemory() + evmInterpreter = NewEVMInterpreter(env, env.Config) + caller = common.Address{} + to = common.Address{1} + contractRef = contractRef{caller} + contract = NewContract(contractRef, AccountRef(to), new(big.Int), 0) + scopeContext = ScopeContext{mem, stack, contract} + value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700") + ) + + // Add a stateObject for the caller and the contract being called + statedb.CreateAccount(caller) + statedb.CreateAccount(to) + + env.interpreter = evmInterpreter + pc := uint64(0) + // push the value to the stack + stack.push(new(uint256.Int).SetBytes(value)) + // push the location to the stack + stack.push(new(uint256.Int)) + opTstore(&pc, evmInterpreter, &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, evmInterpreter, &scopeContext) + // there should be one element on the stack after TLOAD + if stack.len() != 1 { + t.Fatal("stack wrong size") + } + val := stack.peek() + if !bytes.Equal(val.Bytes(), value) { + t.Fatal("incorrect element read from transient storage") + } +} + func BenchmarkOpKeccak256(bench *testing.B) { var ( env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) diff --git a/core/vm/interface.go b/core/vm/interface.go index 88e57a2e5e1e..624272dbf37c 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" ) // StateDB is an EVM database for full state querying. @@ -47,6 +48,9 @@ type StateDB interface { GetState(common.Address, common.Hash) common.Hash SetState(common.Address, common.Hash, common.Hash) + GetTransientState(addr common.Address, key common.Hash) common.Hash + SetTransientState(addr common.Address, key, value common.Hash) + Suicide(common.Address) bool HasSuicided(common.Address) bool @@ -57,7 +61,6 @@ type StateDB interface { // is defined according to EIP161 (balance = nonce = code = 0). Empty(common.Address) bool - PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) AddressInAccessList(addr common.Address) bool SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool) // AddAddressToAccessList adds the given address to the access list. This operation is safe to perform @@ -66,6 +69,7 @@ type StateDB interface { // AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform // even if the feature/fork is not active yet AddSlotToAccessList(addr common.Address, slot common.Hash) + Prepare(rules params.Rules, sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) RevertToSnapshot(int) Snapshot() int diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index fa7de5049ace..9f199eb8f60a 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -219,6 +219,12 @@ const ( SELFDESTRUCT OpCode = 0xff ) +// 0xb0 range. +const ( + TLOAD OpCode = 0xb3 + TSTORE OpCode = 0xb4 +) + // Since the opcodes aren't all in order we can't use a regular slice. var opCodeToString = map[OpCode]string{ // 0x0 range - arithmetic ops. @@ -373,6 +379,10 @@ var opCodeToString = map[OpCode]string{ LOG3: "LOG3", LOG4: "LOG4", + // 0xb0 range. + TLOAD: "TLOAD", + TSTORE: "TSTORE", + // 0xf0 range. CREATE: "CREATE", CALL: "CALL", @@ -463,6 +473,8 @@ var stringToOp = map[string]OpCode{ "GAS": GAS, "JUMPDEST": JUMPDEST, "PUSH0": PUSH0, + "TLOAD": TLOAD, + "TSTORE": TSTORE, "PUSH1": PUSH1, "PUSH2": PUSH2, "PUSH3": PUSH3, diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 7861fb92dba3..b185211ff13e 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -117,10 +117,13 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { address = common.BytesToAddress([]byte("contract")) vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) + rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil) ) - if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil); rules.IsBerlin { - cfg.State.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil) - } + // Execute the preparatory steps for state transition which includes: + // - prepare accessList(post-berlin) + // - reset transient storage(eip 1153) + cfg.State.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil) + cfg.State.CreateAccount(address) // set the receiver's (the executing contract) code for execution. cfg.State.SetCode(address, code) @@ -132,7 +135,6 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { cfg.GasLimit, cfg.Value, ) - return ret, cfg.State, err } @@ -149,10 +151,13 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { var ( vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) + rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil) ) - if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil); rules.IsBerlin { - cfg.State.PrepareAccessList(cfg.Origin, nil, vm.ActivePrecompiles(rules), nil) - } + // Execute the preparatory steps for state transition which includes: + // - prepare accessList(post-berlin) + // - reset transient storage(eip 1153) + cfg.State.Prepare(rules, cfg.Origin, nil, vm.ActivePrecompiles(rules), nil) + // Call the code with the given configuration. code, address, leftOverGas, err := vmenv.Create( sender, @@ -171,14 +176,17 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) { setDefaults(cfg) - vmenv := NewEnv(cfg) - - sender := cfg.State.GetOrNewStateObject(cfg.Origin) - statedb := cfg.State + var ( + vmenv = NewEnv(cfg) + sender = cfg.State.GetOrNewStateObject(cfg.Origin) + statedb = cfg.State + rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil) + ) + // Execute the preparatory steps for state transition which includes: + // - prepare accessList(post-berlin) + // - reset transient storage(eip 1153) + statedb.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil) - if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil); rules.IsBerlin { - statedb.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil) - } // Call the code with the given configuration. ret, leftOverGas, err := vmenv.Call( sender, diff --git a/eth/state_accessor.go b/eth/state_accessor.go index ca59024aed48..778f88ab35d1 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -213,7 +213,7 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec } // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{}) - statedb.Prepare(tx.Hash(), idx) + statedb.SetTxContext(tx.Hash(), idx) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index eb24760afd4a..a9b51c507807 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -552,7 +552,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config txContext = core.NewEVMTxContext(msg) vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{}) ) - statedb.Prepare(tx.Hash(), i) + statedb.SetTxContext(tx.Hash(), i) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) // We intentionally don't return the error here: if we do, then the RPC server will not @@ -647,7 +647,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac // Generate the next state snapshot fast without tracing msg, _ := tx.AsMessage(signer, block.BaseFee()) - statedb.Prepare(tx.Hash(), i) + statedb.SetTxContext(tx.Hash(), i) vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { failed = err @@ -763,7 +763,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) - statedb.Prepare(tx.Hash(), i) + statedb.SetTxContext(tx.Hash(), i) _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) if writer != nil { writer.Flush() @@ -931,7 +931,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex defer cancel() // Call Prepare to clear out the statedb access list - statedb.Prepare(txctx.TxHash, txctx.TxIndex) + statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())); err != nil { return nil, fmt.Errorf("tracing failed: %w", err) } diff --git a/les/state_accessor.go b/les/state_accessor.go index a2d49fbf31ce..091ec8871eee 100644 --- a/les/state_accessor.go +++ b/les/state_accessor.go @@ -63,7 +63,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types. msg, _ := tx.AsMessage(signer, block.BaseFee()) txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil) - statedb.Prepare(tx.Hash(), idx) + statedb.SetTxContext(tx.Hash(), idx) if idx == txIndex { return msg, context, statedb, release, nil } diff --git a/miner/worker.go b/miner/worker.go index 57c1fc7b9f53..e00a494d0155 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -902,7 +902,7 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP continue } // Start executing the transaction - env.state.Prepare(tx.Hash(), env.tcount) + env.state.SetTxContext(tx.Hash(), env.tcount) logs, err := w.commitTransaction(env, tx) switch { diff --git a/tests/state_test.go b/tests/state_test.go index 5c605f6722b1..86b1a0e3c07a 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -241,9 +241,7 @@ func runBenchmark(b *testing.B, t *StateTest) { b.ResetTimer() for n := 0; n < b.N; n++ { snapshot := statedb.Snapshot() - if rules.IsBerlin { - statedb.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) - } + statedb.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) b.StartTimer() start := time.Now() From add337e0f7bad02f3cf535c66cd31f252b0b5c99 Mon Sep 17 00:00:00 2001 From: storyicon Date: Wed, 16 Nov 2022 22:22:12 +0800 Subject: [PATCH 380/715] rpc: support injecting HTTP headers through context (#26023) This adds a way to specify HTTP headers per request. Co-authored-by: Martin Holst Swende Co-authored-by: Felix Lange --- rpc/context_headers.go | 56 ++++++++++++++++++++++++++++++++++++++++++ rpc/http.go | 2 ++ rpc/http_test.go | 42 +++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 rpc/context_headers.go diff --git a/rpc/context_headers.go b/rpc/context_headers.go new file mode 100644 index 000000000000..29a58150e33b --- /dev/null +++ b/rpc/context_headers.go @@ -0,0 +1,56 @@ +// Copyright 2022 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 rpc + +import ( + "context" + "net/http" +) + +type mdHeaderKey struct{} + +// NewContextWithHeaders wraps the given context, adding HTTP headers. These headers will +// be applied by Client when making a request using the returned context. +func NewContextWithHeaders(ctx context.Context, h http.Header) context.Context { + if len(h) == 0 { + // This check ensures the header map set in context will never be nil. + return ctx + } + + var ctxh http.Header + prev, ok := ctx.Value(mdHeaderKey{}).(http.Header) + if ok { + ctxh = setHeaders(prev.Clone(), h) + } else { + ctxh = h.Clone() + } + return context.WithValue(ctx, mdHeaderKey{}, ctxh) +} + +// headersFromContext is used to extract http.Header from context. +func headersFromContext(ctx context.Context) http.Header { + source, _ := ctx.Value(mdHeaderKey{}).(http.Header) + return source +} + +// setHeaders sets all headers from src in dst. +func setHeaders(dst http.Header, src http.Header) http.Header { + for key, values := range src { + dst[http.CanonicalHeaderKey(key)] = values + } + return dst +} diff --git a/rpc/http.go b/rpc/http.go index e806ce98b09d..0ba6588f9906 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -217,6 +217,8 @@ func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadClos hc.mu.Lock() req.Header = hc.headers.Clone() hc.mu.Unlock() + setHeaders(req.Header, headersFromContext(ctx)) + if hc.auth != nil { if err := hc.auth(req.Header); err != nil { return nil, err diff --git a/rpc/http_test.go b/rpc/http_test.go index c84d7705f205..528e1bcfc5e7 100644 --- a/rpc/http_test.go +++ b/rpc/http_test.go @@ -17,6 +17,8 @@ package rpc import ( + "context" + "fmt" "net/http" "net/http/httptest" "strings" @@ -198,3 +200,43 @@ func TestHTTPPeerInfo(t *testing.T) { t.Errorf("wrong HTTP.Origin %q", info.HTTP.UserAgent) } } + +func TestNewContextWithHeaders(t *testing.T) { + expectedHeaders := 0 + server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + for i := 0; i < expectedHeaders; i++ { + key, want := fmt.Sprintf("key-%d", i), fmt.Sprintf("val-%d", i) + if have := request.Header.Get(key); have != want { + t.Errorf("wrong request headers for %s, want: %s, have: %s", key, want, have) + } + } + writer.WriteHeader(http.StatusOK) + _, _ = writer.Write([]byte(`{}`)) + })) + defer server.Close() + + client, err := Dial(server.URL) + if err != nil { + t.Fatalf("failed to dial: %s", err) + } + defer client.Close() + + newHdr := func(k, v string) http.Header { + header := http.Header{} + header.Set(k, v) + return header + } + ctx1 := NewContextWithHeaders(context.Background(), newHdr("key-0", "val-0")) + ctx2 := NewContextWithHeaders(ctx1, newHdr("key-1", "val-1")) + ctx3 := NewContextWithHeaders(ctx2, newHdr("key-2", "val-2")) + + expectedHeaders = 3 + if err := client.CallContext(ctx3, nil, "test"); err != ErrNoResult { + t.Error("call failed", err) + } + + expectedHeaders = 2 + if err := client.CallContext(ctx2, nil, "test"); err != ErrNoResult { + t.Error("call failed:", err) + } +} From 64067fbdc46237df3b862db3ac7ae4c9158618d5 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Thu, 17 Nov 2022 09:27:48 +0100 Subject: [PATCH 381/715] eth/tracers: small refactor for native tracers (#26196) Use noopTracer as a base for other native tracers to avoid extra boilerplate for unimplemented hooks. --- eth/tracers/native/4byte.go | 23 +---------------------- eth/tracers/native/call.go | 5 +---- eth/tracers/native/prestate.go | 14 +------------- 3 files changed, 3 insertions(+), 39 deletions(-) diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index d9b52b184c72..00cd5fe77b8b 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -21,7 +21,6 @@ import ( "math/big" "strconv" "sync/atomic" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" @@ -47,6 +46,7 @@ func init() { // 0xc281d19e-0: 1 // } type fourByteTracer struct { + noopTracer ids map[string]int // ids aggregates the 4byte ids found interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption @@ -90,10 +90,6 @@ func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to commo } } -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *fourByteTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { -} - // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { // Skip if tracing was interrupted @@ -115,23 +111,6 @@ func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to comm t.store(input[0:4], len(input)-4) } -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (t *fourByteTracer) CaptureExit(output []byte, gasUsed uint64, err error) { -} - -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { -} - -func (*fourByteTracer) CaptureTxStart(gasLimit uint64) {} - -func (*fourByteTracer) CaptureTxEnd(restGas uint64) {} - // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). func (t *fourByteTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 2d19c6fdb8dc..4be242c8b43d 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -99,6 +99,7 @@ type callFrameMarshaling struct { } type callTracer struct { + noopTracer callstack []callFrame config callTracerConfig gasLimit uint64 @@ -181,10 +182,6 @@ func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco } } -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *callTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { -} - // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { if t.config.OnlyTopCall { diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 9562bb01caa7..b965c50df730 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -55,6 +55,7 @@ type accountMarshaling struct { } type prestateTracer struct { + noopTracer env *vm.EVM pre state post state @@ -167,19 +168,6 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, } } -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *prestateTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { -} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { -} - -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) { -} - func (t *prestateTracer) CaptureTxStart(gasLimit uint64) { t.gasLimit = gasLimit } From c3b42683b3c9b91f0ec319d6767d2bbe157f9f28 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 17 Nov 2022 10:54:28 +0100 Subject: [PATCH 382/715] Dockerfile: upgrade to Go 1.19 (#26195) --- Dockerfile | 2 +- Dockerfile.alltools | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 143c92f27f50..c16b0ba87bfb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.18-alpine as builder +FROM golang:1.19-alpine as builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/Dockerfile.alltools b/Dockerfile.alltools index 176c4592206d..044a9a689505 100644 --- a/Dockerfile.alltools +++ b/Dockerfile.alltools @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.18-alpine as builder +FROM golang:1.19-alpine as builder RUN apk add --no-cache gcc musl-dev linux-headers git From 12df45662ac8bf497244db144b592b9b1184fda5 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 17 Nov 2022 11:15:28 +0100 Subject: [PATCH 383/715] all: remove remaining uses of untyped golang-lru (#26194) --- common/lru/basiclru.go | 2 +- consensus/clique/clique.go | 16 ++++----- consensus/clique/snapshot.go | 10 +++--- consensus/ethash/ethash.go | 69 +++++++++++++++++++----------------- go.mod | 1 - go.sum | 1 - les/vflux/server/clientdb.go | 10 +++--- light/lightchain.go | 25 ++++++------- 8 files changed, 66 insertions(+), 68 deletions(-) diff --git a/common/lru/basiclru.go b/common/lru/basiclru.go index b3369cf1f252..a429157fe50a 100644 --- a/common/lru/basiclru.go +++ b/common/lru/basiclru.go @@ -34,7 +34,7 @@ type cacheItem[K any, V any] struct { // NewBasicLRU creates a new LRU cache. func NewBasicLRU[K comparable, V any](capacity int) BasicLRU[K, V] { - if capacity < 0 { + if capacity <= 0 { capacity = 1 } c := BasicLRU[K, V]{ diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index dcdfb20c6387..53ccc34ccb8e 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + lru "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" @@ -41,7 +42,6 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" - lru "github.com/hashicorp/golang-lru" "golang.org/x/crypto/sha3" ) @@ -143,11 +143,11 @@ var ( type SignerFn func(signer accounts.Account, mimeType string, message []byte) ([]byte, error) // ecrecover extracts the Ethereum account address from a signed header. -func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) { +func ecrecover(header *types.Header, sigcache *sigLRU) (common.Address, error) { // If the signature's already cached, return that hash := header.Hash() if address, known := sigcache.Get(hash); known { - return address.(common.Address), nil + return address, nil } // Retrieve the signature from the header extra-data if len(header.Extra) < extraSeal { @@ -173,8 +173,8 @@ type Clique struct { config *params.CliqueConfig // Consensus engine configuration parameters db ethdb.Database // Database to store and retrieve snapshot checkpoints - recents *lru.ARCCache // Snapshots for recent block to speed up reorgs - signatures *lru.ARCCache // Signatures of recent blocks to speed up mining + recents *lru.Cache[common.Hash, *Snapshot] // Snapshots for recent block to speed up reorgs + signatures *sigLRU // Signatures of recent blocks to speed up mining proposals map[common.Address]bool // Current list of proposals we are pushing @@ -195,8 +195,8 @@ func New(config *params.CliqueConfig, db ethdb.Database) *Clique { conf.Epoch = epochLength } // Allocate the snapshot caches and create the engine - recents, _ := lru.NewARC(inmemorySnapshots) - signatures, _ := lru.NewARC(inmemorySignatures) + recents := lru.NewCache[common.Hash, *Snapshot](inmemorySnapshots) + signatures := lru.NewCache[common.Hash, common.Address](inmemorySignatures) return &Clique{ config: &conf, @@ -375,7 +375,7 @@ func (c *Clique) snapshot(chain consensus.ChainHeaderReader, number uint64, hash for snap == nil { // If an in-memory snapshot was found, use that if s, ok := c.recents.Get(hash); ok { - snap = s.(*Snapshot) + snap = s break } // If an on-disk checkpoint snapshot can be found, use that diff --git a/consensus/clique/snapshot.go b/consensus/clique/snapshot.go index 35eaf1eb774a..e5efa5108fd6 100644 --- a/consensus/clique/snapshot.go +++ b/consensus/clique/snapshot.go @@ -23,12 +23,12 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - lru "github.com/hashicorp/golang-lru" ) // Vote represents a single vote that an authorized signer made to modify the @@ -47,10 +47,12 @@ type Tally struct { Votes int `json:"votes"` // Number of votes until now wanting to pass the proposal } +type sigLRU = lru.Cache[common.Hash, common.Address] + // Snapshot is the state of the authorization voting at a given point in time. type Snapshot struct { config *params.CliqueConfig // Consensus engine parameters to fine tune behavior - sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover + sigcache *sigLRU // Cache of recent block signatures to speed up ecrecover Number uint64 `json:"number"` // Block number where the snapshot was created Hash common.Hash `json:"hash"` // Block hash where the snapshot was created @@ -70,7 +72,7 @@ func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // newSnapshot creates a new snapshot with the specified startup parameters. This // method does not initialize the set of recent signers, so only ever use if for // the genesis block. -func newSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, number uint64, hash common.Hash, signers []common.Address) *Snapshot { +func newSnapshot(config *params.CliqueConfig, sigcache *sigLRU, number uint64, hash common.Hash, signers []common.Address) *Snapshot { snap := &Snapshot{ config: config, sigcache: sigcache, @@ -87,7 +89,7 @@ func newSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, number uin } // loadSnapshot loads an existing snapshot from the database. -func loadSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) { +func loadSnapshot(config *params.CliqueConfig, sigcache *sigLRU, db ethdb.Database, hash common.Hash) (*Snapshot, error) { blob, err := db.Get(append(rawdb.CliqueSnapshotPrefix, hash[:]...)) if err != nil { return nil, err diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index dfe00d4b93c0..6cb312482795 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -34,11 +34,11 @@ import ( "unsafe" "github.com/edsrzf/mmap-go" + lrupkg "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/rpc" - "github.com/hashicorp/golang-lru/simplelru" ) var ErrInvalidDumpMagic = errors.New("invalid dump magic") @@ -165,34 +165,45 @@ func memoryMapAndGenerate(path string, size uint64, lock bool, generator func(bu return memoryMap(path, lock) } +type cacheOrDataset interface { + *cache | *dataset +} + // lru tracks caches or datasets by their last use time, keeping at most N of them. -type lru struct { +type lru[T cacheOrDataset] struct { what string - new func(epoch uint64) interface{} + new func(epoch uint64) T mu sync.Mutex // Items are kept in a LRU cache, but there is a special case: // We always keep an item for (highest seen epoch) + 1 as the 'future item'. - cache *simplelru.LRU + cache lrupkg.BasicLRU[uint64, T] future uint64 - futureItem interface{} + futureItem T } // newlru create a new least-recently-used cache for either the verification caches // or the mining datasets. -func newlru(what string, maxItems int, new func(epoch uint64) interface{}) *lru { - if maxItems <= 0 { - maxItems = 1 +func newlru[T cacheOrDataset](maxItems int, new func(epoch uint64) T) *lru[T] { + var what string + switch any(T(nil)).(type) { + case *cache: + what = "cache" + case *dataset: + what = "dataset" + default: + panic("unknown type") + } + return &lru[T]{ + what: what, + new: new, + cache: lrupkg.NewBasicLRU[uint64, T](maxItems), } - cache, _ := simplelru.NewLRU(maxItems, func(key, value interface{}) { - log.Trace("Evicted ethash "+what, "epoch", key) - }) - return &lru{what: what, new: new, cache: cache} } // get retrieves or creates an item for the given epoch. The first return value is always // non-nil. The second return value is non-nil if lru thinks that an item will be useful in // the near future. -func (lru *lru) get(epoch uint64) (item, future interface{}) { +func (lru *lru[T]) get(epoch uint64) (item, future T) { lru.mu.Lock() defer lru.mu.Unlock() @@ -226,9 +237,8 @@ type cache struct { once sync.Once // Ensures the cache is generated only once } -// newCache creates a new ethash verification cache and returns it as a plain Go -// interface to be usable in an LRU cache. -func newCache(epoch uint64) interface{} { +// newCache creates a new ethash verification cache. +func newCache(epoch uint64) *cache { return &cache{epoch: epoch} } @@ -308,7 +318,7 @@ type dataset struct { // newDataset creates a new ethash mining dataset and returns it as a plain Go // interface to be usable in an LRU cache. -func newDataset(epoch uint64) interface{} { +func newDataset(epoch uint64) *dataset { return &dataset{epoch: epoch} } @@ -439,8 +449,8 @@ type Config struct { type Ethash struct { config Config - caches *lru // In memory caches to avoid regenerating too often - datasets *lru // In memory datasets to avoid regenerating too often + caches *lru[*cache] // In memory caches to avoid regenerating too often + datasets *lru[*dataset] // In memory datasets to avoid regenerating too often // Mining related fields rand *rand.Rand // Properly seeded random source for nonces @@ -477,8 +487,8 @@ func New(config Config, notify []string, noverify bool) *Ethash { } ethash := &Ethash{ config: config, - caches: newlru("cache", config.CachesInMem, newCache), - datasets: newlru("dataset", config.DatasetsInMem, newDataset), + caches: newlru(config.CachesInMem, newCache), + datasets: newlru(config.DatasetsInMem, newDataset), update: make(chan struct{}), hashrate: metrics.NewMeterForced(), } @@ -573,15 +583,13 @@ func (ethash *Ethash) StopRemoteSealer() error { // stored on disk, and finally generating one if none can be found. func (ethash *Ethash) cache(block uint64) *cache { epoch := block / epochLength - currentI, futureI := ethash.caches.get(epoch) - current := currentI.(*cache) + current, future := ethash.caches.get(epoch) // Wait for generation finish. current.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.CachesLockMmap, ethash.config.PowMode == ModeTest) // If we need a new future cache, now's a good time to regenerate it. - if futureI != nil { - future := futureI.(*cache) + if future != nil { go future.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.CachesLockMmap, ethash.config.PowMode == ModeTest) } return current @@ -596,25 +604,20 @@ func (ethash *Ethash) cache(block uint64) *cache { func (ethash *Ethash) dataset(block uint64, async bool) *dataset { // Retrieve the requested ethash dataset epoch := block / epochLength - currentI, futureI := ethash.datasets.get(epoch) - current := currentI.(*dataset) + current, future := ethash.datasets.get(epoch) // If async is specified, generate everything in a background thread if async && !current.generated() { go func() { current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.DatasetsLockMmap, ethash.config.PowMode == ModeTest) - - if futureI != nil { - future := futureI.(*dataset) + if future != nil { future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.DatasetsLockMmap, ethash.config.PowMode == ModeTest) } }() } else { // Either blocking generation was requested, or already done current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.DatasetsLockMmap, ethash.config.PowMode == ModeTest) - - if futureI != nil { - future := futureI.(*dataset) + if future != nil { go future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.DatasetsLockMmap, ethash.config.PowMode == ModeTest) } } diff --git a/go.mod b/go.mod index 60afbfffb965..2012eda30885 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,6 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 - github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e github.com/holiman/bloomfilter/v2 v2.0.3 github.com/holiman/uint256 v1.2.0 diff --git a/go.sum b/go.sum index 82818291cb60..9e54fafbd6e9 100644 --- a/go.sum +++ b/go.sum @@ -226,7 +226,6 @@ github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpx github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw= github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU= diff --git a/les/vflux/server/clientdb.go b/les/vflux/server/clientdb.go index 30cd9a652829..a39cbec36a92 100644 --- a/les/vflux/server/clientdb.go +++ b/les/vflux/server/clientdb.go @@ -22,13 +22,13 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/les/utils" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rlp" - lru "github.com/hashicorp/golang-lru" ) const ( @@ -57,7 +57,7 @@ var ( type nodeDB struct { db ethdb.KeyValueStore - cache *lru.Cache + cache *lru.Cache[string, utils.ExpiredValue] auxbuf []byte // 37-byte auxiliary buffer for key encoding verbuf [2]byte // 2-byte auxiliary buffer for db version evictCallBack func(mclock.AbsTime, bool, utils.ExpiredValue) bool // Callback to determine whether the balance can be evicted. @@ -67,10 +67,9 @@ type nodeDB struct { } func newNodeDB(db ethdb.KeyValueStore, clock mclock.Clock) *nodeDB { - cache, _ := lru.New(balanceCacheLimit) ndb := &nodeDB{ db: db, - cache: cache, + cache: lru.NewCache[string, utils.ExpiredValue](balanceCacheLimit), auxbuf: make([]byte, 37), clock: clock, closeCh: make(chan struct{}), @@ -125,8 +124,9 @@ func (db *nodeDB) getOrNewBalance(id []byte, neg bool) utils.ExpiredValue { key := db.key(id, neg) item, exist := db.cache.Get(string(key)) if exist { - return item.(utils.ExpiredValue) + return item } + var b utils.ExpiredValue enc, err := db.db.Get(key) if err != nil || len(enc) == 0 { diff --git a/light/lightchain.go b/light/lightchain.go index 84eee8ecaf8c..155f7b0c0548 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -27,6 +27,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -37,7 +38,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - lru "github.com/hashicorp/golang-lru" ) var ( @@ -61,9 +61,9 @@ type LightChain struct { genesisBlock *types.Block forker *core.ForkChoice - bodyCache *lru.Cache // Cache for the most recent block bodies - bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format - blockCache *lru.Cache // Cache for the most recent entire blocks + bodyCache *lru.Cache[common.Hash, *types.Body] + bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] + blockCache *lru.Cache[common.Hash, *types.Block] chainmu sync.RWMutex // protects header inserts quit chan struct{} @@ -79,18 +79,14 @@ type LightChain struct { // available in the database. It initialises the default Ethereum header // validator. func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, checkpoint *params.TrustedCheckpoint) (*LightChain, error) { - bodyCache, _ := lru.New(bodyCacheLimit) - bodyRLPCache, _ := lru.New(bodyCacheLimit) - blockCache, _ := lru.New(blockCacheLimit) - bc := &LightChain{ chainDb: odr.Database(), indexerConfig: odr.IndexerConfig(), odr: odr, quit: make(chan struct{}), - bodyCache: bodyCache, - bodyRLPCache: bodyRLPCache, - blockCache: blockCache, + bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit), + bodyRLPCache: lru.NewCache[common.Hash, rlp.RawValue](bodyCacheLimit), + blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit), engine: engine, } bc.forker = core.NewForkChoice(bc, nil) @@ -233,8 +229,7 @@ func (lc *LightChain) StateCache() state.Database { func (lc *LightChain) GetBody(ctx context.Context, hash common.Hash) (*types.Body, error) { // Short circuit if the body's already in the cache, retrieve otherwise if cached, ok := lc.bodyCache.Get(hash); ok { - body := cached.(*types.Body) - return body, nil + return cached, nil } number := lc.hc.GetBlockNumber(hash) if number == nil { @@ -254,7 +249,7 @@ func (lc *LightChain) GetBody(ctx context.Context, hash common.Hash) (*types.Bod func (lc *LightChain) GetBodyRLP(ctx context.Context, hash common.Hash) (rlp.RawValue, error) { // Short circuit if the body's already in the cache, retrieve otherwise if cached, ok := lc.bodyRLPCache.Get(hash); ok { - return cached.(rlp.RawValue), nil + return cached, nil } number := lc.hc.GetBlockNumber(hash) if number == nil { @@ -281,7 +276,7 @@ func (lc *LightChain) HasBlock(hash common.Hash, number uint64) bool { func (lc *LightChain) GetBlock(ctx context.Context, hash common.Hash, number uint64) (*types.Block, error) { // Short circuit if the block's already in the cache, retrieve otherwise if block, ok := lc.blockCache.Get(hash); ok { - return block.(*types.Block), nil + return block, nil } block, err := GetBlock(ctx, lc.odr, hash, number) if err != nil { From 722bb210bfe86984b39c80dcab79405157338f25 Mon Sep 17 00:00:00 2001 From: therainisme Date: Thu, 17 Nov 2022 21:19:03 +0800 Subject: [PATCH 384/715] rlp: improve tests for Split functions (#26200) This PR improves and extends the tests a bit --- rlp/raw_test.go | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/rlp/raw_test.go b/rlp/raw_test.go index 2812ef74c622..7b3255eca36b 100644 --- a/rlp/raw_test.go +++ b/rlp/raw_test.go @@ -60,15 +60,35 @@ func TestCountValues(t *testing.T) { } } -func TestSplitTypes(t *testing.T) { - if _, _, err := SplitString(unhex("C100")); err != ErrExpectedString { - t.Errorf("SplitString returned %q, want %q", err, ErrExpectedString) - } - if _, _, err := SplitList(unhex("01")); err != ErrExpectedList { - t.Errorf("SplitString returned %q, want %q", err, ErrExpectedList) +func TestSplitString(t *testing.T) { + for i, test := range []string{ + "C0", + "C100", + "C3010203", + "C88363617483646F67", + "F8384C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E7365637465747572206164697069736963696E6720656C6974", + } { + if _, _, err := SplitString(unhex(test)); !errors.Is(err, ErrExpectedString) { + t.Errorf("test %d: error mismatch: have %q, want %q", i, err, ErrExpectedString) + } } - if _, _, err := SplitList(unhex("81FF")); err != ErrExpectedList { - t.Errorf("SplitString returned %q, want %q", err, ErrExpectedList) +} + +func TestSplitList(t *testing.T) { + for i, test := range []string{ + "80", + "00", + "01", + "8180", + "81FF", + "820400", + "83636174", + "83646F67", + "B8384C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E7365637465747572206164697069736963696E6720656C6974", + } { + if _, _, err := SplitList(unhex(test)); !errors.Is(err, ErrExpectedList) { + t.Errorf("test %d: error mismatch: have %q, want %q", i, err, ErrExpectedList) + } } } From 97c563e0557cdfb7013e2377e3aad15bdc5f0a7c Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 17 Nov 2022 15:30:53 +0100 Subject: [PATCH 385/715] rpc, internal/guide: speed up tests a bit (#26193) This removes an RPC test which takes > 90s to execute, and updates the internal/guide tests to use lighter scrypt parameters. Co-authored-by: Felix Lange --- internal/guide/guide_test.go | 4 +- rpc/websocket_test.go | 89 ------------------------------------ 2 files changed, 2 insertions(+), 91 deletions(-) diff --git a/internal/guide/guide_test.go b/internal/guide/guide_test.go index cdf0ec4d262f..f682daac91b0 100644 --- a/internal/guide/guide_test.go +++ b/internal/guide/guide_test.go @@ -38,8 +38,8 @@ func TestAccountManagement(t *testing.T) { // Create a temporary folder to work with workdir := t.TempDir() - // Create an encrypted keystore with standard crypto parameters - ks := keystore.NewKeyStore(filepath.Join(workdir, "keystore"), keystore.StandardScryptN, keystore.StandardScryptP) + // Create an encrypted keystore (using light scrypt parameters) + ks := keystore.NewKeyStore(filepath.Join(workdir, "keystore"), keystore.LightScryptN, keystore.LightScryptP) // Create a new account with the specified encryption passphrase newAcc, err := ks.NewAccount("Creation password") diff --git a/rpc/websocket_test.go b/rpc/websocket_test.go index f74b7fd08bb4..fb9357605b8b 100644 --- a/rpc/websocket_test.go +++ b/rpc/websocket_test.go @@ -19,14 +19,10 @@ package rpc import ( "context" "errors" - "io" "net" "net/http" "net/http/httptest" - "net/http/httputil" - "net/url" "strings" - "sync/atomic" "testing" "time" @@ -227,63 +223,6 @@ func TestClientWebsocketLargeMessage(t *testing.T) { } } -func TestClientWebsocketSevered(t *testing.T) { - t.Parallel() - - var ( - server = wsPingTestServer(t, nil) - ctx = context.Background() - ) - defer server.Shutdown(ctx) - - u, err := url.Parse("http://" + server.Addr) - if err != nil { - t.Fatal(err) - } - rproxy := httputil.NewSingleHostReverseProxy(u) - var severable *severableReadWriteCloser - rproxy.ModifyResponse = func(response *http.Response) error { - severable = &severableReadWriteCloser{ReadWriteCloser: response.Body.(io.ReadWriteCloser)} - response.Body = severable - return nil - } - frontendProxy := httptest.NewServer(rproxy) - defer frontendProxy.Close() - - wsURL := "ws:" + strings.TrimPrefix(frontendProxy.URL, "http:") - client, err := DialWebsocket(ctx, wsURL, "") - if err != nil { - t.Fatalf("client dial error: %v", err) - } - defer client.Close() - - resultChan := make(chan int) - sub, err := client.EthSubscribe(ctx, resultChan, "foo") - if err != nil { - t.Fatalf("client subscribe error: %v", err) - } - - // sever the connection - severable.Sever() - - // Wait for subscription error. - timeout := time.NewTimer(3 * wsPingInterval) - defer timeout.Stop() - for { - select { - case err := <-sub.Err(): - t.Log("client subscription error:", err) - return - case result := <-resultChan: - t.Error("unexpected result:", result) - return - case <-timeout.C: - t.Error("didn't get any error within the test timeout") - return - } - } -} - // wsPingTestServer runs a WebSocket server which accepts a single subscription request. // When a value arrives on sendPing, the server sends a ping frame, waits for a matching // pong and finally delivers a single subscription result. @@ -386,31 +325,3 @@ func wsPingTestHandler(t *testing.T, conn *websocket.Conn, shutdown, sendPing <- } } } - -// severableReadWriteCloser wraps an io.ReadWriteCloser and provides a Sever() method to drop writes and read empty. -type severableReadWriteCloser struct { - io.ReadWriteCloser - severed int32 // atomic -} - -func (s *severableReadWriteCloser) Sever() { - atomic.StoreInt32(&s.severed, 1) -} - -func (s *severableReadWriteCloser) Read(p []byte) (n int, err error) { - if atomic.LoadInt32(&s.severed) > 0 { - return 0, nil - } - return s.ReadWriteCloser.Read(p) -} - -func (s *severableReadWriteCloser) Write(p []byte) (n int, err error) { - if atomic.LoadInt32(&s.severed) > 0 { - return len(p), nil - } - return s.ReadWriteCloser.Write(p) -} - -func (s *severableReadWriteCloser) Close() error { - return s.ReadWriteCloser.Close() -} From c2e0abce2eedc1ba2a1b32c46fd07ef18a25354a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 17 Nov 2022 15:33:03 +0100 Subject: [PATCH 386/715] ethstats: set readlimit on ethstats server connection (#26207) This prevents DoS when connected to a malicious ethstats server. --- ethstats/ethstats.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go index f6ad360519c6..e059844a17e6 100644 --- a/ethstats/ethstats.go +++ b/ethstats/ethstats.go @@ -57,6 +57,8 @@ const ( txChanSize = 4096 // chainHeadChanSize is the size of channel listening to ChainHeadEvent. chainHeadChanSize = 10 + + messageSizeLimit = 15 * 1024 * 1024 ) // backend encompasses the bare-minimum functionality needed for ethstats reporting @@ -121,6 +123,7 @@ type connWrapper struct { } func newConnectionWrapper(conn *websocket.Conn) *connWrapper { + conn.SetReadLimit(messageSizeLimit) return &connWrapper{conn: conn} } From 6975f0999849e5b0ce146b2ef8c87aac2ff22d58 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 21 Nov 2022 09:52:12 +0100 Subject: [PATCH 387/715] eth/catalyst: make tests less time-sensitive (#26201) This makes a couple of sometimes-failing tests less brittle. --- eth/catalyst/api_test.go | 68 +++++++++++++++------------------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 7abca5a9a090..7872c7f711f1 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -93,24 +93,30 @@ func TestEth2AssembleBlock(t *testing.T) { blockParams := beacon.PayloadAttributesV1{ Timestamp: blocks[9].Time() + 5, } - // This test is a bit time-sensitive, the miner needs to pick up on the - // txs in the pool. Therefore, we retry once if it fails on the first attempt. - var testErr error - for retries := 2; retries > 0; retries-- { - if execData, err := assembleBlock(api, blocks[9].Hash(), &blockParams); err != nil { - t.Fatalf("error producing block, err=%v", err) - } else if have, want := len(execData.Transactions), 1; have != want { - testErr = fmt.Errorf("invalid number of transactions, have %d want %d", have, want) - } else { - testErr = nil - break - } - } - if testErr != nil { + // The miner needs to pick up on the txs in the pool, so a few retries might be + // needed. + if _, testErr := assembleWithTransactions(api, blocks[9].Hash(), &blockParams, 1); testErr != nil { t.Fatal(testErr) } } +// assembleWithTransactions tries to assemble a block, retrying until it has 'want', +// number of transactions in it, or it has retried three times. +func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributesV1, want int) (execData *beacon.ExecutableDataV1, err error) { + for retries := 3; retries > 0; retries-- { + execData, err = assembleBlock(api, parentHash, params) + if err != nil { + return nil, err + } + if have, want := len(execData.Transactions), want; have != want { + err = fmt.Errorf("invalid number of transactions, have %d want %d", have, want) + continue + } + return execData, nil + } + return nil, err +} + func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { genesis, blocks := generatePreMergeChain(10) n, ethservice := startEthService(t, genesis, blocks[:9]) @@ -123,21 +129,10 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { blockParams := beacon.PayloadAttributesV1{ Timestamp: blocks[8].Time() + 5, } - // This test is a bit time-sensitive, the miner needs to pick up on the - // txs in the pool. Therefore, we retry once if it fails on the first attempt. - var testErr error - for retries := 2; retries > 0; retries-- { - if execData, err := assembleBlock(api, blocks[8].Hash(), &blockParams); err != nil { - t.Fatalf("error producing block, err=%v", err) - } else if have, want := len(execData.Transactions), blocks[9].Transactions().Len(); have != want { - testErr = fmt.Errorf("invalid number of transactions, have %d want %d", have, want) - } else { - testErr = nil - break - } - } - if testErr != nil { - t.Fatal(testErr) + // The miner needs to pick up on the txs in the pool, so a few retries might be + // needed. + if _, err := assembleWithTransactions(api, blocks[8].Hash(), &blockParams, blocks[9].Transactions().Len()); err != nil { + t.Fatal(err) } } @@ -293,9 +288,9 @@ func TestEth2NewBlock(t *testing.T) { tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) ethservice.TxPool().AddLocal(tx) - execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{ + execData, err := assembleWithTransactions(api, parent.Hash(), &beacon.PayloadAttributesV1{ Timestamp: parent.Time() + 5, - }) + }, 1) if err != nil { t.Fatalf("Failed to create the executable data %v", err) } @@ -915,17 +910,6 @@ func TestSimultaneousNewBlock(t *testing.T) { parent = preMergeBlocks[len(preMergeBlocks)-1] ) for i := 0; i < 10; i++ { - statedb, _ := ethservice.BlockChain().StateAt(parent.Root()) - ethservice.TxPool().AddLocal(types.MustSignNewTx(testKey, types.LatestSigner(ethservice.BlockChain().Config()), - &types.DynamicFeeTx{ - Nonce: statedb.GetNonce(testAddr), - Value: big.NewInt(0), - GasFeeCap: big.NewInt(2 * params.InitialBaseFee), - GasTipCap: big.NewInt(2 * params.InitialBaseFee), - ChainID: genesis.Config.ChainID, - Gas: 1000000, - To: &common.Address{99}, - })) execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{ Timestamp: parent.Time() + 5, }) From 64dccf7aa411c5c7cd36090c3d9b9892945ae813 Mon Sep 17 00:00:00 2001 From: kumavis Date: Sun, 20 Nov 2022 23:18:18 -1000 Subject: [PATCH 388/715] cmd/utils: log path used when checking disk space (#26212) This change logs the path checked when encountering low disk space. --- cmd/utils/cmd.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 90f009041477..d1d900a6da9d 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -125,11 +125,11 @@ func monitorFreeDiskSpace(sigc chan os.Signal, path string, freeDiskSpaceCritica break } if freeSpace < freeDiskSpaceCritical { - log.Error("Low disk space. Gracefully shutting down Geth to prevent database corruption.", "available", common.StorageSize(freeSpace)) + log.Error("Low disk space. Gracefully shutting down Geth to prevent database corruption.", "available", common.StorageSize(freeSpace), "path", path) sigc <- syscall.SIGTERM break } else if freeSpace < 2*freeDiskSpaceCritical { - log.Warn("Disk space is running low. Geth will shutdown if disk space runs below critical level.", "available", common.StorageSize(freeSpace), "critical_level", common.StorageSize(freeDiskSpaceCritical)) + log.Warn("Disk space is running low. Geth will shutdown if disk space runs below critical level.", "available", common.StorageSize(freeSpace), "critical_level", common.StorageSize(freeDiskSpaceCritical), "path", path) } time.Sleep(30 * time.Second) } From ec2ec2d08e28571dc189903f743cc3931da254a9 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 22 Nov 2022 22:39:52 +0100 Subject: [PATCH 389/715] core: implement EIP-3651, warm coinbase (#25819) Implements EIP-3651, "Warm Coinbase", for Shanghai hardfork. Specification: https://eips.ethereum.org/EIPS/eip-3651. --- core/blockchain_test.go | 108 +++++++++++++++++++++++++++++++++++++ core/state/statedb.go | 22 +++++--- core/state_transition.go | 2 +- core/vm/interface.go | 2 +- core/vm/runtime/runtime.go | 6 +-- tests/state_test.go | 2 +- 6 files changed, 128 insertions(+), 14 deletions(-) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index c476d4596296..faa4b383feb4 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4187,3 +4187,111 @@ func TestTransientStorageReset(t *testing.T) { t.Fatalf("Unexpected dirty storage slot") } } + +func TestEIP3651(t *testing.T) { + var ( + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") + bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") + engine = ethash.NewFaker() + + // A sender who makes transactions, has some funds + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + gspec = &Genesis{ + Config: params.AllEthashProtocolChanges, + Alloc: GenesisAlloc{ + addr1: {Balance: funds}, + addr2: {Balance: funds}, + // The address 0xAAAA sloads 0x00 and 0x01 + aa: { + Code: []byte{ + byte(vm.PC), + byte(vm.PC), + byte(vm.SLOAD), + byte(vm.SLOAD), + }, + Nonce: 0, + Balance: big.NewInt(0), + }, + // The address 0xBBBB calls 0xAAAA + bb: { + Code: []byte{ + byte(vm.PUSH1), 0, // out size + byte(vm.DUP1), // out offset + byte(vm.DUP1), // out insize + byte(vm.DUP1), // in offset + byte(vm.PUSH2), // address + byte(0xaa), + byte(0xaa), + byte(vm.GAS), // gas + byte(vm.DELEGATECALL), + }, + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + } + ) + + gspec.Config.BerlinBlock = common.Big0 + gspec.Config.LondonBlock = common.Big0 + gspec.Config.ShanghaiBlock = common.Big0 + signer := types.LatestSigner(gspec.Config) + + _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { + b.SetCoinbase(aa) + // One transaction to Coinbase + txdata := &types.DynamicFeeTx{ + ChainID: gspec.Config.ChainID, + Nonce: 0, + To: &bb, + Gas: 500000, + GasFeeCap: newGwei(5), + GasTipCap: big.NewInt(2), + AccessList: nil, + Data: []byte{}, + } + tx := types.NewTx(txdata) + tx, _ = types.SignTx(tx, signer, key1) + + b.AddTx(tx) + }) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr)}, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + + block := chain.GetBlockByNumber(1) + + // 1+2: Ensure EIP-1559 access lists are accounted for via gas usage. + innerGas := vm.GasQuickStep*2 + params.ColdSloadCostEIP2929*2 + expectedGas := params.TxGas + 5*vm.GasFastestStep + vm.GasQuickStep + 100 + innerGas // 100 because 0xaaaa is in access list + if block.GasUsed() != expectedGas { + t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed()) + } + + state, _ := chain.State() + + // 3: Ensure that miner received only the tx's tip. + actual := state.GetBalance(block.Coinbase()) + expected := new(big.Int).Add( + new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()), + ethash.ConstantinopleBlockReward, + ) + if actual.Cmp(expected) != 0 { + t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual) + } + + // 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee). + actual = new(big.Int).Sub(funds, state.GetBalance(addr1)) + expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64())) + if actual.Cmp(expected) != 0 { + t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) + } +} diff --git a/core/state/statedb.go b/core/state/statedb.go index 559f7fa51898..b85c94850b40 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1067,26 +1067,32 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { // - Add the contents of the optional tx access list (2930) // // Potential EIPs: -// - Reset transient storage(1153) -func (s *StateDB) Prepare(rules params.Rules, sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) { +// - Reset access list (Berlin) +// - Add coinbase to access list (EIP-3651) +// - Reset transient storage (EIP-1153) +func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) { if rules.IsBerlin { // Clear out any leftover from previous executions - s.accessList = newAccessList() + al := newAccessList() + s.accessList = al - s.AddAddressToAccessList(sender) + al.AddAddress(sender) if dst != nil { - s.AddAddressToAccessList(*dst) + al.AddAddress(*dst) // If it's a create-tx, the destination will be added inside evm.create } for _, addr := range precompiles { - s.AddAddressToAccessList(addr) + al.AddAddress(addr) } for _, el := range list { - s.AddAddressToAccessList(el.Address) + al.AddAddress(el.Address) for _, key := range el.StorageKeys { - s.AddSlotToAccessList(el.Address, key) + al.AddSlot(el.Address, key) } } + if rules.IsShanghai { // EIP-3651: warm coinbase + al.AddAddress(coinbase) + } } // Reset transient storage at the beginning of transaction execution s.transientStorage = newTransientStorage() diff --git a/core/state_transition.go b/core/state_transition.go index 7387acf3539b..a6cf3f7c32d6 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -322,7 +322,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - st.state.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) + st.state.Prepare(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) var ( ret []byte diff --git a/core/vm/interface.go b/core/vm/interface.go index 624272dbf37c..0ee32b1dd510 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -69,7 +69,7 @@ type StateDB interface { // AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform // even if the feature/fork is not active yet AddSlotToAccessList(addr common.Address, slot common.Hash) - Prepare(rules params.Rules, sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) + Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) RevertToSnapshot(int) Snapshot() int diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index b185211ff13e..6b355deeb6e2 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -122,7 +122,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - cfg.State.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil) + cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) cfg.State.CreateAccount(address) // set the receiver's (the executing contract) code for execution. @@ -156,7 +156,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - cfg.State.Prepare(rules, cfg.Origin, nil, vm.ActivePrecompiles(rules), nil) + cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil) // Call the code with the given configuration. code, address, leftOverGas, err := vmenv.Create( @@ -185,7 +185,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - statedb.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil) + statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) // Call the code with the given configuration. ret, leftOverGas, err := vmenv.Call( diff --git a/tests/state_test.go b/tests/state_test.go index 86b1a0e3c07a..cb7f76521780 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -241,7 +241,7 @@ func runBenchmark(b *testing.B, t *StateTest) { b.ResetTimer() for n := 0; n < b.N; n++ { snapshot := statedb.Snapshot() - statedb.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) + statedb.Prepare(rules, msg.From(), context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) b.StartTimer() start := time.Now() From 193f350eb911c9d8a93577d619986e97f490b700 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 24 Nov 2022 10:50:28 +0100 Subject: [PATCH 390/715] core/rawdb: improve freezerTable.Sync (#26245) While investigating #22374, I noticed that the Sync operation of the freezer does not take the table lock. It also doesn't call sync for all files if there is an error with one of them. I doubt this will fix anything, but didn't want to drop the fix on the floor either. --- core/rawdb/freezer_table.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 746f825e4038..7af937fd81ad 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -867,13 +867,20 @@ func (t *freezerTable) advanceHead() error { // Sync pushes any pending data from memory out to disk. This is an expensive // operation, so use it with care. func (t *freezerTable) Sync() error { - if err := t.index.Sync(); err != nil { - return err - } - if err := t.meta.Sync(); err != nil { - return err + t.lock.Lock() + defer t.lock.Unlock() + + var err error + trackError := func(e error) { + if e != nil && err == nil { + err = e + } } - return t.head.Sync() + + trackError(t.index.Sync()) + trackError(t.meta.Sync()) + trackError(t.head.Sync()) + return err } func (t *freezerTable) dumpIndexStdout(start, stop int64) { From 8846c07d044f30dca8cd0db91c6245f71f4b24fa Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 24 Nov 2022 11:37:58 +0100 Subject: [PATCH 391/715] cmd/utils: print warning when --metrics.port set without --metrics.addr (#26248) --- cmd/utils/flags.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 974c03579507..41f263530f02 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -926,14 +926,14 @@ var ( // to enable a public-OK metrics endpoint without having to worry about ALSO exposing // other profiling behavior or information. MetricsHTTPFlag = &cli.StringFlag{ - Name: "metrics.addr", - Usage: "Enable stand-alone metrics HTTP server listening interface", - Value: metrics.DefaultConfig.HTTP, + Name: "metrics.addr", + Usage: `Enable stand-alone metrics HTTP server listening interface.`, Category: flags.MetricsCategory, } MetricsPortFlag = &cli.IntFlag{ - Name: "metrics.port", - Usage: "Metrics HTTP server listening port", + Name: "metrics.port", + Usage: `Metrics HTTP server listening port. +Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.`, Value: metrics.DefaultConfig.Port, Category: flags.MetricsCategory, } @@ -2150,6 +2150,8 @@ func SetupMetrics(ctx *cli.Context) { address := fmt.Sprintf("%s:%d", ctx.String(MetricsHTTPFlag.Name), ctx.Int(MetricsPortFlag.Name)) log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address) exp.Setup(address) + } else if ctx.IsSet(MetricsPortFlag.Name) { + log.Warn(fmt.Sprintf("--%s specified without --%s, metrics server will not start.", MetricsPortFlag.Name, MetricsHTTPFlag.Name)) } } } From e76813eb13bc55cfbe1d7487c6fc65b3cbe64d46 Mon Sep 17 00:00:00 2001 From: 6xiaowu9 <736518585@qq.com> Date: Thu, 24 Nov 2022 18:45:20 +0800 Subject: [PATCH 392/715] signer/core/apitypes: deep convert types in slice (#26203) --- .../apitypes/signed_data_internal_test.go | 36 +++++++++++++++++++ signer/core/apitypes/types.go | 19 ++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/signer/core/apitypes/signed_data_internal_test.go b/signer/core/apitypes/signed_data_internal_test.go index 8379c0a7f075..af7fc93ed88f 100644 --- a/signer/core/apitypes/signed_data_internal_test.go +++ b/signer/core/apitypes/signed_data_internal_test.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" ) func TestBytesPadding(t *testing.T) { @@ -197,3 +198,38 @@ func TestParseInteger(t *testing.T) { } } } + +func TestConvertStringDataToSlice(t *testing.T) { + slice := []string{"a", "b", "c"} + var it interface{} = slice + _, err := convertDataToSlice(it) + if err != nil { + t.Fatal(err) + } +} + +func TestConvertUint256DataToSlice(t *testing.T) { + slice := []*math.HexOrDecimal256{ + math.NewHexOrDecimal256(1), + math.NewHexOrDecimal256(2), + math.NewHexOrDecimal256(3), + } + var it interface{} = slice + _, err := convertDataToSlice(it) + if err != nil { + t.Fatal(err) + } +} + +func TestConvertAddressDataToSlice(t *testing.T) { + slice := []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000001"), + common.HexToAddress("0x0000000000000000000000000000000000000002"), + common.HexToAddress("0x0000000000000000000000000000000000000003"), + } + var it interface{} = slice + _, err := convertDataToSlice(it) + if err != nil { + t.Fatal(err) + } +} diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 6e883b27c847..3e099feaab7b 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -367,8 +367,8 @@ func (typedData *TypedData) EncodeData(primaryType string, data map[string]inter encType := field.Type encValue := data[field.Name] if encType[len(encType)-1:] == "]" { - arrayValue, ok := encValue.([]interface{}) - if !ok { + arrayValue, err := convertDataToSlice(encValue) + if err != nil { return nil, dataMismatchError(encType, encValue) } @@ -573,6 +573,19 @@ func dataMismatchError(encType string, encValue interface{}) error { return fmt.Errorf("provided data '%v' doesn't match type '%s'", encValue, encType) } +func convertDataToSlice(encValue interface{}) ([]interface{}, error) { + var outEncValue []interface{} + rv := reflect.ValueOf(encValue) + if rv.Kind() == reflect.Slice { + for i := 0; i < rv.Len(); i++ { + outEncValue = append(outEncValue, rv.Index(i).Interface()) + } + } else { + return outEncValue, fmt.Errorf("provided data '%v' is not slice", encValue) + } + return outEncValue, nil +} + // validate makes sure the types are sound func (typedData *TypedData) validate() error { if err := typedData.Types.validate(); err != nil { @@ -632,7 +645,7 @@ func (typedData *TypedData) formatData(primaryType string, data map[string]inter Typ: field.Type, } if field.isArray() { - arrayValue, _ := encValue.([]interface{}) + arrayValue, _ := convertDataToSlice(encValue) parsedType := field.typeName() for _, v := range arrayValue { if typedData.Types[parsedType] != nil { From c5dc61c62dabf88091943e02ad309448df26feaa Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 24 Nov 2022 13:03:38 +0100 Subject: [PATCH 393/715] cmd/utils: gofmt --- cmd/utils/flags.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 41f263530f02..673aefb5254d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -926,8 +926,8 @@ var ( // to enable a public-OK metrics endpoint without having to worry about ALSO exposing // other profiling behavior or information. MetricsHTTPFlag = &cli.StringFlag{ - Name: "metrics.addr", - Usage: `Enable stand-alone metrics HTTP server listening interface.`, + Name: "metrics.addr", + Usage: `Enable stand-alone metrics HTTP server listening interface.`, Category: flags.MetricsCategory, } MetricsPortFlag = &cli.IntFlag{ From add1bff13fff722acbf1bd06b57245361ff82359 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 25 Nov 2022 16:10:31 +0800 Subject: [PATCH 394/715] core/rawdb: fix freezer validation (#26251) * core/rawdb: fix freezer validation * core/rawdb: address comment --- core/rawdb/freezer.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 53bd989a482d..7bae0a2ea0d1 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -318,30 +318,35 @@ func (f *Freezer) Sync() error { return nil } -// validate checks that every table has the same length. +// validate checks that every table has the same boundary. // Used instead of `repair` in readonly mode. func (f *Freezer) validate() error { if len(f.tables) == 0 { return nil } var ( - length uint64 - name string + head uint64 + tail uint64 + name string ) - // Hack to get length of any table + // Hack to get boundary of any table for kind, table := range f.tables { - length = atomic.LoadUint64(&table.items) + head = atomic.LoadUint64(&table.items) + tail = atomic.LoadUint64(&table.itemHidden) name = kind break } - // Now check every table against that length + // Now check every table against those boundaries. for kind, table := range f.tables { - items := atomic.LoadUint64(&table.items) - if length != items { - return fmt.Errorf("freezer tables %s and %s have differing lengths: %d != %d", kind, name, items, length) + if head != atomic.LoadUint64(&table.items) { + return fmt.Errorf("freezer tables %s and %s have differing head: %d != %d", kind, name, atomic.LoadUint64(&table.items), head) + } + if tail != atomic.LoadUint64(&table.itemHidden) { + return fmt.Errorf("freezer tables %s and %s have differing tail: %d != %d", kind, name, atomic.LoadUint64(&table.itemHidden), tail) } } - atomic.StoreUint64(&f.frozen, length) + atomic.StoreUint64(&f.frozen, head) + atomic.StoreUint64(&f.tail, tail) return nil } From 6a4e05c93accb11d16037bf92534ed57a84f9394 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 25 Nov 2022 09:13:45 +0100 Subject: [PATCH 395/715] signer: enable typed data signing from signer rpc (#26241) This PR should makes it easier to sign EIP-712 typed data via the accounts.Wallet API, by using the mimetype for typed data. Co-authored-by: nasdf --- signer/core/signed_data.go | 121 +++++++++++++++++++------------- signer/core/signed_data_test.go | 22 ++++-- 2 files changed, 89 insertions(+), 54 deletions(-) diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go index c0da22e62662..8ee572f53ec8 100644 --- a/signer/core/signed_data.go +++ b/signer/core/signed_data.go @@ -18,6 +18,7 @@ package core import ( "context" + "encoding/json" "errors" "fmt" "mime" @@ -135,11 +136,7 @@ func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType req = &SignDataRequest{ContentType: mediaType, Rawdata: []byte(msg), Messages: messages, Hash: sighash} case apitypes.ApplicationClique.Mime: // Clique is the Ethereum PoA standard - stringData, ok := data.(string) - if !ok { - return nil, useEthereumV, fmt.Errorf("input for %v must be an hex-encoded string", apitypes.ApplicationClique.Mime) - } - cliqueData, err := hexutil.Decode(stringData) + cliqueData, err := fromHex(data) if err != nil { return nil, useEthereumV, err } @@ -167,27 +164,30 @@ func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType // Clique uses V on the form 0 or 1 useEthereumV = false req = &SignDataRequest{ContentType: mediaType, Rawdata: cliqueRlp, Messages: messages, Hash: sighash} + case apitypes.DataTyped.Mime: + // EIP-712 conformant typed data + var err error + req, err = typedDataRequest(data) + if err != nil { + return nil, useEthereumV, err + } default: // also case TextPlain.Mime: // Calculates an Ethereum ECDSA signature for: // hash = keccak256("\x19Ethereum Signed Message:\n${message length}${message}") - // We expect it to be a string - if stringData, ok := data.(string); !ok { - return nil, useEthereumV, fmt.Errorf("input for text/plain must be an hex-encoded string") - } else { - if textData, err := hexutil.Decode(stringData); err != nil { - return nil, useEthereumV, err - } else { - sighash, msg := accounts.TextAndHash(textData) - messages := []*apitypes.NameValueType{ - { - Name: "message", - Typ: accounts.MimetypeTextPlain, - Value: msg, - }, - } - req = &SignDataRequest{ContentType: mediaType, Rawdata: []byte(msg), Messages: messages, Hash: sighash} - } + // We expect input to be a hex-encoded string + textData, err := fromHex(data) + if err != nil { + return nil, useEthereumV, err } + sighash, msg := accounts.TextAndHash(textData) + messages := []*apitypes.NameValueType{ + { + Name: "message", + Typ: accounts.MimetypeTextPlain, + Value: msg, + }, + } + req = &SignDataRequest{ContentType: mediaType, Rawdata: []byte(msg), Messages: messages, Hash: sighash} } req.Address = addr req.Meta = MetadataFromContext(ctx) @@ -233,20 +233,12 @@ func (api *SignerAPI) SignTypedData(ctx context.Context, addr common.MixedcaseAd // - the signature preimage (hash) func (api *SignerAPI) signTypedData(ctx context.Context, addr common.MixedcaseAddress, typedData apitypes.TypedData, validationMessages *apitypes.ValidationMessages) (hexutil.Bytes, hexutil.Bytes, error) { - sighash, rawData, err := apitypes.TypedDataAndHash(typedData) + req, err := typedDataRequest(typedData) if err != nil { return nil, nil, err } - messages, err := typedData.Format() - if err != nil { - return nil, nil, err - } - req := &SignDataRequest{ - ContentType: apitypes.DataTyped.Mime, - Rawdata: []byte(rawData), - Messages: messages, - Hash: sighash, - Address: addr} + req.Address = addr + req.Meta = MetadataFromContext(ctx) if validationMessages != nil { req.Callinfo = validationMessages.Messages } @@ -255,7 +247,46 @@ func (api *SignerAPI) signTypedData(ctx context.Context, addr common.MixedcaseAd api.UI.ShowError(err.Error()) return nil, nil, err } - return signature, sighash, nil + return signature, req.Hash, nil +} + +// fromHex tries to interpret the data as type string, and convert from +// hexadecimal to []byte +func fromHex(data any) ([]byte, error) { + if stringData, ok := data.(string); ok { + binary, err := hexutil.Decode(stringData) + return binary, err + } + return nil, fmt.Errorf("wrong type %T", data) +} + +// typeDataRequest tries to convert the data into a SignDataRequest. +func typedDataRequest(data any) (*SignDataRequest, error) { + var typedData apitypes.TypedData + if td, ok := data.(apitypes.TypedData); ok { + typedData = td + } else { // Hex-encoded data + jsonData, err := fromHex(data) + if err != nil { + return nil, err + } + if err = json.Unmarshal(jsonData, &typedData); err != nil { + return nil, err + } + } + messages, err := typedData.Format() + if err != nil { + return nil, err + } + sighash, rawData, err := apitypes.TypedDataAndHash(typedData) + if err != nil { + return nil, err + } + return &SignDataRequest{ + ContentType: apitypes.DataTyped.Mime, + Rawdata: []byte(rawData), + Messages: messages, + Hash: sighash}, nil } // EcRecover recovers the address associated with the given sig. @@ -293,30 +324,20 @@ func UnmarshalValidatorData(data interface{}) (apitypes.ValidatorData, error) { if !ok { return apitypes.ValidatorData{}, errors.New("validator input is not a map[string]interface{}") } - addr, ok := raw["address"].(string) - if !ok { - return apitypes.ValidatorData{}, errors.New("validator address is not sent as a string") - } - addrBytes, err := hexutil.Decode(addr) + addrBytes, err := fromHex(raw["address"]) if err != nil { - return apitypes.ValidatorData{}, err + return apitypes.ValidatorData{}, fmt.Errorf("validator address error: %w", err) } - if !ok || len(addrBytes) == 0 { + if len(addrBytes) == 0 { return apitypes.ValidatorData{}, errors.New("validator address is undefined") } - - message, ok := raw["message"].(string) - if !ok { - return apitypes.ValidatorData{}, errors.New("message is not sent as a string") - } - messageBytes, err := hexutil.Decode(message) + messageBytes, err := fromHex(raw["message"]) if err != nil { - return apitypes.ValidatorData{}, err + return apitypes.ValidatorData{}, fmt.Errorf("message error: %w", err) } - if !ok || len(messageBytes) == 0 { + if len(messageBytes) == 0 { return apitypes.ValidatorData{}, errors.New("message is undefined") } - return apitypes.ValidatorData{ Address: common.BytesToAddress(addrBytes), Message: messageBytes, diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index 7d5661e7e6a8..8deff919cba1 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -220,15 +220,29 @@ func TestSignData(t *testing.T) { if signature == nil || len(signature) != 65 { t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) } - // data/typed + // data/typed via SignTypeData control.approveCh <- "Y" control.inputCh <- "a_long_password" - signature, err = api.SignTypedData(context.Background(), a, typedData) - if err != nil { + var want []byte + if signature, err = api.SignTypedData(context.Background(), a, typedData); err != nil { t.Fatal(err) + } else if signature == nil || len(signature) != 65 { + t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) + } else { + want = signature } - if signature == nil || len(signature) != 65 { + + // data/typed via SignData / mimetype typed data + control.approveCh <- "Y" + control.inputCh <- "a_long_password" + if typedDataJson, err := json.Marshal(typedData); err != nil { + t.Fatal(err) + } else if signature, err = api.SignData(context.Background(), apitypes.DataTyped.Mime, a, hexutil.Encode(typedDataJson)); err != nil { + t.Fatal(err) + } else if signature == nil || len(signature) != 65 { t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) + } else if have := signature; !bytes.Equal(have, want) { + t.Fatalf("want %x, have %x", want, have) } } From 8c6e74eed497e1c7088d0362ff64581435b347dd Mon Sep 17 00:00:00 2001 From: Wihan de Beer Date: Fri, 25 Nov 2022 17:29:38 +0200 Subject: [PATCH 396/715] rpc: decrease websocket ping interval (#26253) This is to cater for more node providers. --- rpc/websocket.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/websocket.go b/rpc/websocket.go index f6d09288590c..21e446e9f816 100644 --- a/rpc/websocket.go +++ b/rpc/websocket.go @@ -35,7 +35,7 @@ import ( const ( wsReadBuffer = 1024 wsWriteBuffer = 1024 - wsPingInterval = 60 * time.Second + wsPingInterval = 30 * time.Second wsPingWriteTimeout = 5 * time.Second wsPongTimeout = 30 * time.Second wsMessageSizeLimit = 15 * 1024 * 1024 From 53d1ae096ac0515173e17f0f81a553e5f39027f7 Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Sat, 26 Nov 2022 00:30:07 +0900 Subject: [PATCH 397/715] p2p/nat: use IP.IsPrivate (#26252) --- p2p/nat/natpmp.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/p2p/nat/natpmp.go b/p2p/nat/natpmp.go index 7f85543f8e29..c43580001e36 100644 --- a/p2p/nat/natpmp.go +++ b/p2p/nat/natpmp.go @@ -95,13 +95,6 @@ func discoverPMP() Interface { return nil } -var ( - // LAN IP ranges - _, lan10, _ = net.ParseCIDR("10.0.0.0/8") - _, lan176, _ = net.ParseCIDR("172.16.0.0/12") - _, lan192, _ = net.ParseCIDR("192.168.0.0/16") -) - // TODO: improve this. We currently assume that (on most networks) // the router is X.X.X.1 in a local LAN range. func potentialGateways() (gws []net.IP) { @@ -116,7 +109,7 @@ func potentialGateways() (gws []net.IP) { } for _, addr := range ifaddrs { if x, ok := addr.(*net.IPNet); ok { - if lan10.Contains(x.IP) || lan176.Contains(x.IP) || lan192.Contains(x.IP) { + if x.IP.IsPrivate() { ip := x.IP.Mask(x.Mask).To4() if ip != nil { ip[3] = ip[3] | 0x01 From 1325fef1025b9feb3342308265b6d1399614be30 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 28 Nov 2022 11:03:20 +0100 Subject: [PATCH 398/715] internal/web3ext: fix eth_call stateOverrides in console (#26265) web3.js's eth_call which we were defaulting to doesn't have the stateOverrides parameter, so this param wasn't working in the console. --- internal/web3ext/web3ext.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 134562bde6fc..8f01b2be5094 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -600,6 +600,11 @@ web3._extend({ call: 'eth_getLogs', params: 1, }), + new web3._extend.Method({ + name: 'call', + call: 'eth_call', + params: 3, + }), ], properties: [ new web3._extend.Property({ From 0dc9b01c11e157c241f8436ac7b96689c9819c27 Mon Sep 17 00:00:00 2001 From: setunapo <98502954+setunapo@users.noreply.github.com> Date: Mon, 28 Nov 2022 18:07:25 +0800 Subject: [PATCH 399/715] core: clarify code in forkchoice (#26257) refactoring without logic change --- core/forkchoice.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/core/forkchoice.go b/core/forkchoice.go index b0dbb200ecc7..b293c851bf27 100644 --- a/core/forkchoice.go +++ b/core/forkchoice.go @@ -74,10 +74,10 @@ func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) // In the td mode, the new head is chosen if the corresponding // total difficulty is higher. In the extern mode, the trusted // header is always selected as the head. -func (f *ForkChoice) ReorgNeeded(current *types.Header, header *types.Header) (bool, error) { +func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (bool, error) { var ( localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64()) - externTd = f.chain.GetTd(header.Hash(), header.Number.Uint64()) + externTd = f.chain.GetTd(extern.Hash(), extern.Number.Uint64()) ) if localTD == nil || externTd == nil { return false, errors.New("missing td") @@ -88,21 +88,26 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, header *types.Header) (b if ttd := f.chain.Config().TerminalTotalDifficulty; ttd != nil && ttd.Cmp(externTd) <= 0 { return true, nil } + // If the total difficulty is higher than our known, add it to the canonical chain + if diff := externTd.Cmp(localTD); diff > 0 { + return true, nil + } else if diff < 0 { + return false, nil + } + // Local and external difficulty is identical. // Second clause in the if statement reduces the vulnerability to selfish mining. // Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf - reorg := externTd.Cmp(localTD) > 0 - if !reorg && externTd.Cmp(localTD) == 0 { - number, headNumber := header.Number.Uint64(), current.Number.Uint64() - if number < headNumber { - reorg = true - } else if number == headNumber { - var currentPreserve, externPreserve bool - if f.preserve != nil { - currentPreserve, externPreserve = f.preserve(current), f.preserve(header) - } - reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5) + reorg := false + externNum, localNum := extern.Number.Uint64(), current.Number.Uint64() + if externNum < localNum { + reorg = true + } else if externNum == localNum { + var currentPreserve, externPreserve bool + if f.preserve != nil { + currentPreserve, externPreserve = f.preserve(current), f.preserve(extern) } + reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5) } return reorg, nil } From eb01927e46711d31666c6f96bc5ca553a83ed747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 28 Nov 2022 11:13:41 +0100 Subject: [PATCH 400/715] tests: update evm-benchmarks (#26255) tests: update evm-benchmarks --- tests/evm-benchmarks | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/evm-benchmarks b/tests/evm-benchmarks index 849b3e239a28..d8b88f4046a8 160000 --- a/tests/evm-benchmarks +++ b/tests/evm-benchmarks @@ -1 +1 @@ -Subproject commit 849b3e239a28f236dc99574b2e10e0c720895105 +Subproject commit d8b88f4046a87d6b902378cef752591f95427b43 From 63ffda32517c4f630f8fbfd65fdcfc453a46ec93 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 28 Nov 2022 11:15:34 +0100 Subject: [PATCH 401/715] internal/web3ext: fix eth.call regression in console (#26266) Fixes a regression from #26265, which made it so that the call only worked if all three parameters were provided. --- internal/web3ext/web3ext.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 8f01b2be5094..7db1ebf392d7 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -604,6 +604,7 @@ web3._extend({ name: 'call', call: 'eth_call', params: 3, + inputFormatter: [formatters.inputCallFormatter, formatters.inputDefaultBlockNumberFormatter, null], }), ], properties: [ From 0e067352012f2d4b4e937aef26151f5d371dd70f Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 28 Nov 2022 11:30:05 +0100 Subject: [PATCH 402/715] internal/web3ext: fix eth_call in console, part III (#26268) Fixes regression in #26266. --- internal/web3ext/web3ext.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 7db1ebf392d7..801afedaa02c 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -604,7 +604,7 @@ web3._extend({ name: 'call', call: 'eth_call', params: 3, - inputFormatter: [formatters.inputCallFormatter, formatters.inputDefaultBlockNumberFormatter, null], + inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputDefaultBlockNumberFormatter, null], }), ], properties: [ From 743e404906744e24b43dab49b83deaa9111d3c14 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 28 Nov 2022 21:31:28 +0800 Subject: [PATCH 403/715] core, eth, les, tests, trie: abstract node scheme (#25532) This PR introduces a node scheme abstraction. The interface is only implemented by `hashScheme` at the moment, but will be extended by `pathScheme` very soon. Apart from that, a few changes are also included which is worth mentioning: - port the changes in the stacktrie, tracking the path prefix of nodes during commit - use ethdb.Database for constructing trie.Database. This is not necessary right now, but it is required for path-based used to open reverse diff freezer --- cmd/geth/chaincmd.go | 14 ++- core/blockchain.go | 68 +++++------ core/blockchain_reader.go | 6 + core/chain_makers.go | 3 +- core/genesis.go | 39 ++++--- core/genesis_test.go | 25 +++-- core/headerchain_test.go | 3 +- core/state/database.go | 20 +++- core/state/iterator_test.go | 14 +-- core/state/snapshot/conversion.go | 25 +++-- core/state/snapshot/generate.go | 5 +- core/state/snapshot/generate_test.go | 4 +- core/state/snapshot/snapshot.go | 4 +- core/state/sync.go | 4 +- core/state/sync_test.go | 66 ++++++----- eth/downloader/downloader.go | 7 +- eth/protocols/snap/sync.go | 37 ++++-- eth/protocols/snap/sync_test.go | 149 ++++++++++++++----------- les/client.go | 3 +- les/downloader/downloader.go | 2 +- les/downloader/statesync.go | 6 +- miner/miner_test.go | 6 +- tests/block_test_util.go | 5 +- tests/fuzzers/stacktrie/trie_fuzzer.go | 59 +++++++++- tests/fuzzers/trie/trie-fuzzer.go | 4 +- trie/database.go | 11 +- trie/database_test.go | 4 +- trie/iterator_test.go | 8 +- trie/schema.go | 96 ++++++++++++++++ trie/secure_trie_test.go | 6 +- trie/stacktrie.go | 125 +++++++++++---------- trie/stacktrie_test.go | 14 +-- trie/sync.go | 48 ++++++-- trie/sync_test.go | 37 +++--- trie/trie.go | 16 --- trie/trie_test.go | 23 ++-- 36 files changed, 613 insertions(+), 353 deletions(-) create mode 100644 trie/schema.go diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 48b21ddbf7a5..10af6f32f49a 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/trie" "github.com/urfave/cli/v2" ) @@ -48,7 +49,7 @@ var ( Name: "init", Usage: "Bootstrap and initialize a new genesis block", ArgsUsage: "", - Flags: utils.DatabasePathFlags, + Flags: flags.Merge([]cli.Flag{utils.CachePreimagesFlag}, utils.DatabasePathFlags), Description: ` The init command initializes a new genesis block and definition for the network. This is a destructive action and changes the network in which you will be @@ -188,12 +189,16 @@ func initGenesis(ctx *cli.Context) error { // Open and initialise both full and light databases stack, _ := makeConfigNode(ctx) defer stack.Close() + for _, name := range []string{"chaindata", "lightchaindata"} { chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.String(utils.AncientFlag.Name), "", false) if err != nil { utils.Fatalf("Failed to open database: %v", err) } - _, hash, err := core.SetupGenesisBlock(chaindb, genesis) + triedb := trie.NewDatabaseWithConfig(chaindb, &trie.Config{ + Preimages: ctx.Bool(utils.CachePreimagesFlag.Name), + }) + _, hash, err := core.SetupGenesisBlock(chaindb, triedb, genesis) if err != nil { utils.Fatalf("Failed to write genesis block: %v", err) } @@ -460,7 +465,10 @@ func dump(ctx *cli.Context) error { if err != nil { return err } - state, err := state.New(root, state.NewDatabase(db), nil) + config := &trie.Config{ + Preimages: true, // always enable preimage lookup + } + state, err := state.New(root, state.NewDatabaseWithConfig(db, config), nil) if err != nil { return err } diff --git a/core/blockchain.go b/core/blockchain.go index 863e9424259e..992e5a0f6b47 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -169,10 +169,12 @@ type BlockChain struct { chainConfig *params.ChainConfig // Chain & network configuration cacheConfig *CacheConfig // Cache configuration for pruning - db ethdb.Database // Low level persistent database to store final content in - snaps *snapshot.Tree // Snapshot tree for fast trie leaf access - triegc *prque.Prque // Priority queue mapping block numbers to tries to gc - gcproc time.Duration // Accumulates canonical block processing for trie dumping + db ethdb.Database // Low level persistent database to store final content in + snaps *snapshot.Tree // Snapshot tree for fast trie leaf access + triegc *prque.Prque // Priority queue mapping block numbers to tries to gc + gcproc time.Duration // Accumulates canonical block processing for trie dumping + triedb *trie.Database // The database handler for maintaining trie nodes. + stateCache state.Database // State database to reuse between imports (contains state cache) // txLookupLimit is the maximum number of blocks from head whose tx indices // are reserved: @@ -200,7 +202,6 @@ type BlockChain struct { currentFinalizedBlock atomic.Value // Current finalized head currentSafeBlock atomic.Value // Current safe head - stateCache state.Database // State database to reuse between imports (contains state cache) bodyCache *lru.Cache[common.Hash, *types.Body] bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] receiptsCache *lru.Cache[common.Hash, []*types.Receipt] @@ -231,10 +232,16 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis cacheConfig = defaultCacheConfig } + // Open trie database with provided config + triedb := trie.NewDatabaseWithConfig(db, &trie.Config{ + Cache: cacheConfig.TrieCleanLimit, + Journal: cacheConfig.TrieCleanJournal, + Preimages: cacheConfig.Preimages, + }) // Setup the genesis block, commit the provided genesis specification // to database if the genesis block is not present yet, or load the // stored one from database. - chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, genesis, overrides) + chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides) if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { return nil, genesisErr } @@ -247,15 +254,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis log.Info("") bc := &BlockChain{ - chainConfig: chainConfig, - cacheConfig: cacheConfig, - db: db, - triegc: prque.New(nil), - stateCache: state.NewDatabaseWithConfig(db, &trie.Config{ - Cache: cacheConfig.TrieCleanLimit, - Journal: cacheConfig.TrieCleanJournal, - Preimages: cacheConfig.Preimages, - }), + chainConfig: chainConfig, + cacheConfig: cacheConfig, + db: db, + triedb: triedb, + triegc: prque.New(nil), quit: make(chan struct{}), chainmu: syncx.NewClosableMutex(), bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit), @@ -268,6 +271,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis vmConfig: vmConfig, } bc.forker = NewForkChoice(bc, shouldPreserve) + bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) bc.validator = NewBlockValidator(chainConfig, bc, engine) bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine) bc.processor = NewStateProcessor(chainConfig, bc, engine) @@ -300,7 +304,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } // Make sure the state associated with the block is available head := bc.CurrentBlock() - if _, err := state.New(head.Root(), bc.stateCache, bc.snaps); err != nil { + if !bc.HasState(head.Root()) { // Head state is missing, before the state recovery, find out the // disk layer point of snapshot(if it's enabled). Make sure the // rewound point is lower than disk layer. @@ -388,7 +392,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis var recover bool head := bc.CurrentBlock() - if layer := rawdb.ReadSnapshotRecoveryNumber(bc.db); layer != nil && *layer > head.NumberU64() { + if layer := rawdb.ReadSnapshotRecoveryNumber(bc.db); layer != nil && *layer >= head.NumberU64() { log.Warn("Enabling snapshot recovery", "chainhead", head.NumberU64(), "diskbase", *layer) recover = true } @@ -398,7 +402,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis NoBuild: bc.cacheConfig.SnapshotNoBuild, AsyncBuild: !bc.cacheConfig.SnapshotWait, } - bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.stateCache.TrieDB(), head.Root()) + bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root()) } // Start future block processor. @@ -411,11 +415,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis log.Warn("Sanitizing invalid trie cache journal time", "provided", bc.cacheConfig.TrieCleanRejournal, "updated", time.Minute) bc.cacheConfig.TrieCleanRejournal = time.Minute } - triedb := bc.stateCache.TrieDB() bc.wg.Add(1) go func() { defer bc.wg.Done() - triedb.SaveCachePeriodically(bc.cacheConfig.TrieCleanJournal, bc.cacheConfig.TrieCleanRejournal, bc.quit) + bc.triedb.SaveCachePeriodically(bc.cacheConfig.TrieCleanJournal, bc.cacheConfig.TrieCleanRejournal, bc.quit) }() } // Rewind the chain in case of an incompatible config upgrade. @@ -594,7 +597,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo if root != (common.Hash{}) && !beyondRoot && newHeadBlock.Root() == root { beyondRoot, rootNumber = true, newHeadBlock.NumberU64() } - if _, err := state.New(newHeadBlock.Root(), bc.stateCache, bc.snaps); err != nil { + if !bc.HasState(newHeadBlock.Root()) { log.Trace("Block state missing, rewinding further", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash()) if pivot == nil || newHeadBlock.NumberU64() > *pivot { parent := bc.GetBlock(newHeadBlock.ParentHash(), newHeadBlock.NumberU64()-1) @@ -617,7 +620,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo // if the historical chain pruning is enabled. In that case the logic // needs to be improved here. if !bc.HasState(bc.genesisBlock.Root()) { - if err := CommitGenesisState(bc.db, bc.genesisBlock.Hash()); err != nil { + if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil { log.Crit("Failed to commit genesis state", "err", err) } log.Debug("Recommitted genesis state to disk") @@ -900,7 +903,7 @@ func (bc *BlockChain) Stop() { // - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle // - HEAD-127: So we have a hard limit on the number of blocks reexecuted if !bc.cacheConfig.TrieDirtyDisabled { - triedb := bc.stateCache.TrieDB() + triedb := bc.triedb for _, offset := range []uint64{0, 1, TriesInMemory - 1} { if number := bc.CurrentBlock().NumberU64(); number > offset { @@ -932,8 +935,7 @@ func (bc *BlockChain) Stop() { // Ensure all live cached entries be saved into disk, so that we can skip // cache warmup when node restarts. if bc.cacheConfig.TrieCleanJournal != "" { - triedb := bc.stateCache.TrieDB() - triedb.SaveCache(bc.cacheConfig.TrieCleanJournal) + bc.triedb.SaveCache(bc.cacheConfig.TrieCleanJournal) } log.Info("Blockchain stopped") } @@ -1306,24 +1308,22 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. if err != nil { return err } - triedb := bc.stateCache.TrieDB() - // If we're running an archive node, always flush if bc.cacheConfig.TrieDirtyDisabled { - return triedb.Commit(root, false, nil) + return bc.triedb.Commit(root, false, nil) } else { // Full but not archive node, do proper garbage collection - triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive + bc.triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive bc.triegc.Push(root, -int64(block.NumberU64())) if current := block.NumberU64(); current > TriesInMemory { // If we exceeded our memory allowance, flush matured singleton nodes to disk var ( - nodes, imgs = triedb.Size() + nodes, imgs = bc.triedb.Size() limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024 ) if nodes > limit || imgs > 4*1024*1024 { - triedb.Cap(limit - ethdb.IdealBatchSize) + bc.triedb.Cap(limit - ethdb.IdealBatchSize) } // Find the next state trie we need to commit chosen := current - TriesInMemory @@ -1342,7 +1342,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/TriesInMemory) } // Flush an entire trie and restart the counters - triedb.Commit(header.Root, true, nil) + bc.triedb.Commit(header.Root, true, nil) lastWrite = chosen bc.gcproc = 0 } @@ -1354,7 +1354,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. bc.triegc.Push(root, number) break } - triedb.Dereference(root.(common.Hash)) + bc.triedb.Dereference(root.(common.Hash)) } } } @@ -1760,7 +1760,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) stats.processed++ stats.usedGas += usedGas - dirty, _ := bc.stateCache.TrieDB().Size() + dirty, _ := bc.triedb.Size() stats.report(chain, it.index, dirty, setHead) if !setHead { diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index da948029a13e..e8a5d952a240 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" ) // CurrentHeader retrieves the current head header of the canonical chain. The @@ -375,6 +376,11 @@ func (bc *BlockChain) TxLookupLimit() uint64 { return bc.txLookupLimit } +// TrieDB retrieves the low level trie database used for data storage. +func (bc *BlockChain) TrieDB() *trie.Database { + return bc.triedb +} + // SubscribeRemovedLogsEvent registers a subscription of RemovedLogsEvent. func (bc *BlockChain) SubscribeRemovedLogsEvent(ch chan<- RemovedLogsEvent) event.Subscription { return bc.scope.Track(bc.rmLogsFeed.Subscribe(ch)) diff --git a/core/chain_makers.go b/core/chain_makers.go index 48a5fa162a81..52dd6e2e47be 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" ) // BlockGen creates blocks for testing. @@ -308,7 +309,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse // then generate chain on top. func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) { db := rawdb.NewMemoryDatabase() - _, err := genesis.Commit(db) + _, err := genesis.Commit(db, trie.NewDatabase(db)) if err != nil { panic(err) } diff --git a/core/genesis.go b/core/genesis.go index b5f844724741..bbfa356af9f4 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -138,8 +138,8 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) { // flush is very similar with deriveHash, but the main difference is // all the generated states will be persisted into the given database. // Also, the genesis state specification will be flushed as well. -func (ga *GenesisAlloc) flush(db ethdb.Database) error { - statedb, err := state.New(common.Hash{}, state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}), nil) +func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database) error { + statedb, err := state.New(common.Hash{}, state.NewDatabaseWithNodeDB(db, triedb), nil) if err != nil { return err } @@ -155,9 +155,11 @@ func (ga *GenesisAlloc) flush(db ethdb.Database) error { if err != nil { return err } - err = statedb.Database().TrieDB().Commit(root, true, nil) - if err != nil { - return err + // Commit newly generated states into disk if it's not empty. + if root != types.EmptyRootHash { + if err := triedb.Commit(root, true, nil); err != nil { + return err + } } // Marshal the genesis state specification and persist. blob, err := json.Marshal(ga) @@ -169,8 +171,8 @@ func (ga *GenesisAlloc) flush(db ethdb.Database) error { } // CommitGenesisState loads the stored genesis state with the given block -// hash and commits them into the given database handler. -func CommitGenesisState(db ethdb.Database, hash common.Hash) error { +// hash and commits it into the provided trie database. +func CommitGenesisState(db ethdb.Database, triedb *trie.Database, hash common.Hash) error { var alloc GenesisAlloc blob := rawdb.ReadGenesisStateSpec(db, hash) if len(blob) != 0 { @@ -202,7 +204,7 @@ func CommitGenesisState(db ethdb.Database, hash common.Hash) error { return errors.New("not found") } } - return alloc.flush(db) + return alloc.flush(db, triedb) } // GenesisAccount is an account in the state of the genesis block. @@ -284,15 +286,14 @@ type ChainOverrides struct { // error is a *params.ConfigCompatError and the new, unwritten config is returned. // // The returned chain configuration is never nil. -func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { - return SetupGenesisBlockWithOverride(db, genesis, nil) +func SetupGenesisBlock(db ethdb.Database, triedb *trie.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { + return SetupGenesisBlockWithOverride(db, triedb, genesis, nil) } -func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, error) { +func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, error) { if genesis != nil && genesis.Config == nil { return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig } - applyOverrides := func(config *params.ChainConfig) { if config != nil { if overrides != nil && overrides.OverrideTerminalTotalDifficulty != nil { @@ -313,7 +314,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override } else { log.Info("Writing custom genesis block") } - block, err := genesis.Commit(db) + block, err := genesis.Commit(db, triedb) if err != nil { return genesis.Config, common.Hash{}, err } @@ -323,7 +324,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override // We have the genesis block in database(perhaps in ancient database) // but the corresponding state is missing. header := rawdb.ReadHeader(db, stored, 0) - if _, err := state.New(header.Root, state.NewDatabaseWithConfig(db, nil), nil); err != nil { + if _, err := state.New(header.Root, state.NewDatabaseWithNodeDB(db, triedb), nil); err != nil { if genesis == nil { genesis = DefaultGenesisBlock() } @@ -332,7 +333,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override if hash != stored { return genesis.Config, hash, &GenesisMismatchError{stored, hash} } - block, err := genesis.Commit(db) + block, err := genesis.Commit(db, triedb) if err != nil { return genesis.Config, hash, err } @@ -480,7 +481,7 @@ func (g *Genesis) ToBlock() *types.Block { // Commit writes the block and state of a genesis specification to the database. // The block is committed as the canonical head block. -func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { +func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block, error) { block := g.ToBlock() if block.Number().Sign() != 0 { return nil, errors.New("can't commit genesis block with number > 0") @@ -498,7 +499,7 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { // All the checks has passed, flush the states derived from the genesis // specification as well as the specification itself into the provided // database. - if err := g.Alloc.flush(db); err != nil { + if err := g.Alloc.flush(db, triedb); err != nil { return nil, err } rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) @@ -514,8 +515,10 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { // MustCommit writes the genesis block and state to db, panicking on error. // The block is committed as the canonical head block. +// Note the state changes will be committed in hash-based scheme, use Commit +// if path-scheme is preferred. func (g *Genesis) MustCommit(db ethdb.Database) *types.Block { - block, err := g.Commit(db) + block, err := g.Commit(db, trie.NewDatabase(db)) if err != nil { panic(err) } diff --git a/core/genesis_test.go b/core/genesis_test.go index a7d04f53fe23..135ecb934c03 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -17,6 +17,7 @@ package core import ( + "encoding/json" "math/big" "reflect" "testing" @@ -28,12 +29,14 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" ) func TestInvalidCliqueConfig(t *testing.T) { block := DefaultGoerliGenesisBlock() block.ExtraData = []byte{} - if _, err := block.Commit(nil); err == nil { + db := rawdb.NewMemoryDatabase() + if _, err := block.Commit(db, trie.NewDatabase(db)); err == nil { t.Fatal("Expected error on invalid clique config") } } @@ -60,7 +63,7 @@ func TestSetupGenesis(t *testing.T) { { name: "genesis without ChainConfig", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - return SetupGenesisBlock(db, new(Genesis)) + return SetupGenesisBlock(db, trie.NewDatabase(db), new(Genesis)) }, wantErr: errGenesisNoConfig, wantConfig: params.AllEthashProtocolChanges, @@ -68,7 +71,7 @@ func TestSetupGenesis(t *testing.T) { { name: "no block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - return SetupGenesisBlock(db, nil) + return SetupGenesisBlock(db, trie.NewDatabase(db), nil) }, wantHash: params.MainnetGenesisHash, wantConfig: params.MainnetChainConfig, @@ -77,7 +80,7 @@ func TestSetupGenesis(t *testing.T) { name: "mainnet block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { DefaultGenesisBlock().MustCommit(db) - return SetupGenesisBlock(db, nil) + return SetupGenesisBlock(db, trie.NewDatabase(db), nil) }, wantHash: params.MainnetGenesisHash, wantConfig: params.MainnetChainConfig, @@ -86,7 +89,7 @@ func TestSetupGenesis(t *testing.T) { name: "custom block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { customg.MustCommit(db) - return SetupGenesisBlock(db, nil) + return SetupGenesisBlock(db, trie.NewDatabase(db), nil) }, wantHash: customghash, wantConfig: customg.Config, @@ -95,7 +98,7 @@ func TestSetupGenesis(t *testing.T) { name: "custom block in DB, genesis == ropsten", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { customg.MustCommit(db) - return SetupGenesisBlock(db, DefaultRopstenGenesisBlock()) + return SetupGenesisBlock(db, trie.NewDatabase(db), DefaultRopstenGenesisBlock()) }, wantErr: &GenesisMismatchError{Stored: customghash, New: params.RopstenGenesisHash}, wantHash: params.RopstenGenesisHash, @@ -105,7 +108,7 @@ func TestSetupGenesis(t *testing.T) { name: "compatible config in DB", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { oldcustomg.MustCommit(db) - return SetupGenesisBlock(db, &customg) + return SetupGenesisBlock(db, trie.NewDatabase(db), &customg) }, wantHash: customghash, wantConfig: customg.Config, @@ -122,9 +125,9 @@ func TestSetupGenesis(t *testing.T) { blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) bc.InsertChain(blocks) - bc.CurrentBlock() + // This should return a compatibility error. - return SetupGenesisBlock(db, &customg) + return SetupGenesisBlock(db, trie.NewDatabase(db), &customg) }, wantHash: customghash, wantConfig: customg.Config, @@ -193,6 +196,7 @@ func TestGenesis_Commit(t *testing.T) { db := rawdb.NewMemoryDatabase() genesisBlock := genesis.MustCommit(db) + if genesis.Difficulty != nil { t.Fatalf("assumption wrong") } @@ -219,7 +223,8 @@ func TestReadWriteGenesisAlloc(t *testing.T) { } hash, _ = alloc.deriveHash() ) - alloc.flush(db) + blob, _ := json.Marshal(alloc) + rawdb.WriteGenesisStateSpec(db, hash, blob) var reload GenesisAlloc err := reload.UnmarshalJSON(rawdb.ReadGenesisStateSpec(db, hash)) diff --git a/core/headerchain_test.go b/core/headerchain_test.go index fe083b003145..08d19f695072 100644 --- a/core/headerchain_test.go +++ b/core/headerchain_test.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" ) func verifyUnbrokenCanonchain(hc *HeaderChain) error { @@ -72,7 +73,7 @@ func TestHeaderInsertion(t *testing.T) { db = rawdb.NewMemoryDatabase() gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges} ) - gspec.Commit(db) + gspec.Commit(db, trie.NewDatabase(db)) hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false }) if err != nil { t.Fatal(err) diff --git a/core/state/database.go b/core/state/database.go index 2de0650df892..fbd6d2883cc0 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -130,23 +130,33 @@ func NewDatabase(db ethdb.Database) Database { // large memory cache. func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { return &cachingDB{ - db: trie.NewDatabaseWithConfig(db, config), disk: db, codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), + triedb: trie.NewDatabaseWithConfig(db, config), + } +} + +// NewDatabaseWithNodeDB creates a state database with an already initialized node database. +func NewDatabaseWithNodeDB(db ethdb.Database, triedb *trie.Database) Database { + return &cachingDB{ + disk: db, + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), + codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), + triedb: triedb, } } type cachingDB struct { - db *trie.Database disk ethdb.KeyValueStore codeSizeCache *lru.Cache[common.Hash, int] codeCache *lru.SizeConstrainedCache[common.Hash, []byte] + triedb *trie.Database } // OpenTrie opens the main account trie at a specific root hash. func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { - tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.db) + tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) if err != nil { return nil, err } @@ -155,7 +165,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { // OpenStorageTrie opens the storage trie of an account. func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) { - tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, addrHash, root), db.db) + tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, addrHash, root), db.triedb) if err != nil { return nil, err } @@ -220,5 +230,5 @@ func (db *cachingDB) DiskDB() ethdb.KeyValueStore { // TrieDB retrieves any intermediate trie-node caching layer. func (db *cachingDB) TrieDB() *trie.Database { - return db.db + return db.triedb } diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index f9337512647a..7669ac97a215 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -26,10 +26,10 @@ import ( // Tests that the node iterator indeed walks over the entire database contents. func TestNodeIteratorCoverage(t *testing.T) { // Create some arbitrary test state to iterate - db, root, _ := makeTestState() - db.TrieDB().Commit(root, false, nil) + db, sdb, root, _ := makeTestState() + sdb.TrieDB().Commit(root, false, nil) - state, err := New(root, db, nil) + state, err := New(root, sdb, nil) if err != nil { t.Fatalf("failed to create state trie at %x: %v", root, err) } @@ -42,19 +42,19 @@ func TestNodeIteratorCoverage(t *testing.T) { } // Cross check the iterated hashes and the database/nodepool content for hash := range hashes { - if _, err = db.TrieDB().Node(hash); err != nil { - _, err = db.ContractCode(common.Hash{}, hash) + if _, err = sdb.TrieDB().Node(hash); err != nil { + _, err = sdb.ContractCode(common.Hash{}, hash) } if err != nil { t.Errorf("failed to retrieve reported node %x", hash) } } - for _, hash := range db.TrieDB().Nodes() { + for _, hash := range sdb.TrieDB().Nodes() { if _, ok := hashes[hash]; !ok { t.Errorf("state entry not reported %x", hash) } } - it := db.DiskDB().NewIterator(nil, nil) + it := db.NewIterator(nil, nil) for it.Next() { key := it.Key() if bytes.HasPrefix(key, []byte("secure-key-")) { diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index c15b17aa87e4..43fee456d8e9 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -43,7 +43,7 @@ type trieKV struct { type ( // trieGeneratorFn is the interface of trie generation which can // be implemented by different trie algorithm. - trieGeneratorFn func(db ethdb.KeyValueWriter, owner common.Hash, in chan (trieKV), out chan (common.Hash)) + trieGeneratorFn func(db ethdb.KeyValueWriter, scheme trie.NodeScheme, owner common.Hash, in chan (trieKV), out chan (common.Hash)) // leafCallbackFn is the callback invoked at the leaves of the trie, // returns the subtrie root with the specified subtrie identifier. @@ -52,12 +52,12 @@ type ( // GenerateAccountTrieRoot takes an account iterator and reproduces the root hash. func GenerateAccountTrieRoot(it AccountIterator) (common.Hash, error) { - return generateTrieRoot(nil, it, common.Hash{}, stackTrieGenerate, nil, newGenerateStats(), true) + return generateTrieRoot(nil, nil, it, common.Hash{}, stackTrieGenerate, nil, newGenerateStats(), true) } // GenerateStorageTrieRoot takes a storage iterator and reproduces the root hash. func GenerateStorageTrieRoot(account common.Hash, it StorageIterator) (common.Hash, error) { - return generateTrieRoot(nil, it, account, stackTrieGenerate, nil, newGenerateStats(), true) + return generateTrieRoot(nil, nil, it, account, stackTrieGenerate, nil, newGenerateStats(), true) } // GenerateTrie takes the whole snapshot tree as the input, traverses all the @@ -71,7 +71,8 @@ func GenerateTrie(snaptree *Tree, root common.Hash, src ethdb.Database, dst ethd } defer acctIt.Release() - got, err := generateTrieRoot(dst, acctIt, common.Hash{}, stackTrieGenerate, func(dst ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { + scheme := snaptree.triedb.Scheme() + got, err := generateTrieRoot(dst, scheme, acctIt, common.Hash{}, stackTrieGenerate, func(dst ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { // Migrate the code first, commit the contract code into the tmp db. if codeHash != emptyCode { code := rawdb.ReadCode(src, codeHash) @@ -87,7 +88,7 @@ func GenerateTrie(snaptree *Tree, root common.Hash, src ethdb.Database, dst ethd } defer storageIt.Release() - hash, err := generateTrieRoot(dst, storageIt, accountHash, stackTrieGenerate, nil, stat, false) + hash, err := generateTrieRoot(dst, scheme, storageIt, accountHash, stackTrieGenerate, nil, stat, false) if err != nil { return common.Hash{}, err } @@ -242,7 +243,7 @@ func runReport(stats *generateStats, stop chan bool) { // generateTrieRoot generates the trie hash based on the snapshot iterator. // It can be used for generating account trie, storage trie or even the // whole state which connects the accounts and the corresponding storages. -func generateTrieRoot(db ethdb.KeyValueWriter, it Iterator, account common.Hash, generatorFn trieGeneratorFn, leafCallback leafCallbackFn, stats *generateStats, report bool) (common.Hash, error) { +func generateTrieRoot(db ethdb.KeyValueWriter, scheme trie.NodeScheme, it Iterator, account common.Hash, generatorFn trieGeneratorFn, leafCallback leafCallbackFn, stats *generateStats, report bool) (common.Hash, error) { var ( in = make(chan trieKV) // chan to pass leaves out = make(chan common.Hash, 1) // chan to collect result @@ -253,7 +254,7 @@ func generateTrieRoot(db ethdb.KeyValueWriter, it Iterator, account common.Hash, wg.Add(1) go func() { defer wg.Done() - generatorFn(db, account, in, out) + generatorFn(db, scheme, account, in, out) }() // Spin up a go-routine for progress logging if report && stats != nil { @@ -360,8 +361,14 @@ func generateTrieRoot(db ethdb.KeyValueWriter, it Iterator, account common.Hash, return stop(nil) } -func stackTrieGenerate(db ethdb.KeyValueWriter, owner common.Hash, in chan trieKV, out chan common.Hash) { - t := trie.NewStackTrieWithOwner(db, owner) +func stackTrieGenerate(db ethdb.KeyValueWriter, scheme trie.NodeScheme, owner common.Hash, in chan trieKV, out chan common.Hash) { + var nodeWriter trie.NodeWriteFunc + if db != nil { + nodeWriter = func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { + scheme.WriteTrieNode(db, owner, path, hash, blob) + } + } + t := trie.NewStackTrieWithOwner(nodeWriter, owner) for leaf := range in { t.TryUpdate(leaf.key[:], leaf.value) } diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 8589aa784f67..3ed303cdfc75 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -360,9 +359,9 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi } // We use the snap data to build up a cache which can be used by the // main account trie as a primary lookup when resolving hashes - var snapNodeCache ethdb.KeyValueStore + var snapNodeCache ethdb.Database if len(result.keys) > 0 { - snapNodeCache = memorydb.New() + snapNodeCache = rawdb.NewMemoryDatabase() snapTrieDb := trie.NewDatabase(snapNodeCache) snapTrie := trie.NewEmpty(snapTrieDb) for i, key := range result.keys { diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 784d76859e44..3b44d4d481fd 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -117,12 +117,12 @@ func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) { accIt := snap.AccountIterator(common.Hash{}) defer accIt.Release() - snapRoot, err := generateTrieRoot(nil, accIt, common.Hash{}, stackTrieGenerate, + snapRoot, err := generateTrieRoot(nil, nil, accIt, common.Hash{}, stackTrieGenerate, func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { storageIt, _ := snap.StorageIterator(accountHash, common.Hash{}) defer storageIt.Release() - hash, err := generateTrieRoot(nil, storageIt, accountHash, stackTrieGenerate, nil, stat, false) + hash, err := generateTrieRoot(nil, nil, storageIt, accountHash, stackTrieGenerate, nil, stat, false) if err != nil { return common.Hash{}, err } diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index f07f8d8e31ef..f8f52056dd7e 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -776,14 +776,14 @@ func (t *Tree) Verify(root common.Hash) error { } defer acctIt.Release() - got, err := generateTrieRoot(nil, acctIt, common.Hash{}, stackTrieGenerate, func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { + got, err := generateTrieRoot(nil, nil, acctIt, common.Hash{}, stackTrieGenerate, func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { storageIt, err := t.StorageIterator(root, accountHash, common.Hash{}) if err != nil { return common.Hash{}, err } defer storageIt.Release() - hash, err := generateTrieRoot(nil, storageIt, accountHash, stackTrieGenerate, nil, stat, false) + hash, err := generateTrieRoot(nil, nil, storageIt, accountHash, stackTrieGenerate, nil, stat, false) if err != nil { return common.Hash{}, err } diff --git a/core/state/sync.go b/core/state/sync.go index 00a4c67aa3cb..b40e75f487f6 100644 --- a/core/state/sync.go +++ b/core/state/sync.go @@ -27,7 +27,7 @@ import ( ) // NewStateSync create a new state trie download scheduler. -func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error) *trie.Sync { +func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error, scheme trie.NodeScheme) *trie.Sync { // Register the storage slot callback if the external callback is specified. var onSlot func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error if onLeaf != nil { @@ -52,6 +52,6 @@ func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(k syncer.AddCodeEntry(common.BytesToHash(obj.CodeHash), path, parent, parentPath) return nil } - syncer = trie.NewSync(root, database, onAccount) + syncer = trie.NewSync(root, database, onAccount, scheme) return syncer } diff --git a/core/state/sync_test.go b/core/state/sync_test.go index dbcbb7c96344..62eba60fa01c 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -39,10 +39,11 @@ type testAccount struct { } // makeTestState create a sample test state to test node-wise reconstruction. -func makeTestState() (Database, common.Hash, []*testAccount) { +func makeTestState() (ethdb.Database, Database, common.Hash, []*testAccount) { // Create an empty state - db := NewDatabase(rawdb.NewMemoryDatabase()) - state, _ := New(common.Hash{}, db, nil) + db := rawdb.NewMemoryDatabase() + sdb := NewDatabase(db) + state, _ := New(common.Hash{}, sdb, nil) // Fill it with some arbitrary data var accounts []*testAccount @@ -63,7 +64,7 @@ func makeTestState() (Database, common.Hash, []*testAccount) { if i%5 == 0 { for j := byte(0); j < 5; j++ { hash := crypto.Keccak256Hash([]byte{i, i, i, i, i, j, j}) - obj.SetState(db, hash, hash) + obj.SetState(sdb, hash, hash) } } state.updateStateObject(obj) @@ -72,7 +73,7 @@ func makeTestState() (Database, common.Hash, []*testAccount) { root, _ := state.Commit(false) // Return the generated state - return db, root, accounts + return db, sdb, root, accounts } // checkStateAccounts cross references a reconstructed state with an expected @@ -100,7 +101,7 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accou } // checkTrieConsistency checks that all nodes in a (sub-)trie are indeed present. -func checkTrieConsistency(db ethdb.KeyValueStore, root common.Hash) error { +func checkTrieConsistency(db ethdb.Database, root common.Hash) error { if v, _ := db.Get(root[:]); v == nil { return nil // Consider a non existent state consistent. } @@ -132,8 +133,9 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error { // Tests that an empty state is not scheduled for syncing. func TestEmptyStateSync(t *testing.T) { + db := trie.NewDatabase(rawdb.NewMemoryDatabase()) empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - sync := NewStateSync(empty, rawdb.NewMemoryDatabase(), nil) + sync := NewStateSync(empty, rawdb.NewMemoryDatabase(), nil, db.Scheme()) if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes) } @@ -170,7 +172,7 @@ type stateElement struct { func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { // Create a random state to copy - srcDb, srcRoot, srcAccounts := makeTestState() + _, srcDb, srcRoot, srcAccounts := makeTestState() if commit { srcDb.TrieDB().Commit(srcRoot, false, nil) } @@ -178,7 +180,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil) + sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) var ( nodeElements []stateElement @@ -281,11 +283,11 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { // partial results are returned, and the others sent only later. func TestIterativeDelayedStateSync(t *testing.T) { // Create a random state to copy - srcDb, srcRoot, srcAccounts := makeTestState() + _, srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil) + sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) var ( nodeElements []stateElement @@ -374,11 +376,11 @@ func TestIterativeRandomStateSyncBatched(t *testing.T) { testIterativeRandomS func testIterativeRandomStateSync(t *testing.T, count int) { // Create a random state to copy - srcDb, srcRoot, srcAccounts := makeTestState() + _, srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil) + sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) nodeQueue := make(map[string]stateElement) codeQueue := make(map[common.Hash]struct{}) @@ -454,11 +456,11 @@ func testIterativeRandomStateSync(t *testing.T, count int) { // partial results are returned (Even those randomly), others sent only later. func TestIterativeRandomDelayedStateSync(t *testing.T) { // Create a random state to copy - srcDb, srcRoot, srcAccounts := makeTestState() + _, srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil) + sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) nodeQueue := make(map[string]stateElement) codeQueue := make(map[common.Hash]struct{}) @@ -544,7 +546,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { // the database. func TestIncompleteStateSync(t *testing.T) { // Create a random state to copy - srcDb, srcRoot, srcAccounts := makeTestState() + db, srcDb, srcRoot, srcAccounts := makeTestState() // isCodeLookup to save some hashing var isCode = make(map[common.Hash]struct{}) @@ -554,15 +556,16 @@ func TestIncompleteStateSync(t *testing.T) { } } isCode[common.BytesToHash(emptyCodeHash)] = struct{}{} - checkTrieConsistency(srcDb.DiskDB(), srcRoot) + checkTrieConsistency(db, srcRoot) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil) + sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) var ( - addedCodes []common.Hash - addedNodes []common.Hash + addedCodes []common.Hash + addedPaths []string + addedHashes []common.Hash ) nodeQueue := make(map[string]stateElement) codeQueue := make(map[common.Hash]struct{}) @@ -599,15 +602,16 @@ func TestIncompleteStateSync(t *testing.T) { var nodehashes []common.Hash if len(nodeQueue) > 0 { results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) - for key, element := range nodeQueue { + for path, element := range nodeQueue { data, err := srcDb.TrieDB().Node(element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", element.hash) } - results = append(results, trie.NodeSyncResult{Path: key, Data: data}) + results = append(results, trie.NodeSyncResult{Path: path, Data: data}) if element.hash != srcRoot { - addedNodes = append(addedNodes, element.hash) + addedPaths = append(addedPaths, element.path) + addedHashes = append(addedHashes, element.hash) } nodehashes = append(nodehashes, element.hash) } @@ -655,12 +659,18 @@ func TestIncompleteStateSync(t *testing.T) { } rawdb.WriteCode(dstDb, node, val) } - for _, node := range addedNodes { - val := rawdb.ReadTrieNode(dstDb, node) - rawdb.DeleteTrieNode(dstDb, node) + scheme := srcDb.TrieDB().Scheme() + for i, path := range addedPaths { + owner, inner := trie.ResolvePath([]byte(path)) + hash := addedHashes[i] + val := scheme.ReadTrieNode(dstDb, owner, inner, hash) + if val == nil { + t.Error("missing trie node") + } + scheme.DeleteTrieNode(dstDb, owner, inner, hash) if err := checkStateConsistency(dstDb, srcRoot); err == nil { - t.Errorf("trie inconsistency not caught, missing: %v", node.Hex()) + t.Errorf("trie inconsistency not caught, missing: %v", path) } - rawdb.WriteTrieNode(dstDb, node, val) + scheme.WriteTrieNode(dstDb, owner, inner, hash, val) } } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index af28d9e82097..41c5d66edb38 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" ) var ( @@ -206,6 +207,10 @@ type BlockChain interface { // Snapshots returns the blockchain snapshot tree to paused it during sync. Snapshots() *snapshot.Tree + + // TrieDB retrieves the low level trie database used for interacting + // with trie nodes. + TrieDB() *trie.Database } // New creates a new downloader to fetch hashes and blocks from remote peers. @@ -224,7 +229,7 @@ func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain Bl dropPeer: dropPeer, headerProcCh: make(chan *headerTask, 1), quitCh: make(chan struct{}), - SnapSyncer: snap.NewSyncer(stateDb), + SnapSyncer: snap.NewSyncer(stateDb, chain.TrieDB().Scheme()), stateSyncStart: make(chan *stateSync), } dl.skeleton = newSkeleton(stateDb, dl.peers, dropPeer, newBeaconBackfiller(dl, success)) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 6e8c450f51c3..a9e35f971482 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -417,7 +417,8 @@ type SyncPeer interface { // - The peer delivers a stale response after a previous timeout // - The peer delivers a refusal to serve the requested state type Syncer struct { - db ethdb.KeyValueStore // Database to store the trie nodes into (and dedup) + db ethdb.KeyValueStore // Database to store the trie nodes into (and dedup) + scheme trie.NodeScheme // Node scheme used in node database root common.Hash // Current state trie root being synced tasks []*accountTask // Current account task set being synced @@ -485,9 +486,10 @@ type Syncer struct { // NewSyncer creates a new snapshot syncer to download the Ethereum state over the // snap protocol. -func NewSyncer(db ethdb.KeyValueStore) *Syncer { +func NewSyncer(db ethdb.KeyValueStore, scheme trie.NodeScheme) *Syncer { return &Syncer{ - db: db, + db: db, + scheme: scheme, peers: make(map[string]SyncPeer), peerJoin: new(event.Feed), @@ -581,7 +583,7 @@ func (s *Syncer) Sync(root common.Hash, cancel chan struct{}) error { s.lock.Lock() s.root = root s.healer = &healTask{ - scheduler: state.NewStateSync(root, s.db, s.onHealState), + scheduler: state.NewStateSync(root, s.db, s.onHealState, s.scheme), trieTasks: make(map[string]common.Hash), codeTasks: make(map[common.Hash]struct{}), } @@ -743,8 +745,9 @@ func (s *Syncer) loadSyncStatus() { s.accountBytes += common.StorageSize(len(key) + len(value)) }, } - task.genTrie = trie.NewStackTrie(task.genBatch) - + task.genTrie = trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { + s.scheme.WriteTrieNode(task.genBatch, owner, path, hash, val) + }) for accountHash, subtasks := range task.SubTasks { for _, subtask := range subtasks { subtask.genBatch = ethdb.HookedBatch{ @@ -753,7 +756,9 @@ func (s *Syncer) loadSyncStatus() { s.storageBytes += common.StorageSize(len(key) + len(value)) }, } - subtask.genTrie = trie.NewStackTrieWithOwner(subtask.genBatch, accountHash) + subtask.genTrie = trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { + s.scheme.WriteTrieNode(subtask.genBatch, owner, path, hash, val) + }, accountHash) } } } @@ -810,7 +815,9 @@ func (s *Syncer) loadSyncStatus() { Last: last, SubTasks: make(map[common.Hash][]*storageTask), genBatch: batch, - genTrie: trie.NewStackTrie(batch), + genTrie: trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { + s.scheme.WriteTrieNode(batch, owner, path, hash, val) + }), }) log.Debug("Created account sync task", "from", next, "last", last) next = common.BigToHash(new(big.Int).Add(last.Big(), common.Big1)) @@ -1835,7 +1842,7 @@ func (s *Syncer) processAccountResponse(res *accountResponse) { } // Check if the account is a contract with an unknown storage trie if account.Root != emptyRoot { - if ok, err := s.db.Has(account.Root[:]); err != nil || !ok { + if !s.scheme.HasTrieNode(s.db, res.hashes[i], nil, account.Root) { // If there was a previous large state retrieval in progress, // don't restart it from scratch. This happens if a sync cycle // is interrupted and resumed later. However, *do* update the @@ -2007,7 +2014,9 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { Last: r.End(), root: acc.Root, genBatch: batch, - genTrie: trie.NewStackTrieWithOwner(batch, account), + genTrie: trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { + s.scheme.WriteTrieNode(batch, owner, path, hash, val) + }, account), }) for r.Next() { batch := ethdb.HookedBatch{ @@ -2021,7 +2030,9 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { Last: r.End(), root: acc.Root, genBatch: batch, - genTrie: trie.NewStackTrieWithOwner(batch, account), + genTrie: trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { + s.scheme.WriteTrieNode(batch, owner, path, hash, val) + }, account), }) } for _, task := range tasks { @@ -2066,7 +2077,9 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { slots += len(res.hashes[i]) if i < len(res.hashes)-1 || res.subTask == nil { - tr := trie.NewStackTrieWithOwner(batch, account) + tr := trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { + s.scheme.WriteTrieNode(batch, owner, path, hash, val) + }, account) for j := 0; j < len(res.hashes[i]); j++ { tr.Update(res.hashes[i][j][:], res.slots[i][j]) } diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 1d1ce932e073..9b99d7e7a2d0 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -159,6 +159,13 @@ func newTestPeer(id string, t *testing.T, term func()) *testPeer { return peer } +func (t *testPeer) setStorageTries(tries map[common.Hash]*trie.Trie) { + t.storageTries = make(map[common.Hash]*trie.Trie) + for root, trie := range tries { + t.storageTries[root] = trie.Copy() + } +} + func (t *testPeer) ID() string { return t.id } func (t *testPeer) Log() log.Logger { return t.logger } @@ -562,9 +569,9 @@ func TestSyncBloatedProof(t *testing.T) { }) } ) - sourceAccountTrie, elems := makeAccountTrieNoStorage(100) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) source := newTestPeer("source", t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems source.accountRequestHandler = func(t *testPeer, requestId uint64, root common.Hash, origin common.Hash, limit common.Hash, cap uint64) error { @@ -610,15 +617,15 @@ func TestSyncBloatedProof(t *testing.T) { } return nil } - syncer := setupSyncer(source) + syncer := setupSyncer(nodeScheme, source) if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err == nil { t.Fatal("No error returned from incomplete/cancelled sync") } } -func setupSyncer(peers ...*testPeer) *Syncer { +func setupSyncer(scheme trie.NodeScheme, peers ...*testPeer) *Syncer { stateDb := rawdb.NewMemoryDatabase() - syncer := NewSyncer(stateDb) + syncer := NewSyncer(stateDb, scheme) for _, peer := range peers { syncer.Register(peer) peer.remote = syncer @@ -639,15 +646,15 @@ func TestSync(t *testing.T) { }) } ) - sourceAccountTrie, elems := makeAccountTrieNoStorage(100) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems return source } - syncer := setupSyncer(mkSource("source")) + syncer := setupSyncer(nodeScheme, mkSource("source")) if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) } @@ -668,15 +675,15 @@ func TestSyncTinyTriePanic(t *testing.T) { }) } ) - sourceAccountTrie, elems := makeAccountTrieNoStorage(1) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(1) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems return source } - syncer := setupSyncer(mkSource("source")) + syncer := setupSyncer(nodeScheme, mkSource("source")) done := checkStall(t, term) if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) @@ -698,15 +705,15 @@ func TestMultiSync(t *testing.T) { }) } ) - sourceAccountTrie, elems := makeAccountTrieNoStorage(100) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems return source } - syncer := setupSyncer(mkSource("sourceA"), mkSource("sourceB")) + syncer := setupSyncer(nodeScheme, mkSource("sourceA"), mkSource("sourceB")) done := checkStall(t, term) if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) @@ -728,17 +735,17 @@ func TestSyncWithStorage(t *testing.T) { }) } ) - sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(3, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(3, 3000, true, false) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems - source.storageTries = storageTries + source.setStorageTries(storageTries) source.storageValues = storageElems return source } - syncer := setupSyncer(mkSource("sourceA")) + syncer := setupSyncer(nodeScheme, mkSource("sourceA")) done := checkStall(t, term) if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) @@ -760,13 +767,13 @@ func TestMultiSyncManyUseless(t *testing.T) { }) } ) - sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) mkSource := func(name string, noAccount, noStorage, noTrieNode bool) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems - source.storageTries = storageTries + source.setStorageTries(storageTries) source.storageValues = storageElems if !noAccount { @@ -782,6 +789,7 @@ func TestMultiSyncManyUseless(t *testing.T) { } syncer := setupSyncer( + nodeScheme, mkSource("full", true, true, true), mkSource("noAccounts", false, true, true), mkSource("noStorage", true, false, true), @@ -806,13 +814,13 @@ func TestMultiSyncManyUselessWithLowTimeout(t *testing.T) { }) } ) - sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) mkSource := func(name string, noAccount, noStorage, noTrieNode bool) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems - source.storageTries = storageTries + source.setStorageTries(storageTries) source.storageValues = storageElems if !noAccount { @@ -828,6 +836,7 @@ func TestMultiSyncManyUselessWithLowTimeout(t *testing.T) { } syncer := setupSyncer( + nodeScheme, mkSource("full", true, true, true), mkSource("noAccounts", false, true, true), mkSource("noStorage", true, false, true), @@ -857,13 +866,13 @@ func TestMultiSyncManyUnresponsive(t *testing.T) { }) } ) - sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) mkSource := func(name string, noAccount, noStorage, noTrieNode bool) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems - source.storageTries = storageTries + source.setStorageTries(storageTries) source.storageValues = storageElems if !noAccount { @@ -879,6 +888,7 @@ func TestMultiSyncManyUnresponsive(t *testing.T) { } syncer := setupSyncer( + nodeScheme, mkSource("full", true, true, true), mkSource("noAccounts", false, true, true), mkSource("noStorage", true, false, true), @@ -923,15 +933,16 @@ func TestSyncBoundaryAccountTrie(t *testing.T) { }) } ) - sourceAccountTrie, elems := makeBoundaryAccountTrie(3000) + nodeScheme, sourceAccountTrie, elems := makeBoundaryAccountTrie(3000) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems return source } syncer := setupSyncer( + nodeScheme, mkSource("peer-a"), mkSource("peer-b"), ) @@ -957,11 +968,11 @@ func TestSyncNoStorageAndOneCappedPeer(t *testing.T) { }) } ) - sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) mkSource := func(name string, slow bool) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems if slow { @@ -971,6 +982,7 @@ func TestSyncNoStorageAndOneCappedPeer(t *testing.T) { } syncer := setupSyncer( + nodeScheme, mkSource("nice-a", false), mkSource("nice-b", false), mkSource("nice-c", false), @@ -998,11 +1010,11 @@ func TestSyncNoStorageAndOneCodeCorruptPeer(t *testing.T) { }) } ) - sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) mkSource := func(name string, codeFn codeHandlerFunc) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems source.codeRequestHandler = codeFn return source @@ -1012,6 +1024,7 @@ func TestSyncNoStorageAndOneCodeCorruptPeer(t *testing.T) { // non-corrupt peer, which delivers everything in one go, and makes the // test moot syncer := setupSyncer( + nodeScheme, mkSource("capped", cappedCodeRequestHandler), mkSource("corrupt", corruptCodeRequestHandler), ) @@ -1035,11 +1048,11 @@ func TestSyncNoStorageAndOneAccountCorruptPeer(t *testing.T) { }) } ) - sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) mkSource := func(name string, accFn accountHandlerFunc) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems source.accountRequestHandler = accFn return source @@ -1049,6 +1062,7 @@ func TestSyncNoStorageAndOneAccountCorruptPeer(t *testing.T) { // non-corrupt peer, which delivers everything in one go, and makes the // test moot syncer := setupSyncer( + nodeScheme, mkSource("capped", defaultAccountRequestHandler), mkSource("corrupt", corruptAccountRequestHandler), ) @@ -1074,11 +1088,11 @@ func TestSyncNoStorageAndOneCodeCappedPeer(t *testing.T) { }) } ) - sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) mkSource := func(name string, codeFn codeHandlerFunc) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems source.codeRequestHandler = codeFn return source @@ -1087,6 +1101,7 @@ func TestSyncNoStorageAndOneCodeCappedPeer(t *testing.T) { // so it shouldn't be more than that var counter int syncer := setupSyncer( + nodeScheme, mkSource("capped", func(t *testPeer, id uint64, hashes []common.Hash, max uint64) error { counter++ return cappedCodeRequestHandler(t, id, hashes, max) @@ -1124,17 +1139,18 @@ func TestSyncBoundaryStorageTrie(t *testing.T) { }) } ) - sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(10, 1000, false, true) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(10, 1000, false, true) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems - source.storageTries = storageTries + source.setStorageTries(storageTries) source.storageValues = storageElems return source } syncer := setupSyncer( + nodeScheme, mkSource("peer-a"), mkSource("peer-b"), ) @@ -1160,13 +1176,13 @@ func TestSyncWithStorageAndOneCappedPeer(t *testing.T) { }) } ) - sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(300, 1000, false, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(300, 1000, false, false) mkSource := func(name string, slow bool) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems - source.storageTries = storageTries + source.setStorageTries(storageTries) source.storageValues = storageElems if slow { @@ -1176,6 +1192,7 @@ func TestSyncWithStorageAndOneCappedPeer(t *testing.T) { } syncer := setupSyncer( + nodeScheme, mkSource("nice-a", false), mkSource("slow", true), ) @@ -1201,19 +1218,20 @@ func TestSyncWithStorageAndCorruptPeer(t *testing.T) { }) } ) - sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) mkSource := func(name string, handler storageHandlerFunc) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems - source.storageTries = storageTries + source.setStorageTries(storageTries) source.storageValues = storageElems source.storageRequestHandler = handler return source } syncer := setupSyncer( + nodeScheme, mkSource("nice-a", defaultStorageRequestHandler), mkSource("nice-b", defaultStorageRequestHandler), mkSource("nice-c", defaultStorageRequestHandler), @@ -1239,18 +1257,19 @@ func TestSyncWithStorageAndNonProvingPeer(t *testing.T) { }) } ) - sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) mkSource := func(name string, handler storageHandlerFunc) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems - source.storageTries = storageTries + source.setStorageTries(storageTries) source.storageValues = storageElems source.storageRequestHandler = handler return source } syncer := setupSyncer( + nodeScheme, mkSource("nice-a", defaultStorageRequestHandler), mkSource("nice-b", defaultStorageRequestHandler), mkSource("nice-c", defaultStorageRequestHandler), @@ -1279,18 +1298,18 @@ func TestSyncWithStorageMisbehavingProve(t *testing.T) { }) } ) - sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorageWithUniqueStorage(10, 30, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorageWithUniqueStorage(10, 30, false) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems - source.storageTries = storageTries + source.setStorageTries(storageTries) source.storageValues = storageElems source.storageRequestHandler = proofHappyStorageRequestHandler return source } - syncer := setupSyncer(mkSource("sourceA")) + syncer := setupSyncer(nodeScheme, mkSource("sourceA")) if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) } @@ -1347,7 +1366,7 @@ func getCodeByHash(hash common.Hash) []byte { } // makeAccountTrieNoStorage spits out a trie, along with the leafs -func makeAccountTrieNoStorage(n int) (*trie.Trie, entrySlice) { +func makeAccountTrieNoStorage(n int) (trie.NodeScheme, *trie.Trie, entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) @@ -1373,13 +1392,13 @@ func makeAccountTrieNoStorage(n int) (*trie.Trie, entrySlice) { db.Update(trie.NewWithNodeSet(nodes)) accTrie, _ = trie.New(trie.StateTrieID(root), db) - return accTrie, entries + return db.Scheme(), accTrie, entries } // makeBoundaryAccountTrie constructs an account trie. Instead of filling // accounts normally, this function will fill a few accounts which have // boundary hash. -func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) { +func makeBoundaryAccountTrie(n int) (trie.NodeScheme, *trie.Trie, entrySlice) { var ( entries entrySlice boundaries []common.Hash @@ -1435,12 +1454,12 @@ func makeBoundaryAccountTrie(n int) (*trie.Trie, entrySlice) { db.Update(trie.NewWithNodeSet(nodes)) accTrie, _ = trie.New(trie.StateTrieID(root), db) - return accTrie, entries + return db.Scheme(), accTrie, entries } // makeAccountTrieWithStorageWithUniqueStorage creates an account trie where each accounts // has a unique storage set. -func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) (*trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { +func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) (trie.NodeScheme, *trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) @@ -1491,11 +1510,11 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) trie, _ := trie.New(id, db) storageTries[common.BytesToHash(key)] = trie } - return accTrie, entries, storageTries, storageEntries + return db.Scheme(), accTrie, entries, storageTries, storageEntries } // makeAccountTrieWithStorage spits out a trie, along with the leafs -func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { +func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (trie.NodeScheme, *trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) @@ -1562,7 +1581,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (*trie } storageTries[common.BytesToHash(key)] = trie } - return accTrie, entries, storageTries, storageEntries + return db.Scheme(), accTrie, entries, storageTries, storageEntries } // makeStorageTrieWithSeed fills a storage trie with n items, returning the @@ -1641,7 +1660,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { t.Helper() - triedb := trie.NewDatabase(db) + triedb := trie.NewDatabase(rawdb.NewDatabase(db)) accTrie, err := trie.New(trie.StateTrieID(root), triedb) if err != nil { t.Fatal(err) @@ -1697,16 +1716,16 @@ func TestSyncAccountPerformance(t *testing.T) { }) } ) - sourceAccountTrie, elems := makeAccountTrieNoStorage(100) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) - source.accountTrie = sourceAccountTrie + source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems return source } src := mkSource("source") - syncer := setupSyncer(src) + syncer := setupSyncer(nodeScheme, src) if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) } diff --git a/les/client.go b/les/client.go index c304bf86f8a8..7aa4f9b8cc81 100644 --- a/les/client.go +++ b/les/client.go @@ -48,6 +48,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/trie" ) type LightEthereum struct { @@ -99,7 +100,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { if config.OverrideTerminalTotalDifficultyPassed != nil { overrides.OverrideTerminalTotalDifficultyPassed = config.OverrideTerminalTotalDifficultyPassed } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, &overrides) + chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, trie.NewDatabase(chainDb), config.Genesis, &overrides) if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { return nil, genesisErr } diff --git a/les/downloader/downloader.go b/les/downloader/downloader.go index 9eb7be715cdb..b005aa6a492f 100644 --- a/les/downloader/downloader.go +++ b/les/downloader/downloader.go @@ -226,7 +226,7 @@ func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain Bl headerProcCh: make(chan []*types.Header, 1), quitCh: make(chan struct{}), stateCh: make(chan dataPack), - SnapSyncer: snap.NewSyncer(stateDb), + SnapSyncer: snap.NewSyncer(stateDb, nil), stateSyncStart: make(chan *stateSync), //syncStatsState: stateSyncStats{ // processed: rawdb.ReadFastTrieProgress(stateDb), diff --git a/les/downloader/statesync.go b/les/downloader/statesync.go index 22f952155f11..8816d936f722 100644 --- a/les/downloader/statesync.go +++ b/les/downloader/statesync.go @@ -22,6 +22,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -295,10 +296,13 @@ type codeTask struct { // newStateSync creates a new state trie download scheduler. This method does not // yet start the sync. The user needs to call run to initiate. func newStateSync(d *Downloader, root common.Hash) *stateSync { + // Hack the node scheme here. It's a dead code is not used + // by light client at all. Just aim for passing tests. + scheme := trie.NewDatabase(rawdb.NewMemoryDatabase()).Scheme() return &stateSync{ d: d, root: root, - sched: state.NewStateSync(root, d.stateDB, nil), + sched: state.NewStateSync(root, d.stateDB, nil, scheme), keccak: sha3.NewLegacyKeccak256().(crypto.KeccakState), trieTasks: make(map[string]*trieTask), codeTasks: make(map[common.Hash]*codeTask), diff --git a/miner/miner_test.go b/miner/miner_test.go index 7c07b21dd82f..7bf091f375e5 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/trie" ) @@ -247,10 +246,9 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { Etherbase: common.HexToAddress("123456789"), } // Create chainConfig - memdb := memorydb.New() - chainDB := rawdb.NewDatabase(memdb) + chainDB := rawdb.NewMemoryDatabase() genesis := core.DeveloperGenesisBlock(15, 11_500_000, common.HexToAddress("12345")) - chainConfig, _, err := core.SetupGenesisBlock(chainDB, genesis) + chainConfig, _, err := core.SetupGenesisBlock(chainDB, trie.NewDatabase(chainDB), genesis) if err != nil { t.Fatalf("can't create new chain config: %v", err) } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 313a703fae8f..5b200a60727c 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -107,10 +107,7 @@ func (t *BlockTest) Run(snapshotter bool) error { // import pre accounts & construct test genesis block & state root db := rawdb.NewMemoryDatabase() gspec := t.genesis(config) - gblock, err := gspec.Commit(db) - if err != nil { - return err - } + gblock := gspec.MustCommit(db) if gblock.Hash() != t.json.Genesis.Hash { return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) } diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 6a95a1804c81..3af16bf81df7 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -25,6 +25,9 @@ import ( "io" "sort" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" "golang.org/x/crypto/sha3" @@ -143,11 +146,14 @@ func Debug(data []byte) int { func (f *fuzzer) fuzz() int { // This spongeDb is used to check the sequence of disk-db-writes var ( - spongeA = &spongeDb{sponge: sha3.NewLegacyKeccak256()} - dbA = trie.NewDatabase(spongeA) - trieA = trie.NewEmpty(dbA) - spongeB = &spongeDb{sponge: sha3.NewLegacyKeccak256()} - trieB = trie.NewStackTrie(spongeB) + spongeA = &spongeDb{sponge: sha3.NewLegacyKeccak256()} + dbA = trie.NewDatabase(rawdb.NewDatabase(spongeA)) + trieA = trie.NewEmpty(dbA) + spongeB = &spongeDb{sponge: sha3.NewLegacyKeccak256()} + dbB = trie.NewDatabase(rawdb.NewDatabase(spongeB)) + trieB = trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { + dbB.Scheme().WriteTrieNode(spongeB, owner, path, hash, blob) + }) vals kvs useful bool maxElements = 10000 @@ -206,5 +212,48 @@ func (f *fuzzer) fuzz() int { if !bytes.Equal(sumA, sumB) { panic(fmt.Sprintf("sequence differ: (trie) %x != %x (stacktrie)", sumA, sumB)) } + + // Ensure all the nodes are persisted correctly + var ( + nodeset = make(map[string][]byte) // path -> blob + trieC = trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { + if crypto.Keccak256Hash(blob) != hash { + panic("invalid node blob") + } + if owner != (common.Hash{}) { + panic("invalid node owner") + } + nodeset[string(path)] = common.CopyBytes(blob) + }) + checked int + ) + for _, kv := range vals { + trieC.Update(kv.k, kv.v) + } + rootC, _ := trieC.Commit() + if rootA != rootC { + panic(fmt.Sprintf("roots differ: (trie) %x != %x (stacktrie)", rootA, rootC)) + } + trieA, _ = trie.New(trie.TrieID(rootA), dbA) + iterA := trieA.NodeIterator(nil) + for iterA.Next(true) { + if iterA.Hash() == (common.Hash{}) { + if _, present := nodeset[string(iterA.Path())]; present { + panic("unexpected tiny node") + } + continue + } + nodeBlob, present := nodeset[string(iterA.Path())] + if !present { + panic("missing node") + } + if !bytes.Equal(nodeBlob, iterA.NodeBlob()) { + panic("node blob is not matched") + } + checked += 1 + } + if checked != len(nodeset) { + panic("node number is not matched") + } return 1 } diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index 3cb07dff98e9..85a73c675589 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -21,7 +21,7 @@ import ( "encoding/binary" "fmt" - "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/trie" ) @@ -139,7 +139,7 @@ func Fuzz(input []byte) int { } func runRandTest(rt randTest) error { - triedb := trie.NewDatabase(memorydb.New()) + triedb := trie.NewDatabase(rawdb.NewMemoryDatabase()) tr := trie.NewEmpty(triedb) values := make(map[string]string) // tracks content of the trie diff --git a/trie/database.go b/trie/database.go index 76ca188add9c..469c33fc84dd 100644 --- a/trie/database.go +++ b/trie/database.go @@ -68,7 +68,7 @@ var ( // behind this split design is to provide read access to RPC handlers and sync // servers even while the trie is executing expensive garbage collection. type Database struct { - diskdb ethdb.KeyValueStore // Persistent storage for matured trie nodes + diskdb ethdb.Database // Persistent storage for matured trie nodes cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes @@ -273,14 +273,14 @@ type Config struct { // NewDatabase creates a new trie database to store ephemeral trie content before // its written out to disk or garbage collected. No read cache is created, so all // data retrievals will hit the underlying disk database. -func NewDatabase(diskdb ethdb.KeyValueStore) *Database { +func NewDatabase(diskdb ethdb.Database) *Database { return NewDatabaseWithConfig(diskdb, nil) } // NewDatabaseWithConfig creates a new trie database to store ephemeral trie content // before its written out to disk or garbage collected. It also acts as a read cache // for nodes loaded from disk. -func NewDatabaseWithConfig(diskdb ethdb.KeyValueStore, config *Config) *Database { +func NewDatabaseWithConfig(diskdb ethdb.Database, config *Config) *Database { var cleans *fastcache.Cache if config != nil && config.Cache > 0 { if config.Journal == "" { @@ -917,3 +917,8 @@ func (db *Database) CommitPreimages() error { } return db.preimages.commit(true) } + +// Scheme returns the node scheme used in the database. +func (db *Database) Scheme() NodeScheme { + return &hashScheme{} +} diff --git a/trie/database_test.go b/trie/database_test.go index 81c469500f98..54d752947672 100644 --- a/trie/database_test.go +++ b/trie/database_test.go @@ -20,13 +20,13 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb/memorydb" + "github.com/ethereum/go-ethereum/core/rawdb" ) // Tests that the trie database returns a missing trie node error if attempting // to retrieve the meta root. func TestDatabaseMetarootFetch(t *testing.T) { - db := NewDatabase(memorydb.New()) + db := NewDatabase(rawdb.NewMemoryDatabase()) if _, err := db.Node(common.Hash{}); err == nil { t.Fatalf("metaroot retrieval succeeded") } diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 74b87a25c233..2664dab2d265 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -327,7 +327,7 @@ func TestIteratorContinueAfterErrorDisk(t *testing.T) { testIteratorContinueA func TestIteratorContinueAfterErrorMemonly(t *testing.T) { testIteratorContinueAfterError(t, true) } func testIteratorContinueAfterError(t *testing.T, memonly bool) { - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := NewDatabase(diskdb) tr := NewEmpty(triedb) @@ -419,7 +419,7 @@ func TestIteratorContinueAfterSeekErrorMemonly(t *testing.T) { func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { // Commit test trie to db, then remove the node containing "bars". - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := NewDatabase(diskdb) ctr := NewEmpty(triedb) @@ -532,7 +532,7 @@ func (l *loggingDb) Close() error { func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) { // Create an empty trie logDb := &loggingDb{0, memorydb.New()} - triedb := NewDatabase(logDb) + triedb := NewDatabase(rawdb.NewDatabase(logDb)) trie, _ := NewStateTrie(TrieID(common.Hash{}), triedb) // Fill it with some arbitrary data @@ -567,7 +567,7 @@ func TestNodeIteratorLargeTrie(t *testing.T) { func TestIteratorNodeBlob(t *testing.T) { var ( - db = memorydb.New() + db = rawdb.NewMemoryDatabase() triedb = NewDatabase(db) trie = NewEmpty(triedb) ) diff --git a/trie/schema.go b/trie/schema.go new file mode 100644 index 000000000000..ed049faa5ce0 --- /dev/null +++ b/trie/schema.go @@ -0,0 +1,96 @@ +// 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 . + +package trie + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" +) + +const ( + HashScheme = "hashScheme" // Identifier of hash based node scheme + + // Path-based scheme will be introduced in the following PRs. + // PathScheme = "pathScheme" // Identifier of path based node scheme +) + +// NodeScheme describes the scheme for interacting nodes in disk. +type NodeScheme interface { + // Name returns the identifier of node scheme. + Name() string + + // HasTrieNode checks the trie node presence with the provided node info and + // the associated node hash. + HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash) bool + + // ReadTrieNode retrieves the trie node from database with the provided node + // info and the associated node hash. + ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash) []byte + + // WriteTrieNode writes the trie node into database with the provided node + // info and associated node hash. + WriteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, node []byte) + + // DeleteTrieNode deletes the trie node from database with the provided node + // info and associated node hash. + DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash) + + // IsTrieNode returns an indicator if the given database key is the key of + // trie node according to the scheme. + IsTrieNode(key []byte) (bool, []byte) +} + +type hashScheme struct{} + +// Name returns the identifier of hash based scheme. +func (scheme *hashScheme) Name() string { + return HashScheme +} + +// HasTrieNode checks the trie node presence with the provided node info and +// the associated node hash. +func (scheme *hashScheme) HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash) bool { + return rawdb.HasTrieNode(db, hash) +} + +// ReadTrieNode retrieves the trie node from database with the provided node info +// and associated node hash. +func (scheme *hashScheme) ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash) []byte { + return rawdb.ReadTrieNode(db, hash) +} + +// WriteTrieNode writes the trie node into database with the provided node info +// and associated node hash. +func (scheme *hashScheme) WriteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, node []byte) { + rawdb.WriteTrieNode(db, hash, node) +} + +// DeleteTrieNode deletes the trie node from database with the provided node info +// and associated node hash. +func (scheme *hashScheme) DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash) { + rawdb.DeleteTrieNode(db, hash) +} + +// IsTrieNode returns an indicator if the given database key is the key of trie +// node according to the scheme. +func (scheme *hashScheme) IsTrieNode(key []byte) (bool, []byte) { + if len(key) == common.HashLength { + return true, key + } + return false, nil +} diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index ab8462607d99..24b8c5f095e0 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -24,19 +24,19 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb/memorydb" ) func newEmptySecure() *StateTrie { - trie, _ := NewStateTrie(TrieID(common.Hash{}), NewDatabase(memorydb.New())) + trie, _ := NewStateTrie(TrieID(common.Hash{}), NewDatabase(rawdb.NewMemoryDatabase())) return trie } // makeTestStateTrie creates a large enough secure trie for testing. func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) { // Create an empty trie - triedb := NewDatabase(memorydb.New()) + triedb := NewDatabase(rawdb.NewMemoryDatabase()) trie, _ := NewStateTrie(TrieID(common.Hash{}), triedb) // Fill it with some arbitrary data diff --git a/trie/stacktrie.go b/trie/stacktrie.go index 2df2cd6ed016..fb8cc0d763e6 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -25,7 +25,6 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) @@ -37,10 +36,14 @@ var stPool = sync.Pool{ }, } -func stackTrieFromPool(db ethdb.KeyValueWriter, owner common.Hash) *StackTrie { +// NodeWriteFunc is used to provide all information of a dirty node for committing +// so that callers can flush nodes into database with desired scheme. +type NodeWriteFunc = func(owner common.Hash, path []byte, hash common.Hash, blob []byte) + +func stackTrieFromPool(writeFn NodeWriteFunc, owner common.Hash) *StackTrie { st := stPool.Get().(*StackTrie) - st.db = db st.owner = owner + st.writeFn = writeFn return st } @@ -53,41 +56,41 @@ func returnToPool(st *StackTrie) { // in order. Once it determines that a subtree will no longer be inserted // into, it will hash it and free up the memory it uses. type StackTrie struct { - owner common.Hash // the owner of the trie - nodeType uint8 // node type (as in branch, ext, leaf) - val []byte // value contained by this node if it's a leaf - key []byte // key chunk covered by this (leaf|ext) node - children [16]*StackTrie // list of children (for branch and exts) - db ethdb.KeyValueWriter // Pointer to the commit db, can be nil + owner common.Hash // the owner of the trie + nodeType uint8 // node type (as in branch, ext, leaf) + val []byte // value contained by this node if it's a leaf + key []byte // key chunk covered by this (leaf|ext) node + children [16]*StackTrie // list of children (for branch and exts) + writeFn NodeWriteFunc // function for committing nodes, can be nil } // NewStackTrie allocates and initializes an empty trie. -func NewStackTrie(db ethdb.KeyValueWriter) *StackTrie { +func NewStackTrie(writeFn NodeWriteFunc) *StackTrie { return &StackTrie{ nodeType: emptyNode, - db: db, + writeFn: writeFn, } } // NewStackTrieWithOwner allocates and initializes an empty trie, but with // the additional owner field. -func NewStackTrieWithOwner(db ethdb.KeyValueWriter, owner common.Hash) *StackTrie { +func NewStackTrieWithOwner(writeFn NodeWriteFunc, owner common.Hash) *StackTrie { return &StackTrie{ owner: owner, nodeType: emptyNode, - db: db, + writeFn: writeFn, } } // NewFromBinary initialises a serialized stacktrie with the given db. -func NewFromBinary(data []byte, db ethdb.KeyValueWriter) (*StackTrie, error) { +func NewFromBinary(data []byte, writeFn NodeWriteFunc) (*StackTrie, error) { var st StackTrie if err := st.UnmarshalBinary(data); err != nil { return nil, err } // If a database is used, we need to recursively add it to every child - if db != nil { - st.setDb(db) + if writeFn != nil { + st.setWriter(writeFn) } return &st, nil } @@ -160,25 +163,25 @@ func (st *StackTrie) unmarshalBinary(r io.Reader) error { return nil } -func (st *StackTrie) setDb(db ethdb.KeyValueWriter) { - st.db = db +func (st *StackTrie) setWriter(writeFn NodeWriteFunc) { + st.writeFn = writeFn for _, child := range st.children { if child != nil { - child.setDb(db) + child.setWriter(writeFn) } } } -func newLeaf(owner common.Hash, key, val []byte, db ethdb.KeyValueWriter) *StackTrie { - st := stackTrieFromPool(db, owner) +func newLeaf(owner common.Hash, key, val []byte, writeFn NodeWriteFunc) *StackTrie { + st := stackTrieFromPool(writeFn, owner) st.nodeType = leafNode st.key = append(st.key, key...) st.val = val return st } -func newExt(owner common.Hash, key []byte, child *StackTrie, db ethdb.KeyValueWriter) *StackTrie { - st := stackTrieFromPool(db, owner) +func newExt(owner common.Hash, key []byte, child *StackTrie, writeFn NodeWriteFunc) *StackTrie { + st := stackTrieFromPool(writeFn, owner) st.nodeType = extNode st.key = append(st.key, key...) st.children[0] = child @@ -200,7 +203,7 @@ func (st *StackTrie) TryUpdate(key, value []byte) error { if len(value) == 0 { panic("deletion not supported") } - st.insert(k[:len(k)-1], value) + st.insert(k[:len(k)-1], value, nil) return nil } @@ -212,7 +215,7 @@ func (st *StackTrie) Update(key, value []byte) { func (st *StackTrie) Reset() { st.owner = common.Hash{} - st.db = nil + st.writeFn = nil st.key = st.key[:0] st.val = nil for i := range st.children { @@ -235,7 +238,7 @@ func (st *StackTrie) getDiffIndex(key []byte) int { // Helper function to that inserts a (key, value) pair into // the trie. -func (st *StackTrie) insert(key, value []byte) { +func (st *StackTrie) insert(key, value []byte, prefix []byte) { switch st.nodeType { case branchNode: /* Branch */ idx := int(key[0]) @@ -244,7 +247,7 @@ func (st *StackTrie) insert(key, value []byte) { for i := idx - 1; i >= 0; i-- { if st.children[i] != nil { if st.children[i].nodeType != hashedNode { - st.children[i].hash() + st.children[i].hash(append(prefix, byte(i))) } break } @@ -252,9 +255,9 @@ func (st *StackTrie) insert(key, value []byte) { // Add new child if st.children[idx] == nil { - st.children[idx] = newLeaf(st.owner, key[1:], value, st.db) + st.children[idx] = newLeaf(st.owner, key[1:], value, st.writeFn) } else { - st.children[idx].insert(key[1:], value) + st.children[idx].insert(key[1:], value, append(prefix, key[0])) } case extNode: /* Ext */ @@ -269,7 +272,7 @@ func (st *StackTrie) insert(key, value []byte) { if diffidx == len(st.key) { // Ext key and key segment are identical, recurse into // the child node. - st.children[0].insert(key[diffidx:], value) + st.children[0].insert(key[diffidx:], value, append(prefix, key[:diffidx]...)) return } // Save the original part. Depending if the break is @@ -278,14 +281,19 @@ func (st *StackTrie) insert(key, value []byte) { // node directly. var n *StackTrie if diffidx < len(st.key)-1 { - n = newExt(st.owner, st.key[diffidx+1:], st.children[0], st.db) + // Break on the non-last byte, insert an intermediate + // extension. The path prefix of the newly-inserted + // extension should also contain the different byte. + n = newExt(st.owner, st.key[diffidx+1:], st.children[0], st.writeFn) + n.hash(append(prefix, st.key[:diffidx+1]...)) } else { // Break on the last byte, no need to insert - // an extension node: reuse the current node + // an extension node: reuse the current node. + // The path prefix of the original part should + // still be same. n = st.children[0] + n.hash(append(prefix, st.key...)) } - // Convert to hash - n.hash() var p *StackTrie if diffidx == 0 { // the break is on the first byte, so @@ -298,12 +306,12 @@ func (st *StackTrie) insert(key, value []byte) { // the common prefix is at least one byte // long, insert a new intermediate branch // node. - st.children[0] = stackTrieFromPool(st.db, st.owner) + st.children[0] = stackTrieFromPool(st.writeFn, st.owner) st.children[0].nodeType = branchNode p = st.children[0] } // Create a leaf for the inserted part - o := newLeaf(st.owner, key[diffidx+1:], value, st.db) + o := newLeaf(st.owner, key[diffidx+1:], value, st.writeFn) // Insert both child leaves where they belong: origIdx := st.key[diffidx] @@ -339,7 +347,7 @@ func (st *StackTrie) insert(key, value []byte) { // Convert current node into an ext, // and insert a child branch node. st.nodeType = extNode - st.children[0] = NewStackTrieWithOwner(st.db, st.owner) + st.children[0] = NewStackTrieWithOwner(st.writeFn, st.owner) st.children[0].nodeType = branchNode p = st.children[0] } @@ -348,11 +356,11 @@ func (st *StackTrie) insert(key, value []byte) { // value and another containing the new value. The child leaf // is hashed directly in order to free up some memory. origIdx := st.key[diffidx] - p.children[origIdx] = newLeaf(st.owner, st.key[diffidx+1:], st.val, st.db) - p.children[origIdx].hash() + p.children[origIdx] = newLeaf(st.owner, st.key[diffidx+1:], st.val, st.writeFn) + p.children[origIdx].hash(append(prefix, st.key[:diffidx+1]...)) newIdx := key[diffidx] - p.children[newIdx] = newLeaf(st.owner, key[diffidx+1:], value, st.db) + p.children[newIdx] = newLeaf(st.owner, key[diffidx+1:], value, st.writeFn) // Finally, cut off the key part that has been passed // over to the children. @@ -383,14 +391,14 @@ func (st *StackTrie) insert(key, value []byte) { // - And the 'st.type' will be 'hashedNode' AGAIN // // This method also sets 'st.type' to hashedNode, and clears 'st.key'. -func (st *StackTrie) hash() { +func (st *StackTrie) hash(path []byte) { h := newHasher(false) defer returnHasherToPool(h) - st.hashRec(h) + st.hashRec(h, path) } -func (st *StackTrie) hashRec(hasher *hasher) { +func (st *StackTrie) hashRec(hasher *hasher, path []byte) { // The switch below sets this to the RLP-encoding of this node. var encodedNode []byte @@ -411,8 +419,7 @@ func (st *StackTrie) hashRec(hasher *hasher) { nodes[i] = nilValueNode continue } - - child.hashRec(hasher) + child.hashRec(hasher, append(path, byte(i))) if len(child.val) < 32 { nodes[i] = rawNode(child.val) } else { @@ -428,10 +435,9 @@ func (st *StackTrie) hashRec(hasher *hasher) { encodedNode = hasher.encodedBytes() case extNode: - st.children[0].hashRec(hasher) + st.children[0].hashRec(hasher, append(path, st.key...)) - sz := hexToCompactInPlace(st.key) - n := rawShortNode{Key: st.key[:sz]} + n := rawShortNode{Key: hexToCompact(st.key)} if len(st.children[0].val) < 32 { n.Val = rawNode(st.children[0].val) } else { @@ -447,8 +453,7 @@ func (st *StackTrie) hashRec(hasher *hasher) { case leafNode: st.key = append(st.key, byte(16)) - sz := hexToCompactInPlace(st.key) - n := rawShortNode{Key: st.key[:sz], Val: valueNode(st.val)} + n := rawShortNode{Key: hexToCompact(st.key), Val: valueNode(st.val)} n.encode(hasher.encbuf) encodedNode = hasher.encodedBytes() @@ -467,10 +472,8 @@ func (st *StackTrie) hashRec(hasher *hasher) { // Write the hash to the 'val'. We allocate a new val here to not mutate // input values st.val = hasher.hashData(encodedNode) - if st.db != nil { - // TODO! Is it safe to Put the slice here? - // Do all db implementations copy the value provided? - st.db.Put(st.val, encodedNode) + if st.writeFn != nil { + st.writeFn(st.owner, path, common.BytesToHash(st.val), encodedNode) } } @@ -479,12 +482,11 @@ func (st *StackTrie) Hash() (h common.Hash) { hasher := newHasher(false) defer returnHasherToPool(hasher) - st.hashRec(hasher) + st.hashRec(hasher, nil) if len(st.val) == 32 { copy(h[:], st.val) return h } - // If the node's RLP isn't 32 bytes long, the node will not // be hashed, and instead contain the rlp-encoding of the // node. For the top level node, we need to force the hashing. @@ -502,25 +504,24 @@ func (st *StackTrie) Hash() (h common.Hash) { // The associated database is expected, otherwise the whole commit // functionality should be disabled. func (st *StackTrie) Commit() (h common.Hash, err error) { - if st.db == nil { + if st.writeFn == nil { return common.Hash{}, ErrCommitDisabled } - hasher := newHasher(false) defer returnHasherToPool(hasher) - st.hashRec(hasher) + st.hashRec(hasher, nil) if len(st.val) == 32 { copy(h[:], st.val) return h, nil } - // If the node's RLP isn't 32 bytes long, the node will not - // be hashed (and committed), and instead contain the rlp-encoding of the + // be hashed (and committed), and instead contain the rlp-encoding of the // node. For the top level node, we need to force the hashing+commit. hasher.sha.Reset() hasher.sha.Write(st.val) hasher.sha.Read(h[:]) - st.db.Put(h[:], st.val) + + st.writeFn(st.owner, nil, h, st.val) return h, nil } diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index 069e4981d71a..215c97cfcdf7 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -22,8 +22,8 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb/memorydb" ) func TestStackTrieInsertAndHash(t *testing.T) { @@ -188,7 +188,7 @@ func TestStackTrieInsertAndHash(t *testing.T) { func TestSizeBug(t *testing.T) { st := NewStackTrie(nil) - nt := NewEmpty(NewDatabase(memorydb.New())) + nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") @@ -203,7 +203,7 @@ func TestSizeBug(t *testing.T) { func TestEmptyBug(t *testing.T) { st := NewStackTrie(nil) - nt := NewEmpty(NewDatabase(memorydb.New())) + nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) //leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") //value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") @@ -229,7 +229,7 @@ func TestEmptyBug(t *testing.T) { func TestValLength56(t *testing.T) { st := NewStackTrie(nil) - nt := NewEmpty(NewDatabase(memorydb.New())) + nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) //leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") //value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") @@ -254,7 +254,7 @@ func TestValLength56(t *testing.T) { // which causes a lot of node-within-node. This case was found via fuzzing. func TestUpdateSmallNodes(t *testing.T) { st := NewStackTrie(nil) - nt := NewEmpty(NewDatabase(memorydb.New())) + nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) kvs := []struct { K string @@ -283,7 +283,7 @@ func TestUpdateSmallNodes(t *testing.T) { func TestUpdateVariableKeys(t *testing.T) { t.SkipNow() st := NewStackTrie(nil) - nt := NewEmpty(NewDatabase(memorydb.New())) + nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) kvs := []struct { K string @@ -353,7 +353,7 @@ func TestStacktrieNotModifyValues(t *testing.T) { func TestStacktrieSerialization(t *testing.T) { var ( st = NewStackTrie(nil) - nt = NewEmpty(NewDatabase(memorydb.New())) + nt = NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) keyB = big.NewInt(1) keyDelta = big.NewInt(1) vals [][]byte diff --git a/trie/sync.go b/trie/sync.go index 31d3cbe91b9e..199766983577 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -64,7 +64,7 @@ type SyncPath [][]byte // version that can be sent over the network. func NewSyncPath(path []byte) SyncPath { // If the hash is from the account trie, append a single item, if it - // is from the a storage trie, append a tuple. Note, the length 64 is + // is from a storage trie, append a tuple. Note, the length 64 is // clashing between account leaf and storage root. It's fine though // because having a trie node at 64 depth means a hash collision was // found and we're long dead. @@ -74,6 +74,22 @@ func NewSyncPath(path []byte) SyncPath { return SyncPath{hexToKeybytes(path[:64]), hexToCompact(path[64:])} } +// LeafCallback is a callback type invoked when a trie operation reaches a leaf +// node. +// +// The keys is a path tuple identifying a particular trie node either in a single +// trie (account) or a layered trie (account -> storage). Each key in the tuple +// is in the raw format(32 bytes). +// +// The path is a composite hexary path identifying the trie node. All the key +// bytes are converted to the hexary nibbles and composited with the parent path +// if the trie node is in a layered trie. +// +// It's used by state sync and commit to allow handling external references +// between account and storage tries. And also it's used in the state healing +// for extracting the raw states(leaf nodes) with corresponding paths. +type LeafCallback func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error + // nodeRequest represents a scheduled or already in-flight trie node retrieval request. type nodeRequest struct { hash common.Hash // Hash of the trie node to retrieve @@ -139,6 +155,7 @@ func (batch *syncMemBatch) hasCode(hash common.Hash) bool { // unknown trie hashes to retrieve, accepts node data associated with said hashes // and reconstructs the trie step by step until all is done. type Sync struct { + scheme NodeScheme // Node scheme descriptor used in database. database ethdb.KeyValueReader // Persistent database to check for existing entries membatch *syncMemBatch // Memory buffer to avoid frequent database writes nodeReqs map[string]*nodeRequest // Pending requests pertaining to a trie node path @@ -148,8 +165,9 @@ type Sync struct { } // NewSync creates a new trie data download scheduler. -func NewSync(root common.Hash, database ethdb.KeyValueReader, callback LeafCallback) *Sync { +func NewSync(root common.Hash, database ethdb.KeyValueReader, callback LeafCallback, scheme NodeScheme) *Sync { ts := &Sync{ + scheme: scheme, database: database, membatch: newSyncMemBatch(), nodeReqs: make(map[string]*nodeRequest), @@ -172,7 +190,8 @@ func (s *Sync) AddSubTrie(root common.Hash, path []byte, parent common.Hash, par if s.membatch.hasNode(path) { return } - if rawdb.HasTrieNode(s.database, root) { + owner, inner := ResolvePath(path) + if s.scheme.HasTrieNode(s.database, owner, inner, root) { return } // Assemble the new sub-trie sync request @@ -205,7 +224,7 @@ func (s *Sync) AddCodeEntry(hash common.Hash, path []byte, parent common.Hash, p return } // If database says duplicate, the blob is present for sure. - // Note we only check the existence with new code scheme, fast + // Note we only check the existence with new code scheme, snap // sync is expected to run with a fresh new node. Even there // exists the code with legacy format, fetch and store with // new scheme anyway. @@ -329,7 +348,8 @@ func (s *Sync) ProcessNode(result NodeSyncResult) error { func (s *Sync) Commit(dbw ethdb.Batch) error { // Dump the membatch into a database dbw for path, value := range s.membatch.nodes { - rawdb.WriteTrieNode(dbw, s.membatch.hashes[path], value) + owner, inner := ResolvePath([]byte(path)) + s.scheme.WriteTrieNode(dbw, owner, inner, s.membatch.hashes[path], value) } for hash, value := range s.membatch.codes { rawdb.WriteCode(dbw, hash, value) @@ -450,8 +470,11 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { // If database says duplicate, then at least the trie node is present // and we hold the assumption that it's NOT legacy contract code. - chash := common.BytesToHash(node) - if rawdb.HasTrieNode(s.database, chash) { + var ( + chash = common.BytesToHash(node) + owner, inner = ResolvePath(child.path) + ) + if s.scheme.HasTrieNode(s.database, owner, inner, chash) { return } // Locally unknown node, schedule for retrieval @@ -525,3 +548,14 @@ func (s *Sync) commitCodeRequest(req *codeRequest) error { } return nil } + +// ResolvePath resolves the provided composite node path by separating the +// path in account trie if it's existent. +func ResolvePath(path []byte) (common.Hash, []byte) { + var owner common.Hash + if len(path) >= 2*common.HashLength { + owner = common.BytesToHash(hexToKeybytes(path[:2*common.HashLength])) + path = path[2*common.HashLength:] + } + return owner, path +} diff --git a/trie/sync_test.go b/trie/sync_test.go index a02527855300..821f7cdf4dc4 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb/memorydb" ) @@ -29,7 +30,7 @@ import ( // makeTestTrie create a sample test trie to test node-wise reconstruction. func makeTestTrie() (*Database, *StateTrie, map[string][]byte) { // Create an empty trie - triedb := NewDatabase(memorydb.New()) + triedb := NewDatabase(rawdb.NewMemoryDatabase()) trie, _ := NewStateTrie(TrieID(common.Hash{}), triedb) // Fill it with some arbitrary data @@ -103,13 +104,13 @@ type trieElement struct { // Tests that an empty trie is not scheduled for syncing. func TestEmptySync(t *testing.T) { - dbA := NewDatabase(memorydb.New()) - dbB := NewDatabase(memorydb.New()) + dbA := NewDatabase(rawdb.NewMemoryDatabase()) + dbB := NewDatabase(rawdb.NewMemoryDatabase()) emptyA, _ := New(TrieID(common.Hash{}), dbA) emptyB, _ := New(TrieID(emptyRoot), dbB) for i, trie := range []*Trie{emptyA, emptyB} { - sync := NewSync(trie.Hash(), memorydb.New(), nil) + sync := NewSync(trie.Hash(), memorydb.New(), nil, []*Database{dbA, dbB}[i].Scheme()) if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { t.Errorf("test %d: content requested for empty trie: %v, %v, %v", i, paths, nodes, codes) } @@ -128,9 +129,9 @@ func testIterativeSync(t *testing.T, count int, bypath bool) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := NewDatabase(diskdb) - sched := NewSync(srcTrie.Hash(), diskdb, nil) + sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code // at the testing trie. @@ -194,9 +195,9 @@ func TestIterativeDelayedSync(t *testing.T) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := NewDatabase(diskdb) - sched := NewSync(srcTrie.Hash(), diskdb, nil) + sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code // at the testing trie. @@ -255,9 +256,9 @@ func testIterativeRandomSync(t *testing.T, count int) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := NewDatabase(diskdb) - sched := NewSync(srcTrie.Hash(), diskdb, nil) + sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code // at the testing trie. @@ -313,9 +314,9 @@ func TestIterativeRandomDelayedSync(t *testing.T) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := NewDatabase(diskdb) - sched := NewSync(srcTrie.Hash(), diskdb, nil) + sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code // at the testing trie. @@ -376,9 +377,9 @@ func TestDuplicateAvoidanceSync(t *testing.T) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := NewDatabase(diskdb) - sched := NewSync(srcTrie.Hash(), diskdb, nil) + sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code // at the testing trie. @@ -439,9 +440,9 @@ func TestIncompleteSync(t *testing.T) { srcDb, srcTrie, _ := makeTestTrie() // Create a destination trie and sync with the scheduler - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := NewDatabase(diskdb) - sched := NewSync(srcTrie.Hash(), diskdb, nil) + sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code // at the testing trie. @@ -519,9 +520,9 @@ func TestSyncOrdering(t *testing.T) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler, tracking the requests - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := NewDatabase(diskdb) - sched := NewSync(srcTrie.Hash(), diskdb, nil) + sched := NewSync(srcTrie.Hash(), diskdb, nil, srcDb.Scheme()) // The code requests are ignored here since there is no code // at the testing trie. diff --git a/trie/trie.go b/trie/trie.go index bec6a1cc7891..abc63f46749a 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -35,22 +35,6 @@ var ( emptyState = crypto.Keccak256Hash(nil) ) -// LeafCallback is a callback type invoked when a trie operation reaches a leaf -// node. -// -// The keys is a path tuple identifying a particular trie node either in a single -// trie (account) or a layered trie (account -> storage). Each key in the tuple -// is in the raw format(32 bytes). -// -// The path is a composite hexary path identifying the trie node. All the key -// bytes are converted to the hexary nibbles and composited with the parent path -// if the trie node is in a layered trie. -// -// It's used by state sync and commit to allow handling external references -// between account and storage tries. And also it's used in the state healing -// for extracting the raw states(leaf nodes) with corresponding paths. -type LeafCallback func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error - // Trie is a Merkle Patricia Trie. Use New to create a trie that sits on // top of a database. Whenever trie performs a commit operation, the generated // nodes will be gathered and returned in a set. Once the trie is committed, diff --git a/trie/trie_test.go b/trie/trie_test.go index 832546b1e344..76307ba78686 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -34,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/rlp" "golang.org/x/crypto/sha3" ) @@ -65,7 +64,7 @@ func TestNull(t *testing.T) { func TestMissingRoot(t *testing.T) { root := common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") - trie, err := New(TrieID(root), NewDatabase(memorydb.New())) + trie, err := New(TrieID(root), NewDatabase(rawdb.NewMemoryDatabase())) if trie != nil { t.Error("New returned non-nil trie for invalid root") } @@ -78,7 +77,7 @@ func TestMissingNodeDisk(t *testing.T) { testMissingNode(t, false) } func TestMissingNodeMemonly(t *testing.T) { testMissingNode(t, true) } func testMissingNode(t *testing.T, memonly bool) { - diskdb := memorydb.New() + diskdb := rawdb.NewMemoryDatabase() triedb := NewDatabase(diskdb) trie := NewEmpty(triedb) @@ -414,7 +413,7 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value { func runRandTest(rt randTest) bool { var ( - triedb = NewDatabase(memorydb.New()) + triedb = NewDatabase(rawdb.NewMemoryDatabase()) tr = NewEmpty(triedb) values = make(map[string]string) // tracks content of the trie origTrie = NewEmpty(triedb) @@ -811,7 +810,7 @@ func TestCommitSequence(t *testing.T) { addresses, accounts := makeAccounts(tc.count) // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} - db := NewDatabase(s) + db := NewDatabase(rawdb.NewDatabase(s)) trie := NewEmpty(db) // Another sponge is used to check the callback-sequence callbackSponge := sha3.NewLegacyKeccak256() @@ -854,7 +853,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { prng := rand.New(rand.NewSource(int64(i))) // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} - db := NewDatabase(s) + db := NewDatabase(rawdb.NewDatabase(s)) trie := NewEmpty(db) // Another sponge is used to check the callback-sequence callbackSponge := sha3.NewLegacyKeccak256() @@ -894,11 +893,13 @@ func TestCommitSequenceStackTrie(t *testing.T) { prng := rand.New(rand.NewSource(int64(count))) // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"} - db := NewDatabase(s) + db := NewDatabase(rawdb.NewDatabase(s)) trie := NewEmpty(db) // Another sponge is used for the stacktrie commits stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} - stTrie := NewStackTrie(stackTrieSponge) + stTrie := NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { + db.Scheme().WriteTrieNode(stackTrieSponge, owner, path, hash, blob) + }) // Fill the trie with elements for i := 0; i < count; i++ { // For the stack trie, we need to do inserts in proper order @@ -951,11 +952,13 @@ func TestCommitSequenceStackTrie(t *testing.T) { // not fit into 32 bytes, rlp-encoded. However, it's still the correct thing to do. func TestCommitSequenceSmallRoot(t *testing.T) { s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"} - db := NewDatabase(s) + db := NewDatabase(rawdb.NewDatabase(s)) trie := NewEmpty(db) // Another sponge is used for the stacktrie commits stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} - stTrie := NewStackTrie(stackTrieSponge) + stTrie := NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { + db.Scheme().WriteTrieNode(stackTrieSponge, owner, path, hash, blob) + }) // Add a single small-element to the trie(s) key := make([]byte, 5) key[0] = 1 From 1b8a392153b39fbbde17536c730d96510e57341f Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 28 Nov 2022 20:27:01 +0100 Subject: [PATCH 404/715] console: use default APIs when server doesn't have rpc_modules (#26267) --- console/console.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/console/console.go b/console/console.go index 7b9ed27e15ec..fde673be8be9 100644 --- a/console/console.go +++ b/console/console.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/internal/jsre" "github.com/ethereum/go-ethereum/internal/jsre/deps" "github.com/ethereum/go-ethereum/internal/web3ext" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" "github.com/mattn/go-colorable" "github.com/peterh/liner" @@ -198,13 +199,22 @@ func (c *Console) initWeb3(bridge *bridge) error { return err } +var defaultAPIs = map[string]string{"eth": "1.0", "net": "1.0", "debug": "1.0"} + // initExtensions loads and registers web3.js extensions. func (c *Console) initExtensions() error { - // Compute aliases from server-provided modules. + const methodNotFound = -32601 apis, err := c.client.SupportedModules() if err != nil { - return fmt.Errorf("api modules: %v", err) + if rpcErr, ok := err.(rpc.Error); ok && rpcErr.ErrorCode() == methodNotFound { + log.Warn("Server does not support method rpc_modules, using default API list.") + apis = defaultAPIs + } else { + return err + } } + + // Compute aliases from server-provided modules. aliases := map[string]struct{}{"eth": {}, "personal": {}} for api := range apis { if api == "web3" { From c1aa1db69e74c71f251fc83cf7c120b4d0222728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rich=CE=9Brd?= Date: Wed, 30 Nov 2022 17:03:34 -0400 Subject: [PATCH 405/715] p2p/discover: add config option for discv5 protocol ID (#26041) This option is occasionally useful for advanced uses of the discv5 protocol. Co-authored-by: Felix Lange --- cmd/devp2p/internal/v5test/framework.go | 2 +- p2p/discover/common.go | 16 +++++++++---- p2p/discover/v5_udp.go | 2 +- p2p/discover/v5wire/encoding.go | 31 ++++++++++++++----------- p2p/discover/v5wire/encoding_test.go | 8 +++---- 5 files changed, 36 insertions(+), 23 deletions(-) diff --git a/cmd/devp2p/internal/v5test/framework.go b/cmd/devp2p/internal/v5test/framework.go index 6ccbbd075bf0..f31677e519e7 100644 --- a/cmd/devp2p/internal/v5test/framework.go +++ b/cmd/devp2p/internal/v5test/framework.go @@ -86,7 +86,7 @@ func newConn(dest *enode.Node, log logger) *conn { localNode: ln, remote: dest, remoteAddr: &net.UDPAddr{IP: dest.IP(), Port: dest.UDP()}, - codec: v5wire.NewCodec(ln, key, mclock.System{}), + codec: v5wire.NewCodec(ln, key, mclock.System{}, nil), log: log, } } diff --git a/p2p/discover/common.go b/p2p/discover/common.go index e389821fda8b..c36e8dcc3a71 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -35,16 +35,24 @@ type UDPConn interface { LocalAddr() net.Addr } +type V5Config struct { + ProtocolID *[6]byte +} + // Config holds settings for the discovery listener. type Config struct { // These settings are required and configure the UDP listener: PrivateKey *ecdsa.PrivateKey // These settings are optional: - NetRestrict *netutil.Netlist // list of allowed IP networks - Bootnodes []*enode.Node // list of bootstrap nodes - Unhandled chan<- ReadPacket // unhandled packets are sent on this channel - Log log.Logger // if set, log messages go here + NetRestrict *netutil.Netlist // list of allowed IP networks + Bootnodes []*enode.Node // list of bootstrap nodes + Unhandled chan<- ReadPacket // unhandled packets are sent on this channel + Log log.Logger // if set, log messages go here + + // V5ProtocolID configures the discv5 protocol identifier. + V5ProtocolID *[6]byte + ValidSchemes enr.IdentityScheme // allowed identity schemes Clock mclock.Clock } diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 321c5bd2a818..57d624498ea1 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -154,7 +154,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { callDoneCh: make(chan *callV5), respTimeoutCh: make(chan *callTimeout), // state of dispatch - codec: v5wire.NewCodec(ln, cfg.PrivateKey, cfg.Clock), + codec: v5wire.NewCodec(ln, cfg.PrivateKey, cfg.Clock, cfg.V5ProtocolID), activeCallByNode: make(map[enode.ID]*callV5), activeCallByAuth: make(map[v5wire.Nonce]*callV5), callQueue: make(map[enode.ID][]*callV5), diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index e41d7f4c451e..d979ab0f9cd8 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -98,7 +98,7 @@ const ( randomPacketMsgSize = 20 ) -var protocolID = [6]byte{'d', 'i', 's', 'c', 'v', '5'} +var DefaultProtocolID = [6]byte{'d', 'i', 's', 'c', 'v', '5'} // Errors. var ( @@ -134,10 +134,11 @@ var ( // Codec encodes and decodes Discovery v5 packets. // This type is not safe for concurrent use. type Codec struct { - sha256 hash.Hash - localnode *enode.LocalNode - privkey *ecdsa.PrivateKey - sc *SessionCache + sha256 hash.Hash + localnode *enode.LocalNode + privkey *ecdsa.PrivateKey + sc *SessionCache + protocolID [6]byte // encoder buffers buf bytes.Buffer // whole packet @@ -150,12 +151,16 @@ type Codec struct { } // NewCodec creates a wire codec. -func NewCodec(ln *enode.LocalNode, key *ecdsa.PrivateKey, clock mclock.Clock) *Codec { +func NewCodec(ln *enode.LocalNode, key *ecdsa.PrivateKey, clock mclock.Clock, protocolID *[6]byte) *Codec { c := &Codec{ - sha256: sha256.New(), - localnode: ln, - privkey: key, - sc: NewSessionCache(1024, clock), + sha256: sha256.New(), + localnode: ln, + privkey: key, + sc: NewSessionCache(1024, clock), + protocolID: DefaultProtocolID, + } + if protocolID != nil { + c.protocolID = *protocolID } return c } @@ -255,7 +260,7 @@ func (c *Codec) makeHeader(toID enode.ID, flag byte, authsizeExtra int) Header { } return Header{ StaticHeader: StaticHeader{ - ProtocolID: protocolID, + ProtocolID: c.protocolID, Version: version, Flag: flag, AuthSize: uint16(authsize), @@ -434,7 +439,7 @@ func (c *Codec) Decode(input []byte, addr string) (src enode.ID, n *enode.Node, c.reader.Reset(staticHeader) binary.Read(&c.reader, binary.BigEndian, &head.StaticHeader) remainingInput := len(input) - sizeofStaticPacketData - if err := head.checkValid(remainingInput); err != nil { + if err := head.checkValid(remainingInput, c.protocolID); err != nil { return enode.ID{}, nil, nil, err } @@ -621,7 +626,7 @@ func (c *Codec) decryptMessage(input, nonce, headerData, readKey []byte) (Packet // checkValid performs some basic validity checks on the header. // The packetLen here is the length remaining after the static header. -func (h *StaticHeader) checkValid(packetLen int) error { +func (h *StaticHeader) checkValid(packetLen int, protocolID [6]byte) error { if h.ProtocolID != protocolID { return errInvalidHeader } diff --git a/p2p/discover/v5wire/encoding_test.go b/p2p/discover/v5wire/encoding_test.go index a08cffa2a576..25df732835dd 100644 --- a/p2p/discover/v5wire/encoding_test.go +++ b/p2p/discover/v5wire/encoding_test.go @@ -504,8 +504,8 @@ type handshakeTestNode struct { func newHandshakeTest() *handshakeTest { t := new(handshakeTest) - t.nodeA.init(testKeyA, net.IP{127, 0, 0, 1}, &t.clock) - t.nodeB.init(testKeyB, net.IP{127, 0, 0, 1}, &t.clock) + t.nodeA.init(testKeyA, net.IP{127, 0, 0, 1}, &t.clock, DefaultProtocolID) + t.nodeB.init(testKeyB, net.IP{127, 0, 0, 1}, &t.clock, DefaultProtocolID) return t } @@ -514,11 +514,11 @@ func (t *handshakeTest) close() { t.nodeB.ln.Database().Close() } -func (n *handshakeTestNode) init(key *ecdsa.PrivateKey, ip net.IP, clock mclock.Clock) { +func (n *handshakeTestNode) init(key *ecdsa.PrivateKey, ip net.IP, clock mclock.Clock, protocolID [6]byte) { db, _ := enode.OpenDB("") n.ln = enode.NewLocalNode(db, key) n.ln.SetStaticIP(ip) - n.c = NewCodec(n.ln, key, clock) + n.c = NewCodec(n.ln, key, clock, nil) } func (n *handshakeTestNode) encode(t testing.TB, to handshakeTestNode, p Packet) ([]byte, Nonce) { From e24d6003b180bba0337a57b0c2eaf3966cf4d268 Mon Sep 17 00:00:00 2001 From: Oskar Haarklou Veileborg Date: Fri, 2 Dec 2022 12:26:52 +0100 Subject: [PATCH 406/715] miner: fix potential goroutine leak in test (#26281) --- miner/worker_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/worker_test.go b/miner/worker_test.go index 859495d7bf16..9c7961f7866d 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -328,7 +328,7 @@ func TestStreamUncleBlock(t *testing.T) { w, b := newTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 1) defer w.close() - var taskCh = make(chan struct{}) + var taskCh = make(chan struct{}, 3) taskIndex := 0 w.newTaskHook = func(task *task) { From 10347c6b54d5b28a2e71d9c4993e7f44b0a359c3 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Sat, 3 Dec 2022 21:42:11 +0100 Subject: [PATCH 407/715] core: drop legacy receipt types (#26225) This PR drops the legacy receipt types, the freezer-migrate command and the startup check. The previous attempt #22852 at this failed because there were users who still had legacy receipts in their db, so it had to be reverted #23247. Since then we added a command to migrate legacy dbs #24028. As of the last hardforks all users either must have done the migration, or used the --ignore-legacy-receipts flag which will stop working now. --- cmd/geth/config.go | 22 +----- cmd/geth/dbcmd.go | 102 -------------------------- cmd/geth/main.go | 1 - cmd/utils/flags.go | 5 -- core/rawdb/accessors_chain.go | 28 +------- core/types/legacy.go | 53 -------------- core/types/log.go | 54 +------------- core/types/receipt.go | 89 +---------------------- core/types/receipt_test.go | 130 ---------------------------------- 9 files changed, 8 insertions(+), 476 deletions(-) delete mode 100644 core/types/legacy.go diff --git a/cmd/geth/config.go b/cmd/geth/config.go index a8cee0d13a59..e15302544cc5 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/scwallet" "github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/flags" @@ -166,26 +165,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { cfg.Eth.OverrideTerminalTotalDifficultyPassed = &override } - backend, eth := utils.RegisterEthService(stack, &cfg.Eth) - - // Warn users to migrate if they have a legacy freezer format. - if eth != nil && !ctx.IsSet(utils.IgnoreLegacyReceiptsFlag.Name) { - firstIdx := uint64(0) - // Hack to speed up check for mainnet because we know - // the first non-empty block. - ghash := rawdb.ReadCanonicalHash(eth.ChainDb(), 0) - if cfg.Eth.NetworkId == 1 && ghash == params.MainnetGenesisHash { - firstIdx = 46147 - } - isLegacy, firstLegacy, err := dbHasLegacyReceipts(eth.ChainDb(), firstIdx) - if err != nil { - log.Error("Failed to check db for legacy receipts", "err", err) - } else if isLegacy { - stack.Close() - log.Error("Database has receipts with a legacy format", "firstLegacy", firstLegacy) - utils.Fatalf("Aborting. Please run `geth db freezer-migrate`.") - } - } + backend, _ := utils.RegisterEthService(stack, &cfg.Eth) // Configure log filter RPC API. filterSystem := utils.RegisterFilterAPI(stack, backend, &cfg.Eth) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 9d834ee14b9d..5231ed116bc9 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -33,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/console/prompt" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/flags" @@ -69,7 +68,6 @@ Remove blockchain and state databases`, dbImportCmd, dbExportCmd, dbMetadataCmd, - dbMigrateFreezerCmd, dbCheckStateContentCmd, }, } @@ -195,17 +193,6 @@ WARNING: This is a low-level operation which may cause database corruption!`, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "Shows metadata about the chain status.", } - dbMigrateFreezerCmd = &cli.Command{ - Action: freezerMigrate, - Name: "freezer-migrate", - Usage: "Migrate legacy parts of the freezer. (WARNING: may take a long time)", - ArgsUsage: "", - Flags: flags.Merge([]cli.Flag{ - utils.SyncModeFlag, - }, utils.NetworkFlags, utils.DatabasePathFlags), - Description: `The freezer-migrate command checks your database for receipts in a legacy format and updates those. -WARNING: please back-up the receipt files in your ancients before running this command.`, - } ) func removeDB(ctx *cli.Context) error { @@ -756,92 +743,3 @@ func showMetaData(ctx *cli.Context) error { table.Render() return nil } - -func freezerMigrate(ctx *cli.Context) error { - stack, _ := makeConfigNode(ctx) - defer stack.Close() - - db := utils.MakeChainDatabase(ctx, stack, false) - defer db.Close() - - // Check first block for legacy receipt format - numAncients, err := db.Ancients() - if err != nil { - return err - } - if numAncients < 1 { - log.Info("No receipts in freezer to migrate") - return nil - } - - isFirstLegacy, firstIdx, err := dbHasLegacyReceipts(db, 0) - if err != nil { - return err - } - if !isFirstLegacy { - log.Info("No legacy receipts to migrate") - return nil - } - - log.Info("Starting migration", "ancients", numAncients, "firstLegacy", firstIdx) - start := time.Now() - if err := db.MigrateTable("receipts", types.ConvertLegacyStoredReceipts); err != nil { - return err - } - if err := db.Close(); err != nil { - return err - } - log.Info("Migration finished", "duration", time.Since(start)) - - return nil -} - -// dbHasLegacyReceipts checks freezer entries for legacy receipts. It stops at the first -// non-empty receipt and checks its format. The index of this first non-empty element is -// the second return parameter. -func dbHasLegacyReceipts(db ethdb.Database, firstIdx uint64) (bool, uint64, error) { - // Check first block for legacy receipt format - numAncients, err := db.Ancients() - if err != nil { - return false, 0, err - } - if numAncients < 1 { - return false, 0, nil - } - if firstIdx >= numAncients { - return false, firstIdx, nil - } - var ( - legacy bool - blob []byte - emptyRLPList = []byte{192} - ) - // Find first block with non-empty receipt, only if - // the index is not already provided. - if firstIdx == 0 { - for i := uint64(0); i < numAncients; i++ { - blob, err = db.Ancient("receipts", i) - if err != nil { - return false, 0, err - } - if len(blob) == 0 { - continue - } - if !bytes.Equal(blob, emptyRLPList) { - firstIdx = i - break - } - } - } - first, err := db.Ancient("receipts", firstIdx) - if err != nil { - return false, 0, err - } - // We looped over all receipts and they were all empty - if bytes.Equal(first, emptyRLPList) { - return false, 0, nil - } - // Is first non-empty receipt legacy? - legacy, err = types.IsLegacyStoredReceipts(first) - return legacy, firstIdx, err -} diff --git a/cmd/geth/main.go b/cmd/geth/main.go index a94c0c17db3b..ea747d06253d 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -149,7 +149,6 @@ var ( utils.GpoMaxGasPriceFlag, utils.GpoIgnoreGasPriceFlag, utils.MinerNotifyFullFlag, - utils.IgnoreLegacyReceiptsFlag, configFileFlag, }, utils.NetworkFlags, utils.DatabasePathFlags) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 673aefb5254d..5c0d984cbf16 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -669,11 +669,6 @@ var ( } // MISC settings - IgnoreLegacyReceiptsFlag = &cli.BoolFlag{ - Name: "ignore-legacy-receipts", - Usage: "Geth will start up even if there are legacy receipts in freezer", - Category: flags.MiscCategory, - } SyncTargetFlag = &cli.PathFlag{ Name: "synctarget", Usage: `File for containing the hex-encoded block-rlp as sync target(dev feature)`, diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 881660aa8e8f..a323ab9ad8b9 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -669,10 +669,11 @@ func DeleteReceipts(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { // storedReceiptRLP is the storage encoding of a receipt. // Re-definition in core/types/receipt.go. +// TODO: Re-use the existing definition. type storedReceiptRLP struct { PostStateOrStatus []byte CumulativeGasUsed uint64 - Logs []*types.LogForStorage + Logs []*types.Log } // ReceiptLogs is a barebone version of ReceiptForStorage which only keeps @@ -688,10 +689,7 @@ func (r *receiptLogs) DecodeRLP(s *rlp.Stream) error { if err := s.Decode(&stored); err != nil { return err } - r.Logs = make([]*types.Log, len(stored.Logs)) - for i, log := range stored.Logs { - r.Logs[i] = (*types.Log)(log) - } + r.Logs = stored.Logs return nil } @@ -727,11 +725,6 @@ func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.C } receipts := []*receiptLogs{} if err := rlp.DecodeBytes(data, &receipts); err != nil { - // Receipts might be in the legacy format, try decoding that. - // TODO: to be removed after users migrated - if logs := readLegacyLogs(db, hash, number, config); logs != nil { - return logs - } log.Error("Invalid receipt array RLP", "hash", hash, "err", err) return nil } @@ -752,21 +745,6 @@ func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.C return logs } -// readLegacyLogs is a temporary workaround for when trying to read logs -// from a block which has its receipt stored in the legacy format. It'll -// be removed after users have migrated their freezer databases. -func readLegacyLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.ChainConfig) [][]*types.Log { - receipts := ReadReceipts(db, hash, number, config) - if receipts == nil { - return nil - } - logs := make([][]*types.Log, len(receipts)) - for i, receipt := range receipts { - logs[i] = receipt.Logs - } - return logs -} - // ReadBlock retrieves an entire block corresponding to the hash, assembling it // back from the stored header and body. If either the header or body could not // be retrieved nil is returned. diff --git a/core/types/legacy.go b/core/types/legacy.go deleted file mode 100644 index 14ed30d883d4..000000000000 --- a/core/types/legacy.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2022 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 types - -import ( - "errors" - - "github.com/ethereum/go-ethereum/rlp" -) - -// IsLegacyStoredReceipts tries to parse the RLP-encoded blob -// first as an array of v3 stored receipt, then v4 stored receipt and -// returns true if successful. -func IsLegacyStoredReceipts(raw []byte) (bool, error) { - var v3 []v3StoredReceiptRLP - if err := rlp.DecodeBytes(raw, &v3); err == nil { - return true, nil - } - var v4 []v4StoredReceiptRLP - if err := rlp.DecodeBytes(raw, &v4); err == nil { - return true, nil - } - var v5 []storedReceiptRLP - // Check to see valid fresh stored receipt - if err := rlp.DecodeBytes(raw, &v5); err == nil { - return false, nil - } - return false, errors.New("value is not a valid receipt encoding") -} - -// ConvertLegacyStoredReceipts takes the RLP encoding of an array of legacy -// stored receipts and returns a fresh RLP-encoded stored receipt. -func ConvertLegacyStoredReceipts(raw []byte) ([]byte, error) { - var receipts []ReceiptForStorage - if err := rlp.DecodeBytes(raw, &receipts); err != nil { - return nil, err - } - return rlp.EncodeToBytes(&receipts) -} diff --git a/core/types/log.go b/core/types/log.go index eb30957b1278..e48919136889 100644 --- a/core/types/log.go +++ b/core/types/log.go @@ -64,24 +64,13 @@ type logMarshaling struct { //go:generate go run ../../rlp/rlpgen -type rlpLog -out gen_log_rlp.go +// rlpLog is used to RLP-encode both the consensus and storage formats. type rlpLog struct { Address common.Address Topics []common.Hash Data []byte } -// legacyRlpStorageLog is the previous storage encoding of a log including some redundant fields. -type legacyRlpStorageLog struct { - Address common.Address - Topics []common.Hash - Data []byte - BlockNumber uint64 - TxHash common.Hash - TxIndex uint - BlockHash common.Hash - Index uint -} - // EncodeRLP implements rlp.Encoder. func (l *Log) EncodeRLP(w io.Writer) error { rl := rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data} @@ -97,44 +86,3 @@ func (l *Log) DecodeRLP(s *rlp.Stream) error { } return err } - -// LogForStorage is a wrapper around a Log that handles -// backward compatibility with prior storage formats. -type LogForStorage Log - -// EncodeRLP implements rlp.Encoder. -func (l *LogForStorage) EncodeRLP(w io.Writer) error { - rl := rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data} - return rlp.Encode(w, &rl) -} - -// DecodeRLP implements rlp.Decoder. -// -// Note some redundant fields(e.g. block number, tx hash etc) will be assembled later. -func (l *LogForStorage) DecodeRLP(s *rlp.Stream) error { - blob, err := s.Raw() - if err != nil { - return err - } - var dec rlpLog - err = rlp.DecodeBytes(blob, &dec) - if err == nil { - *l = LogForStorage{ - Address: dec.Address, - Topics: dec.Topics, - Data: dec.Data, - } - } else { - // Try to decode log with previous definition. - var dec legacyRlpStorageLog - err = rlp.DecodeBytes(blob, &dec) - if err == nil { - *l = LogForStorage{ - Address: dec.Address, - Topics: dec.Topics, - Data: dec.Data, - } - } - } - return err -} diff --git a/core/types/receipt.go b/core/types/receipt.go index bdf48451473c..4404b278891f 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -93,28 +93,7 @@ type receiptRLP struct { type storedReceiptRLP struct { PostStateOrStatus []byte CumulativeGasUsed uint64 - Logs []*LogForStorage -} - -// v4StoredReceiptRLP is the storage encoding of a receipt used in database version 4. -type v4StoredReceiptRLP struct { - PostStateOrStatus []byte - CumulativeGasUsed uint64 - TxHash common.Hash - ContractAddress common.Address - Logs []*LogForStorage - GasUsed uint64 -} - -// v3StoredReceiptRLP is the original storage encoding of a receipt including some unnecessary fields. -type v3StoredReceiptRLP struct { - PostStateOrStatus []byte - CumulativeGasUsed uint64 - Bloom Bloom - TxHash common.Hash - ContractAddress common.Address - Logs []*LogForStorage - GasUsed uint64 + Logs []*Log } // NewReceipt creates a barebone transaction receipt, copying the init fields. @@ -292,82 +271,20 @@ func (r *ReceiptForStorage) EncodeRLP(_w io.Writer) error { // DecodeRLP implements rlp.Decoder, and loads both consensus and implementation // fields of a receipt from an RLP stream. func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { - // Retrieve the entire receipt blob as we need to try multiple decoders - blob, err := s.Raw() - if err != nil { - return err - } - // Try decoding from the newest format for future proofness, then the older one - // for old nodes that just upgraded. V4 was an intermediate unreleased format so - // we do need to decode it, but it's not common (try last). - if err := decodeStoredReceiptRLP(r, blob); err == nil { - return nil - } - if err := decodeV3StoredReceiptRLP(r, blob); err == nil { - return nil - } - return decodeV4StoredReceiptRLP(r, blob) -} - -func decodeStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { var stored storedReceiptRLP - if err := rlp.DecodeBytes(blob, &stored); err != nil { + if err := s.Decode(&stored); err != nil { return err } if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil { return err } r.CumulativeGasUsed = stored.CumulativeGasUsed - r.Logs = make([]*Log, len(stored.Logs)) - for i, log := range stored.Logs { - r.Logs[i] = (*Log)(log) - } + r.Logs = stored.Logs r.Bloom = CreateBloom(Receipts{(*Receipt)(r)}) return nil } -func decodeV4StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { - var stored v4StoredReceiptRLP - if err := rlp.DecodeBytes(blob, &stored); err != nil { - return err - } - if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil { - return err - } - r.CumulativeGasUsed = stored.CumulativeGasUsed - r.TxHash = stored.TxHash - r.ContractAddress = stored.ContractAddress - r.GasUsed = stored.GasUsed - r.Logs = make([]*Log, len(stored.Logs)) - for i, log := range stored.Logs { - r.Logs[i] = (*Log)(log) - } - r.Bloom = CreateBloom(Receipts{(*Receipt)(r)}) - - return nil -} - -func decodeV3StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { - var stored v3StoredReceiptRLP - if err := rlp.DecodeBytes(blob, &stored); err != nil { - return err - } - if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil { - return err - } - r.CumulativeGasUsed = stored.CumulativeGasUsed - r.Bloom = stored.Bloom - r.TxHash = stored.TxHash - r.ContractAddress = stored.ContractAddress - r.GasUsed = stored.GasUsed - r.Logs = make([]*Log, len(stored.Logs)) - for i, log := range stored.Logs { - r.Logs[i] = (*Log)(log) - } - return nil -} - // Receipts implements DerivableList for receipts. type Receipts []*Receipt diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index 6f0953bdec7d..f44bb80b04b4 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -91,136 +91,6 @@ func TestDecodeEmptyTypedReceipt(t *testing.T) { } } -func TestLegacyReceiptDecoding(t *testing.T) { - tests := []struct { - name string - encode func(*Receipt) ([]byte, error) - }{ - { - "ReceiptForStorage", - encodeAsReceiptForStorage, - }, - { - "StoredReceiptRLP", - encodeAsStoredReceiptRLP, - }, - { - "V4StoredReceiptRLP", - encodeAsV4StoredReceiptRLP, - }, - { - "V3StoredReceiptRLP", - encodeAsV3StoredReceiptRLP, - }, - } - - tx := NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil) - receipt := &Receipt{ - Status: ReceiptStatusFailed, - CumulativeGasUsed: 1, - Logs: []*Log{ - { - Address: common.BytesToAddress([]byte{0x11}), - Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")}, - Data: []byte{0x01, 0x00, 0xff}, - }, - { - Address: common.BytesToAddress([]byte{0x01, 0x11}), - Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")}, - Data: []byte{0x01, 0x00, 0xff}, - }, - }, - TxHash: tx.Hash(), - ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), - GasUsed: 111111, - } - receipt.Bloom = CreateBloom(Receipts{receipt}) - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - enc, err := tc.encode(receipt) - if err != nil { - t.Fatalf("Error encoding receipt: %v", err) - } - var dec ReceiptForStorage - if err := rlp.DecodeBytes(enc, &dec); err != nil { - t.Fatalf("Error decoding RLP receipt: %v", err) - } - // Check whether all consensus fields are correct. - if dec.Status != receipt.Status { - t.Fatalf("Receipt status mismatch, want %v, have %v", receipt.Status, dec.Status) - } - if dec.CumulativeGasUsed != receipt.CumulativeGasUsed { - t.Fatalf("Receipt CumulativeGasUsed mismatch, want %v, have %v", receipt.CumulativeGasUsed, dec.CumulativeGasUsed) - } - if dec.Bloom != receipt.Bloom { - t.Fatalf("Bloom data mismatch, want %v, have %v", receipt.Bloom, dec.Bloom) - } - if len(dec.Logs) != len(receipt.Logs) { - t.Fatalf("Receipt log number mismatch, want %v, have %v", len(receipt.Logs), len(dec.Logs)) - } - for i := 0; i < len(dec.Logs); i++ { - if dec.Logs[i].Address != receipt.Logs[i].Address { - t.Fatalf("Receipt log %d address mismatch, want %v, have %v", i, receipt.Logs[i].Address, dec.Logs[i].Address) - } - if !reflect.DeepEqual(dec.Logs[i].Topics, receipt.Logs[i].Topics) { - t.Fatalf("Receipt log %d topics mismatch, want %v, have %v", i, receipt.Logs[i].Topics, dec.Logs[i].Topics) - } - if !bytes.Equal(dec.Logs[i].Data, receipt.Logs[i].Data) { - t.Fatalf("Receipt log %d data mismatch, want %v, have %v", i, receipt.Logs[i].Data, dec.Logs[i].Data) - } - } - }) - } -} - -func encodeAsReceiptForStorage(want *Receipt) ([]byte, error) { - return rlp.EncodeToBytes((*ReceiptForStorage)(want)) -} - -func encodeAsStoredReceiptRLP(want *Receipt) ([]byte, error) { - stored := &storedReceiptRLP{ - PostStateOrStatus: want.statusEncoding(), - CumulativeGasUsed: want.CumulativeGasUsed, - Logs: make([]*LogForStorage, len(want.Logs)), - } - for i, log := range want.Logs { - stored.Logs[i] = (*LogForStorage)(log) - } - return rlp.EncodeToBytes(stored) -} - -func encodeAsV4StoredReceiptRLP(want *Receipt) ([]byte, error) { - stored := &v4StoredReceiptRLP{ - PostStateOrStatus: want.statusEncoding(), - CumulativeGasUsed: want.CumulativeGasUsed, - TxHash: want.TxHash, - ContractAddress: want.ContractAddress, - Logs: make([]*LogForStorage, len(want.Logs)), - GasUsed: want.GasUsed, - } - for i, log := range want.Logs { - stored.Logs[i] = (*LogForStorage)(log) - } - return rlp.EncodeToBytes(stored) -} - -func encodeAsV3StoredReceiptRLP(want *Receipt) ([]byte, error) { - stored := &v3StoredReceiptRLP{ - PostStateOrStatus: want.statusEncoding(), - CumulativeGasUsed: want.CumulativeGasUsed, - Bloom: want.Bloom, - TxHash: want.TxHash, - ContractAddress: want.ContractAddress, - Logs: make([]*LogForStorage, len(want.Logs)), - GasUsed: want.GasUsed, - } - for i, log := range want.Logs { - stored.Logs[i] = (*LogForStorage)(log) - } - return rlp.EncodeToBytes(stored) -} - // Tests that receipt data can be correctly derived from the contextual infos func TestDeriveFields(t *testing.T) { // Create a few transactions to have receipts for From 06632da2bb367664b5e1417c55c0d3a2a2bf5166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Anda=20Estensen?= Date: Mon, 5 Dec 2022 13:49:54 +0100 Subject: [PATCH 408/715] all: assign zero after resize in implementations of heap.Interface (#26296) This changes the Pop method to assign the zero value before reducing slice size. Doing so ensures the backing array does not reference removed item values. --- core/txpool/list.go | 1 + core/types/transaction.go | 1 + p2p/util.go | 1 + 3 files changed, 3 insertions(+) diff --git a/core/txpool/list.go b/core/txpool/list.go index eb0c753f21e9..062cbbf63e6a 100644 --- a/core/txpool/list.go +++ b/core/txpool/list.go @@ -45,6 +45,7 @@ func (h *nonceHeap) Pop() interface{} { old := *h n := len(old) x := old[n-1] + old[n-1] = 0 *h = old[0 : n-1] return x } diff --git a/core/types/transaction.go b/core/types/transaction.go index 910c68aea363..353e0e599c68 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -508,6 +508,7 @@ func (s *TxByPriceAndTime) Pop() interface{} { old := *s n := len(old) x := old[n-1] + old[n-1] = nil *s = old[0 : n-1] return x } diff --git a/p2p/util.go b/p2p/util.go index 3c5f6b8508d5..2c8f322a66ac 100644 --- a/p2p/util.go +++ b/p2p/util.go @@ -70,6 +70,7 @@ func (h *expHeap) Pop() interface{} { old := *h n := len(old) x := old[n-1] + old[n-1] = expItem{} *h = old[0 : n-1] return x } From 1f35988a0047b5430eb074f0f43e6d0466c468a9 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 5 Dec 2022 16:57:47 +0100 Subject: [PATCH 409/715] eth/tracers, core/vm: remove `time` from trace output and tracing interface (#26291) This removes the 'time' field from logs, as well as from the tracer interface. This change makes the trace output deterministic. If a tracer needs the time they can measure it themselves. No need for evm to do this. Co-authored-by: Sina Mahmoodi --- core/vm/evm.go | 13 +++++-------- core/vm/logger.go | 3 +-- eth/tracers/js/goja.go | 4 +--- .../js/internal/tracers/call_tracer_legacy.js | 1 - eth/tracers/js/tracer_test.go | 4 ++-- eth/tracers/logger/access_list_tracer.go | 3 +-- eth/tracers/logger/logger.go | 5 ++--- eth/tracers/logger/logger_json.go | 6 ++---- eth/tracers/native/call.go | 3 +-- eth/tracers/native/mux.go | 5 ++--- eth/tracers/native/noop.go | 3 +-- eth/tracers/native/prestate.go | 3 +-- 12 files changed, 19 insertions(+), 34 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 888f4812a590..b9a9d4636b7b 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -19,7 +19,6 @@ package vm import ( "math/big" "sync/atomic" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -183,7 +182,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if evm.Config.Debug { if evm.depth == 0 { evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) - evm.Config.Tracer.CaptureEnd(ret, 0, 0, nil) + evm.Config.Tracer.CaptureEnd(ret, 0, nil) } else { evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) evm.Config.Tracer.CaptureExit(ret, 0, nil) @@ -199,9 +198,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if evm.Config.Debug { if evm.depth == 0 { evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) - defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters - evm.Config.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err) - }(gas, time.Now()) + defer func(startGas uint64) { // Lazy evaluation of the parameters + evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err) + }(gas) } else { // Handle tracer events for entering and exiting a call frame evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value) @@ -448,8 +447,6 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } } - start := time.Now() - ret, err := evm.interpreter.Run(contract, nil, false) // Check whether the max code size has been exceeded, assign err if the case. @@ -487,7 +484,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, if evm.Config.Debug { if evm.depth == 0 { - evm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) + evm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, err) } else { evm.Config.Tracer.CaptureExit(ret, gas-contract.Gas, err) } diff --git a/core/vm/logger.go b/core/vm/logger.go index 50fccafcf53e..2667908a84d1 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -18,7 +18,6 @@ package vm import ( "math/big" - "time" "github.com/ethereum/go-ethereum/common" ) @@ -34,7 +33,7 @@ type EVMLogger interface { CaptureTxEnd(restGas uint64) // Top call frame CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) - CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) + CaptureEnd(output []byte, gasUsed uint64, err error) // Rest of call frames CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) CaptureExit(output []byte, gasUsed uint64, err error) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index ceb591a79afe..9adfca9fb62a 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -21,7 +21,6 @@ import ( "errors" "fmt" "math/big" - "time" "github.com/dop251/goja" @@ -285,9 +284,8 @@ func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope } // CaptureEnd is called after the call finishes to finalize the tracing. -func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, duration time.Duration, err error) { +func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { t.ctx["output"] = t.vm.ToValue(output) - t.ctx["time"] = t.vm.ToValue(duration.String()) if err != nil { t.ctx["error"] = t.vm.ToValue(err.Error()) } diff --git a/eth/tracers/js/internal/tracers/call_tracer_legacy.js b/eth/tracers/js/internal/tracers/call_tracer_legacy.js index b9e555df8746..451a644b917a 100644 --- a/eth/tracers/js/internal/tracers/call_tracer_legacy.js +++ b/eth/tracers/js/internal/tracers/call_tracer_legacy.js @@ -233,7 +233,6 @@ input: call.input, output: call.output, error: call.error, - time: call.time, calls: call.calls, } for (var key in sorted) { diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 6a916f55b2a7..7fba197d8e56 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -76,7 +76,7 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon tracer.CaptureTxStart(gasLimit) tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value) ret, err := env.Interpreter().Run(contract, []byte{}, false) - tracer.CaptureEnd(ret, startGas-contract.Gas, 1, err) + tracer.CaptureEnd(ret, startGas-contract.Gas, err) // Rest gas assumes no refund tracer.CaptureTxEnd(contract.Gas) if err != nil { @@ -206,7 +206,7 @@ func TestNoStepExec(t *testing.T) { } env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) - tracer.CaptureEnd(nil, 0, 1, nil) + tracer.CaptureEnd(nil, 0, nil) ret, err := tracer.GetResult() if err != nil { t.Fatal(err) diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index a8908094eb50..766ee4e4b95c 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -18,7 +18,6 @@ package logger import ( "math/big" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -162,7 +161,7 @@ func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint6 func (*AccessListTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { } -func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {} +func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {} func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index ce774270e127..5e75318b9a92 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -24,7 +24,6 @@ import ( "math/big" "strings" "sync/atomic" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -219,7 +218,7 @@ func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, s } // CaptureEnd is called after the call finishes to finalize the tracing. -func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) { +func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { l.output = output l.err = err if l.cfg.Debug { @@ -385,7 +384,7 @@ func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } -func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, tm time.Duration, err error) { +func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n", output, gasUsed, err) } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 838d5017b863..a2cb4cd9fc59 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -20,7 +20,6 @@ import ( "encoding/json" "io" "math/big" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" @@ -80,18 +79,17 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco } // CaptureEnd is triggered at end of execution. -func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) { +func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) { type endLog struct { Output string `json:"output"` GasUsed math.HexOrDecimal64 `json:"gasUsed"` - Time time.Duration `json:"time"` Err string `json:"error,omitempty"` } var errMsg string if err != nil { errMsg = err.Error() } - l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, errMsg}) + l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), errMsg}) } func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 4be242c8b43d..24fd406398bb 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -21,7 +21,6 @@ import ( "errors" "math/big" "sync/atomic" - "time" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -142,7 +141,7 @@ func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad } // CaptureEnd is called after the call finishes to finalize the tracing. -func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { +func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { t.callstack[0].processOutput(output, err) } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 05b5e3d808b6..878e2dc9d6d7 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -19,7 +19,6 @@ package native import ( "encoding/json" "math/big" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" @@ -67,9 +66,9 @@ func (t *muxTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Add } // CaptureEnd is called after the call finishes to finalize the tracing. -func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, elapsed time.Duration, err error) { +func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { for _, t := range t.tracers { - t.CaptureEnd(output, gasUsed, elapsed, err) + t.CaptureEnd(output, gasUsed, err) } } diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index c252b2408fc9..c1035bd1b7c6 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -19,7 +19,6 @@ package native import ( "encoding/json" "math/big" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" @@ -44,7 +43,7 @@ func (t *noopTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad } // CaptureEnd is called after the call finishes to finalize the tracing. -func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { +func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index b965c50df730..9313d0769071 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -21,7 +21,6 @@ import ( "encoding/json" "math/big" "sync/atomic" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -118,7 +117,7 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo } // CaptureEnd is called after the call finishes to finalize the tracing. -func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { +func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { if t.config.DiffMode { return } From 41306b0af30b3b7b0bd8977b9bcb9e6664e33e33 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 5 Dec 2022 18:58:32 +0100 Subject: [PATCH 410/715] cmd/evm: output stateroot in statetest result (#26297) This adds stateRoot as a field in the JSON output. --- cmd/evm/staterunner.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 36f4e19b0bea..5eba25c725a3 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -22,12 +22,12 @@ import ( "fmt" "os" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/tests" - "github.com/urfave/cli/v2" ) @@ -41,11 +41,12 @@ var stateTestCommand = &cli.Command{ // StatetestResult contains the execution status after running a state test, any // error that might have occurred and a dump of the final state if requested. type StatetestResult struct { - Name string `json:"name"` - Pass bool `json:"pass"` - Fork string `json:"fork"` - Error string `json:"error,omitempty"` - State *state.Dump `json:"state,omitempty"` + Name string `json:"name"` + Pass bool `json:"pass"` + Root *common.Hash `json:"stateRoot,omitempty"` + Fork string `json:"fork"` + Error string `json:"error,omitempty"` + State *state.Dump `json:"state,omitempty"` } func stateTestCmd(ctx *cli.Context) error { @@ -100,8 +101,12 @@ func stateTestCmd(ctx *cli.Context) error { result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true} _, s, err := test.Run(st, cfg, false) // print state root for evmlab tracing - if ctx.Bool(MachineFlag.Name) && s != nil { - fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", s.IntermediateRoot(false)) + if s != nil { + root := s.IntermediateRoot(false) + result.Root = &root + if ctx.Bool(MachineFlag.Name) { + fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) + } } if err != nil { // Test failed, mark as so and dump any state to aid debugging From 01953b347077fdb2be0d741a1782fc6d4e36eeac Mon Sep 17 00:00:00 2001 From: qiuhaohao Date: Tue, 6 Dec 2022 01:59:00 +0800 Subject: [PATCH 411/715] cmd/geth: fix typo in comment (#26308) --- cmd/geth/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index ea747d06253d..25a09749744e 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -337,7 +337,7 @@ func prepare(ctx *cli.Context) { go metrics.CollectProcessMetrics(3 * time.Second) } -// geth is the main entry point into the system if no special subcommand is ran. +// geth is the main entry point into the system if no special subcommand is run. // It creates a default node based on the command line arguments and runs it in // blocking mode, waiting for it to be shut down. func geth(ctx *cli.Context) error { From b44abf56a966016cbb651648ac2d7b6705e80b11 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 6 Dec 2022 16:25:53 +0100 Subject: [PATCH 412/715] cmd/devp2p: add --extaddr flag (#26312) The new flag allows configuring an explicit endpoint which is to be announced in the DHT. This feature was originally developed for the discv5 wormhole experiment (#25798), but it's useful in other contexts as well. --- cmd/devp2p/discv4cmd.go | 61 +++++++++++++++++++++++++++++++++++------ cmd/devp2p/discv5cmd.go | 17 ++++++------ 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/cmd/devp2p/discv4cmd.go b/cmd/devp2p/discv4cmd.go index 9d35880b128b..94e61c36f325 100644 --- a/cmd/devp2p/discv4cmd.go +++ b/cmd/devp2p/discv4cmd.go @@ -19,6 +19,7 @@ package main import ( "fmt" "net" + "strconv" "strings" "time" @@ -50,34 +51,34 @@ var ( Usage: "Sends ping to a node", Action: discv4Ping, ArgsUsage: "", - Flags: v4NodeFlags, + Flags: discoveryNodeFlags, } discv4RequestRecordCommand = &cli.Command{ Name: "requestenr", Usage: "Requests a node record using EIP-868 enrRequest", Action: discv4RequestRecord, ArgsUsage: "", - Flags: v4NodeFlags, + Flags: discoveryNodeFlags, } discv4ResolveCommand = &cli.Command{ Name: "resolve", Usage: "Finds a node in the DHT", Action: discv4Resolve, ArgsUsage: "", - Flags: v4NodeFlags, + Flags: discoveryNodeFlags, } discv4ResolveJSONCommand = &cli.Command{ Name: "resolve-json", Usage: "Re-resolves nodes in a nodes.json file", Action: discv4ResolveJSON, - Flags: v4NodeFlags, + Flags: discoveryNodeFlags, ArgsUsage: "", } discv4CrawlCommand = &cli.Command{ Name: "crawl", Usage: "Updates a nodes.json file with random nodes found in the DHT", Action: discv4Crawl, - Flags: flags.Merge(v4NodeFlags, []cli.Flag{crawlTimeoutFlag}), + Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{crawlTimeoutFlag}), } discv4TestCommand = &cli.Command{ Name: "test", @@ -110,6 +111,10 @@ var ( Name: "addr", Usage: "Listening address", } + extAddrFlag = &cli.StringFlag{ + Name: "extaddr", + Usage: "UDP endpoint announced in ENR. You can provide a bare IP address or IP:port as the value of this flag.", + } crawlTimeoutFlag = &cli.DurationFlag{ Name: "timeout", Usage: "Time limit for the crawl.", @@ -122,11 +127,12 @@ var ( } ) -var v4NodeFlags = []cli.Flag{ +var discoveryNodeFlags = []cli.Flag{ bootnodesFlag, nodekeyFlag, nodedbFlag, listenAddrFlag, + extAddrFlag, } func discv4Ping(ctx *cli.Context) error { @@ -228,7 +234,7 @@ func discv4Test(ctx *cli.Context) error { // startV4 starts an ephemeral discovery V4 node. func startV4(ctx *cli.Context) *discover.UDPv4 { ln, config := makeDiscoveryConfig(ctx) - socket := listen(ln, ctx.String(listenAddrFlag.Name)) + socket := listen(ctx, ln) disc, err := discover.ListenV4(socket, ln, config) if err != nil { exit(err) @@ -266,7 +272,28 @@ func makeDiscoveryConfig(ctx *cli.Context) (*enode.LocalNode, discover.Config) { return ln, cfg } -func listen(ln *enode.LocalNode, addr string) *net.UDPConn { +func parseExtAddr(spec string) (ip net.IP, port int, ok bool) { + ip = net.ParseIP(spec) + if ip != nil { + return ip, 0, true + } + host, portstr, err := net.SplitHostPort(spec) + if err != nil { + return nil, 0, false + } + ip = net.ParseIP(host) + if ip == nil { + return nil, 0, false + } + port, err = strconv.Atoi(portstr) + if err != nil { + return nil, 0, false + } + return ip, port, true +} + +func listen(ctx *cli.Context, ln *enode.LocalNode) *net.UDPConn { + addr := ctx.String(listenAddrFlag.Name) if addr == "" { addr = "0.0.0.0:0" } @@ -274,6 +301,8 @@ func listen(ln *enode.LocalNode, addr string) *net.UDPConn { if err != nil { exit(err) } + + // Configure UDP endpoint in ENR from listener address. usocket := socket.(*net.UDPConn) uaddr := socket.LocalAddr().(*net.UDPAddr) if uaddr.IP.IsUnspecified() { @@ -282,6 +311,22 @@ func listen(ln *enode.LocalNode, addr string) *net.UDPConn { ln.SetFallbackIP(uaddr.IP) } ln.SetFallbackUDP(uaddr.Port) + + // If an ENR endpoint is set explicitly on the command-line, override + // the information from the listening address. Note this is careful not + // to set the UDP port if the external address doesn't have it. + extAddr := ctx.String(extAddrFlag.Name) + if extAddr != "" { + ip, port, ok := parseExtAddr(extAddr) + if !ok { + exit(fmt.Errorf("-%s: invalid external address %q", extAddrFlag.Name, extAddr)) + } + ln.SetStaticIP(ip) + if port != 0 { + ln.SetFallbackUDP(port) + } + } + return usocket } diff --git a/cmd/devp2p/discv5cmd.go b/cmd/devp2p/discv5cmd.go index 298196034b58..343e2a0d5d42 100644 --- a/cmd/devp2p/discv5cmd.go +++ b/cmd/devp2p/discv5cmd.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/devp2p/internal/v5test" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/p2p/discover" "github.com/urfave/cli/v2" ) @@ -42,18 +43,21 @@ var ( Name: "ping", Usage: "Sends ping to a node", Action: discv5Ping, + Flags: discoveryNodeFlags, } discv5ResolveCommand = &cli.Command{ Name: "resolve", Usage: "Finds a node in the DHT", Action: discv5Resolve, - Flags: []cli.Flag{bootnodesFlag}, + Flags: discoveryNodeFlags, } discv5CrawlCommand = &cli.Command{ Name: "crawl", Usage: "Updates a nodes.json file with random nodes found in the DHT", Action: discv5Crawl, - Flags: []cli.Flag{bootnodesFlag, crawlTimeoutFlag}, + Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{ + crawlTimeoutFlag, + }), } discv5TestCommand = &cli.Command{ Name: "test", @@ -70,12 +74,7 @@ var ( Name: "listen", Usage: "Runs a node", Action: discv5Listen, - Flags: []cli.Flag{ - bootnodesFlag, - nodekeyFlag, - nodedbFlag, - listenAddrFlag, - }, + Flags: discoveryNodeFlags, } ) @@ -137,7 +136,7 @@ func discv5Listen(ctx *cli.Context) error { // startV5 starts an ephemeral discovery v5 node. func startV5(ctx *cli.Context) *discover.UDPv5 { ln, config := makeDiscoveryConfig(ctx) - socket := listen(ln, ctx.String(listenAddrFlag.Name)) + socket := listen(ctx, ln) disc, err := discover.ListenV5(socket, ln, config) if err != nil { exit(err) From f20eba426a1a871f98d0d988bfd51767364650b7 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Wed, 7 Dec 2022 14:02:14 +0100 Subject: [PATCH 413/715] graphql, node, rpc: improve HTTP write timeout handling (#25457) Here we add special handling for sending an error response when the write timeout of the HTTP server is just about to expire. This is surprisingly difficult to get right, since is must be ensured that all output is fully flushed in time, which needs support from multiple levels of the RPC handler stack: The timeout response can't use chunked transfer-encoding because there is no way to write the final terminating chunk. net/http writes it when the topmost handler returns, but the timeout will already be over by the time that happens. We decided to disable chunked encoding by setting content-length explicitly. Gzip compression must also be disabled for timeout responses because we don't know the true content-length before compressing all output, i.e. compression would reintroduce chunked transfer-encoding. --- graphql/graphql_test.go | 9 +- graphql/service.go | 65 +++++++-- node/api_test.go | 3 + node/node_test.go | 13 +- node/rpcstack.go | 100 +++++++++++-- node/rpcstack_test.go | 220 +++++++++++++++++++++++++++-- p2p/simulations/adapters/inproc.go | 2 +- rpc/client.go | 5 +- rpc/errors.go | 5 + rpc/handler.go | 142 +++++++++++++++++-- rpc/http.go | 73 +++++++++- rpc/json.go | 26 ++-- rpc/server.go | 3 +- rpc/subscription.go | 6 +- rpc/types.go | 4 +- rpc/websocket.go | 10 +- 16 files changed, 606 insertions(+), 80 deletions(-) diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 491c73152113..46acd1529342 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -321,10 +321,11 @@ func TestGraphQLTransactionLogs(t *testing.T) { func createNode(t *testing.T) *node.Node { stack, err := node.New(&node.Config{ - HTTPHost: "127.0.0.1", - HTTPPort: 0, - WSHost: "127.0.0.1", - WSPort: 0, + HTTPHost: "127.0.0.1", + HTTPPort: 0, + WSHost: "127.0.0.1", + WSPort: 0, + HTTPTimeouts: node.DefaultConfig.HTTPTimeouts, }) if err != nil { t.Fatalf("could not create node: %v", err) diff --git a/graphql/service.go b/graphql/service.go index 684fdc71268d..4392dd83e688 100644 --- a/graphql/service.go +++ b/graphql/service.go @@ -20,12 +20,16 @@ import ( "context" "encoding/json" "net/http" + "strconv" + "sync" "time" "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/rpc" "github.com/graph-gophers/graphql-go" + gqlErrors "github.com/graph-gophers/graphql-go/errors" ) type handler struct { @@ -43,21 +47,60 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second) + var ( + ctx = r.Context() + responded sync.Once + timer *time.Timer + cancel context.CancelFunc + ) + ctx, cancel = context.WithCancel(ctx) defer cancel() - response := h.Schema.Exec(ctx, params.Query, params.OperationName, params.Variables) - responseJSON, err := json.Marshal(response) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - if len(response.Errors) > 0 { - w.WriteHeader(http.StatusBadRequest) + if timeout, ok := rpc.ContextRequestTimeout(ctx); ok { + timer = time.AfterFunc(timeout, func() { + responded.Do(func() { + // Cancel request handling. + cancel() + + // Create the timeout response. + response := &graphql.Response{ + Errors: []*gqlErrors.QueryError{{Message: "request timed out"}}, + } + responseJSON, err := json.Marshal(response) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Setting this disables gzip compression in package node. + w.Header().Set("transfer-encoding", "identity") + + // Flush the response. Since we are writing close to the response timeout, + // chunked transfer encoding must be disabled by setting content-length. + w.Header().Set("content-type", "application/json") + w.Header().Set("content-length", strconv.Itoa(len(responseJSON))) + w.Write(responseJSON) + if flush, ok := w.(http.Flusher); ok { + flush.Flush() + } + }) + }) } - w.Header().Set("Content-Type", "application/json") - w.Write(responseJSON) + response := h.Schema.Exec(ctx, params.Query, params.OperationName, params.Variables) + timer.Stop() + responded.Do(func() { + responseJSON, err := json.Marshal(response) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if len(response.Errors) > 0 { + w.WriteHeader(http.StatusBadRequest) + } + w.Header().Set("Content-Type", "application/json") + w.Write(responseJSON) + }) } // New constructs a new GraphQL service instance. diff --git a/node/api_test.go b/node/api_test.go index d76cb943e4ee..8761c4883ef8 100644 --- a/node/api_test.go +++ b/node/api_test.go @@ -252,6 +252,9 @@ func TestStartRPC(t *testing.T) { config := test.cfg // config.Logger = testlog.Logger(t, log.LvlDebug) config.P2P.NoDiscovery = true + if config.HTTPTimeouts == (rpc.HTTPTimeouts{}) { + config.HTTPTimeouts = rpc.DefaultHTTPTimeouts + } // Create Node. stack, err := New(&config) diff --git a/node/node_test.go b/node/node_test.go index 7c76e21f6baf..560d487fa823 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -559,13 +559,13 @@ func (test rpcPrefixTest) check(t *testing.T, node *Node) { } for _, path := range test.wantHTTP { - resp := rpcRequest(t, httpBase+path) + resp := rpcRequest(t, httpBase+path, testMethod) if resp.StatusCode != 200 { t.Errorf("Error: %s: bad status code %d, want 200", path, resp.StatusCode) } } for _, path := range test.wantNoHTTP { - resp := rpcRequest(t, httpBase+path) + resp := rpcRequest(t, httpBase+path, testMethod) if resp.StatusCode != 404 { t.Errorf("Error: %s: bad status code %d, want 404", path, resp.StatusCode) } @@ -586,10 +586,11 @@ func (test rpcPrefixTest) check(t *testing.T, node *Node) { func createNode(t *testing.T, httpPort, wsPort int) *Node { conf := &Config{ - HTTPHost: "127.0.0.1", - HTTPPort: httpPort, - WSHost: "127.0.0.1", - WSPort: wsPort, + HTTPHost: "127.0.0.1", + HTTPPort: httpPort, + WSHost: "127.0.0.1", + WSPort: wsPort, + HTTPTimeouts: rpc.DefaultHTTPTimeouts, } node, err := New(conf) if err != nil { diff --git a/node/rpcstack.go b/node/rpcstack.go index 8244c892ff50..97d591642c09 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -24,6 +24,7 @@ import ( "net" "net/http" "sort" + "strconv" "strings" "sync" "sync/atomic" @@ -196,6 +197,7 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { } return } + // if http-rpc is enabled, try to serve request rpc := h.httpHandler.Load().(*rpcHandler) if rpc != nil { @@ -462,17 +464,94 @@ var gzPool = sync.Pool{ } type gzipResponseWriter struct { - io.Writer - http.ResponseWriter + resp http.ResponseWriter + + gz *gzip.Writer + contentLength uint64 // total length of the uncompressed response + written uint64 // amount of written bytes from the uncompressed response + hasLength bool // true if uncompressed response had Content-Length + inited bool // true after init was called for the first time +} + +// init runs just before response headers are written. Among other things, this function +// also decides whether compression will be applied at all. +func (w *gzipResponseWriter) init() { + if w.inited { + return + } + w.inited = true + + hdr := w.resp.Header() + length := hdr.Get("content-length") + if len(length) > 0 { + if n, err := strconv.ParseUint(length, 10, 64); err != nil { + w.hasLength = true + w.contentLength = n + } + } + + // Setting Transfer-Encoding to "identity" explicitly disables compression. net/http + // also recognizes this header value and uses it to disable "chunked" transfer + // encoding, trimming the header from the response. This means downstream handlers can + // set this without harm, even if they aren't wrapped by newGzipHandler. + // + // In go-ethereum, we use this signal to disable compression for certain error + // responses which are flushed out close to the write deadline of the response. For + // these cases, we want to avoid chunked transfer encoding and compression because + // they require additional output that may not get written in time. + passthrough := hdr.Get("transfer-encoding") == "identity" + if !passthrough { + w.gz = gzPool.Get().(*gzip.Writer) + w.gz.Reset(w.resp) + hdr.Del("content-length") + hdr.Set("content-encoding", "gzip") + } +} + +func (w *gzipResponseWriter) Header() http.Header { + return w.resp.Header() } func (w *gzipResponseWriter) WriteHeader(status int) { - w.Header().Del("Content-Length") - w.ResponseWriter.WriteHeader(status) + w.init() + w.resp.WriteHeader(status) } func (w *gzipResponseWriter) Write(b []byte) (int, error) { - return w.Writer.Write(b) + w.init() + + if w.gz == nil { + // Compression is disabled. + return w.resp.Write(b) + } + + n, err := w.gz.Write(b) + w.written += uint64(n) + if w.hasLength && w.written >= w.contentLength { + // The HTTP handler has finished writing the entire uncompressed response. Close + // the gzip stream to ensure the footer will be seen by the client in case the + // response is flushed after this call to write. + err = w.gz.Close() + } + return n, err +} + +func (w *gzipResponseWriter) Flush() { + if w.gz != nil { + w.gz.Flush() + } + if f, ok := w.resp.(http.Flusher); ok { + f.Flush() + } +} + +func (w *gzipResponseWriter) close() { + if w.gz == nil { + return + } + w.gz.Close() + gzPool.Put(w.gz) + w.gz = nil } func newGzipHandler(next http.Handler) http.Handler { @@ -482,15 +561,10 @@ func newGzipHandler(next http.Handler) http.Handler { return } - w.Header().Set("Content-Encoding", "gzip") - - gz := gzPool.Get().(*gzip.Writer) - defer gzPool.Put(gz) - - gz.Reset(w) - defer gz.Close() + wrapper := &gzipResponseWriter{resp: w} + defer wrapper.close() - next.ServeHTTP(&gzipResponseWriter{ResponseWriter: w, Writer: gz}, r) + next.ServeHTTP(wrapper, r) }) } diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index ebc253800623..795bc93c8386 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -19,7 +19,9 @@ package node import ( "bytes" "fmt" + "io" "net/http" + "net/http/httptest" "net/url" "strconv" "strings" @@ -34,29 +36,31 @@ import ( "github.com/stretchr/testify/assert" ) +const testMethod = "rpc_modules" + // TestCorsHandler makes sure CORS are properly handled on the http server. func TestCorsHandler(t *testing.T) { - srv := createAndStartServer(t, &httpConfig{CorsAllowedOrigins: []string{"test", "test.com"}}, false, &wsConfig{}) + srv := createAndStartServer(t, &httpConfig{CorsAllowedOrigins: []string{"test", "test.com"}}, false, &wsConfig{}, nil) defer srv.stop() url := "http://" + srv.listenAddr() - resp := rpcRequest(t, url, "origin", "test.com") + resp := rpcRequest(t, url, testMethod, "origin", "test.com") assert.Equal(t, "test.com", resp.Header.Get("Access-Control-Allow-Origin")) - resp2 := rpcRequest(t, url, "origin", "bad") + resp2 := rpcRequest(t, url, testMethod, "origin", "bad") assert.Equal(t, "", resp2.Header.Get("Access-Control-Allow-Origin")) } // TestVhosts makes sure vhosts are properly handled on the http server. func TestVhosts(t *testing.T) { - srv := createAndStartServer(t, &httpConfig{Vhosts: []string{"test"}}, false, &wsConfig{}) + srv := createAndStartServer(t, &httpConfig{Vhosts: []string{"test"}}, false, &wsConfig{}, nil) defer srv.stop() url := "http://" + srv.listenAddr() - resp := rpcRequest(t, url, "host", "test") + resp := rpcRequest(t, url, testMethod, "host", "test") assert.Equal(t, resp.StatusCode, http.StatusOK) - resp2 := rpcRequest(t, url, "host", "bad") + resp2 := rpcRequest(t, url, testMethod, "host", "bad") assert.Equal(t, resp2.StatusCode, http.StatusForbidden) } @@ -145,7 +149,7 @@ func TestWebsocketOrigins(t *testing.T) { }, } for _, tc := range tests { - srv := createAndStartServer(t, &httpConfig{}, true, &wsConfig{Origins: splitAndTrim(tc.spec)}) + srv := createAndStartServer(t, &httpConfig{}, true, &wsConfig{Origins: splitAndTrim(tc.spec)}, nil) url := fmt.Sprintf("ws://%v", srv.listenAddr()) for _, origin := range tc.expOk { if err := wsRequest(t, url, "Origin", origin); err != nil { @@ -231,11 +235,14 @@ func Test_checkPath(t *testing.T) { } } -func createAndStartServer(t *testing.T, conf *httpConfig, ws bool, wsConf *wsConfig) *httpServer { +func createAndStartServer(t *testing.T, conf *httpConfig, ws bool, wsConf *wsConfig, timeouts *rpc.HTTPTimeouts) *httpServer { t.Helper() - srv := newHTTPServer(testlog.Logger(t, log.LvlDebug), rpc.DefaultHTTPTimeouts) - assert.NoError(t, srv.enableRPC(nil, *conf)) + if timeouts == nil { + timeouts = &rpc.DefaultHTTPTimeouts + } + srv := newHTTPServer(testlog.Logger(t, log.LvlDebug), *timeouts) + assert.NoError(t, srv.enableRPC(apis(), *conf)) if ws { assert.NoError(t, srv.enableWS(nil, *wsConf)) } @@ -266,16 +273,33 @@ func wsRequest(t *testing.T, url string, extraHeaders ...string) error { } // rpcRequest performs a JSON-RPC request to the given URL. -func rpcRequest(t *testing.T, url string, extraHeaders ...string) *http.Response { +func rpcRequest(t *testing.T, url, method string, extraHeaders ...string) *http.Response { + t.Helper() + + body := fmt.Sprintf(`{"jsonrpc":"2.0","id":1,"method":"%s","params":[]}`, method) + return baseRpcRequest(t, url, body, extraHeaders...) +} + +func batchRpcRequest(t *testing.T, url string, methods []string, extraHeaders ...string) *http.Response { + reqs := make([]string, len(methods)) + for i, m := range methods { + reqs[i] = fmt.Sprintf(`{"jsonrpc":"2.0","id":1,"method":"%s","params":[]}`, m) + } + body := fmt.Sprintf(`[%s]`, strings.Join(reqs, ",")) + return baseRpcRequest(t, url, body, extraHeaders...) +} + +func baseRpcRequest(t *testing.T, url, bodyStr string, extraHeaders ...string) *http.Response { t.Helper() // Create the request. - body := bytes.NewReader([]byte(`{"jsonrpc":"2.0","id":1,"method":"rpc_modules","params":[]}`)) + body := bytes.NewReader([]byte(bodyStr)) req, err := http.NewRequest("POST", url, body) if err != nil { t.Fatal("could not create http request:", err) } req.Header.Set("content-type", "application/json") + req.Header.Set("accept-encoding", "identity") // Apply extra headers. if len(extraHeaders)%2 != 0 { @@ -315,7 +339,7 @@ func TestJWT(t *testing.T) { return ss } srv := createAndStartServer(t, &httpConfig{jwtSecret: []byte("secret")}, - true, &wsConfig{Origins: []string{"*"}, jwtSecret: []byte("secret")}) + true, &wsConfig{Origins: []string{"*"}, jwtSecret: []byte("secret")}, nil) wsUrl := fmt.Sprintf("ws://%v", srv.listenAddr()) htUrl := fmt.Sprintf("http://%v", srv.listenAddr()) @@ -348,7 +372,7 @@ func TestJWT(t *testing.T) { t.Errorf("test %d-ws, token '%v': expected ok, got %v", i, token, err) } token = tokenFn() - if resp := rpcRequest(t, htUrl, "Authorization", token); resp.StatusCode != 200 { + if resp := rpcRequest(t, htUrl, testMethod, "Authorization", token); resp.StatusCode != 200 { t.Errorf("test %d-http, token '%v': expected ok, got %v", i, token, resp.StatusCode) } } @@ -414,10 +438,176 @@ func TestJWT(t *testing.T) { } token = tokenFn() - resp := rpcRequest(t, htUrl, "Authorization", token) + resp := rpcRequest(t, htUrl, testMethod, "Authorization", token) if resp.StatusCode != http.StatusUnauthorized { t.Errorf("tc %d-http, token '%v': expected not to allow, got %v", i, token, resp.StatusCode) } } srv.stop() } + +func TestGzipHandler(t *testing.T) { + type gzipTest struct { + name string + handler http.HandlerFunc + status int + isGzip bool + header map[string]string + } + tests := []gzipTest{ + { + name: "Write", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("response")) + }, + isGzip: true, + status: 200, + }, + { + name: "WriteHeader", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("x-foo", "bar") + w.WriteHeader(205) + w.Write([]byte("response")) + }, + isGzip: true, + status: 205, + header: map[string]string{"x-foo": "bar"}, + }, + { + name: "WriteContentLength", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("content-length", "8") + w.Write([]byte("response")) + }, + isGzip: true, + status: 200, + }, + { + name: "Flush", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("res")) + w.(http.Flusher).Flush() + w.Write([]byte("ponse")) + }, + isGzip: true, + status: 200, + }, + { + name: "disable", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("transfer-encoding", "identity") + w.Header().Set("x-foo", "bar") + w.Write([]byte("response")) + }, + isGzip: false, + status: 200, + header: map[string]string{"x-foo": "bar"}, + }, + { + name: "disable-WriteHeader", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("transfer-encoding", "identity") + w.Header().Set("x-foo", "bar") + w.WriteHeader(205) + w.Write([]byte("response")) + }, + isGzip: false, + status: 205, + header: map[string]string{"x-foo": "bar"}, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + srv := httptest.NewServer(newGzipHandler(test.handler)) + defer srv.Close() + + resp, err := http.Get(srv.URL) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + + content, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + wasGzip := resp.Uncompressed + + if string(content) != "response" { + t.Fatalf("wrong response content %q", content) + } + if wasGzip != test.isGzip { + t.Fatalf("response gzipped == %t, want %t", wasGzip, test.isGzip) + } + if resp.StatusCode != test.status { + t.Fatalf("response status == %d, want %d", resp.StatusCode, test.status) + } + for name, expectedValue := range test.header { + if v := resp.Header.Get(name); v != expectedValue { + t.Fatalf("response header %s == %s, want %s", name, v, expectedValue) + } + } + }) + } +} + +func TestHTTPWriteTimeout(t *testing.T) { + const ( + timeoutRes = `{"jsonrpc":"2.0","id":1,"error":{"code":-32002,"message":"request timed out"}}` + greetRes = `{"jsonrpc":"2.0","id":1,"result":"Hello"}` + ) + // Set-up server + timeouts := rpc.DefaultHTTPTimeouts + timeouts.WriteTimeout = time.Second + srv := createAndStartServer(t, &httpConfig{Modules: []string{"test"}}, false, &wsConfig{}, &timeouts) + url := fmt.Sprintf("http://%v", srv.listenAddr()) + + // Send normal request + t.Run("message", func(t *testing.T) { + resp := rpcRequest(t, url, "test_sleep") + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + if string(body) != timeoutRes { + t.Errorf("wrong response. have %s, want %s", string(body), timeoutRes) + } + }) + + // Batch request + t.Run("batch", func(t *testing.T) { + want := fmt.Sprintf("[%s,%s,%s]", greetRes, timeoutRes, timeoutRes) + resp := batchRpcRequest(t, url, []string{"test_greet", "test_sleep", "test_greet"}) + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + if string(body) != want { + t.Errorf("wrong response. have %s, want %s", string(body), want) + } + }) +} + +func apis() []rpc.API { + return []rpc.API{ + { + Namespace: "test", + Service: &testService{}, + }, + } +} + +type testService struct{} + +func (s *testService) Greet() string { + return "Hello" +} + +func (s *testService) Sleep() { + time.Sleep(1500 * time.Millisecond) +} diff --git a/p2p/simulations/adapters/inproc.go b/p2p/simulations/adapters/inproc.go index 1cb26a8ea05a..36b5286517ae 100644 --- a/p2p/simulations/adapters/inproc.go +++ b/p2p/simulations/adapters/inproc.go @@ -206,7 +206,7 @@ func (sn *SimNode) ServeRPC(conn *websocket.Conn) error { if err != nil { return err } - codec := rpc.NewFuncCodec(conn, conn.WriteJSON, conn.ReadJSON) + codec := rpc.NewFuncCodec(conn, func(v any, _ bool) error { return conn.WriteJSON(v) }, conn.ReadJSON) handler.ServeCodec(codec, 0) return nil } diff --git a/rpc/client.go b/rpc/client.go index d89aa69277c7..a509cb2e0fa0 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -527,7 +527,7 @@ func (c *Client) write(ctx context.Context, msg interface{}, retry bool) error { return err } } - err := c.writeConn.writeJSON(ctx, msg) + err := c.writeConn.writeJSON(ctx, msg, false) if err != nil { c.writeConn = nil if !retry { @@ -660,7 +660,8 @@ func (c *Client) read(codec ServerCodec) { for { msgs, batch, err := codec.readBatch() if _, ok := err.(*json.SyntaxError); ok { - codec.writeJSON(context.Background(), errorMessage(&parseError{err.Error()})) + msg := errorMessage(&parseError{err.Error()}) + codec.writeJSON(context.Background(), msg, true) } if err != nil { c.readErr <- err diff --git a/rpc/errors.go b/rpc/errors.go index 9a19e9fe67f5..7188332d551e 100644 --- a/rpc/errors.go +++ b/rpc/errors.go @@ -60,10 +60,15 @@ var ( const ( errcodeDefault = -32000 errcodeNotificationsUnsupported = -32001 + errcodeTimeout = -32002 errcodePanic = -32603 errcodeMarshalError = -32603 ) +const ( + errMsgTimeout = "request timed out" +) + type methodNotFoundError struct{ method string } func (e *methodNotFoundError) ErrorCode() int { return -32601 } diff --git a/rpc/handler.go b/rpc/handler.go index f3052e7eb822..c2e7d7dc08c6 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -91,12 +91,83 @@ func newHandler(connCtx context.Context, conn jsonWriter, idgen func() ID, reg * return h } +// batchCallBuffer manages in progress call messages and their responses during a batch +// call. Calls need to be synchronized between the processing and timeout-triggering +// goroutines. +type batchCallBuffer struct { + mutex sync.Mutex + calls []*jsonrpcMessage + resp []*jsonrpcMessage + wrote bool +} + +// nextCall returns the next unprocessed message. +func (b *batchCallBuffer) nextCall() *jsonrpcMessage { + b.mutex.Lock() + defer b.mutex.Unlock() + + if len(b.calls) == 0 { + return nil + } + // The popping happens in `pushAnswer`. The in progress call is kept + // so we can return an error for it in case of timeout. + msg := b.calls[0] + return msg +} + +// pushResponse adds the response to last call returned by nextCall. +func (b *batchCallBuffer) pushResponse(answer *jsonrpcMessage) { + b.mutex.Lock() + defer b.mutex.Unlock() + + if answer != nil { + b.resp = append(b.resp, answer) + } + b.calls = b.calls[1:] +} + +// write sends the responses. +func (b *batchCallBuffer) write(ctx context.Context, conn jsonWriter) { + b.mutex.Lock() + defer b.mutex.Unlock() + + b.doWrite(ctx, conn, false) +} + +// timeout sends the responses added so far. For the remaining unanswered call +// messages, it sends a timeout error response. +func (b *batchCallBuffer) timeout(ctx context.Context, conn jsonWriter) { + b.mutex.Lock() + defer b.mutex.Unlock() + + for _, msg := range b.calls { + if !msg.isNotification() { + resp := msg.errorResponse(&internalServerError{errcodeTimeout, errMsgTimeout}) + b.resp = append(b.resp, resp) + } + } + b.doWrite(ctx, conn, true) +} + +// doWrite actually writes the response. +// This assumes b.mutex is held. +func (b *batchCallBuffer) doWrite(ctx context.Context, conn jsonWriter, isErrorResponse bool) { + if b.wrote { + return + } + b.wrote = true // can only write once + if len(b.resp) > 0 { + conn.writeJSON(ctx, b.resp, isErrorResponse) + } +} + // handleBatch executes all messages in a batch and returns the responses. func (h *handler) handleBatch(msgs []*jsonrpcMessage) { // Emit error response for empty batches: if len(msgs) == 0 { h.startCallProc(func(cp *callProc) { - h.conn.writeJSON(cp.ctx, errorMessage(&invalidRequestError{"empty batch"})) + resp := errorMessage(&invalidRequestError{"empty batch"}) + h.conn.writeJSON(cp.ctx, resp, true) }) return } @@ -113,16 +184,42 @@ func (h *handler) handleBatch(msgs []*jsonrpcMessage) { } // Process calls on a goroutine because they may block indefinitely: h.startCallProc(func(cp *callProc) { - answers := make([]*jsonrpcMessage, 0, len(msgs)) - for _, msg := range calls { - if answer := h.handleCallMsg(cp, msg); answer != nil { - answers = append(answers, answer) + var ( + timer *time.Timer + cancel context.CancelFunc + callBuffer = &batchCallBuffer{calls: calls, resp: make([]*jsonrpcMessage, 0, len(calls))} + ) + + cp.ctx, cancel = context.WithCancel(cp.ctx) + defer cancel() + + // Cancel the request context after timeout and send an error response. Since the + // currently-running method might not return immediately on timeout, we must wait + // for the timeout concurrently with processing the request. + if timeout, ok := ContextRequestTimeout(cp.ctx); ok { + timer = time.AfterFunc(timeout, func() { + cancel() + callBuffer.timeout(cp.ctx, h.conn) + }) + } + + for { + // No need to handle rest of calls if timed out. + if cp.ctx.Err() != nil { + break } + msg := callBuffer.nextCall() + if msg == nil { + break + } + resp := h.handleCallMsg(cp, msg) + callBuffer.pushResponse(resp) } - h.addSubscriptions(cp.notifiers) - if len(answers) > 0 { - h.conn.writeJSON(cp.ctx, answers) + if timer != nil { + timer.Stop() } + callBuffer.write(cp.ctx, h.conn) + h.addSubscriptions(cp.notifiers) for _, n := range cp.notifiers { n.activate() } @@ -135,10 +232,36 @@ func (h *handler) handleMsg(msg *jsonrpcMessage) { return } h.startCallProc(func(cp *callProc) { + var ( + responded sync.Once + timer *time.Timer + cancel context.CancelFunc + ) + cp.ctx, cancel = context.WithCancel(cp.ctx) + defer cancel() + + // Cancel the request context after timeout and send an error response. Since the + // running method might not return immediately on timeout, we must wait for the + // timeout concurrently with processing the request. + if timeout, ok := ContextRequestTimeout(cp.ctx); ok { + timer = time.AfterFunc(timeout, func() { + cancel() + responded.Do(func() { + resp := msg.errorResponse(&internalServerError{errcodeTimeout, errMsgTimeout}) + h.conn.writeJSON(cp.ctx, resp, true) + }) + }) + } + answer := h.handleCallMsg(cp, msg) + if timer != nil { + timer.Stop() + } h.addSubscriptions(cp.notifiers) if answer != nil { - h.conn.writeJSON(cp.ctx, answer) + responded.Do(func() { + h.conn.writeJSON(cp.ctx, answer, false) + }) } for _, n := range cp.notifiers { n.activate() @@ -334,7 +457,6 @@ func (h *handler) handleCall(cp *callProc, msg *jsonrpcMessage) *jsonrpcMessage } start := time.Now() answer := h.runMethod(cp.ctx, msg, callb, args) - // Collect the statistics for RPC calls if metrics is enabled. // We only care about pure rpc call. Filter out subscription. if callb != h.unsubscribeCb { diff --git a/rpc/http.go b/rpc/http.go index 0ba6588f9906..bbabe15bada3 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -23,9 +23,11 @@ import ( "errors" "fmt" "io" + "math" "mime" "net/http" "net/url" + "strconv" "sync" "time" ) @@ -52,7 +54,7 @@ type httpConn struct { // and some methods don't work. The panic() stubs here exist to ensure // this special treatment is correct. -func (hc *httpConn) writeJSON(context.Context, interface{}) error { +func (hc *httpConn) writeJSON(context.Context, interface{}, bool) error { panic("writeJSON called on httpConn") } @@ -256,7 +258,42 @@ type httpServerConn struct { func newHTTPServerConn(r *http.Request, w http.ResponseWriter) ServerCodec { body := io.LimitReader(r.Body, maxRequestContentLength) conn := &httpServerConn{Reader: body, Writer: w, r: r} - return NewCodec(conn) + + encoder := func(v any, isErrorResponse bool) error { + if !isErrorResponse { + return json.NewEncoder(conn).Encode(v) + } + + // It's an error response and requires special treatment. + // + // In case of a timeout error, the response must be written before the HTTP + // server's write timeout occurs. So we need to flush the response. The + // Content-Length header also needs to be set to ensure the client knows + // when it has the full response. + encdata, err := json.Marshal(v) + if err != nil { + return err + } + w.Header().Set("content-length", strconv.Itoa(len(encdata))) + + // If this request is wrapped in a handler that might remove Content-Length (such + // as the automatic gzip we do in package node), we need to ensure the HTTP server + // doesn't perform chunked encoding. In case WriteTimeout is reached, the chunked + // encoding might not be finished correctly, and some clients do not like it when + // the final chunk is missing. + w.Header().Set("transfer-encoding", "identity") + + _, err = w.Write(encdata) + if f, ok := w.(http.Flusher); ok { + f.Flush() + } + return err + } + + dec := json.NewDecoder(conn) + dec.UseNumber() + + return NewFuncCodec(conn, encoder, dec.Decode) } // Close does nothing and always returns nil. @@ -326,3 +363,35 @@ func validateRequest(r *http.Request) (int, error) { err := fmt.Errorf("invalid content type, only %s is supported", contentType) return http.StatusUnsupportedMediaType, err } + +// ContextRequestTimeout returns the request timeout derived from the given context. +func ContextRequestTimeout(ctx context.Context) (time.Duration, bool) { + timeout := time.Duration(math.MaxInt64) + hasTimeout := false + setTimeout := func(d time.Duration) { + if d < timeout { + timeout = d + hasTimeout = true + } + } + + if deadline, ok := ctx.Deadline(); ok { + setTimeout(time.Until(deadline)) + } + + // If the context is an HTTP request context, use the server's WriteTimeout. + httpSrv, ok := ctx.Value(http.ServerContextKey).(*http.Server) + if ok && httpSrv.WriteTimeout > 0 { + wt := httpSrv.WriteTimeout + // When a write timeout is configured, we need to send the response message before + // the HTTP server cuts connection. So our internal timeout must be earlier than + // the server's true timeout. + // + // Note: Timeouts are sanitized to be a minimum of 1 second. + // Also see issue: https://github.com/golang/go/issues/47229 + wt -= 100 * time.Millisecond + setTimeout(wt) + } + + return timeout, hasTimeout +} diff --git a/rpc/json.go b/rpc/json.go index 1064939ff8b6..8a3b162cabbc 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -168,18 +168,22 @@ type ConnRemoteAddr interface { // support for parsing arguments and serializing (result) objects. type jsonCodec struct { remote string - closer sync.Once // close closed channel once - closeCh chan interface{} // closed on Close - decode func(v interface{}) error // decoder to allow multiple transports - encMu sync.Mutex // guards the encoder - encode func(v interface{}) error // encoder to allow multiple transports + closer sync.Once // close closed channel once + closeCh chan interface{} // closed on Close + decode decodeFunc // decoder to allow multiple transports + encMu sync.Mutex // guards the encoder + encode encodeFunc // encoder to allow multiple transports conn deadlineCloser } +type encodeFunc = func(v interface{}, isErrorResponse bool) error + +type decodeFunc = func(v interface{}) error + // NewFuncCodec creates a codec which uses the given functions to read and write. If conn // implements ConnRemoteAddr, log messages will use it to include the remote address of // the connection. -func NewFuncCodec(conn deadlineCloser, encode, decode func(v interface{}) error) ServerCodec { +func NewFuncCodec(conn deadlineCloser, encode encodeFunc, decode decodeFunc) ServerCodec { codec := &jsonCodec{ closeCh: make(chan interface{}), encode: encode, @@ -198,7 +202,11 @@ func NewCodec(conn Conn) ServerCodec { enc := json.NewEncoder(conn) dec := json.NewDecoder(conn) dec.UseNumber() - return NewFuncCodec(conn, enc.Encode, dec.Decode) + + encode := func(v interface{}, isErrorResponse bool) error { + return enc.Encode(v) + } + return NewFuncCodec(conn, encode, dec.Decode) } func (c *jsonCodec) peerInfo() PeerInfo { @@ -228,7 +236,7 @@ func (c *jsonCodec) readBatch() (messages []*jsonrpcMessage, batch bool, err err return messages, batch, nil } -func (c *jsonCodec) writeJSON(ctx context.Context, v interface{}) error { +func (c *jsonCodec) writeJSON(ctx context.Context, v interface{}, isErrorResponse bool) error { c.encMu.Lock() defer c.encMu.Unlock() @@ -237,7 +245,7 @@ func (c *jsonCodec) writeJSON(ctx context.Context, v interface{}) error { deadline = time.Now().Add(defaultWriteTimeout) } c.conn.SetWriteDeadline(deadline) - return c.encode(v) + return c.encode(v, isErrorResponse) } func (c *jsonCodec) close() { diff --git a/rpc/server.go b/rpc/server.go index fe162d5a428e..9c72c26d7b94 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -125,7 +125,8 @@ func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { reqs, batch, err := codec.readBatch() if err != nil { if err != io.EOF { - codec.writeJSON(ctx, errorMessage(&invalidMessageError{"parse error"})) + resp := errorMessage(&invalidMessageError{"parse error"}) + codec.writeJSON(ctx, resp, true) } return } diff --git a/rpc/subscription.go b/rpc/subscription.go index d7ba784fc532..334ead3ace4d 100644 --- a/rpc/subscription.go +++ b/rpc/subscription.go @@ -175,11 +175,13 @@ func (n *Notifier) activate() error { func (n *Notifier) send(sub *Subscription, data json.RawMessage) error { params, _ := json.Marshal(&subscriptionResult{ID: string(sub.ID), Result: data}) ctx := context.Background() - return n.h.conn.writeJSON(ctx, &jsonrpcMessage{ + + msg := &jsonrpcMessage{ Version: vsn, Method: n.namespace + notificationMethodSuffix, Params: params, - }) + } + return n.h.conn.writeJSON(ctx, msg, false) } // A Subscription is created by a notifier and tied to that notifier. The client can use diff --git a/rpc/types.go b/rpc/types.go index e7158796ead0..9dda067e7f2f 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -51,7 +51,9 @@ type ServerCodec interface { // jsonWriter can write JSON messages to its underlying connection. // Implementations must be safe for concurrent use. type jsonWriter interface { - writeJSON(context.Context, interface{}) error + // writeJSON writes a message to the connection. + writeJSON(ctx context.Context, msg interface{}, isError bool) error + // Closed returns a channel which is closed when the connection is closed. closed() <-chan interface{} // RemoteAddr returns the peer address of the connection. diff --git a/rpc/websocket.go b/rpc/websocket.go index 21e446e9f816..0ac2a2792d5a 100644 --- a/rpc/websocket.go +++ b/rpc/websocket.go @@ -287,8 +287,12 @@ func newWebsocketCodec(conn *websocket.Conn, host string, req http.Header) Serve conn.SetReadDeadline(time.Time{}) return nil }) + + encode := func(v interface{}, isErrorResponse bool) error { + return conn.WriteJSON(v) + } wc := &websocketCodec{ - jsonCodec: NewFuncCodec(conn, conn.WriteJSON, conn.ReadJSON).(*jsonCodec), + jsonCodec: NewFuncCodec(conn, encode, conn.ReadJSON).(*jsonCodec), conn: conn, pingReset: make(chan struct{}, 1), info: PeerInfo{ @@ -315,8 +319,8 @@ func (wc *websocketCodec) peerInfo() PeerInfo { return wc.info } -func (wc *websocketCodec) writeJSON(ctx context.Context, v interface{}) error { - err := wc.jsonCodec.writeJSON(ctx, v) +func (wc *websocketCodec) writeJSON(ctx context.Context, v interface{}, isError bool) error { + err := wc.jsonCodec.writeJSON(ctx, v, isError) if err == nil { // Notify pingLoop to delay the next idle ping. select { From 42212808f06881c0568bbd1bad65a3cca1fde52b Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Thu, 8 Dec 2022 00:22:04 +0900 Subject: [PATCH 414/715] p2p/nat: handle responses with alternative port in NAT-PMP (#26321) Co-authored-by: Felix Lange --- p2p/nat/natpmp.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/p2p/nat/natpmp.go b/p2p/nat/natpmp.go index c43580001e36..40f2aff44e7a 100644 --- a/p2p/nat/natpmp.go +++ b/p2p/nat/natpmp.go @@ -50,8 +50,22 @@ func (n *pmp) AddMapping(protocol string, extport, intport int, name string, lif } // Note order of port arguments is switched between our // AddMapping and the client's AddPortMapping. - _, err := n.c.AddPortMapping(strings.ToLower(protocol), intport, extport, int(lifetime/time.Second)) - return err + res, err := n.c.AddPortMapping(strings.ToLower(protocol), intport, extport, int(lifetime/time.Second)) + if err != nil { + return err + } + + // NAT-PMP maps an alternative available port number if the requested + // port is already mapped to another address and returns success. In this + // case, we return an error because there is no way to return the new port + // to the caller. + if uint16(extport) != res.MappedExternalPort { + // Destroy the mapping in NAT device. + n.c.AddPortMapping(strings.ToLower(protocol), intport, 0, 0) + return fmt.Errorf("port %d already mapped to another address (%s)", extport, protocol) + } + + return nil } func (n *pmp) DeleteMapping(protocol string, extport, intport int) (err error) { From 6891288787df7e4d342fef82d7c7581458f6b6b8 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Wed, 7 Dec 2022 17:36:54 +0100 Subject: [PATCH 415/715] core: fix state flushing for catalyst mode (#26319) The gcproc field tracks the amount of time spent processing blocks, and is used to trigger a state flush to disk when a certain threshold is reached. After the merge, single block insertion by CL is the most common source of block processing time, but this time was not added into gcproc. --- core/blockchain.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/blockchain.go b/core/blockchain.go index 992e5a0f6b47..f9b92192cc7d 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1764,6 +1764,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) stats.report(chain, it.index, dirty, setHead) if !setHead { + // After merge we expect few side chains. Simply count + // all blocks the CL gives us for GC processing time + bc.gcproc += proctime + return it.index, nil // Direct block insertion of a single block } switch status { From a9dfac0332ec7316f6797e17c44cb94f463799c7 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Thu, 8 Dec 2022 06:31:47 +0800 Subject: [PATCH 416/715] p2p/discover: improve nodesByDistance.push code (#26019) This improves readability of function 'push'. sort.Search(N, ...) will at most return N when no match, so ix should be compared with N. The previous version would compare ix with N+1 in case an additional item was appended. No bug resulted from this comparison, but it's not easy to understand why. Co-authored-by: Felix Lange --- p2p/discover/table.go | 11 ++++---- p2p/discover/table_test.go | 53 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/p2p/discover/table.go b/p2p/discover/table.go index d08f8a6c69cb..41d5ac6e34e7 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -672,15 +672,14 @@ func (h *nodesByDistance) push(n *node, maxElems int) { ix := sort.Search(len(h.entries), func(i int) bool { return enode.DistCmp(h.target, h.entries[i].ID(), n.ID()) > 0 }) + + end := len(h.entries) if len(h.entries) < maxElems { h.entries = append(h.entries, n) } - if ix == len(h.entries) { - // farther away than all nodes we already have. - // if there was room for it, the node is now the last element. - } else { - // slide existing entries down to make room - // this will overwrite the entry we just appended. + if ix < end { + // Slide existing entries down to make room. + // This will overwrite the entry we just appended. copy(h.entries[ix+1:], h.entries[ix:]) h.entries[ix] = n } diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 5f40c967fd5b..1ef63fe01019 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -396,6 +396,59 @@ func TestTable_revalidateSyncRecord(t *testing.T) { } } +func TestNodesPush(t *testing.T) { + var target enode.ID + n1 := nodeAtDistance(target, 255, intIP(1)) + n2 := nodeAtDistance(target, 254, intIP(2)) + n3 := nodeAtDistance(target, 253, intIP(3)) + perm := [][]*node{ + {n3, n2, n1}, + {n3, n1, n2}, + {n2, n3, n1}, + {n2, n1, n3}, + {n1, n3, n2}, + {n1, n2, n3}, + } + + // Insert all permutations into lists with size limit 3. + for _, nodes := range perm { + list := nodesByDistance{target: target} + for _, n := range nodes { + list.push(n, 3) + } + if !slicesEqual(list.entries, perm[0], nodeIDEqual) { + t.Fatal("not equal") + } + } + + // Insert all permutations into lists with size limit 2. + for _, nodes := range perm { + list := nodesByDistance{target: target} + for _, n := range nodes { + list.push(n, 2) + } + if !slicesEqual(list.entries, perm[0][:2], nodeIDEqual) { + t.Fatal("not equal") + } + } +} + +func nodeIDEqual(n1, n2 *node) bool { + return n1.ID() == n2.ID() +} + +func slicesEqual[T any](s1, s2 []T, check func(e1, e2 T) bool) bool { + if len(s1) != len(s2) { + return false + } + for i := range s1 { + if !check(s1[i], s2[i]) { + return false + } + } + return true +} + // gen wraps quick.Value so it's easier to use. // it generates a random value of the given value's type. func gen(typ interface{}, rand *rand.Rand) interface{} { From 890e2efca2111c790c6d5eb55e29981816ee1fe9 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 8 Dec 2022 21:40:43 +0800 Subject: [PATCH 417/715] eth, cmd: remove syncTarget from eth config (#26330) --syncTarget is a feature for development purpose in post-merge world. Previously it's added into eth.Config. But it turns out that's a stupid idea. - syncTarget is a block object, which is hard to be put in config file(large) - syncTarget is just a dev feature, doesn't make too much sense to add it in config file So I remove it from the eth config object. And it also fixes the #26328 --- cmd/geth/config.go | 8 ++++++- cmd/utils/flags.go | 44 +++++++++++++++---------------------- eth/ethconfig/config.go | 5 ----- eth/ethconfig/gen_config.go | 7 ------ 4 files changed, 25 insertions(+), 39 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index e15302544cc5..e61de4b21efb 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/scwallet" "github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/flags" @@ -165,7 +166,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { cfg.Eth.OverrideTerminalTotalDifficultyPassed = &override } - backend, _ := utils.RegisterEthService(stack, &cfg.Eth) + backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Configure log filter RPC API. filterSystem := utils.RegisterFilterAPI(stack, backend, &cfg.Eth) @@ -179,6 +180,11 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { if cfg.Ethstats.URL != "" { utils.RegisterEthStatsService(stack, backend, cfg.Ethstats.URL) } + + // Configure full-sync tester service if requested + if ctx.IsSet(utils.SyncTargetFlag.Name) && cfg.Eth.SyncMode == downloader.FullSync { + utils.RegisterFullSyncTester(stack, eth, ctx.Path(utils.SyncTargetFlag.Name)) + } return stack, backend } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5c0d984cbf16..cb7ff910d0bd 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1880,25 +1880,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.EthDiscoveryURLs = SplitAndTrim(urls) } } - if ctx.IsSet(SyncTargetFlag.Name) { - path := ctx.Path(SyncTargetFlag.Name) - if path == "" { - Fatalf("Failed to resolve file path") - } - blob, err := os.ReadFile(path) - if err != nil { - Fatalf("Failed to read block file: %v", err) - } - rlpBlob, err := hexutil.Decode(string(bytes.TrimRight(blob, "\r\n"))) - if err != nil { - Fatalf("Failed to decode block blob: %v", err) - } - var block types.Block - if err := rlp.DecodeBytes(rlpBlob, &block); err != nil { - Fatalf("Failed to decode block: %v", err) - } - cfg.SyncTarget = &block - } // Override any default configs for hard coded networks. switch { case ctx.Bool(MainnetFlag.Name): @@ -2052,13 +2033,6 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend Fatalf("Failed to register the Engine API service: %v", err) } stack.RegisterAPIs(tracers.APIs(backend.APIBackend)) - - // Register the auxiliary full-sync tester service in case the sync - // target is configured. - if cfg.SyncTarget != nil && cfg.SyncMode == downloader.FullSync { - ethcatalyst.RegisterFullSyncTester(stack, backend, cfg.SyncTarget) - log.Info("Registered full-sync tester", "number", cfg.SyncTarget.NumberU64(), "hash", cfg.SyncTarget.Hash()) - } return backend.APIBackend, backend } @@ -2090,6 +2064,24 @@ func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconf return filterSystem } +// RegisterFullSyncTester adds the full-sync tester service into node. +func RegisterFullSyncTester(stack *node.Node, eth *eth.Ethereum, path string) { + blob, err := os.ReadFile(path) + if err != nil { + Fatalf("Failed to read block file: %v", err) + } + rlpBlob, err := hexutil.Decode(string(bytes.TrimRight(blob, "\r\n"))) + if err != nil { + Fatalf("Failed to decode block blob: %v", err) + } + var block types.Block + if err := rlp.DecodeBytes(rlpBlob, &block); err != nil { + Fatalf("Failed to decode block: %v", err) + } + ethcatalyst.RegisterFullSyncTester(stack, eth, &block) + log.Info("Registered full-sync tester", "number", block.NumberU64(), "hash", block.Hash()) +} + func SetupMetrics(ctx *cli.Context) { if metrics.Enabled { log.Info("Enabling metrics collection") diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index e9651d041c3c..75606339323a 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -32,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/txpool" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/ethdb" @@ -212,10 +211,6 @@ type Config struct { // OverrideTerminalTotalDifficultyPassed (TODO: remove after the fork) OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` - - // SyncTarget defines the target block of sync. It's only used for - // development purposes. - SyncTarget *types.Block } // CreateConsensusEngine creates a consensus engine for the given chain configuration. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index a3dcf5a12f6f..514facde0a8b 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/txpool" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/miner" @@ -64,7 +63,6 @@ func (c Config) MarshalTOML() (interface{}, error) { CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` - FullSyncTarget *types.Block } var enc Config enc.Genesis = c.Genesis @@ -111,7 +109,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.CheckpointOracle = c.CheckpointOracle enc.OverrideTerminalTotalDifficulty = c.OverrideTerminalTotalDifficulty enc.OverrideTerminalTotalDifficultyPassed = c.OverrideTerminalTotalDifficultyPassed - enc.FullSyncTarget = c.SyncTarget return &enc, nil } @@ -162,7 +159,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` - FullSyncTarget *types.Block } var dec Config if err := unmarshal(&dec); err != nil { @@ -300,8 +296,5 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.OverrideTerminalTotalDifficultyPassed != nil { c.OverrideTerminalTotalDifficultyPassed = dec.OverrideTerminalTotalDifficultyPassed } - if dec.FullSyncTarget != nil { - c.SyncTarget = dec.FullSyncTarget - } return nil } From 711afbc7fd76f1f206429e26f9aa5bf98bc7b43d Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Fri, 9 Dec 2022 13:40:17 +0100 Subject: [PATCH 418/715] core,eth: add `debug_setTrieFlushInterval` to change trie flush frequency (#24785) This PR makes it possible to modify the flush interval time via RPC. On one extreme, `0s`, it would act as an archive node. If set to `1h`, means that after one hour of effective block processing time, the trie would be flushed. If one block takes 200ms, this means that a flush would occur every `5*3600=18000` blocks -- however, if the memory size of the cached states grows too large, it will flush sooner. Essentially, this makes it possible to configure the node to be more or less "archive:ish", and without restarting the node while reconfiguring it. --- core/blockchain.go | 114 ++++++++++++++++++++---------------- eth/api.go | 11 ++++ internal/web3ext/web3ext.go | 5 ++ 3 files changed, 78 insertions(+), 52 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index f9b92192cc7d..e5fd586104ab 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -169,12 +169,14 @@ type BlockChain struct { chainConfig *params.ChainConfig // Chain & network configuration cacheConfig *CacheConfig // Cache configuration for pruning - db ethdb.Database // Low level persistent database to store final content in - snaps *snapshot.Tree // Snapshot tree for fast trie leaf access - triegc *prque.Prque // Priority queue mapping block numbers to tries to gc - gcproc time.Duration // Accumulates canonical block processing for trie dumping - triedb *trie.Database // The database handler for maintaining trie nodes. - stateCache state.Database // State database to reuse between imports (contains state cache) + db ethdb.Database // Low level persistent database to store final content in + snaps *snapshot.Tree // Snapshot tree for fast trie leaf access + triegc *prque.Prque // Priority queue mapping block numbers to tries to gc + gcproc time.Duration // Accumulates canonical block processing for trie dumping + lastWrite uint64 // Last block when the state was flushed + flushInterval int64 // Time interval (processing time) after which to flush a state + triedb *trie.Database // The database handler for maintaining trie nodes. + stateCache state.Database // State database to reuse between imports (contains state cache) // txLookupLimit is the maximum number of blocks from head whose tx indices // are reserved: @@ -258,6 +260,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis cacheConfig: cacheConfig, db: db, triedb: triedb, + flushInterval: int64(cacheConfig.TrieTimeLimit), triegc: prque.New(nil), quit: make(chan struct{}), chainmu: syncx.NewClosableMutex(), @@ -1248,8 +1251,6 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ return 0, nil } -var lastWrite uint64 - // writeBlockWithoutState writes only the block and its metadata to the database, // but does not write any state. This is used to construct competing side forks // up to the point where they exceed the canonical total difficulty. @@ -1311,53 +1312,55 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. // If we're running an archive node, always flush if bc.cacheConfig.TrieDirtyDisabled { return bc.triedb.Commit(root, false, nil) - } else { - // Full but not archive node, do proper garbage collection - bc.triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive - bc.triegc.Push(root, -int64(block.NumberU64())) - - if current := block.NumberU64(); current > TriesInMemory { - // If we exceeded our memory allowance, flush matured singleton nodes to disk - var ( - nodes, imgs = bc.triedb.Size() - limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024 - ) - if nodes > limit || imgs > 4*1024*1024 { - bc.triedb.Cap(limit - ethdb.IdealBatchSize) - } - // Find the next state trie we need to commit - chosen := current - TriesInMemory - - // If we exceeded out time allowance, flush an entire trie to disk - if bc.gcproc > bc.cacheConfig.TrieTimeLimit { - // If the header is missing (canonical chain behind), we're reorging a low - // diff sidechain. Suspend committing until this operation is completed. - header := bc.GetHeaderByNumber(chosen) - if header == nil { - log.Warn("Reorg in progress, trie commit postponed", "number", chosen) - } else { - // If we're exceeding limits but haven't reached a large enough memory gap, - // warn the user that the system is becoming unstable. - if chosen < lastWrite+TriesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit { - log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/TriesInMemory) - } - // Flush an entire trie and restart the counters - bc.triedb.Commit(header.Root, true, nil) - lastWrite = chosen - bc.gcproc = 0 - } - } - // Garbage collect anything below our required write retention - for !bc.triegc.Empty() { - root, number := bc.triegc.Pop() - if uint64(-number) > chosen { - bc.triegc.Push(root, number) - break - } - bc.triedb.Dereference(root.(common.Hash)) + } + // Full but not archive node, do proper garbage collection + bc.triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive + bc.triegc.Push(root, -int64(block.NumberU64())) + + current := block.NumberU64() + // Flush limits are not considered for the first TriesInMemory blocks. + if current <= TriesInMemory { + return nil + } + // If we exceeded our memory allowance, flush matured singleton nodes to disk + var ( + nodes, imgs = bc.triedb.Size() + limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024 + ) + if nodes > limit || imgs > 4*1024*1024 { + bc.triedb.Cap(limit - ethdb.IdealBatchSize) + } + // Find the next state trie we need to commit + chosen := current - TriesInMemory + flushInterval := time.Duration(atomic.LoadInt64(&bc.flushInterval)) + // If we exceeded time allowance, flush an entire trie to disk + if bc.gcproc > flushInterval { + // If the header is missing (canonical chain behind), we're reorging a low + // diff sidechain. Suspend committing until this operation is completed. + header := bc.GetHeaderByNumber(chosen) + if header == nil { + log.Warn("Reorg in progress, trie commit postponed", "number", chosen) + } else { + // If we're exceeding limits but haven't reached a large enough memory gap, + // warn the user that the system is becoming unstable. + if chosen < bc.lastWrite+TriesInMemory && bc.gcproc >= 2*flushInterval { + log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/TriesInMemory) } + // Flush an entire trie and restart the counters + bc.triedb.Commit(header.Root, true, nil) + bc.lastWrite = chosen + bc.gcproc = 0 } } + // Garbage collect anything below our required write retention + for !bc.triegc.Empty() { + root, number := bc.triegc.Pop() + if uint64(-number) > chosen { + bc.triegc.Push(root, number) + break + } + bc.triedb.Dereference(root.(common.Hash)) + } return nil } @@ -2436,3 +2439,10 @@ func (bc *BlockChain) SetBlockValidatorAndProcessorForTesting(v Validator, p Pro bc.validator = v bc.processor = p } + +// SetTrieFlushInterval configures how often in-memory tries are persisted to disk. +// The interval is in terms of block processing time, not wall clock. +// It is thread-safe and can be called repeatedly without side effects. +func (bc *BlockChain) SetTrieFlushInterval(interval time.Duration) { + atomic.StoreInt64(&bc.flushInterval, int64(interval)) +} diff --git a/eth/api.go b/eth/api.go index e480dde8f64f..2bfa60a8e7f2 100644 --- a/eth/api.go +++ b/eth/api.go @@ -590,3 +590,14 @@ func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error } return 0, errors.New("no state found") } + +// SetTrieFlushInterval configures how often in-memory tries are persisted +// to disk. The value is in terms of block processing time, not wall clock. +func (api *DebugAPI) SetTrieFlushInterval(interval string) error { + t, err := time.ParseDuration(interval) + if err != nil { + return err + } + api.eth.blockchain.SetTrieFlushInterval(t) + return nil +} diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 801afedaa02c..388eed8a2fa6 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -490,6 +490,11 @@ web3._extend({ call: 'debug_dbAncients', params: 0 }), + new web3._extend.Method({ + name: 'setTrieFlushInterval', + call: 'debug_setTrieFlushInterval', + params: 1 + }), ], properties: [] }); From 3315bad2565e43fa19becdac32751fc79ef6b0ed Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 9 Dec 2022 16:14:33 +0100 Subject: [PATCH 419/715] core: pass block into collectLogs (#26335) While investigating another issue, I found that all callers of collectLogs have the complete block available. rawdb.ReadReceipts loads the block from the database, so it is better to use ReadRawReceipts here, and derive the receipt information using the block which is already in memory. --- core/blockchain.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index e5fd586104ab..7f476fe59573 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1996,14 +1996,10 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) } // collectLogs collects the logs that were generated or removed during -// the processing of the block that corresponds with the given hash. -// These logs are later announced as deleted or reborn. -func (bc *BlockChain) collectLogs(hash common.Hash, removed bool) []*types.Log { - number := bc.hc.GetBlockNumber(hash) - if number == nil { - return nil - } - receipts := rawdb.ReadReceipts(bc.db, hash, *number, bc.chainConfig) +// the processing of a block. These logs are later announced as deleted or reborn. +func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { + receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64()) + receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Transactions()) var logs []*types.Log for _, receipt := range receipts { @@ -2150,7 +2146,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { bc.chainSideFeed.Send(ChainSideEvent{Block: oldChain[i]}) // Collect deleted logs for notification - if logs := bc.collectLogs(oldChain[i].Hash(), true); len(logs) > 0 { + if logs := bc.collectLogs(oldChain[i], true); len(logs) > 0 { deletedLogs = append(deletedLogs, logs...) } if len(deletedLogs) > 512 { @@ -2165,7 +2161,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // New logs: var rebirthLogs []*types.Log for i := len(newChain) - 1; i >= 1; i-- { - if logs := bc.collectLogs(newChain[i].Hash(), false); len(logs) > 0 { + if logs := bc.collectLogs(newChain[i], false); len(logs) > 0 { rebirthLogs = append(rebirthLogs, logs...) } if len(rebirthLogs) > 512 { @@ -2220,7 +2216,7 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) { bc.writeHeadBlock(head) // Emit events - logs := bc.collectLogs(head.Hash(), false) + logs := bc.collectLogs(head, false) bc.chainFeed.Send(ChainEvent{Block: head, Hash: head.Hash(), Logs: logs}) if len(logs) > 0 { bc.logsFeed.Send(logs) From 3775e198dfc9fec312f44fd563dcc525cefa1e5d Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 9 Dec 2022 16:20:46 +0100 Subject: [PATCH 420/715] event: add FeedOf[T] (#26310) This PR adds a new type event.FeedOf[T], which is like event.Feed but parameterized over the channel element type. Performance is unchanged, and it still uses reflect. But unlike Feed, the generic version doesn't need to type-check interface{} arguments. All panic cases are gone from the API. --- event/feedof.go | 167 +++++++++++++++++++++++++ event/feedof_test.go | 282 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 449 insertions(+) create mode 100644 event/feedof.go create mode 100644 event/feedof_test.go diff --git a/event/feedof.go b/event/feedof.go new file mode 100644 index 000000000000..598038a19e24 --- /dev/null +++ b/event/feedof.go @@ -0,0 +1,167 @@ +// Copyright 2022 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 go1.18 +// +build go1.18 + +package event + +import ( + "reflect" + "sync" +) + +// FeedOf implements one-to-many subscriptions where the carrier of events is a channel. +// Values sent to a Feed are delivered to all subscribed channels simultaneously. +// +// The zero value is ready to use. +type FeedOf[T any] struct { + once sync.Once // ensures that init only runs once + sendLock chan struct{} // sendLock has a one-element buffer and is empty when held.It protects sendCases. + removeSub chan chan<- T // interrupts Send + sendCases caseList // the active set of select cases used by Send + + // The inbox holds newly subscribed channels until they are added to sendCases. + mu sync.Mutex + inbox caseList +} + +func (f *FeedOf[T]) init() { + f.removeSub = make(chan chan<- T) + f.sendLock = make(chan struct{}, 1) + f.sendLock <- struct{}{} + f.sendCases = caseList{{Chan: reflect.ValueOf(f.removeSub), Dir: reflect.SelectRecv}} +} + +// Subscribe adds a channel to the feed. Future sends will be delivered on the channel +// until the subscription is canceled. +// +// The channel should have ample buffer space to avoid blocking other subscribers. Slow +// subscribers are not dropped. +func (f *FeedOf[T]) Subscribe(channel chan<- T) Subscription { + f.once.Do(f.init) + + chanval := reflect.ValueOf(channel) + sub := &feedOfSub[T]{feed: f, channel: channel, err: make(chan error, 1)} + + // Add the select case to the inbox. + // The next Send will add it to f.sendCases. + f.mu.Lock() + defer f.mu.Unlock() + cas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: chanval} + f.inbox = append(f.inbox, cas) + return sub +} + +func (f *FeedOf[T]) remove(sub *feedOfSub[T]) { + // Delete from inbox first, which covers channels + // that have not been added to f.sendCases yet. + f.mu.Lock() + index := f.inbox.find(sub.channel) + if index != -1 { + f.inbox = f.inbox.delete(index) + f.mu.Unlock() + return + } + f.mu.Unlock() + + select { + case f.removeSub <- sub.channel: + // Send will remove the channel from f.sendCases. + case <-f.sendLock: + // No Send is in progress, delete the channel now that we have the send lock. + f.sendCases = f.sendCases.delete(f.sendCases.find(sub.channel)) + f.sendLock <- struct{}{} + } +} + +// Send delivers to all subscribed channels simultaneously. +// It returns the number of subscribers that the value was sent to. +func (f *FeedOf[T]) Send(value T) (nsent int) { + rvalue := reflect.ValueOf(value) + + f.once.Do(f.init) + <-f.sendLock + + // Add new cases from the inbox after taking the send lock. + f.mu.Lock() + f.sendCases = append(f.sendCases, f.inbox...) + f.inbox = nil + f.mu.Unlock() + + // Set the sent value on all channels. + for i := firstSubSendCase; i < len(f.sendCases); i++ { + f.sendCases[i].Send = rvalue + } + + // Send until all channels except removeSub have been chosen. 'cases' tracks a prefix + // of sendCases. When a send succeeds, the corresponding case moves to the end of + // 'cases' and it shrinks by one element. + cases := f.sendCases + for { + // Fast path: try sending without blocking before adding to the select set. + // This should usually succeed if subscribers are fast enough and have free + // buffer space. + for i := firstSubSendCase; i < len(cases); i++ { + if cases[i].Chan.TrySend(rvalue) { + nsent++ + cases = cases.deactivate(i) + i-- + } + } + if len(cases) == firstSubSendCase { + break + } + // Select on all the receivers, waiting for them to unblock. + chosen, recv, _ := reflect.Select(cases) + if chosen == 0 /* <-f.removeSub */ { + index := f.sendCases.find(recv.Interface()) + f.sendCases = f.sendCases.delete(index) + if index >= 0 && index < len(cases) { + // Shrink 'cases' too because the removed case was still active. + cases = f.sendCases[:len(cases)-1] + } + } else { + cases = cases.deactivate(chosen) + nsent++ + } + } + + // Forget about the sent value and hand off the send lock. + for i := firstSubSendCase; i < len(f.sendCases); i++ { + f.sendCases[i].Send = reflect.Value{} + } + f.sendLock <- struct{}{} + return nsent +} + +type feedOfSub[T any] struct { + feed *FeedOf[T] + channel chan<- T + errOnce sync.Once + err chan error +} + +func (sub *feedOfSub[T]) Unsubscribe() { + sub.errOnce.Do(func() { + sub.feed.remove(sub) + close(sub.err) + }) +} + +func (sub *feedOfSub[T]) Err() <-chan error { + return sub.err +} diff --git a/event/feedof_test.go b/event/feedof_test.go new file mode 100644 index 000000000000..8478eeffb1e5 --- /dev/null +++ b/event/feedof_test.go @@ -0,0 +1,282 @@ +// Copyright 2016 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 go1.18 +// +build go1.18 + +package event + +import ( + "sync" + "testing" + "time" +) + +func TestFeedOf(t *testing.T) { + var feed FeedOf[int] + var done, subscribed sync.WaitGroup + subscriber := func(i int) { + defer done.Done() + + subchan := make(chan int) + sub := feed.Subscribe(subchan) + timeout := time.NewTimer(2 * time.Second) + defer timeout.Stop() + subscribed.Done() + + select { + case v := <-subchan: + if v != 1 { + t.Errorf("%d: received value %d, want 1", i, v) + } + case <-timeout.C: + t.Errorf("%d: receive timeout", i) + } + + sub.Unsubscribe() + select { + case _, ok := <-sub.Err(): + if ok { + t.Errorf("%d: error channel not closed after unsubscribe", i) + } + case <-timeout.C: + t.Errorf("%d: unsubscribe timeout", i) + } + } + + const n = 1000 + done.Add(n) + subscribed.Add(n) + for i := 0; i < n; i++ { + go subscriber(i) + } + subscribed.Wait() + if nsent := feed.Send(1); nsent != n { + t.Errorf("first send delivered %d times, want %d", nsent, n) + } + if nsent := feed.Send(2); nsent != 0 { + t.Errorf("second send delivered %d times, want 0", nsent) + } + done.Wait() +} + +func TestFeedOfSubscribeSameChannel(t *testing.T) { + var ( + feed FeedOf[int] + done sync.WaitGroup + ch = make(chan int) + sub1 = feed.Subscribe(ch) + sub2 = feed.Subscribe(ch) + _ = feed.Subscribe(ch) + ) + expectSends := func(value, n int) { + if nsent := feed.Send(value); nsent != n { + t.Errorf("send delivered %d times, want %d", nsent, n) + } + done.Done() + } + expectRecv := func(wantValue, n int) { + for i := 0; i < n; i++ { + if v := <-ch; v != wantValue { + t.Errorf("received %d, want %d", v, wantValue) + } + } + } + + done.Add(1) + go expectSends(1, 3) + expectRecv(1, 3) + done.Wait() + + sub1.Unsubscribe() + + done.Add(1) + go expectSends(2, 2) + expectRecv(2, 2) + done.Wait() + + sub2.Unsubscribe() + + done.Add(1) + go expectSends(3, 1) + expectRecv(3, 1) + done.Wait() +} + +func TestFeedOfSubscribeBlockedPost(t *testing.T) { + var ( + feed FeedOf[int] + nsends = 2000 + ch1 = make(chan int) + ch2 = make(chan int) + wg sync.WaitGroup + ) + defer wg.Wait() + + feed.Subscribe(ch1) + wg.Add(nsends) + for i := 0; i < nsends; i++ { + go func() { + feed.Send(99) + wg.Done() + }() + } + + sub2 := feed.Subscribe(ch2) + defer sub2.Unsubscribe() + + // We're done when ch1 has received N times. + // The number of receives on ch2 depends on scheduling. + for i := 0; i < nsends; { + select { + case <-ch1: + i++ + case <-ch2: + } + } +} + +func TestFeedOfUnsubscribeBlockedPost(t *testing.T) { + var ( + feed FeedOf[int] + nsends = 200 + chans = make([]chan int, 2000) + subs = make([]Subscription, len(chans)) + bchan = make(chan int) + bsub = feed.Subscribe(bchan) + wg sync.WaitGroup + ) + for i := range chans { + chans[i] = make(chan int, nsends) + } + + // Queue up some Sends. None of these can make progress while bchan isn't read. + wg.Add(nsends) + for i := 0; i < nsends; i++ { + go func() { + feed.Send(99) + wg.Done() + }() + } + // Subscribe the other channels. + for i, ch := range chans { + subs[i] = feed.Subscribe(ch) + } + // Unsubscribe them again. + for _, sub := range subs { + sub.Unsubscribe() + } + // Unblock the Sends. + bsub.Unsubscribe() + wg.Wait() +} + +// Checks that unsubscribing a channel during Send works even if that +// channel has already been sent on. +func TestFeedOfUnsubscribeSentChan(t *testing.T) { + var ( + feed FeedOf[int] + ch1 = make(chan int) + ch2 = make(chan int) + sub1 = feed.Subscribe(ch1) + sub2 = feed.Subscribe(ch2) + wg sync.WaitGroup + ) + defer sub2.Unsubscribe() + + wg.Add(1) + go func() { + feed.Send(0) + wg.Done() + }() + + // Wait for the value on ch1. + <-ch1 + // Unsubscribe ch1, removing it from the send cases. + sub1.Unsubscribe() + + // Receive ch2, finishing Send. + <-ch2 + wg.Wait() + + // Send again. This should send to ch2 only, so the wait group will unblock + // as soon as a value is received on ch2. + wg.Add(1) + go func() { + feed.Send(0) + wg.Done() + }() + <-ch2 + wg.Wait() +} + +func TestFeedOfUnsubscribeFromInbox(t *testing.T) { + var ( + feed FeedOf[int] + ch1 = make(chan int) + ch2 = make(chan int) + sub1 = feed.Subscribe(ch1) + sub2 = feed.Subscribe(ch1) + sub3 = feed.Subscribe(ch2) + ) + if len(feed.inbox) != 3 { + t.Errorf("inbox length != 3 after subscribe") + } + if len(feed.sendCases) != 1 { + t.Errorf("sendCases is non-empty after unsubscribe") + } + + sub1.Unsubscribe() + sub2.Unsubscribe() + sub3.Unsubscribe() + if len(feed.inbox) != 0 { + t.Errorf("inbox is non-empty after unsubscribe") + } + if len(feed.sendCases) != 1 { + t.Errorf("sendCases is non-empty after unsubscribe") + } +} + +func BenchmarkFeedOfSend1000(b *testing.B) { + var ( + done sync.WaitGroup + feed FeedOf[int] + nsubs = 1000 + ) + subscriber := func(ch <-chan int) { + for i := 0; i < b.N; i++ { + <-ch + } + done.Done() + } + done.Add(nsubs) + for i := 0; i < nsubs; i++ { + ch := make(chan int, 200) + feed.Subscribe(ch) + go subscriber(ch) + } + + // The actual benchmark. + b.ResetTimer() + for i := 0; i < b.N; i++ { + if feed.Send(i) != nsubs { + panic("wrong number of sends") + } + } + + b.StopTimer() + done.Wait() +} From 262bd38fce0317f0123947add02cbb3ccde75f59 Mon Sep 17 00:00:00 2001 From: Michael de Hoog Date: Sat, 10 Dec 2022 07:34:43 -0600 Subject: [PATCH 421/715] eth/tracers: return proper error from debug_TraceTransaction when tx not found (#26211) Currently calling `debug_TraceTransaction` with a transaction hash that doesn't exist returns a confusing error: `genesis is not traceable`. This PR changes the behaviour to instead return an error message saying `transaction not found` Co-authored-by: Martin Holst Swende Co-authored-by: Sina Mahmoodi --- eth/tracers/api.go | 8 +++++++- eth/tracers/api_test.go | 14 ++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index a9b51c507807..133aefc85fc8 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -68,6 +68,8 @@ const ( maximumPendingTraceStates = 128 ) +var errTxNotFound = errors.New("transaction not found") + // StateReleaseFunc is used to deallocate resources held by constructing a // historical state for tracing purposes. type StateReleaseFunc func() @@ -801,10 +803,14 @@ func containsTx(block *types.Block, hash common.Hash) bool { // TraceTransaction returns the structured logs created during the execution of EVM // and returns them as a JSON object. func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { - _, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash) + tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash) if err != nil { return nil, err } + // Only mined txes are supported + if tx == nil { + return nil, errTxNotFound + } // It shouldn't happen in practice. if blockNumber == 0 { return nil, errors.New("genesis is not traceable") diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index adf65d33fb4f..334f23efd806 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -48,9 +48,8 @@ import ( ) var ( - errStateNotFound = errors.New("state not found") - errBlockNotFound = errors.New("block not found") - errTransactionNotFound = errors.New("transaction not found") + errStateNotFound = errors.New("state not found") + errBlockNotFound = errors.New("block not found") ) type testBackend struct { @@ -117,9 +116,6 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash) - if tx == nil { - return nil, common.Hash{}, 0, 0, errTransactionNotFound - } return tx, hash, blockNumber, index, nil } @@ -365,6 +361,12 @@ func TestTraceTransaction(t *testing.T) { }) { t.Error("Transaction tracing result is different") } + + // Test non-existent transaction + _, err = api.TraceTransaction(context.Background(), common.Hash{42}, nil) + if !errors.Is(err, errTxNotFound) { + t.Fatalf("want %v, have %v", errTxNotFound, err) + } } func TestTraceBlock(t *testing.T) { From 250a80a50e7a1326e35b672b380f9a7cd301f282 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 13 Dec 2022 01:33:40 -0700 Subject: [PATCH 422/715] core: fix comment about recipient for contract creation (#26349) A comment suggests that contract creation happens if the recipient of a call is 0x00..00 ("zero address") but in fact the sender must be nil. The zero address is a regular valid address that is commonly used as a "burn" address. --- core/state_transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state_transition.go b/core/state_transition.go index a6cf3f7c32d6..c49aba708563 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -41,7 +41,7 @@ var emptyCodeHash = crypto.Keccak256Hash(nil) // // 1. Nonce handling // 2. Pre pay gas -// 3. Create a new state object if the recipient is \0*32 +// 3. Create a new state object if the recipient is nil // 4. Value transfer // // == If contract creation == From cda051eba7c3b216e2a3a3c9071cb16e3db72d86 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 13 Dec 2022 20:54:16 +0800 Subject: [PATCH 423/715] core, cmd: fill blockNumber in logs (#26345) * core, cmd: fill blockNumber in logs * Update core/state/statedb.go Co-authored-by: Martin Holst Swende * core/types: revert * core/state: improve comments Co-authored-by: Martin Holst Swende --- cmd/evm/internal/t8ntool/execution.go | 2 +- core/state/statedb.go | 5 ++++- core/state/statedb_test.go | 4 ++-- core/state_processor.go | 8 ++++---- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index a05dbedea700..08d829d7db70 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -218,7 +218,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } // Set the receipt logs and create the bloom filter. - receipt.Logs = statedb.GetLogs(tx.Hash(), blockHash) + receipt.Logs = statedb.GetLogs(tx.Hash(), vmContext.BlockNumber.Uint64(), blockHash) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) // These three are non-consensus fields: //receipt.BlockHash diff --git a/core/state/statedb.go b/core/state/statedb.go index b85c94850b40..91eb07a22800 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -206,9 +206,12 @@ func (s *StateDB) AddLog(log *types.Log) { s.logSize++ } -func (s *StateDB) GetLogs(hash common.Hash, blockHash common.Hash) []*types.Log { +// GetLogs returns the logs matching the specified transaction hash, and annotates +// them with the given blockNumber and blockHash. +func (s *StateDB) GetLogs(hash common.Hash, blockNumber uint64, blockHash common.Hash) []*types.Log { logs := s.logs[hash] for _, l := range logs { + l.BlockNumber = blockNumber l.BlockHash = blockHash } return logs diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 5e134043d243..a39c83d2d1a1 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -473,9 +473,9 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", state.GetRefund(), checkstate.GetRefund()) } - if !reflect.DeepEqual(state.GetLogs(common.Hash{}, common.Hash{}), checkstate.GetLogs(common.Hash{}, common.Hash{})) { + if !reflect.DeepEqual(state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) { return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", - state.GetLogs(common.Hash{}, common.Hash{}), checkstate.GetLogs(common.Hash{}, common.Hash{})) + state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) } return nil } diff --git a/core/state_processor.go b/core/state_processor.go index db17481804ab..da886781e322 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -79,7 +79,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.SetTxContext(tx.Hash(), i) - receipt, err := applyTransaction(msg, p.config, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) + receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -92,7 +92,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return receipts, allLogs, *usedGas, nil } -func applyTransaction(msg types.Message, config *params.ChainConfig, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { +func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) evm.Reset(txContext, statedb) @@ -129,7 +129,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, author *com } // Set the receipt logs and create the bloom filter. - receipt.Logs = statedb.GetLogs(tx.Hash(), blockHash) + receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) receipt.BlockHash = blockHash receipt.BlockNumber = blockNumber @@ -149,5 +149,5 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // Create a new context to be used in the EVM environment blockContext := NewEVMBlockContext(header, bc, author) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) - return applyTransaction(msg, config, author, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) + return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) } From fa97788c757a07c0dd038db5ef1a05ee9158e2e6 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 13 Dec 2022 08:32:29 -0500 Subject: [PATCH 424/715] eth/tracers/native: fix possible crash in prestate tracer (#26351) --- eth/tracers/native/prestate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 9313d0769071..10008699bda3 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -45,7 +45,7 @@ type account struct { } func (a *account) exists() bool { - return a.Balance.Sign() != 0 || a.Nonce > 0 || len(a.Code) > 0 || len(a.Storage) > 0 + return a.Nonce > 0 || len(a.Code) > 0 || len(a.Storage) > 0 || (a.Balance != nil && a.Balance.Sign() != 0) } type accountMarshaling struct { From 502fa829a6a0e5d8e3daf9afae34f106a68b288a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 14 Dec 2022 04:33:57 -0500 Subject: [PATCH 425/715] signer/core: handle gnosis safe problem with missing chain id (#26309) This PR adds a check that the safetxhash that we sign corresponds to the one that is expected by the input. If it differs, it tries again with the configured chainid. --- signer/core/api.go | 21 +++++++++++++++++++++ signer/core/signed_data_test.go | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/signer/core/api.go b/signer/core/api.go index 61793a0e51c3..3c1c94801b11 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -17,6 +17,7 @@ package core import ( + "bytes" "context" "encoding/json" "errors" @@ -31,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" @@ -627,7 +629,26 @@ func (api *SignerAPI) SignGnosisSafeTx(ctx context.Context, signerAddress common } } typedData := gnosisTx.ToTypedData() + // might aswell error early. + // we are expected to sign. If our calculated hash does not match what they want, + // The gnosis safetx input contains a 'safeTxHash' which is the expected safeTxHash that + sighash, _, err := apitypes.TypedDataAndHash(typedData) + if err != nil { + return nil, err + } + if !bytes.Equal(sighash, gnosisTx.InputExpHash.Bytes()) { + // It might be the case that the json is missing chain id. + if gnosisTx.ChainId == nil { + gnosisTx.ChainId = (*math.HexOrDecimal256)(api.chainID) + typedData = gnosisTx.ToTypedData() + sighash, _, _ = apitypes.TypedDataAndHash(typedData) + if !bytes.Equal(sighash, gnosisTx.InputExpHash.Bytes()) { + return nil, fmt.Errorf("mismatched safeTxHash; have %#x want %#x", sighash, gnosisTx.InputExpHash[:]) + } + } + } signature, preimage, err := api.signTypedData(ctx, signerAddress, typedData, msgs) + if err != nil { return nil, err } diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index 8deff919cba1..608b2adebed4 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -21,6 +21,7 @@ import ( "context" "encoding/json" "fmt" + "math/big" "os" "path" "strings" @@ -826,3 +827,24 @@ func TestComplexTypedData(t *testing.T) { t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash) } } + +func TestGnosisSafe(t *testing.T) { + // json missing chain id + js := "{\n \"safe\": \"0x899FcB1437DE65DC6315f5a69C017dd3F2837557\",\n \"to\": \"0x899FcB1437DE65DC6315f5a69C017dd3F2837557\",\n \"value\": \"0\",\n \"data\": \"0x0d582f13000000000000000000000000d3ed2b8756b942c98c851722f3bd507a17b4745f0000000000000000000000000000000000000000000000000000000000000005\",\n \"operation\": 0,\n \"gasToken\": \"0x0000000000000000000000000000000000000000\",\n \"safeTxGas\": 0,\n \"baseGas\": 0,\n \"gasPrice\": \"0\",\n \"refundReceiver\": \"0x0000000000000000000000000000000000000000\",\n \"nonce\": 0,\n \"executionDate\": null,\n \"submissionDate\": \"2022-02-23T14:09:00.018475Z\",\n \"modified\": \"2022-12-01T15:52:21.214357Z\",\n \"blockNumber\": null,\n \"transactionHash\": null,\n \"safeTxHash\": \"0x6f0f5cffee69087c9d2471e477a63cab2ae171cf433e754315d558d8836274f4\",\n \"executor\": null,\n \"isExecuted\": false,\n \"isSuccessful\": null,\n \"ethGasPrice\": null,\n \"maxFeePerGas\": null,\n \"maxPriorityFeePerGas\": null,\n \"gasUsed\": null,\n \"fee\": null,\n \"origin\": \"https://gnosis-safe.io\",\n \"dataDecoded\": {\n \"method\": \"addOwnerWithThreshold\",\n \"parameters\": [\n {\n \"name\": \"owner\",\n \"type\": \"address\",\n \"value\": \"0xD3Ed2b8756b942c98c851722F3bd507a17B4745F\"\n },\n {\n \"name\": \"_threshold\",\n \"type\": \"uint256\",\n \"value\": \"5\"\n }\n ]\n },\n \"confirmationsRequired\": 4,\n \"confirmations\": [\n {\n \"owner\": \"0x30B714E065B879F5c042A75Bb40a220A0BE27966\",\n \"submissionDate\": \"2022-03-01T14:56:22Z\",\n \"transactionHash\": \"0x6d0a9c83ac7578ef3be1f2afce089fb83b619583dfa779b82f4422fd64ff3ee9\",\n \"signature\": \"0x00000000000000000000000030b714e065b879f5c042a75bb40a220a0be27966000000000000000000000000000000000000000000000000000000000000000001\",\n \"signatureType\": \"APPROVED_HASH\"\n },\n {\n \"owner\": \"0x8300dFEa25Da0eb744fC0D98c23283F86AB8c10C\",\n \"submissionDate\": \"2022-12-01T15:52:21.214357Z\",\n \"transactionHash\": null,\n \"signature\": \"0xbce73de4cc6ee208e933a93c794dcb8ba1810f9848d1eec416b7be4dae9854c07dbf1720e60bbd310d2159197a380c941cfdb55b3ce58f9dd69efd395d7bef881b\",\n \"signatureType\": \"EOA\"\n }\n ],\n \"trusted\": true,\n \"signatures\": null\n}\n" + var gnosisTx core.GnosisSafeTx + if err := json.Unmarshal([]byte(js), &gnosisTx); err != nil { + t.Fatal(err) + } + sighash, _, err := apitypes.TypedDataAndHash(gnosisTx.ToTypedData()) + if err != nil { + t.Fatal(err) + } + if bytes.Equal(sighash, gnosisTx.InputExpHash.Bytes()) { + t.Fatal("expected inequality") + } + gnosisTx.ChainId = (*math.HexOrDecimal256)(big.NewInt(1)) + sighash, _, _ = apitypes.TypedDataAndHash(gnosisTx.ToTypedData()) + if !bytes.Equal(sighash, gnosisTx.InputExpHash.Bytes()) { + t.Fatal("expected equality") + } +} From f51f6edb40f714107cfba90d201cba0a97939dd3 Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Wed, 14 Dec 2022 18:48:12 +0900 Subject: [PATCH 426/715] core: fix typo in blockchain_snapshot_test.go (#26357) correspnding -> corresponding --- core/blockchain_snapshot_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index e55431c914fa..b5aa7844b4f6 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -143,7 +143,7 @@ func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks [ // Check the disk layer, ensure they are matched block := chain.GetBlockByNumber(basic.expSnapshotBottom) if block == nil { - t.Errorf("The correspnding block[%d] of snapshot disk layer is missing", basic.expSnapshotBottom) + t.Errorf("The corresponding block[%d] of snapshot disk layer is missing", basic.expSnapshotBottom) } else if !bytes.Equal(chain.snaps.DiskRoot().Bytes(), block.Root().Bytes()) { t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.snaps.DiskRoot()) } From f53ff0ff4a68ffc56004ab1d5cc244bcb64d3277 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Dec 2022 13:52:07 +0100 Subject: [PATCH 427/715] eth/filters, eth/tracers: add request cancellation checks (#26320) This ensures that RPC method handlers will react to a timeout or cancelled request soon after the event occurs. Co-authored-by: Sina Mahmoodi --- eth/api.go | 4 ++-- eth/api_backend.go | 4 ++-- eth/filters/filter.go | 3 +++ eth/state_accessor.go | 13 ++++++++++--- eth/tracers/api.go | 21 ++++++++++++++++----- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/eth/api.go b/eth/api.go index 2bfa60a8e7f2..0591b98de867 100644 --- a/eth/api.go +++ b/eth/api.go @@ -405,13 +405,13 @@ type storageEntry struct { } // StorageRangeAt returns the storage at the given block height and transaction index. -func (api *DebugAPI) StorageRangeAt(blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { +func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { // Retrieve the block block := api.eth.blockchain.GetBlockByHash(blockHash) if block == nil { return StorageRangeResult{}, fmt.Errorf("block %#x not found", blockHash) } - _, _, statedb, release, err := api.eth.stateAtTransaction(block, txIndex, 0) + _, _, statedb, release, err := api.eth.stateAtTransaction(ctx, block, txIndex, 0) if err != nil { return StorageRangeResult{}, err } diff --git a/eth/api_backend.go b/eth/api_backend.go index fad88e801865..3055bae75efa 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -365,9 +365,9 @@ func (b *EthAPIBackend) StartMining(threads int) error { } func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) { - return b.eth.StateAtBlock(block, reexec, base, readOnly, preferDisk) + return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk) } func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { - return b.eth.stateAtTransaction(block, txIndex, reexec) + return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) } diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 26e85a6f1a42..611fc8630144 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -234,6 +234,9 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e var logs []*types.Log for ; f.begin <= int64(end); f.begin++ { + if f.begin%10 == 0 && ctx.Err() != nil { + return logs, ctx.Err() + } header, err := f.sys.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin)) if header == nil || err != nil { return logs, err diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 778f88ab35d1..3bb1464952a0 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -17,6 +17,7 @@ package eth import ( + "context" "errors" "fmt" "time" @@ -56,7 +57,7 @@ var noopReleaser = tracers.StateReleaseFunc(func() {}) // - preferDisk: this arg can be used by the caller to signal that even though the 'base' is // provided, it would be preferable to start from a fresh state, if we have it // on disk. -func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) { +func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) { var ( current *types.Block database state.Database @@ -111,6 +112,9 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state } // Database does not have the state for the given block, try to regenerate for i := uint64(0); i < reexec; i++ { + if err := ctx.Err(); err != nil { + return nil, nil, err + } if current.NumberU64() == 0 { return nil, nil, errors.New("genesis state is missing") } @@ -142,6 +146,9 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state parent common.Hash ) for current.NumberU64() < origin { + if err := ctx.Err(); err != nil { + return nil, nil, err + } // Print progress logs if long enough time elapsed if time.Since(logged) > 8*time.Second && report { log.Info("Regenerating historical state", "block", current.NumberU64()+1, "target", origin, "remaining", origin-current.NumberU64()-1, "elapsed", time.Since(start)) @@ -182,7 +189,7 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state } // stateAtTransaction returns the execution environment of a certain transaction. -func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { // Short circuit if it's genesis block. if block.NumberU64() == 0 { return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis") @@ -194,7 +201,7 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec } // Lookup the statedb of parent block from the live database, // otherwise regenerate it on the flight. - statedb, release, err := eth.StateAtBlock(parent, reexec, nil, true, false) + statedb, release, err := eth.StateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { return nil, vm.BlockContext{}, nil, nil, err } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 133aefc85fc8..4436d13961f6 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -549,6 +549,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) ) for i, tx := range block.Transactions() { + if err := ctx.Err(); err != nil { + return nil, err + } var ( msg, _ = tx.AsMessage(signer, block.BaseFee()) txContext = core.NewEVMTxContext(msg) @@ -609,14 +612,13 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) txs = block.Transactions() results = make([]*txTraceResult, len(txs)) - - pend = new(sync.WaitGroup) - jobs = make(chan *txTraceTask, len(txs)) + pend sync.WaitGroup ) threads := runtime.NumCPU() if threads > len(txs) { threads = len(txs) } + jobs := make(chan *txTraceTask, threads) blockHash := block.Hash() for th := 0; th < threads; th++ { pend.Add(1) @@ -640,12 +642,20 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac } }() } + // Feed the transactions into the tracers and return var failed error blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) +txloop: for i, tx := range txs { // Send the trace task over for execution - jobs <- &txTraceTask{statedb: statedb.Copy(), index: i} + task := &txTraceTask{statedb: statedb.Copy(), index: i} + select { + case <-ctx.Done(): + failed = ctx.Err() + break txloop + case jobs <- task: + } // Generate the next state snapshot fast without tracing msg, _ := tx.AsMessage(signer, block.BaseFee()) @@ -653,12 +663,13 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { failed = err - break + break txloop } // Finalize the state so any modifications are written to the trie // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) } + close(jobs) pend.Wait() From d3411b9f6717dc3c5f9a81496e64f17c47525252 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 19 Dec 2022 17:56:13 +0800 Subject: [PATCH 428/715] trie: wrap deletion in case trie.root is nil (#26365) This PR fixes an error in trie commit. If the trie.root is nil, it can be two possible scenarios: - The trie was empty, and no change happens - The trie was non-empty and all nodes are dropped For the latter one, we should collect the deletions and apply them into database(e.g. in PBSS). --- trie/committer.go | 19 ++++---------- trie/trie.go | 8 +++++- trie/util_test.go | 66 +++++++++++++++++++++++++++++++++++++++++++++++ trie/utils.go | 19 ++++++++++++++ 4 files changed, 97 insertions(+), 15 deletions(-) diff --git a/trie/committer.go b/trie/committer.go index 90191cf9b1dd..13c54d96980a 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -53,20 +53,11 @@ func (c *committer) Commit(n node) (hashNode, *NodeSet, error) { if err != nil { return nil, nil, err } - // Some nodes can be deleted from trie which can't be captured by committer - // itself. Iterate all deleted nodes tracked by tracer and marked them as - // deleted only if they are present in database previously. - for _, path := range c.tracer.deleteList() { - // There are a few possibilities for this scenario(the node is deleted - // but not present in database previously), for example the node was - // embedded in the parent and now deleted from the trie. In this case - // it's noop from database's perspective. - val := c.tracer.getPrev(path) - if len(val) == 0 { - continue - } - c.nodes.markDeleted(path, val) - } + // Some nodes can be deleted from trie which can't be captured + // by committer itself. Iterate all deleted nodes tracked by + // tracer and marked them as deleted only if they are present + // in database previously. + c.tracer.markDeletions(c.nodes) return h.(hashNode), c.nodes, nil } diff --git a/trie/trie.go b/trie/trie.go index abc63f46749a..1a456b8cfd56 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -569,8 +569,14 @@ func (t *Trie) Hash() common.Hash { func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { defer t.tracer.reset() + // Trie is empty and can be classified into two types of situations: + // - The trie was empty and no update happens + // - The trie was non-empty and all nodes are dropped if t.root == nil { - return emptyRoot, nil, nil + // Wrap tracked deletions as the return + set := NewNodeSet(t.owner) + t.tracer.markDeletions(set) + return emptyRoot, set, nil } // Derive the hash for all dirty nodes first. We hold the assumption // in the following procedure that all nodes are hashed. diff --git a/trie/util_test.go b/trie/util_test.go index e0e314205035..d0f8f94f377c 100644 --- a/trie/util_test.go +++ b/trie/util_test.go @@ -242,3 +242,69 @@ func TestTrieTracePrevValue(t *testing.T) { } } } + +func TestDeleteAll(t *testing.T) { + db := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(db) + trie.tracer = newTracer() + + // Insert a batch of entries, all the nodes should be marked as inserted + vals := []struct{ k, v string }{ + {"do", "verb"}, + {"ether", "wookiedoo"}, + {"horse", "stallion"}, + {"shaman", "horse"}, + {"doge", "coin"}, + {"dog", "puppy"}, + {"somethingveryoddindeedthis is", "myothernodedata"}, + } + for _, val := range vals { + trie.Update([]byte(val.k), []byte(val.v)) + } + root, set, err := trie.Commit(false) + if err != nil { + t.Fatal(err) + } + if err := db.Update(NewWithNodeSet(set)); err != nil { + t.Fatal(err) + } + // Delete entries from trie, ensure all values are detected + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + trie.resolveAndTrack(root.Bytes(), nil) + + // Iterate all existent nodes + var ( + it = trie.NodeIterator(nil) + nodes = make(map[string][]byte) + ) + for it.Next(true) { + if it.Hash() != (common.Hash{}) { + nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) + } + } + + // Perform deletion to purge the entire trie + for _, val := range vals { + trie.Delete([]byte(val.k)) + } + root, set, err = trie.Commit(false) + if err != nil { + t.Fatalf("Failed to delete trie %v", err) + } + if root != emptyRoot { + t.Fatalf("Invalid trie root %v", root) + } + for path, blob := range set.deletes { + prev, ok := nodes[path] + if !ok { + t.Fatalf("Extra node deleted %v", []byte(path)) + } + if !bytes.Equal(prev, blob) { + t.Fatalf("Unexpected previous value %v", []byte(path)) + } + } + if len(set.deletes) != len(nodes) { + t.Fatalf("Unexpected deletion set") + } +} diff --git a/trie/utils.go b/trie/utils.go index d462b31bd205..5dce65cd2971 100644 --- a/trie/utils.go +++ b/trie/utils.go @@ -178,3 +178,22 @@ func (t *tracer) copy() *tracer { origin: origin, } } + +// markDeletions puts all tracked deletions into the provided nodeset. +func (t *tracer) markDeletions(set *NodeSet) { + // Tracer isn't used right now, remove this check later. + if t == nil { + return + } + for _, path := range t.deleteList() { + // There are a few possibilities for this scenario(the node is deleted + // but not present in database previously), for example the node was + // embedded in the parent and now deleted from the trie. In this case + // it's noop from database's perspective. + val := t.getPrev(path) + if len(val) == 0 { + continue + } + set.markDeleted(path, val) + } +} From 79a478bb6176425c2400e949890e668a3d9a3d05 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 19 Dec 2022 17:59:12 +0800 Subject: [PATCH 429/715] core/rawdb: implement resettable freezer (#26324) This PR implements resettable freezer by adding a ResettableFreezer wrapper. The resettable freezer wraps the original freezer in a way that makes it possible to ensure atomic resets. Implementation wise, it relies on the os.Rename and os.RemoveAll to atomically delete the original freezer data and re-create a new one from scratch. --- core/rawdb/freezer_resettable.go | 233 ++++++++++++++++++++++++++ core/rawdb/freezer_resettable_test.go | 107 ++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 core/rawdb/freezer_resettable.go create mode 100644 core/rawdb/freezer_resettable_test.go diff --git a/core/rawdb/freezer_resettable.go b/core/rawdb/freezer_resettable.go new file mode 100644 index 000000000000..f9a56c6de552 --- /dev/null +++ b/core/rawdb/freezer_resettable.go @@ -0,0 +1,233 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rawdb + +import ( + "os" + "path/filepath" + "sync" + + "github.com/ethereum/go-ethereum/ethdb" +) + +const tmpSuffix = ".tmp" + +// freezerOpenFunc is the function used to open/create a freezer. +type freezerOpenFunc = func() (*Freezer, error) + +// ResettableFreezer is a wrapper of the freezer which makes the +// freezer resettable. +type ResettableFreezer struct { + freezer *Freezer + opener freezerOpenFunc + datadir string + lock sync.RWMutex +} + +// NewResettableFreezer creates a resettable freezer, note freezer is +// only resettable if the passed file directory is exclusively occupied +// by the freezer. And also the user-configurable ancient root directory +// is **not** supported for reset since it might be a mount and rename +// will cause a copy of hundreds of gigabyte into local directory. It +// needs some other file based solutions. +// +// The reset function will delete directory atomically and re-create the +// freezer from scratch. +func NewResettableFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]bool) (*ResettableFreezer, error) { + if err := cleanup(datadir); err != nil { + return nil, err + } + opener := func() (*Freezer, error) { + return NewFreezer(datadir, namespace, readonly, maxTableSize, tables) + } + freezer, err := opener() + if err != nil { + return nil, err + } + return &ResettableFreezer{ + freezer: freezer, + opener: opener, + datadir: datadir, + }, nil +} + +// Reset deletes the file directory exclusively occupied by the freezer and +// recreate the freezer from scratch. The atomicity of directory deletion +// is guaranteed by the rename operation, the leftover directory will be +// cleaned up in next startup in case crash happens after rename. +func (f *ResettableFreezer) Reset() error { + f.lock.Lock() + defer f.lock.Unlock() + + if err := f.freezer.Close(); err != nil { + return err + } + tmp := tmpName(f.datadir) + if err := os.Rename(f.datadir, tmp); err != nil { + return err + } + if err := os.RemoveAll(tmp); err != nil { + return err + } + freezer, err := f.opener() + if err != nil { + return err + } + f.freezer = freezer + return nil +} + +// Close terminates the chain freezer, unmapping all the data files. +func (f *ResettableFreezer) Close() error { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.Close() +} + +// HasAncient returns an indicator whether the specified ancient data exists +// in the freezer +func (f *ResettableFreezer) HasAncient(kind string, number uint64) (bool, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.HasAncient(kind, number) +} + +// Ancient retrieves an ancient binary blob from the append-only immutable files. +func (f *ResettableFreezer) Ancient(kind string, number uint64) ([]byte, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.Ancient(kind, number) +} + +// AncientRange retrieves multiple items in sequence, starting from the index 'start'. +// It will return +// - at most 'max' items, +// - at least 1 item (even if exceeding the maxByteSize), but will otherwise +// return as many items as fit into maxByteSize +func (f *ResettableFreezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.AncientRange(kind, start, count, maxBytes) +} + +// Ancients returns the length of the frozen items. +func (f *ResettableFreezer) Ancients() (uint64, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.Ancients() +} + +// Tail returns the number of first stored item in the freezer. +func (f *ResettableFreezer) Tail() (uint64, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.Tail() +} + +// AncientSize returns the ancient size of the specified category. +func (f *ResettableFreezer) AncientSize(kind string) (uint64, error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.AncientSize(kind) +} + +// ReadAncients runs the given read operation while ensuring that no writes take place +// on the underlying freezer. +func (f *ResettableFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.ReadAncients(fn) +} + +// ModifyAncients runs the given write operation. +func (f *ResettableFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize int64, err error) { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.ModifyAncients(fn) +} + +// TruncateHead discards any recent data above the provided threshold number. +func (f *ResettableFreezer) TruncateHead(items uint64) error { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.TruncateHead(items) +} + +// TruncateTail discards any recent data below the provided threshold number. +func (f *ResettableFreezer) TruncateTail(tail uint64) error { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.TruncateTail(tail) +} + +// Sync flushes all data tables to disk. +func (f *ResettableFreezer) Sync() error { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.Sync() +} + +// MigrateTable processes the entries in a given table in sequence +// converting them to a new format if they're of an old format. +func (f *ResettableFreezer) MigrateTable(kind string, convert convertLegacyFn) error { + f.lock.RLock() + defer f.lock.RUnlock() + + return f.freezer.MigrateTable(kind, convert) +} + +// cleanup removes the directory located in the specified path +// has the name with deletion marker suffix. +func cleanup(path string) error { + parent := filepath.Dir(path) + if _, err := os.Lstat(parent); os.IsNotExist(err) { + return nil + } + dir, err := os.Open(parent) + if err != nil { + return err + } + names, err := dir.Readdirnames(0) + if err != nil { + return err + } + if cerr := dir.Close(); cerr != nil { + return cerr + } + for _, name := range names { + if name == filepath.Base(path)+tmpSuffix { + return os.RemoveAll(filepath.Join(parent, name)) + } + } + return nil +} + +func tmpName(path string) string { + return filepath.Join(filepath.Dir(path), filepath.Base(path)+tmpSuffix) +} diff --git a/core/rawdb/freezer_resettable_test.go b/core/rawdb/freezer_resettable_test.go new file mode 100644 index 000000000000..d741bc14e54f --- /dev/null +++ b/core/rawdb/freezer_resettable_test.go @@ -0,0 +1,107 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rawdb + +import ( + "bytes" + "os" + "testing" + + "github.com/ethereum/go-ethereum/ethdb" +) + +func TestResetFreezer(t *testing.T) { + items := []struct { + id uint64 + blob []byte + }{ + {0, bytes.Repeat([]byte{0}, 2048)}, + {1, bytes.Repeat([]byte{1}, 2048)}, + {2, bytes.Repeat([]byte{2}, 2048)}, + } + f, _ := NewResettableFreezer(t.TempDir(), "", false, 2048, freezerTestTableDef) + defer f.Close() + + f.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for _, item := range items { + op.AppendRaw("test", item.id, item.blob) + } + return nil + }) + for _, item := range items { + blob, _ := f.Ancient("test", item.id) + if !bytes.Equal(blob, item.blob) { + t.Fatal("Unexpected blob") + } + } + + // Reset freezer + f.Reset() + count, _ := f.Ancients() + if count != 0 { + t.Fatal("Failed to reset freezer") + } + for _, item := range items { + blob, _ := f.Ancient("test", item.id) + if len(blob) != 0 { + t.Fatal("Unexpected blob") + } + } + + // Fill the freezer + f.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for _, item := range items { + op.AppendRaw("test", item.id, item.blob) + } + return nil + }) + for _, item := range items { + blob, _ := f.Ancient("test", item.id) + if !bytes.Equal(blob, item.blob) { + t.Fatal("Unexpected blob") + } + } +} + +func TestFreezerCleanup(t *testing.T) { + items := []struct { + id uint64 + blob []byte + }{ + {0, bytes.Repeat([]byte{0}, 2048)}, + {1, bytes.Repeat([]byte{1}, 2048)}, + {2, bytes.Repeat([]byte{2}, 2048)}, + } + datadir := t.TempDir() + f, _ := NewResettableFreezer(datadir, "", false, 2048, freezerTestTableDef) + f.ModifyAncients(func(op ethdb.AncientWriteOp) error { + for _, item := range items { + op.AppendRaw("test", item.id, item.blob) + } + return nil + }) + f.Close() + os.Rename(datadir, tmpName(datadir)) + + // Open the freezer again, trigger cleanup operation + f, _ = NewResettableFreezer(datadir, "", false, 2048, freezerTestTableDef) + f.Close() + + if _, err := os.Lstat(tmpName(datadir)); !os.IsNotExist(err) { + t.Fatal("Failed to cleanup leftover directory") + } +} From b818e73ef39e376bd5c6d9074c0a432301042e3b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 20 Dec 2022 09:56:52 -0500 Subject: [PATCH 430/715] tests: update tests (#26314) This PR builds on #26299, but also updates the tests to the most recent version, which includes tests regarding TheMerge. This change adds checks to the beacon consensus engine, making it more strict in validating the pre- and post-headers, and not relying on the caller to have already correctly sanitized the headers/blocks. --- cmd/evm/README.md | 409 +++++++++++++++++++---------- cmd/evm/t8n_test.go | 6 +- cmd/evm/transition-test.sh | 275 +++++++++++++++---- consensus/beacon/consensus.go | 121 ++++----- consensus/beacon/consensus_test.go | 137 ---------- core/block_validator_test.go | 29 +- core/blockchain_test.go | 61 ++++- core/chain_makers.go | 5 + eth/catalyst/api_test.go | 2 +- les/catalyst/api_test.go | 36 ++- tests/block_test.go | 1 + tests/block_test_util.go | 4 + tests/init.go | 20 +- tests/state_test.go | 10 +- tests/state_test_util.go | 12 +- tests/testdata | 2 +- 16 files changed, 685 insertions(+), 445 deletions(-) delete mode 100644 consensus/beacon/consensus_test.go diff --git a/cmd/evm/README.md b/cmd/evm/README.md index 1a029ab7091a..6fd0abf65353 100644 --- a/cmd/evm/README.md +++ b/cmd/evm/README.md @@ -1,56 +1,196 @@ -## EVM state transition tool +# EVM tool + +The EVM tool provides a few useful subcommands to facilitate testing at the EVM +layer. + +* transition tool (`t8n`) : a stateless state transition utility +* transaction tool (`t9n`) : a transaction validation utility +* block builder tool (`b11r`): a block assembler utility + +## State transition tool (`t8n`) + The `evm t8n` tool is a stateless state transition utility. It is a utility which can 1. Take a prestate, including -- Accounts, -- Block context information, -- Previous blockshashes (*optional) + - Accounts, + - Block context information, + - Previous blockshashes (*optional) 2. Apply a set of transactions, 3. Apply a mining-reward (*optional), 4. And generate a post-state, including -- State root, transaction root, receipt root, -- Information about rejected transactions, -- Optionally: a full or partial post-state dump + - State root, transaction root, receipt root, + - Information about rejected transactions, + - Optionally: a full or partial post-state dump -## Specification +### Specification The idea is to specify the behaviour of this binary very _strict_, so that other node implementors can build replicas based on their own state-machines, and the -state generators can swap between a `geth`-based implementation and a `parityvm`-based +state generators can swap between a \`geth\`-based implementation and a \`parityvm\`-based implementation. -### Command line params +#### Command line params + +Command line params that need to be supported are + +``` + --input.alloc value (default: "alloc.json") + --input.env value (default: "env.json") + --input.txs value (default: "txs.json") + --output.alloc value (default: "alloc.json") + --output.basedir value + --output.body value + --output.result value (default: "result.json") + --state.chainid value (default: 1) + --state.fork value (default: "GrayGlacier") + --state.reward value (default: 0) + --trace.memory (default: false) + --trace.nomemory (default: true) + --trace.noreturndata (default: true) + --trace.nostack (default: false) + --trace.returndata (default: false) +``` +#### Objects + +The transition tool uses JSON objects to read and write data related to the transition operation. The +following object definitions are required. + +##### `alloc` + +The `alloc` object defines the prestate that transition will begin with. + +```go +// Map of address to account definition. +type Alloc map[common.Address]Account +// Genesis account. Each field is optional. +type Account struct { + Code []byte `json:"code"` + Storage map[common.Hash]common.Hash `json:"storage"` + Balance *big.Int `json:"balance"` + Nonce uint64 `json:"nonce"` + SecretKey []byte `json:"secretKey"` +} +``` + +##### `env` + +The `env` object defines the environmental context in which the transition will +take place. + +```go +type Env struct { + // required + CurrentCoinbase common.Address `json:"currentCoinbase"` + CurrentGasLimit uint64 `json:"currentGasLimit"` + CurrentNumber uint64 `json:"currentNumber"` + CurrentTimestamp uint64 `json:"currentTimestamp"` + Withdrawals []*Withdrawal `json:"withdrawals"` + // optional + CurrentDifficulty *big.Int `json:"currentDifficuly"` + CurrentRandom *big.Int `json:"currentRandom"` + CurrentBaseFee *big.Int `json:"currentBaseFee"` + ParentDifficulty *big.Int `json:"parentDifficulty"` + ParentGasUsed uint64 `json:"parentGasUsed"` + ParentGasLimit uint64 `json:"parentGasLimit"` + ParentTimestamp uint64 `json:"parentTimestamp"` + BlockHashes map[uint64]common.Hash `json:"blockHashes"` + ParentUncleHash common.Hash `json:"parentUncleHash"` + Ommers []Ommer `json:"ommers"` +} +type Ommer struct { + Delta uint64 `json:"delta"` + Address common.Address `json:"address"` +} +type Withdrawal struct { + Index uint64 `json:"index"` + ValidatorIndex uint64 `json:"validatorIndex"` + Recipient common.Address `json:"recipient"` + Amount *big.Int `json:"amount"` +} +``` + +##### `txs` -Command line params that has to be supported are +The `txs` object is an array of any of the transaction types: `LegacyTx`, +`AccessListTx`, or `DynamicFeeTx`. + +```go +type LegacyTx struct { + Nonce uint64 `json:"nonce"` + GasPrice *big.Int `json:"gasPrice"` + Gas uint64 `json:"gas"` + To *common.Address `json:"to"` + Value *big.Int `json:"value"` + Data []byte `json:"data"` + V *big.Int `json:"v"` + R *big.Int `json:"r"` + S *big.Int `json:"s"` + SecretKey *common.Hash `json:"secretKey"` +} +type AccessList []AccessTuple +type AccessTuple struct { + Address common.Address `json:"address" gencodec:"required"` + StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"` +} +type AccessListTx struct { + ChainID *big.Int `json:"chainId"` + Nonce uint64 `json:"nonce"` + GasPrice *big.Int `json:"gasPrice"` + Gas uint64 `json:"gas"` + To *common.Address `json:"to"` + Value *big.Int `json:"value"` + Data []byte `json:"data"` + AccessList AccessList `json:"accessList"` + V *big.Int `json:"v"` + R *big.Int `json:"r"` + S *big.Int `json:"s"` + SecretKey *common.Hash `json:"secretKey"` +} +type DynamicFeeTx struct { + ChainID *big.Int `json:"chainId"` + Nonce uint64 `json:"nonce"` + GasTipCap *big.Int `json:"maxPriorityFeePerGas"` + GasFeeCap *big.Int `json:"maxFeePerGas"` + Gas uint64 `json:"gas"` + To *common.Address `json:"to"` + Value *big.Int `json:"value"` + Data []byte `json:"data"` + AccessList AccessList `json:"accessList"` + V *big.Int `json:"v"` + R *big.Int `json:"r"` + S *big.Int `json:"s"` + SecretKey *common.Hash `json:"secretKey"` +} ``` - --trace Output full trace logs to files .jsonl - --trace.nomemory Disable full memory dump in traces - --trace.nostack Disable stack output in traces - --trace.noreturndata Disable return data output in traces - --output.basedir value Specifies where output files are placed. Will be created if it does not exist. - --output.alloc alloc Determines where to put the alloc of the post-state. - `stdout` - into the stdout output - `stderr` - into the stderr output - --output.result result Determines where to put the result (stateroot, txroot etc) of the post-state. - `stdout` - into the stdout output - `stderr` - into the stderr output - --output.body value If set, the RLP of the transactions (block body) will be written to this file. - --input.txs stdin stdin or file name of where to find the transactions to apply. If the file prefix is '.rlp', then the data is interpreted as an RLP list of signed transactions.The '.rlp' format is identical to the output.body format. (default: "txs.json") - --state.fork value Name of ruleset to use. - --state.chainid value ChainID to use (default: 1) - --state.reward value Mining reward. Set to -1 to disable (default: 0) +##### `result` + +The `result` object is output after a transition is executed. It includes +information about the post-transition environment. +```go +type ExecutionResult struct { + StateRoot common.Hash `json:"stateRoot"` + TxRoot common.Hash `json:"txRoot"` + ReceiptRoot common.Hash `json:"receiptsRoot"` + LogsHash common.Hash `json:"logsHash"` + Bloom types.Bloom `json:"logsBloom"` + Receipts types.Receipts `json:"receipts"` + Rejected []*rejectedTx `json:"rejected,omitempty"` + Difficulty *big.Int `json:"currentDifficulty"` + GasUsed uint64 `json:"gasUsed"` + BaseFee *big.Int `json:"currentBaseFee,omitempty"` +} ``` -### Error codes and output +#### Error codes and output All logging should happen against the `stderr`. There are a few (not many) errors that can occur, those are defined below. -#### EVM-based errors (`2` to `9`) +##### EVM-based errors (`2` to `9`) - Other EVM error. Exit code `2` - Failed configuration: when a non-supported or invalid fork was specified. Exit code `3`. @@ -58,18 +198,30 @@ There are a few (not many) errors that can occur, those are defined below. is invoked targeting a block which history has not been provided for, the program will exit with code `4`. -#### IO errors (`10`-`20`) +##### IO errors (`10`-`20`) - Invalid input json: the supplied data could not be marshalled. The program will exit with code `10` - IO problems: failure to load or save files, the program will exit with code `11` -## Examples +``` +# This should exit with 3 +./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Frontier+1346 2>/dev/null +exitcode:3 OK +``` +#### Forks ### Basic usage +The chain configuration to be used for a transition is specified via the +`--state.fork` CLI flag. A list of possible values and configurations can be +found in [`tests/init.go`](tests/init.go). + +#### Examples +##### Basic usage + Invoking it with the provided example files ``` -./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json +./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Berlin ``` Two resulting files: @@ -94,7 +246,7 @@ Two resulting files: { "stateRoot": "0x84208a19bc2b46ada7445180c1db162be5b39b9abc8c0a54b05d32943eae4e13", "txRoot": "0xc4761fd7b87ff2364c7c60b6c5c8d02e522e815328aaea3f20e3b7b7ef52c42d", - "receiptRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", + "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "receipts": [ @@ -116,78 +268,82 @@ Two resulting files: "index": 1, "error": "nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1" } - ] + ], + "currentDifficulty": "0x20000", + "gasUsed": "0x5208" } ``` We can make them spit out the data to e.g. `stdout` like this: ``` -./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.result=stdout --output.alloc=stdout +./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.result=stdout --output.alloc=stdout --state.fork=Berlin ``` Output: ```json { - "alloc": { - "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": { - "balance": "0xfeed1a9d", - "nonce": "0x1" - }, - "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0x5ffd4878be161d74", - "nonce": "0xac" + "alloc": { + "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": { + "balance": "0xfeed1a9d", + "nonce": "0x1" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x5ffd4878be161d74", + "nonce": "0xac" + }, + "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0xa410" + } }, - "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0xa410" - } - }, - "result": { - "stateRoot": "0x84208a19bc2b46ada7445180c1db162be5b39b9abc8c0a54b05d32943eae4e13", - "txRoot": "0xc4761fd7b87ff2364c7c60b6c5c8d02e522e815328aaea3f20e3b7b7ef52c42d", - "receiptRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", - "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "receipts": [ - { - "root": "0x", - "status": "0x1", - "cumulativeGasUsed": "0x5208", + "result": { + "stateRoot": "0x84208a19bc2b46ada7445180c1db162be5b39b9abc8c0a54b05d32943eae4e13", + "txRoot": "0xc4761fd7b87ff2364c7c60b6c5c8d02e522e815328aaea3f20e3b7b7ef52c42d", + "receiptsRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "logs": null, - "transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673", - "contractAddress": "0x0000000000000000000000000000000000000000", - "gasUsed": "0x5208", - "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "transactionIndex": "0x0" - } - ], - "rejected": [ - { - "index": 1, - "error": "nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1" - } - ] - } + "receipts": [ + { + "root": "0x", + "status": "0x1", + "cumulativeGasUsed": "0x5208", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x5208", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + } + ], + "rejected": [ + { + "index": 1, + "error": "nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1" + } + ], + "currentDifficulty": "0x20000", + "gasUsed": "0x5208" + } } ``` -## About Ommers +#### About Ommers Mining rewards and ommer rewards might need to be added. This is how those are applied: - `block_reward` is the block mining reward for the miner (`0xaa`), of a block at height `N`. - For each ommer (mined by `0xbb`), with blocknumber `N-delta` - - (where `delta` is the difference between the current block and the ommer) - - The account `0xbb` (ommer miner) is awarded `(8-delta)/ 8 * block_reward` - - The account `0xaa` (block miner) is awarded `block_reward / 32` + - (where `delta` is the difference between the current block and the ommer) + - The account `0xbb` (ommer miner) is awarded `(8-delta)/ 8 * block_reward` + - The account `0xaa` (block miner) is awarded `block_reward / 32` -To make `state_t8n` apply these, the following inputs are required: +To make `t8n` apply these, the following inputs are required: -- `state.reward` +- `--state.reward` - For ethash, it is `5000000000000000000` `wei`, - If this is not defined, mining rewards are not applied, - A value of `0` is valid, and causes accounts to be 'touched'. -- For each ommer, the tool needs to be given an `address` and a `delta`. This - is done via the `env`. +- For each ommer, the tool needs to be given an `addres\` and a `delta`. This + is done via the `ommers` field in `env`. Note: the tool does not verify that e.g. the normal uncle rules apply, and allows e.g two uncles at the same height, or the uncle-distance. This means that @@ -208,42 +364,38 @@ Example: ] } ``` -When applying this, using a reward of `0x80` +When applying this, using a reward of `0x08` Output: ```json { - "alloc": { - "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": { - "balance": "0x88" - }, - "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": { - "balance": "0x70" - }, - "0xcccccccccccccccccccccccccccccccccccccccc": { - "balance": "0x60" + "alloc": { + "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": { + "balance": "0x88" + }, + "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": { + "balance": "0x70" + }, + "0xcccccccccccccccccccccccccccccccccccccccc": { + "balance": "0x60" + } } - } } ``` -### Future EIPS +#### Future EIPS It is also possible to experiment with future eips that are not yet defined in a hard fork. -Example, putting EIP-1344 into Frontier: +Example, putting EIP-1344 into Frontier: ``` ./evm t8n --state.fork=Frontier+1344 --input.pre=./testdata/1/pre.json --input.txs=./testdata/1/txs.json --input.env=/testdata/1/env.json ``` -### Block history +#### Block history The `BLOCKHASH` opcode requires blockhashes to be provided by the caller, inside the `env`. If a required blockhash is not provided, the exit code should be `4`: -Example where blockhashes are provided: +Example where blockhashes are provided: ``` -./evm --verbosity=1 t8n --input.alloc=./testdata/3/alloc.json --input.txs=./testdata/3/txs.json --input.env=./testdata/3/env.json --trace -INFO [07-27|11:53:40.960] Trie dumping started root=b7341d..857ea1 -INFO [07-27|11:53:40.960] Trie dumping complete accounts=3 elapsed="103.298µs" -INFO [07-27|11:53:40.960] Wrote file file=alloc.json -INFO [07-27|11:53:40.960] Wrote file file=result.json +./evm t8n --input.alloc=./testdata/3/alloc.json --input.txs=./testdata/3/txs.json --input.env=./testdata/3/env.json --trace --state.fork=Berlin ``` @@ -251,44 +403,34 @@ INFO [07-27|11:53:40.960] Wrote file file=result.j cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2 ``` ``` -{"pc":0,"op":96,"gas":"0x5f58ef8","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":2,"op":64,"gas":"0x5f58ef5","gasCost":"0x14","memory":"0x","memSize":0,"stack":["0x1"],"returnData":"0x","depth":1,"refund":0,"opName":"BLOCKHASH","error":""} -{"pc":3,"op":0,"gas":"0x5f58ee1","gasCost":"0x0","memory":"0x","memSize":0,"stack":["0xdac58aa524e50956d0c0bae7f3f8bb9d35381365d07804dd5b48a5a297c06af4"],"returnData":"0x","depth":1,"refund":0,"opName":"STOP","error":""} -{"output":"","gasUsed":"0x17","time":156276} +{"pc":0,"op":96,"gas":"0x5f58ef8","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"} +{"pc":2,"op":64,"gas":"0x5f58ef5","gasCost":"0x14","memSize":0,"stack":["0x1"],"depth":1,"refund":0,"opName":"BLOCKHASH"} +{"pc":3,"op":0,"gas":"0x5f58ee1","gasCost":"0x0","memSize":0,"stack":["0xdac58aa524e50956d0c0bae7f3f8bb9d35381365d07804dd5b48a5a297c06af4"],"depth":1,"refund":0,"opName":"STOP"} +{"output":"","gasUsed":"0x17"} ``` In this example, the caller has not provided the required blockhash: ``` -./evm t8n --input.alloc=./testdata/4/alloc.json --input.txs=./testdata/4/txs.json --input.env=./testdata/4/env.json --trace +./evm t8n --input.alloc=./testdata/4/alloc.json --input.txs=./testdata/4/txs.json --input.env=./testdata/4/env.json --trace --state.fork=Berlin ERROR(4): getHash(3) invoked, blockhash for that block not provided ``` Error code: 4 -### Chaining +#### Chaining Another thing that can be done, is to chain invocations: ``` -./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.alloc=stdout | ./evm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json -INFO [07-27|11:53:41.049] rejected tx index=1 hash=0557ba..18d673 from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1" -INFO [07-27|11:53:41.050] Trie dumping started root=84208a..ae4e13 -INFO [07-27|11:53:41.050] Trie dumping complete accounts=3 elapsed="59.412µs" -INFO [07-27|11:53:41.050] Wrote file file=result.json -INFO [07-27|11:53:41.051] rejected tx index=0 hash=0557ba..18d673 from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1" -INFO [07-27|11:53:41.051] rejected tx index=1 hash=0557ba..18d673 from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1" -INFO [07-27|11:53:41.052] Trie dumping started root=84208a..ae4e13 -INFO [07-27|11:53:41.052] Trie dumping complete accounts=3 elapsed="45.734µs" -INFO [07-27|11:53:41.052] Wrote file file=alloc.json -INFO [07-27|11:53:41.052] Wrote file file=result.json +./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Berlin --output.alloc=stdout | ./evm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json --state.fork=Berlin ``` -What happened here, is that we first applied two identical transactions, so the second one was rejected. +What happened here, is that we first applied two identical transactions, so the second one was rejected. Then, taking the poststate alloc as the input for the next state, we tried again to include the same two transactions: this time, both failed due to too low nonce. In order to meaningfully chain invocations, one would need to provide meaningful new `env`, otherwise the actual blocknumber (exposed to the EVM) would not increase. -### Transactions in RLP form +#### Transactions in RLP form It is possible to provide already-signed transactions as input to, using an `input.txs` which ends with the `rlp` suffix. The input format for RLP-form transactions is _identical_ to the _output_ format for block bodies. Therefore, it's fully possible @@ -297,12 +439,11 @@ to use the evm to go from `json` input to `rlp` input. The following command takes **json** the transactions in `./testdata/13/txs.json` and signs them. After execution, they are output to `signed_txs.rlp`.: ``` ./evm t8n --state.fork=London --input.alloc=./testdata/13/alloc.json --input.txs=./testdata/13/txs.json --input.env=./testdata/13/env.json --output.result=alloc_jsontx.json --output.body=signed_txs.rlp -INFO [07-27|11:53:41.124] Trie dumping started root=e4b924..6aef61 -INFO [07-27|11:53:41.124] Trie dumping complete accounts=3 elapsed="94.284µs" -INFO [07-27|11:53:41.125] Wrote file file=alloc.json -INFO [07-27|11:53:41.125] Wrote file file=alloc_jsontx.json -INFO [07-27|11:53:41.125] Wrote file file=signed_txs.rlp - +INFO [12-07|04:30:12.380] Trie dumping started root=e4b924..6aef61 +INFO [12-07|04:30:12.380] Trie dumping complete accounts=3 elapsed="85.765µs" +INFO [12-07|04:30:12.380] Wrote file file=alloc.json +INFO [12-07|04:30:12.380] Wrote file file=alloc_jsontx.json +INFO [12-07|04:30:12.380] Wrote file file=signed_txs.rlp ``` The `output.body` is the rlp-list of transactions, encoded in hex and placed in a string a'la `json` encoding rules: @@ -311,7 +452,7 @@ cat signed_txs.rlp "0xf8d2b86702f864010180820fa08284d09411111111111111111111111111111111111111118080c001a0b7dfab36232379bb3d1497a4f91c1966b1f932eae3ade107bf5d723b9cb474e0a06261c359a10f2132f126d250485b90cf20f30340801244a08ef6142ab33d1904b86702f864010280820fa08284d09411111111111111111111111111111111111111118080c080a0d4ec563b6568cd42d998fc4134b36933c6568d01533b5adf08769270243c6c7fa072bf7c21eac6bbeae5143371eef26d5e279637f3bd73482b55979d76d935b1e9" ``` -We can use `rlpdump` to check what the contents are: +We can use `rlpdump` to check what the contents are: ``` rlpdump -hex $(cat signed_txs.rlp | jq -r ) [ @@ -319,17 +460,15 @@ rlpdump -hex $(cat signed_txs.rlp | jq -r ) 02f864010280820fa08284d09411111111111111111111111111111111111111118080c080a0d4ec563b6568cd42d998fc4134b36933c6568d01533b5adf08769270243c6c7fa072bf7c21eac6bbeae5143371eef26d5e279637f3bd73482b55979d76d935b1e9, ] ``` -Now, we can now use those (or any other already signed transactions), as input, like so: +Now, we can now use those (or any other already signed transactions), as input, like so: ``` ./evm t8n --state.fork=London --input.alloc=./testdata/13/alloc.json --input.txs=./signed_txs.rlp --input.env=./testdata/13/env.json --output.result=alloc_rlptx.json -INFO [07-27|11:53:41.253] Trie dumping started root=e4b924..6aef61 -INFO [07-27|11:53:41.253] Trie dumping complete accounts=3 elapsed="128.445µs" -INFO [07-27|11:53:41.253] Wrote file file=alloc.json -INFO [07-27|11:53:41.255] Wrote file file=alloc_rlptx.json - +INFO [12-07|04:30:12.425] Trie dumping started root=e4b924..6aef61 +INFO [12-07|04:30:12.425] Trie dumping complete accounts=3 elapsed="70.684µs" +INFO [12-07|04:30:12.425] Wrote file file=alloc.json +INFO [12-07|04:30:12.425] Wrote file file=alloc_rlptx.json ``` - -You might have noticed that the results from these two invocations were stored in two separate files. +You might have noticed that the results from these two invocations were stored in two separate files. And we can now finally check that they match. ``` cat alloc_jsontx.json | jq .stateRoot && cat alloc_rlptx.json | jq .stateRoot diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index 031def0211b1..b7a0d9c2c3c7 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -230,7 +230,7 @@ func TestT8n(t *testing.T) { { // Test post-merge transition base: "./testdata/24", input: t8nInput{ - "alloc.json", "txs.json", "env.json", "Merged", "", + "alloc.json", "txs.json", "env.json", "Merge", "", }, output: t8nOutput{alloc: true, result: true}, expOut: "exp.json", @@ -238,7 +238,7 @@ func TestT8n(t *testing.T) { { // Test post-merge transition where input is missing random base: "./testdata/24", input: t8nInput{ - "alloc.json", "txs.json", "env-missingrandom.json", "Merged", "", + "alloc.json", "txs.json", "env-missingrandom.json", "Merge", "", }, output: t8nOutput{alloc: false, result: false}, expExitCode: 3, @@ -246,7 +246,7 @@ func TestT8n(t *testing.T) { { // Test base fee calculation base: "./testdata/25", input: t8nInput{ - "alloc.json", "txs.json", "env.json", "Merged", "", + "alloc.json", "txs.json", "env.json", "Merge", "", }, output: t8nOutput{alloc: true, result: true}, expOut: "exp.json", diff --git a/cmd/evm/transition-test.sh b/cmd/evm/transition-test.sh index 250238d1694a..8d7fd799732c 100644 --- a/cmd/evm/transition-test.sh +++ b/cmd/evm/transition-test.sh @@ -20,10 +20,24 @@ function tick(){ echo "$ticks" } -cat << EOF -## EVM state transition tool +function code(){ + echo "$ticks$1" +} + +cat << "EOF" +# EVM tool + +The EVM tool provides a few useful subcommands to facilitate testing at the EVM +layer. + +* transition tool (`t8n`) : a stateless state transition utility +* transaction tool (`t9n`) : a transaction validation utility +* block builder tool (`b11r`): a block assembler utility -The \`evm t8n\` tool is a stateless state transition utility. It is a utility +## State transition tool (`t8n`) + + +The `evm t8n` tool is a stateless state transition utility. It is a utility which can 1. Take a prestate, including @@ -37,55 +51,200 @@ which can - Information about rejected transactions, - Optionally: a full or partial post-state dump -## Specification +### Specification The idea is to specify the behaviour of this binary very _strict_, so that other node implementors can build replicas based on their own state-machines, and the state generators can swap between a \`geth\`-based implementation and a \`parityvm\`-based implementation. -### Command line params +#### Command line params -Command line params that has to be supported are -$(tick) +Command line params that need to be supported are -` ./evm t8n -h | grep "trace\|output\|state\."` - -$(tick) +``` +EOF +./evm t8n -h | grep "\-\-trace\.\|\-\-output\.\|\-\-state\.\|\-\-input" +cat << "EOF" +``` +#### Objects + +The transition tool uses JSON objects to read and write data related to the transition operation. The +following object definitions are required. + +##### `alloc` + +The `alloc` object defines the prestate that transition will begin with. + +```go +// Map of address to account definition. +type Alloc map[common.Address]Account +// Genesis account. Each field is optional. +type Account struct { + Code []byte `json:"code"` + Storage map[common.Hash]common.Hash `json:"storage"` + Balance *big.Int `json:"balance"` + Nonce uint64 `json:"nonce"` + SecretKey []byte `json:"secretKey"` +} +``` + +##### `env` + +The `env` object defines the environmental context in which the transition will +take place. + +```go +type Env struct { + // required + CurrentCoinbase common.Address `json:"currentCoinbase"` + CurrentGasLimit uint64 `json:"currentGasLimit"` + CurrentNumber uint64 `json:"currentNumber"` + CurrentTimestamp uint64 `json:"currentTimestamp"` + Withdrawals []*Withdrawal `json:"withdrawals"` + // optional + CurrentDifficulty *big.Int `json:"currentDifficuly"` + CurrentRandom *big.Int `json:"currentRandom"` + CurrentBaseFee *big.Int `json:"currentBaseFee"` + ParentDifficulty *big.Int `json:"parentDifficulty"` + ParentGasUsed uint64 `json:"parentGasUsed"` + ParentGasLimit uint64 `json:"parentGasLimit"` + ParentTimestamp uint64 `json:"parentTimestamp"` + BlockHashes map[uint64]common.Hash `json:"blockHashes"` + ParentUncleHash common.Hash `json:"parentUncleHash"` + Ommers []Ommer `json:"ommers"` +} +type Ommer struct { + Delta uint64 `json:"delta"` + Address common.Address `json:"address"` +} +type Withdrawal struct { + Index uint64 `json:"index"` + ValidatorIndex uint64 `json:"validatorIndex"` + Recipient common.Address `json:"recipient"` + Amount *big.Int `json:"amount"` +} +``` + +##### `txs` + +The `txs` object is an array of any of the transaction types: `LegacyTx`, +`AccessListTx`, or `DynamicFeeTx`. + +```go +type LegacyTx struct { + Nonce uint64 `json:"nonce"` + GasPrice *big.Int `json:"gasPrice"` + Gas uint64 `json:"gas"` + To *common.Address `json:"to"` + Value *big.Int `json:"value"` + Data []byte `json:"data"` + V *big.Int `json:"v"` + R *big.Int `json:"r"` + S *big.Int `json:"s"` + SecretKey *common.Hash `json:"secretKey"` +} +type AccessList []AccessTuple +type AccessTuple struct { + Address common.Address `json:"address" gencodec:"required"` + StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"` +} +type AccessListTx struct { + ChainID *big.Int `json:"chainId"` + Nonce uint64 `json:"nonce"` + GasPrice *big.Int `json:"gasPrice"` + Gas uint64 `json:"gas"` + To *common.Address `json:"to"` + Value *big.Int `json:"value"` + Data []byte `json:"data"` + AccessList AccessList `json:"accessList"` + V *big.Int `json:"v"` + R *big.Int `json:"r"` + S *big.Int `json:"s"` + SecretKey *common.Hash `json:"secretKey"` +} +type DynamicFeeTx struct { + ChainID *big.Int `json:"chainId"` + Nonce uint64 `json:"nonce"` + GasTipCap *big.Int `json:"maxPriorityFeePerGas"` + GasFeeCap *big.Int `json:"maxFeePerGas"` + Gas uint64 `json:"gas"` + To *common.Address `json:"to"` + Value *big.Int `json:"value"` + Data []byte `json:"data"` + AccessList AccessList `json:"accessList"` + V *big.Int `json:"v"` + R *big.Int `json:"r"` + S *big.Int `json:"s"` + SecretKey *common.Hash `json:"secretKey"` +} +``` + +##### `result` + +The `result` object is output after a transition is executed. It includes +information about the post-transition environment. + +```go +type ExecutionResult struct { + StateRoot common.Hash `json:"stateRoot"` + TxRoot common.Hash `json:"txRoot"` + ReceiptRoot common.Hash `json:"receiptsRoot"` + LogsHash common.Hash `json:"logsHash"` + Bloom types.Bloom `json:"logsBloom"` + Receipts types.Receipts `json:"receipts"` + Rejected []*rejectedTx `json:"rejected,omitempty"` + Difficulty *big.Int `json:"currentDifficulty"` + GasUsed uint64 `json:"gasUsed"` + BaseFee *big.Int `json:"currentBaseFee,omitempty"` +} +``` -### Error codes and output +#### Error codes and output -All logging should happen against the \`stderr\`. +All logging should happen against the `stderr`. There are a few (not many) errors that can occur, those are defined below. -#### EVM-based errors (\`2\` to \`9\`) +##### EVM-based errors (`2` to `9`) -- Other EVM error. Exit code \`2\` -- Failed configuration: when a non-supported or invalid fork was specified. Exit code \`3\`. -- Block history is not supplied, but needed for a \`BLOCKHASH\` operation. If \`BLOCKHASH\` +- Other EVM error. Exit code `2` +- Failed configuration: when a non-supported or invalid fork was specified. Exit code `3`. +- Block history is not supplied, but needed for a `BLOCKHASH` operation. If `BLOCKHASH` is invoked targeting a block which history has not been provided for, the program will - exit with code \`4\`. + exit with code `4`. -#### IO errors (\`10\`-\`20\`) +##### IO errors (`10`-`20`) - Invalid input json: the supplied data could not be marshalled. - The program will exit with code \`10\` -- IO problems: failure to load or save files, the program will exit with code \`11\` - -EOF + The program will exit with code `10` +- IO problems: failure to load or save files, the program will exit with code `11` +``` # This should exit with 3 ./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Frontier+1346 2>/dev/null -if [ $? != 3 ]; then - echo "Failed, exitcode should be 3" +EOF +./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Frontier+1346 2>/dev/null +exitcode=$? +if [ $exitcode != 3 ]; then + echo "Failed, exitcode should be 3,was $exitcode" +else + echo "exitcode:$exitcode OK" fi -cat << EOF -## Examples +cat << "EOF" +``` +#### Forks ### Basic usage +The chain configuration to be used for a transition is specified via the +`--state.fork` CLI flag. A list of possible values and configurations can be +found in [`tests/init.go`](tests/init.go). + +#### Examples +##### Basic usage + Invoking it with the provided example files EOF -cmd="./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json" +cmd="./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Berlin" tick;echo "$cmd"; tick $cmd 2>/dev/null echo "Two resulting files:" @@ -95,7 +254,7 @@ showjson result.json echo "" echo "We can make them spit out the data to e.g. \`stdout\` like this:" -cmd="./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.result=stdout --output.alloc=stdout" +cmd="./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.result=stdout --output.alloc=stdout --state.fork=Berlin" tick;echo "$cmd"; tick output=`$cmd 2>/dev/null` echo "Output:" @@ -103,26 +262,26 @@ echo "${ticks}json" echo "$output" echo "$ticks" -cat << EOF +cat << "EOF" -## About Ommers +#### About Ommers Mining rewards and ommer rewards might need to be added. This is how those are applied: -- \`block_reward\` is the block mining reward for the miner (\`0xaa\`), of a block at height \`N\`. -- For each ommer (mined by \`0xbb\`), with blocknumber \`N-delta\` - - (where \`delta\` is the difference between the current block and the ommer) - - The account \`0xbb\` (ommer miner) is awarded \`(8-delta)/ 8 * block_reward\` - - The account \`0xaa\` (block miner) is awarded \`block_reward / 32\` +- `block_reward` is the block mining reward for the miner (`0xaa`), of a block at height `N`. +- For each ommer (mined by `0xbb`), with blocknumber `N-delta` + - (where `delta` is the difference between the current block and the ommer) + - The account `0xbb` (ommer miner) is awarded `(8-delta)/ 8 * block_reward` + - The account `0xaa` (block miner) is awarded `block_reward / 32` -To make \`state_t8n\` apply these, the following inputs are required: +To make `t8n` apply these, the following inputs are required: -- \`state.reward\` - - For ethash, it is \`5000000000000000000\` \`wei\`, +- `--state.reward` + - For ethash, it is `5000000000000000000` `wei`, - If this is not defined, mining rewards are not applied, - - A value of \`0\` is valid, and causes accounts to be 'touched'. -- For each ommer, the tool needs to be given an \`address\` and a \`delta\`. This - is done via the \`env\`. + - A value of `0` is valid, and causes accounts to be 'touched'. +- For each ommer, the tool needs to be given an `addres\` and a `delta`. This + is done via the `ommers` field in `env`. Note: the tool does not verify that e.g. the normal uncle rules apply, and allows e.g two uncles at the same height, or the uncle-distance. This means that @@ -134,14 +293,14 @@ EOF showjson ./testdata/5/env.json echo "When applying this, using a reward of \`0x08\`" -cmd="./evm t8n --input.alloc=./testdata/5/alloc.json -input.txs=./testdata/5/txs.json --input.env=./testdata/5/env.json --output.alloc=stdout --state.reward=0x80" +cmd="./evm t8n --input.alloc=./testdata/5/alloc.json -input.txs=./testdata/5/txs.json --input.env=./testdata/5/env.json --output.alloc=stdout --state.reward=0x80 --state.fork=Berlin" output=`$cmd 2>/dev/null` echo "Output:" echo "${ticks}json" echo "$output" echo "$ticks" -echo "### Future EIPS" +echo "#### Future EIPS" echo "" echo "It is also possible to experiment with future eips that are not yet defined in a hard fork." echo "Example, putting EIP-1344 into Frontier: " @@ -149,12 +308,12 @@ cmd="./evm t8n --state.fork=Frontier+1344 --input.pre=./testdata/1/pre.json --in tick;echo "$cmd"; tick echo "" -echo "### Block history" +echo "#### Block history" echo "" echo "The \`BLOCKHASH\` opcode requires blockhashes to be provided by the caller, inside the \`env\`." echo "If a required blockhash is not provided, the exit code should be \`4\`:" echo "Example where blockhashes are provided: " -demo "./evm --verbosity=1 t8n --input.alloc=./testdata/3/alloc.json --input.txs=./testdata/3/txs.json --input.env=./testdata/3/env.json --trace" +demo "./evm t8n --input.alloc=./testdata/3/alloc.json --input.txs=./testdata/3/txs.json --input.env=./testdata/3/env.json --trace --state.fork=Berlin" cmd="cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2" tick && echo $cmd && tick echo "$ticks" @@ -163,18 +322,18 @@ echo "$ticks" echo "" echo "In this example, the caller has not provided the required blockhash:" -cmd="./evm t8n --input.alloc=./testdata/4/alloc.json --input.txs=./testdata/4/txs.json --input.env=./testdata/4/env.json --trace" -tick && echo $cmd && $cmd +cmd="./evm t8n --input.alloc=./testdata/4/alloc.json --input.txs=./testdata/4/txs.json --input.env=./testdata/4/env.json --trace --state.fork=Berlin" +tick && echo $cmd && $cmd 2>&1 errc=$? tick echo "Error code: $errc" echo "" -echo "### Chaining" +echo "#### Chaining" echo "" echo "Another thing that can be done, is to chain invocations:" -cmd1="./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.alloc=stdout" -cmd2="./evm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json" +cmd1="./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Berlin --output.alloc=stdout" +cmd2="./evm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json --state.fork=Berlin" echo "$ticks" echo "$cmd1 | $cmd2" output=$($cmd1 | $cmd2 ) @@ -188,14 +347,19 @@ echo "In order to meaningfully chain invocations, one would need to provide mean echo "actual blocknumber (exposed to the EVM) would not increase." echo "" -echo "### Transactions in RLP form" +echo "#### Transactions in RLP form" echo "" echo "It is possible to provide already-signed transactions as input to, using an \`input.txs\` which ends with the \`rlp\` suffix." echo "The input format for RLP-form transactions is _identical_ to the _output_ format for block bodies. Therefore, it's fully possible" echo "to use the evm to go from \`json\` input to \`rlp\` input." echo "" echo "The following command takes **json** the transactions in \`./testdata/13/txs.json\` and signs them. After execution, they are output to \`signed_txs.rlp\`.:" -demo "./evm t8n --state.fork=London --input.alloc=./testdata/13/alloc.json --input.txs=./testdata/13/txs.json --input.env=./testdata/13/env.json --output.result=alloc_jsontx.json --output.body=signed_txs.rlp" +cmd="./evm t8n --state.fork=London --input.alloc=./testdata/13/alloc.json --input.txs=./testdata/13/txs.json --input.env=./testdata/13/env.json --output.result=alloc_jsontx.json --output.body=signed_txs.rlp" +echo "$ticks" +echo $cmd +$cmd 2>&1 +echo "$ticks" +echo "" echo "The \`output.body\` is the rlp-list of transactions, encoded in hex and placed in a string a'la \`json\` encoding rules:" demo "cat signed_txs.rlp" echo "We can use \`rlpdump\` to check what the contents are: " @@ -204,8 +368,11 @@ echo "rlpdump -hex \$(cat signed_txs.rlp | jq -r )" rlpdump -hex $(cat signed_txs.rlp | jq -r ) echo "$ticks" echo "Now, we can now use those (or any other already signed transactions), as input, like so: " -demo "./evm t8n --state.fork=London --input.alloc=./testdata/13/alloc.json --input.txs=./signed_txs.rlp --input.env=./testdata/13/env.json --output.result=alloc_rlptx.json" - +cmd="./evm t8n --state.fork=London --input.alloc=./testdata/13/alloc.json --input.txs=./signed_txs.rlp --input.env=./testdata/13/env.json --output.result=alloc_rlptx.json" +echo "$ticks" +echo $cmd +$cmd 2>&1 +echo "$ticks" echo "You might have noticed that the results from these two invocations were stored in two separate files. " echo "And we can now finally check that they match." echo "$ticks" diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 6d108856e6d6..274b9cf3603e 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -95,44 +95,71 @@ func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *ty return beacon.verifyHeader(chain, header, parent) } -// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers -// concurrently. The method returns a quit channel to abort the operations and -// a results channel to retrieve the async verifications. -// VerifyHeaders expect the headers to be ordered and continuous. -func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { - if !beacon.IsPoSHeader(headers[len(headers)-1]) { - return beacon.ethone.VerifyHeaders(chain, headers, seals) +// errOut constructs an error channel with prefilled errors inside. +func errOut(n int, err error) chan error { + errs := make(chan error, n) + for i := 0; i < n; i++ { + errs <- err + } + return errs +} + +// splitHeaders splits the provided header batch into two parts according to +// the configured ttd. It requires the parent of header batch along with its +// td are stored correctly in chain. If ttd is not configured yet, all headers +// will be treated legacy PoW headers. +// Note, this function will not verify the header validity but just split them. +func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) ([]*types.Header, []*types.Header, error) { + // TTD is not defined yet, all headers should be in legacy format. + ttd := chain.Config().TerminalTotalDifficulty + if ttd == nil { + return headers, nil, nil + } + ptd := chain.GetTd(headers[0].ParentHash, headers[0].Number.Uint64()-1) + if ptd == nil { + return nil, nil, consensus.ErrUnknownAncestor + } + // The entire header batch already crosses the transition. + if ptd.Cmp(ttd) >= 0 { + return nil, headers, nil } var ( - preHeaders []*types.Header + preHeaders = headers postHeaders []*types.Header - preSeals []bool + td = new(big.Int).Set(ptd) + tdPassed bool ) - for index, header := range headers { - if beacon.IsPoSHeader(header) { - preHeaders = headers[:index] - postHeaders = headers[index:] - preSeals = seals[:index] + for i, header := range headers { + if tdPassed { + preHeaders = headers[:i] + postHeaders = headers[i:] break } + td = td.Add(td, header.Difficulty) + if td.Cmp(ttd) >= 0 { + // This is the last PoW header, it still belongs to + // the preHeaders, so we cannot split+break yet. + tdPassed = true + } } + return preHeaders, postHeaders, nil +} +// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers +// concurrently. The method returns a quit channel to abort the operations and +// a results channel to retrieve the async verifications. +// VerifyHeaders expect the headers to be ordered and continuous. +func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { + preHeaders, postHeaders, err := beacon.splitHeaders(chain, headers) + if err != nil { + return make(chan struct{}), errOut(len(headers), err) + } + if len(postHeaders) == 0 { + return beacon.ethone.VerifyHeaders(chain, headers, seals) + } if len(preHeaders) == 0 { - // All the headers are pos headers. Verify that the parent block reached total terminal difficulty. - if reached, err := IsTTDReached(chain, headers[0].ParentHash, headers[0].Number.Uint64()-1); !reached { - // TTD not reached for the first block, mark subsequent with invalid terminal block - if err == nil { - err = consensus.ErrInvalidTerminalBlock - } - results := make(chan error, len(headers)) - for i := 0; i < len(headers); i++ { - results <- err - } - return make(chan struct{}), results - } return beacon.verifyHeaders(chain, headers, nil) } - // The transition point exists in the middle, separate the headers // into two batches and apply different verification rules for them. var ( @@ -144,16 +171,9 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ old, new, out = 0, len(preHeaders), 0 errors = make([]error, len(headers)) done = make([]bool, len(headers)) - oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders, preSeals) + oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders, seals[:len(preHeaders)]) newDone, newResult = beacon.verifyHeaders(chain, postHeaders, preHeaders[len(preHeaders)-1]) ) - // Verify that pre-merge headers don't overflow the TTD - if index, err := verifyTerminalPoWBlock(chain, preHeaders); err != nil { - // Mark all subsequent pow headers with the error. - for i := index; i < len(preHeaders); i++ { - errors[i], done[i] = err, true - } - } // Collect the results for { for ; done[out]; out++ { @@ -181,33 +201,6 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ return abort, results } -// verifyTerminalPoWBlock verifies that the preHeaders conform to the specification -// wrt. their total difficulty. -// It expects: -// - preHeaders to be at least 1 element -// - the parent of the header element to be stored in the chain correctly -// - the preHeaders to have a set difficulty -// - the last element to be the terminal block -func verifyTerminalPoWBlock(chain consensus.ChainHeaderReader, preHeaders []*types.Header) (int, error) { - td := chain.GetTd(preHeaders[0].ParentHash, preHeaders[0].Number.Uint64()-1) - if td == nil { - return 0, consensus.ErrUnknownAncestor - } - td = new(big.Int).Set(td) - // Check that all blocks before the last one are below the TTD - for i, head := range preHeaders { - if td.Cmp(chain.Config().TerminalTotalDifficulty) >= 0 { - return i, consensus.ErrInvalidTerminalBlock - } - td.Add(td, head.Difficulty) - } - // Check that the last block is the terminal block - if td.Cmp(chain.Config().TerminalTotalDifficulty) < 0 { - return len(preHeaders) - 1, consensus.ErrInvalidTerminalBlock - } - return 0, nil -} - // VerifyUncles verifies that the given block's uncles conform to the consensus // rules of the Ethereum consensus engine. func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { @@ -419,11 +412,11 @@ func (beacon *Beacon) SetThreads(threads int) { // IsTTDReached checks if the TotalTerminalDifficulty has been surpassed on the `parentHash` block. // It depends on the parentHash already being stored in the database. // If the parentHash is not stored in the database a UnknownAncestor error is returned. -func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, number uint64) (bool, error) { +func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, parentNumber uint64) (bool, error) { if chain.Config().TerminalTotalDifficulty == nil { return false, nil } - td := chain.GetTd(parentHash, number) + td := chain.GetTd(parentHash, parentNumber) if td == nil { return false, consensus.ErrUnknownAncestor } diff --git a/consensus/beacon/consensus_test.go b/consensus/beacon/consensus_test.go deleted file mode 100644 index 09c0b27c4256..000000000000 --- a/consensus/beacon/consensus_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package beacon - -import ( - "fmt" - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" -) - -type mockChain struct { - config *params.ChainConfig - tds map[uint64]*big.Int -} - -func newMockChain() *mockChain { - return &mockChain{ - config: new(params.ChainConfig), - tds: make(map[uint64]*big.Int), - } -} - -func (m *mockChain) Config() *params.ChainConfig { - return m.config -} - -func (m *mockChain) CurrentHeader() *types.Header { panic("not implemented") } - -func (m *mockChain) GetHeader(hash common.Hash, number uint64) *types.Header { - panic("not implemented") -} - -func (m *mockChain) GetHeaderByNumber(number uint64) *types.Header { panic("not implemented") } - -func (m *mockChain) GetHeaderByHash(hash common.Hash) *types.Header { panic("not implemented") } - -func (m *mockChain) GetTd(hash common.Hash, number uint64) *big.Int { - num, ok := m.tds[number] - if ok { - return new(big.Int).Set(num) - } - return nil -} - -func TestVerifyTerminalBlock(t *testing.T) { - chain := newMockChain() - chain.tds[0] = big.NewInt(10) - chain.config.TerminalTotalDifficulty = big.NewInt(50) - - tests := []struct { - preHeaders []*types.Header - ttd *big.Int - err error - index int - }{ - // valid ttd - { - preHeaders: []*types.Header{ - {Number: big.NewInt(1), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(2), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(3), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(4), Difficulty: big.NewInt(10)}, - }, - ttd: big.NewInt(50), - }, - // last block doesn't reach ttd - { - preHeaders: []*types.Header{ - {Number: big.NewInt(1), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(2), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(3), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(4), Difficulty: big.NewInt(9)}, - }, - ttd: big.NewInt(50), - err: consensus.ErrInvalidTerminalBlock, - index: 3, - }, - // two blocks reach ttd - { - preHeaders: []*types.Header{ - {Number: big.NewInt(1), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(2), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(3), Difficulty: big.NewInt(20)}, - {Number: big.NewInt(4), Difficulty: big.NewInt(10)}, - }, - ttd: big.NewInt(50), - err: consensus.ErrInvalidTerminalBlock, - index: 3, - }, - // three blocks reach ttd - { - preHeaders: []*types.Header{ - {Number: big.NewInt(1), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(2), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(3), Difficulty: big.NewInt(20)}, - {Number: big.NewInt(4), Difficulty: big.NewInt(10)}, - {Number: big.NewInt(4), Difficulty: big.NewInt(10)}, - }, - ttd: big.NewInt(50), - err: consensus.ErrInvalidTerminalBlock, - index: 3, - }, - // parent reached ttd - { - preHeaders: []*types.Header{ - {Number: big.NewInt(1), Difficulty: big.NewInt(10)}, - }, - ttd: big.NewInt(9), - err: consensus.ErrInvalidTerminalBlock, - index: 0, - }, - // unknown parent - { - preHeaders: []*types.Header{ - {Number: big.NewInt(4), Difficulty: big.NewInt(10)}, - }, - ttd: big.NewInt(9), - err: consensus.ErrUnknownAncestor, - index: 0, - }, - } - - for i, test := range tests { - fmt.Printf("Test: %v\n", i) - chain.config.TerminalTotalDifficulty = test.ttd - index, err := verifyTerminalPoWBlock(chain, test.preHeaders) - if err != test.err { - t.Fatalf("Invalid error encountered, expected %v got %v", test.err, err) - } - if index != test.index { - t.Fatalf("Invalid index, expected %v got %v", test.index, index) - } - } -} diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 3bdb20e7e1e7..3e951d56a23f 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -17,7 +17,6 @@ package core import ( - "encoding/json" "math/big" "runtime" "testing" @@ -135,31 +134,29 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { config := *params.TestChainConfig gspec = &Genesis{Config: &config} engine = beacon.New(ethash.NewFaker()) - - td := 0 + td := int(params.GenesisDifficulty.Uint64()) genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 8, nil) - for _, block := range preBlocks { + for _, block := range blocks { // calculate td td += int(block.Difficulty().Uint64()) } preBlocks = blocks gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(td)) - postBlocks, _ = GenerateChain(gspec.Config, preBlocks[len(preBlocks)-1], engine, genDb, 8, nil) + t.Logf("Set ttd to %v\n", gspec.Config.TerminalTotalDifficulty) + postBlocks, _ = GenerateChain(gspec.Config, preBlocks[len(preBlocks)-1], engine, genDb, 8, func(i int, gen *BlockGen) { + gen.SetPoS() + }) } // Assemble header batch preHeaders := make([]*types.Header, len(preBlocks)) for i, block := range preBlocks { preHeaders[i] = block.Header() - - blob, _ := json.Marshal(block.Header()) - t.Logf("Log header before the merging %d: %v", block.NumberU64(), string(blob)) + t.Logf("Pre-merge header: %d", block.NumberU64()) } postHeaders := make([]*types.Header, len(postBlocks)) for i, block := range postBlocks { postHeaders[i] = block.Header() - - blob, _ := json.Marshal(block.Header()) - t.Logf("Log header after the merging %d: %v", block.NumberU64(), string(blob)) + t.Logf("Post-merge header: %d", block.NumberU64()) } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) @@ -172,15 +169,15 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { select { case result := <-results: if result != nil { - t.Errorf("test %d: verification failed %v", i, result) + t.Errorf("pre-block %d: verification failed %v", i, result) } case <-time.After(time.Second): - t.Fatalf("test %d: verification timeout", i) + t.Fatalf("pre-block %d: verification timeout", i) } // Make sure no more data is returned select { case result := <-results: - t.Fatalf("test %d: unexpected result returned: %v", i, result) + t.Fatalf("pre-block %d: unexpected result returned: %v", i, result) case <-time.After(25 * time.Millisecond): } chain.InsertChain(preBlocks[i : i+1]) @@ -197,7 +194,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { select { case result := <-results: if result != nil { - t.Errorf("test %d: verification failed %v", i, result) + t.Errorf("post-block %d: verification failed %v", i, result) } case <-time.After(time.Second): t.Fatalf("test %d: verification timeout", i) @@ -205,7 +202,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { // Make sure no more data is returned select { case result := <-results: - t.Fatalf("test %d: unexpected result returned: %v", i, result) + t.Fatalf("post-block %d: unexpected result returned: %v", i, result) case <-time.After(25 * time.Millisecond): } chain.InsertBlockWithoutSetHead(postBlocks[i]) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index faa4b383feb4..d803617e2f75 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1959,7 +1959,8 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon Alloc: GenesisAlloc{addr: {Balance: big.NewInt(math.MaxInt64)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - signer = types.LatestSigner(gspec.Config) + signer = types.LatestSigner(gspec.Config) + mergeBlock = math.MaxInt32 ) // Generate and import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) @@ -1970,6 +1971,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Activate the transition since genesis if required if mergePoint == 0 { + mergeBlock = 0 merger.ReachTTD() merger.FinalizePoS() @@ -1982,6 +1984,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon t.Fatalf("failed to create tx: %v", err) } gen.AddTx(tx) + if int(gen.header.Number.Uint64()) >= mergeBlock { + gen.SetPoS() + } nonce++ }) if n, err := chain.InsertChain(blocks); err != nil { @@ -2006,7 +2011,10 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon merger.ReachTTD() merger.FinalizePoS() // Set the terminal total difficulty in the config - gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(len(blocks))) + ttd := big.NewInt(int64(len(blocks))) + ttd.Mul(ttd, params.GenesisDifficulty) + gspec.Config.TerminalTotalDifficulty = ttd + mergeBlock = len(blocks) } // Generate the sidechain @@ -2018,6 +2026,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon parent := blocks[parentIndex] fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) + if int(b.header.Number.Uint64()) >= mergeBlock { + b.SetPoS() + } }) // Prepend the parent(s) var sidechain []*types.Block @@ -2226,25 +2237,45 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i BaseFee: big.NewInt(params.InitialBaseFee), Config: &chainConfig, } - engine = beacon.New(ethash.NewFaker()) + engine = beacon.New(ethash.NewFaker()) + mergeBlock = uint64(math.MaxUint64) ) // Apply merging since genesis if mergeHeight == 0 { genesis.Config.TerminalTotalDifficulty = big.NewInt(0) + mergeBlock = uint64(0) } - genDb, blocks, receipts := GenerateChainWithGenesis(genesis, engine, 32, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + + genDb, blocks, receipts := GenerateChainWithGenesis(genesis, engine, 32, + func(i int, b *BlockGen) { + if b.header.Number.Uint64() >= mergeBlock { + b.SetPoS() + } + b.SetCoinbase(common.Address{1}) + }) // Apply merging after the first segment if mergeHeight == 1 { - genesis.Config.TerminalTotalDifficulty = big.NewInt(int64(len(blocks))) + // TTD is genesis diff + blocks + ttd := big.NewInt(1 + int64(len(blocks))) + ttd.Mul(ttd, params.GenesisDifficulty) + genesis.Config.TerminalTotalDifficulty = ttd + mergeBlock = uint64(len(blocks)) } // Longer chain and shorter chain - blocks2, receipts2 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 65, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + blocks2, receipts2 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 65, func(i int, b *BlockGen) { + b.SetCoinbase(common.Address{1}) + if b.header.Number.Uint64() >= mergeBlock { + b.SetPoS() + } + }) blocks3, receipts3 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) b.OffsetTime(-9) // Time shifted, difficulty shouldn't be changed + if b.header.Number.Uint64() >= mergeBlock { + b.SetPoS() + } }) - // Import the shared chain and the original canonical one chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) if err != nil { @@ -2268,7 +2299,10 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i for _, block := range blocks { headers = append(headers, block.Header()) } - _, err := chain.InsertHeaderChain(headers, 1) + i, err := chain.InsertHeaderChain(headers, 1) + if err != nil { + return fmt.Errorf("index %d, number %d: %w", i, headers[i].Number, err) + } return err } asserter = func(t *testing.T, block *types.Block) { @@ -2282,9 +2316,9 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i for _, block := range blocks { headers = append(headers, block.Header()) } - _, err := chain.InsertHeaderChain(headers, 1) + i, err := chain.InsertHeaderChain(headers, 1) if err != nil { - return err + return fmt.Errorf("index %d: %w", i, err) } _, err = chain.InsertReceiptChain(blocks, receipts, 0) return err @@ -2296,8 +2330,11 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } } else { inserter = func(blocks []*types.Block, receipts []types.Receipts) error { - _, err := chain.InsertChain(blocks) - return err + i, err := chain.InsertChain(blocks) + if err != nil { + return fmt.Errorf("index %d: %w", i, err) + } + return nil } asserter = func(t *testing.T, block *types.Block) { if chain.CurrentBlock().Hash() != block.Hash() { diff --git a/core/chain_makers.go b/core/chain_makers.go index 52dd6e2e47be..cbfe5c3ece16 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -80,6 +80,11 @@ func (b *BlockGen) SetDifficulty(diff *big.Int) { b.header.Difficulty = diff } +// SetPos makes the header a PoS-header (0 difficulty) +func (b *BlockGen) SetPoS() { + b.header.Difficulty = new(big.Int) +} + // addTx adds a transaction to the generated block. If no coinbase has // been set, the block's coinbase is set to the zero address. // diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 7872c7f711f1..00ef2203f832 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -852,11 +852,11 @@ func TestInvalidBloom(t *testing.T) { func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(100) - genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty()) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() + genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty()) var ( api = NewConsensusAPI(ethservice) parent = preMergeBlocks[len(preMergeBlocks)-1] diff --git a/les/catalyst/api_test.go b/les/catalyst/api_test.go index 6d0eedeccb77..91d5c9bbb988 100644 --- a/les/catalyst/api_test.go +++ b/les/catalyst/api_test.go @@ -44,7 +44,7 @@ var ( testBalance = big.NewInt(2e18) ) -func generatePreMergeChain(n int) (*core.Genesis, []*types.Header, []*types.Block) { +func generatePreMergeChain(pre, post int) (*core.Genesis, []*types.Header, []*types.Block, []*types.Header, []*types.Block) { config := *params.AllEthashProtocolChanges genesis := &core.Genesis{ Config: &config, @@ -53,21 +53,33 @@ func generatePreMergeChain(n int) (*core.Genesis, []*types.Header, []*types.Bloc Timestamp: 9000, BaseFee: big.NewInt(params.InitialBaseFee), } - _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), n, nil) - totalDifficulty := big.NewInt(0) + // Pre-merge blocks + db, preBLocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), pre, nil) + totalDifficulty := new(big.Int).Set(params.GenesisDifficulty) - var headers []*types.Header - for _, b := range blocks { + var preHeaders []*types.Header + for _, b := range preBLocks { totalDifficulty.Add(totalDifficulty, b.Difficulty()) - headers = append(headers, b.Header()) + preHeaders = append(preHeaders, b.Header()) } config.TerminalTotalDifficulty = totalDifficulty + // Post-merge blocks + postBlocks, _ := core.GenerateChain(genesis.Config, + preBLocks[len(preBLocks)-1], ethash.NewFaker(), db, post, + func(i int, b *core.BlockGen) { + b.SetPoS() + }) - return genesis, headers, blocks + var postHeaders []*types.Header + for _, b := range postBlocks { + postHeaders = append(postHeaders, b.Header()) + } + + return genesis, preHeaders, preBLocks, postHeaders, postBlocks } func TestSetHeadBeforeTotalDifficulty(t *testing.T) { - genesis, headers, blocks := generatePreMergeChain(10) + genesis, headers, blocks, _, _ := generatePreMergeChain(10, 0) n, lesService := startLesService(t, genesis, headers) defer n.Close() @@ -83,21 +95,21 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) { } func TestExecutePayloadV1(t *testing.T) { - genesis, headers, blocks := generatePreMergeChain(10) - n, lesService := startLesService(t, genesis, headers[:9]) + genesis, headers, _, _, postBlocks := generatePreMergeChain(10, 2) + n, lesService := startLesService(t, genesis, headers) lesService.Merger().ReachTTD() defer n.Close() api := NewConsensusAPI(lesService) fcState := beacon.ForkchoiceStateV1{ - HeadBlockHash: blocks[8].Hash(), + HeadBlockHash: postBlocks[0].Hash(), SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, } if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { t.Errorf("Failed to update head %v", err) } - block := blocks[9] + block := postBlocks[0] fakeBlock := types.NewBlock(&types.Header{ ParentHash: block.ParentHash(), diff --git a/tests/block_test.go b/tests/block_test.go index 74c7ed819763..9e72f7f9710a 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -46,6 +46,7 @@ func TestBlockchain(t *testing.T) { // test takes a lot for time and goes easily OOM because of sha3 calculation on a huge range, // using 4.6 TGas bt.skipLoad(`.*randomStatetest94.json.*`) + bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { if err := bt.checkFailure(t, test.Run(false)); err != nil { t.Errorf("test without snapshotter failed: %v", err) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 5b200a60727c..df4f08a76412 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -120,6 +121,9 @@ func (t *BlockTest) Run(snapshotter bool) error { } else { engine = ethash.NewShared() } + // Wrap the original engine within the beacon-engine + engine = beacon.New(engine) + cache := &core.CacheConfig{TrieCleanLimit: 0} if snapshotter { cache.SnapshotLimit = 1 diff --git a/tests/init.go b/tests/init.go index ef5ea4bb9a9a..e6faa483a68d 100644 --- a/tests/init.go +++ b/tests/init.go @@ -197,6 +197,24 @@ var Forks = map[string]*params.ChainConfig{ LondonBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0), }, + "ArrowGlacierToMergeAtDiffC0000": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + GrayGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0xC0000), + }, "GrayGlacier": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), @@ -213,7 +231,7 @@ var Forks = map[string]*params.ChainConfig{ ArrowGlacierBlock: big.NewInt(0), GrayGlacierBlock: big.NewInt(0), }, - "Merged": { + "Merge": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), diff --git a/tests/state_test.go b/tests/state_test.go index cb7f76521780..64d01076c956 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -56,14 +56,12 @@ func TestState(t *testing.T) { // Uses 1GB RAM per tested fork st.skipLoad(`^stStaticCall/static_Call1MB`) + // Not yet supported TODO + st.skipLoad(`^stEIP3540/`) + st.skipLoad(`^stEIP3860/`) + // Broken tests: // Expected failures: - // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test") - // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/3`, "bug in test") - // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/0`, "bug in test") - // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/3`, "bug in test") - // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/0`, "bug in test") - // st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/3`, "bug in test") // For Istanbul, older tests were moved into LegacyTests for _, dir := range []string{ diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 838e85dca2b7..67605a127339 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -249,10 +249,16 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh context.GetHash = vmTestBlockHash context.BaseFee = baseFee context.Random = nil - if config.IsLondon(new(big.Int)) && t.json.Env.Random != nil { - rnd := common.BigToHash(t.json.Env.Random) - context.Random = &rnd + if config.IsLondon(new(big.Int)) { + if t.json.Env.Random != nil { + rnd := common.BigToHash(t.json.Env.Random) + context.Random = &rnd + } context.Difficulty = big.NewInt(0) + } else { + if t.json.Env.Difficulty != nil { + context.Difficulty = new(big.Int).Set(t.json.Env.Difficulty) + } } evm := vm.NewEVM(context, txContext, statedb, config, vmconfig) // Execute the message. diff --git a/tests/testdata b/tests/testdata index a380655e5ffa..24fa31adb30f 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit a380655e5ffab1a5ea0f4d860224bdb19013f06a +Subproject commit 24fa31adb30f71ee700b27decb5204e53a11d9f3 From 01808421e20ba9d19c029b64fcda841df77c9aff Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 21 Dec 2022 17:21:21 +0800 Subject: [PATCH 431/715] core/state: return error when storage trie can't be opened (#26350) This changes the StorageTrie method to return an error when the trie is not available. It used to return an 'empty trie' in this case, but that's not possible anymore under PBSS. --- core/state/dump.go | 7 +++- core/state/state_object.go | 77 ++++++++++++++++++++++++++------------ core/state/statedb.go | 35 +++++++++++------ eth/api.go | 5 ++- eth/api_test.go | 6 ++- internal/ethapi/api.go | 6 ++- 6 files changed, 96 insertions(+), 40 deletions(-) diff --git a/core/state/dump.go b/core/state/dump.go index d97520f08ee7..d834cbad379e 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -168,7 +168,12 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey [] } if !conf.SkipStorage { account.Storage = make(map[common.Hash]string) - storageIt := trie.NewIterator(obj.getTrie(s.db).NodeIterator(nil)) + tr, err := obj.getTrie(s.db) + if err != nil { + log.Error("Failed to load storage trie", "err", err) + continue + } + storageIt := trie.NewIterator(tr.NodeIterator(nil)) for storageIt.Next() { _, content, _, err := rlp.Split(storageIt.Value) if err != nil { diff --git a/core/state/state_object.go b/core/state/state_object.go index d2693b0c02d8..7e1709ee07a1 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -148,7 +148,10 @@ func (s *stateObject) touch() { } } -func (s *stateObject) getTrie(db Database) Trie { +// getTrie returns the associated storage trie. The trie will be opened +// if it's not loaded previously. An error will be returned if trie can't +// be loaded. +func (s *stateObject) getTrie(db Database) (Trie, error) { if s.trie == nil { // Try fetching from prefetcher first // We don't prefetch empty tries @@ -158,15 +161,14 @@ func (s *stateObject) getTrie(db Database) Trie { s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root) } if s.trie == nil { - var err error - s.trie, err = db.OpenStorageTrie(s.db.originalRoot, s.addrHash, s.data.Root) + tr, err := db.OpenStorageTrie(s.db.originalRoot, s.addrHash, s.data.Root) if err != nil { - s.trie, _ = db.OpenStorageTrie(s.db.originalRoot, s.addrHash, common.Hash{}) - s.setError(fmt.Errorf("can't create storage trie: %v", err)) + return nil, err } + s.trie = tr } } - return s.trie + return s.trie, nil } // GetState retrieves a value from the account storage trie. @@ -221,7 +223,12 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has // If the snapshot is unavailable or reading from it fails, load from the database. if s.db.snap == nil || err != nil { start := time.Now() - enc, err = s.getTrie(db).TryGet(key.Bytes()) + tr, err := s.getTrie(db) + if err != nil { + s.setError(err) + return common.Hash{} + } + enc, err = tr.TryGet(key.Bytes()) if metrics.EnabledExpensive { s.db.StorageReads += time.Since(start) } @@ -304,23 +311,29 @@ func (s *stateObject) finalise(prefetch bool) { } // updateTrie writes cached storage modifications into the object's storage trie. -// It will return nil if the trie has not been loaded and no changes have been made -func (s *stateObject) updateTrie(db Database) Trie { +// It will return nil if the trie has not been loaded and no changes have been +// made. An error will be returned if the trie can't be loaded/updated correctly. +func (s *stateObject) updateTrie(db Database) (Trie, error) { // Make sure all dirty slots are finalized into the pending storage area s.finalise(false) // Don't prefetch anymore, pull directly if need be if len(s.pendingStorage) == 0 { - return s.trie + return s.trie, nil } // Track the amount of time wasted on updating the storage trie if metrics.EnabledExpensive { defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now()) } // The snapshot storage map for the object - var storage map[common.Hash][]byte + var ( + storage map[common.Hash][]byte + hasher = s.db.hasher + ) + tr, err := s.getTrie(db) + if err != nil { + s.setError(err) + return nil, err + } // Insert all the pending updates into the trie - tr := s.getTrie(db) - hasher := s.db.hasher - usedStorage := make([][]byte, 0, len(s.pendingStorage)) for key, value := range s.pendingStorage { // Skip noop changes, persist actual changes @@ -331,12 +344,18 @@ func (s *stateObject) updateTrie(db Database) Trie { var v []byte if (value == common.Hash{}) { - s.setError(tr.TryDelete(key[:])) + if err := tr.TryDelete(key[:]); err != nil { + s.setError(err) + return nil, err + } s.db.StorageDeleted += 1 } else { // Encoding []byte cannot fail, ok to ignore the error. v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) - s.setError(tr.TryUpdate(key[:], v)) + if err := tr.TryUpdate(key[:], v); err != nil { + s.setError(err) + return nil, err + } s.db.StorageUpdated += 1 } // If state snapshotting is active, cache the data til commit @@ -358,37 +377,47 @@ func (s *stateObject) updateTrie(db Database) Trie { if len(s.pendingStorage) > 0 { s.pendingStorage = make(Storage) } - return tr + return tr, nil } -// UpdateRoot sets the trie root to the current root hash of +// UpdateRoot sets the trie root to the current root hash of. An error +// will be returned if trie root hash is not computed correctly. func (s *stateObject) updateRoot(db Database) { + tr, err := s.updateTrie(db) + if err != nil { + s.setError(fmt.Errorf("updateRoot (%x) error: %w", s.address, err)) + return + } // If nothing changed, don't bother with hashing anything - if s.updateTrie(db) == nil { + if tr == nil { return } // Track the amount of time wasted on hashing the storage trie if metrics.EnabledExpensive { defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now()) } - s.data.Root = s.trie.Hash() + s.data.Root = tr.Hash() } // commitTrie submits the storage changes into the storage trie and re-computes // the root. Besides, all trie changes will be collected in a nodeset and returned. func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) { - // If nothing changed, don't bother with hashing anything - if s.updateTrie(db) == nil { - return nil, nil + tr, err := s.updateTrie(db) + if err != nil { + return nil, err } if s.dbErr != nil { return nil, s.dbErr } + // If nothing changed, don't bother with committing anything + if tr == nil { + return nil, nil + } // Track the amount of time wasted on committing the storage trie if metrics.EnabledExpensive { defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) } - root, nodes, err := s.trie.Commit(false) + root, nodes, err := tr.Commit(false) if err == nil { s.data.Root = root } diff --git a/core/state/statedb.go b/core/state/statedb.go index 91eb07a22800..993bda3e3ac1 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -339,13 +339,19 @@ func (s *StateDB) GetProofByHash(addrHash common.Hash) ([][]byte, error) { // GetStorageProof returns the Merkle proof for given storage slot. func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte, error) { - var proof proofList - trie := s.StorageTrie(a) + trie, err := s.StorageTrie(a) + if err != nil { + return nil, err + } if trie == nil { - return proof, errors.New("storage trie for requested address does not exist") + return nil, errors.New("storage trie for requested address does not exist") } - err := trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof) - return proof, err + var proof proofList + err = trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof) + if err != nil { + return nil, err + } + return proof, nil } // GetCommittedState retrieves a value from the given account's committed storage trie. @@ -362,15 +368,18 @@ func (s *StateDB) Database() Database { return s.db } -// StorageTrie returns the storage trie of an account. -// The return value is a copy and is nil for non-existent accounts. -func (s *StateDB) StorageTrie(addr common.Address) Trie { +// StorageTrie returns the storage trie of an account. The return value is a copy +// and is nil for non-existent accounts. An error will be returned if storage trie +// is existent but can't be loaded correctly. +func (s *StateDB) StorageTrie(addr common.Address) (Trie, error) { stateObject := s.getStateObject(addr) if stateObject == nil { - return nil + return nil, nil } cpy := stateObject.deepCopy(s) - cpy.updateTrie(s.db) + if _, err := cpy.updateTrie(s.db); err != nil { + return nil, err + } return cpy.getTrie(s.db) } @@ -654,7 +663,11 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common if so == nil { return nil } - it := trie.NewIterator(so.getTrie(db.db).NodeIterator(nil)) + tr, err := so.getTrie(db.db) + if err != nil { + return err + } + it := trie.NewIterator(tr.NodeIterator(nil)) for it.Next() { key := common.BytesToHash(db.trie.GetKey(it.Key)) diff --git a/eth/api.go b/eth/api.go index 0591b98de867..ceed85ef576b 100644 --- a/eth/api.go +++ b/eth/api.go @@ -417,7 +417,10 @@ func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, } defer release() - st := statedb.StorageTrie(contractAddress) + st, err := statedb.StorageTrie(contractAddress) + if err != nil { + return StorageRangeResult{}, err + } if st == nil { return StorageRangeResult{}, fmt.Errorf("account %x doesn't exist", contractAddress) } diff --git a/eth/api_test.go b/eth/api_test.go index 250591c1079b..fca17f12171b 100644 --- a/eth/api_test.go +++ b/eth/api_test.go @@ -209,7 +209,11 @@ func TestStorageRangeAt(t *testing.T) { }, } for _, test := range tests { - result, err := storageRangeAt(state.StorageTrie(addr), test.start, test.limit) + tr, err := state.StorageTrie(addr) + if err != nil { + t.Error(err) + } + result, err := storageRangeAt(tr, test.start, test.limit) if err != nil { t.Error(err) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index ea0cbfe867aa..49b65559da23 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -660,8 +660,10 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st if state == nil || err != nil { return nil, err } - - storageTrie := state.StorageTrie(address) + storageTrie, err := state.StorageTrie(address) + if err != nil { + return nil, err + } storageHash := types.EmptyRootHash codeHash := state.GetCodeHash(address) storageProof := make([]StorageResult, len(storageKeys)) From 577db2edf7cd07729995a79978b8d1ca2f2b3743 Mon Sep 17 00:00:00 2001 From: Zachinquarantine Date: Tue, 27 Dec 2022 02:52:29 -0500 Subject: [PATCH 432/715] build: add support for Ubuntu 22.10 (Kinetic Kudu) (#26379) Adds uploads to Kinetic in Launchpad, and removes the upload for 21.10 impish (not supported since July) --- build/ci.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/ci.go b/build/ci.go index 572519b9698e..2c2af0899da5 100644 --- a/build/ci.go +++ b/build/ci.go @@ -129,15 +129,15 @@ var ( // Distros for which packages are created. // Note: vivid is unsupported because there is no golang-1.6 package for it. // Note: the following Ubuntu releases have been officially deprecated on Launchpad: - // wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy, hirsuite + // wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy, hirsuite, impish debDistroGoBoots = map[string]string{ "trusty": "golang-1.11", // EOL: 04/2024 "xenial": "golang-go", // EOL: 04/2026 "bionic": "golang-go", // EOL: 04/2028 "focal": "golang-go", // EOL: 04/2030 - "impish": "golang-go", // EOL: 07/2022 "jammy": "golang-go", // EOL: 04/2032 - //"kinetic": "golang-go", // EOL: 07/2023 + "kinetic": "golang-go", // EOL: 07/2023 + //"lunar": "golang-go", // EOL: 01/2024 } debGoBootPaths = map[string]string{ From 9921ca0f0afa4991a0a9a4f55795a8c8d33cc923 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 28 Dec 2022 09:48:26 +0100 Subject: [PATCH 433/715] miner: allow for extradata in post-merge blocks (#26387) * miner: allow for extradata in post-merge blocks * miner: nits * miner: remove extradata checks --- miner/worker.go | 8 +++----- miner/worker_test.go | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index e00a494d0155..45450237fe6d 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -959,13 +959,12 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP // generateParams wraps various of settings for generating sealing task. type generateParams struct { - timestamp uint64 // The timstamp for sealing task + timestamp uint64 // The timestamp for sealing task forceTime bool // Flag whether the given timestamp is immutable or not parentHash common.Hash // Parent block hash, empty means the latest chain head coinbase common.Address // The fee recipient address for including transaction random common.Hash // The randomness generated by beacon chain, empty before the merge noUncle bool // Flag whether the uncle block inclusion is allowed - noExtra bool // Flag whether the extra field assignment is allowed noTxs bool // Flag whether an empty block without any transaction is expected } @@ -1001,8 +1000,8 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { Time: timestamp, Coinbase: genParams.coinbase, } - // Set the extra field if it's allowed. - if !genParams.noExtra && len(w.extra) != 0 { + // Set the extra field. + if len(w.extra) != 0 { header.Extra = w.extra } // Set the randomness field from the beacon chain if it's available. @@ -1225,7 +1224,6 @@ func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase coinbase: coinbase, random: random, noUncle: true, - noExtra: true, noTxs: noTxs, }, result: make(chan *newPayloadResult, 1), diff --git a/miner/worker_test.go b/miner/worker_test.go index 9c7961f7866d..5db90546ceca 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -568,7 +568,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co } _, isClique := engine.(*clique.Clique) if !isClique { - if len(block.Extra()) != 0 { + if len(block.Extra()) != 2 { t.Error("Unexpected extra field") } if block.Coinbase() != coinbase { From c87f321b8feb7137d83b202bcfc3b5f1a78142bf Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 28 Dec 2022 21:53:43 +0800 Subject: [PATCH 434/715] core/state: maintain destruction flag by default (#26371) This changes moves the tracking of "deleted in this block" out from snap-only domain, so that it happens regardless of whether the execution is snapshot-backed or trie-backed. --- core/state/journal.go | 4 +- core/state/state_object.go | 18 ++--- core/state/statedb.go | 135 ++++++++++++++++++++++--------------- 3 files changed, 90 insertions(+), 67 deletions(-) diff --git a/core/state/journal.go b/core/state/journal.go index dabc1cf7d768..1722fb4c02e1 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -156,8 +156,8 @@ func (ch createObjectChange) dirtied() *common.Address { func (ch resetObjectChange) revert(s *StateDB) { s.setStateObject(ch.prev) - if !ch.prevdestruct && s.snap != nil { - delete(s.snapDestructs, ch.prev.addrHash) + if !ch.prevdestruct { + delete(s.stateObjectsDestruct, ch.prev.address) } } diff --git a/core/state/state_object.go b/core/state/state_object.go index 7e1709ee07a1..bea8f17be32e 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -199,21 +199,21 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has if value, cached := s.originStorage[key]; cached { return value } + // If the object was destructed in *this* block (and potentially resurrected), + // the storage has been cleared out, and we should *not* consult the previous + // database about any storage values. The only possible alternatives are: + // 1) resurrect happened, and new slot values were set -- those should + // have been handles via pendingStorage above. + // 2) we don't have new values, and can deliver empty response back + if _, destructed := s.db.stateObjectsDestruct[s.address]; destructed { + return common.Hash{} + } // If no live objects are available, attempt to use snapshots var ( enc []byte err error ) if s.db.snap != nil { - // If the object was destructed in *this* block (and potentially resurrected), - // the storage has been cleared out, and we should *not* consult the previous - // snapshot about any storage values. The only possible alternatives are: - // 1) resurrect happened, and new slot values were set -- those should - // have been handles via pendingStorage above. - // 2) we don't have new values, and can deliver empty response back - if _, destructed := s.db.snapDestructs[s.addrHash]; destructed { - return common.Hash{} - } start := time.Now() enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes())) if metrics.EnabledExpensive { diff --git a/core/state/statedb.go b/core/state/statedb.go index 993bda3e3ac1..8d0aacf580de 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -72,16 +72,16 @@ type StateDB struct { // It will be updated when the Commit is called. originalRoot common.Hash - snaps *snapshot.Tree - snap snapshot.Snapshot - snapDestructs map[common.Hash]struct{} - snapAccounts map[common.Hash][]byte - snapStorage map[common.Hash]map[common.Hash][]byte + snaps *snapshot.Tree + snap snapshot.Snapshot + snapAccounts map[common.Hash][]byte + snapStorage map[common.Hash]map[common.Hash][]byte // This map holds 'live' objects, which will get modified while processing a state transition. - stateObjects map[common.Address]*stateObject - stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie - stateObjectsDirty map[common.Address]struct{} // State objects modified in the current execution + stateObjects map[common.Address]*stateObject + stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie + stateObjectsDirty map[common.Address]struct{} // State objects modified in the current execution + stateObjectsDestruct map[common.Address]struct{} // State objects destructed in the block // DB error. // State objects are used by the consensus core and VM which are @@ -139,23 +139,23 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) return nil, err } sdb := &StateDB{ - db: db, - trie: tr, - originalRoot: root, - snaps: snaps, - stateObjects: make(map[common.Address]*stateObject), - stateObjectsPending: make(map[common.Address]struct{}), - stateObjectsDirty: make(map[common.Address]struct{}), - logs: make(map[common.Hash][]*types.Log), - preimages: make(map[common.Hash][]byte), - journal: newJournal(), - accessList: newAccessList(), - transientStorage: newTransientStorage(), - hasher: crypto.NewKeccakState(), + db: db, + trie: tr, + originalRoot: root, + snaps: snaps, + stateObjects: make(map[common.Address]*stateObject), + stateObjectsPending: make(map[common.Address]struct{}), + stateObjectsDirty: make(map[common.Address]struct{}), + stateObjectsDestruct: make(map[common.Address]struct{}), + logs: make(map[common.Hash][]*types.Log), + preimages: make(map[common.Hash][]byte), + journal: newJournal(), + accessList: newAccessList(), + transientStorage: newTransientStorage(), + hasher: crypto.NewKeccakState(), } if sdb.snaps != nil { if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap != nil { - sdb.snapDestructs = make(map[common.Hash]struct{}) sdb.snapAccounts = make(map[common.Hash][]byte) sdb.snapStorage = make(map[common.Hash]map[common.Hash][]byte) } @@ -622,10 +622,10 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that! var prevdestruct bool - if s.snap != nil && prev != nil { - _, prevdestruct = s.snapDestructs[prev.addrHash] + if prev != nil { + _, prevdestruct = s.stateObjectsDestruct[prev.address] if !prevdestruct { - s.snapDestructs[prev.addrHash] = struct{}{} + s.stateObjectsDestruct[prev.address] = struct{}{} } } newobj = newObject(s, addr, types.StateAccount{}) @@ -696,18 +696,19 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common func (s *StateDB) Copy() *StateDB { // Copy all the basic fields, initialize the memory ones state := &StateDB{ - db: s.db, - trie: s.db.CopyTrie(s.trie), - originalRoot: s.originalRoot, - stateObjects: make(map[common.Address]*stateObject, len(s.journal.dirties)), - stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)), - stateObjectsDirty: make(map[common.Address]struct{}, len(s.journal.dirties)), - refund: s.refund, - logs: make(map[common.Hash][]*types.Log, len(s.logs)), - logSize: s.logSize, - preimages: make(map[common.Hash][]byte, len(s.preimages)), - journal: newJournal(), - hasher: crypto.NewKeccakState(), + db: s.db, + trie: s.db.CopyTrie(s.trie), + originalRoot: s.originalRoot, + stateObjects: make(map[common.Address]*stateObject, len(s.journal.dirties)), + stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)), + stateObjectsDirty: make(map[common.Address]struct{}, len(s.journal.dirties)), + stateObjectsDestruct: make(map[common.Address]struct{}, len(s.stateObjectsDestruct)), + refund: s.refund, + logs: make(map[common.Hash][]*types.Log, len(s.logs)), + logSize: s.logSize, + preimages: make(map[common.Hash][]byte, len(s.preimages)), + journal: newJournal(), + hasher: crypto.NewKeccakState(), } // Copy the dirty states, logs, and preimages for addr := range s.journal.dirties { @@ -725,9 +726,10 @@ func (s *StateDB) Copy() *StateDB { state.stateObjectsPending[addr] = struct{}{} // Mark the copy pending to force external (account) commits } } - // Above, we don't copy the actual journal. This means that if the copy is copied, the - // loop above will be a no-op, since the copy's journal is empty. - // Thus, here we iterate over stateObjects, to enable copies of copies + // Above, we don't copy the actual journal. This means that if the copy + // is copied, the loop above will be a no-op, since the copy's journal + // is empty. Thus, here we iterate over stateObjects, to enable copies + // of copies. for addr := range s.stateObjectsPending { if _, exist := state.stateObjects[addr]; !exist { state.stateObjects[addr] = s.stateObjects[addr].deepCopy(state) @@ -740,6 +742,10 @@ func (s *StateDB) Copy() *StateDB { } state.stateObjectsDirty[addr] = struct{}{} } + // Deep copy the destruction flag. + for addr := range s.stateObjectsDestruct { + state.stateObjectsDestruct[addr] = struct{}{} + } for hash, logs := range s.logs { cpy := make([]*types.Log, len(logs)) for i, l := range logs { @@ -751,13 +757,13 @@ func (s *StateDB) Copy() *StateDB { for hash, preimage := range s.preimages { state.preimages[hash] = preimage } - // Do we need to copy the access list? In practice: No. At the start of a - // transaction, the access list is empty. In practice, we only ever copy state - // _between_ transactions/blocks, never in the middle of a transaction. - // However, it doesn't cost us much to copy an empty list, so we do it anyway - // to not blow up if we ever decide copy it in the middle of a transaction + // Do we need to copy the access list and transient storage? + // In practice: No. At the start of a transaction, these two lists are empty. + // In practice, we only ever copy state _between_ transactions/blocks, never + // in the middle of a transaction. However, it doesn't cost us much to copy + // empty lists, so we do it anyway to not blow up if we ever decide copy them + // in the middle of a transaction. state.accessList = s.accessList.Copy() - state.transientStorage = s.transientStorage.Copy() // If there's a prefetcher running, make an inactive copy of it that can @@ -768,16 +774,13 @@ func (s *StateDB) Copy() *StateDB { } if s.snaps != nil { // In order for the miner to be able to use and make additions - // to the snapshot tree, we need to copy that aswell. + // to the snapshot tree, we need to copy that as well. // Otherwise, any block mined by ourselves will cause gaps in the tree, // and force the miner to operate trie-backed only state.snaps = s.snaps state.snap = s.snap + // deep copy needed - state.snapDestructs = make(map[common.Hash]struct{}) - for k, v := range s.snapDestructs { - state.snapDestructs[k] = v - } state.snapAccounts = make(map[common.Hash][]byte) for k, v := range s.snapAccounts { state.snapAccounts[k] = v @@ -842,14 +845,17 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { if obj.suicided || (deleteEmptyObjects && obj.empty()) { obj.deleted = true + // We need to maintain account deletions explicitly (will remain + // set indefinitely). + s.stateObjectsDestruct[obj.address] = struct{}{} + // If state snapshotting is active, also mark the destruction there. // Note, we can't do this only at the end of a block because multiple // transactions within the same block might self destruct and then // resurrect an account; but the snapshotter needs both events. if s.snap != nil { - s.snapDestructs[obj.addrHash] = struct{}{} // We need to maintain account deletions explicitly (will remain set indefinitely) - delete(s.snapAccounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a resurrect) - delete(s.snapStorage, obj.addrHash) // Clear out any previously updated storage data (may be recreated via a resurrect) + delete(s.snapAccounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a resurrect) + delete(s.snapStorage, obj.addrHash) // Clear out any previously updated storage data (may be recreated via a resurrect) } } else { obj.finalise(true) // Prefetch slots in the background @@ -1037,7 +1043,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { start := time.Now() // Only update if there's a state transition (skip empty Clique blocks) if parent := s.snap.Root(); parent != root { - if err := s.snaps.Update(root, parent, s.snapDestructs, s.snapAccounts, s.snapStorage); err != nil { + if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.snapAccounts, s.snapStorage); err != nil { log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) } // Keep 128 diff layers in the memory, persistent layer is 129th. @@ -1051,7 +1057,10 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if metrics.EnabledExpensive { s.SnapshotCommits += time.Since(start) } - s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil + s.snap, s.snapAccounts, s.snapStorage = nil, nil, nil + } + if len(s.stateObjectsDestruct) > 0 { + s.stateObjectsDestruct = make(map[common.Address]struct{}) } if root == (common.Hash{}) { root = emptyRoot @@ -1148,3 +1157,17 @@ func (s *StateDB) AddressInAccessList(addr common.Address) bool { func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) { return s.accessList.Contains(addr, slot) } + +// convertAccountSet converts a provided account set from address keyed to hash keyed. +func (s *StateDB) convertAccountSet(set map[common.Address]struct{}) map[common.Hash]struct{} { + ret := make(map[common.Hash]struct{}) + for addr := range set { + obj, exist := s.stateObjects[addr] + if !exist { + ret[crypto.Keccak256Hash(addr[:])] = struct{}{} + } else { + ret[obj.addrHash] = struct{}{} + } + } + return ret +} From db82ea2ee375b80809673316ec79578c9e883166 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 29 Dec 2022 13:24:34 +0100 Subject: [PATCH 435/715] core: reset txpool on sethead (#26392) This change sends a HeadChainEvent when SetHead is invoked. The txpool will then reset the txnoncer on receiving the event. --- core/blockchain.go | 8 ++++++-- ethclient/gethclient/gethclient_test.go | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 7f476fe59573..2ca1e2fc7b93 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -532,8 +532,12 @@ func (bc *BlockChain) loadLastState() error { // was fast synced or full synced and in which state, the method will try to // delete minimal data from disk whilst retaining chain consistency. func (bc *BlockChain) SetHead(head uint64) error { - _, err := bc.setHeadBeyondRoot(head, common.Hash{}, false) - return err + if _, err := bc.setHeadBeyondRoot(head, common.Hash{}, false); err != nil { + return err + } + // Send chain head event to update the transaction pool + bc.chainHeadFeed.Send(ChainHeadEvent{Block: bc.CurrentBlock()}) + return nil } // SetFinalized sets the finalized block. diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index e60490c61646..ef84d71559c8 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -118,9 +118,6 @@ func TestGethClient(t *testing.T) { }, { "TestGetNodeInfo", func(t *testing.T) { testGetNodeInfo(t, client) }, - }, { - "TestSetHead", - func(t *testing.T) { testSetHead(t, client) }, }, { "TestSubscribePendingTxHashes", func(t *testing.T) { testSubscribePendingTransactions(t, client) }, @@ -138,6 +135,9 @@ func TestGethClient(t *testing.T) { { "TestAccessList", func(t *testing.T) { testAccessList(t, client) }, + }, { + "TestSetHead", + func(t *testing.T) { testSetHead(t, client) }, }, } for _, tt := range tests { From 9d38466437acebf4d09548ce066eb5a5db60cd2c Mon Sep 17 00:00:00 2001 From: Ha DANG Date: Tue, 3 Jan 2023 16:03:44 +0700 Subject: [PATCH 436/715] eth/downloader: fix some typos (#26396) --- eth/downloader/downloader.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 41c5d66edb38..f58da869ee30 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -481,7 +481,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * return err } } else { - // In beacon mode, user the skeleton chain to retrieve the headers from + // In beacon mode, use the skeleton chain to retrieve the headers from latest, _, err = d.skeleton.Bounds() if err != nil { return err @@ -1174,7 +1174,7 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, head uint64) e } } } - // If no headers have bene delivered, or all of them have been delayed, + // If no headers have been delivered, or all of them have been delayed, // sleep a bit and retry. Take care with headers already consumed during // skeleton filling if len(headers) == 0 && !progressed { From dad92500e7802db94b92a962fec1d80f70c676b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Tue, 3 Jan 2023 10:04:54 +0100 Subject: [PATCH 437/715] cmd, internal: update copyright year to 2023 (#26382) * internal/flags: update copyright year to 2023 * cmd/geth: update copyright year to 2023 --- cmd/geth/main.go | 2 +- internal/flags/helpers.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 25a09749744e..bf7097b02cf2 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -206,7 +206,7 @@ func init() { // Initialize the CLI app and start Geth app.Action = geth app.HideVersion = true // we have a command to print the version - app.Copyright = "Copyright 2013-2022 The go-ethereum Authors" + app.Copyright = "Copyright 2013-2023 The go-ethereum Authors" app.Commands = []*cli.Command{ // See chaincmd.go: initCommand, diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index 3be0a5807290..f210e729dd27 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -32,7 +32,7 @@ func NewApp(usage string) *cli.App { app.EnableBashCompletion = true app.Version = params.VersionWithCommit(git.Commit, git.Date) app.Usage = usage - app.Copyright = "Copyright 2013-2022 The go-ethereum Authors" + app.Copyright = "Copyright 2013-2023 The go-ethereum Authors" app.Before = func(ctx *cli.Context) error { MigrateGlobalFlags(ctx) return nil From c6a2f77c2ee80afb6ab3ab9912005224f22bdccc Mon Sep 17 00:00:00 2001 From: strykerin Date: Tue, 3 Jan 2023 07:30:34 -0300 Subject: [PATCH 438/715] cmd/devp2p/internal/v4test: add pong validation in bond (#26400) --- cmd/devp2p/internal/v4test/discv4tests.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/devp2p/internal/v4test/discv4tests.go b/cmd/devp2p/internal/v4test/discv4tests.go index 7b818a52f9c5..d799e4194b60 100644 --- a/cmd/devp2p/internal/v4test/discv4tests.go +++ b/cmd/devp2p/internal/v4test/discv4tests.go @@ -395,7 +395,7 @@ func FindnodePastExpiration(t *utesting.T) { // bond performs the endpoint proof with the remote node. func bond(t *utesting.T, te *testenv) { - te.send(te.l1, &v4wire.Ping{ + pingHash := te.send(te.l1, &v4wire.Ping{ Version: 4, From: te.localEndpoint(te.l1), To: te.remoteEndpoint(), @@ -417,7 +417,9 @@ func bond(t *utesting.T, te *testenv) { }) gotPing = true case *v4wire.Pong: - // TODO: maybe verify pong data here + if err := te.checkPong(req, pingHash); err != nil { + t.Fatal(err) + } gotPong = true } } From efc9409ca9ba913977360cc5038b7f7db666718d Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 27 Sep 2022 13:42:57 +0200 Subject: [PATCH 439/715] params: core: enable shanghai based on timestamps --- core/state_transition.go | 2 +- core/vm/evm.go | 2 +- core/vm/runtime/runtime.go | 6 +++--- eth/tracers/js/goja.go | 2 +- eth/tracers/native/4byte.go | 2 +- internal/ethapi/api.go | 2 +- params/config.go | 28 +++++++++++++++------------- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index c49aba708563..fe94161e14f9 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -300,7 +300,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { var ( msg = st.msg sender = vm.AccountRef(msg.From()) - rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil) + rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time) contractCreation = msg.To() == nil ) diff --git a/core/vm/evm.go b/core/vm/evm.go index b9a9d4636b7b..149e9f761be3 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -131,7 +131,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig StateDB: statedb, Config: config, chainConfig: chainConfig, - chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil), + chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), } evm.interpreter = NewEVMInterpreter(evm, config) return evm diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 6b355deeb6e2..a330825b10d8 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -117,7 +117,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { address = common.BytesToAddress([]byte("contract")) vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) - rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil) + rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) @@ -151,7 +151,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { var ( vmenv = NewEnv(cfg) sender = vm.AccountRef(cfg.Origin) - rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil) + rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) @@ -180,7 +180,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er vmenv = NewEnv(cfg) sender = cfg.State.GetOrNewStateObject(cfg.Origin) statedb = cfg.State - rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil) + rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 9adfca9fb62a..cf27acbb4ab2 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -242,7 +242,7 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr t.ctx["value"] = valueBig t.ctx["block"] = t.vm.ToValue(env.Context.BlockNumber.Uint64()) // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) + rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) t.activePrecompiles = vm.ActivePrecompiles(rules) } diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 00cd5fe77b8b..afe70ea089aa 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -81,7 +81,7 @@ func (t *fourByteTracer) store(id []byte, size int) { // CaptureStart implements the EVMLogger interface to initialize the tracing operation. func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) + rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) t.activePrecompiles = vm.ActivePrecompiles(rules) // Save the outer calldata also diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 49b65559da23..58be2f8bf80e 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1440,7 +1440,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH } isPostMerge := header.Difficulty.Cmp(common.Big0) == 0 // Retrieve the precompiles since they don't need to be added to the access list - precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge)) + precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, new(big.Int).SetUint64(header.Time))) // Create an initial tracer prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles) diff --git a/params/config.go b/params/config.go index e3e48f9c2597..c4fc021c722c 100644 --- a/params/config.go +++ b/params/config.go @@ -281,7 +281,7 @@ var ( TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(EthashConfig), nil} NonActivatedConfig = &ChainConfig{big.NewInt(1), nil, nil, false, nil, common.Hash{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, new(EthashConfig), nil} - TestRules = TestChainConfig.Rules(new(big.Int), false) + TestRules = TestChainConfig.Rules(new(big.Int), false, new(big.Int)) ) // NetworkNames are user friendly names to use in the chain spec banner. @@ -371,7 +371,7 @@ type ChainConfig struct { ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated) GrayGlacierBlock *big.Int `json:"grayGlacierBlock,omitempty"` // Eip-5133 (bomb delay) switch block (nil = no fork, 0 = already activated) MergeNetsplitBlock *big.Int `json:"mergeNetsplitBlock,omitempty"` // Virtual fork after The Merge to use as a network splitter - ShanghaiBlock *big.Int `json:"shanghaiBlock,omitempty"` // Shanghai switch block (nil = no fork, 0 = already on shanghai) + ShanghaiTime *big.Int `json:"shanghaiBlock,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) CancunBlock *big.Int `json:"cancunBlock,omitempty"` // Cancun switch block (nil = no fork, 0 = already on cancun) // TerminalTotalDifficulty is the amount of total difficulty reached by @@ -465,8 +465,8 @@ func (c *ChainConfig) Description() string { if c.GrayGlacierBlock != nil { banner += fmt.Sprintf(" - Gray Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md)\n", c.GrayGlacierBlock) } - if c.ShanghaiBlock != nil { - banner += fmt.Sprintf(" - Shanghai: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", c.ShanghaiBlock) + if c.ShanghaiTime != nil { + banner += fmt.Sprintf(" - Shanghai: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", c.ShanghaiTime) } if c.CancunBlock != nil { banner += fmt.Sprintf(" - Cancun: %-8v\n", c.CancunBlock) @@ -567,9 +567,9 @@ func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *bi return parentTotalDiff.Cmp(c.TerminalTotalDifficulty) < 0 && totalDiff.Cmp(c.TerminalTotalDifficulty) >= 0 } -// IsShanghai returns whether num is either equal to the Shanghai fork block or greater. -func (c *ChainConfig) IsShanghai(num *big.Int) bool { - return isForked(c.ShanghaiBlock, num) +// IsShanghai returns whether time is either equal to the Shanghai fork time or greater. +func (c *ChainConfig) IsShanghai(time *big.Int) bool { + return isForked(c.ShanghaiTime, time) } // IsCancun returns whether num is either equal to the Cancun fork block or greater. @@ -620,7 +620,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "arrowGlacierBlock", block: c.ArrowGlacierBlock, optional: true}, {name: "grayGlacierBlock", block: c.GrayGlacierBlock, optional: true}, {name: "mergeNetsplitBlock", block: c.MergeNetsplitBlock, optional: true}, - {name: "shanghaiBlock", block: c.ShanghaiBlock, optional: true}, + //{name: "shanghaiBlock", block: c.ShanghaiBlock, optional: true}, {name: "cancunBlock", block: c.CancunBlock, optional: true}, } { if lastFork.name != "" { @@ -700,9 +700,11 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, head) { return newCompatError("Merge netsplit fork block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock) } - if isForkIncompatible(c.ShanghaiBlock, newcfg.ShanghaiBlock, head) { - return newCompatError("Shanghai fork block", c.ShanghaiBlock, newcfg.ShanghaiBlock) - } + /* + if isForkIncompatible(c.ShanghaiBlock, newcfg.ShanghaiBlock, head) { + return newCompatError("Shanghai fork block", c.ShanghaiBlock, newcfg.ShanghaiBlock) + } + */ if isForkIncompatible(c.CancunBlock, newcfg.CancunBlock, head) { return newCompatError("Cancun fork block", c.CancunBlock, newcfg.CancunBlock) } @@ -788,7 +790,7 @@ type Rules struct { } // Rules ensures c's ChainID is not nil. -func (c *ChainConfig) Rules(num *big.Int, isMerge bool) Rules { +func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp *big.Int) Rules { chainID := c.ChainID if chainID == nil { chainID = new(big.Int) @@ -806,7 +808,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool) Rules { IsBerlin: c.IsBerlin(num), IsLondon: c.IsLondon(num), IsMerge: isMerge, - IsShanghai: c.IsShanghai(num), + IsShanghai: c.IsShanghai(timestamp), isCancun: c.IsCancun(num), } } From a4e19c5ca3c8e28cf68b7ef9f16ea548fd3dafb2 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 10 Nov 2022 15:25:32 +0100 Subject: [PATCH 440/715] all: implement forkid changes for shanghai --- cmd/devp2p/internal/ethtest/chain.go | 2 +- core/forkid/forkid.go | 115 +++++++++++----- core/forkid/forkid_test.go | 188 ++++++++++++++++++++++++++- eth/handler.go | 2 +- eth/protocols/eth/discovery.go | 2 +- eth/protocols/eth/handshake_test.go | 2 +- les/client_handler.go | 2 +- les/peer_test.go | 4 +- les/server_handler.go | 2 +- les/test_helper.go | 4 +- tests/state_test.go | 2 +- 11 files changed, 277 insertions(+), 48 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index 83ceb2a4f2c5..f4db05db8e39 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -76,7 +76,7 @@ func (c *Chain) RootAt(height int) common.Hash { // ForkID gets the fork id of the chain. func (c *Chain) ForkID() forkid.ID { - return forkid.NewID(c.chainConfig, c.blocks[0].Hash(), uint64(c.Len())) + return forkid.NewID(c.chainConfig, c.blocks[0].Hash(), uint64(c.Len()), c.blocks[0].Time()) } // Shorten returns a copy chain of a desired height from the imported diff --git a/core/forkid/forkid.go b/core/forkid/forkid.go index f56ce85feeed..b35fd92b2aa2 100644 --- a/core/forkid/forkid.go +++ b/core/forkid/forkid.go @@ -24,6 +24,7 @@ import ( "math" "math/big" "reflect" + "sort" "strings" "github.com/ethereum/go-ethereum/common" @@ -65,19 +66,28 @@ type ID struct { // Filter is a fork id filter to validate a remotely advertised ID. type Filter func(id ID) error -// NewID calculates the Ethereum fork ID from the chain config, genesis hash, and head. -func NewID(config *params.ChainConfig, genesis common.Hash, head uint64) ID { +// NewID calculates the Ethereum fork ID from the chain config, genesis hash, head and time. +func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) ID { // Calculate the starting checksum from the genesis hash hash := crc32.ChecksumIEEE(genesis[:]) // Calculate the current fork checksum and the next fork block - var next uint64 - for _, fork := range gatherForks(config) { + forks, forksByTime := gatherForks(config) + for _, fork := range forks { if fork <= head { // Fork already passed, checksum the previous hash and the fork number hash = checksumUpdate(hash, fork) continue } + return ID{Hash: checksumToBytes(hash), Next: fork} + } + var next uint64 + for _, fork := range forksByTime { + if time >= fork { + // Fork passed, checksum previous hash and fork time + hash = checksumUpdate(hash, fork) + continue + } next = fork break } @@ -90,6 +100,7 @@ func NewIDWithChain(chain Blockchain) ID { chain.Config(), chain.Genesis().Hash(), chain.CurrentHeader().Number.Uint64(), + chain.CurrentHeader().Time, ) } @@ -99,36 +110,40 @@ func NewFilter(chain Blockchain) Filter { return newFilter( chain.Config(), chain.Genesis().Hash(), - func() uint64 { - return chain.CurrentHeader().Number.Uint64() + func() (uint64, uint64) { + return chain.CurrentHeader().Number.Uint64(), chain.CurrentHeader().Time }, ) } // NewStaticFilter creates a filter at block zero. func NewStaticFilter(config *params.ChainConfig, genesis common.Hash) Filter { - head := func() uint64 { return 0 } + head := func() (uint64, uint64) { return 0, 0 } return newFilter(config, genesis, head) } // newFilter is the internal version of NewFilter, taking closures as its arguments // instead of a chain. The reason is to allow testing it without having to simulate // an entire blockchain. -func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() uint64) Filter { +func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() (uint64, uint64)) Filter { // Calculate the all the valid fork hash and fork next combos var ( - forks = gatherForks(config) - sums = make([][4]byte, len(forks)+1) // 0th is the genesis + forks, forksByTime = gatherForks(config) + sums = make([][4]byte, len(forks)+len(forksByTime)+1) // 0th is the genesis ) + allForks := append(forks, forksByTime...) hash := crc32.ChecksumIEEE(genesis[:]) sums[0] = checksumToBytes(hash) - for i, fork := range forks { + for i, fork := range allForks { hash = checksumUpdate(hash, fork) sums[i+1] = checksumToBytes(hash) } // Add two sentries to simplify the fork checks and don't require special // casing the last one. - forks = append(forks, math.MaxUint64) // Last fork will never be passed + if len(forksByTime) == 0 { + forks = append(forks, math.MaxUint64) + } + forksByTime = append(forksByTime, math.MaxUint64) // Last fork will never be passed // Create a validator that will filter out incompatible chains return func(id ID) error { @@ -151,19 +166,14 @@ func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() ui // the remote, but at this current point in time we don't have enough // information. // 4. Reject in all other cases. - head := headfn() - for i, fork := range forks { - // If our head is beyond this fork, continue to the next (we have a dummy - // fork of maxuint64 as the last item to always fail this check eventually). - if head >= fork { - continue - } + + verify := func(index int, headOrTime uint64) error { // Found the first unpassed fork block, check if our current state matches // the remote checksum (rule #1). - if sums[i] == id.Hash { + if sums[index] == id.Hash { // Fork checksum matched, check if a remote future fork block already passed // locally without the local node being aware of it (rule #1a). - if id.Next > 0 && head >= id.Next { + if id.Next > 0 && headOrTime >= id.Next { return ErrLocalIncompatibleOrStale } // Haven't passed locally a remote-only fork, accept the connection (rule #1b). @@ -171,10 +181,10 @@ func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() ui } // The local and remote nodes are in different forks currently, check if the // remote checksum is a subset of our local forks (rule #2). - for j := 0; j < i; j++ { + for j := 0; j < index; j++ { if sums[j] == id.Hash { // Remote checksum is a subset, validate based on the announced next fork - if forks[j] != id.Next { + if allForks[j] != id.Next { return ErrRemoteStale } return nil @@ -182,7 +192,7 @@ func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() ui } // Remote chain is not a subset of our local one, check if it's a superset by // any chance, signalling that we're simply out of sync (rule #3). - for j := i + 1; j < len(sums); j++ { + for j := index + 1; j < len(sums); j++ { if sums[j] == id.Hash { // Yay, remote checksum is a superset, ignore upcoming forks return nil @@ -191,6 +201,27 @@ func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() ui // No exact, subset or superset match. We are on differing chains, reject. return ErrLocalIncompatibleOrStale } + + head, time := headfn() + // Verify forks by block + for i, fork := range forks { + // If our head is beyond this fork, continue to the next (we have a dummy + // fork of maxuint64 as the last item to always fail this check eventually). + if head >= fork { + continue + } + return verify(i, head) + } + // Verify forks by time + for i, fork := range forksByTime { + // If our head is beyond this fork, continue to the next (we have a dummy + // fork of maxuint64 as the last item to always fail this check eventually). + if time >= fork { + continue + } + return verify(len(forks)+i, time) + } + log.Error("Impossible fork ID validation", "id", id) return nil // Something's very wrong, accept rather than reject } @@ -212,17 +243,22 @@ func checksumToBytes(hash uint32) [4]byte { } // gatherForks gathers all the known forks and creates a sorted list out of them. -func gatherForks(config *params.ChainConfig) []uint64 { +func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) { // Gather all the fork block numbers via reflection kind := reflect.TypeOf(params.ChainConfig{}) conf := reflect.ValueOf(config).Elem() var forks []uint64 + var forksByTime []uint64 for i := 0; i < kind.NumField(); i++ { // Fetch the next field and skip non-fork rules field := kind.Field(i) + time := false if !strings.HasSuffix(field.Name, "Block") { - continue + if !strings.HasSuffix(field.Name, "Time") { + continue + } + time = true } if field.Type != reflect.TypeOf(new(big.Int)) { continue @@ -230,17 +266,17 @@ func gatherForks(config *params.ChainConfig) []uint64 { // Extract the fork rule block number and aggregate it rule := conf.Field(i).Interface().(*big.Int) if rule != nil { - forks = append(forks, rule.Uint64()) - } - } - // Sort the fork block numbers to permit chronological XOR - for i := 0; i < len(forks); i++ { - for j := i + 1; j < len(forks); j++ { - if forks[i] > forks[j] { - forks[i], forks[j] = forks[j], forks[i] + if time { + forksByTime = append(forksByTime, rule.Uint64()) + } else { + forks = append(forks, rule.Uint64()) } } } + + sort.Slice(forks, func(i, j int) bool { return forks[i] < forks[j] }) + sort.Slice(forksByTime, func(i, j int) bool { return forksByTime[i] < forksByTime[j] }) + // Deduplicate block numbers applying multiple forks for i := 1; i < len(forks); i++ { if forks[i] == forks[i-1] { @@ -248,9 +284,18 @@ func gatherForks(config *params.ChainConfig) []uint64 { i-- } } + for i := 1; i < len(forksByTime); i++ { + if forksByTime[i] == forksByTime[i-1] { + forksByTime = append(forksByTime[:i], forksByTime[i+1:]...) + i-- + } + } // Skip any forks in block 0, that's the genesis ruleset if len(forks) > 0 && forks[0] == 0 { forks = forks[1:] } - return forks + if len(forksByTime) > 0 && forksByTime[0] == 0 { + forksByTime = forksByTime[1:] + } + return forks, forksByTime } diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index 2a0fb167d516..0158545f345e 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -185,7 +185,105 @@ func TestCreation(t *testing.T) { } for i, tt := range tests { for j, ttt := range tt.cases { - if have := NewID(tt.config, tt.genesis, ttt.head); have != ttt.want { + if have := NewID(tt.config, tt.genesis, ttt.head, 0); have != ttt.want { + t.Errorf("test %d, case %d: fork ID mismatch: have %x, want %x", i, j, have, ttt.want) + } + } + } +} + +// TestCreationWithTimestamps tests that different genesis and fork rule combinations result in +// the correct fork ID even for time based forks. +func TestCreationWithTimestamps(t *testing.T) { + mergeConfig := *params.MainnetChainConfig + mergeConfig.MergeNetsplitBlock = big.NewInt(18000000) + + withdrawalConfig := *params.MainnetChainConfig + withdrawalConfig.MergeNetsplitBlock = big.NewInt(18000000) + withdrawalConfig.ShanghaiTime = big.NewInt(1668000000) + type testcase struct { + head uint64 + time uint64 + want ID + } + tests := []struct { + config *params.ChainConfig + genesis common.Hash + cases []testcase + }{ + // Mainnet test cases + { + params.MainnetChainConfig, + params.MainnetGenesisHash, + []testcase{ + {0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced + {1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block + {1150000, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // First Homestead block + {1919999, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // Last Homestead block + {1920000, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // First DAO block + {2462999, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // Last DAO block + {2463000, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // First Tangerine block + {2674999, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // Last Tangerine block + {2675000, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // First Spurious block + {4369999, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // Last Spurious block + {4370000, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // First Byzantium block + {7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // Last Byzantium block + {7280000, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // First and last Constantinople, first Petersburg block + {9068999, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // Last Petersburg block + {9069000, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // First Istanbul and first Muir Glacier block + {9199999, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // Last Istanbul and first Muir Glacier block + {9200000, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // First Muir Glacier block + {12243999, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // Last Muir Glacier block + {12244000, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // First Berlin block + {12964999, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block + {12965000, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block + {13772999, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block + {13773000, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block + {15049999, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block + {15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}}, // First Gray Glacier block + {20000000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}}, // Future Gray Glacier block + }, + }, + // Withdrawal test cases + { + &withdrawalConfig, + params.MainnetGenesisHash, + []testcase{ + {0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced + {1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block + {1150000, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // First Homestead block + {1919999, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // Last Homestead block + {1920000, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // First DAO block + {2462999, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // Last DAO block + {2463000, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // First Tangerine block + {2674999, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // Last Tangerine block + {2675000, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // First Spurious block + {4369999, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // Last Spurious block + {4370000, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // First Byzantium block + {7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // Last Byzantium block + {7280000, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // First and last Constantinople, first Petersburg block + {9068999, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // Last Petersburg block + {9069000, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // First Istanbul and first Muir Glacier block + {9199999, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // Last Istanbul and first Muir Glacier block + {9200000, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // First Muir Glacier block + {12243999, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // Last Muir Glacier block + {12244000, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // First Berlin block + {12964999, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block + {12965000, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block + {13772999, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block + {13773000, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block + {15049999, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block + {15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 18000000}}, // First Gray Glacier block + {18000000, 0, ID{Hash: checksumToBytes(0x4fb8a872), Next: 1668000000}}, // First Merge Start block + {20000000, 0, ID{Hash: checksumToBytes(0x4fb8a872), Next: 1668000000}}, // Last Merge Start block + {20000000, 1668000000, ID{Hash: checksumToBytes(0xc1fdf181), Next: 0}}, // First Merge Start block + {20000000, 2668000000, ID{Hash: checksumToBytes(0xc1fdf181), Next: 0}}, // Future Merge Start block + }, + }, + } + for i, tt := range tests { + for j, ttt := range tt.cases { + if have := NewID(tt.config, tt.genesis, ttt.head, ttt.time); have != ttt.want { t.Errorf("test %d, case %d: fork ID mismatch: have %x, want %x", i, j, have, ttt.want) } } @@ -267,7 +365,93 @@ func TestValidation(t *testing.T) { {7279999, ID{Hash: checksumToBytes(0xa00bc324), Next: 7279999}, ErrLocalIncompatibleOrStale}, } for i, tt := range tests { - filter := newFilter(params.MainnetChainConfig, params.MainnetGenesisHash, func() uint64 { return tt.head }) + filter := newFilter(params.MainnetChainConfig, params.MainnetGenesisHash, func() (uint64, uint64) { return tt.head, 0 }) + if err := filter(tt.id); err != tt.err { + t.Errorf("test %d: validation error mismatch: have %v, want %v", i, err, tt.err) + } + } +} + +// TestValidationByTimestamp tests that a local peer correctly validates and accepts a remote +// fork ID. +func TestValidationByTimestamp(t *testing.T) { + withdrawalConfig := *params.MainnetChainConfig + withdrawalConfig.MergeNetsplitBlock = big.NewInt(18000000) + withdrawalConfig.ShanghaiTime = big.NewInt(1668000000) + tests := []struct { + head uint64 + time uint64 + id ID + err error + }{ + // Local is mainnet Withdrawals, remote announces the same. No future fork is announced. + {20000000, 1668000001, ID{Hash: checksumToBytes(0xc1fdf181), Next: 0}, nil}, + + // Local is mainnet Withdrawals, remote announces the same also announces a next fork + // at block/time 0xffffffff, but that is uncertain. + {20000000, 1668000001, ID{Hash: checksumToBytes(0xc1fdf181), Next: math.MaxUint64}, nil}, + + // Local is mainnet currently in Byzantium only (so it's aware of Petersburg & Withdrawals), remote announces + // also Byzantium, but it's not yet aware of Petersburg (e.g. non updated node before the fork). + // In this case we don't know if Petersburg passed yet or not. + {7279999, 1667999999, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, + + // Local is mainnet currently in Byzantium only (so it's aware of Petersburg & Withdrawals), remote announces + // also Byzantium, and it's also aware of Petersburg (e.g. updated node before the fork). We + // don't know if Petersburg passed yet (will pass) or not. + {7279999, 1667999999, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + + // Local is mainnet currently in Byzantium only (so it's aware of Petersburg & Withdrawals), remote announces + // also Byzantium, and it's also aware of some random fork (e.g. misconfigured Petersburg). As + // neither forks passed at neither nodes, they may mismatch, but we still connect for now. + {7279999, 1667999999, ID{Hash: checksumToBytes(0xa00bc324), Next: math.MaxUint64}, nil}, + + // Local is mainnet exactly on Withdrawals, remote announces Byzantium + knowledge about Petersburg. Remote + // is simply out of sync, accept. + {20000000, 1668000000, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + + // Local is mainnet Withdrawals, remote announces Byzantium + knowledge about Petersburg. Remote + // is simply out of sync, accept. + {20000000, 1668000001, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + + // Local is mainnet Withdrawals, remote announces Spurious + knowledge about Byzantium. Remote + // is definitely out of sync. It may or may not need the Petersburg update, we don't know yet. + {20000000, 1668000001, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, + + // Local is mainnet Byzantium & pre-withdrawals, remote announces Petersburg. Local is out of sync, accept. + {7279999, 1667999999, ID{Hash: checksumToBytes(0x668db0af), Next: 0}, nil}, + + // Local is mainnet Spurious, remote announces Byzantium, but is not aware of Petersburg. Local + // out of sync. Local also knows about a future fork, but that is uncertain yet. + {4369999, 1667999999, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, + + // Local is mainnet Withdrawals. remote announces Byzantium but is not aware of further forks. + // Remote needs software update. + {20000000, 1668000001, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, ErrRemoteStale}, + + // Local is mainnet Withdrawals, and isn't aware of more forks. Remote announces Petersburg + + // 0xffffffff. Local needs software update, reject. + {20000000, 1668000001, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, + + // Local is mainnet Withdrawals, and is aware of Petersburg. Remote announces Petersburg + + // 0xffffffff. Local needs software update, reject. + {20000000, 1668000001, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, + + // Local is mainnet Withdrawals, remote is Rinkeby Petersburg. + {20000000, 1668000001, ID{Hash: checksumToBytes(0xafec6b27), Next: 0}, ErrLocalIncompatibleOrStale}, + + // Local is mainnet Withdrawals, far in the future. Remote announces Gopherium (non existing fork) + // at some future block 88888888, for itself, but past block for local. Local is incompatible. + // + // This case detects non-upgraded nodes with majority hash power (typical Ropsten mess). + {88888888, 1668000001, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 88888888}, ErrRemoteStale}, + + // Local is mainnet Withdrawals. Remote is in Byzantium, but announces Gopherium (non existing + // fork) at block 7279999, before Petersburg. Local is incompatible. + {20000000, 1668000001, ID{Hash: checksumToBytes(0xa00bc324), Next: 7279999}, ErrRemoteStale}, + } + for i, tt := range tests { + filter := newFilter(&withdrawalConfig, params.MainnetGenesisHash, func() (uint64, uint64) { return tt.head, tt.time }) if err := filter(tt.id); err != tt.err { t.Errorf("test %d: validation error mismatch: have %v, want %v", i, err, tt.err) } diff --git a/eth/handler.go b/eth/handler.go index 143147b0c815..c67a62b86700 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -331,7 +331,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { number = head.Number.Uint64() td = h.chain.GetTd(hash, number) ) - forkID := forkid.NewID(h.chain.Config(), h.chain.Genesis().Hash(), h.chain.CurrentHeader().Number.Uint64()) + forkID := forkid.NewID(h.chain.Config(), h.chain.Genesis().Hash(), h.chain.CurrentHeader().Number.Uint64(), h.chain.CurrentHeader().Time) if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter); err != nil { peer.Log().Debug("Ethereum handshake failed", "err", err) return err diff --git a/eth/protocols/eth/discovery.go b/eth/protocols/eth/discovery.go index 03f2ea3cc297..345c6e5e2768 100644 --- a/eth/protocols/eth/discovery.go +++ b/eth/protocols/eth/discovery.go @@ -60,6 +60,6 @@ func StartENRUpdater(chain *core.BlockChain, ln *enode.LocalNode) { // currentENREntry constructs an `eth` ENR entry based on the current state of the chain. func currentENREntry(chain *core.BlockChain) *enrEntry { return &enrEntry{ - ForkID: forkid.NewID(chain.Config(), chain.Genesis().Hash(), chain.CurrentHeader().Number.Uint64()), + ForkID: forkid.NewID(chain.Config(), chain.Genesis().Hash(), chain.CurrentHeader().Number.Uint64(), chain.CurrentHeader().Time), } } diff --git a/eth/protocols/eth/handshake_test.go b/eth/protocols/eth/handshake_test.go index 8cf5216cf442..c768edaeac01 100644 --- a/eth/protocols/eth/handshake_test.go +++ b/eth/protocols/eth/handshake_test.go @@ -40,7 +40,7 @@ func testHandshake(t *testing.T, protocol uint) { genesis = backend.chain.Genesis() head = backend.chain.CurrentBlock() td = backend.chain.GetTd(head.Hash(), head.NumberU64()) - forkID = forkid.NewID(backend.chain.Config(), backend.chain.Genesis().Hash(), backend.chain.CurrentHeader().Number.Uint64()) + forkID = forkid.NewID(backend.chain.Config(), backend.chain.Genesis().Hash(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time) ) tests := []struct { code uint64 diff --git a/les/client_handler.go b/les/client_handler.go index e416f92e29a9..cce99d41dc14 100644 --- a/les/client_handler.go +++ b/les/client_handler.go @@ -111,7 +111,7 @@ func (h *clientHandler) handle(p *serverPeer, noInitAnnounce bool) error { p.Log().Debug("Light Ethereum peer connected", "name", p.Name()) // Execute the LES handshake - forkid := forkid.NewID(h.backend.blockchain.Config(), h.backend.genesis, h.backend.blockchain.CurrentHeader().Number.Uint64()) + forkid := forkid.NewID(h.backend.blockchain.Config(), h.backend.genesis, h.backend.blockchain.CurrentHeader().Number.Uint64(), h.backend.blockchain.CurrentHeader().Time) if err := p.Handshake(h.backend.blockchain.Genesis().Hash(), forkid, h.forkFilter); err != nil { p.Log().Debug("Light Ethereum handshake failed", "err", err) return err diff --git a/les/peer_test.go b/les/peer_test.go index b8a1482a040a..021d5cb594c4 100644 --- a/les/peer_test.go +++ b/les/peer_test.go @@ -124,8 +124,8 @@ func TestHandshake(t *testing.T) { genesis = common.HexToHash("cafebabe") chain1, chain2 = &fakeChain{}, &fakeChain{} - forkID1 = forkid.NewID(chain1.Config(), chain1.Genesis().Hash(), chain1.CurrentHeader().Number.Uint64()) - forkID2 = forkid.NewID(chain2.Config(), chain2.Genesis().Hash(), chain2.CurrentHeader().Number.Uint64()) + forkID1 = forkid.NewID(chain1.Config(), chain1.Genesis().Hash(), chain1.CurrentHeader().Number.Uint64(), chain1.CurrentHeader().Time) + forkID2 = forkid.NewID(chain2.Config(), chain2.Genesis().Hash(), chain2.CurrentHeader().Number.Uint64(), chain2.CurrentHeader().Time) filter1, filter2 = forkid.NewFilter(chain1), forkid.NewFilter(chain2) ) diff --git a/les/server_handler.go b/les/server_handler.go index 28815c3d85ef..b9fb1d19bfc2 100644 --- a/les/server_handler.go +++ b/les/server_handler.go @@ -117,7 +117,7 @@ func (h *serverHandler) handle(p *clientPeer) error { hash = head.Hash() number = head.Number.Uint64() td = h.blockchain.GetTd(hash, number) - forkID = forkid.NewID(h.blockchain.Config(), h.blockchain.Genesis().Hash(), h.blockchain.CurrentBlock().NumberU64()) + forkID = forkid.NewID(h.blockchain.Config(), h.blockchain.Genesis().Hash(), h.blockchain.CurrentBlock().NumberU64(), h.blockchain.CurrentBlock().Time()) ) if err := p.Handshake(td, hash, number, h.blockchain.Genesis().Hash(), forkID, h.forkFilter, h.server); err != nil { p.Log().Debug("Light Ethereum handshake failed", "err", err) diff --git a/les/test_helper.go b/les/test_helper.go index 33a76252bf05..714bc7b3f625 100644 --- a/les/test_helper.go +++ b/les/test_helper.go @@ -489,7 +489,7 @@ func (client *testClient) newRawPeer(t *testing.T, name string, version int, rec head = client.handler.backend.blockchain.CurrentHeader() td = client.handler.backend.blockchain.GetTd(head.Hash(), head.Number.Uint64()) ) - forkID := forkid.NewID(client.handler.backend.blockchain.Config(), genesis.Hash(), head.Number.Uint64()) + forkID := forkid.NewID(client.handler.backend.blockchain.Config(), genesis.Hash(), head.Number.Uint64(), head.Time) tp.handshakeWithClient(t, td, head.Hash(), head.Number.Uint64(), genesis.Hash(), forkID, testCostList(0), recentTxLookup) // disable flow control by default // Ensure the connection is established or exits when any error occurs @@ -553,7 +553,7 @@ func (server *testServer) newRawPeer(t *testing.T, name string, version int) (*t head = server.handler.blockchain.CurrentHeader() td = server.handler.blockchain.GetTd(head.Hash(), head.Number.Uint64()) ) - forkID := forkid.NewID(server.handler.blockchain.Config(), genesis.Hash(), head.Number.Uint64()) + forkID := forkid.NewID(server.handler.blockchain.Config(), genesis.Hash(), head.Number.Uint64(), head.Time) tp.handshakeWithServer(t, td, head.Hash(), head.Number.Uint64(), genesis.Hash(), forkID) // Ensure the connection is established or exits when any error occurs diff --git a/tests/state_test.go b/tests/state_test.go index 64d01076c956..4c5e7b914f9b 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -183,7 +183,7 @@ func runBenchmark(b *testing.B, t *StateTest) { b.Error(err) return } - var rules = config.Rules(new(big.Int), false) + var rules = config.Rules(new(big.Int), false, new(big.Int)) vmconfig.ExtraEips = eips block := t.genesis(config).ToBlock() From 08481028fe08233fd285746139ac31a027382cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 15 Dec 2022 09:40:33 +0200 Subject: [PATCH 441/715] core, les, params: add timestamp based fork compatibility checks --- core/blockchain.go | 6 +- core/blockchain_test.go | 2 +- core/genesis.go | 10 +- core/genesis_test.go | 8 +- les/client.go | 6 +- params/config.go | 289 ++++++++++++++++++++++++++-------------- params/config_test.go | 106 +++++++++------ 7 files changed, 272 insertions(+), 155 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 2ca1e2fc7b93..62f435060eb0 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -427,7 +427,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // Rewind the chain in case of an incompatible config upgrade. if compat, ok := genesisErr.(*params.ConfigCompatError); ok { log.Warn("Rewinding chain to upgrade configuration", "err", compat) - bc.SetHead(compat.RewindTo) + if compat.RewindToTime > 0 { + log.Crit("Timestamp based rewinds not implemented yet /sad") + } else { + bc.SetHead(compat.RewindToBlock) + } rawdb.WriteChainConfig(db, genesisHash, chainConfig) } // Start tx indexer/unindexer if required. diff --git a/core/blockchain_test.go b/core/blockchain_test.go index d803617e2f75..36bfa0752558 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4275,7 +4275,7 @@ func TestEIP3651(t *testing.T) { gspec.Config.BerlinBlock = common.Big0 gspec.Config.LondonBlock = common.Big0 - gspec.Config.ShanghaiBlock = common.Big0 + gspec.Config.ShanghaiTime = common.Big0 signer := types.LatestSigner(gspec.Config) _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { diff --git a/core/genesis.go b/core/genesis.go index bbfa356af9f4..e1d7778bbb86 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -371,12 +371,12 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen } // Check config compatibility and write the config. Compatibility errors // are returned to the caller unless we're already at block zero. - height := rawdb.ReadHeaderNumber(db, rawdb.ReadHeadHeaderHash(db)) - if height == nil { - return newcfg, stored, fmt.Errorf("missing block number for head header hash") + head := rawdb.ReadHeadHeader(db) + if head == nil { + return newcfg, stored, fmt.Errorf("missing head header") } - compatErr := storedcfg.CheckCompatible(newcfg, *height) - if compatErr != nil && *height != 0 && compatErr.RewindTo != 0 { + compatErr := storedcfg.CheckCompatible(newcfg, head.Number.Uint64(), head.Time) + if compatErr != nil && ((head.Number.Uint64() != 0 && compatErr.RewindToBlock != 0) || (head.Time != 0 && compatErr.RewindToTime != 0)) { return newcfg, stored, compatErr } // Don't overwrite if the old is identical to the new diff --git a/core/genesis_test.go b/core/genesis_test.go index 135ecb934c03..d7030a201ec4 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -132,10 +132,10 @@ func TestSetupGenesis(t *testing.T) { wantHash: customghash, wantConfig: customg.Config, wantErr: ¶ms.ConfigCompatError{ - What: "Homestead fork block", - StoredConfig: big.NewInt(2), - NewConfig: big.NewInt(3), - RewindTo: 1, + What: "Homestead fork block", + StoredBlock: big.NewInt(2), + NewBlock: big.NewInt(3), + RewindToBlock: 1, }, }, } diff --git a/les/client.go b/les/client.go index 7aa4f9b8cc81..9f5822e082c4 100644 --- a/les/client.go +++ b/les/client.go @@ -179,7 +179,11 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { // Rewind the chain in case of an incompatible config upgrade. if compat, ok := genesisErr.(*params.ConfigCompatError); ok { log.Warn("Rewinding chain to upgrade configuration", "err", compat) - leth.blockchain.SetHead(compat.RewindTo) + if compat.RewindToTime > 0 { + log.Crit("Timestamp based rewinds not implemented yet /sad") + } else { + leth.blockchain.SetHead(compat.RewindToBlock) + } rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) } diff --git a/params/config.go b/params/config.go index c4fc021c722c..215c6848a68b 100644 --- a/params/config.go +++ b/params/config.go @@ -371,9 +371,12 @@ type ChainConfig struct { ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated) GrayGlacierBlock *big.Int `json:"grayGlacierBlock,omitempty"` // Eip-5133 (bomb delay) switch block (nil = no fork, 0 = already activated) MergeNetsplitBlock *big.Int `json:"mergeNetsplitBlock,omitempty"` // Virtual fork after The Merge to use as a network splitter - ShanghaiTime *big.Int `json:"shanghaiBlock,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) CancunBlock *big.Int `json:"cancunBlock,omitempty"` // Cancun switch block (nil = no fork, 0 = already on cancun) + // Fork scheduling was switched from blocks to timestamps here + + ShanghaiTime *big.Int `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) + // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. TerminalTotalDifficulty *big.Int `json:"terminalTotalDifficulty,omitempty"` @@ -465,9 +468,7 @@ func (c *ChainConfig) Description() string { if c.GrayGlacierBlock != nil { banner += fmt.Sprintf(" - Gray Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md)\n", c.GrayGlacierBlock) } - if c.ShanghaiTime != nil { - banner += fmt.Sprintf(" - Shanghai: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", c.ShanghaiTime) - } + banner += fmt.Sprintf(" - Shanghai: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", c.ShanghaiTime) if c.CancunBlock != nil { banner += fmt.Sprintf(" - Cancun: %-8v\n", c.CancunBlock) } @@ -489,74 +490,74 @@ func (c *ChainConfig) Description() string { // IsHomestead returns whether num is either equal to the homestead block or greater. func (c *ChainConfig) IsHomestead(num *big.Int) bool { - return isForked(c.HomesteadBlock, num) + return isBlockForked(c.HomesteadBlock, num) } // IsDAOFork returns whether num is either equal to the DAO fork block or greater. func (c *ChainConfig) IsDAOFork(num *big.Int) bool { - return isForked(c.DAOForkBlock, num) + return isBlockForked(c.DAOForkBlock, num) } // IsEIP150 returns whether num is either equal to the EIP150 fork block or greater. func (c *ChainConfig) IsEIP150(num *big.Int) bool { - return isForked(c.EIP150Block, num) + return isBlockForked(c.EIP150Block, num) } // IsEIP155 returns whether num is either equal to the EIP155 fork block or greater. func (c *ChainConfig) IsEIP155(num *big.Int) bool { - return isForked(c.EIP155Block, num) + return isBlockForked(c.EIP155Block, num) } // IsEIP158 returns whether num is either equal to the EIP158 fork block or greater. func (c *ChainConfig) IsEIP158(num *big.Int) bool { - return isForked(c.EIP158Block, num) + return isBlockForked(c.EIP158Block, num) } // IsByzantium returns whether num is either equal to the Byzantium fork block or greater. func (c *ChainConfig) IsByzantium(num *big.Int) bool { - return isForked(c.ByzantiumBlock, num) + return isBlockForked(c.ByzantiumBlock, num) } // IsConstantinople returns whether num is either equal to the Constantinople fork block or greater. func (c *ChainConfig) IsConstantinople(num *big.Int) bool { - return isForked(c.ConstantinopleBlock, num) + return isBlockForked(c.ConstantinopleBlock, num) } // IsMuirGlacier returns whether num is either equal to the Muir Glacier (EIP-2384) fork block or greater. func (c *ChainConfig) IsMuirGlacier(num *big.Int) bool { - return isForked(c.MuirGlacierBlock, num) + return isBlockForked(c.MuirGlacierBlock, num) } // IsPetersburg returns whether num is either // - equal to or greater than the PetersburgBlock fork block, // - OR is nil, and Constantinople is active func (c *ChainConfig) IsPetersburg(num *big.Int) bool { - return isForked(c.PetersburgBlock, num) || c.PetersburgBlock == nil && isForked(c.ConstantinopleBlock, num) + return isBlockForked(c.PetersburgBlock, num) || c.PetersburgBlock == nil && isBlockForked(c.ConstantinopleBlock, num) } // IsIstanbul returns whether num is either equal to the Istanbul fork block or greater. func (c *ChainConfig) IsIstanbul(num *big.Int) bool { - return isForked(c.IstanbulBlock, num) + return isBlockForked(c.IstanbulBlock, num) } // IsBerlin returns whether num is either equal to the Berlin fork block or greater. func (c *ChainConfig) IsBerlin(num *big.Int) bool { - return isForked(c.BerlinBlock, num) + return isBlockForked(c.BerlinBlock, num) } // IsLondon returns whether num is either equal to the London fork block or greater. func (c *ChainConfig) IsLondon(num *big.Int) bool { - return isForked(c.LondonBlock, num) + return isBlockForked(c.LondonBlock, num) } // IsArrowGlacier returns whether num is either equal to the Arrow Glacier (EIP-4345) fork block or greater. func (c *ChainConfig) IsArrowGlacier(num *big.Int) bool { - return isForked(c.ArrowGlacierBlock, num) + return isBlockForked(c.ArrowGlacierBlock, num) } // IsGrayGlacier returns whether num is either equal to the Gray Glacier (EIP-5133) fork block or greater. func (c *ChainConfig) IsGrayGlacier(num *big.Int) bool { - return isForked(c.GrayGlacierBlock, num) + return isBlockForked(c.GrayGlacierBlock, num) } // IsTerminalPoWBlock returns whether the given block is the last block of PoW stage. @@ -567,30 +568,37 @@ func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *bi return parentTotalDiff.Cmp(c.TerminalTotalDifficulty) < 0 && totalDiff.Cmp(c.TerminalTotalDifficulty) >= 0 } -// IsShanghai returns whether time is either equal to the Shanghai fork time or greater. -func (c *ChainConfig) IsShanghai(time *big.Int) bool { - return isForked(c.ShanghaiTime, time) -} - // IsCancun returns whether num is either equal to the Cancun fork block or greater. func (c *ChainConfig) IsCancun(num *big.Int) bool { - return isForked(c.CancunBlock, num) + return isBlockForked(c.CancunBlock, num) +} + +// IsShanghai returns whether time is either equal to the Shanghai fork time or greater. +func (c *ChainConfig) IsShanghai(time *big.Int) bool { + return isTimestampForked(c.ShanghaiTime, time) } // CheckCompatible checks whether scheduled fork transitions have been imported // with a mismatching chain configuration. -func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError { - bhead := new(big.Int).SetUint64(height) - +func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError { + var ( + bhead = new(big.Int).SetUint64(height) + btime = new(big.Int).SetUint64(time) + ) // Iterate checkCompatible to find the lowest conflict. var lasterr *ConfigCompatError for { - err := c.checkCompatible(newcfg, bhead) - if err == nil || (lasterr != nil && err.RewindTo == lasterr.RewindTo) { + err := c.checkCompatible(newcfg, bhead, btime) + if err == nil || (lasterr != nil && err.RewindToBlock == lasterr.RewindToBlock && err.RewindToTime == lasterr.RewindToTime) { break } lasterr = err - bhead.SetUint64(err.RewindTo) + + if err.RewindToTime > 0 { + btime.SetUint64(err.RewindToTime) + } else { + bhead.SetUint64(err.RewindToBlock) + } } return lasterr } @@ -599,9 +607,10 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *Confi // to guarantee that forks can be implemented in a different order than on official networks func (c *ChainConfig) CheckConfigForkOrder() error { type fork struct { - name string - block *big.Int - optional bool // if true, the fork may be nil and next fork is still allowed + name string + block *big.Int // forks up to - and including the merge - were defined with block numbers + timestamp *big.Int // forks after the merge are scheduled using timestamps + optional bool // if true, the fork may be nil and next fork is still allowed } var lastFork fork for _, cur := range []fork{ @@ -620,93 +629,107 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "arrowGlacierBlock", block: c.ArrowGlacierBlock, optional: true}, {name: "grayGlacierBlock", block: c.GrayGlacierBlock, optional: true}, {name: "mergeNetsplitBlock", block: c.MergeNetsplitBlock, optional: true}, - //{name: "shanghaiBlock", block: c.ShanghaiBlock, optional: true}, {name: "cancunBlock", block: c.CancunBlock, optional: true}, + {name: "shanghaiTime", timestamp: c.ShanghaiTime}, } { if lastFork.name != "" { - // Next one must be higher number - if lastFork.block == nil && cur.block != nil { - return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at %v", - lastFork.name, cur.name, cur.block) - } - if lastFork.block != nil && cur.block != nil { - if lastFork.block.Cmp(cur.block) > 0 { - return fmt.Errorf("unsupported fork ordering: %v enabled at %v, but %v enabled at %v", + switch { + // Non-optional forks must all be present in the chain config up to the last defined fork + case lastFork.block == nil && lastFork.timestamp == nil && (cur.block != nil || cur.timestamp != nil): + if cur.block != nil { + return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at block %v", + lastFork.name, cur.name, cur.block) + } else { + return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at timestamp %v", + lastFork.name, cur.name, cur.timestamp) + } + + // Fork (whether defined by block or timestamp) must follow the fork definition sequence + case (lastFork.block != nil && cur.block != nil) || (lastFork.timestamp != nil && cur.timestamp != nil): + if lastFork.block != nil && lastFork.block.Cmp(cur.block) > 0 { + return fmt.Errorf("unsupported fork ordering: %v enabled at block %v, but %v enabled at block %v", lastFork.name, lastFork.block, cur.name, cur.block) + } else if lastFork.timestamp != nil && lastFork.timestamp.Cmp(cur.timestamp) > 0 { + return fmt.Errorf("unsupported fork ordering: %v enabled at timestamp %v, but %v enabled at timestamp %v", + lastFork.name, lastFork.timestamp, cur.name, cur.timestamp) + } + + // Timestamp based forks can follow block based ones, but not the other way around + if lastFork.timestamp != nil && cur.block != nil { + return fmt.Errorf("unsupported fork ordering: %v used timestamp ordering, but %v reverted to block ordering", + lastFork.name, cur.name) } } } // If it was optional and not set, then ignore it - if !cur.optional || cur.block != nil { + if !cur.optional || (cur.block != nil || cur.timestamp != nil) { lastFork = cur } } return nil } -func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError { - if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) { - return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock) +func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, headTimestamp *big.Int) *ConfigCompatError { + if isForkBlockIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, headNumber) { + return newBlockCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock) } - if isForkIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, head) { - return newCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock) + if isForkBlockIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, headNumber) { + return newBlockCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock) } - if c.IsDAOFork(head) && c.DAOForkSupport != newcfg.DAOForkSupport { - return newCompatError("DAO fork support flag", c.DAOForkBlock, newcfg.DAOForkBlock) + if c.IsDAOFork(headNumber) && c.DAOForkSupport != newcfg.DAOForkSupport { + return newBlockCompatError("DAO fork support flag", c.DAOForkBlock, newcfg.DAOForkBlock) } - if isForkIncompatible(c.EIP150Block, newcfg.EIP150Block, head) { - return newCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block) + if isForkBlockIncompatible(c.EIP150Block, newcfg.EIP150Block, headNumber) { + return newBlockCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block) } - if isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) { - return newCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block) + if isForkBlockIncompatible(c.EIP155Block, newcfg.EIP155Block, headNumber) { + return newBlockCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block) } - if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) { - return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block) + if isForkBlockIncompatible(c.EIP158Block, newcfg.EIP158Block, headNumber) { + return newBlockCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block) } - if c.IsEIP158(head) && !configNumEqual(c.ChainID, newcfg.ChainID) { - return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block) + if c.IsEIP158(headNumber) && !configBlockEqual(c.ChainID, newcfg.ChainID) { + return newBlockCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block) } - if isForkIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, head) { - return newCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock) + if isForkBlockIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, headNumber) { + return newBlockCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock) } - if isForkIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) { - return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock) + if isForkBlockIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, headNumber) { + return newBlockCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock) } - if isForkIncompatible(c.PetersburgBlock, newcfg.PetersburgBlock, head) { + if isForkBlockIncompatible(c.PetersburgBlock, newcfg.PetersburgBlock, headNumber) { // the only case where we allow Petersburg to be set in the past is if it is equal to Constantinople // mainly to satisfy fork ordering requirements which state that Petersburg fork be set if Constantinople fork is set - if isForkIncompatible(c.ConstantinopleBlock, newcfg.PetersburgBlock, head) { - return newCompatError("Petersburg fork block", c.PetersburgBlock, newcfg.PetersburgBlock) + if isForkBlockIncompatible(c.ConstantinopleBlock, newcfg.PetersburgBlock, headNumber) { + return newBlockCompatError("Petersburg fork block", c.PetersburgBlock, newcfg.PetersburgBlock) } } - if isForkIncompatible(c.IstanbulBlock, newcfg.IstanbulBlock, head) { - return newCompatError("Istanbul fork block", c.IstanbulBlock, newcfg.IstanbulBlock) + if isForkBlockIncompatible(c.IstanbulBlock, newcfg.IstanbulBlock, headNumber) { + return newBlockCompatError("Istanbul fork block", c.IstanbulBlock, newcfg.IstanbulBlock) } - if isForkIncompatible(c.MuirGlacierBlock, newcfg.MuirGlacierBlock, head) { - return newCompatError("Muir Glacier fork block", c.MuirGlacierBlock, newcfg.MuirGlacierBlock) + if isForkBlockIncompatible(c.MuirGlacierBlock, newcfg.MuirGlacierBlock, headNumber) { + return newBlockCompatError("Muir Glacier fork block", c.MuirGlacierBlock, newcfg.MuirGlacierBlock) } - if isForkIncompatible(c.BerlinBlock, newcfg.BerlinBlock, head) { - return newCompatError("Berlin fork block", c.BerlinBlock, newcfg.BerlinBlock) + if isForkBlockIncompatible(c.BerlinBlock, newcfg.BerlinBlock, headNumber) { + return newBlockCompatError("Berlin fork block", c.BerlinBlock, newcfg.BerlinBlock) } - if isForkIncompatible(c.LondonBlock, newcfg.LondonBlock, head) { - return newCompatError("London fork block", c.LondonBlock, newcfg.LondonBlock) + if isForkBlockIncompatible(c.LondonBlock, newcfg.LondonBlock, headNumber) { + return newBlockCompatError("London fork block", c.LondonBlock, newcfg.LondonBlock) } - if isForkIncompatible(c.ArrowGlacierBlock, newcfg.ArrowGlacierBlock, head) { - return newCompatError("Arrow Glacier fork block", c.ArrowGlacierBlock, newcfg.ArrowGlacierBlock) + if isForkBlockIncompatible(c.ArrowGlacierBlock, newcfg.ArrowGlacierBlock, headNumber) { + return newBlockCompatError("Arrow Glacier fork block", c.ArrowGlacierBlock, newcfg.ArrowGlacierBlock) } - if isForkIncompatible(c.GrayGlacierBlock, newcfg.GrayGlacierBlock, head) { - return newCompatError("Gray Glacier fork block", c.GrayGlacierBlock, newcfg.GrayGlacierBlock) + if isForkBlockIncompatible(c.GrayGlacierBlock, newcfg.GrayGlacierBlock, headNumber) { + return newBlockCompatError("Gray Glacier fork block", c.GrayGlacierBlock, newcfg.GrayGlacierBlock) } - if isForkIncompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, head) { - return newCompatError("Merge netsplit fork block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock) + if isForkBlockIncompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, headNumber) { + return newBlockCompatError("Merge netsplit fork block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock) } - /* - if isForkIncompatible(c.ShanghaiBlock, newcfg.ShanghaiBlock, head) { - return newCompatError("Shanghai fork block", c.ShanghaiBlock, newcfg.ShanghaiBlock) - } - */ - if isForkIncompatible(c.CancunBlock, newcfg.CancunBlock, head) { - return newCompatError("Cancun fork block", c.CancunBlock, newcfg.CancunBlock) + if isForkBlockIncompatible(c.CancunBlock, newcfg.CancunBlock, headNumber) { + return newBlockCompatError("Cancun fork block", c.CancunBlock, newcfg.CancunBlock) + } + if isForkTimestampIncompatible(c.ShanghaiTime, newcfg.ShanghaiTime, headTimestamp) { + return newTimestampCompatError("Shanghai fork timestamp", c.ShanghaiTime, newcfg.ShanghaiTime) } return nil } @@ -721,21 +744,49 @@ func (c *ChainConfig) ElasticityMultiplier() uint64 { return DefaultElasticityMultiplier } -// isForkIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to -// block s2 because head is already past the fork. -func isForkIncompatible(s1, s2, head *big.Int) bool { - return (isForked(s1, head) || isForked(s2, head)) && !configNumEqual(s1, s2) +// isForkBlockIncompatible returns true if a fork scheduled at block s1 cannot be +// rescheduled to block s2 because head is already past the fork. +func isForkBlockIncompatible(s1, s2, head *big.Int) bool { + return (isBlockForked(s1, head) || isBlockForked(s2, head)) && !configBlockEqual(s1, s2) } -// isForked returns whether a fork scheduled at block s is active at the given head block. -func isForked(s, head *big.Int) bool { +// isBlockForked returns whether a fork scheduled at block s is active at the +// given head block. Whilst this method is the same as isTimestampForked, they +// are explicitly separate for clearer reading. +func isBlockForked(s, head *big.Int) bool { if s == nil || head == nil { return false } return s.Cmp(head) <= 0 } -func configNumEqual(x, y *big.Int) bool { +func configBlockEqual(x, y *big.Int) bool { + if x == nil { + return y == nil + } + if y == nil { + return x == nil + } + return x.Cmp(y) == 0 +} + +// isForkTimestampIncompatible returns true if a fork scheduled at timestamp s1 +// cannot be rescheduled to timestamp s2 because head is already past the fork. +func isForkTimestampIncompatible(s1, s2, head *big.Int) bool { + return (isTimestampForked(s1, head) || isTimestampForked(s2, head)) && !configTimestampEqual(s1, s2) +} + +// isTimestampForked returns whether a fork scheduled at timestamp s is active +// at the given head timestamp. Whilst this method is the same as isBlockForked, +// they are explicitly separate for clearer reading. +func isTimestampForked(s, head *big.Int) bool { + if s == nil || head == nil { + return false + } + return s.Cmp(head) <= 0 +} + +func configTimestampEqual(x, y *big.Int) bool { if x == nil { return y == nil } @@ -749,13 +800,21 @@ func configNumEqual(x, y *big.Int) bool { // ChainConfig that would alter the past. type ConfigCompatError struct { What string - // block numbers of the stored and new configurations - StoredConfig, NewConfig *big.Int + + // block numbers of the stored and new configurations if block based forking + StoredBlock, NewBlock *big.Int + + // timestamps of the stored and new configurations if time based forking + StoredTime, NewTime *big.Int + // the block number to which the local chain must be rewound to correct the error - RewindTo uint64 + RewindToBlock uint64 + + // the timestamp to which the local chain must be rewound to correct the error + RewindToTime uint64 } -func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError { +func newBlockCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError { var rew *big.Int switch { case storedblock == nil: @@ -765,15 +824,45 @@ func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatEr default: rew = newblock } - err := &ConfigCompatError{what, storedblock, newblock, 0} + err := &ConfigCompatError{ + What: what, + StoredBlock: storedblock, + NewBlock: newblock, + RewindToBlock: 0, + } if rew != nil && rew.Sign() > 0 { - err.RewindTo = rew.Uint64() - 1 + err.RewindToBlock = rew.Uint64() - 1 + } + return err +} + +func newTimestampCompatError(what string, storedtime, newtime *big.Int) *ConfigCompatError { + var rew *big.Int + switch { + case storedtime == nil: + rew = newtime + case newtime == nil || storedtime.Cmp(newtime) < 0: + rew = storedtime + default: + rew = newtime + } + err := &ConfigCompatError{ + What: what, + StoredTime: storedtime, + NewTime: newtime, + RewindToTime: 0, + } + if rew != nil && rew.Sign() > 0 { + err.RewindToTime = rew.Uint64() - 1 } return err } func (err *ConfigCompatError) Error() string { - return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo) + if err.StoredBlock != nil { + return fmt.Sprintf("mismatching %s in database (have block %d, want block %d, rewindto block %d)", err.What, err.StoredBlock, err.NewBlock, err.RewindToBlock) + } + return fmt.Sprintf("mismatching %s in database (have timestamp %d, want timestamp %d, rewindto timestamp %d)", err.What, err.StoredTime, err.NewTime, err.RewindToTime) } // Rules wraps ChainConfig and is merely syntactic sugar or can be used for functions diff --git a/params/config_test.go b/params/config_test.go index 3c8ebaf4a511..523ba26fdc7d 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -20,79 +20,99 @@ import ( "math/big" "reflect" "testing" + "time" ) func TestCheckCompatible(t *testing.T) { type test struct { - stored, new *ChainConfig - head uint64 - wantErr *ConfigCompatError + stored, new *ChainConfig + headBlock uint64 + headTimestamp uint64 + wantErr *ConfigCompatError } tests := []test{ - {stored: AllEthashProtocolChanges, new: AllEthashProtocolChanges, head: 0, wantErr: nil}, - {stored: AllEthashProtocolChanges, new: AllEthashProtocolChanges, head: 100, wantErr: nil}, + {stored: AllEthashProtocolChanges, new: AllEthashProtocolChanges, headBlock: 0, headTimestamp: 0, wantErr: nil}, + {stored: AllEthashProtocolChanges, new: AllEthashProtocolChanges, headBlock: 0, headTimestamp: uint64(time.Now().Unix()), wantErr: nil}, + {stored: AllEthashProtocolChanges, new: AllEthashProtocolChanges, headBlock: 100, wantErr: nil}, { - stored: &ChainConfig{EIP150Block: big.NewInt(10)}, - new: &ChainConfig{EIP150Block: big.NewInt(20)}, - head: 9, - wantErr: nil, + stored: &ChainConfig{EIP150Block: big.NewInt(10)}, + new: &ChainConfig{EIP150Block: big.NewInt(20)}, + headBlock: 9, + wantErr: nil, }, { - stored: AllEthashProtocolChanges, - new: &ChainConfig{HomesteadBlock: nil}, - head: 3, + stored: AllEthashProtocolChanges, + new: &ChainConfig{HomesteadBlock: nil}, + headBlock: 3, wantErr: &ConfigCompatError{ - What: "Homestead fork block", - StoredConfig: big.NewInt(0), - NewConfig: nil, - RewindTo: 0, + What: "Homestead fork block", + StoredBlock: big.NewInt(0), + NewBlock: nil, + RewindToBlock: 0, }, }, { - stored: AllEthashProtocolChanges, - new: &ChainConfig{HomesteadBlock: big.NewInt(1)}, - head: 3, + stored: AllEthashProtocolChanges, + new: &ChainConfig{HomesteadBlock: big.NewInt(1)}, + headBlock: 3, wantErr: &ConfigCompatError{ - What: "Homestead fork block", - StoredConfig: big.NewInt(0), - NewConfig: big.NewInt(1), - RewindTo: 0, + What: "Homestead fork block", + StoredBlock: big.NewInt(0), + NewBlock: big.NewInt(1), + RewindToBlock: 0, }, }, { - stored: &ChainConfig{HomesteadBlock: big.NewInt(30), EIP150Block: big.NewInt(10)}, - new: &ChainConfig{HomesteadBlock: big.NewInt(25), EIP150Block: big.NewInt(20)}, - head: 25, + stored: &ChainConfig{HomesteadBlock: big.NewInt(30), EIP150Block: big.NewInt(10)}, + new: &ChainConfig{HomesteadBlock: big.NewInt(25), EIP150Block: big.NewInt(20)}, + headBlock: 25, wantErr: &ConfigCompatError{ - What: "EIP150 fork block", - StoredConfig: big.NewInt(10), - NewConfig: big.NewInt(20), - RewindTo: 9, + What: "EIP150 fork block", + StoredBlock: big.NewInt(10), + NewBlock: big.NewInt(20), + RewindToBlock: 9, }, }, { - stored: &ChainConfig{ConstantinopleBlock: big.NewInt(30)}, - new: &ChainConfig{ConstantinopleBlock: big.NewInt(30), PetersburgBlock: big.NewInt(30)}, - head: 40, - wantErr: nil, + stored: &ChainConfig{ConstantinopleBlock: big.NewInt(30)}, + new: &ChainConfig{ConstantinopleBlock: big.NewInt(30), PetersburgBlock: big.NewInt(30)}, + headBlock: 40, + wantErr: nil, }, { - stored: &ChainConfig{ConstantinopleBlock: big.NewInt(30)}, - new: &ChainConfig{ConstantinopleBlock: big.NewInt(30), PetersburgBlock: big.NewInt(31)}, - head: 40, + stored: &ChainConfig{ConstantinopleBlock: big.NewInt(30)}, + new: &ChainConfig{ConstantinopleBlock: big.NewInt(30), PetersburgBlock: big.NewInt(31)}, + headBlock: 40, wantErr: &ConfigCompatError{ - What: "Petersburg fork block", - StoredConfig: nil, - NewConfig: big.NewInt(31), - RewindTo: 30, + What: "Petersburg fork block", + StoredBlock: nil, + NewBlock: big.NewInt(31), + RewindToBlock: 30, + }, + }, + { + stored: &ChainConfig{ShanghaiTime: big.NewInt(10)}, + new: &ChainConfig{ShanghaiTime: big.NewInt(20)}, + headTimestamp: 9, + wantErr: nil, + }, + { + stored: &ChainConfig{ShanghaiTime: big.NewInt(10)}, + new: &ChainConfig{ShanghaiTime: big.NewInt(20)}, + headTimestamp: 25, + wantErr: &ConfigCompatError{ + What: "Shanghai fork timestamp", + StoredTime: big.NewInt(10), + NewTime: big.NewInt(20), + RewindToTime: 9, }, }, } for _, test := range tests { - err := test.stored.CheckCompatible(test.new, test.head) + err := test.stored.CheckCompatible(test.new, test.headBlock, test.headTimestamp) if !reflect.DeepEqual(err, test.wantErr) { - t.Errorf("error mismatch:\nstored: %v\nnew: %v\nhead: %v\nerr: %v\nwant: %v", test.stored, test.new, test.head, err, test.wantErr) + t.Errorf("error mismatch:\nstored: %v\nnew: %v\nheadBlock: %v\nheadTimestamp: %v\nerr: %v\nwant: %v", test.stored, test.new, test.headBlock, test.headTimestamp, err, test.wantErr) } } } From d0211578206f462c44b13c4ca6e38438774c081c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 16 Dec 2022 14:06:22 +0200 Subject: [PATCH 442/715] core, les, light: implement timestamp based sethead and genesis rewinds --- core/blockchain.go | 52 +++++++++++++++++++++++++++++++++------------ core/headerchain.go | 30 ++++++++++++++++++++------ les/client.go | 2 +- light/lightchain.go | 11 ++++++++++ 4 files changed, 74 insertions(+), 21 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 62f435060eb0..ebb985e9b28d 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -318,7 +318,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis if diskRoot != (common.Hash{}) { log.Warn("Head state missing, repairing", "number", head.Number(), "hash", head.Hash(), "snaproot", diskRoot) - snapDisk, err := bc.setHeadBeyondRoot(head.NumberU64(), diskRoot, true) + snapDisk, err := bc.setHeadBeyondRoot(head.NumberU64(), 0, diskRoot, true) if err != nil { return nil, err } @@ -328,7 +328,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } } else { log.Warn("Head state missing, repairing", "number", head.Number(), "hash", head.Hash()) - if _, err := bc.setHeadBeyondRoot(head.NumberU64(), common.Hash{}, true); err != nil { + if _, err := bc.setHeadBeyondRoot(head.NumberU64(), 0, common.Hash{}, true); err != nil { return nil, err } } @@ -428,7 +428,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis if compat, ok := genesisErr.(*params.ConfigCompatError); ok { log.Warn("Rewinding chain to upgrade configuration", "err", compat) if compat.RewindToTime > 0 { - log.Crit("Timestamp based rewinds not implemented yet /sad") + bc.SetHeadWithTimestamp(compat.RewindToTime) } else { bc.SetHead(compat.RewindToBlock) } @@ -536,7 +536,20 @@ func (bc *BlockChain) loadLastState() error { // was fast synced or full synced and in which state, the method will try to // delete minimal data from disk whilst retaining chain consistency. func (bc *BlockChain) SetHead(head uint64) error { - if _, err := bc.setHeadBeyondRoot(head, common.Hash{}, false); err != nil { + if _, err := bc.setHeadBeyondRoot(head, 0, common.Hash{}, false); err != nil { + return err + } + // Send chain head event to update the transaction pool + bc.chainHeadFeed.Send(ChainHeadEvent{Block: bc.CurrentBlock()}) + return nil +} + +// SetHeadWithTimestamp rewinds the local chain to a new head that has at max +// the given timestamp. Depending on whether the node was fast synced or full +// synced and in which state, the method will try to delete minimal data from +// disk whilst retaining chain consistency. +func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error { + if _, err := bc.setHeadBeyondRoot(0, timestamp, common.Hash{}, false); err != nil { return err } // Send chain head event to update the transaction pool @@ -573,8 +586,12 @@ func (bc *BlockChain) SetSafe(block *types.Block) { // in which state, the method will try to delete minimal data from disk whilst // retaining chain consistency. // +// The method also works in timestamp mode if `head == 0` but `time != 0`. In that +// case blocks are rolled back until the new head becomes older or equal to the +// requested time. If both `head` and `time` is 0, the chain is rewound to genesis. +// // The method returns the block number where the requested root cap was found. -func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bool) (uint64, error) { +func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Hash, repair bool) (uint64, error) { if !bc.chainmu.TryLock() { return 0, errChainStopped } @@ -588,7 +605,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo pivot := rawdb.ReadLastPivotNumber(bc.db) frozen, _ := bc.db.Ancients() - updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (uint64, bool) { + updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (*types.Header, bool) { // Rewind the blockchain, ensuring we don't end up with a stateless head // block. Note, depth equality is permitted to allow using SetHead as a // chain reparation mechanism without deleting any data! @@ -669,16 +686,18 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo bc.currentFastBlock.Store(newHeadFastBlock) headFastBlockGauge.Update(int64(newHeadFastBlock.NumberU64())) } - head := bc.CurrentBlock().NumberU64() - + var ( + headHeader = bc.CurrentBlock().Header() + headNumber = headHeader.Number.Uint64() + ) // If setHead underflown the freezer threshold and the block processing // intent afterwards is full block importing, delete the chain segment // between the stateful-block and the sethead target. var wipe bool - if head+1 < frozen { - wipe = pivot == nil || head >= *pivot + if headNumber+1 < frozen { + wipe = pivot == nil || headNumber >= *pivot } - return head, wipe // Only force wipe if full synced + return headHeader, wipe // Only force wipe if full synced } // Rewind the header chain, deleting all block bodies until then delFn := func(db ethdb.KeyValueWriter, hash common.Hash, num uint64) { @@ -705,13 +724,18 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo // touching the header chain altogether, unless the freezer is broken if repair { if target, force := updateFn(bc.db, bc.CurrentBlock().Header()); force { - bc.hc.SetHead(target, updateFn, delFn) + bc.hc.SetHead(target.Number.Uint64(), updateFn, delFn) } } else { // Rewind the chain to the requested head and keep going backwards until a // block with a state is found or fast sync pivot is passed - log.Warn("Rewinding blockchain", "target", head) - bc.hc.SetHead(head, updateFn, delFn) + if time > 0 { + log.Warn("Rewinding blockchain to timestamp", "target", time) + bc.hc.SetHeadWithTimestamp(time, updateFn, delFn) + } else { + log.Warn("Rewinding blockchain to block", "target", head) + bc.hc.SetHead(head, updateFn, delFn) + } } // Clear out any stale content from the caches bc.bodyCache.Purge() diff --git a/core/headerchain.go b/core/headerchain.go index 482b5f6fbe91..ba8f550a8c86 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -556,7 +556,7 @@ type ( // before head header is updated. The method will return the actual block it // updated the head to (missing state) and a flag if setHead should continue // rewinding till that forcefully (exceeded ancient limits) - UpdateHeadBlocksCallback func(ethdb.KeyValueWriter, *types.Header) (uint64, bool) + UpdateHeadBlocksCallback func(ethdb.KeyValueWriter, *types.Header) (*types.Header, bool) // DeleteBlockContentCallback is a callback function that is called by SetHead // before each header is deleted. @@ -566,15 +566,33 @@ type ( // SetHead rewinds the local chain to a new head. Everything above the new head // will be deleted and the new one set. func (hc *HeaderChain) SetHead(head uint64, updateFn UpdateHeadBlocksCallback, delFn DeleteBlockContentCallback) { + hc.setHead(head, 0, updateFn, delFn) +} + +// SetHeadWithTimestamp rewinds the local chain to a new head timestamp. Everything +// above the new head will be deleted and the new one set. +func (hc *HeaderChain) SetHeadWithTimestamp(time uint64, updateFn UpdateHeadBlocksCallback, delFn DeleteBlockContentCallback) { + hc.setHead(0, time, updateFn, delFn) +} + +// setHead rewinds the local chain to a new head block or a head timestamp. +// Everything above the new head will be deleted and the new one set. +func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn UpdateHeadBlocksCallback, delFn DeleteBlockContentCallback) { var ( parentHash common.Hash batch = hc.chainDb.NewBatch() origin = true ) - for hdr := hc.CurrentHeader(); hdr != nil && hdr.Number.Uint64() > head; hdr = hc.CurrentHeader() { + done := func(header *types.Header) bool { + if headBlock != 0 || headTime == 0 { + return header.Number.Uint64() <= headBlock + } + return header.Time <= headTime + } + for hdr := hc.CurrentHeader(); hdr != nil && !done(hdr); hdr = hc.CurrentHeader() { num := hdr.Number.Uint64() - // Rewind block chain to new head. + // Rewind chain to new head parent := hc.GetHeader(hdr.ParentHash, num-1) if parent == nil { parent = hc.genesisHeader @@ -591,9 +609,9 @@ func (hc *HeaderChain) SetHead(head uint64, updateFn UpdateHeadBlocksCallback, d markerBatch := hc.chainDb.NewBatch() if updateFn != nil { newHead, force := updateFn(markerBatch, parent) - if force && newHead < head { - log.Warn("Force rewinding till ancient limit", "head", newHead) - head = newHead + if force && ((headTime > 0 && newHead.Time < headTime) || (headTime == 0 && newHead.Number.Uint64() < headBlock)) { + log.Warn("Force rewinding till ancient limit", "head", newHead.Number.Uint64()) + headBlock, headTime = newHead.Number.Uint64(), 0 } } // Update head header then. diff --git a/les/client.go b/les/client.go index 9f5822e082c4..3c222f819196 100644 --- a/les/client.go +++ b/les/client.go @@ -180,7 +180,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { if compat, ok := genesisErr.(*params.ConfigCompatError); ok { log.Warn("Rewinding chain to upgrade configuration", "err", compat) if compat.RewindToTime > 0 { - log.Crit("Timestamp based rewinds not implemented yet /sad") + leth.blockchain.SetHeadWithTimestamp(compat.RewindToTime) } else { leth.blockchain.SetHead(compat.RewindToBlock) } diff --git a/light/lightchain.go b/light/lightchain.go index 155f7b0c0548..f42c904f57eb 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -178,6 +178,17 @@ func (lc *LightChain) SetHead(head uint64) error { return lc.loadLastState() } +// SetHeadWithTimestamp rewinds the local chain to a new head that has at max +// the given timestamp. Everything above the new head will be deleted and the +// new one set. +func (lc *LightChain) SetHeadWithTimestamp(timestamp uint64) error { + lc.chainmu.Lock() + defer lc.chainmu.Unlock() + + lc.hc.SetHeadWithTimestamp(timestamp, nil, nil) + return lc.loadLastState() +} + // GasLimit returns the gas limit of the current HEAD block. func (lc *LightChain) GasLimit() uint64 { return lc.hc.CurrentHeader().GasLimit From 9e6a1c3834e26049a05e9b96ae91278bfdad7281 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 3 Jan 2023 12:10:48 +0100 Subject: [PATCH 443/715] common/mclock: add Alarm (#26333) Alarm is a timer utility that simplifies code where a timer needs to be rescheduled over and over. Doing this can be tricky with time.Timer or time.AfterFunc because the channel requires draining in some cases. Alarm is optimized for use cases where items are tracked in a heap according to their expiry time, and a goroutine with a for/select loop wants to be woken up whenever the next item expires. In this application, the timer needs to be rescheduled when an item is added or removed from the heap. Using a timer naively, these updates will always require synchronization with the global runtime timer datastructure to update the timer using Reset. Alarm avoids this by tracking the next expiry time and only modifies the timer if it would need to fire earlier than already scheduled. As an example use, I have converted p2p.dialScheduler to use Alarm instead of AfterFunc. --- common/mclock/alarm.go | 106 ++++++++++++++++++++++++++++++++ common/mclock/alarm_test.go | 116 ++++++++++++++++++++++++++++++++++++ p2p/dial.go | 57 +++++++----------- 3 files changed, 244 insertions(+), 35 deletions(-) create mode 100644 common/mclock/alarm.go create mode 100644 common/mclock/alarm_test.go diff --git a/common/mclock/alarm.go b/common/mclock/alarm.go new file mode 100644 index 000000000000..e83810a6a07f --- /dev/null +++ b/common/mclock/alarm.go @@ -0,0 +1,106 @@ +// Copyright 2022 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 mclock + +import ( + "time" +) + +// Alarm sends timed notifications on a channel. This is very similar to a regular timer, +// but is easier to use in code that needs to re-schedule the same timer over and over. +// +// When scheduling an Alarm, the channel returned by C() will receive a value no later +// than the scheduled time. An Alarm can be reused after it has fired and can also be +// canceled by calling Stop. +type Alarm struct { + ch chan struct{} + clock Clock + timer Timer + deadline AbsTime +} + +// NewAlarm creates an Alarm. +func NewAlarm(clock Clock) *Alarm { + if clock == nil { + panic("nil clock") + } + return &Alarm{ + ch: make(chan struct{}, 1), + clock: clock, + } +} + +// C returns the alarm notification channel. This channel remains identical for +// the entire lifetime of the alarm, and is never closed. +func (e *Alarm) C() <-chan struct{} { + return e.ch +} + +// Stop cancels the alarm and drains the channel. +// This method is not safe for concurrent use. +func (e *Alarm) Stop() { + // Clear timer. + if e.timer != nil { + e.timer.Stop() + } + e.deadline = 0 + + // Drain the channel. + select { + case <-e.ch: + default: + } +} + +// Schedule sets the alarm to fire no later than the given time. If the alarm was already +// scheduled but has not fired yet, it may fire earlier than the newly-scheduled time. +func (e *Alarm) Schedule(time AbsTime) { + now := e.clock.Now() + e.schedule(now, time) +} + +func (e *Alarm) schedule(now, newDeadline AbsTime) { + if e.timer != nil { + if e.deadline > now && e.deadline <= newDeadline { + // Here, the current timer can be reused because it is already scheduled to + // occur earlier than the new deadline. + // + // The e.deadline > now part of the condition is important. If the old + // deadline lies in the past, we assume the timer has already fired and needs + // to be rescheduled. + return + } + e.timer.Stop() + } + + // Set the timer. + d := time.Duration(0) + if newDeadline < now { + newDeadline = now + } else { + d = newDeadline.Sub(now) + } + e.timer = e.clock.AfterFunc(d, e.send) + e.deadline = newDeadline +} + +func (e *Alarm) send() { + select { + case e.ch <- struct{}{}: + default: + } +} diff --git a/common/mclock/alarm_test.go b/common/mclock/alarm_test.go new file mode 100644 index 000000000000..d2ad9913fd28 --- /dev/null +++ b/common/mclock/alarm_test.go @@ -0,0 +1,116 @@ +// Copyright 2022 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 mclock + +import "testing" + +// This test checks basic functionality of Alarm. +func TestAlarm(t *testing.T) { + clk := new(Simulated) + clk.Run(20) + a := NewAlarm(clk) + + a.Schedule(clk.Now() + 10) + if recv(a.C()) { + t.Fatal("Alarm fired before scheduled deadline") + } + if ntimers := clk.ActiveTimers(); ntimers != 1 { + t.Fatal("clock has", ntimers, "active timers, want", 1) + } + clk.Run(5) + if recv(a.C()) { + t.Fatal("Alarm fired too early") + } + + clk.Run(5) + if !recv(a.C()) { + t.Fatal("Alarm did not fire") + } + if recv(a.C()) { + t.Fatal("Alarm fired twice") + } + if ntimers := clk.ActiveTimers(); ntimers != 0 { + t.Fatal("clock has", ntimers, "active timers, want", 0) + } + + a.Schedule(clk.Now() + 5) + if recv(a.C()) { + t.Fatal("Alarm fired before scheduled deadline when scheduling the second event") + } + + clk.Run(5) + if !recv(a.C()) { + t.Fatal("Alarm did not fire when scheduling the second event") + } + if recv(a.C()) { + t.Fatal("Alarm fired twice when scheduling the second event") + } +} + +// This test checks that scheduling an Alarm to an earlier time than the +// one already scheduled works properly. +func TestAlarmScheduleEarlier(t *testing.T) { + clk := new(Simulated) + clk.Run(20) + a := NewAlarm(clk) + + a.Schedule(clk.Now() + 50) + clk.Run(5) + a.Schedule(clk.Now() + 1) + clk.Run(3) + if !recv(a.C()) { + t.Fatal("Alarm did not fire") + } +} + +// This test checks that scheduling an Alarm to a later time than the +// one already scheduled works properly. +func TestAlarmScheduleLater(t *testing.T) { + clk := new(Simulated) + clk.Run(20) + a := NewAlarm(clk) + + a.Schedule(clk.Now() + 50) + clk.Run(5) + a.Schedule(clk.Now() + 100) + clk.Run(50) + if !recv(a.C()) { + t.Fatal("Alarm did not fire") + } +} + +// This test checks that scheduling an Alarm in the past makes it fire immediately. +func TestAlarmNegative(t *testing.T) { + clk := new(Simulated) + clk.Run(50) + a := NewAlarm(clk) + + a.Schedule(-1) + clk.Run(1) // needed to process timers + if !recv(a.C()) { + t.Fatal("Alarm did not fire for negative time") + } +} + +func recv(ch <-chan struct{}) bool { + select { + case <-ch: + return true + default: + return false + } +} diff --git a/p2p/dial.go b/p2p/dial.go index 02878fae4d31..134e6e2eae1a 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -117,9 +117,8 @@ type dialScheduler struct { staticPool []*dialTask // The dial history keeps recently dialed nodes. Members of history are not dialed. - history expHeap - historyTimer mclock.Timer - historyTimerTime mclock.AbsTime + history expHeap + historyTimer *mclock.Alarm // for logStats lastStatsLog mclock.AbsTime @@ -160,18 +159,20 @@ func (cfg dialConfig) withDefaults() dialConfig { } func newDialScheduler(config dialConfig, it enode.Iterator, setupFunc dialSetupFunc) *dialScheduler { + cfg := config.withDefaults() d := &dialScheduler{ - dialConfig: config.withDefaults(), - setupFunc: setupFunc, - dialing: make(map[enode.ID]*dialTask), - static: make(map[enode.ID]*dialTask), - peers: make(map[enode.ID]struct{}), - doneCh: make(chan *dialTask), - nodesIn: make(chan *enode.Node), - addStaticCh: make(chan *enode.Node), - remStaticCh: make(chan *enode.Node), - addPeerCh: make(chan *conn), - remPeerCh: make(chan *conn), + dialConfig: cfg, + historyTimer: mclock.NewAlarm(cfg.clock), + setupFunc: setupFunc, + dialing: make(map[enode.ID]*dialTask), + static: make(map[enode.ID]*dialTask), + peers: make(map[enode.ID]struct{}), + doneCh: make(chan *dialTask), + nodesIn: make(chan *enode.Node), + addStaticCh: make(chan *enode.Node), + remStaticCh: make(chan *enode.Node), + addPeerCh: make(chan *conn), + remPeerCh: make(chan *conn), } d.lastStatsLog = d.clock.Now() d.ctx, d.cancel = context.WithCancel(context.Background()) @@ -222,8 +223,7 @@ func (d *dialScheduler) peerRemoved(c *conn) { // loop is the main loop of the dialer. func (d *dialScheduler) loop(it enode.Iterator) { var ( - nodesCh chan *enode.Node - historyExp = make(chan struct{}, 1) + nodesCh chan *enode.Node ) loop: @@ -236,7 +236,7 @@ loop: } else { nodesCh = nil } - d.rearmHistoryTimer(historyExp) + d.rearmHistoryTimer() d.logStats() select { @@ -297,7 +297,7 @@ loop: } } - case <-historyExp: + case <-d.historyTimer.C(): d.expireHistory() case <-d.ctx.Done(): @@ -306,7 +306,7 @@ loop: } } - d.stopHistoryTimer(historyExp) + d.historyTimer.Stop() for range d.dialing { <-d.doneCh } @@ -343,28 +343,15 @@ func (d *dialScheduler) logStats() { // rearmHistoryTimer configures d.historyTimer to fire when the // next item in d.history expires. -func (d *dialScheduler) rearmHistoryTimer(ch chan struct{}) { - if len(d.history) == 0 || d.historyTimerTime == d.history.nextExpiry() { +func (d *dialScheduler) rearmHistoryTimer() { + if len(d.history) == 0 { return } - d.stopHistoryTimer(ch) - d.historyTimerTime = d.history.nextExpiry() - timeout := time.Duration(d.historyTimerTime - d.clock.Now()) - d.historyTimer = d.clock.AfterFunc(timeout, func() { ch <- struct{}{} }) -} - -// stopHistoryTimer stops the timer and drains the channel it sends on. -func (d *dialScheduler) stopHistoryTimer(ch chan struct{}) { - if d.historyTimer != nil && !d.historyTimer.Stop() { - <-ch - } + d.historyTimer.Schedule(d.history.nextExpiry()) } // expireHistory removes expired items from d.history. func (d *dialScheduler) expireHistory() { - d.historyTimer.Stop() - d.historyTimer = nil - d.historyTimerTime = 0 d.history.expire(d.clock.Now(), func(hkey string) { var id enode.ID copy(id[:], hkey) From a251bca67ce2355f5262d116f882617317033dd6 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 3 Jan 2023 12:36:38 +0100 Subject: [PATCH 444/715] p2p/discover: add more packet information in logs (#26307) * p2p/discover: add more packet information in logs This adds more fields to discv5 packet logs. These can be useful when debugging multi-packet interactions. The FINDNODE message also gets an additional field, OpID for debugging purposes. This field is not encoded onto the wire. I'm also removing topic system related message types in this change. These will come back in the future, where support for them will be guarded by a config flag. * p2p/discover/v5wire: rename 'Total' to 'RespCount' The new name captures the meaning of this field better. --- cmd/devp2p/internal/v5test/discv5tests.go | 2 +- cmd/devp2p/internal/v5test/framework.go | 12 +- p2p/discover/v5_udp.go | 27 +++-- p2p/discover/v5_udp_test.go | 28 ++--- p2p/discover/v5wire/encoding_test.go | 8 +- p2p/discover/v5wire/msg.go | 140 ++++++++++------------ 6 files changed, 105 insertions(+), 112 deletions(-) diff --git a/cmd/devp2p/internal/v5test/discv5tests.go b/cmd/devp2p/internal/v5test/discv5tests.go index a7cd352763fe..56624a0ca8e9 100644 --- a/cmd/devp2p/internal/v5test/discv5tests.go +++ b/cmd/devp2p/internal/v5test/discv5tests.go @@ -355,7 +355,7 @@ func (bn *bystander) loop() { wasAdded = true bn.notifyAdded() case *v5wire.Findnode: - bn.conn.write(bn.l, &v5wire.Nodes{ReqID: p.ReqID, Total: 1}, nil) + bn.conn.write(bn.l, &v5wire.Nodes{ReqID: p.ReqID, RespCount: 1}, nil) wasAdded = true bn.notifyAdded() case *v5wire.TalkRequest: diff --git a/cmd/devp2p/internal/v5test/framework.go b/cmd/devp2p/internal/v5test/framework.go index f31677e519e7..10856a50bcf9 100644 --- a/cmd/devp2p/internal/v5test/framework.go +++ b/cmd/devp2p/internal/v5test/framework.go @@ -44,6 +44,8 @@ func (p *readError) Unwrap() error { return p.err } func (p *readError) RequestID() []byte { return nil } func (p *readError) SetRequestID([]byte) {} +func (p *readError) AppendLogInfo(ctx []interface{}) []interface{} { return ctx } + // readErrorf creates a readError with the given text. func readErrorf(format string, args ...interface{}) *readError { return &readError{fmt.Errorf(format, args...)} @@ -171,16 +173,16 @@ func (tc *conn) findnode(c net.PacketConn, dists []uint) ([]*enode.Node, error) // Check total count. It should be greater than one // and needs to be the same across all responses. if first { - if resp.Total == 0 || resp.Total > 6 { - return nil, fmt.Errorf("invalid NODES response 'total' %d (not in (0,7))", resp.Total) + if resp.RespCount == 0 || resp.RespCount > 6 { + return nil, fmt.Errorf("invalid NODES response count %d (not in (0,7))", resp.RespCount) } - total = resp.Total + total = resp.RespCount n = int(total) - 1 first = false } else { n-- - if resp.Total != total { - return nil, fmt.Errorf("invalid NODES response 'total' %d (!= %d)", resp.Total, total) + if resp.RespCount != total { + return nil, fmt.Errorf("invalid NODES response count %d (!= %d)", resp.RespCount, total) } } // Check nodes. diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 57d624498ea1..53a1c6f7670a 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -70,6 +70,9 @@ type UDPv5 struct { clock mclock.Clock validSchemes enr.IdentityScheme + // misc buffers used during message handling + logcontext []interface{} + // talkreq handler registry trlock sync.Mutex trhandlers map[string]TalkRequestHandler @@ -158,6 +161,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { activeCallByNode: make(map[enode.ID]*callV5), activeCallByAuth: make(map[v5wire.Nonce]*callV5), callQueue: make(map[enode.ID][]*callV5), + // shutdown closeCtx: closeCtx, cancelCloseCtx: cancelCloseCtx, @@ -385,7 +389,7 @@ func (t *UDPv5) waitForNodes(c *callV5, distances []uint) ([]*enode.Node, error) nodes = append(nodes, node) } if total == -1 { - total = min(int(response.Total), totalNodesResponseLimit) + total = min(int(response.RespCount), totalNodesResponseLimit) } if received++; received == total { return nodes, nil @@ -601,13 +605,18 @@ func (t *UDPv5) sendResponse(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.P // send sends a packet to the given node. func (t *UDPv5) send(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet, c *v5wire.Whoareyou) (v5wire.Nonce, error) { addr := toAddr.String() + t.logcontext = append(t.logcontext[:0], "id", toID, "addr", addr) + t.logcontext = packet.AppendLogInfo(t.logcontext) + enc, nonce, err := t.codec.Encode(toID, addr, packet, c) if err != nil { - t.log.Warn(">> "+packet.Name(), "id", toID, "addr", addr, "err", err) + t.logcontext = append(t.logcontext, "err", err) + t.log.Warn(">> "+packet.Name(), t.logcontext...) return nonce, err } + _, err = t.conn.WriteToUDP(enc, toAddr) - t.log.Trace(">> "+packet.Name(), "id", toID, "addr", addr) + t.log.Trace(">> "+packet.Name(), t.logcontext...) return nonce, err } @@ -657,7 +666,9 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { } if packet.Kind() != v5wire.WhoareyouPacket { // WHOAREYOU logged separately to report errors. - t.log.Trace("<< "+packet.Name(), "id", fromID, "addr", addr) + t.logcontext = append(t.logcontext[:0], "id", fromID, "addr", addr) + t.logcontext = packet.AppendLogInfo(t.logcontext) + t.log.Trace("<< "+packet.Name(), t.logcontext...) } t.handle(packet, fromID, fromAddr) return nil @@ -712,7 +723,7 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) case *v5wire.Nodes: t.handleCallResponse(fromID, fromAddr, p) case *v5wire.TalkRequest: - t.handleTalkRequest(p, fromID, fromAddr) + t.handleTalkRequest(fromID, fromAddr, p) case *v5wire.TalkResponse: t.handleCallResponse(fromID, fromAddr, p) } @@ -827,7 +838,7 @@ func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*en // packNodes creates NODES response packets for the given node list. func packNodes(reqid []byte, nodes []*enode.Node) []*v5wire.Nodes { if len(nodes) == 0 { - return []*v5wire.Nodes{{ReqID: reqid, Total: 1}} + return []*v5wire.Nodes{{ReqID: reqid, RespCount: 1}} } // This limit represents the available space for nodes in output packets. Maximum @@ -851,13 +862,13 @@ func packNodes(reqid []byte, nodes []*enode.Node) []*v5wire.Nodes { resp = append(resp, p) } for _, msg := range resp { - msg.Total = uint8(len(resp)) + msg.RespCount = uint8(len(resp)) } return resp } // handleTalkRequest runs the talk request handler of the requested protocol. -func (t *UDPv5) handleTalkRequest(p *v5wire.TalkRequest, fromID enode.ID, fromAddr *net.UDPAddr) { +func (t *UDPv5) handleTalkRequest(fromID enode.ID, fromAddr *net.UDPAddr, p *v5wire.TalkRequest) { t.trlock.Lock() handler := t.trhandlers[p.Protocol] t.trlock.Unlock() diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index ab0cb9a8211c..481bb1cdc389 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -208,8 +208,8 @@ func (test *udpV5Test) expectNodes(wantReqID []byte, wantTotal uint8, wantNodes if !bytes.Equal(p.ReqID, wantReqID) { test.t.Fatalf("wrong request ID %v in response, want %v", p.ReqID, wantReqID) } - if p.Total != wantTotal { - test.t.Fatalf("wrong total response count %d, want %d", p.Total, wantTotal) + if p.RespCount != wantTotal { + test.t.Fatalf("wrong total response count %d, want %d", p.RespCount, wantTotal) } for _, record := range p.Nodes { n, _ := enode.New(enode.ValidSchemesForTesting, record) @@ -301,14 +301,14 @@ func TestUDPv5_findnodeCall(t *testing.T) { t.Fatalf("wrong distances in request: %v", p.Distances) } test.packetIn(&v5wire.Nodes{ - ReqID: p.ReqID, - Total: 2, - Nodes: nodesToRecords(nodes[:4]), + ReqID: p.ReqID, + RespCount: 2, + Nodes: nodesToRecords(nodes[:4]), }) test.packetIn(&v5wire.Nodes{ - ReqID: p.ReqID, - Total: 2, - Nodes: nodesToRecords(nodes[4:]), + ReqID: p.ReqID, + RespCount: 2, + Nodes: nodesToRecords(nodes[4:]), }) }) @@ -409,16 +409,16 @@ func TestUDPv5_callTimeoutReset(t *testing.T) { test.waitPacketOut(func(p *v5wire.Findnode, addr *net.UDPAddr, _ v5wire.Nonce) { time.Sleep(respTimeout - 50*time.Millisecond) test.packetIn(&v5wire.Nodes{ - ReqID: p.ReqID, - Total: 2, - Nodes: nodesToRecords(nodes[:4]), + ReqID: p.ReqID, + RespCount: 2, + Nodes: nodesToRecords(nodes[:4]), }) time.Sleep(respTimeout - 50*time.Millisecond) test.packetIn(&v5wire.Nodes{ - ReqID: p.ReqID, - Total: 2, - Nodes: nodesToRecords(nodes[4:]), + ReqID: p.ReqID, + RespCount: 2, + Nodes: nodesToRecords(nodes[4:]), }) }) if err := <-done; err != nil { diff --git a/p2p/discover/v5wire/encoding_test.go b/p2p/discover/v5wire/encoding_test.go index 25df732835dd..a5387311a5d0 100644 --- a/p2p/discover/v5wire/encoding_test.go +++ b/p2p/discover/v5wire/encoding_test.go @@ -92,7 +92,7 @@ func TestHandshake(t *testing.T) { } // A <- B NODES - nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{Total: 1}) + nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{RespCount: 1}) net.nodeA.expectDecode(t, NodesMsg, nodes) } @@ -150,7 +150,7 @@ func TestHandshake_norecord(t *testing.T) { net.nodeB.expectDecode(t, FindnodeMsg, findnode) // A <- B NODES - nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{Total: 1}) + nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{RespCount: 1}) net.nodeA.expectDecode(t, NodesMsg, nodes) } @@ -190,7 +190,7 @@ func TestHandshake_rekey(t *testing.T) { net.nodeB.expectDecode(t, FindnodeMsg, findnode) // A <- B NODES - nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{Total: 1}) + nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{RespCount: 1}) net.nodeA.expectDecode(t, NodesMsg, nodes) } @@ -225,7 +225,7 @@ func TestHandshake_rekey2(t *testing.T) { net.nodeB.expectDecode(t, FindnodeMsg, findnode) // A <- B NODES - nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{Total: 1}) + nodes, _ := net.nodeB.encode(t, net.nodeA, &Nodes{RespCount: 1}) net.nodeA.expectDecode(t, NodesMsg, nodes) } diff --git a/p2p/discover/v5wire/msg.go b/p2p/discover/v5wire/msg.go index 1316598a4722..fb8e1e12c294 100644 --- a/p2p/discover/v5wire/msg.go +++ b/p2p/discover/v5wire/msg.go @@ -20,6 +20,7 @@ import ( "fmt" "net" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" @@ -32,6 +33,10 @@ type Packet interface { Kind() byte // Kind returns the message type. RequestID() []byte // Returns the request ID. SetRequestID([]byte) // Sets the request ID. + + // AppendLogInfo returns its argument 'ctx' with additional fields + // appended for logging purposes. + AppendLogInfo(ctx []interface{}) []interface{} } // Message types. @@ -44,9 +49,6 @@ const ( TalkResponseMsg RequestTicketMsg TicketMsg - RegtopicMsg - RegconfirmationMsg - TopicQueryMsg UnknownPacket = byte(255) // any non-decryptable packet WhoareyouPacket = byte(254) // the WHOAREYOU packet @@ -59,7 +61,7 @@ type ( Nonce Nonce } - // Whoareyou contains the handshake challenge. + // WHOAREYOU contains the handshake challenge. Whoareyou struct { ChallengeData []byte // Encoded challenge Nonce Nonce // Nonce of request packet @@ -73,13 +75,13 @@ type ( sent mclock.AbsTime // for handshake GC. } - // Ping is sent during liveness checks. + // PING is sent during liveness checks. Ping struct { ReqID []byte ENRSeq uint64 } - // Pong is the reply to Ping. + // PONG is the reply to PING. Pong struct { ReqID []byte ENRSeq uint64 @@ -87,62 +89,35 @@ type ( ToPort uint16 // packet, which provides a way to discover the external address (after NAT). } - // Findnode is a query for nodes in the given bucket. + // FINDNODE is a query for nodes in the given bucket. Findnode struct { ReqID []byte Distances []uint + + // OpID is for debugging purposes and is not part of the packet encoding. + // It identifies the 'operation' on behalf of which the request was sent. + OpID uint64 `rlp:"-"` } - // Nodes is the reply to Findnode and Topicquery. + // NODES is a response to FINDNODE. Nodes struct { - ReqID []byte - Total uint8 - Nodes []*enr.Record + ReqID []byte + RespCount uint8 // total number of responses to the request + Nodes []*enr.Record } - // TalkRequest is an application-level request. + // TALKREQ is an application-level request. TalkRequest struct { ReqID []byte Protocol string Message []byte } - // TalkResponse is the reply to TalkRequest. + // TALKRESP is the reply to TALKREQ. TalkResponse struct { ReqID []byte Message []byte } - - // RequestTicket requests a ticket for a topic queue. - RequestTicket struct { - ReqID []byte - Topic []byte - } - - // Ticket is the response to RequestTicket. - Ticket struct { - ReqID []byte - Ticket []byte - } - - // Regtopic registers the sender in a topic queue using a ticket. - Regtopic struct { - ReqID []byte - Ticket []byte - ENR *enr.Record - } - - // Regconfirmation is the reply to Regtopic. - Regconfirmation struct { - ReqID []byte - Registered bool - } - - // TopicQuery asks for nodes with the given topic. - TopicQuery struct { - ReqID []byte - Topic []byte - } ) // DecodeMessage decodes the message body of a packet. @@ -161,16 +136,6 @@ func DecodeMessage(ptype byte, body []byte) (Packet, error) { dec = new(TalkRequest) case TalkResponseMsg: dec = new(TalkResponse) - case RequestTicketMsg: - dec = new(RequestTicket) - case TicketMsg: - dec = new(Ticket) - case RegtopicMsg: - dec = new(Regtopic) - case RegconfirmationMsg: - dec = new(Regconfirmation) - case TopicQueryMsg: - dec = new(TopicQuery) default: return nil, fmt.Errorf("unknown packet type %d", ptype) } @@ -188,62 +153,77 @@ func (*Whoareyou) Kind() byte { return WhoareyouPacket } func (*Whoareyou) RequestID() []byte { return nil } func (*Whoareyou) SetRequestID([]byte) {} +func (*Whoareyou) AppendLogInfo(ctx []interface{}) []interface{} { + return ctx +} + func (*Unknown) Name() string { return "UNKNOWN/v5" } func (*Unknown) Kind() byte { return UnknownPacket } func (*Unknown) RequestID() []byte { return nil } func (*Unknown) SetRequestID([]byte) {} +func (*Unknown) AppendLogInfo(ctx []interface{}) []interface{} { + return ctx +} + func (*Ping) Name() string { return "PING/v5" } func (*Ping) Kind() byte { return PingMsg } func (p *Ping) RequestID() []byte { return p.ReqID } func (p *Ping) SetRequestID(id []byte) { p.ReqID = id } +func (p *Ping) AppendLogInfo(ctx []interface{}) []interface{} { + return append(ctx, "req", hexutil.Bytes(p.ReqID), "enrseq", p.ENRSeq) +} + func (*Pong) Name() string { return "PONG/v5" } func (*Pong) Kind() byte { return PongMsg } func (p *Pong) RequestID() []byte { return p.ReqID } func (p *Pong) SetRequestID(id []byte) { p.ReqID = id } -func (*Findnode) Name() string { return "FINDNODE/v5" } -func (*Findnode) Kind() byte { return FindnodeMsg } +func (p *Pong) AppendLogInfo(ctx []interface{}) []interface{} { + return append(ctx, "req", hexutil.Bytes(p.ReqID), "enrseq", p.ENRSeq) +} + +func (p *Findnode) Name() string { return "FINDNODE/v5" } +func (p *Findnode) Kind() byte { return FindnodeMsg } func (p *Findnode) RequestID() []byte { return p.ReqID } func (p *Findnode) SetRequestID(id []byte) { p.ReqID = id } +func (p *Findnode) AppendLogInfo(ctx []interface{}) []interface{} { + ctx = append(ctx, "req", hexutil.Bytes(p.ReqID)) + if p.OpID != 0 { + ctx = append(ctx, "opid", p.OpID) + } + return ctx +} + func (*Nodes) Name() string { return "NODES/v5" } func (*Nodes) Kind() byte { return NodesMsg } func (p *Nodes) RequestID() []byte { return p.ReqID } func (p *Nodes) SetRequestID(id []byte) { p.ReqID = id } +func (p *Nodes) AppendLogInfo(ctx []interface{}) []interface{} { + return append(ctx, + "req", hexutil.Bytes(p.ReqID), + "tot", p.RespCount, + "n", len(p.Nodes), + ) +} + func (*TalkRequest) Name() string { return "TALKREQ/v5" } func (*TalkRequest) Kind() byte { return TalkRequestMsg } func (p *TalkRequest) RequestID() []byte { return p.ReqID } func (p *TalkRequest) SetRequestID(id []byte) { p.ReqID = id } +func (p *TalkRequest) AppendLogInfo(ctx []interface{}) []interface{} { + return append(ctx, "proto", p.Protocol, "reqid", hexutil.Bytes(p.ReqID), "len", len(p.Message)) +} + func (*TalkResponse) Name() string { return "TALKRESP/v5" } func (*TalkResponse) Kind() byte { return TalkResponseMsg } func (p *TalkResponse) RequestID() []byte { return p.ReqID } func (p *TalkResponse) SetRequestID(id []byte) { p.ReqID = id } -func (*RequestTicket) Name() string { return "REQTICKET/v5" } -func (*RequestTicket) Kind() byte { return RequestTicketMsg } -func (p *RequestTicket) RequestID() []byte { return p.ReqID } -func (p *RequestTicket) SetRequestID(id []byte) { p.ReqID = id } - -func (*Regtopic) Name() string { return "REGTOPIC/v5" } -func (*Regtopic) Kind() byte { return RegtopicMsg } -func (p *Regtopic) RequestID() []byte { return p.ReqID } -func (p *Regtopic) SetRequestID(id []byte) { p.ReqID = id } - -func (*Ticket) Name() string { return "TICKET/v5" } -func (*Ticket) Kind() byte { return TicketMsg } -func (p *Ticket) RequestID() []byte { return p.ReqID } -func (p *Ticket) SetRequestID(id []byte) { p.ReqID = id } - -func (*Regconfirmation) Name() string { return "REGCONFIRMATION/v5" } -func (*Regconfirmation) Kind() byte { return RegconfirmationMsg } -func (p *Regconfirmation) RequestID() []byte { return p.ReqID } -func (p *Regconfirmation) SetRequestID(id []byte) { p.ReqID = id } - -func (*TopicQuery) Name() string { return "TOPICQUERY/v5" } -func (*TopicQuery) Kind() byte { return TopicQueryMsg } -func (p *TopicQuery) RequestID() []byte { return p.ReqID } -func (p *TopicQuery) SetRequestID(id []byte) { p.ReqID = id } +func (p *TalkResponse) AppendLogInfo(ctx []interface{}) []interface{} { + return append(ctx, "req", p.ReqID, "len", len(p.Message)) +} From 41fe9d646ca25e47e10055d2937df187cfcf3fec Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 3 Jan 2023 12:37:48 +0100 Subject: [PATCH 445/715] cmd/evm: update documentation (#26385) --- cmd/evm/README.md | 167 +++++++++++++++++++++++++++++++++++-- cmd/evm/transition-test.sh | 137 ++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+), 9 deletions(-) diff --git a/cmd/evm/README.md b/cmd/evm/README.md index 6fd0abf65353..8496e7235330 100644 --- a/cmd/evm/README.md +++ b/cmd/evm/README.md @@ -439,11 +439,11 @@ to use the evm to go from `json` input to `rlp` input. The following command takes **json** the transactions in `./testdata/13/txs.json` and signs them. After execution, they are output to `signed_txs.rlp`.: ``` ./evm t8n --state.fork=London --input.alloc=./testdata/13/alloc.json --input.txs=./testdata/13/txs.json --input.env=./testdata/13/env.json --output.result=alloc_jsontx.json --output.body=signed_txs.rlp -INFO [12-07|04:30:12.380] Trie dumping started root=e4b924..6aef61 -INFO [12-07|04:30:12.380] Trie dumping complete accounts=3 elapsed="85.765µs" -INFO [12-07|04:30:12.380] Wrote file file=alloc.json -INFO [12-07|04:30:12.380] Wrote file file=alloc_jsontx.json -INFO [12-07|04:30:12.380] Wrote file file=signed_txs.rlp +INFO [12-27|09:25:11.102] Trie dumping started root=e4b924..6aef61 +INFO [12-27|09:25:11.102] Trie dumping complete accounts=3 elapsed="275.66µs" +INFO [12-27|09:25:11.102] Wrote file file=alloc.json +INFO [12-27|09:25:11.103] Wrote file file=alloc_jsontx.json +INFO [12-27|09:25:11.103] Wrote file file=signed_txs.rlp ``` The `output.body` is the rlp-list of transactions, encoded in hex and placed in a string a'la `json` encoding rules: @@ -463,10 +463,10 @@ rlpdump -hex $(cat signed_txs.rlp | jq -r ) Now, we can now use those (or any other already signed transactions), as input, like so: ``` ./evm t8n --state.fork=London --input.alloc=./testdata/13/alloc.json --input.txs=./signed_txs.rlp --input.env=./testdata/13/env.json --output.result=alloc_rlptx.json -INFO [12-07|04:30:12.425] Trie dumping started root=e4b924..6aef61 -INFO [12-07|04:30:12.425] Trie dumping complete accounts=3 elapsed="70.684µs" -INFO [12-07|04:30:12.425] Wrote file file=alloc.json -INFO [12-07|04:30:12.425] Wrote file file=alloc_rlptx.json +INFO [12-27|09:25:11.187] Trie dumping started root=e4b924..6aef61 +INFO [12-27|09:25:11.187] Trie dumping complete accounts=3 elapsed="123.676µs" +INFO [12-27|09:25:11.187] Wrote file file=alloc.json +INFO [12-27|09:25:11.187] Wrote file file=alloc_rlptx.json ``` You might have noticed that the results from these two invocations were stored in two separate files. And we can now finally check that they match. @@ -475,3 +475,152 @@ cat alloc_jsontx.json | jq .stateRoot && cat alloc_rlptx.json | jq .stateRoot "0xe4b924a6adb5959fccf769d5b7bb2f6359e26d1e76a2443c5a91a36d826aef61" "0xe4b924a6adb5959fccf769d5b7bb2f6359e26d1e76a2443c5a91a36d826aef61" ``` + +## Transaction tool + +The transaction tool is used to perform static validity checks on transactions such as: +* intrinsic gas calculation +* max values on integers +* fee semantics, such as `maxFeePerGas < maxPriorityFeePerGas` +* newer tx types on old forks + +### Examples + +``` +./evm t9n --state.fork Homestead --input.txs testdata/15/signed_txs.rlp +[ + { + "error": "transaction type not supported", + "hash": "0xa98a24882ea90916c6a86da650fbc6b14238e46f0af04a131ce92be897507476" + }, + { + "error": "transaction type not supported", + "hash": "0x36bad80acce7040c45fd32764b5c2b2d2e6f778669fb41791f73f546d56e739a" + } +] +``` +``` +./evm t9n --state.fork London --input.txs testdata/15/signed_txs.rlp +[ + { + "address": "0xd02d72e067e77158444ef2020ff2d325f929b363", + "hash": "0xa98a24882ea90916c6a86da650fbc6b14238e46f0af04a131ce92be897507476", + "intrinsicGas": "0x5208" + }, + { + "address": "0xd02d72e067e77158444ef2020ff2d325f929b363", + "hash": "0x36bad80acce7040c45fd32764b5c2b2d2e6f778669fb41791f73f546d56e739a", + "intrinsicGas": "0x5208" + } +] +``` +## Block builder tool (b11r) + +The `evm b11r` tool is used to assemble and seal full block rlps. + +### Specification + +#### Command line params + +Command line params that need to be supported are: + +``` + --input.header value `stdin` or file name of where to find the block header to use. (default: "header.json") + --input.ommers value `stdin` or file name of where to find the list of ommer header RLPs to use. + --input.txs value `stdin` or file name of where to find the transactions list in RLP form. (default: "txs.rlp") + --output.basedir value Specifies where output files are placed. Will be created if it does not exist. + --output.block value Determines where to put the alloc of the post-state. (default: "block.json") + - into the file + `stdout` - into the stdout output + `stderr` - into the stderr output + --seal.clique value Seal block with Clique. `stdin` or file name of where to find the Clique sealing data. + --seal.ethash Seal block with ethash. (default: false) + --seal.ethash.dir value Path to ethash DAG. If none exists, a new DAG will be generated. + --seal.ethash.mode value Defines the type and amount of PoW verification an ethash engine makes. (default: "normal") + --verbosity value Sets the verbosity level. (default: 3) +``` + +#### Objects + +##### `header` + +The `header` object is a consensus header. + +```go= +type Header struct { + ParentHash common.Hash `json:"parentHash"` + OmmerHash *common.Hash `json:"sha3Uncles"` + Coinbase *common.Address `json:"miner"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot"` + ReceiptHash *common.Hash `json:"receiptsRoot"` + Bloom types.Bloom `json:"logsBloom"` + Difficulty *big.Int `json:"difficulty"` + Number *big.Int `json:"number" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed"` + Time uint64 `json:"timestamp" gencodec:"required"` + Extra []byte `json:"extraData"` + MixDigest common.Hash `json:"mixHash"` + Nonce *types.BlockNonce `json:"nonce"` + BaseFee *big.Int `json:"baseFeePerGas"` +} +``` +#### `ommers` + +The `ommers` object is a list of RLP-encoded ommer blocks in hex +representation. + +```go= +type Ommers []string +``` + +#### `txs` + +The `txs` object is a list of RLP-encoded transactions in hex representation. + +```go= +type Txs []string +``` + +#### `clique` + +The `clique` object provides the neccesary information to complete a clique +seal of the block. + +```go= +var CliqueInfo struct { + Key *common.Hash `json:"secretKey"` + Voted *common.Address `json:"voted"` + Authorize *bool `json:"authorize"` + Vanity common.Hash `json:"vanity"` +} +``` + +#### `output` + +The `output` object contains two values, the block RLP and the block hash. + +```go= +type BlockInfo struct { + Rlp []byte `json:"rlp"` + Hash common.Hash `json:"hash"` +} +``` + +## A Note on Encoding + +The encoding of values for `evm` utility attempts to be relatively flexible. It +generally supports hex-encoded or decimal-encoded numeric values, and +hex-encoded byte values (like `common.Address`, `common.Hash`, etc). When in +doubt, the [`execution-apis`](https://github.com/ethereum/execution-apis) way +of encoding should always be accepted. + +## Testing + +There are many test cases in the [`cmd/evm/testdata`](./testdata) directory. +These fixtures are used to power the `t8n` tests in +[`t8n_test.go`](./t8n_test.go). The best way to verify correctness of new `evm` +implementations is to execute these and verify the output and error codes match +the expected values. + diff --git a/cmd/evm/transition-test.sh b/cmd/evm/transition-test.sh index 8d7fd799732c..2dac61d9669e 100644 --- a/cmd/evm/transition-test.sh +++ b/cmd/evm/transition-test.sh @@ -379,3 +379,140 @@ echo "$ticks" echo "cat alloc_jsontx.json | jq .stateRoot && cat alloc_rlptx.json | jq .stateRoot" cat alloc_jsontx.json | jq .stateRoot && cat alloc_rlptx.json | jq .stateRoot echo "$ticks" + +cat << "EOF" + +## Transaction tool + +The transaction tool is used to perform static validity checks on transactions such as: +* intrinsic gas calculation +* max values on integers +* fee semantics, such as `maxFeePerGas < maxPriorityFeePerGas` +* newer tx types on old forks + +### Examples + +EOF + +cmd="./evm t9n --state.fork Homestead --input.txs testdata/15/signed_txs.rlp" +tick;echo "$cmd"; +$cmd 2>/dev/null +tick + +cmd="./evm t9n --state.fork London --input.txs testdata/15/signed_txs.rlp" +tick;echo "$cmd"; +$cmd 2>/dev/null +tick + +cat << "EOF" +## Block builder tool (b11r) + +The `evm b11r` tool is used to assemble and seal full block rlps. + +### Specification + +#### Command line params + +Command line params that need to be supported are: + +``` + --input.header value `stdin` or file name of where to find the block header to use. (default: "header.json") + --input.ommers value `stdin` or file name of where to find the list of ommer header RLPs to use. + --input.txs value `stdin` or file name of where to find the transactions list in RLP form. (default: "txs.rlp") + --output.basedir value Specifies where output files are placed. Will be created if it does not exist. + --output.block value Determines where to put the alloc of the post-state. (default: "block.json") + - into the file + `stdout` - into the stdout output + `stderr` - into the stderr output + --seal.clique value Seal block with Clique. `stdin` or file name of where to find the Clique sealing data. + --seal.ethash Seal block with ethash. (default: false) + --seal.ethash.dir value Path to ethash DAG. If none exists, a new DAG will be generated. + --seal.ethash.mode value Defines the type and amount of PoW verification an ethash engine makes. (default: "normal") + --verbosity value Sets the verbosity level. (default: 3) +``` + +#### Objects + +##### `header` + +The `header` object is a consensus header. + +```go= +type Header struct { + ParentHash common.Hash `json:"parentHash"` + OmmerHash *common.Hash `json:"sha3Uncles"` + Coinbase *common.Address `json:"miner"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot"` + ReceiptHash *common.Hash `json:"receiptsRoot"` + Bloom types.Bloom `json:"logsBloom"` + Difficulty *big.Int `json:"difficulty"` + Number *big.Int `json:"number" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed"` + Time uint64 `json:"timestamp" gencodec:"required"` + Extra []byte `json:"extraData"` + MixDigest common.Hash `json:"mixHash"` + Nonce *types.BlockNonce `json:"nonce"` + BaseFee *big.Int `json:"baseFeePerGas"` +} +``` +#### `ommers` + +The `ommers` object is a list of RLP-encoded ommer blocks in hex +representation. + +```go= +type Ommers []string +``` + +#### `txs` + +The `txs` object is a list of RLP-encoded transactions in hex representation. + +```go= +type Txs []string +``` + +#### `clique` + +The `clique` object provides the neccesary information to complete a clique +seal of the block. + +```go= +var CliqueInfo struct { + Key *common.Hash `json:"secretKey"` + Voted *common.Address `json:"voted"` + Authorize *bool `json:"authorize"` + Vanity common.Hash `json:"vanity"` +} +``` + +#### `output` + +The `output` object contains two values, the block RLP and the block hash. + +```go= +type BlockInfo struct { + Rlp []byte `json:"rlp"` + Hash common.Hash `json:"hash"` +} +``` + +## A Note on Encoding + +The encoding of values for `evm` utility attempts to be relatively flexible. It +generally supports hex-encoded or decimal-encoded numeric values, and +hex-encoded byte values (like `common.Address`, `common.Hash`, etc). When in +doubt, the [`execution-apis`](https://github.com/ethereum/execution-apis) way +of encoding should always be accepted. + +## Testing + +There are many test cases in the [`cmd/evm/testdata`](./testdata) directory. +These fixtures are used to power the `t8n` tests in +[`t8n_test.go`](./t8n_test.go). The best way to verify correctness of new `evm` +implementations is to execute these and verify the output and error codes match +the expected values. + +EOF From 6c149fd4ad063f7c24d726a73bc0546badd1bc73 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 3 Jan 2023 21:41:40 +0800 Subject: [PATCH 446/715] core, eth, trie, light: clean up trie interface (#26388) * all: cleanup trie interface * eth, trie: address comments --- core/state/database.go | 17 ++++++++++++----- core/state/statedb.go | 6 +++--- core/state/trie_prefetcher.go | 6 +----- eth/protocols/snap/handler.go | 4 ++-- eth/protocols/snap/sync.go | 2 +- light/trie.go | 12 ++++++------ trie/secure_trie.go | 26 +++++++++++++------------- 7 files changed, 38 insertions(+), 35 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index fbd6d2883cc0..7a719f0d9a7d 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -73,8 +73,13 @@ type Trie interface { // trie.MissingNodeError is returned. TryGet(key []byte) ([]byte, error) - // TryGetAccount abstract an account read from the trie. - TryGetAccount(key []byte) (*types.StateAccount, error) + // TryGetAccount abstracts an account read from the trie. It retrieves the + // account blob from the trie with provided account address and decodes it + // with associated decoding algorithm. If the specified account is not in + // the trie, nil will be returned. If the trie is corrupted(e.g. some nodes + // are missing or the account blob is incorrect for decoding), an error will + // be returned. + TryGetAccount(address common.Address) (*types.StateAccount, error) // TryUpdate 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 @@ -82,15 +87,17 @@ type Trie interface { // database, a trie.MissingNodeError is returned. TryUpdate(key, value []byte) error - // TryUpdateAccount abstract an account write to the trie. - TryUpdateAccount(key []byte, account *types.StateAccount) error + // TryUpdateAccount 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. + TryUpdateAccount(address common.Address, account *types.StateAccount) error // TryDelete removes any existing value for key from the trie. If a node was not // found in the database, a trie.MissingNodeError is returned. TryDelete(key []byte) error // TryDeleteAccount abstracts an account deletion from the trie. - TryDeleteAccount(key []byte) error + TryDeleteAccount(address common.Address) error // Hash returns the root hash of the trie. It does not write to the database and // can be used even if the trie doesn't have one. diff --git a/core/state/statedb.go b/core/state/statedb.go index 8d0aacf580de..fb2459ffc83c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -510,7 +510,7 @@ func (s *StateDB) updateStateObject(obj *stateObject) { } // Encode the account and update the account trie addr := obj.Address() - if err := s.trie.TryUpdateAccount(addr[:], &obj.data); err != nil { + if err := s.trie.TryUpdateAccount(addr, &obj.data); err != nil { s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err)) } @@ -531,7 +531,7 @@ func (s *StateDB) deleteStateObject(obj *stateObject) { } // Delete the account from the trie addr := obj.Address() - if err := s.trie.TryDeleteAccount(addr[:]); err != nil { + if err := s.trie.TryDeleteAccount(addr); err != nil { s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err)) } } @@ -585,7 +585,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { if data == nil { start := time.Now() var err error - data, err = s.trie.TryGetAccount(addr.Bytes()) + data, err = s.trie.TryGetAccount(addr) if metrics.EnabledExpensive { s.AccountReads += time.Since(start) } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 2e16f587ce56..f142c86bbfa0 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -336,11 +336,7 @@ func (sf *subfetcher) loop() { if _, ok := sf.seen[string(task)]; ok { sf.dups++ } else { - if len(task) == len(common.Address{}) { - sf.trie.TryGetAccount(task) - } else { - sf.trie.TryGet(task) - } + sf.trie.TryGet(task) sf.seen[string(task)] = struct{}{} } } diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 60f9898f406b..6941d522aa2e 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -417,7 +417,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP if err != nil { return nil, nil } - acc, err := accTrie.TryGetAccountWithPreHashedKey(account[:]) + acc, err := accTrie.TryGetAccountByHash(account) if err != nil || acc == nil { return nil, nil } @@ -523,7 +523,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s if snap == nil { // We don't have the requested state snapshotted yet (or it is stale), // but can look up the account via the trie instead. - account, err := accTrie.TryGetAccountWithPreHashedKey(pathset[0]) + account, err := accTrie.TryGetAccountByHash(common.BytesToHash(pathset[0])) loads += 8 // We don't know the exact cost of lookup, this is an estimate if err != nil || account == nil { break diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index a9e35f971482..1193af6769d7 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -3083,7 +3083,7 @@ func (t *healRequestSort) Swap(i, j int) { func (t *healRequestSort) Merge() []TrieNodePathSet { var result []TrieNodePathSet for _, path := range t.syncPaths { - pathset := TrieNodePathSet([][]byte(path)) + pathset := TrieNodePathSet(path) if len(path) == 1 { // It's an account reference. result = append(result, pathset) diff --git a/light/trie.go b/light/trie.go index 0092eee136c3..c7c08331cb50 100644 --- a/light/trie.go +++ b/light/trie.go @@ -115,9 +115,9 @@ func (t *odrTrie) TryGet(key []byte) ([]byte, error) { return res, err } -func (t *odrTrie) TryGetAccount(key []byte) (*types.StateAccount, error) { - key = crypto.Keccak256(key) +func (t *odrTrie) TryGetAccount(address common.Address) (*types.StateAccount, error) { var res types.StateAccount + key := crypto.Keccak256(address.Bytes()) err := t.do(key, func() (err error) { value, err := t.trie.TryGet(key) if err != nil { @@ -131,8 +131,8 @@ func (t *odrTrie) TryGetAccount(key []byte) (*types.StateAccount, error) { return &res, err } -func (t *odrTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { - key = crypto.Keccak256(key) +func (t *odrTrie) TryUpdateAccount(address common.Address, acc *types.StateAccount) error { + key := crypto.Keccak256(address.Bytes()) value, err := rlp.EncodeToBytes(acc) if err != nil { return fmt.Errorf("decoding error in account update: %w", err) @@ -157,8 +157,8 @@ func (t *odrTrie) TryDelete(key []byte) error { } // TryDeleteAccount abstracts an account deletion from the trie. -func (t *odrTrie) TryDeleteAccount(key []byte) error { - key = crypto.Keccak256(key) +func (t *odrTrie) TryDeleteAccount(address common.Address) error { + key := crypto.Keccak256(address.Bytes()) return t.do(key, func() error { return t.trie.TryDelete(key) }) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 96faab158265..158a69cc2982 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -90,11 +90,11 @@ func (t *StateTrie) TryGet(key []byte) ([]byte, error) { return t.trie.TryGet(t.hashKey(key)) } -// TryGetAccount attempts to retrieve an account with provided trie path. +// TryGetAccount 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. -func (t *StateTrie) TryGetAccount(key []byte) (*types.StateAccount, error) { - res, err := t.trie.TryGet(t.hashKey(key)) +func (t *StateTrie) TryGetAccount(address common.Address) (*types.StateAccount, error) { + res, err := t.trie.TryGet(t.hashKey(address.Bytes())) if res == nil || err != nil { return nil, err } @@ -103,11 +103,11 @@ func (t *StateTrie) TryGetAccount(key []byte) (*types.StateAccount, error) { return ret, err } -// TryGetAccountWithPreHashedKey does the same thing as TryGetAccount, however -// it expects a key that is already hashed. This constitutes an abstraction leak, -// since the client code needs to know the key format. -func (t *StateTrie) TryGetAccountWithPreHashedKey(key []byte) (*types.StateAccount, error) { - res, err := t.trie.TryGet(key) +// TryGetAccountByHash does the same thing as TryGetAccount, however +// it expects an account hash that is the hash of address. This constitutes an +// abstraction leak, since the client code needs to know the key format. +func (t *StateTrie) TryGetAccountByHash(addrHash common.Hash) (*types.StateAccount, error) { + res, err := t.trie.TryGet(addrHash.Bytes()) if res == nil || err != nil { return nil, err } @@ -156,8 +156,8 @@ func (t *StateTrie) TryUpdate(key, value []byte) error { // TryUpdateAccount account will abstract the write of an account to the // secure trie. -func (t *StateTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error { - hk := t.hashKey(key) +func (t *StateTrie) TryUpdateAccount(address common.Address, acc *types.StateAccount) error { + hk := t.hashKey(address.Bytes()) data, err := rlp.EncodeToBytes(acc) if err != nil { return err @@ -165,7 +165,7 @@ func (t *StateTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error if err := t.trie.TryUpdate(hk, data); err != nil { return err } - t.getSecKeyCache()[string(hk)] = common.CopyBytes(key) + t.getSecKeyCache()[string(hk)] = address.Bytes() return nil } @@ -186,8 +186,8 @@ func (t *StateTrie) TryDelete(key []byte) error { } // TryDeleteAccount abstracts an account deletion from the trie. -func (t *StateTrie) TryDeleteAccount(key []byte) error { - hk := t.hashKey(key) +func (t *StateTrie) TryDeleteAccount(address common.Address) error { + hk := t.hashKey(address.Bytes()) delete(t.getSecKeyCache(), string(hk)) return t.trie.TryDelete(hk) } From f426805fdd33df996e519fbdc999f14a70a64e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Fri, 6 Jan 2023 12:25:58 +0100 Subject: [PATCH 447/715] build: upgrade -dlgo version to Go 1.19.4 (#26440) --- build/checksums.txt | 28 ++++++++++++++-------------- build/ci.go | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index bd11b218dcbd..173087945966 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,19 +1,19 @@ # This file contains sha256 checksums of optional build dependencies. -2ce930d70a931de660fdaf271d70192793b1b240272645bf0275779f6704df6b go1.19.2.src.tar.gz -16f8047d7b627699b3773680098fbaf7cc962b7db02b3e02726f78c4db26dfde go1.19.2.darwin-amd64.tar.gz -35d819df25197c0be45f36ce849b994bba3b0559b76d4538b910d28f6395c00d go1.19.2.darwin-arm64.tar.gz -7831a406447a14d964212d07f68e77cf7fe7fb7286bade6eeb9fbea39b192984 go1.19.2.freebsd-386.tar.gz -d74c88430484d14826ec21161e3b9336bd021f502b6594c4dd00e9ec730ee51d go1.19.2.freebsd-amd64.tar.gz -ba8c97965e0856c69c9ca2c86f96bec5bb21de43e6533e25494bb211d85cda1b go1.19.2.linux-386.tar.gz -5e8c5a74fe6470dd7e055a461acda8bb4050ead8c2df70f227e3ff7d8eb7eeb6 go1.19.2.linux-amd64.tar.gz -b62a8d9654436c67c14a0c91e931d50440541f09eb991a987536cb982903126d go1.19.2.linux-arm64.tar.gz -f3ccec7816ecd704ebafd130b08b8ad97c55402a8193a107b63e9de12ab90118 go1.19.2.linux-armv6l.tar.gz -37e1d4342f7103aeb9babeabe8c71ef3dba23db28db525071119e94b2aa21d7d go1.19.2.linux-ppc64le.tar.gz -51b45dec41295215df17f78e67d1a373b9dda97a5e539bed440974da5ffc97de go1.19.2.linux-s390x.tar.gz -9355b09b23e9db33945a7ba45bb75981ab0bb6006713099732167722cf081b53 go1.19.2.windows-386.zip -e132d4f0518b0d417eb6cc5f182c3385f6d24bb2eebee2566cd1a7ab6097e3f2 go1.19.2.windows-amd64.zip -4049435f77fb2a0642fd8740c588aadbcc446056e637e835a8e223fdb897cb3e go1.19.2.windows-arm64.zip +eda74db4ac494800a3e66ee784e495bfbb9b8e535df924a8b01b1a8028b7f368 go1.19.4.src.tar.gz +44894862d996eec96ef2a39878e4e1fce4d05423fc18bdc1cbba745ebfa41253 go1.19.4.darwin-amd64.tar.gz +bb3bc5d7655b9637cfe2b5e90055dee93b0ead50e2ffd091df320d1af1ca853f go1.19.4.darwin-arm64.tar.gz +dd6c401cc6d0692995ed9b0f37482a724b5b9d9c1119d620862766c60708630f go1.19.4.freebsd-386.tar.gz +84489ebb63f1757b79574d7345c647bd40bc6414cecb868c93e24476c2d2b9b6 go1.19.4.freebsd-amd64.tar.gz +e5f0b0551e120bf3d1246cb960ec58032d7ca69e1adcf0fdb91c07da620e0c61 go1.19.4.linux-386.tar.gz +c9c08f783325c4cf840a94333159cc937f05f75d36a8b307951d5bd959cf2ab8 go1.19.4.linux-amd64.tar.gz +9df122d6baf6f2275270306b92af3b09d7973fb1259257e284dba33c0db14f1b go1.19.4.linux-arm64.tar.gz +7a51dae4f3a52d2dfeaf59367cc0b8a296deddc87e95aa619bf87d24661d2370 go1.19.4.linux-armv6l.tar.gz +fbc6c7d1d169bbdc82223d861d2fadc6add01c126533d3efbba3fdca9b362035 go1.19.4.linux-ppc64le.tar.gz +4b8d25acbdca8010c31ea8c5fd4aba93471ff6ada7a8b4fb04b935baee873dc8 go1.19.4.linux-s390x.tar.gz +51d8d895deb9883aa2daa291572f483fead69f577bf4e7cf8381c8001e37778e go1.19.4.windows-386.zip +ada490e188bfb57c7388da7c5eba7565390992b6496204d30e710d37755956b0 go1.19.4.windows-amd64.zip +66cfa12f408806c0fabfc10726a57b090c0c3ef3efddd944400af678ff10b851 go1.19.4.windows-arm64.zip 20cd1215e0420db8cfa94a6cd3c9d325f7b39c07f2415a02d111568d8bc9e271 golangci-lint-1.49.0-darwin-amd64.tar.gz cabb1a4c35fe1dadbe5a81550a00871281a331e7660cd85ae16e936a7f0f6cfc golangci-lint-1.49.0-darwin-arm64.tar.gz diff --git a/build/ci.go b/build/ci.go index 2c2af0899da5..f3a8c5a045f7 100644 --- a/build/ci.go +++ b/build/ci.go @@ -148,7 +148,7 @@ var ( // This is the version of go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.19.2" + dlgoVersion = "1.19.4" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) From fcf3d00488e471bcaf069862c6d811490d77b53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 3 Jan 2023 13:06:32 +0200 Subject: [PATCH 448/715] eth, les: polish forkid a bit, fix races and transition validation --- core/forkid/forkid.go | 128 ++++---- core/forkid/forkid_test.go | 553 ++++++++++++++++----------------- core/headerchain.go | 8 +- eth/handler.go | 2 +- eth/protocols/eth/discovery.go | 3 +- les/server_handler.go | 2 +- 6 files changed, 339 insertions(+), 357 deletions(-) diff --git a/core/forkid/forkid.go b/core/forkid/forkid.go index b35fd92b2aa2..300dca6cfba0 100644 --- a/core/forkid/forkid.go +++ b/core/forkid/forkid.go @@ -45,6 +45,12 @@ var ( ErrLocalIncompatibleOrStale = errors.New("local incompatible or needs update") ) +// timestampThreshold is the Ethereum mainnet genesis timestamp. It is used to +// differentiate if a forkid.next field is a block number or a timestamp. Whilst +// very hacky, something's needed to split the validation during the transition +// period (block forks -> time forks). +const timestampThreshold = 1438269973 + // Blockchain defines all necessary method to build a forkID. type Blockchain interface { // Config retrieves the chain's fork configuration. @@ -72,8 +78,8 @@ func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) I hash := crc32.ChecksumIEEE(genesis[:]) // Calculate the current fork checksum and the next fork block - forks, forksByTime := gatherForks(config) - for _, fork := range forks { + forksByBlock, forksByTime := gatherForks(config) + for _, fork := range forksByBlock { if fork <= head { // Fork already passed, checksum the previous hash and the fork number hash = checksumUpdate(hash, fork) @@ -81,26 +87,26 @@ func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) I } return ID{Hash: checksumToBytes(hash), Next: fork} } - var next uint64 for _, fork := range forksByTime { - if time >= fork { - // Fork passed, checksum previous hash and fork time + if fork <= time { + // Fork already passed, checksum the previous hash and fork timestamp hash = checksumUpdate(hash, fork) continue } - next = fork - break + return ID{Hash: checksumToBytes(hash), Next: fork} } - return ID{Hash: checksumToBytes(hash), Next: next} + return ID{Hash: checksumToBytes(hash), Next: 0} } // NewIDWithChain calculates the Ethereum fork ID from an existing chain instance. func NewIDWithChain(chain Blockchain) ID { + head := chain.CurrentHeader() + return NewID( chain.Config(), chain.Genesis().Hash(), - chain.CurrentHeader().Number.Uint64(), - chain.CurrentHeader().Time, + head.Number.Uint64(), + head.Time, ) } @@ -111,7 +117,8 @@ func NewFilter(chain Blockchain) Filter { chain.Config(), chain.Genesis().Hash(), func() (uint64, uint64) { - return chain.CurrentHeader().Number.Uint64(), chain.CurrentHeader().Time + head := chain.CurrentHeader() + return head.Number.Uint64(), head.Time }, ) } @@ -128,23 +135,23 @@ func NewStaticFilter(config *params.ChainConfig, genesis common.Hash) Filter { func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() (uint64, uint64)) Filter { // Calculate the all the valid fork hash and fork next combos var ( - forks, forksByTime = gatherForks(config) - sums = make([][4]byte, len(forks)+len(forksByTime)+1) // 0th is the genesis + forksByBlock, forksByTime = gatherForks(config) + forks = append(append([]uint64{}, forksByBlock...), forksByTime...) + sums = make([][4]byte, len(forks)+1) // 0th is the genesis ) - allForks := append(forks, forksByTime...) hash := crc32.ChecksumIEEE(genesis[:]) sums[0] = checksumToBytes(hash) - for i, fork := range allForks { + for i, fork := range forks { hash = checksumUpdate(hash, fork) sums[i+1] = checksumToBytes(hash) } // Add two sentries to simplify the fork checks and don't require special // casing the last one. + forks = append(forks, math.MaxUint64) // Last fork will never be passed if len(forksByTime) == 0 { - forks = append(forks, math.MaxUint64) + // In purely block based forks, avoid the sentry spilling into timestapt territory + forksByBlock = append(forksByBlock, math.MaxUint64) // Last fork will never be passed } - forksByTime = append(forksByTime, math.MaxUint64) // Last fork will never be passed - // Create a validator that will filter out incompatible chains return func(id ID) error { // Run the fork checksum validation ruleset: @@ -166,14 +173,24 @@ func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() (u // the remote, but at this current point in time we don't have enough // information. // 4. Reject in all other cases. - - verify := func(index int, headOrTime uint64) error { + block, time := headfn() + for i, fork := range forks { + // Pick the head comparison based on fork progression + head := block + if i >= len(forksByBlock) { + head = time + } + // If our head is beyond this fork, continue to the next (we have a dummy + // fork of maxuint64 as the last item to always fail this check eventually). + if head >= fork { + continue + } // Found the first unpassed fork block, check if our current state matches // the remote checksum (rule #1). - if sums[index] == id.Hash { + if sums[i] == id.Hash { // Fork checksum matched, check if a remote future fork block already passed // locally without the local node being aware of it (rule #1a). - if id.Next > 0 && headOrTime >= id.Next { + if id.Next > 0 && (head >= id.Next || (id.Next > timestampThreshold && time >= id.Next)) { return ErrLocalIncompatibleOrStale } // Haven't passed locally a remote-only fork, accept the connection (rule #1b). @@ -181,10 +198,10 @@ func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() (u } // The local and remote nodes are in different forks currently, check if the // remote checksum is a subset of our local forks (rule #2). - for j := 0; j < index; j++ { + for j := 0; j < i; j++ { if sums[j] == id.Hash { // Remote checksum is a subset, validate based on the announced next fork - if allForks[j] != id.Next { + if forks[j] != id.Next { return ErrRemoteStale } return nil @@ -192,7 +209,7 @@ func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() (u } // Remote chain is not a subset of our local one, check if it's a superset by // any chance, signalling that we're simply out of sync (rule #3). - for j := index + 1; j < len(sums); j++ { + for j := i + 1; j < len(sums); j++ { if sums[j] == id.Hash { // Yay, remote checksum is a superset, ignore upcoming forks return nil @@ -201,27 +218,6 @@ func newFilter(config *params.ChainConfig, genesis common.Hash, headfn func() (u // No exact, subset or superset match. We are on differing chains, reject. return ErrLocalIncompatibleOrStale } - - head, time := headfn() - // Verify forks by block - for i, fork := range forks { - // If our head is beyond this fork, continue to the next (we have a dummy - // fork of maxuint64 as the last item to always fail this check eventually). - if head >= fork { - continue - } - return verify(i, head) - } - // Verify forks by time - for i, fork := range forksByTime { - // If our head is beyond this fork, continue to the next (we have a dummy - // fork of maxuint64 as the last item to always fail this check eventually). - if time >= fork { - continue - } - return verify(len(forks)+i, time) - } - log.Error("Impossible fork ID validation", "id", id) return nil // Something's very wrong, accept rather than reject } @@ -242,45 +238,45 @@ func checksumToBytes(hash uint32) [4]byte { return blob } -// gatherForks gathers all the known forks and creates a sorted list out of them. +// gatherForks gathers all the known forks and creates two sorted lists out of +// them, one for the block number based forks and the second for the timestamps. func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) { // Gather all the fork block numbers via reflection kind := reflect.TypeOf(params.ChainConfig{}) conf := reflect.ValueOf(config).Elem() - var forks []uint64 - var forksByTime []uint64 + var ( + forksByBlock []uint64 + forksByTime []uint64 + ) for i := 0; i < kind.NumField(); i++ { // Fetch the next field and skip non-fork rules field := kind.Field(i) - time := false - if !strings.HasSuffix(field.Name, "Block") { - if !strings.HasSuffix(field.Name, "Time") { - continue - } - time = true + + time := strings.HasSuffix(field.Name, "Time") + if !time && !strings.HasSuffix(field.Name, "Block") { + continue } if field.Type != reflect.TypeOf(new(big.Int)) { continue } - // Extract the fork rule block number and aggregate it + // Extract the fork rule block number or timestamp and aggregate it rule := conf.Field(i).Interface().(*big.Int) if rule != nil { if time { forksByTime = append(forksByTime, rule.Uint64()) } else { - forks = append(forks, rule.Uint64()) + forksByBlock = append(forksByBlock, rule.Uint64()) } } } - - sort.Slice(forks, func(i, j int) bool { return forks[i] < forks[j] }) + sort.Slice(forksByBlock, func(i, j int) bool { return forksByBlock[i] < forksByBlock[j] }) sort.Slice(forksByTime, func(i, j int) bool { return forksByTime[i] < forksByTime[j] }) - // Deduplicate block numbers applying multiple forks - for i := 1; i < len(forks); i++ { - if forks[i] == forks[i-1] { - forks = append(forks[:i], forks[i+1:]...) + // Deduplicate fork identifiers applying multiple forks + for i := 1; i < len(forksByBlock); i++ { + if forksByBlock[i] == forksByBlock[i-1] { + forksByBlock = append(forksByBlock[:i], forksByBlock[i+1:]...) i-- } } @@ -291,11 +287,11 @@ func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) { } } // Skip any forks in block 0, that's the genesis ruleset - if len(forks) > 0 && forks[0] == 0 { - forks = forks[1:] + if len(forksByBlock) > 0 && forksByBlock[0] == 0 { + forksByBlock = forksByBlock[1:] } if len(forksByTime) > 0 && forksByTime[0] == 0 { forksByTime = forksByTime[1:] } - return forks, forksByTime + return forksByBlock, forksByTime } diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index 0158545f345e..4e8b4f411189 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -30,177 +30,10 @@ import ( // TestCreation tests that different genesis and fork rule combinations result in // the correct fork ID. func TestCreation(t *testing.T) { - mergeConfig := *params.MainnetChainConfig - mergeConfig.MergeNetsplitBlock = big.NewInt(18000000) - type testcase struct { - head uint64 - want ID - } - tests := []struct { - config *params.ChainConfig - genesis common.Hash - cases []testcase - }{ - // Mainnet test cases - { - params.MainnetChainConfig, - params.MainnetGenesisHash, - []testcase{ - {0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced - {1149999, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block - {1150000, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // First Homestead block - {1919999, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // Last Homestead block - {1920000, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // First DAO block - {2462999, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // Last DAO block - {2463000, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // First Tangerine block - {2674999, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // Last Tangerine block - {2675000, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // First Spurious block - {4369999, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // Last Spurious block - {4370000, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // First Byzantium block - {7279999, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // Last Byzantium block - {7280000, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // First and last Constantinople, first Petersburg block - {9068999, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // Last Petersburg block - {9069000, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // First Istanbul and first Muir Glacier block - {9199999, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // Last Istanbul and first Muir Glacier block - {9200000, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // First Muir Glacier block - {12243999, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // Last Muir Glacier block - {12244000, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // First Berlin block - {12964999, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block - {12965000, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block - {13772999, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block - {13773000, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block - {15049999, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block - {15050000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}}, // First Gray Glacier block - {20000000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}}, // Future Gray Glacier block - }, - }, - // Ropsten test cases - { - params.RopstenChainConfig, - params.RopstenGenesisHash, - []testcase{ - {0, ID{Hash: checksumToBytes(0x30c7ddbc), Next: 10}}, // Unsynced, last Frontier, Homestead and first Tangerine block - {9, ID{Hash: checksumToBytes(0x30c7ddbc), Next: 10}}, // Last Tangerine block - {10, ID{Hash: checksumToBytes(0x63760190), Next: 1700000}}, // First Spurious block - {1699999, ID{Hash: checksumToBytes(0x63760190), Next: 1700000}}, // Last Spurious block - {1700000, ID{Hash: checksumToBytes(0x3ea159c7), Next: 4230000}}, // First Byzantium block - {4229999, ID{Hash: checksumToBytes(0x3ea159c7), Next: 4230000}}, // Last Byzantium block - {4230000, ID{Hash: checksumToBytes(0x97b544f3), Next: 4939394}}, // First Constantinople block - {4939393, ID{Hash: checksumToBytes(0x97b544f3), Next: 4939394}}, // Last Constantinople block - {4939394, ID{Hash: checksumToBytes(0xd6e2149b), Next: 6485846}}, // First Petersburg block - {6485845, ID{Hash: checksumToBytes(0xd6e2149b), Next: 6485846}}, // Last Petersburg block - {6485846, ID{Hash: checksumToBytes(0x4bc66396), Next: 7117117}}, // First Istanbul block - {7117116, ID{Hash: checksumToBytes(0x4bc66396), Next: 7117117}}, // Last Istanbul block - {7117117, ID{Hash: checksumToBytes(0x6727ef90), Next: 9812189}}, // First Muir Glacier block - {9812188, ID{Hash: checksumToBytes(0x6727ef90), Next: 9812189}}, // Last Muir Glacier block - {9812189, ID{Hash: checksumToBytes(0xa157d377), Next: 10499401}}, // First Berlin block - {10499400, ID{Hash: checksumToBytes(0xa157d377), Next: 10499401}}, // Last Berlin block - {10499401, ID{Hash: checksumToBytes(0x7119b6b3), Next: 0}}, // First London block - {11000000, ID{Hash: checksumToBytes(0x7119b6b3), Next: 0}}, // Future London block - }, - }, - // Rinkeby test cases - { - params.RinkebyChainConfig, - params.RinkebyGenesisHash, - []testcase{ - {0, ID{Hash: checksumToBytes(0x3b8e0691), Next: 1}}, // Unsynced, last Frontier block - {1, ID{Hash: checksumToBytes(0x60949295), Next: 2}}, // First and last Homestead block - {2, ID{Hash: checksumToBytes(0x8bde40dd), Next: 3}}, // First and last Tangerine block - {3, ID{Hash: checksumToBytes(0xcb3a64bb), Next: 1035301}}, // First Spurious block - {1035300, ID{Hash: checksumToBytes(0xcb3a64bb), Next: 1035301}}, // Last Spurious block - {1035301, ID{Hash: checksumToBytes(0x8d748b57), Next: 3660663}}, // First Byzantium block - {3660662, ID{Hash: checksumToBytes(0x8d748b57), Next: 3660663}}, // Last Byzantium block - {3660663, ID{Hash: checksumToBytes(0xe49cab14), Next: 4321234}}, // First Constantinople block - {4321233, ID{Hash: checksumToBytes(0xe49cab14), Next: 4321234}}, // Last Constantinople block - {4321234, ID{Hash: checksumToBytes(0xafec6b27), Next: 5435345}}, // First Petersburg block - {5435344, ID{Hash: checksumToBytes(0xafec6b27), Next: 5435345}}, // Last Petersburg block - {5435345, ID{Hash: checksumToBytes(0xcbdb8838), Next: 8290928}}, // First Istanbul block - {8290927, ID{Hash: checksumToBytes(0xcbdb8838), Next: 8290928}}, // Last Istanbul block - {8290928, ID{Hash: checksumToBytes(0x6910c8bd), Next: 8897988}}, // First Berlin block - {8897987, ID{Hash: checksumToBytes(0x6910c8bd), Next: 8897988}}, // Last Berlin block - {8897988, ID{Hash: checksumToBytes(0x8E29F2F3), Next: 0}}, // First London block - {10000000, ID{Hash: checksumToBytes(0x8E29F2F3), Next: 0}}, // Future London block - }, - }, - // Goerli test cases - { - params.GoerliChainConfig, - params.GoerliGenesisHash, - []testcase{ - {0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block - {1561650, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block - {1561651, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block - {4460643, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block - {4460644, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block - {5000000, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block - {5062605, ID{Hash: checksumToBytes(0xB8C6299D), Next: 0}}, // First London block - {6000000, ID{Hash: checksumToBytes(0xB8C6299D), Next: 0}}, // Future London block - }, - }, - // Sepolia test cases - { - params.SepoliaChainConfig, - params.SepoliaGenesisHash, - []testcase{ - {0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin and first London block - {1735370, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Last London block - {1735371, ID{Hash: checksumToBytes(0xb96cbd13), Next: 0}}, // First MergeNetsplit block - }, - }, - // Merge test cases - { - &mergeConfig, - params.MainnetGenesisHash, - []testcase{ - {0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced - {1149999, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block - {1150000, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // First Homestead block - {1919999, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // Last Homestead block - {1920000, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // First DAO block - {2462999, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // Last DAO block - {2463000, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // First Tangerine block - {2674999, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // Last Tangerine block - {2675000, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // First Spurious block - {4369999, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // Last Spurious block - {4370000, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // First Byzantium block - {7279999, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // Last Byzantium block - {7280000, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // First and last Constantinople, first Petersburg block - {9068999, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // Last Petersburg block - {9069000, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // First Istanbul and first Muir Glacier block - {9199999, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // Last Istanbul and first Muir Glacier block - {9200000, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // First Muir Glacier block - {12243999, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // Last Muir Glacier block - {12244000, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // First Berlin block - {12964999, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block - {12965000, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block - {13772999, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block - {13773000, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block - {15049999, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block - {15050000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 18000000}}, // First Gray Glacier block - {18000000, ID{Hash: checksumToBytes(0x4fb8a872), Next: 0}}, // First Merge Start block - {20000000, ID{Hash: checksumToBytes(0x4fb8a872), Next: 0}}, // Future Merge Start block - }, - }, - } - for i, tt := range tests { - for j, ttt := range tt.cases { - if have := NewID(tt.config, tt.genesis, ttt.head, 0); have != ttt.want { - t.Errorf("test %d, case %d: fork ID mismatch: have %x, want %x", i, j, have, ttt.want) - } - } - } -} + // Temporary non-existent scenario TODO(karalabe): delete when Shanghai is enabled + timestampedConfig := *params.MainnetChainConfig + timestampedConfig.ShanghaiTime = big.NewInt(1668000000) -// TestCreationWithTimestamps tests that different genesis and fork rule combinations result in -// the correct fork ID even for time based forks. -func TestCreationWithTimestamps(t *testing.T) { - mergeConfig := *params.MainnetChainConfig - mergeConfig.MergeNetsplitBlock = big.NewInt(18000000) - - withdrawalConfig := *params.MainnetChainConfig - withdrawalConfig.MergeNetsplitBlock = big.NewInt(18000000) - withdrawalConfig.ShanghaiTime = big.NewInt(1668000000) type testcase struct { head uint64 time uint64 @@ -244,40 +77,113 @@ func TestCreationWithTimestamps(t *testing.T) { {20000000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}}, // Future Gray Glacier block }, }, - // Withdrawal test cases + // Ropsten test cases + { + params.RopstenChainConfig, + params.RopstenGenesisHash, + []testcase{ + {0, 0, ID{Hash: checksumToBytes(0x30c7ddbc), Next: 10}}, // Unsynced, last Frontier, Homestead and first Tangerine block + {9, 0, ID{Hash: checksumToBytes(0x30c7ddbc), Next: 10}}, // Last Tangerine block + {10, 0, ID{Hash: checksumToBytes(0x63760190), Next: 1700000}}, // First Spurious block + {1699999, 0, ID{Hash: checksumToBytes(0x63760190), Next: 1700000}}, // Last Spurious block + {1700000, 0, ID{Hash: checksumToBytes(0x3ea159c7), Next: 4230000}}, // First Byzantium block + {4229999, 0, ID{Hash: checksumToBytes(0x3ea159c7), Next: 4230000}}, // Last Byzantium block + {4230000, 0, ID{Hash: checksumToBytes(0x97b544f3), Next: 4939394}}, // First Constantinople block + {4939393, 0, ID{Hash: checksumToBytes(0x97b544f3), Next: 4939394}}, // Last Constantinople block + {4939394, 0, ID{Hash: checksumToBytes(0xd6e2149b), Next: 6485846}}, // First Petersburg block + {6485845, 0, ID{Hash: checksumToBytes(0xd6e2149b), Next: 6485846}}, // Last Petersburg block + {6485846, 0, ID{Hash: checksumToBytes(0x4bc66396), Next: 7117117}}, // First Istanbul block + {7117116, 0, ID{Hash: checksumToBytes(0x4bc66396), Next: 7117117}}, // Last Istanbul block + {7117117, 0, ID{Hash: checksumToBytes(0x6727ef90), Next: 9812189}}, // First Muir Glacier block + {9812188, 0, ID{Hash: checksumToBytes(0x6727ef90), Next: 9812189}}, // Last Muir Glacier block + {9812189, 0, ID{Hash: checksumToBytes(0xa157d377), Next: 10499401}}, // First Berlin block + {10499400, 0, ID{Hash: checksumToBytes(0xa157d377), Next: 10499401}}, // Last Berlin block + {10499401, 0, ID{Hash: checksumToBytes(0x7119b6b3), Next: 0}}, // First London block + {11000000, 0, ID{Hash: checksumToBytes(0x7119b6b3), Next: 0}}, // Future London block + }, + }, + // Rinkeby test cases + { + params.RinkebyChainConfig, + params.RinkebyGenesisHash, + []testcase{ + {0, 0, ID{Hash: checksumToBytes(0x3b8e0691), Next: 1}}, // Unsynced, last Frontier block + {1, 0, ID{Hash: checksumToBytes(0x60949295), Next: 2}}, // First and last Homestead block + {2, 0, ID{Hash: checksumToBytes(0x8bde40dd), Next: 3}}, // First and last Tangerine block + {3, 0, ID{Hash: checksumToBytes(0xcb3a64bb), Next: 1035301}}, // First Spurious block + {1035300, 0, ID{Hash: checksumToBytes(0xcb3a64bb), Next: 1035301}}, // Last Spurious block + {1035301, 0, ID{Hash: checksumToBytes(0x8d748b57), Next: 3660663}}, // First Byzantium block + {3660662, 0, ID{Hash: checksumToBytes(0x8d748b57), Next: 3660663}}, // Last Byzantium block + {3660663, 0, ID{Hash: checksumToBytes(0xe49cab14), Next: 4321234}}, // First Constantinople block + {4321233, 0, ID{Hash: checksumToBytes(0xe49cab14), Next: 4321234}}, // Last Constantinople block + {4321234, 0, ID{Hash: checksumToBytes(0xafec6b27), Next: 5435345}}, // First Petersburg block + {5435344, 0, ID{Hash: checksumToBytes(0xafec6b27), Next: 5435345}}, // Last Petersburg block + {5435345, 0, ID{Hash: checksumToBytes(0xcbdb8838), Next: 8290928}}, // First Istanbul block + {8290927, 0, ID{Hash: checksumToBytes(0xcbdb8838), Next: 8290928}}, // Last Istanbul block + {8290928, 0, ID{Hash: checksumToBytes(0x6910c8bd), Next: 8897988}}, // First Berlin block + {8897987, 0, ID{Hash: checksumToBytes(0x6910c8bd), Next: 8897988}}, // Last Berlin block + {8897988, 0, ID{Hash: checksumToBytes(0x8E29F2F3), Next: 0}}, // First London block + {10000000, 0, ID{Hash: checksumToBytes(0x8E29F2F3), Next: 0}}, // Future London block + }, + }, + // Goerli test cases { - &withdrawalConfig, + params.GoerliChainConfig, + params.GoerliGenesisHash, + []testcase{ + {0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block + {1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block + {1561651, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block + {4460643, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block + {4460644, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block + {5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block + {5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 0}}, // First London block + {6000000, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 0}}, // Future London block + }, + }, + // Sepolia test cases + { + params.SepoliaChainConfig, + params.SepoliaGenesisHash, + []testcase{ + {0, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin and first London block + {1735370, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Last London block + {1735371, 0, ID{Hash: checksumToBytes(0xb96cbd13), Next: 0}}, // First MergeNetsplit block + }, + }, + // Temporary timestamped test cases + { + ×tampedConfig, params.MainnetGenesisHash, []testcase{ - {0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced - {1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block - {1150000, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // First Homestead block - {1919999, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // Last Homestead block - {1920000, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // First DAO block - {2462999, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // Last DAO block - {2463000, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // First Tangerine block - {2674999, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // Last Tangerine block - {2675000, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // First Spurious block - {4369999, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // Last Spurious block - {4370000, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // First Byzantium block - {7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // Last Byzantium block - {7280000, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // First and last Constantinople, first Petersburg block - {9068999, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // Last Petersburg block - {9069000, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // First Istanbul and first Muir Glacier block - {9199999, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // Last Istanbul and first Muir Glacier block - {9200000, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // First Muir Glacier block - {12243999, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // Last Muir Glacier block - {12244000, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // First Berlin block - {12964999, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block - {12965000, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block - {13772999, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block - {13773000, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block - {15049999, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block - {15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 18000000}}, // First Gray Glacier block - {18000000, 0, ID{Hash: checksumToBytes(0x4fb8a872), Next: 1668000000}}, // First Merge Start block - {20000000, 0, ID{Hash: checksumToBytes(0x4fb8a872), Next: 1668000000}}, // Last Merge Start block - {20000000, 1668000000, ID{Hash: checksumToBytes(0xc1fdf181), Next: 0}}, // First Merge Start block - {20000000, 2668000000, ID{Hash: checksumToBytes(0xc1fdf181), Next: 0}}, // Future Merge Start block + {0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced + {1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block + {1150000, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // First Homestead block + {1919999, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // Last Homestead block + {1920000, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // First DAO block + {2462999, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // Last DAO block + {2463000, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // First Tangerine block + {2674999, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // Last Tangerine block + {2675000, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // First Spurious block + {4369999, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // Last Spurious block + {4370000, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // First Byzantium block + {7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // Last Byzantium block + {7280000, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // First and last Constantinople, first Petersburg block + {9068999, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // Last Petersburg block + {9069000, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // First Istanbul and first Muir Glacier block + {9199999, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // Last Istanbul and first Muir Glacier block + {9200000, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // First Muir Glacier block + {12243999, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // Last Muir Glacier block + {12244000, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // First Berlin block + {12964999, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block + {12965000, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block + {13772999, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block + {13773000, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block + {15049999, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block + {15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1668000000}}, // First Gray Glacier block + {19999999, 1667999999, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1668000000}}, // Last Gray Glacier block + {20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}}, // First Shanghai block + {20000000, 2668000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}}, // Future Shanghai block }, }, } @@ -293,165 +199,244 @@ func TestCreationWithTimestamps(t *testing.T) { // TestValidation tests that a local peer correctly validates and accepts a remote // fork ID. func TestValidation(t *testing.T) { + // Temporary non-existent scenario TODO(karalabe): delete when Shanghai is enabled + timestampedConfig := *params.MainnetChainConfig + timestampedConfig.ShanghaiTime = big.NewInt(1668000000) + tests := []struct { - head uint64 - id ID - err error + config *params.ChainConfig + head uint64 + time uint64 + id ID + err error }{ - // Local is mainnet Petersburg, remote announces the same. No future fork is announced. - {7987396, ID{Hash: checksumToBytes(0x668db0af), Next: 0}, nil}, + //------------------ + // Block based tests + //------------------ + + // Local is mainnet Gray Glacier, remote announces the same. No future fork is announced. + {params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, nil}, - // Local is mainnet Petersburg, remote announces the same. Remote also announces a next fork + // Local is mainnet Gray Glacier, remote announces the same. Remote also announces a next fork // at block 0xffffffff, but that is uncertain. - {7987396, ID{Hash: checksumToBytes(0x668db0af), Next: math.MaxUint64}, nil}, + {params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: math.MaxUint64}, nil}, // Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote announces // also Byzantium, but it's not yet aware of Petersburg (e.g. non updated node before the fork). // In this case we don't know if Petersburg passed yet or not. - {7279999, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, + {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, // Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote announces // also Byzantium, and it's also aware of Petersburg (e.g. updated node before the fork). We // don't know if Petersburg passed yet (will pass) or not. - {7279999, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, // Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote announces // also Byzantium, and it's also aware of some random fork (e.g. misconfigured Petersburg). As // neither forks passed at neither nodes, they may mismatch, but we still connect for now. - {7279999, ID{Hash: checksumToBytes(0xa00bc324), Next: math.MaxUint64}, nil}, + {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: math.MaxUint64}, nil}, // Local is mainnet exactly on Petersburg, remote announces Byzantium + knowledge about Petersburg. Remote // is simply out of sync, accept. - {7280000, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + {params.MainnetChainConfig, 7280000, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, // Local is mainnet Petersburg, remote announces Byzantium + knowledge about Petersburg. Remote // is simply out of sync, accept. - {7987396, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + {params.MainnetChainConfig, 7987396, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, // Local is mainnet Petersburg, remote announces Spurious + knowledge about Byzantium. Remote // is definitely out of sync. It may or may not need the Petersburg update, we don't know yet. - {7987396, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, + {params.MainnetChainConfig, 7987396, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, // Local is mainnet Byzantium, remote announces Petersburg. Local is out of sync, accept. - {7279999, ID{Hash: checksumToBytes(0x668db0af), Next: 0}, nil}, + {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 0}, nil}, // Local is mainnet Spurious, remote announces Byzantium, but is not aware of Petersburg. Local // out of sync. Local also knows about a future fork, but that is uncertain yet. - {4369999, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, + {params.MainnetChainConfig, 4369999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, // Local is mainnet Petersburg. remote announces Byzantium but is not aware of further forks. // Remote needs software update. - {7987396, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, ErrRemoteStale}, + {params.MainnetChainConfig, 7987396, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, ErrRemoteStale}, // Local is mainnet Petersburg, and isn't aware of more forks. Remote announces Petersburg + // 0xffffffff. Local needs software update, reject. - {7987396, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, + {params.MainnetChainConfig, 7987396, 0, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Byzantium, and is aware of Petersburg. Remote announces Petersburg + // 0xffffffff. Local needs software update, reject. - {7279999, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, + {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Petersburg, remote is Rinkeby Petersburg. - {7987396, ID{Hash: checksumToBytes(0xafec6b27), Next: 0}, ErrLocalIncompatibleOrStale}, + {params.MainnetChainConfig, 7987396, 0, ID{Hash: checksumToBytes(0xafec6b27), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Gray Glacier, far in the future. Remote announces Gopherium (non existing fork) // at some future block 88888888, for itself, but past block for local. Local is incompatible. // // This case detects non-upgraded nodes with majority hash power (typical Ropsten mess). - {88888888, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 88888888}, ErrLocalIncompatibleOrStale}, + // + // TODO(karalabe): This testcase will fail once mainnet gets timestamped forks, make legacy chain config + {params.MainnetChainConfig, 88888888, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 88888888}, ErrLocalIncompatibleOrStale}, // Local is mainnet Byzantium. Remote is also in Byzantium, but announces Gopherium (non existing // fork) at block 7279999, before Petersburg. Local is incompatible. - {7279999, ID{Hash: checksumToBytes(0xa00bc324), Next: 7279999}, ErrLocalIncompatibleOrStale}, - } - for i, tt := range tests { - filter := newFilter(params.MainnetChainConfig, params.MainnetGenesisHash, func() (uint64, uint64) { return tt.head, 0 }) - if err := filter(tt.id); err != tt.err { - t.Errorf("test %d: validation error mismatch: have %v, want %v", i, err, tt.err) - } - } -} + // + // TODO(karalabe): This testcase will fail once mainnet gets timestamped forks, make legacy chain config + {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7279999}, ErrLocalIncompatibleOrStale}, -// TestValidationByTimestamp tests that a local peer correctly validates and accepts a remote -// fork ID. -func TestValidationByTimestamp(t *testing.T) { - withdrawalConfig := *params.MainnetChainConfig - withdrawalConfig.MergeNetsplitBlock = big.NewInt(18000000) - withdrawalConfig.ShanghaiTime = big.NewInt(1668000000) - tests := []struct { - head uint64 - time uint64 - id ID - err error - }{ - // Local is mainnet Withdrawals, remote announces the same. No future fork is announced. - {20000000, 1668000001, ID{Hash: checksumToBytes(0xc1fdf181), Next: 0}, nil}, + //------------------------------------ + // Block to timestamp transition tests + //------------------------------------ - // Local is mainnet Withdrawals, remote announces the same also announces a next fork - // at block/time 0xffffffff, but that is uncertain. - {20000000, 1668000001, ID{Hash: checksumToBytes(0xc1fdf181), Next: math.MaxUint64}, nil}, + // Local is mainnet currently in Gray Glacier only (so it's aware of Shanghai), remote announces + // also Gray Glacier, but it's not yet aware of Shanghai (e.g. non updated node before the fork). + // In this case we don't know if Shanghai passed yet or not. + {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, nil}, - // Local is mainnet currently in Byzantium only (so it's aware of Petersburg & Withdrawals), remote announces - // also Byzantium, but it's not yet aware of Petersburg (e.g. non updated node before the fork). - // In this case we don't know if Petersburg passed yet or not. - {7279999, 1667999999, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, + // Local is mainnet currently in Gray Glacier only (so it's aware of Shanghai), remote announces + // also Gray Glacier, and it's also aware of Shanghai (e.g. updated node before the fork). We + // don't know if Shanghai passed yet (will pass) or not. + {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1668000000}, nil}, - // Local is mainnet currently in Byzantium only (so it's aware of Petersburg & Withdrawals), remote announces - // also Byzantium, and it's also aware of Petersburg (e.g. updated node before the fork). We - // don't know if Petersburg passed yet (will pass) or not. - {7279999, 1667999999, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + // Local is mainnet currently in Gray Glacier only (so it's aware of Shanghai), remote announces + // also Gray Glacier, and it's also aware of some random fork (e.g. misconfigured Shanghai). As + // neither forks passed at neither nodes, they may mismatch, but we still connect for now. + {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: math.MaxUint64}, nil}, - // Local is mainnet currently in Byzantium only (so it's aware of Petersburg & Withdrawals), remote announces - // also Byzantium, and it's also aware of some random fork (e.g. misconfigured Petersburg). As + // Local is mainnet exactly on Shanghai, remote announces Gray Glacier + knowledge about Shanghai. Remote + // is simply out of sync, accept. + {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1668000000}, nil}, + + // Local is mainnet Shanghai, remote announces Gray Glacier + knowledge about Shanghai. Remote + // is simply out of sync, accept. + {×tampedConfig, 20123456, 1668123456, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1668000000}, nil}, + + // Local is mainnet Shanghai, remote announces Arrow Glacier + knowledge about Gray Glacier. Remote + // is definitely out of sync. It may or may not need the Shanghai update, we don't know yet. + {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}, nil}, + + // Local is mainnet Gray Glacier, remote announces Shanghai. Local is out of sync, accept. + {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(0x71147644), Next: 0}, nil}, + + // Local is mainnet Arrow Glacier, remote announces Gray Glacier, but is not aware of Shanghai. Local + // out of sync. Local also knows about a future fork, but that is uncertain yet. + {×tampedConfig, 13773000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, nil}, + + // Local is mainnet Shanghai. remote announces Gray Glacier but is not aware of further forks. + // Remote needs software update. + {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, ErrRemoteStale}, + + // Local is mainnet Gray Glacier, and isn't aware of more forks. Remote announces Gray Glacier + + // 0xffffffff. Local needs software update, reject. + {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(checksumUpdate(0xf0afd0e3, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, + + // Local is mainnet Gray Glacier, and is aware of Shanghai. Remote announces Shanghai + + // 0xffffffff. Local needs software update, reject. + {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(checksumUpdate(0x71147644, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, + + // Local is mainnet Gray Glacier, far in the future. Remote announces Gopherium (non existing fork) + // at some future timestamp 8888888888, for itself, but past block for local. Local is incompatible. + // + // This case detects non-upgraded nodes with majority hash power (typical Ropsten mess). + {params.MainnetChainConfig, 888888888, 1660000000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1660000000}, ErrLocalIncompatibleOrStale}, + + // Local is mainnet Gray Glacier. Remote is also in Gray Glacier, but announces Gopherium (non existing + // fork) at block 7279999, before Shanghai. Local is incompatible. + {×tampedConfig, 19999999, 1667999999, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1667999999}, ErrLocalIncompatibleOrStale}, + + //---------------------- + // Timestamp based tests + //---------------------- + + // Local is mainnet Shanghai, remote announces the same. No future fork is announced. + {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}, nil}, + + // Local is mainnet Shanghai, remote announces the same. Remote also announces a next fork + // at time 0xffffffff, but that is uncertain. + {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: math.MaxUint64}, nil}, + + // Local is mainnet currently in Shanghai only (so it's aware of Cancun), remote announces + // also Shanghai, but it's not yet aware of Cancun (e.g. non updated node before the fork). + // In this case we don't know if Cancun passed yet or not. + // + // TODO(karalabe): Enable this when Cancun is specced + //{×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}, nil}, + + // Local is mainnet currently in Shanghai only (so it's aware of Cancun), remote announces + // also Shanghai, and it's also aware of Cancun (e.g. updated node before the fork). We + // don't know if Cancun passed yet (will pass) or not. + // + // TODO(karalabe): Enable this when Cancun is specced and update next timestamp + //{×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, nil}, + + // Local is mainnet currently in Shanghai only (so it's aware of Cancun), remote announces + // also Shanghai, and it's also aware of some random fork (e.g. misconfigured Cancun). As // neither forks passed at neither nodes, they may mismatch, but we still connect for now. - {7279999, 1667999999, ID{Hash: checksumToBytes(0xa00bc324), Next: math.MaxUint64}, nil}, + // + // TODO(karalabe): Enable this when Cancun is specced + //{×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: math.MaxUint64}, nil}, - // Local is mainnet exactly on Withdrawals, remote announces Byzantium + knowledge about Petersburg. Remote + // Local is mainnet exactly on Cancun, remote announces Shanghai + knowledge about Cancun. Remote // is simply out of sync, accept. - {20000000, 1668000000, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + // + // TODO(karalabe): Enable this when Cancun is specced, update local head and time, next timestamp + // {×tampedConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, nil}, - // Local is mainnet Withdrawals, remote announces Byzantium + knowledge about Petersburg. Remote + // Local is mainnet Cancun, remote announces Shanghai + knowledge about Cancun. Remote // is simply out of sync, accept. - {20000000, 1668000001, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + // TODO(karalabe): Enable this when Cancun is specced, update local head and time, next timestamp + //{×tampedConfig, 21123456, 1678123456, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, nil}, - // Local is mainnet Withdrawals, remote announces Spurious + knowledge about Byzantium. Remote - // is definitely out of sync. It may or may not need the Petersburg update, we don't know yet. - {20000000, 1668000001, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, + // Local is mainnet Osaka, remote announces Shanghai + knowledge about Cancun. Remote + // is definitely out of sync. It may or may not need the Osaka update, we don't know yet. + // + // TODO(karalabe): Enable this when Cancun **and** Osaka is specced, update all the numbers + //{×tampedConfig, 0, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, - // Local is mainnet Byzantium & pre-withdrawals, remote announces Petersburg. Local is out of sync, accept. - {7279999, 1667999999, ID{Hash: checksumToBytes(0x668db0af), Next: 0}, nil}, + // Local is mainnet Shanghai, remote announces Cancun. Local is out of sync, accept. + // + // TODO(karalabe): Enable this when Cancun is specced, update remote checksum + //{×tampedConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x00000000), Next: 0}, nil}, - // Local is mainnet Spurious, remote announces Byzantium, but is not aware of Petersburg. Local + // Local is mainnet Shanghai, remote announces Cancun, but is not aware of Osaka. Local // out of sync. Local also knows about a future fork, but that is uncertain yet. - {4369999, 1667999999, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, + // + // TODO(karalabe): Enable this when Cancun **and** Osaka is specced, update remote checksum + //{×tampedConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x00000000), Next: 0}, nil}, - // Local is mainnet Withdrawals. remote announces Byzantium but is not aware of further forks. + // Local is mainnet Cancun. remote announces Shanghai but is not aware of further forks. // Remote needs software update. - {20000000, 1668000001, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, ErrRemoteStale}, + // + // TODO(karalabe): Enable this when Cancun is specced, update local head and time + //{×tampedConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}, ErrRemoteStale}, - // Local is mainnet Withdrawals, and isn't aware of more forks. Remote announces Petersburg + + // Local is mainnet Shanghai, and isn't aware of more forks. Remote announces Shanghai + // 0xffffffff. Local needs software update, reject. - {20000000, 1668000001, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, + {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(checksumUpdate(0x71147644, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, - // Local is mainnet Withdrawals, and is aware of Petersburg. Remote announces Petersburg + + // Local is mainnet Shanghai, and is aware of Cancun. Remote announces Cancun + // 0xffffffff. Local needs software update, reject. - {20000000, 1668000001, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, + // + // TODO(karalabe): Enable this when Cancun is specced, update remote checksum + //{×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(checksumUpdate(0x00000000, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, - // Local is mainnet Withdrawals, remote is Rinkeby Petersburg. - {20000000, 1668000001, ID{Hash: checksumToBytes(0xafec6b27), Next: 0}, ErrLocalIncompatibleOrStale}, + // Local is mainnet Shanghai, remote is random Shanghai. + {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x12345678), Next: 0}, ErrLocalIncompatibleOrStale}, - // Local is mainnet Withdrawals, far in the future. Remote announces Gopherium (non existing fork) - // at some future block 88888888, for itself, but past block for local. Local is incompatible. + // Local is mainnet Shanghai, far in the future. Remote announces Gopherium (non existing fork) + // at some future timestamp 8888888888, for itself, but past block for local. Local is incompatible. // // This case detects non-upgraded nodes with majority hash power (typical Ropsten mess). - {88888888, 1668000001, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 88888888}, ErrRemoteStale}, + {×tampedConfig, 88888888, 8888888888, ID{Hash: checksumToBytes(0x71147644), Next: 8888888888}, ErrLocalIncompatibleOrStale}, - // Local is mainnet Withdrawals. Remote is in Byzantium, but announces Gopherium (non existing - // fork) at block 7279999, before Petersburg. Local is incompatible. - {20000000, 1668000001, ID{Hash: checksumToBytes(0xa00bc324), Next: 7279999}, ErrRemoteStale}, + // Local is mainnet Shanghai. Remote is also in Shanghai, but announces Gopherium (non existing + // fork) at timestamp 1668000000, before Cancun. Local is incompatible. + // + // TODO(karalabe): Enable this when Cancun is specced + //{params.MainnetChainConfig, 20999999, 1677999999, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, ErrLocalIncompatibleOrStale}, } for i, tt := range tests { - filter := newFilter(&withdrawalConfig, params.MainnetGenesisHash, func() (uint64, uint64) { return tt.head, tt.time }) + filter := newFilter(tt.config, params.MainnetGenesisHash, func() (uint64, uint64) { return tt.head, tt.time }) if err := filter(tt.id); err != tt.err { t.Errorf("test %d: validation error mismatch: have %v, want %v", i, err, tt.err) } diff --git a/core/headerchain.go b/core/headerchain.go index ba8f550a8c86..b76af1345ce4 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -584,10 +584,10 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat origin = true ) done := func(header *types.Header) bool { - if headBlock != 0 || headTime == 0 { - return header.Number.Uint64() <= headBlock + if headTime > 0 { + return header.Time <= headTime } - return header.Time <= headTime + return header.Number.Uint64() <= headBlock } for hdr := hc.CurrentHeader(); hdr != nil && !done(hdr); hdr = hc.CurrentHeader() { num := hdr.Number.Uint64() @@ -611,7 +611,7 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat newHead, force := updateFn(markerBatch, parent) if force && ((headTime > 0 && newHead.Time < headTime) || (headTime == 0 && newHead.Number.Uint64() < headBlock)) { log.Warn("Force rewinding till ancient limit", "head", newHead.Number.Uint64()) - headBlock, headTime = newHead.Number.Uint64(), 0 + headBlock, headTime = newHead.Number.Uint64(), 0 // Target timestamp passed, continue rewind in block mode (cleaner) } } // Update head header then. diff --git a/eth/handler.go b/eth/handler.go index c67a62b86700..078133f059f2 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -331,7 +331,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { number = head.Number.Uint64() td = h.chain.GetTd(hash, number) ) - forkID := forkid.NewID(h.chain.Config(), h.chain.Genesis().Hash(), h.chain.CurrentHeader().Number.Uint64(), h.chain.CurrentHeader().Time) + forkID := forkid.NewID(h.chain.Config(), genesis.Hash(), number, head.Time) if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter); err != nil { peer.Log().Debug("Ethereum handshake failed", "err", err) return err diff --git a/eth/protocols/eth/discovery.go b/eth/protocols/eth/discovery.go index 345c6e5e2768..87857244b589 100644 --- a/eth/protocols/eth/discovery.go +++ b/eth/protocols/eth/discovery.go @@ -59,7 +59,8 @@ func StartENRUpdater(chain *core.BlockChain, ln *enode.LocalNode) { // currentENREntry constructs an `eth` ENR entry based on the current state of the chain. func currentENREntry(chain *core.BlockChain) *enrEntry { + head := chain.CurrentHeader() return &enrEntry{ - ForkID: forkid.NewID(chain.Config(), chain.Genesis().Hash(), chain.CurrentHeader().Number.Uint64(), chain.CurrentHeader().Time), + ForkID: forkid.NewID(chain.Config(), chain.Genesis().Hash(), head.Number.Uint64(), head.Time), } } diff --git a/les/server_handler.go b/les/server_handler.go index b9fb1d19bfc2..2ea496ac2c3a 100644 --- a/les/server_handler.go +++ b/les/server_handler.go @@ -117,7 +117,7 @@ func (h *serverHandler) handle(p *clientPeer) error { hash = head.Hash() number = head.Number.Uint64() td = h.blockchain.GetTd(hash, number) - forkID = forkid.NewID(h.blockchain.Config(), h.blockchain.Genesis().Hash(), h.blockchain.CurrentBlock().NumberU64(), h.blockchain.CurrentBlock().Time()) + forkID = forkid.NewID(h.blockchain.Config(), h.blockchain.Genesis().Hash(), number, head.Time) ) if err := p.Handshake(td, hash, number, h.blockchain.Genesis().Hash(), forkID, h.forkFilter, h.server); err != nil { p.Log().Debug("Light Ethereum handshake failed", "err", err) From b56c7962202a7e93bf9bf0d90434346ed00f980f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 6 Jan 2023 15:07:38 +0200 Subject: [PATCH 449/715] cmd, core, eth, els, params: disallow setheads below genesis, tweaks --- cmd/geth/config.go | 9 +- cmd/geth/main.go | 3 +- cmd/utils/flags.go | 11 +-- core/genesis.go | 11 +-- core/headerchain.go | 13 +++ eth/backend.go | 7 +- eth/ethconfig/config.go | 7 +- eth/ethconfig/gen_config.go | 184 +++++++++++++++++------------------- les/client.go | 7 +- params/config.go | 52 +++++----- 10 files changed, 147 insertions(+), 157 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index e61de4b21efb..9c6fd9baae2e 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -158,14 +158,9 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // makeFullNode loads geth configuration and creates the Ethereum backend. func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { stack, cfg := makeConfigNode(ctx) - if ctx.IsSet(utils.OverrideTerminalTotalDifficulty.Name) { - cfg.Eth.OverrideTerminalTotalDifficulty = flags.GlobalBig(ctx, utils.OverrideTerminalTotalDifficulty.Name) + if ctx.IsSet(utils.OverrideShanghai.Name) { + cfg.Eth.OverrideShanghai = flags.GlobalBig(ctx, utils.OverrideShanghai.Name) } - if ctx.IsSet(utils.OverrideTerminalTotalDifficultyPassed.Name) { - override := ctx.Bool(utils.OverrideTerminalTotalDifficultyPassed.Name) - cfg.Eth.OverrideTerminalTotalDifficultyPassed = &override - } - backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Configure log filter RPC API. diff --git a/cmd/geth/main.go b/cmd/geth/main.go index bf7097b02cf2..c6fe66cb6a29 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -64,8 +64,7 @@ var ( utils.NoUSBFlag, utils.USBFlag, utils.SmartCardDaemonPathFlag, - utils.OverrideTerminalTotalDifficulty, - utils.OverrideTerminalTotalDifficultyPassed, + utils.OverrideShanghai, utils.EthashCacheDirFlag, utils.EthashCachesInMemoryFlag, utils.EthashCachesOnDiskFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index cb7ff910d0bd..20822f25e926 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -271,14 +271,9 @@ var ( Value: 2048, Category: flags.EthCategory, } - OverrideTerminalTotalDifficulty = &flags.BigFlag{ - Name: "override.terminaltotaldifficulty", - Usage: "Manually specify TerminalTotalDifficulty, overriding the bundled setting", - Category: flags.EthCategory, - } - OverrideTerminalTotalDifficultyPassed = &cli.BoolFlag{ - Name: "override.terminaltotaldifficultypassed", - Usage: "Manually specify TerminalTotalDifficultyPassed, overriding the bundled setting", + OverrideShanghai = &flags.BigFlag{ + Name: "override.shanghai", + Usage: "Manually specify the Shanghai fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } // Light server and client settings diff --git a/core/genesis.go b/core/genesis.go index e1d7778bbb86..c3c2381eeb4d 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -269,8 +269,7 @@ func (e *GenesisMismatchError) Error() string { // ChainOverrides contains the changes to chain config. type ChainOverrides struct { - OverrideTerminalTotalDifficulty *big.Int - OverrideTerminalTotalDifficultyPassed *bool + OverrideShanghai *big.Int } // SetupGenesisBlock writes or updates the genesis block in db. @@ -296,15 +295,11 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen } applyOverrides := func(config *params.ChainConfig) { if config != nil { - if overrides != nil && overrides.OverrideTerminalTotalDifficulty != nil { - config.TerminalTotalDifficulty = overrides.OverrideTerminalTotalDifficulty - } - if overrides != nil && overrides.OverrideTerminalTotalDifficultyPassed != nil { - config.TerminalTotalDifficultyPassed = *overrides.OverrideTerminalTotalDifficultyPassed + if overrides != nil && overrides.OverrideShanghai != nil { + config.ShanghaiTime = overrides.OverrideShanghai } } } - // Just commit the new block if there is no stored genesis block. stored := rawdb.ReadCanonicalHash(db, 0) if (stored == common.Hash{}) { diff --git a/core/headerchain.go b/core/headerchain.go index b76af1345ce4..d40d26f72bf7 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -578,6 +578,19 @@ func (hc *HeaderChain) SetHeadWithTimestamp(time uint64, updateFn UpdateHeadBloc // setHead rewinds the local chain to a new head block or a head timestamp. // Everything above the new head will be deleted and the new one set. func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn UpdateHeadBlocksCallback, delFn DeleteBlockContentCallback) { + // Sanity check that there's no attempt to undo the genesis block. This is + // a fairly synthetic case where someone enables a timestamp based fork + // below the genesis timestamp. It's nice to not allow that instead of the + // entire chain getting deleted. + if headTime > 0 && hc.genesisHeader.Time > headTime { + // Note, a critical error is quite brutal, but we should really not reach + // this point. Since pre-timestamp based forks it was impossible to have + // a fork before block 0, the setHead would always work. With timestamp + // forks it becomes possible to specify below the genesis. That said, the + // only time we setHead via timestamp is with chain config changes on the + // startup, so failing hard there is ok. + log.Crit("Rejecting genesis rewind via timestamp", "target", headTime, "genesis", hc.genesisHeader.Time) + } var ( parentHash common.Hash batch = hc.chainDb.NewBatch() diff --git a/eth/backend.go b/eth/backend.go index ab2aaf7b6b12..6b1c04468922 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -195,11 +195,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { ) // Override the chain config with provided settings. var overrides core.ChainOverrides - if config.OverrideTerminalTotalDifficulty != nil { - overrides.OverrideTerminalTotalDifficulty = config.OverrideTerminalTotalDifficulty - } - if config.OverrideTerminalTotalDifficultyPassed != nil { - overrides.OverrideTerminalTotalDifficultyPassed = config.OverrideTerminalTotalDifficultyPassed + if config.OverrideShanghai != nil { + overrides.OverrideShanghai = config.OverrideShanghai } eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) if err != nil { diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 75606339323a..04ef21f49df9 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -206,11 +206,8 @@ type Config struct { // CheckpointOracle is the configuration for checkpoint oracle. CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - // OverrideTerminalTotalDifficulty (TODO: remove after the fork) - OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` - - // OverrideTerminalTotalDifficultyPassed (TODO: remove after the fork) - OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` + // OverrideShanghai (TODO: remove after the fork) + OverrideShanghai *big.Int `toml:",omitempty"` } // CreateConsensusEngine creates a consensus engine for the given chain configuration. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 514facde0a8b..3506d39d5b54 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -19,50 +19,49 @@ import ( // MarshalTOML marshals as TOML. func (c Config) MarshalTOML() (interface{}, error) { type Config struct { - Genesis *core.Genesis `toml:",omitempty"` - NetworkId uint64 - SyncMode downloader.SyncMode - EthDiscoveryURLs []string - SnapDiscoveryURLs []string - NoPruning bool - NoPrefetch bool - TxLookupLimit uint64 `toml:",omitempty"` - RequiredBlocks map[uint64]common.Hash `toml:"-"` - LightServ int `toml:",omitempty"` - LightIngress int `toml:",omitempty"` - LightEgress int `toml:",omitempty"` - LightPeers int `toml:",omitempty"` - LightNoPrune bool `toml:",omitempty"` - LightNoSyncServe bool `toml:",omitempty"` - SyncFromCheckpoint bool `toml:",omitempty"` - UltraLightServers []string `toml:",omitempty"` - UltraLightFraction int `toml:",omitempty"` - UltraLightOnlyAnnounce bool `toml:",omitempty"` - SkipBcVersionCheck bool `toml:"-"` - DatabaseHandles int `toml:"-"` - DatabaseCache int - DatabaseFreezer string - TrieCleanCache int - TrieCleanCacheJournal string `toml:",omitempty"` - TrieCleanCacheRejournal time.Duration `toml:",omitempty"` - TrieDirtyCache int - TrieTimeout time.Duration - SnapshotCache int - Preimages bool - FilterLogCacheSize int - Miner miner.Config - Ethash ethash.Config - TxPool txpool.Config - GPO gasprice.Config - EnablePreimageRecording bool - DocRoot string `toml:"-"` - RPCGasCap uint64 - RPCEVMTimeout time.Duration - RPCTxFeeCap float64 - Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` - CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` - OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` + Genesis *core.Genesis `toml:",omitempty"` + NetworkId uint64 + SyncMode downloader.SyncMode + EthDiscoveryURLs []string + SnapDiscoveryURLs []string + NoPruning bool + NoPrefetch bool + TxLookupLimit uint64 `toml:",omitempty"` + RequiredBlocks map[uint64]common.Hash `toml:"-"` + LightServ int `toml:",omitempty"` + LightIngress int `toml:",omitempty"` + LightEgress int `toml:",omitempty"` + LightPeers int `toml:",omitempty"` + LightNoPrune bool `toml:",omitempty"` + LightNoSyncServe bool `toml:",omitempty"` + SyncFromCheckpoint bool `toml:",omitempty"` + UltraLightServers []string `toml:",omitempty"` + UltraLightFraction int `toml:",omitempty"` + UltraLightOnlyAnnounce bool `toml:",omitempty"` + SkipBcVersionCheck bool `toml:"-"` + DatabaseHandles int `toml:"-"` + DatabaseCache int + DatabaseFreezer string + TrieCleanCache int + TrieCleanCacheJournal string `toml:",omitempty"` + TrieCleanCacheRejournal time.Duration `toml:",omitempty"` + TrieDirtyCache int + TrieTimeout time.Duration + SnapshotCache int + Preimages bool + FilterLogCacheSize int + Miner miner.Config + Ethash ethash.Config + TxPool txpool.Config + GPO gasprice.Config + EnablePreimageRecording bool + DocRoot string `toml:"-"` + RPCGasCap uint64 + RPCEVMTimeout time.Duration + RPCTxFeeCap float64 + Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` + CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` + OverrideShanghai *big.Int `toml:",omitempty"` } var enc Config enc.Genesis = c.Genesis @@ -107,58 +106,56 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.RPCTxFeeCap = c.RPCTxFeeCap enc.Checkpoint = c.Checkpoint enc.CheckpointOracle = c.CheckpointOracle - enc.OverrideTerminalTotalDifficulty = c.OverrideTerminalTotalDifficulty - enc.OverrideTerminalTotalDifficultyPassed = c.OverrideTerminalTotalDifficultyPassed + enc.OverrideShanghai = c.OverrideShanghai return &enc, nil } // UnmarshalTOML unmarshals from TOML. func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { type Config struct { - Genesis *core.Genesis `toml:",omitempty"` - NetworkId *uint64 - SyncMode *downloader.SyncMode - EthDiscoveryURLs []string - SnapDiscoveryURLs []string - NoPruning *bool - NoPrefetch *bool - TxLookupLimit *uint64 `toml:",omitempty"` - RequiredBlocks map[uint64]common.Hash `toml:"-"` - LightServ *int `toml:",omitempty"` - LightIngress *int `toml:",omitempty"` - LightEgress *int `toml:",omitempty"` - LightPeers *int `toml:",omitempty"` - LightNoPrune *bool `toml:",omitempty"` - LightNoSyncServe *bool `toml:",omitempty"` - SyncFromCheckpoint *bool `toml:",omitempty"` - UltraLightServers []string `toml:",omitempty"` - UltraLightFraction *int `toml:",omitempty"` - UltraLightOnlyAnnounce *bool `toml:",omitempty"` - SkipBcVersionCheck *bool `toml:"-"` - DatabaseHandles *int `toml:"-"` - DatabaseCache *int - DatabaseFreezer *string - TrieCleanCache *int - TrieCleanCacheJournal *string `toml:",omitempty"` - TrieCleanCacheRejournal *time.Duration `toml:",omitempty"` - TrieDirtyCache *int - TrieTimeout *time.Duration - SnapshotCache *int - Preimages *bool - FilterLogCacheSize *int - Miner *miner.Config - Ethash *ethash.Config - TxPool *txpool.Config - GPO *gasprice.Config - EnablePreimageRecording *bool - DocRoot *string `toml:"-"` - RPCGasCap *uint64 - RPCEVMTimeout *time.Duration - RPCTxFeeCap *float64 - Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` - CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` - OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` + Genesis *core.Genesis `toml:",omitempty"` + NetworkId *uint64 + SyncMode *downloader.SyncMode + EthDiscoveryURLs []string + SnapDiscoveryURLs []string + NoPruning *bool + NoPrefetch *bool + TxLookupLimit *uint64 `toml:",omitempty"` + RequiredBlocks map[uint64]common.Hash `toml:"-"` + LightServ *int `toml:",omitempty"` + LightIngress *int `toml:",omitempty"` + LightEgress *int `toml:",omitempty"` + LightPeers *int `toml:",omitempty"` + LightNoPrune *bool `toml:",omitempty"` + LightNoSyncServe *bool `toml:",omitempty"` + SyncFromCheckpoint *bool `toml:",omitempty"` + UltraLightServers []string `toml:",omitempty"` + UltraLightFraction *int `toml:",omitempty"` + UltraLightOnlyAnnounce *bool `toml:",omitempty"` + SkipBcVersionCheck *bool `toml:"-"` + DatabaseHandles *int `toml:"-"` + DatabaseCache *int + DatabaseFreezer *string + TrieCleanCache *int + TrieCleanCacheJournal *string `toml:",omitempty"` + TrieCleanCacheRejournal *time.Duration `toml:",omitempty"` + TrieDirtyCache *int + TrieTimeout *time.Duration + SnapshotCache *int + Preimages *bool + FilterLogCacheSize *int + Miner *miner.Config + Ethash *ethash.Config + TxPool *txpool.Config + GPO *gasprice.Config + EnablePreimageRecording *bool + DocRoot *string `toml:"-"` + RPCGasCap *uint64 + RPCEVMTimeout *time.Duration + RPCTxFeeCap *float64 + Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` + CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` + OverrideShanghai *big.Int `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { @@ -290,11 +287,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.CheckpointOracle != nil { c.CheckpointOracle = dec.CheckpointOracle } - if dec.OverrideTerminalTotalDifficulty != nil { - c.OverrideTerminalTotalDifficulty = dec.OverrideTerminalTotalDifficulty - } - if dec.OverrideTerminalTotalDifficultyPassed != nil { - c.OverrideTerminalTotalDifficultyPassed = dec.OverrideTerminalTotalDifficultyPassed + if dec.OverrideShanghai != nil { + c.OverrideShanghai = dec.OverrideShanghai } return nil } diff --git a/les/client.go b/les/client.go index 3c222f819196..9ac85ecdac6f 100644 --- a/les/client.go +++ b/les/client.go @@ -94,11 +94,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { return nil, err } var overrides core.ChainOverrides - if config.OverrideTerminalTotalDifficulty != nil { - overrides.OverrideTerminalTotalDifficulty = config.OverrideTerminalTotalDifficulty - } - if config.OverrideTerminalTotalDifficultyPassed != nil { - overrides.OverrideTerminalTotalDifficultyPassed = config.OverrideTerminalTotalDifficultyPassed + if config.OverrideShanghai != nil { + overrides.OverrideShanghai = config.OverrideShanghai } chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, trie.NewDatabase(chainDb), config.Genesis, &overrides) if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { diff --git a/params/config.go b/params/config.go index 215c6848a68b..e3ebffdfb047 100644 --- a/params/config.go +++ b/params/config.go @@ -445,45 +445,53 @@ func (c *ChainConfig) Description() string { // Create a list of forks with a short description of them. Forks that only // makes sense for mainnet should be optional at printing to avoid bloating // the output for testnets and private networks. - banner += "Pre-Merge hard forks:\n" - banner += fmt.Sprintf(" - Homestead: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/homestead.md)\n", c.HomesteadBlock) + banner += "Pre-Merge hard forks (block based):\n" + banner += fmt.Sprintf(" - Homestead: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/homestead.md)\n", c.HomesteadBlock) if c.DAOForkBlock != nil { - banner += fmt.Sprintf(" - DAO Fork: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/dao-fork.md)\n", c.DAOForkBlock) - } - banner += fmt.Sprintf(" - Tangerine Whistle (EIP 150): %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/tangerine-whistle.md)\n", c.EIP150Block) - banner += fmt.Sprintf(" - Spurious Dragon/1 (EIP 155): %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md)\n", c.EIP155Block) - banner += fmt.Sprintf(" - Spurious Dragon/2 (EIP 158): %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md)\n", c.EIP155Block) - banner += fmt.Sprintf(" - Byzantium: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/byzantium.md)\n", c.ByzantiumBlock) - banner += fmt.Sprintf(" - Constantinople: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/constantinople.md)\n", c.ConstantinopleBlock) - banner += fmt.Sprintf(" - Petersburg: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/petersburg.md)\n", c.PetersburgBlock) - banner += fmt.Sprintf(" - Istanbul: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/istanbul.md)\n", c.IstanbulBlock) + banner += fmt.Sprintf(" - DAO Fork: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/dao-fork.md)\n", c.DAOForkBlock) + } + banner += fmt.Sprintf(" - Tangerine Whistle (EIP 150): #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/tangerine-whistle.md)\n", c.EIP150Block) + banner += fmt.Sprintf(" - Spurious Dragon/1 (EIP 155): #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md)\n", c.EIP155Block) + banner += fmt.Sprintf(" - Spurious Dragon/2 (EIP 158): #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md)\n", c.EIP155Block) + banner += fmt.Sprintf(" - Byzantium: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/byzantium.md)\n", c.ByzantiumBlock) + banner += fmt.Sprintf(" - Constantinople: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/constantinople.md)\n", c.ConstantinopleBlock) + banner += fmt.Sprintf(" - Petersburg: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/petersburg.md)\n", c.PetersburgBlock) + banner += fmt.Sprintf(" - Istanbul: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/istanbul.md)\n", c.IstanbulBlock) if c.MuirGlacierBlock != nil { - banner += fmt.Sprintf(" - Muir Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/muir-glacier.md)\n", c.MuirGlacierBlock) + banner += fmt.Sprintf(" - Muir Glacier: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/muir-glacier.md)\n", c.MuirGlacierBlock) } - banner += fmt.Sprintf(" - Berlin: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/berlin.md)\n", c.BerlinBlock) - banner += fmt.Sprintf(" - London: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/london.md)\n", c.LondonBlock) + banner += fmt.Sprintf(" - Berlin: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/berlin.md)\n", c.BerlinBlock) + banner += fmt.Sprintf(" - London: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/london.md)\n", c.LondonBlock) if c.ArrowGlacierBlock != nil { - banner += fmt.Sprintf(" - Arrow Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/arrow-glacier.md)\n", c.ArrowGlacierBlock) + banner += fmt.Sprintf(" - Arrow Glacier: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/arrow-glacier.md)\n", c.ArrowGlacierBlock) } if c.GrayGlacierBlock != nil { - banner += fmt.Sprintf(" - Gray Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md)\n", c.GrayGlacierBlock) - } - banner += fmt.Sprintf(" - Shanghai: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", c.ShanghaiTime) - if c.CancunBlock != nil { - banner += fmt.Sprintf(" - Cancun: %-8v\n", c.CancunBlock) + banner += fmt.Sprintf(" - Gray Glacier: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md)\n", c.GrayGlacierBlock) } banner += "\n" // Add a special section for the merge as it's non-obvious if c.TerminalTotalDifficulty == nil { banner += "The Merge is not yet available for this network!\n" - banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md" + banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md\n" } else { banner += "Merge configured:\n" banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md\n" banner += fmt.Sprintf(" - Network known to be merged: %v\n", c.TerminalTotalDifficultyPassed) banner += fmt.Sprintf(" - Total terminal difficulty: %v\n", c.TerminalTotalDifficulty) - banner += fmt.Sprintf(" - Merge netsplit block: %-8v", c.MergeNetsplitBlock) + if c.MergeNetsplitBlock != nil { + banner += fmt.Sprintf(" - Merge netsplit block: #%-8v\n", c.MergeNetsplitBlock) + } + } + banner += "\n" + + // Create a list of forks post-merge + banner += "Post-Merge hard forks (timestamp based):\n" + if c.ShanghaiTime != nil { + banner += fmt.Sprintf(" - Shanghai: @%-10v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", c.ShanghaiTime) + } + if c.CancunBlock != nil { + banner += fmt.Sprintf(" - Cancun: @%-10v\n", c.CancunBlock) } return banner } From 686f7438d37db6cf1fea640df51f8f4a36b6d6c2 Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Mon, 9 Jan 2023 15:07:08 +0800 Subject: [PATCH 450/715] eth/downloader: fix unexpected skeleton header deletion --- eth/downloader/skeleton.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/eth/downloader/skeleton.go b/eth/downloader/skeleton.go index 8dcec2292b49..6fa565bd5bcc 100644 --- a/eth/downloader/skeleton.go +++ b/eth/downloader/skeleton.go @@ -977,8 +977,14 @@ func (s *skeleton) processResponse(res *headerResponse) (linked bool, merged boo // the expected new sync cycle after some propagated blocks. Log // it for debugging purposes, explicitly clean and don't escalate. case subchains == 2 && s.progress.Subchains[1].Head == s.progress.Subchains[1].Tail: - log.Debug("Cleaning previous beacon sync state", "head", s.progress.Subchains[1].Head) - rawdb.DeleteSkeletonHeader(batch, s.progress.Subchains[1].Head) + // Remove the leftover skeleton header associated with old + // skeleton chain only if it's not covered by the current + // skeleton range. + if s.progress.Subchains[1].Head < s.progress.Subchains[0].Tail { + log.Debug("Cleaning previous beacon sync state", "head", s.progress.Subchains[1].Head) + rawdb.DeleteSkeletonHeader(batch, s.progress.Subchains[1].Head) + } + // Drop the leftover skeleton chain since it's stale. s.progress.Subchains = s.progress.Subchains[:1] // If we have more than one header or more than one leftover chain, From 71f7988b0f6abc6db84e0ef6ec80766b946229f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 9 Jan 2023 12:12:25 +0200 Subject: [PATCH 451/715] eth/downloader: create repro testcase for beacon header loss --- eth/downloader/skeleton.go | 2 +- eth/downloader/skeleton_test.go | 157 ++++++++++++++++++++++++-------- 2 files changed, 120 insertions(+), 39 deletions(-) diff --git a/eth/downloader/skeleton.go b/eth/downloader/skeleton.go index 6fa565bd5bcc..15d473af263c 100644 --- a/eth/downloader/skeleton.go +++ b/eth/downloader/skeleton.go @@ -520,7 +520,7 @@ func (s *skeleton) initSync(head *types.Header) { } break } - // If the last subchain can be extended, we're lucky. Otherwise create + // If the last subchain can be extended, we're lucky. Otherwise, create // a new subchain sync task. var extended bool if n := len(s.progress.Subchains); n > 0 { diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index 41373d33a861..3b8e627cba89 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -37,7 +37,7 @@ import ( type hookedBackfiller struct { // suspendHook is an optional hook to be called when the filler is requested // to be suspended. - suspendHook func() + suspendHook func() *types.Header // resumeHook is an optional hook to be called when the filler is requested // to be resumed. @@ -56,7 +56,7 @@ func newHookedBackfiller() backfiller { // on initial startup. func (hf *hookedBackfiller) suspend() *types.Header { if hf.suspendHook != nil { - hf.suspendHook() + return hf.suspendHook() } return nil // we don't really care about header cleanups for now } @@ -525,9 +525,21 @@ func TestSkeletonSyncRetrievals(t *testing.T) { Number: big.NewInt(int64(i)), }) } + // Some tests require a forking side chain to trigger cornercases. + var sidechain []*types.Header + for i := 0; i < len(chain)/2; i++ { // Fork at block #5000 + sidechain = append(sidechain, chain[i]) + } + for i := len(chain) / 2; i < len(chain); i++ { + sidechain = append(sidechain, &types.Header{ + ParentHash: sidechain[i-1].Hash(), + Number: big.NewInt(int64(i)), + Extra: []byte("B"), // force a different hash + }) + } tests := []struct { - headers []*types.Header // Database content (beside the genesis) - oldstate []*subchain // Old sync state with various interrupted subchains + fill bool // Whether to run a real backfiller in this test case + unpredictable bool // Whether to ignore drops/serves due to uncertain packet assignments head *types.Header // New head header to announce to reorg to peers []*skeletonTestPeer // Initial peer set to start the sync with @@ -760,11 +772,41 @@ func TestSkeletonSyncRetrievals(t *testing.T) { endstate: []*subchain{{Head: 2*requestHeaders + 2, Tail: 1}}, endserve: 4 * requestHeaders, }, + // This test reproduces a bug caught by (@rjl493456442) where a skeleton + // header goes missing, causing the sync to get stuck and/or panic. + // + // The setup requires a previously successfully synced chain up to a block + // height N. That results is a single skeleton header (block N) and a single + // subchain (head N, Tail N) being stored on disk. + // + // The following step requires a new sync cycle to a new side chain of a + // height higher than N, and an ancestor lower than N (e.g. N-2, N+2). + // In this scenario, when processing a batch of headers, a link point of + // N-2 will be found, meaning that N-1 and N have been overwritten. + // + // The link event triggers an early exit, noticing that the previous sub- + // chain is a leftover and deletes it (with it's skeleton header N). But + // since skeleton header N has been overwritten to the new side chain, we + // end up losing it and creating a gap. + { + fill: true, + unpredictable: true, // We have good and bad peer too, bad may be dropped, test too short for certainty + + head: chain[len(chain)/2+1], // Sync up until the sidechain common ancestor + 2 + peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-oldchain", chain)}, + midstate: []*subchain{{Head: uint64(len(chain)/2 + 1), Tail: 1}}, + + newHead: sidechain[len(sidechain)/2+3], // Sync up until the sidechain common ancestor + 4 + newPeer: newSkeletonTestPeer("test-peer-newchain", sidechain), + endstate: []*subchain{{Head: uint64(len(sidechain)/2 + 3), Tail: uint64(len(chain) / 2)}}, + }, } for i, tt := range tests { // Create a fresh database and initialize it with the starting state db := rawdb.NewMemoryDatabase() - rawdb.WriteHeader(db, chain[0]) + + rawdb.WriteBlock(db, types.NewBlockWithHeader(chain[0])) + rawdb.WriteReceipts(db, chain[0].Hash(), chain[0].Number.Uint64(), types.Receipts{}) // Create a peer set to feed headers through peerset := newPeerSet() @@ -780,8 +822,43 @@ func TestSkeletonSyncRetrievals(t *testing.T) { peerset.Unregister(peer) dropped[peer]++ } + // Create a backfiller if we need to run more advanced tests + filler := newHookedBackfiller() + if tt.fill { + var filled *types.Header + + filler = &hookedBackfiller{ + resumeHook: func() { + var progress skeletonProgress + json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) + + for progress.Subchains[0].Tail < progress.Subchains[0].Head { + header := rawdb.ReadSkeletonHeader(db, progress.Subchains[0].Tail) + + rawdb.WriteBlock(db, types.NewBlockWithHeader(header)) + rawdb.WriteReceipts(db, header.Hash(), header.Number.Uint64(), types.Receipts{}) + + rawdb.DeleteSkeletonHeader(db, header.Number.Uint64()) + + progress.Subchains[0].Tail++ + progress.Subchains[0].Next = header.Hash() + } + filled = rawdb.ReadSkeletonHeader(db, progress.Subchains[0].Tail) + + rawdb.WriteBlock(db, types.NewBlockWithHeader(filled)) + rawdb.WriteReceipts(db, filled.Hash(), filled.Number.Uint64(), types.Receipts{}) + }, + + suspendHook: func() *types.Header { + prev := filled + filled = nil + + return prev + }, + } + } // Create a skeleton sync and run a cycle - skeleton := newSkeleton(db, peerset, drop, newHookedBackfiller()) + skeleton := newSkeleton(db, peerset, drop, filler) skeleton.Sync(tt.head, true) var progress skeletonProgress @@ -815,19 +892,21 @@ func TestSkeletonSyncRetrievals(t *testing.T) { t.Error(err) continue } - var served uint64 - for _, peer := range tt.peers { - served += atomic.LoadUint64(&peer.served) - } - if served != tt.midserve { - t.Errorf("test %d, mid state: served headers mismatch: have %d, want %d", i, served, tt.midserve) - } - var drops uint64 - for _, peer := range tt.peers { - drops += atomic.LoadUint64(&peer.dropped) - } - if drops != tt.middrop { - t.Errorf("test %d, mid state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) + if !tt.unpredictable { + var served uint64 + for _, peer := range tt.peers { + served += atomic.LoadUint64(&peer.served) + } + if served != tt.midserve { + t.Errorf("test %d, mid state: served headers mismatch: have %d, want %d", i, served, tt.midserve) + } + var drops uint64 + for _, peer := range tt.peers { + drops += atomic.LoadUint64(&peer.dropped) + } + if drops != tt.middrop { + t.Errorf("test %d, mid state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) + } } // Apply the post-init events if there's any if tt.newHead != nil { @@ -868,25 +947,27 @@ func TestSkeletonSyncRetrievals(t *testing.T) { continue } // Check that the peers served no more headers than we actually needed - served = 0 - for _, peer := range tt.peers { - served += atomic.LoadUint64(&peer.served) - } - if tt.newPeer != nil { - served += atomic.LoadUint64(&tt.newPeer.served) - } - if served != tt.endserve { - t.Errorf("test %d, end state: served headers mismatch: have %d, want %d", i, served, tt.endserve) - } - drops = 0 - for _, peer := range tt.peers { - drops += atomic.LoadUint64(&peer.dropped) - } - if tt.newPeer != nil { - drops += atomic.LoadUint64(&tt.newPeer.dropped) - } - if drops != tt.middrop { - t.Errorf("test %d, end state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) + if !tt.unpredictable { + served := uint64(0) + for _, peer := range tt.peers { + served += atomic.LoadUint64(&peer.served) + } + if tt.newPeer != nil { + served += atomic.LoadUint64(&tt.newPeer.served) + } + if served != tt.endserve { + t.Errorf("test %d, end state: served headers mismatch: have %d, want %d", i, served, tt.endserve) + } + drops := uint64(0) + for _, peer := range tt.peers { + drops += atomic.LoadUint64(&peer.dropped) + } + if tt.newPeer != nil { + drops += atomic.LoadUint64(&tt.newPeer.dropped) + } + if drops != tt.enddrop { + t.Errorf("test %d, end state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) + } } // Clean up any leftover skeleton sync resources skeleton.Terminate() From ccacb9930ea5a24a87e42708da74ec187acbac22 Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Tue, 10 Jan 2023 02:04:21 -0600 Subject: [PATCH 452/715] cmd/evm: support shanghai in tests + evm t8n (#26458) --- tests/init.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/init.go b/tests/init.go index e6faa483a68d..fd0b015086a1 100644 --- a/tests/init.go +++ b/tests/init.go @@ -248,6 +248,24 @@ var Forks = map[string]*params.ChainConfig{ MergeNetsplitBlock: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0), }, + "Shanghai": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + ShanghaiTime: big.NewInt(0), + }, } // AvailableForks returns the set of defined fork names From faff980d97ea73e8b51d388d4d92cdb86481c179 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 10 Jan 2023 00:16:17 -0800 Subject: [PATCH 453/715] crypto/bls12381: use worst case scalar for input to G1/G2 mul benchmarks (#26447) * test * crypto/bls12381: use worst case scalar for input to G1/G2 mul benchmarks --- crypto/bls12381/g1_test.go | 3 ++- crypto/bls12381/g2_test.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crypto/bls12381/g1_test.go b/crypto/bls12381/g1_test.go index eef9f4505583..87140459fbc5 100644 --- a/crypto/bls12381/g1_test.go +++ b/crypto/bls12381/g1_test.go @@ -262,8 +262,9 @@ func BenchmarkG1Add(t *testing.B) { } func BenchmarkG1Mul(t *testing.B) { + worstCaseScalar, _ := new(big.Int).SetString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16) g1 := NewG1() - a, e, c := g1.rand(), q, PointG1{} + a, e, c := g1.rand(), worstCaseScalar, PointG1{} t.ResetTimer() for i := 0; i < t.N; i++ { g1.MulScalar(&c, a, e) diff --git a/crypto/bls12381/g2_test.go b/crypto/bls12381/g2_test.go index f16f0e5eea72..4d1f3a19ac67 100644 --- a/crypto/bls12381/g2_test.go +++ b/crypto/bls12381/g2_test.go @@ -265,8 +265,9 @@ func BenchmarkG2Add(t *testing.B) { } func BenchmarkG2Mul(t *testing.B) { + worstCaseScalar, _ := new(big.Int).SetString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16) g2 := NewG2() - a, e, c := g2.rand(), q, PointG2{} + a, e, c := g2.rand(), worstCaseScalar, PointG2{} t.ResetTimer() for i := 0; i < t.N; i++ { g2.MulScalar(&c, a, e) From b8bc8c2465869ca596be3febae31cefbe5bdadf9 Mon Sep 17 00:00:00 2001 From: Joseph Cook <33655003+jmcook1186@users.noreply.github.com> Date: Tue, 10 Jan 2023 13:20:47 +0000 Subject: [PATCH 454/715] README.md: add website contribution instructions (#26442) --- README.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 59fcd4a12eb7..326437dfe02d 100644 --- a/README.md +++ b/README.md @@ -34,16 +34,16 @@ make all The go-ethereum project comes with several wrappers/executables found in the `cmd` directory. -| Command | Description | -| :-----------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI page](https://geth.ethereum.org/docs/interface/command-line-options) for command line options. | -| `clef` | Stand-alone signing tool, which can be used as a backend signer for `geth`. | -| `devp2p` | Utilities to interact with nodes on the networking layer, without running a full blockchain. | -| `abigen` | Source code generator to convert Ethereum contract definitions into easy-to-use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://docs.soliditylang.org/en/develop/abi-spec.html) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://geth.ethereum.org/docs/dapp/native-bindings) page for details. | -| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | -| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug run`). | -| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | -| `puppeth` | a CLI wizard that aids in creating a new Ethereum network. | +| Command | Description | +| :--------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI page](https://geth.ethereum.org/docs/interface/command-line-options) for command line options. | +| `clef` | Stand-alone signing tool, which can be used as a backend signer for `geth`. | +| `devp2p` | Utilities to interact with nodes on the networking layer, without running a full blockchain. | +| `abigen` | Source code generator to convert Ethereum contract definitions into easy-to-use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://docs.soliditylang.org/en/develop/abi-spec.html) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://geth.ethereum.org/docs/dapp/native-bindings) page for details. | +| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | +| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug run`). | +| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | +| `puppeth` | a CLI wizard that aids in creating a new Ethereum network. | ## Running `geth` @@ -368,6 +368,12 @@ Please see the [Developers' Guide](https://geth.ethereum.org/docs/developers/dev for more details on configuring your environment, managing project dependencies, and testing procedures. +### Contributing to geth.ethereum.org + +For contributions to the [go-ethereum website](https://geth.ethereum.org), please checkout and raise pull requests against the `website` branch. +For more detailed instructions please see the `website` branch [README](https://github.com/ethereum/go-ethereum/tree/website#readme) or the +[contributing](https://geth.ethereum.org/docs/developers/geth-developer/contributing) page of the website. + ## License The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the From 4ada314fff1c688127b7d818b4edfadcc47f33d5 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 10 Jan 2023 08:22:43 -0500 Subject: [PATCH 455/715] tests: fix DIFFICULTY error in state executor (#26465) --- tests/state_test_util.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 67605a127339..b2e87fb004b9 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -249,16 +249,13 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh context.GetHash = vmTestBlockHash context.BaseFee = baseFee context.Random = nil - if config.IsLondon(new(big.Int)) { - if t.json.Env.Random != nil { - rnd := common.BigToHash(t.json.Env.Random) - context.Random = &rnd - } + if t.json.Env.Difficulty != nil { + context.Difficulty = new(big.Int).Set(t.json.Env.Difficulty) + } + if config.IsLondon(new(big.Int)) && t.json.Env.Random != nil { + rnd := common.BigToHash(t.json.Env.Random) + context.Random = &rnd context.Difficulty = big.NewInt(0) - } else { - if t.json.Env.Difficulty != nil { - context.Difficulty = new(big.Int).Set(t.json.Env.Difficulty) - } } evm := vm.NewEVM(context, txContext, statedb, config, vmconfig) // Execute the message. From 7a489623ac09158f98c3a839cff88a14db3f039d Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 10 Jan 2023 08:24:30 -0500 Subject: [PATCH 456/715] core/state: remove notion of fake storage (#24916) This PR removes the notion of fakeStorage from the state objects, and instead, for any state modifications that are needed, it simply makes the changes. --- core/state/state_object.go | 32 ------- core/state/statedb.go | 10 ++- eth/tracers/api_test.go | 170 ++++++++++++++++++++++++++++++++++++- internal/ethapi/api.go | 4 + 4 files changed, 181 insertions(+), 35 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index bea8f17be32e..6bd6f18322e3 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -84,7 +84,6 @@ type stateObject struct { originStorage Storage // Storage cache of original entries to dedup rewrites, reset for every transaction pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block dirtyStorage Storage // Storage entries that have been modified in the current transaction execution - fakeStorage Storage // Fake storage which constructed by caller for debugging purpose. // Cache flags. // When an object is marked suicided it will be delete from the trie @@ -173,10 +172,6 @@ func (s *stateObject) getTrie(db Database) (Trie, error) { // GetState retrieves a value from the account storage trie. func (s *stateObject) GetState(db Database, key common.Hash) common.Hash { - // If the fake storage is set, only lookup the state here(in the debugging mode) - if s.fakeStorage != nil { - return s.fakeStorage[key] - } // If we have a dirty value for this state entry, return it value, dirty := s.dirtyStorage[key] if dirty { @@ -188,10 +183,6 @@ func (s *stateObject) GetState(db Database, key common.Hash) common.Hash { // GetCommittedState retrieves a value from the committed account storage trie. func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash { - // If the fake storage is set, only lookup the state here(in the debugging mode) - if s.fakeStorage != nil { - return s.fakeStorage[key] - } // If we have a pending write or clean cached, return that if value, pending := s.pendingStorage[key]; pending { return value @@ -251,11 +242,6 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has // SetState updates a value in account storage. func (s *stateObject) SetState(db Database, key, value common.Hash) { - // If the fake storage is set, put the temporary state update here. - if s.fakeStorage != nil { - s.fakeStorage[key] = value - return - } // If the new value is the same as old, don't set prev := s.GetState(db, key) if prev == value { @@ -270,24 +256,6 @@ func (s *stateObject) SetState(db Database, key, value common.Hash) { s.setState(key, value) } -// SetStorage replaces the entire state storage with the given one. -// -// After this function is called, all original state will be ignored and state -// lookup only happens in the fake state storage. -// -// Note this function should only be used for debugging purpose. -func (s *stateObject) SetStorage(storage map[common.Hash]common.Hash) { - // Allocate fake storage if it's nil. - if s.fakeStorage == nil { - s.fakeStorage = make(Storage) - } - for key, value := range storage { - s.fakeStorage[key] = value - } - // Don't bother journal since this function should only be used for - // debugging and the `fake` storage won't be committed to database. -} - func (s *stateObject) setState(key, value common.Hash) { s.dirtyStorage[key] = value } diff --git a/core/state/statedb.go b/core/state/statedb.go index fb2459ffc83c..ebbf64a01866 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -442,9 +442,15 @@ func (s *StateDB) SetState(addr common.Address, key, value common.Hash) { // SetStorage replaces the entire storage for the specified account with given // storage. This function should only be used for debugging. func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common.Hash) { + // SetStorage needs to wipe existing storage. We achieve this by pretending + // that the account self-destructed earlier in this block, by flagging + // it in stateObjectsDestruct. The effect of doing so is that storage lookups + // will not hit disk, since it is assumed that the disk-data is belonging + // to a previous incarnation of the object. + s.stateObjectsDestruct[addr] = struct{}{} stateObject := s.GetOrNewStateObject(addr) - if stateObject != nil { - stateObject.SetStorage(storage) + for k, v := range storage { + stateObject.SetState(s.db, k, v) } } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 334f23efd806..29ec80868579 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -454,12 +454,21 @@ func TestTracingWithOverrides(t *testing.T) { t.Parallel() // Initialize test accounts accounts := newAccounts(3) + storageAccount := common.Address{0x13, 37} genesis := &core.Genesis{ Config: params.TestChainConfig, Alloc: core.GenesisAlloc{ accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)}, accounts[2].addr: {Balance: big.NewInt(params.Ether)}, + // An account with existing storage + storageAccount: { + Balance: new(big.Int), + Storage: map[common.Hash]common.Hash{ + common.HexToHash("0x03"): common.HexToHash("0x33"), + common.HexToHash("0x04"): common.HexToHash("0x44"), + }, + }, }, } genBlocks := 10 @@ -579,6 +588,164 @@ func TestTracingWithOverrides(t *testing.T) { }, want: `{"gas":72666,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`, }, + /* + pragma solidity =0.8.12; + + contract Test { + uint private x; + + function test2() external { + x = 1337; + revert(); + } + + function test() external returns (uint) { + x = 1; + try this.test2() {} catch (bytes memory) {} + return x; + } + } + */ + { // First with only code override, not storage override + blockNumber: rpc.LatestBlockNumber, + call: ethapi.TransactionArgs{ + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, + Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), // + }, + config: &TraceCallConfig{ + StateOverrides: ðapi.StateOverride{ + randomAccounts[2].addr: ethapi.OverrideAccount{ + Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")), + }, + }, + }, + want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`, + }, + { // Same again, this time with storage override + blockNumber: rpc.LatestBlockNumber, + call: ethapi.TransactionArgs{ + From: &randomAccounts[0].addr, + To: &randomAccounts[2].addr, + Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), // + }, + config: &TraceCallConfig{ + StateOverrides: ðapi.StateOverride{ + randomAccounts[2].addr: ethapi.OverrideAccount{ + Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")), + State: newStates([]common.Hash{{}}, []common.Hash{{}}), + }, + }, + }, + //want: `{"gas":46900,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000539"}`, + want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`, + }, + { // No state override + blockNumber: rpc.LatestBlockNumber, + call: ethapi.TransactionArgs{ + From: &randomAccounts[0].addr, + To: &storageAccount, + Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), // + }, + config: &TraceCallConfig{ + StateOverrides: ðapi.StateOverride{ + storageAccount: ethapi.OverrideAccount{ + Code: newRPCBytes([]byte{ + // SLOAD(3) + SLOAD(4) (which is 0x77) + byte(vm.PUSH1), 0x04, + byte(vm.SLOAD), + byte(vm.PUSH1), 0x03, + byte(vm.SLOAD), + byte(vm.ADD), + // 0x77 -> MSTORE(0) + byte(vm.PUSH1), 0x00, + byte(vm.MSTORE), + // RETURN (0, 32) + byte(vm.PUSH1), 32, + byte(vm.PUSH1), 00, + byte(vm.RETURN), + }), + }, + }, + }, + want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000077"}`, + }, + { // Full state override + // The original storage is + // 3: 0x33 + // 4: 0x44 + // With a full override, where we set 3:0x11, the slot 4 should be + // removed. So SLOT(3)+SLOT(4) should be 0x11. + blockNumber: rpc.LatestBlockNumber, + call: ethapi.TransactionArgs{ + From: &randomAccounts[0].addr, + To: &storageAccount, + Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), // + }, + config: &TraceCallConfig{ + StateOverrides: ðapi.StateOverride{ + storageAccount: ethapi.OverrideAccount{ + Code: newRPCBytes([]byte{ + // SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x00) + byte(vm.PUSH1), 0x04, + byte(vm.SLOAD), + byte(vm.PUSH1), 0x03, + byte(vm.SLOAD), + byte(vm.ADD), + // 0x11 -> MSTORE(0) + byte(vm.PUSH1), 0x00, + byte(vm.MSTORE), + // RETURN (0, 32) + byte(vm.PUSH1), 32, + byte(vm.PUSH1), 00, + byte(vm.RETURN), + }), + State: newStates( + []common.Hash{common.HexToHash("0x03")}, + []common.Hash{common.HexToHash("0x11")}), + }, + }, + }, + want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000011"}`, + }, + { // Partial state override + // The original storage is + // 3: 0x33 + // 4: 0x44 + // With a partial override, where we set 3:0x11, the slot 4 as before. + // So SLOT(3)+SLOT(4) should be 0x55. + blockNumber: rpc.LatestBlockNumber, + call: ethapi.TransactionArgs{ + From: &randomAccounts[0].addr, + To: &storageAccount, + Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), // + }, + config: &TraceCallConfig{ + StateOverrides: ðapi.StateOverride{ + storageAccount: ethapi.OverrideAccount{ + Code: newRPCBytes([]byte{ + // SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x44) + byte(vm.PUSH1), 0x04, + byte(vm.SLOAD), + byte(vm.PUSH1), 0x03, + byte(vm.SLOAD), + byte(vm.ADD), + // 0x55 -> MSTORE(0) + byte(vm.PUSH1), 0x00, + byte(vm.MSTORE), + // RETURN (0, 32) + byte(vm.PUSH1), 32, + byte(vm.PUSH1), 00, + byte(vm.RETURN), + }), + StateDiff: &map[common.Hash]common.Hash{ + common.HexToHash("0x03"): common.HexToHash("0x11"), + }, + }, + }, + }, + want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000055"}`, + }, } for i, tc := range testSuite { result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config) @@ -605,7 +772,8 @@ func TestTracingWithOverrides(t *testing.T) { json.Unmarshal(resBytes, &have) json.Unmarshal([]byte(tc.want), &want) if !reflect.DeepEqual(have, want) { - t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(resBytes), want) + t.Logf("result: %v\n", string(resBytes)) + t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, have, want) } } } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 58be2f8bf80e..b6efba079a4a 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -909,6 +909,10 @@ func (diff *StateOverride) Apply(state *state.StateDB) error { } } } + // Now finalize the changes. Finalize is normally performed between transactions. + // By using finalize, the overrides are semantically behaving as + // if they were created in a transaction just before the tracing occur. + state.Finalise(false) return nil } From 2c6dda5ad7a720cccd957230f7978de0082ec8c7 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 10 Jan 2023 09:11:53 -0500 Subject: [PATCH 457/715] eth/tracers: use non-threaded tracechain (#24283) This makes non-JS tracers execute all block txs on a single goroutine. In the previous implementation, we used to prepare every tx pre-state on one goroutine, and then run the transactions again with tracing enabled. Native tracers are usually faster, so it is faster overall to use their output as the pre-state for tracing the next transaction. Co-authored-by: Sina Mahmoodi --- core/vm/runtime/runtime_test.go | 6 +- eth/tracers/api.go | 57 +++++++++++-- .../internal/tracetest/calltrace_test.go | 6 +- .../internal/tracetest/prestate_test.go | 2 +- eth/tracers/js/goja.go | 21 +++-- eth/tracers/native/4byte.go | 2 +- eth/tracers/native/call.go | 2 +- eth/tracers/native/mux.go | 4 +- eth/tracers/native/noop.go | 2 +- eth/tracers/native/prestate.go | 2 +- eth/tracers/native/tracer.go | 79 ------------------- eth/tracers/tracers.go | 67 ++++++++++------ 12 files changed, 121 insertions(+), 129 deletions(-) delete mode 100644 eth/tracers/native/tracer.go diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index ab77e284df35..868d41e50348 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -333,7 +333,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) cfg.GasLimit = gas if len(tracerCode) > 0 { - tracer, err := tracers.New(tracerCode, new(tracers.Context), nil) + tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil) if err != nil { b.Fatal(err) } @@ -832,7 +832,7 @@ func TestRuntimeJSTracer(t *testing.T) { statedb.SetCode(common.HexToAddress("0xee"), calleeCode) statedb.SetCode(common.HexToAddress("0xff"), depressedCode) - tracer, err := tracers.New(jsTracer, new(tracers.Context), nil) + tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil) if err != nil { t.Fatal(err) } @@ -868,7 +868,7 @@ func TestJSTracerCreateTx(t *testing.T) { code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)} statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - tracer, err := tracers.New(jsTracer, new(tracers.Context), nil) + tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil) if err != nil { t.Fatal(err) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 4436d13961f6..5a34d9d4a6ab 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -593,6 +593,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac if block.NumberU64() == 0 { return nil, errors.New("genesis is not traceable") } + // Prepare base state parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) if err != nil { return nil, err @@ -607,23 +608,64 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac } defer release() + // JS tracers have high overhead. In this case run a parallel + // process that generates states in one thread and traces txes + // in separate worker threads. + if config != nil && config.Tracer != nil && *config.Tracer != "" { + if isJS := DefaultDirectory.IsJS(*config.Tracer); isJS { + return api.traceBlockParallel(ctx, block, statedb, config) + } + } + // Native tracers have low overhead + var ( + txs = block.Transactions() + blockHash = block.Hash() + is158 = api.backend.ChainConfig().IsEIP158(block.Number()) + blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) + results = make([]*txTraceResult, len(txs)) + ) + for i, tx := range txs { + // Generate the next state snapshot fast without tracing + msg, _ := tx.AsMessage(signer, block.BaseFee()) + txctx := &Context{ + BlockHash: blockHash, + TxIndex: i, + TxHash: tx.Hash(), + } + res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config) + if err != nil { + return nil, err + } + results[i] = &txTraceResult{Result: res} + // Finalize the state so any modifications are written to the trie + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect + statedb.Finalise(is158) + } + return results, nil +} + +// traceBlockParallel is for tracers that have a high overhead (read JS tracers). One thread +// runs along and executes txes without tracing enabled to generate their prestate. +// Worker threads take the tasks and the prestate and trace them. +func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, statedb *state.StateDB, config *TraceConfig) ([]*txTraceResult, error) { // Execute all the transaction contained within the block concurrently var ( - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) - txs = block.Transactions() - results = make([]*txTraceResult, len(txs)) - pend sync.WaitGroup + txs = block.Transactions() + blockHash = block.Hash() + blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) + results = make([]*txTraceResult, len(txs)) + pend sync.WaitGroup ) threads := runtime.NumCPU() if threads > len(txs) { threads = len(txs) } jobs := make(chan *txTraceTask, threads) - blockHash := block.Hash() for th := 0; th < threads; th++ { pend.Add(1) go func() { - blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) defer pend.Done() // Fetch and execute the next transaction trace tasks for task := range jobs { @@ -645,7 +687,6 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac // Feed the transactions into the tracers and return var failed error - blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) txloop: for i, tx := range txs { // Send the trace task over for execution @@ -923,7 +964,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex // Default tracer is the struct logger tracer = logger.NewStructLogger(config.Config) if config.Tracer != nil { - tracer, err = New(*config.Tracer, txctx, config.TracerConfig) + tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig) if err != nil { return nil, err } diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 0827d3b40e41..5cfb5b33c1b0 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -140,7 +140,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { } _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) ) - tracer, err := tracers.New(tracerName, new(tracers.Context), test.TracerConfig) + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) } @@ -243,7 +243,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - tracer, err := tracers.New(tracerName, new(tracers.Context), nil) + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil) if err != nil { b.Fatalf("failed to create call tracer: %v", err) } @@ -309,7 +309,7 @@ func TestZeroValueToNotExitCall(t *testing.T) { } _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false) // Create the tracer, the EVM environment and run it - tracer, err := tracers.New("callTracer", nil, nil) + tracer, err := tracers.DefaultDirectory.New("callTracer", nil, nil) if err != nil { t.Fatalf("failed to create call tracer: %v", err) } diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 9227aff9453d..2fee7d6fb7ed 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -110,7 +110,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { } _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) ) - tracer, err := tracers.New(tracerName, new(tracers.Context), test.TracerConfig) + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) } diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index cf27acbb4ab2..8e52f5b21077 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -45,7 +45,16 @@ func init() { if err != nil { panic(err) } - tracers.RegisterLookup(true, newJsTracer) + type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error) + lookup := func(code string) ctorFn { + return func(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { + return newJsTracer(code, ctx, cfg) + } + } + for name, code := range assetTracers { + tracers.DefaultDirectory.Register(name, lookup(code), true) + } + tracers.DefaultDirectory.RegisterJSEval(newJsTracer) } // bigIntProgram is compiled once and the exported function mostly invoked to convert @@ -122,16 +131,14 @@ type jsTracer struct { frameResultValue goja.Value } -// newJsTracer instantiates a new JS tracer instance. code is either -// the name of a built-in JS tracer or a Javascript snippet which -// evaluates to an expression returning an object with certain methods. +// newJsTracer instantiates a new JS tracer instance. code is a +// Javascript snippet which evaluates to an expression returning +// an object with certain methods: +// // The methods `result` and `fault` are required to be present. // The methods `step`, `enter`, and `exit` are optional, but note that // `enter` and `exit` always go together. func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { - if c, ok := assetTracers[code]; ok { - code = c - } vm := goja.New() // By default field names are exported to JS as is, i.e. capitalized. vm.SetFieldNameMapper(goja.UncapFieldNameMapper()) diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index afe70ea089aa..1b4649baa33e 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -28,7 +28,7 @@ import ( ) func init() { - register("4byteTracer", newFourByteTracer) + tracers.DefaultDirectory.Register("4byteTracer", newFourByteTracer, false) } // fourByteTracer searches for 4byte-identifiers, and collects them for post-processing. diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 24fd406398bb..5bf49e744dec 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -32,7 +32,7 @@ import ( //go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go func init() { - register("callTracer", newCallTracer) + tracers.DefaultDirectory.Register("callTracer", newCallTracer, false) } type callLog struct { diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 878e2dc9d6d7..db8ddd64380d 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -26,7 +26,7 @@ import ( ) func init() { - register("muxTracer", newMuxTracer) + tracers.DefaultDirectory.Register("muxTracer", newMuxTracer, false) } // muxTracer is a go implementation of the Tracer interface which @@ -47,7 +47,7 @@ func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, er objects := make([]tracers.Tracer, 0, len(config)) names := make([]string, 0, len(config)) for k, v := range config { - t, err := tracers.New(k, ctx, v) + t, err := tracers.DefaultDirectory.New(k, ctx, v) if err != nil { return nil, err } diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index c1035bd1b7c6..3beecd8abfed 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -26,7 +26,7 @@ import ( ) func init() { - register("noopTracer", newNoopTracer) + tracers.DefaultDirectory.Register("noopTracer", newNoopTracer, false) } // noopTracer is a go implementation of the Tracer interface which diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 10008699bda3..948d09ef767c 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -32,7 +32,7 @@ import ( //go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go func init() { - register("prestateTracer", newPrestateTracer) + tracers.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false) } type state = map[common.Address]*account diff --git a/eth/tracers/native/tracer.go b/eth/tracers/native/tracer.go deleted file mode 100644 index f70d4b2af1ae..000000000000 --- a/eth/tracers/native/tracer.go +++ /dev/null @@ -1,79 +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 . - -// Package native is a collection of tracers written in go. -// -// In order to add a native tracer and have it compiled into the binary, a new -// file needs to be added to this folder, containing an implementation of the -// `eth.tracers.Tracer` interface. -// -// Aside from implementing the tracer, it also needs to register itself, using the -// `register` method -- and this needs to be done in the package initialization. -// -// Example: -// -// func init() { -// register("noopTracerNative", newNoopTracer) -// } -package native - -import ( - "encoding/json" - "errors" - - "github.com/ethereum/go-ethereum/eth/tracers" -) - -// init registers itself this packages as a lookup for tracers. -func init() { - tracers.RegisterLookup(false, lookup) -} - -// ctorFn is the constructor signature of a native tracer. -type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error) - -/* -ctors is a map of package-local tracer constructors. - -We cannot be certain about the order of init-functions within a package, -The go spec (https://golang.org/ref/spec#Package_initialization) says - -> To ensure reproducible initialization behavior, build systems -> are encouraged to present multiple files belonging to the same -> package in lexical file name order to a compiler. - -Hence, we cannot make the map in init, but must make it upon first use. -*/ -var ctors map[string]ctorFn - -// register is used by native tracers to register their presence. -func register(name string, ctor ctorFn) { - if ctors == nil { - ctors = make(map[string]ctorFn) - } - ctors[name] = ctor -} - -// lookup returns a tracer, if one can be matched to the given name. -func lookup(name string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { - if ctors == nil { - ctors = make(map[string]ctorFn) - } - if ctor, ok := ctors[name]; ok { - return ctor(ctx, cfg) - } - return nil, errors.New("no tracer found") -} diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index 3d2d1256c091..b93f7db6f570 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -19,7 +19,6 @@ package tracers import ( "encoding/json" - "errors" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" @@ -42,31 +41,55 @@ type Tracer interface { Stop(err error) } -type lookupFunc func(string, *Context, json.RawMessage) (Tracer, error) +type ctorFn func(*Context, json.RawMessage) (Tracer, error) +type jsCtorFn func(string, *Context, json.RawMessage) (Tracer, error) -var ( - lookups []lookupFunc -) +type elem struct { + ctor ctorFn + isJS bool +} -// RegisterLookup registers a method as a lookup for tracers, meaning that -// users can invoke a named tracer through that lookup. If 'wildcard' is true, -// then the lookup will be placed last. This is typically meant for interpreted -// engines (js) which can evaluate dynamic user-supplied code. -func RegisterLookup(wildcard bool, lookup lookupFunc) { - if wildcard { - lookups = append(lookups, lookup) - } else { - lookups = append([]lookupFunc{lookup}, lookups...) - } +// DefaultDirectory is the collection of tracers bundled by default. +var DefaultDirectory = directory{elems: make(map[string]elem)} + +// directory provides functionality to lookup a tracer by name +// and a function to instantiate it. It falls back to a JS code evaluator +// if no tracer of the given name exists. +type directory struct { + elems map[string]elem + jsEval jsCtorFn +} + +// Register registers a method as a lookup for tracers, meaning that +// users can invoke a named tracer through that lookup. +func (d *directory) Register(name string, f ctorFn, isJS bool) { + d.elems[name] = elem{ctor: f, isJS: isJS} +} + +// RegisterJSEval registers a tracer that is able to parse +// dynamic user-provided JS code. +func (d *directory) RegisterJSEval(f jsCtorFn) { + d.jsEval = f } // New returns a new instance of a tracer, by iterating through the -// registered lookups. -func New(code string, ctx *Context, cfg json.RawMessage) (Tracer, error) { - for _, lookup := range lookups { - if tracer, err := lookup(code, ctx, cfg); err == nil { - return tracer, nil - } +// registered lookups. Name is either name of an existing tracer +// or an arbitrary JS code. +func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (Tracer, error) { + if elem, ok := d.elems[name]; ok { + return elem.ctor(ctx, cfg) + } + // Assume JS code + return d.jsEval(name, ctx, cfg) +} + +// IsJS will return true if the given tracer will evaluate +// JS code. Because code evaluation has high overhead, this +// info will be used in determining fast and slow code paths. +func (d *directory) IsJS(name string) bool { + if elem, ok := d.elems[name]; ok { + return elem.isJS } - return nil, errors.New("tracer not found") + // JS eval will execute JS code + return true } From 452a12aa7903209713ccdc54af65a1a31e73190d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 10 Jan 2023 19:16:54 +0200 Subject: [PATCH 458/715] eth/downloader: move the pivot in beacon sync mode too (#26453) In legacy (pre-merge) sync mode, headers were contiguously downloaded from the network and when no more headers were available, we checked every few seconds whether there are 64 new blocks to move the pivot. In beacon (post-merge) sync mode, we don't need to check for new skeleton headers non stop, since those re delivered one by one by the engine API. The missing code snippet from the header fetcher was to actually look at the latest head and move the pivot if it was more than 2*64-8 away. This PR adds the missing movement logic. --- eth/downloader/beaconsync.go | 49 ++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 484a4e20de64..65d9225f8b51 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -23,6 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" ) @@ -270,7 +271,8 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { // fetchBeaconHeaders feeds skeleton headers to the downloader queue for scheduling // until sync errors or is finished. func (d *Downloader) fetchBeaconHeaders(from uint64) error { - head, tail, err := d.skeleton.Bounds() + var head *types.Header + _, tail, err := d.skeleton.Bounds() if err != nil { return err } @@ -288,6 +290,47 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error { log.Warn("Retrieved beacon headers from local", "from", from, "count", count) } for { + // Some beacon headers might have appeared since the last cycle, make + // sure we're always syncing to all available ones + head, _, err = d.skeleton.Bounds() + if err != nil { + return err + } + // If the pivot became stale (older than 2*64-8 (bit of wiggle room)), + // move it ahead to HEAD-64 + d.pivotLock.Lock() + if d.pivotHeader != nil { + if head.Number.Uint64() > d.pivotHeader.Number.Uint64()+2*uint64(fsMinFullBlocks)-8 { + // Retrieve the next pivot header, either from skeleton chain + // or the filled chain + number := head.Number.Uint64() - uint64(fsMinFullBlocks) + + log.Warn("Pivot seemingly stale, moving", "old", d.pivotHeader.Number, "new", number) + if d.pivotHeader = d.skeleton.Header(number); d.pivotHeader == nil { + if number < tail.Number.Uint64() { + dist := tail.Number.Uint64() - number + if len(localHeaders) >= int(dist) { + d.pivotHeader = localHeaders[dist-1] + log.Warn("Retrieved pivot header from local", "number", d.pivotHeader.Number, "hash", d.pivotHeader.Hash(), "latest", head.Number, "oldest", tail.Number) + } + } + } + // Print an error log and return directly in case the pivot header + // is still not found. It means the skeleton chain is not linked + // correctly with local chain. + if d.pivotHeader == nil { + log.Error("Pivot header is not found", "number", number) + d.pivotLock.Unlock() + return errNoPivotHeader + } + // Write out the pivot into the database so a rollback beyond + // it will reenable snap sync and update the state root that + // the state syncer will be downloading + rawdb.WriteLastPivotNumber(d.stateDB, d.pivotHeader.Number.Uint64()) + } + } + d.pivotLock.Unlock() + // Retrieve a batch of headers and feed it to the header processor var ( headers = make([]*types.Header, 0, maxHeadersProcess) @@ -343,9 +386,5 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error { case <-d.cancelCh: return errCanceled } - head, _, err = d.skeleton.Bounds() - if err != nil { - return err - } } } From 793f0f9ec860f6f51e0cec943a268c10863097c7 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Wed, 11 Jan 2023 10:05:47 +0100 Subject: [PATCH 459/715] core/vm: implement EIP-3860: Limit and meter initcode (#23847) Implementation of https://eips.ethereum.org/EIPS/eip-3860, limit and meter initcode. This PR enables EIP-3860 as part of the Shanghai fork. Co-authored-by: lightclient@protonmail.com Co-authored-by: Martin Holst Swende Co-authored-by: Marius van der Wijden --- cmd/evm/internal/t8ntool/transaction.go | 6 +- core/bench_test.go | 2 +- core/error.go | 4 ++ core/state_processor_test.go | 75 +++++++++++++++++++++++++ core/state_transition.go | 31 ++++++++-- core/txpool/txpool.go | 4 +- core/vm/eips.go | 8 +++ core/vm/errors.go | 1 + core/vm/gas_table.go | 33 +++++++++++ core/vm/gas_table_test.go | 72 ++++++++++++++++++++++++ core/vm/instructions.go | 1 - core/vm/interpreter.go | 2 + core/vm/jump_table.go | 7 +++ light/txpool.go | 4 +- params/protocol_params.go | 4 +- tests/transaction_test_util.go | 2 +- 16 files changed, 245 insertions(+), 11 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 3409c0a3bf01..1bd370918e3e 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -140,7 +140,7 @@ func Transaction(ctx *cli.Context) error { } // Check intrinsic gas if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, - chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int))); err != nil { + chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int))); err != nil { r.Error = err results = append(results, r) continue @@ -171,6 +171,10 @@ func Transaction(ctx *cli.Context) error { case new(big.Int).Mul(tx.GasFeeCap(), new(big.Int).SetUint64(tx.Gas())).BitLen() > 256: r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits") } + // Check whether the init code size has been exceeded. + if chainConfig.IsShanghai(new(big.Int)) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + r.Error = errors.New("max initcode size exceeded") + } results = append(results, r) } out, err := json.MarshalIndent(results, "", " ") diff --git a/core/bench_test.go b/core/bench_test.go index f7cf0146060d..7fc8a760f703 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -83,7 +83,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { return func(i int, gen *BlockGen) { toaddr := common.Address{} data := make([]byte, nbytes) - gas, _ := IntrinsicGas(data, nil, false, false, false) + gas, _ := IntrinsicGas(data, nil, false, false, false, false) signer := types.MakeSigner(gen.config, big.NewInt(int64(i))) gasPrice := big.NewInt(0) if gen.header.BaseFee != nil { diff --git a/core/error.go b/core/error.go index 5b69c8dcaf26..872ba8d365d8 100644 --- a/core/error.go +++ b/core/error.go @@ -63,6 +63,10 @@ var ( // have enough funds for transfer(topmost call only). ErrInsufficientFundsForTransfer = errors.New("insufficient funds for transfer") + // ErrMaxInitCodeSizeExceeded is returned if creation transaction provides the init code bigger + // than init code size limit. + ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded") + // ErrInsufficientFunds is returned if the total cost of executing a transaction // is higher than the balance of the user's account. ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value") diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 1df4a0e80418..400ccd318793 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -75,6 +75,17 @@ func TestStateProcessorErrors(t *testing.T) { }), signer, key1) return tx } + var mkDynamicCreationTx = func(nonce uint64, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, data []byte) *types.Transaction { + tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{ + Nonce: nonce, + GasTipCap: gasTipCap, + GasFeeCap: gasFeeCap, + Gas: gasLimit, + Value: big.NewInt(0), + Data: data, + }), signer, key1) + return tx + } { // Tests against a 'recent' chain definition var ( db = rawdb.NewMemoryDatabase() @@ -294,6 +305,70 @@ func TestStateProcessorErrors(t *testing.T) { } } } + + // ErrMaxInitCodeSizeExceeded, for this we need extra Shanghai (EIP-3860) enabled. + { + var ( + db = rawdb.NewMemoryDatabase() + gspec = &Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + GrayGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + ShanghaiTime: big.NewInt(0), + }, + Alloc: GenesisAlloc{ + common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ + Balance: big.NewInt(1000000000000000000), // 1 ether + Nonce: 0, + }, + }, + } + genesis = gspec.MustCommit(db) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} + smallInitCode = [320]byte{} + ) + defer blockchain.Stop() + for i, tt := range []struct { + txs []*types.Transaction + want string + }{ + { // ErrMaxInitCodeSizeExceeded + txs: []*types.Transaction{ + mkDynamicCreationTx(0, 500000, common.Big0, misc.CalcBaseFee(config, genesis.Header()), tooBigInitCode[:]), + }, + want: "could not apply tx 0 [0x832b54a6c3359474a9f504b1003b2cc1b6fcaa18e4ef369eb45b5d40dad6378f]: max initcode size exceeded: code size 49153 limit 49152", + }, + { // ErrIntrinsicGas: Not enough gas to cover init code + txs: []*types.Transaction{ + mkDynamicCreationTx(0, 54299, common.Big0, misc.CalcBaseFee(config, genesis.Header()), smallInitCode[:]), + }, + want: "could not apply tx 0 [0x39b7436cb432d3662a25626474282c5c4c1a213326fd87e4e18a91477bae98b2]: intrinsic gas too low: have 54299, want 54300", + }, + } { + block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config) + _, err := blockchain.InsertChain(types.Blocks{block}) + if err == nil { + t.Fatal("block imported without errors") + } + if have, want := err.Error(), tt.want; have != want { + t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) + } + } + } } // GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be diff --git a/core/state_transition.go b/core/state_transition.go index fe94161e14f9..653c6b183618 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -120,7 +120,7 @@ func (result *ExecutionResult) Revert() []byte { } // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) { +func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool, isEIP3860 bool) (uint64, error) { // Set the starting gas for the raw transaction var gas uint64 if isContractCreation && isHomestead { @@ -128,8 +128,9 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b } else { gas = params.TxGas } + dataLen := uint64(len(data)) // Bump the required gas by the amount of transactional data - if len(data) > 0 { + if dataLen > 0 { // Zero and non-zero bytes are priced differently var nz uint64 for _, byt := range data { @@ -147,11 +148,19 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b } gas += nz * nonZeroGas - z := uint64(len(data)) - nz + z := dataLen - nz if (math.MaxUint64-gas)/params.TxDataZeroGas < z { return 0, ErrGasUintOverflow } gas += z * params.TxDataZeroGas + + if isContractCreation && isEIP3860 { + lenWords := toWordSize(dataLen) + if (math.MaxUint64-gas)/params.InitCodeWordGas < lenWords { + return 0, ErrGasUintOverflow + } + gas += lenWords * params.InitCodeWordGas + } } if accessList != nil { gas += uint64(len(accessList)) * params.TxAccessListAddressGas @@ -160,6 +169,15 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b return gas, nil } +// toWordSize returns the ceiled word size required for init code payment calculation. +func toWordSize(size uint64) uint64 { + if size > math.MaxUint64-31 { + return math.MaxUint64/32 + 1 + } + + return (size + 31) / 32 +} + // NewStateTransition initialises and returns a new state transition object. func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { return &StateTransition{ @@ -305,7 +323,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { ) // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul) + gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) if err != nil { return nil, err } @@ -319,6 +337,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex()) } + // Check whether the init code size has been exceeded. + if rules.IsShanghai && contractCreation && len(st.data) > params.MaxInitCodeSize { + return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize) + } + // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 8905140fdb69..dc6a71f07ac2 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -245,6 +245,7 @@ type TxPool struct { istanbul bool // Fork indicator whether we are in the istanbul stage. eip2718 bool // Fork indicator whether we are using EIP-2718 type transactions. eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions. + shanghai bool // Fork indicator whether we are in the Shanghai stage. currentState *state.StateDB // Current state in the blockchain head pendingNonces *noncer // Pending state tracking virtual nonces @@ -637,7 +638,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return core.ErrInsufficientFunds } // Ensure the transaction has more gas than the basic tx fee. - intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul) + intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai) if err != nil { return err } @@ -1306,6 +1307,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { pool.istanbul = pool.chainconfig.IsIstanbul(next) pool.eip2718 = pool.chainconfig.IsBerlin(next) pool.eip1559 = pool.chainconfig.IsLondon(next) + pool.shanghai = pool.chainconfig.IsShanghai(big.NewInt(time.Now().Unix())) } // promoteExecutables moves transactions that have become processable from the diff --git a/core/vm/eips.go b/core/vm/eips.go index 26c450905662..29ff27c55268 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -27,6 +27,7 @@ import ( var activators = map[int]func(*JumpTable){ 3855: enable3855, + 3860: enable3860, 3529: enable3529, 3198: enable3198, 2929: enable2929, @@ -233,3 +234,10 @@ func opPush0(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by scope.Stack.push(new(uint256.Int)) return nil, nil } + +// ebnable3860 enables "EIP-3860: Limit and meter initcode" +// https://eips.ethereum.org/EIPS/eip-3860 +func enable3860(jt *JumpTable) { + jt[CREATE].dynamicGas = gasCreateEip3860 + jt[CREATE2].dynamicGas = gasCreate2Eip3860 +} diff --git a/core/vm/errors.go b/core/vm/errors.go index 004f8ef1c83c..fbbf19e178bf 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -29,6 +29,7 @@ var ( ErrInsufficientBalance = errors.New("insufficient balance for transfer") ErrContractAddressCollision = errors.New("contract address collision") ErrExecutionReverted = errors.New("execution reverted") + ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded") ErrMaxCodeSizeExceeded = errors.New("max code size exceeded") ErrInvalidJump = errors.New("invalid jump destination") ErrWriteProtection = errors.New("write protection") diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 57fb1a8d98b2..65d46b3436d9 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -302,6 +302,39 @@ func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memoryS return gas, nil } +func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + size, overflow := stack.Back(2).Uint64WithOverflow() + if overflow || size > params.MaxInitCodeSize { + return 0, ErrGasUintOverflow + } + // Since size <= params.MaxInitCodeSize, these multiplication cannot overflow + moreGas := params.InitCodeWordGas * ((size + 31) / 32) + if gas, overflow = math.SafeAdd(gas, moreGas); overflow { + return 0, ErrGasUintOverflow + } + return gas, nil +} +func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + size, overflow := stack.Back(2).Uint64WithOverflow() + if overflow || size > params.MaxInitCodeSize { + return 0, ErrGasUintOverflow + } + // Since size <= params.MaxInitCodeSize, these multiplication cannot overflow + moreGas := (params.InitCodeWordGas + params.Keccak256WordGas) * ((size + 31) / 32) + if gas, overflow = math.SafeAdd(gas, moreGas); overflow { + return 0, ErrGasUintOverflow + } + return gas, nil +} + func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index 6cd126c9b4ca..c3d06e515b17 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -17,8 +17,10 @@ package vm import ( + "bytes" "math" "math/big" + "sort" "testing" "github.com/ethereum/go-ethereum/common" @@ -105,3 +107,73 @@ func TestEIP2200(t *testing.T) { } } } + +var createGasTests = []struct { + code string + eip3860 bool + gasUsed uint64 + minimumGas uint64 +}{ + // legacy create(0, 0, 0xc000) without 3860 used + {"0x61C00060006000f0" + "600052" + "60206000F3", false, 41237, 41237}, + // legacy create(0, 0, 0xc000) _with_ 3860 + {"0x61C00060006000f0" + "600052" + "60206000F3", true, 44309, 44309}, + // create2(0, 0, 0xc001, 0) without 3860 + {"0x600061C00160006000f5" + "600052" + "60206000F3", false, 50471, 50471}, + // create2(0, 0, 0xc001, 0) (too large), with 3860 + {"0x600061C00160006000f5" + "600052" + "60206000F3", true, 32012, 100_000}, + // create2(0, 0, 0xc000, 0) + // This case is trying to deploy code at (within) the limit + {"0x600061C00060006000f5" + "600052" + "60206000F3", true, 53528, 53528}, + // create2(0, 0, 0xc001, 0) + // This case is trying to deploy code exceeding the limit + {"0x600061C00160006000f5" + "600052" + "60206000F3", true, 32024, 100000}, +} + +func TestCreateGas(t *testing.T) { + for i, tt := range createGasTests { + var gasUsed = uint64(0) + doCheck := func(testGas int) bool { + address := common.BytesToAddress([]byte("contract")) + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb.CreateAccount(address) + statedb.SetCode(address, hexutil.MustDecode(tt.code)) + statedb.Finalise(true) + vmctx := BlockContext{ + CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true }, + Transfer: func(StateDB, common.Address, common.Address, *big.Int) {}, + BlockNumber: big.NewInt(0), + } + config := Config{} + if tt.eip3860 { + config.ExtraEips = []int{3860} + } + + vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, config) + var startGas = uint64(testGas) + ret, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, startGas, new(big.Int)) + if err != nil { + return false + } + gasUsed = startGas - gas + if len(ret) != 32 { + t.Fatalf("test %d: expected 32 bytes returned, have %d", i, len(ret)) + } + if bytes.Equal(ret, make([]byte, 32)) { + // Failure + return false + } + return true + } + minGas := sort.Search(100_000, doCheck) + if uint64(minGas) != tt.minimumGas { + t.Fatalf("test %d: min gas error, want %d, have %d", i, tt.minimumGas, minGas) + } + // If the deployment succeeded, we also check the gas used + if minGas < 100_000 { + if gasUsed != tt.gasUsed { + t.Errorf("test %d: gas used mismatch: have %v, want %v", i, gasUsed, tt.gasUsed) + } + } + } +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 22c72c10a491..8fa2fc57e51f 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -633,7 +633,6 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) gas = scope.Contract.Gas ) - // Apply EIP150 gas -= gas / 64 scope.Contract.UseGas(gas) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index c99e54b76dc0..7b040aac9e11 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -60,6 +60,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { // If jump table was not initialised we set the default one. if cfg.JumpTable == nil { switch { + case evm.chainRules.IsShanghai: + cfg.JumpTable = &shanghaiInstructionSet case evm.chainRules.IsMerge: cfg.JumpTable = &mergeInstructionSet case evm.chainRules.IsLondon: diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 7cbcc56c5adc..240f3734a5a3 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -55,6 +55,7 @@ var ( berlinInstructionSet = newBerlinInstructionSet() londonInstructionSet = newLondonInstructionSet() mergeInstructionSet = newMergeInstructionSet() + shanghaiInstructionSet = newShanghaiInstructionSet() ) // JumpTable contains the EVM opcodes supported at a given fork. @@ -78,6 +79,12 @@ func validate(jt JumpTable) JumpTable { return jt } +func newShanghaiInstructionSet() JumpTable { + instructionSet := newMergeInstructionSet() + enable3860(&instructionSet) + return validate(instructionSet) +} + func newMergeInstructionSet() JumpTable { instructionSet := newLondonInstructionSet() instructionSet[PREVRANDAO] = &operation{ diff --git a/light/txpool.go b/light/txpool.go index 3e3572faaf11..e12f6ef94425 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -70,6 +70,7 @@ type TxPool struct { istanbul bool // Fork indicator whether we are in the istanbul stage. eip2718 bool // Fork indicator whether we are in the eip2718 stage. + shanghai bool // Fork indicator whether we are in the shanghai stage. } // TxRelayBackend provides an interface to the mechanism that forwards transactions to the @@ -317,6 +318,7 @@ func (pool *TxPool) setNewHead(head *types.Header) { next := new(big.Int).Add(head.Number, big.NewInt(1)) pool.istanbul = pool.config.IsIstanbul(next) pool.eip2718 = pool.config.IsBerlin(next) + pool.shanghai = pool.config.IsShanghai(big.NewInt(time.Now().Unix())) } // Stop stops the light transaction pool @@ -384,7 +386,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error } // Should supply enough intrinsic gas - gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul) + gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai) if err != nil { return err } diff --git a/params/protocol_params.go b/params/protocol_params.go index b0037fd471c4..bb703d0b74dc 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -38,6 +38,7 @@ const ( Keccak256Gas uint64 = 30 // Once per KECCAK256 operation. Keccak256WordGas uint64 = 6 // Once per word of the KECCAK256 operation's data. + InitCodeWordGas uint64 = 2 // Once per word of the init code when creating a contract. SstoreSetGas uint64 = 20000 // Once per SSTORE operation. SstoreResetGas uint64 = 5000 // Once per SSTORE operation if the zeroness changes from zero. @@ -123,7 +124,8 @@ const ( DefaultElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. - MaxCodeSize = 24576 // Maximum bytecode to permit for a contract + MaxCodeSize = 24576 // Maximum bytecode to permit for a contract + MaxInitCodeSize = 2 * MaxCodeSize // Maximum initcode to permit in a creation transaction and create instructions // Precompiled contract gas prices diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 82ee01de15c8..391aa57584cf 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -55,7 +55,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { return nil, nil, err } // Intrinsic gas - requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, isHomestead, isIstanbul) + requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, isHomestead, isIstanbul, false) if err != nil { return nil, nil, err } From c125e6e00c6408cd544fd567dda50ef5edadeb02 Mon Sep 17 00:00:00 2001 From: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com> Date: Thu, 12 Jan 2023 11:00:08 +0100 Subject: [PATCH 460/715] core/vm: enable EIP-3855 (PUSH0) in Shanghai (#26475) --- core/vm/jump_table.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 240f3734a5a3..91f1be669a40 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -81,7 +81,8 @@ func validate(jt JumpTable) JumpTable { func newShanghaiInstructionSet() JumpTable { instructionSet := newMergeInstructionSet() - enable3860(&instructionSet) + enable3855(&instructionSet) // PUSH0 instruction + enable3860(&instructionSet) // Limit and meter initcode return validate(instructionSet) } From 6f858fa806c43d6a5af6f5213b4aae517136378a Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 12 Jan 2023 03:04:34 -0700 Subject: [PATCH 461/715] rpc: fix setting client in DialHTTPWithClient (#26470) --- rpc/http.go | 1 + 1 file changed, 1 insertion(+) diff --git a/rpc/http.go b/rpc/http.go index bbabe15bada3..074c57ab1ad3 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -137,6 +137,7 @@ func DialHTTPWithClient(endpoint string, client *http.Client) (*Client, error) { } var cfg clientConfig + cfg.httpClient = client fn := newClientTransportHTTP(endpoint, &cfg) return newClient(context.Background(), fn) } From b748709a11fee4de95634980eab2e13d66834b82 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 12 Jan 2023 18:19:16 +0800 Subject: [PATCH 462/715] eth/downloader: fix cornercase when clean stale beacon headers (#26441) --- eth/downloader/skeleton.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/eth/downloader/skeleton.go b/eth/downloader/skeleton.go index 15d473af263c..142e9e5e6bcb 100644 --- a/eth/downloader/skeleton.go +++ b/eth/downloader/skeleton.go @@ -1102,6 +1102,7 @@ func (s *skeleton) cleanStales(filled *types.Header) error { var ( start = s.progress.Subchains[0].Tail // start deleting from the first known header end = number // delete until the requested threshold + batch = s.db.NewBatch() ) s.progress.Subchains[0].Tail = number s.progress.Subchains[0].Next = filled.ParentHash @@ -1111,16 +1112,13 @@ func (s *skeleton) cleanStales(filled *types.Header) error { // subchain forward to keep tracking the node's block imports end = s.progress.Subchains[0].Head + 1 // delete the entire original range, including the head s.progress.Subchains[0].Head = number // assign a new head (tail is already assigned to this) - } - // Execute the trimming and the potential rewiring of the progress - batch := s.db.NewBatch() - if end != number { // The entire original skeleton chain was deleted and a new one // defined. Make sure the new single-header chain gets pushed to // disk to keep internal state consistent. rawdb.WriteSkeletonHeader(batch, filled) } + // Execute the trimming and the potential rewiring of the progress s.saveSyncStatus(batch) for n := start; n < end; n++ { // If the batch grew too big, flush it and continue with a new batch. @@ -1176,8 +1174,13 @@ func (s *skeleton) Bounds() (head *types.Header, tail *types.Header, err error) return nil, nil, err } head = rawdb.ReadSkeletonHeader(s.db, progress.Subchains[0].Head) + if head == nil { + return nil, nil, fmt.Errorf("head skeleton header %d is missing", progress.Subchains[0].Head) + } tail = rawdb.ReadSkeletonHeader(s.db, progress.Subchains[0].Tail) - + if tail == nil { + return nil, nil, fmt.Errorf("tail skeleton header %d is missing", progress.Subchains[0].Tail) + } return head, tail, nil } From d379e3f605351cd21d0feab63077cb300298ca6e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 12 Jan 2023 11:31:21 +0100 Subject: [PATCH 463/715] ethclient/gethclient: ensure getProof keys parameter is not null (#26409) Other clients do not accept a parameter value of null for this array. --- ethclient/gethclient/gethclient.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index 8211ee75ae01..fdcfb9a0ac40 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -96,6 +96,11 @@ func (ec *Client) GetProof(ctx context.Context, account common.Address, keys []s StorageProof []storageResult `json:"storageProof"` } + // Avoid keys being 'null'. + if keys == nil { + keys = []string{} + } + var res accountResult err := ec.c.CallContext(ctx, &res, "eth_getProof", account, keys, toBlockNumArg(blockNumber)) // Turn hexutils back to normal datatypes From a21e963ac29c39cb985e2f389e4767c44cc4d368 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 13 Jan 2023 15:13:27 +0800 Subject: [PATCH 464/715] eth/catalyst: trigger beacon sync directly with provided chain head (#26489) --- eth/catalyst/tester.go | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/eth/catalyst/tester.go b/eth/catalyst/tester.go index 63ee5feb26be..05511eaf7a2f 100644 --- a/eth/catalyst/tester.go +++ b/eth/catalyst/tester.go @@ -20,9 +20,9 @@ import ( "sync" "time" - "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" ) @@ -50,10 +50,7 @@ func RegisterFullSyncTester(stack *node.Node, backend *eth.Ethereum, block *type return cl, nil } -// Start launches the full-sync tester by spinning up a background thread -// for keeping firing NewPayload-UpdateForkChoice combos with the provided -// target block, it may or may not trigger the beacon sync depends on if -// there are protocol peers connected. +// Start launches the beacon sync with provided sync target. func (tester *FullSyncTester) Start() error { tester.wg.Add(1) go func() { @@ -70,19 +67,19 @@ func (tester *FullSyncTester) Start() error { continue } // Short circuit in case the target block is already stored - // locally. + // locally. TODO(somehow terminate the node stack if target + // is reached). if tester.api.eth.BlockChain().HasBlock(tester.block.Hash(), tester.block.NumberU64()) { log.Info("Full-sync target reached", "number", tester.block.NumberU64(), "hash", tester.block.Hash()) return } - // Shoot out consensus events in order to trigger syncing. - data := beacon.BlockToExecutableData(tester.block) - tester.api.NewPayloadV1(*data) - tester.api.ForkchoiceUpdatedV1(beacon.ForkchoiceStateV1{ - HeadBlockHash: tester.block.Hash(), - SafeBlockHash: tester.block.Hash(), - FinalizedBlockHash: tester.block.Hash(), - }, nil) + // Trigger beacon sync with the provided block header as + // trusted chain head. + err := tester.api.eth.Downloader().BeaconSync(downloader.FullSync, tester.block.Header()) + if err != nil { + log.Info("Failed to beacon sync", "err", err) + } + case <-tester.closed: return } From e04d63ebd3dd5441690da22c43e29b7bd78861af Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 13 Jan 2023 18:55:50 +0800 Subject: [PATCH 465/715] core/rawdb: fsync head data file before closing it (#26490) This PR fixes an issue which might result in data lost in freezer. Whenever mutation happens in freezer, all data will be written into head data file and it will be rotated with a new one in case the size of file reaches the threshold. Theoretically, the rotated old data file should be fsync'd to prevent data loss. In freezer.Sync function, we only fsync: (1) index file (2) meta file and (3) head data file. So this PR forcibly fsync the head data file if mutation happens in the boundary of data file. --- core/rawdb/chain_freezer.go | 4 ++-- core/rawdb/freezer_table.go | 7 +++++-- core/rawdb/freezer_test.go | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 212ec73ed73d..4348fb5d772e 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -86,14 +86,14 @@ func (f *chainFreezer) Close() error { // This functionality is deliberately broken off from block importing to avoid // incurring additional data shuffling delays on block propagation. func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { - nfdb := &nofreezedb{KeyValueStore: db} - var ( backoff bool triggered chan struct{} // Used in tests + nfdb = &nofreezedb{KeyValueStore: db} ) timer := time.NewTimer(freezerRecheckInterval) defer timer.Stop() + for { select { case <-f.quit: diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 7af937fd81ad..394bd576142e 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -852,8 +852,11 @@ func (t *freezerTable) advanceHead() error { if err != nil { return err } - - // Close old file, and reopen in RDONLY mode. + // Commit the contents of the old file to stable storage and + // tear it down. It will be re-opened in read-only mode. + if err := t.head.Sync(); err != nil { + return err + } t.releaseFile(t.headId) t.openFile(t.headId, openFreezerFileForReadOnly) diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index 630911ec867c..8deb04a7928a 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -190,7 +190,7 @@ func TestFreezerConcurrentModifyTruncate(t *testing.T) { var item = make([]byte, 256) - for i := 0; i < 1000; i++ { + for i := 0; i < 10; i++ { // First reset and write 100 items. if err := f.TruncateHead(0); err != nil { t.Fatal("truncate failed:", err) From 0e486a56c99bd4646b0a26f195e1cd218cee4e63 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 13 Jan 2023 15:48:42 +0100 Subject: [PATCH 466/715] Use filepath.clean instead of path.clean (#26404) * internal/flags: use filepath.Clean instead of path.Clean * internal/flags: fix windows pipe issue * internal/flags: modify test for windows * internal/flags: use backticks, fix test --- internal/flags/flags.go | 8 ++++++-- internal/flags/flags_test.go | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/internal/flags/flags.go b/internal/flags/flags.go index 0ae2c6a512ef..b0756b4e0a1f 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -23,7 +23,7 @@ import ( "math/big" "os" "os/user" - "path" + "path/filepath" "strings" "github.com/ethereum/go-ethereum/common/math" @@ -314,12 +314,16 @@ func GlobalBig(ctx *cli.Context, name string) *big.Int { // 3. cleans the path, e.g. /a/b/../c -> /a/c // Note, it has limitations, e.g. ~someuser/tmp will not be expanded func expandPath(p string) string { + // Named pipes are not file paths on windows, ignore + if strings.HasPrefix(p, `\\.\pipe`) { + return p + } if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { if home := HomeDir(); home != "" { p = home + p[1:] } } - return path.Clean(os.ExpandEnv(p)) + return filepath.Clean(os.ExpandEnv(p)) } func HomeDir() string { diff --git a/internal/flags/flags_test.go b/internal/flags/flags_test.go index a0d4af7ca360..681586b46c74 100644 --- a/internal/flags/flags_test.go +++ b/internal/flags/flags_test.go @@ -19,23 +19,43 @@ package flags import ( "os" "os/user" + "runtime" "testing" ) func TestPathExpansion(t *testing.T) { user, _ := user.Current() - tests := map[string]string{ - "/home/someuser/tmp": "/home/someuser/tmp", - "~/tmp": user.HomeDir + "/tmp", - "~thisOtherUser/b/": "~thisOtherUser/b", - "$DDDXXX/a/b": "/tmp/a/b", - "/a/b/": "/a/b", + var tests map[string]string + + if runtime.GOOS == "windows" { + tests = map[string]string{ + `/home/someuser/tmp`: `\home\someuser\tmp`, + `~/tmp`: user.HomeDir + `\tmp`, + `~thisOtherUser/b/`: `~thisOtherUser\b`, + `$DDDXXX/a/b`: `\tmp\a\b`, + `/a/b/`: `\a\b`, + `C:\Documents\Newsletters\`: `C:\Documents\Newsletters`, + `C:\`: `C:\`, + `\\.\pipe\\pipe\geth621383`: `\\.\pipe\\pipe\geth621383`, + } + } else { + tests = map[string]string{ + `/home/someuser/tmp`: `/home/someuser/tmp`, + `~/tmp`: user.HomeDir + `/tmp`, + `~thisOtherUser/b/`: `~thisOtherUser/b`, + `$DDDXXX/a/b`: `/tmp/a/b`, + `/a/b/`: `/a/b`, + `C:\Documents\Newsletters\`: `C:\Documents\Newsletters\`, + `C:\`: `C:\`, + `\\.\pipe\\pipe\geth621383`: `\\.\pipe\\pipe\geth621383`, + } } - os.Setenv("DDDXXX", "/tmp") + + os.Setenv(`DDDXXX`, `/tmp`) for test, expected := range tests { got := expandPath(test) if got != expected { - t.Errorf("test %s, got %s, expected %s\n", test, got, expected) + t.Errorf(`test %s, got %s, expected %s\n`, test, got, expected) } } } From 450d771bee9cc8c90d54dce212da2986f9f9bcc1 Mon Sep 17 00:00:00 2001 From: David Hwang <69114096+dhij@users.noreply.github.com> Date: Sun, 15 Jan 2023 03:23:58 -0500 Subject: [PATCH 467/715] readme: fix broken link to installation instructions (#26497) update link to the installation instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 326437dfe02d..c4900633ab69 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ archives are published at https://geth.ethereum.org/downloads/. ## Building the source -For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/install-and-build/installing-geth). +For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth). Building `geth` requires both a Go (version 1.18 or later) and a C compiler. You can install them using your favourite package manager. Once the dependencies are installed, run From 0b53b29078d55fb69ae347d6944bf6521e00bdb4 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 16 Jan 2023 03:57:27 -0500 Subject: [PATCH 468/715] core/rawdb: fix cornercase shutdown behaviour in freezer (#26485) This PR does a few things. It fixes a shutdown-order flaw in the chainfreezer. Previously, the chain-freezer would shutdown the freezer backend first, and then signal for the loop to exit. This can lead to a scenario where the freezer tries to fsync closed files, which is an error-conditon that could lead to exit via log.Crit. It also makes the printout more detailed when truncating 'dangling' items, by showing the exact number instead of approximate MB. This PR also adds calls to fsync files before closing them, and also makes the `db inspect` command slightly more robust. --- cmd/geth/dbcmd.go | 12 ++------ core/rawdb/chain_freezer.go | 3 +- core/rawdb/freezer_table.go | 55 +++++++++++++++++++++++++------------ core/rawdb/freezer_test.go | 22 +++++++++++++++ 4 files changed, 62 insertions(+), 30 deletions(-) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 5231ed116bc9..4deb081ed8f6 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -551,16 +551,8 @@ func freezerInspect(ctx *cli.Context) error { return err } stack, _ := makeConfigNode(ctx) - defer stack.Close() - - db := utils.MakeChainDatabase(ctx, stack, true) - defer db.Close() - - ancient, err := db.AncientDatadir() - if err != nil { - log.Info("Failed to retrieve ancient root", "err", err) - return err - } + ancient := stack.ResolveAncient("chaindata", ctx.String(utils.AncientFlag.Name)) + stack.Close() return rawdb.InspectFreezerTable(ancient, freezer, table, start, end) } diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 4348fb5d772e..738295cfb702 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -70,14 +70,13 @@ func newChainFreezer(datadir string, namespace string, readonly bool, maxTableSi // Close closes the chain freezer instance and terminates the background thread. func (f *chainFreezer) Close() error { - err := f.Freezer.Close() select { case <-f.quit: default: close(f.quit) } f.wg.Wait() - return err + return f.Freezer.Close() } // freeze is a background thread that periodically checks the blockchain for any diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 394bd576142e..b111797d5297 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -229,6 +229,7 @@ func (t *freezerTable) repair() error { lastIndex indexEntry contentSize int64 contentExp int64 + verbose bool ) // Read index zero, determine what file is the earliest // and what item offset to use @@ -272,9 +273,10 @@ func (t *freezerTable) repair() error { // Keep truncating both files until they come in sync contentExp = int64(lastIndex.offset) for contentExp != contentSize { + verbose = true // Truncate the head file to the last offset pointer if contentExp < contentSize { - t.logger.Warn("Truncating dangling head", "indexed", common.StorageSize(contentExp), "stored", common.StorageSize(contentSize)) + t.logger.Warn("Truncating dangling head", "indexed", contentExp, "stored", contentSize) if err := truncateFreezerFile(t.head, contentExp); err != nil { return err } @@ -282,7 +284,7 @@ func (t *freezerTable) repair() error { } // Truncate the index to point within the head file if contentExp > contentSize { - t.logger.Warn("Truncating dangling indexes", "indexed", common.StorageSize(contentExp), "stored", common.StorageSize(contentSize)) + t.logger.Warn("Truncating dangling indexes", "indexes", offsetsSize/indexEntrySize, "indexed", contentExp, "stored", contentSize) if err := truncateFreezerFile(t.index, offsetsSize-indexEntrySize); err != nil { return err } @@ -343,7 +345,11 @@ func (t *freezerTable) repair() error { if err := t.preopen(); err != nil { return err } - t.logger.Debug("Chain freezer table opened", "items", t.items, "size", common.StorageSize(t.headBytes)) + if verbose { + t.logger.Info("Chain freezer table opened", "items", t.items, "size", t.headBytes) + } else { + t.logger.Debug("Chain freezer table opened", "items", t.items, "size", common.StorageSize(t.headBytes)) + } return nil } @@ -553,21 +559,31 @@ func (t *freezerTable) Close() error { defer t.lock.Unlock() var errs []error - if err := t.index.Close(); err != nil { - errs = append(errs, err) - } - t.index = nil - - if err := t.meta.Close(); err != nil { - errs = append(errs, err) + doClose := func(f *os.File, sync bool, close bool) { + if sync && !t.readonly { + if err := f.Sync(); err != nil { + errs = append(errs, err) + } + } + if close { + if err := f.Close(); err != nil { + errs = append(errs, err) + } + } } - t.meta = nil - + // Trying to fsync a file opened in rdonly causes "Access denied" + // error on Windows. + doClose(t.index, true, true) + doClose(t.meta, true, true) + // The preopened non-head data-files are all opened in readonly. + // The head is opened in rw-mode, so we sync it here - but since it's also + // part of t.files, it will be closed in the loop below. + doClose(t.head, true, false) // sync but do not close for _, f := range t.files { - if err := f.Close(); err != nil { - errs = append(errs, err) - } + doClose(f, false, true) // close but do not sync } + t.index = nil + t.meta = nil t.head = nil if errs != nil { @@ -724,7 +740,7 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i defer t.lock.RUnlock() // Ensure the table and the item are accessible - if t.index == nil || t.head == nil { + if t.index == nil || t.head == nil || t.meta == nil { return nil, nil, errClosed } var ( @@ -872,7 +888,9 @@ func (t *freezerTable) advanceHead() error { func (t *freezerTable) Sync() error { t.lock.Lock() defer t.lock.Unlock() - + if t.index == nil || t.head == nil || t.meta == nil { + return errClosed + } var err error trackError := func(e error) { if e != nil && err == nil { @@ -903,7 +921,8 @@ func (t *freezerTable) dumpIndex(w io.Writer, start, stop int64) { fmt.Fprintf(w, "Failed to decode freezer table %v\n", err) return } - fmt.Fprintf(w, "Version %d deleted %d, hidden %d\n", meta.Version, atomic.LoadUint64(&t.itemOffset), atomic.LoadUint64(&t.itemHidden)) + fmt.Fprintf(w, "Version %d count %d, deleted %d, hidden %d\n", meta.Version, + atomic.LoadUint64(&t.items), atomic.LoadUint64(&t.itemOffset), atomic.LoadUint64(&t.itemHidden)) buf := make([]byte, indexEntrySize) diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index 8deb04a7928a..5896e43ce232 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -407,3 +407,25 @@ func TestRenameWindows(t *testing.T) { t.Errorf("unexpected file contents. Got %v\n", buf) } } + +func TestFreezerCloseSync(t *testing.T) { + t.Parallel() + f, _ := newFreezerForTesting(t, map[string]bool{"a": true, "b": true}) + defer f.Close() + + // Now, close and sync. This mimics the behaviour if the node is shut down, + // just as the chain freezer is writing. + // 1: thread-1: chain treezer writes, via freezeRange (holds lock) + // 2: thread-2: Close called, waits for write to finish + // 3: thread-1: finishes writing, releases lock + // 4: thread-2: obtains lock, completes Close() + // 5: thread-1: calls f.Sync() + if err := f.Close(); err != nil { + t.Fatal(err) + } + if err := f.Sync(); err == nil { + t.Fatalf("want error, have nil") + } else if have, want := err.Error(), "[closed closed]"; have != want { + t.Fatalf("want %v, have %v", have, want) + } +} From 554c8d77c599c1135c5b388ac73ddf299039a719 Mon Sep 17 00:00:00 2001 From: Zachinquarantine Date: Mon, 16 Jan 2023 04:57:35 -0500 Subject: [PATCH 469/715] cmd/utils: update Rinkeby deprecation message (#26496) --- cmd/utils/flags.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 20822f25e926..9997755cf216 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1899,9 +1899,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { log.Warn("") log.Warn("--------------------------------------------------------------------------------") log.Warn("Please note, Rinkeby has been deprecated. It will still work for the time being,") - log.Warn("but there will be no further hard-forks shipped for it. Eventually the network") - log.Warn("will be permanently halted after the other networks transition through the merge") - log.Warn("and prove stable enough. For the most future proof testnet, choose Sepolia as") + log.Warn("but there will be no further hard-forks shipped for it.") + log.Warn("The network will be permanently halted in Q2/Q3 of 2023.") + log.Warn("For the most future proof testnet, choose Sepolia as") log.Warn("your replacement environment (--sepolia instead of --rinkeby).") log.Warn("--------------------------------------------------------------------------------") log.Warn("") From 55c3b6fc3714d816891c9b3764b6984f8de20af0 Mon Sep 17 00:00:00 2001 From: ucwong Date: Mon, 16 Jan 2023 04:00:55 -0600 Subject: [PATCH 470/715] swarm: fix outdated link (#26501) --- swarm/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swarm/README.md b/swarm/README.md index 265883181306..41b6aa910090 100644 --- a/swarm/README.md +++ b/swarm/README.md @@ -1,7 +1,7 @@ # Swarm -https://swarm.ethereum.org +https://www.ethswarm.org/ Swarm is a distributed storage platform and content distribution service, a native base layer service of the ethereum web3 stack. The primary objective of Swarm is to provide a decentralized and redundant store for dapp code and data as well as block chain and state data. Swarm is also set out to provide various base layer services for web3, including node-to-node messaging, media streaming, decentralised database services and scalable state-channel infrastructure for decentralised service economies. -**Note**: The codebase has been moved to [ethersphere/swarm](https://github.com/ethersphere/swarm) +**Note**: The codebase has been moved to [ethersphere/bee](https://github.com/ethersphere/bee) From d345a4a3c6e44f271681491b133607fe532d57f7 Mon Sep 17 00:00:00 2001 From: Seungbae Yu Date: Mon, 16 Jan 2023 19:21:41 +0900 Subject: [PATCH 471/715] cmd/bootnode, cmd/utils: add 'pmp:' to --nat flag description (#26381) --- cmd/bootnode/main.go | 2 +- cmd/utils/flags.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/bootnode/main.go b/cmd/bootnode/main.go index 036b968ef83d..748113aa4841 100644 --- a/cmd/bootnode/main.go +++ b/cmd/bootnode/main.go @@ -40,7 +40,7 @@ func main() { writeAddr = flag.Bool("writeaddress", false, "write out the node's public key and quit") nodeKeyFile = flag.String("nodekey", "", "private key filename") nodeKeyHex = flag.String("nodekeyhex", "", "private key as hex (for testing)") - natdesc = flag.String("nat", "none", "port mapping mechanism (any|none|upnp|pmp|extip:)") + natdesc = flag.String("nat", "none", "port mapping mechanism (any|none|upnp|pmp|pmp:|extip:)") netrestrict = flag.String("netrestrict", "", "restrict network communication to the given IP networks (CIDR masks)") runv5 = flag.Bool("v5", false, "run a v5 topic discovery bootnode") verbosity = flag.Int("verbosity", int(log.LvlInfo), "log verbosity (0-5)") diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 9997755cf216..541c8ee82699 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -828,7 +828,7 @@ var ( } NATFlag = &cli.StringFlag{ Name: "nat", - Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:)", + Usage: "NAT port mapping mechanism (any|none|upnp|pmp|pmp:|extip:)", Value: "any", Category: flags.NetworkingCategory, } From c858da555d608eb648193554933a0976e6acba1e Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Mon, 16 Jan 2023 19:23:24 +0900 Subject: [PATCH 472/715] cmd/evm: fix typo in README.md (#26500) --- cmd/evm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/evm/README.md b/cmd/evm/README.md index 8496e7235330..296215861218 100644 --- a/cmd/evm/README.md +++ b/cmd/evm/README.md @@ -585,7 +585,7 @@ type Txs []string #### `clique` -The `clique` object provides the neccesary information to complete a clique +The `clique` object provides the necessary information to complete a clique seal of the block. ```go= From 8d4c81dab1fc944c2c3a6a44e06b7798454d8b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Mon, 16 Jan 2023 14:24:11 +0100 Subject: [PATCH 473/715] build: upgrade -dlgo version to Go 1.19.5 (#26472) --- build/checksums.txt | 28 ++++++++++++++-------------- build/ci.go | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 173087945966..a5c29353797f 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,19 +1,19 @@ # This file contains sha256 checksums of optional build dependencies. -eda74db4ac494800a3e66ee784e495bfbb9b8e535df924a8b01b1a8028b7f368 go1.19.4.src.tar.gz -44894862d996eec96ef2a39878e4e1fce4d05423fc18bdc1cbba745ebfa41253 go1.19.4.darwin-amd64.tar.gz -bb3bc5d7655b9637cfe2b5e90055dee93b0ead50e2ffd091df320d1af1ca853f go1.19.4.darwin-arm64.tar.gz -dd6c401cc6d0692995ed9b0f37482a724b5b9d9c1119d620862766c60708630f go1.19.4.freebsd-386.tar.gz -84489ebb63f1757b79574d7345c647bd40bc6414cecb868c93e24476c2d2b9b6 go1.19.4.freebsd-amd64.tar.gz -e5f0b0551e120bf3d1246cb960ec58032d7ca69e1adcf0fdb91c07da620e0c61 go1.19.4.linux-386.tar.gz -c9c08f783325c4cf840a94333159cc937f05f75d36a8b307951d5bd959cf2ab8 go1.19.4.linux-amd64.tar.gz -9df122d6baf6f2275270306b92af3b09d7973fb1259257e284dba33c0db14f1b go1.19.4.linux-arm64.tar.gz -7a51dae4f3a52d2dfeaf59367cc0b8a296deddc87e95aa619bf87d24661d2370 go1.19.4.linux-armv6l.tar.gz -fbc6c7d1d169bbdc82223d861d2fadc6add01c126533d3efbba3fdca9b362035 go1.19.4.linux-ppc64le.tar.gz -4b8d25acbdca8010c31ea8c5fd4aba93471ff6ada7a8b4fb04b935baee873dc8 go1.19.4.linux-s390x.tar.gz -51d8d895deb9883aa2daa291572f483fead69f577bf4e7cf8381c8001e37778e go1.19.4.windows-386.zip -ada490e188bfb57c7388da7c5eba7565390992b6496204d30e710d37755956b0 go1.19.4.windows-amd64.zip -66cfa12f408806c0fabfc10726a57b090c0c3ef3efddd944400af678ff10b851 go1.19.4.windows-arm64.zip +8e486e8e85a281fc5ce3f0bedc5b9d2dbf6276d7db0b25d3ec034f313da0375f go1.19.5.src.tar.gz +23d22bb6571bbd60197bee8aaa10e702f9802786c2e2ddce5c84527e86b66aa0 go1.19.5.darwin-amd64.tar.gz +4a67f2bf0601afe2177eb58f825adf83509511d77ab79174db0712dc9efa16c8 go1.19.5.darwin-arm64.tar.gz +b18a5e1e60130003896e1d1c8a9e142c7cccf6f5063d52c55dd42006434419c1 go1.19.5.freebsd-386.tar.gz +317996f7427691ff3a7ffd1b6aa089b9c66cd76f32e9107443f2f6aad1bb568a go1.19.5.freebsd-amd64.tar.gz +f68331aa7458a3598060595f5601d5731fd452bb2c62ff23095ddad68854e510 go1.19.5.linux-386.tar.gz +36519702ae2fd573c9869461990ae550c8c0d955cd28d2827a6b159fda81ff95 go1.19.5.linux-amd64.tar.gz +fc0aa29c933cec8d76f5435d859aaf42249aa08c74eb2d154689ae44c08d23b3 go1.19.5.linux-arm64.tar.gz +ec14f04bdaf4a62bdcf8b55b9b6434cc27c2df7d214d0bb7076a7597283b026a go1.19.5.linux-armv6l.tar.gz +e4032e7c52ebc48bad5c58ba8de0759b6091d9b1e59581a8a521c8c9d88dbe93 go1.19.5.linux-ppc64le.tar.gz +764871cbca841a99a24e239b63c68a4aaff4104658e3165e9ca450cac1fcbea3 go1.19.5.linux-s390x.tar.gz +8873f5871d996106b701febd979c5af022e6ea58bdbbb3817a28ab948b22c286 go1.19.5.windows-386.zip +167db91a2e40aeb453d3e59d213ecab06f62e1c4a84d13a06ccda1d999961caa go1.19.5.windows-amd64.zip +85a75555e82d8aa6f486d8d29491c593389682acce9f0c270090d5938eee30ef go1.19.5.windows-arm64.zip 20cd1215e0420db8cfa94a6cd3c9d325f7b39c07f2415a02d111568d8bc9e271 golangci-lint-1.49.0-darwin-amd64.tar.gz cabb1a4c35fe1dadbe5a81550a00871281a331e7660cd85ae16e936a7f0f6cfc golangci-lint-1.49.0-darwin-arm64.tar.gz diff --git a/build/ci.go b/build/ci.go index f3a8c5a045f7..c6a6ffca605a 100644 --- a/build/ci.go +++ b/build/ci.go @@ -148,7 +148,7 @@ var ( // This is the version of go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.19.4" + dlgoVersion = "1.19.5" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) From f2758a8dac7f0e2c54133274dc78279ce7dc32e9 Mon Sep 17 00:00:00 2001 From: ucwong Date: Mon, 16 Jan 2023 12:14:21 -0600 Subject: [PATCH 474/715] cmd/evm: typo fix in docs (#26506) --- cmd/evm/transition-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/evm/transition-test.sh b/cmd/evm/transition-test.sh index 2dac61d9669e..a2ea5341892c 100644 --- a/cmd/evm/transition-test.sh +++ b/cmd/evm/transition-test.sh @@ -476,7 +476,7 @@ type Txs []string #### `clique` -The `clique` object provides the neccesary information to complete a clique +The `clique` object provides the necessary information to complete a clique seal of the block. ```go= From 297ec0669d204f9df0558eb6e6e78626b8d3e9b1 Mon Sep 17 00:00:00 2001 From: ucwong Date: Tue, 17 Jan 2023 06:45:35 -0600 Subject: [PATCH 475/715] metrics/influxdb: fix time ticker leaks (#26507) --- metrics/influxdb/influxdb.go | 3 +++ metrics/influxdb/influxdbv2.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go index 1bf0c355edfe..748c692e1310 100644 --- a/metrics/influxdb/influxdb.go +++ b/metrics/influxdb/influxdb.go @@ -101,6 +101,9 @@ func (r *reporter) run() { intervalTicker := time.NewTicker(r.interval) pingTicker := time.NewTicker(time.Second * 5) + defer intervalTicker.Stop() + defer pingTicker.Stop() + for { select { case <-intervalTicker.C: diff --git a/metrics/influxdb/influxdbv2.go b/metrics/influxdb/influxdbv2.go index dc4c04fae16c..bfb762196cb3 100644 --- a/metrics/influxdb/influxdbv2.go +++ b/metrics/influxdb/influxdbv2.go @@ -62,6 +62,9 @@ func (r *v2Reporter) run() { intervalTicker := time.NewTicker(r.interval) pingTicker := time.NewTicker(time.Second * 5) + defer intervalTicker.Stop() + defer pingTicker.Stop() + for { select { case <-intervalTicker.C: From 97401b6c6310bf468c40f4dc2ea643aee1425a21 Mon Sep 17 00:00:00 2001 From: Paul <41552663+molecula451@users.noreply.github.com> Date: Tue, 17 Jan 2023 16:29:08 -0600 Subject: [PATCH 476/715] eth/filters: fix typo in comment (#26515) --- eth/filters/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index 0b4e9a91a885..a30eb28befd2 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -46,7 +46,7 @@ type filter struct { } // FilterAPI offers support to create and manage filters. This will allow external clients to retrieve various -// information related to the Ethereum protocol such als blocks, transactions and logs. +// information related to the Ethereum protocol such as blocks, transactions and logs. type FilterAPI struct { sys *FilterSystem events *EventSystem From 4a3fb585dd1a9e5f62057b17dd62cabc01dfadc0 Mon Sep 17 00:00:00 2001 From: ucwong Date: Wed, 18 Jan 2023 02:46:32 -0600 Subject: [PATCH 477/715] les/fetcher : fix requestTimer leak (#26514) les/fetcher : fix requestTimer leak --- les/fetcher.go | 1 + 1 file changed, 1 insertion(+) diff --git a/les/fetcher.go b/les/fetcher.go index ef37d80cd6f4..c7a55b193dcc 100644 --- a/les/fetcher.go +++ b/les/fetcher.go @@ -272,6 +272,7 @@ func (f *lightFetcher) mainloop() { localHead = f.chain.CurrentHeader() localTd = f.chain.GetTd(localHead.Hash(), localHead.Number.Uint64()) ) + defer requestTimer.Stop() sub := f.chain.SubscribeChainHeadEvent(headCh) defer sub.Unsubscribe() From a35b654f25fdac518d5775b55aa064025040b01a Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 18 Jan 2023 09:47:42 +0100 Subject: [PATCH 478/715] core/txpool: check if initcode size is exceeded (#26504) * core/txpool: check if initcode size is exceeded * core/txpool: move check --- core/txpool/txpool.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index dc6a71f07ac2..3e4eb21cfc68 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -18,6 +18,7 @@ package txpool import ( "errors" + "fmt" "math" "math/big" "sort" @@ -599,6 +600,10 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { if tx.Size() > txMaxSize { return ErrOversizedData } + // Check whether the init code size has been exceeded. + if pool.shanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + return fmt.Errorf("%w: code size %v limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) + } // Transactions can't be negative. This may never happen using RLP decoded // transactions but may occur if you create a transaction using the RPC. if tx.Value().Sign() < 0 { From 690338f0faff4c15459384b62b6287407b8953be Mon Sep 17 00:00:00 2001 From: Zachinquarantine Date: Thu, 19 Jan 2023 04:49:48 -0500 Subject: [PATCH 479/715] all: remove Kiln testnet (#26522) Kiln was deprecated after the merge. --- cmd/geth/main.go | 4 ---- cmd/utils/flags.go | 23 +---------------------- core/genesis.go | 12 ------------ params/bootnodes.go | 7 ------- params/config.go | 1 - 5 files changed, 1 insertion(+), 46 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index c6fe66cb6a29..e3ffcc5151b2 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -285,9 +285,6 @@ func prepare(ctx *cli.Context) { case ctx.IsSet(utils.SepoliaFlag.Name): log.Info("Starting Geth on Sepolia testnet...") - case ctx.IsSet(utils.KilnFlag.Name): - log.Info("Starting Geth on Kiln testnet...") - case ctx.IsSet(utils.DeveloperFlag.Name): log.Info("Starting Geth in ephemeral dev mode...") log.Warn(`You are running Geth in --dev mode. Please note the following: @@ -316,7 +313,6 @@ func prepare(ctx *cli.Context) { !ctx.IsSet(utils.SepoliaFlag.Name) && !ctx.IsSet(utils.RinkebyFlag.Name) && !ctx.IsSet(utils.GoerliFlag.Name) && - !ctx.IsSet(utils.KilnFlag.Name) && !ctx.IsSet(utils.DeveloperFlag.Name) { // Nope, we're really on mainnet. Bump that cache up! log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 541c8ee82699..4c66800d5d92 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -155,11 +155,6 @@ var ( Usage: "Sepolia network: pre-configured proof-of-work test network", Category: flags.EthCategory, } - KilnFlag = &cli.BoolFlag{ - Name: "kiln", - Usage: "Kiln network: pre-configured proof-of-work to proof-of-stake test network", - Category: flags.EthCategory, - } // Dev mode DeveloperFlag = &cli.BoolFlag{ @@ -1002,7 +997,6 @@ var ( RinkebyFlag, GoerliFlag, SepoliaFlag, - KilnFlag, } // NetworkFlags is the flag group of all built-in supported networks. NetworkFlags = append([]cli.Flag{MainnetFlag}, TestnetFlags...) @@ -1035,9 +1029,6 @@ func MakeDataDir(ctx *cli.Context) string { if ctx.Bool(SepoliaFlag.Name) { return filepath.Join(path, "sepolia") } - if ctx.Bool(KilnFlag.Name) { - return filepath.Join(path, "kiln") - } return path } Fatalf("Cannot determine default data directory, please set manually (--datadir)") @@ -1092,8 +1083,6 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { urls = params.RinkebyBootnodes case ctx.Bool(GoerliFlag.Name): urls = params.GoerliBootnodes - case ctx.Bool(KilnFlag.Name): - urls = params.KilnBootnodes } // don't apply defaults if BootstrapNodes is already set @@ -1550,8 +1539,6 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) { cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli") case ctx.Bool(SepoliaFlag.Name) && cfg.DataDir == node.DefaultDataDir(): cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia") - case ctx.Bool(KilnFlag.Name) && cfg.DataDir == node.DefaultDataDir(): - cfg.DataDir = filepath.Join(node.DefaultDataDir(), "kiln") } } @@ -1742,7 +1729,7 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) { // SetEthConfig applies eth-related command line flags to the config. func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // Avoid conflicting network flags - CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, SepoliaFlag, KilnFlag) + CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, SepoliaFlag) CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light") CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer if ctx.String(GCModeFlag.Name) == "archive" && ctx.Uint64(TxLookupLimitFlag.Name) != 0 { @@ -1917,12 +1904,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { } cfg.Genesis = core.DefaultGoerliGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash) - case ctx.Bool(KilnFlag.Name): - if !ctx.IsSet(NetworkIdFlag.Name) { - cfg.NetworkId = 1337802 - } - cfg.Genesis = core.DefaultKilnGenesisBlock() - SetDNSDiscoveryDefaults(cfg, params.KilnGenesisHash) case ctx.Bool(DeveloperFlag.Name): if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 1337 @@ -2230,8 +2211,6 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { genesis = core.DefaultRinkebyGenesisBlock() case ctx.Bool(GoerliFlag.Name): genesis = core.DefaultGoerliGenesisBlock() - case ctx.Bool(KilnFlag.Name): - genesis = core.DefaultKilnGenesisBlock() case ctx.Bool(DeveloperFlag.Name): Fatalf("Developer chains are ephemeral") } diff --git a/core/genesis.go b/core/genesis.go index c3c2381eeb4d..47974f63ab33 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -431,8 +431,6 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { return params.RinkebyChainConfig case ghash == params.GoerliGenesisHash: return params.GoerliChainConfig - case ghash == params.KilnGenesisHash: - return DefaultKilnGenesisBlock().Config default: return params.AllEthashProtocolChanges } @@ -581,16 +579,6 @@ func DefaultSepoliaGenesisBlock() *Genesis { } } -// DefaultKilnGenesisBlock returns the kiln network genesis block. -func DefaultKilnGenesisBlock() *Genesis { - g := new(Genesis) - reader := strings.NewReader(KilnAllocData) - if err := json.NewDecoder(reader).Decode(g); err != nil { - panic(err) - } - return g -} - // DeveloperGenesisBlock returns the 'geth --dev' genesis block. func DeveloperGenesisBlock(period uint64, gasLimit uint64, faucet common.Address) *Genesis { // Override the default period to the user requested one diff --git a/params/bootnodes.go b/params/bootnodes.go index b80997774536..1e2bfa5a0876 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -75,13 +75,6 @@ var GoerliBootnodes = []string{ "enode://d2b720352e8216c9efc470091aa91ddafc53e222b32780f505c817ceef69e01d5b0b0797b69db254c586f493872352f5a022b4d8479a00fc92ec55f9ad46a27e@88.99.70.182:30303", } -var KilnBootnodes = []string{ - "enode://c354db99124f0faf677ff0e75c3cbbd568b2febc186af664e0c51ac435609badedc67a18a63adb64dacc1780a28dcefebfc29b83fd1a3f4aa3c0eb161364cf94@164.92.130.5:30303", - "enode://d41af1662434cad0a88fe3c7c92375ec5719f4516ab6d8cb9695e0e2e815382c767038e72c224e04040885157da47422f756c040a9072676c6e35c5b1a383cce@138.68.66.103:30303", - "enode://91a745c3fb069f6b99cad10b75c463d527711b106b622756e9ef9f12d2631b6cb885f831d1c8731b9bc7177cae5e1ea1f1be087f86d7d30b590a91f22bc041b0@165.232.180.230:30303", - "enode://b74bd2e8a9f0c53f0c93bcce80818f2f19439fd807af5c7fbc3efb10130c6ee08be8f3aaec7dc0a057ad7b2a809c8f34dc62431e9b6954b07a6548cc59867884@164.92.140.200:30303", -} - var V5Bootnodes = []string{ // Teku team's bootnode "enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2Gxb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNlY3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA", diff --git a/params/config.go b/params/config.go index e3ebffdfb047..9c9942f8b22c 100644 --- a/params/config.go +++ b/params/config.go @@ -32,7 +32,6 @@ var ( SepoliaGenesisHash = common.HexToHash("0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9") RinkebyGenesisHash = common.HexToHash("0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177") GoerliGenesisHash = common.HexToHash("0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a") - KilnGenesisHash = common.HexToHash("0x51c7fe41be669f69c45c33a56982cbde405313342d9e2b00d7c91a7b284dd4f8") ) // TrustedCheckpoints associates each known checkpoint with the genesis hash of From 2d2c069ffe6db76133d07e14e5db4a3c761fa3f5 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Thu, 19 Jan 2023 19:43:29 +0100 Subject: [PATCH 480/715] console, internal/jsre: fix autocomplete issues (#26518) Fixes #26505 where the console crashed when a property getter raised an exception during autocompletion. I also noticed while fixing this issue that autocomplete wasn't working for objects/fields with numbers in them (most importantly web3.) which is also now fixed. --- console/console.go | 8 ++------ internal/jsre/completion.go | 13 ++++++++++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/console/console.go b/console/console.go index fde673be8be9..f72c3507244a 100644 --- a/console/console.go +++ b/console/console.go @@ -305,12 +305,8 @@ func (c *Console) AutoCompleteInput(line string, pos int) (string, []string, str start := pos - 1 for ; start > 0; start-- { // Skip all methods and namespaces (i.e. including the dot) - if line[start] == '.' || (line[start] >= 'a' && line[start] <= 'z') || (line[start] >= 'A' && line[start] <= 'Z') { - continue - } - // Handle web3 in a special way (i.e. other numbers aren't auto completed) - if start >= 3 && line[start-3:start] == "web3" { - start -= 3 + c := line[start] + if c == '.' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '1' && c <= '9') { continue } // We've hit an unexpected character, autocomplete form here diff --git a/internal/jsre/completion.go b/internal/jsre/completion.go index 538fca298dde..844a0532fdba 100644 --- a/internal/jsre/completion.go +++ b/internal/jsre/completion.go @@ -17,12 +17,16 @@ package jsre import ( + "regexp" "sort" "strings" "github.com/dop251/goja" ) +// JS numerical token +var numerical = regexp.MustCompile(`^(NaN|-?((\d*\.\d+|\d+)([Ee][+-]?\d+)?|Infinity))$`) + // CompleteKeywords returns potential continuations for the given line. Since line is // evaluated, callers need to make sure that evaluating line does not have side effects. func (jsre *JSRE) CompleteKeywords(line string) []string { @@ -43,6 +47,9 @@ func getCompletions(vm *goja.Runtime, line string) (results []string) { // and "x.y" is an object, obj will reference "x.y". obj := vm.GlobalObject() for i := 0; i < len(parts)-1; i++ { + if numerical.MatchString(parts[i]) { + return nil + } v := obj.Get(parts[i]) if v == nil || goja.IsNull(v) || goja.IsUndefined(v) { return nil // No object was found @@ -67,7 +74,11 @@ func getCompletions(vm *goja.Runtime, line string) (results []string) { // Append opening parenthesis (for functions) or dot (for objects) // if the line itself is the only completion. if len(results) == 1 && results[0] == line { - obj := obj.Get(parts[len(parts)-1]) + // Accessing the property will cause it to be evaluated. + // This can cause an error, e.g. in case of web3.eth.protocolVersion + // which has been dropped from geth. Ignore the error for autocompletion + // purposes. + obj := SafeGet(obj, parts[len(parts)-1]) if obj != nil { if _, isfunc := goja.AssertFunction(obj); isfunc { results[0] += "(" From 24c7023df6056c157b812d91a6c53b6f5b9ae252 Mon Sep 17 00:00:00 2001 From: meehow Date: Fri, 20 Jan 2023 10:33:41 +0100 Subject: [PATCH 481/715] go.mod: upgrade to go-bip39 v1.1.0 (#26527) --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2012eda30885..fd401b26a455 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,7 @@ require ( github.com/stretchr/testify v1.7.2 github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef + github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa golang.org/x/crypto v0.1.0 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 diff --git a/go.sum b/go.sum index 9e54fafbd6e9..0376f1fded1f 100644 --- a/go.sum +++ b/go.sum @@ -413,6 +413,8 @@ github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefld github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= From 87489723ac337f89879bd58170dac198cfbec00f Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 20 Jan 2023 03:53:24 -0600 Subject: [PATCH 482/715] go.sum: tidy (#26525) --- go.sum | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/go.sum b/go.sum index 0376f1fded1f..1396f43b66e8 100644 --- a/go.sum +++ b/go.sum @@ -25,7 +25,6 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -65,12 +64,10 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2 github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -94,8 +91,6 @@ github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhr github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= -github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= @@ -123,7 +118,6 @@ github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0= @@ -226,7 +220,6 @@ github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpx github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw= github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= @@ -286,7 +279,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= @@ -332,7 +324,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= @@ -369,7 +360,6 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= -github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -389,7 +379,6 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -416,7 +405,6 @@ github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:s github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -427,8 +415,6 @@ github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6Ut github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -445,7 +431,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -458,7 +443,6 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -478,8 +462,6 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -507,9 +489,6 @@ golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -563,20 +542,12 @@ golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -617,12 +588,10 @@ golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191126055441-b0650ceb63d9/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 3f544ce8ebd90f985bdbe3162fec677ab2e91d35 Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 20 Jan 2023 03:54:53 -0600 Subject: [PATCH 483/715] .travis.yml: go1.19.5 for android builds (#26524) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a32b44506664..1dc2c20a7a04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -148,7 +148,7 @@ jobs: - sdkmanager "platform-tools" "platforms;android-15" "platforms;android-19" "platforms;android-24" "ndk-bundle" # Install Go to allow building with - - curl https://dl.google.com/go/go1.18.linux-amd64.tar.gz | tar -xz + - curl https://dl.google.com/go/go1.19.5.linux-amd64.tar.gz | tar -xz - export PATH=`pwd`/go/bin:$PATH - export GOROOT=`pwd`/go - export GOPATH=$HOME/go From 50e65392aacdb3f03dc6cdbd73059aff38642106 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 20 Jan 2023 17:57:50 +0800 Subject: [PATCH 484/715] params: define cancun and prague as timestamp based forks (#26481) * params: define cancun and osaka as timestamp based forks * core, params: change osaka to prague * params: fix --- core/forkid/forkid_test.go | 10 +-- params/config.go | 169 +++++++++++++++++++++++++++++++------ 2 files changed, 148 insertions(+), 31 deletions(-) diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index 4e8b4f411189..7d6e89c81178 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -387,10 +387,10 @@ func TestValidation(t *testing.T) { // TODO(karalabe): Enable this when Cancun is specced, update local head and time, next timestamp //{×tampedConfig, 21123456, 1678123456, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, nil}, - // Local is mainnet Osaka, remote announces Shanghai + knowledge about Cancun. Remote - // is definitely out of sync. It may or may not need the Osaka update, we don't know yet. + // Local is mainnet Prague, remote announces Shanghai + knowledge about Cancun. Remote + // is definitely out of sync. It may or may not need the Prague update, we don't know yet. // - // TODO(karalabe): Enable this when Cancun **and** Osaka is specced, update all the numbers + // TODO(karalabe): Enable this when Cancun **and** Prague is specced, update all the numbers //{×tampedConfig, 0, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, // Local is mainnet Shanghai, remote announces Cancun. Local is out of sync, accept. @@ -398,10 +398,10 @@ func TestValidation(t *testing.T) { // TODO(karalabe): Enable this when Cancun is specced, update remote checksum //{×tampedConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x00000000), Next: 0}, nil}, - // Local is mainnet Shanghai, remote announces Cancun, but is not aware of Osaka. Local + // Local is mainnet Shanghai, remote announces Cancun, but is not aware of Prague. Local // out of sync. Local also knows about a future fork, but that is uncertain yet. // - // TODO(karalabe): Enable this when Cancun **and** Osaka is specced, update remote checksum + // TODO(karalabe): Enable this when Cancun **and** Prague is specced, update remote checksum //{×tampedConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x00000000), Next: 0}, nil}, // Local is mainnet Cancun. remote announces Shanghai but is not aware of further forks. diff --git a/params/config.go b/params/config.go index 9c9942f8b22c..41072d3eac88 100644 --- a/params/config.go +++ b/params/config.go @@ -266,21 +266,124 @@ var ( // AllEthashProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Ethash consensus. - // - // This configuration is intentionally not using keyed fields to force anyone - // adding flags to the config to also have to set these fields. - AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(EthashConfig), nil} + AllEthashProtocolChanges = &ChainConfig{ + ChainID: big.NewInt(1337), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + EIP150Block: big.NewInt(0), + EIP150Hash: common.Hash{}, + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + GrayGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: nil, + ShanghaiTime: nil, + CancunTime: nil, + PragueTime: nil, + TerminalTotalDifficulty: nil, + TerminalTotalDifficultyPassed: false, + Ethash: new(EthashConfig), + Clique: nil, + } // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. - // - // This configuration is intentionally not using keyed fields to force anyone - // adding flags to the config to also have to set these fields. - AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, false, nil, &CliqueConfig{Period: 0, Epoch: 30000}} - - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(EthashConfig), nil} - NonActivatedConfig = &ChainConfig{big.NewInt(1), nil, nil, false, nil, common.Hash{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, false, new(EthashConfig), nil} - TestRules = TestChainConfig.Rules(new(big.Int), false, new(big.Int)) + AllCliqueProtocolChanges = &ChainConfig{ + ChainID: big.NewInt(1337), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + EIP150Block: big.NewInt(0), + EIP150Hash: common.Hash{}, + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: nil, + GrayGlacierBlock: nil, + MergeNetsplitBlock: nil, + ShanghaiTime: nil, + CancunTime: nil, + PragueTime: nil, + TerminalTotalDifficulty: nil, + TerminalTotalDifficultyPassed: false, + Ethash: nil, + Clique: &CliqueConfig{Period: 0, Epoch: 30000}, + } + + // TestChainConfig contains every protocol change (EIPs) introduced + // and accepted by the Ethereum core developers for testing proposes. + TestChainConfig = &ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: false, + EIP150Block: big.NewInt(0), + EIP150Hash: common.Hash{}, + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + GrayGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: nil, + ShanghaiTime: nil, + CancunTime: nil, + PragueTime: nil, + TerminalTotalDifficulty: nil, + TerminalTotalDifficultyPassed: false, + Ethash: new(EthashConfig), + Clique: nil, + } + + // NonActivatedConfig defines the chain configuration without activating + // any protocol change (EIPs). + NonActivatedConfig = &ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: nil, + DAOForkBlock: nil, + DAOForkSupport: false, + EIP150Block: nil, + EIP150Hash: common.Hash{}, + EIP155Block: nil, + EIP158Block: nil, + ByzantiumBlock: nil, + ConstantinopleBlock: nil, + PetersburgBlock: nil, + IstanbulBlock: nil, + MuirGlacierBlock: nil, + BerlinBlock: nil, + LondonBlock: nil, + ArrowGlacierBlock: nil, + GrayGlacierBlock: nil, + MergeNetsplitBlock: nil, + ShanghaiTime: nil, + CancunTime: nil, + PragueTime: nil, + TerminalTotalDifficulty: nil, + TerminalTotalDifficultyPassed: false, + Ethash: new(EthashConfig), + Clique: nil, + } + TestRules = TestChainConfig.Rules(new(big.Int), false, new(big.Int)) ) // NetworkNames are user friendly names to use in the chain spec banner. @@ -370,11 +473,12 @@ type ChainConfig struct { ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated) GrayGlacierBlock *big.Int `json:"grayGlacierBlock,omitempty"` // Eip-5133 (bomb delay) switch block (nil = no fork, 0 = already activated) MergeNetsplitBlock *big.Int `json:"mergeNetsplitBlock,omitempty"` // Virtual fork after The Merge to use as a network splitter - CancunBlock *big.Int `json:"cancunBlock,omitempty"` // Cancun switch block (nil = no fork, 0 = already on cancun) // Fork scheduling was switched from blocks to timestamps here ShanghaiTime *big.Int `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) + CancunTime *big.Int `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun) + PragueTime *big.Int `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. @@ -489,8 +593,11 @@ func (c *ChainConfig) Description() string { if c.ShanghaiTime != nil { banner += fmt.Sprintf(" - Shanghai: @%-10v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", c.ShanghaiTime) } - if c.CancunBlock != nil { - banner += fmt.Sprintf(" - Cancun: @%-10v\n", c.CancunBlock) + if c.CancunTime != nil { + banner += fmt.Sprintf(" - Cancun: @%-10v\n", c.CancunTime) + } + if c.PragueTime != nil { + banner += fmt.Sprintf(" - Prague: @%-10v\n", c.PragueTime) } return banner } @@ -575,16 +682,21 @@ func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *bi return parentTotalDiff.Cmp(c.TerminalTotalDifficulty) < 0 && totalDiff.Cmp(c.TerminalTotalDifficulty) >= 0 } -// IsCancun returns whether num is either equal to the Cancun fork block or greater. -func (c *ChainConfig) IsCancun(num *big.Int) bool { - return isBlockForked(c.CancunBlock, num) -} - // IsShanghai returns whether time is either equal to the Shanghai fork time or greater. func (c *ChainConfig) IsShanghai(time *big.Int) bool { return isTimestampForked(c.ShanghaiTime, time) } +// IsCancun returns whether num is either equal to the Cancun fork time or greater. +func (c *ChainConfig) IsCancun(time *big.Int) bool { + return isTimestampForked(c.CancunTime, time) +} + +// IsPrague returns whether num is either equal to the Prague fork time or greater. +func (c *ChainConfig) IsPrague(time *big.Int) bool { + return isTimestampForked(c.PragueTime, time) +} + // CheckCompatible checks whether scheduled fork transitions have been imported // with a mismatching chain configuration. func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError { @@ -636,8 +748,9 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "arrowGlacierBlock", block: c.ArrowGlacierBlock, optional: true}, {name: "grayGlacierBlock", block: c.GrayGlacierBlock, optional: true}, {name: "mergeNetsplitBlock", block: c.MergeNetsplitBlock, optional: true}, - {name: "cancunBlock", block: c.CancunBlock, optional: true}, {name: "shanghaiTime", timestamp: c.ShanghaiTime}, + {name: "cancunTime", timestamp: c.CancunTime, optional: true}, + {name: "pragueTime", timestamp: c.PragueTime, optional: true}, } { if lastFork.name != "" { switch { @@ -732,12 +845,15 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, if isForkBlockIncompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, headNumber) { return newBlockCompatError("Merge netsplit fork block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock) } - if isForkBlockIncompatible(c.CancunBlock, newcfg.CancunBlock, headNumber) { - return newBlockCompatError("Cancun fork block", c.CancunBlock, newcfg.CancunBlock) - } if isForkTimestampIncompatible(c.ShanghaiTime, newcfg.ShanghaiTime, headTimestamp) { return newTimestampCompatError("Shanghai fork timestamp", c.ShanghaiTime, newcfg.ShanghaiTime) } + if isForkTimestampIncompatible(c.CancunTime, newcfg.CancunTime, headTimestamp) { + return newTimestampCompatError("Cancun fork timestamp", c.CancunTime, newcfg.CancunTime) + } + if isForkTimestampIncompatible(c.PragueTime, newcfg.PragueTime, headTimestamp) { + return newTimestampCompatError("Prague fork timestamp", c.PragueTime, newcfg.PragueTime) + } return nil } @@ -882,7 +998,7 @@ type Rules struct { IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool - IsMerge, IsShanghai, isCancun bool + IsMerge, IsShanghai, isCancun, isPrague bool } // Rules ensures c's ChainID is not nil. @@ -905,6 +1021,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp *big.Int) Rule IsLondon: c.IsLondon(num), IsMerge: isMerge, IsShanghai: c.IsShanghai(timestamp), - isCancun: c.IsCancun(num), + isCancun: c.IsCancun(timestamp), + isPrague: c.IsPrague(timestamp), } } From 4f4a25d79f75fd30652922d5a4307cfc8c0cee7b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 20 Jan 2023 05:01:33 -0500 Subject: [PATCH 485/715] signer/core: don't require capital lettered reference types (#26462) --- signer/core/apitypes/types.go | 31 +++---- signer/core/signed_data_test.go | 150 ++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 21 deletions(-) diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 3e099feaab7b..c72cad5939cf 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -27,8 +27,6 @@ import ( "sort" "strconv" "strings" - "unicode" - "unicode/utf8" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" @@ -38,7 +36,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) -var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Z](\w*)(\[\])?$`) +var typedDataReferenceTypeRegexp = regexp.MustCompile(`^[A-Za-z](\w*)(\[\])?$`) type ValidationInfo struct { Typ string `json:"type"` @@ -224,15 +222,6 @@ func (t *Type) typeName() string { return t.Type } -func (t *Type) isReferenceType() bool { - if len(t.Type) == 0 { - return false - } - // Reference types must have a leading uppercase character - r, _ := utf8.DecodeRuneInString(t.Type) - return unicode.IsUpper(r) -} - type Types map[string][]Type type TypePriority struct { @@ -731,15 +720,15 @@ func (t Types) validate() error { if typeKey == typeObj.Type { return fmt.Errorf("type %q cannot reference itself", typeObj.Type) } - if typeObj.isReferenceType() { - if _, exist := t[typeObj.typeName()]; !exist { - return fmt.Errorf("reference type %q is undefined", typeObj.Type) - } - if !typedDataReferenceTypeRegexp.MatchString(typeObj.Type) { - return fmt.Errorf("unknown reference type %q", typeObj.Type) - } - } else if !isPrimitiveTypeValid(typeObj.Type) { - return fmt.Errorf("unknown type %q", typeObj.Type) + if isPrimitiveTypeValid(typeObj.Type) { + continue + } + // Must be reference type + if _, exist := t[typeObj.typeName()]; !exist { + return fmt.Errorf("reference type %q is undefined", typeObj.Type) + } + if !typedDataReferenceTypeRegexp.MatchString(typeObj.Type) { + return fmt.Errorf("unknown reference type %q", typeObj.Type) } } } diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index 608b2adebed4..3e3837cae281 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -848,3 +848,153 @@ func TestGnosisSafe(t *testing.T) { t.Fatal("expected equality") } } + +var complexTypedDataLCRefType = ` +{ + "types": { + "EIP712Domain": [ + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "verifyingContract", + "type": "address" + }, + { + "name": "version", + "type": "string" + } + ], + "Action": [ + { + "name": "action", + "type": "string" + }, + { + "name": "params", + "type": "string" + } + ], + "cCell": [ + { + "name": "capacity", + "type": "string" + }, + { + "name": "lock", + "type": "string" + }, + { + "name": "type", + "type": "string" + }, + { + "name": "data", + "type": "string" + }, + { + "name": "extraData", + "type": "string" + } + ], + "Transaction": [ + { + "name": "DAS_MESSAGE", + "type": "string" + }, + { + "name": "inputsCapacity", + "type": "string" + }, + { + "name": "outputsCapacity", + "type": "string" + }, + { + "name": "fee", + "type": "string" + }, + { + "name": "action", + "type": "Action" + }, + { + "name": "inputs", + "type": "cCell[]" + }, + { + "name": "outputs", + "type": "cCell[]" + }, + { + "name": "digest", + "type": "bytes32" + } + ] + }, + "primaryType": "Transaction", + "domain": { + "chainId": "56", + "name": "da.systems", + "verifyingContract": "0x0000000000000000000000000000000020210722", + "version": "1" + }, + "message": { + "DAS_MESSAGE": "SELL mobcion.bit FOR 100000 CKB", + "inputsCapacity": "1216.9999 CKB", + "outputsCapacity": "1216.9998 CKB", + "fee": "0.0001 CKB", + "digest": "0x53a6c0f19ec281604607f5d6817e442082ad1882bef0df64d84d3810dae561eb", + "action": { + "action": "start_account_sale", + "params": "0x00" + }, + "inputs": [ + { + "capacity": "218 CKB", + "lock": "das-lock,0x01,0x051c152f77f8efa9c7c6d181cc97ee67c165c506...", + "type": "account-cell-type,0x01,0x", + "data": "{ account: mobcion.bit, expired_at: 1670913958 }", + "extraData": "{ status: 0, records_hash: 0x55478d76900611eb079b22088081124ed6c8bae21a05dd1a0d197efcc7c114ce }" + } + ], + "outputs": [ + { + "capacity": "218 CKB", + "lock": "das-lock,0x01,0x051c152f77f8efa9c7c6d181cc97ee67c165c506...", + "type": "account-cell-type,0x01,0x", + "data": "{ account: mobcion.bit, expired_at: 1670913958 }", + "extraData": "{ status: 1, records_hash: 0x55478d76900611eb079b22088081124ed6c8bae21a05dd1a0d197efcc7c114ce }" + }, + { + "capacity": "201 CKB", + "lock": "das-lock,0x01,0x051c152f77f8efa9c7c6d181cc97ee67c165c506...", + "type": "account-sale-cell-type,0x01,0x", + "data": "0x1209460ef3cb5f1c68ed2c43a3e020eec2d9de6e...", + "extraData": "" + } + ] + } +} +` + +func TestComplexTypedDataWithLowercaseReftype(t *testing.T) { + var td apitypes.TypedData + err := json.Unmarshal([]byte(complexTypedDataLCRefType), &td) + if err != nil { + t.Fatalf("unmarshalling failed '%v'", err) + } + _, sighash, err := sign(td) + if err != nil { + t.Fatal(err) + } + expSigHash := common.FromHex("0x49191f910874f0148597204d9076af128d4694a7c4b714f1ccff330b87207bff") + if !bytes.Equal(expSigHash, sighash) { + t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash) + } +} From 2b44ef5f93cc7479a77890917a29684b56e9167a Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Sat, 21 Jan 2023 00:26:01 +0800 Subject: [PATCH 486/715] miner, cmd, eth: require explicit etherbase address (#26413) This change introduces a breaking change to miner.etherbase is configured. Previously, users did not need to explicitly set the etherbase address via flag, since 'first' local account was used as etherbase automatically. This change removes the "default first account" feature. In Proof-of-stake world, the fee recipient address is provided by CL, and not configured in Geth any more - meaning that miner.etherbase is mostly for legacy networks(pow, clique networks etc). --- cmd/geth/les_test.go | 2 +- cmd/utils/flags.go | 41 +++++++++++++++++------------------------ eth/backend.go | 14 +------------- miner/miner.go | 31 +++++++++++++------------------ miner/miner_test.go | 33 ++++++++++++++++++--------------- miner/worker.go | 17 +++++++++++++---- 6 files changed, 63 insertions(+), 75 deletions(-) diff --git a/cmd/geth/les_test.go b/cmd/geth/les_test.go index d06c3b91d8a5..607b454eadfb 100644 --- a/cmd/geth/les_test.go +++ b/cmd/geth/les_test.go @@ -146,7 +146,7 @@ func startLightServer(t *testing.T) *gethrpc { t.Logf("Importing keys to geth") runGeth(t, "account", "import", "--datadir", datadir, "--password", "./testdata/password.txt", "--lightkdf", "./testdata/key.prv").WaitExit() account := "0x02f0d131f1f97aef08aec6e3291b957d9efe7105" - server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--mine", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1", "--verbosity=4") + server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--miner.etherbase=0x02f0d131f1f97aef08aec6e3291b957d9efe7105", "--mine", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1", "--verbosity=4") return server } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 4c66800d5d92..4bee6093ea28 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -538,8 +538,7 @@ var ( } MinerEtherbaseFlag = &cli.StringFlag{ Name: "miner.etherbase", - Usage: "Public address for block mining rewards (default = first account)", - Value: "0", + Usage: "0x prefixed public address for block mining rewards", Category: flags.MinerCategory, } MinerExtraDataFlag = &cli.StringFlag{ @@ -1343,25 +1342,15 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error return accs[index], nil } -// setEtherbase retrieves the etherbase either from the directly specified -// command line flags or from the keystore if CLI indexed. -func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *ethconfig.Config) { - // Extract the current etherbase - var etherbase string +// setEtherbase retrieves the etherbase from the directly specified command line flags. +func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) { if ctx.IsSet(MinerEtherbaseFlag.Name) { - etherbase = ctx.String(MinerEtherbaseFlag.Name) - } - // Convert the etherbase into an address and configure it - if etherbase != "" { - if ks != nil { - account, err := MakeAddress(ks, etherbase) - if err != nil { - Fatalf("Invalid miner etherbase: %v", err) - } - cfg.Miner.Etherbase = account.Address - } else { - Fatalf("No etherbase configured") + b, err := hexutil.Decode(ctx.String(MinerEtherbaseFlag.Name)) + if err != nil || len(b) != common.AddressLength { + log.Info("Failed to decode etherbase", "err", err) + return } + cfg.Miner.Etherbase = common.BytesToAddress(b) } } @@ -1739,11 +1728,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ctx.IsSet(LightServeFlag.Name) && ctx.Uint64(TxLookupLimitFlag.Name) != 0 { log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited") } - var ks *keystore.KeyStore - if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { - ks = keystores[0].(*keystore.KeyStore) - } - setEtherbase(ctx, ks, cfg) + setEtherbase(ctx, cfg) setGPO(ctx, &cfg.GPO, ctx.String(SyncModeFlag.Name) == "light") setTxPool(ctx, &cfg.TxPool) setEthash(ctx, cfg) @@ -1921,6 +1906,14 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // when we're definitely concerned with only one account. passphrase = list[0] } + // Unlock the developer account by local keystore. + var ks *keystore.KeyStore + if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { + ks = keystores[0].(*keystore.KeyStore) + } + if ks == nil { + Fatalf("Keystore is not available") + } // setEtherbase has been called above, configuring the miner address from command line flags. if cfg.Miner.Etherbase != (common.Address{}) { developer = accounts.Account{Address: cfg.Miner.Etherbase} diff --git a/eth/backend.go b/eth/backend.go index 6b1c04468922..6368c0e03c56 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -329,18 +329,6 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) { if etherbase != (common.Address{}) { return etherbase, nil } - if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { - if accounts := wallets[0].Accounts(); len(accounts) > 0 { - etherbase := accounts[0].Address - - s.lock.Lock() - s.etherbase = etherbase - s.lock.Unlock() - - log.Info("Etherbase automatically configured", "address", etherbase) - return etherbase, nil - } - } return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") } @@ -456,7 +444,7 @@ func (s *Ethereum) StartMining(threads int) error { // introduced to speed sync times. atomic.StoreUint32(&s.handler.acceptTxs, 1) - go s.miner.Start(eb) + go s.miner.Start() } return nil } diff --git a/miner/miner.go b/miner/miner.go index 5102cb523c39..c969aec73546 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -45,7 +45,7 @@ type Backend interface { // Config is the configuration parameters of mining. type Config struct { - Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards (default = first account) + Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages (only useful in ethash). NotifyFull bool `toml:",omitempty"` // Notify with pending block headers instead of work packages ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner @@ -73,25 +73,24 @@ var DefaultConfig = Config{ // Miner creates blocks and searches for proof-of-work values. type Miner struct { - mux *event.TypeMux - worker *worker - coinbase common.Address - eth Backend - engine consensus.Engine - exitCh chan struct{} - startCh chan common.Address - stopCh chan struct{} + mux *event.TypeMux + eth Backend + engine consensus.Engine + exitCh chan struct{} + startCh chan struct{} + stopCh chan struct{} + worker *worker wg sync.WaitGroup } func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, isLocalBlock func(header *types.Header) bool) *Miner { miner := &Miner{ - eth: eth, mux: mux, + eth: eth, engine: engine, exitCh: make(chan struct{}), - startCh: make(chan common.Address), + startCh: make(chan struct{}), stopCh: make(chan struct{}), worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true), } @@ -138,20 +137,17 @@ func (miner *Miner) update() { case downloader.FailedEvent: canStart = true if shouldStart { - miner.SetEtherbase(miner.coinbase) miner.worker.start() } case downloader.DoneEvent: canStart = true if shouldStart { - miner.SetEtherbase(miner.coinbase) miner.worker.start() } // Stop reacting to downloader events events.Unsubscribe() } - case addr := <-miner.startCh: - miner.SetEtherbase(addr) + case <-miner.startCh: if canStart { miner.worker.start() } @@ -166,8 +162,8 @@ func (miner *Miner) update() { } } -func (miner *Miner) Start(coinbase common.Address) { - miner.startCh <- coinbase +func (miner *Miner) Start() { + miner.startCh <- struct{}{} } func (miner *Miner) Stop() { @@ -223,7 +219,6 @@ func (miner *Miner) PendingBlockAndReceipts() (*types.Block, types.Receipts) { } func (miner *Miner) SetEtherbase(addr common.Address) { - miner.coinbase = addr miner.worker.setEtherbase(addr) } diff --git a/miner/miner_test.go b/miner/miner_test.go index 7bf091f375e5..2e7682acd331 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -86,7 +86,8 @@ func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) func TestMiner(t *testing.T) { miner, mux, cleanup := createMiner(t) defer cleanup(false) - miner.Start(common.HexToAddress("0x12345")) + + miner.Start() waitForMiningState(t, miner, true) // Start the downloader mux.Post(downloader.StartEvent{}) @@ -114,7 +115,8 @@ func TestMiner(t *testing.T) { func TestMinerDownloaderFirstFails(t *testing.T) { miner, mux, cleanup := createMiner(t) defer cleanup(false) - miner.Start(common.HexToAddress("0x12345")) + + miner.Start() waitForMiningState(t, miner, true) // Start the downloader mux.Post(downloader.StartEvent{}) @@ -146,7 +148,8 @@ func TestMinerDownloaderFirstFails(t *testing.T) { func TestMinerStartStopAfterDownloaderEvents(t *testing.T) { miner, mux, cleanup := createMiner(t) defer cleanup(false) - miner.Start(common.HexToAddress("0x12345")) + + miner.Start() waitForMiningState(t, miner, true) // Start the downloader mux.Post(downloader.StartEvent{}) @@ -159,7 +162,7 @@ func TestMinerStartStopAfterDownloaderEvents(t *testing.T) { miner.Stop() waitForMiningState(t, miner, false) - miner.Start(common.HexToAddress("0x678910")) + miner.Start() waitForMiningState(t, miner, true) miner.Stop() @@ -170,13 +173,13 @@ func TestStartWhileDownload(t *testing.T) { miner, mux, cleanup := createMiner(t) defer cleanup(false) waitForMiningState(t, miner, false) - miner.Start(common.HexToAddress("0x12345")) + miner.Start() waitForMiningState(t, miner, true) // Stop the downloader and wait for the update loop to run mux.Post(downloader.StartEvent{}) waitForMiningState(t, miner, false) // Starting the miner after the downloader should not work - miner.Start(common.HexToAddress("0x12345")) + miner.Start() waitForMiningState(t, miner, false) } @@ -184,7 +187,7 @@ func TestStartStopMiner(t *testing.T) { miner, _, cleanup := createMiner(t) defer cleanup(false) waitForMiningState(t, miner, false) - miner.Start(common.HexToAddress("0x12345")) + miner.Start() waitForMiningState(t, miner, true) miner.Stop() waitForMiningState(t, miner, false) @@ -194,7 +197,7 @@ func TestCloseMiner(t *testing.T) { miner, _, cleanup := createMiner(t) defer cleanup(true) waitForMiningState(t, miner, false) - miner.Start(common.HexToAddress("0x12345")) + miner.Start() waitForMiningState(t, miner, true) // Terminate the miner and wait for the update loop to run miner.Close() @@ -206,21 +209,21 @@ func TestCloseMiner(t *testing.T) { func TestMinerSetEtherbase(t *testing.T) { miner, mux, cleanup := createMiner(t) defer cleanup(false) - // Start with a 'bad' mining address - miner.Start(common.HexToAddress("0xdead")) + miner.Start() waitForMiningState(t, miner, true) // Start the downloader mux.Post(downloader.StartEvent{}) waitForMiningState(t, miner, false) // Now user tries to configure proper mining address - miner.Start(common.HexToAddress("0x1337")) + miner.Start() // Stop the downloader and wait for the update loop to run mux.Post(downloader.DoneEvent{}) - waitForMiningState(t, miner, true) - // The miner should now be using the good address - if got, exp := miner.coinbase, common.HexToAddress("0x1337"); got != exp { - t.Fatalf("Wrong coinbase, got %x expected %x", got, exp) + + coinbase := common.HexToAddress("0xdeedbeef") + miner.SetEtherbase(coinbase) + if addr := miner.worker.etherbase(); addr != coinbase { + t.Fatalf("Unexpected etherbase want %x got %x", coinbase, addr) } } diff --git a/miner/worker.go b/miner/worker.go index 45450237fe6d..ee4969623d12 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -276,12 +276,14 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus chainConfig: chainConfig, engine: engine, eth: eth, - mux: mux, chain: eth.BlockChain(), + mux: mux, isLocalBlock: isLocalBlock, localUncles: make(map[common.Hash]*types.Block), remoteUncles: make(map[common.Hash]*types.Block), unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), sealingLogAtDepth), + coinbase: config.Etherbase, + extra: config.ExtraData, pendingTasks: make(map[common.Hash]*task), txsCh: make(chan core.NewTxsEvent, txChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), @@ -290,8 +292,8 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus getWorkCh: make(chan *getWorkReq), taskCh: make(chan *task), resultCh: make(chan *types.Block, resultQueueSize), - exitCh: make(chan struct{}), startCh: make(chan struct{}, 1), + exitCh: make(chan struct{}), resubmitIntervalCh: make(chan time.Duration), resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize), } @@ -340,6 +342,13 @@ func (w *worker) setEtherbase(addr common.Address) { w.coinbase = addr } +// etherbase retrieves the configured etherbase address. +func (w *worker) etherbase() common.Address { + w.mu.RLock() + defer w.mu.RUnlock() + return w.coinbase +} + func (w *worker) setGasCeil(ceil uint64) { w.mu.Lock() defer w.mu.Unlock() @@ -1114,11 +1123,11 @@ func (w *worker) commitWork(interrupt *int32, noempty bool, timestamp int64) { // Set the coinbase if the worker is running or it's required var coinbase common.Address if w.isRunning() { - if w.coinbase == (common.Address{}) { + coinbase = w.etherbase() + if coinbase == (common.Address{}) { log.Error("Refusing to mine without etherbase") return } - coinbase = w.coinbase // Use the preset address as the fee recipient } work, err := w.prepareWork(&generateParams{ timestamp: uint64(timestamp), From d36e6fc49d1ca3d7f76fb45d411369e1e6ee89d6 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 23 Jan 2023 17:59:25 +0100 Subject: [PATCH 487/715] go.mod: upgrade to latest goja (#26523) Co-authored-by: Felix Lange --- eth/tracers/js/tracer_test.go | 8 ++++---- go.mod | 4 ++-- go.sum | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 7fba197d8e56..524d17474930 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -107,15 +107,15 @@ func TestTracer(t *testing.T) { { // tests that we don't panic on bad arguments to memory access code: "{depths: [], step: function(log) { this.depths.push(log.memory.slice(-1,-2)); }, fault: function() {}, result: function() { return this.depths; }}", want: ``, - fail: "tracer accessed out of bound memory: offset -1, end -2 at step (:1:53(15)) in server-side tracer function 'step'", + fail: "tracer accessed out of bound memory: offset -1, end -2 at step (:1:53(13)) in server-side tracer function 'step'", }, { // tests that we don't panic on bad arguments to stack peeks code: "{depths: [], step: function(log) { this.depths.push(log.stack.peek(-1)); }, fault: function() {}, result: function() { return this.depths; }}", want: ``, - fail: "tracer accessed out of bound stack: size 0, index -1 at step (:1:53(13)) in server-side tracer function 'step'", + fail: "tracer accessed out of bound stack: size 0, index -1 at step (:1:53(11)) in server-side tracer function 'step'", }, { // tests that we don't panic on bad arguments to memory getUint code: "{ depths: [], step: function(log, db) { this.depths.push(log.memory.getUint(-64));}, fault: function() {}, result: function() { return this.depths; }}", want: ``, - fail: "tracer accessed out of bound memory: available 0, offset -64, size 32 at step (:1:58(13)) in server-side tracer function 'step'", + fail: "tracer accessed out of bound memory: available 0, offset -64, size 32 at step (:1:58(11)) in server-side tracer function 'step'", }, { // tests some general counting code: "{count: 0, step: function() { this.count += 1; }, fault: function() {}, result: function() { return this.count; }}", want: `3`, @@ -150,7 +150,7 @@ func TestTracer(t *testing.T) { }, { code: "{res: [], step: function(log) { if (log.op.toString() === 'STOP') { this.res.push(log.memory.slice(5, 1025 * 1024)) } }, fault: function() {}, result: function() { return this.res }}", want: "", - fail: "tracer reached limit for padding memory slice: end 1049600, memorySize 32 at step (:1:83(23)) in server-side tracer function 'step'", + fail: "tracer reached limit for padding memory slice: end 1049600, memorySize 32 at step (:1:83(20)) in server-side tracer function 'step'", contract: []byte{byte(vm.PUSH1), byte(0xff), byte(vm.PUSH1), byte(0x00), byte(vm.MSTORE8), byte(vm.STOP)}, }, } { diff --git a/go.mod b/go.mod index fd401b26a455..08cc41937c88 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 github.com/docker/docker v1.6.2 - github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf + github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 github.com/edsrzf/mmap-go v1.0.0 github.com/fatih/color v1.7.0 github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c @@ -82,7 +82,7 @@ require ( github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect - github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect + github.com/dlclark/regexp2 v1.7.0 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect diff --git a/go.sum b/go.sum index 1396f43b66e8..077ed66e95a1 100644 --- a/go.sum +++ b/go.sum @@ -105,14 +105,26 @@ github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMa github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/docker v1.6.2 h1:HlFGsy+9/xrgMmhmN+NGhCc5SHGJ7I+kHosRR1xc/aI= github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20230116105012-0341fef34b46 h1:MucQxd3z8vNuGWhFcEWYkJa9jV703kHso89O4wmT4iI= +github.com/dop251/goja v0.0.0-20230116105012-0341fef34b46/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= +github.com/dop251/goja v0.0.0-20230118114522-2c325f1ef691 h1:MZ3CbU2fmuY/Vn/1rx6daNfDeicxSWRlcj79pon4wfs= +github.com/dop251/goja v0.0.0-20230118114522-2c325f1ef691/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= +github.com/dop251/goja v0.0.0-20230119130012-17fd568758fe h1:PsLX9tWRxptk4COd23DJ0bnbXRKPDvBP+A6740Ndxp0= +github.com/dop251/goja v0.0.0-20230119130012-17fd568758fe/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= +github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 h1:kgvzE5wLsLa7XKfV85VZl40QXaMCaeFtHpPwJ8fhotY= +github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -275,6 +287,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -361,6 +374,7 @@ github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= From e4fa2cf5e3eed64c5e1aa7592394fa098f20505c Mon Sep 17 00:00:00 2001 From: ucwong Date: Mon, 23 Jan 2023 17:59:57 -0600 Subject: [PATCH 488/715] go.sum: go mod tidy (#26536) --- go.sum | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/go.sum b/go.sum index 077ed66e95a1..b715e3421458 100644 --- a/go.sum +++ b/go.sum @@ -103,7 +103,6 @@ github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRk github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= @@ -113,14 +112,6 @@ github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5O github.com/docker/docker v1.6.2 h1:HlFGsy+9/xrgMmhmN+NGhCc5SHGJ7I+kHosRR1xc/aI= github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= -github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja v0.0.0-20230116105012-0341fef34b46 h1:MucQxd3z8vNuGWhFcEWYkJa9jV703kHso89O4wmT4iI= -github.com/dop251/goja v0.0.0-20230116105012-0341fef34b46/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= -github.com/dop251/goja v0.0.0-20230118114522-2c325f1ef691 h1:MZ3CbU2fmuY/Vn/1rx6daNfDeicxSWRlcj79pon4wfs= -github.com/dop251/goja v0.0.0-20230118114522-2c325f1ef691/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= -github.com/dop251/goja v0.0.0-20230119130012-17fd568758fe h1:PsLX9tWRxptk4COd23DJ0bnbXRKPDvBP+A6740Ndxp0= -github.com/dop251/goja v0.0.0-20230119130012-17fd568758fe/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 h1:kgvzE5wLsLa7XKfV85VZl40QXaMCaeFtHpPwJ8fhotY= github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= @@ -285,8 +276,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -374,6 +365,7 @@ github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -414,8 +406,6 @@ github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= -github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= -github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= From 163e996d0ee4cda5afcd9adfb851d50109deecd6 Mon Sep 17 00:00:00 2001 From: Shude Li Date: Tue, 24 Jan 2023 17:12:25 +0800 Subject: [PATCH 489/715] all: use http package to replace http method names (#26535) --- cmd/faucet/faucet.go | 4 ++-- consensus/ethash/sealer.go | 2 +- graphql/graphiql.go | 2 +- metrics/librato/client.go | 2 +- node/rpcstack_test.go | 4 ++-- p2p/simulations/http.go | 8 ++++---- rpc/http.go | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index bec1f6d33b8e..3dfd63914420 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -747,7 +747,7 @@ func authTwitter(url string, tokenV1, tokenV2 string) (string, string, string, c func authTwitterWithTokenV1(tweetID string, token string) (string, string, string, common.Address, error) { // Query the tweet details from Twitter url := fmt.Sprintf("https://api.twitter.com/1.1/statuses/show.json?id=%s", tweetID) - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return "", "", "", common.Address{}, err } @@ -784,7 +784,7 @@ func authTwitterWithTokenV1(tweetID string, token string) (string, string, strin func authTwitterWithTokenV2(tweetID string, token string) (string, string, string, common.Address, error) { // Query the tweet details from Twitter url := fmt.Sprintf("https://api.twitter.com/2/tweets/%s?expansions=author_id&user.fields=profile_image_url", tweetID) - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return "", "", "", common.Address{}, err } diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index ec4696390028..340ad440f380 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -379,7 +379,7 @@ func (s *remoteSealer) notifyWork() { func (s *remoteSealer) sendNotification(ctx context.Context, url string, json []byte, work [4]string) { defer s.reqWG.Done() - req, err := http.NewRequest("POST", url, bytes.NewReader(json)) + req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(json)) if err != nil { s.ethash.config.Log.Warn("Can't create remote miner notification", "err", err) return diff --git a/graphql/graphiql.go b/graphql/graphiql.go index 864ebf57df21..576a0cbe953e 100644 --- a/graphql/graphiql.go +++ b/graphql/graphiql.go @@ -48,7 +48,7 @@ func errorJSON(msg string) []byte { } func (h GraphiQL) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if r.Method != "GET" { + if r.Method != http.MethodGet { respond(w, errorJSON("only GET requests are supported"), http.StatusMethodNotAllowed) return } diff --git a/metrics/librato/client.go b/metrics/librato/client.go index eebe20521b1a..729c2da9a9bc 100644 --- a/metrics/librato/client.go +++ b/metrics/librato/client.go @@ -80,7 +80,7 @@ func (c *LibratoClient) PostMetrics(batch Batch) (err error) { return } - if req, err = http.NewRequest("POST", MetricsPostUrl, bytes.NewBuffer(js)); err != nil { + if req, err = http.NewRequest(http.MethodPost, MetricsPostUrl, bytes.NewBuffer(js)); err != nil { return } diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index 795bc93c8386..4d10e61e2dec 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -167,7 +167,7 @@ func TestWebsocketOrigins(t *testing.T) { // TestIsWebsocket tests if an incoming websocket upgrade request is handled properly. func TestIsWebsocket(t *testing.T) { - r, _ := http.NewRequest("GET", "/", nil) + r, _ := http.NewRequest(http.MethodGet, "/", nil) assert.False(t, isWebsocket(r)) r.Header.Set("upgrade", "websocket") @@ -294,7 +294,7 @@ func baseRpcRequest(t *testing.T, url, bodyStr string, extraHeaders ...string) * // Create the request. body := bytes.NewReader([]byte(bodyStr)) - req, err := http.NewRequest("POST", url, body) + req, err := http.NewRequest(http.MethodPost, url, body) if err != nil { t.Fatal("could not create http request:", err) } diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go index f3ea87930858..7a4f70e9b08b 100644 --- a/p2p/simulations/http.go +++ b/p2p/simulations/http.go @@ -102,7 +102,7 @@ type SubscribeOpts struct { // nodes and connections and filtering message events func (c *Client) SubscribeNetwork(events chan *Event, opts SubscribeOpts) (event.Subscription, error) { url := fmt.Sprintf("%s/events?current=%t&filter=%s", c.URL, opts.Current, opts.Filter) - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return nil, err } @@ -215,18 +215,18 @@ func (c *Client) RPCClient(ctx context.Context, nodeID string) (*rpc.Client, err // Get performs a HTTP GET request decoding the resulting JSON response // into "out" func (c *Client) Get(path string, out interface{}) error { - return c.Send("GET", path, nil, out) + return c.Send(http.MethodGet, path, nil, out) } // Post performs a HTTP POST request sending "in" as the JSON body and // decoding the resulting JSON response into "out" func (c *Client) Post(path string, in, out interface{}) error { - return c.Send("POST", path, in, out) + return c.Send(http.MethodPost, path, in, out) } // Delete performs a HTTP DELETE request func (c *Client) Delete(path string) error { - return c.Send("DELETE", path, nil, nil) + return c.Send(http.MethodDelete, path, nil, nil) } // Send performs a HTTP request, sending "in" as the JSON request body and diff --git a/rpc/http.go b/rpc/http.go index 074c57ab1ad3..8712f99610b5 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -209,7 +209,7 @@ func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadClos if err != nil { return nil, err } - req, err := http.NewRequestWithContext(ctx, "POST", hc.url, io.NopCloser(bytes.NewReader(body))) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, hc.url, io.NopCloser(bytes.NewReader(body))) if err != nil { return nil, err } From 59a48e0289b1a7470a8285e665cab12b29117a70 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 24 Jan 2023 11:11:33 +0100 Subject: [PATCH 490/715] cmd/utils: improve parsing of --miner.etherbase address (#26541) This fixes a regression where the flag did not accept values without the 0x prefix anymore. What's worse, if an invalid value was passed, the client would just log an INFO level message and continue. --- cmd/utils/flags.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 4bee6093ea28..e4a9f2ff7d9a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -21,6 +21,7 @@ import ( "bytes" "context" "crypto/ecdsa" + "encoding/hex" "errors" "fmt" "math" @@ -1344,14 +1345,19 @@ func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error // setEtherbase retrieves the etherbase from the directly specified command line flags. func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) { - if ctx.IsSet(MinerEtherbaseFlag.Name) { - b, err := hexutil.Decode(ctx.String(MinerEtherbaseFlag.Name)) - if err != nil || len(b) != common.AddressLength { - log.Info("Failed to decode etherbase", "err", err) - return - } - cfg.Miner.Etherbase = common.BytesToAddress(b) + if !ctx.IsSet(MinerEtherbaseFlag.Name) { + return + } + addr := ctx.String(MinerEtherbaseFlag.Name) + if strings.HasPrefix(addr, "0x") || strings.HasPrefix(addr, "0X") { + addr = addr[2:] + } + b, err := hex.DecodeString(addr) + if err != nil || len(b) != common.AddressLength { + Fatalf("-%s: invalid etherbase address %q", MinerEtherbaseFlag.Name, addr) + return } + cfg.Miner.Etherbase = common.BytesToAddress(b) } // MakePasswordList reads password lines from the file specified by the global --password flag. From 2b57a27d9e2865d3a82ab8f57eb1d80e23e1cd3c Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 25 Jan 2023 06:12:28 -0500 Subject: [PATCH 491/715] all: make timestamp-based fork checks based on uint64 (#26474) This PR changes the API so that uint64 is used for fork timestamps. It's a good choice because types.Header also uses uint64 for time. Co-authored-by: Felix Lange --- cmd/evm/internal/t8ntool/execution.go | 2 +- cmd/evm/internal/t8ntool/transaction.go | 4 +- cmd/evm/runner.go | 2 +- cmd/geth/config.go | 3 +- cmd/utils/flags.go | 2 +- core/blockchain_test.go | 2 +- core/evm.go | 2 +- core/forkid/forkid.go | 18 +++---- core/forkid/forkid_test.go | 7 +-- core/genesis.go | 2 +- core/state_processor_test.go | 4 +- core/txpool/txpool.go | 2 +- core/vm/evm.go | 2 +- core/vm/instructions.go | 3 +- core/vm/runtime/runtime.go | 6 +-- core/vm/runtime/runtime_test.go | 5 +- eth/ethconfig/config.go | 3 +- eth/ethconfig/gen_config.go | 5 +- .../internal/tracetest/calltrace_test.go | 6 +-- .../internal/tracetest/prestate_test.go | 2 +- eth/tracers/tracers_test.go | 2 +- internal/ethapi/api.go | 6 +-- light/txpool.go | 2 +- params/config.go | 50 +++++++++---------- params/config_test.go | 34 ++++++++++--- tests/init.go | 4 +- tests/state_test.go | 2 +- 27 files changed, 100 insertions(+), 82 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 08d829d7db70..63c54b1d8a6c 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -138,7 +138,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, Transfer: core.Transfer, Coinbase: pre.Env.Coinbase, BlockNumber: new(big.Int).SetUint64(pre.Env.Number), - Time: new(big.Int).SetUint64(pre.Env.Timestamp), + Time: pre.Env.Timestamp, Difficulty: pre.Env.Difficulty, GasLimit: pre.Env.GasLimit, GetHash: getHash, diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 1bd370918e3e..21279e8f0a80 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -140,7 +140,7 @@ func Transaction(ctx *cli.Context) error { } // Check intrinsic gas if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, - chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int))); err != nil { + chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(0)); err != nil { r.Error = err results = append(results, r) continue @@ -172,7 +172,7 @@ func Transaction(ctx *cli.Context) error { r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits") } // Check whether the init code size has been exceeded. - if chainConfig.IsShanghai(new(big.Int)) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + if chainConfig.IsShanghai(0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { r.Error = errors.New("max initcode size exceeded") } results = append(results, r) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 9b1975c0500e..3a010da9f2dc 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -209,7 +209,7 @@ func runCmd(ctx *cli.Context) error { GasPrice: flags.GlobalBig(ctx, PriceFlag.Name), Value: flags.GlobalBig(ctx, ValueFlag.Name), Difficulty: genesisConfig.Difficulty, - Time: new(big.Int).SetUint64(genesisConfig.Timestamp), + Time: genesisConfig.Timestamp, Coinbase: genesisConfig.Coinbase, BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), EVMConfig: vm.Config{ diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 9c6fd9baae2e..61b7ed5ec1e3 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -159,7 +159,8 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { stack, cfg := makeConfigNode(ctx) if ctx.IsSet(utils.OverrideShanghai.Name) { - cfg.Eth.OverrideShanghai = flags.GlobalBig(ctx, utils.OverrideShanghai.Name) + v := ctx.Uint64(utils.OverrideShanghai.Name) + cfg.Eth.OverrideShanghai = &v } backend, eth := utils.RegisterEthService(stack, &cfg.Eth) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index e4a9f2ff7d9a..2bbbc381bea1 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -267,7 +267,7 @@ var ( Value: 2048, Category: flags.EthCategory, } - OverrideShanghai = &flags.BigFlag{ + OverrideShanghai = &cli.Uint64Flag{ Name: "override.shanghai", Usage: "Manually specify the Shanghai fork timestamp, overriding the bundled setting", Category: flags.EthCategory, diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 36bfa0752558..2f9e604de9d1 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4275,7 +4275,7 @@ func TestEIP3651(t *testing.T) { gspec.Config.BerlinBlock = common.Big0 gspec.Config.LondonBlock = common.Big0 - gspec.Config.ShanghaiTime = common.Big0 + gspec.Config.ShanghaiTime = u64(0) signer := types.LatestSigner(gspec.Config) _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { diff --git a/core/evm.go b/core/evm.go index e929da25eaee..35e12338ef05 100644 --- a/core/evm.go +++ b/core/evm.go @@ -61,7 +61,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common GetHash: GetHashFn(header, chain), Coinbase: beneficiary, BlockNumber: new(big.Int).Set(header.Number), - Time: new(big.Int).SetUint64(header.Time), + Time: header.Time, Difficulty: new(big.Int).Set(header.Difficulty), BaseFee: baseFee, GasLimit: header.GasLimit, diff --git a/core/forkid/forkid.go b/core/forkid/forkid.go index 300dca6cfba0..f536019dac12 100644 --- a/core/forkid/forkid.go +++ b/core/forkid/forkid.go @@ -244,7 +244,7 @@ func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) { // Gather all the fork block numbers via reflection kind := reflect.TypeOf(params.ChainConfig{}) conf := reflect.ValueOf(config).Elem() - + x := uint64(0) var ( forksByBlock []uint64 forksByTime []uint64 @@ -257,15 +257,15 @@ func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) { if !time && !strings.HasSuffix(field.Name, "Block") { continue } - if field.Type != reflect.TypeOf(new(big.Int)) { - continue - } + // Extract the fork rule block number or timestamp and aggregate it - rule := conf.Field(i).Interface().(*big.Int) - if rule != nil { - if time { - forksByTime = append(forksByTime, rule.Uint64()) - } else { + if field.Type == reflect.TypeOf(&x) { + if rule := conf.Field(i).Interface().(*uint64); rule != nil { + forksByTime = append(forksByTime, *rule) + } + } + if field.Type == reflect.TypeOf(new(big.Int)) { + if rule := conf.Field(i).Interface().(*big.Int); rule != nil { forksByBlock = append(forksByBlock, rule.Uint64()) } } diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index 7d6e89c81178..c4b46bf411d0 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -19,7 +19,6 @@ package forkid import ( "bytes" "math" - "math/big" "testing" "github.com/ethereum/go-ethereum/common" @@ -27,12 +26,14 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) +func u64(val uint64) *uint64 { return &val } + // TestCreation tests that different genesis and fork rule combinations result in // the correct fork ID. func TestCreation(t *testing.T) { // Temporary non-existent scenario TODO(karalabe): delete when Shanghai is enabled timestampedConfig := *params.MainnetChainConfig - timestampedConfig.ShanghaiTime = big.NewInt(1668000000) + timestampedConfig.ShanghaiTime = u64(1668000000) type testcase struct { head uint64 @@ -201,7 +202,7 @@ func TestCreation(t *testing.T) { func TestValidation(t *testing.T) { // Temporary non-existent scenario TODO(karalabe): delete when Shanghai is enabled timestampedConfig := *params.MainnetChainConfig - timestampedConfig.ShanghaiTime = big.NewInt(1668000000) + timestampedConfig.ShanghaiTime = u64(1668000000) tests := []struct { config *params.ChainConfig diff --git a/core/genesis.go b/core/genesis.go index 47974f63ab33..b4f49a1e1a8e 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -269,7 +269,7 @@ func (e *GenesisMismatchError) Error() string { // ChainOverrides contains the changes to chain config. type ChainOverrides struct { - OverrideShanghai *big.Int + OverrideShanghai *uint64 } // SetupGenesisBlock writes or updates the genesis block in db. diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 400ccd318793..c91adc36ed46 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -35,6 +35,8 @@ import ( "golang.org/x/crypto/sha3" ) +func u64(val uint64) *uint64 { return &val } + // TestStateProcessorErrors tests the output from the 'core' errors // as defined in core/error.go. These errors are generated when the // blockchain imports bad blocks, meaning blocks which have valid headers but @@ -327,7 +329,7 @@ func TestStateProcessorErrors(t *testing.T) { ArrowGlacierBlock: big.NewInt(0), GrayGlacierBlock: big.NewInt(0), MergeNetsplitBlock: big.NewInt(0), - ShanghaiTime: big.NewInt(0), + ShanghaiTime: u64(0), }, Alloc: GenesisAlloc{ common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 3e4eb21cfc68..6b878ed58613 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -1312,7 +1312,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { pool.istanbul = pool.chainconfig.IsIstanbul(next) pool.eip2718 = pool.chainconfig.IsBerlin(next) pool.eip1559 = pool.chainconfig.IsLondon(next) - pool.shanghai = pool.chainconfig.IsShanghai(big.NewInt(time.Now().Unix())) + pool.shanghai = pool.chainconfig.IsShanghai(uint64(time.Now().Unix())) } // promoteExecutables moves transactions that have become processable from the diff --git a/core/vm/evm.go b/core/vm/evm.go index 149e9f761be3..f6a1557e821b 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -71,7 +71,7 @@ type BlockContext struct { Coinbase common.Address // Provides information for COINBASE GasLimit uint64 // Provides information for GASLIMIT BlockNumber *big.Int // Provides information for NUMBER - Time *big.Int // Provides information for TIME + Time uint64 // Provides information for TIME Difficulty *big.Int // Provides information for DIFFICULTY BaseFee *big.Int // Provides information for BASEFEE Random *common.Hash // Provides information for PREVRANDAO diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 8fa2fc57e51f..886ff6323d50 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -460,8 +460,7 @@ func opCoinbase(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ } func opTimestamp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - v, _ := uint256.FromBig(interpreter.evm.Context.Time) - scope.Stack.push(v) + scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.Time)) return nil, nil } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index a330825b10d8..15a1f1a1bd90 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -19,7 +19,6 @@ package runtime import ( "math" "math/big" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -37,7 +36,7 @@ type Config struct { Origin common.Address Coinbase common.Address BlockNumber *big.Int - Time *big.Int + Time uint64 GasLimit uint64 GasPrice *big.Int Value *big.Int @@ -74,9 +73,6 @@ func setDefaults(cfg *Config) { if cfg.Difficulty == nil { cfg.Difficulty = new(big.Int) } - if cfg.Time == nil { - cfg.Time = big.NewInt(time.Now().Unix()) - } if cfg.GasLimit == 0 { cfg.GasLimit = math.MaxUint64 } diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 868d41e50348..607259106536 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -48,9 +48,6 @@ func TestDefaults(t *testing.T) { t.Error("expected difficulty to be non nil") } - if cfg.Time == nil { - t.Error("expected time to be non nil") - } if cfg.GasLimit == 0 { t.Error("didn't expect gaslimit to be zero") } @@ -174,7 +171,7 @@ func benchmarkEVM_Create(bench *testing.B, code string) { State: statedb, GasLimit: 10000000, Difficulty: big.NewInt(0x200000), - Time: new(big.Int).SetUint64(0), + Time: 0, Coinbase: common.Address{}, BlockNumber: new(big.Int).SetUint64(1), ChainConfig: ¶ms.ChainConfig{ diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 04ef21f49df9..db686c5d0875 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -18,7 +18,6 @@ package ethconfig import ( - "math/big" "os" "os/user" "path/filepath" @@ -207,7 +206,7 @@ type Config struct { CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` // OverrideShanghai (TODO: remove after the fork) - OverrideShanghai *big.Int `toml:",omitempty"` + OverrideShanghai *uint64 `toml:",omitempty"` } // CreateConsensusEngine creates a consensus engine for the given chain configuration. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 3506d39d5b54..b7255a242e9f 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -3,7 +3,6 @@ package ethconfig import ( - "math/big" "time" "github.com/ethereum/go-ethereum/common" @@ -61,7 +60,7 @@ func (c Config) MarshalTOML() (interface{}, error) { RPCTxFeeCap float64 Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - OverrideShanghai *big.Int `toml:",omitempty"` + OverrideShanghai *uint64 `toml:",omitempty"` } var enc Config enc.Genesis = c.Genesis @@ -155,7 +154,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { RPCTxFeeCap *float64 Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` - OverrideShanghai *big.Int `toml:",omitempty"` + OverrideShanghai *uint64 `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 5cfb5b33c1b0..d240e9a4b107 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -133,7 +133,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { Transfer: core.Transfer, Coinbase: test.Context.Miner, BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), - Time: new(big.Int).SetUint64(uint64(test.Context.Time)), + Time: uint64(test.Context.Time), Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), BaseFee: test.Genesis.BaseFee, @@ -234,7 +234,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { Transfer: core.Transfer, Coinbase: test.Context.Miner, BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), - Time: new(big.Int).SetUint64(uint64(test.Context.Time)), + Time: uint64(test.Context.Time), Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), } @@ -288,7 +288,7 @@ func TestZeroValueToNotExitCall(t *testing.T) { Transfer: core.Transfer, Coinbase: common.Address{}, BlockNumber: new(big.Int).SetUint64(8000000), - Time: new(big.Int).SetUint64(5), + Time: 5, Difficulty: big.NewInt(0x30000), GasLimit: uint64(6000000), } diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 2fee7d6fb7ed..03f06311a3b9 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -103,7 +103,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { Transfer: core.Transfer, Coinbase: test.Context.Miner, BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), - Time: new(big.Int).SetUint64(uint64(test.Context.Time)), + Time: uint64(test.Context.Time), Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), BaseFee: test.Genesis.BaseFee, diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 12e01abae403..6cd5a022b1a1 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -56,7 +56,7 @@ func BenchmarkTransactionTrace(b *testing.B) { Transfer: core.Transfer, Coinbase: common.Address{}, BlockNumber: new(big.Int).SetUint64(uint64(5)), - Time: new(big.Int).SetUint64(uint64(5)), + Time: 5, Difficulty: big.NewInt(0xffffffff), GasLimit: gas, BaseFee: big.NewInt(8), diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b6efba079a4a..e0e4278bb467 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -920,7 +920,7 @@ func (diff *StateOverride) Apply(state *state.StateDB) error { type BlockOverrides struct { Number *hexutil.Big Difficulty *hexutil.Big - Time *hexutil.Big + Time *hexutil.Uint64 GasLimit *hexutil.Uint64 Coinbase *common.Address Random *common.Hash @@ -939,7 +939,7 @@ func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) { blockCtx.Difficulty = diff.Difficulty.ToInt() } if diff.Time != nil { - blockCtx.Time = diff.Time.ToInt() + blockCtx.Time = uint64(*diff.Time) } if diff.GasLimit != nil { blockCtx.GasLimit = uint64(*diff.GasLimit) @@ -1444,7 +1444,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH } isPostMerge := header.Difficulty.Cmp(common.Big0) == 0 // Retrieve the precompiles since they don't need to be added to the access list - precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, new(big.Int).SetUint64(header.Time))) + precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, header.Time)) // Create an initial tracer prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles) diff --git a/light/txpool.go b/light/txpool.go index e12f6ef94425..e59dc3e77434 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -318,7 +318,7 @@ func (pool *TxPool) setNewHead(head *types.Header) { next := new(big.Int).Add(head.Number, big.NewInt(1)) pool.istanbul = pool.config.IsIstanbul(next) pool.eip2718 = pool.config.IsBerlin(next) - pool.shanghai = pool.config.IsShanghai(big.NewInt(time.Now().Unix())) + pool.shanghai = pool.config.IsShanghai(uint64(time.Now().Unix())) } // Stop stops the light transaction pool diff --git a/params/config.go b/params/config.go index 41072d3eac88..aac4392301de 100644 --- a/params/config.go +++ b/params/config.go @@ -383,7 +383,7 @@ var ( Ethash: new(EthashConfig), Clique: nil, } - TestRules = TestChainConfig.Rules(new(big.Int), false, new(big.Int)) + TestRules = TestChainConfig.Rules(new(big.Int), false, 0) ) // NetworkNames are user friendly names to use in the chain spec banner. @@ -476,9 +476,9 @@ type ChainConfig struct { // Fork scheduling was switched from blocks to timestamps here - ShanghaiTime *big.Int `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) - CancunTime *big.Int `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun) - PragueTime *big.Int `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) + ShanghaiTime *uint64 `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) + CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun) + PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. @@ -683,17 +683,17 @@ func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *bi } // IsShanghai returns whether time is either equal to the Shanghai fork time or greater. -func (c *ChainConfig) IsShanghai(time *big.Int) bool { +func (c *ChainConfig) IsShanghai(time uint64) bool { return isTimestampForked(c.ShanghaiTime, time) } // IsCancun returns whether num is either equal to the Cancun fork time or greater. -func (c *ChainConfig) IsCancun(time *big.Int) bool { +func (c *ChainConfig) IsCancun(time uint64) bool { return isTimestampForked(c.CancunTime, time) } // IsPrague returns whether num is either equal to the Prague fork time or greater. -func (c *ChainConfig) IsPrague(time *big.Int) bool { +func (c *ChainConfig) IsPrague(time uint64) bool { return isTimestampForked(c.PragueTime, time) } @@ -702,7 +702,7 @@ func (c *ChainConfig) IsPrague(time *big.Int) bool { func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError { var ( bhead = new(big.Int).SetUint64(height) - btime = new(big.Int).SetUint64(time) + btime = time ) // Iterate checkCompatible to find the lowest conflict. var lasterr *ConfigCompatError @@ -714,7 +714,7 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time u lasterr = err if err.RewindToTime > 0 { - btime.SetUint64(err.RewindToTime) + btime = err.RewindToTime } else { bhead.SetUint64(err.RewindToBlock) } @@ -728,7 +728,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { type fork struct { name string block *big.Int // forks up to - and including the merge - were defined with block numbers - timestamp *big.Int // forks after the merge are scheduled using timestamps + timestamp *uint64 // forks after the merge are scheduled using timestamps optional bool // if true, the fork may be nil and next fork is still allowed } var lastFork fork @@ -769,7 +769,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { if lastFork.block != nil && lastFork.block.Cmp(cur.block) > 0 { return fmt.Errorf("unsupported fork ordering: %v enabled at block %v, but %v enabled at block %v", lastFork.name, lastFork.block, cur.name, cur.block) - } else if lastFork.timestamp != nil && lastFork.timestamp.Cmp(cur.timestamp) > 0 { + } else if lastFork.timestamp != nil && *lastFork.timestamp > *cur.timestamp { return fmt.Errorf("unsupported fork ordering: %v enabled at timestamp %v, but %v enabled at timestamp %v", lastFork.name, lastFork.timestamp, cur.name, cur.timestamp) } @@ -789,7 +789,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { return nil } -func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, headTimestamp *big.Int) *ConfigCompatError { +func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, headTimestamp uint64) *ConfigCompatError { if isForkBlockIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, headNumber) { return newBlockCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock) } @@ -895,28 +895,28 @@ func configBlockEqual(x, y *big.Int) bool { // isForkTimestampIncompatible returns true if a fork scheduled at timestamp s1 // cannot be rescheduled to timestamp s2 because head is already past the fork. -func isForkTimestampIncompatible(s1, s2, head *big.Int) bool { +func isForkTimestampIncompatible(s1, s2 *uint64, head uint64) bool { return (isTimestampForked(s1, head) || isTimestampForked(s2, head)) && !configTimestampEqual(s1, s2) } // isTimestampForked returns whether a fork scheduled at timestamp s is active // at the given head timestamp. Whilst this method is the same as isBlockForked, // they are explicitly separate for clearer reading. -func isTimestampForked(s, head *big.Int) bool { - if s == nil || head == nil { +func isTimestampForked(s *uint64, head uint64) bool { + if s == nil { return false } - return s.Cmp(head) <= 0 + return *s <= head } -func configTimestampEqual(x, y *big.Int) bool { +func configTimestampEqual(x, y *uint64) bool { if x == nil { return y == nil } if y == nil { return x == nil } - return x.Cmp(y) == 0 + return *x == *y } // ConfigCompatError is raised if the locally-stored blockchain is initialised with a @@ -928,7 +928,7 @@ type ConfigCompatError struct { StoredBlock, NewBlock *big.Int // timestamps of the stored and new configurations if time based forking - StoredTime, NewTime *big.Int + StoredTime, NewTime *uint64 // the block number to which the local chain must be rewound to correct the error RewindToBlock uint64 @@ -959,12 +959,12 @@ func newBlockCompatError(what string, storedblock, newblock *big.Int) *ConfigCom return err } -func newTimestampCompatError(what string, storedtime, newtime *big.Int) *ConfigCompatError { - var rew *big.Int +func newTimestampCompatError(what string, storedtime, newtime *uint64) *ConfigCompatError { + var rew *uint64 switch { case storedtime == nil: rew = newtime - case newtime == nil || storedtime.Cmp(newtime) < 0: + case newtime == nil || *storedtime < *newtime: rew = storedtime default: rew = newtime @@ -975,8 +975,8 @@ func newTimestampCompatError(what string, storedtime, newtime *big.Int) *ConfigC NewTime: newtime, RewindToTime: 0, } - if rew != nil && rew.Sign() > 0 { - err.RewindToTime = rew.Uint64() - 1 + if rew != nil { + err.RewindToTime = *rew - 1 } return err } @@ -1002,7 +1002,7 @@ type Rules struct { } // Rules ensures c's ChainID is not nil. -func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp *big.Int) Rules { +func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules { chainID := c.ChainID if chainID == nil { chainID = new(big.Int) diff --git a/params/config_test.go b/params/config_test.go index 523ba26fdc7d..f3911f433f3c 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -21,8 +21,12 @@ import ( "reflect" "testing" "time" + + "github.com/ethereum/go-ethereum/common/math" ) +func u64(val uint64) *uint64 { return &val } + func TestCheckCompatible(t *testing.T) { type test struct { stored, new *ChainConfig @@ -91,19 +95,19 @@ func TestCheckCompatible(t *testing.T) { }, }, { - stored: &ChainConfig{ShanghaiTime: big.NewInt(10)}, - new: &ChainConfig{ShanghaiTime: big.NewInt(20)}, + stored: &ChainConfig{ShanghaiTime: u64(10)}, + new: &ChainConfig{ShanghaiTime: u64(20)}, headTimestamp: 9, wantErr: nil, }, { - stored: &ChainConfig{ShanghaiTime: big.NewInt(10)}, - new: &ChainConfig{ShanghaiTime: big.NewInt(20)}, + stored: &ChainConfig{ShanghaiTime: u64(10)}, + new: &ChainConfig{ShanghaiTime: u64(20)}, headTimestamp: 25, wantErr: &ConfigCompatError{ What: "Shanghai fork timestamp", - StoredTime: big.NewInt(10), - NewTime: big.NewInt(20), + StoredTime: u64(10), + NewTime: u64(20), RewindToTime: 9, }, }, @@ -116,3 +120,21 @@ func TestCheckCompatible(t *testing.T) { } } } + +func TestConfigRules(t *testing.T) { + c := &ChainConfig{ + ShanghaiTime: u64(500), + } + var stamp uint64 + if r := c.Rules(big.NewInt(0), true, stamp); r.IsShanghai { + t.Errorf("expected %v to not be shanghai", stamp) + } + stamp = 500 + if r := c.Rules(big.NewInt(0), true, stamp); !r.IsShanghai { + t.Errorf("expected %v to be shanghai", stamp) + } + stamp = math.MaxInt64 + if r := c.Rules(big.NewInt(0), true, stamp); !r.IsShanghai { + t.Errorf("expected %v to be shanghai", stamp) + } +} diff --git a/tests/init.go b/tests/init.go index fd0b015086a1..a36ab4d9d435 100644 --- a/tests/init.go +++ b/tests/init.go @@ -24,6 +24,8 @@ import ( "github.com/ethereum/go-ethereum/params" ) +func u64(val uint64) *uint64 { return &val } + // Forks table defines supported forks and their chain config. var Forks = map[string]*params.ChainConfig{ "Frontier": { @@ -264,7 +266,7 @@ var Forks = map[string]*params.ChainConfig{ ArrowGlacierBlock: big.NewInt(0), MergeNetsplitBlock: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0), - ShanghaiTime: big.NewInt(0), + ShanghaiTime: u64(0), }, } diff --git a/tests/state_test.go b/tests/state_test.go index 4c5e7b914f9b..a68321e76236 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -183,7 +183,7 @@ func runBenchmark(b *testing.B, t *StateTest) { b.Error(err) return } - var rules = config.Rules(new(big.Int), false, new(big.Int)) + var rules = config.Rules(new(big.Int), false, 0) vmconfig.ExtraEips = eips block := t.genesis(config).ToBlock() From 2a2b0419fb966c54fb86b17bbccea743a45b4d2a Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 25 Jan 2023 15:32:25 +0100 Subject: [PATCH 492/715] all: implement withdrawals (EIP-4895) (#26484) This change implements withdrawals as specified in EIP-4895. Co-authored-by: lightclient@protonmail.com Co-authored-by: marioevz Co-authored-by: Martin Holst Swende Co-authored-by: Felix Lange --- cmd/evm/internal/t8ntool/block.go | 108 +++++----- cmd/evm/internal/t8ntool/execution.go | 32 ++- cmd/evm/internal/t8ntool/flags.go | 4 + cmd/evm/internal/t8ntool/gen_header.go | 70 ++++--- cmd/evm/internal/t8ntool/gen_stenv.go | 7 + cmd/evm/internal/t8ntool/transition.go | 3 + cmd/evm/main.go | 1 + cmd/evm/t8n_test.go | 37 +++- cmd/evm/testdata/26/alloc.json | 8 + cmd/evm/testdata/26/env.json | 17 ++ cmd/evm/testdata/26/exp.json | 20 ++ cmd/evm/testdata/26/txs.json | 1 + cmd/evm/testdata/27/exp.json | 4 + cmd/evm/testdata/27/header.json | 12 ++ cmd/evm/testdata/27/ommers.json | 1 + cmd/evm/testdata/27/txs.rlp | 1 + cmd/evm/testdata/27/withdrawals.json | 8 + consensus/beacon/consensus.go | 45 +++- consensus/beacon/faker.go | 41 ++++ consensus/clique/clique.go | 16 +- consensus/consensus.go | 4 +- consensus/ethash/consensus.go | 17 +- core/beacon/gen_blockparams.go | 37 ++-- core/beacon/gen_ed.go | 107 +++++----- core/beacon/gen_epe.go | 46 +++++ core/beacon/types.go | 122 ++++++----- core/block_validator.go | 5 + core/blockchain_test.go | 12 +- core/chain_makers.go | 35 +++- core/genesis.go | 3 + core/rawdb/accessors_chain.go | 6 +- core/state_processor.go | 7 +- core/state_processor_test.go | 65 +++--- core/types/block.go | 69 ++++++- core/types/gen_header_json.go | 72 ++++--- core/types/gen_header_rlp.go | 10 +- core/types/gen_withdrawal_json.go | 55 +++++ core/types/gen_withdrawal_rlp.go | 20 ++ core/types/withdrawal.go | 56 +++++ core/vm/runtime/runtime.go | 2 - eth/catalyst/api.go | 46 ++++- eth/catalyst/api_test.go | 207 +++++++++++++++---- eth/catalyst/queue.go | 2 +- eth/downloader/downloader.go | 6 +- eth/downloader/downloader_test.go | 7 +- eth/downloader/fetchers_concurrent_bodies.go | 6 +- eth/downloader/queue.go | 12 +- eth/downloader/queue_test.go | 2 +- eth/fetcher/block_fetcher.go | 4 +- eth/protocols/eth/handler_test.go | 71 +++++-- eth/protocols/eth/handlers.go | 10 +- eth/protocols/eth/protocol.go | 13 +- internal/ethapi/api.go | 6 + les/catalyst/api.go | 6 +- les/catalyst/api_test.go | 2 +- miner/payload_building.go | 27 +-- miner/payload_building_test.go | 13 +- miner/stress/beacon/main.go | 8 +- miner/worker.go | 37 ++-- miner/worker_test.go | 4 +- 60 files changed, 1236 insertions(+), 439 deletions(-) create mode 100644 cmd/evm/testdata/26/alloc.json create mode 100644 cmd/evm/testdata/26/env.json create mode 100644 cmd/evm/testdata/26/exp.json create mode 100644 cmd/evm/testdata/26/txs.json create mode 100644 cmd/evm/testdata/27/exp.json create mode 100644 cmd/evm/testdata/27/header.json create mode 100644 cmd/evm/testdata/27/ommers.json create mode 100644 cmd/evm/testdata/27/txs.rlp create mode 100644 cmd/evm/testdata/27/withdrawals.json create mode 100644 consensus/beacon/faker.go create mode 100644 core/beacon/gen_epe.go create mode 100644 core/types/gen_withdrawal_json.go create mode 100644 core/types/gen_withdrawal_rlp.go create mode 100644 core/types/withdrawal.go diff --git a/cmd/evm/internal/t8ntool/block.go b/cmd/evm/internal/t8ntool/block.go index 4a070b6c71b5..1140daa2c27f 100644 --- a/cmd/evm/internal/t8ntool/block.go +++ b/cmd/evm/internal/t8ntool/block.go @@ -38,22 +38,23 @@ import ( //go:generate go run github.com/fjl/gencodec -type header -field-override headerMarshaling -out gen_header.go type header struct { - ParentHash common.Hash `json:"parentHash"` - OmmerHash *common.Hash `json:"sha3Uncles"` - Coinbase *common.Address `json:"miner"` - Root common.Hash `json:"stateRoot" gencodec:"required"` - TxHash *common.Hash `json:"transactionsRoot"` - ReceiptHash *common.Hash `json:"receiptsRoot"` - Bloom types.Bloom `json:"logsBloom"` - Difficulty *big.Int `json:"difficulty"` - Number *big.Int `json:"number" gencodec:"required"` - GasLimit uint64 `json:"gasLimit" gencodec:"required"` - GasUsed uint64 `json:"gasUsed"` - Time uint64 `json:"timestamp" gencodec:"required"` - Extra []byte `json:"extraData"` - MixDigest common.Hash `json:"mixHash"` - Nonce *types.BlockNonce `json:"nonce"` - BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` + ParentHash common.Hash `json:"parentHash"` + OmmerHash *common.Hash `json:"sha3Uncles"` + Coinbase *common.Address `json:"miner"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot"` + ReceiptHash *common.Hash `json:"receiptsRoot"` + Bloom types.Bloom `json:"logsBloom"` + Difficulty *big.Int `json:"difficulty"` + Number *big.Int `json:"number" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed"` + Time uint64 `json:"timestamp" gencodec:"required"` + Extra []byte `json:"extraData"` + MixDigest common.Hash `json:"mixHash"` + Nonce *types.BlockNonce `json:"nonce"` + BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` + WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` } type headerMarshaling struct { @@ -67,10 +68,11 @@ type headerMarshaling struct { } type bbInput struct { - Header *header `json:"header,omitempty"` - OmmersRlp []string `json:"ommers,omitempty"` - TxRlp string `json:"txs,omitempty"` - Clique *cliqueInput `json:"clique,omitempty"` + Header *header `json:"header,omitempty"` + OmmersRlp []string `json:"ommers,omitempty"` + TxRlp string `json:"txs,omitempty"` + Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` + Clique *cliqueInput `json:"clique,omitempty"` Ethash bool `json:"-"` EthashDir string `json:"-"` @@ -114,21 +116,22 @@ func (c *cliqueInput) UnmarshalJSON(input []byte) error { // ToBlock converts i into a *types.Block func (i *bbInput) ToBlock() *types.Block { header := &types.Header{ - ParentHash: i.Header.ParentHash, - UncleHash: types.EmptyUncleHash, - Coinbase: common.Address{}, - Root: i.Header.Root, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, - Bloom: i.Header.Bloom, - Difficulty: common.Big0, - Number: i.Header.Number, - GasLimit: i.Header.GasLimit, - GasUsed: i.Header.GasUsed, - Time: i.Header.Time, - Extra: i.Header.Extra, - MixDigest: i.Header.MixDigest, - BaseFee: i.Header.BaseFee, + ParentHash: i.Header.ParentHash, + UncleHash: types.EmptyUncleHash, + Coinbase: common.Address{}, + Root: i.Header.Root, + TxHash: types.EmptyRootHash, + ReceiptHash: types.EmptyRootHash, + Bloom: i.Header.Bloom, + Difficulty: common.Big0, + Number: i.Header.Number, + GasLimit: i.Header.GasLimit, + GasUsed: i.Header.GasUsed, + Time: i.Header.Time, + Extra: i.Header.Extra, + MixDigest: i.Header.MixDigest, + BaseFee: i.Header.BaseFee, + WithdrawalsHash: i.Header.WithdrawalsHash, } // Fill optional values. @@ -153,7 +156,7 @@ func (i *bbInput) ToBlock() *types.Block { if header.Difficulty != nil { header.Difficulty = i.Header.Difficulty } - return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers) + return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers).WithWithdrawals(i.Withdrawals) } // SealBlock seals the given block using the configured engine. @@ -259,14 +262,15 @@ func BuildBlock(ctx *cli.Context) error { func readInput(ctx *cli.Context) (*bbInput, error) { var ( - headerStr = ctx.String(InputHeaderFlag.Name) - ommersStr = ctx.String(InputOmmersFlag.Name) - txsStr = ctx.String(InputTxsRlpFlag.Name) - cliqueStr = ctx.String(SealCliqueFlag.Name) - ethashOn = ctx.Bool(SealEthashFlag.Name) - ethashDir = ctx.String(SealEthashDirFlag.Name) - ethashMode = ctx.String(SealEthashModeFlag.Name) - inputData = &bbInput{} + headerStr = ctx.String(InputHeaderFlag.Name) + ommersStr = ctx.String(InputOmmersFlag.Name) + withdrawalsStr = ctx.String(InputWithdrawalsFlag.Name) + txsStr = ctx.String(InputTxsRlpFlag.Name) + cliqueStr = ctx.String(SealCliqueFlag.Name) + ethashOn = ctx.Bool(SealEthashFlag.Name) + ethashDir = ctx.String(SealEthashDirFlag.Name) + ethashMode = ctx.String(SealEthashModeFlag.Name) + inputData = &bbInput{} ) if ethashOn && cliqueStr != "" { return nil, NewError(ErrorConfig, fmt.Errorf("both ethash and clique sealing specified, only one may be chosen")) @@ -312,6 +316,13 @@ func readInput(ctx *cli.Context) (*bbInput, error) { } inputData.OmmersRlp = ommers } + if withdrawalsStr != stdinSelector && withdrawalsStr != "" { + var withdrawals []*types.Withdrawal + if err := readFile(withdrawalsStr, "withdrawals", &withdrawals); err != nil { + return nil, err + } + inputData.Withdrawals = withdrawals + } if txsStr != stdinSelector { var txs string if err := readFile(txsStr, "txs", &txs); err != nil { @@ -351,15 +362,14 @@ func readInput(ctx *cli.Context) (*bbInput, error) { // files func dispatchBlock(ctx *cli.Context, baseDir string, block *types.Block) error { raw, _ := rlp.EncodeToBytes(block) - type blockInfo struct { Rlp hexutil.Bytes `json:"rlp"` Hash common.Hash `json:"hash"` } - var enc blockInfo - enc.Rlp = raw - enc.Hash = block.Hash() - + enc := blockInfo{ + Rlp: raw, + Hash: block.Hash(), + } b, err := json.MarshalIndent(enc, "", " ") if err != nil { return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 63c54b1d8a6c..2c68659945eb 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -47,16 +47,17 @@ type Prestate struct { // ExecutionResult contains the execution status after running a state test, any // error that might have occurred and a dump of the final state if requested. type ExecutionResult struct { - StateRoot common.Hash `json:"stateRoot"` - TxRoot common.Hash `json:"txRoot"` - ReceiptRoot common.Hash `json:"receiptsRoot"` - LogsHash common.Hash `json:"logsHash"` - Bloom types.Bloom `json:"logsBloom" gencodec:"required"` - Receipts types.Receipts `json:"receipts"` - Rejected []*rejectedTx `json:"rejected,omitempty"` - Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` - GasUsed math.HexOrDecimal64 `json:"gasUsed"` - BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` + StateRoot common.Hash `json:"stateRoot"` + TxRoot common.Hash `json:"txRoot"` + ReceiptRoot common.Hash `json:"receiptsRoot"` + LogsHash common.Hash `json:"logsHash"` + Bloom types.Bloom `json:"logsBloom" gencodec:"required"` + Receipts types.Receipts `json:"receipts"` + Rejected []*rejectedTx `json:"rejected,omitempty"` + Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` + GasUsed math.HexOrDecimal64 `json:"gasUsed"` + BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` + WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"` } type ommer struct { @@ -79,6 +80,7 @@ type stEnv struct { ParentTimestamp uint64 `json:"parentTimestamp,omitempty"` BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` Ommers []ommer `json:"ommers,omitempty"` + Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` BaseFee *big.Int `json:"currentBaseFee,omitempty"` ParentUncleHash common.Hash `json:"parentUncleHash"` } @@ -254,6 +256,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } statedb.AddBalance(pre.Env.Coinbase, minerReward) } + // Apply withdrawals + for _, w := range pre.Env.Withdrawals { + // Amount is in gwei, turn into wei + amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) + statedb.AddBalance(w.Address, amount) + } // Commit block root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber)) if err != nil { @@ -272,6 +280,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, GasUsed: (math.HexOrDecimal64)(gasUsed), BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee), } + if pre.Env.Withdrawals != nil { + h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil)) + execRs.WithdrawalsRoot = &h + } return statedb, execRs, nil } diff --git a/cmd/evm/internal/t8ntool/flags.go b/cmd/evm/internal/t8ntool/flags.go index 626220315e19..339523593a90 100644 --- a/cmd/evm/internal/t8ntool/flags.go +++ b/cmd/evm/internal/t8ntool/flags.go @@ -112,6 +112,10 @@ var ( Name: "input.ommers", Usage: "`stdin` or file name of where to find the list of ommer header RLPs to use.", } + InputWithdrawalsFlag = &cli.StringFlag{ + Name: "input.withdrawals", + Usage: "`stdin` or file name of where to find the list of withdrawals to use.", + } InputTxsRlpFlag = &cli.StringFlag{ Name: "input.txs", Usage: "`stdin` or file name of where to find the transactions list in RLP form.", diff --git a/cmd/evm/internal/t8ntool/gen_header.go b/cmd/evm/internal/t8ntool/gen_header.go index 196e49dd716f..76228394dc1d 100644 --- a/cmd/evm/internal/t8ntool/gen_header.go +++ b/cmd/evm/internal/t8ntool/gen_header.go @@ -18,22 +18,23 @@ var _ = (*headerMarshaling)(nil) // MarshalJSON marshals as JSON. func (h header) MarshalJSON() ([]byte, error) { type header struct { - ParentHash common.Hash `json:"parentHash"` - OmmerHash *common.Hash `json:"sha3Uncles"` - Coinbase *common.Address `json:"miner"` - Root common.Hash `json:"stateRoot" gencodec:"required"` - TxHash *common.Hash `json:"transactionsRoot"` - ReceiptHash *common.Hash `json:"receiptsRoot"` - Bloom types.Bloom `json:"logsBloom"` - Difficulty *math.HexOrDecimal256 `json:"difficulty"` - Number *math.HexOrDecimal256 `json:"number" gencodec:"required"` - GasLimit math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` - GasUsed math.HexOrDecimal64 `json:"gasUsed"` - Time math.HexOrDecimal64 `json:"timestamp" gencodec:"required"` - Extra hexutil.Bytes `json:"extraData"` - MixDigest common.Hash `json:"mixHash"` - Nonce *types.BlockNonce `json:"nonce"` - BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas" rlp:"optional"` + ParentHash common.Hash `json:"parentHash"` + OmmerHash *common.Hash `json:"sha3Uncles"` + Coinbase *common.Address `json:"miner"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot"` + ReceiptHash *common.Hash `json:"receiptsRoot"` + Bloom types.Bloom `json:"logsBloom"` + Difficulty *math.HexOrDecimal256 `json:"difficulty"` + Number *math.HexOrDecimal256 `json:"number" gencodec:"required"` + GasLimit math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` + GasUsed math.HexOrDecimal64 `json:"gasUsed"` + Time math.HexOrDecimal64 `json:"timestamp" gencodec:"required"` + Extra hexutil.Bytes `json:"extraData"` + MixDigest common.Hash `json:"mixHash"` + Nonce *types.BlockNonce `json:"nonce"` + BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas" rlp:"optional"` + WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` } var enc header enc.ParentHash = h.ParentHash @@ -52,28 +53,30 @@ func (h header) MarshalJSON() ([]byte, error) { enc.MixDigest = h.MixDigest enc.Nonce = h.Nonce enc.BaseFee = (*math.HexOrDecimal256)(h.BaseFee) + enc.WithdrawalsHash = h.WithdrawalsHash return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. func (h *header) UnmarshalJSON(input []byte) error { type header struct { - ParentHash *common.Hash `json:"parentHash"` - OmmerHash *common.Hash `json:"sha3Uncles"` - Coinbase *common.Address `json:"miner"` - Root *common.Hash `json:"stateRoot" gencodec:"required"` - TxHash *common.Hash `json:"transactionsRoot"` - ReceiptHash *common.Hash `json:"receiptsRoot"` - Bloom *types.Bloom `json:"logsBloom"` - Difficulty *math.HexOrDecimal256 `json:"difficulty"` - Number *math.HexOrDecimal256 `json:"number" gencodec:"required"` - GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` - GasUsed *math.HexOrDecimal64 `json:"gasUsed"` - Time *math.HexOrDecimal64 `json:"timestamp" gencodec:"required"` - Extra *hexutil.Bytes `json:"extraData"` - MixDigest *common.Hash `json:"mixHash"` - Nonce *types.BlockNonce `json:"nonce"` - BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas" rlp:"optional"` + ParentHash *common.Hash `json:"parentHash"` + OmmerHash *common.Hash `json:"sha3Uncles"` + Coinbase *common.Address `json:"miner"` + Root *common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot"` + ReceiptHash *common.Hash `json:"receiptsRoot"` + Bloom *types.Bloom `json:"logsBloom"` + Difficulty *math.HexOrDecimal256 `json:"difficulty"` + Number *math.HexOrDecimal256 `json:"number" gencodec:"required"` + GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` + GasUsed *math.HexOrDecimal64 `json:"gasUsed"` + Time *math.HexOrDecimal64 `json:"timestamp" gencodec:"required"` + Extra *hexutil.Bytes `json:"extraData"` + MixDigest *common.Hash `json:"mixHash"` + Nonce *types.BlockNonce `json:"nonce"` + BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas" rlp:"optional"` + WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` } var dec header if err := json.Unmarshal(input, &dec); err != nil { @@ -131,5 +134,8 @@ func (h *header) UnmarshalJSON(input []byte) error { if dec.BaseFee != nil { h.BaseFee = (*big.Int)(dec.BaseFee) } + if dec.WithdrawalsHash != nil { + h.WithdrawalsHash = dec.WithdrawalsHash + } return nil } diff --git a/cmd/evm/internal/t8ntool/gen_stenv.go b/cmd/evm/internal/t8ntool/gen_stenv.go index da449e659dca..c2cc3a2c8a38 100644 --- a/cmd/evm/internal/t8ntool/gen_stenv.go +++ b/cmd/evm/internal/t8ntool/gen_stenv.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/types" ) var _ = (*stEnvMarshaling)(nil) @@ -29,6 +30,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) { ParentTimestamp math.HexOrDecimal64 `json:"parentTimestamp,omitempty"` BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` Ommers []ommer `json:"ommers,omitempty"` + Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` ParentUncleHash common.Hash `json:"parentUncleHash"` } @@ -46,6 +48,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) { enc.ParentTimestamp = math.HexOrDecimal64(s.ParentTimestamp) enc.BlockHashes = s.BlockHashes enc.Ommers = s.Ommers + enc.Withdrawals = s.Withdrawals enc.BaseFee = (*math.HexOrDecimal256)(s.BaseFee) enc.ParentUncleHash = s.ParentUncleHash return json.Marshal(&enc) @@ -67,6 +70,7 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { ParentTimestamp *math.HexOrDecimal64 `json:"parentTimestamp,omitempty"` BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` Ommers []ommer `json:"ommers,omitempty"` + Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` ParentUncleHash *common.Hash `json:"parentUncleHash"` } @@ -117,6 +121,9 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { if dec.Ommers != nil { s.Ommers = dec.Ommers } + if dec.Withdrawals != nil { + s.Withdrawals = dec.Withdrawals + } if dec.BaseFee != nil { s.BaseFee = (*big.Int)(dec.BaseFee) } diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 8b05f1def9db..cb7466d86cae 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -262,6 +262,9 @@ func Transition(ctx *cli.Context) error { return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) } } + if chainConfig.IsShanghai(prestate.Env.Number) && prestate.Env.Withdrawals == nil { + return NewError(ErrorConfig, errors.New("Shanghai config but missing 'withdrawals' in env section")) + } isMerged := chainConfig.TerminalTotalDifficulty != nil && chainConfig.TerminalTotalDifficulty.BitLen() == 0 env := prestate.Env if isMerged { diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 5f9e75f48c6f..a9ce83a3e657 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -176,6 +176,7 @@ var blockBuilderCommand = &cli.Command{ t8ntool.OutputBlockFlag, t8ntool.InputHeaderFlag, t8ntool.InputOmmersFlag, + t8ntool.InputWithdrawalsFlag, t8ntool.InputTxsRlpFlag, t8ntool.SealCliqueFlag, t8ntool.SealEthashFlag, diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go index b7a0d9c2c3c7..067660c7e7ff 100644 --- a/cmd/evm/t8n_test.go +++ b/cmd/evm/t8n_test.go @@ -251,6 +251,14 @@ func TestT8n(t *testing.T) { output: t8nOutput{alloc: true, result: true}, expOut: "exp.json", }, + { // Test withdrawals transition + base: "./testdata/26", + input: t8nInput{ + "alloc.json", "txs.json", "env.json", "Shanghai", "", + }, + output: t8nOutput{alloc: true, result: true}, + expOut: "exp.json", + }, } { args := []string{"t8n"} args = append(args, tc.output.get()...) @@ -391,13 +399,14 @@ func TestT9n(t *testing.T) { } type b11rInput struct { - inEnv string - inOmmersRlp string - inTxsRlp string - inClique string - ethash bool - ethashMode string - ethashDir string + inEnv string + inOmmersRlp string + inWithdrawals string + inTxsRlp string + inClique string + ethash bool + ethashMode string + ethashDir string } func (args *b11rInput) get(base string) []string { @@ -410,6 +419,10 @@ func (args *b11rInput) get(base string) []string { out = append(out, "--input.ommers") out = append(out, fmt.Sprintf("%v/%v", base, opt)) } + if opt := args.inWithdrawals; opt != "" { + out = append(out, "--input.withdrawals") + out = append(out, fmt.Sprintf("%v/%v", base, opt)) + } if opt := args.inTxsRlp; opt != "" { out = append(out, "--input.txs") out = append(out, fmt.Sprintf("%v/%v", base, opt)) @@ -480,6 +493,16 @@ func TestB11r(t *testing.T) { }, expOut: "exp.json", }, + { // block with withdrawals + base: "./testdata/27", + input: b11rInput{ + inEnv: "header.json", + inOmmersRlp: "ommers.json", + inWithdrawals: "withdrawals.json", + inTxsRlp: "txs.rlp", + }, + expOut: "exp.json", + }, } { args := []string{"b11r"} args = append(args, tc.input.get(tc.base)...) diff --git a/cmd/evm/testdata/26/alloc.json b/cmd/evm/testdata/26/alloc.json new file mode 100644 index 000000000000..d67655a8a8e6 --- /dev/null +++ b/cmd/evm/testdata/26/alloc.json @@ -0,0 +1,8 @@ +{ + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x0", + "code": "0x", + "nonce": "0xac", + "storage": {} + } +} diff --git a/cmd/evm/testdata/26/env.json b/cmd/evm/testdata/26/env.json new file mode 100644 index 000000000000..03d817b93bc6 --- /dev/null +++ b/cmd/evm/testdata/26/env.json @@ -0,0 +1,17 @@ +{ + "currentCoinbase": "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty": null, + "currentRandom": "0xdeadc0de", + "currentGasLimit": "0x750a163df65e8a", + "currentBaseFee": "0x500", + "currentNumber": "1", + "currentTimestamp": "1000", + "withdrawals": [ + { + "index": "0x42", + "validatorIndex": "0x42", + "address": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "amount": "0x2a" + } + ] +} diff --git a/cmd/evm/testdata/26/exp.json b/cmd/evm/testdata/26/exp.json new file mode 100644 index 000000000000..4815e5cb65ef --- /dev/null +++ b/cmd/evm/testdata/26/exp.json @@ -0,0 +1,20 @@ +{ + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x9c7652400", + "nonce": "0xac" + } + }, + "result": { + "stateRoot": "0x6e061c2f6513af27d267a0e3b07cb9a10f1ba3a0f65ab648d3a17c36e15021d2", + "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [], + "currentDifficulty": null, + "gasUsed": "0x0", + "currentBaseFee": "0x500", + "withdrawalsRoot": "0x4921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5" + } +} diff --git a/cmd/evm/testdata/26/txs.json b/cmd/evm/testdata/26/txs.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/cmd/evm/testdata/26/txs.json @@ -0,0 +1 @@ +[] diff --git a/cmd/evm/testdata/27/exp.json b/cmd/evm/testdata/27/exp.json new file mode 100644 index 000000000000..5975a9c25af5 --- /dev/null +++ b/cmd/evm/testdata/27/exp.json @@ -0,0 +1,4 @@ +{ + "rlp": "0xf90239f9021aa0d6d785d33cbecf30f30d07e00e226af58f72efdf385d46bc3e6326c23b11e34ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0325aea6db48e9d737cddf59034843e99f05bec269453be83c9b9a981a232cc2ea056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082100082c3be83050785808455c5277e80a05865e417635a26db6d1d39ac70d1abf373e5398b3c6fd506acd038fa1334eedf88000000000000000080a04921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5c0c0d9d8424394a94f5374fce5edbc8e2a8697c15331677e6ebf0b2a", + "hash": "0xdc42abd3698499675819e0a85cc1266f16da90277509b867446a6b25fa2b9d87" +} diff --git a/cmd/evm/testdata/27/header.json b/cmd/evm/testdata/27/header.json new file mode 100644 index 000000000000..4ed7eaca09d6 --- /dev/null +++ b/cmd/evm/testdata/27/header.json @@ -0,0 +1,12 @@ +{ + "parentHash": "0xd6d785d33cbecf30f30d07e00e226af58f72efdf385d46bc3e6326c23b11e34e", + "stateRoot": "0x325aea6db48e9d737cddf59034843e99f05bec269453be83c9b9a981a232cc2e", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x1000", + "number": "0xc3be", + "gasLimit": "0x50785", + "gasUsed": "0x0", + "timestamp": "0x55c5277e", + "mixHash": "0x5865e417635a26db6d1d39ac70d1abf373e5398b3c6fd506acd038fa1334eedf", + "withdrawalsRoot": "0x4921c0162c359755b2ae714a0978a1dad2eb8edce7ff9b38b9b6fc4cbc547eb5" +} diff --git a/cmd/evm/testdata/27/ommers.json b/cmd/evm/testdata/27/ommers.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/cmd/evm/testdata/27/ommers.json @@ -0,0 +1 @@ +[] diff --git a/cmd/evm/testdata/27/txs.rlp b/cmd/evm/testdata/27/txs.rlp new file mode 100644 index 000000000000..e815397b333b --- /dev/null +++ b/cmd/evm/testdata/27/txs.rlp @@ -0,0 +1 @@ +"c0" diff --git a/cmd/evm/testdata/27/withdrawals.json b/cmd/evm/testdata/27/withdrawals.json new file mode 100644 index 000000000000..6634aff089b1 --- /dev/null +++ b/cmd/evm/testdata/27/withdrawals.json @@ -0,0 +1,8 @@ +[ + { + "index": "0x42", + "validatorIndex": "0x43", + "address": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "amount": "0x2a" + } +] diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 274b9cf3603e..eb5aa58ca887 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -257,7 +257,18 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa return consensus.ErrInvalidNumber } // Verify the header's EIP-1559 attributes. - return misc.VerifyEip1559Header(chain.Config(), parent, header) + if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil { + return err + } + // Verify existence / non-existence of withdrawalsHash. + shanghai := chain.Config().IsShanghai(header.Time) + if shanghai && header.WithdrawalsHash == nil { + return fmt.Errorf("missing withdrawalsHash") + } + if !shanghai && header.WithdrawalsHash != nil { + return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash) + } + return nil } // verifyHeaders is similar to verifyHeader, but verifies a batch of headers @@ -316,13 +327,20 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H } // Finalize implements consensus.Engine, setting the final state on the header -func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { +func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { // Finalize is different with Prepare, it can be used in both block generation // and verification. So determine the consensus rules by header type. if !beacon.IsPoSHeader(header) { - beacon.ethone.Finalize(chain, header, state, txs, uncles) + beacon.ethone.Finalize(chain, header, state, txs, uncles, nil) return } + // Withdrawals processing. + for _, w := range withdrawals { + // Convert amount from gwei to wei. + amount := new(big.Int).SetUint64(w.Amount) + amount = amount.Mul(amount, big.NewInt(params.GWei)) + state.AddBalance(w.Address, amount) + } // The block reward is no longer handled here. It's done by the // external consensus engine. header.Root = state.IntermediateRoot(true) @@ -330,15 +348,26 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. // FinalizeAndAssemble implements consensus.Engine, setting the final state and // assembling the block. -func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { +func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { // FinalizeAndAssemble is different with Prepare, it can be used in both block // generation and verification. So determine the consensus rules by header type. if !beacon.IsPoSHeader(header) { - return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts) + return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts, nil) + } + shanghai := chain.Config().IsShanghai(header.Time) + if shanghai { + // All blocks after Shanghai must include a withdrawals root. + if withdrawals == nil { + withdrawals = make([]*types.Withdrawal, 0) + } + } else { + if len(withdrawals) > 0 { + return nil, errors.New("withdrawals set before Shanghai activation") + } } - // Finalize and assemble the block - beacon.Finalize(chain, header, state, txs, uncles) - return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil + // Finalize and assemble the block. + beacon.Finalize(chain, header, state, txs, uncles, withdrawals) + return types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, trie.NewStackTrie(nil)), nil } // Seal generates a new sealing request for the given input block and pushes diff --git a/consensus/beacon/faker.go b/consensus/beacon/faker.go new file mode 100644 index 000000000000..981e345e3e1d --- /dev/null +++ b/consensus/beacon/faker.go @@ -0,0 +1,41 @@ +// Copyright 2023 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 beacon + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core/types" +) + +// NewFaker creates a fake consensus engine for testing. +// The fake engine simulates a merged network. +// It can not be used to test the merge transition. +// This type is needed since the fakeChainReader can not be used with +// a normal beacon consensus engine. +func NewFaker() consensus.Engine { + return new(faker) +} + +type faker struct { + Beacon +} + +func (f *faker) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { + return beaconDifficulty +} diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 53ccc34ccb8e..4706bbac1ca9 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -298,6 +298,9 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H if header.GasLimit > params.MaxGasLimit { return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit) } + if chain.Config().IsShanghai(header.Time) { + return fmt.Errorf("clique does not support shanghai fork") + } // If all checks passed, validate any special fields for hard forks if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { return err @@ -564,7 +567,7 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header // Finalize implements consensus.Engine, ensuring no uncles are set, nor block // rewards given. -func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { +func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { // No block rewards in PoA, so the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.UncleHash = types.CalcUncleHash(nil) @@ -572,9 +575,13 @@ func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Heade // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, // nor block rewards given, and returns the final block. -func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { +func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { + if len(withdrawals) > 0 { + return nil, errors.New("clique does not support withdrawals") + } + // Finalize block - c.Finalize(chain, header, state, txs, uncles) + c.Finalize(chain, header, state, txs, uncles, nil) // Assemble and return the final block for sealing return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil @@ -743,6 +750,9 @@ func encodeSigHeader(w io.Writer, header *types.Header) { if header.BaseFee != nil { enc = append(enc, header.BaseFee) } + if header.WithdrawalsHash != nil { + panic("unexpected withdrawal hash value in clique") + } if err := rlp.Encode(w, enc); err != nil { panic("can't encode: " + err.Error()) } diff --git a/consensus/consensus.go b/consensus/consensus.go index af8ce98ff3be..190d5ae12c8a 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -90,7 +90,7 @@ type Engine interface { // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, - uncles []*types.Header) + uncles []*types.Header, withdrawals []*types.Withdrawal) // FinalizeAndAssemble runs any post-transaction state modifications (e.g. block // rewards) and assembles the final block. @@ -98,7 +98,7 @@ type Engine interface { // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, - uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) + uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) // Seal generates a new sealing request for the given input block and pushes // the result into the given channel. diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index b49fcf0ce5a7..da29e16597b6 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -310,6 +310,9 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { return consensus.ErrInvalidNumber } + if chain.Config().IsShanghai(header.Time) { + return fmt.Errorf("ethash does not support shanghai fork") + } // Verify the engine specific seal securing the block if seal { if err := ethash.verifySeal(chain, header, false); err != nil { @@ -597,7 +600,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H // Finalize implements consensus.Engine, accumulating the block and uncle rewards, // setting the final state on the header -func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { +func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { // Accumulate any block and uncle rewards and commit the final state root accumulateRewards(chain.Config(), state, header, uncles) header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) @@ -605,10 +608,13 @@ func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types. // FinalizeAndAssemble implements consensus.Engine, accumulating the block and // uncle rewards, setting the final state and assembling the block. -func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { - // Finalize block - ethash.Finalize(chain, header, state, txs, uncles) +func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { + if len(withdrawals) > 0 { + return nil, errors.New("ethash does not support withdrawals") + } + // Finalize block + ethash.Finalize(chain, header, state, txs, uncles, nil) // Header seems complete, assemble into a block and return return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil } @@ -635,6 +641,9 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { if header.BaseFee != nil { enc = append(enc, header.BaseFee) } + if header.WithdrawalsHash != nil { + panic("withdrawal hash set on ethash") + } rlp.Encode(hasher, enc) hasher.Sum(hash[:0]) return hash diff --git a/core/beacon/gen_blockparams.go b/core/beacon/gen_blockparams.go index 0e2ea4bb1338..a7df96e091c1 100644 --- a/core/beacon/gen_blockparams.go +++ b/core/beacon/gen_blockparams.go @@ -8,46 +8,53 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" ) var _ = (*payloadAttributesMarshaling)(nil) // MarshalJSON marshals as JSON. -func (p PayloadAttributesV1) MarshalJSON() ([]byte, error) { - type PayloadAttributesV1 struct { - Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` - Random common.Hash `json:"prevRandao" gencodec:"required"` - SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"` +func (p PayloadAttributes) MarshalJSON() ([]byte, error) { + type PayloadAttributes struct { + Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Random common.Hash `json:"prevRandao" gencodec:"required"` + SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` } - var enc PayloadAttributesV1 + var enc PayloadAttributes enc.Timestamp = hexutil.Uint64(p.Timestamp) enc.Random = p.Random enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient + enc.Withdrawals = p.Withdrawals return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. -func (p *PayloadAttributesV1) UnmarshalJSON(input []byte) error { - type PayloadAttributesV1 struct { - Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` - Random *common.Hash `json:"prevRandao" gencodec:"required"` - SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"` +func (p *PayloadAttributes) UnmarshalJSON(input []byte) error { + type PayloadAttributes struct { + Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Random *common.Hash `json:"prevRandao" gencodec:"required"` + SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` } - var dec PayloadAttributesV1 + var dec PayloadAttributes if err := json.Unmarshal(input, &dec); err != nil { return err } if dec.Timestamp == nil { - return errors.New("missing required field 'timestamp' for PayloadAttributesV1") + return errors.New("missing required field 'timestamp' for PayloadAttributes") } p.Timestamp = uint64(*dec.Timestamp) if dec.Random == nil { - return errors.New("missing required field 'prevRandao' for PayloadAttributesV1") + return errors.New("missing required field 'prevRandao' for PayloadAttributes") } p.Random = *dec.Random if dec.SuggestedFeeRecipient == nil { - return errors.New("missing required field 'suggestedFeeRecipient' for PayloadAttributesV1") + return errors.New("missing required field 'suggestedFeeRecipient' for PayloadAttributes") } p.SuggestedFeeRecipient = *dec.SuggestedFeeRecipient + if dec.Withdrawals != nil { + p.Withdrawals = dec.Withdrawals + } return nil } diff --git a/core/beacon/gen_ed.go b/core/beacon/gen_ed.go index dcee3bf18c79..397504da7f05 100644 --- a/core/beacon/gen_ed.go +++ b/core/beacon/gen_ed.go @@ -9,29 +9,31 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" ) var _ = (*executableDataMarshaling)(nil) // MarshalJSON marshals as JSON. -func (e ExecutableDataV1) MarshalJSON() ([]byte, error) { - type ExecutableDataV1 struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` - StateRoot common.Hash `json:"stateRoot" gencodec:"required"` - ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` - LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"` - Random common.Hash `json:"prevRandao" gencodec:"required"` - Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"` - GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` - ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"` - BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` - BlockHash common.Hash `json:"blockHash" gencodec:"required"` - Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` - } - var enc ExecutableDataV1 +func (e ExecutableData) MarshalJSON() ([]byte, error) { + type ExecutableData struct { + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` + StateRoot common.Hash `json:"stateRoot" gencodec:"required"` + ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` + LogsBloom hexutil.Bytes `json:"logsBloom" gencodec:"required"` + Random common.Hash `json:"prevRandao" gencodec:"required"` + Number hexutil.Uint64 `json:"blockNumber" gencodec:"required"` + GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` + ExtraData hexutil.Bytes `json:"extraData" gencodec:"required"` + BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` + BlockHash common.Hash `json:"blockHash" gencodec:"required"` + Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` + } + var enc ExecutableData enc.ParentHash = e.ParentHash enc.FeeRecipient = e.FeeRecipient enc.StateRoot = e.StateRoot @@ -51,89 +53,94 @@ func (e ExecutableDataV1) MarshalJSON() ([]byte, error) { enc.Transactions[k] = v } } + enc.Withdrawals = e.Withdrawals return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. -func (e *ExecutableDataV1) UnmarshalJSON(input []byte) error { - type ExecutableDataV1 struct { - ParentHash *common.Hash `json:"parentHash" gencodec:"required"` - FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"` - StateRoot *common.Hash `json:"stateRoot" gencodec:"required"` - ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"` - LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"` - Random *common.Hash `json:"prevRandao" gencodec:"required"` - Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"` - GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` - ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"` - BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` - BlockHash *common.Hash `json:"blockHash" gencodec:"required"` - Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` - } - var dec ExecutableDataV1 +func (e *ExecutableData) UnmarshalJSON(input []byte) error { + type ExecutableData struct { + ParentHash *common.Hash `json:"parentHash" gencodec:"required"` + FeeRecipient *common.Address `json:"feeRecipient" gencodec:"required"` + StateRoot *common.Hash `json:"stateRoot" gencodec:"required"` + ReceiptsRoot *common.Hash `json:"receiptsRoot" gencodec:"required"` + LogsBloom *hexutil.Bytes `json:"logsBloom" gencodec:"required"` + Random *common.Hash `json:"prevRandao" gencodec:"required"` + Number *hexutil.Uint64 `json:"blockNumber" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Timestamp *hexutil.Uint64 `json:"timestamp" gencodec:"required"` + ExtraData *hexutil.Bytes `json:"extraData" gencodec:"required"` + BaseFeePerGas *hexutil.Big `json:"baseFeePerGas" gencodec:"required"` + BlockHash *common.Hash `json:"blockHash" gencodec:"required"` + Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` + } + var dec ExecutableData if err := json.Unmarshal(input, &dec); err != nil { return err } if dec.ParentHash == nil { - return errors.New("missing required field 'parentHash' for ExecutableDataV1") + return errors.New("missing required field 'parentHash' for ExecutableData") } e.ParentHash = *dec.ParentHash if dec.FeeRecipient == nil { - return errors.New("missing required field 'feeRecipient' for ExecutableDataV1") + return errors.New("missing required field 'feeRecipient' for ExecutableData") } e.FeeRecipient = *dec.FeeRecipient if dec.StateRoot == nil { - return errors.New("missing required field 'stateRoot' for ExecutableDataV1") + return errors.New("missing required field 'stateRoot' for ExecutableData") } e.StateRoot = *dec.StateRoot if dec.ReceiptsRoot == nil { - return errors.New("missing required field 'receiptsRoot' for ExecutableDataV1") + return errors.New("missing required field 'receiptsRoot' for ExecutableData") } e.ReceiptsRoot = *dec.ReceiptsRoot if dec.LogsBloom == nil { - return errors.New("missing required field 'logsBloom' for ExecutableDataV1") + return errors.New("missing required field 'logsBloom' for ExecutableData") } e.LogsBloom = *dec.LogsBloom if dec.Random == nil { - return errors.New("missing required field 'prevRandao' for ExecutableDataV1") + return errors.New("missing required field 'prevRandao' for ExecutableData") } e.Random = *dec.Random if dec.Number == nil { - return errors.New("missing required field 'blockNumber' for ExecutableDataV1") + return errors.New("missing required field 'blockNumber' for ExecutableData") } e.Number = uint64(*dec.Number) if dec.GasLimit == nil { - return errors.New("missing required field 'gasLimit' for ExecutableDataV1") + return errors.New("missing required field 'gasLimit' for ExecutableData") } e.GasLimit = uint64(*dec.GasLimit) if dec.GasUsed == nil { - return errors.New("missing required field 'gasUsed' for ExecutableDataV1") + return errors.New("missing required field 'gasUsed' for ExecutableData") } e.GasUsed = uint64(*dec.GasUsed) if dec.Timestamp == nil { - return errors.New("missing required field 'timestamp' for ExecutableDataV1") + return errors.New("missing required field 'timestamp' for ExecutableData") } e.Timestamp = uint64(*dec.Timestamp) if dec.ExtraData == nil { - return errors.New("missing required field 'extraData' for ExecutableDataV1") + return errors.New("missing required field 'extraData' for ExecutableData") } e.ExtraData = *dec.ExtraData if dec.BaseFeePerGas == nil { - return errors.New("missing required field 'baseFeePerGas' for ExecutableDataV1") + return errors.New("missing required field 'baseFeePerGas' for ExecutableData") } e.BaseFeePerGas = (*big.Int)(dec.BaseFeePerGas) if dec.BlockHash == nil { - return errors.New("missing required field 'blockHash' for ExecutableDataV1") + return errors.New("missing required field 'blockHash' for ExecutableData") } e.BlockHash = *dec.BlockHash if dec.Transactions == nil { - return errors.New("missing required field 'transactions' for ExecutableDataV1") + return errors.New("missing required field 'transactions' for ExecutableData") } e.Transactions = make([][]byte, len(dec.Transactions)) for k, v := range dec.Transactions { e.Transactions[k] = v } + if dec.Withdrawals != nil { + e.Withdrawals = dec.Withdrawals + } return nil } diff --git a/core/beacon/gen_epe.go b/core/beacon/gen_epe.go new file mode 100644 index 000000000000..0b4d8598f7a1 --- /dev/null +++ b/core/beacon/gen_epe.go @@ -0,0 +1,46 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package beacon + +import ( + "encoding/json" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*executionPayloadEnvelopeMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) { + type ExecutionPayloadEnvelope struct { + ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` + BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` + } + var enc ExecutionPayloadEnvelope + enc.ExecutionPayload = e.ExecutionPayload + enc.BlockValue = (*hexutil.Big)(e.BlockValue) + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error { + type ExecutionPayloadEnvelope struct { + ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` + BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` + } + var dec ExecutionPayloadEnvelope + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.ExecutionPayload == nil { + return errors.New("missing required field 'executionPayload' for ExecutionPayloadEnvelope") + } + e.ExecutionPayload = dec.ExecutionPayload + if dec.BlockValue == nil { + return errors.New("missing required field 'blockValue' for ExecutionPayloadEnvelope") + } + e.BlockValue = (*big.Int)(dec.BlockValue) + return nil +} diff --git a/core/beacon/types.go b/core/beacon/types.go index e06ab5c692d9..656115c78542 100644 --- a/core/beacon/types.go +++ b/core/beacon/types.go @@ -26,38 +26,41 @@ import ( "github.com/ethereum/go-ethereum/trie" ) -//go:generate go run github.com/fjl/gencodec -type PayloadAttributesV1 -field-override payloadAttributesMarshaling -out gen_blockparams.go - -// PayloadAttributesV1 structure described at https://github.com/ethereum/execution-apis/pull/74 -type PayloadAttributesV1 struct { - Timestamp uint64 `json:"timestamp" gencodec:"required"` - Random common.Hash `json:"prevRandao" gencodec:"required"` - SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"` +//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go + +// PayloadAttributes describes the environment context in which a block should +// be built. +type PayloadAttributes struct { + Timestamp uint64 `json:"timestamp" gencodec:"required"` + Random common.Hash `json:"prevRandao" gencodec:"required"` + SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` } -// JSON type overrides for PayloadAttributesV1. +// JSON type overrides for PayloadAttributes. type payloadAttributesMarshaling struct { Timestamp hexutil.Uint64 } -//go:generate go run github.com/fjl/gencodec -type ExecutableDataV1 -field-override executableDataMarshaling -out gen_ed.go - -// ExecutableDataV1 structure described at https://github.com/ethereum/execution-apis/tree/main/src/engine/specification.md -type ExecutableDataV1 struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` - StateRoot common.Hash `json:"stateRoot" gencodec:"required"` - ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` - LogsBloom []byte `json:"logsBloom" gencodec:"required"` - Random common.Hash `json:"prevRandao" gencodec:"required"` - Number uint64 `json:"blockNumber" gencodec:"required"` - GasLimit uint64 `json:"gasLimit" gencodec:"required"` - GasUsed uint64 `json:"gasUsed" gencodec:"required"` - Timestamp uint64 `json:"timestamp" gencodec:"required"` - ExtraData []byte `json:"extraData" gencodec:"required"` - BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"` - BlockHash common.Hash `json:"blockHash" gencodec:"required"` - Transactions [][]byte `json:"transactions" gencodec:"required"` +//go:generate go run github.com/fjl/gencodec -type ExecutableData -field-override executableDataMarshaling -out gen_ed.go + +// ExecutableData is the data necessary to execute an EL payload. +type ExecutableData struct { + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` + StateRoot common.Hash `json:"stateRoot" gencodec:"required"` + ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` + LogsBloom []byte `json:"logsBloom" gencodec:"required"` + Random common.Hash `json:"prevRandao" gencodec:"required"` + Number uint64 `json:"blockNumber" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed" gencodec:"required"` + Timestamp uint64 `json:"timestamp" gencodec:"required"` + ExtraData []byte `json:"extraData" gencodec:"required"` + BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"` + BlockHash common.Hash `json:"blockHash" gencodec:"required"` + Transactions [][]byte `json:"transactions" gencodec:"required"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` } // JSON type overrides for executableData. @@ -72,6 +75,18 @@ type executableDataMarshaling struct { Transactions []hexutil.Bytes } +//go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go + +type ExecutionPayloadEnvelope struct { + ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` + BlockValue *big.Int `json:"blockValue" gencodec:"required"` +} + +// JSON type overrides for ExecutionPayloadEnvelope. +type executionPayloadEnvelopeMarshaling struct { + BlockValue *hexutil.Big +} + type PayloadStatusV1 struct { Status string `json:"status"` LatestValidHash *common.Hash `json:"latestValidHash"` @@ -141,8 +156,10 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) { // uncleHash = emptyUncleHash // difficulty = 0 // -// and that the blockhash of the constructed block matches the parameters. -func ExecutableDataToBlock(params ExecutableDataV1) (*types.Block, error) { +// and that the blockhash of the constructed block matches the parameters. Nil +// Withdrawals value will propagate through the returned block. Empty +// Withdrawals value must be passed via non-nil, length 0 value in params. +func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) { txs, err := decodeTransactions(params.Transactions) if err != nil { return nil, err @@ -157,34 +174,43 @@ func ExecutableDataToBlock(params ExecutableDataV1) (*types.Block, error) { if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) { return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas) } + // Only set withdrawalsRoot if it is non-nil. This allows CLs to use + // ExecutableData before withdrawals are enabled by marshaling + // Withdrawals as the json null value. + var withdrawalsRoot *common.Hash + if params.Withdrawals != nil { + h := types.DeriveSha(types.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil)) + withdrawalsRoot = &h + } header := &types.Header{ - ParentHash: params.ParentHash, - UncleHash: types.EmptyUncleHash, - Coinbase: params.FeeRecipient, - Root: params.StateRoot, - TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), - ReceiptHash: params.ReceiptsRoot, - Bloom: types.BytesToBloom(params.LogsBloom), - Difficulty: common.Big0, - Number: new(big.Int).SetUint64(params.Number), - GasLimit: params.GasLimit, - GasUsed: params.GasUsed, - Time: params.Timestamp, - BaseFee: params.BaseFeePerGas, - Extra: params.ExtraData, - MixDigest: params.Random, + ParentHash: params.ParentHash, + UncleHash: types.EmptyUncleHash, + Coinbase: params.FeeRecipient, + Root: params.StateRoot, + TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), + ReceiptHash: params.ReceiptsRoot, + Bloom: types.BytesToBloom(params.LogsBloom), + Difficulty: common.Big0, + Number: new(big.Int).SetUint64(params.Number), + GasLimit: params.GasLimit, + GasUsed: params.GasUsed, + Time: params.Timestamp, + BaseFee: params.BaseFeePerGas, + Extra: params.ExtraData, + MixDigest: params.Random, + WithdrawalsHash: withdrawalsRoot, } - block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */) + block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals) if block.Hash() != params.BlockHash { return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash()) } return block, nil } -// BlockToExecutableData constructs the executableDataV1 structure by filling the +// BlockToExecutableData constructs the ExecutableData structure by filling the // fields from the given block. It assumes the given block is post-merge block. -func BlockToExecutableData(block *types.Block) *ExecutableDataV1 { - return &ExecutableDataV1{ +func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadEnvelope { + data := &ExecutableData{ BlockHash: block.Hash(), ParentHash: block.ParentHash(), FeeRecipient: block.Coinbase(), @@ -199,5 +225,7 @@ func BlockToExecutableData(block *types.Block) *ExecutableDataV1 { Transactions: encodeTransactions(block.Transactions()), Random: block.MixDigest(), ExtraData: block.Extra(), + Withdrawals: block.Withdrawals(), } + return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees} } diff --git a/core/block_validator.go b/core/block_validator.go index 3763be0be08d..813ac0a4384d 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -65,6 +65,11 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash { return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash) } + if header.WithdrawalsHash != nil { + if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash { + return fmt.Errorf("withdrawals root hash mismatch: have %x, want %x", hash, *header.WithdrawalsHash) + } + } if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { return consensus.ErrUnknownAncestor diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 2f9e604de9d1..5554361dbf0c 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4229,7 +4229,7 @@ func TestEIP3651(t *testing.T) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") - engine = ethash.NewFaker() + engine = beacon.NewFaker() // A sender who makes transactions, has some funds key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -4237,8 +4237,9 @@ func TestEIP3651(t *testing.T) { addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey) funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + config = *params.AllEthashProtocolChanges gspec = &Genesis{ - Config: params.AllEthashProtocolChanges, + Config: &config, Alloc: GenesisAlloc{ addr1: {Balance: funds}, addr2: {Balance: funds}, @@ -4275,6 +4276,8 @@ func TestEIP3651(t *testing.T) { gspec.Config.BerlinBlock = common.Big0 gspec.Config.LondonBlock = common.Big0 + gspec.Config.TerminalTotalDifficulty = common.Big0 + gspec.Config.TerminalTotalDifficultyPassed = true gspec.Config.ShanghaiTime = u64(0) signer := types.LatestSigner(gspec.Config) @@ -4317,10 +4320,7 @@ func TestEIP3651(t *testing.T) { // 3: Ensure that miner received only the tx's tip. actual := state.GetBalance(block.Coinbase()) - expected := new(big.Int).Add( - new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()), - ethash.ConstantinopleBlockReward, - ) + expected := new(big.Int).SetUint64(block.GasUsed() * block.Transactions()[0].GasTipCap().Uint64()) if actual.Cmp(expected) != 0 { t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual) } diff --git a/core/chain_makers.go b/core/chain_makers.go index cbfe5c3ece16..de63f234ac14 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -41,10 +41,11 @@ type BlockGen struct { header *types.Header statedb *state.StateDB - gasPool *GasPool - txs []*types.Transaction - receipts []*types.Receipt - uncles []*types.Header + gasPool *GasPool + txs []*types.Transaction + receipts []*types.Receipt + uncles []*types.Header + withdrawals []*types.Withdrawal config *params.ChainConfig engine consensus.Engine @@ -205,6 +206,26 @@ func (b *BlockGen) AddUncle(h *types.Header) { b.uncles = append(b.uncles, h) } +// AddWithdrawal adds a withdrawal to the generated block. +func (b *BlockGen) AddWithdrawal(w *types.Withdrawal) { + // The withdrawal will be assigned the next valid index. + var idx uint64 + for i := b.i - 1; i >= 0; i-- { + if wd := b.chain[i].Withdrawals(); len(wd) != 0 { + idx = wd[len(wd)-1].Index + 1 + break + } + if i == 0 { + // Correctly set the index if no parent had withdrawals + if wd := b.parent.Withdrawals(); len(wd) != 0 { + idx = wd[len(wd)-1].Index + 1 + } + } + } + w.Index = idx + b.withdrawals = append(b.withdrawals, w) +} + // PrevBlock returns a previously generated block by number. It panics if // num is greater or equal to the number of the block being generated. // For index -1, PrevBlock returns the parent block given to GenerateChain. @@ -281,8 +302,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse gen(i, b) } if b.engine != nil { - // Finalize and seal the block - block, _ := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts) + block, err := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts, b.withdrawals) + if err != nil { + panic(err) + } // Write state changes to db root, err := statedb.Commit(config.IsEIP158(b.header.Number)) diff --git a/core/genesis.go b/core/genesis.go index b4f49a1e1a8e..62096541f984 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -469,6 +469,9 @@ func (g *Genesis) ToBlock() *types.Block { head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee) } } + if g.Config != nil && g.Config.IsShanghai(g.Timestamp) { + head.WithdrawalsHash = &types.EmptyRootHash + } return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)) } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index a323ab9ad8b9..4df580e8c4ab 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -760,7 +760,7 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { if body == nil { return nil } - return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) + return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithWithdrawals(body.Withdrawals) } // WriteBlock serializes a block into the database, header and body separately. @@ -860,7 +860,7 @@ func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block { } for _, bad := range badBlocks { if bad.Header.Hash() == hash { - return types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles) + return types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals) } } return nil @@ -879,7 +879,7 @@ func ReadAllBadBlocks(db ethdb.Reader) []*types.Block { } var blocks []*types.Block for _, bad := range badBlocks { - blocks = append(blocks, types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles)) + blocks = append(blocks, types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals)) } return blocks } diff --git a/core/state_processor.go b/core/state_processor.go index da886781e322..163ea0a0200a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -86,8 +86,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } + // Fail if Shanghai not enabled and len(withdrawals) is non-zero. + withdrawals := block.Withdrawals() + if len(withdrawals) > 0 && !p.config.IsShanghai(block.Time()) { + return nil, nil, 0, fmt.Errorf("withdrawals before shanghai") + } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) + p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), withdrawals) return receipts, allLogs, *usedGas, nil } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index c91adc36ed46..305948d54c0d 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/rawdb" @@ -314,22 +315,24 @@ func TestStateProcessorErrors(t *testing.T) { db = rawdb.NewMemoryDatabase() gspec = &Genesis{ Config: ¶ms.ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - MuirGlacierBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - ArrowGlacierBlock: big.NewInt(0), - GrayGlacierBlock: big.NewInt(0), - MergeNetsplitBlock: big.NewInt(0), - ShanghaiTime: u64(0), + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + GrayGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + TerminalTotalDifficultyPassed: true, + ShanghaiTime: u64(0), }, Alloc: GenesisAlloc{ common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ @@ -339,7 +342,7 @@ func TestStateProcessorErrors(t *testing.T) { }, } genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil, nil) tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} smallInitCode = [320]byte{} ) @@ -361,7 +364,7 @@ func TestStateProcessorErrors(t *testing.T) { want: "could not apply tx 0 [0x39b7436cb432d3662a25626474282c5c4c1a213326fd87e4e18a91477bae98b2]: intrinsic gas too low: have 54299, want 54300", }, } { - block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config) + block := GenerateBadBlock(genesis, beacon.New(ethash.NewFaker()), tt.txs, gspec.Config) _, err := blockchain.InsertChain(types.Blocks{block}) if err == nil { t.Fatal("block imported without errors") @@ -378,23 +381,31 @@ func TestStateProcessorErrors(t *testing.T) { // valid to be considered for import: // - valid pow (fake), ancestry, difficulty, gaslimit etc func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions, config *params.ChainConfig) *types.Block { - header := &types.Header{ - ParentHash: parent.Hash(), - Coinbase: parent.Coinbase(), - Difficulty: engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{ + difficulty := big.NewInt(0) + if !config.TerminalTotalDifficultyPassed { + difficulty = engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{ Number: parent.Number(), Time: parent.Time(), Difficulty: parent.Difficulty(), UncleHash: parent.UncleHash(), - }), - GasLimit: parent.GasLimit(), - Number: new(big.Int).Add(parent.Number(), common.Big1), - Time: parent.Time() + 10, - UncleHash: types.EmptyUncleHash, + }) + } + + header := &types.Header{ + ParentHash: parent.Hash(), + Coinbase: parent.Coinbase(), + Difficulty: difficulty, + GasLimit: parent.GasLimit(), + Number: new(big.Int).Add(parent.Number(), common.Big1), + Time: parent.Time() + 10, + UncleHash: types.EmptyUncleHash, } if config.IsLondon(header.Number) { header.BaseFee = misc.CalcBaseFee(config, parent.Header()) } + if config.IsShanghai(header.Time) { + header.WithdrawalsHash = &types.EmptyRootHash + } var receipts []*types.Receipt // The post-state result doesn't need to be correct (this is a bad block), but we do need something there // Preferably something unique. So let's use a combo of blocknum + txhash diff --git a/core/types/block.go b/core/types/block.go index 603a3f771208..ac8c031acf18 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -87,6 +87,9 @@ type Header struct { // BaseFee was added by EIP-1559 and is ignored in legacy headers. BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` + // WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers. + WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` + /* TODO (MariusVanDerWijden) Add this field once needed // Random was added during the merge and contains the BeaconState randomness @@ -149,9 +152,12 @@ func (h *Header) SanityCheck() error { } // EmptyBody returns true if there is no additional 'body' to complete the header -// that is: no transactions and no uncles. +// that is: no transactions, no uncles and no withdrawals. func (h *Header) EmptyBody() bool { - return h.TxHash == EmptyRootHash && h.UncleHash == EmptyUncleHash + if h.WithdrawalsHash == nil { + return h.TxHash == EmptyRootHash && h.UncleHash == EmptyUncleHash + } + return h.TxHash == EmptyRootHash && h.UncleHash == EmptyUncleHash && *h.WithdrawalsHash == EmptyRootHash } // EmptyReceipts returns true if there are no receipts for this header/block. @@ -164,6 +170,7 @@ func (h *Header) EmptyReceipts() bool { type Body struct { Transactions []*Transaction Uncles []*Header + Withdrawals []*Withdrawal `rlp:"optional"` } // Block represents an entire block in the Ethereum blockchain. @@ -171,6 +178,7 @@ type Block struct { header *Header uncles []*Header transactions Transactions + withdrawals Withdrawals // caches hash atomic.Value @@ -184,9 +192,10 @@ type Block struct { // "external" block encoding. used for eth protocol, etc. type extblock struct { - Header *Header - Txs []*Transaction - Uncles []*Header + Header *Header + Txs []*Transaction + Uncles []*Header + Withdrawals []*Withdrawal `rlp:"optional"` } // NewBlock creates a new block. The input data is copied, @@ -228,6 +237,28 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* return b } +// NewBlockWithWithdrawals creates a new block with withdrawals. The input data +// is copied, changes to header and to the field values will not +// affect the block. +// +// The values of TxHash, UncleHash, ReceiptHash and Bloom in header +// are ignored and set to values derived from the given txs, uncles +// and receipts. +func NewBlockWithWithdrawals(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, withdrawals []*Withdrawal, hasher TrieHasher) *Block { + b := NewBlock(header, txs, uncles, receipts, hasher) + + if withdrawals == nil { + b.header.WithdrawalsHash = nil + } else if len(withdrawals) == 0 { + b.header.WithdrawalsHash = &EmptyRootHash + } else { + h := DeriveSha(Withdrawals(withdrawals), hasher) + b.header.WithdrawalsHash = &h + } + + return b.WithWithdrawals(withdrawals) +} + // NewBlockWithHeader creates a block with the given header data. The // header data is copied, changes to header and to the field values // will not affect the block. @@ -252,6 +283,9 @@ func CopyHeader(h *Header) *Header { cpy.Extra = make([]byte, len(h.Extra)) copy(cpy.Extra, h.Extra) } + if h.WithdrawalsHash != nil { + *cpy.WithdrawalsHash = *h.WithdrawalsHash + } return &cpy } @@ -262,7 +296,7 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error { if err := s.Decode(&eb); err != nil { return err } - b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, eb.Txs + b.header, b.uncles, b.transactions, b.withdrawals = eb.Header, eb.Uncles, eb.Txs, eb.Withdrawals b.size.Store(rlp.ListSize(size)) return nil } @@ -270,9 +304,10 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error { // EncodeRLP serializes b into the Ethereum RLP block format. func (b *Block) EncodeRLP(w io.Writer) error { return rlp.Encode(w, extblock{ - Header: b.header, - Txs: b.transactions, - Uncles: b.uncles, + Header: b.header, + Txs: b.transactions, + Uncles: b.uncles, + Withdrawals: b.withdrawals, }) } @@ -315,10 +350,14 @@ func (b *Block) BaseFee() *big.Int { return new(big.Int).Set(b.header.BaseFee) } +func (b *Block) Withdrawals() Withdrawals { + return b.withdrawals +} + func (b *Block) Header() *Header { return CopyHeader(b.header) } // Body returns the non-header content of the block. -func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles} } +func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles, b.withdrawals} } // Size returns the true RLP encoded storage size of the block, either by encoding // and returning it, or returning a previously cached value. @@ -361,6 +400,7 @@ func (b *Block) WithSeal(header *Header) *Block { header: &cpy, transactions: b.transactions, uncles: b.uncles, + withdrawals: b.withdrawals, } } @@ -378,6 +418,15 @@ func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { return block } +// WithWithdrawals sets the withdrawal contents of a block, does not return a new block. +func (b *Block) WithWithdrawals(withdrawals []*Withdrawal) *Block { + if withdrawals != nil { + b.withdrawals = make([]*Withdrawal, len(withdrawals)) + copy(b.withdrawals, withdrawals) + } + return b +} + // Hash returns the keccak256 hash of b's header. // The hash is computed on the first call and cached thereafter. func (b *Block) Hash() common.Hash { diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index 74746d033aa0..5c8b81652d2e 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -16,23 +16,24 @@ var _ = (*headerMarshaling)(nil) // MarshalJSON marshals as JSON. func (h Header) MarshalJSON() ([]byte, error) { type Header struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase common.Address `json:"miner"` - Root common.Hash `json:"stateRoot" gencodec:"required"` - TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` - ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` - Bloom Bloom `json:"logsBloom" gencodec:"required"` - Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` - Number *hexutil.Big `json:"number" gencodec:"required"` - GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Time hexutil.Uint64 `json:"timestamp" gencodec:"required"` - Extra hexutil.Bytes `json:"extraData" gencodec:"required"` - MixDigest common.Hash `json:"mixHash"` - Nonce BlockNonce `json:"nonce"` - BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` - Hash common.Hash `json:"hash"` + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase common.Address `json:"miner"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom Bloom `json:"logsBloom" gencodec:"required"` + Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` + Number *hexutil.Big `json:"number" gencodec:"required"` + GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Time hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Extra hexutil.Bytes `json:"extraData" gencodec:"required"` + MixDigest common.Hash `json:"mixHash"` + Nonce BlockNonce `json:"nonce"` + BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` + WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` + Hash common.Hash `json:"hash"` } var enc Header enc.ParentHash = h.ParentHash @@ -51,6 +52,7 @@ func (h Header) MarshalJSON() ([]byte, error) { enc.MixDigest = h.MixDigest enc.Nonce = h.Nonce enc.BaseFee = (*hexutil.Big)(h.BaseFee) + enc.WithdrawalsHash = h.WithdrawalsHash enc.Hash = h.Hash() return json.Marshal(&enc) } @@ -58,22 +60,23 @@ func (h Header) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (h *Header) UnmarshalJSON(input []byte) error { type Header struct { - ParentHash *common.Hash `json:"parentHash" gencodec:"required"` - UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase *common.Address `json:"miner"` - Root *common.Hash `json:"stateRoot" gencodec:"required"` - TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` - ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"` - Bloom *Bloom `json:"logsBloom" gencodec:"required"` - Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` - Number *hexutil.Big `json:"number" gencodec:"required"` - GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"` - Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` - MixDigest *common.Hash `json:"mixHash"` - Nonce *BlockNonce `json:"nonce"` - BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` + ParentHash *common.Hash `json:"parentHash" gencodec:"required"` + UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase *common.Address `json:"miner"` + Root *common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom *Bloom `json:"logsBloom" gencodec:"required"` + Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` + Number *hexutil.Big `json:"number" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` + MixDigest *common.Hash `json:"mixHash"` + Nonce *BlockNonce `json:"nonce"` + BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` + WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` } var dec Header if err := json.Unmarshal(input, &dec); err != nil { @@ -139,5 +142,8 @@ func (h *Header) UnmarshalJSON(input []byte) error { if dec.BaseFee != nil { h.BaseFee = (*big.Int)(dec.BaseFee) } + if dec.WithdrawalsHash != nil { + h.WithdrawalsHash = dec.WithdrawalsHash + } return nil } diff --git a/core/types/gen_header_rlp.go b/core/types/gen_header_rlp.go index e1a687331853..7fd2cf8f2d3e 100644 --- a/core/types/gen_header_rlp.go +++ b/core/types/gen_header_rlp.go @@ -41,7 +41,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { w.WriteBytes(obj.MixDigest[:]) w.WriteBytes(obj.Nonce[:]) _tmp1 := obj.BaseFee != nil - if _tmp1 { + _tmp2 := obj.WithdrawalsHash != nil + if _tmp1 || _tmp2 { if obj.BaseFee == nil { w.Write(rlp.EmptyString) } else { @@ -51,6 +52,13 @@ func (obj *Header) EncodeRLP(_w io.Writer) error { w.WriteBigInt(obj.BaseFee) } } + if _tmp2 { + if obj.WithdrawalsHash == nil { + w.Write([]byte{0x80}) + } else { + w.WriteBytes(obj.WithdrawalsHash[:]) + } + } w.ListEnd(_tmp0) return w.Flush() } diff --git a/core/types/gen_withdrawal_json.go b/core/types/gen_withdrawal_json.go new file mode 100644 index 000000000000..983a7f7a1248 --- /dev/null +++ b/core/types/gen_withdrawal_json.go @@ -0,0 +1,55 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package types + +import ( + "encoding/json" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*withdrawalMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (w Withdrawal) MarshalJSON() ([]byte, error) { + type Withdrawal struct { + Index hexutil.Uint64 `json:"index"` + Validator hexutil.Uint64 `json:"validatorIndex"` + Address common.Address `json:"address"` + Amount hexutil.Uint64 `json:"amount"` + } + var enc Withdrawal + enc.Index = hexutil.Uint64(w.Index) + enc.Validator = hexutil.Uint64(w.Validator) + enc.Address = w.Address + enc.Amount = hexutil.Uint64(w.Amount) + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (w *Withdrawal) UnmarshalJSON(input []byte) error { + type Withdrawal struct { + Index *hexutil.Uint64 `json:"index"` + Validator *hexutil.Uint64 `json:"validatorIndex"` + Address *common.Address `json:"address"` + Amount *hexutil.Uint64 `json:"amount"` + } + var dec Withdrawal + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Index != nil { + w.Index = uint64(*dec.Index) + } + if dec.Validator != nil { + w.Validator = uint64(*dec.Validator) + } + if dec.Address != nil { + w.Address = *dec.Address + } + if dec.Amount != nil { + w.Amount = uint64(*dec.Amount) + } + return nil +} diff --git a/core/types/gen_withdrawal_rlp.go b/core/types/gen_withdrawal_rlp.go new file mode 100644 index 000000000000..d0b4e0147a0d --- /dev/null +++ b/core/types/gen_withdrawal_rlp.go @@ -0,0 +1,20 @@ +// Code generated by rlpgen. DO NOT EDIT. + +//go:build !norlpgen +// +build !norlpgen + +package types + +import "github.com/ethereum/go-ethereum/rlp" +import "io" + +func (obj *Withdrawal) EncodeRLP(_w io.Writer) error { + w := rlp.NewEncoderBuffer(_w) + _tmp0 := w.List() + w.WriteUint64(obj.Index) + w.WriteUint64(obj.Validator) + w.WriteBytes(obj.Address[:]) + w.WriteUint64(obj.Amount) + w.ListEnd(_tmp0) + return w.Flush() +} diff --git a/core/types/withdrawal.go b/core/types/withdrawal.go new file mode 100644 index 000000000000..d1ad918f985c --- /dev/null +++ b/core/types/withdrawal.go @@ -0,0 +1,56 @@ +// Copyright 2022 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 types + +import ( + "bytes" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rlp" +) + +//go:generate go run github.com/fjl/gencodec -type Withdrawal -field-override withdrawalMarshaling -out gen_withdrawal_json.go +//go:generate go run ../../rlp/rlpgen -type Withdrawal -out gen_withdrawal_rlp.go + +// Withdrawal represents a validator withdrawal from the consensus layer. +type Withdrawal struct { + Index uint64 `json:"index"` // monotonically increasing identifier issued by consensus layer + Validator uint64 `json:"validatorIndex"` // index of validator associated with withdrawal + Address common.Address `json:"address"` // target address for withdrawn ether + Amount uint64 `json:"amount"` // value of withdrawal in Gwei +} + +// field type overrides for gencodec +type withdrawalMarshaling struct { + Index hexutil.Uint64 + Validator hexutil.Uint64 + Amount hexutil.Uint64 +} + +// Withdrawals implements DerivableList for withdrawals. +type Withdrawals []*Withdrawal + +// Len returns the length of s. +func (s Withdrawals) Len() int { return len(s) } + +// EncodeIndex encodes the i'th withdrawal to w. Note that this does not check for errors +// because we assume that *Withdrawal will only ever contain valid withdrawals that were either +// constructed by decoding or via public API in this package. +func (s Withdrawals) EncodeIndex(i int, w *bytes.Buffer) { + rlp.Encode(w, s[i]) +} diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 15a1f1a1bd90..56ff5eeabe33 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -119,7 +119,6 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) - cfg.State.CreateAccount(address) // set the receiver's (the executing contract) code for execution. cfg.State.SetCode(address, code) @@ -153,7 +152,6 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil) - // Call the code with the given configuration. code, address, leftOverGas, err := vmenv.Create( sender, diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 8dd71f48a7f8..39dcba04f83e 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -155,7 +155,19 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { // // If there are payloadAttributes: we try to assemble a block with the payloadAttributes // and return its payloadID. -func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributesV1) (beacon.ForkChoiceResponse, error) { +func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { + if payloadAttributes != nil && payloadAttributes.Withdrawals != nil { + return beacon.STATUS_INVALID, fmt.Errorf("withdrawals not supported in V1") + } + return api.forkchoiceUpdated(update, payloadAttributes) +} + +// ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes. +func (api *ConsensusAPI) ForkchoiceUpdatedV2(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { + return api.forkchoiceUpdated(update, payloadAttributes) +} + +func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { api.forkchoiceLock.Lock() defer api.forkchoiceLock.Unlock() @@ -285,6 +297,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa Timestamp: payloadAttributes.Timestamp, FeeRecipient: payloadAttributes.SuggestedFeeRecipient, Random: payloadAttributes.Random, + Withdrawals: payloadAttributes.Withdrawals, } id := args.Id() // If we already are busy generating this work, then we do not need @@ -334,7 +347,20 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.Transit } // GetPayloadV1 returns a cached payload by id. -func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableDataV1, error) { +func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableData, error) { + data, err := api.getPayload(payloadID) + if err != nil { + return nil, err + } + return data.ExecutionPayload, nil +} + +// GetPayloadV2 returns a cached payload by id. +func (api *ConsensusAPI) GetPayloadV2(payloadID beacon.PayloadID) (*beacon.ExecutionPayloadEnvelope, error) { + return api.getPayload(payloadID) +} + +func (api *ConsensusAPI) getPayload(payloadID beacon.PayloadID) (*beacon.ExecutionPayloadEnvelope, error) { log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID) data := api.localBlocks.get(payloadID) if data == nil { @@ -344,7 +370,19 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.Execu } // NewPayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. -func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.PayloadStatusV1, error) { +func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { + if params.Withdrawals != nil { + return beacon.PayloadStatusV1{Status: beacon.INVALID}, fmt.Errorf("withdrawals not supported in V1") + } + return api.newPayload(params) +} + +// NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. +func (api *ConsensusAPI) NewPayloadV2(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { + return api.newPayload(params) +} + +func (api *ConsensusAPI) newPayload(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { // The locking here is, strictly, not required. Without these locks, this can happen: // // 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to @@ -361,7 +399,7 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa api.newPayloadLock.Lock() defer api.newPayloadLock.Unlock() - log.Trace("Engine API request received", "method", "ExecutePayload", "number", params.Number, "hash", params.BlockHash) + log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash) block, err := beacon.ExecutableDataToBlock(params) if err != nil { log.Debug("Invalid NewPayload params", "params", params, "error", err) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 00ef2203f832..8df48bd08e10 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -18,6 +18,7 @@ package catalyst import ( "bytes" + "context" "fmt" "math/big" "sync" @@ -26,6 +27,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus" + beaconConsensus "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/beacon" @@ -38,6 +41,7 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" ) @@ -51,8 +55,14 @@ var ( testBalance = big.NewInt(2e18) ) -func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) { +func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) { config := *params.AllEthashProtocolChanges + engine := consensus.Engine(beaconConsensus.New(ethash.NewFaker())) + if merged { + config.TerminalTotalDifficulty = common.Big0 + config.TerminalTotalDifficultyPassed = true + engine = beaconConsensus.NewFaker() + } genesis := &core.Genesis{ Config: &config, Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, @@ -69,17 +79,21 @@ func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) { g.AddTx(tx) testNonce++ } - _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), n, generate) - totalDifficulty := big.NewInt(0) - for _, b := range blocks { - totalDifficulty.Add(totalDifficulty, b.Difficulty()) + _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, n, generate) + + if !merged { + totalDifficulty := big.NewInt(0) + for _, b := range blocks { + totalDifficulty.Add(totalDifficulty, b.Difficulty()) + } + config.TerminalTotalDifficulty = totalDifficulty } - config.TerminalTotalDifficulty = totalDifficulty + return genesis, blocks } func TestEth2AssembleBlock(t *testing.T) { - genesis, blocks := generatePreMergeChain(10) + genesis, blocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, blocks) defer n.Close() @@ -90,7 +104,7 @@ func TestEth2AssembleBlock(t *testing.T) { t.Fatalf("error signing transaction, err=%v", err) } ethservice.TxPool().AddLocal(tx) - blockParams := beacon.PayloadAttributesV1{ + blockParams := beacon.PayloadAttributes{ Timestamp: blocks[9].Time() + 5, } // The miner needs to pick up on the txs in the pool, so a few retries might be @@ -102,7 +116,7 @@ func TestEth2AssembleBlock(t *testing.T) { // assembleWithTransactions tries to assemble a block, retrying until it has 'want', // number of transactions in it, or it has retried three times. -func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributesV1, want int) (execData *beacon.ExecutableDataV1, err error) { +func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributes, want int) (execData *beacon.ExecutableData, err error) { for retries := 3; retries > 0; retries-- { execData, err = assembleBlock(api, parentHash, params) if err != nil { @@ -118,7 +132,7 @@ func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params } func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { - genesis, blocks := generatePreMergeChain(10) + genesis, blocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, blocks[:9]) defer n.Close() @@ -126,7 +140,7 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { // Put the 10th block's tx in the pool and produce a new block api.eth.TxPool().AddRemotesSync(blocks[9].Transactions()) - blockParams := beacon.PayloadAttributesV1{ + blockParams := beacon.PayloadAttributes{ Timestamp: blocks[8].Time() + 5, } // The miner needs to pick up on the txs in the pool, so a few retries might be @@ -137,7 +151,7 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { } func TestSetHeadBeforeTotalDifficulty(t *testing.T) { - genesis, blocks := generatePreMergeChain(10) + genesis, blocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, blocks) defer n.Close() @@ -155,7 +169,7 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) { } func TestEth2PrepareAndGetPayload(t *testing.T) { - genesis, blocks := generatePreMergeChain(10) + genesis, blocks := generateMergeChain(10, false) // We need to properly set the terminal total difficulty genesis.Config.TerminalTotalDifficulty.Sub(genesis.Config.TerminalTotalDifficulty, blocks[9].Difficulty()) n, ethservice := startEthService(t, genesis, blocks[:9]) @@ -165,7 +179,7 @@ func TestEth2PrepareAndGetPayload(t *testing.T) { // Put the 10th block's tx in the pool and produce a new block ethservice.TxPool().AddLocals(blocks[9].Transactions()) - blockParams := beacon.PayloadAttributesV1{ + blockParams := beacon.PayloadAttributes{ Timestamp: blocks[8].Time() + 5, } fcState := beacon.ForkchoiceStateV1{ @@ -221,7 +235,7 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan co } func TestInvalidPayloadTimestamp(t *testing.T) { - genesis, preMergeBlocks := generatePreMergeChain(10) + genesis, preMergeBlocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() var ( @@ -244,7 +258,7 @@ func TestInvalidPayloadTimestamp(t *testing.T) { for i, test := range tests { t.Run(fmt.Sprintf("Timestamp test: %v", i), func(t *testing.T) { - params := beacon.PayloadAttributesV1{ + params := beacon.PayloadAttributes{ Timestamp: test.time, Random: crypto.Keccak256Hash([]byte{byte(123)}), SuggestedFeeRecipient: parent.Coinbase(), @@ -265,7 +279,7 @@ func TestInvalidPayloadTimestamp(t *testing.T) { } func TestEth2NewBlock(t *testing.T) { - genesis, preMergeBlocks := generatePreMergeChain(10) + genesis, preMergeBlocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() @@ -288,7 +302,7 @@ func TestEth2NewBlock(t *testing.T) { tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) ethservice.TxPool().AddLocal(tx) - execData, err := assembleWithTransactions(api, parent.Hash(), &beacon.PayloadAttributesV1{ + execData, err := assembleWithTransactions(api, parent.Hash(), &beacon.PayloadAttributes{ Timestamp: parent.Time() + 5, }, 1) if err != nil { @@ -330,7 +344,7 @@ func TestEth2NewBlock(t *testing.T) { ) parent = preMergeBlocks[len(preMergeBlocks)-1] for i := 0; i < 10; i++ { - execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{ + execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributes{ Timestamp: parent.Time() + 6, }) if err != nil { @@ -367,7 +381,7 @@ func TestEth2DeepReorg(t *testing.T) { // TODO (MariusVanDerWijden) TestEth2DeepReorg is currently broken, because it tries to reorg // before the totalTerminalDifficulty threshold /* - genesis, preMergeBlocks := generatePreMergeChain(core.TriesInMemory * 2) + genesis, preMergeBlocks := generateMergeChain(core.TriesInMemory * 2, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() @@ -442,7 +456,7 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) } func TestFullAPI(t *testing.T) { - genesis, preMergeBlocks := generatePreMergeChain(10) + genesis, preMergeBlocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() var ( @@ -494,7 +508,7 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Bl } func TestExchangeTransitionConfig(t *testing.T) { - genesis, preMergeBlocks := generatePreMergeChain(10) + genesis, preMergeBlocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() @@ -555,7 +569,7 @@ We expect └── P1'' */ func TestNewPayloadOnInvalidChain(t *testing.T) { - genesis, preMergeBlocks := generatePreMergeChain(10) + genesis, preMergeBlocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() @@ -577,7 +591,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { }) ethservice.TxPool().AddRemotesSync([]*types.Transaction{tx}) var ( - params = beacon.PayloadAttributesV1{ + params = beacon.PayloadAttributes{ Timestamp: parent.Time() + 1, Random: crypto.Keccak256Hash([]byte{byte(i)}), SuggestedFeeRecipient: parent.Coinbase(), @@ -587,7 +601,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, } - payload *beacon.ExecutableDataV1 + payload *beacon.ExecutableData resp beacon.ForkChoiceResponse err error ) @@ -634,22 +648,23 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { } } -func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributesV1) (*beacon.ExecutableDataV1, error) { +func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributes) (*beacon.ExecutableData, error) { args := &miner.BuildPayloadArgs{ Parent: parentHash, Timestamp: params.Timestamp, FeeRecipient: params.SuggestedFeeRecipient, Random: params.Random, + Withdrawals: params.Withdrawals, } payload, err := api.eth.Miner().BuildPayload(args) if err != nil { return nil, err } - return payload.ResolveFull(), nil + return payload.ResolveFull().ExecutionPayload, nil } func TestEmptyBlocks(t *testing.T) { - genesis, preMergeBlocks := generatePreMergeChain(10) + genesis, preMergeBlocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() @@ -708,8 +723,8 @@ func TestEmptyBlocks(t *testing.T) { } } -func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon.ExecutableDataV1 { - params := beacon.PayloadAttributesV1{ +func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon.ExecutableData { + params := beacon.PayloadAttributes{ Timestamp: parent.Time() + 1, Random: crypto.Keccak256Hash([]byte{byte(1)}), SuggestedFeeRecipient: parent.Coinbase(), @@ -724,7 +739,7 @@ func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon // setBlockhash sets the blockhash of a modified ExecutableData. // Can be used to make modified payloads look valid. -func setBlockhash(data *beacon.ExecutableDataV1) *beacon.ExecutableDataV1 { +func setBlockhash(data *beacon.ExecutableData) *beacon.ExecutableData { txs, _ := decodeTransactions(data.Transactions) number := big.NewInt(0) number.SetUint64(data.Number) @@ -764,7 +779,7 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) { func TestTrickRemoteBlockCache(t *testing.T) { // Setup two nodes - genesis, preMergeBlocks := generatePreMergeChain(10) + genesis, preMergeBlocks := generateMergeChain(10, false) nodeA, ethserviceA := startEthService(t, genesis, preMergeBlocks) nodeB, ethserviceB := startEthService(t, genesis, preMergeBlocks) defer nodeA.Close() @@ -783,7 +798,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Block) {}) commonAncestor = ethserviceA.BlockChain().CurrentBlock() - var invalidChain []*beacon.ExecutableDataV1 + var invalidChain []*beacon.ExecutableData // create a valid payload (P1) //payload1 := getNewPayload(t, apiA, commonAncestor) //invalidChain = append(invalidChain, payload1) @@ -827,7 +842,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { } func TestInvalidBloom(t *testing.T) { - genesis, preMergeBlocks := generatePreMergeChain(10) + genesis, preMergeBlocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) ethservice.Merger().ReachTTD() defer n.Close() @@ -851,12 +866,12 @@ func TestInvalidBloom(t *testing.T) { } func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { - genesis, preMergeBlocks := generatePreMergeChain(100) - + genesis, preMergeBlocks := generateMergeChain(100, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty()) + var ( api = NewConsensusAPI(ethservice) parent = preMergeBlocks[len(preMergeBlocks)-1] @@ -887,7 +902,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { if err != nil { t.Fatalf("error preparing payload, err=%v", err) } - data := *payload.Resolve() + data := *payload.Resolve().ExecutionPayload resp2, err := api.NewPayloadV1(data) if err != nil { t.Fatalf("error sending NewPayload, err=%v", err) @@ -901,7 +916,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { // newPayLoad and forkchoiceUpdate. This is to test that the api behaves // well even of the caller is not being 'serial'. func TestSimultaneousNewBlock(t *testing.T) { - genesis, preMergeBlocks := generatePreMergeChain(10) + genesis, preMergeBlocks := generateMergeChain(10, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() @@ -910,7 +925,7 @@ func TestSimultaneousNewBlock(t *testing.T) { parent = preMergeBlocks[len(preMergeBlocks)-1] ) for i := 0; i < 10; i++ { - execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{ + execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributes{ Timestamp: parent.Time() + 5, }) if err != nil { @@ -984,3 +999,117 @@ func TestSimultaneousNewBlock(t *testing.T) { parent = block } } + +// TestWithdrawals creates and verifies two post-Shanghai blocks. The first +// includes zero withdrawals and the second includes two. +func TestWithdrawals(t *testing.T) { + genesis, blocks := generateMergeChain(10, true) + // Set shanghai time to last block + 5 seconds (first post-merge block) + time := blocks[len(blocks)-1].Time() + 5 + genesis.Config.ShanghaiTime = &time + + n, ethservice := startEthService(t, genesis, blocks) + ethservice.Merger().ReachTTD() + defer n.Close() + + api := NewConsensusAPI(ethservice) + + // 10: Build Shanghai block with no withdrawals. + parent := ethservice.BlockChain().CurrentHeader() + blockParams := beacon.PayloadAttributes{ + Timestamp: parent.Time + 5, + Withdrawals: make([]*types.Withdrawal, 0), + } + fcState := beacon.ForkchoiceStateV1{ + HeadBlockHash: parent.Hash(), + } + resp, err := api.ForkchoiceUpdatedV2(fcState, &blockParams) + if err != nil { + t.Fatalf("error preparing payload, err=%v", err) + } + if resp.PayloadStatus.Status != beacon.VALID { + t.Fatalf("unexpected status (got: %s, want: %s)", resp.PayloadStatus.Status, beacon.VALID) + } + + // 10: verify state root is the same as parent + payloadID := (&miner.BuildPayloadArgs{ + Parent: fcState.HeadBlockHash, + Timestamp: blockParams.Timestamp, + FeeRecipient: blockParams.SuggestedFeeRecipient, + Random: blockParams.Random, + }).Id() + execData, err := api.GetPayloadV2(payloadID) + if err != nil { + t.Fatalf("error getting payload, err=%v", err) + } + if execData.ExecutionPayload.StateRoot != parent.Root { + t.Fatalf("mismatch state roots (got: %s, want: %s)", execData.ExecutionPayload.StateRoot, blocks[8].Root()) + } + + // 10: verify locally built block + if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil { + t.Fatalf("error validating payload: %v", err) + } else if status.Status != beacon.VALID { + t.Fatalf("invalid payload") + } + + // 11: build shanghai block with withdrawal + aa := common.Address{0xaa} + bb := common.Address{0xbb} + blockParams = beacon.PayloadAttributes{ + Timestamp: execData.ExecutionPayload.Timestamp + 5, + Withdrawals: []*types.Withdrawal{ + { + Index: 0, + Address: aa, + Amount: 32, + }, + { + Index: 1, + Address: bb, + Amount: 33, + }, + }, + } + fcState.HeadBlockHash = execData.ExecutionPayload.BlockHash + _, err = api.ForkchoiceUpdatedV2(fcState, &blockParams) + if err != nil { + t.Fatalf("error preparing payload, err=%v", err) + } + + // 11: verify locally build block. + payloadID = (&miner.BuildPayloadArgs{ + Parent: fcState.HeadBlockHash, + Timestamp: blockParams.Timestamp, + FeeRecipient: blockParams.SuggestedFeeRecipient, + Random: blockParams.Random, + }).Id() + execData, err = api.GetPayloadV2(payloadID) + if err != nil { + t.Fatalf("error getting payload, err=%v", err) + } + if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil { + t.Fatalf("error validating payload: %v", err) + } else if status.Status != beacon.VALID { + t.Fatalf("invalid payload") + } + + // 11: set block as head. + fcState.HeadBlockHash = execData.ExecutionPayload.BlockHash + _, err = api.ForkchoiceUpdatedV2(fcState, nil) + if err != nil { + t.Fatalf("error preparing payload, err=%v", err) + } + + // 11: verify withdrawals were processed. + db, _, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number)) + if err != nil { + t.Fatalf("unable to load db: %v", err) + } + for i, w := range blockParams.Withdrawals { + // w.Amount is in gwei, balance in wei + if db.GetBalance(w.Address).Uint64() != w.Amount*params.GWei { + t.Fatalf("failed to process withdrawal %d", i) + } + } +} diff --git a/eth/catalyst/queue.go b/eth/catalyst/queue.go index c15799487f20..5c60f70e44b3 100644 --- a/eth/catalyst/queue.go +++ b/eth/catalyst/queue.go @@ -70,7 +70,7 @@ func (q *payloadQueue) put(id beacon.PayloadID, payload *miner.Payload) { } // get retrieves a previously stored payload item or nil if it does not exist. -func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutableDataV1 { +func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutionPayloadEnvelope { q.lock.RLock() defer q.lock.RUnlock() diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index f58da869ee30..f7790b2d80f0 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -1548,7 +1548,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { ) blocks := make([]*types.Block, len(results)) for i, result := range results { - blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) + blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals) } // Downloaded blocks are always regarded as trusted after the // transition. Because the downloaded chain is guided by the @@ -1748,7 +1748,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state blocks := make([]*types.Block, len(results)) receipts := make([]types.Receipts, len(results)) for i, result := range results { - blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) + blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals) receipts[i] = result.Receipts } if index, err := d.blockchain.InsertReceiptChain(blocks, receipts, d.ancientLimit); err != nil { @@ -1759,7 +1759,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state } func (d *Downloader) commitPivotBlock(result *fetchResult) error { - block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) + block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals) log.Debug("Committing snap sync pivot as new head", "number", block.Number(), "hash", block.Hash()) // Commit the pivot block as the new head, will require full sync from here on diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 36d6795e7afe..2f0c4acf7887 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -273,8 +273,9 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et rlp.DecodeBytes(blob, bodies[i]) } var ( - txsHashes = make([]common.Hash, len(bodies)) - uncleHashes = make([]common.Hash, len(bodies)) + txsHashes = make([]common.Hash, len(bodies)) + uncleHashes = make([]common.Hash, len(bodies)) + withdrawalHashes = make([]common.Hash, len(bodies)) ) hasher := trie.NewStackTrie(nil) for i, body := range bodies { @@ -287,7 +288,7 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et res := ð.Response{ Req: req, Res: (*eth.BlockBodiesPacket)(&bodies), - Meta: [][]common.Hash{txsHashes, uncleHashes}, + Meta: [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes}, Time: 1, Done: make(chan error, 1), // Ignore the returned status } diff --git a/eth/downloader/fetchers_concurrent_bodies.go b/eth/downloader/fetchers_concurrent_bodies.go index e84206fe9951..9440972c6d70 100644 --- a/eth/downloader/fetchers_concurrent_bodies.go +++ b/eth/downloader/fetchers_concurrent_bodies.go @@ -89,10 +89,10 @@ func (q *bodyQueue) request(peer *peerConnection, req *fetchRequest, resCh chan // deliver is responsible for taking a generic response packet from the concurrent // fetcher, unpacking the body data and delivering it to the downloader's queue. func (q *bodyQueue) deliver(peer *peerConnection, packet *eth.Response) (int, error) { - txs, uncles := packet.Res.(*eth.BlockBodiesPacket).Unpack() - hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes} + txs, uncles, withdrawals := packet.Res.(*eth.BlockBodiesPacket).Unpack() + hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes, withdrawal hashes} - accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1]) + accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1], withdrawals, hashsets[2]) switch { case err == nil && len(txs) == 0: peer.log.Trace("Requested bodies delivered") diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 60a83a7fb0d9..c71b36466d41 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -67,6 +67,7 @@ type fetchResult struct { Uncles []*types.Header Transactions types.Transactions Receipts types.Receipts + Withdrawals types.Withdrawals } func newFetchResult(header *types.Header, fastSync bool) *fetchResult { @@ -764,7 +765,9 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, hashes []comm // DeliverBodies injects a block body retrieval response into the results queue. // The method returns the number of blocks bodies accepted from the delivery and // also wakes any threads waiting for data delivery. -func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListHashes []common.Hash, uncleLists [][]*types.Header, uncleListHashes []common.Hash) (int, error) { +func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListHashes []common.Hash, + uncleLists [][]*types.Header, uncleListHashes []common.Hash, + withdrawalLists [][]*types.Withdrawal, withdrawalListHashes []common.Hash) (int, error) { q.lock.Lock() defer q.lock.Unlock() @@ -775,12 +778,19 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH if uncleListHashes[index] != header.UncleHash { return errInvalidBody } + if header.WithdrawalsHash == nil { + // discard any withdrawals if we don't have a withdrawal hash set + withdrawalLists[index] = nil + } else if withdrawalListHashes[index] != *header.WithdrawalsHash { + return errInvalidBody + } return nil } reconstruct := func(index int, result *fetchResult) { result.Transactions = txLists[index] result.Uncles = uncleLists[index] + result.Withdrawals = withdrawalLists[index] result.SetBodyDone() } return q.deliver(id, q.blockTaskPool, q.blockTaskQueue, q.blockPendPool, diff --git a/eth/downloader/queue_test.go b/eth/downloader/queue_test.go index 8631b27c9275..6babf9440869 100644 --- a/eth/downloader/queue_test.go +++ b/eth/downloader/queue_test.go @@ -339,7 +339,7 @@ func XTestDelivery(t *testing.T) { uncleHashes[i] = types.CalcUncleHash(uncles) } time.Sleep(100 * time.Millisecond) - _, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes) + _, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes, nil, nil) if err != nil { fmt.Printf("delivered %d bodies %v\n", len(txset), err) } diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index bd1a34c83c00..156d07e9131f 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -540,8 +540,8 @@ func (f *BlockFetcher) loop() { select { case res := <-resCh: res.Done <- nil - - txs, uncles := res.Res.(*eth.BlockBodiesPacket).Unpack() + // Ignoring withdrawals here, since the block fetcher is not used post-merge. + txs, uncles, _ := res.Res.(*eth.BlockBodiesPacket).Unpack() f.FilterBodies(peer, txs, uncles, time.Now()) case <-timeout.C: diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 5c3d1be0a123..201dc98b6aec 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -23,6 +23,8 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -45,6 +47,8 @@ var ( testAddr = crypto.PubkeyToAddress(testKey.PublicKey) ) +func u64(val uint64) *uint64 { return &val } + // testBackend is a mock implementation of the live Ethereum message handler. Its // purpose is to allow testing the request/reply workflows and wire serialization // in the `eth` protocol without actually doing any data processing. @@ -56,21 +60,53 @@ type testBackend struct { // newTestBackend creates an empty chain and wraps it into a mock backend. func newTestBackend(blocks int) *testBackend { - return newTestBackendWithGenerator(blocks, nil) + return newTestBackendWithGenerator(blocks, false, nil) } // newTestBackend creates a chain with a number of explicitly defined blocks and // wraps it into a mock backend. -func newTestBackendWithGenerator(blocks int, generator func(int, *core.BlockGen)) *testBackend { - // Create a database pre-initialize with a genesis block - db := rawdb.NewMemoryDatabase() +func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, *core.BlockGen)) *testBackend { + var ( + // Create a database pre-initialize with a genesis block + db = rawdb.NewMemoryDatabase() + config = params.TestChainConfig + engine consensus.Engine = ethash.NewFaker() + ) + + if shanghai { + config = ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + GrayGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + ShanghaiTime: u64(0), + TerminalTotalDifficulty: big.NewInt(0), + TerminalTotalDifficultyPassed: true, + Ethash: new(params.EthashConfig), + } + engine = beacon.NewFaker() + } + gspec := &core.Genesis{ - Config: params.TestChainConfig, + Config: config, Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, } - chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) - _, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, generator) + _, bs, _ := core.GenerateChainWithGenesis(gspec, engine, blocks, generator) if _, err := chain.InsertChain(bs); err != nil { panic(err) } @@ -305,7 +341,17 @@ func TestGetBlockBodies68(t *testing.T) { testGetBlockBodies(t, ETH68) } func testGetBlockBodies(t *testing.T, protocol uint) { t.Parallel() - backend := newTestBackend(maxBodiesServe + 15) + gen := func(n int, g *core.BlockGen) { + if n%2 == 0 { + w := &types.Withdrawal{ + Address: common.Address{0xaa}, + Amount: 42, + } + g.AddWithdrawal(w) + } + } + + backend := newTestBackendWithGenerator(maxBodiesServe+15, true, gen) defer backend.close() peer, _ := newTestPeer("peer", protocol, backend) @@ -355,7 +401,7 @@ func testGetBlockBodies(t *testing.T, protocol uint) { block := backend.chain.GetBlockByNumber(uint64(num)) hashes = append(hashes, block.Hash()) if len(bodies) < tt.expected { - bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles()}) + bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles(), Withdrawals: block.Withdrawals()}) } break } @@ -365,9 +411,10 @@ func testGetBlockBodies(t *testing.T, protocol uint) { hashes = append(hashes, hash) if tt.available[j] && len(bodies) < tt.expected { block := backend.chain.GetBlockByHash(hash) - bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles()}) + bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles(), Withdrawals: block.Withdrawals()}) } } + // Send the hash request and verify the response p2p.Send(peer.app, GetBlockBodiesMsg, &GetBlockBodiesPacket66{ RequestId: 123, @@ -426,7 +473,7 @@ func testGetNodeData(t *testing.T, protocol uint, drop bool) { } } // Assemble the test environment - backend := newTestBackendWithGenerator(4, generator) + backend := newTestBackendWithGenerator(4, false, generator) defer backend.close() peer, _ := newTestPeer("peer", protocol, backend) @@ -544,7 +591,7 @@ func testGetBlockReceipts(t *testing.T, protocol uint) { } } // Assemble the test environment - backend := newTestBackendWithGenerator(4, generator) + backend := newTestBackendWithGenerator(4, false, generator) defer backend.close() peer, _ := newTestPeer("peer", protocol, backend) diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 85a59969ebf8..74e514b863a3 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -379,15 +379,19 @@ func handleBlockBodies66(backend Backend, msg Decoder, peer *Peer) error { } metadata := func() interface{} { var ( - txsHashes = make([]common.Hash, len(res.BlockBodiesPacket)) - uncleHashes = make([]common.Hash, len(res.BlockBodiesPacket)) + txsHashes = make([]common.Hash, len(res.BlockBodiesPacket)) + uncleHashes = make([]common.Hash, len(res.BlockBodiesPacket)) + withdrawalHashes = make([]common.Hash, len(res.BlockBodiesPacket)) ) hasher := trie.NewStackTrie(nil) for i, body := range res.BlockBodiesPacket { txsHashes[i] = types.DeriveSha(types.Transactions(body.Transactions), hasher) uncleHashes[i] = types.CalcUncleHash(body.Uncles) + if body.Withdrawals != nil { + withdrawalHashes[i] = types.DeriveSha(types.Withdrawals(body.Withdrawals), hasher) + } } - return [][]common.Hash{txsHashes, uncleHashes} + return [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes} } return peer.dispatchResponse(&Response{ id: res.RequestId, diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index 6c59fcae655a..0d4b368988f7 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -239,19 +239,22 @@ type BlockBodiesRLPPacket66 struct { type BlockBody struct { Transactions []*types.Transaction // Transactions contained within a block Uncles []*types.Header // Uncles contained within a block + Withdrawals []*types.Withdrawal `rlp:"optional"` // Withdrawals contained within a block } // Unpack retrieves the transactions and uncles from the range packet and returns // them in a split flat format that's more consistent with the internal data structures. -func (p *BlockBodiesPacket) Unpack() ([][]*types.Transaction, [][]*types.Header) { +func (p *BlockBodiesPacket) Unpack() ([][]*types.Transaction, [][]*types.Header, [][]*types.Withdrawal) { + // TODO(matt): add support for withdrawals to fetchers var ( - txset = make([][]*types.Transaction, len(*p)) - uncleset = make([][]*types.Header, len(*p)) + txset = make([][]*types.Transaction, len(*p)) + uncleset = make([][]*types.Header, len(*p)) + withdrawalset = make([][]*types.Withdrawal, len(*p)) ) for i, body := range *p { - txset[i], uncleset[i] = body.Transactions, body.Uncles + txset[i], uncleset[i], withdrawalset[i] = body.Transactions, body.Uncles, body.Withdrawals } - return txset, uncleset + return txset, uncleset, withdrawalset } // GetNodeDataPacket represents a trie node data query. diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e0e4278bb467..1ac9c5faa74a 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1214,6 +1214,10 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee) } + if head.WithdrawalsHash != nil { + result["withdrawalsRoot"] = head.WithdrawalsHash + } + return result } @@ -1242,6 +1246,8 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param } } fields["transactions"] = transactions + // inclTx also expands withdrawals + fields["withdrawals"] = block.Withdrawals() } uncles := block.Uncles() uncleHashes := make([]common.Hash, len(uncles)) diff --git a/les/catalyst/api.go b/les/catalyst/api.go index 822e0af038a7..b5957583289d 100644 --- a/les/catalyst/api.go +++ b/les/catalyst/api.go @@ -70,7 +70,7 @@ func NewConsensusAPI(les *les.LightEthereum) *ConsensusAPI { // // If there are payloadAttributes: we return an error since block creation is not // supported in les mode. -func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributesV1) (beacon.ForkChoiceResponse, error) { +func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { if heads.HeadBlockHash == (common.Hash{}) { log.Warn("Forkchoice requested update to zero hash") return beacon.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this? @@ -100,12 +100,12 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads beacon.ForkchoiceStateV1, pay } // GetPayloadV1 returns a cached payload by id. It's not supported in les mode. -func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableDataV1, error) { +func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableData, error) { return nil, beacon.GenericServerError.With(errors.New("not supported in light client mode")) } // ExecutePayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. -func (api *ConsensusAPI) ExecutePayloadV1(params beacon.ExecutableDataV1) (beacon.PayloadStatusV1, error) { +func (api *ConsensusAPI) ExecutePayloadV1(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { block, err := beacon.ExecutableDataToBlock(params) if err != nil { return api.invalid(), err diff --git a/les/catalyst/api_test.go b/les/catalyst/api_test.go index 91d5c9bbb988..2af90dfc6e69 100644 --- a/les/catalyst/api_test.go +++ b/les/catalyst/api_test.go @@ -130,7 +130,7 @@ func TestExecutePayloadV1(t *testing.T) { BaseFee: block.BaseFee(), }, nil, nil, nil, trie.NewStackTrie(nil)) - _, err := api.ExecutePayloadV1(beacon.ExecutableDataV1{ + _, err := api.ExecutePayloadV1(beacon.ExecutableData{ ParentHash: fakeBlock.ParentHash(), FeeRecipient: fakeBlock.Coinbase(), StateRoot: fakeBlock.Root(), diff --git a/miner/payload_building.go b/miner/payload_building.go index 2e3ebe356c59..75bca67cbb32 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -34,10 +34,11 @@ import ( // Check engine-api specification for more details. // https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#payloadattributesv1 type BuildPayloadArgs struct { - Parent common.Hash // The parent block to build payload on top - Timestamp uint64 // The provided timestamp of generated payload - FeeRecipient common.Address // The provided recipient address for collecting transaction fee - Random common.Hash // The provided randomness value + Parent common.Hash // The parent block to build payload on top + Timestamp uint64 // The provided timestamp of generated payload + FeeRecipient common.Address // The provided recipient address for collecting transaction fee + Random common.Hash // The provided randomness value + Withdrawals types.Withdrawals // The provided withdrawals } // Id computes an 8-byte identifier by hashing the components of the payload arguments. @@ -107,7 +108,7 @@ func (payload *Payload) update(block *types.Block, fees *big.Int, elapsed time.D // Resolve returns the latest built payload and also terminates the background // thread for updating payload. It's safe to be called multiple times. -func (payload *Payload) Resolve() *beacon.ExecutableDataV1 { +func (payload *Payload) Resolve() *beacon.ExecutionPayloadEnvelope { payload.lock.Lock() defer payload.lock.Unlock() @@ -117,23 +118,23 @@ func (payload *Payload) Resolve() *beacon.ExecutableDataV1 { close(payload.stop) } if payload.full != nil { - return beacon.BlockToExecutableData(payload.full) + return beacon.BlockToExecutableData(payload.full, payload.fullFees) } - return beacon.BlockToExecutableData(payload.empty) + return beacon.BlockToExecutableData(payload.empty, big.NewInt(0)) } // ResolveEmpty is basically identical to Resolve, but it expects empty block only. // It's only used in tests. -func (payload *Payload) ResolveEmpty() *beacon.ExecutableDataV1 { +func (payload *Payload) ResolveEmpty() *beacon.ExecutionPayloadEnvelope { payload.lock.Lock() defer payload.lock.Unlock() - return beacon.BlockToExecutableData(payload.empty) + return beacon.BlockToExecutableData(payload.empty, big.NewInt(0)) } // ResolveFull is basically identical to Resolve, but it expects full block only. // It's only used in tests. -func (payload *Payload) ResolveFull() *beacon.ExecutableDataV1 { +func (payload *Payload) ResolveFull() *beacon.ExecutionPayloadEnvelope { payload.lock.Lock() defer payload.lock.Unlock() @@ -145,7 +146,7 @@ func (payload *Payload) ResolveFull() *beacon.ExecutableDataV1 { } payload.cond.Wait() } - return beacon.BlockToExecutableData(payload.full) + return beacon.BlockToExecutableData(payload.full, payload.fullFees) } // buildPayload builds the payload according to the provided parameters. @@ -153,7 +154,7 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { // Build the initial version with no transaction included. It should be fast // enough to run. The empty payload can at least make sure there is something // to deliver for not missing slot. - empty, _, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, true) + empty, _, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, args.Withdrawals, true) if err != nil { return nil, err } @@ -177,7 +178,7 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { select { case <-timer.C: start := time.Now() - block, fees, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, false) + block, fees, err := w.getSealingBlock(args.Parent, args.Timestamp, args.FeeRecipient, args.Random, args.Withdrawals, false) if err == nil { payload.update(block, fees, time.Since(start)) } diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index 226ae71b4add..8d6ffaff13a2 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -47,20 +47,21 @@ func TestBuildPayload(t *testing.T) { if err != nil { t.Fatalf("Failed to build payload %v", err) } - verify := func(data *beacon.ExecutableDataV1, txs int) { - if data.ParentHash != b.chain.CurrentBlock().Hash() { + verify := func(outer *beacon.ExecutionPayloadEnvelope, txs int) { + payload := outer.ExecutionPayload + if payload.ParentHash != b.chain.CurrentBlock().Hash() { t.Fatal("Unexpect parent hash") } - if data.Random != (common.Hash{}) { + if payload.Random != (common.Hash{}) { t.Fatal("Unexpect random value") } - if data.Timestamp != timestamp { + if payload.Timestamp != timestamp { t.Fatal("Unexpect timestamp") } - if data.FeeRecipient != recipient { + if payload.FeeRecipient != recipient { t.Fatal("Unexpect fee recipient") } - if len(data.Transactions) != txs { + if len(payload.Transactions) != txs { t.Fatal("Unexpect transaction set") } } diff --git a/miner/stress/beacon/main.go b/miner/stress/beacon/main.go index 7dabc97c003f..bd500453d2b3 100644 --- a/miner/stress/beacon/main.go +++ b/miner/stress/beacon/main.go @@ -142,7 +142,7 @@ func newNode(typ nodetype, genesis *core.Genesis, enodes []*enode.Node) *ethNode } } -func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) (*beacon.ExecutableDataV1, error) { +func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) (*beacon.ExecutableData, error) { if n.typ != eth2MiningNode { return nil, errors.New("invalid node type") } @@ -150,7 +150,7 @@ func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) if timestamp <= parentTimestamp { timestamp = parentTimestamp + 1 } - payloadAttribute := beacon.PayloadAttributesV1{ + payloadAttribute := beacon.PayloadAttributes{ Timestamp: timestamp, Random: common.Hash{}, SuggestedFeeRecipient: common.HexToAddress("0xdeadbeef"), @@ -168,7 +168,7 @@ func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) return n.api.GetPayloadV1(*payload.PayloadID) } -func (n *ethNode) insertBlock(eb beacon.ExecutableDataV1) error { +func (n *ethNode) insertBlock(eb beacon.ExecutableData) error { if !eth2types(n.typ) { return errors.New("invalid node type") } @@ -194,7 +194,7 @@ func (n *ethNode) insertBlock(eb beacon.ExecutableDataV1) error { } } -func (n *ethNode) insertBlockAndSetHead(parent *types.Header, ed beacon.ExecutableDataV1) error { +func (n *ethNode) insertBlockAndSetHead(parent *types.Header, ed beacon.ExecutableData) error { if !eth2types(n.typ) { return errors.New("invalid node type") } diff --git a/miner/worker.go b/miner/worker.go index ee4969623d12..49204f71a076 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -968,13 +968,14 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP // generateParams wraps various of settings for generating sealing task. type generateParams struct { - timestamp uint64 // The timestamp for sealing task - forceTime bool // Flag whether the given timestamp is immutable or not - parentHash common.Hash // Parent block hash, empty means the latest chain head - coinbase common.Address // The fee recipient address for including transaction - random common.Hash // The randomness generated by beacon chain, empty before the merge - noUncle bool // Flag whether the uncle block inclusion is allowed - noTxs bool // Flag whether an empty block without any transaction is expected + timestamp uint64 // The timstamp for sealing task + forceTime bool // Flag whether the given timestamp is immutable or not + parentHash common.Hash // Parent block hash, empty means the latest chain head + coinbase common.Address // The fee recipient address for including transaction + random common.Hash // The randomness generated by beacon chain, empty before the merge + withdrawals types.Withdrawals // List of withdrawals to include in block. + noUncle bool // Flag whether the uncle block inclusion is allowed + noTxs bool // Flag whether an empty block without any transaction is expected } // prepareWork constructs the sealing task according to the given parameters, @@ -1108,7 +1109,7 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, e log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.newpayloadTimeout)) } } - block, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts) + block, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts, params.withdrawals) if err != nil { return nil, nil, err } @@ -1193,7 +1194,8 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti // Create a local environment copy, avoid the data race with snapshot state. // https://github.com/ethereum/go-ethereum/issues/24299 env := env.copy() - block, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, env.txs, env.unclelist(), env.receipts) + // Withdrawals are set to nil here, because this is only called in PoW. + block, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, env.txs, env.unclelist(), env.receipts, nil) if err != nil { return err } @@ -1224,16 +1226,17 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti // getSealingBlock generates the sealing block based on the given parameters. // The generation result will be passed back via the given channel no matter // the generation itself succeeds or not. -func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, noTxs bool) (*types.Block, *big.Int, error) { +func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, withdrawals types.Withdrawals, noTxs bool) (*types.Block, *big.Int, error) { req := &getWorkReq{ params: &generateParams{ - timestamp: timestamp, - forceTime: true, - parentHash: parent, - coinbase: coinbase, - random: random, - noUncle: true, - noTxs: noTxs, + timestamp: timestamp, + forceTime: true, + parentHash: parent, + coinbase: coinbase, + random: random, + withdrawals: withdrawals, + noUncle: true, + noTxs: noTxs, }, result: make(chan *newPayloadResult, 1), } diff --git a/miner/worker_test.go b/miner/worker_test.go index 5db90546ceca..a3f46db17cc9 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -637,7 +637,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co // This API should work even when the automatic sealing is not enabled for _, c := range cases { - block, _, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, false) + block, _, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, nil, false) if c.expectErr { if err == nil { t.Error("Expect error but get nil") @@ -653,7 +653,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co // This API should work even when the automatic sealing is enabled w.start() for _, c := range cases { - block, _, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, false) + block, _, err := w.getSealingBlock(c.parent, timestamp, c.coinbase, c.random, nil, false) if c.expectErr { if err == nil { t.Error("Expect error but get nil") From 55f41d198c133d672cdba258cdca40a9cb23005c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 26 Jan 2023 10:07:20 +0100 Subject: [PATCH 493/715] cmd/utils: fix error at geth startup in --dev mode (#26550) This fixes a regression in #26541 where we turned the miner address being missing into a startup error. The address was not configured in --dev mode. --- cmd/utils/flags.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 2bbbc381bea1..597fc5603fc9 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1912,6 +1912,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // when we're definitely concerned with only one account. passphrase = list[0] } + // Unlock the developer account by local keystore. var ks *keystore.KeyStore if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { @@ -1920,6 +1921,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { if ks == nil { Fatalf("Keystore is not available") } + + // Figure out the dev account address. // setEtherbase has been called above, configuring the miner address from command line flags. if cfg.Miner.Etherbase != (common.Address{}) { developer = accounts.Account{Address: cfg.Miner.Etherbase} @@ -1931,6 +1934,10 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { Fatalf("Failed to create developer account: %v", err) } } + // Make sure the address is configured as fee recipient, otherwise + // the miner will fail to start. + cfg.Miner.Etherbase = developer.Address + if err := ks.Unlock(developer, passphrase); err != nil { Fatalf("Failed to unlock developer account: %v", err) } From 245cff0a1a6d2f67169fcd59b2997c5b7a98338b Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 27 Jan 2023 11:42:14 +0100 Subject: [PATCH 494/715] eth/catalyst: error on nil withdrawals post-shanghai (#26549) This adds explicit checks for the presence of withdrawals in the engine API. Co-authored-by: Felix Lange --- eth/catalyst/api.go | 12 +++++ eth/catalyst/api_test.go | 112 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 39dcba04f83e..3b931abffe45 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -164,6 +164,18 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa // ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes. func (api *ConsensusAPI) ForkchoiceUpdatedV2(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { + if !api.eth.BlockChain().Config().IsShanghai(payloadAttributes.Timestamp) { + // Reject payload attributes with withdrawals before shanghai + if payloadAttributes != nil && payloadAttributes.Withdrawals != nil { + return beacon.STATUS_INVALID, beacon.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai")) + } + } else { + // Reject payload attributes with nil withdrawals after shanghai + if payloadAttributes != nil && payloadAttributes.Withdrawals == nil { + return beacon.STATUS_INVALID, beacon.InvalidPayloadAttributes.With(errors.New("missing withdrawals list")) + } + } + return api.forkchoiceUpdated(update, payloadAttributes) } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 8df48bd08e10..d9280e99d673 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -1113,3 +1113,115 @@ func TestWithdrawals(t *testing.T) { } } } + +func TestNilWithdrawals(t *testing.T) { + genesis, blocks := generateMergeChain(10, true) + // Set shanghai time to last block + 4 seconds (first post-merge block) + time := blocks[len(blocks)-1].Time() + 4 + genesis.Config.ShanghaiTime = &time + + n, ethservice := startEthService(t, genesis, blocks) + ethservice.Merger().ReachTTD() + defer n.Close() + + api := NewConsensusAPI(ethservice) + parent := ethservice.BlockChain().CurrentHeader() + aa := common.Address{0xaa} + + type test struct { + blockParams beacon.PayloadAttributes + wantErr bool + } + tests := []test{ + // Before Shanghai + { + blockParams: beacon.PayloadAttributes{ + Timestamp: parent.Time + 2, + Withdrawals: nil, + }, + wantErr: false, + }, + { + blockParams: beacon.PayloadAttributes{ + Timestamp: parent.Time + 2, + Withdrawals: make([]*types.Withdrawal, 0), + }, + wantErr: true, + }, + { + blockParams: beacon.PayloadAttributes{ + Timestamp: parent.Time + 2, + Withdrawals: []*types.Withdrawal{ + { + Index: 0, + Address: aa, + Amount: 32, + }, + }, + }, + wantErr: true, + }, + // After Shanghai + { + blockParams: beacon.PayloadAttributes{ + Timestamp: parent.Time + 5, + Withdrawals: nil, + }, + wantErr: true, + }, + { + blockParams: beacon.PayloadAttributes{ + Timestamp: parent.Time + 5, + Withdrawals: make([]*types.Withdrawal, 0), + }, + wantErr: false, + }, + { + blockParams: beacon.PayloadAttributes{ + Timestamp: parent.Time + 5, + Withdrawals: []*types.Withdrawal{ + { + Index: 0, + Address: aa, + Amount: 32, + }, + }, + }, + wantErr: false, + }, + } + + fcState := beacon.ForkchoiceStateV1{ + HeadBlockHash: parent.Hash(), + } + + for _, test := range tests { + _, err := api.ForkchoiceUpdatedV2(fcState, &test.blockParams) + if test.wantErr { + if err == nil { + t.Fatal("wanted error on fcuv2 with invalid withdrawals") + } + continue + } + if err != nil { + t.Fatalf("error preparing payload, err=%v", err) + } + + // 11: verify locally build block. + payloadID := (&miner.BuildPayloadArgs{ + Parent: fcState.HeadBlockHash, + Timestamp: test.blockParams.Timestamp, + FeeRecipient: test.blockParams.SuggestedFeeRecipient, + Random: test.blockParams.Random, + }).Id() + execData, err := api.GetPayloadV2(payloadID) + if err != nil { + t.Fatalf("error getting payload, err=%v", err) + } + if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil { + t.Fatalf("error validating payload: %v", err) + } else if status.Status != beacon.VALID { + t.Fatalf("invalid payload") + } + } +} From 2fecac60414e5d3593b04680d252ae3bdd04c60a Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 27 Jan 2023 12:03:03 +0100 Subject: [PATCH 495/715] eth/catalyst: implement exchangeCapabilities method (#26555) Spec: ethereum/execution-apis#364 --- eth/catalyst/api.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 3b931abffe45..dd6fa2349e08 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -79,6 +79,17 @@ const ( beaconUpdateWarnFrequency = 5 * time.Minute ) +// All methods provided over the engine endpoint. +var caps = []string{ + "engine_forkchoiceUpdatedV1", + "engine_forkchoiceUpdatedV2", + "engine_exchangeTransitionConfigurationV1", + "engine_getPayloadV1", + "engine_getPayloadV2", + "engine_newPayloadV1", + "engine_newPayloadV2", +} + type ConsensusAPI struct { eth *eth.Ethereum @@ -732,3 +743,8 @@ func (api *ConsensusAPI) heartbeat() { } } } + +// ExchangeCapabilities returns the current methods provided by this node. +func (api *ConsensusAPI) ExchangeCapabilities([]string) []string { + return caps +} From 34115c8f6371e9de5d686eb7bf9427b39838514d Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 27 Jan 2023 12:03:34 +0100 Subject: [PATCH 496/715] params: fix timestamp display in fork banner (#26553) --- params/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/params/config.go b/params/config.go index aac4392301de..3196a31de0ce 100644 --- a/params/config.go +++ b/params/config.go @@ -591,13 +591,13 @@ func (c *ChainConfig) Description() string { // Create a list of forks post-merge banner += "Post-Merge hard forks (timestamp based):\n" if c.ShanghaiTime != nil { - banner += fmt.Sprintf(" - Shanghai: @%-10v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", c.ShanghaiTime) + banner += fmt.Sprintf(" - Shanghai: @%-10v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", *c.ShanghaiTime) } if c.CancunTime != nil { - banner += fmt.Sprintf(" - Cancun: @%-10v\n", c.CancunTime) + banner += fmt.Sprintf(" - Cancun: @%-10v\n", *c.CancunTime) } if c.PragueTime != nil { - banner += fmt.Sprintf(" - Prague: @%-10v\n", c.PragueTime) + banner += fmt.Sprintf(" - Prague: @%-10v\n", *c.PragueTime) } return banner } From abe4159cb5086281e042f7906d02a28482e7653f Mon Sep 17 00:00:00 2001 From: Nicola Cocchiaro <3538109+ncocchiaro@users.noreply.github.com> Date: Fri, 27 Jan 2023 04:32:24 -0800 Subject: [PATCH 497/715] params: remove deprecated bootnodes (#26530) This change removes the Infura rinkeby bootnode as well as two deprecated ropsten bootnodes. Co-authored-by: Nicola Cocchiaro Co-authored-by: Martin Holst Swende --- params/bootnodes.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/params/bootnodes.go b/params/bootnodes.go index 1e2bfa5a0876..409e1d19e6c7 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -35,8 +35,6 @@ var MainnetBootnodes = []string{ // RopstenBootnodes are the enode URLs of the P2P bootstrap nodes running on the // Ropsten test network. var RopstenBootnodes = []string{ - "enode://30b7ab30a01c124a6cceca36863ece12c4f5fa68e3ba9b0b51407ccc002eeed3b3102d20a88f1c1d3c3154e2449317b8ef95090e77b312d5cc39354f86d5d606@52.176.7.10:30303", // US-Azure geth - "enode://865a63255b3bb68023b6bffd5095118fcc13e79dcf014fe4e47e065c350c7cc72af2e53eff895f11ba1bbb6a2b33271c1116ee870f266618eadfc2e78aa7349c@52.176.100.77:30303", // US-Azure parity "enode://6332792c4a00e3e4ee0926ed89e0d27ef985424d97b6a45bf0f23e51f0dcb5e66b875777506458aea7af6f9e4ffb69f43f3778ee73c81ed9d34c51c4b16b0b0f@52.232.243.152:30303", // Parity "enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303", // @gpip } @@ -54,7 +52,6 @@ var SepoliaBootnodes = []string{ // Rinkeby test network. var RinkebyBootnodes = []string{ "enode://a24ac7c5484ef4ed0c5eb2d36620ba4e4aa13b8c84684e1b4aab0cebea2ae45cb4d375b77eab56516d34bfbd3c1a833fc51296ff084b770b94fb9028c4d25ccf@52.169.42.101:30303", // IE - "enode://343149e4feefa15d882d9fe4ac7d88f885bd05ebb735e547f12e12080a9fa07c8014ca6fd7f373123488102fe5e34111f8509cf0b7de3f5b44339c9f25e87cb8@52.3.158.184:30303", // INFURA "enode://b6b28890b006743680c52e64e0d16db57f28124885595fa03a562be1d2bf0f3a1da297d56b13da25fb992888fd556d4c1a27b1f39d531bde7de1921c90061cc6@159.89.28.211:30303", // AKASHA } From a63875bf4d7f6c70bad4fd33db6fb9f1de137706 Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 27 Jan 2023 06:39:26 -0600 Subject: [PATCH 498/715] go.mod: gnark-crypto upgrade (#26545) --- go.mod | 7 +++++-- go.sum | 31 ++++++++++++++----------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 08cc41937c88..a370b0dcfa23 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.2.0 github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.14.0 - github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f + github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 github.com/docker/docker v1.6.2 @@ -52,7 +52,7 @@ require ( github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 - github.com/stretchr/testify v1.7.2 + github.com/stretchr/testify v1.8.0 github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.1.0 @@ -78,6 +78,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect github.com/aws/smithy-go v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/consensys/bavard v0.1.13 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect @@ -91,6 +92,7 @@ require ( github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mitchellh/pointerstructure v1.2.0 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect github.com/opentracing/opentracing-go v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -105,4 +107,5 @@ require ( google.golang.org/protobuf v1.26.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index b715e3421458..0413347a14a0 100644 --- a/go.sum +++ b/go.sum @@ -77,9 +77,10 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= -github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= -github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f h1:C43yEtQ6NIf4ftFXD/V55gnGFgPbMQobd//YlnLjUJ8= -github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c h1:llSLg4o9EgH3SrXky+Q5BqEYqV76NGKo07K5Ps2pIKo= +github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -209,6 +210,7 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -313,6 +315,9 @@ github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxd github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= @@ -389,14 +394,16 @@ github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobt github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= @@ -418,7 +425,6 @@ github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -434,7 +440,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -464,8 +469,6 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -487,10 +490,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= @@ -506,7 +507,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -540,11 +540,9 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -590,12 +588,10 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -678,6 +674,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= From 90f15a0230be34a292c5d0574ee7910ee44267de Mon Sep 17 00:00:00 2001 From: Mario Vega Date: Fri, 27 Jan 2023 07:30:13 -0600 Subject: [PATCH 499/715] cmd/evm: add blocktest subcommand to evm (#26526) Adds blocktest subcommand to the evm command, which is very similar to statetest, but instead of loading a StateTest static test it loads a BlockchainTest from a json file and runs it. Co-authored-by: Martin Holst Swende Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- cmd/evm/blockrunner.go | 61 ++++++++++++++++++++++++++++++++++++++++++ cmd/evm/main.go | 1 + 2 files changed, 62 insertions(+) create mode 100644 cmd/evm/blockrunner.go diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go new file mode 100644 index 000000000000..ffd76b8fb0c9 --- /dev/null +++ b/cmd/evm/blockrunner.go @@ -0,0 +1,61 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package main + +import ( + "encoding/json" + "errors" + "fmt" + "os" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/tests" + "github.com/urfave/cli/v2" +) + +var blockTestCommand = &cli.Command{ + Action: blockTestCmd, + Name: "blocktest", + Usage: "executes the given blockchain tests", + ArgsUsage: "", +} + +func blockTestCmd(ctx *cli.Context) error { + if len(ctx.Args().First()) == 0 { + return errors.New("path-to-test argument required") + } + // Configure the go-ethereum logger + glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) + glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) + log.Root().SetHandler(glogger) + + // Load the test content from the input file + src, err := os.ReadFile(ctx.Args().First()) + if err != nil { + return err + } + var tests map[string]tests.BlockTest + if err = json.Unmarshal(src, &tests); err != nil { + return err + } + for i, test := range tests { + if err := test.Run(false); err != nil { + return fmt.Errorf("test %v: %w", i, err) + } + } + return nil +} diff --git a/cmd/evm/main.go b/cmd/evm/main.go index a9ce83a3e657..35f3e37ae50f 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -218,6 +218,7 @@ func init() { compileCommand, disasmCommand, runCommand, + blockTestCommand, stateTestCommand, stateTransitionCommand, transactionCommand, From df52967ff6080a27243569020ff64cd956fb8362 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 27 Jan 2023 15:33:28 +0100 Subject: [PATCH 500/715] eth/catalyst: fix panic in TestWithdrawals (#26563) Fixes a regression introduced in #26549 --- eth/catalyst/api.go | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index dd6fa2349e08..96964b619522 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -175,19 +175,27 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa // ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes. func (api *ConsensusAPI) ForkchoiceUpdatedV2(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { - if !api.eth.BlockChain().Config().IsShanghai(payloadAttributes.Timestamp) { + if payloadAttributes != nil { + if err := api.verifyPayloadAttributes(payloadAttributes); err != nil { + return beacon.STATUS_INVALID, beacon.InvalidPayloadAttributes.With(err) + } + } + return api.forkchoiceUpdated(update, payloadAttributes) +} + +func (api *ConsensusAPI) verifyPayloadAttributes(attr *beacon.PayloadAttributes) error { + if !api.eth.BlockChain().Config().IsShanghai(attr.Timestamp) { // Reject payload attributes with withdrawals before shanghai - if payloadAttributes != nil && payloadAttributes.Withdrawals != nil { - return beacon.STATUS_INVALID, beacon.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai")) + if attr.Withdrawals != nil { + return errors.New("withdrawals before shanghai") } } else { // Reject payload attributes with nil withdrawals after shanghai - if payloadAttributes != nil && payloadAttributes.Withdrawals == nil { - return beacon.STATUS_INVALID, beacon.InvalidPayloadAttributes.With(errors.New("missing withdrawals list")) + if attr.Withdrawals == nil { + return errors.New("missing withdrawals list") } } - - return api.forkchoiceUpdated(update, payloadAttributes) + return nil } func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { From fd4230f695247102c249d5ece2c7f6760350ae6f Mon Sep 17 00:00:00 2001 From: ucwong Date: Mon, 30 Jan 2023 07:33:03 -0600 Subject: [PATCH 501/715] log: fix typo in comment (#26569) --- log/logger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log/logger.go b/log/logger.go index 276d6969e24d..1549e3285481 100644 --- a/log/logger.go +++ b/log/logger.go @@ -46,7 +46,7 @@ func (l Lvl) AlignedString() string { } } -// Strings returns the name of a Lvl. +// String returns the name of a Lvl. func (l Lvl) String() string { switch l { case LvlTrace: From 3ff3d07e2c644128cf984ba751b9fd3f59ffe833 Mon Sep 17 00:00:00 2001 From: Pascal Marco Caversaccio Date: Mon, 30 Jan 2023 15:12:55 +0100 Subject: [PATCH 502/715] cmd/devp2p: fix broken link in readme(#26576) fix broken link to DNS discovery tutorial --- cmd/devp2p/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/devp2p/README.md b/cmd/devp2p/README.md index 7f816b602e3d..7b90bbeb806a 100644 --- a/cmd/devp2p/README.md +++ b/cmd/devp2p/README.md @@ -135,6 +135,6 @@ replacing `` with the enode of the geth node: ``` [eth]: https://github.com/ethereum/devp2p/blob/master/caps/eth.md -[dns-tutorial]: https://geth.ethereum.org/docs/developers/dns-discovery-setup +[dns-tutorial]: https://geth.ethereum.org/docs/developers/geth-developer/dns-discovery-setup [discv4]: https://github.com/ethereum/devp2p/tree/master/discv4.md [discv5]: https://github.com/ethereum/devp2p/tree/master/discv5/discv5.md From 17017b251622bf120fe4b87bc102747a50109cce Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 30 Jan 2023 12:43:12 -0500 Subject: [PATCH 503/715] log: better sanitation (#26556) --- log/format.go | 38 ++++++++++++++++++++++++++++++++------ log/format_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/log/format.go b/log/format.go index 613dc33be769..42525ea6d296 100644 --- a/log/format.go +++ b/log/format.go @@ -86,6 +86,7 @@ type TerminalStringer interface { // [DBUG] [May 16 20:58:45] remove route ns=haproxy addr=127.0.0.1:50002 func TerminalFormat(usecolor bool) Format { return FormatFunc(func(r *Record) []byte { + msg := escapeMessage(r.Msg) var color = 0 if usecolor { switch r.Lvl { @@ -122,19 +123,19 @@ func TerminalFormat(usecolor bool) Format { // Assemble and print the log heading if color > 0 { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s|%s]%s %s ", color, lvl, r.Time.Format(termTimeFormat), location, padding, r.Msg) + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s|%s]%s %s ", color, lvl, r.Time.Format(termTimeFormat), location, padding, msg) } else { - fmt.Fprintf(b, "%s[%s|%s]%s %s ", lvl, r.Time.Format(termTimeFormat), location, padding, r.Msg) + fmt.Fprintf(b, "%s[%s|%s]%s %s ", lvl, r.Time.Format(termTimeFormat), location, padding, msg) } } else { if color > 0 { - fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %s ", color, lvl, r.Time.Format(termTimeFormat), r.Msg) + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %s ", color, lvl, r.Time.Format(termTimeFormat), msg) } else { - fmt.Fprintf(b, "%s[%s] %s ", lvl, r.Time.Format(termTimeFormat), r.Msg) + fmt.Fprintf(b, "%s[%s] %s ", lvl, r.Time.Format(termTimeFormat), msg) } } // try to justify the log output for short messages - length := utf8.RuneCountInString(r.Msg) + length := utf8.RuneCountInString(msg) if len(r.Ctx) > 0 && length < termMsgJust { b.Write(bytes.Repeat([]byte{' '}, termMsgJust-length)) } @@ -167,6 +168,8 @@ func logfmt(buf *bytes.Buffer, ctx []interface{}, color int, term bool) { v := formatLogfmtValue(ctx[i+1], term) if !ok { k, v = errorKey, formatLogfmtValue(k, term) + } else { + k = escapeString(k) } // XXX: we should probably check that all of your key bytes aren't invalid @@ -471,7 +474,7 @@ func formatLogfmtBigInt(n *big.Int) string { func escapeString(s string) string { needsQuoting := false for _, r := range s { - // We quote everything below " (0x34) and above~ (0x7E), plus equal-sign + // We quote everything below " (0x22) and above~ (0x7E), plus equal-sign if r <= '"' || r > '~' || r == '=' { needsQuoting = true break @@ -482,3 +485,26 @@ func escapeString(s string) string { } return strconv.Quote(s) } + +// escapeMessage checks if the provided string needs escaping/quoting, similarly +// to escapeString. The difference is that this method is more lenient: it allows +// for spaces and linebreaks to occur without needing quoting. +func escapeMessage(s string) string { + needsQuoting := false + for _, r := range s { + // Carriage return and Line feed are ok + if r == 0xa || r == 0xd { + continue + } + // We quote everything below (0x20) and above~ (0x7E), + // plus equal-sign + if r < ' ' || r > '~' || r == '=' { + needsQuoting = true + break + } + } + if !needsQuoting { + return s + } + return strconv.Quote(s) +} diff --git a/log/format_test.go b/log/format_test.go index d7e0a9576805..cfcfe85802a4 100644 --- a/log/format_test.go +++ b/log/format_test.go @@ -1,9 +1,11 @@ package log import ( + "fmt" "math" "math/big" "math/rand" + "strings" "testing" ) @@ -93,3 +95,47 @@ func BenchmarkPrettyUint64Logfmt(b *testing.B) { sink = FormatLogfmtUint64(rand.Uint64()) } } + +func TestSanitation(t *testing.T) { + msg := "\u001b[1G\u001b[K\u001b[1A" + msg2 := "\u001b \u0000" + msg3 := "NiceMessage" + msg4 := "Space Message" + msg5 := "Enter\nMessage" + + for i, tt := range []struct { + msg string + want string + }{ + { + msg: msg, + want: fmt.Sprintf("] %q %q=%q\n", msg, msg, msg), + }, + { + msg: msg2, + want: fmt.Sprintf("] %q %q=%q\n", msg2, msg2, msg2), + }, + { + msg: msg3, + want: fmt.Sprintf("] %s %s=%s\n", msg3, msg3, msg3), + }, + { + msg: msg4, + want: fmt.Sprintf("] %s %q=%q\n", msg4, msg4, msg4), + }, + { + msg: msg5, + want: fmt.Sprintf("] %s %q=%q\n", msg5, msg5, msg5), + }, + } { + var ( + logger = New() + out = new(strings.Builder) + ) + logger.SetHandler(LvlFilterHandler(LvlInfo, StreamHandler(out, TerminalFormat(false)))) + logger.Info(tt.msg, tt.msg, tt.msg) + if have := out.String()[24:]; tt.want != have { + t.Fatalf("test %d: want / have: \n%v\n%v", i, tt.want, have) + } + } +} From 78d089b5b76776f297d4cb351ffee031adebf891 Mon Sep 17 00:00:00 2001 From: Mio Date: Tue, 31 Jan 2023 16:28:32 +0800 Subject: [PATCH 504/715] ethclient/gethclient: fix typo (#26580) fix grammar typo --- ethclient/gethclient/gethclient_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index ef84d71559c8..a9637d182f1f 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -299,7 +299,7 @@ func testSubscribePendingTransactions(t *testing.T, client *rpc.Client) { if err != nil { t.Fatal(err) } - // Check that the transaction was send over the channel + // Check that the transaction was sent over the channel hash := <-ch if hash != signedTx.Hash() { t.Fatalf("Invalid tx hash received, got %v, want %v", hash, signedTx.Hash()) @@ -333,7 +333,7 @@ func testSubscribeFullPendingTransactions(t *testing.T, client *rpc.Client) { if err != nil { t.Fatal(err) } - // Check that the transaction was send over the channel + // Check that the transaction was sent over the channel tx = <-ch if tx.Hash() != signedTx.Hash() { t.Fatalf("Invalid tx hash received, got %v, want %v", tx.Hash(), signedTx.Hash()) From efbd508d213f77461a445f1c80c29423e7bcd6a3 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 31 Jan 2023 16:29:17 +0800 Subject: [PATCH 505/715] eth/tracer: rename to revertReason (#26574) --- .../internal/tracetest/calltrace_test.go | 22 ++++---- eth/tracers/native/call.go | 24 ++++---- eth/tracers/native/gen_callframe_json.go | 56 +++++++++---------- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index d240e9a4b107..808841ade111 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -55,17 +55,17 @@ type callLog struct { // callTrace is the result of a callTracer run. type callTrace struct { - From common.Address `json:"from"` - Gas *hexutil.Uint64 `json:"gas"` - GasUsed *hexutil.Uint64 `json:"gasUsed"` - To common.Address `json:"to,omitempty"` - Input hexutil.Bytes `json:"input"` - Output hexutil.Bytes `json:"output,omitempty"` - Error string `json:"error,omitempty"` - Revertal string `json:"revertReason,omitempty"` - Calls []callTrace `json:"calls,omitempty"` - Logs []callLog `json:"logs,omitempty"` - Value *hexutil.Big `json:"value,omitempty"` + From common.Address `json:"from"` + Gas *hexutil.Uint64 `json:"gas"` + GasUsed *hexutil.Uint64 `json:"gasUsed"` + To common.Address `json:"to,omitempty"` + Input hexutil.Bytes `json:"input"` + Output hexutil.Bytes `json:"output,omitempty"` + Error string `json:"error,omitempty"` + RevertReason string `json:"revertReason,omitempty"` + Calls []callTrace `json:"calls,omitempty"` + Logs []callLog `json:"logs,omitempty"` + Value *hexutil.Big `json:"value,omitempty"` // Gencodec adds overridden fields at the end Type string `json:"type"` } diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 5bf49e744dec..75103f64cc87 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -42,17 +42,17 @@ type callLog struct { } type callFrame struct { - Type vm.OpCode `json:"-"` - From common.Address `json:"from"` - Gas uint64 `json:"gas"` - GasUsed uint64 `json:"gasUsed"` - To common.Address `json:"to,omitempty" rlp:"optional"` - Input []byte `json:"input" rlp:"optional"` - Output []byte `json:"output,omitempty" rlp:"optional"` - Error string `json:"error,omitempty" rlp:"optional"` - Revertal string `json:"revertReason,omitempty"` - Calls []callFrame `json:"calls,omitempty" rlp:"optional"` - Logs []callLog `json:"logs,omitempty" rlp:"optional"` + Type vm.OpCode `json:"-"` + From common.Address `json:"from"` + Gas uint64 `json:"gas"` + GasUsed uint64 `json:"gasUsed"` + To common.Address `json:"to,omitempty" rlp:"optional"` + Input []byte `json:"input" rlp:"optional"` + Output []byte `json:"output,omitempty" rlp:"optional"` + Error string `json:"error,omitempty" rlp:"optional"` + RevertReason string `json:"revertReason,omitempty"` + Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Logs []callLog `json:"logs,omitempty" rlp:"optional"` // Placed at end on purpose. The RLP will be decoded to 0 instead of // nil if there are non-empty elements after in the struct. Value *big.Int `json:"value,omitempty" rlp:"optional"` @@ -84,7 +84,7 @@ func (f *callFrame) processOutput(output []byte, err error) { return } if unpacked, err := abi.UnpackRevert(output); err == nil { - f.Revertal = unpacked + f.RevertReason = unpacked } } diff --git a/eth/tracers/native/gen_callframe_json.go b/eth/tracers/native/gen_callframe_json.go index f6b48366fe80..21fc9e2b31af 100644 --- a/eth/tracers/native/gen_callframe_json.go +++ b/eth/tracers/native/gen_callframe_json.go @@ -16,19 +16,19 @@ var _ = (*callFrameMarshaling)(nil) // MarshalJSON marshals as JSON. func (c callFrame) MarshalJSON() ([]byte, error) { type callFrame0 struct { - Type vm.OpCode `json:"-"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasUsed hexutil.Uint64 `json:"gasUsed"` - To common.Address `json:"to,omitempty" rlp:"optional"` - Input hexutil.Bytes `json:"input" rlp:"optional"` - Output hexutil.Bytes `json:"output,omitempty" rlp:"optional"` - Error string `json:"error,omitempty" rlp:"optional"` - Revertal string `json:"revertReason,omitempty"` - Calls []callFrame `json:"calls,omitempty" rlp:"optional"` - Logs []callLog `json:"logs,omitempty" rlp:"optional"` - Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` - TypeString string `json:"type"` + Type vm.OpCode `json:"-"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasUsed hexutil.Uint64 `json:"gasUsed"` + To common.Address `json:"to,omitempty" rlp:"optional"` + Input hexutil.Bytes `json:"input" rlp:"optional"` + Output hexutil.Bytes `json:"output,omitempty" rlp:"optional"` + Error string `json:"error,omitempty" rlp:"optional"` + RevertReason string `json:"revertReason,omitempty"` + Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Logs []callLog `json:"logs,omitempty" rlp:"optional"` + Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` + TypeString string `json:"type"` } var enc callFrame0 enc.Type = c.Type @@ -39,7 +39,7 @@ func (c callFrame) MarshalJSON() ([]byte, error) { enc.Input = c.Input enc.Output = c.Output enc.Error = c.Error - enc.Revertal = c.Revertal + enc.RevertReason = c.RevertReason enc.Calls = c.Calls enc.Logs = c.Logs enc.Value = (*hexutil.Big)(c.Value) @@ -50,18 +50,18 @@ func (c callFrame) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (c *callFrame) UnmarshalJSON(input []byte) error { type callFrame0 struct { - Type *vm.OpCode `json:"-"` - From *common.Address `json:"from"` - Gas *hexutil.Uint64 `json:"gas"` - GasUsed *hexutil.Uint64 `json:"gasUsed"` - To *common.Address `json:"to,omitempty" rlp:"optional"` - Input *hexutil.Bytes `json:"input" rlp:"optional"` - Output *hexutil.Bytes `json:"output,omitempty" rlp:"optional"` - Error *string `json:"error,omitempty" rlp:"optional"` - Revertal *string `json:"revertReason,omitempty"` - Calls []callFrame `json:"calls,omitempty" rlp:"optional"` - Logs []callLog `json:"logs,omitempty" rlp:"optional"` - Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` + Type *vm.OpCode `json:"-"` + From *common.Address `json:"from"` + Gas *hexutil.Uint64 `json:"gas"` + GasUsed *hexutil.Uint64 `json:"gasUsed"` + To *common.Address `json:"to,omitempty" rlp:"optional"` + Input *hexutil.Bytes `json:"input" rlp:"optional"` + Output *hexutil.Bytes `json:"output,omitempty" rlp:"optional"` + Error *string `json:"error,omitempty" rlp:"optional"` + RevertReason *string `json:"revertReason,omitempty"` + Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Logs []callLog `json:"logs,omitempty" rlp:"optional"` + Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` } var dec callFrame0 if err := json.Unmarshal(input, &dec); err != nil { @@ -91,8 +91,8 @@ func (c *callFrame) UnmarshalJSON(input []byte) error { if dec.Error != nil { c.Error = *dec.Error } - if dec.Revertal != nil { - c.Revertal = *dec.Revertal + if dec.RevertReason != nil { + c.RevertReason = *dec.RevertReason } if dec.Calls != nil { c.Calls = dec.Calls From bd6a05e1eea340cead56478f7fc81cade80a3cad Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 31 Jan 2023 01:34:03 -0700 Subject: [PATCH 506/715] internal/ethapi: always return block withdrawals if present (#26565) The execution-apis specification says that the full list of withdrawals should always be returned when requesting a block over RPC: https://github.com/ethereum/execution-apis/blob/378c4304f75b5af2c9b5263c9c76b511e33e8984/src/schemas/block.yaml#L90-L94 This change adopts the expected behavior. --- internal/ethapi/api.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1ac9c5faa74a..4fa5b9e67e36 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1246,8 +1246,6 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param } } fields["transactions"] = transactions - // inclTx also expands withdrawals - fields["withdrawals"] = block.Withdrawals() } uncles := block.Uncles() uncleHashes := make([]common.Hash, len(uncles)) @@ -1255,7 +1253,9 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param uncleHashes[i] = uncle.Hash() } fields["uncles"] = uncleHashes - + if block.Header().WithdrawalsHash != nil { + fields["withdrawals"] = block.Withdrawals() + } return fields, nil } From 8ded6a9fcd883d7d96ef695f5b312c509eae3a0a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 31 Jan 2023 10:16:30 +0100 Subject: [PATCH 507/715] cmd/puppeth: remove puppeth --- README.md | 1 - build/ci.go | 5 - cmd/puppeth/module.go | 161 ------ cmd/puppeth/module_dashboard.go | 661 ----------------------- cmd/puppeth/module_ethstats.go | 176 ------ cmd/puppeth/module_explorer.go | 194 ------- cmd/puppeth/module_faucet.go | 254 --------- cmd/puppeth/module_nginx.go | 119 ---- cmd/puppeth/module_node.go | 266 --------- cmd/puppeth/puppeth.go | 65 --- cmd/puppeth/ssh.go | 271 ---------- cmd/puppeth/testdata/stureby_aleth.json | 113 ---- cmd/puppeth/testdata/stureby_geth.json | 54 -- cmd/puppeth/testdata/stureby_parity.json | 213 -------- cmd/puppeth/wizard.go | 312 ----------- cmd/puppeth/wizard_dashboard.go | 152 ------ cmd/puppeth/wizard_ethstats.go | 126 ----- cmd/puppeth/wizard_explorer.go | 120 ---- cmd/puppeth/wizard_faucet.go | 195 ------- cmd/puppeth/wizard_genesis.go | 285 ---------- cmd/puppeth/wizard_intro.go | 157 ------ cmd/puppeth/wizard_netstats.go | 284 ---------- cmd/puppeth/wizard_network.go | 197 ------- cmd/puppeth/wizard_nginx.go | 65 --- cmd/puppeth/wizard_node.go | 178 ------ go.mod | 1 - go.sum | 2 - 27 files changed, 4627 deletions(-) delete mode 100644 cmd/puppeth/module.go delete mode 100644 cmd/puppeth/module_dashboard.go delete mode 100644 cmd/puppeth/module_ethstats.go delete mode 100644 cmd/puppeth/module_explorer.go delete mode 100644 cmd/puppeth/module_faucet.go delete mode 100644 cmd/puppeth/module_nginx.go delete mode 100644 cmd/puppeth/module_node.go delete mode 100644 cmd/puppeth/puppeth.go delete mode 100644 cmd/puppeth/ssh.go delete mode 100644 cmd/puppeth/testdata/stureby_aleth.json delete mode 100644 cmd/puppeth/testdata/stureby_geth.json delete mode 100644 cmd/puppeth/testdata/stureby_parity.json delete mode 100644 cmd/puppeth/wizard.go delete mode 100644 cmd/puppeth/wizard_dashboard.go delete mode 100644 cmd/puppeth/wizard_ethstats.go delete mode 100644 cmd/puppeth/wizard_explorer.go delete mode 100644 cmd/puppeth/wizard_faucet.go delete mode 100644 cmd/puppeth/wizard_genesis.go delete mode 100644 cmd/puppeth/wizard_intro.go delete mode 100644 cmd/puppeth/wizard_netstats.go delete mode 100644 cmd/puppeth/wizard_network.go delete mode 100644 cmd/puppeth/wizard_nginx.go delete mode 100644 cmd/puppeth/wizard_node.go diff --git a/README.md b/README.md index c4900633ab69..ff58887383aa 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,6 @@ directory. | `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | | `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug run`). | | `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | -| `puppeth` | a CLI wizard that aids in creating a new Ethereum network. | ## Running `geth` diff --git a/build/ci.go b/build/ci.go index c6a6ffca605a..bd265865fd22 100644 --- a/build/ci.go +++ b/build/ci.go @@ -77,7 +77,6 @@ var ( executablePath("bootnode"), executablePath("evm"), executablePath("geth"), - executablePath("puppeth"), executablePath("rlpdump"), executablePath("clef"), } @@ -100,10 +99,6 @@ var ( BinaryName: "geth", Description: "Ethereum CLI client.", }, - { - BinaryName: "puppeth", - Description: "Ethereum private network manager.", - }, { BinaryName: "rlpdump", Description: "Developer utility tool that prints RLP structures.", diff --git a/cmd/puppeth/module.go b/cmd/puppeth/module.go deleted file mode 100644 index 771ae38058bc..000000000000 --- a/cmd/puppeth/module.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "errors" - "fmt" - "net" - "strconv" - "strings" - "time" - - "github.com/ethereum/go-ethereum/log" -) - -var ( - // ErrServiceUnknown is returned when a service container doesn't exist. - ErrServiceUnknown = errors.New("service unknown") - - // ErrServiceOffline is returned when a service container exists, but it is not - // running. - ErrServiceOffline = errors.New("service offline") - - // ErrServiceUnreachable is returned when a service container is running, but - // seems to not respond to communication attempts. - ErrServiceUnreachable = errors.New("service unreachable") - - // ErrNotExposed is returned if a web-service doesn't have an exposed port, nor - // a reverse-proxy in front of it to forward requests. - ErrNotExposed = errors.New("service not exposed, nor proxied") -) - -// containerInfos is a heavily reduced version of the huge inspection dataset -// returned from docker inspect, parsed into a form easily usable by puppeth. -type containerInfos struct { - running bool // Flag whether the container is running currently - envvars map[string]string // Collection of environmental variables set on the container - portmap map[string]int // Port mapping from internal port/proto combos to host binds - volumes map[string]string // Volume mount points from container to host directories -} - -// inspectContainer runs docker inspect against a running container -func inspectContainer(client *sshClient, container string) (*containerInfos, error) { - // Check whether there's a container running for the service - out, err := client.Run(fmt.Sprintf("docker inspect %s", container)) - if err != nil { - return nil, ErrServiceUnknown - } - // If yes, extract various configuration options - type inspection struct { - State struct { - Running bool - } - Mounts []struct { - Source string - Destination string - } - Config struct { - Env []string - } - HostConfig struct { - PortBindings map[string][]map[string]string - } - } - var inspects []inspection - if err = json.Unmarshal(out, &inspects); err != nil { - return nil, err - } - inspect := inspects[0] - - // Infos retrieved, parse the above into something meaningful - infos := &containerInfos{ - running: inspect.State.Running, - envvars: make(map[string]string), - portmap: make(map[string]int), - volumes: make(map[string]string), - } - for _, envvar := range inspect.Config.Env { - if parts := strings.Split(envvar, "="); len(parts) == 2 { - infos.envvars[parts[0]] = parts[1] - } - } - for portname, details := range inspect.HostConfig.PortBindings { - if len(details) > 0 { - port, _ := strconv.Atoi(details[0]["HostPort"]) - infos.portmap[portname] = port - } - } - for _, mount := range inspect.Mounts { - infos.volumes[mount.Destination] = mount.Source - } - return infos, err -} - -// tearDown connects to a remote machine via SSH and terminates docker containers -// running with the specified name in the specified network. -func tearDown(client *sshClient, network string, service string, purge bool) ([]byte, error) { - // Tear down the running (or paused) container - out, err := client.Run(fmt.Sprintf("docker rm -f %s_%s_1", network, service)) - if err != nil { - return out, err - } - // If requested, purge the associated docker image too - if purge { - return client.Run(fmt.Sprintf("docker rmi %s/%s", network, service)) - } - return nil, nil -} - -// resolve retrieves the hostname a service is running on either by returning the -// actual server name and port, or preferably an nginx virtual host if available. -func resolve(client *sshClient, network string, service string, port int) (string, error) { - // Inspect the service to get various configurations from it - infos, err := inspectContainer(client, fmt.Sprintf("%s_%s_1", network, service)) - if err != nil { - return "", err - } - if !infos.running { - return "", ErrServiceOffline - } - // Container online, extract any environmental variables - if vhost := infos.envvars["VIRTUAL_HOST"]; vhost != "" { - return vhost, nil - } - return fmt.Sprintf("%s:%d", client.server, port), nil -} - -// checkPort tries to connect to a remote host on a given -func checkPort(host string, port int) error { - log.Trace("Verifying remote TCP connectivity", "server", host, "port", port) - conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), time.Second) - if err != nil { - return err - } - conn.Close() - return nil -} - -// getEthName gets the Ethereum Name from ethstats -func getEthName(s string) string { - n := strings.Index(s, ":") - if n >= 0 { - return s[:n] - } - return s -} diff --git a/cmd/puppeth/module_dashboard.go b/cmd/puppeth/module_dashboard.go deleted file mode 100644 index fbbbb66501a7..000000000000 --- a/cmd/puppeth/module_dashboard.go +++ /dev/null @@ -1,661 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "fmt" - "html/template" - "math/rand" - "path/filepath" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/log" -) - -// dashboardContent is the actual dashboard HTML content to serve up when users -// load the dashboard website. -var dashboardContent = ` - - - - - - - - - - {{.NetworkTitle}}: Network Dashboard - - - - - - - - -
-
-
-
- -
-
- -
-
-
- - {{if .Ethash}} - {{end}} - - -
-
-
- - - - - - - -` - -// dashboardMascot is the png dump of the mascot to display on the dashboard about page. -// nolint: misspell -var dashboardMascot = []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01s\x00\x00\x02\x00\b\x06\x00\x00\x00p\xe4\x8c`\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x00\tpHYs\x00\x00\v\x13\x00\x00\v\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\atIME\a\xe1\x03\x1d\x0e0&\xf3\xca\t\x11\x00\x00\x00\x1diTXtComment\x00\x00\x00\x00\x00Created with GIMPd.e\a\x00\x00 \x00IDATx\xda\xec\xbdw|\x15U\xfe\xff\xff<3s[\x12BB\x12H!\x90\u0411&H\a\x01i\"V\xb0!b\xc1^>\xbb\xee\xae\xdd\xd5u\xed}-k/X\u058e\xa8\xa0\u049bH\x87\bH\xef\x04BI\x81\xf4[\xa6\x9c\xf3\xfbcnB`\xdd\xef\xcf\xdd\xd5\xddU\xe7\xf9x\\\u023d\u027dw\xee\u0339\xafy\xcd\xfb\xbc\xcf\xfb\r\x1e\x1e\xff\";wn\x17\xb7\xdf~\xabQw_)\xa5+\xa5\x1a)\xa5\u0494R\xc9J\xa9D\xa5T\xf0\xb8\xa7\xe9\x1f|\xf0\x9eQYyXx{\xd0\xc3\xe3\xc7\xc3\xfbBy\xfcK\xbc\xf3\xce[\xe2\xd2K/Wq\x11o>y\xf2G'\xaf[\xb7\xae\xff\u05ad\xdb2\xa5\x94\xa9\xd1h\xb4:---\u06b9s\xe7HJJ\xf2\xb2f\xcd27\x9e}\xf6\x98\"!\xc4\u07ba\xd7x\xf6\xd9g\xb4\xcb.\xbbD\xa6\xa4\xa4\xb1d\xc97\f\x18p\xb2\xb7c=<<1\xf7\xf8O\xf0\x97\xbf\xbf_\x89\xef\x15u]\x86B!\x99\x93\x93\xa3\xfa\xf6\xed\xab.\xb8\xe0\x82\x8a\a\x1e\xb8\xef\x83}\xfbv\xf7k\xf8\x1e\u007f\xf8\xc3\x1f\xc4\u0739\xb3\xbc\x9d\xed\xe1\xe1\xe1\xf1S\xb0r\xe5r\r@)\xd5\xee\xf6\xdbo\u06d2\u07fa\xb5\x02$\xa04]W\x86\xe1S\t\u024dUjV\xaeJ\xcdn\xa9\x12S\u04d5\x10\xe2\x18A\x17B(\xbf\xdfo'5jde\xe74W\xfd\xfa\xf5WW^yE\xe5k\xaf\xbf\xfa\xa0R*\xb1\xee\xbdz\xf7\xee#\xdex\xe35o\xa7{x\xfc@\fo\x17x\xfc\x10\x94R\x9cz\xeaH\x00\xfe\xf6\xb7\xb7\xaf\u0634yK\xfb\xdd;w\u0680\xa1\xe9:\x86\xcfO\x93\xdc\xd6t\x18r\x06\x19m\xbb\xa0\xe9\x06f\xd5\x11\xcavmd\xff\xa65\x1c\u06be\x91pU\x05J)L\xd3\xd4\x1d)\xb1\x1d\u01e9\xae\xae\xe1\u0421\x83\u027bw\xef\xfe\xe3\x96\xcd[\u03999s\xfam\xa3F\x8d\x9e\xber\xe5\n\xb5r\xe5\n>\xfa\xe8\x03q\xe1\x85\x17)\xef\bxxxx\xfc\b\u0318\xf1U\x9d+O\xbe\u66ab\xe7\xb6\xcc\xcbW\x80\x85\x10J7|\xaay\x97^\ua497\xa7\xab{\xd7Ku\xcfw\x8e\xbao\x83\xa3\x9e\xd8\"\xd53[\x1d\xf5\xe0\xd2\xfd\xea\xca\x17>Q\xfd/\xbcZ\xa5\xe5\xe6\xff]X&!1Q\xa6\xa5\xa5\xa9\xf6\xed\u06ebs\xce9[=\xfa\xe8#\x1f\u06b6\x99Y\xf7\u0793&\xbd\xe1\x99\x0e\x0f\x0f\u03d9{\xfc\x18l\u0630A\x03\xe4\xf4\xe9\xd3z\x95\x1d>\xd2\xfdPq1\x80.4\x8d`R2\x9dF\x9eG\xab\xc1\xa7\x11\x8dJ|\xd2B\xf3\t4\f4M#%3\x9b\x93\xce<\x97\x13O=\x97\xc2u+Y\xf1\xc9$VM{\x8fhm\r\xb6\x94H\xc7\x11JJu\xe8\xd0!QYYIY\xd9\xe1\v\v\v\v{\xbf\xfa\xea\xcb\u007f\xbc\xfa\xeak?\x12B\xd8c\u019c\xa3=\xf0\xc0\xfd\xaas\u7b9eK\xf7\xf0\xf0\xc4\xdc\xe3\xdf\b\xb3\u803dq\u00e6v\xa6i6\x89E\xc2\x12\xd0p\x1c2\xf2\xdb\u04a6\xcf`t\xc0pb\x04|\x02\x03\xb0-\vi\x83\xa6\t\x10\x02C\xf7\u0476ooZu\xefM\x87\x81#\x98?\xe9iv\x16,AJI$\x12\x11J)4Mc\u02d6-\x1c\xe7\xc9'\x9f\x10II\x89\xea\xba\xebn\xf0\x0e\x8a\x87G\x03to\x17x\xfc\x10\xe6\u0319\xeb(\xa5\xf4\x85\v\x17\\\xb5x\xf1\u0493JJJ\x00\x84\xa6\xe9\xe4\x9f4\x90^\xe7\\\x8a\xdf\x1f\xc4'\x1c4\x01 @\x80B\xe1(\x85t\x14\xb6\xed`\xc5\x1c\x84\xd0\xc9\xed|\x02\xed\xfb\x8d\xc4\x17\brp\xebz,3\x86m\xdbH)\xd14\r\u02f2\u063f\u007f?\xd5\xd5\xd5\x1d\xb7n\xdd:\xfc\xfd\xf7\u07dd\xf3\xf4\xd3\xcf\x1c\x99={\x0eYYYb\xfc\xf8q\u031e=\xc7;0\x1e\x1eq4o\x17x\xfc\x13\xe4X\x96\u0569\xa2\xa2<\xae\xd6`\x04\x83\xa4d\u5498\x92\x8a\x81D\x17u+\xd1\x14(\x85T \x158\xb87KB,\x16\xa5\xb6\"L\x93\x9c\xe6\x9cu\xcb\xc3\\\xf9\u0707\xb4\xee\xd1\x1f\x00\xd34\xa9\xad\xad\xc54M\xa4t\xd4\u06b5\xeb\x983gn\xe7G\x1ey\xec\u04d2\x92\x03\xb9\x00\xaf\xbd\xf6\xba*--\xf5V\x17yxxb\xee\xf1\xafP[Se\x16\x15\xed\x8fX\x8e\x13Wk\b$$\xd18\xb39\x9a\x06\x02\x85&@\x8b\vz\xc3\u015c\ueb27B\x01\xb6\u0490B'\\S\x8be\xd9t\x191\x8a\u02df\xf9\x80\xbec/\x03\xc0\xb6mjjj\x88FcB\b\xa1v\xed\xda\u0152%K\xbb\xfc\xe1\x0f\xb7~\xban\u0777-\x00\x1e{\xec\t5c\u0197\x9e\xa0{xxb\xee\xf1\xcfR\xb4\xbfH\x84\xc3a\u0371\xed\xfa\xc7|\x81 \xa1\u4538\x11W8J \x95\xa83\ueba0\xbb&\x1d\xea\\\xbar\x1d\xba\x12:\u04b1\xa9\xad\xb6i\u05a6\x05\xe3\x1fy\x83\xb3n~\x88P\xa3d\xa4\x94\xd4\u0506\tG\"BJ\xa9\n\v\vY\xb7n]\xcfG\x1ey\xec\x8b\x193\xbe\xec\fp\xdaig\xa8\r\x1b\xbe\xf3B\x85\x1e\x1e\x9e\x98{\xfc3\xa4\xa4\xa4\xa0i\x9aRR\x1e}P\b\x94Tq\xe7-\u0730J\u0703\u02fa$\u0138So\x98\x86\"\x15\xd8R\xa0\x14(\xe9P]a\xe2O\xd09\xf5\x86\xbb\xb8\xe0\xde\x17H\xcdj\x8e\x92\x0e\xe1p\x98H4*\x14\xa8\x83\a\x0f\xb1a\u00c6\xae\xef\xbf\xff\xc1\x97\v\x16\xcc;\x1f\xa0s\xe7\xae\xce\u0319\u04fdq\xec\u1279\xb7\v<~(\u035ae\xeb)\xa9\xa9\xbe:\xd3\r`\x9b&\xe1\x8a#q]\x17\xf5\x95\xdb\xd4q\xff\x1f\r\xb7\xa8\xfa\u01dc\xb8\x93\a\xd7\xd5\xd7VE\xb1\xa5\xa2\xf7y\x13\x18\xf7\xd0\xeb4ks\x02(E4\x12!\x12\x8d\n\u02d1\xeaPq\t\u02d7\xafh\xf9\xe1\a\x1f~\xfc:\xad{\x0f\x06\xc0\x8eE\x89\x86\u00d8\xb6Cyu\r\xf3\xe7/\xe0\x93O\xa6<\xb6h\xd1\u009b\x00\xfe\xf4\xa7{\u055a5k\u0164I\xaf{\a\xcc\xc3\x13s\x0f\x8f\xef\xe3\xfe\a\xfe\xac\x03\xb4i\u04fa\xbcY\xb3f\xf5\x9a,\x1d\x87\xaa\u0483T\x1c\xda\x17\x9f\xect\xeb%\xba\x99,\xea8\xf9v\u007f\xaf\xe2.\xbc\xee/l)p\x94h\x10W\x17\xeeB\xa2\xea(\xb9\u077ar\xc1C\xaf\xd3a\xd0i\xae\xa0\x9b1\xccH\x18\u01d1T\xd4\u052a\xb9\xf3\x17\xf0\u059bo=\xb3`\xfe\u071b\x00\x1e~\xf8\x11\x15\x8b\u017cq\xed\u1279\x87\xc7?\xc0\x01h\u07fe\xfd\x16M\xd3\x0e\x01B)\xa5P\x8a\xea\xb2b\x8e\xec\u0749\xe1sE\xbc\xae\xc1\x84\x10 \x8e\x9f\xfa\x14\xaa~R\xb4>$\x03\xd8Ra\xab\x86a\x18\xe1\xc6\u02ebbd\xb5o\xc3y\xf7\xbfD\x87\x93G\xb9\x82n\x99\u0122a\x1c\xa9DyU\x8d\x9c5g\x1e\x93&\xbd\xf9\xccg\x9f~\xf2;\x80\ubbffQ~\xfa\xe9'\xde\xd8\xf6\xf0\xc4\xdc\xc3\xe3x\xfa\xf4\xee\xad\x00\x86\x0e\x1d\xbe==#cKBR\x12\xae\xc1\x96\xd4\x1c.\xe6\xd0\xf6\x8d\xf1\xa5\xfb\xc7\x0f\xa9\xe3\x03,\xc2\x15\xf4\x06\x8f\v\x14J\x81\x1d\x8f\xb3\x83B\x13\n\x81\xe6\nz\xb5Ef\xbb\x96\x9c\xff\xd0kt\x19y\xae{f1M\xccH\x18\xe98Zyu\xad\x9c\xbb\xe0k>\xfc\u88e7\xdf{\xf7\x9d\xdb\x01\u018e=O\xae^\xbd\xd2K[\xf4\xf0\xc4\xdc\u00e3!C\x87\x0e\x97\x80\x10B\x1c\xc8i\xde|k\x8b\xdc\\\x00[I\x89\x15\rS\xbag;U%\xc5\xe8\x86\xcfm\xff\u01b1\xee\\\x1c\u04e1P\x1c\xa3\xf3*\x1e\x9d\xc15\xfa\rD\x1f4\xcdM]\xac=b\x91\u05a29c\xef}\x81\ue9cfs\x05\xdd2\xb1\xcc(J)\xad\xaa6\xa2\xbeY\xb2\x8c\xaf\xa6O\u007ft\xea\xd4Oo\a\xe8\u0673\xb73c\xc6W\xde\xc2\"\x0fO\xcc=<\xea\xe5W\b\x9ey\xe6\x19\r\xa0u~\xfe\xdaF\x8d\x1b\x03\xf8\xa5m#\x1d\x87\xe2]\x9b9\xb4s\x13\xbe@\xbd<\xd7GR\xc41.\xbdAz\v\r&G\xd5\u047fQ\xf5r\xee\xfe\xa4\t\x01\xca!V\x15%-\xa7\x19c\xee~\x8e\xeeg\\T\xef\u042dh\x18)\xa5\xa8\xac\x8d\xb0h\xf1R\xbe\xf8\xe2\xabG\xe7\u039d5\x01\xe0\xb4\xd3NW\x0f,L3\x9a\xf7\u007f7\u07980{\xf6\xec\xb9\v\x17~\r\xc0k\xaf\xbd\xca\x17_|\xe1\x1dD\x0f\u03d9{\xfcz\xb9\xe1\x86\xeb]\xc1\x15\xe2\u0420\x81\x03\x16d\xba\xee\xdc\xcd\x15\xb7,\xf6|\xbb\x94\xdd\x05\x8bQJa\xf8|GE\xbb>\x98\u00b1\xf1\xf3\xfag\x1f]`TW\xac\xcbQ\x02[\x1d\x9f\xc4\xe8.0B\b\x94c\x13\xaeth\u0465\vg\xdc\xf9\x14i-\u06c0RX\xb1\bJ\xda\xc2r\xa4Z\xb7~\x13\x05\x05\x05\xb7\u035e=}\f\xc0\x94)\x93\xf5\xab\xaf\xbe\xc6;\x90\x1e\x9e\x98{\xfc\xba\xb9\xf6\u06ab\xeb\u007f>}\xf4i\x9ft<\xa1\x83\n%$\xba\x8a\xac$\xe1\x8a26\xcd\xff\x9c\u0292\x03\xf8\x03:\xba\x00\xedh\xbb\x8a\x06\x01\x95\x06%\x15\x1b8\xf2\xba`\x8a#AJ\x15\xaf\xaa\x18\xbf\xc5\v\xbe\xd4M\x90\n\x01\xca6\x89\xd5Z\xb4\xedw2\xa7\xfd\xfea\x12S\u04d0\x8e\x83m\xc6\x10(Q\x13\x8eX\x9b6oe\xc6\xf4YW\x01\x9c{\xee\xf9\xce\u0295\u02fdq\xef\u1279\u01ef\x9bn\xddz0y\xf2\xc7\x00\xe4\xe7\xb7^\u04a3[\xb79\xd99\xd9\xf5Z,m\x8b\u00b5+(\\\xbb\x1c!\xc00\f4\xa1\x8e6\xach \xe0\xa2\xc1?nhE\"m\a\u01f4pL\x13\u01f6\xdd>\xa2\xf1a\xea\x98Ql3\x86m\xd9HG\xba\xb1u!P\x8e\x85\x15u8q\xf4\xf9\f\x9ax\v\bp,\v\xdb4\xd1\f\xdd\xd8Y\xb8\x97\xad\xdbw\x8c\xfe\xf8\xe3\x0fo\x04\xe8\u077b\xaf\xfa\xee\xbb5\xde\xc1\xf4\xf0\xc4\xdc\xe3\xd7\xcd\xf9\xe7_P\xffs\xcb\x16-\x1e\xec\u043e\x1dqw\x0e@e\xf1~\xd6N\xff\x98\u02b2rt\xbf\x8e@\xb8\x0e\xbd~y\u007f\u0709\xd7?\xa6PR\"-\xcb\x15k3\x86c\x9b\x14\x16,a\xf6Sw1\xf7\xaf\xf7rp\xdb\x06\x84\xeesE:\x1a\x8d\xf7\fu\x90\n\x84\xa6\xe3X&\n\xe87\xfez\xba\x8d\x1eW/\xfe\x8ei\nG*\xb9u\xfbN\xbe-\xf8\xf67J\xa9\x96\x80\x9a9s\xb67\x19\xea\xf1\x8b\u009b\x00\xf5\xf8\x97\x989s\x86x\xf7\xdd\xf7\xf8\xec\xb3\xcf\x0f.[\xb6\xb4WQQQ\x9b\xca\xca\xca\xfa\xdf\xd7\x1c)\xa1i\xab\x0e4?\xa1\x13\x8eS\x97\x9a(\xe2\xf9\u3abe\xad\x9c\x06(i#-\vi\xdbH\xdbB)\x89c[\xac\xf9\xfcmV|\xf0\x02\xfb\xd6-\xa7t\xf762\xdbu%9#\x13;\x16E9\x0e2\xde$C\x17\x02M\u05f0-\x8bPr\x12\xa9-:\xb0k\xd5\"j\x8f\x94 \x1d\x1b\xc3\xf0\x8bp4\x8a\xa6\x91n\x9b\x91\xa2i\u04fe\\6g\xce\\f\u039c\u03bb\xef\xbe\xe7\x1dL\x0f\u03d9{\xfcz\x195\xea4w\xe1\xbd\x10V\x97\u039d\xa6\xb6i\u075a@0T\xff\xfb\xda#\xa5\xac\xfd\xea#*\x8b\xcb\xf0\x05\xf4z'\xae\x8b\xa3\v\x88\x04\xa0\xa4\x04\xdbF\xd9\x16\u04b6\x90\x8e\x83\xb4,t\xdd 5;\x8fPr*\x00\xbbW.\xe4\x9bIOR]V\x8c\xee\xf3!-\x13\u01ccaG\xa3\u0626+\xee\x9a\xd00\xc3&M;t\xa6\xcfe7\xa3\xf9\xfc()1c\x11\xa4\x92l\u0676\x83\xd5\x05k\xae\t\xd7V\xe7\x02L\x9c8\xd1s\xe7\x1e\x9e3\xf7\xf0\xa8\xe3\x8b/\xbe(.(X5\xbch\xff\xfef\xb5\xe1\bR:\x00T\x1c\xdaKJ\xb3\x1cZ\x9e\xd8\vi+\x94\x92\xf5\x8b\x81\xa4\x02\xa9\x14\u02b6Q\xb6\x8dt,\x1c\xc7A92\xbezT\x91\x9e\xd7\x16\xcd0(\u0779\x19\xc74)?\xb0\a#\x98@\xf3N'!m\x1b%%B\xc9x-\x18\x88w\x95F\t\x1f)\xf9\x9d)\u07fb\x9d\xd2\xed\xebQn\x03j,[\xe2\xd8vZ\xf9\x91\xb2\xb2\xf9\xf3\x17|SSS\x8bR\x92\xfb\xee\xbb\xcf;\x88\x1e\x9e3\xf7\xf8\xf5\xb2c\xc7\u05b89\xd7\xf6\xf5\xec\xd9\xf3\xf5.\x9d:\x11\b\x06\xd0\r\x03\x003\\\u02ea\xcf\xdf\xe1\u040e\x1d\x18A\xb7\x00\x97T\x10\xb3%Q\xcb\xc1q$B)7\\\"\x15\x9a\xaa\x13g\x89c\x99\x18\xfe }\xc6]\xcf\xc0\x897\u04e8i6V4\xc2\xe6yS)Z\xbf\x1a\xdd\x1f@96R\xd6M\x9a\x9a(+\x86\x94\x92X$\x8a\x11\xf4\xd1k\xfcoIHM\a\xeaV\x88\xc6\xd8[T\xc4\xe6-[\xafUJ\xba+\x9e\x84\xf7\x15\xf0\xf0\x9c\xb9\u01ef\x9c\xe7\x9e{\x9e/\xbf\x9cf\xbc\xff\xfe\a\xf2\xb3\xcf>\xdf\xf5\xdd\xfa\xef\x86\x1eY\xe7zWN\x99\u0136of\x12Lr\x1d\xbbO\x17\x04}\x1aZ\xbc\u035c\xc2\x15b'\xde4T(U\xbfX\u050aF\x90\xb6M\x97Q\xe7\xd3\xed\x8c\xf1\x18\xc1\x10;\x97\xcfg\xc7\u04b9h\x9a\x8e\x00\xa4\x94\u060eD:\xd2\x15w\xe5\x80\x19!\x10\xd4\xe8|\xda8B)\xae;\x97\xb6I,\x16\xa5\xb8\xb8\x84\u056b\v\xaePJ5\x05\x188p\x90w =<1\xf7\xf8al\u07bc\xe1\u07dal[\xb3\xa6\xe0\u007f\xb2\xea\x9f\x10\x82\u0673g\xba\xd5\x14/\xbaxr\xabV\xf9S\xf3Z\xb6@\xd34G\xb8\xa5\x0e\xa99\\\u02827\x9e\xe4\xf0\xde\x03$$'\xa0\xa1\u0705D\x02\x948Zd\xcb\xed\x17\x1a_\xbc_W\x17W)\xcch\x18!4:\x8f<\x8f\xfc\x9e\x83\x88V\x1da\xc3\xec)\x1c.\u070e\x11\f\xe1H\x85\x94\xf1\xd5E\xd2A96\xb6\xe3\x10\x8bJ2\xdau\xa5\xc3\u0433\u074dU\n\u01f69|\xa4\x9cM[\xb6\xb4\xff\xec\xd3O\xeas,\xa7O\xff\xd2\x1b\xa4\x1e\x9e\x98{\x1c/\xdc\x1b\xffN\xb8;v\xec\xac\xfe\x9d\xd7\xec\xde\xfd$\x95\x95\x95\xf3w\x8f\xef\u06f7\xe7\xbf\xfaY\x8b\x8a\xf6\u04a2E\xbe\x9a>\xfdK\r\u0b33\u039a\x94\x97\x97\x17m\x94\x94\xe4\xf3\x19>U\x97W\xbec\xf9|\xbe\x9e\xf4$2f\x13LH<\xdaRN\xd3\x11\xba\x01B\xe0H\x85-\xdd0\x8b\x8aOl\xd6aE#4JoF\xd7\xd1\xe3Hm\u078aC\u06fec\u04c2/\x88\x86k1|~\x90\x12\u02d1\x98\x96\x83m\xdb\b\xe9\xe0\xc4\xc2\x04\x1b5\xa6\u07503\xf1\x05\x13\\w\xee\xd8D\xa2QJJ\xcbX\xb0p\u163a\xd7\x1f=\xfa\fo\xe0z\xfc\xac\xf1R\xb3\xfe\r\x94R\u031f?W[\xbbv\x9d\xb6k\xd7N\xfd\x85\x17^\x8a\x1d\xf7\xfb\x04)\xed\xc0\u0739s\xd2g\u03de\xa3L\xd3N\xea\u07ff\uf165\xa5\xa5I\u06f7\uf215\x96\x96\x12\x0eG\xb0m7\x93C\xd7u\f\xc3 11\x91\xa6M\x9b\x92\x97\x97\xe7\xcf\xc8H\x0fo\u077au\xea\x91#\x87\xcbN9\xe5\x14\u0577o\u07f2\x9c\x9c\x16\xa6\x10\"|\xdc\xe6\x18\x8f=\xf6\xa8\xc8\xc9\xc9v.\xbe\xf8\x12)\xc4\u007f\xef\xd0>\xf8\xe0\xfd\x0f|\xf5\xd5\xf4\xbb7n\xdeJ$\x1cV\x96e\n\xe2\x19'g\xdd\xf9\x17\x06^z\x13\b\x81m\u0190\nl\xd3$V[K4\x1aA\xd96B\x88x\xfdrw\x88\xaa\xb8\xab\xd6t\x1dG\x18,\xfb\xf8u\xd6M~\x89\x84\x944\x86\xff\xdf}\xb4\xee=\x18+\x16\xc1Q\x02\x89@7\f\x94\xe1G\xe9>\xfc\t\x89\u012a\x8e0\xe3\xc1\xeb\xd9<\xf73\x00t\u007f@\xa56N\x16}\xfb\xf4\xae\xbe\xf7O\xf7\\\u052bw\u07ef\x00\xbe\xfbn\r]\xbbv\xf7\x06\xb6\x87'\xe6\xbf&\xbe\xfa\xea\v\xed\x0f\u007f\xb8\x85\xad[\xb7\xca\x06\xe2ml\u0630\xb6\xcd\xe4\u025f\xa4WUU\xb7\xf6\xfb\x03\xc3\xf7\xed+\xca\b\x04|\x03\x0e\x1e<\x94\xb4\u007f\xff\x01\xc2\xe10\xb1X\x94X\xcc\xc4i\xb0\xf0E)U_\x94J\xd34\fC\xc7\xe7\xf3\xe1\xf7\a\b\x85\x82dee\u046cY\xb3\x9ah4\xba8''\xa7\xaci\u04cc-J\xa9UC\x86\f\xd9;h\u0410\"!DM\xddv\xa4\xa5\xa5j/\xbe\xf8\"\x17\\0\xee\xbf\"\xeaJ\xa9\x8c\x1b\u007f\xfb\xdbY\u04e7\xcf\xe8^\\\\\x8c\x15\x8bb[\x16\x00\xa1F)\x8c\xfd\xd3_\xe9u\xee\x04\xa2\x11\a\xe9\xd8\u0636\x85Y[K,\x12\xc1\xb6,\x84R\b];Z\x90K\xc5\xc3/Rb\x1a\t\x1c\u06b7\x97o'=\xc8\xfe\xb5\x8bi?\xf8L\x86]\u007f7\xc1\xe4\x14b\xd1\x18a\a\xfc>\x03\u007f\xc0\x87\xa3\xfb\xd14\x8dPJ\n\x05\x1f\xbd\xca\xf4\a\xae\a%\xd1t\x03\u007f {\x9d\xd4C\x1b}\u06a8G\xee\xbc\xeb\x8fwy#\xda\xc3\x13\xf3_\t\xf3\xe6\xcdf\u0630\x91L\x9a\xf4\x12\x13'^W/\xbcJ\xa9\xd0\xec\xd93\xfb\u035a5+\xaf\xa4\xa4\xb4\xb7eY\xa7TTT\xb4\u06f3\xa7\x90\x92\x92\x12,\xcbB)E0\x18\xa4q\xe3\xc6$''\x93\x9c\u0708\x84\x84D\x12\x12B\x04\x02\x01t]G\xd7uw\"\u03f6\x89FcD\"a\xc2\xe1\b\xd5\xd5\xd5TUUQQQA4\x1a\x05\xc0\xe73h\u04a4\t\xf9\xf9y4i\x92V\u0628Q\xa3e\u035b7_\u06f6m\x9b\xe5\x13&\\\xbaR\b\x119\xea\x92\x1f\xc4q\x14\xfd\xfa\xf5d\xe4\xc8\xd3~\xd2}t\xf7\xddw\xf1\xe0\x83\x0f\x030k\xd1\xe2S\x9e{\xfa\x99\x99\u02d7.\xf6\xd7VWc\u01a2\xc8x\xbewjV.\x17<2\x89\x0e\x83\x87\x13\xad\xb5\xb1\xad\x18v$\x82\x15\tc\x99\x16\x8eTG\xfbV4\xa8\xb4(\x95\xa2*\xea@0\x89\x03K\xbed\u065b\x8f#\x1d\x87\xc1W\xdfA\xe7\x91c\x89DbT\xc7,\x82>\x83P\u0407\xd2\xfdh\x86N\xa0q\x13\x0emY\xcb\u053b.\xa3x\xdbw\bM\xc3\x1f\bZ\xad\xf3\xf3|C\x86\f\xfa\xfa\x85\x17^\x1a%\x84\x88\x1e<\xb8Ode\xe5*o\xb4{xb\xfe\v\xa4\xa4\xe4 M\x9bf\xfd\xdd\xe3{\xf7\xee\xea2y\xf2\xa7\x97-_\xbe\xbc]MM\xcd\xe0\x8a\x8a\x8a\xe4\xad[\xb7Q[[\x8b\xae\x1bdee\u04be};\xf2\xf2\xf2\xc8\xc9\xc9&++\x8b\x8c\x8c\f22\xd2INN&!!\x81P(\x84\xdf\xef\xbaGW\xcc\x15\x8ec\x13\x8b\u0148D\"D\xa3Q\xaa\xaa\xaa)++\xa3\xa4\xa4\x84\xe2\xe2b\x8a\x8a\xf6SX\xb8\x97\xed\u06f7\xb3\u007f\xff~b\xb1\x18\xc1`\x90\xb6m\u06d2\x9c\x9c\\\x15\f\x06\xbe\xee\xd9\xf3\xa4\xcdc\u01ce\xfd\xb8{\xf7\x93\n\x8e\xdf\xee\u077b\xb7\x93\x9f\xdf\xf6'\xd9W\x05\x05\xab\x985\u007f\xa1\xb8\xeb\xd6[\x15\xc0\v\x93\xdez\xf1\x93\x0f?\xbc~\xf5\u0295\u0122\x11e\u0162\xa2.\x0e\u07b2[\x1f\xce}\xe0Ur\xbbv%R\x15\u00caF\xb0\"\x11wE\xa7\xe3\xb8\xcd+\x94jP[\xd1Mo\x89\xda\x12\xcd\xf0#\xec\x18\x8b_\u007f\x94Ms>#\xf7\u013e\x8c\xb8\xe9A\x82\xe99T\xd7F0\f\x9d\u0120\x81\xe1\xf3#u\x1f\xba?\x00\x02f>\xfc\x1b\xd6|\xf6\xa6+\xe6\xfe\x80\u04f8qc}\xc8\xe0\x93\xf7>\xf5\xd4\xe3\x17\xe5\xe6\xe6/\xfd\xfc\xf3O\xc59\xe7\x8c\xf5\xc4\xdc\xe3g\x89\xe1\xed\x82\xefg\u0294\u027c\xf3\xce;\xa2i\xd3,u\xdc\xe3\xe7}\xfe\xf9\u0511\x97]v\xc5\u041a\x9a\xda\xd6;w\ue92a\xaa\x8aF\x8d\x1a\xa9.]:\x8b\x9e=O\xa2{\xf7\x1e\xe4\xe7\xbb\"\x9e\x91\x91Abb\xf2\xf1\x81\b@\x1d3\xc9W\xf7\xbf\x887np\xd3\xfa\xfe\xbe\xf2w8\xec\x8a\xfb\xc1\x83\a),\xdc\u02da5k((\xf8\x965k\u05a8\x8a\x8a\xaa\u4924\x843\xf7\xef\xdf\u007f\xe6\u0085\x8b.\xbc\xfc\xf2\xcbV\x8c\x181b\xf2\xc5\x17O\xf8\xa4\xee\xf9uB>s\xe6tF\x8d\x1a\xfd\xa3\uecd3N\xeau\xd4J\x037L\xbc\xec\xee\u28bd9\xd5\x15G\xce\u06bcy\xb3@\xf91c&\xa0(\\\xb7\x82\x99O\xdf\xcd\xd8\xfb^\xa2I\xf3\x1cl\xdbF7,\x94\xae\xa1\x94\x83-\x05R\xe0\x86\\\xe2\xcbF\x95\x02\xbf\xae\xa1\t\a\u007fr\n\x1dO9\x93\x03\x1b\v8\xb4e-[\xbe\x9eA\x971Wa\xe8\x1aR),[\xa1\xeb\x0eB\xd3Q\x8eE(5\x85\x8cV\x1d\xdd}-%RJ-\x12\x8b\x12\xae\xad\xcd]\xf4\xf57\ud065;v\xec\x10\r\xb7\xdf\xc3\xc3\x13\xf3\x9f1_}\xf5\x05\x8b\x16-\x12\xe7\x9e{\xfe\xd1\xc6\xf1J\xa5\xbd\xf9\xe6\xeb\x17O\x9d\xfa\xc5\x19\x0f>\xf8\xf0\xc9ee\xa5\xc1\xe2\xe2\x12\xfc~\xbf\u0763G\x0fN=u\x84\u07bbw/\x91\x9f\u07caf\u035a\x92\x94\u0538^\xb4m\xdb$\x1a\xad=&3\u37c9c\x1f\x15{\xb7\xff\xa5\xdf\xef\xa7E\x8b\x96\xb4h\x91O\x9f>\xfd9\xf3\xcc3(--e\xf7\xee=b\xe5\xcaUj\xee\u0739\xce\xea\u056b\u067auk\xcb\xed\u06f7\xb7\\\xbd\xba`\xf4\x84\t\x13\xee9\xf5\xd4\x113&L\xb8\xf4q!\xc4\x11\x80Q\xa3Fs\ubb77\x88!C\x06\xab\xd3O?\xf3G\u0747u\xf1\u007f!\xc4\x11\xa5\u0504CE\xfb>\x8aE\"\xa7\xed\u06bd\xcbM54-@\xb1i\xc1\x17$7\xcba\xf4\x1dO\xe3OL$b\x9a\b\xc3@H\x89\xa6\x1c\xa4\x12G\xd3\x14\x1b4\xa9PRa\x9bQ\xb2;\x9dD\xab\u07a7\xb0\xf6\u02ff\xb1c\xd9\x1c\x9au?\x99\xf4\xbc\xf6\u0122\x11L\xdb\x01M#\xa89 u\x90\x90\x9c\x99K09\x95hU9JI\x11\x8b\xc6,\xdbq|\xc5%\xa5\x1d\x00\xaa\xaa\xaa\xbd+U\x0fO\xcc\u007f\tTU\x95\x8b\xe4\xe4\u0506mox\xf6\xd9g\xae\xba\xf2\xca+\xee[\xb6ly\xf6\u07bd\x85\x84\xc3\x11\xb2\xb3\xb3\xcdq\xe3.\xd0/\xb8\xe0|\xa3{\xf7\x1edd\xa4\xe3\xf3\x05\x01\xb0\xed\x18\xe1p5J)4M\x8b\v\xb7@\xd3\xfe5\x9d8^\xf8m\xdb\u01b2,\xa4\x94\b!\xf0\xf9|\xb4h\x91O\x8b\x16\xf9\f\x18\xd0_\\~\xf9\xa5\xc6\xfa\xf5\x1b\x98:u\xaa3g\xce\\\xb9}\xfb\x8e\xa4\xfd\xfb\xf7w]\xb3fM\xd7\xf9\xf3\x17\\\xfe\xfa\ubbfd|\xe5\x95W\xdd/\x84\x90O<\xf1\xa4z\xe2\x89'9r\xa4T4i\x92\xf1\xa39R!\x04J)\xee{\xf0\x01\x9f\x10\xa2z\u03de\x1d\xf7\xff\xe5/\xcf\f\xa8\xae\xaeJ.--SJ)a\xdb6J)\x96\u007f\xf82\xfe\xe44\x06\xdf\xf0gT\xa0\x11\xb1\xa8\x89\xc2F)\a\x15oN\xd1\xf0\xe2\xa4.\xd5Q:\x0e\xbeP\x02\xed\x06\x8f\xa6p\xcd\x12\xcavof\xd7\xf2\xb9\xa4\u4dad\x0f\xc98\x8e\xc4r\x14>]\"\x1dE\xa3\xf4L\x12\x1a7\x89\x8b\xb9['\xecHy9\u06f7os\xdc\x10\xd4n\xefK\xe0\xe1\x89\xf9\u03dd\x993\xbf\u0493\x93S\x9d\xb8\xb3\f=\xf3\xcc3#\x97.]r\xe3k\xaf\xbd>\xa2\xa8\xa8\x88H$B\u01ce\x1d\x195j\xa4\x1a3f\x8c\xbf[\xb7\xae\x04\x02\t\xf1g;XV\xf4hIV\xfd\xa7\xab\x92P\x17\x86q\x1b&\xbb\xab\x1fc\xb10B\xb8\xae=##\x93\xa1C3\x192d\xb0\xbe{\xf7n\xfd\xf3\u03e72m\xda\x17j\xed\xdau\xe2\xc0\x81\x03\xcd\n\n\n\xee\x9d5kV\xffg\x9e\xf9\xcb\xf37\xdd\xf4\xfb9B\x88H\x93&\x19j\xe6\xcc\xe9\xfa\xa8Q\xa3\x9d\x1fs;\xcb\u028a\xed?\xdf\xf3'\xf2\xf2\xda,_\xb4h\xc1\x05EE\a\xfe\xb6d\u0252\x8cp8\xecD\xa3\x11\u0772\x1dP\x8aE\xaf>\x04\xbaA\x9f\x89w \x83\xc9D\xa2&8\x02\xa4[tK\b04\x81\xae\xc5\xc3N\xc2]d\xe4\xd8\x0e\xe9m:\u04e2\xd7\x10\x8e|6\x89}\xab\x16\xd0\xf2\xa4!4m\xd3\t\u06cc`\xa1\x10\x8e\u0110\x12\u01f2\t5iJ0\u0794Z\u0157\xf7G\xa31\x8e\x1c)\a\xa0\xbc\xbc\x9c\x993\xa72j\xd4\xd9\xde\x17\xc2\xc3\x13\xf3\x9f\x1b;vlc\xc0\x80\x93\u0168Q\xa7;\x00K\x96|3\xec\xe6\x9b\u007f\u007f\xc7\xe2\xc5K\x86o\u0672\x95H$\xc2\t'td\xec\u0631j\u0738\vD\xbbv\x1d\xc5\xd1\x10J\f\xc7q\xfe'>\x87R\x8aX,V\u007f21\f\x1f\xad[\xb7\xe3\xe6\x9bo\xe5\xe2\x8b\u01cb\xa9S\xa71y\xf2dV\xacX\xc9\xee\xdd{F\x14\x16\xee\x1dQX\xb8w\xee\u0085\xf3\x1e\x1d2d\u063cQ\xa3F;-Z\u42af\xbf^\xa8\xf2\xf3[\xff(\u06d4\x9e\xdeL-[\xb6X\xf4\xeb7P\r\x1at\u02ac7\xdex\xedV\u04cc\xbd\xb5r\xe5J\xddql\th\x96e\x03\xb0\xe8\xa5\xfb@)\xfa_u\x17\xaaq\x1a\x91#%8\xb6\u0114\uef02O\x13\x04\r\x1d]S\xf5\u92a6i\xa2\x05\x13\xc9:i\b;\x96\u03a6\xa2p\x1b%\x9bV\u04fcCg\x94\xa90\xa5\xc4q$\xd2qP\xd2\u0097\x90T\xbfx(\xfe\x12H\xa5\x88F#\x0e@ff3O\xc8=~\xb6\xfc*c\x84EE{\x99:u\x1a7\xde\xf8\u007f\r\xc50\xf9\xa6\x9b~{\xe5\xb6m\xdb\xfe\xbca\u00c6\u48a2\xfd\xe4\xe66g\xfc\xf8\xf1L\x980\x9e\u039d\xbb\u015d\xb0uL~\xf8\xff\xf4\xc1\x15\"\x9e\xf6\xe8\a\xe0\xc0\x81}|\xfc\xf1d\xde~\xfb\x1d\u05ad\xfb\x8e\xec\xec,\xbat\xe9R\u0561C\x87??\xfd\xf43o\b!\xaa\xea\x9e\xfb\xf6\u06d38\xe5\x94Sh\xd1\"\xff\xdf\u078e\xab\xae\xba\x92\xd7_\u007f\x03\x80G\x1ey\u8669S\xa7\u0774e\xcb\x16,\xcbR\xa6i\t+\x9e\x83\x0e\xd0\u007f\xe2\xad\xf4\x9dx;\x18A\xc2e\xc5\u0636\x8d\xe9Hl\x05\xba&\xf0k\xe0\xd3\xdc@\x8a\xa3\x14\xd2\x1f\xa2\xb6\xb2\x825o?\xce\ue15f\x93?`\x14C\xae\xb9\x93\xa4\xd4tjL\x1bt?\xc1\x80ABR\x12\xb6\x19e\xca\xed\x17\xb3s\xe9\x1c4]\xc7\b\x84\x9c\u071cl}\xf4\xa8\x11\x9f>\xf7\xdc\xf3\x13\x84\x10\x91\xc2\xc2]\xa2e\xcbV\xde$\xa8\xc7\u03ce_\xe5r\xfeo\xbeY|\x8c\x90/^\xbc\xa8\xef\x84\t\x17\u007f5s\xe6\u033f\u031a5;\xf9\u0421b\u018c9\x87\xd7^{\x95G\x1f}\x84\u039d\xbba\xdb1b\xb1p}\xbc\xfa\xe7\x80R\n\u06f6\xe3\xdb\x1d%;;\x97\xdf\xfd\xee\x0f\xbc\xf1\xc6k\xdcp\xc3\xf5\xc4b&s\xe6\xccM\x9e1c\xc6_.\xbf\xfc\xb2\xaf\u05ac)\xe8[\xf7\xdc\xcb.\xbb\x82\xa5K\x97\xfd(\xdb1n\xdc\xd16sw\xde\xf9\xc7\xdf\xf5\xee\xddkR\u02d6y\x18\x86!\x02\x01\xbf\xf2\xfb\xfd\xf5s\x03K\xdf|\x82yO\xddL\xf8\xf0A\x92\u049a\x12\xf0\x1b\x18\x9a\xc0\xd0\x04R*\xa2\x0e\x84-E\xad%\x89\xd8\xeed\xaa/)\x85f\x9d\xfbb\x84\x12(\u0771\x9e\x8a};\t\x04\x02\b\xe9\xa0\xe2\xee\u0736\x1d@\xa05\x98\x83\xd04!\"\x91(MR\x9bt\x06\xda\x03\u0636\ud578\xf0\xf0\xc4\xfc\xe7\xc0\xa2E\v\xc5E\x17\x8d\xaf\xbf\xff\xf8\xe3\x8f]\u007f\xd7]w\u007f2k\u05ac\x81\u06f6m'??O>\xf2\xc8\u00fc\xfc\xf2\x8b\x9cz\xeai8\x8eM$R\xf3?\x13N\xf9W\x91R\x12\x8d\xd6b\x9a\x11z\xf4\xe8\xc5\x13O<\u018b/\xbe@\x9f>}\xe4\xb6m\u06d81c\xc6\xc0[n\xb9e\xf2s\xcf=\xf3\x1b\xa5T\xc0\x15\xe1\xf1\u03181\xfd\xdf~\xef\xe1\xc3Oe\u0294\xc9\xf5\xf7\x9f}\xf6\xafw\x9e}\xf6Y\x85\xb9\xb9-\x10B\b\xbf\u07e7|>_\xfd<\xc0\xba\xa9o3\xeb\xa1\xeb)\u07bc\x8a`\xe3&\x84BA\fA\xbc@W}).\xb7\xe2\xa2\x02#\x10\"\xa5U'\x92\x9a\xe5R{\xb8\x98\x8a};\xb0L\xab\xfe\xaf\xed\xf8D\xaa\xb2-l\xdb>\xbaO\x14*\x10\nRU]\xb5\x1d\xd8\x1d\x0fQy\xae\xdc\xe3g\u026f*f>o\xdelm\u0420!2\xeeZ\x1b\xdd~\xfb\xad/\u007f\xf4\xd1\xc7\xe3\v\n\n\x00\x9cQ\xa3N\x15w\xdcq\x9b6x\xf0\x10\xc0\xcd\xe9\xd64\xad^d~\xf615!\x90R\x12\x0eW\x13\f\x069\xff\xfc\v\xe8\u05ad\x8b\xf6\xdcs\xcf\u02f7\xdf~G\u035b\xb7\xa0yuu\xcds\a\x0e\x1c\x1c\xa0\x94\xbaB\b\x11>\xed\xb4\xd1,]\xbaX\xeb\xdf\u007f\xe0\xbfu9r\xee\xb9\xe7S^^Fjj:B\x88\x92}\xfb\xf6^\\YY\xf5\xf1\xb4i\u04f2\x8b\x8b\x0f\t\xbf\u07e7\x84\x10\u00b2m\xa4\xe3\xb0{\xd6vD[\x00\x00 \x00IDAT\xf9\\j\x8a\x8b\xe8?\xf16\xf2\xfa\x8e !1\x89\xda\xdaZ\x1c\xe9\x80\x10\bM\u00f6lJ6\xad\xc0\xb1LR\xf3;\x92\u07be\a\x15\x85\xdb(\u07f7\x93hM9\x9a?\x19G)lGaK\x90\x910\x8e\x19\xab\xdf\x17\x80\n\x85B\x1c8pp\xa3\x10\xa223;K\xcb\xcd\u0353\x9e,xx\xce\xfc\u007f\x98\xd7_\u007fM\x1b6l\xa4\x04X\xb1bY\x9f\xf1\xe3/\x9a\xf5\u99df\x8d/(( 11Q\xddv\xdb-\xda\xdf\xfe\xf6\xb66x\xf0P\x00\xa2\xd1\b\xba\xae\xf3\xdf,X\xf5S\t\xba\xae\ub626\x89\u3634k\u05d1\xe7\x9e{Z{\xfa\u99f4\xbc\xbc\x96j\xe5\xcaUL\x992\xe5\xc2\xf3\xce;\xf7\xf3\x82\x82\xd5]\x00\xfa\xf7\x1f(?\xf8\xe0\xbd\u007f{\xac\xa4\xa6\xa63c\xc6W\x1a@nn\x8b%c\u01desf\x8f\x1e=\xf64i\x92\x86\x10B\x05\x02~\xfc>_}6P\xe9\xee-\xcc|\xf4&\x96\xbf\xf98\xe1\xb2\xfd$%7\xc6\xef\xf3#\xa4D\xd7t\x90\x0e\aV\xcfc\xcd[\x0f\xb3o\xe9t\x1ae\xb6@\xf7\xfb).\xdcAuy9\x9a\u03c7\x94\n)\x1d,\x05U\xe5e\xc4j\xea\x9aN\v\xea\u02a6\u06cek\xd7'\x8c\x1f\x1f\xb8\xf3\xce;|g\x9ey\x86~\xe3\x8d\xd7\ubbfe\xfa\xb2>g\xce,}\u04e6\rZ\xc3u\x02\x1e\x1e\x9e3\xff/\xf1\xc8#\x0f\x8b\xab\xae\xbaZ\x02|\xfc\xf1G\xe7>\xf1\u0113o-X\xb00\xe9\xf0\xe1\xc34o\x9e\xa3\xee\xb8\xe3vq\xe3\x8d7\x00:\xb6\x1dsK\xa8\x8a_\xf6\u0730\x10n\xd7\x1f\xc7q\xf0\xfbC\\u\xd55\"77\x97\xbb\xef\xbeG\xae^]\xa0UTT\x8e\b\x85\x9e^2}\xfa\x97\x13G\x8f>c\xcaE\x17],\x9f}\xf6\x19q\xd3M\xbf\xfb\xb7T\xed\xb4\xd3N\x97\xef\xbf\xff\x9e\x18?\xfeb5x\xf0)\u07fe\xfa\xea+cm\u06da\xf2\xed\xb7k\xf2\xcb\u02cfH\xc3\u0405\x10BX\x96\x1b\x12\x89\x85\xabY\xf5\xc1\xf3\x14o]G\xb7\xb1\u05d0\u0575?\xbe\xe4T\xccH-\t\t\x89d\xb4\xeeD\xe1\u0499\xec\x98\xfd1M\xf2;\xe0\v%RUz\x90\x8a\xcaJ\x82\xb9\x06J\xc4\xdcu\xb4B\x10\xa9\xac \x16\xae\x89\u007f~\x90\xd2\xc1\xef\xf7\xd3(\xa9Q-\xc0\x93O>\x15\xf9G\xdb=p\xe0@\xfdO\u007f\xba\x1b\u01d1j\xf8\xf0a\xea\xe4\x93\a(\xc3\b\xb2g\xcfN\xf2\xf2Z{J\xe2\xf1\xdf\xffN\xff\x92?\xdc\xef\u007f\u007f\x13\x8e\xe3\x88\xe7\x9e{^\x01<\xff\xfc_\xc7N\x9b6\xed\u0765K\x97\x85jjjh\u06f6\xadz\xfc\xf1G\xc59\xe7\x8c\x05\xc04#\xfcZ\x1dX \x10\x044\u05ae\xfd\x96;\xee\xb8S\u035a5[\xa4\xa44f\u0420A\x911c\xc6L\x988\xf1\x8aO\x01n\xbd\xf5\x16\xe1\xf7\xfb\xd5C\x0f=\xfcO\xbf\u01de=;\xf9\xeb__\u2a67\x9e\xe4\uaaef\xe6\xb5\xd7^\x03\xe0\xbd\xf7\xde\xed>u\xea\xd4OV\xacX\u046a\xa4\xa4\x04!4%\xa5\x8c/,r\x87\xa9t,\x92\x9ad\xd2\xfe\x941\xb4\x1dq.\xa9y\x1d\x11\x02\xecX\x94\xed\xf3\xa6\xb0i\xc6\xfbD*\x8f\xa0l\x1b4A\xff\xdf\u00d0\xb1(J@Bj\x06{\x17\u007f\xc1\xdc\xc7~Cmy\x19\x86\u03cf\x12\x9a\u04f6Mk}\xe4\xf0\xa1\u04c7\x0f\x1b\xf6F\xd1\xfe\xfdM5M\v\xef\u077bw\xe5\xc9'\x0f\x8c\x0e\x1f>\xd40\x8c\xa0\x01\xec\xfd\x9e\x92\xc3\xc7T\xba\\\xb6l\t\xfd\xfa\r\xf0\x14\xc5\xc3\x13\xf3\x9f\x82\x1bn\xb8^\xbc\xf8\xe2K\n\xe0\xc5\x17\xffz\xfaG\x1fM\x9e\xbcr\xe5\xaaP$\x12\xa1[\xb7\xae<\xf9\xe4\x13\f\x1f>\x12)M\xea\xf2\x9d\u007f\u0543A\b\xfc\xfe\x10\x85\x85\xbb\xb8\xf3\xce?\xf2\xe1\x87\x1f\x92\x90\x90\xc0\xc0\x81\x03#\xe3\u018d;\u007f\xe2\xc4+\xbe\x02\xb8\xed\xb6[\xc5\xe3\x8f?\xf1\x0f\xcfz\xdf~\xbb\x9a\x1e=z\xfeS\xef]SS\xde\xea\xce;\xef\x992s\xe6\xac\x13\x8b\x8a\x8a\\\xb1\x94\x12\xa9\x14\b\x1d!t\x94t\x90\xb6EZ\xab\x8et\x18u\x11m\x06\x9fIJ\xb3\xe68\xb10;W-b\xeb\xbcO)\u07b8\x12'\x16\xa5\xf7\xb5\xf7\x91?\xe8\f\x84\xb4\xd1\x04$\xa5g\xb1\xe1\xb3W\x99\xf7\xd4\x1fp,\v\xe16\x0e\xc5\xd05\u0661C\a-'';~\xa5\"),,\\\u05e8QR$33\u04d7\x96\x96\xee\x03\xb9\xc3\xe7\xf3\xefh\u07fe}E\xf3\xe6\xcd\x17]r\u0265\x87\x85\x10[\xbe\xefs\xfc\xf1\x8fw1x\xf0 F\x8e\x1c\u5a4b\x87'\xe6?\x06o\xbe9IL\x9cxE\x9d\x90\x8f\xfe\xf0\u00cf\xdf[\xb5jUJ$\x12\xa5W\xaf\x9e<\xfb\xec\xd3\xf4\xeb7\x10\u02ca\xe28\xce/>\xac\xf2Cq\xcb\xf5&RZZ\xcc\x1f\xffx7\x93&M\xc2\xef\xf73`\xc0\x80\x8aK/\xbd\xf4\xe2K/\xbdl:\xc0G\x1f} .\xbc\xf0\xa2c\x04\xfd\xb3\u03e60f\u0339?\xe4=\xda\xee\u07bd\xa3\xe3\xea\xd5\x05r\xf7\xee\u0772\xb2\xb2Jj\x9aV2l\xd8\xd0\xd3\u05ee]w\xff\xfb\xef\xbf\u03d6-[\xb0m\xc7\xcd\"\x12\x1aB\xe8\b\xcd\x00\x01v4\x8c\x11\b\u0462\xe7`N\x18y.-N:\x05\xbdq\x06\xbbW-`\xc5\xcb\u007f\xa6r\xdf\x0ez]s/\xad\x86\x8dE\x03\f\rR\xd23Y\xfc\u04bd,\x99\xf4\x88\x1bc\xf9\xfe+0\xe5\x9e\xd3D})\x06M\xd3HJJ\"++\x93\x94\x94\x14,\xcb\u079b\x99\x99Y\x99\x9f\x9fw 77w\xe6%\x97L\xf8\xb2Y\xb3\xac\x1d\xff\xaf\xfd\xe9\x8d-\x0fO\xcc\xffEV\xae\\&z\xf7\xee\xa7\\\xd1\xf9p\xf4\xcb/\xbf\xf2\xde\xe2\u014bS,\u02e2w\xef\u07bc\xf0\xc2s\xf4\xec\xd9\a\u04cc\xd4\xd78\xf18\x8a\x94\x92P(\x89\x8a\x8a\xc3\xdcq\u01dd\xbc\xfa\xeak\xe8\xba\xce\u0211\xa7V\xfc\xfe\xf7\xbf\xbbx\u0108\x91\xd3\x01V\xaf^!z\xf6\xec\xf3\x0f\x1d\xfa\xaaU+\xfa}\xf6\xd9\xe7\xadJKK\xba$$$\x0e\u07bd{O\xb8\xac\xacL$$$\xe4\x80\u02a8\xaa\xaaR\xb1XL\u0555\xfe5\f\xa3\xa6}\xfb\xf6\xd9EEE\xbe-[\xb6P[S\x8b\xed\xb8\x95\x0fu\u0747\xa6\x1b\bMC\xd3t\x1c\xdb\u010eFH\xca\xc8&\xb7\xfb@:\x9c~\t\xca\b\xb0\xf4\x85\xbb(\u07fd\x99>\xd7\xddG\x9ba\xe7!P\x18~\x1f2Z\xcb\xfc\xc7\u007f\xcf\xf6E\xd3\x10\x9a\x86j\xb0V\xa0\xaeDB\x03\x01\x96\xc7=\xae\x1c\u01d1\x80\x1e\n\x055\x9f\xcfOVV&\t\t\x894j\x94\xb4\xbbC\x87\x0e\xbb\xf3\xf2\xf2>\x1f>|\xd8w\xbd{\xf7\xfd\xfa\xfb\xf6\xc5\xff\xfd\xdf\r\\{\xed5t\xe9r\xa27\xc0<<1\xff!\xbc\xf3\xce[\xe2\xd2K/\aP\xdf~[0\xfc\xfe\xfb\xef\x9f2}\xfa\x8cd\xd34\x9d\xee\u077b\ubbfc\xf2\"\xbdz\xf5\xf5\x84\xfc\a\nzyy\x197\xdf|+o\xbe\xf9\x96\x13\b\x04\xf41c\xc6T\xdd{\xef=c:v\xec4?\x18\fj\xd1h\xb4auI\u07c2\x05\xf3:~\xf8\xe1G\x83\x0e\x1e4]\a\xb4x\x98\x04\xacH\x18P\xa4\xb4hKbz6\xe5{\xb7a\x9b\x11\x86\xde\xfa,\xad\x87\x9c\x8dm\x9a\x04\x92\x1aQ\xba\xa5\x80\x19\u007f\xbe\x92\x92m\xeb\xfeN\u033f/\xdcTGC\x87\x1e/ \xe6(\xa5\xb0,\xcb\xd14\xcd\u07e8Q\x12\xa9\xa9\xa9\x04\x83A'9\xb9QU\xabV\xad\xcb:v\uce22}\xfb\xb6S\x87\r\x1b\xb6*##\xb3\xf0\xf8\xd7_\xb6l\x89\xe8\xd7o\x80\x97\x1e\xe3\xe1\x89\xf9\x0f\xb9\xa4-**l\xf5\xdb\xdf\xfe~\xfa\xfc\xf9\xf3\xdbWTT\u0431c\a^\u007f\xfdU\xfa\xf7?\x19\xa5\xdc\x06\x10\x9e\x90\xff\xff\f\x8ex\f\xfd\u02112\xae\xbd\xf6:>\xf9d\niiM\x18:t\xe8\xc6\x17^x\xee\xf4\xa6M\xb3\v\xe3\xfb=\xf5\x81\a\xee;s\u04e6\u037f\u0674is\xcf\x1d;v \x84 \x1c\x0e7\x9cP\xae\xaf\u007fX\x97\x1e\xf9}\xf9\xfbu\xc7\xd00\x8c\xfa\x15\xac\xb6m\xbb\xee\xdc\xf0\xa3\xeb\x06\x9a\xa6\xe3\u0583\xaf;\xf1\xd8H\xcbD\xd3\f4\x9f\x8f\xa4\xa6\xd9\xf4\xbb\xf2.\xd2\xdbt&RSE \x94\xc8\xc1\x8d\xabX\xfa\xda\x03T\x97\x1e\xa8\xaf\xeaX\xf7\x15h8\f\xea\xab4\xba\xa7\xa7\xef\x1d#\rJ\xfc\"\xa5T\x80\xd0u\xb7\xcd_rr2\x81@\x80\xb4\xb4&t\xea\xd4\xc9NII\xf9\xa8m\u06f6_\xe6\xe7\xb7Z}\xd6Yg\x954,\x99\u0423G\x0f\xe3\xba\xeb\xaea\xe4\xc8\x11N^^kO\xdc=<1\xff\x9e/[\xfa\x84\t\xe3\u07de7o\xfe\xe8C\x87\x8a\xc9\xc9\xc9\xe1\xf9\xe7\x9f\xc3\xcdZq\x88F\xa3\x9e\x90\xff@4M\xc3\xe7\v\xb2c\xc7V\xae\xb9\xe6:\x16,XHNN6#G\x8e\xfcj\u04a47\xcf\x02|\xbf\xfb\xddM\x9f~\xf3\u0362\xd1\x1b7n\"\x163\x8f9\x14\xc4c\xd0J\xb9\xa1\xea\xba\xfd\xfe}9\xfc\r\ufeee\xdd}\t\xdbvk\xe1h\xba\x0fM3\x10\x9a~\x8c\x007\x8c\x81\vM#\u0538\t\x89M\x9ab[&V,\x82t\x1cb5\x95\x84+\u0290\x8e\xddP\xad\u007f2|>\x1f\xc1`\x90`0H\xeb\u05ad\xc9\xc9\xc9.MKK[\x92\x96\x96V\x90\x92\xd2x\xfem\xb7\xddQ$\x84\xd8[\xf7\xf7o\xbd\xf5\x866r\xe4\xa92;\xbb9\xf3\xe7\xcfe\xe8\xd0\xe1\xde\xe0\xf3\xf8\xf5\x89\xf9\x8c\x19_\xb1p\xe1\xd7\xe2\xb1\xc7\x1eW\x00\xf7\xdcs\xf7\vS\xa6|z\u00e6M\x9bHHHP\x8f?\xfe\x98pk\xb1(\xa2\u0470'\xe4\xff\xe4\u054ea\x18\x18F\x80\xe5\u02d7r\xf5\xd5\u05e8\r\x1b6\x8aN\x9dN\xe0\x8a+&>\x9e\x94\x94\xd4\xf4\xd9g\x9f\xbb|\xf3\xe6-\xff0\xad\xb3n\u007f7lX}\xb4\xd6\xfb?h\u05a1\x14R)\xb7T\xadRnHL\xd3\u30ae\xd7\u05c9o(\xca\xf1P7B)\xecX\fG\xd9?H\xb2u@\xd3\x05\xb6\xa3~\x12\x897\f\x03\xbf\xdfG(\x14\"33\x93\x9c\x9c\x1c\u0574i\xd3\xe5\x19\x19\xe9S\u018e\x1d\xb3\xec\u44c7,=\xfe93g~\u0168Q\xa7{\x03\xd0\xe3\xd7%\xe67\xdex\x03/\xbc\xf0\"\x00\xaf\xbe\xfa\u0288\x17_|q\u06bau\xdf\x05\x95R\xfc\xe1\x0f\xbf\xe7\xd1G\x1f\xc6\xe7\xf3y\x8e\xfc\xdf\x10tM\xd3\xf0\xfbC|\xf8\xe1\xfb\xfc\xf6\xb77QZZF\x9f>\xbdcyy-\x03\v\x16,\xa4\xa4\xa4L\x89x\xe7\x88\xe3E\xfd\x18\xc7]\xe7\xa4\x1b\x8a|\x03\x1b\x0f\n%]!\xff\u01c36^b\xa1>\xde\xee\xde\xfc\t\x894JoF()\x19_(\x01_ \x88\xe1\xf3\xe1\xf3\x19\x84\xfc\x06\x86\xc0\x9dh\xd5\x04\x89\x8d\x92\xc9h\u0782\xe4\x8cl\x84\xe1\aM#\x1251-\x13G\xbaW\x03V\xa4\x96HM5\xb5U\x15T\x94\x1e\xa2d\xefN\x8e\xec\xdbE\xac\xb6\xa6~\xfb\xea?O\x83\xab\x83\xff\xd7IM\b\xd04\x9dF\x8d\x1a\u047auk\xd2\xd3\u04cb\xf3\xf3\xf3\xbe>\xf7\u0731\x8b\x86\r\x1b\xf1\x8a\x10\xa2>G\xf6\x92K&0b\xc4p\xe2s@\x1e\x1e\xbfl1\u007f\xe2\x89\u01f8\xf5\xd6\xdb\xeb\xbeDY\xa7\x9f~\xfa\xeco\xbe\xf9\xa6suu5g\x9cq:o\xbc\xf1\x1aM\x9bf\x11\x0eW\xff\xa4M#~\xe9H\xa9\xf0\xfb}\b!\xb8\xff\xfe\ax\xf8\xe1G\xd1u\x9d\xe4\xe4d\x94\x92\xaa\xb2\xb2\xaa\xbe{\xd0O\xb1\xf0J\xd7\r\x8c@\x00_ \xc1m\xd4l\u06d8\xd1\bB\bB\u0269d\xb4\xea@\xeb\x01\xa7\u04b4M\x17t\xbf\x1f_ \x80?\x10\xc4\xef\xf7\x91\x14\xf4\x91\x92\xe0\xc3\xf0\xb9\xd5\x195\x01\x9a/@(9\x15\x15\x00G\x82\xe5\x80%\x8f\x9eT\x1c\a\xa4\x05\x96\x19\xc32\xa3\x985U\u0516\x1f\xa6\xa4p'\xfb\xb7\xac\xa1\xe8\xbb\x15\x14\xef\xdcL\xb4\xaa\x1c+v\xb41\x89\xe6\xaau\xbc\u035d\x02)\xff\xce\xed\xc7E]*\x05~\xbfO\xcb\xcf\xcf'//\x8f\x13N8a\u0168Q#\xdf\x1e1b\xd4K\rO\x80\u007f\xfd\xeb\xb3\xe27\xbf\xb9\u024b\xa9{\xfc\xb2\xc5|\xc1\x82\xb9\xe2\x94S\x86+\x80K/\xbd\xe4\x91y\xf3\xe6\u0771\u007f\xff\x01\u06b5k\xab\xde~\xfbM\u0477\xef\x00\"\x91\x9a_L\xb1\xac\xff\xae\xa0KB\xa1D\xca\xcaJ\xb9\xfa\xeak\xf8\xfc\xf3\xa9\xca\xef\xf7\x8b\xc4\xc4$\x1c\xc7&\x1c\x0e#\xe3\xcd$\xfe\x91\xa0\a\x02A\xfc\xc1 >\u007f\x00M\xd7\x11\x9a\xee\xe6\x91\xeb\x1a\x9an\xe0\v\x04\t&5&)-\x83\x94f9$7\xcb!9\xad\x19IM\xd2\t5N\xc5\x1f\b\xa1\xa4\xc24c\u0516\x97Qqp?\xc2\xf0\x91\x9a\u05d1\x94\x96\xed\xd0\x02!l\xc7F\x17`h\x1a\xba\xa6\xe1\xd3\x05~C\x03MG\x02\xb6\x84\x98\xa3\x88\xc6Lbu\xd50\x95@\x89\xba/\x85\xdb\xcdH\b\xf7\n\xc0gh\x04|\x06\x01\xbf\x0f\xa5 RSM\xb8\xe20\x87\xf7\xed\xe2\xc0\x96\xef\u063f~\x05%\xdb\xd6Q[v\x88XMe}\xa6\x8c\xd0\u2379\x1b\x84\x8b\x8e\x17uM\x13\xd2q\xa4\r\xf8[\xb5jEnns:w\xee\xfc\xdd\xc9'\x0f|l\u0738\xf1\xef\x1f\xbf\xff\x16/^$\x06\x0e\x1c\xe4\t\xbb\xc7/G\xcc\xdf\u007f\xff]\u018f\x9fP\u007f\xff\x85\x17\xfez\xfeK/\xbd\xfc\u0386\r\x1b\x83III\xea\xe9\xa7\xff\"\xae\xba\xea\xea\xff\xa9n@\xbf\x14\x02\x81\x04V\xadZ\xc1\xd5W_\u00fau\xdf\u0468Q#\xfc~?\xd55n\xa9`\xa5\x14\xb2\xc1>Oi\x9aI\u04fc\xb6\xb4\xec\u0503\xdc\xf6]H\xcbjNb\xe3\x14\x94\xe1\a\xcd@\t\x1d\xdd\xef\xc7\x1f\bb\xf8\xfdh\x86\x0f\xdd\xe7G\xf3\xf9\x11\x86\x0f\xc3\aq\xcdwO*\x8e\xeb\x9c\x1d\x1b\xccH\x14\u04f2\x89Y\n\xd32\xe3B.\xd04\x1d]\xd7PB\xc3A\xb8\xff+0\xa5\xdbrNA}\x8c\\*7n.\x04\b\x14*^[W\x13\x02\x05\xe8\xc2-\xb7+P\u8e86\xe6\xf7\xe3\xf3\xfb\xdd\x05L\xa6\x83\x19\rS]\xba\x9f\xd2-k8\xb0v\te\xdb\xd7S}h\x1f\xe1#\x87\xb0\xa2\x11@C7\f\x84\u0410\xd2q;\x1f\xa9\xefM\x8dTB\b\x91\x99\x99I\u02d6-\xe8\u0673\xe7\xa6\xe6\xcds\x1e:\u55213{\xf7\xeeS)\x84\xa8\u06e9\xdaSO=a\xb4i\xd3\xda:\xfb\xec\xb1\xea\xd5W_\xe6\x9ak\xae\xf3\x06\xa6'\xe6?_\xbe\xf9f\xa18\xf9\xe4!J)\x95w\xe1\x85\x17\u03181cF\x87\xea\xea\x1a\xfb\xf2\xcb/7^\u007f\xfd\x15t\xddO4Z\xeb\xc5\xc9\u007fd\xdcf\x12\x06\x0f?\xfc\x10\xf7\xdcs\x0fR*\x02\x81\x00\x8e\x94\xd8\xf1\xaeA\t\x8dS\xc8l\u0749\xdcN\xdd\xe9|\xf2\bZu\xefO\xa8qj}\u03b6\x03H\xe2m>\x05\xf8}\xf5\xd1\t7\xf4,\xe3\xa1\x0e\x89[\xf6\xf68\xc7_\xefr\x85\xc0\xb4$\xb5\x11\x13+\xbe\x92\xd7\xd0\x056\x1a\xb6\x128\b\x1c\xa9\xb0\xe2o(\x94B9\xa0I\xe5\x164w\x14\x9a\x12h(\xa4\x00\xa1@\xb8\xadG]a\x8f\x8bCH\xcf\xcd\xc3\x10`9\xee*O\xe5H\xa4\x94X\xf1IN\r\xf0\xf94|\xba\x1e\x9f?\xfc\xfb\x8c\x12\xe9\x06\xa0\xe3\xf3\xa6\x02\xd5`\xf0*\x14Q[Q\x13s\x889\nG\xba\xae\xdav\xc0\xb6\x95+\xe0\x8eB\xd9\n\xddQ\xe8\x12\x84T\x88:{^\x97O\x1e\x0f\xaf(\x11?\x9b\xc4\xdfO\xe1\u693b\xb1pp\u217f\x10\xf1\t\xd0\xf8k\b@\xf3\x19\x88\x80\x0f\xcdo`\xf8u|\x86\u00ac,\xa5l\xc7:\x0em_\xc7\xc1\xed\xeb8\xb0m\x1de\xfbw\xe2\x9814\xddp_K\xc9\xf8\xa4\xef\u07fbu\x9f\xcf \x18\f\x91\x92\x92B\xeb\u05adHKK\x9bw\xc2\t\x1d\x17\x0f\x1atr\xc1\x88\x11\xa3\xbe\xa8\xfb;]\x0f\xb0e\xcbwL\x9d:\x8d[n\xb9\xd5\x1b\xa4\xbf\xc6\xef\xe5\xcfu\xc3\x1fy\xe4a\x03\xb0W\xae\\\xde\xe6\x96[n\x9d\xb8c\xc7\x0e\x00\xe7\xd2K/\u047bv\xed\x0e8\x9e\x90\xffT\x0e@\b\xa4t\x1dx\xe3\xe4d\x8e\x94\xbbF1-\xbb\x05g\xdd\xfc0-\xfb\f!f\x81m;\x84\xc3Q4%\xd1\\I\u018a\xbb\xdeXD#\xdc\xfct\u074dq\xfb\xfc\x01\x8cP\x10\u007fB\b\u007f(\x84\x91\x10\xc4\x17\f\xa0\a\xfd\xe8\x01?F\xc0\x8f\x11\xf2c\x04\xdd\x14\xc7@(H !\x84?\x18\xc0\xef\v\xa0\x1b\x06\x1aZ\xbd\x90\u05c9:\u01c9=\x8eB\xd8\xeee\x84c;D\xa3\x11L\xd3$\x98\x94F\xb3\xfc\xae\xb4\xe8\u060f\xacV\xdd\x10B#Ru\x183Z\x8b\x94\x0e\x9a\x86\x9b\xe9s\xdcITJ\x89\xae\xebB\xd7u*\xca\xcb\xed=\x85{\xb4\xe2\xe2\xe2\xdc={\n/\xbc\xe8\xa2\v;,^\xbcd\xf9}\xf7\xddW=k\xd6l\x1e~\xf8Am\u07bc\xf9\xde\xe5\xa9\x17f\xf9\xdfd\xc1\x82\xb9\u0525\"\xbe\xfd\xf6[\xa3\u05af\u07d0\x020`\xc0\x00F\x8d\x1a\x15\xbf4\xb5\xbc#\xfb\x1f\xc0\x8eE\x89\xe0#\xbf[_\xfa\x8c>\x9f\xd9o=\u02eeU_\xb3\xe7\xdb\xc5t8\xf5B\x1ca\xe0H\x87\x04\x1d\x92\xfd\x10\x8b\x82\xa3\x14\x8e\x04\xbf\x00\xbf\x13W]\x9fpSFp\xc5W:\xb8jo*\x94%Q\x96D8\xa0\x1c\x85\xb2%\xa6\xa3\x88\xd8no\xcf\xfa\x90\b\u2a17mPwE\xf7\xf9\xd1\xfd\x01t\xbf\x1ft\x81\xe3XH'\x86\xe9DP\x96\x85f[H3\x8cY[\x89\x15\x8b\xe2\xd8\x16\x8e\x1dC\xd96B\xd30|\x01|~?~\u007f\x10\u007f\xb0\x11>\u007f\"\x9a\x1e\x00\u0347\x1e\xf2\xe1\x0f%\xa2\v\x03iK\xac\x98\x89\x8a\xc5pl\u06dd\xb9=\xbaA`\xc7C?\x9a@\tI$Z\t\x9a\xc0\x1fJ\xa7\xcdIg\x91\xd3~ E[\x97\xb3i\xc9\x14\xf6o[IeY\x11\x8e\xed\x8ec\xa1\u05657R_\xafF\xd34t]7\x84\x10r\xff\xfe\x03\xce\xe1\u00c7}ee%\xe3\x0e\x1c8\xd8w\u07bc9w\r\x1b6\u20fb\xee\xba[\xe6\xe6\u62bd{\xf7*/\t\xe0W\x10\xfe\xfc\xb9n\xf8\xfb\xef\xbf\xdb\xea\xe5\x97_\x99\xbft\xe9\u0496Bh\xbc\xf2\u028bL\x9cx\x95\x97\xbd\xf2\x9ft\x02\x02\xaab6[U23\xe6\xaf\xe0\xc5\xdfM\xa0\xacp\a\x9dF\x8c\xe5\xf4\xbb\x9f')=\v'\\C\xcb$A\x93\x00\xec\xa8V\x14V+b&$*H\xd4\xdcE6\x9a_C\v\xb8\x82ET\xa2\xa2\x12,\xe9f\x95HE]B\x9e\x9b#\xae\x88\u064a\x98T\u023a\xd4\x17\x11\x9f\xbcT\x12)\x14\x9a\u03c7\x16L@\xf3\xf9\xb0c\xb5\xc4\"\x15\xc4j+\bW\x16SY\xbc\x9b\x9a\xb2}\xd4\x14\xef%r\xf8\x00\u044aR\xccp\r\xb6\x19E\u019bI+\xe5\x06\xf6\x15\xc4K\b\xb8\x8e^\xf7\x05\t&&\x93\xd0$\x83\xa4\xf4l\x92\u04f3Ii\x9aG\xe3\xb4<\x12\x933\t\x06S\b\x05\x1ac\xe8A\x1c\xd3\u008a\x85ql;\xbeJ\u050d\xe9\u0539w\x15\u03d0Q\x024C\xc7\b& \x84\x86\x15\xae\xa4\xb8p=\xdbW~I\u0476\u5517\xee!RS\x8eR2^`L\x1c\xb3}\x9a&\u0404@JG*%\xb5&M\xd28\xf1\xc4nj\xc0\x80\xfew\xdc{\xef}\x8f\xd7\x1d\xab\xfb\xef\xbf\xcf\xf8\xdd\xef~\xeb$'\xa7zN\xdds\xe6\xff[l\u0738\xf1\xe2\xc2\xc2\u0096\xb6\xed0d\xc8\x00\x86\r\x1b\x06\x80\xe3H\f\xc3[\xe9\xf9\x9f@\x01~C\u00e8\x8e\u04aa\xf3\x89t\x1dz\x16\xf3\xdf\xfc\v{V/\xa2t\xfb\x062\xb2\xb2\xc0/\b\u06cajKP\x1e\x83\x98\x03\xd2V\xf1\x15\x92n\xf8A\x85\x1d\xa4\x16?\x01[\n\xe1\xb81\v\xd5\xc0mK\xa9\xea#)\x86\xe1\xc6eL\xa9\u0710\x8cP(CG\x0f5\xc2\b\xf9\x89\x85\xab\xa8,\xd9N\xd5\xc1]\x1c\u07b9\x8e#{6pd\xcf\x16j\x8b\xf7aEkp,\xeb\u01e9\xb3%p\xcb\x05\x04\x13I\xcdjE\xd3\x16'\xd04\xa7\x13\xe9\xd9\xedHMoIJZ\v\x92R\u04f1b1\xa2\xd1p\u072d\x8b\xfaP\x90\x92\xee\x0fR9\u011cj\x84a`\xf8\x12h\u07a6\x1f\x99\u037bQQ\xbc\x8b\xa2\x1d+8\xb8\xb3\x80\xb2\x03[(/\xd9E\xa4\xb62^hL;f;t\xdd\xd0\x04\x8a\xf2\xf2\n\x16/^\"\xaa\xaa\xaa\x1e\x9b8\xf1\xf2\x93\a\r\x1a\xf4\xc8\xe5\x97O\\&\x84\xb0\xff\xf4\xa7{\xf9\xec\xb3O\xb4s\xce9W\n!\u0639s\x1b\xad[\xb7\xf3\x06\xb2'\xe6\xffy^y\xe5eq\xed\xb5\xd7)\xa5\x94\x187\xee\xc2\u02cf\x1cq\xb3(\xce8\xe3\fZ\xb4\xc8'\x1a\xadE\u05fd\x95\x9e\xffI1\xf7\xe9\x1a\x8d5\x8b\u018d\x1a\xd1i\xd0\b\n\xbe\xfa\x90\u0292\x03l_<\x936\xbd\ac\x18AJ\xc3\x11bRa\xd5\t\xb8\xed\u01b9\x95r\x85]\xd8\xf1\xec\x10#^|K\xa8\xfaKF7Y$\x9eQ\"@\xd7\xdc\xa2h\xc3jb5\xf1\xc6=\x9aARF\x16\xf9]{\xd1u\xf0H:u;\x89\xbc\xdc\x1c\xba\xb4\u0320u\x8aA\b\x00\x1b\xcb4\xb1l\xc7\x15\xbc\xffG=\xf5c\xbb\x11\x1d\xfd\xacuY%\xa0\xd0\x04\xfc\u007f\xec\x9dw|UU\xba\xfe\xbfk\x97\u04d2\x13\xd2h\xa1\x86^D@)\n\x88\xbd\x01\x96\xb1\x97k\x1d\xb1a\x1f\xcbXf\xece\xf4\u07b9\xe3X\xc6^\u007f\x8c]\xb0PT\x8a\x02\x82\bH'\xa1CBB \xbd\x9c\xba\xcb\xfa\xfd\xb1\xf7>I(\x8ewF$\xced}>\x87\x84\xe4$\xd9\xe7\ucd5e\xf5\xae\xe7}\xde\xe7\xd5T\x15M\xd7A\xe8H\xa02nR\xbc\xbb\x8a\xcdE%,]\xb6\x8c\x85\xb3f\xb2j\xf1Bj\xcb\u02fc\u07c0/\x10\"\xaf\xfbP\x0e\x1d}\x01}\x0f\x9f@Zf\a,\xd3&\x11\x8f8]\x93l\x13\xcb4\x90\xb6\x89\x94n\u027f[\xf4$\xa5\x8dD\xa2\xeb\x014M\xa5z\xd7fV-\xf8;\x9bV~I\xa4\xa1\nE\xf3\xa3*\x9a\xa3\x9dW\x85\xfb\xde\n\xa4\xb4\xedx<&\xc3\xe9ij~~w\x86\r;l\xe6]w\xde\xfe`~~\xef\xef\x00F\x1d9J\xfc\xfe\xee;\xe5\u99df\xd9:\xa9[#\xf3\x037\x16-Z\xc0\x91G\x8e\x01\xe0\x95W^>\xff\x89'\x9e8\xa4\xa1\xa1\x811cFs\xec\xb1\u01f0\xbf\xf6^\xad\u35cb\u03b3\xfd\x82\x8e\t\x83.}\x06\xd2}\xc8H\x8a\xd7\xfe@\xc9\xea%Tm\\OV\x87~(\x8a\xc3A;\x05\x94N\xc1\x8e\xd4@Z\xb8\x05C\x8e\u02e0/\xa8\xe0\xcf\xd0\xd13T\x046\x9a\xee#\x10T\xa9/\xaff\xf5\x17\x1f\xb2\xf4\xe37(Y\xb7\f3\xe1P)\xbeP\x98.\x87\x1c\xc6\xe0\xa3Of\xd4\xf1\xa7\u043bO\x1f\xdae\xa6\xd19\x03rT\b\xd8\x06\x981L[\xe2)\x19\u007f\xea\tn\xafNH\xce\x17\x9b}\u0352`%\r\x14a\xa0\nAn@#\xb7k;\x86vm\xc7o\xc6\f\xa5\xf2\xb7\x17\xb1rM\x01\xd3?\xff\x9c93g\xb2~\xdd\x1a\x12\xb1\x06\xb6\x15~K\u0676\x15\xac^\xf8\x1e\x83\x8e\xba\x88^\x87\x9eLZF{\x8cd\x8cD,\xd1\xe8\xb4h7z\xd1x\x1d\xed\x04\n\x86\x11\u01f6u\xb2;\xf6c\u0504\xdb\xc8\xcd\xeb\xcd\xea\x85\xefS\xb9k\v\xb6\xb4P\x15\x1d\xdbvr\x11\x8a\xa3\x84W\xfc\xfe \xd1XB\xae][(jjjOI&\x8c\xe3f\u0318v\u07a9\xa7\x8e\xffd\u1885\xb2\xbc\xbcB\x00\xf2\xb9\xe7\x9ec\u04a4I\xad\x13\xfb\xd7Fy\xfe\x1a.\xf2\xd5W_K}\u07b6m\xdb\x1b\n\n\n\x8e\xa8\xafo\xe0\xf4\xd3O\xe3\x82\v.r\xb4\xc3?\u04a0\xb7u\x1c\u0623\x9d\r\xf8\\\xaa\xa4\x16\x9d\xf2\xcaZ\xd6/\x9aM\xb4\xae\x86\xbc\u0783\xe9\xd4{\b\xa6ab\xdb\x0e I!\x90\x9a\xc0\xf6)\u062a+\xd3S\x05\xfe\x80B\u042f\xa2\xa9\xa0\x06T\x02\xe1 \u04b0\xd9\xf8\xedl\xbe\xf8\xcb},x\xebi\xaaK\xb6a[\x16\xbe\xb4\fz\x1fy\x1c\xa7^\xfd;.\xb9\xe3\x01N\x9fp\"c\xfav\xa4\u007f\xb6\x8f.\xbaA\x86L\xa2\xd9\u03bc0\xed\x03\xdd$\x8e\x94\xfb\xa2e\xd9H\xdb\x00\xdb@U \xcd\x1f\xa0g\xe7\xd2J\x12\xa9)#\x11m@(\x9a#\u007f\x942\xd5<[Q\x15!\x84\"kjk\xc5\u039dej\xf9\xee\xddg\xdes\xcf\xef\xd7|\xfc\xf1\x94\xf5\x9f~\xfa)\xd3gL\x17\x17_t1\bv\x99\xcf\x00\x00 \x00IDATO\xff\xf5if\u0398\xd9:\xc1[\xc1\xfc\xe7\x1dEE[\xf9\xdf\xff}\x1a)e\x9b\xbf\xfd\xed\xf9{\u05ed+\xe8\x18\x0e\x87\xe55\xd7\\-\x06\r:\x14\xcb2Z}X\x0e2\xa0\v\xc0\xa7\b\"\xb6N\xbd\b\xb2f\xfeWT\xef,\"\xb3}Wz\x1fq2\x96e9\xf2BM C\nvH%\x99\xa6`\xe9\n\xc2r\x8a\x88\xfc\x9a\x82\x8aDS5\xfc\x19!\xcawlf\xde\xcb\u007f\u2aff\xdeO\xc9\xdaeH\xdbB\xf1\a\xe9?\xf6\x14&\\{'\xe7\xdf|\x0f\xa3\x8e>\x82\x1e\xd9A\xfa\a-rE\x02\xd54\x1c\xe3*<;\x80\x83C=y\xc0nY\x06H\vE\x856\xe1\f\x8e\x18q\x18\xc7\x1cs\n9\xb9\xf9\xd4\xd4\xd4SV\xba\x1d\xcb2\xa8,\xdb\u0226U_\x11m\xa8\xa0MN\x17\xda\xe4vv]\x15\x8dT\u0751l${R\x04\xa9Db\xdb&RB\x9b\xb6]\xc9\xeby8\xe9m\xdaa&\"\xd4W\xef\xc42\x9dF\xd7N\x929E\xbb\bEQe}}\x83\xa8\xa8\xa8\xd0*+\xab\u03bc\xf9\xc6\x1b\xd7L\x9f1c\xfd\xe4\u0253\x99\xfa\xc9\x14q\xf9e\x97\xb7N\xecV0\xff\xf9\u01e0A\x87\xf0\xc9'\x9fq\xec\xb1c\xc7~\xf8\xe1\u01d7\x97\x94\x94\xa6\xf5\xea\xd5S\xdcr\xcb\xcd\xe4\xe6\xb6u\x16L\xeb8\xa8C\x02>\x15,\x14\xea\xf40k\x16\u007fK\xe9\x865\x04\xc2\x19\xf4\x1du\x12\xc1p\x1a\xaa_\"\xd2U\x94t\x15\xcb'0\x85@*\x02\xc5\x02\xdd\x06](\x04\x02!\x04\x925\xdfLa\xfa\xd3w\xb1j\xc6\xfb$c\x11\x00\xf2\x0f\x1b\xc3\xe97\xde\xc3\xf97\xdd\xcdQ\u01ce$7\x18 \xcd6\xc9S\x93d*f\x13?\x97\x83\x03\xe2\xfb}o\xa4t73\x03\x81Mvv:\u00c6\re\xe0!c\xc9\xca\xe9Bee\x05U\x95;1\x93qJ6/\xa5l\xfbJ\xd2\u04b3\xc8\xed\xd0\x1bE\xd3\xddJ\u0426\x15\xa5\xa4<\v<'I\xc7\xc2\xc2@\xf3\xa5\u046e\xeb :\xf7\x18B\x9b\x8cl\xea\xabJ\xa9\xafs\xc4\x02\x8a\xa2:\u0564Bq\xc4C\xaaB,\x1e\xb7*++}UUUgN\x9cxU\xe1\xec\u0673\v\xde}\xf7=\x1ex\xe8\x01q\xe7\x9dw1y\xf2\xe4\xd6\xc9\xdd\n\xe6?\xdf8\xf7\xdcs\xc5\xc7\x1fO!?\xbf\xc7y+W\xae<\xa3\xa2\xa2\x82\x91#Gr\xcd5\x13QU\r\xd3l\x05\xf3\x960\x14@U\x15\xaa-\x1f\x9b\xb6l\xa5\xe0\xdb\u0668\xbaN\x8f#\x8e!+\xbf;>\xbf\x81\xeeW\xb0qx\\\x81\xdb\xf4AJt\xa9\x92\x9e\u0786H\xed.\xe6\xbd\xfb\x14\xb3_\u007f\x88\x8a\xed\x1b\x01\bf\xb5\xe5\xc4\xcbo\xe4\xd2{\x1e\xe3\xb8S\x8f\xa3mZ\x10%\x91D\x97&\x1d|6\xed\xfd\xb6\xe3\xef\xf2\v!\xb8\xa2(h\x9a\x86\xae\xebh\x9a\xf7\xd0\xd045\xd5\xd1j\u007f'E\xdbv\"iU1\xe8\xd0>\x87C\a\x1fI\xbf\xfe#\xf1\xf9\xd2).\xdaB<\x1e\xa1\xbe\xba\x94\xe2\r\x8b0\x8d\x18\xb9\x1d\xfb\x11J\xcf\xc62\x93N\xe5g\xd3>\xd6{6\xb5\xb6\x9d\x1e\xa7\x96\x99$\x18\u03a5k\xcfat\xea\u069fD\xa4\x9a\xdd;7!m\x1bU\xd5R\xbdS\x05\x02EU\x95D\xc5o.\xbf\x8a\ue773Q\xa2\t|\xb6I\xa6.\xe9\x14\x90\xe4\xfa$\xaaH\u016d\at\xf8|>4\u034f\xaaj\b\xd7\xd9PJ\xdb}H\xb7\xb7\xa7\xe6\xf4+\xd5t4\xcd)\xe0\xd9\xef\xe2SM\xfc~\x83\xee\u077a2d\xe8\x18\xf2{\f\xa2\xbc|\x17\xa5\xa5[I\xc6\x1b\u0631y)uU\xc5d\xb7\xcf'\xabm7\xc7j\xc0\xb6HeB\x9bR/\x82Ta\x95\x94\x12#\x99\xc02mr:\xf6\xa4k\xfe`\xccX\x1de%\xeb1-\xd31\x1b\x13\x8d-\xedTUU\x12\u0244U]]\xed\xab\xaa\xae:\xf5\x81\a\x1e\xe8>\xe5\xe3\x8fg<\xf8\xe0\x83\xd6\u0529Sy\xe6\xd9g\u014c\xe9\xd3[\xe7w\v\x1f-^\u0372y\xf3\x06\u0473g\x1f)\xa5\f\x9dt\u0489\ud28b\x8bIK\v\xa9\x83\x06\rr#\x9d\xd6\xc4g\u02e1\x13@\x936m\x03\u042dG/\xd2s\xdaS\xbei-\x95E\x9b\x10@\xd4\x14\xc4-\a||\x8a@\x15\x92@z\x1a>\xbfB\xe1\x97\xd3\xf9\xea\xd9\xfb\xd9Q\xb8\u0519\x98iY\x9c}\xd9U\xfcv\xd2\rt\xcb\xefJ<\x9eD$\"\xa4\x05\x14\xc2\x1a\x844\x89.R\x01\xe9\x01\xa5H\xfc~?B8K\xa5\xba\xba\x82M\x9b6\xb3z\xf5j\xb6n\xddFEE\x05\x91H\x04]\xd7i\u06f6-\xf9\xf9\xdd\x190`\x00}\xfb\xf6\xa1]\xbbv\xf8|\x8e(2\xb1G1\x91t\x9b\\\xf8t\x81\xa64\x90\xdf\xddG\xe7\xff:\x8d\x11\xc3\a\xf1\xea\xab\xcf\xf1\xe6\x9b/\x90\x887\xb0\xee\xfbO\xa8\xad(b\xec\xe9w\x90?\xf0X\xe2\xf1(\x89D\xa4\x11\xc4]\x95K3^I\b\x14T,\u06e4\xa6\xa6\x92P\xb8#\xa3'\u0702/\x98\u0392\xf9\uf4ccG\xf1\aB\xa8\x8ak?\x8cDU55\x96HXK\x97\xfe\xa0J)/\xaf\xaa\xaa\n\x02\x17\x00\xdcx\xc3\r<\xf3\xec\xb3\xdcx\xc3\r\xad\x93\xbc\x15\xcc\xff\xf91g\xce\\\x01\xc8m\xdb6\xf7\x8dD\"=M\u04e4c\xc7\x0eb\xe0\xc0\x81\xad`\xde\xd2\xc0\x1c'!\x97\ud0ce\xedrh\u06f5\xa7\x03\xe6;\xb6QW\x17#j\xab$-\x13]\x11\x98\x96M(\x14\x00i\xb0x\xf2\xeb\xccy\xe91jv\x16\x03\u042d\xff\x10\xae\xbf\xedn~{\xe9y\xe4\xf8 a$0\x83NoO\x95\xc6f\x12\xf2\x00'8\x9d\x06\xd6\xe9\x80Ea\xe1Zf\xcc\xf8\x82\xa9S\xa7RX\xb8\x9e\xfa\xfa:\x12\x89d\xb3\xf9'\x84\xc0\xef\xf7\x93\x96\x16\"??\x9f\x13O<\x91q\xe3Ne\u0108a\xf8\xfd!\xe2\xf1H\xeayMA]QUTa\x11\xf0'\x181\xbc;C\x06?\u0148\xe1\x83x\xfc\xf1\xc7\u067c\xb9\x90\x92-\u02d9\xf6\xd6\xef8\xf6\xcc\xdfs\u0211\xe7\xa2(\x82x<\x82\xeb\xf4\xd2\xecd\x84\xe7\xad.\x1c\xe2K\u0692h\xb4\x81`(\x97#N\xb9\x01\u0757\u0192y\xef`\x1a\x06\xc2\xe7kTZJ\xd0\x14U5MS~\xf7\xdd\x12\x11i\x88\x9c\xff\xf0#\x8f\x88\xfb\xee\xbd\xf7b!\x84\u0675k\x17\x15\xb0\xa6L\x99\xc2o~\xf3\x9b\xd6\xc9\xdeJ\xb3\xfc\xdfG\u06f6m\xc5\xf2\xe5+d\u06f6m{~\xf7\xdd\xe2\v+++\xdbt\xef\u078dI\x93&\x89\xb4\xb4tL3\xd9z\x17[\x16\u04c2OU\xa9L\n\x96\xafX\u0156\x1f\x16\x92\x9e\u06d1\xbca\xc7!\x82\x19\x98\x96\x89%%\x81@\x00U\x1a\xcc\u007f\xe3\u007f\xf8\xea\xb9\ai\xa8*\a`\xf8\t\x13x\xe2\xcf\u007f\xe1\xca3O \xa4\x82iD\x11\xb6Ds)\x19\xb7\xc7\xc4\x01\x05q\xaf\xf9F \x90\u01ae]\xa5\xbc\xf8\xe2K\xdcw\xdf\x1fx\xf7\xdd\xf7\u063au+\x91H\x04\u06f6\xf1\xf9|4iE\xdaX\xfa\x1f\x8bQZ\xba\x93\x05\v\x160e\xcaTv\xec(\xa1G\x8fnt\xec\xd8\x19!\xc0r{\x95\xee\x19\xa9;\x15\xa8&>\x9f\xcea\x87\r\xe6\xb0\u00c6\xb3~\xc3V\x8a\x8b\xb7\x92\x885P\xbc\xf1;\xd2\xc3Yt\xee1\x14E\u0571,3\xf5\xa6\xefS\x13/\x1b?1M\x03\u0557F\xe7\xfcCQ\x05\xec,ZC\xd2H8\xfe.\x1eG\x83@(\x8a\x90H\xb9{W\xb9\xa8\xae\xae\x1eX^Q\xdeo\xf6\xacYS\xfb\xf5\xebg\u03593G\x1d7n\\\xabl\xac52\xff\xe7F8\x1cV\x00[Q\u0120\xf4\xf4\xb4.\x00\x9d:u\x12\xa1P\xa8\xf5\xee\xb5\xd0\xe8\\`\x93\x1d\xd2\xe9\u0439\v\xa0PWUNmu%9\xb9\x9d\x90R\x12Ho\x83\x99\xa8g\xce\x1bO0\xef\xf5\xff\xc1t\xbdT\x8e=\xe7\x12\x9ex\xe21F\xf4\xec\f\x18$\x13\xc6>[\xc7\x1dX\xaaH\xba\xc9L?\x8b\x17/\xe2\x91G\x1ee\xe6\xcc/R\x1e\u22a2 \xa5t\xf9s\r\xd3\xf5?Q\x145U5\xea\xd9\x02H)\xa9\xa9\xa9\xe1\x85\x17^d\u039c9<\xf6\u0623\x9c}\xf69\xa8\xaaJ<\x1e\xdf/\xa0'\x12Q4Me\u0318\x91<\xfb\xcc\v<\xf0\xe0\xc3|\xfe\xf9;D\x1bj\x98\xf5\xc1#\u0636\u0270\xe3~\x8b\xaa\xa84D\xebphtoW\x91\xcd{\xeb5\":\xf1D\x84\x80?\u0110\xa3/\u00d6\x92\xef\xe7\xbeE\"\x1e\xc5\xe7\x0f9\x85Tnd\xaf\xaa\x9a\xb0\xb1\xe4\xbau\x05B\xd5\xd4\xf3\xc2\x19\x19H)/\x11B$g\u03de\xad&M\xd3:\xf5\xe4\x93['{kd\xfe\u007f\x1b\xfd\xfb\xf7UV\xacXi\x0f\x1c8p\xdc\xe6\xcd[\x8e\u077d{\xb7y\xdcq\u01ea\xa7\x9d6\x01U\xd5Ze\x89-qR)\x02C\xd5X\xb1a;\x8b\xbf\xfa\x1cEQ\xc8?\xf2D\xb2\xba\xf6D\xd5|\b\xcb`\xd1\xcb\x0f\xf3\xed\xebO9v\xb4B\u5b097\xf1\xa7?=\xcea\xdd\xdac\x9bq\x92\xc6/\x9f\xd4\xf6\xf8qU\xf51s\xe64n\xbc\xf1&\x16,\xf86\x05\xe2\x9e\u007f\v\x80i\x9a$\x93\xc9\x14h{\tPUUS\x80\xdfT\xd1RYY\xc5\xe7\x9fO#++\x93\xe1\u00c7\xa3\xaa\xaa\xbb\x11\x88\xfdP<\x12)M:uj\xcf\xe0\xc1G\x11\x8dI\n\nV\x10\x8f\xd5S\xbcy\x19i\xe9\x99t\xeb3\x02M\u04f0\\\x9d9{)hd\xaai\x87\x87\xeb\x96e\xa0\xeaA:v\x1d\x88\"MJ\xb7\xaf\xc60\x92NR\xd7;\xfdH\x10\x8a\"\x84\xa2\xc8]e\xbbD}]\xdd@\xa1\xd0y\ua529\x9f\xbc\xf5\xd6[R(\xaax\xe0\x81\ax\xef\xbd\xf7Z'{+\x98\xff\xf4\u0467O\x1fu\xed\xdau\xb6\xdf\xef\x1fQZZzb}}\xbd\x9c0a\xbcr\xdcq\xc7\"\x84lU\xb2\xb4@\x9aE\x11 u\x8dU[\xcaX0}\nf,B\xaf#O\xa0\xeb\xd0C0c&\u07ff\xf1\x14\u07fd\xf6\x84\xa3\x9fV}\\t\xe3\x1d<\xfa\xd0\xfd\xf4o\x1f\xc6H\u01b0\xec\x83s\x92\xd7u\x1dE\u04595\xebKn\xbc\xf1f\n\n\n\xc9\xcc\xcc\xc4\xef\xf7\x13\x8f\u01db\x81s\xd3(\xbd\x11\x80\xed\x94U\xc0\x9e\xf3RQ\x14\x92\xc9$\xb3f\u0362]\xbb\xb6\f\x1b6\u048d\xec\x8d\xfd\x02\xba\x94`\xdbI\xb2s2\xe9\xdb\xef\b\xa4\xf4\xb3b\xc5w$bu\x14m\\JFf[\xba\xf7\x19\x01B`Zf3,oz]\"\xa5g\u013d6\x03\xcd\x17\xa2C\xb7C\xc0JPV\xbc\x163\x99L\x9d.\x9a \x10\f\xa1\xea:F\xb4\x1e;\x11!\xe0\x83\x95\xef?\xcf\u04b7\xfe\x1b\xcbH\x82\xaas\u044dw\xf0\xf0\x03\u007f\xa0WN\x90x,\xc2A\xc2q7\xaa\xf6\xb1aC!w\xdf}\x0f\x1b6l$\x1cN\xa7G\x8f|\xc2\xe1\xf4\xbd\x12\xed\xd9\xd9\u0664\xa7\xa7\xa7~\xb6\x11(-L\xd3\xdc\u06e4\xcb\xe5\xe1\x93\xc9$\xbf\xff\xfd=\u03181\rP\xd0u\xfd\x1f\x9c\x16\x04\xc8\b]\xbb\x84\xb8\xe6\x9a[\xf8\xedUw\xa3\a\u04895T\xf2\xe5\xfb\x0f\xb3z\xf1T\xc2\xe9Y\xa4\x87\xd2\xd1u\xdd1\xd9J\xa9\xf8\xd9\xef&\x11\x8fGA\vq\xf8qW0\xec\xe8\vP5\x95d\"\x86e\xd9)\xf0O9\t\b!\x97|\xbf\x94\u0253\xdfy\xe4\xed\u0253\xcf\x03X\xb3z\x85\xfc\u04df\x9e\x14\x85\x1b6\xb4N\xf7V0\xff\xc7c\u04e6M*`I);\x1fr\xc8\xc0\xe3\xea\xeb\xeb\xd0u]\xe4\xe4d\xe3T\xbd\xb5*YZ\x1e\x8c;\xc5;\x01 '\u034f\xe2v\xc41j*X\xf3\xf1T\xbe}\xe9\x11\xe2\xf55\b\xdd\u03f97\xdc\u0243\x0f=@\x8f\xcc F\"\xbeW\x03\xe3_r\xf8|~\xa2\xd1z\x1ey\xe4Q\x96.]\x86\xcf\xe7#++\x9b\xea\xeaj\x8a\x8a\x8a\xf7z~CC=\x86\x91\xdc+\n\xb6m{\xafy)\x84H\x15\x13\x01\xd4\xd4\xd4p\xd7]\xbf\xa7\xb8x\x1b\xaa\xea\xfb\t&q\x82\xa0?N~\xf7 \xd7]w+\xd7^s\x1f\x81`\x98\xba\xea\x9d\xcc\xfc\xfb\x1f\u0670\xf2KBi\x19\xa4\x05\xd3\xf0i:\x9a\xaa!\x14\a\xd0=P\xf7\xca\xf9\x9b\x02z\"\x1eE\rf1\xe2\xe4\xab9\xfc\xd8\v\xd0\xfd\x01,\xd3\xc0\xf6\x1a`\v\xc5K\xae\x8ah,\xce\u04a5\u02d4\x8f?\x9e\xfa\u03b4\xe9\xd3\u007f\x030c\xfa4\xa9\xbb\xcd`J\xcbv\xb6N\xfe\x83=J\xe7N~\xae\xbcr\x12\x91H=o\xbe\xf1\x14\x95\xbb\xb60c\xf2}\x9c}\u074bt\xea>\x04a[\u0130\x91\xb6\x8d\xad\xe0\xf6\vu\xb4\u4379P\x91re\x8cE\x1b\b\xa5\xb7a\u0109\x13\xc1\x96\xacX0\x05\xcb4\x10\x9a\xee\xde\x11\x05\x90h\xba.kj\xeb\xc5\xf7\xdf\u007f\xafdee\xbe\xbbf\xed\xdas\x0f\x198\xf0\u04de={\xb5v-j\x05\xf3\u007f<\xaa\xaa\xaa\xbcO\x8d\x86\x86\x86$8\xf6\xa5>_\xa0\x15\xcc[\xf0\xf0\xa0-S\x93\xe0&\xa8\xb7.[\x90\x02\xbd\x11\xa7\x9e\xc5\xed\xf7=\xc0\x90v\x01l3\x86y\x90o\xa3\xae\xeb\xd4\xd6V\xf1\xfe\xfb\xefS[[K\x9b6\x19\b!\xd04\x95+\xaf\xbc\x82\x1bo\x9cD\x8f\x1e\xbd\x9bD\xdf\x06_~\xf9%\x8f=\xf6\x04\xdf~\xbb\x10UU\xb1,\xa7C\xa9\xa7\x86\xf1d\x8a\x9e\xc2\u0176m\xd2\xd2B\xa8\xaaB$\xe2\x14\x10\xbd\xfb\xee{\\~\xf9e\xf4\xeb7`\x9f\xfe\xe9\xcd\xdeS\x1b\x14\x05B\xc18\xf9\xddC\\w\xedmTW\x973\u58d7(\u0776\x8a\xd9\x1f<\u0339\u05fdB \xad\r\xa6i`\xa9\x16\xa6\xe54\xbd\x964\xa9P\xa5\x89\xf2\xc5\x05\xf5x\xa4\x81P8\x8b\x91']\x8d\xb4,V,\x9a\x8ai&Q\x15\xcd\xdd\xe8\x1c\xe3\x05]\xd7eyy\x85\xf8\xe6\x9by\xbe\x8cp\xf8\xb5\xfa\xfa\xfa\x13\xc3\xe1\xf0r!D\x13O\x81\xd6\xd1J\xb3\xecc4\x8dVL\xd3LE8\x9a\xd6\xda\xe7\xb3eG\xe6\xce\xc7t\x1d|\xba\x9a\xa2\x1f\x00\xfa\x1d6\x92\xbb\xfe\xf8\x00\xa3{d\xa1\x99qLK\x1e\xe4k\x95\x80\xca7\xdf\xccc\u0672\xe5\xf8|:\xa1P\b\u02f28\xed\xb4\xf1<\xfe\xf8\xa3\xf4\xe8\xd1\x1b\xdb6\xb0m\x03\xcbJ\xa2(\n\xa7\x9c2\x9e\xc7\x1e{\x94~\xfd\xfa\xb8\xba\xf1\xc6\xdf\xe9\xa9^\xf6\xe4\xd2\x13\x89d3\xcae\xfb\xf6\xed|\xf8\xe1\x87xA\xca?\xdc$m\x87\xfe\b\xf8c\xf4\xef\x9f\u036d\xb7\xde\xc3\xf0\x11'\x00\xb0n\xe9t\xbe\xfb\xeaE\x14EC\xf7\x05\xf1i*\xba\xab\xac\xf1\xeco\xc1\x05w)\x91\xee\xc6#\xa5\xd3X:\x1ai@\x0fd1\xf2\xe4\xab\x198|\x1cB\x82i$\x1b7\x18\x97?\xf7\xf9\xfc\x94\x96\ucd27M\x9f\x91\xf3\xd0#\x8f\xbe!\xa5\xec\x04\xc8W^{\xad\xb5\xcdW+\x98\xef\u007f$\x93F\x93\x89\u072aZ\xf9\xb5\x8d\xdc\xecl\xb7\u035a3\xdaw\xcc\xe3\xc1\a\xefg\xc2\x11\x83\xf0[IL\xcb>\xe8\xe1\x9c\a\xac\xdf}\xf7\x1d\xa5\xa5\xa5\x84\xc3a\x84P\xc8\xcb\xeb\u0239\xe7\x9eC \x90F<\x1e\xc10\f\f\xc3\xc04M\x12\x89\x04\xb6m0f\xccXN>\xf9\x14\xb7xho\xde|O\xaa%\x99Lb\x18f\xb3\xa4\xe7\x9c9s\x89\xc5\x1a~r\xc3\f\xe9\xf2\u067a\x16a\xe4\x88n<\xf0\xc0\xe3t\xeb\xd6\a\x80\xf9\u04dee\u00ca/\b\x04\u00e8\xaa\x8a\xae*\u8aa3\xbaAx}Mid\xd2]\x91\x8b\rH\xcb\x01\xf4@(\x97Q\xa7\\G\xff\xc3N\u0136\r\x92\u0244\xdb|Z\xa4\x1e\xbaO\x17%;J\xf8\xfc\xf3\xcf\x0f}\xf4\xf1\xc7\u07d6R\xe6^u\xe5\x95\xd6\v/\xbe\xa4\xae\u07f0\xbeu\u2dc2\xf9>8 M\xdbk\xd1Ii\xbbG\xda\xd6\xd1b'\x95\x17y\x16\x15QSS\xedF\x9e\nw\xdd\xf9;\u039bp*\x8a\x11\xc30\x8c\x83\x0e\xe4RJt]g\xf7\ue76c[\xb7\x0e\x80\x9c\x9c\\\x84\x10t\xed\u0695\xbe}\xfb\x02\xd6>\xf9`Oz8l\xd8\xe18\t\xf9\xc6!\xd2\xd3\xd3R\x9f\xfb|\xbe\xd4\x02\xf4\x16Rk\u04a5e\x0e]\x0f\x10\x8fG\xf8\xdf\xff\xfdKJ\tr\xf1\xc5\x17s\xd5o\xafDJ\x93\xa4a\xee\xd5~\xed`\x81\xb9\x10\x1aEE\xc5\x14\x15\x15\xe3\xf7\xfb\xc8\xca\xca\xc40\x1c*%\x18\f\xfd\x03z\xc6I\x94\x06\x83\xc1\xbd\xc0\xdc)\x1e\x12\xfb\xa0J\xec\x14e\bN\x92\u007f\xed\u06b5\xff\x14\x95\xe5\x045&\x97^r6\xb7\xdcz+\x00[\n\xe6\xb3\xf4\xeb\xb7P\x14\x15Us\xfa\xa6j\x8a@W\x9c\x9e\xa7\u04b3Vt\xd5-.{\x92\xb2I\xb0%D#u\x84s\xbar\xd4i7\x92\xdfo$\x96\x11\xc34\f\xa7\x85\x9d\x10^\xf7\"\xa1\xea\xba\\\xb1b%_}5\xeb\u0799_|1\x11`\xd6W_\xc8{\xef\xfdC\xeb\xc2l\x05\xf3=\x8e\xe9\xb99)|\b\x87\xc3>\x00\u04f4\x88\u0162\xadw\xae\x85\x9f\xa6^{\xed\xf5\x942d\u0630\u00f9\xfb\xee\xbb\b\x873\x89\xc7\xe3?\x99R\xf8\xa5\u01ae]\xbb\xa8\xa8\xa8@UU6m\xda\xc4\xee\xdd\xe5l\u0672\x95\xd2\xd2\x12@\xfdQ\t\xec\xb6m\u06e8\xaf\xaf\xdf\v\xe8\x1d\xaaE6\xfbZ\xd32\u007f\x0f\xf4\xe3\xf18;v\xec\xf8\xa7\xaf=\x99t\xe4\x91w\xdc~\vc\x8f>\x11\x80\u0173_g\xcb\u06af\xf1\xf9\u04f0\u0756q\xaa\x10(\u00a1X$`#\xdd*\xd3\xc6k\xf3\x14.\x96m\x13\x8b6\x90\u04f9?\u01de};]{\rs\xbay\xe16\x96\x16\x8a#}\x14\x8a0-\x8b\x1f~X\xc1\xab\xaf\xbd\xfe\u0127\x9f}:\x02\xe0\xd5W^\x96\x0f=\xfcH\xebbh\x05\xf3\u0191\x93\x93\u3b46J\u02f2w\uae8ei\x9a\xb2\xb6\xb6\xae\xd9q\xbeu\xb4\x8c\u0474\xf0\u6957^\xc60\f22\xc2\\\u007f\xfdu\xf4\xeb7\x10\u00c8\xb7\xa8{\xe6\x81jmm\x1d\x91H\x14\u06f6\xa9\xact\x14Tk\u05ac\xe1\xddw\xdf\al\x02\x81@\xb3\x8aN\xc7d+H}}\rs\xe6|MUU\xf5>\xc1\xfc\xc7\xd4){&G\xe1\x9f;\xac8\x11z\x82\xcc\xcc,n\xbb\xf5v22r\x89\u0515\xb3\xe4\xeb7\x89\xd6W\xa2\xfb\x82\xce\xc6\xe2\xd4\xe6:\u007fW\x8af\u0562\x8e\x0eG`#\\\xf5\x8b\xc02M\"\r\xf5\xb4\xebv(\u01ddu\v\x1d\xbb\xf4\xc30\x12\xa9&\u04e2Io\u044a\xca*f\u035a\x93\xfd\xdcs/L\x9e:uj\x1f\x80?\xfe\xe1>~\u007f\xf7\u077c\xfc\xca\u02ed\v\xa3\x15\xcca\xc0\x80Av\x87\x0e\xed5!DUaa\xe1\xa2p8\x8ca\x18\xb2\xa6\xa6\u0199~-\x98f\xf18S\xaf+\x8d\xcf\xe7K=4MsU\x06\xe2\u07ca*\xf2\"\xeeW_}\x95\x95+W\x010~\xfcx.\xbc\xf0\x02\xa0\xe5Z/4m0\xd1(\u0143g\x9f}\x8e\x97_~\x19!4B\xa10\xba\xae\xa3\xeb\xbak\x8bk\xf2\xec\xb3\xcf3\u007f\xfe\xfc}\x82vS^|_\xf7\xb8\xa9\x14\u0463i\xfeY\xa5\xadC\xdbH\x8e?\xe1x.\xbc\xf8*\x00\n\x96\xcd`\xcb\u06b9h\xba\x0f\u02d68i&\x97\xcbW\x1a#t\xefO\xca&\x9b\x83m;t\x8biZD\"\xf5t\xea3\x82c\u03fc\x91\x9c\xdcN\x18F\x1c[\u068dQ=\xa0\ubeac\xad\xad\xe3\u06c5\x8bz\xbd\xf0\xe2K\x1f\xaf]\xbb\xba7\xc0\x13\x8f?\u0395W\\\u054a\xb2\xad`\xeeL\xf8\x11#F\x00\u0436m[\xdb+\x9f./\xaf\xc0\xb6M\xa7B\xad\x05\x02\x9a\xdf\xef\xc7\xe7\v\xe2\xf3\x05\xd1\xf5\x00RJ\xea\xeb\uba69\xa9\xa1\xa1\xa1\xc1Q#\xe8\x81\xd4s|>\u07ef\xfe\x94!\xa5DU},\\\xb8\x80\x8f>\x9a\x02@\xe7\u039d\x988\xf1*\x02\x814\x92\xc9x\x8b\u0778\x02\x81\x00>\x9f\xaf\xc9\xe6\xea\x00qmm-\xf7\xdcs/w\xdf}\x17\v\x17.\xa0\xaa\xaa\x8a\x9a\x9a\x1a\xbe\xff~\x11w\xddu\x0f\u007f\xfb\xdb\vMk!\xf6\xe1\x82(\x9b}\xdcWd\xee\xf7\xfb\xc9\xce\xce\xf9WW\n\x86\x11#=M\xe5\xa2\v/\xa5g\xaf!\u0636\u024ao\u07e7\xb6\xb2\x04\u055f\xe6F\u070d\xcfol9\xd7\u0737E\xba\x91\xba-A\xda`\x99&\r\xd1(]\xfa\x8fe\u0538\xab\t\xa5g\x92\x88G\x9a\x9c<\x04B(\xc2\xef\x0f\u0206\x86\b\xdf-\xfe~\xe0S\xff\xfd\xbfS\xa4\x94}\x00~\xff\xfb\xbbZ\xf9\xf3_\x8a\xe2l\xc9\x17\xb7sg\t\xf7\xde{\x1f\x00\xfd\xfb\xf7\xd7JJJ(**\x92\xa5\xa5\xa5\x98\xa6\xe3\xfb\xdcbvEEA\u05ddb&\u00c8\xb3z\xf5r\xbe\xff\xfe{6l\xd8\xc8\xee\u077b\x89D\"\x98\xa6\x85\xaek\x84\xc3a\xf2\xf2:1p`\u007f\x86\x0f\x1fN\u07fe}\u071f\x95$\x93\xf1_]1\x94\xa7\n\xb1m\x83\u0253\xdfa\xf3\xe6\xcd\x00\x9cs\xce\xd9\x1c{\xec1\x80\xd5\"_\x93\a\xa8YY\x99dddP[[\x8b\xa6\xa9)\u0149\xa2(TTT\xf2\xc4\x13O\xf2\xe1\x87\x1f\u04ff\u007f\u007f\x82\xc1\x00\x9b7oa\u02d6-\x18\x86\xe1\xf4\x1eu9\xf5\xa6\\\xf8\xfe@|\xcf\u0476m[\xbaw\xef\xf63\xdc\x03H$\x1a\x18:\xa4?\xe7\x9d\u007f%\x8f?z\x13[\n\u6ce5\xf0[\xfa\r\xff\x8d\xd3+\xd7J\xba\u0478H\xb5\x99s\xaeQ\xa6\xe8\x16\\\x80\xb6\x05(R`\xdb`\x1a\x06q\x04}\x87M \x11\xade\ue53f\x92\x8cG\xf1\x05B\xde\x1b\x89\x00\x11\f\x86dMM=\xb3g\xcf\x1dx\xdf\x1f\xfe\xf0\xb6\x94\xf2\f!D\u0663\x8f=\xae\xa4\xa5\x85\xec[n\xbe\xb9\x15q\xffS\xc1\xbcc\xc7N\\w\xdd5\x12 ##\xbc\u057b\u6492\x12\x99L&\x85\u05d2\xeb`\x03\x99\xd7V,\x99\x8c\xf1\xd5W\xb3\x98<\xf9\xef,_\xbe\x82\xb2\xb2\x9d\xd4\xd4\xd4\xee\x17Hrrr\xe8\xd4)\x8f\x11#\x86s\u99572f\xccQ\xf8|AW\u07db\xfc\xd5P0\x8e[\xa0\x8fo\xbe\x99\xcb\xf4\xe9\xd3\x00\xe8\u07bd\x1bW^y\x05\xa0b\x181Z\xf6<\u02e3}\xfb\xf6l\u0672\x856m21\x8c\x9a\x94V\xdc;1m\u06b4\x89M\x9b6\xb9^\xe7\x0eMf\x9a&\xa6i\xeds\x83h\n\xec{\x82\xba'S\x04h\u07fe\x1d\u077a\xfd<`\xee\x9c2l&L8\x9d/f~\xcc\x0f\u02fef\xed\xe2)t\xe97\x96P\xb8-V\xd4Db\xbb\x8d4\x1acq\xdbkL\xd4\u060c\u03b5\x10\xb0Ql\x81\xb0\xc10\x12(\"\xc0\xa0\xa3\u03a3\xben7\xdf}\xf16\xa6\x91@\xd7\xfd\xc8T\xb0/DZZ\x9a,.)\x95\x9f~\xfa\xf9\b\u02f4\xee\a\xae\xbb\xf7\x9e\xbbm\x80\x0f>\xfa\x88s\xcf>\xbb\x15u\xff\x13i\x16wQH\x80\xcc\xcc\u0302d\xd2\xd8\x04\xb0c\xc7\x0e\xdb\xe1\xcd\x0f\xae<\u0476mt]G\b\x95\u014b\x17q\xc5\x15Wr\xd9eW\xf0\xce;\xefRXXHMM-\xaa\xaa\xee\xa57\xf6\x16{EE\x05+W\xae\xe2\xe5\x97_\xe5\x82\v.\xe4\xfa\xeb\xafc\u035a\x95(\x8a\xeeF\xba-_O\xefE\xe5\xa6\x19g\xea\u0529l\u06f6\x1d\x80\v/\xbc\x90A\x83\x86\x00\xcdU\x1d--27\xcd\x04=z\xe4\u04f7o_l\xdbIv6-\xea\xf1\x80\xd8\xcbqx\xd2\xc2h4\x9aR\x92\xec\xeb=\xf9\xb1\xb9\xa9\xaa\x8d\n\x99\u07bd{\u04ebWO\xa44\u007f\x96\xe5l\xdbQ\x86\f\xe9\xc6Yg_\x8a\xaa\xeal-\xfc\x96\xe2\r\v\x9d\xe8Y\xd3\x1dO\x00!\x90BA\xba2C\xa1\xb8\x92\u0166f\\\x12\x90\"E\xb7H\x04\xc9d\x02\u0157\xc6\x11\xe3&r\xe8\x91\u3476\x85\u0133\th,E\xf2\xfb\xfc\xac+X\xcf\xf4\x193\xaf\xbd\xe1\u019b\x9e\xf2\xae\xee\u0733\xcfn\xb5\xe0\xf8O\x06\xf3\x13Np\u0295o\xba\xe9\x96h\xbbvmc\xe0\xb8\xce\x15\x15\x15\x1dT0\xf7\"r\u06f6y\xf9\u55f8\xe4\x92\xcb\xf8\xfb\xdf\u07e5\xb2\xb2\xb2\x19X\xec+\u0269\xaa\xaacW\xea\x96[\x03\x94\x94\x94\U000b7ffd\xc8\xc5\x17_\xc2G\x1f}\xe0r\xef\xbe\x16\x0f\xe8\x96e\xa1\xeb\x01\x96/_\xc1\xb4iN\a\xf7\xfc\xfc\xee\x9cw\u07b9\x00$\x93\x89\x16{\xedB\b,\xcb\xc2\xef\x0f1t\xe8P\xc2\xe10\xb1Xt/\xe9dSu\u029e:\xf1\xfd\x01\xb9\xe7w\xbe/:\xce{NFF\x06#G\x8e\xc4\xe7\v\xfel\xc9a\xa7:\xd4b\xfc\xb8\xf1\f\x1b~\f\xb6e\xb2a\xf9t\f#\x86\xa6\xfb\x11( \x14\x84\ua078\u04b8\x8e\x14\a\xd0e\x93\xe8\x1c\xc0\xb2%\xa6ec\xd96\x91\xfaz\xb4`\x16\xa3\u03f8\x8e\xfc~\xc3H\xc6\x1be\xc2\x12/w\xa2\n\xa1(r\xe3\xa6-,Y\xba\xec\xf6?\xfe\xf1\xfe?\xed\x19\u0334\x8e\xff@0\x1f=\xfaH\xe9N\x82\x02\x9fO\xdf\x10\n\x05\xa9\xa9\xa9\xb5\v\n\nS\x8b\xe3`\x8c@ \r\xd34y\xea\xa9\xff\xe1\xb6\xdbng\xe3\u018d\xfb\\\u0626i\xa6\x00\xd9+&\xf1>\x06\x83\x01\xfc~\u007fJ%\xa1\xaa\x1a\xabV\xad\xe6\x86\x1bn\xe4\x85\x17^\x04\x04>\x9f\xbfEG3\x8e\xae\xdcb\xee\u072f\u0678q\x13\x00\xa7\x9dv\x1a\xfd\xfb\xf7k\x06n-}\x1c\u007f\xfc\xb1\xf4\xe9\u04d7\xba\xba:TUiv\x0f\xffQ\xa4\xbd\u03c5\x95\xaaX\x96\xfb\x05\xf3\xee\u077bs\xe2\x89'\xa4Ny?O\x90!@&\xe9\u07ff\x1d\xa7\x9c\xea4^\u07b6~\x11\x15%\x85\bE\x03UE\xb8\u0560RU\x9c\xc2SE8\x0f\x0f\u061b\x81\xb3\xb7\x99\x81e\x83mY4\xd4\u0551\u046e\a\u01dc=\x89\xdc\x0e]\x88\xc7\"N\xc4\xdf\xe4\x87uM\x17I\u00d4\xeb\xd6\x15\xf0\xfd\x92\xa5wN\xfe\xfb\xe4\u06fck|\xfeo\u007fkE\xf4\xffD0\xef\u0631\x8b|\u5557\x04@\x9f>}k;w\xeeB\"\x91\xb0=\xe9\xdb\xc1(@\xf1\xfb\x9dD\xe73\xcf<\u01e3\x8f>FCC\xc3O\x8e\x9aTUu9W\a\xa8u]G\xd34TUC\xd75\xfc~?ee\xbb\xb8\xf7\xde?\xf0\xf6\u06d3QU\x1d\xbf\xbf\xe5\x02\xba\xdf\x1f\xa2\xb8\xb8\x98\xcf?w\xb8\xf2\xcc\xccL&L\x18\x87\xdf\x1f\"\x99\x8c\xfd*\x16\x81e%\xe9\xd7o '\x9exB\xaa\x9d\x9b\xdf\xef\xdf\xe7\xe6\xdc\xf4\xb4\xf5cN\x87^\xe9\xfe\x9e\xf7\xdf;\xcd\b\x01'\x9ex\x02\x03\a\x0e\xe0gO\x10K\x89\xdf'9\xef\xdc3\xe9?`(\xf1\x86j6,\x9f\x81P\x15\x14UsA[`\xab\x02\u02efb\xeb*R\x15HE \xf7B\x04\x99\x92\xb8XR:\xc9S)i\xa8\xaf\xa5c\x9f\xe1\x1cu\xfaU\x84B\xe9\xa9NE4\xb1\v\xf0\u9e88\xc5\xe2,]\xf6\x03\x9f|\xf2\xd9\xfd\x8b\x16-<\n\xe0\xfa\ubb93\x1f\xb8\x06c-y\xac_\xbf\xee_\xfc\xf9\x82V0\xdfs\xec\u0631C\x02t\xed\xdau\x99\xa2(\x12\xf0\x17\x16\x16\x12\x8d6\xfc\xe2/\xc1\x89D\x15>\xfdt\nO>\xf9$\xd1h\x94\xb4\xb4\xb4\xbd\x9ew\xf2\xc9'q\xc7\x1d\xb73q\xe2U\xa9\x04\x97\x97PSU\x15)!\x1a\x8d\x12\x8b\xc5\xdc^\x92V*r\v\x04\x02TUU\xf1\xf0\xc3\x0f3o\xde\\\x84\u041a\xf9\u0534\x98H\xc0\x8d\xc6V\xacX\xc9\x0f?,\a`\xec\u06238\xf4\xd0C\x01\xfbW\x13\x95{\xa0{\xc5\x15\x971d\xc8\x10b\xb18\xc1`\xe0'\x95\xf3\xefo\xd3\xdeW\xa4\xdd\xe8^\b\x03\a\x0e\xe4\xca+/\xc7I\x10\xff\xbc}l\x1d\x9e\xdbd@\xff\x8e\x9c~\xfa\x04\x00\xb6\xae[@\xbc\xa1\x12U\xd7A\x11)\x9e\xdb\xd6\x15\x8c\xa0\x82\xa9\v,\r\xa4\xe2x\xa7\xbbt:\u04a3]\\Su\xcb+*\xb2m\x1a\xa2\t\xfa\x8f9\x8da\u01df\x8em\x19\u0636\xebc\xd3D_\xafi\x1a\xd5\xd55|\xbbpQ\u01bb\xef}\xf0\xb6\x94r(\xc0\xb9\xe7\x9c\xd3\"\xe6\xc7\u018d\x85\xfb\xfd^\u07fe\x03\xfe\xa5\xdf\u0777o\xff\xbd\xbe\xb6e\xcb\xc6\x03\x87M\xbf\x86\xc56d\xc8`\x00\xce>\xfb\xcc\xd5\x1f~\xf8\xe1.\xa0CQQ1\x1b7n`\xf0\xe0\xc3\xfe\xa1\x17\xf4\xcf\u0271\xaa\xaa\x8f\xe2\xe2\xed\xfc\xf9\xcf\u007fa\xf7\xeerrrr\xc8\xcd\xcda\xfb\xf6b\f#\xc9\xd1G\x8f\xe5\x96[nf\u0528#\xc9\xce\xce&\x91HPPP\xc0\x9f\xff\xfc\x17\xfe\xfe\xf7wH&\x13dffb\x18&\xf5\xf5\xf5\xa9\xeb\xb6,\vEQ\xf0\xf9\xf4\x94V}\xf3\xe6-<\xf1\u0113\f\x192\x84\x8c\x8c,,\xabe\xd9\x18\xe8z\x80X\xac\x81\u0673g\x13\x89D\x00'\xdal\xdf>\x8fX\xac\xe1W\xa3\x9dw\xfc~\x92\xf4\xee\u074f\x9bo\xbe\x89k\xaf\xbd\xce\xf55w|Z\xf6\xe4\u021b\xea\u01fd\xc20E\x11n\xbb\xb8\x1f{\xbf4\f#Izz\x1a\x93&Mb\xc0\x80AHi\x1e\x90\xbc\x88\xe1Jw/\xba\xf0l^}\xe9\x19\u028b\v\u0639u\x19=\x0e\x1bO\xd2H\x80\x90\b\t\u00b2As\xa3r\x01\x12\x05M\u06a9\x86\x18 \x91\xb6\xa7F\x97\u062e\\Q\x95\x02#\x99\xc0\fe0\xea7WP\xb6\xbd\x90\xf5\u02d7\x12\b\xa55\xd9\t\x9c\nQM\xd3)/\xaf\xb4\xe6\xcc\xfd\xba\xdb\x1f\xfex\xff\x93R\xcaqB\b\xe3\x8c3~sP|\u043f\xfcr\xa68\xe9\xa4S$@\xef\xde\xfd\xfe\xd1\xdc\u040b\x8b\xb7\x1d\xbbl\xd9\x0f\x9d~\xf8\xe1\a\xa3\xacl\x97\x15\b\x042\xbbw\xefv\x88\xcf\xe7\u03c8D\"\xbb7l\u0638\xda\xef\xf7%{\xf4\xc8W\x87\f\x19\xa2\x0f\x1e|\xe8\xf6v\xed:\xce\xde\xd7\xef\xf3|\xf1\x9f~\xfa/b\xe8\xd0!r\xec\xd8c\xfe\xb3\xc0|\u0528Q\x00\xf4\xea\xd5o\xfe\xf8\xf1\xe36\x86\xc3\xe9\x1d\x8a\x8b\x8b\xf9\xee\xbb\u017f(\x98{\x94\u039bo\xbe\xc5\xf7\xdf\u007f\x0f@,\x16\xa3\xb8x\a\xe3\u019d\u00ad\xb7\xdeB\xbf~}\xc9\xcdm\x0f@2\x19E\xd7u\x86\x0e\x1d\xc6s\xcf=\x83a$y\xef\xbd\x0fH$\x92)u\u011e\u05a9\u0264\x81\xdf\xefD4\x86\x91d\u039c\xb9\xbc\xf7\xde{L\x9cx-\xba\xae\xff\xecQ\u073f:v\xef.g\u07bc\x0584Xo\x86\r\x1b\xf6\x0f#\u05d68L\xd3DUU.\xb8\xe0<\u05ad+\xe0\x89'\xfeD\xc1 \xe3A\x00\x00 \x00IDAT]]\xad[\xca\xefT\x88\xee\xebu)\x8aB8\x1c\xc64M\f\xa3\xa1\xd9s\x9a\xde_]\u05f1,gS\x988q\"\xff\xf5_\x17\xe1\xd4\x15$\x0f\xd8\x06\x050\xa0\u007f_F\x8d\x1e\u00e7\x9f}\xce\xf6\xc2\x05\xf4\x1dq:BU\xb0\xb1Q$\xf8\xa5\xc0\x92\x12Kq\x146R\xb3\xb1m\x81\xb0%\xb6\x02B*\bl\a\xe8\xdd\r\xc0\x96\xa0HP\x10D\x1b\x1a\xc8\xed\u0715\xa3\u03fd\x92]E\u06e8\xad\xac$\xe0\x16\xf7y\u01b9\xaa\xa2 \x84\xaal\u07bc\x95\x99_|yBfV\xe6\x8bR\xca+\x85\x10\xf2\xfd\x0f?P\xcf;\xe7\xdc\x03Z\x1a\xbcr\xe5\x0f\f\x1e|X\xea\xff\x1e\x90\xbb\xefS\xa0\xa4\xa48TXX8z\u0252%\xf9\xb5\xb5\xb5\x87\xf9\xfd\xfe\xa3\x8b\x8a\x8a\xa2\xf5\xf5\xf5\xf6\xc9'\x9f\xa8\x1b\x86\xd5.\x12i\bF\xa3\x11\x99L\x1a6\b_(\x14\xd4\x15E\xc54\r\xa2\xd1X\\Q\x84\xbd`\x81_|\xf4\xd1\x14%\x1cNo8\u7733\xcb{\xf5\xea\x95\x00\xb9\xb0c\u01ce\x9b\x86\x0e\x1d\xb2}\u0420C\xe6ge\xb5\xdd\rp\xf3\u0377\xc8=\xe9\xbb\xff\b0o\u05eec\xea\xf3^\xbdz}\xb3j\u056a\xa3\x8a\x8bw\xb0`\xc1\x02&N\xbc\xaa\x99\xd4\xeb\xc0\x82\xb9\x8f5kV\xf2\xd1G\x1f\x11\x8b9\x15\x8d\u0468\x13-\x8f\x1e=\x8a1c\u01ba \x1e\u00f6mW\xfa\xe64\xf7\xcd\xc8\xc8\xe2\xb6\xdbn\xe5\xeb\xaf\xe7\xb1k\xd7.4M\xdb\xe75\u06f6M\"\x91$\x10\b\x10\b\x04\x88Fc\xbc\xfe\xfa\x9b\x9cv\xdait\xe8\xd0\t!\xcc\x16\x01\x94\xde\u01b6l\xd926mr\x12\x9fc\u018cf\xf0\xe0CS\r\x1c~m#\x91H\xe0\xf7\x87\xb8\xfb\xee\xbb0M\x83\xe7\x9e{\x9ex\xb6\xaa\xaa\xaa\xe7\xb6m\xdb\xd5\xda\xda\x1aa\xdb\x16\x8a\xa2\x92H$\xb0,\v\xc30\x89\xc7cn\x9eC\xb8\xef\xabt,\x9c\xa5\xed\xe6\xc0\xf4\x80s\x10\x91\x9eT\xd7\x1f\x0e\x87sV\xacX\x010\xd8\xe7\U000d16dbK\xf7\xee\xdd\xe3\xb7\xdf\xfe\xbb)\x1d;\xe6\xbd\u007f\xd2I\xc7\xfd0h\xd0\xd0\"o\u04ff\xef\xbe{\xb5+\xae\xb8\xdc\xee\u0673\xb7\xfdo\r\xe6M\xc7\t'\x1c\xff\u0357_~u\x13\x90\xb1j\xd5\x1a\u05ae]\u01e0A\x83\x81\x03\x1b\xb1z7r\xe6\xcc/(,,l\xa6J\x00\xa7$\x1c \x12\xa9C\u04f4\xbd\x8c\x944\r\xfa\xf5\xebO\x97.\x9d\u0675k\u05cf\xca\xdbl\xdb\xc60\f\xfc~\xc7\xf6\xb7\xb0p=_}5\x8bK.\xb9\xec\x17;\x85\xfc\xe3\u0701\x0eX,X\xf0m\xca5\xf0\xf0\xc3\x0f'\x18L\xffUQ,{\x03z\x94\xb4\xb4\f\xee\xbf\xff\x8f\xe4\xe4\xe4\xf0\u05ff>CII\t\xc1`\x10U\xf5\xa3\xaa*\xc9d2\xb5\x89\xefi\xc9\u073c\xef\xa7s\xc2J&\x93dggs\xed\xb5\xd7\xf0\xbb\xdf\xddF\x9b6\xd9\xc4\xe3\x91f\xf3\xea@\x9d6|>\x9d\xa1#G\x93\x99\x95\u016e\x1d\x85T\x94\xae\xa6\xef\xb0\t\xd4V\xc6\x01\x81%,\xa4\x10(\xd2F*N\xa7\n\xa9\bPAZn\x8b9\xd7\xfaV\n\u0464\xdc_\xa2I\x81*!\x19K\x12\xb5\xd2\x18>\xe1|6.[\u0136\x8d\x85(\x9a\xe6\xb0-\x12\xa4\xf0\\\xd4Ql[\xca\u014b\x97\x88\x8cp\xf8\x8e\x05\xdf~\xbbl\xcc\xe8\xd1\x1fuh\xdfA\xd6G\xea\t\xa7\x85\u007f\xf2k+,\\K\xbf~\x03\x91R\xf2\xc9'S\u0122E\x8b\x94\x01\x03\x0e\xb1\x00\uf0542\f\xa4O\x9b\xf6y\xc6\u018d\x1b\xf2KJJ\x87M\x9cx\u0571555\xc7l\u0738I)/\u07cdiZX\x96I<\x1eO\x15\x8a\x99\xa6)\x15E\x11N#\x10\x87B\u06f3VDU\xb5\x94$\u007f\u03e0,\x99L\xb2{w9R\u06ae\xd8Ae\u01ce\x12\u05af_\x1f\xf0\xfb\xfd\x17v\xeb\xd6\xed\u0082\x82\xb5e\xf7\xdc\xf3\xfbWF\x8d\x1a5g\xfc\xf8\xd3\x16\n!\x12\x8f<\xf2(\u007f\xfd\xeb_\u052b\xae\xfa\xad\x15\n\x85Y\xb7n5\x03\x06\f\xfa\xf7\x05\xf3\t\x13N\x9f\xfb\x97\xbf\xfcu]I\u024e#\n\v\v\x99?\u007f\x01\x83\x06\r>\xa0Me\xbd\u0098\xfa\xfa\x1a\x96.]F<\x9e@\u04f4f=\x1e\xcb\xcb+R\xc7\xee\xfdo\b\xec3\x91\xd9\x14\x04\xbc\xd7\xe0\x1d\xfb\x03\x81\x00\xd5\xd5\xd5\u031b7\x9fK.\xb9l\x9f\r\x84\x0f\xceP\xa8\xaf\xafa\u0672\x1fp\xb8\xc7\xde\f\x1e<\x98\u007f\x87\x11\x8fG\b\x06\u04f9\xe3\x8e\xdb\xe9\u07ff\x1f\xcf?\xff\x02\xf3\xe7\xcf'\x1a\x8d\x10\x0e\x87IK\v\xa56\\\xa7\xefg\xa3\u4c39\xbb\xa2#M\x1d3f\f\xd7\\s\r\xe7\x9f\u007f.\xaa\xea#\x91\x88\xfe2zk\xefd\x90\u04c1\x01\x87\x8fd\u1b19\xec,Y\xc9\u19ddOL\xd6b&-0\xc1\xb6l\xb0\x04~U\xa0\xa2:RD\xd5y-\xb6\x05\xb6pZ\xcba:\xe0.\x15\x1c\x8d\xba\"\x10\x8a\xc46-jj#du\xec\xc5\xf0\t\xe7\xb3\xf3\xf9'\xb0L\xc3\xdd\xf0\x1b\xbdn\x1c;^!b\xf1\x18\x8b\xbf_\xaa\xf5\xeb\xd7\xf7Y)\xe5:!DA8-\u0316\xad[\u945f\xff\x0f_\xd6\x17_L\xa7_\xbf\x81M\u05cb\xf4\x00|\xfb\xf6\xad\x87|\xfe\xf9\xe7\xc3W\xaf^\xdd\xfe\x9ak\xae>\xbc\xb2\xb2*'\x91\x88w6M\xb3\xf7\xb6m\xdb(//'\x99Lb\x9a\x16\xb6m\xb9\xf5\x03\x8dEa \xd04]\xec\x19\xc4\xed\xfd9?b\x94'S\xbeQ^m\x82\xd360\x81\xaa*\xd4\xd4\xd4RXX\xd8!//\xef\xbeM\x9b6\xdf\xfb\xf5\xd7\xdf|\xf0\xe1\x87\x1f\xbcu\xce9\xe7N\xbb\xe9\xa6[\xac\x9bn\xba\x85\x17_|\x9e\x8d\x1b7\xff{F\xe6\xf3\xe7\u007f\xc3QG\x1d\x8d\x10\u00ba\xe3\x8e\xdf}SP\xb0\ue23a\xbaz\x16.\xfc\x96+\xaf\xbc\x1c\x9f\xcfw\xc0J\xe0\x1d\x9f\x0e\x9d\x8d\x1b7\xa6|G\x9aj\u01e5\x94\xacZ\xb5\x8a\xda\xda*\u06b4\xc9$\x1e\x8f\xeds\x12\x94\x95\xed\xa2\xbc|\xf7~\x8f\xe3M\x9f\ub045\a\xfe\xabW\xaf\xa6\xb4t\ayyy?\x1a\xd5\xff\x12\u00fb\xc6m\u06f6\xa5\xbc\xb8{\xf6\xecI\u07fe}\xd8_g\x9e_\xd3\x10B\x90H8\xf9\x8e\t\x13\xce`\xe8\xd0\xc3\xf8\xec\xb3\u03d86m:\xf3\xe7/\xa0\xb2\xb2\x12EQ\xdd\xc8L\xa4\xf2}M;`\x85BA\x86\f\x19\u00b8q\xa7r\xfe\xf9\xe7\u04eb\x97\xf3\xde\x1chje\xcf\xe0\xc1\xc6\xc6\x17J\xa3\xff\xd0\xe1,\x9c5\x93\x92\xad\xab\x88\x8bJ\u04bbeR_[\x0f1\x05b&\"ia\x1b\x02M\xd8H\xdbi\xe7\xa7\t\x05K\xb1\x1d\x8d\xb9\x05\xa6%\x91\xb6C\xb1\b\u06e1X,\x17\xbc\xccx\x82\xb8\x11\xa0\xe7\x11\xc7\xd3g\xf17\xacY8\u05c9^\x9b\x18\x05\b!R\r.**\u02993\xf7\xeb\x0e}\xfa\xf4\xb9\t\xb8\x0e`\u02d6\xad\xec\xdcUF\xc7\xf6\x1d\xf6z-\xc5\xc5\u06d86m:\xd7^{='\x9f9~\u04e6-G^{\xedu\x03l\xdb\x1eTVVFYY\x19\x89D\xd2\xcdg\x18)\x16\xbf\xf9zSR\xc0\xdc|~;\xf7\u054b\u029dG\xa3\x0e\xdfk\x8a-]1~c\x91\x95\xe7&\xe99\x9b\x89\xd4)\xad\xe9\x89\u0272L6o\xde\u0136m\xdbD\u01ce\x1d\xcf+,,\xfc\xcd\xef~w\xdb\xfb\xe7\x9cs\u059bG\x1e9\xe6\xabk\xae\xb9\x1e\x80%K\x163|\xf8\xc8\u007f/0\xef\u0631C\x13\xaa\xe5\xb8\x17\xbe\xf9f\u078d\xbbw\xef\x0e\u035f\xff-K\x96,\u1a23\x8eA\xca\xc4\x01\x05\x92\xa2\xa2bJKK\xf7\x99\b\x9b;\xf7k\xbe\xfbn1'\x9f|*\x81@\x90d2\x912k\xf2\f\xb8>\xfex\n;w\x96\xb9\xaa\x06s\xbf\x1bGS@\xf7\x80\xbb\xb4\xb4\x94M\x9b6\x92\x97\xd7\xf9\xe0\xc7\xe4\xee\xe9c\xf5\xea5)\xd7\xc0\u07bd{\x92\x9b\xdb\x1e\u00c8\xff\xdbT\xf99\x00`\u0429S\x17\xae\xbd\xf6z&L\x18\u03d2%KY\xb1b\x05\x05\x05\x85\x14\x15\x15S]]\x8da8ADFF\x06\u077au\xa3_\xbf~\f\x192\x98\xa1C\x87\u0437o?@!\x91\x88\x1e\xd0\xd3\xe3\xfe\x02s\xdb4\xc8\f\xf9\xe9;\xe0\x10\x00vo\xddH\xd5\xce\":\x1d2\x94x2\x06\x9a@\xf8\x05VRAIZ\x88\x84\x8dL\x9aH\xc3FJ\a\xc4l/\x02\x176\xb6\x05\xd8\x12i:\x85D\xd8\x02Ew\x14.\xb1h\x946Y\xed\x18v\xea9\x14\x17\xac\xa2\xa1\xbe\x1e\xdd\x1f\xf0\x10/\x05t\xb6\x9bP.,\\\xcf\xd7\xdf\u033bDJ\xf9\x8a\x10b\xd9\t\xc7\x1f\xc7\xd6\xed\xdb\xf7z\x1d_~9\x93.]\xba\xef\xb9N\xd4Y\xb3\xbe8g\xfa\xf4\x99'\x9fq\xc6Y\xa3\xaa\xaa*\xfbVVV\xb2k\xd7n\xa2\xd1(\x8a\xa2\u062a\xaa\n!R\xddNS`\xbb\xaf\xc0\u010b\u031d\x8f\x8eE\xb0\xd7(\xd5m\x85\x8d\xf4\xac\u007f\xbd\xc6\x1e^\x03\x12ic\xe36\xf7p\xbf\xef\xd9\r\xe3Ya\xa7TOJ\x93\xa8\x1d,\u02d2EEE\xb2\xa4\xa4T\u07fau\xeb\xc5\xc5\xc5\xc5g=\xfb\xec3\xafM\x9at\u00fdB\x88\xda\xe1\xc3G\xf2\xd4S\u007f\x12w\xdcq\x97\xfc\xb7\x01\xf3;\xef\xfc}\xea\xf3\x93N:\xb5\xcd\xdbo\xff]]\xbdz\rEEE\xbc\xf9\xe6[\f\x1e<\x98p8L\"q\xe0\x00\xbd\xb2\xb2\x8a\xda\xdaZ\x14E\xa4\xfcF\x9f\x02({6\xd4\xf6\xd6X\xf3\xfb RHo#\xb1M{\xaf\xf5g[\x0e%c\xfd\x9f<\x86\x9a\xffm\xab\xc9\xdaQT\x15MU\xbdz\x13\xe1\xf0\xf3\xd2\u07bau\x9b]^^\x11,))\x99TYY1DJy\xb9\x10b\xd3\x1dw\xdc%O;\xed4\xf1\xfc\xf3\xcf\xc8=7\xb5_\x1d\x98O\x9d\xfa1g\x9ey\x16\x00\xf5\xf55C\xee\xbf\xff\xfe\x0f\u05ef_\xef\x8f\xc7\xe3\x00\xbc\xfd\xf6d\xbav\xed\u01ad\xb7\xdeL \x108`\x9cr\"\x11wmO\x95\xd4\xed\xf1\xa2-)%\xf3\xe6\xcd\xe3\x82\v.\xe2\xea\xab'2z\xf4h\xc2\xe10\xe5\xe5\xe5\u03181\x83\xb7\xde\xfa\u007f\xec\u0739\x93`0\xf8\xa34\xc9\xfe\x12\x9c\xb1X\x8c\xda\xda\xda\x16\x03\u6595\xa4\xb0\xd0)\xb8\xc8\xcb\xcbc\xc0\x80\xfe\xfc\xbb\x0eo\xf3J$\x1c\xfa\xcc\xe7\xf3\u047e}\x1e\xed\xdb\xef\xef'l\xa7\x89\x83;\x0f\x0ff2\u061bJ\x83\xf2\xf38\xe6\xb8\xe3\xf9t\xea\x14j\xcaw\x82\x04U\x15(\x96\x03\u0336G\x1d(\x02\xe1S\x10\xba@\x06U'R\x8f\x99\u0204\x85\x86\x8de\xb9d\x85l\xf4b\x91\xa6D\x899\x96\x00I#F\xa8]\x16\x87\x9et6\xdb\xd7.\xa7\xacx\x1b\xbe@\b)\xad&\xe0\x99\xf2\xba\x91\u06f7o\x17\xb3f\xcd>#\x1a\x8f\x8d\v\x05\x82\u04fd5\xf5\xd8c\x8f\xea=z\xf41\xdc\xff\xa7\xbf\xf7\u07bb}\u05ef/\xbc\xf8\xa2\x8b.\xbcp\xed\xda5\x1d***\xa9\xac\xac\xf6\xfa\xb5J\xc5\xe11\xf4=\xd7~s\x8a\u0109\x99m)\x9b\xb9FJ\x01\xd86\xb6e\xa5(\xa6f \xa9\xfb\xd0C!B\x81\x10z \x88\x1e\f\xe1\x0f\xa5\xe3\v\xa5\xe1\xf3\a\x91\xaa\xcf\u9deai(B`\x18\t\x92\xb1(\u0246:\x12\xf55\xc4\x1bj\x89\xd5V\x93\x886\xa4\x92\xac\u0496\xae0Bs\xe7\x87T\x84\x10JCC\xbd\\\xb9r\xa5hhh\x18\xbdk\u05eeO?\xff\xfc\u04f3'L8\xbd\xe0\xb3\xcf>\x93\x17_|\xe1\x8f\xea\xf2\u007f\x15`\xee\x019\xc0_\xff\xfa\xccog\u0318\xd9s\xe5\xcaU(\x8a\"-\xcb\x12\xc9d\x92\xb7\xdez\x9bc\x8e\x19\xcb\u0631cS2\xb2\x03\xc3\x15\x8b}\x82\xae\x97\x10]\xbbv\x1dw\xdf}/m\u06f6\xc5\xef\xf7\x13\x89D\x9a\xa9W\"\x91H\xb3\xe3\xf6\xfe\"q\x0f\x04\xfc~\u007fJ9\xd1r\xe8\v\x85\xf2\xf22v\xedr\xf8\xff\xdc\xdc\\\xb7\xcaU\xfe\u06fb\xe2I)I$\x12\xbf\x9e\xebu\xe3\xc2v\x99\xe9\f\xe8\u06db\xa9\x96EEi\x11\x89H\x12MU1\x15\v\u06e5\x01\xa4t\x13\x9d\xd2%\xdc\x15\x10A\x05|:2\xa1 \xa2&:N\xa4\xeaq\u0136\xed\x16|J\x89L\xd8`@\u012a\xa5}\xf7\xc1\x1c2v\x1c\x15\uff88\xb4\xf7P\xfb8\xa5\xa5(B\x88\x9a\x9aZ\x96,Y\x1a|\xe7\x9d\xf7\xae\x91R\xce\x12B$\xcf8\xf3L\xed\xd3O>1\x00\xdeyg\xf2\xb8\a\x1f\xfc\xe3\xbd?\xfc\xb0r\u052aU+ihh\xa0\xa1!B2\u9038\xa6iBJ)\xf6\x06p\x1c{\x01o\x9d\xb9fa\xa9^\xacV\xf3\x80J\xf3\xf9\b\xb6\xc9\xc1\x9f\x1e\u019f\x96\x8e?-\x03\u007fZ\x06\xa1\xac\xb6\xb4i\u05d1\xb4\xb6y\xa4\xe7\xb6'\xb3m\x1e\xa1\xac\\|\xe1L\xfc\xc1\x90\x03\u07b8.\x94\xb8'\x16\xe9P\xa4\xb6\x91 QWE}Y1\xe5[\n)[\xb7\x94\xe25K\u067d\xb9\x00\xcb2\xb1,'I\xae\xeb\x1a\x9a\xa6\xba\x1b\x8c\x10\xb6m\u02cd\x1b7\x8a\xfa\xfa\xfa\xfe55\xb5\xd3\x16,\x98w\xe7\x981c?\xbc\xe0\x82\x8b\xe4s\xcf=\xc7\xf5\xd7_\xbfO,h\xf1`\xbej\xd5r\xc2\xe1\f\xf2\xf3{\"\xa5\f\x9dp\xc2\xf1\xa3\v\n\nH&\x93R\xd34\xe1M\x90\u035b7\xb3f\xcdZ\x8e:\xea\xa8\x03\xa6;\x0f\x06\x83\xf8\xfd\xfe\xfdz\xb1\xf8|>\f\xc3 \x1a\x8d\xb2}\x1f\u071f\u01c3\xef\xc9\xd7\xed\v\xc8\xc1\xd1rgff\x12\x8dFS\u0296\x83=\xbc\rm\xe7\xce2<\x1b\xe2\xdc\xdc\\:t\xe8\xe0\xc6w\xad\xa3\xa5\r\x87\xda\v\u0465Kg\x84\xa2PWVJ\xb4\xbe\x16\xdd\x1fBS\xc0R@X^\xcc,\x1b9\x11w:\nU \x82*\xaa.@\x15(\xa6D&m,KbI\xe7\xae+\xe0\xfa\b\b\xac\xa8A\xb4\u06a4\xef\u19f2q\xe9\xb7l+\xf8\xc1md!R\xc9C\xcfS]QT\xb9q\xc3F1o\u07bcqg\x9c>\xe1:\xe0\xe9O?\xf9\xc4L\xc4c\xdd\xee\xbe\xe7\xee{\xdf{\uff49\u02d6-\xa7\xba\xba\x8aD\"\xd9\xcc\x12\x03\x10{\xaa\xc0\x1a\xbf\xe7\xca(]%\x89m[\u0626\x99\nk\x03\xe9\x19du\xeaNF\x87.\x84\xdbw&\xabcW\xdat\xe8L0\xbb\x1d\xe1\x9cv\xa4g\xb5\u00d7\x9e\x81\x16LCSU\x04`z\u007f\v0l\xe7/\b\x01\x9a\x04\xd3v\xde7E\x80\x94\nR\x82?\x10\"\xd8&\x9b\x9cn\xbd\xe93\xfa84\x01\xbb7\xae\xa5\xf0\x9b\xe9\xac\xfej*\xdbV,\u00b2LG!$mt\xdd\xe76;q\xf6\xbd\x9d;w\x8aE\x8b\xbe\xcb\x0f\x85B\x1f|\xf9\xe5\u0309'\x9dt\xca+\x93&Mb\u04a4I\xbc\xf9\xe6\xeb\\v\xd9\x15\xbf.0?\xf4\u0421\xfc\xfd\xef\xffO\x00\xf2\xf5\xd7_;\xa3\xa4\xa4d\x80\xdbzM\xec\t\xd8k\u05ee\xc30\f\x97\xaf\xfe\xf9u\xe7m\xdb\u6493\x93M}}\xfd^\xfd\x1dM\xd3l:\u0270m\x99\xf2[\xd9W\xc2\xe5\xa7\xf0\xcbR\xcaT\xc5gzz:\xb9\xb9\xb9-\u6f94\x96\x96R[\xeb\x80y\x87\x0e\x1d\b\x04\xd2~&O\xee\xd6q \xc0\\U}\xe4\xb6k\x8f\xee\x0f\x10\xad\xa9$\x19i@\xf7\x87\x1c@\x15\x8d\x8a\x1c\xe1\xa4\xfaR`\xeeQ*\x02\x89\xa2*\u0220\x8a\x1dT]\xfd\xb8\xc42m,)Q\xa4\x13\xdd#\xc0\xb6\x05\xf1\xfa\b\xe9m\xba2p\xe48vm\xdf@<\x1eE\xf7;y$\xe1\x05\xd2B\"TE\xc4\xe2q\xeb\x87\xe5+\xb4\xe93\xbe\xb8PJ\xb9\xe0\xaf\xcf<\x93\u007f\xe9e\x97=\xb9l\xd9\x0f\xf9\u06f7ow\x03 \x81\xa2\x88f\x94US\u00f3\x94\x9d\xb4P\x90H\u01f6\xd70\xb0\f#\xb5\x0eC\x19Y\xe4\r<\x9c\x8e\xfd\x87\u04b6\xd7@\xb2\xbb\xf6!\xbbs>\xc1\xecvh>\x05lG\xb1\xa3\xba4P\u04b21L\x03\xd3H\xa2\xe2\x18\x8dY\xb6\xd3\x1a\u06e3\xd6U\xc5q\x93\x94\x80\"$6`\xd9\xc2\xf5\xa5\x01UU\x1c\x17N\xa9`\xab*y\xfd\x06\xd2e\xe0@\x06\x9fr.\xdf}\xf0\n\x8b\xde{\x89\x86\xaarL\x04B\x98\xf8\xfd>\x84\xb0\xb1m[\xa8\xaa\u02ae]e|\xf5\xd5,TU}y\xc1\x82o\xca\u018c9\xfa\xf3;\xef\xbcC\\v\xd9\x15\xf2W\x17\x99\x1bF\f]\x0fJ\x80\x0f>\xf8\xe0\xf8\xd2\u049d~\x97\xb0V\xf7\x04\xf3/\xbf\xfc\x92\x82\x82\x02\x06\x0f>\xacY\x92\xf2\xe7\x89F\xa1s\xe7.\xe4\xe5ud\u06f6\xed.ol\xed\x15u7\xe5\xd0\xf7\u03c3\xcbf\x1e\x1e\xfb\x02x\u03ec\xa9\xba\xba\xca\xddH\xda\u04af_\xbf\x16s_\xca\xca\xcaR\x1c~^^\xdeO\u069cZ\xc7\xc1%\xceC\x19Y\xa4\x87\xdb\xd0P]I\"\xda@ZN{$\x12U\x11h\x9a\x02\x86t\xacl\xed\xa6\x80\xeeT\x89\xba\x04\x82\u04c2BU\x90>W\x9f(\x14\xa4%\xb1\\6W\xd8N\xa8.5I2\x91\xa0\u03f0\x93\u067af\x11k\xbf\xff\x12[\xf77\x82\xb1\x10N\x85\xa9\x94\xf8\x03\x01e\xe3\x86M\u031e=wP]m\xed\x9b\xef\xbe\xfb\xde\xc0\x82u\uba29\xa9F\xd34\xe9IR\x9a\xae\r'pRP]\xc7Q\x89\xc0\x966\xa6i\x91\x8c\u01f1M\x03\t\xa8\x9aN^\xdfC\xc9\x1fq,]\x0f\x1bC\xdb\u0783\xc8\ua50f/\xa0\x12\x8bK\xa4i`$\xe3\x18qGo.\xdc\xfc/\xd2=uH\xf0\xb9o\x8d)\xdd\xcaW\xf7-U\x04\xa8R\xa2\xbaI]7\xbcCU\x15\xfc\x9a@W\\\xba\a\x89\xb4-,\xdb\"n\n\x14\xa0]~w\xc6\xdf\xf6\b\xed{\xf6g\xe6\xd3\u007f\xa4\xa2x\v\x00\xba\xa6\xa3\xfb|\x18F\xe3)\xa4\xa2\xa2\u009c3g\x8e\x16\b\xf8\xff\xec\xea\xf2\xb7\xbc\xf1\xc6k\xea\xe5\x97_i\xfd\xaa\xc0\xfc\x99g\x9eS\x00{\u04e6\xc2\xfe\xe7\x9e{\xc1\xa8\xba\xba:\xf7\xbe\xee\r\x1c\x9b6m\xe6\xb9\x17^\xe6\u017f=\x87\xae\aI&\xa2?\x9b\x8b\x8fm\x1b\xf4\xec\u0643\xee\xdd{\xb0p\xe1w?\xda\xe7\xf1\xc7<\xb0\xf7l^\xe0%D\xf6\x04\xfc=\vP\xbaw\xef\xf63v\xa4\xf9\xd7GEE%\x91H\x14\xbf\xdfO\u06f6\xb9\xad`\xfe+\x18\xa1p\x069\xed\xda\xd3P]I2\x16I\u9f85\x04MQ\xb0UW#-,\a\xbaE\x93~\xa1\x02W\xaa\xe8&L]\xac\xb7\x14\a\x98\xa5\xe5&B\xa5\x1b\xa1\x9a\x82D\x12\tG\u07aci\x9a\xb6s\xe7Nk\xf1\xe2%\xbd\x1fz\u807b\x80k.\xbf\xfcJ\xeb\xbb\xef\x16*G\x1c1\xcan\xccd\xb5\xf0Q]]\xad8\x89\x90\xf7G\x00\xfd] \u072f\x89\xf9\xbb\xef}\xc0\x1b\x1fNs9l\x95\x9f#g\xe8y\xac\xa4\xa7\xb7a\xf8\xf0\xc3\t\x87\xd3\xd9W\xd6|\xcf\xe3\xdf\xdeI\x99\u01afk\x9aJ \xe0\xdfo\x13\x83=\xc7q\xc7\x1d\v\xa8?[G\x9a\u007f\xf5\x94\xe2\x9d\x18\x02\x81\x00\xd9\xd9\u066d`\xfe+\x18\x19\xe9id\xe7d\x13\x8f4`\xc4b\xa9\xee\x13\xb6\xab\x8f\x16x\xa0\u04f4\xd0\xc7\x13i7\u2ba7\x1a7%\u0616t8\a[b[\xce\x03\v\xa7\xb24i\x13\x8f\xc7\xe9\xd4g\x04\x03\x86\x9f\x04\x12,\xd3H!8M\xdc'\x15U\x15\xbbv\xed\x92E\xc5;,\u007f UUU\xa5\xb4\xf7\n~\x9c\xa4\xa6\x82iY$\x92\x06\u0446:\"u\xb5$\xe31\x82\xe16t\x194\x82\xe3&\xdd\xcf\xf9\xff\xfb\x01\xe3\xee}\x96\xc1g\\F\xdb\u0783\x90\b\xea\xabj0\xa2\x11t\xe1PF\xaapZ\xe8y\ax[:\\x\xd2r\x94\x99q\x13\x92\x96$fB\xdcr^\xa6)%\x86\xed\xbeg\xd2\x01y\x84@SU\xfc\x9a\x82\xae:\xe5\xff4\xed\xbe\x97z\xfb\x9a`\x84\xa2`$\xe3$\xa3\x16\x83O\x19\xcf\xe9w\xfc\x89\xb4\xcc\x1c\x12\x89\x04\xa6i\x11\b\x04S\x9e\xfa\xae\xeaE\u0670a\x03\xeb\xd6\x15\\=m\u06a7\xe3\x01\xde}\xf7]\xf5W\x13\x99K)\xc9\xce\u0392\x00\x05\x05\x05=\u0768\xdc\xdc\xf3\xba}\x814\xba\xf4\x1dJy\xf1F\xea\xaav\xf1\xe4\x13\xffM\x87\xae\x87r\u0310nhD\u070d\xff_\xbf\x16\x80\xf1\xe3\xc7\xf1\xe1\x87\x1f\xf1\xed\xb7\v\u007f2\xf0y\u050b\xa3+u\"n\xa7\x11\xf0O\xe3\xf5{\xf5\xea\x95j\xc3\xd6R\xda\xc8y\x96\xb7~\xbf\x8f6m\u06b4\"eK^G\x0e$\x90\x95\x1e '3\x83u\x898f2\xe9\x02\x92K\r\x02\xaap|Yl\x84\xc3k\x8b\xa6 \u07ac\xa0\x11\xcbv\xc0\\\x91\xa0\x9a\xeeF\xe0VW\xdaB\xba\xa9T\x81\x11K\xe2\xcbl\u00e1c\u03e1h\xc32\xcavlD\xa2\xa7:\x86\xa6*)m\x89\xaaiB\xd3T\xd59\xd9:rB\xa7\x01\xb5H\x81\xa1\xed6\xc70\xe21\xa4\x94\x84\xdad\x91\x99\u05ddN\x83F\xd0k\u0329t\x188\x9c\xb4\xdc\x0e\xe8>\x05\u06c4d<\x86i\x99h\x02\x14UC\xb8{\x8d\a\u0216\x14\xa9\x86\x1b6{tW\xf2\xf6\x1c/\xf7@\xa3$S\xc1\x89\xb4}\x9a\x82\xae)(\n\xa8B\xa04\xba\xffz\xf9`\x8fU\x02!S\xf4\x8cpv(,\xcb\xc02T\x86\x9dy6\xb5\xbbJ\xf8\xec\u007f\xee!\x1a\x8d\xd0&\xb3\r\xd9\xd99TVVx\xa6_\xc24-\xb9j\xd5*\xb1d\u0272{\xa5\x94\x8b\x85\x10\x15R\u06a9\"\xa4\x16\x1d\x99\u007f\xfa\xe9\x14\xa5\xba\xba\u0192R\x86jjj\xfa\xef\u06b5\x1b!\x84\xb2g\x04\x98\u06f97\u01dcw7\xdd\x06\x8c\x06\xa0p\xd9<\x9e\xfe\xf3\xb3,^\x1f'\x12W\x11?\x13\xd9\xe2y^\x9fv\u0684\xbd\x1aR\xecI\x914}4MDy\x91\xb5cw\x9blf\u04b4\xbfq\xe1\x85\xe7\u04ed[\x0f\xa4<\xf8\x8e\x89\xceuJb\xb1\x98{\xc2\u041a\xa8lZ#\xf3\x96\x1c\x18\xa5\xf9u2BA\f\xd3\xc42\x12\x0e\x9f\x90j\v'Q\\5Fc\u0562\xdb\xfc9\u0144\b\xb7\u0273\xc0\xb4\x1d\xf0p\u0336\x04\xc2rM\xba\xa4\x9b\x10t\x1bA[\x96E<\x16!\xb3c>\x83\u01dc\x89\xae\xfb\x91\xaeX=\x15d\xb9\n)e\x8f\xc6\x16B\xa8(Bi\x8c\x82m\x9bd<\x8a\x11\x8f\x92\u06ed7\x87\x8c\xbb\x80\xa3o\xf9\x13g>\xf5>\xc7\xfd\xfeY\xba\x1e}\x06zN\x1e\r\t\x93\u02aa\x06j\xea\x1a\x88&-\x926\xc4m\x88\x9a\x92\xa8%\xa9KJ\"\x06DM\a\xd4\rK\x12\xb7\x9c\xa8\u0734\x1b#pO\xa9#\xf6\x00h[\x82\xa6\b\xd2|*A\u0761V\xbc\u04cc\xe2n\x8a\xba\x02~\x15|\xaa@\xf5z\xab\xcaF\xa32p\xe8\x18\x80D,\x81\xb4a\xf4\x05\x13\x19~\xfaE\x98\xa6IMM-\xa1p\x06\x99Y\xd9)\xdf\x1f!\x84\u0639\xb3\x8c\x82\x82\x82#\xdfyg\xf2a\xce\xfb\xa4\xfc:\"\xf3\xe5\xcbW*\x80=o\xde\xdc\x1e\xb1Xl\x90k;\xbb\x97\x8a%\xaf\xe7at\xedw4\u0246\x04E\x05\x8b\xa9\xad,a\xfe\x8c\xb7\xe8\xdas(\x81K/\xe0\x90Nq\xfc>\xf8W\xf3\xa1\x8e\xf9\x95\x8fK/\xbd\x94\xb9s\xbf\xe1\x8b/\xbe\xd8o\x04\xbf'\x00\xee\xcb\xe3\xfa\xa7P\x13\xf9\xf9\xf9L\x9cx\x15\xc0A\xf72W\x00MuZ\x8ey\x8bN\xd5tTM\a\x1c\x1d/\x12Z{\xf6\xb6H4O\xf1\u0376ma$\x13H\x17\xccE\x13\xe5\x8a\xf7\u007f\xa9\xb8\x06Y\xd2u\au\x13|R8`g\xb8\xe0+\\\x13-'d\x95\xa9\xed\xdcvs\xa9H\x81\x15Obj\x1a\xf9\x83\x8f\xa1\xeb\xcayl.\xf8\u07b1\xc8udx.\xed\xe0l\x14\x9ew\x8b\xf7\x90\xb6DZ\x166\xa0\xfb|t\x1c|$\x9d\x87\x1dC\x8fQ'\xd3a\xe0p\xec@\b\u06f4\x89\x18&v<\x8a\xb4\xadF{^\x9a\xf2\xd4\xce?V\x93\x90Cu\xbfg7\tElI\xea5y*\x1eM\b\xcc&\xbf\u03ef)\xa4\xfb\x14|\xeeRHu\xd6\x13\x12\v\xc7\xda\xc0k\xab\x8at*m=\x9e\xddF\xa04v\xe2\u00d3P\xc6\x1a\x12\x842\x82\x1c}\xe9Ml_\xb5\x84\x1d\x05+\xa8\xaa\xa9\xa1mN\x0e\xd1H\x84\x86\x86:\xc0Q\u022d\\\xb9\x8a\xbe}\xfb\x9c%\xa5\x9c#\x840\x17-Z\xc0\x91G\x8ei\u0651yeE\x85\x020o\u0782n\x96e\xf5\xb5\x9cb\x85f\t\x11\xdd\x1f\xa0]\xb7CAjt\xe9=\x8a!G_\x8a\xa6\xfb\x89\xd6\xedf\xda;\u007ff\u019c%\x945\x04\x11H\u051f\xe1\u055af\x82\x8e\x1d;q\xdbm\xb7\u042d[\xd7\x1f\x8d`\xf7\x17m\xef\xeb{\xfb\x03\xf5\a\x1f\xbc\x9f.]\xbac\xdb\xc6A\x8b\xca\x15G^\x8c)\x14j\x92\xb0`\xe9\x0fl\u073c\u074d\xccu\x84\x10\x18\x86\x81\x914S\xfe\xed\xad\xa3\x05R-B \x14\x05i\xdbX\xa6\xe7\x18\xe8\x16\xd2\xe0&\u294dg'%\x84\x82PDc\xbb;\xe1D\xe5\x86\xddX\\$\xbc\x877\xb7S2u\x99\xda\x04\xa4\r\xf1\xfa\b\xe1\u030e\f\x18y\n\x81`h\x9f\xa78\x8fJ\xf1|Ql\xdb\u00b6LT]\xa7\xeb\xe1c9\xe6\xd6\xff\xe6\xa4\xfb_\xe5\xc8I\x8f\xd2\xf6\xb0\xa3\x89K\x95XC\x84x4J\"\x9e aX$-\x97\xdep\x81\u0652\x8d\x11\xb7\xe5\tt\x9c\u032esZv\x9fc\x81K\xb9x\xd7@\ua512p\u007f^U\x04!\x9fJ\u062f\xa0\xb9t\x94\x94\"\x15\xad{\xf9\x84\x14\xf7\xeeF\xf86\x8d\a\x10\xd1d\xb3\xf3\"\u007f\xe7\xff\x92h}\x9c.\x87\x1c\u00a8\xf3~\x8bP5\xca\xcb\xcaPT\x95\xac\xac,TEK\x9dNjkk)))\xbdp\xf6\xec/\xdb\x01l\u06f6]\xb4x\x9a\xe5\x99g\x9f\xb3\x00\xca\xcav\xf6/\u06f5\xcba\u063c\x12iU\x03\x04\xd9y\xbd\xc9\xc9\xebC|\x91'\xe3\xfe\xfe\x05\xdd\x16\u0590\xab\xaf\xfec\xae\xb9\xe6s\xbf5\xc9=\u059d\xff&<=)\x96\xd1b\x1e[\xd8?\xf3\x99O\xf3w\u007f\xf7\xbf\xd1:\xa4T*\xbc&\xa3\xfcR\x80#\xa0\xab(xn\xc0\xe5\u0387\x9f\xe1k_\xfeg\xb6n\u0708\x9b\xab\x01\xa5\b4\x14\xfc\x900\xb4\xb8k\x18j\x82P\x13\x84!\xfad\x87\xfe\xbak\u03f56\b)m\x94\xdb\x18\x9e#5\xf4\x99\xae>VK.\x04\xa1\x11\x94C\x13\r\xc8\u0204(\x14X\\8^\xa2\xb1ml\x8c\x9b\xdb.^R\x1e-P\xd78\x89\x99\x8bW\x93\xc9\xe6\xd1:@D.\x82\"ZpZ\a\x94\x8b#\xd45\xb6p\xe6{?\xca\x1b?\xf3u\x16\xbd\xfd\xc34L\x9a\xce\xc8\xd0\x10##C\x16\u0089\xbeYhD\x02\x9d\xa4\xbb^\x13\xad\xdfT\x13\x9e\xa8s\u049d\xb1I?\xe2\r \xfa=\x88\xb2Ok3\x92\xa6\xbc$\xe7V\xfb\x99W\u03caT:}\x13\xd1\v\"\xe9\xf1I\xac\x12td\x8f\x9bl>1m\x10\xe1\u07e5B\x89\x96)\x93Xu\xe9{\xc9\xd55p\xac\xbb\x8b\xd1\u0451*\xe5[\x18\x06\x1c=z\x8cm\u06f6\xaf\x8c\xbf\xff\x81\x03{_\x9f\xc5\xdc\x18\u00e7>\xf1\t\x03\xf0w\x9f\xfe\u07e7\xbd|\xa4\xfb\xb2\x91\xe1\xca\b\xbd\x90\x12\xa4$W\xdf\xc8\u0139\u02e9ik'\b\x03\xb4\x0e\xf1J\xa3L\x99u*\xe7^\xf2\t\x9a\u06a6\x10\x06\x05\x9e\xb8\xef&\xbe\xf1\xb5\x1byd\xe7\b\xa3\xa1\x83#\x19\xb3\x8c\xff\xebW\xa9TB)\xc5\xff\xfc\x9f\x1f\xe7{\u07fb\x89\u014b\x17Uu\xe4\xe9\"\x1dc\x95\xe9\xa9Q\x1b\u079c!\x93\xc9\xe0\xbanR\xe0\xdb\xda\u06b8\xf1\u01af\xf2\x0f\xff\xf0\x8fH\u9f22.\x90\xff\x99b\xdeW\xd2E\xe3\xf4Ex\xe5\x12\xa3\x03}\xd6O\x1dY\xe9\x9c\xe3\xcd\xc4T\to*\x8a\x14D\x82g\xc7\x18\xb5I\xc9\x10\xc7v\xec&\xc5\x1b\x84\x91\xea\xa4!\xa7h\xcaI2R$|\x90H\x1a1\x128FF\x9b\x99\x92\x15,\x9eH\xd3c\"\xf9\xa7\x8eI\xe4D\xdeY\xed\x83\x1ek{\x02\x0f\x96\xbd\xf1\n\u67f3\x86r\xb1@oOo\xd5ty\x18\x86\x94J%\x8e\x1d;\xfe\x16cL-\xc0\u05293^\x9f\xc5<%\xe9k\xda\xf7r\u05e7\xb6\xed\u0611>'\"\xa4\x83\t\x02\x9a&Lg\xe2\xdceh\x13\xa0\x85u?\vB\x8fR\xa9\xc0\xac\xa5o\xe0\xd4\v\xff\x84\x9a\xbaf\xfc\xf2\x00\x8f\xde\xfe5n\xfa\xee-\xc2\xf4\xe9\xd3S]9d\xb3Y\x9a\x9a\x1aijj\xa2\xbe\xbe.\xc9\xf6\xcc\xe5r\x94\xcbeJ\xa5\x12\x9e\u7854\xe2\roX\xc3]w\xdd\xc9G>\xf2\xd1h\xc3(\xbcf\x8e{BX\xc2wg1\xc3\xd3[\xf7q\xff\xb7\xbe\xcc\u02db\x9f\xa6\xa1m\"\x8b/y?\x8d\x1d3-\xfc\xe3\xfb\x1c\x1f\x1a\xa5\x14D\x04X\xea\x11\x17\xf5\x93\xd7\xeb\xe3\x9e\xf2<\x9fR\xa9\x84\xe3\xba(\u05ed(G\xd2 \x8c\xf9\xcdx\xbb\x01J\x91\x17K\xacp\x11\xd1\u007f:\xe9ze\xa5\x80\xa5\xfd\xcbM\xe4}n\x04\xe5B\x89\x9a\x86\x89L\x9fw\x16\xd9\\\xad\xf5K1\x10\xfa>Fk\xe6\x9d\xfd\x06\xde\xf6\xa9\u007fa\xd6y\x97\xe0\x87\x9a\xc2@\x0f~\xb9\x80W\xf6\b\xcbeL\u08c3\xc0\x8e\xe9\xfb\x1e\xc6\xf70\x81\x1f=\x02\xc2 \xb0|@h\x1f\xc6Da\x1b:\xd2\xc2\xc7\xda\xf0\xdf\xc2+\xc4\x1d\xb7#\x05\rYI]F\xe0\xa4D7\xf1C&\x9dw\xf5C2\xb6#\x8f\xcf?qa\xaf\x04ZXX&\x9e4\x15\xc9\xe6\xe9{\x1e5-\xb5,\xb9\xe82\xeaZ\xda\x18\x1a\x1c\xc0\xf7\x03\\\xd7M\x92\x95FGG9x\xf0\xe0\x94M\x9b^<#~\xfe\xaf;5\xcb\xc3[\xf6\x8b\v\x16N3\x00\xff\xfa\x9d\xef]\xbde\xcb\xd67\rG\x86N\x90J\x06\x91\x92q\xd3\x17\xd1\u06b9\x800(\x81cU\"\"\x14\xf8\xbe\x87\x11\x92\xc5g\xbd\x87\xc2H\x1f\xcf=z3\u0151\xe3\xfc\xea\xe6/\xe3\xe6\xf2\x94>x\x15+&\xb8\x8cw}\xa4\xb0\xbb\xf0\xefz\x83\x94\xcbe\\\xd7e\xe1\xc2\xc5\xdcp\xc3\xf5\xbc\xfd\xed\x97r\xc7\x1dw\xb2a\xc3s\xec\u07bd\x87\xa1\xa1AFF\xc2\u0102\xd3J\x11\xad\xe6<\xf6[\x99?\u007f\x1e\xef~\xf7\xbb\xb8\xf2\xca\xf7\x90\xc9\xe41&xM;r\x00\x13\x84\f\x84.On;\xc0/\xbfs\x1d\a\x9e}\x84\x9a\xa6q\x9c\xf1\xa1O\u04be\xf4lv<\xf5\bB(|\u07e7o`\x18?4d\x18sl\u0546\x93H\xcb\xeb\u5494JE\x86\x87\x87\xc9\xe4\xf2H\xc7M\x06\x85\xa2\x066\x1a\x0eJK\x11\xa3\xc6\u0280\xa7\r^\x84K\x88\x04\xaf0\x952&Rmm\xbcE\xa4\x8c\xa9t\xd4\xf6*\t\x81\x1f0g\xe9E\x1c\xd8\xf1\x14{\xb7=\x89T\x0e\x99\\\r\v/x\x1bg\xbc\xe7\xcfh\x1c\xdf\xc1\xc0\xf0\b\x81\xd6\bc\xbd^\xb41\xd6* \xf4#\xff\x15\"\xf5L\xb4\xa5\b\xfbg\x1d\x85B\x04\xa4\xa2\xdd\xe2\u009a\xb4\u0572B\x06G?_<\xd9i\x8c\xc1U\x82\u01ac\xa4&##\xe3\xac4\x142\x16\x86\x8a\xbfG\xdco\x8b\xb1\x1fN\xe1\xf9\x95\xff9\xdeFu\xca\xda#\xde\n\x851\xf8e\x98s\xe6E\xb4\u03d8\u01de\r\xebl\u4723\x92\xc2S\xf6\xcatww\xf3\xd4SO/\x06\x1e|\xdd\x15\xf3\rG\x06Y9\xa9\xd1\x00\xf4\x1as\xee\a\xaf\xfc\xe0\xff\xdal\x13\xae\x13xEHE\xe8{\u050d\x1f\u03d4%\xe7\xe1d\xea\t\x87\aQ\nK\xb4hkG\xe9{%2\xd9ZN\xb9\xe0j\u02a5a6=\xf9\x13\x06{\x0e\xf2\x8bo}\x01\xad4\x85\xf7\xbf\x8f\xa5\xad\x19:\xb3\x1eY\x19a]\xbf\xe3\xf3\xb6\x1e\xe7v\xe7\xbc\xe0\x82\x8bY\xbdz5\x9b6mb\xe3\xc6M\xec\u0673\x87#G\xba\x18\x1c\x1c\x8cB\x9a\xb3\xb4\xb5\xb5\xd1\xd99\x85\x8e\x8e\x0ef\u0318\u03aaU\xab\x90\xd2\xc5\xfa`\x17-\xae\xf9\x1a\x16\xf20\b\xd02\xc3\u04fb^\xe6'_\xfb\x17\xb6\xfc\xf2\x87\u0535\x8c\xe3\xd4\x0f|\x92Yk\xdeE\xc1\vP5\r\xb8\xf9:\xfcr\x99\x91\xc1~\xeb\xe1Aug\x1e\xc7n\x9d\xbc^\x1f\xd4\xe7\xf0\xf0\b=\xbd\xbd\xe4\xeb\x9a\xc8ds\xb6\u0324\x8a\x95I\xad9\x19\xfd]G\x05\xa7\x14X\u065d\x13O2#\x11\xd1{l\x03'D<\u0493*\x9e&E\xbbF\xe3\xf0\xc6\xe0\x97\xcb\xd45Mf\xde)o\xa1\xeb\xe0V\x86\xfb\xba\x19?u>K\xdft%\xf9\xb6\xc9\f\x0f\x0e\xa0\x84 @F\x10\x8d\xd5\xc0\xa3\xed0\x91\x91\xca\x16\xed\u0529!\xf6d'5\xa1j\xf9\u0644\xf2M\xac\tb\x1e\xc0\xaau\xe2\xc2n\xfb\ua332\x1dy\x8d##7\x9aJ\x017T|\x1f\x05\x95\x13J\xfa\xa3\x95Bn\xaa\x9eK\xe5\xb3L\x15$\x14\xff9q\x1e\x8e\x88P\x11h\x9a&\x8cg\xea\x92S\xd9\xf7\xfc\x13\x14K%\xb2\xb9\xbc\xb5\xda\xd5Vd\x10\x84!\u01cf\x1f?\xfdu\u05d9\xef\xe9\x1fefsm\f\xaf\x9c\xfb\u037b\x1e\xfc\xf1\x86'\u058d\u04e1\x9f\x9cq\x84T\xc9\xca\x1b?\xfb\x14\xa6,:\x87\xb0XB\x87\x1aGY\xb3\x04-L\xf2\x92\x95K\xa3dk\x9a8m\xcdG\b\xfc2\x9b\x9f\xbe\x83\x81c\xfb\xf9\xc5\u05ef\xc1\u01e7p\xe5\x87\xe8k\xc91'W\xa45+\x12,\xeew\xc5\xf9-1j!\x93\xa5KW\xb0t\xe9\n\x00FF\x06\x19\x19\x19\x89\xc6r]\x1a\x1b\x1b\xc8\xe5*CGa\u8f6a\u0650\xff\xd1\x15\x04!\x197\u02c6]\x87\xf8\xfa\xf5\xd7\xf3\xdc=\xb7\x92\xcd\u05f0\xec=\x1fc\xe6EW\xe0\xf9!\u0294\xc856\xe3\xe6k)\x0e\xf7S\xec?NV\x1a\x1b\xfe\xabu\x82\xb1J%\xff\xdbD\xc8\xfd\xff]\xc6\xed\xd5;8\xcc\xf1\x9e~\x1a\xa7\xce%\x93\xaf\x89\x94 i( E\xeaI\u06f9\n$A\b~d0\"\x84\xed\x85e\xba+\xaf\xa0\xc8X%u\x1c\x9cV\t\x84H \x17\xec\x1a)\x97Kt\xce=\x8b\xa9s\u05f3\xfd\xf9\xfb\x18:~\x84\x83[^$\xdf1\x93\x92\xafq\xa4\xed\xae\x8d\x01\x95\x10\x93\xd2B$&LHY\x11\xdd{!V\xab\x9eH$\x11\xa9gd\x12\xfc<)\xbcFG\xa7\tk\u022e5()\u027b.9iU'\bQ\u054d'\xaf\x8d\x11U\xc4\xe5\xd8\x12\x9d*\xf7c\u0781\n\x8e.\x10U\x9b\x83\x89\xbe\xae\x10V\x11#\x02\x8d\xceH\xa6.YE\xbe\xbe\x89rq\x04'\x93\x8dN%!Zkc\xb4\x16CCC\xf3_W\xc5\u0718\x12k\x9e\xc9\xc6Eq\xfc\xbac\xfe\r\xb7\xdf\xf6\x83\t\xdd\a\xf7V\x93\x9e\x80\x0e\x03jZ\xc73\xef\r\xef%\xdf\u070e\xd7\xdfoM~\"\x12\"\x99B\x8e\xce\xfa\xa5\xe20\xf9\xfaq\x9c\xf1\xe6\xbf\"\fC\xb6m\xf89C\xc7\x0eq\xff\x8d\xff@qh\x90\v\xde\xf7aF&7\xb2\u0414\x98\x90\xd5\xd6\xdfY\xff~\xe4\xa8\x1d\xd7\x1fM2@\xf3\xf9<\xb5\xb5\xb5\xc9\xc0\x90%0*!\x15\xaf\x97\x82\xa7\xb5!\x93\u0272i\xdb.\xbe\xf4\xa5\xebx\xf4\xee;\xa9o\x19\xc7\xe2w\xfe\x053/~\x0f\x81\xd6\x04\xbe\x87P\x92l}+\x99\xda:F{\xbb\x18\xe9=\x8aB'\xa4T\x95N\xf9\xb7$'\x9d\xbc^E\x80%:\x1d\x1d:\xd6\xcf\xf0\xc80\x1d\xcd-dr\xf9\xc8\xe7;\x9ar\x8c\x8b\xad\x88\x8ap\u0535J\xa1\bBA \x05J\tT Q\x0e`4\"\xf0\xa3\xe2])H\xf1z\xb6\xfauRU\xb0\xe2\x96\x1e\x1a\xf0}\x8fL\xae\x81\x05\xa7_\u0391\x83\x1b\x19\xe8\xda\u03ce\xc7\xef\xa5}\xd1*r\xed\x93\x18-\x160\xd2>w\x19\r\xed\x84F\x83\x88\x02'\xa4B\xb9\x0eJ\xaa\b*1Ud\xa7-\u4552jL\x94\xc7\x19oB\xe9IS\xc0\bI\xc6U\xe4\\\x85\x92\xd2nV\xc6$Dp\f\xef\xc2\u0621\xb8\x13;\xed\xb1\x9dz\xa5\xc0\x9b\x04\xd3\x1a\x13\xa7Q\xe9\xe7\xa3\xc1+\xad\xed\xfd4n\xfa<\xf2\xf5\x8d\x14\x87\xfa\xad\x8b\xa2\x90\x84\b\x84T\xa2X*q\xe0\xc0\xc1\xe2\ub998\x1f\x19\x1a\u5fae\x8c|\xe04\xa1\x8d1\xe2%\xc3\xf5?\xf9\xe1\x0f\x97>t\xfb\x0f\x13\xcf{!\x95\xf5i\xd0\xf6X8\xed\u07372\xe1\xac5\x94J\xc2\xfe`\bth\xb1<\x19\xb9\x02\x89T\x01)\x95\x86\xc97\x8c\xe7\xccK\xfe\x1a'\x93e\xcbS\xb73\xdcs\x84\a\xbf\xf3E\x06{\xba\x19\xfd\xd3O\xe0\xcd\xef`\x8e\xf6\x99\x9a\xf3\xad\xe5\xe5\xefY\xd0\xd3E\xda\xf7\xfd\x13,q_OE\xdcz/;\xf8\x81\u6a67\x9f\u57fer\x1d\x0f?\xf0 \xcd\x13\xa7\xb0\xfc\u028f\xd1q\xe6\x9b\xd1BP.\x95PB`\xb4&\xd7\xd4F\xa6\xa6\x1e0\f\xf6\xf5R(\x14\xc8fs\x95\xee$\xf2\xa989\xe2\xff\xdaw\xe5J)\x86\xbc\x80\x03]\xc7\b|\x9f\xda\xc6\x16T&G\x10\x84)\x89\\\x05K0\xc9H\xbfD\v\x89'\x04\xc2u\x11J\xa2\x82\x10\x95q\x80\x00\x11D\xbai\x01&\x12L\xeb\x04\xfb\x15\t\rZY\xe7\x95\x13\x80\x1fj\xf0<\xc6MY\xc8\xf4E\u7c79\xff(G\xb7?\u03c1\rk\x99\u007f\xc9{-\x84a\f\xa1\x16\x84R \x94\x83\xe3f\x11\xcaE\x1bM\xe8{\x04\xa5\x12^\xe0\x11ze\x82\xe2\bAq\xd4\x12\xa0~\x19\xed\x951:@\x87\x9a0\b\x18\x1b\x9cb\xa2\rF)\a\x95\xc9\xe2\xd4\xd6S\xdf\u0502jmA\xd7\u0510\xc9\xe5psy\x9cl\xce\x16\xd70\xc0\u8832Y\xa5\x02\x9f\xd3K\xbc\xba\xdb6\x15\xc8)!\x98+\xffF\x15\x1cS\xbd!\xc6\xde0u\ud4e8il\xa6\xf7\xf0>\xb4\xd6(\xa9\x92S\x8e\xe7\a\f\f\x0e\x8a\xd7M1\u007f\xf28\xe2\x1d3\xa56\xc1\u05dc\x8d%n\xb9\xef\xd7O\xbe\xe7\u07ef\xfb\x02\xc4QSR&]\xb91\x9a\u018eY\xcc~\xcb\x1f!\x9b\x1b(\xf4\x0f\xa2\xea2\xa8Q{,\x11\x84 t\x12\x1b\x15\xbfa\x00\xe5\xf2(\xb5M\x139\xe3\xd2O\x92ije\xe3#\xb7P\x18\xe8a\xfd\x0f\xbf\u03b1\xfd{\xe8\xfb\xcb\xcf1\xb0r%\xbdy\x98\x93/\u04d4\x93\x04z\xec\xfe\xfa\xfb\x17\xf6\xd7\xd5\x15u\x01n&\xcb\xe8h\x81\xbb\xef\xfe%\xff\xf7\x86\x1by\xe1\u0157\u8637\x843\xde\xffW\xb4/_\xcdh\xa9L\xe0\x95\x93\x13\x8f\u059a\x9a\xd6vj\x1a\x9a\x018\xde\xd3C\u05d1nf\u035a\x811\x12\xc7Qd\\'\xf2\x948YP_\xebj.\xa4\xa2o`\x80\x03{\xf7`\xb4\xa6\xb1}\x12nM=\x85b1\x9a\xb4\xa4\xe2\xfd\x1f\xfb\xa4 \"\xfbWM9\x10\x11\x84\x11!\xe2R!\x1d\x89p\x01\xcfD\u49b4\xddx\nX\xf9M+>\u0351\x06\x81G\xb6\xae\x819+\xde\xcc\xcb;\x9f\xe5\xf8\xa1m\xec]w/\x13\x16\x9dJ\xe3\x94\xe9\x84a\x80v\xf3\xb6\x93/\x15\xf0\a\xfb(\r\xf53r\xfc0\x83\x87\xf70\xdau\x90B\xcf\x11\xcaC\xfd\x04^\x89\xd0\xf7\xac\xef\x8b\x0e\xaa\xa6[#l&u?Vj\x83\x88\x88P\xe1\xb88\xd9<\xf9\xfaF\x1a\xc6M\xa0\xa5c:\xadSg3n\xfa|\xea\xdb'\x90ol!_\u05c0\t\x03|\xaf\fJ\"\x1d\x17\x19\x9f\f\xc6\xf4\xdfT\x9dE*8\x8d\x10\xa2\xaa\xa6$\xf8z\xa2\x8d\xafl\x05Z\x83\x93\xaf\xa1\xa6\xb95B%Bdd\xa7!\x84\xf5\x8b\x17B4\x19c:\x84\x10\x87_\xd3b~\u02ce\x11\U0004e675\x06`\xb3\xf7\x17\xff\xf8\u0736\xc3W\xde\xfc\x95\xcf\xd3\u007fx\x9fA\b)b\x9c<\xfa\x81\xa5\x94L;\xf72Zf/\xc5/\x87h)\xd0\rY\x8c\x12\xa8\x11\x1f\xe1\x03\xa1\xed\b\x8d\xd4\x15\x1aY\xc4\u064d\x05\u071a&V\xbc\xf5\xa3\xe4Z\xdby\xe9\x17\xdfb\xa0{?;\xd6\xfe\x82\xa1\xe3/s\xf4C\u007f\xcd\xe9o\xbe\x9c\xd1\xf6Z\xe6\x86\x05&\xe4\xad\xd7q\xf0\xdfP]g\x8cA)\x85\xeb\xe68t\xf8\x10\xb7\xfc\xe0\x87|\xf3\xdb\xff\u0191\xaen\xe6\x9c~>g\xbc\xf7c\xb4\xcf[\xc1\xf0h\x01\x1d\xf8\xa9\xde\xc1\xfe\x9aoh\xa2\xb6\xb5\xddb\xb1\xbd\xbd\x1c>|\x98\x85\v\u7864$\x93\xb1\x99\x86\xe2d_\xfez\xe9\xcd\x19\xea\xef\xe3\xe0\xee]\xb8n\x96\xfa\xb6v\xa4\x9b%\x18\x19E\vI\xd97\x14\xfd\x10)\x05\x19G\xa2\x94\x81\xc0\xe0\xa1)\x04\x10b\x13\xe5\x851\xc8x\xbc\x11cG\xcc\x1d\xd7f|\x1a\x1dy\xa3\xc70\x86I\x8a\u007f|*\x8d\x15(\xb1\x02\xc4\x18\b\xca%\x9a\xdbg2k\xe9\xc5\f\x1c;\xc0\xb1]\x1b9\xf2\xecZ:f\xcdg\xa80L\xcf\u07ad\f\x1c9\xc0\xe0\xa1]\xf4\xef\xdf\xce\xd0\xe1=\x94\x86\xfa\b\xcb\x05\x82r\t\xed\x97O \x19S~\x1fv[\x12\x95M\xaa\xfa\x95\x89\xe0 \x1dF\xb8\xba\xfd\x8c.\xa1P\x99\x1cN&\x1b\u017e\xcdb\xf2\xc2S\x98\xbc\xf0\x14\xc6\xcfZ@\xe3\xf8\xc9\xd6\u07e6P\xb0A\u03ae\x83P\u059a7\u0749\x8b\xb1P\xcc\tR\xd0\x18\u007f7i\xda8\xf9\fk\xaf\xebP\xd3\xd8\x12y\xcfW\xc3\x05e\xcf#\x9f\u02f5\x06~i\t\xf0\xda\x14\U000d738d0\xec#\u039e\\g\x00^\x1a6\u007f\xbd\xad\xab\xf8\xa9[\xbez\x1d;\xd6\xfd\xda\xc4o\x03\x91#\x98\x10\x02\x1d\xf84\xcfX\u0234\x8b\xae@\xe5k\xf1\v\xc3\b#0J\xe1\xd7f\xd0\x02\x9c\x11\x10:\xb4\x93V\x91-g\xa5\x15\x10\x18!(\xfb\x05d6\u01e2\v?Dm\xcb$\x9e\xff\xf9W9\xb6\xfbE\xba\xb6=\xcf\u03ff\xf4I\x8el{\x91s\xdes5\xbd\v\xe617\xf4\x99]\x13P\xebZ\xd8E\xff7\xaaL\xb9\\\r\xc6h\x1eyl-\xdf\xfc\u6df9\xff\xbe\xfb\xf0\x85\u00eaK\xdf\xcf\xf2\xb7\xff\x11\u0353gP*\x8cb\xc2\xd0\x12P\u046b\xa8\x845br\x1c\x87\x96\xc9S\xc9\xd5\xd4s\xb4\xbb\x9b\xbd\xfb\xf6R_WK\xb1XD)\x99`\u007f'\xaf\xd7\xfe\xf4\x050\xd8\xd7\xc3\xc1\xdd;i\x1e\xd7NC\xebx\xcaAH)\u0414BC9\x88\x92\x854\x94\xb5\u5374\f\xf0\x8dU\xb0\b'\x9a\x88\t+\x86[\xf1\x9b+\xa5\x8bQ!\xda\xe8$9\xc8\xf2U\"\"\x11+\u05b8q!O\xab@\x02\xcf#WS\xcb\xf4\x85\xab9\xb0u\x1d]\xfb^b\xff\xd3\x0fP\xd7\xd0H\xcf\xf1\xc3\xec\xdb\xf0(#\xdd\a\t\xfd2&\f\xac\x1f\xba68\xb9\x1c5m\x13\xc97\xb7\x93kh\u00adm\xc0\xc9\xd5\"39\xa4\x93A(\x85r3\xb6\x19\x14$]x\x02\x99':p\x8d\t<\xfc\xd1aJC\xfdx\xc3}x\x83\xbd\f\x1f{\x99\xe2`?\xa5\xe1~\x06\x8f\x1cd\xff\xb3k\xc954\u0471x\x15\xb3\xcfZ\xc3\xf4U\xe7\xd2\xda9\x9b\xc0+\x12\x94KH\xa9\x10\x8e\x83t\x1c\xdb\u96f8\xf5\x11\x95\x01\xac1\xc7\xfcx\x8f\xd1\x11dc\f)\x8d\x8e\xfdM*E\xae\xa1\xd9\xdaf\xe8\x94\a<\x10\x86\x1a)e\xaeX*\xb6\xbc&0\u02c6\xae\x11\x06=\u0139\x1d\xb6\x90\xef\xf3\u037b6\xf5\xf0\xa5{~\xfa#\x1e\xfd\xc1\x8dQ\xed\xb6lf\x85L1H7\u00cc\x8b\xdfc\xbb\xf2\xe2h\nB\xb1\xdd{X\x13\rA\b\x0f\x8cF\x9a\xc8\xf6&u|\xb4\x83jV\x1a%1\xccX\xf5f\x1a'Na\xe3\xbd\xdfb\xe7\u06bb\x19\xed\xeb\xe6\xf1\x1f\xdc\xc0\xc1-\x1b8\xe3]\u007fF\xd7Eof\xb8\xb3\x89Y\u01a7\xcd\r\xc8\bC`\u018c=\xff\u007ft))q\xdc\f 9t\xf8\x10\xff\xfe\xc3\x1fs\xcb\x0f~\u020e\x1d\xdb\x197y:g\xbf\xe9C\u033b\xe0r\u0716F\xfc\xe20FWf\xd6\u048bPk\x8d\xc20\xaes\x165u\r\xf4\x1d{\x99\x9d\xbbw\x01\xe0\xba\xcek\x1e\xa0q\xf2\xaa\xc0{\x18\xf0\x03\x8fC\a\x0e\xd0\xdf{\x8c\x19\x8bW\xd0\xd0:\x8e\xc1\xd12\u00de\xcd\xca4Q\xa1\xd3X\x13-\xdf\x18L\x18\u0372K\xa7\"\xdf3\x06\x19\x8e\t\x95\x90\x02\xa5\\\v\x8b\x1aM\xa8u\x05h0Q\x11OKB\xc4\x18Y\x9e\x81Rq\x94\xe6q\u04d8\xb5\xf4\"z\xbbw\xd3wd7\xeb~p-~\xb9\x801\x1a\xe1\xb8dj\x1b\u0237\xb4S7\xbe\x93\xda\tS\xa8\x9f4\x9d|\xebD\xf2\xcd\xe3\xc8\xd67\xe2\xe6\xebPY\xab\x9f\x17\xcaI\b\\De\x9c^P\x19\x15M\x80\x11a\xe1\xa1\xd0+\u23ce\xe0\x8f\xf4#\v}\x04}\xdd\xf4\x1f9H\xcf\xdem\x1c\u0779\x91\xc1\xae\x83\x14\xfa\x8e\xb3\xfd\x91{\xd8\xfb\u0323t,Y\u0172\xb7\\\xc5\xfc\xf3\u0782[S\x87_*$Cs\xcaq#hX\x9c@pV\xce\x04\xd5\x1fM \xb1\xb1p\xba\x14\xb8\xb9\x9a\x14\xa9\\)\xf4\xae\xe3\xe0y\xde`}}\u04de\u05e4\x987d`e\xab-\xe4]\xa5\xf0\x8am\xa3|\xef\xf1\xc7\u05b9w\xff\xeb\xe7\xed@\x80\xdd\xee+\x18\xb3\x90h\xbfD\xc7i\x173\xe3\xe2w[\x02\xa4\\Np\xf4\xcaiE\x12\xe4\x15h\a\xe9Ysb\x13\x92\x1c\xe9*>\x956\xa7P\a\x1e\xda\xd3LY\xb8\x8c\xf1\xb3\xff\x0f\xe3f\xce\xe6\u017b\xbe\xcf\xe0\xd1\xc3\xec}\xf61\x8e\xef\xdd\xc1\x8e\xf5\xbf\xe6\u0eeef\xe5\x19g2\xbb)\u03f4|H\xb3\xf4QBW\x19\xe9\xbc\xde\x0f\u064e\xa3\x90\u02aa\x85F\xcbe\xee\xbc\xeb\x1en\xb9\xf9\x16\x1e_\xfb\x18A\xa0\x99\xbb\xec|\x96_\xf8>\xa6.9\x9b\xc0\u04d4\xba\a\x10\xf5\n2\xc2\x06\x16D\xb7g\xec\xe6\xe1\n;X\xd1:u6nM\x1d\x00\xbbv\xed\xe6\xe0\xe1\x97\xe9\xec\x98L\x10\x04'%\x89\xaf\x13(MH\xc5\xf0\xf0\b\x9b6m\xa1T,2\xb5\xb3\x93\xd6q\xed\xec\x18\xf1\b\u3390\x8a_\xb9L\x95\x1d\x13%V\xc4\xf7\x9a\x88\x9d\x12\x13a]T\x18\xa5\x83t2h\x1d\"D\\pL\xc5L\xcaD\xb2A\xf1\x1f\xc5,\n\xa6\xcd=\x8b\xfd[\x1f\xe7\xf0\x9egq\x9c,H\x89R.n\xae\x96|\xdb\x04&\xad\xbc\x80i\u7f55|\xdbdT&\x17\xf17!h\x8d1\xf6w\x1d\x04\x10\xf8Ie\xb4\xcf\xddDj\x96\x8az%\r\xbb\xe80@\x87>N6\x87\x93\xef\xa0&;\x9d\xa6\xba\x1c\"\xf0\x18\xed=\xc6p\xf7A\x8e\xed\xde\u010e\xb5\xf7\xf3\xf2\x96\r\xf8\xc5\x02\xbb\x9f|\x90\xae-/px\u04f3\x9c\xfd\xa1\xbf\xa6q\xfcd\xca\xc5QL`'beR\xd0S$\xa8H\x17\xf6\xdf\"e4&\r\xb1c\x8c@erV>\x99\xf8\x1d\xd9G.\x9bedd\xa4K\b\xf9\xe4kR\xcc7\xf6\xc7<\x9an}|X\\\xf3\xe2\xf6\xae\x9a\x9f|\xe5\xd3f\xb0\xeb\xa0H\b\xcf\x18^\x91\n\ud5e9i\x9b\xc8\xdc\xcb\xfe\x94\x86)\xb3\xf1F\x86*\x8b\v\xa2\u022b\x10\x11\x86\xa8\xb2\xc6)\x9b(%E\x82\xd4cH\x97hzMG\xde\xceyA\xc00\xb5-M\x9c\xf1\u078f2i\xdeR6\xfc\xf4\xbb\x1cxa=\u00fd\xddl\xb8\xeb\xfb\x1c\xde\xfc\x1c/\x9e\xffVN\u007f\u06fbY\xbah\x01\xb3\x9asL\xad14\xcb2\xae\xd1\x15\u00de\xd7\u064d,\x85\u0779\x91\x19\x00\xfa\x8ae\x1eY\xf7\x14?\xbe\xf5V\x1e\xb8\xf7\x97\f\x1c;\u02b8\x8eY,>\xedm\xcc]y\t\xf5\xad\x1d\x94\a\x8b\x04\x04\xe0(\x8co\x90\xf5\n\x99\x17d\x1cA\x10V\x16\\F\x1a\x1c)h\x9c4\x95\xfa\xf1\x939\xba\u007f\a[\xb7\xed\xe0\x85M[\xe8\xec\x98\xf2\x9fr\x84L\xae\xa1\x95\x902\xa1\x86\xb2\x16d5\xc8\xc0\xa7\x9ez\xf6yv\xbc|\x94\xb9\x93[)\x16K'@a'\xafW\xef\xd2\xda\xde\xf8\xe5\xb2\u01c6\r\xcf\xd1\xd7\xdb\u00fc\xe5\xe7\x90k\x9b\xc9\xc0P\x11\xe9\x1b\x84\xaf\xed@\x91\x12h\u01e0\x95\xc48\x12\xed`\x8b\xbcR\x18e\x87td\xa8\x11\xa1\xa9\xaaGBT\xf5\x93H\xa5\x90\xcaA\x87~\x95\x83.\txc\xaa\xb0|\x91\x82b\x84\x10\x94\xca%\x9a[;\x98\xbf\xe4|\xba\x0fo\xa30:\x80\xebf\xad\u076eT\x88l\x1eod\x90\xcdw|\x03\xaf8BC\xe7lr\r-d\x1b[\xc85\xb7\x93o\x19\xcf\xc0\xfem\xbcp\xf3?s|\xeb3\x04\xc5\x02\xa1WD(\a\xe5f-1*\x15\xd2u\"\vm\x89p\x9ch\x94\xbf\U00084170A\u03a5\x00\x1c\x19\xf9\x97\x87\x01\xc5\xe1\x01\xb25u,Z\xf3\x0e\x8a\x83\xfd\xdc\xfb\u5ff1N\xad\xe5\x02\xc7\xf6lG\x87aEzhl\xf1\x8d\xcd\xc8\xcc\x18\xe2uL4M\x85R\x88a\xa9\xb8\xe9\u0506\xd0+\xd9F+Eh\x1b\x03\xb9l\x96\xce\xce)\xaf\xfe\xd0\xd0\u06a3H \xdc\xdd3t\xf1^\xdc\xcf>\xb9\xfe\t~\xfd\xad/j\xc2 \x19\f\xaa\"\xd9B\x9f\xda\xf6\xc9\u033f\xfc\u007f\xd04m\x16\xe5\u0442\r\x8a\rBD9@\x15m7.\xfd\x10\xa1+\x13\x9fF\b\x84\x0e\xab(\x86\xc4`G\xa4\xce5\x1a(\x1b\x18\t!\u0087\xb5\x0e(\x17\x86Q\x8eK\xdb\xf4y\\\xf0\xe1\xcf0\xf3\xb4\xd5l}\xf8n\xf6nXG\xcf\xfe\x9d\f\x1c\xde\xc3\xf3G\x0e\xb2\xf9\xc1\xbbX\xbf\xec4\x16\x9cq>KV\xac`\xd5\xc2Y,\x99>\x89\xf1\xb5\x0e9\f\x84\x1e^`1\xae?dQ\x8fG\f\x1c)q\\\x17p\xf1\x81\x97{\xca\xec=\xb0\x8b\xed{w\xf3\u0533O\xf3\xe8\xaf\xee\xe5\xc0\xf6\xcd\xe0\x15q\xb2uL[t6\xb3\x96^\xc4\xcc%khh\x99B\xe0y\x94FG\"WCSE\n\x99h\xc4Y`\x03{\u0168&+C\x8c\x92hW\xe2FR,#a\u072c\xf9\xb4u\xce\xe4\xe0\xa6>^\xda\xf04O<\xbf\x89\xb9\x93/\xaa\x1a\xda:y\xbd\xfaW\x10h\x10\x92\xe1\xe1\x11\x9e|\xf2I\xbc \xa4u\xda|L];\xe5\xbe\x11{\u007f\xe8JR\x90\f\r\x9a\x10\u0436\xa0g#_\x11\t\xc65Hm!\x96\x98\xb4\x94P\x05\x1f\xc4\xe8\xafT\n\xa1\x1c\x8452O\xec]\u01de\x8eI\xe3\xc7\xd1}\xa9\x81\x92\xe73w\xf1jvo~\x94-\x1b\x1fAJ\xc7\u00ae\x91L\xd9\xc9\xd7Q\xe8\xed\xe6\xa5\u007f\xff\x17T&\x87[[O\u0744\xa9\xb4\xccZ\u0338\x05\xabpj\xeai\x984\xcdz\xc0\x14G\b=\x8f\\S+\xf9\x96v2\xf5\u0378\xf9:\xb2\xf5\x8dd\xeb\x9bps\xb5H\xd7%\xd74\x0e\xb7\xa6\x81 \xf0*\u0773\xb6\xb9\xa09mpb\xbc\x1d\xf0\n#H\xc7e\xd1\x1b\xae`\xcf\xd3\x0f\xb3\xf9\xc1;q\x9c,M\x93:\x93\x0e\\V\xba\xad\x13\t\xe04\xb7i8\x11z\x12U\xb80ZkJ\xa3\u00f6sO\rve\\'\xfe&\x8f\xbf\xaa\xc5\xfc\xf9\xeeQ\xb1bBmh\xf6\xfc:\xf7L\xa6\xfeo\xb6o=\\{\xd7\xf5\x9fg\xf0\xc8~\x19\x9b\u0724\v\x9e\t\x03\x84\x90\u0338\xe0\n\xa6\x9e\xfb6\x02/\xb4\x129O\xa3\n>\xaa\xe0#\xcba\xc5\xc1-R]\xd8\x01\x01\x8d\bmjI\x1c\x95m\xa4\xc2\b\xab-\xb4\x8bP\xe0(\x81\x02L\u0672\xf6\xa2\xc1\xb1\xba;\xac\x1dg)\xf0Q\x8e\xc3\xd4\x15g\u04f1p\x15\x87\xb7l`\xd7S\x0f\xb3\xf7\u0675\x1c\u06f3\x15o\xb8\x9f\xed\x8f\xff\x8a\x1dO<\xc8#\x13;\x99\xbap9s\x17-b\xf9\xc2\xf9\x9c\xbal!\x8b\xe6\xcc`\\mM\xbaW\xc2\x18\x9d\x04V\xc4\xef\xcao\xaby\xa2*\xd8VDV\xb8\x95\x93K\x00\xec9\xd6\xc7\xc6-;xi\xe3v6m\xda\xc2\xd6M/\xb0o\xfbF\xcaC=\x00\xd46\x8dc\xf2\xf2\xf3\x99\xb6\xe8\\\xa6\xcc?\x8b\xa6\xc6NB?\xa0T\x18\u0184a\x92rb\x17j\xd4%%\xfffC\x1c\x05\xa0B\x83S2\x04\xa3\x86 \xa3Py\x97\xacR\xe8 \xd7\xd4\u01b4SWsp\u04f3\x8c\x1c?\xc2\u06a7\x9e\xe1mo\xbc\x88&G&\xb9\x89'\xafW\xbf+\x0ft\x88\xa3$;\xb6\xef`\xeb\x96-\u0535L\xa0}\xfeJF\xb5\xb5]\xad8\x01\xc6)C\"I\x90\x17\x81FZ'\x14\xf0\x02BW 4\u0220\xd26\xc6E\xca6O\x95\x82%\xa4c\xbd\u024d\u0104\xe6\x841\xf6\xb4\x8a\u00cc\xd5u\x18C\xc9\xf7h\xa9og\xc1\xd2\v\u0637k\x03\xc5r\x81L&\x97nJQN&\xc1\xbc\x83r\x81BO7G7=\xc9\xee_\xddJ\xcb\uc974/\\\xc5\xcc7\\I\xf3\xccEH7\x83r\xb3\x89\"\u013a\x12Z\x88VD>\xe3a\x10\x10\xf8^\x15!\x89\x90\x84\xdaP\f\f\x8e2\xb8\x91\xef\xad\x04\xbc\xd1!\x9c\\\r\xe7^\xfd)\x1a'vR\xd3\xd8\u00ac3.\"\xf4\xbcd\xe8'\x9em\x91\xe6D}y\xfc\x9a\xc4\x19\xaa\xb1\x90\u008c\x11\xbfHi\xdf\u02d1\x9e\xee\b\x86\x16),]RSS\u00e2EK^~\u054a\xf9\x86\xee\x11VL\xb0\x83A[&\\\xfc\x8e\xfdG\xcbk\xee\xfe\xb7\x1b\xd8\xf3\xe4\x03Q\xb1\x92U\t\xd3\xf1.>~\xc9\xe9\u033f\xe2\u00e8l\x8e``\x98l)D\x16}d)\x88r\x99t\xb2\x83\xc5\xc7\x11\x11\u0623`\x92I\xa8e\x1c\xe4Wy%\xc3Hq%\r2\x8e!)i\x8c\f\x10\xf5N\xb2\xad\x1ac5\xb0\xa1\uf8e4b\xda)g\u04f1\xe4T\x16\\\xf06\x0eo|\x9a}\u03ed\xe3\xe0KOS\x1a\x1ed\xe0\xf0>\xfa\x0f\xef\xe6\xc5_\xdd\xce=\xad\x13\x98:k\x1esf\xcfd\xe1\x9c\x19,\x9e;\x93\xe9\u04e60i\xe2\x04\u018dk\xaf2\xd8\xfa\xcf^~\xe8\xd1\xd5}\x8c\xae\xa3\xc7y\xb9\xab\x8b]{\xf6\xb1}\xd7\x1ev\xef\xdd\xcf\xce\xed\xdb\xe8\u06b7\x1b\x82\xb2]\xe8\xcae\u0714\xb9L]v\x1e\x93\xe6\x9e\u0284)K\xa8k\x9c\x84\xf6|\xca\xc5\x02\x84:\xc9f\xac\xe0Yc\b\x9a\u06379\x9a\xed\x16Q\xfa\xba\xe3\t(J\u00bc\xc4S\x90-\x97\xa9\xa9\xabc\xfa\xa9\xaby\xfaG\u07e4<:\u0313\x8f<\xc8\xf3W^\xc5\u014b\xa6a\xbc\xc2\xefl\\v\xf2\xfa\xdd/?\x88B\x8d\xb5\u6847\x1f\xa6\xeb\xc8\x11&/?\x97\xe6\xd9K)\x95<\b-\xf6-\f\x89\xef82vB\x8c\xd1Z\x89\x8a\xf8\x13U\xb2\u0713\x8cn9\x13y \xe98\x861n\xaa\"\x0f\x13\xa52\x18\x13F\xa4\xa3\x8eh\u0394@\xbd\u2ddb@1q\xeeg\xa85\x05\xcfg\xfa\x82s\x98\xdcy\x0f;\xb7?m\vo\x94\x04\x11\xdb\xef\x1a\xa5\x10FYO\u01e8\u0287^\x89\xee\x97\xd6\u047b\xebE\xba^Z\xcf\xf8%g\u04b1\xeaB\xc6\xcd_\x89r3\x98\xa0\f~\x19\xc2 \xf1^\x89\xa3\xe5D\xe4\xefbR)E\x00\xe5\xd0\xe0\x866\xffS\x1a\x83\x89\x14*~\xb9H\xeb\xd4Y\x9c\xff\xe1\xbfKN\r\xa1\xefY\u062a*\x9c\xe27\x9d\xabM\u22de\xda\xe7*\xc0DdC,$\x04^\x89\x81\xeeC\x89 \u013e\x01\x9a\\\xae\x86q\xe3\u0195O9e\xf9\xab\u04d9\x1f\x19\x1c\xe1\xd1cQ\xd3\uc3f6=Q\xe0\x8bk\ufedb\xb5\xb7}+*\x1a\u056ezB\b\xc2\xc0\xa7v\xdcD\x96\xbc\xfb\xafh\x9d4\x8f\xf0\xd80\xd9Q\x0f\x15\x00\x81\x8e<\xb2M%4V\u0605)=[\xc8\x11\xa6\xc2\x06\x1bK\xc4\bm\xc7d\x8d\xb4/\xa4\xd4 C\x99\xec\x84B\x02%\x03\x8e\x86\x1aY\x95\xb8\r\x10\xe8\x90`h\x10\xa9$\x93\xe6-e\xe2\x9c\xc5\xcc=\xf7\xcdt\xef\xdc\xc4\xe1\xcd\x1b8\xb8\xf1i\xfa\x0e\xed\xc3\x1b\x1d\xa1\xd8{\x8cm\xbd]l{\xfa\x11~\x8e\xa0\xb9m\x1c\xe3\u01f5\xd1\xda\xd2D[[\x1b\xadmm475\xd1\xda\xdaB}}=\xd9\\\x0e\xd7\xcdD\x836v\xc4\u0646\b\x94\xe9\xeb\x1f\xe0\xe8\xb1\xe3\x1c;~\x9c\xe3=\xbd\xf4\xf5\xf7\xd3\xd7\xdb\xc7\xf1\xa3]h\xbf\x92\t\x9a\xcd\xd5R\xd36\x81q\xd3\x17\xd11\xff,\xc6O]B\xcbf\xa3\xc1\x82\x00\x00 \x00IDAT\xa4\x99d\xf2\x8d\xe8\xd1\x12\xa5\xc1A\x9b\xcen\u0184\x0f\x881\x06\x9ecL\xf8e\xf4\x9e\x18$Z+T\xe8\x90)I\xfc>\x8d_+p\xb3\x06\x9c\x80\t\xb3\x171u\xd9\xe9\xec\\\xff\x00;\x9f{\x8aG\x9e\xda\xc0\xf2\xf9\xd3hS\x12\x1d\xe8\x93\xc3C\xafvW\x1e\x84(\xc7\xe1\xc0\xfe\x03<\xb1~=\x81PLYt\x06\x8e\xd3@a\xb8\x80\x0el\xc7h\vz\xa5\xa0\x1at\xe4\xa9#PH\xa4\x0fF\x9a\x8a\xe2BG2;i\xd0J`\x14\x84R \x8d@\x06\xd1\xf4\xa7\x14\b\xe1 \x8dk!\xbctdb<\xb6n*^\xe3\xe9\x8f\u0152A/\b\xc8\u05f6\xb1h\u0645\x1c\u073f\t\xdf\xf7q3\u0654\xe5m\xf5\xf0LlK\x81\x90(7\x8b\x0e\x02z\xb6=G\xcf\xf6\xe79\xb8\xf6n&,9\x93)g\xbc\x81\xc9\xcb\xce\"_\u05c8\x0e}\xc2R\x11\x13\x06\xf60.L\x14\xe5f\xed~U\xd4\xc8H \xc4P\xf45\xae\x14d\x85\x8c\x8c\xe4l\xf3\xe9\xfb\x1e*\u04b2\x1bm3\v\xd2F\x06R\x8a\u02ae0F\xfd\x93D\xdcE\xbfK\xaa\x05\x8b\xb1%\xc9\xf0\xf1.\x86\x8e\x1dI5\xbe\xf6g\xad\xa9\xc9\xd3\xd1\xd1\xf1Rg\xe7\xf4\x97\x00v\xed\xda\xf1\xca\x16\xf3m\x83\x88\xabf[M\xf9N\xa7\xe6\xcf7<\xb7\xb9\xe3\xe7\xdf\xf82\xde\xc8P\xc5C8\xfd\x86\xea\x10\xe5\xb8,^\xf3G\xccZ\xb4\x06ul\x14Y('\fzl\xfc\x9b(-\x05\x88\xd0 }\x1d\r3\xa4X\xe3d\x81\x88\xca\xc8l\xec\x02d\"\xf1\x94\xa8\u021a\x84\x06S\b\x11\n\xc8\xc9\xea\xe2\x86\u0571k\xad)\x0e\r\x80\x10\u0536\xb63\xe7\xac7\u0439\xfc\f\x96\r\xbe\x97\xfe\xc3\xfb9\xb2\xfdE\xbavl\xa2g\xff.J\xc3\xfdx\x85\x11\xfa{\x8e\xd1\xdfs\xec\x84\xd7F\np3\x19\x1c\u01f58c\x14{d\xb4&\fmZJ\xf9\xb7\x848g\xf3ud\x9b\u06e8in\xa7m\xd6b\xc6\xcdXF\xfb\xe4\xf9\xd47M\"\x9fkB\xe1\xe0\x97\n\x94z{\x11Z$\x1d\x80\xd1&\x05\xab\x90\u023a\xaa\xe2\x1e\x93p]S!\x92\xa5\x02\xe1 \xb4\x83(\x83\xf2B\xf0\fA\x9d\xa4\xe4\r\xd3\xd8:\x89\xb9\u7f45\x9d\xeb\x1f\xc0xE\x1e\xfe\xe5=\x9c\u007f\xe1\xc5\\<\xbd\x11',\xe0\x9f\xac\xe6\xaf\xf8%\x84\xf5W\xf1\xfd\x900\f\xc9fs<\xf2\u0223l\u077a\x95\xd6\tS\xe9\x98}\x06z$\x80r`\x15\xbb&\x1d*n\u05de\x8c\xd15%\x90Q\x97NhR\x1dqtOi\x8b\xf7j!\b]\x81\xd1\x12\xa1\xb5\xbdO\x8dU\xb6\b\xe5 B\x1f\xa3\xd3\x16\xafT\x85>\x8b\xb4{a\xfcA#\b\x82\x10\xdfHf.8\x8b\xc9\xcf\xfe\x82}\xfb\xb6\u0635+\u0485<\xa5\xd1\x16\"j\xdc*\xae\x83\"\"n\x87\xbb\xf63\xd2}\x88\xae\x17\x1fg\u0082UL;\xeb\x8dLZ~.\xf9\xc6\x16k\xd0U*\xe2\b\xaa\xf0nA\xf5p\xa0\u0586R\xa0q\x94\xc0!\n\u0280$pF\x18\x91\xd8\xf1\xc6E\u061e$*\x83C\x82\x94\xbdA\xb2a\x9c\xe8\xfd\x14\x8d:\xa2\x94B\n\xe8\xda\xfe\x12\xc3}\u01d3\xcd\xc1\xdapHr\xb9\x1cs\xe6\xcc~\"\xfe\xfff\u03de\xfb\xca\x14\xf3\x83\x03#t6\xd5qag]T[\xcd\xe2\u06f7\xf7|\xfa\xc7_\xbf\x8e\u00db7\xfcFxE\nI\x18\x86\xcc8e\rK.\xf8cra\x0eot\xb8\xc2\xfe\xc6$\x89\xa80\xc32\xb4\x8c\xbc\b+\v\x04\x93\xda\xe5\xa9\x18\xea\x98\x04\x96\x13\bi\x1d\xc9|$\x19a\x902\xaa\xae\x010\xaa\xed\xa0\x84\x9bJ\x1eO0\xb0\x94\x13b\xb1@ \x04N&K\xcb\xe4\x19\xb4t\xcc`\ua2b3\xf0J%\x06{\x8fs\xec\xc0^\xfa\x0e\xef\xa6\xff\xe0\x1e\x06\x8f\x1e\xa68\xd4Oyx\x00\xbf8\x82_*\xe1{%\u029eO\xb9<:\xf6\xb6\x04\xe5\"3YrMM\xb8\xb9<\x99|-\x99\xdazr\r\xcd\u050f\xef\xa4y\xea\\\x1a\xa7\u03a6~B'\u0646\x16\x1c\x95%\xeb)\x18\xf5\u0445\x02a\xb9h\x8f\xd2(\xabJ1\xa6z\xdb7\xa6\x1a\x97\xa7\xe2\x05m\xa8V\x04\t\xa9\x90\xd2E\xaa\f\x02\x05\x81]n\xca\xd8\x00g?\xab\xc9\xe7\x05S\x97\x9d\xcf\xc4\x05\xcb\xe9\xda\xfa\x02/<\xf4\v\x1eZ\xff^fO^C\xa7\x94\xc8\xc87\xfb\xe4\xf5\xca]\xf6T\x17R\xf6|\x94r8p\xe0\x00\xf7\xdd\xff+\x06FF8\xfd\x9c\xb3hn\x9eN\xe0\x85\t\xe9Y9\x8e\x99\xe4\x18&\x8c\xb4]v\xe4RJ\xc5f%)\xc2I\x90\xb1 \x95\x9c\x1c\xed\xf9\xc2rUV\x8b\xa0,, C\xdb\u045b\xf4]\xa9\xab\x03\x89\xc6\xe8\xd6\rP\xf4<\x9a\x9a:X\xba\xf2M\x1c9\xb2\x97 \bP\u02a9\x10\x86\xa6\x02\x87\x86a\x88\x10hG9\"\fC\xa1\x03\x9f0\x88\f\xf7\xa4-q\xc3\xdd\a\x19=v\x84\x97_x\x9c\x89KNg\xfe\x9b\xaeb\u0082Udkj\xc0+B\x18\xa2\xa4\x8d\x88\u04c0\x17\xa6\x03\x9e\x05\xa1\xb1\x01\x1d\xb5\xd2$\xd8u\x1c\u0111l\x88\xa2\x12\xa5\x97\x14u\xaa+\xb6\x10)\x188\xc5\x05\x1b\u049b\x1cH%\t|\u0631\xeeW\x84QS'\x85\x04cp3\x19:;;\x99>}\xfa\xa3\xe95\xf0\x8a\x14\xf3\u03a6:\x8e\x8c\x96\x99Tk\xa7\x0e\x9f\x1d\xe5\v\xbf\xba\xeb\x8e\xdc\x13w\xdc\x12U\xee\x8a\x13\xa2\x05\xfa\x15:\xf4i\x9d<\x9b\x15o\xf9\v\x1aZ;)\x8e\f&8\x9a\x88\xbc\x1eLD\x02\x1a\xa1\x11\x81%d\x84\xa6\x92p\x93\xb2\xbe5b\xcc\xd1&\x15\xfddM\xf25^`\xacw\xb1\x93\xac*K\x88\x8e\x82hP\x95x\uf60d7\xa6*B\xca\x18CP.\x13D\x13\xa9\xc2qqs5\xb4M\x99N\xd3\xe4\xe9hs\x01A\xa8\x19-\x96\x19\x1d\x1a\xa0\xd0\u007f\x9c\xd2@\x0f\xe5\xe1~\xbc\xd1a\x82b\x81\xc0+\xa0\x83H\x9b+%N&\x8b\x93\xad\xc1\xa9\xa9#[\xd7H\xa6\xb6\x9elC3\xb9\xa66r\xf5M(7WI\x8f\x05t\x10\x12\x84>~P\xc0\xf1}T\xa0\x13\x85B%p0-\x1c\x88\x19\xf6\xf8\x06\x16iuY\nw\xb27\x82\x90\x0eB\xb9v\x80+\xe9H\xc0\x04\x91\xb1\xbf\x94\x94\x06\x86\x187~.s\xcfz\v][_\xc0\x1b\xee\xe3\xa1;o\xe3\x8cs\u03a5\xa5#G\x9d(\x9c,\xe6\xafpW\x1e\x04\x9a\xb2\xe7\xe3\a\x01\x99l\x96G\x1f[\u02f3\x1b6\xd0\xdc6\x89\x99K.@\xca,Aa4\x9daV\x89o0\x15\xcc\xda\xe2\xdb\xf2\x04\xf5\x85 \x95t\x9f\x92\u0449\xd0~\xaa\xebH\x9c\x88 \xb1\x84\xaa\"t\x1ckb\x15\xc1\xa1\x15\xb5Fe\u011e(\xad\u0224<\x94$\x06?\xf0(gj\xe9\x9c}\x1a\xe3\xda\xef\xe6\u0211\xbdQ-\x90\x91\u72c98\"I]}\xab)\x16Kr\xa0\xf78H\x11*\x89\xc4\x18\xa1CKrZ\u0264\v\x02\x8a\x83\xbd\xec[w/=;^b\xc69\x970\xef\xc2\u02d80s.\x19GQ\x1a\x1d\u0173)\x17d\x94\xed\x9eCc\vy`\x04~\xe4c\x93\u02d0H\x18IQr2vG\x15\xe2D\xd1NU\xf1Oo`c\x06\xfd\xa3\u04f1r\x04\xc7\xf7\xecd\xdfs\xeb\x00R\xf9\x9f\x06\xd7\xcd\xd0\xd9\xd9\xd9=y\xf2\xe4g\x01\xae\xbb\xeeZ>\xfe\xf1O\xbc2\xc5<\f\n(\xc7\x16\xf2\x97\x8d\xf9\xd8m\xf7={\xd9\xdd\u07f9\xde\xc6s\x83\x90c\x16\x8a\xd6!\u065a\x06\x96\xbd\xf1O\xe9\\|>^i$\xe5\xbef\a\x19b\xa3,!%\xb2,\xec\x00C*\x930\xc9\xeeHgIUy\nW\xceR\u0080\t\xad\x87\x84\x0e\xac\x86\xb5*\xe2{Tc\x14\x88\xdaH\xab\xae\x89\xa4V\xd5T\x86I\x919Bk\xf0\xca@9\xe9j\xa5T\xb8B\x91\xcfg!3\x81|\xdb\xe4J\x8cZ<( \u04a9%\"\xbe\x13\"c\xba\xf8\xe8\xa8#\x9bQC\xa8C\x1b^\x1b\xb9\xd4\xc5x\xa1q\x05\"\xa7\x90e\x93\xe8\xea\x05\xd5\x1dy\u0711I!\x93\x9b\u0264N=\t\xeb.\x94\xbd\x01\xa4\x8bRN\xe4_a\xaa\xa6\x04\x85\x89\n\xbag\bU@\xb6\xd6a\xf6\xca7\xb1\xf9\xc1\xdb\xe9\u0677\x9d\xadk\xef\u7a67\x9faJ\xeb\xb9,\xccJ\x94\xd0'\xc9\xd0W\xa4\x90\v;%\xe9\xfbx\x9eG6\x9b\xe3\xf0\xe1\xc3\xdc{\xdf\xfd\xf4\x0f\f\xb0\xea\xfc7\xd02y>\xa1\x1fB\xa0#\xbf\"\x12\x88\xc3\xca\f#\x92\x1b\xab\x9a\x12B\xd9\xf7WX\xb23N|\u0462:?GG\xd0BNJ\xb2Y+$ 4\x18\x19}L\xabJb\f\xf1\xa8\xe9\x18\x9f\x12\x93Z\xfb\xa9/n\xb4\xa1P*Q\xdf<\x85y\v\u03a4\xbbk_J\x9e\x17Y\x0fD\x039\xabW\x9f+::\xa7\xbd\xfc\xc2\u018d\x93w\xef\u06a9\xf6\xef\xdcn\ub0b4~&:4\x11\x89j\u05f5\x00\x86\x8f\x1eb\xe3\u03feC\xf7\xc6\xf5,\xb8\xf0r\xe6\x9f\u007f\tM\x13;\x19-\x96(\x95\xcbv\x03J\fj+\x9a\x1b/4d\xb4\xc1Q\x95\xe7\x11\xf3\f1\xf9\x99\xa44\xa5\x92\x8a\xe2B\x9cL\xacF7\xa5L\v\u0222_\xa5P\xb8\x19\xd8x\u07cf9\xbe\xdfz\x1eIe}\u0305\x90477\xd1\xd8\xd8p\xeb\u99dfy\x04\xe0\xf2\xcb/}\xe5\x8a\xf9\v}B\x02\xda\x18s\xfa\xdd;\xfb\xfe\xe9\xce\xef|\x95c{\xb7G\xb4\xb6\xb5r\x14VRb\x85\xf5\x02f\x9dv\t\v\u03bb\xca\x16Y/\x88\n\x87\xb1\xb0J$\x19\x14\xda \x03\x81\xf4\x05\xf8Q\xdd3q\xe7]\tI\x8d\xb3\a\x8d\xa9:\xc0$\xb8[\x14\xa7\x12\xad+\x83\x0e\xc2h\x047\xeaV}\"\x8a\xdbA\xd4\xc8\x13:r\xfb\xb5S\xbe\xb81\xfb,\xd2\u040e\x86P\xa3M\x00\x06B\xdf\xee\xee1\xd6fDu\xa3R\x95P\x12\x1dI\rc&X\u0349\x98\xb7I\x1d_\x83\xacDf\xa5\xdd\xe8b2\xcaT\ba#H\x05\xf6\x926g\xab\u0605FS\xb8\u05ab\u0669$\xb1\x8c\x91\xc0\xc6I\xe4\u06b7)\xbd\xe5\xa1a\xa6\xccX\xc1\xfc3/\xe1\xf1}\xdb)\xf4v\xf3\xf0m7\xb1h\xe5\u9d0c\xcf2\xc5-\x9e\xb4\xc4}\x85\xf0\x95 \b\xf1\xfc\xc0F\x9f)\xc9#\x8f<\xc6\xfa\xf5\xebii\x9b\xc8\xecS\u0788r\xeb(\x15KQg\x1b\xdd\x1f\xa6\u04bf\xc4P\x8a\x10\n%\xdd$\x872>\xb9\x19a\tO-\xa5%M\xa3\xc9F\xa3\xb0\u0120\x13\xf1|\x0e\xa9p\xe2\xc8$/\xe6\u0174\xb40\xa6\xd1T\a\x8f&r\x96d\xb6!n@\xfc\xc0C\xe4\x1b\u9735\x92\x86g\xefchx \xcab\x96\x897\xb8\xef{\x94\n\x05\xae|\xd7;~\xfa\xa1\x0f\xff\xd9\xfao|\xe3;\x97n\u06fa\xe5\x8a\xed\x9b7\xe5\x8e\x1e>@\xe0{\x91\xaa&\x88\x1cU\xa3\xcdJJ0\x9a\xae\x1d/\u0473\u007f'\x877>\u0242\v/\xa3s\xe5j\xea\x9b\xda(\x97J\xf8\xbe\aZ#\x05\xf8\xa1\x85H\xe2\x00x7\n_Q2.\xe4\xd2n\x84\xca\xde?FV\":D\x95\u0657\x957J\x11)i\xc6\xeem\xc6P\xd3\xe0\u0435}'\xcf\xff\xe2G\x16>q\x1c\x94\xb4V\xbeJI\xa6M\x9b\x1e.[\xb6\xec\x81\xf8\xff\x99>}\x96=\xa5\xfc\xa1\xd7\u05be\x82\x91\v\x9b\\\r\xf0\x96\xff\xf5\xf9/\xfd\xf0\xdb\xdf9\xe5\xeeo|9\x04T\xeae\xe4\x8bdHd\x1d\x95H\xb9\xd4\xfd\xab\x1d(\xd7Jd[\x86\\s\x06\x91\x89&4\x1da\xff\xec\xdaiN#\x04B\xc9\xc4J\xc3(\xecC$\x06\xa6\x89-E\xfc\u0426\xb2\u07a5\x90\x94\xbc2\xd9\xc6\tt\xce\\N\xc6\xcd\u0606H\xa4\bF)\x18\x18\xe8\xe7\xf8\xb1\xe3o\u0771s\xd7B\x80\xb7\x9fs\xca\x03\xdf\xfe\xca?~\xe0\xfd\u007f|\xf5\x9b\xdey\xd5\xfb\u007f\xb5\xf2\u0333i\x9d0\t\xa4\x93\x0e\xdb\u0104!\xa1_\xb6\x1e\xe9\x02F\xfbz\xd8\xf2\xe0\x1d\xfc\xfa\xfa\xbf\xe5\xa1\x1b>\xcd\xd1-\xcf\xd0\xd0PO\u02f8\xf146\u0593\xc9f\xc1\xcdbT\x862\n\xed\xb8\b7\x13=\\\x90\n\x13E]'gkQ\x11p8R$J\xc5Tnv\xd2df\xf2y\\\a\x1e\xbb\xe9Z\x9e\xfa\xc9wm\xb7\xed8\x11\xf4\x85\tC-\x16-Z\u013cys~$\x848>n\\\x9bZ\xb0`qr;\xfdA;\xf3\xa7\x0e\r\x88\xf3\xa75\x85\u0198\xa6\xfb\xb7t\xfd\xeb\xbf]\xfbOSv<\xfdh(b\x11uJEa\x8c\xc6q\xb3\x9c\xf5\u058f\xb3\xe8\xac+\xf1K%K\x04\xc6<\x896\xa8\xc0X\x82E\xa7\x18\xe0\x8a\x99\x83=.\xc5\x1dA\xfc\xfbX\xe8\xa3J\xd5)\xaa\x8c\xf1\x13T#6\xaf7\xd5\x04\x86\x9d\x8c0V\u0652U\xd5#\ufc5f\x82H\xdd\x14\xa9\x82\x19w\u035e\x86b\x90\xf2\xd8I\x9f\x0e\x12\x83|\xfb\xd6[\xa2h\f\xfcq\xc2\xc8/'<\u007f!R7\x9c\x10v\x98\xc3\u0122\x01\x11I\xc6R\xafQ,\x9b\x8a'\xf6\x1c\x17\x91\u0260\x1c\xbb \xb5J\xe9cS\xafk,\xbdJ`\x19Y\xbdO\n@e2\xb4u\xcc\xe0\xe5\x9d\x1b\x188z\x88\x81#\a\xc9\xd471a\xf99\u4961\xd5\xd5'\x90k'\xaf\xffb!\x8f\u0580\xe7\x05\x94\xca\x1e\xc6@]m\x1dO=\xf54\xd7^\xf7\xaf\xf4\xf5\xf5\xb1\xf2\xfc\xab\x98\xb9\xfc\u0354\u02be\u0748\xe3\xb5l*\x837\x96l\x94\b\u9814\x9b\x14\xf3*\xf6.\uaa0d\xac,\xdc\xc0\x11\x98zEc\xa3C\xaeVAF\x8e\xa9Pv\xdd\xfb\xc6j\xd75\x1a\x1d\xf9$Y\x8bQ]M\x10\xa61\xe34Y\x18\xe1\xcc\xca\u0252s$G\x0fm\xa1\xbf\xefh\xc4\xe3Tn\n\xad\r\x19\u05eds\x1c\xe7\xc1\xfb\xef\xbbo;\xb8\xea\x9ak>\xa7\xef\xbd\xf3\xa7{\x9f]\xbf\xf6\xd6\xfaq\x13\x0f\xb8\x8eZ822\xd2R,\x96D\xe0\x95\x01aD\n\xff0QL\xa5T\x8a\xd2\xf0 \xc7vm\xe2\xd0KO\xe1\x15Gi\x9e4\x95|\xdbxL\xb6\x16\xa3\r\xa1\x94h\xe5D\u0779\x8ax\xaf\xd4t\xa6\x00W\u0187^\x81\x12\x16\xeb\xafVb\xa7g_\x05\xf9\x86\x1cJ\xc0\xba\u007f\xff&\xf7|\xe5o\t}\x1f\xc7q\xad@CJ\x82 \xd4\x13&L\x90+V\x9c\xf2\xe0\xe7>\xf7\xf9O]s\xcd5\u07bd\xf7\xfeB\xde|\xf3\xf7\x93r\xf0\a\xed\xccO\x9f\xd2d\x00^\x1c\xe1\xf2\xfb~\xfc\x833\xd6\xdf\xf5C\xbba\x981\x9dlT|\xe7\xad|+K\xcfy?B+t\u0673\x9a\xf1\xd0 \x83\xa8\x90k\x93\x14\xf2j\xb2\xa4\x82\xb5\xc9(\xe8U\xa9\fJ:Q\x81\x97\x95\x02O\xcac2)\xba\xd5\xf5D\x87\x10\x84\xb1A\x96H&\xe0@@ \xa0`\xc1-\xa1RE0\xaadf\xccfB\x14\xf6j\xb0\u01f1b\b^\x84\xd1K\x91\x86\xbe-\xf9\x14K\x9f\xd2A\xe6c1\xed\u050cDu!\x17\x15hE\xa7:h-\x05~N\x11\xba\x12\xa3\x04F\u026abo\x84\x04\xa5\xec\xa8s&\x87\xccd\x11n\x06\xa3\x94u\xcfs\x05AF\x10:\x820\xfa\xbbQ\u0092a\xa9<\xd3D\xd2(m^d\xe0\x19\xc2b\x89\xd6\t38\xe3\x1d\x1f#\xdf\xd0L\x18\xf8\xac\xbd\xf5\x9b\xac\u007f\xf8!\xb6\x15\xb3\xbc<\xaa\x91\x9ctT\xfc\xbd`r\xb0\x83e\xe52A\x10\x92\xc9dx\xf9\xe5#|\xeb\xdb7\xb1s\xc7\x0ef,<\x93\x85g\xbe\x03T\x8e \x8c\"\u03f5\x1d\x96\x8bo\x85\x8a^>\xf0\x12\xa5r!\"\x1c+\xcfW\xeb\x90q\xe3\xda\xe6ds\xd9;o\xbb\xf5\xb6\xaeo\u007f\xfdk\u0737\xf6\tf\u031e#\xd6>\xf4 \x00\x8f<\xf8\xe0\xba\xc7\x1ey\xf0\xa1\xc1\xa1a\x84\x10\x1d\x9e\xef\xd5\x0f\r\x8f\b!\xa4\x96R\x89\xc4\xdf)\xad\xd8\t\x03\x06\xba\x0er`\u00e3\xf4\xed\u07c9R\x0e\xf5\xcd-\u0536\xb4Y\x8f\x980\xc0\x11\x06%\xad\ubd8c\xeeSM\xac\xb2K\x87R\xa4\xd1\x02\x83r]j\x1b2\xf4\x1c8\xc4\xfd\xff\xfa\xf7\xfc\xea\x1b\xff\x94\x88C\\\u05cd\xe0\x15a\xc0\xc8\x05\v\xe6s\xf9\xe5\x97\xddt\xe5\x95\xef\xbd\x01\xe0\xfb\xdf\xff\x9e\xb9\xfe\xfa\x1b\xf8\x83\x17\xf3\xdbn\xbf\x9dw\xbey\r\x00SW\xad\xfe\xe0O\xbe\xf7\xed\xab\xb7?\xff\x94]6\xd1\x00B\xa50\n\xb2\xb9Z\xcex\xe3\u01d8\xb7\xf2R|\xafhM\xe4\xc7\xe4U\xff\xb6\xa3\xb8\xf8\x0f\x96z\xec\xbf\x1c\u007f\x9fd\xca,u\xb0I\x13\xa2U\r\xae\x10(!\x927C\b\x81P\")\xa2\xd2\x11\xd6\xcc[\xc9\u0502\x8b\xb5\xa5\x95i/\x1dg\x8dj\x18\xf6Lb\xfcobC\x9d\x94\x83\xa3\x11\x15V6\xfd\x86\x8b\u0602 *\xd020(/\xe2\x0f<\x83S68\xbe\xc1\xf1\f\xaa\xa4Qe\x8d*\x1b\\\u03e0J\xd1\xe7\xf8\x06\x11\n\xa4\xb6Gi),.\xaeT\x06\xa5\xa2\"\x1eMz\xa4\x9a\x1c[\xcc\xd3p\u0558l+a\xa8\xba\u046a\xce\xfd\x11,kB\x9fl\xbe\x9e\x86\x89\x9d\x1c\xde\xf5\f#=\xdd\xf4\x1c\xd8\x05\xd9<\x13\x96\x9dC]\u01a1=\xa3c>\xee\xe4\xf5_(\xe7\xbe\x1fR*\x95\xf1}\x9b\xa6S[[\u01e3\x8f>\xc6W\xfe\xe5Zzz\xfb8\xf5\xc2+Y|\xf6\xbb)\x95}\xc2\xd0J[e\\4\x93\x81\x16\xa2\xf0a\xebA.\x1d\xf7\x84BN\n7O\xbb\x8f\uab24\xa6-CM\xde\x0e\x18U\xa9\xac\x88< \\\x89\xcc)\x9c\xac\xb4\xc5\u0704\xa0\xc3\xd8\xf1?\x81\x1bBm\xc64h\xa2\xca\u0714\x14\x1c\xa9\x81\x86\xda\x1a\xba\xf6o\xe4\xf8\xb1CH\xa9PJ\xa5,\x024\xc5B\x91\xfa\xfa\xfa\x17\x1e_\xbb\xf69\x80/\xfe\xc3\xdfs\xd9[\xde\u00b57|\x95\xd0\xf3\u0637o\x1f\xd7^{]\xd7\xfau\xeb~q\xf3\xf7\xbe\xf3p\x10\x84\xadm\xad\xad\vF\x87\x87\xc5\xf0\xf0\xb0\xad\x1d\xc8\xdf\xe8r\x1axe\x8e\xef\xd9\u0281\xa7\x1f\xa0o\xffN\xbc\xe1Ajjkhnk\xa7\xb6>\x8b+\x9d\xe8\xa0,*[a\xea\xd4n\x930\xad\xeaE9.\xf9\xfa\fRJ\xb6>\xf2\x00w\xfd\xf3\xdf\xf0\xdc/\u007f\x9c|/\xa7\xba\x90\x8bi\u04e6\xb1f\xcd\xc5\xcf|\xfa\u04df\xf9\xe3k\xae\xb9\xa6x\xf3\xcd\xff&V\xaf\xbe\xf0\x84[\xe7\xf7\x96&~\xff\x96\xefs\xe5\x15W\xc4\xd8\xef\xacw~\xf0O\xfe\xfe\x99\xc7\xecN(\xe2\xc2\x1a\xb5\xdbR*\xc2\xc0c\xfa\x82\xf3\x98\xbf\xf2R\x00\xc2 H\x82\x9b\xd3\xed\xa90'\x1a\xe0S\xa1\v\u007f#\x8a\x98,Y\xa9P\xd1\xd1\xd1\xc6JE\t\x1dq{\xa1OTtTO\xa1\xa5gm#\u054dg\x10%\x83\xa8\xa9hD\xab\x95\"&\xd1Q\xfb\x1aF|\x83\x1f\rD\xe8\xcag\u06db)\xf6\xb9\x88d\x83\x96\x17\xa8\x98\x19\xc5$\x95\xd4$#\xd2\xc9\xe4^<\x82\x1d\x9b9\xe8\x8aBE\x88\xb8s\x16\t\x14$\xa5\xb4_\a\xfbzXZX$\x01\x1d:\xd6\xfd\xa6HRK2\xc9$?\u057a6ZH\xc5(\x13\x195\xa5<\x9aSu@\x1b\x83\xe7\x01\x03CL\xecX\xc4\xd9\xef\xf98w_\xf7Q\xcaCC\xe0[\x00;w\xec\x00\xe0\x13\u007f\xf91^z\xe9\x05\x96.]\x9e\xfc\\\xabW_\xf4\xbc1\xe6\x03?\xfc\xe1\x0f\xee\x986\xb5\xf3Ov\xec\xd8q\xe1K/md`p0z\xbd\x94\x95-kS%C\x1e\x1d\xe8g\xf3\xaf~\u02ae\xb5\xbfd\xca\xe2UL]v&\xd3V\x9c\u0174\xa5\xabh\x9a\xd0n\xa5\x8ba5\xc1\x19\xf3ZRY\x88h\xa4o\x80\xfd\xcfmd\xf3Cw\xb3\xe1\x9e\xdb\x18Ly\xaf(%\xad\u07cbMc\x13\xed\xed\xed\x9cz\xea\xaa\x1d\x1f\xfb\xd8G\xaf\x16B\xf4\x02,_\xbe\xfc7\xbeY\xbfw1\xff\xecg?\x9b\xfc\xf9/\xff\xe6\x93\x1fY\xff\xc8\x03\x13\x83r\xc9v\xb31;n\fR:\x84\xa1Gc\xeb\x14\x96\x9e\xf3~\xeaZ&S*\x0e\xa7\n9't\xe7I\x896\x95\x9d\x9bTa\xac\x02\x95S9\xd8\xd1N\x82T.B(\x8c\b\xd0\xc2&\x88W\xa6g\xac\xec\u0764\xc0\xe9\xf4\x10ME\xdc\x1f-\xfc\x10(j\u06dd\xbb\"\x19T\"\xe9\xba\x05F\x1a\xfc\x10\x86}M94Q\x87\x1d\x15\xe8\x88\x0f\xb0\xb0\x88\x88\xd2X\xe2\xc1'\x11'\u070d1\nK\xfdt&u\xbeHOC\xa7\xb8\x01i\xa2\xa2\x1du\xe2\x91O\x01B\xc5\x03I\xa6\xca@LK\x119\xe0\xc9dH\x84\xe8\x18\xac\x04H\xd7~M\x95z\xed\xb5\x16\x11\xa9e\x12#}\x1d\xdd\xc1\xb1\t\u007fh \xf0|\xc4h\x81\x05g^\xc6\xd1\x03[X\xfb\xbd/Q\x1c\xe8\xe5\x81o\xfc#\xed\x1dSi\xba\xf0tj\x95\xa6\xd5\r#\xa2\xec\xe4\xf5\x1fI\x10+\x13\x9e!A\x10\x92\xaf\xa9\xa1\xaf\xb7\x8f\xaf\u007f\xfd[\xac[\xf78\xe3'\xcd\u4d0b\xaf\xa6\xbeu*\u00e3#v87\x9eGO\xcf\xc0GJ\xa6\xf4)V0\xb6q:\x91\xa3\xd2\x00\x8e [\xef\xe08\xb2bn\xf5\x9b\x98Y*>/d$\xb21\x834\x01\fht\xd1@`UR\xd2\x11v\xbe\u00c8\xe4\xebUZ\x9e1\u007f3\x86\x92\x96L\x9e\xb1\x9c\x86\x97\x1e\xa2\xa7\xe7\b\x86\xac\u0154\xad/\x93)\x97\u02e2\xab\xab{U\x10x3\x1d'\xb3\xe7\xc2\v/N\x9e\xda\u04a5\xcby\xe8\xa1_s\xe1\x85k0\xc6\xf0\xd5\x1boPB\x88\"\xf0#c\xcc=\xd7_\u007f\xed%\x1d\x1d\x93\xfff\xf3\xe6\xad+\xf7\xec\xd9C\xa1X\xc0D\xba}m*\n\xb5\xb8\xe1,\x17\v\xec~\xe61v?\xf3\x18M\x13:\x980k\x01\x93\xe7-f\xd2\u0725\xb4M\x9bMMC3N&\x83#\x05\xbeW\xa68<\xc4\xc0\u04579\xb8\xe9Y\x0eo}\x91#;7\xd1\u007f\xe4P\xd5=,\x95\xaa*\xe4mm\xe3X\xb6l\xf9\x81\xcb.\xbb\xec\x1d\x9d\x9d\u04f7\x00\xdcr\xcb\xcd,]\xba\x82?x1\xff\xc2\x17>\xcf\xe7>\xf7y\x00\xee\xf8\u065do\xbb\xe6\v\xff\xe7O\xbb\x0e\x1f\x8aX\xe1\xc8GA\x9b\x84\x95\x96B1\uf5372m\xc1j|\xafT\x95\x9c=\xd6M\xac\xaaS\x16\x86\x8a\x9dd\x95\xa9C\xd5\xfa\xab\xea\u06a3\x91\xf5X/-\x8cFF\xc1\xafFT\x8c\xf3c\uf4b8\xb3\x16\xc6Nr\u0274\xd66.\ua041\x92\xb6\xea\x96\xd8\x18\v\x83\xb1\xc1\xe4\xe8\xc0P.\x85\x84e\x8d\x1b\xe5%&\x98v\u0509\x93\x1e\x9f\xaf8\x83Uu\xb7\xc9\"\x8e\xd4-\x15[\x83\x94z\xc4\xc8H~)+\xd3{\bl\u53a4\x9a\xe67l|\xa2\x8a\u07cad\x8b\x95\xe1%G\br\x11w \x85\xdd\x0f$\xc90\xaa\ud0a4$\bt4\x19K\x1c\x17i_\xcf\u8865\xc0+{\xe4\xca\x19\xcex\u04df\u04f3{\a[\x1f\xbf\x8b\ue75b\xf8\xf9\xbf\xfc\x1d\xed\x13\xbeG\xc3\xf2Nra\x89\x1a\xa5\xf1\xf5\u0262\xfd\xdb$\x88a\x18\xe2y>\x9e\x17\xe0\a\x01\xd9\\\x8e\xb2\xe7\xf3\x9d\xef\xdc\u011dw\xdeA\xbe\xb6\x81\x95\x17}\x80\u0273O\xa5P\x18%\f\xc2\xc8\x02\xda$\xa6r\t\xe7\x92\xccW\xd8\xe1\x16Q\xa5\x81H\xb9\xf3\x88\xd4L\x82\xb1\xfc\x89S\xa3\xc8\xd5\u02a8\xdb\x14c\uee0a>\xbcJuf\xacp@\xd6: 2\x18\x05\f[\x82\xc5\bc\xe7\xf7\xc4\x18W\xdc(\xfdb,\xd4\xe7\x05!\xed\x9dKhi\x9bB\xcf\xf1\xc3h\xadQ\x11\xdf#\xa5\x12\x85b\x91}\xfb\xf6\xca{\xef\xbdw%\xb0g\xecky\xe1\x85k\xd2Ma\xf8\xf0\xc3\x0f\xc9{\xee\xb9\xc7\x11B\x8c\x02?6\xc6\xf4\xc1-[\xb6\x8c\xeb\xee\xeeft\xb4\x80R\x8eA\"\xaa%\u0155\xaeo\xa0\xfb0\x03\u0747\u067e\xee\xd7\xe4\xea\x1a\xa8mj!SSg\x9d\x1e#'X\xafT\xa484\xc0p\ufc6a\xf76&_\x85\xact\xe4Z\x87b\xe2\u0109\xac\\\xb9\xf2\xc0y\xe7\x9d{\xf9\xdb\xdf~\xc5\x16\x80\x1bn\xf8\xbf\xe2\x03\x1f\xf8\xd0o\xed{~\xafb\xfe\xd9\xcf\xfe=\x9f\xfb\xdc\xe71\u01a8\xcb\xdf~\xf9\xe7\x0e\x1e\xd8_\x8b1HiI\x99x\xba3f\x8a;f\x9f\xce\xf2\xf3\xaf\xc6\xcd\xd6Q*\xfe?\xf6\xde;\u0732\xab\xba\xf2\xfd\u0375\xf6>\xe7\xe6{+\xe7*\x85RD9`\x81$\x04B \x92\rn0m\f4B\xed6\xc16m\xbb\xbb\xdd\xee\xee\x87\xc1&\xf8\xb5\x03`c\x03\xc6 \x82\xdbX\xc6&H\xc6`L\v\t0 \x19$\x94\x91J\x15\xa5\n\xaa\\7\x9e\xb0\xf7^\xf3\xfd\xb1\xd6N\u772a\x92\x84x_\x9b\xea\xfa\xbe\v\xa5[7\x9c\xb0\xf7Xs\x8e9\xe6\x18\xd3 \xa6>\xe7D\xfb\\\xc4J@\xef-\xc6\xf5\xd8\xe3\xfe\x9a\xc3M\u0e6d\x05\xa2B\xff\xed\x01\xbd\xbe\xc8\xe3\x03\xa2\rX?\xc0\xc1\x80D\xc6\xf7\x85N\x83U\xae\xcfN\x94\xc4y\x8b\u05eeC;J\xdaq\xd0u\f\x17\xaa\x01\xed\xd1[Ulu\xb4\"&\xaa\x96FR\x1a^\xf9\r\u03bc\u0291\xca\xd6^\x0e\xe2\xb64+\xab\f\xa9\x8a\x90\t\xa9\x94\xf4\x15\xb5\xa5\x0f\xec\xf0\xab\xda\xd2\xf0[\xa3\x00\x91\x85!\xeb\u0346\n]O\xb1\xecPv\bF\x15q\xc6o\x1c\x86\xe9\xbd\x03\x92\xc4!\x89\ay\u007f0\x1a\xba\xd3\xf3LN\xad\xe6\x9a\u05fe\x83\xf9\xc3\xfb\xd9q\xff\xb7\xd9|\xc7\xd7\xf9\xebw\xfd'\xec;\xfe\x18s\xf6j\xcen\xce\u04f4\x92\x1b\xf4\xfd\xdf?5j%\xa3\xd3\xe9\x86\xc5 o\xb3\x9a$)7\xdc\xf0)>\xf2\x91\x8f\xd2M2\x9e\xfd\xfc\u007f\xc7Y?\xf5r2'dIRvn.\x18;Uc\f%l@\xda(t\xcez\x94\xe1Hy\xdbe\x06h\n\xcd\u0248\xa8a\x8aJ\xba\x8fZ\xae\xeaj+\xffh\x8c\xc1X\x83\x0ey\xf7M\xc4\xc1\xacCS\x83D\x95\x03!-\xfd\x8fLAe\xe6A\x18~\xc8\x19\x8d-c\xdd)\xe7\xf1\xe8\xb6{H\x92\xa4\xb0\xa0\x15\xe3\x03\x8fgg\xe7\xe2\xef~\xf7\xf63\x9e\xc8k{\xf5\xd5\xcfw@\xf7\xc3\x1f\xfe3y\xcb[~YE\xe41\xe0\xbft:\xad\x0f\xbe\xf3\x9d\xbf\xf3k\xb7\xdf~\xfb/n\u0672u|\u03de\u0752e\xae\xdbh4bU\x95,\xcbJm|\xa5\x93\ah\xcf\xcd\u041e\x9b9\xee\xef6\xf9\xba\u007f\xf8\u007fk\f\xaa\x9a\x1ac\xa2\xd3O?\x8d\xcb/\xbf\xfc\xa1\u05fd\xeeu\xaf\xba\xe2\x8a+\x1f\x00\xf8\xe5_~\xab\xbc\xedm\xbf~\xcc\x06\xf6)\x81\xf9g?{#\xaf~\xf5\xcf=\x05\xff\xf0\x00\x00 \x00IDAT\x17\x15\xeb\u007f\xff\xef\xbf\xf5\xae\xfb\xef\u007f\xe0\xe2#\x87\x0e\xf9\x9a\xd1\xd6WC\xb24alj\x05\xe7_\xf9:\x96\xad=\x9bvk\u059f\xe9Zsw\xaa\xd4\xdeR\xd7\xe4I\x8f\x1a\xb5\xee\xe4\u0783\xe0R\xf3\xe9\xeeUhK\x18\x94\x92\x0fO(\xb7u\xb4R\xfbK\x84\x97QY\x81X\x8a\xe9\x9ev\x80T\x90\x18\x9c\n\x92x\xdf\u7d2b\xb8\x14\xe2\xa0\x1c)x\xff\x8a\xefJ-\xbe\xae\"\x0e\xad\xaa\x05j\xa6G\xf9\u07f5^\x9dKE\x8d\xa3\xbd\x0ex\xda\xeb\x8aW\xbfU\x9d\b\x1a\xf9OD\x91!\x1a3\xd8E\rl\xecA\xdcJ]\x9aFO\ua560X\x04\u027c$\xcbW\xee\xe1\x86K\x95d.\xf5V\xab\x99w\xa1\u031c2?=\xc3\xca\xf5\xe7\xf1\x82\u05fe\x93\x9b?\xf4\xab\xec{\xec!\xee\xfe\xa7\xbf\xc3D\u00d8\xff\xf1\xfb\x8c\x9c\xb3\x92\x8d2\xef=\xe7\xff/~\x17\u007f\x92$\xa5\xd3\xe9\xd2MR\xd2,%n4\xc82\xc7g>\xf37\xfc\xe9\x9f~\x88\xb9\xf9Y.\xbc\xfcg\xb9\xf0\xaa\xd7a\xa3a\x16\xe6\xe7Kh\xd6z\x17V\\?\xb9\xa2\xc9D=\xb3\xa6\xfe2JC\xd7\xe6\"C<\x1a\xd1\x18\u036d\x9a\xf5\xb8\xb2\x1b\xa1\xec\xa6ErE[\xe2\x1b\xc7q\xef\x85d\xd5\xf9\xeb\xcd:\\\xaad\x9a\x15\u02b2\xc2>BJ\x95[FB\xd7\u016c>\xe5bFn\xbf\x89C\a\xf7\xe2\xe2\x18\x1b\xf9\xc8\xc94M1\xc6\xd0\xedv_\x04\xfc.\xc0\xe6\u035b\u0638\xf1\xf4c>\u0737\xbc\xe5\x97U+\xf1\x8e\xcd\xe6\xf0\xa3\xc0o|\xf5\xab_\xf9\xc7/|\xe1\v\xbf\xf3\xe0\x83?\xbcl\u01ce\x1d\x8d\x9d;w\xa1\xaai\x1c\xc7VUE\x8b<\xcez,\x9e\xcb\xdb\xd8*u\x94\x0fw\x03x\x17\x15\xb9\xf7t\xd14M\xdd\xc4\xc4Dt\xca)\xa7p\xed\xb5/\xfc\xa7w\xbe\xf3\x1d\xff%\x8a\x9a\x0f\x00\xfc\xfa\xaf\xff\x9a\xbc\xff\xfd\x1f8\xee\xad\xf1\x94t\xe6\xaf~\xf5\xcf\xf3\xc1\x0f\xfe\xb1\x05\xb8\xed\xb6\xafo\xbc\xed\xb6o\xfe\u008e\x1d;\x00\x12k}]W\xf2\u007f\xb7t\x9d!q\x11\xa9\xb3\xa4\x1a\x91jLFL&M2\x19\"3C\xa4v\x88\xcc\f\xe3\xec0\x1a\r\x03C\x18mbhb\xb5I\x94\u0158,\xc6h\x03#MT\x9b8i\x10\xd9!\xa2x\b\x1b7\x89\xa2!\xa2\xa8\xe9?g\x87\x88l\x83\xd84\x88\x8cW\x93\u0628A\x145\x88L\x93H\xe2\xfa\a\x11\x111\x111\x96\b+\x91W\xa4`\v};=\x1dM\xf5P\xa2\x92$$\xc5\x10\x95B\xd9`RG\x94)C\xaa4Rh\xa04\x9b\xc6W]\x91\xff\x90\xd8x)\xe6\x90A\x86\xa4\xf8\xbb\x19\xb2\xd8a\u007fs\u01e3\x16\x19\xb20d`\xd8\x12OD\x98\x89\x18\x9a\x96\xb0}L\x16\xfc\xa9\x17ff9\xe5\u072b\xb9\xfa\u07fe\x9d\xc9%k\x00\xb8\xeb\xcb\u007f\xc9_\xbd\xe7\xbf\xf1\xad\a\xf7\xb1\u06cd\xfa\x83\xe2\x04/\xcd\xf3C\xb3\x9b\xa4\xb4\xda\x1d_\x91\xa7)\x8dF\x13k-7\xde\xf8\xb7\xfc\xd1\xfb>\xc0\xfe\x03\xfb8\xfb\xa2kx\xd6K\xde\xc2\xd0\xf8R\xda\v\xf3\xfe^s=\x90\xac\xd5\x05\x1c\x0f\xaa\xc6D=\x86W\xd2W\xf8\x14\xdeXV0MCs\xccb\x1b&tj\xdaS0\xd5|i\x8bR\xa3J\x8b\x16\xdar\r\x8a\x8e\u0448xQL\xf5_i\xcd\x1f\xe1\xce/\u007f\x12#\x86\xf8\x1d\xef\xe5\xa5\x17\xac`\x95i\xa3\xa9\u00dd\x90@\ue2e0\x1c\u023b\xdd\x04\xe7\x1c\u0366\xcf\xc0\xfc\xf4\xa7\xff\x8a?\xf8\x83\xf7\xb1o\xdf\xe3\x9c~\u0795\\\xfe\xd3ocb\xd9\x06\xda\xf3\xb3!\u078f~\x806\xa1\x1f\r\x1b\xd3&X`\xe4r\x01A\x06z\x1a\xa9\x88\x1f\x90GBc\xd8\xf8\x83\xdb\x1cM\xf5R\xad\xc2{\xaf\xc6RY\x95\xdblHX\xae\x91\xa1\xc8\xdf\xdb\xf8`\x18\x13y\x03=\xa7\xa5*R+j\x10\x102\x97\x11\x0fO\xb2\xfa\xe4\xf3xt\xeb\xbddY\xf09\x0f\x1d\xc0\xec\xdc\x1c\x87\x8e\x1c^\xf6\xe0\x83\xf7=\v\xf8\xa7'\xfb\x1e\xbc\xf1\x8d\xff\x9eO|\xe2\xe3l\u07fe\x83\xdf\xf9\x9d\xdfED\x16\x80\x0f\x01\x1f\xfa\xc2\x17\xfe\xee\xd5_\xfb\xda-W\x9ey\xe6\x99/\u07bf\u007f\xff\xa9\x0f?\xbc\x89\xd9\xd9Y\xb2,+\ue0fc\xc2/\xabq)l\xa7\x15\xaf\n\xf3n\x8f\x868\x8eY\xb6l\x19g\x9cq\x06\xeb\u05ef\xbb\xf95\xaf\xf9\xf9\x0f\\u\xd5\xf3n\xcd\x1f\xcb?\xfe\xe3\x97y\u044b^\xf2\x84\x9b\xd5'\r\xe6w\xdf}\x17\xef~\xf7\xbb-\xe0n\xb8\xe1c/\u07b1c\u01db\xf6\xef\u07c7\x18\xa3\"\xf5\xba\xcae\x19C\xa3S\\|\xf5/\xb2\xe2\xa4\vH:\v~S\xaag\u02cb\xca\"\x8d\xf6L^\xacu4\xa3\x94\x86\xcd\x18\x96\x84\x86\xa4\fI\x97a\xe92b\x13\x9a\x92\xd00)q\x0e\xe6&+9\xac\x82\xb7\xf6\v*V|[\xe7\x804\x04\x19f\xea\u056fF\\q\x11:\x04U\x03\x91\xc5\x19K7\xb3$YL\xd7\u0174\\L[c:\x123\xa7\x11F\x84Fp\x8bS'\xb8\xcc\xe0\x9c\xff\xb9\x19\xa6\x18h\xf6\xc4\x1e\xd6\x14]\xa6\xea'\xaeT\x92\xed\xeb\x19$\xd5\xd7E\n(\u05c1\xf3\x02\xa9\xef\x9a\xd1\x176\x98\x17X\xa9C\xe6\x1dL(\f\x1b\xfa\xcd\xcd{\x84\xa1R\x0e\xba\x8cJ_a\x16\x19C\xbbaH[Bd\xbd\x8aG\x9d7-\xeb\xb6\xdaH\n\x17^\xf9z\xd2\xd6<_\xfb\xec\xef\u041a\x9f\xe6{\xffp\x03Y\xda!z\xe7\xef\xf1\xaa\xcb\xd61f\xbb$\xdd\xf4\x84\x92,V\x81\xbc\x9d\x03\xb9*###\xb4Zm>\xfd\xe9\xbf\xe4\x83\x1f\xfc\x10\xfb\xf6\xede\xe39\xcf\xe2\xaaW\xfc'\x96\xac:\x9d\xf6\xfc\\!\xed\u04f0}\x9c\x83_!\xd5\x15?\x18\x97P1J\xbf\\\xa0\xf6~kP99+D\rCc\xd4z7\xce\xda\xf5U\u05dd)\x83\xae\xd9z%\xa1H\xcfj\x82b\x9a\x06\x9d\x8cQ#\x18u\x98Lp\xa9\xef\xe8\xb3\xf0\x18sS-\x05\xd24\xa11<\u02aa\xd3/f\xe8\u06dfgnn\x16\xa7.\xb8\n\nY\x9a17;?~\xdbm\xdfX\xffT\u07cb7\xbe\xf1\xdf\xd7\xfe\xfb\x93\x9f\xbcA\xae\xbb\xeez\xfd\u065f}\xd5g\x81\xcf\xee\u0739\xfd\xec\x1bn\xf8\xe4E\xe7\x9dw\xfe/\xec\u07bd\xeb\xca\xc7\x1e\xdb9\xb6g\xcfnZ\xad6Y\x96\x9bx\xd5\r\x05}\xd5ni4b\xc6\xc6F9\xe5\x94SY\xbcx\xc9c\x13\x13\xe37?\xebY\xcf\xfa\xf6u\u05fd\xf1\x8bA]\xc3_\xff\xf5g\u456f\xfcY\xfd\xe2\x17ozR\x8f\xfbI\x83\xf9[\xdf\xfa+\xf2\x9d\xef|'QU\xfb3?\xf3\xd3o\xbc\xf7\xde\xfb\x82\xca\u0358\xdcs\xa5\xfa\x86\x9eu\xf1\xcfp\xe6\xc5?\x83s)i\x9a\x14\xff\x96\x05g5*\xa0dEi\u0614!\xd3e,\xea0\x16\xb7\x19\x8a\x12\x86\xe2\x84f\x94\x10\x9b\x8c\xa6&44#\x96\xd4W\xe1\x15@s\xf9\v\x17\x92L\xf2\u007f1E\r\xa2\x95\\g\xc1\xa9\t\x16\x95a\x80n\xb4\xc2\x15\xe6\xaelJf\xfd\xae|\x86\r\U0010d84b\xa1E\x8c\x03\xac\x962=\xd4\xcb\xf7<\xa5\x13\xd1\xca\x1a\xb4\xb3\x98D-i\xc8\xd2L\xd4\xd0\xcd,\x1d\x17\xd3uQi\xf4U9\x80\xf2}Q#\xa5\x11W\u0756@\x8f\xcaWr\f-~\x11\xc2\xe1r]\xa1@'C\u06e1:\xef\xfbV\xad5N\"\xa5}\xa3\x88\x86%\t-\x00$\xb2~\x13\xb0\x13\xf2V%\x8fn\xf1V\xf6t:m\xd4)\x17=\uf348\x8d\xb9\xe5o\xdf\xc5\xdc\xf4>\xee\xfa\xea_\xf1\xfbs\u04d8\xdf{\x1f\xff\xf6\xca\xd3h6\"\u04a4M\xe6N\x1c \xeftSZ\xed6\xddn\x02x\xbf\x95\xfd\xfb\xf7\xf3\x17\u007f\xf1q>\xf1\x89O23}\x98\xd3\u03bd\x9c\xe7\xbc\xe27X\xbe\xee\x19\xb4\u06c1ZQ)\u02e3\xea\x06X^\x1d\xe6\x89Q6\xea3\x88\xeb\xab\x02BI\xec\x8c@$D\u00c6h\xccz\x95\xabj\x0f\x0f_W\x95Uw\x1c{y\xf8\xde\rfo#\x10$\x89\rA',\x96\x98\x86\x80\xeb*\x9a*Y\xe6z\xe8y\xc1\x89\x92\u0186\x89u\x1bY\xbcj\x1d\xb3\x0f\xdd\xe7\x15&\x01\xcc\xd34\xc5X\u04dc\x99\x99\xbd\x1c\xf8\u060f\xfa\xde|\xf4\xa3\x1f\xe1\xba\xeb\xae\xd7/}\xe9f\u067au\xab}\xdb\xdb~-[\xbb\xf6\xa4\a\x81\aU\xf5+7\xdc\xf0\xf1\xa5\xd3\xd3\xd3\xcf\u0777o\u07f3\xf6\xee\xdd{F\x9a\xa6\x97\xee\u0673\xc7\xce\xcd\xcdfI\xe2+\xf6f\xb3!\xabV\xad2\u02d6-\xdf\x1fE\xf6\xd6\x15+V\xdc\xdbj\xb5o\xbb\xf6\xda\x17\x1e\xb8\xea\xaa\xe7=\xfc\u044f\xfe\x05o|\xe3\xf5\xbc\xeb]\xbf\x1b\xbd\xf5\xado\u0396,Y\xfe\x94\u0298'\x05\xe6\u007f\xf5W\u007f\xc9k_\xfbz\x05x\xff\xfb\xdf\xf7+[\xb7n}\u0561C\x87\x101&\x0f0\xc8\u06dd,\xed\xb0b\xfdy\\\xf0\xdc724\xba\x88n\xa7\x85SC\xa6~\xa8bP\x1a&e\xd8&LF\v\x8cGm\u01a2\x0e\xc36a\xc8vi\xda\x04k\x1d\x91u\xc46\r^\xc9B\x949\xbf(\xa3y\xe8jYaD\x92o\\j\xe1\x87.\x95\xaaV+2-\xff\xb5\xfe\x00)\x82\xe6*b\x13'%\xf4[\xc90Vi\x900\f\xa5\x99\xb7U\x0f\xb6A\xe1\x81+I\xbe\xdc0,\u0448\xc4Y25t\u0552:K\xa2\x96\xc4YZY\x83\xb9\xb4\xc9|6D;\x8b\xe9d\x11\xed,\xa6\xed<\xf8g\xcex\x85Gx\xbd$\x1cL\xf5\x84\xf3\xa3\u0718\xb9t\xac\"\ub522\x82\xf2\xca\x112\xf5+\u0459\xc2B\x06\x13.\x80o\x0f\x87Z\x1d\xa6\xa9\x1fJ\x99\x1a\u0397z4\x01\x86\x87,:bI\xdb\xce\xfbT4(\xaas\x14\xba\x9d\x16\x99\x89\xb9\xe09\xff\x8e\xb81\u00ad\x9f{7\a\xf7n\xe3\x87\xdf\xfe\x12\xefz\xdb\f\x87\xfe\xeb\xefr\u077f\xb9\x8a\xa9\xc6\b\x92.\x90\xb9\xe3\xcf\xdc\xfe5\x03\xb9s\x8eN\xa7\uba55$\xa3\u0448i4\x1b\xfc\xf0\x87\x0f\xf1\xa1?\xfb\b_\xfc\xe2\x17I\x92.\xa7_p5W\xbe\xfc\xd7X\xbe\xf6,Z\xf3sE`H>0\xec\xe5\xbf\xf3hF\x9f\x16\x15\xd5b\x1a\xebB\x83\xf2\xfbT\x84\u0302\xb3\x105\x84x\xccb\x1af \xaf\x9e\u007f\x97\xab\xca\x19\xe9\x8dB+7\xcb\nc6\xa9\u020d\xf3\an\x053f\xbd\xc4u.C\x13\x87I\xfd\x02\x8es\x81\x8e\x14\x1f0\xddM\x13\u2265\xac9\xf3Bv<|\x1fY\x96\x95\x1d\x87\x88v:]\u067am\xdb\xe8\xd3\xf1\xfe\xfc\xd2/\xbd\xb9x\xb9\xde\xf6\xb6_K\xb7l\xd9$\xdf\xfc\xe6\xb7\xe2\x1bo\xfc\xac\x84%\x9e\x83\xc0\u00ea\xfa\xc9\xe9\xe9\x83c\xb7\xdcr\xeb\xe4\x9dw\xde%{\xf7\xee\xd5V\xab\x8ds\x8e\xf1\xf1Q\xb9\xe0\x82\v\xe5\xf2\u02df\xdd9\xff\xfc\v\x0f\x06\xea\x86\xf7\xbe\xf7\xf7\x00x\xd9\xcb^\x1a\xfd\xc6o\xfc\xba\xbb\xfa\xeak\u04b7\xbf\xfd\xb7\x9f\xfa\xb5\xf4T\xbe\xe9;\xdf\xf9\xf6\xea\xf7\xbc\xe7=\xdf\xfd\xfa\xd7o]\xdfj\xb5\x82\xbfGXo\n\v(\xcd\xe11\x9e\xf7s\xef\xe0\x82\xe7^O\xbb\xe5\xe9\x15c\x1cC\xa6\xcbx\xd4f2n1\x15\xcf3\x1e\xb7\x18\xb3\x1d\x9a&\xc5\x18_\x89\x1aQR1\x18\xeb\u0273\xcc\x18\xc4(F\x15\x9b\xf9\xe0X_X\x8a\aS\xa9\f^\xd4ar}uu\xa8\xaau\xa6\u064a\xab\x0f\x12\xf3!k\xc9\x0ec$\x0f}\xf6\x15\xba\xcd\xd70\x8b\xc8(\xadK\xb2\xd4oFV\x01\xbd\x9e}(\xc1\xb6\xd6\xf3\xf2\x8a\x1f\xe0v3K\xe2\":.\xa2\xed\x1a,\xa413\xe9\b\x87\x92Q\x8e$\u00f4\xb2\x06Y\x18\xe4\xaa\xfaX-\x11\x87\xad\xcc\x06t\xc0[YU\xee\xf7\xd6\xf4\xf9\xf3\x1a\x8a\rQ$\u0218\u016ci\u0090\xad\u0336\xf4(\x17J\xdd'\xa7\\\xf5\x0f\xfa \x11\xba\xad\x8c\u03be.\xe9B\xe6_\xd1\x04\xa4\xebB\x86\xa8?\x15\xa2\xb8\xc9Ps\x84\xed\x0f\xde\u02ad\x9f\u007f\x0f\xdb~\xe8#\xb2&W\x9c\xca/\\\xff\x1b\xbc\xe9\xba\xd7q\xe6\x86\t\u0439\x90\x1a#?A \xee/\x93$H\x0f\xfd\x8a\xbe\xf7$\a\xf8\xdf\xff\xfb\x16\xfe\xf4O?\xcc\x1dw\xdcA\xa39\u0139\x97\xbd\x8c\xcb^\xf4&\x16\xaf\xdaH{a\x864I\xcb\xf9\x8cJ\xb0G\xf6T_\xfe\x1e\xf8\u0160\xc8\xe7\xb7\u06a8\xef=T\xd5>\xabB\x17\x19\xd2\xd8+\xb8\x86'\"\x86\x975\xb09\xc52\xb0\x1b\xec\x8d%\xee'\xf7\xc2\xee>I\xbbE\x9a$a#\xdbk\xb6\x9d\xba\xc2\xd8G\x83\x8d\xb3.d\xb8\xd9\f\xd7\xf5\xd6\xd1Y\x9a\x87\x94\x85\x1fl-c\xcb\xc7\xd9\xf3\xd0W\xb9\xe9\x0f\xff3\xdd4\xa3\xd1h\xfa\x19M\x96\xb1x\xf1\x14\xe7\x9fw\xce?~\xe9\xef\xbf\xf4b\x80Gwlc\xfd\x86\x93\u007f,\xef\xe3\xddw\xdf)\x17\\p\xf1\x93.5>\xf8\xc1?\x91\v/<_\xaf\xb8\u2aa7\xed\xb1<\xe1\xca\xfc\x86\x1b>&\xd7_\xff\x8b\n\xf0\xb9\xcf}\xee?\xdfs\u03fd\xeb[\xadV\xb12\xae\x85\x1e\xd9\xe0\\\xc2I\u7f00\x93/x9I\xeah\xd2fj\xa8\xcd\xe2\xc6,K\x9b3LF-\x86l\x12\x86\x95.\x00k\xa9\xadQ#\x88U\xc4\xf8\xab\xd5\xe2\xbc;Cn\x8e\xdf\x13\u03e3\x02\x11\xce{P8oA\xa99\x8dS\xc4\xc7\xf5\xd8\xceV\xeb\x87\xf0W\x93[\u0245\x03B\xc2\u007f\x8bh\x1f4\xd6d\x81\x15\xfd\x9eV\xdd\xd2\\8\u07e8\xef\t\xe5\x81\u0222\x10\x89\xa3iRT\u06e1s\xf0|{\xa2\x1e\xd8\xe7\x92&3\xe90s\xe9\x10sY\x93\xb9\xb4I;k\xd0v1\x9d,&US\x1c\x80\xa6\x10\x97k\x11\x1a\xa1\x03\xd9K\x8a!T>\x84%QoY0\x94'\xa9K\xb1*\xcd1H\x1bz+\xf4\x9c2k\bQ\xd3\xe0:\x19i\nQ\xee@ \xe5\xe9\x99$\x1dP\xe5\xa4s\x9e\xcf\u02e6\x96s\xdb\xe7\xdf\xcb}\xdf\xfd\x1c\xd3{\xb7\xf0\x91?\xf8M\xb6\xfc\xf0>\xde\xfc\x1f~\x85\u02dfy6\xe3\xa3]\xa2(\xf5\xaf\u047f\xf2*]\x80,s\x85\x85m\xa7\xdbE\xc4099\u026e\u077b\xf9\xdc\xe7>\xcf'>\xf1)vl\xdb\xc6\u0112\x95\\z\xf5/p\xe1U\xbf@sd1\v\xb3Gp\x9a\x15\xf5o\xd9\fJmP\x98\x87q\x8b\x8d\x91\x82'\x1f !\xac\x8cR\xd4\b\xce\xfa\xfd\x83F\xc3\xd0\x18\xb3\u0626\xfch@N)f\x10c\xbc\xfcT\f\x98P\u03c7\xa7\xa2&l\x83\n\u0208/\b\x99\xf1\xdeDe&y\u0634\xce2\\\n\xe3+Nb\u046a\xb5\xec\u067e\x05\xd5\x06\x1a\xf6Ifff\x19\x19\x19=OU\x9f+\"\xb7\xed\u06ff\xff\xc7\x16r\xf5T\x80\x1c\xe0W\u007f\xf5mO\xfb\xe3yB`\xfe\x8ew\xbc\x9d\x1c\u023f\xf1\x8d[/|\xf7\xbb\xdf\xf3\xeb\xfb\x0f\x1c\xf0\xb8k\xad\x94\v\xbfB\x9a&,Zy:\x17_\xf5Z6,\x1fa4\xd9\u02b2\xb1y\x964f\x19\xb1\x1db\x93\x16tAUl/a\xffW\x83\x0e\xdaX-\x92uL\xa5as\x01\xd0\x05%B1\xeaC[\xadj\xa1V\x91Z\xb1\xec\xe5q`\u020aX\xaa\xd2\tP\x04\xacq~\x81\x06\x10\xe3j\x1b\xa5\xf5\x14\x94\x92{\xd7\xdeK\xba\a\xd9D\xf0{\xf0\xa6\xde\xd2JE>\xe6zt\x04&\x1cj\x16\xa1I\xc68m\x966\xfc\xefs\b\xa9\x8bh\xb9\x98\xf9\xb4\xc9L2\u0311d\x84\x83\xddQ\xa6\x93\x11f\xd2a\xba\xce\x06.\u0495@-=\x83\xd7\xea^Gx-\x9c\x06\xd7\xc5N\x99cU\x8clU\x06\xc8\u0434\xf4\xb3\xd1j\xd6G\xa9\u007f\x17\x03v\xc8`\xe6\x8dW\xa78\x17|B\xea`\x90\xa6]\x16\xe6\xa6Y\xb2\xfa\x19\xbc\xe8\xf5\u007f\xc8\u0112\xb5|\xff\x96\x8f\xd3i\xcd\xf1O_\xfc\b\x9b\x1f\xfa\x01\xaf\u007f\xfd\xaf\xf0\xaaW\xbc\x82\x8d\xa7\x8e\x11\xd9\x0e\xe0\x82g\u01bf\xcej\xbc\x9b\xa6t:\t\u076e7\xc3\x1a\x19\x1e%u)\xb7\xde\xf6\r>\xf5\xa9Os\xeb\u05ff\xce\xdc\xfc<\xabO>\x9b\x9f\xba\xf6\xdfs\xe6%/\x05c\x99_\x98\r\x87\xb4)\xfc{\xaa\U000196e0i\xd0u[\x1bC\u0413\xf7\x8f\xb4\xc3\x15]\xd9\x15r\xd6\a\x9a\x98Hh\x8cx\xae\\\xe4h\xbar\xa9\u02e6D\x06\xb6\xfcZQn\xe5v\xc99\xe5Y\xec^h\xe9\xcb+\xaa\x9e\xff\x1e\x01\xe3\xac\x1f\xce\xe7a(\xb9U\x84\x13\xba\xf3\x1d\xa2\xc6\x14K\u059d\u02ae-\x9bp\xea0j\x8a\x8e\xe3\xf1=\x8f\xa7\xb7|\xfd\x96\x04\u0ef7\xdfqB\f\u045f\x10\x98\xaf\\\xb9\xb2\xf8\xfb\x8d7\xfe\xcd\xff\xb8\xe7\xde\xfb\xe8\xb4\xdb\x18\x13\x891\xd6k=\xf1-N\xdc\x1c\xe6\xaa+\xae\u19df\xb9\x8e){?\xa3#s4M\xeaU&5\x11S\xd8N\xab,Gj\x0e\x80\xd6S\ty\xa5\xaa\x05\xf0\xf9*\xbdAF\xa4Y\xc1K\xe7\xa1\xce5hT\u03e7;\xf1\xc6R\xb9g\x9b\xa0\x18\xeb)\x1fc\xb4\xcf\x1d\xdfU\x00\\\x06\xd0\f2\x803\xa4F\xd8\xf4\xaf\xcfk\xb5\x1f\xc8}\xb0r\xbe>\x1f\xd4\xf6\x82l\xe0\xfb%\f\x1a\xad8\x1a\x921\x12uX\x1c\u03e1\u00de\xa2ie1G\x92\x11\x0et\xc69\xd4\x1d\xe5p2\xcaL2\u0302k\x92\xfa\x8d$\xff3\xf2\xdf]\t\xf3\xcc\xfd\xd4s\xcb\x01M\xfc\xf2\x86D\xd5\v\xa3W-S\xbe\x83Z\x1b\x8c\xf6v,\x826\xbdf]\xbb>\xcb\u0569\xab\xf8h\x97\xff\x9fe)\vsG\x18\x1a[\xc6U\xaf\xfc\u007fX\xb1\xfe\\\xbe\xfb\xe5?a\xcf\xf6{\xd9\xfa\xd0\x1d\xfc\xbf\xefy\x98\x1f\xdc\xf9\x1d\xae{\u00db\xb8\xe2\xd9\xe735\tQ\xdc\xc5e\u067f\x1aP/\xd4*\xdd\xc4\aF8%\x8ab\xe2\x86a\u04e6M|\xfe\xf3_\u099bnb\xeb\x96\xcd4\x1aM\u03be\xe8\x1a\x9e\xf9\xa2_d\xf5)\x97\xd0I\xbat\xdb\v!\u4efa8\x96'?yE\x94\xe6\xaa\x151\x9e\xfa\xb4qE\xef]\x16'\x94S\xa2R\x8d\x12xr\f4\x86\f\xf1D\xe4\xe7'z\xac\x81{\x8f4\xaa\xe7_\xb4RIh\uf234\x92\xf9\xe9\xfa\x0e\b\xdf6\x9aQ\xeb\xbfo&-\xae\xad\x00\xd7d\x9d.\xcd\xc6\x18\xe3\x8b\xd7x\u05be\x90\x05B\x96e\xb4;\xed\xc9\xfb\xee\xb9g)\xc0\xc2\xfc\xfc\t\x11?\xfb\x84\xc0\xfc-o\xf9e\x00>\xf5\xa9\x1b\x9e\xfd\x81\x0f\xfc\u0275\xd3G\x8e\x14Uy\u0357A3\xce\u06b8\x91\u05ff\xe8RN\x9f\xd8K\xb7\xbd\x00\xa2\x85\xf6\x1b\xb4\x00\xe5\xfc\xe22\x81\u05b0\xe2.\x979Cwa*\xdby\xf9\x9c2\x1f\xd4\x16^'Z?-\x02m\xa4\xd4Z\x00\xac8\u01a3\x0e\x13Q\x9b\xb5\u00c7\u9e88\u0664\xc9t2\xc2\xc1d\x9c\xc3\xc9(\xd3\xc90\u04e9\xe7\xddS5\x98bh\xac^d\x92{\xe78\xc5%\x0e\xd7\xcdhD\xb6\xbc\xf1e\xf0-\x9c\x1bj\u55a6\xd5\n>\xb7\xa0qF\xc8b?0\xd5pP\x9az\xc0^e\x96\xa1\xb4\x17f\xb0\x8d\x06\xe7\\\xf1\x1a\x96o8\x9b\xef}\xf5\xc3<\xf0\xdd/\xd0^8\xc2\u035f\xff0\x0f>p\a?\xfd\u04ef\xe5U\xaf\xfc\xb7<\xe3\xec5L\x8cCd\x13\xd24)d\x8c\xff'\x02{1\xe4\xec\xa6d\x99\xa3\xd1h\x80\b\xbbw\xed\xe6K\xff\xf0e\xfe\xee\xef\xfe\x8e\xbb\u007f\xf0\x03\x92\xa4\u02d2\xe5k9\u7c97s\ue56fat\xf1:\xe6\x17\xe6H\xb3^gQ-=u\xb4\xea\xc1\x13\xb6\vm\xe4\xf5\xe4\x95\xd9F\xff\x9et\xa5\xbf\x14p\xd6x)b$4\xc6\"\xec\xb0=\x06\xbdBeVt\xb4\xc9\xdb\xd1.\x9c:\xfc\xe7y\xb9\xb9\xec\xd5I\xe9\x0e\x8a\x11\u0730A[\x02]\x17\x16\x87$\u0200S\";\xc5\xf8\xc4j\xaf3\x0f[\x98\xde\xee \u0262\xc8N\xce\xce\xcd]\x04\xdct\xe8\u0421\x13b\x15\xed\xb8`\xfe\xe8\xa3[e\xfd\xfaSTU\u01ef\xbf\xfe\xba\xdf\u06f1\xe3\u0471N\xa7\x83\xb1\x91\xe4\u0546\x15%IS\xc6\xc6\xc6\xf87/\xb8\x8asNZL\xb7;\x1f\xb8\xdc|PG\x9f\xc9S\xfe\x9e[\x93\xf9ac\x14\xacV\xd5W\xe5\xa2\x10k\x86\xa8\xd2$\xf5\x03H\xadT\xf6\xf4.\xd6\xe4K:e\xb5\xab\x95\u0163\xd4\x18\x1f\xcc\n\xc1Y\xd9W\xfa&\x1c2B\xa9\x98\xf5\xa0W\x17ZQY\u0411ZUr\x94J]\x06\xb2\x1b>\xb1\ajUj\xde=\xa3G\xd1\r\u0200\x9bD\xa9t-B\u04e44\x9b\tK\x9a\xf3\xacs\x87ie1sY\x93\xc3\xc9\x18\xfb:\x13\xec\xedLp\xb8;B'\x8b\x83\n\xcd\x0f\x9fr\x1c\xeev\x1c\xdar4\x86\xad\x9fW\x1c\xe5\xa8R\xf2\u03ae-w\xb1\xf9\xe1\xbb\xf8\x93-\xf7\xf3\x8d\u06fe\xc4+^\xfe:^\xfc\xe2\x97p\xc6\xe9+\x19\x1f\x8f\x81 }\r-\xf9\xff)\x1a\xf5\x1c\xc8U\x85F\xa3I7\xe9\xb2o\xdf\x01n\xbd\xf56>\xfb7\x9f\u5bbb\xee\xe4\xf0\xa1\x03\x8cM,\xe6\x94s.\xe7\xfc+_\xc3\xda3\x9f\rv\x88\xd9\xd9#%h\x86*E\\X\xe8\x91\xea\xec#\f\xf9\xc5`L\x8c\xb1q\t\xfeG\xad\xa9+\n\x94\xbc*\x0f\x16\xb7v\xd4\x06\xa7\u0363T\xe5\xc7RR\x95\u00e9Z\xdbVv\xa6%}Z\xfdr\xcde\xc5Z\xce{2\xf5\xb4+\r\x03\xad\xb0\xf2\x9f/\xe08\x05\xb5\x8cN\xae`dl\u048b,\xac\xb7\xad\xb5\xc6\xea\xbe}\xfb\u067d{\xd7Ya\x89'{\xfc\xf1\x9d\xb2r\xe5\u069f\xe8\xea\xfc\xb8\xe1\x14\x87\x0e\x1d\x92{\uee57ukW\xbf\xf5+_\xf9\xc77m\u0672\x05D4\x8a\xe2B\xfb\xe1\u0375\x84k.\xbf\x8c\xb7\xbc\u654c\fY\u04b4\x8b1\x1a\\XC\n\x8f)\xe5\u007f\x0e\xc1\x18%6\x19\xd6(\x1aU\xd4T~\u007f@\x11\xa9\x01\nEt\x9e\x11e\xd4v\x18\xb1\x1dV4f8i\xe4\x00\xfb:\x13\xeciO\xf1x2\xc9\x117BK#T-MBu4 \x06(\u007f\\\xf9AX\x030\xf17g\xea`\xbe\xeb\x98K\x1c\x99z\xb32\x97o\xf0U\xed\x84+s\x93j\xadX0\xbb\xaat\x17\xe6\u0212\x06\xa3S\xeb\xb8\xfc\xe5\xbf\u0269\xe7]\xcd}\xdf\xfe,\x9b\xee\xfa*\xfbwm\xe2\aw\xde\xc2=w\u007f\x9b\x9bnz&\u03fd\xea%\\\xfa\xcc\xcb9\xed\xb4SY\xbf~\x19\x13c\x06c\xbb\x88\xa4\x15J@~L\x00^\x1a.\x19c\x18\x1a\x1a\x06,Y\x96\xb0\xe3\xb1\u01f8\xf7\x9e\xfb\xf9\xd6?\u007f\x87[o\xfb\x06[6oaf\xe60\xd6X\xd6m\xbc\x80\x8d\xe7^\xc9i\x97\xbc\x94\u0255\xa7\x93e\x8eVk\xde\a\xaaH\x91A\x86:\xa9\f7)\xe8\x95\"\xcd&O\f\n\x15y\xfd\xaa\xae+\xb1*\x11.\xbe\x832!\xe3\xd5\bi\x03h\n\xc3F\x8e\xbe\x96\xa6u\xb6\xbd\xa0\xe3BA\x93\xef\u007f(up\xef\xe3\r{7P\xb5\xfc.\r\xee\xa5\xdd\f:\xed\f\xd7J\x91\xd4\xfb\xf6D\x95\x94\xaf\xa4\xdbab\xd1*\x16\xafX\u03ceG\xeeF\x1b\xc38\x1cVD:\x9d\x0es\xf3\xf3g\xddx\xe3gO\x03\xee\u0773\xe7q\v?\xd9.\x11G\x05\xf3\xbb\xbe\xf7\x1d\xce?\u03db\xa0\xbf\xff}\u007f\xf4s\x0f=\xf4\xf0%\xd3G\xa6\xb1\x91\xb5\xd6V\xc7\x16\x8a5\xc2\xf3\x9eu1\x97\x9c{&I\x96\x90\xe2\u021a\x96\xc8xm\xb6\x84\x05\x1d\u07d3\xfbIvL\x1alUC\x85\x1b<\xbf\xab\xc0j\x8e\x9aI_\xb7\xe9\xf4\xd5x/\x05Q\xfaN\xf8'\x9aa\xaa\xd5v\x0f`\x0f\xfa|\xfd'j\xcd8_+\u0740\x1c\x85)\xd4c3\x88\xc7\xe9\xcfC\x84\x9b\x96R\xc1\xa2\a\x19\x14\x84\x9a\x83\xb7\xeb}\xd4\xf5\xd7+2)K\xe3Y\x16\xc7sl\x189\xc8\xe1t\x84=\xdd)v&\x8b8d\xa7\x10\x1d#u\x06\x1bUm\x05J\xb8uZ\x06S\xf7V\xa4\xdd\f\u6e8e\x85\u0115C\u047cC\xa2\xb6@\xd838\xa5\xb7\xe7.Z\x98,Ih\xa5G\x88\xa2\x06\xcb\xd7_\xc4\v6\x9c\u03f9\x97\xbf\x92\a\xef\xf8{\xb6\xdc\xfbuvm\xbd\x87{~\xf0M\xee\xf9\xc1wX\xb5\xfa$\u03bf\xf0r\xce;\xf7\x12\xce:\xf3,\xce:\xfbTN9e5##\x16#)\u05b8\xe0_\xdf;\xfdx\xe2CT\xe9y\u074d\x91\x90\x16\x1f\x85\u7532c\xc7c<\xf4\xf0#\xdcs\u03fd\xdc~\xc7\x1d|\xf7\xbbwp\xe0\xc0\x01\u04b4K\xdc\x18b\u0769\x17p\u0499?\xc5\x19\x17\xbe\x80\xa5\xeb\xcf!q\x86v\xbbE\x16\xf4\u05e5o\x8f\x94iV\xb9@\xc0\x14\xe1o\x14f\xc8&p\xe4b*Wf=.\xb1\x8f\xeeSBU.>\f\xdcB:li\xc6&\x80\x82\u053f\xa3G~:\x88:\xaf\u0280k\x15y\xf86c,N\xd2\xda04\xf7W\xd7\xca\xf6j\u6105\xaec\xae\xe3H\xda\x19\xcd\xc4\xd1\u0410tU\x19\u00a7i\u00a2\xa9\xa5,]\xb1\xbev\xb5\x87\x82\xdf\x1d>|\xc8l\u07fe\xfd,\x80\xb7\xbf\xfd\xb7\u007f\xe2w\x89\x8f\n\xe6\xf7\xdds\x8fg\xe9TW\xbe\xeeu\xbf\xf0\x86M\x0fo\xf2\a\xb9\x11\xbf\xb6\x1f\x02bS\xa7\x9c\xba~-/\xbf\xf6y\x8c\x8e\x8f0\xdf\xed\xfaTxc0\xa4Xu\x1e\xc8\xc9\x17\x19\x94H\x9d\xaf\xbe\xc3\xe2\x8f8\u05e3 \x19D\xcaI\xed\xfa*+\xf0\xc1\x15pu\xa2.(1Ye\xff\x91\x01\xb6\x9f\xfd\x9f\x91~8,\xe0\xfb\xa9\x9a\xb5>\xe9\xe6_\xeaC&=\xc6\xd7iX\xcb\x14W\xef\x12\xea\xc9Ee\x18\u0148m3\x1auX\u079c\xe1T\xb7\x97\x83,\xe2\x80]\xc6\xfet\x193\xf1\x04\xa9D\xde/#\xf0\x94N\x198Ps\xaa\xb4S\xc7\\W\xe9dZ?g\x8c\xa0qE\x02\xa7\xfd\xd4XM\u03a95c\x91B\xf5\x9a&]\xb2,\xc1\u0688\x95'\xff\x14\xabO\xbe\x84\xf3\x9e\xfdsl}\xe0\x9bl\xbe\xfbk<\xb6\xf9\xfb\xec\u067d\x99=\xbb7\xf3\xb5\xaf\xfe\rk\u05de\xca\xc6\xd3\xce\u1b33\xce\xe3\xb4\xd3O\xe3\xb4\xd3N\xe5\xe4\x93\u05b1b\xf9$\xe3c\x11qD!\xe9)\xaaU\xc9\x13e\xfay\xef\xf29\x19\xeaf\xa3\x8e\x03\a\x0e\xb0e\xcbV\x1e~x\x13\x0f\xfe\xf0!\x1ex\xf0\x87\xdc{\xef\xfd\xec\u07bd\x8b,\u02c8\xacedl\x82U'\x9d\xcb\xfa\xd3/c\xdd\xc6KY\xbc\xeat\xc4\xc6,\xccuH\xb3\xcc\x1fzZ\xd3y\x96\x9d\x9b\x04\xaf\xe1\xab\xba|o\xa1\xd7\xee!7d\xab\xf8{\x9b\x9e\xd3Z\xfcp\xccW\x02N\xea\x93\xd0\u028f\xcaTi%\x8e\xd9VF\xe2\xbcL7\xf76\xd7\xfc\x1a\xcf\xd4o\x8a\x8a\"&f\xf1\u04b5\x8c\x8c\x8c\x91d)Q\x14\xf99\x9e\xb5\xb2g\xcf\xe3\xcc\xcf\xcf]\xa4\xaa\x93\"2}B\x82\xf9\xe6\a\xefd\xe3\xd9^\f\xffG\u007f\xf0{/\u007f\xf0\xfe\a.\x99\x9b\x9f\xc7\x18cLem\x1f\x81\xd8Z^\xf2\xfc+9\xfb\xec\xd3h\xa7]2\vj\fq\x90\x0fVR\x12|\xc6e\x05\xc8sS)\xe9\xc9\xc3\xe9\xa3\"jU\xb8\x1c\x15\t\xb5oPW\xd5>k\x1f\x84\xf4\xd6\u294b\x9c\x1es\u03a3\x95Fq\x90\x19m/\xe4\x1d\xebsOk\xe3_\xf0\xa9Z\x13\xc4\x14\x80\xdes\xf3\xe4\xaf|$\x8e\xa9x\x81)\xd3f\x9d\x1cb:y\x9c\xddf9\xbb\xa3\xe5\x1c1\x93$\xc4\xc1\xa3\xd9U\xba%\x0fz\x9dLYH\xfd\r\x98\xb8\xf2F\xae\xfe*'\x12\u031b\U0008391e\xd4R\x02\x98\xf6(\x93\xa4^\x14:%u\t\xe9\xcc462,]s6K\u05dc\xc5i\xe7_\xc3\xe3\x8f\xde\xc7\xceG\xfe\x85\xc7\x1e\xbe\x83\x03\x8foe\xe7\xceG\u0631\xfd\x01n\xfb\xfa\x17X\xb2l\x15\xabVm`\xf5\xeau\xacY\xb3\x9aSN\xde\xc0\xa9\x1b\u05f3j\xd5r\x96-]\xc6\xc4\xe4\x14C\xcd!\xe2\xc8\xd2lZ\x1a\x8d\xa8\x06\u058a\xd2\xedt\x99\x9d\x9d\xe5\xe0\xa1C\xec\xdf\u007f\x80\u077bw\xb3}\xdb\x0ev\xec\xd8\u03ae\xdd{\u063a4\xa7\n\x00\x00 \x00IDAT\xbe}\a;v<\u0291\xc3\a\x01\x88\x1bC\f\r\x8f0\xb9d5kO\xbf\x84u\x1b/e\xf9\u06b3\x18_\xb4\x864\x83v\xbb\x85s\xed\xf2\xc2\xcez{\xa0\xb0OQ\x84/\u7b85\x06\xa3>\xecA\x8c\xc5`\a\\Ez\x9c^\xd1'e\x15Uy\xc3\u0418\x88\x19i\x1a\x1a\x86b~Q\xab\xf0\x85\xbay\u0500\x8a\x9c\xaa\xc1\x9dT\xa6\xdc9\xa0\x1b\x1f%\xa9d\x15)n\u0391\xfb\xfflg0\x9fx\xa5U\x1e\xfc,\x15\xea\xd0\x05\xff\xfc\\\xff\x9e\xa4)K\x96\xaebjj)\xbb\xf7\xee&\x8a\xe2B\xf2\xdciw\xd8\xf9\u062eE\x0f\xb5\x8a\u0265\xeb9\xe9\xcc\u02d9\xbdb7\x87\x1e\xdf\u009em\xf7\xb0{\xfb=\x1c\u07bb\x8d\xb9\xf9i\xee\xbf\xffv\xee\xf9\xc17\x111\x8c\x8eN2\xb5h1\x93\x93\x13L\x8cO2>1\xc5\xc8\xc8\x18CCC\f\x0f7\x19\x1e\x8ei\u013e%hw\xba\xb4[m\xe6\x17\x16\x98\x99\x99\xe6\xf0\xe1ifff8r\xf80\a\x0f\x1c$I;\xa1\x03\x89\x19\x19\x1bg\xe9\xea\rL,Y\u0272\x93\xceb\xd5)\xe7\xb3x\u0169LL\xacfhh\x8a4I\x99_\x98\xf7^#b\xe8[\xe6\xd1r\x10\x9e\xf3\xc2B\x1e}\xe8kT\xa3\x12\x92\x82\x82\xb7\xbd\x1bTvT\x87\x90\xd2s\x9d\x86n\xcaz\x19\xb0\xb3\x06;\x161X\xd89\xad\x9d\xb5\x03;\x19)\xa3O\xeb\x83\xc5\xcb\xd6\u04b0c\x183\x02\xa9\x90\u0336\x98\x999\x12\xb6\x1eM\xbd\tQ_\xfbK\xd1\u0494\x85\x8c\xe4\xe1\xaa\xc1,\xcb\xe2o\f\ttK\r1u\x90\xba\x8b~\xff\x15\xbc\x141\vC\xcfh\xc4\u041c\x88\x88\xad\x10\x99\x90\xe5J\x9f\xfbN%\x01\xb1'\xc36\xbf7\xf2\x9c\xdf\xda\x1c\xaaz\xb5W\x12w\x8cx\x0f\x19-\xfdvT\x95N\xeaH3\xafV\xc9[\x15\x13\xd4m\u04ab\xce\t\x85\xa1K\x1c\xcd\xc6\x18\xf1\xd0\b\xe41\x95\xe1\tdiF\x96ef\u07fe}\x8b9\x01\xfe\xf4\x81\xf9G>\xfc\xa7\xf2\xe6\xb7\xfc\x8a\xaaj\xf3-\xff\xe1\x8d\xffq\xeb\xb6G\x01\xb0\u0592+X\xac1t\xbb\t\x17^\xf4\f\xaey\u03a5\x18\x11:\xce\x12\x19\xa1\x11\xf4\xe0y\x80\xb1uZ;\xb2{\x17_T\xca1e1\xc8|\x92 \x9e\xff=\xc3\xd0\xc1\x1b\xdeG\xb8\x02\xa0\xb5OR\xe5\a\xb3\xb6\x10\xc3y_\x13\xd3\xf3\x95\xda\xc3<\xf6\x91%\xa1\xa2w\b]\xe2`1\x90\xd5\x06\xb7\xdeU\xc6\x06=\xbb\x1b \xab\xa4\u03d6T)Ez\x83\x8e<\x8e\xf3\xb9~0\x95\xb0*->\x86\xab\xfao\x96\xc2\xc9N\x8d\x9fi\x94\u06f4J\xa4\tK\xdda&\xb3Y\xd6\xcbn\xb6\xb2\x8c\xfb\xb2\x95<\xea\xa6\xe8h\x03+\xfe9\x17G\x9f\xd4+\xcd\x1c\xc4]8\xefr\x83\xaf\x1c\x99\xb52\xf8\x10\xad\xce?\xfdB\x99\u04de\xbc\x8c\x9e'\x9dyS\x11\xefS\x9fet\x16\xe6\xc0\x18\xa2x\x98\xf1\xc9q\u01a6V\xb3b\xc3\x05\xa0\t.Kh\xcf\x1fa\xe6\xe0.f\x0f\xef\xa55\u007f\x88\x85\xb9\xc3,\xcc\x1e\xa6\u04de'\xe9\xb6H\xba\x9d`\xd5\xec\x13\xb2\xc4\x1aL#\"j6i\f\x8d0<1\xc5\xc8\xe2e\x8c,Z\xc2\xd8\xe2%L.[\xc5\xf8\x92\x15\xc4\u00e3\xa8X$\x8a0\b\xe9L\x87\xee\x91\x16\xddVB\x9af%\u0329+\x02\u0335\xb7\v5R\xef\xf5\x82<\u0408\u0146\x94)\x0ft\xe1\xea\xecuZ\u8ece\xa4\xcfD_E\xc8bCf\r\u0450\xa1\xb9(&j\n6\xa75\xa8[\xd9\xf6\xa1\xb9\xd6\xff.}\x95\xbfV\x92\x8d\x06\\\x9ba\x05Z\xabn\xbd\b]\a\xad\xb44\xb6\u00c8\xb7\x98\u02028\"\xffy\xc1\x8c&\x97j\xaa\u02c8\x1ac\u010d\xd1zL\x1b\xbe\xf8\u073b\xf7q\xee\xbf\xff\xbe\xe4\x84\x04\xf37\xbf\xe5W\x14\xe0\xbd\xef~\xe7\xd9\u07fd\xe3{g/\xb4Z\x1e\xccM\t-\xce)\xe3c#<\xff\x8aK\u0670~-\xfb\xe7\x12\x8c14Ih\x90\x16~)\xb5\xe4\x13\xd5\xfa\u025a\v\xb2\xf3\x05\b\xe9+\x04\x8e\tR\xdaC\xa5\xa4\x18\xba\x1a\xd1\x15KLV,\x03U\u056b\xd6\xd7@\b\x10\x91\xfa\xea\xbdpI\xac\xfb\x0f\xea\x00~{\xf0c\xf2\xdfms\x97\xa0\xa2\xa1\x84|\xe3\xd5\xd4l\xbd$\xac\xda\x1c\x9bb\xe9\r\x0e\xd0\x01\xdc\xfc\x13\x16\xdb\xe5\xb3\x06\x13\xd2\xd2+\u06e7\xb9'Mi;\xa0\xb5\xda\u0285\x1e\xcbi\xc6X6\xcb9\u0332\x81\xddl\x91\xe5\xfcPV\xf3\x98.f\x8e!\x9f\xfc\xa4Y9\xbb\xec\rL\x92j\x958\xe0Y\xea`2\xab\x8c\x9c\xd4\x1e\x85F\xf8y\xe1\u07camT\u007f\x81\x92t\xdat\xdb\xfe\xf7Yk\xbdEj\x1c3\xbax\x94\xd1EkX\x1dN\a\t\x8f\xcb9\xc5e)Y\xda%s\xa9/\x88\u0160V\x90\xe1\x88hx\x88\xa8a!\xb6d\xc6'*EQ\xa9\xc5vY\x86f\x19Y\xda&I3\x9cq\u0210b3AS!u\x8afZ\fX=X\a\xf0\n\x87h\xe9l,\x15P\xb3X\x13\x87\xcc\xce*\xb0J\x9f\xda\xe8h\u05d4V\xba\x1cg\x84\xcc\nQShN\xc5D#\x16#\x14`\x9eW\u0245+\xa8\xf6\xf0\xe3U\xfd~\xcf$\\z\x93+zd\x04B\x99PU}/3\xf5@\x9e\vy\\\x00s#\x82\xc9*\u0770\n5\a\x8e\xd0\xf1;bT\"\u007f\x8dT\x8bG\x81\xf9\xf9y\xf6\xed\xdb\xcf\t\a\xe6\x9f\xfa\xd4'y\xc3\x1b\xae\x03`\xdf\xfeCo\u07f9k\x0f\x99sXk\xc3p#7\xd3J9\xf7\u0333\xb8\xe6\x8aK\xe8\xa6\xfev\x1f\r@nU}U^\xbb\x93\xfbU)\x1a\x8c\xf0\x9d\x19\xdc\xdc\x1e\xab\x12\xad\x02\x9c\v@\x9e\xe1}\x1c\"\xf5qryU<\b`\a\xc1q\x17S9\x00\\52\xf9\xa8\xdd@\xfe\x15&\xa8eJ\xbe\xbc\x94n\xda\xf0Y\xa5\xee\x8dq\xac\x01\u0560\xdf*\xa1\xf3\xc8B\x0f!\xc1\xa3f\xb0\xf9\xed\x80?\x86P\x05k\x1f\x87Z\x85J-8o_5\xbb\xa0\xf9\xd5J\x8b=)m.\xe6QNc/[X\xce&V\xb2C\x970-\xc3\x18\xbcZ\xa96\u0516\xea{\x96k\u0635\xae\x8d\xcf\x1f\x912\x80n\xa1\xd8\x1bp\x85\x9e\u065fD\xe2\xfc\x01\xed\r\xd5\xf2MBW\xbe\x8eNq\x9a\xe0\\\x82K\xc2s\x0e\x89\xee\xd6HI\xbd\t~\xf1&\x1e\xf6[\u00a2\xb8,|}*\xe8\x02tZ\t4\x12\x88\xc0\x841o\xea\x1c\xear%\x87\x16^1j\x05F-\x91\xf5\x1d\x86\x11p]G\x9a\xfa\x9f\xab\xf9i*ZZ4Ky\xb5J\x11\xb5fJ\x1f\xf2Z\xf4\x9f\x1eC\u07a4\x03\x8a\x1e\xff\xebR\v\xb6!4\xc6-f\xcc\xebD\x82\x1d\x12=\xfbp\xa5\xc3\xf31\xab+\xad_\xd7rl\u05af\xa6p\x14A\x9d\x1f\xa2w\xb3\u04b7\u0204=\nu`\\\t\xfe\xf9\x82b!\xcc\x14\x83:o\xbcU\xdd\xf8-\xe7EB\x969\x92$=\xf1\xc0<\a\xf2n\xb7\xb5\xf2\x85/|\xd1U\v\v\v\x9e\xc26\"\xa5\xb63crb\x8c\xe7_y)\xeb\u05eeb\xba\xd5a\x98\x94\u0607\xa4\x15Ugq\xba\x17\xc5q\xb8\tM~sW\xe4jO`\x188\xc8\xcaU+cF!\u00c8\x90\x15\xd3\xfdrE\xc2\xf4\xd4\a\xf9\x1a\xba\xf6\x1aF\r\xf0_9\xba\u0250\xf4\x18\x87U\xb74\xb5\xa7&\xa9\xd7\xd7R\xfb}G;&\x06\xcf\x04<\xa5\xe3\x87a\x16\r\x1d\xc1\x13\x1c\x9e\xf6\xe53\xd6o\x00\x97?\xa2\xf0\xc68u=L\xb2G\xda|\xc0;N\x87\v\xe41Nc\x1f\x8f\xcab6\xebr\xb6\xb1\x8c\x83\x8c\u1430\xb5\xab\xc5T\xa0\\t:\u01aax\xcd\u0295\x92N\b\ufa69\xe4\xa9J\xde\xd9i\xd9z\xbbJ&i^i\xbaj>\xa67\xf6\xf0\xfbiR/2\x8b\xdf\x19\xac\x94]\xde\xdew\x02\xfdg\x05\xed(f\u0220\x8d\x88,\xb6%\x90\xe7\x86i\xb9\xd41\u007fZC\x06\x91\x88H|\xe1\"\x89\xa0]G\x96iPrI)I\fT\x8b\x02V\xbc$\u03c6\xf7z\xe0\xcaE\x0f\xf8\xd6\x05\x05\xfd.Bi\bgn\x8cZ\xcch\x14\xf6;\x14c\xfd\xe1\xe1(3l\xa5\x17\x82\aJ\xcc\xfa\x03(\x8ev\xe7\x94~\xa3\xf5qY\xa6\xd0I=\xfdc\xaa\xc3U\xc1W\xe5\x15*\xa7W\xb5\x9c?\xc6j\u982a\xb5\xd7 \xcb2\xba\xdd\u0389\x05\xe6_\xfb\xdaWy\xc1\v\xae\x05\xe0\x03\x1f\xf8\x93\x9f\u06fcy\xcbD\xab\xdd\xc6Z#\xa5\x1cQ\u025c\xe3\u0513\xd6p\xcd\x15\x97x\xbe\xca%\x05\xdf\\\xb1\xaa\xa6w\x9b\xba\xba\xf4p\xd4\xd3Z\xfb\xa9\x96\xa3\xa1\x92\x14f\\\x8a\xadU\aYm\x01Hj\xff&\x94A\xf5R\x8c-%\xf0\xe7\x1c\x0fd\x8eR\xf5T\x0f\n\x83\x1bx\xf0\xc8\xc0q\xef\x13\u05ea\xfb\x0e\xc0\xd1\b\x9d@\xb9\xb2e\xca\x03\xf4GT\xc3\x14\xac\xc51\xd46\xd5\xe5\xa9\xfc&\x1a\xa1\xcbY\xec\xe6$9\xc0>&\xd8\xc626\xb1\x82\xdd:EBDD\x86\x13Wn/\xf6\r\x97{\xdfs\xad\xad\xc5he\xde\"aP\x9aW\xebN\r\xc6e\x85iZ\xd1\f\xaa\x92U\xf0E2-\xbeW\xaby\xabT6X\x1d\xe5\x82VX\x1d\xaf\xea\xe3\x9d\xf3\x9f\x88\x1a\x82f\x12\x12\x90\xca\x1fT|\xbd\xd6\xdfmi\b:i\xb1\r\xc1\xb4\x14\x8d\x1cY'C\xb3\xde!q(\xe1\xadE\xd5\xfa\u047d5\x85\x84\xb3\xda9\xf5]\x1c\x85LE\xfa.YU\xbc\xb5\xed\x90!\x1e\x8f0\xe3\x11&\xf2\a\\^\xfa\xb8^)kM\xf6$\xf4\xa6Ni/\xf1%\xbdc\xd3\xd2\ufa38\xb6D+\xc0\xeb?:\x99zI\xab\x8a\x1f\xc2W\xc0>\xe7\xcb{'W*\x82q\x14IK\xfe\xec\x1d@A\x1a\xc19\xf5A\x1e'\x12\x98\xe7@\x0ep\xf7\xddw\xbf@w=u\xfe\x8f\xcf\xe1S\x8e\t\xea\x9e\xffw\xc1\xad\xa9!)'q\x805r\x98\xb3\xd8\xcdfV\xf0CV\xb1\x87I\xbab\xc1@S\xd2\u00b7\x9d\x819IZToZM\xf2\x93\xbaJ\xdf \x181\x1e\x8d4D\t\x86.E\xb5b\xbd\xaa\xe5 Zz\xd0H\xa4N\x03i1\xa9\xf5\xc3\xe2\xda\x01\x13\x02ql\xe4\xaf!\x97\xa9\xa7\x00l.\xbf\u0492\xcf\x12WZ\xb4\u57cf\f\x8c\xfa\xb9E,\x8aSC')\xb70\xfc\xf4\u0440\xf5\xb4J\xbe0=h\x06Y\xbamV\x1e\x9f\xe4\x8b5\x15\\\x95\x12\xdf\u0350\x10OX\xccT\x04\xc1#\xdf\x1a_\r\xbbL\xc3\xfc@\n\xb37=j\x9aEO)S\xbc\x9cR(\u0574\x06\xe8\x15\xe1\x83+\xfd\xcd\xf3\x85\xc3v\xea\x818\u03fa\xcd\v4\u3d28\xcc\xcb\x01\xb9T\xde3\u03df#~\x86\xe7\xdc\x13\x13J\x9cP\x03\u043d{w\xaf\xbb\xe6\x9a\x17\x9e|\xf0\xe0!O\xb1\x88H^\x95\xbb\u0331~\xfdj^\xf2\xbcg\u04b0\x86\xb9N\xb7\x06\xe4\xbdn\x88G\x83\xab'\x10K|||\xaf-\t\xd6o\xd5^H5}U\u07e0){\xce\xc3\x1e\x8dq<\xca\x05\"\xe5\xf0\xae\x94n\x1d\xfd\xfb\xe4\x18\xc7\u00d3;\xef\xb4\xe6\xb5\xf1\xe3\x02\xf2\xe3\x01:\xa1S(\x80\x03\xbf0\xb6\x86#,\x939\xced7\xdb\xec2\x1e\x8eW\xb2?\x9d IlH+\xcfz\x16e\xfa_#Wl\x83j\x9d&\ntJ\xae\xc216\xf6\xab\xe2\xaeLF\xf7\x9c\xbf\xab\r\u07b5\x8aR=\xd9\u01c5\t\\@\xedb\xd2R\xb1\x18\xf0\u0671\xa6\xb4X\x90\xd2\x18>7\x8e\xd2\xde\"\"\xb7f%$h\x8d\b\u0608\x86q\xd0vtSj\x9d\xa3*H\xe6\x02p\x95\xa7\x99\f\xaa\x9b\xfb\xf60*:\xfe\xd0\x01;\x01\xd304\xa6\"\u0322\x18m\x94\x12!U\x0f\xa8\x05\u0154SX\"\xd8 U\xad\xf2\xe5\xf9 \xba\x06\xd0E\xaeD\xa9\xae\xa9\x96Py\xc5o\xf2\xb9G\xe8\x96R\xa0\x9d:\x12\xa7\xc5<$\xa7]\x14\xc1\xa6\x0e\xeb\xf2\x83\xd8o5\x9b\xe0GcB\xf9\xae\x94[\x1cZ\x9f\x0e\xf4w\xfc'\n\x98\xdfy\xe7\xf7\xb8\xf8\xe2K\x01\xf8\xf4\xa7\xff\xd7\xcb\xe6\xe7\xe7\u05e5i\x8a\x91\"\xaf\x06uJ\x14E\\\xfc\x8c\xd3\u0638a\rY\x96\xf9\xb0\x01\xaaaaz\\\x84>\x9a\xdb\u02a0RU\x9e \xd8\xf4%\x81\x0fPz\xc8q`\xb3\x1aKE/\x1f\x9fK\xf7\xd0J\xa8CUc\xab\xc1\x97\x9dB\xae\xd5ov4\xb8B\u007f\xd2M\xc9q\xe6\n\xfa4\xfc\xcc'W\xa1SL\xcb\xf2\xae\xc7\xf9\t\x06\x06\xc7R\xe6Xd\xe69ed\x1f[\xcdr\xb6\xe8\n\xf6\xbbq\xda.\xc6\xc7g\xb8\xa3\xf4?A\xf7\xa3e\x17&Z\xe5\xfd\xb5R\xd6z\xf9\x9eD\x06\xa31\xaa.|(\xea\xb2|\xc70\xd0$\x01\xb0\xabUs1q\xd5\u06ba\x8d\xa1\n\xfcBd\xfc\xd0TB\xe0I\xf1\xb5\xd2S\xa9R\x82{\xfd\x00\x0f\xb2\x91\x91\b\x89\x95\u01bc\u00f4\x1c\u074e\x06P\xcd/.\t\x83\xe0 &\xb0G\xa9\x8e+\x06s\x85\xc2\xc5J\xe1u\xae\x026\x16\x1a\xe3\x11vq\x03\x86\xbc\x99]\xeec\x8f\xfa\xeb62\x82-\xb67\u00dd\xac\xa1\xeb\t|\xa9Sj\x96\x0eE'\x13T8\x92\x1fD\x94A%U;\u072a\xa7\x8a\"\xdeD+\v\x11\x8f\x15jJ\xc5\xcf+l\xe2\x15q*\xf9\xe6x\xa0\\\x8c\x0f\x06\xafJ\t\x9cs\x14\x9cU\x8f\xd8\xc6\x1aK\u0708O\x1c0\u03c1\x1c`\u01ce\x1d\xcf\x1111\xd0\x11#\xcd\xfc\xc6r\xea\x18\x1d\x1e\xe6\x99\x17\x9c\xc5\xc8P\x83v7\xa9\xe7\a\xa2\xc7<\x05\xf5I\xa0\u0493\x01!\ud66bs\x94\x15\xfbz\x04\x9c\xd6\xf3@\xc5`m\x8c\x8db\xd4Z\u007f\xc3\xe6\n\t\x97\x91e.\xe8\xeb\xfd\r\x1eE\x9682a\x131#I\x13\xb2\xa4\xeb\xdd\xee\xe85\xa8\xd2\xe3\xd6\xd0Oy1\xe88\xac\xbe\xf6\t\x1c\x9f\x9eJ]\x8f\xfa\xde\xf5\x1fay\u03f4\xc4\xcc35\xbc\x83S\xe2\xfdlm,g\xd3\xec*\x0e\u034f\x92\xba\x88X\xb2\x01A\bU\xa9\xa2T\xdc\xfa\xaa\U000b6cbc.L#\xf2\xb4\x1d|0\xb5\x1a\x87\xe2\xc1]\x8c\v\xc3M\x17\xec\x85u\xc0u+}v\xc2\x1a\xacQ\xac\t\x8bs\"X\xe3\xd7\xe9\u0542f\x0e\u056c\xa0A\\\x95\xc8\x13jFi\x84\x8a\xdb4\r\x1a\x19\x88\x1d:\x9f\xe1\xda>\xd72\x1f\x14kF\xcd`\xabj\u00ec\x15]zAg\x86\xf0\x12\r.\x95*\u07b1\xb21\x12\xa8\x95\xe1\xf0\xaa\x99\xca\xd05,\xa2J\x1e~R\xe4\xf8\xfa\u1dc4\xa1\x83J\x91RW\xd0R\xd2+=\xad\xddo\x95\xc0\x89\n\xaek\xb8\x17\x12\f\v\xa9w\xd8\xcc\xd7\xea\xf2 \x18\xf0rD*4\xb78\xf1\xea\x9d<0]\xa4\xa6\xfc\u0272\x94,K\xfb:e\x14\x8c54N$0\u07fau\xb3\x9cr\xcaFU\xd5E/z\u044b\xd6\xed\u06b5\u02ff\xa7\x95\x8aC\x15\x16OMp\xc6\xc6\xf5\x18\x1b\x93d\u0770\xf03\b6\x8e\x0f\xe0G\x03\x86\x1f\x1d\u0334\xe6\xb7Ru\x13\xf1'\xb5?\xad\x8d5DQ\x8c\xb1\x11\x9dn\xc2\xdeC3\xec;x\x84#\xd33\xcc\xcc\xce177\xcf\xfcB\x9b\x85v\x9bN'\xf1\x12M\x11\x8c\x11\x86\x87\x1aX#\u0111e\u0572\u015c\xb4n\r\xa7lX\xcd\xe2\xc9q\xb2$!M|\xa4Y\xear\xdd\xeb\xb1\x0f\xa2\xbal\xf1\xe9\xeb\t\x95r'O\x8a[\xe9\xe9\x01u}\x92\a\x80\vJ\x94%\xf1\x1c\x8b\xc6\xe7Y\x1b\x1fbs\xb4\x82ms\xcb8\xd2\x1d\xf1\x8e\x8e\x15W\xcbz\x180T\xa7\xa0J\xff\xa0\x9d\x17\xcdu\xf9\xf9\x90\u04d0t[\xa4\xddN\xe9\xe3RI%n\xc41\xa3\xa3\xa3'\x0e\x98\u007f\xe7;\xdf\x05`\xf3\xe6M\xe7\x1c:th}\xbb\xdd\xc6\x18cD\xeaV}g\x9e\xba\x9e\x95\u02d7\x929\x17\xde\u0132*\x10\xd1\xe3\x80\xf8`A\u078f\x02\u40f2~\xf2P4W\xf9\x00\xc1F\x96(\x8a\x88\xacg\xd1\xf7\x1d<\xcc#[\x1e\u246d\x8f\xf2\u062e\xc7\xd9\xfd\xf8~\x0e\x1c>\xc2\xfc\xdc\x02s\xf3-f\xe6\xe6\x98_h\xe1\xb2\uc60fa|l\x94\x95\u02d7\xb2v\xf5rN;e\x03\x97\x9e\u007f\x16\x97]|.\x8b\xa6&1Y\niB\xb7\xdb\r9\xa9\f\xf0y\x91\x01\xa0\xaeO\x19p\xab\xf3\x02W1\x1b+f\a\x05%\xf2\xa3u\x02\xf2\x14\xe8\xc8\xfc\xbd0(\xab\xe2#,Y4\u01c6\xe6\x016\u03ef`{k)s\xc9P\xe0\xa5]9H\x13\x1d\x9cC\xa9\xd4\U000a628d]\xa9S%9x\x16\xda\x18\x01c\xf3OG~\a@\u0577\xf7\xf9\x81\xe1\xb4F\x91\xe4\xbc-\xc6gk\x9a8\xc2\xc41\xa6\u0440\x18\xe8&\x1e\xc8]\xeaW\xca+A)\xc5;*u7I\xadX\xdcJl\xb0\x9104dH\xdb\x0e\xed(\x9a\b\xa6k\x82[b}8_X\v\x9bJi,e\xc5j\x8d0\xdc\xf49\x9ef<\xf2\x86]\xf9\xb0\x90R6\\\x04\x82x\xb5fy\xd0T\xa8DU%\r\xbe)i\x00\xfa,\xfc\xb7+R\x81\xca*\xdd\u4389\x15\xf9\xa0\x15\xc1\x86\xa7\x91*\xdes\xa5\xe2K\xae\x95\xca\x1d\x85(\xf5\x03\u043c\v\xab\x9a\xf2\xf5\xe8\x9d1b\xe8\xb6\xe7\xe9v\x17JW\u01fcCSel|\x9cU\xabV\x9b\x13\x883\xff\xbe\x00z\xf3\xcd7\xaf\x9c\x99\x99^\x1c^\x8cZ\xf3\x1cG\x96\x8b\xce=\x83\xa9\xc9\t\xda\u0764\xa2\x1a\xad@\xb4\x0e\x8eR\xeb\xd7w<\xb5\xe1\xdf\xf1i\x96R.\x97/\xd84bK\xb3\xd9\xf4i/G\xa6\xb9\xff\x81M\xdc\xfe\xfd{xx\xf3v\xf6\xec\xdd\u03c1\x83\x87i\xb5;\x81:\x89\xe9&yjzV\x02p~\xe1U\u03efp\xa1\xcf\xce\xcd3;7\xcf#[wp\xeb?\u007f\x8f\xcfNNp\xea\xc9\xeb\xb9\xf8\x82gp\xcds~\x8a\xf3\xce<\x99\xb1\xd1Q\xc82\xda\xed6Y\x96URu\xf2g`zh\xa1~\xc5\u0353\xedN\\\x10\x8c\xd6\x01^C;[7Q2uB\xe3G\xe2\xec\x8f\xfd\xb5\x95\x90k\x11\xaf~\x199\xc8\xf2\xe6,\x1b\xda\ayxv\x15\x8f\xb6\x96\xd0u\x91W\xe8\x19W\xb1U8\x96\x8c\xb1\xfeI\x95\x9a\u0322\xb6\xd2^\xd2\xcd\xc1#Dm\x19,\x9e\x9f \x01$\xf3\xed\xd0B\x06n\r&\xb2\xd8\xc8bl\xe4\x95'\x91\xc1:\u023a]\u0124\xe1,\xa8\x9a\xbbU\xcaE\xca\u02bd\xd8\x00\xd5\xd2\xfa\xd64\f\x8d\xa6\xf5\xdcp\"\x98\xc4\x12\xa5\x11\x92\x19\xd2\xc4y\u0146\x84\xf0e*\x19\x00A\xf6\x87\b6\x12\x1aV\xfcf\xe7d\x84\xc4R\x94\xcfN)\xf6+\xea\x81\xe3!\x99\xcb)\x99\x83,\xf5\xa9>\x9d\xf0\xff\x89\u02fd#\x01+Hd\xfa\u0788\xbe,#-\xd55\xce\xf9Ak\xc1O\xa1\x9e\x04\x8b\\)f\xa4tU\u0334\xbe\xdf\x14\x80\x06\xd3uu\xab\x82\x9a\xbfW-x\xd6\xdf\xf1b\x98\x9f\xdeO{a\x1a\x1b\r\x05\xae\xc7\u007fw\x14\u01d2en\xcb\xe5\u03feb\xdf\t\x01\xe6\xdf\xff\xfe\x1dr\xc9%?\x95\xaa\xaa\xb9\xf0\xc2\v7\x1c\x12\xac\xb2uXT/\xaa\x83\x82C\xca\x16_\x9e\xccx\xf4\x89\x83V\x16@\xdc!8\xb1\x8c\x8c\f\xd3\xee$|\xed\xd6\xdb\xf9\xcc\xdf\xfd=\xdf\xff\xc1\xfd$\x897M\xb3\x91er|\x9c\xd1\xd1Q\x8c1\xcc\xcc\xce07\xb7P\xab\xbc\xa3(\n`\xac\xfd\x8fQ\x95\xd6\xc2B\x81\b)e\xfaz\x1e\xde\x1b\xc51.P4Y\x96\x91\x05\xce\xfd\x9f\xff\xe5nn\xbf\xeb~\xae\xff\xf9\x97q\xfd\u03ff\x94\rkV2;7_.;h\x95\n\xd0\x01\xa0\xf5\xc4\x01]B\xc5\xdbk\x1cVMrr\xde\u06f2\xe0\xe7\xf5)\xd2:\xc7;l\a\xbe\xdbR.\xbdHOXF$\x19\x8b\x1bsLD-\u058e\x1c\xe2\u0445%l\x9d_\xc6\xfe\xee8\x9d,\xc6J\x16\xfc\xe7{\x0f\xb9:9\u0557\x88#u\xf8\x96\nG\x9bs\xad\xfdFg\xdaw=;J\xa7\xda\xe2\x00Q\xe7\x15-\xc1\x06 '\x9d\xfb_S)*L\x05Z\x99#s0\u0590bXh\x82\u0574\xb5\x96\xc8z\aFg\x14\x1d1hf\u04594x\xc7K\x90\xeeU\x0e(\xe3W\xf6Q\xa5\x91\x80\xa6\x8at\x95l!#1B\x1aA7\x12\x92HH\fE6kI\x93\xf8\u06575`\x9a\x86,Q\x9cG\xfa\x82K\x0f\xedT\xc0L\x87D\xa67\xcf|\xa0\xc0\xc9\xef\x06H\xed\x8c\x15\xa4\u0432;QL\xaa\x98\xc4\xd5_lWJ&\xa9\x1c^\x85r\u0265\xb4\x17\xa6I\x93\x84(\x1e\xae\xa5\x17\x18#\x9c~\xc6\xe9\x13\xcbW\xac\x1a>!\xc0\xfc\x96[\xben\x80l\u05ee\xc7N5F\xce\f\xa0&\u057d\xc2f#\xe6\xe4\rk\x19\x1b\x1fgvn\xc1'w\xd7\xe0z0<\xf5U\x96\xc1\x1a\xe3U@\xceq\xc7]\x0f\xf0\x1f\u007f\xfb\xfd\xfc\xb7_\xfdw\xbc\xec\x9a\xcb\x11\x91\xe0\xec&\xb5\x9c\xd2\xfc\u0412\xd2\x11\xfc\t\xe2d\x90\xe1\xf5\x01\\p\x1e\xacU\xe4n@\x16\u04cf\x05\xbb\xfb\xc1\xd1\xe4\x8b \xbdu\x81\a'\x14\"IY\u059ce\xaa\xb1\xc0\xaa\xe64\xdbZ\xcb\u063e\xb0\x94C\u0771`\n\x15\f\u07a4\xbf<\xac\x99\xf9\xf6\xc8l\xfb\x00=\xff_\xa75\x9fm*Fa9\xb5\x12\xca\xe8pP;\\\x9a\xa0YVKw\xea_?\u0329\x1a_\x8d\xa30\x12\x19\x0f\xacR\x89H\x93|\xaeaH\x9c\x90\x89\xd2\xed8\x92\x83\t\xc9l\x8a&Z0\x1e\x1aI}\xdb9\xf3+\xf0>K\xb3r\x00\xd9p\xad\xe6\xcfO\x15\x9b\n\xdaq\xb8\u06106=\xb0k$\xc5p\xba\x1cx\x12R8]\x91\xf8T\xbc\xbeN!\xad\x04k\xf4X\xe0\x1a\xa9\x843\x8a\v\u0665\xe1,\xc8\xc3,\xf2\f\x83T1\x9dJ\x9c\xa4\xcb3\x82\u02d7T(\xa9_\u007foY:\xadYZ\xf3Gz\xcc\u0494,K\x98\x9a\x9ad\u7b9d\xdf\x13\x91\xec\x97\xde\xf4K\x8d\x8f\xfe\xf9G\xbb?\xd1`>==m\x00\xb6m\xdbv\x92\xaa6\x8aN2\xac\xdef\x99c\xdd\xea\x15\xac\\\xb1\x8cV\xe2\xfc\xc6\x18Y\xc9\xd9\x1dc\xd8%\xc5e\xf9\xf4\x01y\xe6c\xa2\xfd\x96[\u042a\x8e\x8e\x8d\xf1\xe0#\xdb\xf9\xfd?\xb9\x81o}\xfb{\u0638A\x1c\x19\xda\v\xf3\x00\xbc\xe4%/\xe2\xcdo~3\x97\\r1\u02d6-#\x8a\x9a\xc5\xcf}\xc5+^\xc1\xcc\xcc,\xd3\xd3G\u0633\xe7q\xbe\xff\xfd\xefs\xe3\x8d\u007f\xc3\xfd\xf7?\xc0\x81\x03\a\x98\x9a\x9a\n\x11V\xd9\xf1\x1f\xa3j\x0fo\x1a\xb6\xd3\xc2.\xa1\x84e\x13\xa7\xca\xce=\xfb\xf8\xad\xf7~\x84\xf9V\xc2\xcf\xfd\xf4\xf3h\x1aC\xa7\xdd\xed\xc9\xc0|r\x15\xf9\xa0?f@\u022f\x14\n\x16\t\x16\xbdZR0OsY~\xac\x1f\xa7\x86\"N/_\xa1\xd7\xca\xd6 \x15*&2\x8e\x95C\xd3,j,\xb0f\xf80;\x16\x96\xb2}~)\xd3\xdd!\xef\xd0(\xae\x9c\xcb\u0220\xf7\xa6w\x96\u04eb\x89\xa9\x1eh=)>\xc5PS\xfa\xaa~M3\x0f\xe6\xce\xd5N$? 5\x18\xebm\xe0\xc8\x14\xe7\xb20T\xf4\x1cyd\xbceK\x8e\xe2\x12~h\x06$\x99\xd2\xe9d$\x89\"\xd3)2\x9b\xf9 \xe3\xf0d\xa4\xfaV\x85\x83\xcf8*1r\x94\xe1\x11\x198[\x1e\x90\xb9\x85\xae(\x98,\xc3v\x85\xac\xad\xb8\x86\xe0\x1a\x824\fD\x94\x9e\x97\xd6?\x17\xe9:4\xed9\xf0\x83O\xbb\x982tBzl0\xf2m\u06b2\xf8\x97\x9aK\xa5(\xd0\r*\x16\xf5\U000c0a85\xb6jM\xf2\x12\xdec\x1f\x1e\xd2\xed\xcc\xd1i\xcf\xd6<\xa4P%MR\x9d\x9a\x9c\x94s\xcf9w\xfc\xe6\x9b\xfe\x1eu\xee'^\xd1\x12}\xe4#\u007f\xde\x05\x98\x9b\x9b=\xe9\xb1\xc7\x1e\x030Z\x88\xf4\xfd\xab\xbdr\xc52\x16OM\x92%\t\xb1\xb8\xa2\xea\xabUY\x03\xd6\x02\r\xfa#i\xa6\xfb\x95\x19\xf8\x19L\xd3\x00\x00 \x00IDAT\x86.Q\xe1i\x8d*c\xa3#l\u06f5\x8f\xf7}\xe8/\xf9\u05b7\xee`dr\x92\xd8Z\xe6g<}r\xfd\xf5\xd7\xf1\xeew\xbf\x8bU\xab\xd6\xe2\x95;-\x16\x16fQ\xf5C\xa6\xc9\xc9I\x16-Z\x02\b\xe7\x9d\a\xd7^{-\xaf~\xf5\xab\xf9\xfd\xdf\xff\x03>\xf6\xb1\x8fs\xf0\xe0\xc1\x10\x97\xd7\xf3\xec\x02\xb7\u9723:,\x1e\x04\xf0\xf9A \x81\xb7\x8f\xc4\xe02\xc7\xec\xdc\x1c\xbf\xfb\xfe\x8f142\u032b^\xfa<27G\x92$E\xcdl\xa4\xf4\x16\u0441U\xfb\x13H\x19\xa2\x8eo}1^\xbd\a\xad<}`=H\xe1\"\xfd\xa7M\xb8\u0524\xcc*\xed1m\xf3]\xa2_\xa6id\tk\x86\x0f\xb1\xb41\xc3\xda\xe1\x83l\x9e]\xc1\xf6\x85e\xb4\xb3\x18+>]\xaag&YqN-\x97k*\xa3\x9e\u0497\xa7w6\xa1u\x85Q\x9e\x1eo\x83\t\xb8:\x87K\x124\xcd\x02\xc0jA\xc5\xd9(\x06c\xc8B\x97G\x14\xa3b\x8bMb[XDT\x06\xf9\xea]\xfe:\x0e\xda*d\x89bgS\xe2\x85\f\x93\xe5+\xed\u07a7\xa4\xf0\x8fq\x83\tN5R\x02b\xbenoKUHMq\xe2 \xea8\xe8\xf8\xe1\xa16\x8c\xff\x88\r.\n\xbe5\xc6K'\x1d\x9e\xc2\xd1\xfc\xec2~1\xce\xd4y\x16\xaa\xf3J\x18\x14\x82\x9eK8\xfd\u01a7\xe9:$+\xccX*\xd66=I\x00A\u032e\xea\xedE:\xadiZs\x870\xc6R\xb5hTU\x19\x1d\x1de\u035a\xd5\x1d\x80\x95+W\x9c\x18j\x16U]\xf5\u05b7\xbe\xf9\x92\xb9\xb9\u067e[\xd1Z\xc3\xdaU\xcbX41J\xbb\xd3%\x92\xca\xd0(\xf8G\f\uea5f\x1e \xa7\x02\xe4\xa5\u046e\xe7\xa1\x1b\x8d\x06\xfb\x8e\xcc\xf1\xc1\x8f}\x86[o\xfdg\u0196.crb\x82\xf9\xc3\aH\u04c4\x97\xbe\xf4%\xfc\xe1\x1f\xfe\x01\x8b\x16-\xa5\xdbm\x15\x83JkK\xb3\v?\x1c-S\xa5\x9a\xcd&\xa7\x9dv\x06\x1f\xfe\xf0\x9f111\xce\xfb\xde\xf7\x81\x822\xa9\xfei4\x1aDQD\xab\xd5\xea\x931V\x01_{\xac9\x9dSo\x05`=\xed277\xcf\xff\xfc\xe0'X\xb3z%\x97\x9ew\x06N\xe7\u0086\xa2T\xb8B\x18\xb0\n\xd3'0<^\xf73H\xc9.O\xcb \xfa\x89\x02\xfaQ\u010bR\x16\x04\xd2[\x1d\x88\x14\x99\xb0b\xbc6\xc7:\x88m\xc6\xc8\xf0\x01V4fX3t\x98\x87\xe7V\x05>\xdd\u0516\x8e\xaa\xd4Sm^_qZ\xef\x9bs\xd7\u01a4\u055f\xe0\x15 \x9a{\x91Wl\x1c\xb4\xc2\a\x18kI\x93\x0e{\x1fy\x80}\x9b\u007f\x88s\x19\x93kOa\xc5\xc6s\x18\x19\x9f \xa4^\xf8\x85\x9c\u04359\x85\xaeS\xda\x0e\x92\xc8\u03c0\x1a\v\x19\xf1\xbc\arq\x81O\xce\xc1\xbc7\xb0\x9b\xba\u04e1\x14\xe9\x12\xfe\xf5\x13\xa5\xf4twR\xd0\x1cyu\ud36c\u00b5\xd1q\xa88L\f\xb6ap\x91\x906<\xbfN\xb8n\xb5\xdaI9\x87\xba\x10\xfa1\xd0)I\v\x17H[\x8dc\f\xef\xbb\xc9\x14\x9b\x849E\x90$\xaa\xcb\xfd\u07a9\xa5~ke\xbadl\xc4\xcc\xe1\xbd\xcc\x1c\u068d1\xd6\xd3>^J\ud187\x87\xcc\xec\xec\u0716\xd1\xd1\xd1;\x00Z\xad\xb6\xfbI\as\x03\xf0\xf8\xe3;\xd3M\x9b\x1eiW;\x11\r\x14\xc1\xe8\xc80\xabW,\xa3\xd9h\xe0\x82\v]\x8d\xa9\xcb#L\xfa\x86w\xcc\u06b5k\xf8\xad\xdf\xfaM\x16-ZJ\xbb=\u007f\xcc\xea\xb9\xfa\xa7\xd3\xe9\xd0\xed\xb6\x88\xa2&\xbf\xfd\xdbo\xe79\u03f9r`U\xdel6\xb1\xd6\x1e\xf5\xe7\xd6\x16\x8dz*\xf54s \x86F\xec=#v\xed\xde\xcbG>\xf9\xb7\x1c<2K\xa39\x84\x18\x9f\xb7\xeaz\"\xb7\x8e?\x16>\xfek\xd8o>\xf6\xe4\x17\xfc\x95\xbe\x9c\x80'\xf0(\xe8s\xd7\u0523\xf0\xe8j\x14\xb5\x12\xbcG@\xabv\u06a6\x944\x1aq\x8cEm\xce\x18\xdf\u00d5K\x1e\xe6\u00a9G\x99j,\x90\xa9\x1f\x8eW\x96\"\xfbsV\vu\x86\x14\u04b9\xa3\x0f\xf4\xa5\xc2g{\x83\xa8\x99N\xca|\xab\xeb;)\x97\x15\u065e\xbe\xdd7l\xff\x97o\xf2/7~\x84\a\xff\xf7\x17x\xf8\x1b\xff\xc0\x03_\xb9\x91G\xbf\xff\r\xd2n\v\t\u05cd\xaa\x97\b\xb6Re\xbe\xebXH\x95D\f\xd8\xff\x8f\xbd\xf7\x8e\x92\xe38\xefE\u007f_Uw\xcf\xcc\xeeb\x01,r \x88@\x80A\xccA\x04\xb3$\x9a\x92\xa8@E\u0496D\u0274l_Y\xbe>\x96l_\xf9\xfa\x9e{\xed'\xd9\xef\x1d\x9fg\xeb:\xe9]\xcb\u05b3h_\xcbV\"MR$%J\fb\x00s\x06!0\x00 r\\\x84\xcd\x13\xba\xab\xea{\u007fTuw\xf5L\xcf\xee\"\xf0<\x1f\xc1s\u0392\x8b\xdd\xd9\xd9\xd9\x0e_}\xf5\xfb~A\"l2\u00ba\xca0p2\x16\x13\x87F\u0198!?(\xdd/\xe2\x9c\xd1GrV\x88+\xfa\xa4Sow\xce$\xfa\x94a\xe19\xffR(\x83\xa0i\x10\x8d\x1bD\xe3\x1a\xd5\x11\x85\xeap\x82\xa8i\xdd\f)\xcb\xe8K\xb38\xb9\x80e\x15\xdc=3\x8b\\\u4ed2\x141ag\xaa\xe5\x06\x9e\"\xc3\u033d\xdd\x15\xf9\xc3\xcd\xd4)S\xc0h\x85\x91\u00fb\xd1l\x8c\x822Y\xafe\x17\x85a\x809s\x06\x0e}\xe63\xb7\x1c\x06\x80\x8b.\xba\x90O\x8ab\xfe\xdcs\xcf\u03cb\xa2\xca\x1a\u02ea\xc8\x1f\xda\x18\xcc\ua7c1\xb9s\x06,\x8f\x1f\xc2\xcf\xf1*/\u0669\u007f\xc2\t\xf3\x18\xf1\xec\xb1R~\xb0\u327f\xf6\xc6\x16|\xef\xce\x1f\x81c\x85@\x12\xf6m\u07c2}\xbbl\x00\xf5\xfb\xdf\xff~\\y\xe55\xd0:\x9eV\x11\xef\xbc\xd1\x15f\xce\x1c\xc0M7\xddX\xfa\x9c$I\xd0l6\v\xf8x{1\xef\xf6\xef\x94\xd9\x02BV\u041f|\xe6E\xdc\xf7\xe0:DQ\x05\u0489\x1f\f\x93\a_\xf11\x1f\xd3\xc9\x13\x9b\xe8\x04\xcc2\xa6ge\u0325\xef\x87:\xb9\xe1i\x05\x16%\xbe\xda\u0085P\vd\x1e\xd8\x01\x19\u0329\x8c\xe3\xfc\x99\xdbq\xd5\xc0\x1bX\u077b\x1f\xa1\u0408Y\xc2\x18j\xdb\xc1P\xa9\xc8%\xfb\xbc\x8d\u0398\xef2s\x06\x86\x01c\"N0<\xd1\xc4\xc8D\x82zK\xbb\u0754\x86\x8c*8\xbc\xebMl\xf8\xc9\xed\u063f\xf9g\x98\x18>\x84\xfa\xd0A\x1c\u0679\x05\u06de}\x18\xc3{v@\x86\u0591>a\xa0\xa9\x18-\x05(&\x18!@2@\xd4\x12\x88\\G\x0e\xb8n<\xfd<-\xca\u0736*\xa6\x05\x10\x19\xa4\xecX!\xa978 \x94}\x9dla \xce\x16\u0334\xcdN\x03\x93\xd3\xd7\x13\xca@$\f\x910d\u04e02\xa6Q\x1b\u05c8\x9a\x06B\xe76\xb4E_k\xdbY\u06cf|x)|\xc8%\xe5\xdbk\x06Z\xc6\xce\x03\x98<\x16\v2\x87\xd2\xf6Z@ H\x19\xa211\x84\xc3\xfb\xb7\x80\u074e;}\x8aVZ\x0f\f\f`\xf6\xec\xd9\u06c8h\x1b\x00\\v\xd9e'G1\x1f\x1b\x1b[5s\xe6\x8cU)\x1f\xdb/j\xfd\xfd}\x98=\xab\xbf\xe0Q\xc2\xecd\xf3\xae{4De\xb5\xf7\x84\r\xd0l!\u03e1\x96\xb0RE\xbd\x11\xe3\xbe\a\x1f\u014em\xdbA\x81@k|\x14\xadF\xbd\xd0a7\x1a\xe3\x19m\xf0h\x1f)\u03bdl\xd9)\b\x02Y\xda\xc1+\xa5&\xc5\xca\xcb~o\xfau\xcbC\xb7\x17a\x14\x06\x98\xa87p\u03cf\x1f\xc1\xe0\xfe\x03\xe8\x89B\x80\x04\x98\x84c\xb3\xe4v\xab'\x92i\u00a5{\x9f\xe9/\x0e\x1eWa\xda?\u05feK\x98\xca\u317a\rN]{g\xa5\xf8\xb6\xfb\x8bHci\xed\b.\x1b\u0602\xb7\xcf\u078a\x05\xd5\x11(\x12HXf\x96\x00\u0183\xac\x8a\xd3\x03W\xe8\x8bI%\x056E\xaa\xa2\xd4l\xa0T\x82VKa\xbc\xa50\xd4\xd0\x18j\x1a4b\r\xc8\x10{__\x8f\xfdo\xac\xb7\xf1t\x89\x85b\x92f\x1dC{\xb6a\xe2\xc8 \x88$\x12m\u0408\x8d\xa5(\x12A\x93\xe5\xe5\u0216@Xgk\xdce\\A\u0576\xbb\xee(\xe2\xd3\xd9\xca\"g\x87\b\x9d\x17u\x19[h\x03\x9c{\xbe\xf8\x8b\x85\xff\xb3\xc20\xa4\v\xe3 \xc3\bbFe\u00a0:n\x10\xb5\xac\xc8'\u0760\xa7\xb9\xab\xac\xed\u0417\xb5\xb1\x9fgktq&!\x13\x03R\xce\xee\xd6\x13\\\x11\xfc\u0646g\x94\xee\x16W\x19D\x98\x18=\x8cC{7e\xc3\xcf\xf4\xacj\xa3\xe5\xc0\xc0l\u031f?o=\x00\xfc\xf1\x1f\u007fY._\xbe\xf2\xe4(\xe6\x1b7\xbe\xaa\x06\a\a\xb3A\x9f\xaf`\xeb\xed\xe9A__/\x8cq\xd1j\x1e\xf9\xdf\x0e\xcf\xe9-\xf3~7Y^g\xfe;\x04Y\\{\xeb\xae}\xf8\xe9c\xcf\x00\xac\xc1\xaa\x93q\xf4\xd0C?\xc5#\x8f<\n\xa2\x00\xc7P\xcb\x11\x046\xb7c\u02d67a\f\xa3R\xa9\xa0\xaf\xaf\xaf\xd0]\x9b.\xf1&e]y\xe9\x82BdS\xe3I \f\x02\xbc\xbey+\xd6=\xf5nAA\xa3\xecN,\x8eaT\x02\b\x89\xa6f4b\x03\xc5\x04&\x81\x04\x84\x04\x04\xd1\x12\b\x1b\xce\x02\u0597\x9cr\x8emw\xc2VS\\%\u073ek\xb6\xf0\x8c\x15\xe80d\xcbv\xde\xc4m\x8b\x19\x173VH\x1b\xdb\xd9\x1b\xc7\xccd \x88\r\xaa\xe3\x1a\xb5\t\x8d\xb0e t\t#\x93m\xf7M\x86\xddB\x98\x8f\xf2Y3\xa8e\xa1#\x06\xdbP\x0e\xb7\x80\xb1\xe1\u04acS\"\u01dc\x010zd\x0fF\x8f\xec\xc9\xee7v\xbb\x820\bDT\xa9\x1e\xbel\xed\xda\r\x00\xd0\xdb\xdb\xfbs\x8f\x97g\xc5|\u03de\xbd\x18\x1b\x1b/\x14\xa1\xf4D\xf6\u052a\xe8\xed\xadA\x9b\xd4ZV\x14\xd8%\x9aDi\xfft\"\x18,9\xb4\xe2\xba$X\xdb\xd9$Qx\xe9\x95\u05f0w\u07c1\u049f\r\xc3\x10\xbbv\xed\xc2]w\xfd\x00Z\u01e8\xd5z;\x86\x93\xdd!\x16\xb8N\\\xe2\xe0\xc1}\xb8\xed\xb6\xdba\x8c\xc1\x9c9\x03\xe8\xef\xef/\fO\xfdb]\xc6x\x99\xb2\u023b\xf7$\xa4D%\n14:\x81'_\u0608\x91\xb1\t\bY\xec\x96\u028b\u0431\xc3-8Nw\xc6\xe9\xa0\xf7<\t\xd43\x95?\u03d4E=\xc3\u05d1:2\x81\x04C\n'\x1b\x17\x8c\xf9\x95\x11\\2k+.\x1d\u0602\xf9\x95Qh\x16HXt.\xeel\xfd\xc8\xd9\xd8\x0f\x93\x89\u007f\x00_\xe3\xcf00:\x86\xd61\xb4\u0459\xe5-\x01\x10l\x80\xb0\x8a\xc1]\xdb1\xb8e\xa3\xf5\xc6\xf7\xa6\n\xba\xd5@\xcf\xdc\xc5\b\u7702\xb1F\xcb\xc2* (\"(\x10\x82\x16\xa1\xda$\x04\x9ar\u1303X2\x8eu\xdb\x11\xe2\xc9\x0e&u\xc20\xed\xc5\xd1\x0e\x1e\rdl R\U000bbdc0\x907t\x04\xac\xa7\xb8L\\QO\xb1k\x06\u0096AuB\xa32\xae![^\xb4\x90scd\xc30:\xb7\x83Na\u007f\xa9\fD\xa2s\xe8\xc8\x15\xfd\xfc=\xd87[8\x1fD\x10A\x00\x954ph\xef\x1b\x88\x9b\x13\x10Bf]\xbf1\x86{{{10{`\xd7G>\xfa\xf1\x97\x01\xe0\xf2\xcb/\xc3IS\u0337n\xdd\xdaj4\x1a\xa5\u017c\xb7\xa7\x8a\x9ej\xc5%\xebp\xe6H\u01c0\x1b4\x15\x15\x1f'\x14\x06\xf0H\r\xa9<=\f\x024\x1b\r\xbc\xfc\xcaF$q\xdc\x15\"\x91R\xe2\xb6\xdbn\xc3_\xfe\xe5_\xc1\x98\x04\x95J\x0f\xaa\u055eI\xf1s!\x04\xaa\xd5\x1eHY\xc1\xd0\xd0!\xfc\xe1\x1f\xfe\x1fx\xfa\xe9\xa7\xd1\xd3\xd3\x03\"\x01{\x8cDa\xfb\x97\x0e@}X\xa5\xfd\xff\xdd\x06\xa2\xa9\xe4\xdf\xf2\xcf\xed\"\xb1y\xfbn\xbc\xb1c/(\b\xf3F\x8c\x8e\xbf\xc0v\xde\xcb\xdcm\xea1\xed\xd7,-\xc0\xdc\xd9G\xfbW\aO\xf1zG\x15\x9dG\x80\x91\xf6#\xa5\u03f1d\x904\x10\xc26cU\x19cM\xdf~\\=g\x13\xce\xe8\u06c7\x904\x12\x0e\xb2\xdcX6\nF\u06ee\xd9h\x05\xa3\x95\x15\x00\x19c\x8b\x88\xfb}\xc6\x18(\x1dC\xe9&4+K746\xf4\x02N\xcc\"%\xe1\xc8\xf6\xd71\xb2{+d\x18Z\xbb\xc0\xecZ0\x98\xb9\xe2LD\x8b\x96#Nb\xb0\x14PD\xd0L\b\x9a@\xa5\x01H\x96 \a\xed\xb0+n0%\xf88\nU\u0583\xe1:q+\xa2I\x86\x1c).\xaes\b\x86<\xdf\xf0\x8c^$rA\x15\xa50\x8d\xe79N\xb0\x01\xcbA]\xa3:\xaa\x10\x8d\x1b\x88\x98\x8bR\xfe\x14z\xa1|6!2n9\x1cf\xee`Hmrr\xb9\x9f[\xe7\x86\x01RFhN\x8c`\u07f6\x97aX\x81\x84\u022c\x01\x94R4o\xfe<\xacX\xb1|\x1b\x11\xed\x01\x80\xb5k\xaf8y\\\x13W\xacX1\xe7\xe0\xc1\x83mrg\x06\x91@__\x1f\xaa\xd5j\xb6\xaa\x8a<\xab+\x0fa\xed0\x14:1\x83O\xe6\xdc\u0396\x1d\x8fIJ\x81\xb1\xf1:\xb6l\xdd1i\a\xcc\xcc\x18\x1a\x1a\xc6\xff\xf8\x1f\u007f\x84\xad[\xb7\xe2s\x9f\xfb\x1c\xce>\xfblDQ\u037b\x9a\xd3\xddW\xdem\x8f\x8d\r\xe3\xb9\xe7\x9e\xc3_\xfc\xc5_\xe3\xbe\xfb~\x840\f\xd1\xd7\u05cbF\xa3\x81\x89\x89\t\x18\xa3\n\xf8w\xd9\xe7\xdd\xdeS;,\xc3\xccPJ\xd9E\xa4RA\x14\x86\u0633\xff\x10\xde\xdcy\x00\xabN[\x05\xc3\rOP\xc7G\r\x8a\xe4\xae+\xe4\x05w\x94\xe1\xde\xc7\xd7\xed\x17zF\xe2i\xf5\xed]\xbd<\xa6\xf9\xbe\n\u040c\u021d\x03\xb3\x81.3\xa4+J\x02\x1a\v\xab\u00d8\x1140\xa72\x86\xd7\u01d6\xe0H\\\x03\x99\x040IfA\x9b\xdf\x00\x1e\x01\x9d\xac\xb3\x9f6\t\x14+(\xd2Pnn\xc4Y\aK\x10Q\x15c\a\xf7a\xf7\xf3\x8f i\xd4!+\x95\xac\x90\xeb$F\xcf\xc0B\xcc[y>$\"$\xba\t\x04V{\x1f4\x19QL\b -\xbd.-\xc0&\x87U\xc8cw\xb4w[\xbe\x10\xa7c\x89%\x14B6:\x96N\xff\xe9\xda\u044c\xdb\x17\x03\xedL\xca\xd9[\xfc\x8d\xa5\x87\x8alwdM\xceSk\x01\x91\x18\x04\x82\x90T\b*\xb2\xb35\x18\v\xb7\xb0K\u0720XC45\xa0\r\xc8\x18\x90vN\x93\x86Q\xd0\xf702\x85)9!\x163chp+\x0e\xee}\x1di\f\x94\x15\x9fYk\x8d\xfe\x19\xfd\xb8\u448b_\xec\xb6#\xfe\xb9-\xe6\xcc\\\xf9\xda\xd7\xfe\xfa\xba\xc7\x1f\u007f\xc2Q\xab\xd2H)\x06I\x81J\xb5\n\x11F.\u02638\x1cI\xf3\x1b\xa9M\xa4q\x82Jyf\u07aa!m\a\xe3\x9c\xea\xc7\xc6\xc70661)\x1e-\xa5t\x8e\x88-|\xfd\xeb\u007f\x8f\a\x1ex\x107\xde\xf8q\\~\xf9\x15X\xbat\tf\xce\xecG\xa5R\x05\xb3\xc1\xc4D\x1d\x87\x0e\x1d\u009bo\xbe\x89\a\x1f|\b?\xfe\xf1O088\x88(\x8aP\xadV\xd1j\xb5\xd0t\x1e*\xedB\xb2\xf6\xae<\xc3\xef\xa6\t\u0527\x05\xdd0#\f\x03\x8c\x8cO\xe0\xf0\u0430\x1d\xdcN\xa3\x1b\x9e\xea\x18v\xf1\x13\xcc_}1j}s\xa1\x1a\x13\b \x00e Y@\xb2\r\xba \x9b\x9e\xec\xe2x\x8c\xc5\xcd\x1d\xae\xdd\xee[\xe3S\x83\xbb\xda\fS\x11\xf2/\x1ea*\xc1\\\xa8}e\xc8\xe1\x96IN\x90\xe0\xb4\xe3v\x87N[\xa6\x11\t\x824\fj\x1aH\u0148k\x02\xa6F\xd0\x06\x10-\x05\xd9T@\xcat\xf1\x84P\xc4%\xa3t\x8f\xf9(\x84D\xdc\x18\xc1\xbe\x1d\xaf@%-\x9b\u0104\xdc\\k\u05acYX\xb6\uc517\x06\xe6\xcc\u007f\x19\x00n\xbd\xf5\x1f\xf0\xd9\xcf\xfe\xdaIS\xcc\xcd\xf8\xf8\x84\xb2\xea\xc8\xf6\xb9\x90\x8d\x87#O\xfak\x9d\xce\u0716\x06o5\x14e\u007fG\x00\xbb\xb5\xd5,\xc0\x9cg1NVP\x93D\u0658\xb8\xcc\xd2\xd6~4\x1a\r\xbc\xf6\xda\xebx\xed\xb5\xd7\xdb:y\x01!l*Q\xfa\xbbS\v\xdb\xd4\x1dq\xb2\x9d\xc0d8<\x11ux\xbb\xb4o\xfd\xb4\xd6v\xf0Jde\xdf\xe9\xce\xe7X\xecR\u0607?\xca\xfb\xe7\x13a\xc1R\x9c\xb1\xe5\x11}HM\x99\xb2!+OVk\xba\x0e@\x8f\xb7\xb8\x17\x1aV\x01\x10\x1b\u8111$\x06\xb3\xc2\x18\xe7\xf6\xc7\xe8\x93-l\xae/\u0138\xa9A\xa6>Bl\xb1p\xc3\x16;gg\xfc\xc5\x04ha\xa09\x8b\x9b\xb2\xc7X\x06\x18\u06ff\x03\a6>\xe3\x1c\xfd,\xfc\xdc\u03f4\x93\x9fL\xe19\x9d\x0e=}\x1d\xff\xb8\x96\rd\x02)\xa1\x12\x85\x19\xfd\xfd\x98;g\x00P\x89\x8b\xdc\xe0\xa3,\xac\xdd\x06\xa1\xd3h\xb0\x8e\x037\xb7;(ktea\x96\xdc-3\u035d\xe4B\x91\xe7\xa73\x9b\x91\xdb \x16\xf6\xfe\xc5m\x03\xb72\x04\x17m\xcf/K\x02\xa2)\x8azZ\x9bbePO\x14Z\xda@\xbb\xf0cCl\x8d\xbb\x84A$\x13\x9cR=\x88\v\xfa\xb7\u151eA\x18\xa1m\xd6&\x19\x1b\xf8\xe0B\x1f\x8c\x042\u0751\vxf0\xf6\xbd\xf8(\x86\xb7\xbf\xe6-\x1e\f\xa3\x15\x82J\x0f\x16_p\rj\xa7,G\x12\xa5\xbclw\x8f\x91\x84\x10\x81\x1d\xb8:\xb7E\x169\x13\xa7-\xdf\u00a5u\xf9\xd6\xc0T>\xbc\xf0W\xba\xec \xe5]6u$\xf7\x96X\xb7\xb9\x00\xeaN\x8eZ\xf9\xcc%\xb5\x0f\u0228\x8b\xe9\xa03\xb5\xd9Mi\x96-\rn% \xa5A\x89\x06%\x16b\u024c\xd4R\xa5g\xa7\x8e\xdf\xd5&\x89\xa1\xfd[ph\xdf&h\xadlg\xee.~!\t\xb5Z\rk\u05acy*\xfd\x99w\xbd\xf3]'W1\xb7\x85E\xef\\\xb2d\x91\x17\xb8\x90\xe3\xd1\xfb\xf6\x0fb\xf7\x81C\xa0 \x82f@\xb1\x80rFF\tK/\x1c\xf8\xd8\x13\xe5\xa7[\xd0\x05\x18P-\xf4\xd6B\x9c\u007f\ue648\xa2\bR\n\x04%B\x9e\xb2!c\x8e}s)~\xcd\x05Iq\x97\xf72I!?\u0582/R:\x90\x90Xu\xda*\x9c\xbax\x81\r\u0560\xce>\x94\xa7\xdeEg\xf1_\xed\x16\x00\x85e\xe1-ak\xe5%\xbbH\x85\xccc\u0734o\x8cL\xe5FbT\xc0\xf6\x8b\x85\xbf\x9dr\u074d\x9b\x9e^\x8dqb\u040a5bm\xa0a`\x88\xed \xd3a\xe0\xf6s\x03\"\x8d\xb9\xd10\u039e\xb1\x03\xa7\xf6\f\x02\xd2 \x11\xd6\x02V\t\x82\x16\f\x0e\x8a]\xb2\b+\xa8\x1f\u0687=\xcf=\x00U\x1f\x87\x90\x01RoXf\x83\x9e9\v\xb1\xe0\xbc+Aa\bE\x06p\xf3\x13!$\u0205@\x93\x8b\xe31.~\xad|\x97EE8\xa2D$D\xe8\x92\xcc\xc8\u0716\xe1\xc6m;\x1f\x9e|\x95\u6a7e\x99/<\xa9\x17LZ\xc8ar\x0e<\x19\x9d\xd9\x05\xb31\x99\x0f\xba=^\u02024\xc8[\x10\xb3\xe1gz\x92\x05ap\xf7\xabh\x8c\x1d\xca-o]\xf7\"\x84\xc0\xa9\xa7\x9e\x8a\x8b.\xbeh\f'\xe9C\x00\xc09\xe7\x9cs\xa8V\xeb\x19I;]\xbf0\xed\u067d\x1bol\xd9\x0e\x11F\x0e\xf2\xb0)6\x99y\x0e\u02b9\xe6o\xd5@\x94\xb5BU\x18\x9c\u007f\xe6J\xac\\\xbe\x14Z\x1b\xd4*\x95\fC\x9f\x0e\xe3\xa4\x1d\xf2(\x13\xfc\xb4\x1f\a\xff\xdf\u077a\xff\xa9\x86\xa4\xed\x8bF\xf6\xbaB\xa0\u054a1{\xde|\xac\xbd\xe4\x02T\xa5U$\u0494\v\\\xb7\xed4g[SP;^z\xfcA!\u04c3y\xb8\xa3\"p\xb7\xad{\x17\u0225\xd0\xd9Sw\xbdj\xc7\xf2\xec_\xadV\v\x85\x8b\b0q\v\xeb_y\x15\aG\x1a\x90A\x94y@\v6\x1e\xa6k\xcf\xde[\xc9\xcd'\xef\x06O\x9a\r\xacX4\a\xef\xbf\xf6\n\x1b\xfe`\fz{z\nR\xfb\xfco\xa0)\vy\xd9\xd7\xcb\x16\x81\xe9`\xe4Sa\xe9e~.\x96k\xaeq\xf6\xd9g\xe2\xf2\v\xdf\x06\xd5j8/\xe7\xee\x1b\u074ecCE\xf7C?\u00ac\fu~\xabe\x14\xbe\xea\xb3\xe8\xc7RfH\x8bB\xf9.\xff\x9by\xca\xe3\x90b\xf2\xc6\x10Z\x89F+\xd6HT\n\xa7\u5fd7Hd\xfe\x1e~\x97\x9f\x9a\xc6\xf5\xc9&\xde\u05b3\x1bg\xf6\xecA5J\x90\x04\x12:\x12v!p\xe7KTj8\xf4\xfa\v\xd8\xfd\xf4O\xa0\x93\x96\x1d\xcei\x9d\xe5\x99\xd6f\xcf\u01d2K~\x01\u044c~p\x1cC*\x9b\xedIA\x88 \xeaAX\x9b\x81 \xea\x01U\"\x10\xdb\xfc\xcbT\x00\xd5^c\xb9\xc4\xd1\u0187\xc1}\u031b\b%\xfe\xc4\xed\u017bDB6i\xf1\xc7\xf4a\xba6a\x13ke\xad\x12\xc8\xd9%\xb8\xc5.\xb3Vg\xbbS\xe2\xc22OY~if\xeb/\x04\x9a\x8d\x11\xd4G\x0f\xc3h\x95\xeaNA\xb0\x011Q%\xc2\xd9g\xbf\r\xbd==k\x98\xb9\x17\x00\x16-Xx\xf2\x15s\"\u06bfx\xf1\xe2\x17\x97,Y\f\xad\x15\xa7t\xba\xf4\f\xbf\xf0\xc2\xcb\u0630y'\x82\xde>$\x06.C\xb2\xbd{x\xeb\x1f\xe9\xefH\x92\x04Q(q\xdd\u0557\u0f37\xadF\xbdaC\x97\xa3\x8c\xe125d\u04ad\x90\xfb?\x9f\xb2QR\xdf\xf22\x1c\xbd\xfdg\xa7\xea\xc8\xcb\x16\x0e\xa5\x14f\u03dd\x8b\x8f\xdf\xf0n,\u83e0\x9d{e7Z_g!\xf7\x90f\xf2h\x89\\\x84Zh:p\xcdQ\u0737\u075e\xe7g\xc3\xf8\v\x89\x81\x80\xcaF\x8f\xd41\a \x94\xd1]=\xdf\xf16\x90\x80J\xd0[\u0144\x96\xd2h%\x06\x8960i\xf7\xe7\x89hR\xf4\xc1\xea(\x9c\x96\xc2\xc0:\xfc\xb9\xc56\"\x85\u0555}x[u\x17*Q\x82$\xb4\x8d\x02k\r\x11U\xd1\x1c9\x82]\xeb\xee\xc5\xc4\xe0\x1e\x90\b\\\xa1\xb2\x1d\xa5\x90\x01\x16\x9c{\x05\x06N?\u07fe+e \rA\x86UT\xfaf\x81a0\xb8\xfd\x15\xec\xd9\xf2\f\xc6G\xf7CBXO\x16\xe7\u007f\u4670\xa3\x8c\x8a\x98\r;}\xaf\xf7)\xb8\x9e\xed;\"\uee8b\x9atDZ(\xd4\xe5\xa3j\u01ddJ\x83\xa6\x8d\xa3x:\x98\u02a4\x10Jz\xdc\xe1\xabx\xd3y\x1c\xb2\x9cU\x16\x9cE\xf0%q\x1dq<\x81v\x034f\xc6\xec\u06730\u007f\xfe|0p\xca\xfe\xc1\xc1\x15'%\xcc\xf2w\u007f\xf7\xb7\x11\x00\x9cy\xe6\x19\x8f.[\xb6\f\xb6\x86\x11\xfb\xc6Q\x87\xf6\xec\xc4\xf3\u03ff\x88Fl d\xd0&\b\xe1\xd2\xc1\xd4[]\xd0\x1b\xf5:V\x9f\xba\x18\x9f\xb9\xf1}\xe8\xed\xa9adtlZ\x01\x14~\x10s\x19\x9c\xe2\x17\xdd\xf6\xe7v{\xbd\xa9:\xf5n\x98\xbaOO\xfc\xf0\a\u078dw\xad=\x17\xbaU\u03feF\xd3=\x9e\x85y\x11\xb51\x02\x90m[\t\xc7&\xe3'\x0f~\x9d\xee\xf3E\xa1\x88\x13\xb4#\xfc\t/\x98\xba\x9b\x11\x17M\x8d\xd2vl\xfc\xc9)\x00\x13\xa5\xd0J4b\xcdP\xa6\xe8]\x9e{\x85pV\u0233L\x06\a\a\xe4\x9f\x03\x01i\x9c\x1a\x1c\u009ap?\"RPL \x19\x02`\xecy\xea>\fn|\x06$\x84\x83\x0f8\vH\u8677\x18K.{/*3\xe7@\xc7-\x04\bP\xad\xf5\xa3\xda7\x80\xc3{7c\xddm\u007f\x8cG\xbe\xf3\xdf\xf1\xcc=\u007f\x81W\x1e\xf8&\x0e\xee\u0610\xf9\x9bP\xfa\x9e:'\u02c5\x93g\u00d7)\xd3\xf90g\xc1B\xc5\xed\x19O\x1f\x18+37\u0387\xa2\xed\xab\x03\x95\xee\xf4\n\xbf\xde0\xd8\x1bhZh\xcb\x0e\x94\xdd\x06\x06B\n\xab\x1b\x91\x00\x02\xfb|f\x86\xce1\x00\xb7x1\x94N\xa0un\xbf\xe0\xdfS\xbd\xbd}\b\x82\x10\u0198\xc0\x18\xb3\xf8d,\xe6\xc1\x19g\x9c\xae\x00\xe0\u04df\xfe\xe5\xd7\u05ed{\xfc\x95\x81\x81\x81s\x87\x86\x86\xb5\x10\"\xf0\xb9\u044f>\xfa\x04\xae{\u05d58g\xc5B\x98\xc6h\xc7\xcdM\xc7\xd1\xd1\x1d\xed\xf6=\xbd\xd0T\x92\xe0\xfaw^\x867\xb6\xec\xc07\xfe\xe5.\u0109\xea\x1a\xbe\xdc\xceR)+\xc8e\xf0J{`\xc7d]\xf7d\xde\xe6e\xbc\xf5\xf4\xf3+\xaf\xb8\x14\xb7\xfc\xe2\a\xd0\x1b0\x92\x89\xb8\xa4\x93\x9a^\x05M3\x1f\xb9\xacu\xe5Ni\xfdQ/\xba\u053dw+{rj1\xe2\x17x\xea\u03a1(_@\u0494\x9f6V\x8f(\xbc\x0f\xb2\xb1kJ#I4\x942\xce\xf8/}\xae\xb7#1\xb9\xb29+\xdc\u0739\xb0\xd8\xee\x92Q\x81\xc22\x1c\xc6(j\xd8&\x17\x82\xc3\x1a\x06\xd7?\x86\xed\x0f\xdf\x01\xd5\x18w\xb0\x8e\xce~JFU,\xbd\xecz\xccY}\x1e\x8cJ\x10\xf5\xf4\xa3\xda\n\x11\x1f\x1e\u0096\xf5wc\xfdO\xbe\x81\x83\xdb\xd7C\x06\x15\x04\x95\x1e\x1c\u067b\tZ\u0168\xbd{.f\xcd\\\x04\xc4-\x97\r\xea\x18\xd7e\x91vm\xc3\xc2\x02\x15\x9b\vzN\x97\xf9Yf\xa4\xc0%M\xb9\xe7\x8cE\xed{8*\xc1\xdcK5\xa4\xb9\xf5\x1e\u5db4\fc\xbf!\xad\xb9\x98\x88\b\x81\x04\xa4\x84\v\x87\xb7_W*\x8fLd'\xf6\x82\xb1\xdd:\t\x99\xbd\x96/\xf3\x17\x82\xd0l6\xa1\xb4\x02\x119\u01d8\x93\xb03\u007f\xc7;\xae5\x1f\xfa\xd0\r\x92\x88\xde\\\xbdz\xf5\xed\xa7\x9d\xb6\nJ%$\x84(\u063an}\xf5U<\xfe\xf4Kh*\x03\xc8\xc8c\xb1\x14/$?\xaa\xeb-\x85\\\xc8\x0eDf\xd4*\xf8\xfc/\u007f\f\x1f\xff\xe0\xb5\x16\xcb\x14\x02A \u074a/\xa6\xd5A\x97\r?\xa7\xd3}\xd34(\x91\x9d\x03R*\x18\xef_|\xd1\xf9\xf8\x83/\xfc\x1aV.\x99\x87\xa41\x81\"1\xef(\x8e\x87o2W\xb2\x9aNWV?9\xccB]Xp\xd4uqH\xa5\xfd\xb2\x00\xa1\x14\xa5\xfe<\xe5\xfa\xc1\x93\xa2\xea\x86\x19\xb1\xeb\xc8\x13m\xd0NXJ\xc3s\xb4\xb1\xf4S\x93u\xe6^A7\\$\x8b8\x88J\u00a0\x0f-\xac\xa0\x83X\x1c51\xba\xf3\rl\xba\xf7\u007fcl\xdf\x0e\x80lt\x19\u0600\x84]\xac\xe7\x9f{9N\xbd\xe6C\bzf \xa8\xf6@\xd7'\xb0\xfd\x99\x1f\xe2\xfe\xff\xf5y<\xf0w\xbf\x89\xfd[\x9e\x87V\tT\xdc@c\xf4\x10\x86\xf7m\xc1\xf6\x97\xeeG\xfd\xf0V\xf4\xf5VQ\r\x05\xa2\xc0\xfa\x10Q\x19w\\x\xe1q\x18\xd1\xfd\x00\x00 \x00IDAT\xd7\x1eP\x9e\x96\xaf\xa2-.\x95br\xdc\xd1aSgW\xc0m\u06c2\x12\xdf\x00\x9f\x19\xd6\x16\x14W0@3\x86\xf3\xfd\x18\x01\x14\x10\xc2~\x89hN\x80\xb0*\x10HB \ba@\x90!\x15h9\xe9.\x93\x89\x11\xd5z\x11Vz\xbc\xeb\xdc\xcd!H`hx\b\x87\x0f\x1d\x063\u01f5j\xed\xe0IY\xcc\x01\xe0\xf3\x9f\xff\x1c\x03\xc0\x97\xbe\xf4\xfb\xff\xb0`\xc1\x82W\xe7\u035b'\xb5\xd6I\x8e\x9d\x03\x80\xc6c\x8f?\x8d\xbdG&\x10Uk@\u6652\u039a\xf3\x05\x8d\xd1!\x90N\n\f\xa1\xa39\x16>\x83\x8f\xa9[\x97{l\xbb t \xa3\x9dI\xa2\x9d\xc8k9y\x90\xc0^h\fO\xb9\xab+[\u0532m<\x01\x86\xad\xaa3Nlr\x931~\xa2\xbbU\x19\xb2a\xe8\xf4\x1c\xc1\xb3d5\x1e\u0312\x0eA}\xa6Qv\xae\x193\"\u00bc\xe6~\xec{\xe4v\x1c\u07ba\x11B\x06\xd9@\u03fe\x9e\xc6\xccS\xd6`\xcd\an\xc1\xc0i\xe7\u00a8\x18\a6<\x85\x17n\xfd\n\x1e\xfb\xdb\xdf\u014e\xf5\x0f\xd9\u008f\xd4w[g\u007feR\x1fA%\x14\xa8\xd4$d\b\x04\x92\x10\n\x82\xf4\xb8\xe4)\xcf=KXB.2b?j\u03c3\xda\v;\x9aB\xc25M\r\xb3L\x87\xcd@\xe5\v.\xda\x03\xa6\xdd{c\x00$\t\x95\x9aD83\x80\x9c\x19@\xce\b@\x91\xb5\xb0\x15\x82 #\x01\x11\n\x8b\x97S\xbe\xa34l\x10\xf5\xf5\xa3\xda7\xdb\t\x8cR3\x17\xfbs\xf5\x89:\xb6n\u074aV\xb3\u065a=k\xd6\xf0I[\xcc\xdf\xfb\xde\xf7\x9b\x83\a\u007f\x06\"\xdaw\xdey\xe7\u07fex\xf1\"\x18c\x82\xf6\u0405W_Y\x8f\xf5ol\x87\x96\x15\xb0\x88\n\x81\xc3\xfe\xb0\xe6X\xb1\xd9c\x83]\x18\x13\xe3\x138e\xe1\\\xfc\xe1\x17o\xc1-7}\x00RJ\xb4Z\xb1\u06c2\t\xaf\xf0\xa2t\x88\x99\x16\xe70\f2FL\xfa\x9ct\bZV\u0627\x1b\x19GD\b\x83\x00Q\x18@\x1b\x03!%\xde\xf7\vW\xe2\xff\xfa\xaf\xff\t\x17\x9d\xb9\x1c\xad\xf1\x11\xc0$v\x11\xe4\xe3\xc8\xfa,\xe1\x06w\u04d3L\a\x06\xa3\xd2\r\xb6/\xe4!\xb4k4\u065b\xa4\x14\xf0m?K\x93\xa6\u0388\x9d\f\xbeI_[k\xb6<\xf2\xc4@i\xce\nq\xdaYg\x10\x8a\xd7yk\xb6\u0676\x99\xba7\xed\u0239\x04KwEM\xca\x00\xa1\x14\xd8\xf9\xe2:\xecy\xfe\xe1\u0316\u0546Y\x18\xb0V\xe8_r\x1aN\xff\xe8\xe70c\xc9*\xecy\xe6\x01\xfc\xec{\u007f\x8d\xe7\xfe\xd7\x1f\xe0\u0347nCc\xfcH\xe1\x04\xa5@Xz\x8d\xac\xb9\xecz,Ys!\x94j\x81\xa2\x00\x14\x10\x84\x04Bi=\xd2\xf3\x18{r\xd0\x05\x15l\xe3\v\xd4\xe0\x8ek\xa0\x18p\u0285E\xb6\u06d5Q\xb6\x9cs\xd7U\x9e\xdb!3\x8f\xff\x9d\x82\xf9i4]\x10\x10\xc2^\tY\xb5\xa1\xe5\xa8\x12\xb8O\x80+\xb6\xe0KA\bB\x02\x059L\xc3l\a\xcf2\xac\xa0\u007f\xeeR\x04Q\u0545h\xa7\xf5\\@%\t6l\u0600\xf1\xf1\xf1\x04@|Rb\xe6\xe9'\xf3\xe6\x9d\r\x00\xf8\xf2\x97\xbf\xfc\u05ef\xbc\xb2\xfeS\a\x0e\f\xae:x\xf0 \v!\xc8hmW\xc7\xc68\xee\u007f\xe0a\\\xfe\xf6\xf30/\xea\x81i$n\xa8E\xe0\xe3\b\x1cFigw\x14\xc396\x18\x9b\x98\xc0\xbc9\xb3\xf0\a\xff\xf9f,\\0\a\xff\xf8\xdd{\xb1\xef\x80\xddm\x05\x81\x8df\xb3\xa2!\xd3u\x90g;;sTC\xce2\x1c<\xe5\x8e\vB\xb6c\xd1Z#I\f\xe6\x0e\xcc\u00a7>\xfa^\xdcr\xd3\xf5X0w6\xc6\xc7\xc6\xf2N\x9c\x8fn\xd2\xd0\xce5\xeff\x99;\tb\xda\xf5\x98\x97\ty\xca;u?\x8a-\x85[\x8aT\xc0b\x01\xe0i_\v(\x81s\x00\x02\x1b\x03e\f\x942P\x86a<\xd6\n\xbcn.\xeb\xb8\xfd\xee\u06dd\u007fk\x16\x87,t\xc5\xd7\xe5\x14\xf1X\x81J%\xc4+?\u06c8\xc7~\xf2c4\xc6G\x10\xc8 \v\xb0\x00\x00Y\xa9\"\xac\xf5\xe1\xf0\x1b/a\xd7\x13?\u0111-\xaf`\xfc\xc0.\xdb};\xac\x97\xbd\xa0\x8a\xec\x98\n\x81\xb7\xff\xe2o\xe0\x1d\x9f\xfdo\xe8\ud7cf\xf8\xd0((\xb0v\xbd\xc4\x02\x82\r\x02\x10X[H(u\xea\xed\xd8y\x15`\x95\xfco\xf1=\xc8;\x05}\xdcf`E\xe8n\xb0P\xb6?\x9b\xfc\xdc1\xe5\xda\x02\xe3\xbar!\x80\xa0B\x10\xbd\x02$`=\xd0\xc1@\x85l\xe6\xed\x98\x01\x9a\x1a$\x800 \xb0\x01\xb4rW\x98]\x851g\xe9\x19\xa8\xf6\xcd\xc2\xd8\u1f50A\xba\xc6\x11\x12f\xbc\xfe\xc6&l\u07f1#:\xf3\x8c\u04eb'mg\x0e\x00_\xfb\xda\u07e4\xc5\xe9\xc85\xd7\\\xfd\xed\u014b\x17AJA\x00Xx\xfc\xedg\x1f_\x87\xa7\x9e\xdf\b\x84\x15@\xe4~-\xbe\a>\xb7\xc1q\xddvle\xf9\x90|\f\x85,\x1d\xfc\x8d\x8fO \x8a$>\xfb\x89\x1b\xf0\xe7_\xfe\x1d\\\u007f\ud568U+PJ\xbb\xf0e{s\n\xf7\xc6|(\x85\x99\v\xde,\x19\xde\xea\xbc]\xcaR\x84\xca:\xf0J\x14\xa1\xbf\xaf\x17\xbd\xb5\n\xc2@\xba\"n\xe5\xfc\x97_|\x0e\xfe\xe7\x1f\xfd\x16~\xe7\xd7n\xc4\xfc\x81\x99\x18\x1f\x9b\xc8\xfbL\xe6)C\xe1\u0288\r\x93A)e\x86\xa74\xc5\xebLVP\xc9y\xae\xf8\xc3\u0254f\xa8\xb3\xef\x14\u007f\xdex\xbd4\x1d\x85B\xb8\xdb{\xd3\xc6 q\xb0J\xa2\f\x8c6\xc5\x01&\x17\xab\x9d\x0f\xa1\xd8N\x1c\x9e\xab\xa4\xbdn\r\xdb@\x04\xbf\x90\xb3[\x84\xab\x95\n\xb6\xed\u0703{\xee\xfd\t\xf6\xee\u0647@\x06 \xe3(\x8c\x9c\xefE\x87\xb7\xbf\x8a\xd7\xef\xfa\u007f\xb1\u3c7b1\xbe\u007f\xa7\xed\xf0\xb5\x82Nb\xdbE\xb6\x1d\u0359\x8b\x97\xe1#\u007f\xf2\x0fx\xdf\u007f\xfd\v\xcc^\xb1\x14\xaa\xd2\x02\u034d\x80>\t\xaaJ\xa0\"\xc0!A\b@z\xd3^r\x01\xcb\xd4n\x8a\xc5\xc5\x15=\x8dQ\xeb6-\xe1\u0098\xbam\xc8\xc9\u076e\x94\xac\x15n[`\u06f6\x87\xd9\xf6\x8b\xac\r\x88\xf3\x9e\t#B8#\x80\xac\x884\xe7)_mC\x02f\x04\xe0\x1e\t!\tR\x10\"ae\xfaLn\x80\xaa\rf/X\x89\xdeY\v\xb3\xc8>\x9b\xf4d\x11\x84\x83\a\x0f\xe2\xd1G\xd7U\x01\xcc:\x19\x8byV\xa5\xef\xbb\xef>\xe4\x9f\xff\xf8\xf9\xe7\x9e{\xe6\x86\u077b\xf7\u032f\xd7\xeb$\x84p\x1d\f\xa0[M(\n\xb0\xf6\xca\xcb\xd1\x1b\x00\xa4Z\xb9\n\x14>\u038cLxT&\xbb\xe6)\x98\f\u01c2\xa5\x83\bIb\xb7_+O]\x8aK/>\x0f+\x97/\xc5\xd8\xc4\x04\x8e\f\x8d\xa2\x15\xe7\x9e\xe4\x16O\x9fj/P\xc4\xcdE\xdaq\xb7a\xf1A \x11\x06!zjUDA\x00\xa5\x12L\u051bH\x94F\x10\x068c\xf5r\xfc\xc6\xcd\x1f\xc1o\xdd\xf21\\|\xee\xe9H\x92\x04\x8df\xcb.*<=4{2\xfa\xe7\xd1`\xe2t\x14\xc7sRn{\x16\xea-\x9c\x8f9\n\xe5\xc1\xef\u0667\xc2\u01e7\xfb~\x94f$Z#Ql\x87\x99\x1e\x94\xd2\x0eo\x15\x98*\xe9\x87\xc9\v\b\x15v]T0\xb8\xb1\x9d%\xa1Z\xaba\xff\xc1#\xf8\xce]\x0f`\xc3k\x9b!\x88\xa0\xb3\xc5\u0763X\x1a\r\xa3\x14H\xda\x0e\xd3\x18\x03\x9d\xb42\x8c\xdc\u007f\x84=3p\xce{o\xc2\xf5\xbf\xff\xe78\xfb\xba\x0f\x00\x14 \x9e\xa8[Ec(l!\x0f\xc8S\xef\xe7<\xd5\xe2\xdc\u05a3\xfb\xdc\xc7\u051d\xd3\xf7\x04\xa0N\x02{\xd1\x1e\x82\u0684`y1OU\xb6 \x82\x11\xd6\a'\f\x80\xea\x8c\x00\xb2O\u61da\xdbV[\x01P(l=\xf1h\x9a\xc6\xc1a BT\xe9\xc1\xc8\xc1\x9d8\xb8s\xa3\x1b<\xcbl\b\x9a$1\x94J\xa25kV?}\xeb7\xbf\xf9\x12\x00l\xf8\xd9\x06|\xfdo\xbf~r\xc1,\x00\xf0\xcf\xff\xfcO\xf8\xccgn\x01\x11\x8d\xddy\xe7\xbf\xfd\xfe\xe6\xcd[~8::\x9aejjG\xd3{\xee\xc9'p\xff\xe3\xd7\xe2c\xef\xba\x18\x11\xd5!\xd8\xf6h\x06V\x19\xea|z\\\u03ae\xbd\xf0L!\xee\xc4\xcfvo\xff\na\xf2h\x94\x92A\x98\xf7oA\x04\xc3\x1a\xcdF\x1ds\x06f\xe1c7\xbc\x1b\xef\xb8\xe2b<\xfd\xdc+\xf8\xc1\x8f\x1f\xc1\xc67\xb6\xe0\u0411a\xc4q\x92]\xb3\xa1sS\u0303c\xadC\x9b\x10\x02\x81\xb47g\x10H\x84a\x80@J0\x03\xcdV\vq\xac\x1c\xceg\xcbV\xa3i\vx\x14\x04X\xb0`.N_u*\xde}\xf5\xa5x\xe7\x15\x17\xe2\xd4Es!\x880Qo@+\x93\xfb\xb1\x1cC!o\xff&s\xf7\x8ez\xba\f\x16\x9e\xe2y\x9d\xb4F\xfb_\xe1\x06\xe1\x94\xf5\xe5m\xbcc\x86\xe7\x13s\xec\xf0\x9b\xd2\x06q\xa2\xa1t^\u023b\xc17&c\xaaX\x9a[\xb6\x8bB\x1e\x05\xc7\xce>\x04\x19\x14\x96\xe3\u0646\x81 \xac`\xdf\xc1a|\xef\xae\a\xf0\xcc\v\xafd\xe5Li\x95u\x85\xfe\xae\x10\xb0\xbb\x04\xad\x94\xe5B\x1b\xed\"\xcel\xd1\uf67b\x10\xa7]\xf5>\\\xf8\xe1_\u018a\xf3\u05e2\xda\x17A55t\x12\u06f8\xb8\xb4\xb0I\x003$\x10\x11DU\xc0\x8c\v\u0206\x06\xb7\fLb\xe07\xf9T\xb0\x9f\xf5\x8ac[t\\\xc7}\xd7\xee\x91\xce\x00\x89\xa2V\x81\xb8\x1b\x82\xce\x1e1\xb1Dn\xeae\x86\u06a2.\x11\bF\xb5F\x90\xfdd\xff>\xc3\x1d\x17Zv<%\x03}\xd2>o\x9c\xed.\x84\xac2\xd7h\x8d \x8c\xb0\xec\xac+\xb1m\xfd\x03\x18\x1f\xda\x0f\xe9\u03ad\x10\x84\xb8\xd9\xc4\xe0\xe0 ~\xfa\xf0#\xb7\x00\xb8\x15\x00\xce9\xfb\x9c\x93\xaf3\a\x80;\xef\xbc\v\x9f\xfe\xf4\xa7\xe8\x95W6\xe0{\xdf\xfb\xfe\xe6\x9bo\xbe\xf9\x8a\u077bw\xaf\x1a\x19\x19q~\xdb\xf6\xc0\xa9V\x03\a\x87\xc7q\xee\x05\x17`\xc1\xac^h\x15\xbb\x9c\x14\xeeX\xa9\x05\xa5\x1d\x1c\xa6t\x05i/\x06G\xd3E\x16;t\xbb\x93h%\x1a-C\xe8\xef\xeb\xc1\x19\xabW\xe0\x1dW\\\x84\v\xcf9\x03\xf3\xe7\x0e\xa0Z\x89\x10\x86\x12Ji4\\\x1a\x11{\x16\x9c\x96yb\v\xba\x10\xd6\x14\x89\xd9 I\x14Zq\x828I\x10+\x05\xad\xed\xb6?\b\x02,\x987\ag\xaeY\x89\xf7\\{\x05>\xfb\xc9\x0f\xe3W?\xf9!\\v\u1658\xdd\u07cb$\x8e\xd1h\xb62\x95 xz\x1e\xe54I\xa7\u0716\xa8\xd5q\x1c\u02e4\xf1S\x15\xf1\xc9\xf6+T\xb6s\xc9(\x87T\n\xed\x1co!\x87W\xc8\x13e\xa0M\x1b\xe5\xd3\xfd7E\xc7\xd8%c\xa5\xb4C\x98\u0734)\x03\fr\x97\xd7\xccy/\x9f\xd9\x11\u00a8\x82##u\xdcv\xefCX\xf7\xf4K0ly\xeb\x16.3\x05\xb0\"\xdd\xea\x1b\xada\x8c\v\x84v\x1d#\xb3\x81\x88jX~\xcd\rx\xe7o\xfd\x9f\xb8\xf23_\xc0\xa2\xd3V@\n\x89\xa4\x11\xdb\u039d\xa8\xb0\x9b\xc9p\xfb\x80@U\x01\x11\u065d\xa0$B@\x94u\xab\x85\xf9J!\u05c1\xa6X\xa2i\x92\xe99O~\xc6\u067f\u6f06\u0311\xde-\u00db`\xd2\u0667$ \x14\xa8V\tQ\xbf\x00E\xe4\xe6\f>\xc3\xc6g\x0f9\xf5\xa8 P(\xec\xb9L\x87\xdb\xee7J)Q\xe9\xed\u01e1]\x1b12h\xe9\xa1\xf6\xfc\x11 \x88\xe3V\x93\x84\x103\u05ad{\u426f\xfe\xf9Ww\x01\xc0\x0f\xee\xbe\v\xdf\xfd\xcewO\xae\xce\x1c\x00n\xbe\xf9f\xfe\u05b7\xfe\x15\x00\xf0\xb1\x8f}\xf4\xcb\x1b7\xbe\xbafdd\xe8\xd4\xf1\xf1\t\x04\x1c qE\xef\x8dg\x9f\xc4\xf7\xff\xed^,\xfd\xf5\x9b03\xac\xa2\x157\xec\x1c\x03\xbap\xf2\r\x8a'?s='\x1f\x9f+\u0798\xdd:\xef)\a\xa1)\xae\u02e9\u007f\x8cF\xac\x12\x8c\xaa\x04\x95\x00\xa8U+\xb8\xf4\xa2sq\xe9\xc5\xe7ahx\x14[\xb7\xed\u0126\xad;\xb1u\xc7\x1e\xec\u06bd\x17\x87\x8e\fatl\x02\x13\x13\r\x8c\xd7\x1bh\xb5b(\x13g7\x8f\x10\x840\fQ\xabV1\xaf\xaf\a\x03\xb3\xfb10{&\x16\u039b\x8b\xe5\xcb\x16\xe3\xf4\xd5+p\xc6i\xcb1o\xee\x1c\xabtT1Z\xcd&\x94\xd6Y 62\xc6\xca\xe4\u007fYG!\xa7\xa2\xa0\x8f<:0g\xdd9\x15\xc6ZeCOB\x99@f\xfa\n\xcc\xf4sS\xe2\f\x95E{u\x89\x8c;\x96G\xa2\r\xe2\xd8 q\x1dy\n\x9f\x14\xf8\x17\xe9V\xdc}O\xbb\xffS\xc7\xd5d\x1c\xd4R\x98\x9e\x17p\xdeZ\xa5\x82\xfd\x87\x86q\xfb\xbd\x0fc\u0753/d3\x14\xed\xf2_\x89\xf2\xe0\u2b10\x1b\r\xa3\x13h\xad\xb2\xfc\\f\x8d\xfeS\xcf\xc4\x19\xef\xff4.\xfd\xc5\xff\x84\x85K\xe7\x80\x12 \x99HlxEV\xccr;Z\xff\x9cQ\u0298\xe9\x11\x90\x01A\x84\x04\x1eW \xc1\xe0\x86\x81J\xf2\xa2^\x9e\xa1\xcd%g\x87\xbao\xb9\fw\xf2\x89\xdb\x02*\x88\xbaL\xb5\xc8\x19\x1e\x93o\xfae\xb3R\xab\x91@\xb5_\x02\xbd\x1aF%\x85\xd0\xed,!(C}(\xd7K\x10@\xbd\x02\xa4%\xc8%/13\x14+D\xb5~\x9cr\u0595\u063b\xe99\xa8\xb8\t#\x04\x041\xa4\x1046>\x81}\xfb\xf6\r|\xeb[\xffz#\x80'\x00\xe0C7|\xf8\xe4\x83Y\x00\x9b\xccq\xc7\x1d\xb7\xd3G?\xfaq\xbe\xf0\u008b\x9f\xfc\xf6\xb7\xff\xe5\xbf\x11\xe1\xdb\x0f=\xf4S0\xc0ZI2\x8e_\xfb\xc0=\xf7\xe0\xfc\xb3V\xe1\x86k\xd7\xc2\xc4\t\x88\x15$\x11B\xe8L\x05\xa6\u0754\xd5\x06t\v7\xec\xcb?'\U000b71b9Y\x97\x1f\x14>]@\"\u007f\xbeM\x92\xb1#\xb9\x04\t$\x94\x02\x8cj\"q\x98w\u007fo\x15\x97\x9cw&.\xbf\xf8\x1c\x18\xadq\xe4\xc80\x06\x0f\x1d\xc6\xd0\xe8\x18\xc6\xc6\xea\x18\x19\x9f\xc0D\xbd\x89X\x99lK/\xa5@\xb5RAoo/f\xce\xe8\xc1\xbc\x81Y\x98;g\x16\xe6\xce\x19@\x14\x06H\x94\x82N\x12$\x8d:\xd8(\x10k\x14\x93QyJ\u018ao\xc91\x15\xbd\x93K\t0\x9d\x0e\xe8\x93\xcd*\xcaX-\x8c\xa9\xb8\xdf\xe5\xfb\xa9N\\\x9f\x8f\xbf\x90;\x8f\x15m\x8a>+\xec\r\u074d[\xe5\xd8+\xea\xe9n\xb0 i\u271cW`\u007f\x00\x10$Q\xadF844\x8a\xef\xde\xfd \x1e}\xeaE\x18c \x85\xcc\x02\xb7\x995X\xbbW%\x8b\xe3\x1a60*\xb1\x96\xc5\xeeQ\u96cde\xef\xfc(N\u007f\u07e7p\xfa\u06ef\u00ac\xde\x00z\"v\x05\x93;\xa9(\xdc~ls:!\x81\x80\x88\x80Y\x04\x84\x04!\x05$'\xd0F\x83U\xdb\u0312\xf3\xb3GGA'`\ued01!t\xb2f\xca2~\xb3\xb6\xc4\x17$\x11\xa0% #BuF\x88\xa0\x9f\xa0\xc1\x80&KQ4\\\xec\u0385\xb0Ceo\xdea\xbb'\x80\xfa\x02H\xc3\xc0\xb8\x86\xd66\xf4\x03\x82\xb0`\xf9y\x985\u007f\xb9\xc3\u0383\xec\xaf\x0ed\xc0\a\x0e\f\xd2\xd3\xcf<\xb3\x96\x99{\x89h\xe2\x99g\x9f\xa6K\u07fe\x96O\xbab\x0e\x00g\x9ey\x06\xff\xcd\xdf\xfc5\xfd\xf6o\u007f\x81?\xf1\x89O}w\u01ce\x9d\x17\xef\u0739\xf3w7m\xdaDA\x18\x98VK\v\x00\x18?\xbc\x1fw\xdc\xf9C\x9c}\xe6j\x9c\xbeh&Z\xe3#\b\x1c\x13 \xed\x92\xd1\xfd\xb0\x02\xd7\xd1\x11\x15\xbe\u05ae+$.z\xefOBq\x9d\xa4(rF[\x94\x99\xb0\u0240\xb4\xb6)\xe0\u0292Qc\x87\xeb\xcf\xec\x8d00s)\x02!!\xa4\x04\x89<\x88\u00f8\xad\xb0v]\x85a\x86QvK\xad\xb5F\u0728\xa3U\xf7L\xf5\xc9\xce\x0e:\xcb\xeb\u051d*\x95\u031e|\xeb\x84BG\x0e\x94\xda'\x91\x1757\x99\a\x13w\xe9\u0727\xc2\xdd\xfd\b\xba\xf6\xe1X\x99\xac\xe8\x98\n\xb9J\v\xb9v\x18\xb9\x1d`\x1a\x8f\a\x9e\x0f=\xdb\xff>G\x93\xe4\x1c\n!/\u07cc\xbc\x95\x92a\x17\xf7j-\xc2\xc8\xe8\x04n\xff\xe1#x\xf4\xa9\x97\xa0\x8d\x81\x14\"\u03cf\xd5\x1a:i\x02\xb0.\x9d\xa9\xb1\x96\x0f\xf9\xf4\r,\xc6)\xe7\xbf\vK\xdf\xf9a,\xb9\xfc]\x98?o6\xaa&\x86i6\x8b\u0175=z\x8d\\0\xb2\xdf\u9ca7\xaa5\xb0.\x8f}\x01H\n\xbb;PV\xcd*\xdc\\\xa0]\xb2\xcf\x05\x1f\xfb\x829BfN\xc5\x1e\xbe\xcep\\u\xea\f\x15\xa4.\xe6l\xedWX\xca}\u05c2@\x01\xa1\xd6\x1b \x9c\x19\x80\xab\x04\x8auf[\x9b*XS\xc8\xd1\xe6'pg\xdc)\xac\xc8H\xf6\x05\x16F\x9b\xb0;\\\x9d\xc4\u86fd\x10\xa7\x9c\xb1\x16\awnty\xad\x96\xa5&\x03I\x83\x83\ay||\xe2\u04bb~p\xe7\xaf\x03\xf8\xab\x17^xA\xb8\xbe\xf2d,\xe6g\x03\x00\xdf\u007f\xff\x8f\x03\"R\xcc\xfc\x95#\x87\x0f_1>>~\xe9\xb6\xed; \x85\x84v\x93\xfa\xf5\xcf=\x8b\xbb\xef{\x18\x9f\xbf\xe5\xe3\xa8Uj\xe0\xa4\x01C\x021\v\b\x17#f\x03~\xdd\xc5I\x1e\xc7\xd7\x15wIE\x8e:Q\x9b\xf7\x86\xe7?Q\xec:i\x12\x94\x8f3\x9f\x88\x00\xda+7E\xdd;9\v\xce8\xd6\xe08\xbf6\v\xc6U~\a\x82b\xcee\xfb\xfb\x05\xf9\xdd :n\x88\xc9\x17\x1f*\xfa\x17qI\xa2\x10\x8a\x05\x9e\x8fb\x91\xa3i\xfe\x9bJn_.-\xf2\\p\xe9\xa0c\u0499vB>\x896\x88U\u0691[\u06a0q\xaaM\xe31\x1c&\x03\x17l\x01\xf7\x80\xe6\xd8\x11\xb4&\x86\xc1\u0318\xbf\xf2\x02,\xbf\xf0:\xcc=\xedB\xd4V\xaeFu\xe9<\xf4\x06\t*I\u074a\xee|\xba\t\xba\x0f&\x88\xda\xf6T\xfe\xf7\x8d\xbb\xcej\x02\x8c\x10\xb1b\x18V\x88Z61\x89\x8d\xdf\xf8\xe4\x05\xddU\xe9\x8e3\x96z\xb6p\xfb\xc04+\xe8e\x9e\x94\x93\xc08\xc2\xdel\xc6\xf9\xafT{\x02Tf\x05@\xcd\xd2\x10!\x03\x18\xa1@Bg0hv\x93\t\xb8@haC+\x90[2\b\x02(\x12P}\x12Z\x19\xc8&\u00e8\x18Q\xb5\aKN\xbf\x04\x9b\x9f\xbb\x17c\xc3\a]XE\xba\x83\x96j\u01ce\x9d\xe1\x03\x0fx\xedZ\b0t\xdct|]\x01\x05'*r\u05f2L\v;Q\xdeC\xb1\x87\xc0\x12Cp\xfb\x8d\u0649\x01s\x89/7\x95l\xffDv;{\x8aEo\xf9/\xa4\xbb\xa4-qfND\x9eq\x90\xc9::fn\xebx\x8a\xfd,\xe5\xab\xd64q\xfe|P\xdcm\aRz{\x95\xee\xa4;\x91\xe2\u92b1:\xed\x93\xfc$ .,h\xd4\xf1\f\x00\xc7\u0451\xa73\x81D\x19\xb4\x94\xe3\x90;h\xc5/\xe4\xc6\xf8\xe8\xbc\xd7\x15\xb2\xb7\x843w:*\xb6\x1fC7\x03\xa9U+8ph\x18\xb7\xff\xe8\x11<\xf2\xf4\xcbH\x94\x82\x94\xc2v\x80Z#Nb4\xeb#Xu\xd6y\xb8\xe2\x96?Fm\xfeyH&F\xa1\x9bu$\xad&d\xb5\x8a\xdeY\xf3Q\x9d5\x0fI_\x15I\xb5\x85\xaa\x19C\x0fKH):\xad\xc2\u0476\xe5\xccL\xc9\v\x88\xb9-\xec%\x97\x97\x00 #\x01\xd5\x1fX\x99\u3a36A\xc9\xcc\u0747\"]\xc06.1\xcf\u028b?\xb5\xdda\u0735=`\u07cf\\\x10\u00aa@uf\x00\u0457\x97\x17!\x05D\x108K\\\x06\x9c\x101SQ\v\x91N5\x1c>\x96\x0f7\x04\x11\u008aD2\x03`N`Z\f\x95\u0118\xb3h5\x96\xae\xb9\x04?{\xf2N\x04a\x04\xc3\fA\x84\xa8R\tv\xee\u0705\u077b\xf7\\\xf7\u063aG\xae\xbe\xfa\xaaw\x8b\xa51\xeb\xbb\t\x8e\xdf\xd5\xd9\xc1\x94\xe1\x91\xe9\xff\x05\xca\xe7N\xfe\x93\x89<\u04e5\xb6\xf8\xb4no\xfehL\xb5\xa8\u02f3}\xc0\xc4x\x8e1\xe5\xf5\xe2\xf8#\x03\x13\xa5\xd1Lre\xa7\xf6?\xf4\xf4\xccF\xdf\xecE\x981\xef\x14\u0318\xb3\b\xb2\u0683\x96L\xa0k1\xfa\xfb$\xfa#im]SC\xac\xec\xb2)\x02\\\xcc\xe4\xe5^\xe6\uf66d\xd9K\xa6\x1a%\xf8\x0ev\fA@\x18\n\xe8\x90\x10K\xb7P\xb9\xc0d\U000b72e5K:\xa1d\x85ikh\xdaH.\x1d@Z\xfagP\xceZqL\x96\xa0G\xa26\x10\"\x9a\x1dX\xde}\xda\x12e\x17\xb1\xcf\x1a\xa3\x9csN\u0536fPA\xab\"\x84\x1d\x02+\x02X1\x90$\xe8\x9b9\a\x9c\xb4\xb0\xeb\x8dg\xa1\xb5r|s\xfbbI\xa2LT\tjc\xa3\xa3;\x9e}\xf6\xb9G\xef\xb9\xe7\xde\x13\x1dO\xfc\xef\xee1\xa5U\xe4\x82\x05\x8b\xf9\v_\xf8m\x00\xc0\xb5\xd7^\xf7\x8d\xab\xaf\xbe\xfa\xcf\xce?\xff<\xf4\xf6\xd4 \x82 +]\xfb\xb6m\xc1\u05fe\xf6u\xac\u007fu3\xaa\xbd}\x99:\x94\x19\x99BP\xb1\x84\xce\xf0\x03\xcbK\x97\x04\x04\x94\x1761\x9d\x81_\xc9\xd73\x93\xfb6\x1de\xc1\\n\x92B\xceSa\xf3T\x9c\xcar\xbb\xae\xb1\x8de\xd1\u0669\x96'\xe8LZ\xc81\xb9\u043a\x13\xbb\xc41\x16T.\xed\xda\xd2\x1c\xa9\xf4\xfc\xa5\xf9\x9d\xa6C.\xc2\xc7\xc5\\a\xb0\xed\u0213\x9cKn\x8c\u0166\xd3b\x9e\x1ac\x15\xfe>\xceY<\u0145Ix\xb517\x81\xb3X\xb1\xd5\x15T\xa2\n~\xb6i\x1bn\xfd\u07bdx\xf2\xf9\r0\xc6r\x95\xad(\u0206p\xb7\x1a\x13X\xb1r9\xae\xff\xe5/a\xe6\xcak\xd0\x18m\xc04&\xa0\x9a\x13\x88\x1bc\x88\xeb\xa3h\x8c\x0f\xa3a\xea\xe0\x19\x84\xfe\xfe\x10\xbd\x01\xb9\x05\x9a\xba\x9c\xb0\x9cuC~\xd7\xec\xfcGT\x12C\xb5\x9aH\x9a\r\xa8f\x03\xaa\u0544\x8acOIj_\xbb&\tsj\x12\xfd\x03\x01\xc4\xfc\x10jV\x80$\x12.\u06d4\u06ba\x1c.\x1d\xccPG\xf4\x1by\x83T*\xccl(\x03\x17\xdb\x1ayw\xc32\u0641g43@8+\x00\x82\xb4\xb1\xf1\x82\u02e5\x84\fB\x9b\x89 \x05\x84\x14\x16/\xf7S\xc1<\xf1\x96\xbf\xf4\t\x00\x91 \u022a\x04\xf5I\x84U\t21\x16/?\a\x8b\x96\x9f\x03\x157\xad%\x80\xdb\xc1\x85QH;\xb6\xef\u0091\xc3C\x1fd\x93\xac8\x190s9\x9d'\xfd\x97\xff\xf2\xbb\xb8\xed\xb6\xdb\x01\x00\x0f>\xf8\xe0\xcb\xeb_~\xe9\xc2\xc1\xc1\x03\xab\xea\xf5\x06i\xe6\xec\";28\x88m;\xf7b\xd5i+\xb1t\xd1B$Jyy\xb2\xe4\x8a5#\x00[\xb8\x85\x01I\x8c\x88L\xae\xb0\xf4\v3O\xd98w\xed\u01cfv\x19\x9e\nO\xee\xfe[\xf2\xff\v\x0f\x1b\x17(Wm\n\xbf\x1b\xa7\xeeE\x1c]\n\xbd\xefg\xcdDG\xfd\xbe\xa7*\xe59D+\xa1!]G.Jv64\xfd\xf0\x8ci\f;[\xb1\x85V\xb4\xb6]\xb86)[\xa4\xcd>\x98\xba\x9f\x8d\\L\xe8\r\xff2\x15\xb2\x84!\x89\u0219\xa9=\xf9\xc2\xcf\xf0/w\u070f\u05f7\xec\x00\t{\xedi'\xfaI\x92\x04q\xab\x893\xcf:\x03\xd7\xdf\xfc\x05TW^\x87\u047a\x85\b\xadq\x9b],\f\x01\xaa\"@\xb3\x03\u0318i\v\xb9\xec8 y\x81J'\v\xa9}\x80Q\n&I\xa0\xe2\x16T\u0482j5\xa1\xe3\x16t\x12\xc3\x18eM\xbc\xd2\x04#cR\x16v\xa6\xb4\x0e\x88P\x91\x02\x95H@\xf6Hk\u0125\xd3E\x8f<7[\xcam\n\xfcXXj\u03dc+\x0e\xec\v$\x84\x0e\x88\x8f<\x81\x90\xb5\xae\x8df\x85\b\xe7\x86\b\xaa\xd2m6J\xae,!,W\xde\xcb\a-t\\\xdc%\r\x89r\xd6M\x10\tDB\x00\xcd\x043\xfa\xe6b\xec\xf0^\xec\xda\xf2\x02\xac\xed\x88=\x97B\x10)\x95`\u018c\xbe\u015b7o\xfe\xfe\xbau\x8f\xef\xfa\xbb\xbf\xff:\xdd{\xef\x0fO\xeeb~\xdbm\xb7\xe3\x87?\xbc\a\xdf\xfe\xf6w\xf0\x95\xaf|\xa5\xf1\x8do|\xe3\xf9\xd1\xd1\xd1_\u077bgOPo4\x9cT\u06b27\xf6\xed\u074b\xdd{\a\xf1\xb6\xb3\xd6`\xe1\x82yH\xe2\x96\xdf+\xd9\x13\ufdb9\x12\x8c\xc0\xf5\xea\xe9\x10\x91\xdb:m\xfawx\u040aB\x1e\xbf\xb8qG\xca\x0eP\x12\x14C\xdd!$\x97\x96\xd5Q\xb4:\xdc\x0e3\t\xf6\x89)\xaa\xdc\xe6\xc3\xd1D\x88:\"\x00\u0085x\x1b\b\xb2;)ry\xaf\xe2x\xcd\xd5\x18\x88\xb5\xed\xc8\x13\xa53.y\x86\x8f\xa7|\xee.\u02d4\u007f\xdb3S\x86\u074a\\q`U\x88$`H\"\xa8\xf4@\x1b\x8d\a\x1f{\x16\u07fe\xf3\x01\xec\xde\u007f\xd0F\x02\xc2\xc2*Zk4\x1a\r\x04\x02X{\xd5\x15\xb8\xf6\x93\xbf\x05Zr\x15\x86\xc6\x00i\xf2\x80m\x12\x02,\x04tU@\f\x84\xe8\xeb\x0f\xd1\x13\tH'+\xb7]\xa6/\xcfLC\x8d\x9dB4\x8eaZM\xa8f\xd3v\u07ad\x16t\u0702Q\xca\x1ax\xb1K\xaf\xef\xf0\xff\xc9}|\xb2\x8e\x16\x80$B\x14\nD5\x89 \xb2\v\xaf-\xea\x1e\xba\xc3\u014e\x82D\x97\xe5\x9f\U000ee768[\xa3\x90c\xe5F\x10\xa4\x04\xc2\xfe\x10r^\x84\xa07\xc8]\x1c\xcb`Ka\x8fQjM\x9c\xedR\xb2\x85\x9a\xbc\xd0\xe7\xce\xf4\x1bA\x96\"L\x02\xe0\x86F\xc0\x01X+\xec\u0776\x1e\xf5\xb1#\b\x82\xa8x\xcf\x18\x8dE\v\x17\xecz\xfe\xf9\x17\x1e\xfdy.\xe4\u04c2Y\xd2\xc7\xfb\xdf\xffA|\xff\xfbVEu\xdey\xe7\xbfv\xd3M7~\xee\xdak\u07e5\xe7\u03db\x870\x8a \x830{\xee\xd3O=\x83\xbf\xfc\xdb\u007f\u00ae\xfd\x87\xd17\xa3/\xe3\x05\xa7%\u0278N/e\xb6h&hCP\u01a9\xc9\x18\xa5,\n\xfewV\xd0\xf3\xa8Fg@E\x9c\xdd\u0113\xc1F\xecc\xbfmE|\xda\xed3\xbb\x1b\x86\xf9h\xeb\xe7\xa4\xff\xb69\x9d\x12\x89]r\x11@!\x84\x86$\x03\xc9\xda\x0e\xab\x19 6\xc7~F\xdc)\x8e\x95F3Vh\xc5\x1a\xb1b\xa8\x94On\xfc\xce\xcd+\xd8\xe9U\x94\x168\xcf \xcb\xc0\xa7(z\x16\xb1L`\x92\x88\xaa5\x8c\x8eM\xe0\xce\x1f=\x8c\xef\xfe\xe0\x01\x1c8x\x04R\bh\xa3\xa1\x12\x858NP\x1f\x1f\u01cc\x9e*>x\xe3\xc7\xf0\v\xb7\xfc\x1e\x9as\u07ceC\xc3\x1a\x82\xb5\x85\x05\xb5\x82V1\x94\x8e\xa1B\x86\x98\x15\xa2\xb7?@o(\xac\x02\x9a\x19\xac\xadD_\xb5b\u8e05\xa4\xd9@\u04a8#\x99\x98@k|\x1c\xf1\xf8\x18T}\x1c\xaaY\x87\x8a\x9b\xd0q\fVy\x17n\xb4\xe5\xb2\x1bcla\xd7\x1aFi\x98D\xd9N\xde}h\xa5\xdc1r\u05c2\x01d@\xa8\xcc\x0eP\x9b\x1f!\x9a\x1d\x02\xa1\xc8!\x17\x81\x82\x01\x96\x95\u06a7\x17\x9d\xef\xf5\xc2\x05\b\xab\xfc\xbe\xe3\fb\t\x04\x10\xf5H\x88\x81\x10\xb2W\xe6\v\xfc$X)\ta\xe3\xf7\x84\xc8\xe1\x15\xe1\xcf6\x04r\xae\xbc{\xa1t`\xe2\u4ed6o\xceh\xc5u\xcc]z\x06\xe6-Y\x03\xad\x93\x82\xbf\x0e\x91\xc0\xe1#C\x18\x1b\x1b\xff\u022e]\xdb\x17\xd8\x19\xe0\x9d\xf4\xf3Z\xcc\xe5\xd1<\xf9\xb6\xdbn\xc7K/=/\xfe\xfe\xef\xbf\xc1\xb7\xde\xfa\x8f\xeb\xbf\xfa\xd5?\xdf\xd6l6o\u063f\u007f\xbfh4\x9a\f\"2\x8e_\xbdm\xdbv\x8c\x8eO\xe0\xfc\xf3\xcfE\u007f\u007f\x1ft\x12\x03\xccH\xed\x99S\x87\xba\xb4\x935>\u036e,\f\xe2\x18\xa0\x92\xff_Z\xf5\x927CS-\bS\x04y\xf04\x82\xd2\t\xc7\xfe\x1cn\x1bz\x02V\xf8UC\xe2\x86\u04e6\xb0(\x1d\xaf9\x9a1\x8c8\xd1h\u0116K\xae\x8d\x1bxj\x93+e\u0459\xf1\x99\xee\xb5\xdb\xf9\xd1\xfe\xf85\xb7(qL$!\x11Vj\u0631\xef \xee\xb8\xfb~\xfct\u0773\xa87\x1a\x10B Q\x89\xa5\x1e&\t\x92V\x8cU\u02d7\xe0\xc37\u007f\x1a\xa7]w3\xf6%K0>\x9c \x022X\x85a`\xc00! g\n\xd4z\tU\x18\xc0\xc9\xf8-d\x92v\xda1t\xabe!\x948\xceqo\xa5l\xc16\xd6\x05\xd0?\xb9\xd46%\xf1\xfd_\n,\x1dW\xf4\x84\xb4\xc6o\xe9,\x87\xdc\n&\"\x01\x8a\x84\x9d;\xb4l\x97O\xa9\xaa\xd2?\xd7\xee\xa4R\x99\u027d\xc7\xc7\xcf\u0198~(6\x01R\x12\u008a\x00\xe6D\bf\x87\b\x04\xd96\x8d&\xbf\x963\xa7R\xe3\\\x0f\xb9\xe8\x1a\u019eL\x97\n\x9d\\\xaa\xae5@\u02c0[\f\u048c0\xea\xc5\xc8\xe1\xbd\x18\u0739\xd1y\xe2Pv\xce\xc0\x06Q\x14.\u073dg\xf7\xb7\x9ez\xf2\xa9\x03\xdf\xfd\xee\xf7~n;\xf3\xe0h\u007f\xe0\x82\v.6\xeb\xd6=*\xae\xba\xea\x1a\xf3\xcew^\xfb\xad\u035b^o\xd5j\xd5[\xef\xbc\xeb\xee\u0783\x87\x0e\x19\x80\x85R6\xe0\xf6\xae\x1f\xfc\b$\x04\xbe\xf8\x9b\xbf\x82\xc5sf\xa0>6j\xbb)\x12`\x92\bX\xb7\t`\xc8R\x00\x8b\xd6\r\xedb\xbd\xa3\xc2~\x8f\xb7\bN\xf5\xbb\xd2 a\xff\x8by\xacW\xc1\x9e\xaf V!tr\xc6A\x1d\xf7S\xe9\x0e\xe5h\ni7\x1e~Y\ta\"\xc8\xcc{$\xdd\xd2\u04d4\u01fe\x9d>\u0775\x88\xb3\xed\xbe\x13e}s,Fn\xa9j\xda\xf0\xa4|\x98\xe2\x0e\xadS\xaa\xc8m\xef\xc00C:\xc8\xe3\u535b\xf0o\xf7>\x84\xd7\xde\u0612m\xd5ce\xdd5\x8d\xb1\xa6gW\\\xf1v\\w\xe3/\xc1\xac\xb8\f\xdbFfB\x0f7QqT70\xdb\x10b6@@\x88f\x00\x95\x9aB\xa04r\xe1g\x8aU;\xf8\xc0\x15\xaa4\x9e\xae}H\x9c\xa6!Y& e\x05\xb2\xa8\x9c\xf5\xf8\xfe\xc6\xd22\x89\xb5\x15\x10\xb1\x00sP\x84\xb9\U0008a360W\xa2**\x80\x00\xf4\x91\x04\x1csg\u01b7A!g3\xe3\x98\x17|_\xa835\x0e\x80\f\x04\u0090@\xb3\x02\xd0@\x88 @F)\xb6?\xc3]\x9b\x12\x9b8$ \x03\xeb\vo\x8c\xce\x17*a\xbfg\xb7[\x94\xef\xc0\xd8W\xde\x02H\f\xb4\xd2H\f\xc0\x94`\xe9\ua2f1\xe9\xc5\xfbph\xef\x16\x84Q\xd5\xd5\x0f\x01\xa5\x15\xf6\xee\u06c7\xbe\u07be\xcf\x02\xf8\xe2\xcf3\xcc\x12\x1c\xcb\x0f]u\xd55\xe6\x81\a~\"\xae\xbb\xee=f\xf5\x9a3\xbe\xff\u66dbxdx\xf4\xd6\x1f\xddw_\u07e81LD\x94$\t\xc0\x8c;\xef\xbc\x17:\x89\xf1{\xbf\xf5+8u\xf1|\x8c\x8f\x8eBi\xe3\x06E\xe4.t\x82\xc86\xd3%\xfa\xc4\x13\xd8rwS=\x1eMa/\n\x88r\xbc\x9c=\f\xc1\xff\x1c\x9e\xe5g7\x1b$\u007f\xc03\xd9`\xf4X\xf8U\x93\xcb\xf49\xf3\u02a1\xb6R\x99)t\xb9\xfb\xb1\xe2i.\xa6\u06b0\r\\N\x95\x9d\xcaX\xba\xa1\xc9\u04c1\xdam\x1b\n\xdcv\xcfG\x9e2\xbadn!L\x9e\xaa\x98\x19\bC\x89@\x06x\xf2\x85\x9f\xe1\xbbw?\x84\x9d\xbb\xf6@Jk\xbf\x1a+;TTI\x82(\fp\xf5UW\xe2\u068f\u0708#\x8b/\xc4\xd6\xe1*\u0091\x16*\xdad;G\x8b\xef\x02\x88\x80\xa0_ \xecaH\x9d\xc0$\xbeN\x92\xb3\xf3\xc7\xe9\xcfx\xe2\xa6\xe2\xf1\xe2\xdc\u007f\xa4M\xb0S\xb0,\u02c4c\x9c\x15Hr\x8b\x06\x1b\xdb\u0676\ufb6dw\x8c}\x05Y\x13\xa8\u032f\xc0\x04\x02\xeaP\f\u0772\xb1z\xd4\x01\x99g\xb9\x9d\x00\x00 \x00IDAT\u0561\xcde\x8d\v\x17\x1f\u00df\xd83d@\b\x02\x82\xe8\x91\x10s\"\u020a\x00\x99\xa2\x81\\g!\xf7--\x9c\x96CJ\xabh\u054e+C\x9c\rk\x99\xa8p\xbc\bN0\x06\x02\fC\u0156\xc2j\x1b$\x8d\x81E+\xd1?\xb0\x04\x87\xf6lvL\xa1\xdc\x1a\xa0>\xd1\xc0\xc1\x83\a\xdf\xcd\xccU\"j\x1e8\xb0\a\v\x16,9y1\xf3\xf6\xc7u\u05fd\u01e4\xf8\u04eaUkn\xbb\xfe}\xef\xf9\xb5\xcb/\xbb\f\xfd3fP\x14\x85\x1c\x85Qv\x83\xdd}\xef\xfd\xf8\xef\u007f\xf2Wx\xfc\xb9\r\x88\xaaU\xf4\xd4*\x8e\xb5b\xe9n\x86rq\x05\xa1\x18\x12\x9c}\xdd\x13\xa6\xd1\t(\xe8e]*\x97\f\x1a\xdb?LF\u0663\u008e\xc2d\xd1\xc5\xc5!g\xa1\"S\x113o\x87\xbc\xa9=\n\xac\xa3H\xf21\x17r`\n\xf9\a\xb3g\x00V\xb2s\x98\xe45'\x9bg\xa4B\xa0fK\xa1\xd92h\xc6\x06J[\\<\vW\xce\f\br\xd6\au\x8c\u073c\u063e\xb9B\xdef\x95\xcb6\x81I\x04\x01HH\xbb\xdb\xc8\xdc+\xc9\xfe\x1bT\\W\xd86}F\x19$\xb1\x816\xe9\xa2n \xa2\bs\x97\xacAT\xed\xb5\xe7\xcb->\x82$\x12\xa5\xb1c\u01ce\xd5/\xbf\xfc\xdc\"\x00?\x97\x85\xfc\xa81\xf3\xf6\xc7'?\xf9\t\x9cw\xdey\xf4\xe0\x83\x0f\xe1\xb6\xdb\xfem\xe3\xef\xfc\xce\x17\x16\f\r\r_\xb2\xff\xc0~\xeb\a'\x88\x8c\x1b\\\xec\u0735\a\u03fd\xf8\n\xa4\x108u\xd9R\xf4\xf7\xcf@\xa2\x8d-\x8c\f\xebW\xec\xd6\x16Q\xd8bR\xe6'\x91]s\xe2\xc4LC\xb9C\xe5V\xd6\x05\xe7\xfc\x94n\xae#^)j+?m\xc0\x01\xb5\xd5\xf5\x92\xd0\xf3n\x90E\x19\x0419\x0e>\x05V\x8f\x12\x96\r&g\xc5\xf0tw\b\xee\x05\x94\xb6\xd8x3\xd1V\xd5\xe9\xe4\xf9:\xf3W!\xcf\x12*\xff\x1c(\b\x11\xbb,b\xe4\xf9k;j\xa8 \xd4j\x154[1\x1eX\xf7,n\xbb\xe7\xa7\xd8?x\x18a\x10\x80\rCi\r\xa3\r\x1a\x8d&\xe6\x0e\xcc\xc6\xc7o\xfc\x10.\xb9\xfe\xa3\xd8Z[\x89\xad\xcd\x1a\x82\x98QmiH\xe5e4\xa4\xb9\xa0\xc4@\x00\x04\x11l\x82|\xa1\x9b\xf6\xbc*\t\x85\xecQ\x12T`\xc1\b\x19 \x8c\xaa\b\xabU\x04a\x04\x19F\x96\x1dS\x18(S\xc7\xf5\x05\xe1\x162a}\x83D !\x82\x10\xe4\xaa3y'\xc5\x17\xf8\b\x06D@\xa0\xaa-\x98B\xc3v\xd1\xde.\x87\xfc\v\x92\xca\aA$l7\x1e\x04\x02\"\"\xc89!\x829\x91\vW\xf6\xad\b\xbc\x06\xbc\xf4J\xf1\x96\xea,\xe5\u02e4\xc9!E]\x95?\xe8N\xcf\x03\x80V]C7\x8c\xfd\xdb\\\ve\xed\x174v\xbd\xf1,\x9a\x8dQ\u0220\x92\x89\x88\xb4V`c\xc4\xf2\xe5\u02df\xbd\xfb\xee{6\xfc\xc7\x00\xb4\xe4\xf1\x9d\xef|\x17\xd7_\xff^\xdc\u007f\xff\x03\x00\x80{\xee\xb9\xf7\u01fbw\xef8\xad\xd1h\x9es\xe8\xd0!J/n\xe3\x9c\xe6FG\xc7\xf0\xcc\v\x1bp`\xf0\b\x16\u031f\x83\xc5\v\xe6B\b\x91\x19)\x19\x88\xccMQ\x90_j\u06f8\xcd\x1e'\xfdXg\x95\u9ad9l\xfe\u07aet\xa4\x82\xea\u0447W|\x9b0\xf2\x1c@\xba{\xb1{e\x8a&\xe7\xb4w\xe88\xa6\xb9\xbb8\xdeY\xc0t\x06\xa8\xd3}h\xc3H\xb4\xb1~\xf2\x0e\x1b\xb7B\xa04\x00\xa4\u0762\x81\vXr\x0e\xd9z\xdb|\xcf\x11\u0424\xb0K\xba \b\x81 \bP\xadD\u0635\xef \xfe\xed\x87\x0f\xe3\xc7\x0f?\x8d\x91\xd1q\b\x17.\x92R\x0f\x9b\xcd&\x96.\x9c\x87O\xdc\xfcK8\xe3\x1d\x1f\xc0\xab\xb4\x14{\x92*\xa4aT\x9a\x1aA\x92\x17\x12\xf2\xa8\x91l)<\b\x88!B\x80d\xfe\x9e\n\xe7/\x1d\xbe\x91\xb0\"\x19ae\xecA\x18BV\xaa0I\x82\x03\x9b7`\xcb\x13\xf7c\ubccf\xe2\xe0\xd67 \x84D\xcf\xcc\x01\x17f\xe1\x0f3\xbdE\x9e,\xbf\u074aml!\x97A\xe0\f\xe1<\x0e\xbe\xa7\xbb\xf1wz\x90\x04\xaaX\x93.\xa1\x1c^\x9e\x0e5\x99\x8ab8\xa2B\x87.$\x10\x84\xc2\x05-\x13\xc4\xec\x10r~\x04\n(\x17\x06Q\xb7\x96\xa1\xfb\xfe\x90\xf8\f\x02\x89(\n\xa1\x94\xc2\xd3/\xbd\x8a{\x1f|\x12\xafm\xden}\u0209\xa0\x13e\xe9\x87J#n\xb5\xb0r\xd9R\xfc\xe2\xa7n\u0092\xb5\xef\xc1\xcb\xf1\\\x1cIB\x04\xc2 L\fd\xe2\x16\x88\x94\x1dbl\x04\x0fI\x17\x15(\x81\x80%\x02- \xc2 \xf7\x01/`\u0294\xc1G\xa9\xc531P\x1f>\x82]\xaf<\x8b\x9d/=\x81\xc17_\xc5\xf8\xa1\xfdPI\x82JO\x1f\xf6\x9ey>.\xb8\xe1\xd3Xx\xfa\xb9\x801\xd9\f\x83\xdb|\xe13\x1e\xb6\x83%\v\x1eZ\x93\f\x1e\x01\x17\x06\x1d\x10\u012c\xd0r\xf1\x87\x12P\xc3\xc2]>|\xc5\xf6D\xe6l \xb2\x85<\f\\JP_\x00\x9a\x17\x82B\xe1\xcc]\xb4\x1a\x83\xbb^\x831\x1a\"\xc8\u0565q\x92`\u04d6\xcd\x17\xa6\xbf\xfb\xca+\xae\xfa\x8f\x01h\xe9\x85\xe2,5\x17/^@D\xd4`\xe6\xdf\xe8\xef\x9f1X\xadV\xbf\xb8a\xc3\xcfp\xe0\xc0~03\xc7IB\xa9\xb8\u854do`\xcf\xde\x03x\xed\xcd\x1d\xf8\u055b?\x86\x95K\x17\"N\x12\xa8$\xb1\x1d\x1d\vH6\b\xa1\x10\xb0C\xa9\xa9\x8bS\"\x15g/G\xa7\xfcd'V\"w@4\x82\f\x15/w;\x14\x05.H\xb1|\xa6\xaf\xa3=\x01t*d)\xf3\xf6\xe7\xe3(\x9e'\xa2\x90\xd3q\x16\xf0\x94q\x94\xe6s*\u05c5\xa7TC\u035c\x8bC\u041ejFY\xdef\x16\x15\xe4\vm\xbcX7\xf6\xd8\x1a\xe4\xb6\xfd\xd5J\x15a \xb1{\xffA<\xf8\xf8\xf3x\xf8\u0257p\xe8\xc8\b\x84 \x186P\x89\u016e\x95\xd2\xd0*\xc6Y\xa7\xaf\xc0G~\xf1&\xcc=\xf7j\xbc\u051c\x8b!\x15 $\x03\xd2\f\xd1\xd46\x04\x81$d\xe4\xe0\x8bD\x83\xb5\x82\x86\x82Jb\x98\xa6\x027\x19aS@$\x01\xa8\" D`c\xcd\x18PI\x8c\xe6\xd8\b&\x0e\x0f\xa21z\x18I\xa3\x0e\x93\xc4\x18\x1d\u070b}o\xac\xc7\xd0\xeemh\x8d\x8dX\xf5fda\x16\xad\x12\xec}\xf5E\xcc^\xba\x02\xb3\x97\x9d\x86\xb0R\xb5\xf8\xbb\u020b\xac\xf0\xf8\xd7$\x85\x85K\xb2,Z\xce\x06\x9fS^\x1bi\x82\xd1\xcc\xc0\xed<\x14$3\xa0\xbdE6\ud4055\xf4\xaa\x046\\\x19\x82\x80\x1eKCDE\xe4\ucb2eq'\xf0\x98F\xdc\xe5\x9at\u0443BB\x04\x12l\xa4m\f\xd9X\xdfsw\\\x8d\x01Z\x9a\xd1L\f\xa2\x84!\r{a\x16\xee}$\n$\x02,8\xe5llz\xe9'\xd0*\x81\x91\x01\x04\bA\x10bl\xbc\x8e]\xbbv/x\xe1\xc5\u7bbb\xe8\xc2K\x1e\xf8\x0f6\xcb\x14\x05\xfd\u99df\xc4\u06b5\x97\x83\x88\xc6\x00\xfc\xce\x13O\xac{\xfa\xae\xbb~\xf0\u01cf=\xf6\u061am\u06f6\xd3\xe8\u0628VJ\t\xa54\x81\x19\x87\x87\x86\xf1O\xffz\a\xf6\xef?\x88\xcf\xfc\xd2\r8e\xf1\x02\xf4\xd5\"\xf4\xf7\xf7C1\xa1^o 1\x12\xa1\x90\b\x9chEd\xae\x8a\xdc\xe9}\\t\x01\x9a\xd4\u00ef\xddN\x97\x00DPmE\x9a\xba\xbe\xceT_K\x87\xa2>\xf7\xc5\xef,i\x1a\x05\xf2h\xa0\x93N\xaa!\x1f\xd7b0mHE[HE)\xceB$\xb4\xb6\x18\xa7f.\xaa\\\x19\x1dA\x1d\xa9\xbc\x9d<\u0715\xbc\x00\x8aB2\x8d\u00e1\x830@%\n161\x81\x176l\xc2=\x0f<\x81\u05f6\xec\x80R\x1a\x950\xb0\xbf\u07e4\u0656\x84\x9e\x9e\x1a\xce9\xfbB\xbc\xf7\xa3\x1fEe\xf5Z\xac\xaf\xcf\xc0\xa8\x91\b\xa5\x01\x91@\x90\x00\x91\b!\x03\x03\xd5j\xa01v\x18qs\x1c\xcd\xd1\u00d8\x18:\x80\x89\xe1\xfd\x98\x18\u068f\xb81\x0e\u05b1\x85*\"\x89\xa0VEP\xadA\b\x89\xa4\xd5Bsl\b\x8d\x91!\xc4\xf51$-+\b2*\xb1>+I\vB\x06\x90a\xe82?M\x16\x1bW\x1f>\x8c\xc3;\u07c4j5\x11\xd5zm\x97\x9aA6\xb6C\xb5B\x1b\x99\xbfF\x10\xa2`\x14=\xcd\u055b\x00\x88P\x00\xb3C@\x10\xe4\b\x01\xb1\x014\xa0\x13\x83\xc4\x15_)\b\x95\x80\x10Fv\xf1@E\x80g\x05@U\x80\x8d\v\x9dqP(qq\xb8\xef\x13\x00\xda=8\x19E\xd6V\x16\xb0.\x03\x18\xa9AZ[k\xect7G\x84D\x03\xf5\x96\x86I\f(6Y\x8a\x14\f@\x9a\x9dy\x9a\x86\x90U,Xr&z\xfa\x060:\xb4/\xfbE6\xec9\xc1\xf0\xf0\xe8\xec\x87\x1e|\xe8b\x00\xffQ\u0327z\xac]{9\xa7\x90\v\x00\\q\xc5U\xdfc\xe6\x9f\xfc\u065f\xfd\xd9o>\xf1\xc4\xe3_\u06bcy\u04ec]\xbb\xf7\xa2\xd5j\xb1J\x12JO\xe4\x8f\x1fZ\x87\x177\xbc\x8a\xd3V,\xc3\xcae\x8b\xf1\xb6\xd3O\xc3\x05\u7781\xd3O[\x0e&\x89\xb1\x89:\x9aZC\x92\x84dv>\xe9\xd6\xf6\x899\x87.\x98\x8f\x06\x05\xee\xe2nX\xb2%\u0325\xc9\xdc\x01\x9f\xf8\xd1\x1aT\xd2\xf5\x17Cp\xbb\x8f\x0e\xdb\xe1\x96\xf6\xa7uc\xa2\xd0q\x94d\x9a\xe6B\u046d\xf0+m\xe9a6\x9b\xb3]\x8a\xdf)\x1fL-\x00\f\xa7v\r\x94\xb3=\x88\x8b\x8e\x87(H\x80\x00\x00Q\x18 \x8aB\x8c\xd5\x1bxu\xe3\x0e<\xb8\xee9<\xf1\xfc\x06\f\x8f\x8c#\f$\x82@Bi\xe3\x15\x16F$\x03,;u\x19.\xba\xe6]\x98\x98\xb3\x06/\xef\xd7ha\x02\xa1\xb4\xe97Fk\xa8\x91\t4\x8e\x8c\xa21<\x88\xe1}\xdbpx\xcf\xeb\x988\xb2\x17qs\fI\xab\x01\x1d7]\xb6g\xee\xfc\x92\x05-\xa4CP\xa3-\x17\u06a7\xf39\xae9\tB\xa5\xa77\x17\x1f\xa52}\xad\x11\xd7\xc7\x11\xf5\xf4a\xf1\x19\xe7\xa3\xda7#\x17\xbdd3I\xab\xd4$\x87\x93\xa7CSHYlb&=Y\xd4I1\n\bbf`\v\uaa06hh\u02002\xbb\xe1\x00\xb0\t?\x86\x81\x8a\x80\x98\x19\x80{\x84\x9bW\xf8\xd7iz\x8fP\x9b\xf6\"]\x9c\xfd\xa6\xc8\u3d34[\x05\basS\xc9*\u008d\a\u02754#\xd1@\xa8l\xf1\xce\xe6\x02i4`F\xff4\xe8\x9d1\a\x03\vWal\xf8@\xfeur\r\x03\t\xec\u077b\xef\x1d\x00\xfe\x14\x00\x9e|\xf2q\\~\xf9\x95?7\xc5\xfc-\x13M\xfe\xe3?~\x93~\xe5W~5\xbb\x95\x1fz\xe8\xfew\xdf}\xf7\xbd\u007f\xf2\xf4\xd3O\xbf}\u02d67111\x818I`t\xb9\x99\xd9Y\xa7\xaf\xc4\a\xdes\r.\xbd\xe8<\xbcm\xcdJT\xab\x15\x8c7Z\x88\x95-\xe6\x15$n\\\n\x87zs\xdb\x14\xfd\xc4<\xba\xb1(\xb8\xf0yqPk\xda\xfa\xe2\xb43\x17\x05^\xcc4@}/v\xfd\xe8f\x01\u04c7X\x8eZh\u0140r\xcc\x10\xad<{Z\xe7p\x98\xfa\xa9\x982\x17\xc9\xff\x8f\xbd7\r\xb2\xe4:\xaf\xc4\xcew\xef\xcd\u0337\xd5^\xd5\xfb\n\x10\r\x80X\tb\xe3Np\x81(B\x94DK3\x1cihY\xd684\xe3P\xcc(\x183\xa6\x15\xe1\t\u02e3\x88\xb14\x94\x1c\x1e\x85\xc2\x16I{,\xc7\f\x15Z\fQ\x96\xc4m8\xdcA\x90\x00\xb1/\xc4\xd6@7\xba\xbb\x1a\xbd\xd6\xfa\xf6\x97y\xef\xe7\x1f\xf7f\xe6\xcd|\xf9\xaa\x01nSptF\x14\xd0\xdd\xf5\xeaU\xe6{\xf9\xce\xfd\xee\xf9\xcew\x0e{\xbe;\xec\xf1\xe1\xa9\xee\x98\xf3+M\xfd\u0749\b\x81\xab\xc4/\xaem\xe2\xd9\x17O\xe2\u0467\x9f\u01c3\x8f=\x83\xd3g.\xd8\u079ep\u0563\xbfj\xc0r\xf4J\n\xcc\xce\u0361\xb9\xb4\a\xa3\xda,X\xd5\x10F\x01\x94\x8a\xec4\xe7h\x04\xbd\xb9\x81\xde\xca9\xf4\xdb\x17\x10\x0f{\xcez\x16\xde|@\xb1kM$\n\x00U\x90(ybs.v\xf3\n/z\x12[/\x96\x1dW\xbe\x11o\xfa\xb9\xff\x12ox\xeb\xddPa\xe4\x85<\xbb\xa6\xa7\x14\x10A\x00\x15FPadm3\x84\u020a\x18P\x15oWV\xb5\xe7Z}\u00dc\u075f\xd6\xdf\xc4\x00\xe7G\xa0N\x02c\x80\x81{OC\x82\x95 \x06\x04\x9a\r@\x8b\x01\x8c\xb4 \xcdd\xfd`R\n_PQ\x1b\x9fs\xe5<\xa6h\xc9*\xf3\n\x9fw\xa3\x13\xc4\xfd>\xe2Q\xec\xb2U\r\xfa\xfd\x18\xeb\xed>\x92~\x8c\xa8\x1bC%\x06R\x00\x01\x03\xd0\fh\xeb\xf1\x04\x86\xf5e!\xc2c\xdf\xfaS<\xf2\xf5\xff\xdb6\xa0\x9dm\x80N\x124\xeb\x11n\xb9\xf9\xfa\xa7?\xff\xf9\u03fd\x87\x88.\\\xae\xcc_\xe5q\xe3\x8d7\xf2'>\xf1\t|\xfc\xe3\x1f\a\x00\xbc\xf7\xbdw\u007f\x99\x99\x1f\xfaW\xff\xea\xb7\xff\xf1\x13O<\xf9?>\xf3\xcc3\xf5W^9\x83~\xbf\x8f$I\xc6~\xfe\x99\xe7\x8f\xe1\x99\xe7\x8f\xe1\xe0\xbe\xddx\xe7[\u078c\xf7\xbe\xebN\xdcz\xf3u\x98m\xd6m3U\v\xd8E\u06a0\x18%Q\xb2\xea|\x95\x15ieu\xea\u0758E\xba\xa3z\u0528l\xc0UUR\xb3\x9f\xc4\x0e\x14$e\x93\x90\xb6*\xddh\xf2>\xa2z\xff\xf0\x83\xae\xe2)\x96\x19cUI\xb1\xb1\x94J\x9e\xfaS\xde\x15\xe5\xd5P\nt\xe9LA*\xee\x14p\xd9S\xe9\xf5\trS\x90\xec\xf9WK\x04JA\t\x81\xf3+kx\xfa\xe8q|\xef\xf1g\xf1\u0533\xc7pqu\xc3\u01baI\x91\x9f\xa5\x1f>\xec\xe8\x1d\"@\x1b\x83\v\x17.\xe0\uc673\x16tDn\x86\x95\xf3Y\xe9X\xbc\xafe\xa7|]\xa0\xf1\xb6t\xae\xc4\xf0\x16\x0f6\u067f1\xe7u({\x1aq\xa3\rt<\x04\x18\xb8\xf6\xae\x0f\u1dbf\xff\x8f\xb1\xf3\xaa\xeb0\xec\xf5`t\xe2\x940\xf6<\x85R\x10A\b\x15\xd6 \xc3\u0426\xe9\x00\x85\xa1\x98R:u\xc5\xddIYsZ\xfb*\"\x01 \xb6\u065aF3X\x10\x928o\x88j\x00\xd2]\x9b\x88\rL[\x83[\xd2:\xade}\u07f42v\xaa\x17b\bL\x8a*\xc9\xefI\xa2\xea\x1b\xdd\xf7/O\xafch\x18\x9a\tR3\x843\x0fK\xef=2\u0206\xaa\x88\x81$\x89Q\xab\xb7\xb0\xb0\xebJ\xc80\x82\x8ec\xa4\x01DRH\xf4z=\xac\xae\xaf\xed\xfa\xd2\x17?\u007f+\x80/^\x06\xf3Wy\xbc\xf9\u0377e\u007f>}\xfa$\xfd\xcb\u007f\xf9\xdbDDk\x00~\xef\xcb_\xfe\u04a3_\xfa\xd2\u007f\xfc\u0503\x0f>x\xe8\xc9'\x9fB\xbb\xdd\x1e\xc3\u04f4\xa9zb\xf9\f\xfe\xc3\xff\xf39|\xe9k\xf7\xe3\x9doy3>\xfc3\xef\u016d7_\x8fz\xad\x05\x13\x0f\xc0\xc9(\xe3\x18\xdd~\xad0\xfcR\x05\xdaU\x80\xe6\x9b\u0231\xa7\xbc\xc8e^T\x01\x9d\x19\xc1\xe3Et\xf9|~9\x93\x87\xe1\xe7\u07fd:@\xe5B\xd5\u03d7`\u0479:\x93h\xe2b\xb6\x15o\x0f\xd8\x0fN\xa2\xd9\xd2)n\xd8'\xd5P\xe7\xa6W>WJn\xea\x913\x8b\x00O\xba\xe0\xc9\xf9(\v\xa7'\xa4@.\x10H\t\xa9$\x8ca,\x9f9\x8f\x87\x9fx\x0eO<\xfb\x12^<\xb1\x8c\x15\xd7\xdc\x14\x04h\u0599\xd5+\t\xdfm\xdbQ7^\xfe\x9e\x90.\xd75G\xe1\u0716\x96\xb7&\x99R|\xce\x1f\xe2\xe0*\x05{\x81\x82\x97}6z\xee\x82[\u04a1\xa3\xf4\xcb\x18\x83Zk\no|\xef\x87q\xe7/\xff\x06\x9a\x8b;1\xe8lzT\x83\x93\x1f\x06!d\x18Y\x10\x972\xcb\xed\u012b\\\xa2\x99\xd2\xe0t\xbbK\xd2\xc6s\x97\x14\f3b`-\x01w\x12g;\xec\xde\v\a\xa4\x9a\x80>\x01\x92\x19r` \xe2\xd8V\xc2S\n\xc25@\xb3\r\x87\u06cd\x18\xa6\xcc{\x89\xb2\xa6lu\xd1A\x15\xea\x17\xc0\x99\u007f\xb9k\x1d&\x8c\xa1\xf3\x99W\xda)r\xd2\xdfk\xac\xda\u021ff5l\xef\xcf\xd6\xccN\xb4fvb\xfd\xe2\xc9\xcc7\x9e\x04!\x1eiN\x12\xbd\xf8\xf0\xa3\x8f\xdc\n\xe0\x8b\x9d\xce:\xb5Z\xb3|\x19\xcc_\u00f1w\xef\x01\x86\xcd\x14\x95w\xdf\xfd\x01}\xf7\xdd\x1f\xf823\xdf\xfe;\xbf\xf3?\xfd\xdbVk\xea\x97\x1f{\xec1\x9c?\u007f\xbeP\xeaf\x8d\x11a\xb7v\x17V\xd6\xf0W\x9f\xfb\n\x1ex\xe4)\xfc\xd4{\u078a{\xde\xf7v\\s\xd5!\xcc4\x1aP\xd0H\xe2\x18q\x1c\xdb\u02a2\x94\x95I|\u9294\\\xf52r\x9e\u06a9\x97v\x9ar\"\x05Y\xf5@aK\xe9\u03f9S\u05bc\xf3\x15\x18\x94i\xa3\xd9Q-T\x92t\xf0\xe4\x91\xd4Kp\xecE.\x1e\x85\xdd\u026b\xa9\xc6'%-1[\xad\xb8\u05b9\xccP\xeb\xbc\n\u03f7\xec\xe3K\xce\x18h\xbb\xd2^P\x1e\x1dB\u0796\x842><@\x10(\f\x86#\x1c;\xb6\x8c\xef<\xf24\x9e\xf8\xfeQ\x9cx\xe5,\xba\xdd~\x0e\xe2I\x82D\ub8bf\xb9\x11\x05\xc4\xf5\xdb\xd0i)\xca^\xf6l\x1a\x98\x9cJ\xfc\xf2\n3\x05B*\xc4\"g3\xaa~@\xab%\xc5\xf3\x85_k\x18\x13\xc3$\xb1\xa5J`w\x17\xb6i\x19@\xd6\xea\b\xeaM,]\xf1F\\\xf3\x9e\x0f\xe1\xd0-oG\u051c\u00b0\xb3\xe9\x02\xc4\xedh\xbb\x90\xca\xd1*5\b\xa5<\x83\xa2\x92-\x00\x97\x03\x1cx\x8c\x0e3\u0657U\x17%\x06\x88\x8d]\x98i3\x81\xe8h\v\xd0\xc6\x01%\x91}I\x8c\xb5j\xd1\x00\xe2\u0600b\xb7\xe0\x8e\fxh\x80\xf9\x00A \x10\xc0R,\x82r\xd2)\xad\xfe%\xa5!\x1d\xbc\xe5}\xc7^\xd4\"\x93\xe5\xcdA\x02\x9a\r\x06\t\u00f0\x05r\x99x\xbd\x14\xc3 \xe3\xf9\xb6\xe7\xac\x17\xb4\x8eQk\xcc`a\xe7a\xac_8Q\xbc\xaf\rF\xbdn7z\xf9\xf8\x89\xeb\x00\xa0\u055a-\xf4\xf8.\x83\xf9k8\xee\xbe\xfb\x03\xfa\xbb\u07fd\x9f\xde\U00096df1\xe3\xac\xfe\xe1\xe7?\xffw\xf7\xdd{\xef_\xfd\x0f_\xff\xfa7\xf6-//S\x92$\f \x91R\x06\xc6\xe4\u06fe\xac\xca?s\x0e\xff\u05df\xfe5\xbe\xfe\xed\xef\xe1\xe6\x1b\xae\xc5\xfb\xde\xf5\x16\xdct\xf5\x01,M\xd5\xd1j\xd4 \xa5@\x1c'\x8e\x8fw\xa6Q\x82\xbcq\xf0q\x0e8\x05\xf2\xcc\xfc\u0254\x12\xe0\xe19\x1c\n\xca\x00*\xad\xd8\r\x17\xedk\xa9d\xfa\x9fZ\xfd\xda\xf1\xe2\x1c\xf0S\xb9b>\x04UE\x10\xf1\x96\x11p\x97\x8c\x87\u02ea\u03ca\xb0\vWys\xf6\xe1\xe7\f\xc8\x13\xe34\xe2\x06^\xcc\x172\x10-\x0fx\x8c)\xd2\xc0\xce\x10*\xd7\x031\xfb\xe7\x04h\xb6UW\x14\x86H\x92\x04/\x1e}\x19_\xfd\u03a3x\xe4\xc9\xe7q\xe6\xdc\x05\f\x86C+\x8bc\x83\xd10\x81N\x9b\x9b$2\x8d\xb2T\xcaM\x0fR\x9e)Ib\x82\x1c\xa88\x11@.\x8f\x16\xe5k\x01g\v2\x15\xc6b\u0269P,`\xb3\xb1v\xb5iU-\x82\b\xd1\xcc4\xc2\xe6\f\xa2\x99\x05D\xd3s\x88\x9aS\x98\x9a[\xc0\xec\xee\xfdX8t5\xe6\xf6]\x81\xe6\xec\x02\x88\xadU\xae\b#\x90T\x80\xfb\x12nQ\x13\x82<>~<\x9d\xb5j\xbf\xc9^\v\x82a\x81{\xa4\x19\xa3\x84m\x13\x91\xad\u03f9\xeaj\x04\x1d\x9d\xb9)J\r\x906\x85\xf4:2VVn\x90F\xf4\xb8\x02G\xc7\xd0\xcc\xe8N\xdbs\f\b\b%\xd91\u007fApsD\u064e\xc06\x8bKq\x90^hz\x96\xb1\x9b\xaa_\xa4\x02d\x82x\x94`\xe8V#\x19[\xa5\xa6I\xcd\u0334\xef\x83\u3337\u049d\xa4\x8eQo\xce`i\xf7\x11\x1c\xfb\xfe7=\xd5\x14\x10\x06R\x9d>\xfd\n\xd6\xd77\xaeg\xe6\xeb\x88\xe8\xfb\x0f<\xf0\x1d\xe1.\xf32\x98\xbf\xd6\xe3-oy\x1b\xff\xe1\x1f\xfe\xaf\xf8\xcd\xdf\xfc\x18\x01\xe0{\xee\xf9\xd0'\x99\xf9O\u007f\xeb\xb7>\xfe\xb1\xaf}\xed\xeb\x1f=}\xfa\xf4U\xe7\xcf_\b\x1c\xa8kr\xdd&\xe6bK\xfe\xf8\x89\xd38y\xfa,\xbe\xf5\x9dGp\xf8\xc0\x1e\xbc\xf9\xfa#\xb8\xe5\xfa+q\xc5\xfe\xdd\u06390\x87\xd9\xe9&\xea\xad\x10Z\x1b\f\x86\xb1\xe3\xe5\xd3j\xae\x18Ll\x00\x9b\x06\x9f\u4cba\x8cB\xf0@/\x05\xea\\vE\x13Io\xf6V\x8e\xbc\x92/\xf2\xeb\xc2q\xc4R\x90\xb5\x0f\x15y|\x96\xc8\x02}\xe9\x92\x16\xb9\x97\xecX\x96\xcf0\xab\xd6,\xff\xad\xbd\xf1\xf3\xb4\x92\xcb\r\xb0\u0704\x1e\xa8\x04\x1b\x18k&\xa4\u065a)\xd02\x8a\xf9\x9c\xe9K\x92\xaa9\xeaQ\b\"\x81S\xaf\x9c\u00f7\xbe\xf7\x04\xee\xfb\u07938\xb9|\x16q\x1c\x83\x88!\x05C'\xf6\xbd3F\x17\x16\xf6\x99f\x1d,\x02\f\x13\r\b\xe5Y\xa9::\x82\xca\xd1\xd4\xee}O+u\xe1\xde\xff\xf2\xf6\x82<\xbb]r`\xa15\x92d\b\x9d\xc460\xb8>\x8d\xc6\xd4\x02\x82Z\v\xaa\u0442l4\x10\xcd.\xa2\xb1\xb8\x1bS{\x0ecz\u07d5\xa8\xcf\uf08cj\x10B\"\f\x15\x1aQ\x80Z\x18@\bB\x92\xc4\xf6\xfd\xaf\xd5\x1d\x85\"\xa1\x85Mv\"a\x13\x84\xc0\xe3\xadl\x86\xbf\xeb\xc9{/\xc6\x03q\xe3\x16\xc9X\x03\x83\u0120\x9f\u062a<\x9d\xef\t{\x1aa\xcf\x05\x002 \x13\x06\xa5#\xfe\xeey9\r I\xe1Rx\x8e\x8e\x9a!:\x1a,\bqCbD@?a(\x01\x04\x82\x10)\x81@\x00J\x10\xa4p\xe7lJ\n-\"+/vU\xbd\u007f\xee ;\xa0\xdfO\xec\xdfe\u0090\t\x17\xed\x1e\xb8L\xdb\xe4K\xb4\xd1\tT\xd0\xc2\xcc\xc2>\x04a\x03:\x199+\x04{K\x8c\x86C\xac\xac\xac\xcc}\xfd\xeb_Y\x04\x80\x87\x1ez\xe82g\xfe\xc3\x1c\xbf\xf9\x9b\x1f\u00d7\xbe\xf4y\xfe\xdd\xdf\xfd=\xfa\xe67\xefc\xa7K\xff\x1df\xfe\xc3\u007f\xf6\xcf\xfe\xe9o>\xf2\xc8#\xbf\xb0\xb6\xb6~\xe3\u0253'U\xb7\u06ddH\xb5\xe9Dceu\r+\xabkx\xfc\xe9\xe7\xf1\xe7\x8d:\xf6\xeeZ\xc4\rG\x0e\xe1\xea+\xf6\xe3\xf0\x81=8\xb0g\t\xbb\x97\x160?;\x05%\x05\x86q\x828N\x9c\t\x12\x9c\u0740\vFH\xb5\xd1i\x13\r\xc5(\xb2t\x84\\x\xe8J\x9c\xfbqT\xc1:gU\x15gF]\xec*>\xe1l\v\x04\x11F\xe9vU\xb8x=7\x8aL\xd9v\xd5U\xf0\x8en \xaf;[H.\xe2\x94#-\xce\xcc[_\v\xf6>8\x9c\aA\xf86\xa7\xde8\xbdU.\xe4\\0{WS\xf8l2\x8fy\x8f\xb3\xdf\xe0\xf4\x99\xa8tj3\b\xb0\xb2\xbe\x89\a\x1e\xfd>\xbe\xfc\xad\x87p\xf4\xe5eG\x93i\b\xc1\xd0:A<\xb2\x15\xb0\xf1\x16\x84\x85\xd9)\\q\xcb[\xb1\xef\x8e\xf7\xe3\xc2\xc55<\xf1\xf9?E\xfb\x95\x97\x01\x00A\x10\x81\\t\x98]L\xc8k\xc62\xd8P\u039b39\x90\x19\xb7\x84\xe4Tj\xa8ch\x1d#\b\xeah\xcd\xed\xc1\xd4\xfc>\xcc\xee\xb9\x023{\xaeDki?jsK\x90K\x8b\xc0L\x13*j@H\xe5M(\xe7J\x8e\x04@;\x06\x86\x9c\xa0\x11)\xd4ju[\xc9;\x15\x0e\x91\xb0\xc0\n\x86\x12\xbe\xa3\xa2\x0fU\xa5\x05\x94\xfc\xc57\u007fOc\xc3\xe8'\x8c~l{\x1d\xbeY\x9d\x1a\x18\x84=\x03\xa1\x1d\x90\u01f6\xa9\x98V\xe8>\xedg_\"\xceR\x83X\xe44\"%\x8c\xa8\xab!\b\x186\xa4\x93\xa9\x02\xb1f\xf4\x13\r%\b\xa1\x00\x02%\xec\xff\x85\xf3\x96\xe1\\\x0f\xa6\x992/\x11.\x15\tCc\x1b\x9fd\x00\x15\xc36>\xc9\x1a\xf2\x11\x93]xD\xfax\xe1\x8a\x1d\xce\xc4\x05\xcc\x1a\xf5\xd6\x02\x9a3;\xb0~\xf1$dn@I\xa3\xd1\bI\x92\xecy\xf2\u0267\xae\x05\xf0\xcd3g\xce\xd07\xbe\xf15\xbc\xfb\xdd\xef\xb9\f\xe6?\xe8\xf1\x81\x0f\xdc\x03\x00\xfc\x89O\xfc\x1b|\xfc\xe3\xff}\xfa\xa1\xdbp\xa0\xfe\xe9O|\xe2\xdf\xfc\xbd\xaf|\xe5+w\\\xbcx\xf1M\xab\xabko\xbcp\xe1\x02\xf5{\xbd\x89M\xbb$I\xb0\xb1\xd9\xc6\xe6f\a\u03fft\x12\x81\x92\x98j5qx\xff.\\}\xc5~\xbc\xe1\xe0^\\}\xc5~\x1c\u063b\x03{v,`\xba\xd5p\xcd=\r\x8c\x12\b\x9d'\xe80\xa7\xe3\u031c\r\xb5\x14\xa8\x89\u031b\x9c\xf3\x06\x90\xc3\b]\xb007\xd9$\x93\xd7\x12t\x80n}2\xa4I}hr\xd0\xcf\x03+<\xbf\rg\xf3*D\x1aO\xe6\xd1\xf6\x94\x876hf\x1b\x19\xc6~\x02\x0fg\x95O1\u0601=f\xd8\a\xe2\xb1\xfek\xc1\x1f\xc5\xdf\u044cW\u0754\ro1\xb8\xe0\x86)\x85D-\f\xd1\x1f\x8d\xf0\xc0c\xcf\xe0\xab\xf7?\x82\x87\x9ex\x16\xdd^?\xb3\x9a5\xdaN[\xdaj<\xff\r;\x17fp\xed\xdb\u07cf\xddw\xfe4\xe6n\xbe\vb\xf7aLo\xf4\x10\x1c\xba\x01\u01fe\xfcg\xb8\xf8\xec#\xe8\x9e_\x06b\xbf\xa9M\xb9#\x1f\u0195*Y3\x8d\xf2\xf7\x8b@PA\x1d\xad\x99]\x98Z\u060b\x99\x85\x83\x98\xdbq\x18s;\xaf\xc0\xcc\xce+P\u07f9\a\\\x0fa\x8c\x86\x96\x8c$\x12\xd0!Y\xd9\x1e\xb4\xf5\xe0\xce$M\x02p`\xcdB`(m\xfa- Q\x93n'\xe6^#\xe9^?\u9a38K\x1a;0C\x1b{\xbf\xc1Q\x1a\xfd\x84\xd1\x1d\x19\x8c\xb4?=k\xd5Bj`,\x00k\v\x922f\x88\x84=\x0f\x1a\x14\xf5/\x8e\xff \xb2\x14\x87\xf6\xfb\x94\f\x88\x04\bz\x06F\x10t]\x14*\xad\xc40b\x03\x90\x03\xf6H\x12j\xca\xfe_\n\xbf7\xe1\x9e\xd7S\xe4\x8c\f\xa3\x97\u061d\x84t\u7656\xf0\x04\x80\xd2\x05\xb9\x9c\x15\xea\xed\xb6\xb5NPk\xcc`jv\x17\xd6\xce\x1fw\xbb\r\x06\x98\x89\x99\x93n\xb7\xa3\x9e|\xf2\xa9E\x00\xe8\xf7\a\xe2\xdd\xef~\x8f\xbe\\\x99\xff\b\x8e\x14\xc8\xff\xe0\x0f>\x81\u007f\xf1/>\x8e\xcf~\xf6^\x10\xd1Y\x00\u007f\x04\xe0\x8f\x1e}\xf4\xa1k\xfe\u077f\xfb\x93[VVV\xff\xeb\x97^|\xf1}'N\x9e@\xbb\xdd\xc1p8,|\xd8\xfdJ\xd8\x18\x838f\xacmlbmc\x13\x8f<\xf5<\xa20\u011e\x9d\v8\xb8g'\x0e\xee\u06c9\xc3\xfbw\xe3\r\a\xf7\xe2\xe0\xbe]X\x9c\x9bA-\x8a \x94\x1d\x821\u0330\x8e\xa6\u059c\xc9h.\x86\x9dL\u0a33\x01!\xbf\xd8c\xf6\x92\x93\xbc!$\xa4`\v\x8c\x91\xb6Y\x95h\xe0u\x87\\Ui\n\xbc\u007f\xce\xf2\xf8q_9H\x1b\xe61\xe0\xf2\u01f0\xfd\x19W\xeb#\x9d7\xa4*\x98\x94L\xf7c|\xf6\x99\xf2\x9d\a\xf9i\xf0d\xd5\rRZ\x99\xa11\x8cg_:\x81\xaf?\xf08\xee{\xf0\t\x9c\xbd\xb8\x9a-L\x16\xc4c\x8cFCho\xf6`\xef\ue778\xfe\xdd\x1f\xc0\x9e\xb7\xfc4\xa6\xae{\aF3{\xd0\x19&\xc0z\a2Px\xc3\xdd\x1f\xc1\xee7\xbd\x13\x1b'\x9e\xc3\xe6\xf21l\x9ez\x01\x1b'\x8f\xa2{~\x19\xfd\x95\xb3\x88\xbbm\xb0N\xf2IJ\x12\u05a4*\x8clcR\x86\b\x82\x1a\xa2\xda4\x9a\xd3;05\xbb\v3K\x870=\xbf\x0f\xcd\xd9\x1dh\xcd\xecFT\x9f\x86\xd61\xb4\xb1v\x13\tb\x98@\u0606]\fH&P `j\xcaV\xd9BZw*\x91Rz\xf9\xffcfl\x0e5FZ\xa0\x19\nD\n\x10\\}Gqe\x13\xdcI\a\r\xb2]d\xac\x81^l\u040dm\x8f\xa3\xb0^\t@\xc4\x06AGC\xc6v7*c\x03\x11{\xd5xy\xf5N\xdf>c\xf9n\x86\x05t\xf6\x82V\xc0\x96\x9e\x89\xba\x1a#\x02\u26a8\xf4\xeb\x1fiF\xac\x19\x83\x84\x10J\xa0\x11\b\u02f1\v.\xb65\x98\x900\xd0\x191\x86\xc6\u07a3rd\xad\x16\xb2\u05cfE6\x8b\x90G\x8cZ\xc2\\x\xeb\xb3\xd11\x1aS3\x98\x99\u07d5\xd1o\xe9g3PJ\x9cy\xe5,\xae\xbbnxC\xeao\xfe\xd0C\x0f\x8a\xdbn\xbb\xe3u\u03dbo\xcb6\xeeW\xbf\xfae\xfa\u02ff\xbcW|\xeaS\x9f\xd6y!\u008dO~\xf2\u007f\xffo\x9fy\xe6\xd9\xdf~\xf8\u11e7\x8e\x1d;\x86N\xbb\x8d$\xd1\xd6\xf3e\x82)\xbe\x10\x02J\xda-\xad1\x96Z\x10\x044\x1bu\xecX\x98\xc3\u03a59\xec\\\x9a\xc7\u03a5%,-\xcec\xc7\xc2\x16o$\x1a}B\xa4\x15\x94\x88\x10\x85M\x84\xb5&T\xd8t\u05a91L2\xb2\x8dNA`!\x00%\xc1\x81\x80\x8e\x14L(\x01!,\xff+\x04\x92\x86B\u04b0N\x86\u9389\xb9\x1a\x96\x99m\xe3\xb0\x11\x10\xeaJ \x90\xf9\xa0\x94\xf4$\x82\xe5\x06\xa7\xa3\xa0\xed\xbd\xec\xaa\xf1\xde\xc8`\xa8y\xec\xfe`\x02\x84\x01\x82\xb6F\xd0\xd3\x10\x86!b\x86\x1cq\xd6\x14\xcf\\\x0f1i8\x8d`\x84\x15\f\xb1\xeb5\xd8F\xa5\x00\xa4\x95\x12&\x11a\u0612\xd05Q\x88\xa1\xe3\n\x95\xad\x10@\xa4\b\r%\x10\xcaT\x82lw\xbb\xbd\x98\xd1M,\u0146\xde\x00\xc1\xc5.\xe4\xc0\xa6\x96q\x92\x80\xfa\t\x10\x8f\xc0.\x93\x95\xbc`\x12\x99\ue01d\u02a81=\x83'\xbe\xf3\x17x\xe0\U000df10a\x1a A0\xf1\x10\xa3a\xd7H)\xc4\xdd\xef\u007f\uf4df\xfe\xf4\xa7>\xb2\xb4\xb4\xeb\xb9O\u007f\xfa\x93\xf2\xd7\u007f\xfd\x9f\xbc\xee\xabs\xb5\x1dO\xea\xbd\uff5b\x01\xe8\xe7\x9e\xfb>}\xf5\xab_\x13\xbf\xf1\x1b\xff\x94\x88\xa8\a\xe0\u007f9w\xee\x95{\xbf\xf0\x85/\xfe\xd2\x03\x0f<\xf8\x8bO>\xf1\xe4-O>\xf5\x14\rG\xa3L\x97^>\x8c1\x18\xb9h0!\x05\xa4\x14\x90B`0\x1c\xe1\xf8\xa93x\xe9\xe4i\b!Q\xaf7\xd0l6\xd0l4\xd0j6\xb1\xb40\x8bC\a\xf7\u16ab\x0e\xe3\x8a};13\u0570\xe3\xe4A\bU\x93\xaeq\xe3\x05,\xa4\xd5\n\x91\xa7\x84\xb0\x1a\xe71\xb5\x01\x8a\x86\xec\xecM\u0325\xdbg\xe3\xbaF\xb9\xe6\xdd\xe4A\xbf\xde'%\xeb\xe6\xbb'2\x15\nG\x1aSux\xe9=\xe4\x19&\xf9\xfc{\x19\xd0K\x95\xba`\x1fp\xf2\u6c12\x12\xb5(\x80\x10\x02\xbd\xfe\x00\u03fft\n_\u007f\xe01<\xfa\xf4Q,\x9f\xb9\x88\xd1h\x04\xa5\xec$G\x1c\xc7\xd0\xfbeH\x9c\x00\x00 \x00IDATI\x8c8\xb1\xd4\n\x00\x04a\x88\xeb\xde\xf7a\\\xff\v\xbf\x8e\xa9\xabo\x83\x0e[X\x1b\f\xc0\xed6\xa4\x80\xf3\xfe\xf6w\x04\xf6C:\x1c\xf6\xc1`\b\xa1Ps\xcdH!E\xee!oRE\x86\x81a\x031\x18!\u060c\x11n&\x90#\r\xc4\x1a&\x89\xc1&A2\xec95\x8etS\x98\n\x10\x04\x0e%X);\xd0\x04\x01M\x02Z\u0694\x1db@\x0e\b\xa4\x80\xa4\x96\x0e\xeeVF!g\u02a8\xd806\x87VO\xdd\f\x05j\n\x19\u0152\xca\xfa\xd2j7\x9f\x9a\xb5\x80\x15\x1bF7\xb6\xb4J\xb9\x1a\xf7\x95\xb3AW#\x18\u0608\xf3\xef\xe9\xa3\x1f\xfd\x15\u07b9s\xcf\t\x00\xbf\xc7\xcc\u007f\xfc\xb1\x8f}\xec\u007f{\xea\xe9\xa7\xff\xe1V\xcf!\x84\xa3\x05\xd8\xc0$\x1a\x80\xcen\x80T9\xc2\xcc\x18\f\x87\x18\x8eb\xac\xacm\x82aG\xc4\x1f|\xec\xfb\x98\x9aja~f\n{v-\xe2\xf0\xfe=8\xb0g\av,\xcea\xbaUG=\x8a2O\x10)\\\xb5m\xf2\x84y\xadmXp\xa2\r\xe28A\u007f\x14\xa3?J\x9c\x0e\xb7\xa8\xb2\b\x02\x850P\b\x02\x05\xa5\x94\x9dnt\x93\x8aRX\x90\xac\x87\x01\x820\xb0\xbf+\xf5zv\xc6V\x89\xfb\xbd\x99\tQ!\xb9)\x9b\xe2(*<\u01a2\xb9\xa8z\x14\xc97\xbeB.+3\xae\x19,%!P\n\x81R\x88\x93\x04\xe7V\xd6pr\xf9\x1c\xee\xfb\u0793\xf8\xde\x13\xcf\xe1\xec\x85\x15\x8c\\%N`\xf4\a#\x9b0o\\\u2f63Uv\\\xf3&\xdc\U000abfc5\x83\xef\xfcyP=D\xbf\xaf\xa1\xbb]\xab\xec\x91b|w\xe0\xb7\\\u04e1 \x00&\x19\xc1$\xa3\x12(\xe5CJrd\xa06c\xa8n\x02\x8c4Lb\xab<;\xb4\x13B\xaa\xa8\xc0\xa5\xdb\x12\x97\xc0\x81\xb0\xf4\x89\x93\xee\x89! \xb4q\x13\xac\x96X\x16\x9b\xdaR\v\rY\b#\x99$+e\xd8\x11\xfa\x91\u05b6b\r\xac\"D\x11\xf9Im\x19\u0367\r0L\x18\xdd\xd8*U\xc0\x13\xbcY\x18\b\xfa\x06AO\xdbsM\x81\xdcp\x85\xe72\x8f-\xe0e\xf5Sj~\x96%~ymK\xe9\xaaa\x100$\x82\ti\uceb3\"\xc0\xbb\x8e\xbe\x19\xb7#H\U000e90c4@i\xff!\xfd\xbd\xec\x87\xc5\x18\x17\xe8\x01/!>\xed\x93\x10t\x12\xa31\xb5\x84\xe6\xec\x0e\xac\x9d?\x01\xa9\xac\xc1\x99\r\xf3`>w\xfe<=\xf6\xf8\x13\xfb\x00\xe0\xaf\xff\xfao\xfe\u007f18\xa4^/'\xfa\u044f\xfe\n\xdf\u007f\xff}\xf8\x9b\xbf\xf9\x1b\xfa\xc4'\xfe\x80\x01t\x1ez\xe8{\xbb\xfa\xfd\xfe\u011f\x99\x9e\x9e\x02k\x8dv\xb7Wb&\xb8\xf0\u007f\xfbB\x10\xa4\x12\x90\xceG\x99@H\x92\x04\xab\xab\xebX]]\u01f1\x13\xa7\xf1\xe0\xa3\xdfG\x18(\xd4k\x11\xa6\x9a\r\xcc\u037405\xd5\xc4T\xa3\x8e(\n-\u007f9\x8am\xda{\xac\xd1\x1b\f\xb0\xd9\xeeb0\x8c\x11'1\x86\xa3\x04q\xa2\xb3\xada\xda\xe0\xb4\x15\xad\x82\n$jQ\x88F\xbd\x8eZ-\xb4\xff\xa6\x14j\xb5\x10\xcdz\rK\v\xb3X\x98\x9b\xc6T\xa3\x810\f\x10\x86\x01\xea\xb5\b\xf5Z\r\xf5z\x1dQ\xad\x06%\t\xacu\x9a\xae\xe2\x00\x1e\x05c\xbd\xdcn G|\xe6\x92\x05\t{4\x8e\x10P\xca\xeehD\xf6\xe5*\"\xad1\x18\x8epqm\x13\x17.\xae\xe1\xf9c\xa7\xf0\u0413\xcf\xe1\u0157\x97qqm#\xa3S\u0229\x8f\xb4\v\xf05i\x90/\x80\xe6\xd2^\\\xf5\xc1\x8f\xe2\xda\xff\xe2\x9f`\xe6\xe0!$CF\xbc\xd9\x05\x1c%\xe6\xef\x0e\xaajH\x1f\x93\xb8\u0510\xcd\xf6/\xcc\x0e\xc8\x19\xe1\xa6F\xd03\x10\x9a `\xabo\b?\xb0\xb0b$K\xd8\xecI\x03\xdb\x03a0(a(M0\x92a\xdc\x00\x81\x18\x01\xa1\xd1 \x06\xe2\xba\x04\xcb\xf1V\xc8\x18\xa0{\x15\xebH3\x1a\x01\xd0\f,\xf5B\xb9t\x05\xb1\x01:#\x83^l\x90TU\xe3\xfe\a{`\x10t\xb5\x95\x1d\xb2mv\nS\xe2\xcch\xf29\x15-\x12\xca\n\x1dW\x1c\v7|\xa5\x19$\x009d\x84\xd0\x18MI\xe8\x80&)XK\xef\u0378\x92V&\f\xa9\tl\\\xe4\x9csG\xf4\xcf'\x9d\xfcMUVy7\u01e9\xc6t\x82fs\x1e\x8d\xd6\xdef\r\xe5\x19\x00~\xeb\xb7>\xfe\xae\v\x17.\xbcWO0\xea\xaa\xd5j\xf8\xd5_\xfdU\\\xf7\xc6k\xf1\xf0\xf7\x1e\xc0K\xcf?\x8bg\x9f?\x8as+\xeb0\\\xad\x86a\xa7~\x10d\a^\x04\x89L\x1eH\x00\xe28\xc6h4B\xa7\xdb\u00c5\x95\xb5,\xce\xcb\xdfG\x8e\xd1\x14\x9eJ\x80\xbd\u01a7?\xafY\u04a2\xb9\x9b]\xe4zv\xb2\u0a64\x95\xf4EQ\x88Z\x14\xa2^\xafaz\xaa\x85\xb9\xb9\x19,\xcc\xce`nv\x1a\v\xf3\xb3X\x98\x9d\xc6\xecT\x1d\xf5(D\xb3Qszn\x02\xb3\x86N,U\x834\xa6\x8cr\x85G\xea\x13nw\x03\x02\x81\xb2\xe9\xef\x83\xe1\b\xdd^\x1f\xbd\xfe\x00\xfdA\x8ca\x1c\xa3\xd3\xed\xa3\xd3\xeda\xb3\xd3\xc3\xca\xea\x06\x96\u03dc\xc7K'^\xc1\xb9\x8b\xab\x18\x8eF\x96\x0er\u05db\xc4\xec\x00<\xc9\x00\x1c\x00\xa6\x16\xf6\xe2\xd0-?\x85\xab>\xf8+X\xbc\xfd\x1d0\x01a\xd0\xeeY?\xefR)KeN7\x1d<)\xb9\x8b\xf9\xfd\x85\x02R\t\xeb1\x12\xb65T\xdf5\x005;\x90Hw&[E\x9c\xb8II7\x1e\u039e4U\xb8\x0e!K\xcb/\x8b\x84\x10\xb65(f\xc4M\x01\x1d\x8a\u0262\x94\x12\xb8i\x03l\x8e\fb\xc3h\x05\xc2\xd2\x10\xb0Z\xf1nl\xa7\"\xb94\xa4VFb94\b;\xda59\xd9\xc6\xe0\x19.\xc8E\xfd\xac\xd9\t\xb0\x8a\x02\xda\x13\x17\xe5K\x94N\x8d\xda\xc5M\x18\x00\x9a\xa1\x86\xaeBoI\x98\x90^\xd58N\xf6\x16\xa6\xebfl\x157\xec\xe5\xa3\xda\xe7\x19\xf7\xd5e\xce\xfbE\u067bG\u05b4\xab\u079cC\xb35o)!JS\x93\x14HJ\xb4\xdb\x1dlll\xdc\u011c\xec\x06\xb0|\x19\xcc\u007f\xc2\xc7\xfd\xf7\u07d7\x02:\x9e~\xfa\xfbw\x9e8qb\xac\xdaN\x8f\xa5\xa5E\xfc\xf2/\xff\x03\xdcq\xc7[\xf1K\xbf\xf4\x0f\xb0|\xfc(\x8e>\xf90\x8e>\xf74\x9e;z\x1cO=\u007f\f\xc7N\x9d\xc5z\xbb\x9bU\xcb:\u06da\v@*[\x89\xa6C\x80]\xd7\xdc\x01j\xd4\u047b\xd8A\xd2\x008\x14\x95\x01\xa8\\\n\xf7\xf0m\x1a\x88\xb6n\xef3Y\x05G\xd8\xd6\b\x06\xc6R\r&\xa5\x1c\xb82\a\xb6 F\xa5\xbc\xca$O\xd2d\x03\x14\\\xc3\u05cd-\xb0\x15]\x804\xdb\xe1\x1c\u0348\x9b@R\x13\u0145g\x12\xa8\xb9\xe7\x1b$\x96:S\"w\xaa\xd4\x06y\x90\xf5\x84'\x101#\xec\x1a\x88\xc4%\x1d9\x90%FiBw\xb2\x1d\x1d\x97UR\xec\xe3\xa8'ka\xef\xe5q[;b\v\xe8L\xc0\x88$\x8c\x12\x93\xb8\xb1jZ\xd4 W\u06a4U\xb8\xc9\x04]\xee\xf3\xe6\xfc[L\xeeL\x99\xf6\x15\x84\xa3MM\xa2Qk\xb4\xd0h\u0343\x84t\x16\xb8\x80\x94\nB(\x8cF#\xc4q|\xeb\xbd\xf7\xfe\xd5.\x00\xcb\x0f\xec\u0673\a\x80A\xbd\xd9\u01357\u074ekoz\x13\xd0>\x83\xd5S\xc7\xf0\u02a9\x97qj\xf9\fN\x9e>\x8b\x93\xa7\xcf\xe2\x85\x13\xa7q|\xf9\x1cN\x9f\xbb\x88\xf5v\x0f\x83\xe1\bZ\x97\xbb\"\"K\x11\u03ebv\u1188\x8a9\x9fy%>>*N\xbe\u0169\xd7\xc8\u02dd\xf8\xbcf.\xe5\xfc6g\x9ab\x064\xd94\x18!A\x8c\x8c\xf6\xb0\x15\xc7&\x8eq>d\xa4\x94\xa5\x86\xe6fZX\x9a\x9f\xc3\xd2\xc2\x1c\xe6f\xa71;\xddD\xa3Q\x87\x92\x12Zklv:XYY\xc7\xea\xfa\x06V\xd77q\xe6\xfc\n\xd66\xdav\x98G\x97\x06\x83\x1c\xf0\xa7\x15x^\x89\xbb\u01b0\xb6C7\xa9|4\xa8\xb5\xb0c\xffux\xc3-\x1f\u0121\x1b\u07c3\x9d\x87o\x86\x10\x11F\xbdM\xe8n\x0fA @#\x81\xe1L\x80$\x12\x05Kc\xc03(D\x01G&\x03c>(\t\x91\xc0\x02y\xca\x1fk\x86(\f\u028c\xc1wE\xa9_\xfd;\n\x14\x90\xb6*r\x1d\xe4\u0563\x1c\x1a\xfb\xbb\x12\x89\xa4!ad\x81\xa6\x1e\xe3\xd3\xfd_\x17;\xbdv\n\x98[Y\x880Yz\"\xecj\u0221\x9b\x99H\xc3\x1bR\u0547\xd74\xa7\n\u0687\x8a\xec\x9a#\xaa\U000f26483O\x98\xbc\x9bO)]\x9e\xff\xb0a\xa8\x81\xfd\xe4\x8cZ\x04\xad&\xa6\u064d\xbd\xb4\"a+I4\xb0\rh$\xb6\xd9\xee/=\\\xbc\x0fQ\xb8'\xf2\xc9U\"Bsf\x11a\u0530>\xf1R\x82\xa4\x82T\nF\x8fp\xfe\xfc\xf9\xf0\xa1\x87\x1e\x9e\x02\x80\u007f\xfd\xaf\xff\xe7\u02d5\xf9O\xf2\xf8\xdc\xe7>\x0f\x00\xf8\xecg\xef\xbd\xee\u0739s\xd7UY\xe7\xa6\u01d5W^\x81\xfd\xfb\x0f!I\x86H\x92\x04\xf1h\x04&\x01\x11.b\xf6\xcaY\xcc\x1f\xbe\x16\xd7\x0f7\x80\xf6\x1az\xed\rln\xaec\xb3\xdd\u0145\x8b\xabx\xf1\xc4+x\xe2\xf9\xe3x\xf4\xfbGq\xf4\xc4+X\xddhc0\x8cm\xcf\xdc\x15\x98\xaf\xad\xf5M\x90*\xb4\xcd\u0634\xbc\xa4t@Hd\xa1\x05 \u06f0e\xa7\x90I?\x18\xbe\xb9\xb6o}k\xaba\x032n\x98HHk\n\xa6\x14\x94G/23z\xfd>:\x9d.N\x9c:\x03\x80\x10\x84\n\xb50D\x10(\xeb:\xa8\r\x06\xc3!z\xfd\x01\x92D[e\x88\xa3w|\x90N\x17\x14\xceF\xfeM\xd1C$=m\x93@\x06\x11\xa6\xa6\x96\xb0t\xf0z\\u\xf3O\xe3\xc0\xd5o\xc3\xf4\x8eC\x10*D\xdc\xeb\xc1\xe8v\xb6\x18R\xcc\x10Z\x83\fa0\xa7,\xa0W,\x86\x85`\x03.J\xec\xc7\x12\x9a\x04\x814#\xea$\x19\x90\x93\v\x00\xceS\x16\x8a\xae\u06d5\u068e2\x8ap\x1emG\xc6n\xe4\xf2\tIKk\x18IY$'%@\xd8\xd5\x10\t#n:\xfa\xe1U\x98\xc9\xd3%\xf8e\x1f\u0205\x01\x82\x9e\x86r;\x8fl\xf4^\x97\x16\xad\x94&\xc2d'\xd1\xfc5\xa6bk\xb420%\ud193\xa5FR`w\xe7C\f\f\x1d\x87Nf\xeb\x8b%\xb6\xcdi\xa1\xd9J \xd3\xe9X/\xac\x84\xbd\xc72\x8d\xf9D{V\x04V\xc9Vo. \xacO\xa1\xdfY\xb3\x86f$ U\x88x4\xc0\u0253\xa7\xf0\xfe\xf7\xbf\xef=\x00\xbe\xfew\u007f\xf7\xf9\xcb`\xfe\x93:\u039cY\xc6\xee\xdd\xfb\x00\x00_\xf8\xc2\x17\u007f\xf6\u0739s\x98\xa4-\x97R\xe2\x96[nq\xa0b2\u054a\xbd#\x04b\xaa\x01\x14\x81\xeaS\x90\xd1\x0e4\xe6zh$\x1d\xec2#\x1cIb\xbcm\xd4G\xd2\xedb\xb3\xd3\xc1\xcb\xcbg\xf1\xcc\u0457\xf1\xe4s\xc7\xf0\xfc\xf1e\x9c\xbd\xb0\x86\x8dN\x17\x1d\xc7!\x0f\xe3\x04\xc3QR\x18t\x91B@)\t%\x05jQ\x00\x90@\xb77\xc4(\x1e\u066a^\b\b!a`\xacQ\x94Kf1\u01a0\x16E\u0635k\x17\xc2(\x82q\x89\xf2\xc3\xd1\x00\xf1(vZ\xec\x11\xe2$\xc1h\x94 \xd6\x1aqb\x15%a\x10@\x90\x80\xd6\x15\xed&_\u0152\u068b\x0e\x86\xe8\xf5\xfa.\x1d\a\x19\r\xe2\xeb\x9b\r\x19\x90.\u058by\xb2\x0eg\xbax\u03a6f5\x8c1\x88\xea\xd3\xd8s\xe8&\xec\xbd\xeav\x1c\xba\xe1=\xd8u\xc5\u03687\x16@\x10\x88G\x03\xc4\xfd\xae\xe5\x9aS\xe3a7\x80\x02M\xa0\x8e\xd5\x15\xf7\x17\x03\vz\xba\xbaI\xe61\x1f\x05\xed6\xf2\u034d\x05\xf2v\x82\xc0M>\xc2\x01\x1c\x95\x00\x8e\xb6\xe4h\xb6\xc0\x1f\x93\x03\vL>\x1cF\xda-\xb9\xa9d\xc9X^=\xe8k\u02041jJK\xbb\x88\x92\xf1&.\xf9+'\x82`\xd03P}\xe3\x1a\x9e\x94/Zi\xdf\u0420\xb0k\x9c4\x92\xe4\xb3+9\xb7QvQ+\xe6\u0125\xf4\x910\x06\xd0\xc5\xd7M&\tH3\x06\xb3\nZ\u0456\x15\xbaH\xac\xdd.\x19\x17\x00\x92\x1a\xaa\x15\xe6\xde\xdct\x03\t\x10\xe5\xc5U\xc1\x84\u051d\x93I\x124\xa6\x16\x10\u0567\xd0k\xafdW*\xa4\x02\t\x85\xcd\xcdM\x1c?\xfe\xf2\xad\xcc\xfa\xfd\x81\xd5\xc7\xc71\xfa\xfd!\xda\xdd\x0e\xd6V\xd7\xd0\xed\xf6p\xe1\xe2\nVVWQ\x8bB4\x9b-LOOaff\x06\v\xf3\xf3\u063d{\x17v\xef\xd9\r%\xc3\x02\xa0\x19\xc3h6\x1b\u0540\xe3}\xa2.,?\x83ao\x13\xb5\xd6|\xb6) S\xad\xe4\xe0B\x022y\x1fpv[tk\xe4\xe4\x03\x05U\x045A\xb8E\xa0\xe3\x14\x1d&'L\x84\x01D\x89\x9a+\xe7\xbf\xfaCU<\x11\xecP$\xec\xbd+\xc8\xdf%\x9fr\"\xc8\u0100\x98\xa0\xc3\xf8]\xdcq\xc7[.\x83\xf9\x8f\xeb\xd8\xd8\xd8 \x00\xfc\x99\xcf\xfc\xfb\x0ft\xbb\xddk:\x9d\x0e\xa4\x94\x94s\xc0\xf9q\xfd\xf5\xd7\xe3\xb6\xdbn\u035a\x9f?\xfa\x83\xc7\xcc\xf1/u\xa4\xe1\n\x85f\x8f\x1b\xc9O\xc1<=W\x02\xa3^\x8fP\v#\x98V=W\xba\x94T\r\x13\xf3\x9f\x19\x18%\x89\x05\x91\xb0\x8e\xe9Z3\xf7A\x17\x02\xb9\x8b4\xd0\xedn\xa2\xd3\xe9bn~\x0ea\x10\x00\xf0+m\x8d8\x1ea\x10ws\xafv\"\xec\u0631\v\xd7\\s\r\xbe\xf0\x85\xad\xf3p\x87\xbd\r\xac_8\x8e\xe9\x1d\a\x1c\xf7\xa9\x8bzB\xaeh\xf9yZ?\"\xbb.\u02a1A\xe8\xc0/\xad\xd0=?\xb2\xfc\xda\xc9V\xdeaGC\r\xd8\xf1\xd3\xde\xebm\xbc\x99\xf8J\x19\xe28\xe5P\xdd\x13%\x94'\x97\xa8\x9c\xef\xea+/8\xe7\x93e\f\x18i\x95\x1a~\xcf@\x8c\x80P'\x19\xa0'\x91\x18\xabp\u02e7\x915<\xd3\x06d\xdah-{\x94\xbb\xc1\x1e\x9atY\u07a9\x17\xbc\x1a\xc6\x1a\xa5\xbe\xd8\xdc\xf9\xa5\xf89\xa0n\x95)\x18\xba\xa5\xef\x95qrA\xe7Q\x1e\fL\x01\xd0\xd5\xc8\xca\x11\v\xc6\x12\xee\x9c\x04\xa8@\x162\xb9\xb6W\x99=,uA\xd2A?A\x12Q\xad\t\xa9\x82\xcc?)-\x88H\x06l\x18\xb4\xbe\xbe~\x13\x80\x10\xc0\xf0\xde{?{\xb92\xffq\x1d.\xa3\x8f\x01\xe0\xfe\xfb\xbfs\xd3\xc6\xc6\x06\x88(!\"U\x06r\xa5\x14~\xfe\xe7\u007f\x0e33\xf3`N\xb6\xcd5\xc4\u039f;\x05D\xf2\x06\x91R\xfa%\xbd\x96\u010d\u29c0\x9fz\u02cc\x93\u00d3K&\x9f\re\x9d\x14\xa3\xbf8\xe7\x0eG\xa3\xa1\xb5!0\x06\x83\xc1\x00\xfe\xe2\xe8\x9fgff\xe4\x16\x9c;\xef\xbc\x13\xd3\xd3\u04d6\u04dft\xcd\xc3\x1e\xd6\xce\x1e\u00fek\xdf\x01\x01\x01\u05ba$s+\x0e\xe2p\xa9$\xe6\xd4\xc3\xddyZ\xa7M\xb4\xa4N\xb9%k\xa9\xb8\fz\x1aA?\x1fa\xf7\xb7\xfad&\x039\x95\xaa\xf3j\u04ba\xb8\xf8PE\r\xcf\xf0\ar\xc6w-V\xa5\xe1\x93\xea\xf9\x0f\x92\xb6\xb2\xf5\"l4:kg\xdd(5\xd2`\u0209\xe7X\xacx\x91i\rS)\xa1\x1c\x1aD\xed\x04j`\x8a\u041a6<\x9d\x17\x89\xf0\u0324\xc8G\xe8\t\x9e\xe1\xe3\r\xc7\xd2$\u0418/@\x99\xf2'g\x04@\x05&\xa6\xfc\v\u04a6+\x19[9\xdbp\b\u05f0t\ra\xe1\xc6\xe1\xa3M\x8d\xa8\xe3\u4525\u0758\x8c\x19a'\xb1\xa1\r\x8cl\xb1SCc\xadm\xc7v \u049b\xf0\xe2\u014b\x8ef\xf1\xd2\xe2\x19XXX\xc0\xe2\xe2\x12\xa4\x14\x85\x9b6\xbd\x86\xd7J\x83\xfc$\x8f\x03\a\xf6cvvv\xe2N\x1b\x00\xe2a\x17Z\xc7VZF^\xfd\xc6\xe3UVUm\x9c\x8e\xc9Sb\xb2*\x94\x9c\xc4P\x8e\x18\xd1f\x82h3\xc9\xd2s\xc8\x14<(\xf3m\xbb).\x1a%bd\x8c\"\x98h\x81[\xe2\xceil)\xe0\U00045a7a\x9e/^s\x89\x82\xb1\xf6\xafy*\x85\xdf/ ]\xc4V\xf6\xa5\x92\\\u0352\xe4\x97E\xd5\x15\xfaV\x8c\xe4\x18\xc5R\xf4\n*\xfe..\x18;\xfbt\fy\x14P\xba\xab\xf0\xcd\xce\xc8 7\xec\xf2{&\x94\xe7\v Wv\xe6\v\xa6\x97\x9a\x95\xf7\x96\u0606\u0478>p\u0618B\x10\u05b2\xe9\xe7l\x91\x80}nm\x80~\u007f\xb0\xe3[\u07fa\xef\xb6\xcb`\xfec:\xbe\xf2\x95\xaf\x02\x00\x9e|\xf2\xc9\xfd) \xa6\x1e&>\x98\xdfu\xd7]\xb8\xf3\xce;\xb0\x9d\x92\x9f\x98\x19RJ\f\x06=\x9c;w\xce\xed (\vv`6\xbc\xb8\xb8\x88\xc5\xc5\xc5\xec\u3402w\xa7\xd3\xde\xf6`\xbeg\xcfn\xcc\xce\u030c\u05fa^E8\x1at0\u8b3b\xc1\x92\xbc:\x1foA\x96A&\xafb\xd3\x11|\x91\x18\x88\xc4d`G\xda\x0e\xa1\x84\xa9\xef\x8aO\xf1\xfaO\xa7\x91+;x\x12R\x95\xbb{\x15 _Q\x02\xf3%8\xf7\x94N\xf0\xab[\xda\nI=u#a\xbcj\x17\x89\xe5\xd9\xc9\u016be\x8a\x98\x8ak\xcb\xcd\xcf\xf2\x05\x94+\x17\x13.]3UL\xc7\xfa\x12L\xaf\xa3K\x97\xc0\u007f\xef/i\x837\xdd}X\x130d\x8d\xf1|\xb9\xa3\xc2\xe2d?\x18\"\u05da\xfb\x97\xe4}>\xb2\u0701\xb1\xb4sF\x10\u05ad\xd6\xdc\x19\xd51\xe7=\x9c\xd4\xcb?I4\x8e\x1d?\xfe\xe6\xcb`\xfec:>\xfb\u067f\x1e1s\xb3\xdd\xee\xdc\xf5\xd2K/e\xda\xecL\x93M\x84\xc5\xc5E\xdc}\xf7\xdd\u0631c7\xfa\xfd\xbe'\xe5\xfb\xcf\u007fH)\xb1\xba\xba\x82W^9\xe3\xe1\\\xf6\xa1\xa1\xe9\xe9\xe9daa^KY4\xac\xe8t:H\xe3\xed\xb6S#7\xa7Y\x18\a\x0e\x1c\xc0\xae\u077b*Y\x96\xf4\x03\x95\x8c\xfa\xe8wW*\u22f6\x9c\xa1D\x85p8\xab\xca-\x18X\x0f\x0f\x998\xe5CR\f]`\xd7=M\xab\xdd1)P\x01Z\xab\xd4*\\\xcd%s\xd5u\xe4\xb1\x19T\xb5\xb3\x98D\x85\xa0\x94\xfa\xe4I\xf7\x84W\xb9\xca$\xe7\u01b3\xa6\xb03\r3\"\x9f&\x9d\u073b\xad\x18\x10\xaa\u0715x\x8f\x13\xe4\xd3\xe4[\x97\xf1\x13\xa2\xf1\xaa\xa2\aS\xed{A*\xca\\\x99\x15\x9aSE\x15\xd4\x11\xd1\x18;\x97[\xafsa\xc6K\x1b\x06\x84Dcz\x11B\x05\u0678?\xdc\xf0\x143 U\xc0k\x1b\x9bX>\xfd\xca5\u033c\x04\x00\x0f=\xf4\xc0e0\xffQs\xb3\xcf<\xf3\xd4\xe2\xf2\xf2\xf2\xf5\xa9\x17K\xd97\xfb\x86\x1b\xae\xc7-\xb7\xbci\x9b\x9e\xbf\xc4\xea\xea*.:\x83-\xf6R)\xa2(\xc4\xe6\xe6\u01a3\xccx\xb1^\xaf;\x89o\u0299\x0f\x91$\xf16\xae\xcc\rv\xef\u078d\x03\xfb\xf7W\\w~\x1d:\x1e`\xd0]\xf7\xb24=\xdeSL\x029_\xcb]\xaa{9\xa5S\\\x95\x97\xd2'\xee\xef\xb6\x1a\xf6\xb7\xff\xec\xe5\x97Va\xdb\xe4\x99\xcfJ\xe8\xa5\xf2\xa2S\x04\xc1\xf2d%\xf1\xf8\xba\xc0\xd9uQ\xe15K\u007fF8n\xc0\xf2\xc8\xc8\x1d\x1eK\xe1\x12\x82\x91}\u007f\xe2\nI\x84KxB\x8e\u007f\x9f\xca\xc0?\xb9M\\\xa4\u04cb\xa4\x13\x97h\xa4\ft\x99KE}\xc9*\xc0\xf5\v\xb2\xc1*\xf7\x021sa\xea\x17\xdeD4;\x9bg\xf6\u04d1\xdc{\x94\xba\x826\xa6\x16 \x83\xc8\xd9L[\xf9\xadt\xf2[)\x15u{\x03\xb4\xdb\xed\xbd\xdf\xf8\xc6W\xdf\f\x00\x0f<\xf0=z\xfe\xf9g.\x83\xf9\x8f\x92o\xfe\xeew\x1f\xb8\xa2\xdf\xef\xdf<\x1c\x8e\n\x14\x8b}\x13$n\xbf\xfdv\x1c9r\x04I2\u0716\u0dfe\xbe\x81\x8d\x8d\xf51\xc0SJ\xa1\xd3\xe9.\x03\xb8\x10\x04AA\x156\x18\f\x11\xc7\u0276\x05sc\f\x84\bp\xe8\xf0!\x04a\xe8\xde/Q\u0612\x03\xc0h8@o\xf3b\xb6\x95\x1d\xa3A\xca3\xf4\xa8\xaa\U000386be5\xe34\xae0\u0784\x9f\x86\r\xd64\\fn\xc6+\xd3J~\x9b*P\x8bQ!\x8es~+\x13\b\x94\t\x8bU\xc1E\xdd\xef\xe4\x19/&\x8d\xb9\xe8\x1b\xe4-\x19\xe94#U\xbdp\x15\xd5\xebX5=\x19\xc1+\u007f\x80\xb6\xdaHU\xf6\x19J\xa6\xf3\x85]VYic\r\xc1\x8c$\xbb\x18g\x93\xab\xe9\x1f\u075bm\xf2\xd7\xc3.\fn_\x94\xe9\xd1}\xab\x02\xcf7\x97\t\xf5\xc6\x1c\xa4T\xf9\u0535\x90Y\x1c\xa3\x10\x02Z\x1b6\x9aw<\xfa\xe8\xa37\x02@\xb3\u0660\xab\xaf~\xe3e0\xffQ\x1e\x17/\xae\xdc\xf1\xd2K/\x15\x12m\xd2\xcaw\xff\xfe}x\xeb[\xef\x84R!\x92d{\x82\xdf\xc6\xc6FiR2o\x82\xee\u0631C\xd6\xebuYV\xdf\f\x06\x03\f\x062\b\u0272\x00\x00 \x00IDAT\x83mE\x19U\xed\x9a\x0e\x1f>\x84\u9a69\xb1\x0fl\xba\xd8&\xc3.:\xeb\xe7,\xb0\b\x0f\\\x04\xc1\x10U\x83\xdd\x16\xdc6y\xab\xa1\x9f\x9eC\x1e\xc0g\x14E\x95\x05,\x97\xaa\xec-\xe9\x0f\xae`\x87h\xac\x06\xcf]B\x18[\xea\xd4y\x12oQE\xcf\xe4\x8dP\xcaV?\xf7{\xd3T\xab\u0523\x9e\x8a_\xd5\x05\xb7G@\xf3$\x90/7\xa7/\xd1[(}\xffR\x8f\x18_\x84\xb9\xb0\xf8\xb0\xb0\xbb5#\xc9\xd2G\xde\xee\x80Y\xdbIO\x14\x15\xe5\xe9k@yW\xd4\xfa\xec\xa7\xf3\xfeY\xc5\x0e\xd4[s\x90\xd2N;[\x03/k\xd6k\\\xffA\xca \xd9\xd8l\xe3\u0631\xe3\xd7\x01\xc0\xaf\xfd\xda\u007fc\xb6\x1b\xc5\xf9\xba\x04\xf3\x17^x6\x05\x85\xc6\xf9\xf3\xe7\xefX]]-LC\xa6\xc7\xcd7\xbf\tw\xdcq'\x00\xb3m\xab\xd8N\xa7\x83^\xaf\xe7\xed8\xd8\xf1\xe9\n\xbbw\xef\x0e\xa2(\x94eJ\xa5\xdb\xedf\xfc\xffv\xbc\xa1\xd2s\u06b3g/Z\xadVa'\x95]\xa7\x10\x88G=\xf46\xce\xe7\x8a\v\u05c02\xe9\xcc5Uh\xb1\xc9\x17\xf6Q>8\xefeQ\x92\xcb\xde\x1c\xab&\x9dv9\xe5\xd0s\x19\x1bc\xa2\xeb\n\xf3\x18\xc8\xfa\x93\x9dE\xb8\u326al\xa2\t\xca\xf2R(\x84O@\x8c\xd7\xc3\xf9.B\xf8\u050a3\x912 (E\b\x03\x81P\xd8\xec\x8b\xc9q\xa0r\xa0vE`\xad\xb5\x00\x19\xd4\xc0Z\xc3\xc0\a~[\xf1\x87a(\xce_\xb8\x88\u04e7\xcf\x1ca\xe6\x03\x00\xf0\xb9\xcf\xfd\xad\xb8\f\xe6?\xe4\xf1g\u007f\xf6g\x00\x80\xfb\xef\xbfof}}\xfdm\xa3\xd1(\x03\xf2\xb4\x8am6\x9bx\xe7;\u07ce\x9d;w#I\xe2m\xfb\x02\xf7\xfb=\xc4qR\u079br\xad\x16A)\xb9<\x1c\x0e/R\xe6\xe4fo\u0635\xb5ulll\xa2h|\xb5\xfd\xc0|ii\x11\xadV\xb3\xa2\xbe\xb4\n\t\x93\xc4\xe8\xb5/ \x89\a\xce\x1a\x18\xa5\x00\x1f\xb6\x91k4\x89\x06\xc8a\x8f\xfd\xea\xab\x04&\\\x1a{\x1c\x93\xe5y\xcd4\xa6I\xac\x82\xaf\x14/\u007f\x8b\x8b\xe7\xbc\x05A\xe1\xab\xce\v\xc3<\x15\x89B\xd5\xc4\xc6\xf8\xa4,\x180\x12\x90M\x89\xa8\xa5\x10\x86@ \tJ\xe6>\xf4\xc4\x15\r\u05can$\x8fq\xe2\x97F\xf7\\\xc7R\x150W\xfe\x15\xc5&\x01c2{\xc5\x00H\x11\u0114\x84lI\x04\x01!\n\b\xb5@ \f\x04TV\xa1;\xddb\xd5$+\xe5\x9c:\x17\x9a\xb1\x949*\x02@\x106\x11\u0567\xb3\u0140\xa4\xcc\x1dH\xad\xfcQ\f\x87#lln^\xfb\u007f\xfc\x9f\x9f~\x03\x00\xbcp\xf4\xe8e0\xffa\x8f\xdf\xfe\xed\xdf\x01\x00\x9c={\u6593'O-\xd9!\x1a\xce\xfcM\x00\xe0\xdak\xaf\xc5\a>pw\xc6\xe1nW\u03bf\xdd\xeed&[)\bZ\x1b\xd9&N\x9dZ~\xe4\u0529S/*\x15xJ\x17`mm-\x1b\xe9\xdf\u0395\xf9\x8e\x1d;0==3\x0emi\xf1\u010c\xc1\xe6\n\x86\xed5\xab\x15N\xa9\x11m\xdcT \x95\xfa\x88\xc5\xe4\xf7\xb1\xd6${\x9c\xabo\x8d\x9am\u0569dKR\x04\x95,6\x8f\xb6\xc6\xcf\u025c\x0f\x15\x95\x13\x19\x85K\x15\x04L\xe9\x19y\xacN\xf5\xe0\x9agF9n\x9e\xaa\xc2\xe0\x90\xed\x02\nU$\x97\x99\x80\x8am\x02\x95\x1a\x9e\xa5\tN\x06\x17\n\u0182\xbb\x1f<\x1e\xa6b\xa2t\\UB\x85\x06\xb1\x0e\bIK\"\xdc\x11!\x9c\r f$h1\x80\x98\x92\x10\x81\x00I\v\xeae\x0e=\xd5a\x17TC\\E\xdb\xd3\x18\u060eW\xdf\xc5\xf0\x16\xe6I\xb2E\x14'@\xa9\x94?\x97>\x8b\x80\xa3\x8b\bAK!\x9cRv\xc71\xab C\x01!\t\" \u021a\x80t\xa9D\xcc\xc5\x1d\x12\xfbrt\xdf\n\xdf\x05\x84\xa3\xe0\x9eh d\x80\u9e7d\x10$a\xb4v\x01\xebA\xf6\x9c\x86\x19R\x05|\xe6\xcc9\xf4\xba\xbd\x9fb\xe6\xc5S'N$\x97\xc1\xfc\x878^~\xf9X\xf6\xe7S\xa7\x96\xdf\xea\xab:\xd2\n|\u07fe}\xf8\u065f\xfd\x10\x00\x8c\x01\xe5v\xaa\xccG\xa3\x18\x9dN\xb7\xb0s \u05d4i4\x1a8t\xe8p\x90$\x894.\x9d&\xa5Y:\x9dv68\xb4}\x9b0\x8c0\f\xb1\xb8\xb8\b%U\x11<\xbd\xff\x8d\xfam\f;k\x99\u01ca\xc8\x1a\x96\\P5\x14E-\x13\\\x14\xab\xceB\x10\x92\x9aDR\xb7\xde\xd8,\x8b\xcd@\x1f\x18\x99\xa80\x0e\xee+\u034b\xd4CU\x1d\u0293Kx\xf67\xf6\x1e\xd7N\xbeR\x851\xa9\xf6\xcd\x11\xa9\x88\x8a\x86\x80$\x10\b\xe7\x034g\x94\u0376\x04A\xb4\x14\u010e\x104\xab\x104\x04\xa2\x86DX#\xc8\xc0\xaa3\xca\x16\x88\\-\xb6\xc1\x98\x82\xe7UD\xe4\xb1'\v\xe2rhK\xc5N\xa6J\x97.\xa5@(\t\"\x14\x10S\n*\x10v\r\xae\vPS:\x87D\x86P\x04\n\x90\xc9\x14\x99`\x1b\xe7\xee\x1a\xb3\xf5?\xf3\ua9ca\u05d6\xc0\xc6@H\x89\xa9\xf9\u0750*\x84\x8e\x87\x10BB\x85\xb5\x8c\x8f'\x10\xa4\x90\xd4\xeb\rq\xf1\xe2\u0291o~\xf3k\xfb\xf1:;\xb6\x1d\x98\x1f:t\x85\x03\xb4\x8d#\x17/^\xbc15\xa0\xf2\x03\x9c\xef\xba\xeb\u0778\xf1\xc6\x1b\xb7-\xc5\x02X\xbf\x98\xd1h\x84^\xaf[Y\xed\xd4\xebu\xec\u06b5\xdb-F\xc5\b\xba~\u007f\x80~\u007f\xb0\xcdo\x1d\x03\xa5\x14v\xed\xdam\u524c\x92\x0e\x98A$0\xe8m\xa0\xbfy\x01\u0485Xg\xfc\xae\xa3A}\x8e=W`O\xe0\xae=\xe0Kk\\\xa9\b\xc1\x9cB\xb8+B4-\x11\x04\xae\x9a\x93\u00abP=m\xbb(\xf3\u9503\x00y\x89N\x15\xa0\xc7>\xe0\x15x\x96-p\xb24\tC%v\x19%\x83)\xbf\xfa\u0512\x10\xce(L\xcd\a\x90\x8a\xb2\xea\x94\x00P]\x82\x16C\xc8\xf9\x10\xb2%\xa1\x9a\x12a3\x05v\x01\xa1\xc4Xq\xfc\xc3\x05\x9e\xd2$W\u0742\xb4r\xac\xd7P\x9eG\x12\x84@\x00R\xa6\\\xb9\xb0k\x9e\x81m~\xb6\xa4\xbd6W\xd8hg>f\xdf?\x02K\xf7\xe5/Zd\x1b\xa6\xe9i\xd8\xde\x1a\xe7\n8m@$\u0418^B\x105a\x92\x11\x88\x04\x82\xb0\x9e5p]\u07ca\x12m\x10\xc7\u0261\xfb\xee\xfb\xf6^\x00\xf8\x8b\xbf\xf83\xba\f\xe6?\xe4q\xff\xfd\xdf}\xfb\u0673\xe7\x9a\xddn\u01fd9:\x03\u024f|\xe4\xefA\xa9\bI2\u07364\x84\xb5\x8b\xd5^s\x96\xb2b\xcd\x18\u00edV\v\xfb\xf7\xef\rF\xa3xl\ua0d91\x1c\x0e\v\x00\xbf=\xafQb\u03de\u0748\xc20\xf3\xd1@\x01\x9f%F\x83\x0ez\x9d\x15\xa7C/\x19\xb2O\xf2*\xa9\xa0_\v\x01\ri\xb8\x80\"\u0526\x14\x9a\xf3!\xa6f\x034\x97B\xd4\xe6\x03\x845\t)\x01#,\x18he\xbf\xd8\xe3\u05ab\x16\x86q=J\x95\xab\xa0w\x19c\xdb\u007f\x06ck\xba\x82_\x05l\x02\xb6*W-\x85\xd6R\b\x15\n\x97\x1f\xee\xe9\xaa\rCD\x02b.\x80\x98Q\x10\x91\x80T\x02A] \xaaK\u051b\x12Q]Zj\xa9\\\xa5W\xf6\x05\xb8\xe2\xef[xLr\xb1/Q\xb4\xdf\xe2\xca>\n\x13 \x05!\x10\x04D\x041\x13\x80\x94p\x13\xacNG\x1e\x120\xa3@\x91\vr\x16v\xc7\x01o\xc7e$`\x04\x175\xf5Y\x95^\xbc\fv1zF3\xc2h\n\u0359\x9d0\xc6\xc0h\x9di\xcd}\a\xc6 \bp\xf4\xa5\x97\xf0\u02993\xb7\x00\xc0G>\xf2K|\x19\xcc\u007f\xc8\xe3\xf1\xc7\x1f\u007f\xc3\xfa\xfa:\xe28v\xa1\u01f6\x8c\xbb\xf9\xe6\x9bp\xd3M7\xd9U[\xebm\xfd\xe2\xa6\x15\x02{\x83\x1f\xcc\xe0(\x8a\xd4\xc6\xc6F\xbb^o}\xc3'?\xf5\xe9]\x00p\xdbmw\\\x06\xf3\xd7z\xbc\xe9M\xb7f\u007f>~\xfc\xe5\xb9^\xaf_\b;\x06l\xfed\xad\xd6D\x1c\x8f\xf0z>\x1a\x8d\xba\xba\xf2\xcaCJJU9\xe9ii\x16\xb3\xadi\x16\x00\u0635k\x17\xe6\xe6\xe6\x9cE)\x8d}\x98\xd9\x18\xb4WO\xa3\xbf\xb9\x02!TA\a\\\xa5N\xe6\x02\x90\x97\xab}\a\xe4u\x89\xa0\xa5 f\x02@Z\xc9c\x01\x9f\x14AN+\xd4\xe6\x034[\x12\xb5P \x90\xb6R\xcb\xf8h%\xa0C\x01\xdej\xf2\x06\x93H\xe2\x8a\xc7l\xe5\x9a[\xad\xad\x19_\xcel\xe61DC\"\x98\x0f,(\x1b*\x00\xb9\xf103[z\xd8y\xbd\xd6$h!\x00MI;x\xe3\x1e\xa4\x02BT\x97P\x01\xc0i\x8a=\xa1\xdc\xe4\x98@\x00q\xd5*\x9b\xe3n6\xfcU\xa5\x9e\xf7\x8c\x81\x89 \xa5}ohZ\x82\x1a\xa2\xba\xdf\xc0.\xf89\xe5\xcf#@\x10CR\xdab\xe5,z\x8e\x05\xdb0\x8f\xec\xb51\xee+U\xa8\x98\f\u05d95\x88\x14\x9a3\xbb\x11\xd5g\x90$#\x00\x04)\xc3,\xfc\x82\\\x9f\aDx\xf9\xc4I\xb4;\x9d\xd7U\x94\u0736\xa4Y\x8e\x1e}\xf6g\xd6\xd7\xd7\x0f\xb6\xdbm(\xa52\x8a\xe5\x96[n\xd9\xf6\x8d\u03f1\x8a\x8c\xaa\xff-\bB\x04A\x1dJI7\xe9\t\xf8\x01\x15\x9dN\a\xa3\xd1h\u06cf\xf4\xcf\xce\xce\xe0\xe0\xc1\x83PJ\xa0<\xff\u01ce\x1f\xd8X9\x89\xf6\xdaiH\x15\x8cU\xabT\xfe \x13\x15\xb6\xee\x19^\x01 \xc1\b#\x81\xb0! f\x94U?\x94'@]\u04cf\x14A\xcd\x06\b\xe7C\xd4\x1a\x12\x8dH\xa0\x1e\t\x04\x82\x9cc\x1f\xc3( \t\x85\x954z\xa4|\xbeo\x98\xe0\xa4H\x15Z\xeaI:\xed\x82+ O\xa0c\x9cZ\x8b\x192\"\xd4v\x84\bZ\xaa\x10f\\\x984\xa5\xaa6\xad\x03\xb9P\x00s\x01hV\x01\x91\xbd.A\x84@\x11\xa2\x86\xb4\xfc{\u5fa1\xca[\x86's\xe0\xe9>\xa3\xf0\x92P\xf5\xf3\t@)XuJS\xdas\x134Y\xaa\xee\x16(\x0e\x004\xad\xa2\x85Rq\xbfa\x10\xe7\x03D,a+\xfcBw\xc26=\xcb=\x11\xd61\xea\xad\x05\xcc,\x1e\x86\xd1\x1a\xc3A\a*\xaaC\xa9\xc8=.=s\x81\xd5\xd55\x1c\u007f\xf9\xe5w1st\x19\xcc\u007f\x88\xe3\x1b\xdf\xf8\xd6\xc2\xc6\xc6f=\xedF\xa7\x14\xcb\xdb\xde\xf6V\x1c\x18\x80\x90\x02A$ \x9a\x12\xd4\x14\u0632\x1cf\xab\x83\x14-\t9\xa3 k\x02\xa1\"\xd4\x03B- \xfb\xf97\xae\x99\x16\x88\xdc\x0f\xa4\xb8ba\xe2\x84\xd1V&]\x99/9\x15(j\x1a{\\i\xb1\x92\x84p.@8\xa7\x1c54>y\xeaOb\xd2\xd8\xf9\xb0\xe5\u0195k\"\xce* \xccJW\xdbg\xa8K\u0210\nz\xf4I\x84?a\xf2\xda\u00d4S>\xbc\xc5N\x86\x85U\x1cII\xa0@\x80f\x03P]nyO\xa5.\x88\xd0\xda.H5\xe7\xa3b\t\x95\xac\x02O'?\r\x8c\x1d\xfb\xf7\x16\x1f\xbf\xa5\xcd\xc6\xc0\x18F\x12\x0f\x11\u05a60\xb3x\x10\x00c\xd0Y\x87\njPQ\x03\u0326d\x8fK\u8d3b?u\xfa\xe5\xa3!\x00|\xf3[_\xa7\xcb`\xfe\x03\x1cI\x92\u0726\x94\xac\xc7\xf1\xc8v\x9eMZ\x99\xbf\taX\xc7h\x14\xbf\x8e`\x9b*+\xf5\x14\u0327\xa6\xa6\x10\x04jLOnm\x00\xe2m[\x99\xdb\xddQ\x82(\x8ap\xf8\xf0!DQ*O\u0307P\xec5\t\f{\x1b\xd8\\}\x05Z\xfb\x1e4\x8cr\x13\x8d&#\xbdU5\x84\x04\x11\t\xa0\xa9\x00)&\xb3\x1f)mj\xec\x1d.\xa6\x14\xc4l\x00\x8a\x04\xa4\x04\xa2\x80P\x97\x84\xc0\r\xdah\t\x18\xe5\xa9\\\xbc\xc5e<\x1d\xf9\xd5|\xbb\x8a\xed\xa7\xc2w\xfc$\n\xbb\xeb\x00\xa2)\x85p)\xb4\xea\r\xe6\xca\n\x9a\xb6\xb8\xb7\xb2\xbf\xa7\u0297\x96\x02\xcd\x05v\a\xe3\xaaW)-\x8f.BQ\bw\xf0\x17\x84-]\x12\xdd\x0e\x8a\u0299\xae<~\x9eL\xee}\x13\xee\xf7OK\u0434\xac\xfa\x81\xf1\xb5\x80\x19Fk\v\xcbu\x01\xad\xa8\x90\x13j\xc1\xdd\x01\xbb\xb6`n\xd8@\x1b\xe3vC\xaer7\x9c\xed\xe4u\x12C\xca\x10\xd3s{\x10\x84\r\xc4\xf1\x00\xc6\r\x14\xf9\x94\x93\x10\x12q\xac\xf1\xfc\v/\x04\xdf}\xf8\xd1\xdb\x01\xe0]\uff0b/\x83\xf9\x0fp\xf4\xfb\x83}\xcc\x06I\x92p\n\xe4\x87\x0e\x1d\u0111#G&R\x17\u06cbZ\xb1\xa1\x12J)\x84aP\xf9\xfd\xd42vqq\x11a\x18\x8e\x81y\x1c'\u06deJ\xd2ZC\xca\x10\x87\x0e\x1dB\xb3\xd9\x04\x8d\u036b\xb8\x0f\x92N\xd0^[\u01b0\xbf\t\x92j\xecs<1<\xce\xeb5\x92\x84mf6%P\x17\x97\xd4L\x97{|4%!\xe7\x02\x88\x9a\xb4\xcd8E\xa8)\xb2L\x04;\xb3\xa7\xb0\u031f\xfb\x13G\xfe\t\xb9\xa6$U\xc78\xd3\x18\xdf_0\xcb\xf5*\\\xf7h\u05e8\x8c\x96\xacf<\xdd\x11\x14\x1d\x82+\xf25'\x82:\xf2\u0160)m5\\s\xce\\l\xd7\xc10\x12\xa0\x80,%?&\xe8\xe1\xb1\x19\xa6\xe2\n\x96n*\x8a*\xa0\u00a2E\x16]\xa4 (bP]B\xcc\a\xa0\x80r[\xe2\xca\xe7\xf7\x831\x9cQ\x96\x02\x92\x1a\x90\x10g\xcdN\x18\xb7+H)\x97\xb4]K9\xc5\xc7\xc6d\xbd\x01\xb2Sy`N\u041a\u074d\xe9\x85}`\x93`4\xe8@\x05a\x1e\xf8\xec\xceA\x1b\xc6\xda\xda:^|\xf1\xa5\xb7\\\xa6Y~\x88cuue4\x18\f\x01\x10\xa5\xc3BW^y%\xf6\xed\u06c7\xed\xdc\x14,V\xad\x06Q\x14\xa1\xd9lU\x9e/;\xbd\xe2\xd2\xd2R\x10E5\x18w\xa1\xe9c\xe38\xb6\x9e\x12\xdb\xf8Z}E\xcb\xc2\xc2B%\u0352n\xc6\u06eb\xaf`\xd0\u07c0P\n\x13`\xa2\x1a\xc5\x1df\xaa@@\u0525\xad6\xabT\x10\x18\xe7\x97\xcb\xcc\b\xb5,\xa0\u021a\x84 \x82\x14@\xa4\x04\xea\u03b0J+\xabt\xa9<1*k\xce\xc7\u03c1\xb6\xa0\x0e\u0199\xe8\x94\xcf\x06\u0080\x10\xcd)\x88Y\xe5=\xfc\u0485 OlV\xe6\u007f%fPC\x80\xe6\x02\x88\x86\x84P\x04\x99r\xe85\tR\x02\xc6\a\xeeB\x9a\x0f\x8d\xc5o\x94\u007f\x0f\x8f-d~\x8f\xc35=\x03\xf7\xfb\xeb\x12\xd0[Y9\x96^'\xf6<\xcc#\x01Q\x17\x10\xa2\xd8*\x17\xe9Tq:8$\x04\x84\xb7\x98\x12R\x99\xa2\x80 \x01\x9d\xc4h\xcc\xee\xc4\xcc\xd2!\x18\x9d`\xd8\u06c4TA\xd6\xcfI3D53\x12mp\xee\xdc\xf9w\xa5g\xf4\xf0\xc3\x0f^\x06\xf3\xd7z\f\x87\xa3l\xe23\xb7[\u074d\xa5\xa5\xc5m\x9e\xc0S\x04\xba0\f1==]:\xdf\u051a@\x13\x00Q\xafG\x17l\xd1P$mm\xdaP\xf2:\xb8V\xc6\xcc\xcc4\xf6\xef\xdf?^\x99{ \xb1\xb1z\n\xfd\u038a\xfd\xd0\xf0\xa5\xdcW\xbc\xa7 @*\x01U\x13\x10-\t\x8e\xc4%p\x8e'>+\x11\xac\xdcm.\x80\xacK\xeb\x01B@(\b\ra\xa9f\x1d\n\v\xe8\x84\n\xbd\xb8\x1f\r?I\x01R\x95Z49\xb8\"\b\b\xe1t\x00\xb1\x18\x82\x14Ys@\xc7Qp%\xe8\x95'-\xcb\xf9\xa5\x9e\u076f\xff\xad\xba\x80\x98U\x10N\xbah\x9b\xa2@X\xb3>(LEs\xafI\xec\xc7\xd8N\x83\x8a\x8b({\u0222\x84m\xbe\u04b4\x82\x9cQ\x15\xd4\u04c4EW\x00`\xe3\xeck\xed\xffCEh\xce(4Z\x12\xf5\x10\b$l#\xd4x\x80\x9f\xf2\xf8i\xc2\x14\x18\x865\x8cvT-3\x8cI\xa0\xa2\x06\xa6\x16\x0e@\x86u\x8cF}h\x9dX\xd9,\t/\xb1Np\x1c'X^^~#3\xd7\x00\xe0\xd6[\xef\xb8\f\xe6\xaf\xf5\x90Rf>%)\x98OOO\xa3^o\xbc.T,)\xcdB\xa4077\x8b \b\xe0W\u0756\xa20\xd8\xd8X\t\x9e\u007f\xfe\xe8\x97766\u06f5Z\xbd\x10H;\x18\f\u0728\xff\xf6\x06s\xadc\xcc\xce\xce\xe2\u0211\xab\xac?\x06\xa1\u020b;:\xa2\xbd\xf6\n:\x9d\xf3v\xab[\xa60\xaa\x02\x9d\xddC\x94\x04TD\x90-\t\x9aRn\xc2o\x82\xcf\t\u00c5\xf5\xa2Z\x80\x91\xfe[\u04daU\u0256\xb2\n\vE\b\x94@]Y\xd3*\x1d\t\x98\xc0sW\xf49\x9b\t\xa1<\x05m\xfa%\x17\x18\x02\t L\x1b\x92\x8b\x01\xe0\x86\x83\xf2\x11\xfc\xaa&g\xfe/\x95\xfd\x05\x1e\xcf\x02%\xa2|\u0769\t\xd0|\x00L\u0641*!\xad7z\xbdf-g\x89\xc6s83\x9f\u022cb/\xee\b\xd2\xde\x04yzI\u06ec&H)\xecnh)\x80\b\xa8b\xc7Q\xd4\xed3\xf2\xb8?\xd6\x1aF'\x96\x0f7\x06\x82\x18A\x04\xa8\x96@P\x13\x88\x027\x80\x94\x017\xf2&\xa9\xf1\x16\x027=\x9e\xfa\x9a\x83\x01\x9d\u0118\xddq\x18\xd3\xf3{\x91\x8c\xfa\x18\r{\x102\x80H\xc7G\x89\xa0\x94\xa2N\xb7\x87\x13'OM\u007f\xfb\xdb\u07f8\xe72\xcd\xf2\x03\x1e\x8dF\x1dR\xca\xd2M)\xb6=\xb0\x95h\x14\x00\xc0\xcc\u0334m\x0e\x96\x8e$\xd1t\xe1\xc2*\x1a\x8d\xc6@\b\x91\x94+\xf0tXj\xbb_s\x92h4\x1a\r\xec\u06f7\xcf)Z\xaag8G\xc3\x1e\xba\xed\x8b\xd0&\xa9l\x82\x8e\xcdQ\x12 \x89\xa0\xa4\xb0\xb4\u0234\x0f\b\xd5\xceQ\xa9\xcd\x15\xc0\x93\xeb\xf3\xf4W\xd6\x04h^\xd9\xe6\xa8\x04 \xac?xMX\xa0M\x02\x01\x13\x8a|\xb0(\xe5^\xb7|?\xe8U\xbc[\xf6\xf9\x02A\b#\x011\xa7\x80i\x8fz\xe2\\\xbf]\xad+a\xcfY\xb2\xaa\x84\x9eddnA\x17\x01\x81f\x953\xb4\xb2^)2\x14\x88\"\xfb%E\x89P\xa9Xo\xa9\xfc_\u02af\x9d\t\x80$(a\x9b\xd5b1\x80\xac\x8b\t@>.+\x05\xb9f\xa5N\xc0\u0680\x8dv\x92D\a\xc6\x01@!A(\x810\x90P\x822\xeew\xa8[Swuu\xf5(uK-\xa9\u0552\x00\v4\xa0\x81Qf\xe6a<\x80\x00\x93x9\xb1\x8d\x89\x87\x84\x10\x9c\u007f\xf2\xfe\xc9K\x9c\xbc8\xce\xf3\xb2\r\xbc\xb0\x1c\x9c\tX\xd8\x01\x83\x9e\x102\xc6\x0fd\x03\x92h\t\xa3yhuK=O\xd5\xd55\xdc\u1733\xf7\xfe\xde\x1f{8\xfb\u073a%!/\xbf\u040a\xea\xacURu\u056d{\xcf\x1d\u03b7\xbf\xfd\xfb~\x83\xff\xc8\x14E\x81}\xfb\xae\xcc\xda\xed\xb6\x1c\xee\u078a\xa2\x80\xd6\xe6\x82/\xe6\xd6\x1a(\xd5\u0116-[\xd0h40\xdam\x10`]\xa2\u05dd\x87\xe6\xd2\x05\x03\xd4:\xb3a\xba\x9f\u00f33\tg\xf3:\xa9\xa2T\xbd\xa6\xeec\x1a\x01\x05$\xf0\x04\x0fA\xde4T\xd8\x1a\x02\xb4A\x81&\x14D\xe6.\xfaL\x12\x1a\xbe\xa0[E\xb0\xa9RT8\xb5\xe1\xaa::T\xf0h\xcd e\x1f\x94 \b\rE\x10\x93\n4S\xc1+\xa9\x00sT\x02Sb\t\x81\xe7\x97 \r\x95\xfa\xa1\xe7N\xbe\xa0cR9\x11\x8fpP\x8bj8\ua9d4U\x90G\x88s\x1b\xbe\xb3\xe1\xfdA\xb4i!o\xa2\x95\x11\xc4F\x055\x95\xd5\xf8\xe8\xa3\xf1\x9b\xfaN.v\xd26\xd0\x0f]\x97\rk\x01\xc1\xe0&9\xda)\xac\x0f\xe7\xf0\xcc\x16k\xc1\xda8.zl\xaal\xfc^\x04\xd8\xc72\x94ja\xc3\xe6K\xd1lO\xc0\xe8\x1c\xd6j@\u0238xy\xb1\"\x17E\x81\xe3\u01cf\xbf=\x9cn\x96\xb5\u058b\xf9\x8b:)!\x9e\xb1\xd6B)E\xa1\x8b[ZZB\xbf\xdf_\u0571_\xe8G\xbb=\x86V\xab=\xf2w\x83A\x1f7\xdexC699!\x86#\xf1*\x98\xe5\u009f\r\x00\xc0\xec\xec,:\x9d\xb1\xd5\xe5\xc5\xeb\u05ad5\xc8{K0\\\x823\x91fP\xa0\x96\xa4\xe9\x8bA&\x9d\x9d+\x8fI\xe7\xd3!B\x9e\xa3\xaf2\xc4\xd1pkTM\x8dl\x88U\xbfO~`\x01(\xe1:\xd5\t7\f$\u12ad\xf4\xf7a\x15\xc14\xbdR\x14\x14\xdd\xfcj@|(n\xabL\xc4\xea\x10\x05\x93\x83\x1f2E\x0e\xbb\x9ei8\x0e\xb5\xad\xa0\x82\xf8\xf4j\u0557Gw\xe8#\x81\x9e\xbai\x18Q\x8a\x87$\v\x99\"\xc7r\x99T\x80r;\x13\xca\x04dS\"k\b(\x95\xb4\xca\u00b3n\u05b0\b\x8e*K_\x04\x95$\u0229\fjc\x96\u030d+\xc6Im\xf1\x1e\xe6wz~9\x9b\n/\xaf \x12\xcfb\x91N\xf0\xc5`\bb\bI1g6\xae[\"\x9d\u06cc\xb04\xb6%f\xb6^\x8e\xf1\xa99\xe82\x875\xdaw\xe6\x14\xbby\xa5\x14\x9d=s\x06\x8f<\xf2\xe8\xe6s\xe7\u03bcj\x1df\xf9[\x1cJ\xa9\xfd\xd6r\xb7\u0468\xe0\x89\x03\a\x0e\xe0\u0529S\x90\xb2\xf1\x92Q\u007f\xbab\xdeF\xab\xd5J0\xf3\xc0\xf7\x15$\x84\x90;w\xeez\xaa\xd9l\x9ck6\x9b\xb5\u03bd\xdf\x1f\xa0,_:|\xfa\xa9\xa9)l\u0738\xd1C\xe4\xc3v\x87\x04f\x8b\xa2\xbf\fkJgO+\x87\x82\x13\"F\ue2dd$\xa0)\xc0S\xd2\tG,\xeav\xe2UtP\x1a(\x14\xbb;Ak\x80\x1ea\u06ddt\x82\x94\t\xd0T\x06\x9aR\x10\x99\x80\xf4\vJ\xac;\x020\x99\xa8V\t\x1a\u00a91\xdc\xfe\xf3PG\x8dJ\xb4\xd3$\u020e\xb3\xafE\xa0!bDm\xe3\x90\xda1\\\xbbG\x81/\xc3\x05\x96F\x92\x06k\x1d\xb4u\"%\x9a\x92\xa0\xa9\f\u021c\xf1\x18Ig\xd2\xd5P\x02*]O\x12\x16\xce(\x83\xe2`Q+$ \xc7\xdd\x1c\x802\xb1\xea\xbcG\xa6\x15%\xef_eN\x97\x0e@\x1d\xccb=\x06\x0e\x82\xa3Z*\xb7\x83\x12\xd2\xef.\x84\xa3\xfc\x92W\x11\xdb@]\xf4CR\xf6n\x89\xe1\xff\x9d\xa99L\xcf\xee\x82\x10\x12V;C?!\xbd\x93\xa2\xef6\xba\xbd>\x16\x16\xce\xed\xfc\xecg?{C\n\x9f\xae\x17\xf3\x1f\xf1\xb8\xed\xb67\xcf\xcf\xcdm6Y\u0588\xea\xee\xfb\xef\xff>\xee\xb8\xe3N7\xc7i\xb5\xf0RI\xceN\x8byz\xd5\n!!\xa5\x90Dt\xa8\xd5j\x9d\xe8t\xc6\xfds\xaa\x02*\xf2\xfc\xc2W\xba\x06\xf5\xea\u018d\x1b\xb0m\u06f6h\xff;b\x88\x80\xa2\xbf\f\xa3K\x10I\xb7}W\xae\x80\x84\xad\xbc\x94\x84,#\bE\x80\x02xR\x82\xc7%\xb4e\x94\xb6N\x88s]\xa7+x\x14\xc1Z\xae\x93\xe6\x88kt\xb9\x14\xaap\x85\xb2\x12\u0650\xf2l\x8f\r\x95Z\xb4\xa5\xc8\xd58v\xe7g2\xaa\x02.j\v\x11\xd7\xf0c\x1e^\xc8\xe0\ng\xd6\x12\x90\xbe#\xa7\r^\xa8bQs.X\x9bQB\xabb\xa9y\xd5\"B\u03c3\xdb\xd7=^\x9c\xe4\x9da\x05\x81'=\u44b9\xe2H\x19\x81\u048cQN\x92\x93\u05a2\xb9{\x18J\x8dI\xa8M\x19\u460c\x8b\x00%\xbb\xa2\x10\xc2<\u0681\u04a7\x18\xd9\xca_\x98\r\x83\xad\x89E\x18\x81?.\x1d]\x91}\xe83\xc8\u07f7\xf7\xe7t\x8fc\x9cR\x14U~\xb0\xf1\"Dk4\x88$6_\xf4\n4\u06d3\xd0e\xee\xc2S\x84\x02\x91\xf0\xf5\x87\xe8v\x97\x90e-\xb4Z\x9d\x18\x04q\xe1\x15v\x8b\xf1\xf1qt:\x9dX\xf8\xc2d}0\x18\xf0\xd3O?\r\x00\x98\x99\xd9x<\xcb\x14\x88D\x04\x00\xfa\xfd\x01B\xca\u0485^\u03356\x98\x9e\x9e\u008e\x1d\u06e1\x94\xac\x158J'\x90\xe1\xfaU\xbe\xb3\r\xdc\xe0\xe0\u06e1\b$\x05\xa8! &%DGB\x06\xebT$\xd71%\xfe\xd9k\x18N\xd5\xca\xf6\xdaNX\xfe\xd4\xea\u014a\xc6%\xe4\xc6\f\xaa#\x915\xc8w\xe9\xc2y\xba4\x84S\xfa\f\x19N1\rei&6\x04\xaa)\\1\x1f\x97\xa0)\xd7\x01\xaf*\xb2k\u060c\xa7\v\x16\x0fc\x12\xabj4\x0f\xc5\xd6\xd5\x1f\"\xb8\x97\x18\xbf\x1b\x10\u00a9AE\xa8\x04\x13\x12\u0618\x01c\x12\xdc p\x96\xfa\xbe\xfb\x00\xee\xa4\v\x0f\xef\xa7\x11~\xe71\xad 7fn\xae\xc0\x95\xe2U\xf8B\x1es\xb8\x13\u03da:=\xd1\xf90Y\xad\u0757q\x9duE3\xb4n8\x1a\xa0\x13I\x10-\x01\xf2\xce\u0281\xcdR\x83\xd4D\xb2c\x1b2\xf6\xb4VC\x8dM`\xf6\x92WB5Z\u043a\x88!8l\x8dc^\x81D\xb7\xd7\u0179s\xf3;\xef\xb8\xe3\xcf\xf6:\x94\xe0\xfe\xf5b\xfeB\xc7+_ym\xfc\xfe\xf6\xdb?\xf8\xf9W\xbc\xe2\x15\agg7\xa1\xd1hF\xae\xf6\x993g\xf0\u044f\xfe\x1a~\xf1\x17\xff!\xbe\xf8\xc5/\xe0\x89'\x1eE\x96)\x8c\x8dMDY\xfc\x85R\u052d\xb5\xe8t:\x18\x1bk'\u015c\u0207m\xa8^\xaf\xdf\x04\x80\xa3G\x8f\xdd5\x18\xe45\nc\xc5f\xb9\xf0\x8b\xb91\x1aY\xd6\u009e={0>1Q\xcd4\x88 \xa4\x84\x94\n\x82\x04Z\x9di\xa8\xac\xe9\xe9f\t\xea\xc1\\\xcd\xc0\x04\x1cF>\xae\\\\\x183\x94/:af\x99:\xf5\xb9\xf7\x9bF\x16?pR\xf2\u05fc\xfc\x86\x13t<&;\xe6\n\xba\xecH\x90r\x85/\x13\u0085\x10\xd7d\xff<\x94\xe7@\xb5\u007f\u02cc\x905\x04dS8\x8c\xbc)j\xf8\u007f\x8c\x81[\u02dbf\xad8\xb6\x11~\xf0\xc3I?\xe9e`\xbdK.\xfb\xc7S\x92\xa0(q,\x0f\x1ds[\xc0N+7x\u039c\x1f\x8ejJ\xc8\xcc\r\x87S9\xbf\x15\xf0A\xda\x02j\\A\xcdd\xa0\x86g\xe6\xa4^\x91\x01M\xe2\xe1\xd79\xa5\x1b\xb9\u0398u\tk48\xc0*)~\x9e|\x05?\x16d\x00)\x00\x1eR1\x9ek\x1e`5\x1b=n\xea0\v\xb3Ei4\f\x03\x1bw\xecE\xa3=\u9b54)\x16sv\x9fcQ\x14\xa5VJM\x1d;v\xe2\x06\x00\xe8v\xbb\xeb\xc5\xfcG9\xee\xbc\xf3\xab\xa1H\x1c\xbd\xe9\xa6\x1b?q\xc5\x15W\x94\xe3\xe3\x13h\xb7\u06f5b\xf7\xc5/\xfe\t\xde\xff\xfe\x0f\xe0\xfd\xef\xff ~\xe37\xfe\t\xbe\xf4\xa5?\xc5\xf2\xf22Z\xad\x0eZ\xad\x8e\x17\x1e\x89\x1f\x9b\x822\xf8\xb0w:\xe3\x18\x1b\x1bK\xb0rAy\x9ec\xf3\xe6\xd9\xcbv\xee\xdcq\r\x00l\xd92WfY\x16\xa5\u0100\xa3b^\x88\x03P\"7h\x12B@J\t\xa5\x14\xb2\xccm\xabw\xed\u0685,s\x03j\xe1y\xbbB*\x88,\x83l4\xd1\xecL\x82\xbc\x02Tp\xe2Sb\x00.-\xacq\x96\xa6<&\xc1\xde\xc3#4\x86\x888(\xa2\xfc\x9c_\x88\xe4\xf1\x02\x1d9^\xa0\xbeS\xdb\xcb\xd0;N\\$\xa4\xc3\xf5\x95$\x84H\u04c0\xa1\xa7\x8f\x19\xfe-\x95\xa3\xfb\x89\x967\xbdZ\xcd@\xad\t\x84^\xe4;1\xa2\x93\xe7\xbammH\u0671\xce^W\x80\xbc\x8d\xc1h\xbe|@3\xa8%\x9c\xeb\u2e02jJdaA\x92\xc1m\xd1\xedDB\u0407h\t\xa8i\x05j\xc9\x1a\x1e\x9e\x12i\bnA\xaco\xd9\ua2f0\xd1\x06\xa6(\\Wn\x8d/\xa8\xa6\xf2_I\xbe\b\x0e#bb@q\xa2/p\x98y\xa4*\xc2\xc2x\x13.\xf6!7\x96\x03\xben\xc1l06\xb1\t\xd3s\xbb@B\x80\u0640\xad_\x04\xb8Zu\u03df?\x8f'\x9ex\x82\x00\xe0\xe0\xc1C\xeb\x98\xf9\x8fr\xec\u06f7\x0f\x9f\xfd\xec\u007f\"\x00\xf8\u065f}\xff\xff\xb8\xed\xb67\xff\xdb\u05fe\xf6\x06\x8c\x8d\x8d\xa1\xd9lal\xac\r\xa5T\xbc\xfdC\x0f=\x84?\xf8\x83?\u0107?\xfc\x9c\xd2\xd3\xda\x00\x00 \x00IDAT\xf7\xf0\xa1\x0f}\x18\x9f\xfc\xe4\x1f\xe0\u0211g\xa1T\x13Y\xd6B\xa3\xd1F\xb3\xd9F\xb3\xe9\xba\xfb\xe0\x1f\xfe?\xa7\xc83\xa4\x14\xd1\xf90\xc8\xf6\x8d1\xba\xd9l\xa2,\xcd\x0e\x00\xb8\xf6\xdak\xdb\xe3\xe3\x1d\xdf\xd1V\x17\xf6\u0673g]Q\xf81\xd11]\xe1\x16PJ\xa1\xd9l\xa2\xd9l\xa3\xd1h#\xcb\xda\u0232\x16\x94jB\xca\f\xd62~\xf8\xd0\x0f\xf0G\xff\xe9\xb38\xe3\xe7\x00 \x82\x94\n$\\zK\xa3\xd3A{n\x1b\xa8\xd5\xf2\x83\xac\n\x12\x11p\x81\u077a\xb0\xc8\x19\x184\x05\n\xf6A\f\xd1\x1a\xb7^\x1c\xd2\xee\x94\xd2\xeb<\xc1Vb\xafK/\xae\xa6\a\x9a!Y\xb8l\u034d\nb\xdc\xcb\xe0}Z\x8eLW\x19\u0090\x01\x95\xc7\xc9[\x12\xa2)@-\t\x1a\x97\x80\xac\x9a\xd1:\uf15egQ\xa1\x17t\xb2\x19B\xb5\x93\xe2\xcc0\xbe\x0eJr\xc3Lz\x9e\u05c2*<\xc6\x19\x92M+g5\x9c9\x93.\x12\x95\n4\u0707\x90@c\\B\x8cK\x17\xe3\x96t\xe5<4\xba\x88 \"\x8fp\x8ed\x86-K\x18]\xbaa\xa7\xa9\xe0\x15\xd808\xf5 \u007f\xf2of\xeb\x87\xe7\x0e\xce\t[>\x1b\x86\xa1\\\xd9\xf4R\x98eQ\xb2\xb33\x1a\xaa\xd9\xc6\xc6\xdd\xfb\x00!\xa0K\rcu\x14+1;\x87\u04d5\x95\x15<\xf7\xdca\xed\n\xfb\xe2\x05Y\xcc\u0545vB\xbbw\xef\x01\x00~\xcdk\xae\xa5\xfd\xfb\x1f\xe4\u007f\xf4\x8f~\xfd\xb7\xdb\xed\xf65\x00\xdes\xef\xbd\xf7\xa1\xdb]\x81\x94\x92\xad\xb5d\x8c\x89)\u073d^\x1fw\xde\xf95\xdcu\xd7\xd7\xf1\xd9\xcf\xfe1\xae\xbd\xf6Z\xdc|\xf3M\xb8\xfe\xfa\xeb\xb0s\xe7E\xe8t\xc6 D\xe6\x8bc\xfa\x81\u05c9\xda\xf2\xef\xbc\x1c&\xd3\xfb\x8a\xb2'\x84\x10EQ\xa0\xd7\xebZ\x00\u0631c\xfb\x9f\x13\xd1B\x96e\x1bz\xbd\xea\x12x\xf2\u0267P\x96\x03dY\xf6\xa2\xf3N]\xe7,\x9c\x87\xf8\xdf\u025am\xb0\xb4t\x1e\u01cf\x9f\xc0\x91#Gp\xfc\xf8\t\x9c\x00cl\xfc\xa4\xff\xf0\x87?\xc4\xe2\xe2\"6m\x9a\x83R\xcaE\\\xbd\xd8\x12l\n\x94e\x89\xb2,\xdd\x16\xd3\x1b\xf5\xaf.\xfeT\xf3\x86)\xcb\x12\xcb\xcb+8y\xf2$\x9e~\xfai<\xfc\xf0#8x\xf0\x10N\x9e<\x89\xf9\xf9\xb38wn\x01\x8b\x8b\x8b\xab\xa0 !\x84\x8bw\x13TQ-\x85\xc0\xc4\xec\x16l\u06b5\v\xa2\u04c0!\x86\xb4\x94^\xe3\xae\fy\x86\a\x9d\xd70Z`0&\xd1\x17\x04E@K\xba`\t\xe1;+Z+K\"tb\xb6\x1a8\xf3*\xb1\xca\xf3\x15B\x1ajS]e\xe4\xcc\a>\x18G\x97C\x11\f\xa1\xbc[\x9f\u007f|+\xe0\x84Ha\xa0;&\u0717/\xb0\xc4\u0568r5.\x9e&\x85R\xa2~J\xb924\xf2\x8c\xe3z\xc0\xe4!\x06\x1f\xecL\xf0\xd1s<\xa2\x9b\xf7\xc3\xc1\x04\xbe\xaa\xa0\x1f\xbf\xc06%\u0318\x85Y\x04\xac\xa9\xcf\x17\x049\aFa\xbc{\xa1?5c\x1dN.\xd3A\xb1\x1fZ\x83\xc3{R\xedI\xac\xd10y\x0eS\x140\xba\x04[\xedZ\xfc\xe4\u06b1\xfe\x04+\xd3,[\xb9*\x02n\xb1\x94\x00\xca\xc4x+\xce\u0753E\x88\x03'\xde\xc2\xc2\xe1\xfd,,\x1a\x13\x1b1\xb1e\x17z\vagY\xf1\u0549\x88\x8a\"\u01d6-\x9bw\x00\xc0\x9f\xfe\xe9\xff\xd0G\x8e\aV\t\b\xa3\x91\xb5'1\xb5\xfd2\x9c~r\xbf\xff<+\b\xa1\xc2g\x99\x8a\xa2\xc0\xec\xec\xecnf\xdeBD'\xf1\u0084\xd2\xf5b>\x8c\xd9\x02\xe0\xdf\xfd\xdd\u07e1\x8f}\xec\xe3\xfc\xeaW\xdf\xf0\x97\xcc\xfc\xe6\xff\xfe\xdf\xff\xeb\xffv\xcf=\xf7\xfc\xd2\xe1\xc3G\xdfx\xfc\xf8\xf1\u01a1C\x87\xc0l\xb5\x94JJ)I)\aKh]\x87P\xba\xdd.\xba\xdd.\x80\xe3\x00\x80\a\x1f\xfc\x01\xbe\xf1\x8d\xbf\xc0\xb6m[\xf1\xa67\xbd\to{\xdb[q\xcd5\xd7`\u06f6- \x1a\x8b\xf0B(\x80U\xd7N\x95q\u03e8\x8e\x87\x19\x8dF\x03R6\xb0\u007f\xffw\xf1\xc8#\x8f\u059eO\xa3\u0450y\x9ek!\xe8\xa0\xffy\xf1\xab\xbf\xfa+w\x18c\xaf\x96R\xc6b;??\x8f/}\xe9\u03d0\xe7\x05\x1ez\xe8!\xfc\xe0\a?\xc0\xc1\x83\x87p\xee\xdc9\xb8\xb0k\xa0\xd9la|\xbc\x83\x89\x89\t\xb4Zm0[\xcc\xcf\xcf\xe3\u0109\x93\xe8vW\x90\xe79\xca2\x9c\xbf\x19\xda)P\xf4\x1c\x0f\u07ff\x18\x8a'\t\x01!\xa4S\xcdI\x05!\x1c~EF;xE)\x90\x14\x98\xb9x\x0f\xf6\xdc\xfcV\xa8\xc64\xfa'\xcfC\x90\x80\x95\x1e\u03b0U:\x1bK'\x19g\x02d\u0260\x15\x03bF1.a\x05\xa10\x8c\xd202a\xd1\xca\x04Z\x8a\u0410\"F@\xba\xady(h\xec|\xae\x87\xdc7WA\x15\x9e\xed`9\x91\xfb\xd7\xec\u0513n\xd8\xd3\xe10\xa9\\\xa1X6\xe0\x81\x01t\x05MXCN\x8cSX\xb0P0\xd2CM\xab\xb2,|a\f\x16\x05\xb5\x1a\xef\u07cb\b\xf7\xa4[\xfe\xba\\?-\xd6a\x14\x11\xb1\xf1\xe1\xa0\xe9\xb0\xc8P\xeaT\xb8\x8aM\tm\x19}m\xd1-\x19\xb6k\xd0X1N\xdf\x14\x16\xaf`\xe3\fr\xe7h\x18\xb4l\xdc\xef'$\x023\xd1V(\x8e\xa7L\xa6\xe9\xae\x04k\xdc\xc0\xd3\x149LY:Z\xa0\xc7\u016d\xad[\xe0Zk1l\x04C\x9c:(8\x89\xbf{\xc1\xb8\xc2\xe6\xfd\xfb\x1b\x94\xa3a\x12\xab%\xa0\xa5\xff\xbb\xa2\x84\x18\xeb`|\xd36d\xcd6\xcaA\x1fBH\x90l\x00\xa6\x04\xc3\xc0\x18\v\xa5\xb26\x80\v6\x13\xf4\x82.\xe6\xe1\xf8\xd8\xc7>\u039f\xf9\u0327\xe9\x97~\xe9#LD]\x00\x9f\a\xf0\xf9;\xee\xf8\xca\a\xbe\xfd\xed{\xfe\u0791#G\xde\xf6\xec\xb3\u03e9g\x9f}\x16\x83\xc1\x00D\x8c,SPJ\xc2\x18\x05c\u071bQ/\xc8\xce3<\xcfs\x9c?\xbf\x80\x83\a\x0f\xe1+_\xf9*^\xf3\x9aW\xe3u\xaf\xbb\x15\x97_~9\xe6\xe6\xe60;;\x8b\r\x1b\xa6166\xf1\xa2\xceY\xeb\x1c_\xff\xfa\xd7\xf0\u06ff\xfdoq\xe0\xc03\xd1\x1e\x16\x80m6\x9b\xb2,\xcb\x03\x9b6\xcd>\x19n\xff\x8aW\xbc\xe2\xf4]w}}U!\xfd\u0527>\x8d?\xfc\xc3Obqq\xf1y\x16=8\xfa\x9f\u007f\x8c\x88iz\xe8$\xfc?\fR]\xb3\x13\xf2U\xd9\xc3.\xbc\x9a\xa7;bq%\xe1L\xfe\x11\xd9B\"^_\u0194\xf1\x82\x93J\xa23\xb5\x01\x9b\xf7\\\x8d\xab\xdf\xf5al\xdc{#V\xe6{\xe0\u0702\xd8\xfb\x1bJ\xc0\x12\x83\x02\f`\xad\xc3.|\xbc\xa7`\x8b\u018a\x1bD\xe6\xe3\xd2\xd9\xd22PX\xa0\xc8-\xba%\u0412\x16c\x99@S\x0e\x85\v3\xc5b\u00a3\xe4\xf7\xb4\x1ax\xb1pp\x81\xa5\x91\xe4\x16\xf7\xba\x19\xef\t3.\xdd\xcfK\xeb\x8a9\x85N\u0531G4\xbb\x8eU-\v\xf0\x84t\v\x95M\x89\x1c\xf9\xe4S;F\xe3\xda\xf5\">\xfc}\x1a1\x97B)\xe1{_\xb8\xf9\x85HzD\x04\xa9T2\xfd'\x80\x84\x13\xffd\x19\x1a\xad1\x8co\u068a\x99]\x97c\u64bd\x98\u06be\a\x9d\x99Y\xb4'\xa7\u045a\xd8\x0096\x01-[0B\xc1\x88\x06\x8a\xdcb\xb9?@\xd6+\xd1.Qc2\x90\xf5A\x04\xc1\xf1\xce\xc0o\xe3\xb9R\x1b\u00b5\xca\xd9\xc0\x80\xc0\xc8'\x15LC\x80\xa9\u2a57\x86Q\x96\x8c\xbee\x8cenP\x9aIJ \x16\xdfuS:(\xad<\xae\xeb\x905\xd5\xcc\x0fC\x17\xccL\xae`\xfb\xdd>k\x06V\f\x88\xbdp\u01ba\xc1\x9f\xf10\x06\xc1y\x8c\xe8\x9c\xc1\xe7J\xa0\xb0\xa0I\x05\xd5\x10\x88\"R\xaeZ\u22bf\xed\x9e/\x0f\x85\x98\x86\x1al\x93?c[)+\x89\u073f\x1dN\\\x87t\x1c\xb3eH?J\xee9\x15\x86\xd1--\xfa\xda\xc2\xf8\xa1)\t@\u632co\xe2L \x0e\xab\xc3\xceE\x00d\u072e\x89\x19\xd0\xd6u\u045a\x19\x12\x80\x9c\xc9 2\x01k\xbdM\x82p\x85\u0616\x1a\xba\xc8aB!\x8ftD\xed8\xde\xc1{\x85\x19ll\f\xa7\b\u0316`o\xcb\x1e\x9b\x93\x82<\x1f\xdci\x15\xb8t\xb7\xa3j\xb5\x84\xa7\xa0\xc0\x92t\x1d\xb9\xa8\x16n\xf2\u05c71\x06\xb2\xd9B\u0599\x8a\xf7\x97\xc2TB\b\xf4\a\xc5\x00\x00^s\xfd\r47\xb7e\xbd3\xff\xbb:\xee\xb8\xe3+x\xdb\xdb\xde\xc1\x0f=\xf47\xf4\xe0\x83\x0f\xca_\xf8\x85_4ss\xdb\x1f\a\xf08\x80\xcf3\xf3\xb6\xff\xf6\xdf\xfe\xcb\xdc\xe1\u00c7ggf6\xbe\xe9\u0739\xf3;\x1ey\xe4\xe1%)\xd5E\x1b6lx\xeb\xc1\x83\a\xd5\u0463G\xb1\xbc\xbc\x82\x95\x95\x15,//#\xcfs\x0e\n\xcd\xe1\x8e\xd5u\xdf\x05\u039c9\x833g^\x98\x16\x18:q)E\x847\xac\xb5\xbcy\xf3\\v\xf9\xe5{\x06\xb7\xddv\xdb\u007f\x01\x80\xc7\x1e{\x98\xf6\xed\xbb\x86?\xf8\xc1\x9f_z\xf2\u0267\xfe\xea\u0211\xa3\x1fx\u4447\xd1\xeb\xf5G\x16\xde\xf4\xbc\xc2\xf7C\x85\u007f\xe4\xdf\x11\x11Z\xad\x16\t!\xe2\x1c!\xfd\xbb\xb4\xf8K\x95\xa13\xbd\x01B5AY\x86\xf6\xe4\x06\xcc\\t\x19\xb6\\~\r6\xee\u078b\xf6\u62d0M\u03601>\r\xb4\xc6\xdd6\u057a\xf3\xe8\x97\x1a\xa56\xb0\u0682M\x0f\xb64\x10\xc6uy\xc2$\x92\xf9\x9a\xf2\x93]\xa7g\x03\x8c\xe0)e^\x90\x130c\u0577\x00k\x14\x13\n\xa6\xe9\v\x9cE\xbc\xb8\xf3\u04a2,\x81AF\x18oJ\xb4\x1aU\xa7\xce5x\x82V\xe1\xc4\xe9\x8bfb\x91\xe4\x88)k\xc3\u0425+.\xc62d\xcfB,\x1b\x90u\x85-\x868\b\xef\u07c2D\xe0h\x00\xbbl\u07023\xa9@\r\x82\x02\x90\x81\x90\x81#\a\x9c\xfd\xf3\x14*a\xa2\xa0\xdaYp\xbaCH\xb6\xfa\x82\xea\u04c0\u06ae$\xb0K\xb8>-\xd0\x06\xe8Y\x87\x8b\x97&Q\u0252\xdf\r\xf5-T\xe1vI,\xfc\xfba\x00\xd2\xd6\xe3\xfc~\x87\xe1'\xa8\x82\x00\xd6@I\x8cr\xd9@\nB\xb61\x83\xf23\x83R\x1bp\xe9\xf0q.\x1dk\xc5j\r\xa35\xd8w\xe4)\xac\xc2\u0182\x8d\x89\x83P\xa7\b\xe5\xa4kO\xb6\x1b\xecp&1\xb0\xb0%;s-\xef\xfbB\x11\xa7r,\x1f\xaey\xe1x(\xce/ \xa42H\xcflcx_u6\x00;\xe7\x97M\xb3\x9b'\x01`\xff\xfd\xf7\x99\x93g\x17\xd6\a\xa0\u007fW\u01fb\xdf\xfd\x1e\x8f5\xbf\x8a\x01\xe8\x13'\x8e\u04b7\xbf}\x8f\xba\u77bf\x12\x9f\xfc\xe4\xa7\n\":\x1e&\x9d\xcc\xfc\r\x00-\x00\xdaZ\u04fe\xf7\xde{7\x1e8p\xa0\xdd\xedv_\u007f\xe4\u0211\xf7?\xf6\xd8c?q\xf8\xf0\xe1\xa9n\xb7K\v\v\xe71\x188_\x14\xb7]\x17\x15\xc5\xcdo\xfd\xa8>?\x1b\x8aJ\xab`\x8e\xa4Sf\"A[\xb7n\xa3\x9bo\xbe\t\xb7\xdcr\u02ff\u0677\xef\xea\xbb\x01`\u07fekB\x90s~\xd7]_\xfb\xbd,\xcb\xde=>>>\xfe\xc0\x03\xfbiqq\xe9Gz-\xaa\xee_\xa1\xd9l\x12\x11\xa1\xdf\xef#\xcb\x14\x8f\x8d\x8dQ\xbb=\x06\",l\u07fe\xddn\u06f6m\xfe\xfc\xf9\xf3_\x1b\f\xfao\xfc\xde\xf7\xee{e\xea\xff\x12\x1c\xe1\xc6&7\xe2\u019f\xfbUl\xdc\xfbJ\xa09\x86\xf1\x99-hM\xcd@\xb6;0\xaa\x05C\x02eYb\xa5,\xa1\xcf/:\xb8*\xf0\x95\xa9JI'\x02\x98\x04Di\xdc@3TTI\xd5\xf7\x9c\x14\xf6\x00lp\xc5\xf1vX\xad\xc3iI\x00j`AF\xa3\x98\x94\xd0-\xe1=^b\x1d\x85\xb5\x8cA\xc1(5\xa3m\x04&\xda@K\xc8\xc4\xe3|m<\xbc\xb4\fm\x19\x03mQ\x9a\nk\xb6\xceb\x1b:wb\x16\xa9\x19\x8d\x15\vU\xb2\x87\xa1\x82\xa0\x06\x95\xe8\xa66\xcfd\bKP\x03\xbf\x18\x8dK\x14\x19\x01\xdaB\x18\x8bL\xb8\x9d\x84\x92\x04\xa5\b\x92\x9c\u06b2\xdaI\x84\xe2\x9d\xf8\x8cp`\xab\x84q\"\xc7\xcf)\xaa\x97..H\xe9B\x95kF\xcfX\xe4NG\x19\xcd\u0442Y\x95\xea[\u0201\x89wB\f@3\xa4\xf1,\x16\x03\b\xe6\x88\xd4 @\x16\x9eQd4C\x9f/Q\x12\xa31)\xa1\xd8\xc0\x16\x8e\xb1\xc2Z\x03F;\uee9fc\xc1\x98\xaa\x90\a>\xb9\x87A\xd9$\x1cs\xb6\x91c\x8e\x80\x99\xb3\x05\x97\f;0@a\"}2:4\"\xb11`@X\x86%\xaa\xbbf\x06\xdez\x80\x1d\xbdk\xa21\xda)G\x01\xc7\xcc\xf2\xa1\xcf\xd5\u02b7\u0799\xff\xffrl\u077a\x83\x01\xd4\xd2\x1c\x9e~\xfa\t\\v\xd9^\x90\xe3\xa2\x05\v\xc2\x12@\xa8\x92\x8f\x03\xf8\xf4\xf1\xe3G\xf6\xfd\xf1\x1f\xff\xe7\x9f9|\xf8\xf0\xcf=\xfd\xf4\x81\xd9~\xbf\xbf\x19\x80XZZ\u00993g\x90\xe79\x8a\xa2,=.-\x84\x10\x94b\xd1\u00d0\a\xbb\xc3Z\u02d4e\x99\u06b0a\x9a\xb6n\u074ak\xae\xb9\xfa\xec{\xdf\xfb\xde\xdf{\xeb[\xdf\xfe\u007f\x00\xc0\x1f\xfc\xc1\xef\u04ef\xfd\u06af\xf3\x17\xbe\xf09\xba\xfd\xf6\x0f\xf2\xdb\xdf\xfe\x8e\xfb\xfa\xfd\xe57\\t\xd1\xce\xffs\u01ce\xed\xb7<\xf1\u0113\x8dS\xa7Na0\x18@)\x85\xb2,K\xa5\xd4\xf2\xe4\xe4\xa4PJ\"\xcb\x1a\x12@\xbe\xb0p\xee(3z[\xb6\u0309]\xbbv5\xa6\xa6\xa6N?\xf5\xd4S\xff\u03d5W\xee\xed\xddt\xd3M\xadK/\xbd\xd4LMM|\xf3\xaa\xab^\xf9\x8c?\xbf\xe6\xdf\xff\xfb\x1f\xfe\xcf\xdf\xf9\xcew_\x19,k\x03\x9c\x026 \xa9\xb0s\u07ed\xd8y\u02ed\xe8\x19\x86\x06A\x1bF^\x14\x18\xf4s\xb05\xb1\xd0H)!\xa5\x88\x1d\xec\xaay\x1e[d\x85u\x83&O\x13$\x9bx\v&xFJ\x19\x8c\x9e\xdb)\x89#p\xa7K\x8b\xe6\x12\x83\x8cB\xd9\x11\xb1[Mi\x88\xdaX\xac\f\x18%\bc\xd6A/JT\x9d\xab\xf5x\xb5\xb5\f\xc3@a\x18\xb9\x1f\x06\u06e4\xcb\r\x1d\xb01\xae\x90\x90\x01T\x9f]!\x0f#\xa9\xcdU\xfdBg\xd8-p\xfd\u00a2[X\x18\x01\x88L\u01a4\x9ep{\x953\x1a=S=\a\x06\x84f\x90\xf6\xbb(\xeb0\xf4\xf0^\xa4\xf3\x06\xb7\xbb\xb2\xb1\xf8\x17g\v\xf4\a\x80j\x1ad\xa6pE\xdcxz\xa1\xadb\xe1\xc2\xc03\xf8\x98#t\xe2\xa6\xe2\x92G\v[\xe3\xfd\xcd\x03,ZZ\x98\xae\x86\xcd\xdd\xcf\xe3{b\xc9\u0767_\x04c\xb0\x89\x00l\x18\xe4\u05f6#\xc2\x0f_\r\xa4Tn\xbeV\x16a\x17\xc0\xadV\v\xcdv;\x0f\x9bo\xb7\x8f\\/\xe6\xff\u04ce\xcb.\xdb;\xf2\xe7\xcf<\xf34.\xbd\xf4\xb2\xf8\xefm\xdbv>\x06\xe01f\xfe\x97\xf7\xde\xfb\xdd\xeb\x1ex`\xffM\v\v\xe7_\xf5\xec\xb3\xcfN//\xaf\xec[^^\xdeND\x9ds\xe7\xce\xe1\u0739\x05\xf4z\xbd\x04/\xaf\x8a\xb9\x10\x8e1\xd2\xe9\x8ccjjRNMM\xa1\xd9l\xf6ggg\x0f]u\xd5U\xdf\xfc\xf0\x87\u007f\xfe\xd3ss[\x1f\x03\x80\xf7\xbd\xef\xe7h\u04e6\x19\x06\x80\xdbo\xff \u007f\xedkw\xd2;\xde\xf1Nn\xb7'\x1e`\xe6\u06ee\xbb\xee5\xb7\xdfu\xd7\xd7\xdf\xf5\xdd\xef~\xaf\xd9\xedvinn\xae\xdbh4\xbf{\xf3\u036f=\xf2\xaew\xbd#k\xb7\u06f0\x96\x1b\x9dN\xe7<\x91\xba\x87\x88\x06\xcf=\xf7\x1c\xee\xbb\xef\xfe\xf8\xbc\xbe\xf5\xado\xe3S\x9f\xfa\xbfG\x12\x8c\x17\x17\x97D:+H\x9b\r]j\fV\xfa(\x16\x80>\xaf@+G\xb7\xd3\\\x9f]\x06\x88\xe4\xf9\xecE\x84f\u021c\xbd\x89Q`\xa9$\x86F\x89\xc9\x16\xfb*\xcabd\xc4g\xac\xea\xc2\x12\xa8`4\xac\x06A\xa2\x1c\x93\x18\x8e\xbe\x16\x9e\x9fg\xc0X),\x06\x06hJ\x82\x0f\f\x82\xb1\x0ek7\x89\xe4=\xb0A\x86\x1e\xce\r\xf0\xfc\u03f2\x82\x91\xe5\xbe`\t\xf7\x1aH\xcd\x0e~\b,\x99\x94\xefg<\u03ac\xdc\x0e\x83\fC\r<\u04e2I(%\u0570m\xb0\x13\xe7\x14\x96=\xd4\xe2DS\xd2\xf3\u01a5p\xcf\xc1Y\n\xa0bQ'\x9c\xf2\xb8T\xfa\x81mQZ\xf4s\x8b^\xcen\xe1 @HQ\xdfa\x12 \r\x90\xf5\rD\xe9\x19 \xcc\x0e\x177\u026e*\x95\xd8&\x19\x9b\x1c\x02 `\x00m\xc1\xc2\x02\xb9\x81\x19\x18\xf4\xdb\x06J\x19\xb4\xc8\xe1\xe9\b\xbe*1\x1e\x8e\xa3\xdd-\x12qP\xc57\xf7\x81\x15\x89X\xc8\x18FQX\xe8\xae\x06\xe5\xa6fU\x1f\x98J\x14w\x1d\xceg\x80-\x03\x86\xc1B\xfa\x1cU\xf6\r\x84\xdbY9\xb7\xc6\x02\xc2\u04c3\x1d;\xcb\xdd\xf1X\xa7\x83\xe9\r\x1b\a\x00\xf0\v\xbf\xfc\xab\xb4u\xd3\xf4zg~!\x1c\xa1\x90?\xf6\xd8\xc3x\xcb[\u0789\xa3G\x0f\xa7\xdd\xf5\xf7\xfdW(6\xaf\xf8\xeaW\xbf\xbc\xf7\xe8\xd1c\xaf}\xf0\xc1\x1f\f:\x9d\xb1\xab\x1a\x8d\u019e\xc5\u0165\xb2(\n\x18\xe3\x042Y\x96\xa1\xd5j\u0271\xb16///?\\\x96\xfa\xe8\x15W\\Q\xec\u06f7\xf7\xe1w\xbd\xeb=\xf7\x12\xd1s\x1f\xff\xf8?\x03\x00\xbc\xf7\xbd\xef\xc1\x87?\xfc\xf3\x1c\xa0\"\x00x\xc7;\xde\xc9\u007f\xf5W\xff/n\xbd\xf5\x8da'\xf1y\xffU;>\xf3\x99\xcf\xfc\xad\x9f\xf7\xa1C\a\x82]BK)IB\xb8\xc1\xdd0\xe8`u\x89\xbc\u06c7^\xd10\xd0>\xb6\xcdC\x1d\x9c$\xb1F\xaa\x9cg\xba\xa0^\x1c\xc8\x02\xaa\xe0\xd8\xe5\x11\xfb\xa1\x19\b$\xb8\x1e\xda3\xd4\xd2\x13\xb9A\x1bQ=U,\x82\xd1\x02\x10\x1ah,\x1b\xc0\x00&\xab\x84\x8eQ\x96\xe2\x17X\x80}\a\u0315\xfd\xe9pr\x19\xd5a\xb3d\"\x8a #R\x1a\xc8r\x1b!\x05b@\x1a\xf7\xfc\xaa>\xad\xae\xd4$\xf8\xae\xd6\x12\xac\xf4E\xdd\x12Tn\xd1,\x9dK\xa1n\xb8\xd2#\xe06G\x94\x88?K\u02c8\x1a[r\x9d\xb9c\xbe\xb8b.C\x81\x17\fEa1r\x85\xbcdF^X\xe4\x03\x8b\xbc0\xfe\xf5&\a\xfb\xd0\xea\x18S\x99[\x88\xbc\xfa@\x90\xf5\x1c\xf2Z\xa6\a\xd5\xf0*f\v\xd6\xd6\v\xe8\r\xac\x1fb\x82\f\x98\f\x044\xa8\xb0\u8d41\\0Z\x02\xf0\x96\xe9\xc9{jcQG*\x18\x8a\x85\xdc\xcd*\xc2\xe3j\x03\xf4\xfb\x1a\xbao \n\v\x19\x86\x99\xfe=g\"\x18\xb8\xc5UD\x18T@\xa02\x1b\v\x10Tx=!\x04t>@\xd1[\xf2\xbb\x00\xe3rA\xfdy\x8e\x8fOb\xe7E\x17K\x87\x02l\xbb \xeb\xda\u02f2\x98\x87c\u07fek\xe2\xf7\xa7N\x9d\xc0\xdc\xdc\xd6Q\uc387\x00<\x04\xe0\x8b\xbe\xb8w\x00\\\xe2\xe1\x9a\xe1\xfeQ\xfa\x06\xebq\x1a%3\x04\xf0\u05b7\xbe\x15\x9f\xf8\xc4'\xf0\xda\xd7\u07bc\xeaw\xb7\xde\xfaF\x1c=\xfa\x1cv\xec\xb8\xf8E?\x97\x83\a\x9fF\xa3\xd1x\u07bf\xf5\x85\xdcw\xa0>\x1e\v\xa6>\x00\x00\x90\xf7\x96\xd1]8\xeb@\xabA\t\xce\b\xba)`\xd9\x0f$\x13\x18\x82\x13~\xb5\x1drV\x92\u05ba\xe2g\xfd\xb0\xcc\xfa\xa2\xe7)\x11\xf4|#\xdbT'\x13\a\x9d\x9c\xdc\xd6A\x17T02m\xc1\r\x81A[\xc0\u02aa\xa0\u04c8D\x1c\x1e\x01y\xa64>\u02d1\u679c\n\x83J\x8b\xac\xe7\xb0\xffpr\u00b3o\xc8\x0e\xe1\x1a\xc3\xd6\x00\xfe\x8eC\u0383\x95N %4\xa3\u0673 \x16(\x9b.FO\f\xf1\xdf\x05\ra\xfbn\xd6\a\xcd\xd1\xd36\xce'\x94\xa0\x1ac\xc70\xc3h\xf7\x05\x10\x04U\\\xc1\x9a.\u04cb\xb4T\xdf\r\xab\x01\a\xa5\xb8E(Y \xd9\x01O\x96C\x87\xec\xbai\x1b\x92~\x9c\x91\x80\u01f6\r\x98]3 4C\x82P6]\x91-\x89\u0410\x80\"\xe7\x9e\x19\xb8\xe2A\xbe\x1f\x86\x9fV\xdb8\xec\f_\x85\xb6\xe8\r\\\u01df\x95\xbe\x90'\xde6\x14\x06\x9d\x91zX\xa7\xc2:h\x8f\xa3\xe5\x04E\xc30\x05\x9d\xf7\x90/\x9fw\x9b\x03S\x82\x8d\r\x8c(j\xb7\xdb\u0631}{\x1f\x006\xcdlZ/\xe6\x17\xf21\xaa\x9033\xee\xbd\xf7\xbb\xf4\xe0\x83\x0f\xd0\xd2\u04b2\xbb\xb6\x9ch\xe9\xe1\x17\xba\xbf\x8f\u007f\xfc\x9f\xcaM\x9bf055\u016fz\u056b\xf8\xc6\x1bob\"\xc2\xddw\u07cd\xbb\xef\xbe{\u037f\xfb\xdb\x14r\x00\xb8\xe4\x92\xcb^\xd4\xed\x83#b\r\xef\xf7\xb4\x0f\xf2\xdd9\x9b\x12\x18\x14\xe0e\x06\x93\x02\x87|DO\u007f\v\x85Cx\xdb\u046a/\xa5\xd8\xe9\xa9\xc2\xe3\xab~\xcb.\x18#r-\xeb\xb5/0Z(\xf8\xb7\xc8\x04\xc0\x0e\xd7f\x80\xa8\x85S\x916z.\x95=\xefH\x87Q\xfb.7\x8c\aG\xfa\x13&4\x97\x10~\x1c\u050b\x14:r\x02Dn\xa1V\f\xd4\xc0-L\xc1cE\x9a\xb4`\x8c\x1a\xab\x0e5\xf8\xec\u0395\xe0pzA\xfeu\xe9\x19\x10\x00=&\"\x85e\x94\xab\xef0\xf3&\x8d\x1ce\x8f\xfb#\x11\x1aU\x8f\x9d\xec\x16\x86m\x81\xc3\x0e\xaao\x1d\xa7\u0727jS\xc4\xcc#\x01\xdf\x15n\xad\xc1\x1e[\x8e\x8a\xe2\xf0\x86\x04\vZ\xdf\u055a@Q\xb2\f\x05\x02\x93\x80V@\xdfZ\xe4%\xa3)\x81\x86\x00\xa4\xd7\xe4[c`\xb5\x01\xeb\xb0X\xa0\x1a|ZF^\x18\xf4s\x03S2\x1a\x06P\xa1\xb3\xf0|Q\"\x87\x93\x93\xb7i\x11\xf1\x9d\xaf\"\x9d\xd3l\xec h\x12B@*\t[\x0e\xa0\a]\a\xcf\x19\xed\xf1{a\xa5\xca\xe4`\xd0??>\xde\xf9\x1b\xbf\x1b\xe1\xf5b\xfe\x12;(j\xa2\xe3\xf5d\x9f}\xf6\x19ZYY\x11\v\v\xe7\xbdO\xca\x00B\b\x8c\x8f\x8fcbb\x02\x13\x13\xe3\x18\x1f\x1f\xb7;v\\l.\xf4\xe7\x96\n\x8d\\\xf1\x930\u05a2=\xb5\t\x9d\xa9Y\u75e15\xa8\xcb\x10\xc2\u008c+\x80$\x94\x94h*\x89\x8er\xe2\x96\xdc\x00\xb9q\x8d\xbca\x9f#i\u06337\xb8\xea\xf4\xc2\xe0\x93it\x15O@\xea\xa0t\x8c\xc6Tr\xa8\xa0yqQ\xb0\x9c&\x06\x1a\x03\x87e\xe7\x1d\xe1|Q<\x9f\x8f}g&\x92\x87K\xad\x188\xed\xf6\x87\x02\x96\x85f\xa8e\x03\xd5s]k\xb0\t\x10\x9aGx\x82\x8f\xf6_IU\x9b\xe4\xbbHa\x1cvm\x15A0\xd0\xe8:\xb8\xced\xfe\xb9\xda\u054b\x01\x0f}\x9f\n+\x13K\x97:\xc7|8\b\x9a\x87\"CAn\xd1\xed\xdb\xc8\x1b'c\xe12\xe5\x9c\u0692|\x00\xb2\xb5\x16\xec\xbd\u01a3B3\t\x99p]9;u\xa7\u05700\xb0d\xbdI\x8e/\xaem\xf2\"+\xa0o\x19\x05\x80\x8c-\x945\x10\x9c\xb8$\xa6P\x8e\x05\xf2\u0720;0\xb0\xa5Ef\xfc0\x99\xa8\x06\xd5\t\x1b:\xf2J5\x15\xf8\xe8Lu\xfc\x8c\u00c4]H\a\xcb\x18\x8d\xb2\xb7\x04\u05b9\xeb\xee=\xc3\x06\x04\u03b2\x06\xc6\xc6\xc6\xe6o\xbd\xf9\xc6S\x00p\u026e\x8b\xd6;\xf3\xff\x15\x8e]\xbb.\xe5:6\xf1\xd2<\x94R$j\u05a0.H\xc2\xe8\x12\u04db/\xc6\xcc\xd6Ka\xf2\xbe+D\x85\x81Xf(\t\xa0\xcdh\x801\x91\tlk\x13\xba\x86p\xaa\xcfCb\x14@\xf6-dnk\u04514\xf4\x1dV\xf7\u02a8\u0665V\x81\x91\x80\xf1\xe1\xcfI@M\x10\xda @\x1d`'.bF.\b\xdc\xf0\xde,\xb6j\xbd9\x8apFy\xc2r\xec\xc8\x1d\xf7\x9d\xa1z\x06\xaak \x8a$W\xd2\xfa\x0e\x9b0zQJ\x8a:y47\x9a\x81y0\\\xa4\x18\xbb\xa7j\x8a\x9e\x81\x96\x84\xa2\xe3\x02\xaf\x89\xebU\x9c\xd6\xda\x04\xd0j\u007f\x95\xd5\u007f\xc3\xf5\u074f\u01cdEi\xd1X\xd1P\x03\x03\xd2\xd6\xd1\x04=\x93\x04\x91.h\x00\x1f\xda\xc06\xfcn(\b\xc3\xe3\xe76t\xec\xde\x13\x9c\x03\xe3F\xc03b\x04\xd0\x12Q,Uh\x8b\xbc\xd0 \xb6h\b@\t\x06\xac\x89|sk\x19EiQ\xe4\xce\xeeZ1A\xf9\xd7\xce\x18\x87\x8b+\x12n\u0776\x9e\xba\b\xae\r\xf6\u067f\xa7B\b\xb0p\xb9\xa0L\x02\xf0\xcai\xa9\x14L\x99\xa3w\ue933\x15\xb0\x1a\u0194N\xf0\u0116'g&09>\xf6\xdc\xc6\u0249\xc7\x01\xe0\xdaW]\xb5\u0799\xaf\x1f\x17\xcca\a\x83\x81\xa6\xe4\xc2v_\x0ev\x99\u06b4\x03\xe3Ss\xd0y\x0e\xc1\x16L\x04QZ\xd0J\xe9\xdc\x0e%\x81\xacA\xc9\n\xda\xc2\xcb\xdf\x13\xcf\x13\xed\x04\x1c\x94\xd0\xdb\xc8>_\xe1\x1b\xb6{\xad\xb7\xa1\x01g\x0f\t\xf1\x9cH\x1c\xa9\xb6\x89v\x9445`@\x18\x94\r\x11;\xfapq\xa7\xdd\xfe\xa8\x90y\xf6\x95\x91\xc8q\xdaU\xdf@\x1a\xae\u01fc\x99\xb5h\u018c\x11%tu\xdf\x1e-\xbd9\x0e\x14\t\x0e\xda\u023a.R\xaf\x18\x97\xe0\u0107\x9cj\x03\xe7:\xee\xcfo\xaa\x82\x1e,i\x13\xf1N\x98'T\x01\x13\x15\x8e\x0e\xb6\x91Ji}Q\xb6l!\xfa\x16\x86\x85\x8b\x04\xd4\x1e\x1b7\xae\x1b\u05de\xad\x12\xe4\xf9\x96\x19\xd68\xe6\n3#cB\xe6\xc5d\xde\xe38J\xf2\x03\xccRE\xcbzk\x83\x10q\xe4\a\v\x04\xf2Fo\xce$\x8e\x84\x80P\r\x94+\xf3X9y\b\xd6j\u8c80\u0445\u007f\xad\xd8n\x9e\x9d\xc5\xd6-sG\x88h\x05\x00v]|\xc9z1_?~\xbc\xc7\x03\x0f|\x1f\xaf~\xf5u\xc8\xf3^\xb3(\x8a\rU\u01a8\xb7r\xb2\x16RJL\xcelA\xa62\x94\xdd~\xf4\x90\xb5\x02@nA+\x06F\ttK\v\xddw>&\xa5\xe7f\a\xbf)\x99[\x88\xc2\"u\x06\xac\xb7\x94#@s~\xbei\xf6\xc3_Q\x00\x00 \x00IDAT\xa8\xef\u01bds\x96\x15nX\u82b7\xdb-\xb3\xad{9e9C.\x1b\xe4D\xce\xcf%\xe9\xc4y\x04lQ\xc1-\xde\u042a\xe4\xaa#\xb7U[\x1d\xed\x06\xaa\xdc\xf75\xbcP\xd3\u0166\x8e\x9bG7\xc6Z:}\x80_\x18\x8d\xae\x06\xc0(\xc6\xd5\xd0b\x94@7#\x1f\xaf\x1a$\xc6\xf5\xd1X\x87q\x97\xdaK\xdb\x19$\x01+\x04Ta!\u03d7@\xee=\xe0\r{\x01\x8f\x89\x1e(\xd1\x0f,\xfc\x8c\xab\xc2\x1e\x87\u00fe\x98W\xe1\u02ee#\x8f\x03\bN\xa8\xa9\xa5\x81\xb0\x06Zy\v\x8a\xa8nr\xf7\x19\xbcj\x8cGA\x02\xe2\xa2\x18P\x815\xe4\x1f[\x10A\x06;\x84\x04o\t\"(x\xbfu\xeb\x19.\xcc\x16\xde\u0165*\xee\xc2\x05\x90\xaf\x9c:\x8c\xe5\x13\x87\xc0\u01a2\xcc\xfb0F{\xc1 \x1a\xadV\x13\x97_~\xf9\xa3\x17\xfcn{\xbd\u013d|\x8e\x83\a\x0f\x11\x00\xfe\xcaW\xbe2\x93e\xd9\xcd5?\x17r\x17Tsl\x12\x13\x1b\xb6T\xb8\xa5\xb5`\xeb\xd3\u7640\x9e\x86Q\x80!\x89\xc2\xe3\x00%\a/oDY\xb50\x88\xb1[\xc18k\xb4x\xfe\xf9\x8a\xfcj\xfbB\x0e\xf0\x8bq\x8c\x10p\xc5(a\xf2\xaaD?DT\x03\v@c0\xa1`\x9bT\xc1\x11C\x0f\x1f\x9d\xbcC!\xb7N\xce.\xca\xcad*.(5N>\xaf\x02Uj\xb0C\xba\xe3H\"\xf0j\u05b5\f\x10\v\xe7\xaaH\xd5.&\xeb[\x80\r\u028e\xf0\xe6V\xd5\xcea\xd8J\x97B\x18r\xf4\xff\xae|Gl\xaea\xcb2B# \x02\v\x82*-\xb2%\r10\x91\xe7M!<\u067f\xef\xa9t\x9e\x83\x978\xd8u\xec6\xc9w\xa2Du\xe9\xcdZ\xc2\x10;\x1ac%\xd9~\u04baA\xb2\t\x1cO;\x94\xfb\x17T\xa7\xfe\xf5\x94\xccP\xda\x0f\x9b\x03\x87\u072b9\x11\xe9\x96>\xc0\x82R\x9f\x1a\xe1\ny:\xbf\x00E\xd5.\bP\xcd&t\xd1\u00d9\xc7\xefE\xb1\xb2\x80|\xd0E\x91w\xdds\x90\x02\xe3\x9d1\x8c\x8d\x8d\x1d\xb9\xed\xb67\xfd\xc5z1_?.\x98\xe3\xe7~\xee}\f\x00\x87\x0f\x1f\xbd\xe2\xe8\u0463\x1d\xf6pBhj\x98\r:\x13\x1b19\xb3\x13\xba\f9\x8c\x1c\xa5\xe2L\x02\xa4-xE\xc3H\r\x9b5\xc0\x02\u0436\xa2\x83\xc9\u04b1\"R9(%6\x1a\xb4*d\x99F\xa3\x15D#\xb1aw\xf1Wj\xd1\u062c\x86\x02@\x1c%\xfe\xf0|\xee\x96\xd5\xc8'%L\xab\x12\xca\f\xd3\x0fA\x1c\xe3\xc4D\xe9\xf0\xfeXP\xfc\x13\xa0\xc8J\\K\xca]\xcbMJA\xf2\u06a8\x80\x12\x06M\xa0\x04\r\xc3\xef\xc2\vx\x82\x9f;gT\x9d\nP\xa5\xf0\x04I{\xf01\xf1?'x\xca_a\xc0\xdaT\xe6QB@\xb0\x80\xea\x1a\xa8\xae\x87W\x9cK\xd8*\u07df\x00\x9b\x04\x13\x1c\x8e0\x8bM\xd01Nr\x908v\xc4Q\x1d\xed\xb9\xe3\xae+\xae\x1c\u0365e\xd8\xcc\xdb\xd2&\xbe@\xe4!!cl\f\fQ6\x14*\xaa\x99\x93\xa5a\u0615\n\xb6\x82\\l\xb0\xe9\x8d\x0e\xa3\xae)\x11$\xc1R@6Z\x00I\x9c~\xec\xbb8\xfb\xf4\xf7\xd1\xef\x9eG>\xe8\xc1\xe8\x12B\bXcx\xf3\xe69\xba\xfe\xfa\xeb\xe7\xf7\xee\xbd\xea\a\xeb\xc5|\xfd\xb8\xe0\x8e\x13'N\xbc\xf1\u0631\xe3U\xac[\xa0\x9e\xc1\xa23=\x87\xe9\x8d\x17\xc1\xe6eT\xf5\x81\xc8yZ\x04\xac\xb7`\x88\x15\r\u06f60M\xe1\xb0M\u007fO\"\xe7\n+\x8f\x85kh\x1aGk\x10\xcb\u04e4\xddx\xfb:o\xbb\x86\xbd[$\x9d.\xfb\xce\xd9ue,\xc8\x1b(\x11Ta\x81e \a`Z\"v\xe8<40\f\xb6\xa8j`A%GC)'\xf6\xf4~25o\xd9a\x80\x85VA8\x15\xf0\x9f\aus\xe7\x17b\n\xa7\x03\xd0\x05\u0614\x0e\x13\x0f\xe6U\xb6\x8aV\xe3\x98.\x15\n\xbc\x85\xd0\x16\u064a\x86\xccMe`eS\x88\xc3e\xe0\u054a3\xb8\u05a9W\xde\xf8\xec\x98\x1f\xfe1l\x90\xe6\x1b\xeb\x04?6\xc9\xe9\xf4\xefQTezz'\xb4\x1brF\u007f\xfd$\xbfSZg\x95\x00\xcb0\x9e\xa9B\x00$\xeaA\xe0\x11\xff\xf6\xda\t!\xa4\x1f\xde\x10\x84\x94\xd1\x04(\xec\x84T\xbb\r\xa1$\xce>y?\x9e\xfb\u0397\xb0|\xe60\xcab\xe0\x14\x9f@p9\xa5\xd9\xd9Y\\s\xcd5O\xde~\xfb\a\xff\xaf\xf0h\x17j!_/\xe6/\xa3\xe3\xd2K/\a\x00|\xf3\x9b\u007f>\xf7\xcc3\a7\x17E\xeeY\x01\x0e^\xb0\xc6@eMl\x98\xdb\x05!\x9b\xce\x1b\xa3\xa6\xbeC\x84]\x9c5\x1eCu-\u050aF\xd8\xc1\xbb\xc1\xe7\x90\xe9v(\xe4r\xa8\xa3]\xa5\xe3\x1f\xa2f\xd4\xc484:\x95\xc7:>\xbbH\x1e/\xa6\xf2$\x18s\x18\x94\xca\u0722\xb9d\x90\rx5:O\xa1+w\x1dk\x8a\x92\b[Q\t\xa96~\x1cm S\xa3v\x0fS\xea\xb9>\xf4%\xeb-\x01<\x1f:\xf0\xf1\x85\xb6@Q\xba\\\u0322\x80X\x19 ;\u05c3\xe8\x0e\xbc\x87\x88\xb3\x8e\xb5Z;K\xc7\x00\x97p*\x87\xaf0hf\xebT\xac]\r\xd9\xf7\xf0\x8a\xef\xe6\x899\xc1\xc28\xc2'q\u01d6Z\xce&\x9dz\xbdsw\u007fk\xb5\xf1\xbeE\x1c\xb1\xed\xcaL\x8dc\xda\x12\xc0 c!Jw\xbe\xe4\x87\xc1\xe1\xe5\x91\f(\x1df\x16\x15\xfbH0U\x9e+)\xa7\xde\xffCx\x97S\xe7y \xdc\xe03(B\x05!k\x8d\x81m\x89\xe3?\xf8\x06\x0e}\xeb\vX>y\be\xdew\x8aO\x0e\xc6q\x12\xcdf\x13{\xf7^\x81w\xbe\xf3\x1d\x9f \xa2\x02\x00\xbe\xf8\xc5/\xac\xc3,\xeb\xc7\x05\xb4z\v\xf9\xe6s\xe7\xe6\x91\xe7E\xb4\xbc\r\x95\x85\x84\x84h4\x87\xe2\xba*\xa5%\x05\x01L\xa0\x8d0\xa0z\x06\x99\x00tK@\xe5\\\x85\x19\u0512\u042b\xa1\xd5jT\x85\x86\x18}k\tq\xea\xaaE$\x14\xf4X\xb8E:\u0324!%\xb7\x83\\dn\u0440\x06\x93\x84nz\x8d\xa0\u007f\rT\xe1\x15\xab\x11[q\xf0\x920Im\x16XM\x00\x1f\xb9\xb5\xa8o\xffk\u03c6\x91.3\xee|\r\xbb\x01.\x12Z\xa0\xe7\xbd[o\n%\xb4E\xa6\t\xb6C.B\xcfw\xf6\x8c49\x89+\xd1&\u06da\x8dm\x96[\xa8\xdcQF\xbd\x02?\x89\xacOv\"\xf1g\xc904\xe0\xf3\xb1\x90\aY|\b\u00a6\u02b66\fJ-j\xf0J\x94\xeb\xa3R_*r\x81\x1e\x9a\xaa\xe1\xabd\x82\nj\xe1\xd4R:\b\x8a\x82\xc68}\x9e\xd5\b\xb6\n\a\xf7\x8b\x8c\x90\nY\xd6\x06I\x81\xe5s\xc7q\xe4\x89{p\xf2\xc9{Q\xf6\xbb1\f\u00c5\x9a\x13\xa4\x92`\u02f8\xea\xaa}x\xdd\xeb^\xf7\x1f\xdf\xfd\xee\xf7|\x15\x00>\xfa\u044f\xd2\xfb\xdew;_\xd0\xd7\xf6zy{y\x1dKKKse\xa9\xfdE\x97\x94 \"Xk0\xc8W\xc0#:M\x1f\xc1\xe8qj\xcf\x06\xf0[\xe5F\u03c5\xfe\x8a\xe8Y\xee\xf1KOidO\xfe%\x1e\xeaVGu\xdb\xc35\x91\xab\x01e\xed\a4\fkT\nS\b\xaf\xe7\xf6\u007f\xc7IJ\x0e\x19\x86\x1cX4\x96-T\x81\xc8[\x17\x9a!\xbb\x9e\xc1\x82j\xb8'-Cr\xe2OO\xcf\u007f\xb2\\\u06d2\x8c(\xf3\xf1iT\u07be\u0387D\x83\x8b\x01l\xeeS\xeaKO',5\x10%\xf4\x16\"7h,\x97\xceo\xdc\x06/\x14\x93\xb0M\xc2\xe3\xa4\xee\x86\x16j\xa0\xa1r\xebw\x19\x1c\xe1\xa7t\xf7\xe5\xfcTL\x02\xa7\xd8X<\x81\x14\x8e\xe1\u029b\xc5T\xd0\xca0\x9eN\x1e\u06a9Ac\xf0\xec&[9-\x8a\x84E#\xe0\n\xb9\xb4\x9ez\xe8\xc3]\x04Q\xfc\x8aiP\\}v)\x11\x84!\x0e\xb9%\xb2\xac\x05\x10ci\xe1\b\x0e\xfd\xcd\xd7\xf1\xc87?\x8b#\u007f\xf3M\xe8\xbc\x0f\xa12\x17\u007fH\x0e\x8e\x91J\xc1\x1a\x8b\u077bw\xe3\xcdo~\xd3\xe3\xff\xe2_\xfc\xef\xff\f\x00~\xe6g~\x9a\xde\xf2\x96\xdb\xf8B\xbf\xb6\xd7;\xf3\x97]g^\x850\xd7\n\x8d\x10\xb0\xb6\u0120\xb7\xe8\xd3}j\x16\x84C\x05\x98\x12\xcbU_\xd0KS\xf3\xbd\x88\x05\vU\xe8A\xed\xf1hDXD\x8d\x88\x9d\fCiD\xe7;\xb2)\xa6\x8a\xd1\x12\\\xbah(\x17\xde\xe3\xdf2\xb7h,i\xe4S.(Z\r,dak\xc3Z\xb2n\x0e\x00\xfc(Y\x04#h\x97C;\x8d H\x8aV\xae\xa1\u02e5*\x12-(&#VM\x95\x0fwX\x91d\xc1hXF9&\xa0\x9bb\u0235r\xa8#f@\xe5\xce\xf0L\x1a$\x90T:\u04f0C\xe9=~Qb\x8eC\xc7\b\xa9p\n{P\xb4\x92\x8d\xae\x87\xa8\xbcpl(\xe4\xfe\xef*Q\x16\x92\xa1)A\xb1c\x9e\x18\xe1(\x88\x8a\xadw\x00\xa0\xca?\xc5&Cu\xaa\xad\xe4N\xd1\t\xf6\xbeA~\xc1\x90\x19\u02a2\x8f3G\x1f\xc6\xfc\u0267\xb04\u007f\x04\xcbg\x8e\xc0Z\x03\xa9\x1a\xee:\x00\xc1J\x05\x995`m\u0266,h\xc7\xce\x1d\xb8\xf1\xc6\x1b\x9e\xfc\x95_\xf9\x95\x9f%\xa2%\x00\xb8\xe5\x96[\xf8\xa7~\ua9f1^\xcc\u05cf\v\xeah\xb7\xdbOeY\x06)E\x15\x1b\xe7\xc4\x11`mP\xf4V\x92Z\x1a\xe8p\x14)^\x84\xaaH\x06\x95\x0e\x99\xca\xe6\xd6J\xbf\xe5\x0eb\x11/\xf4\x11\xb6Nba^\vv\xa6\xd1?\xe7\xa1\xda\xe8\u04cdyDkO\u05a9P\x8d\f9\x90ud\xc4\xd5s\u03eb\x16\f\xd3\x10\x90=\xafX\xb5\xc9I\xfa\xe7\x14\xec|\xe3\x02E\xc3\u0388\x8cQ\x88z=\xc0\xc4\x15<\x1b\x14\x96\xa8\xa0\v\x88\n\x1a\x89\u007f\xe8\x17\xb6\xb8\x96Q=\xf8Zj\x06y\xb5\xa8n\x8a\xdaZRQ\x16\x1927\xce\u007f\u0778!v\xf5<\xb8\xce\xebDU`+\xf6\x89\x8d\xafU\u0569W\"*\x8e\v\xa8\xf5b\x1fNT\xa9\xd503x\xa8\xb07\xacw\v\x96\xcb+\r\xcfI\xb2\xc3\xc33\xdfp\xb0\x17\x1a\xc1CI\x91zjy\xd5\xce\xd1c_\x11Z#!Q\xe6=\x1c;\xf0=\x1c;p/\xfa+\xf3\xaeOWM\xa8\x84\x11\xc3\u0110RA\xaa\x06\x0f\xfa+\u0632u+\xae\xbf\xee\xfa'\u007f\xf1\x17\xff\xe1{w\xef\xbe\xf4q\x004?\u007f\x86gff_\x12\xd7\xf6z1\u007f\x99\x1d\u059a\xefl\u06b4\x11Y\xd6\xf0\xb8y\u0569\x1b[\xa2\xe8\xaf\xc0\x98\x12\x14$\xd0q\xe7JUWe\xd9\x19MyN\xb7cdT]\x19+D\xae4\xfb!\x1fE\xee\xe2\v\xb4\xb8<\xe4}\x9b0Ix\xa8\u00a7!\fq\xdc\x19\xdc\x15\xb5ss4\xa2:\xe7\xaa\xe5\xe6\xb8-\u03fa\x16Y\x8f\xeb\x186\rm\x0eR\x1d=\x85x\xbbZ\xd4r\r\xcbO\xb2#+\xfc\x98\x11=Ol\xe899Y\x1b\x12ug\x8a\xabGn\xb9q\x11u\x10\x15\xebD2\xd0\xec\x1a\b\xcb([n\xb7D\\A\"r`\x90\r\x8c{\xaflE\x19\r\x90S\x85.\xa36\u8904\xc1b\xb9\xf2\x19\xb7\xde3%\r\xa7H$\xa2\xfe\xed\xe3jw\x10\x96\x8a`\x9aOT\xb1g\xa8Z\xf6\xd8r\xe5;\xceT\xc9\xf1}\xe1%\"? v\xb4\u01b8\x03\xe1\n\xdc\x12\x14\x18Y\x0e_[8u\x00\u01df\xb9\x1fy\u007f\t\xb2\xd1Nf#\xfe~\x02\x14D\x84R[\xda4;\x87\xd7\xdet\xe3\x93\xff\xf4\x9f\xfc\xc6{o\xbc\xe9\x96\xc7\x01Px\xec\x97\u032e{\xbd\xbc\xbd<\x8e\xa7\x9f~\x02\x00\U00016dfc}qvv\xf3q)e\x92\x14C\xb1\x9b\uebdcG\xde_\xae\"w\x12\x8b\xbd*\u6362\xbc^\x98P$\xd8[\xbc\xfad\x1a\u02f5b\x94\x0eBG\x17\xf1\x14\u007f\x19\xfe9\x8d\xbei\x8aj\xac\xc6x@\x06\x90E\xa5\x10\r\xe7\xe5,\x00\xdc\xffe\xc9P\xb9\xb7\u007fM\xf3\xe2\x14\xd5t\xfeU\x97]\x89cj\xcf\xc6\x17\x13k\n\x18=\x80\xd19\xb4\xcea\xb4\x0f/6\x05\xac)amj\x1f[%\xe7 \xc2\xd1\\1R\x12<\x1b\x9e\xe1\"K\x860\xde\xe1P[\xc8\u0720\xb1T\xa2\xd1\xd5 cb\xa7-\n\x83\xacg\x1c[\xc4\xdfV$y\x9a\x96\x13\u02a2\xef\xc2\x19)\xab%\x04){\xcfr\x9b\xc07IW\xcf\xdes%(b\x839\x96+\x84\"R_\xab]C\xaa\u016c\x16\u02cc\x05T\xf0h`\xef\xcb\x12>k\xe1M\xf1l\x15\x11\xfe/\x84\xf3V\xa1\xa4+\x97\x12\xba\xe8\xe1\xec\xd1G\xd1[\x99w\x8d\x8a\xad\xf2=\xd97\v\x82\x84\v\xea\xd6\x1a\x17\xed\u0709\xf7\xbd\xef\xfd+\xff\xe1?\xfc\xeeo\xf9B\x8e;\xef\xbc\x13ke\x12\xac\x17\xf3\xf5\xe3\xc7z\x84\b=\"Z9}\xfa\xf4\x97\x01\x80|vg\xca\xd3-\a]\xe4\u0765\xea\x02\x1a\u00a9E\x9a>\x13\vd\xbd\x8c\x86\xa81w-\xd2\b~\xf9\x1a\x85\x9c\u05c0\xa1\x87\xb0sZ\x033\xafq\u0343J0$\x01\x05\x9es\u02b6\xb1\x15O=\xdc\x16\xd6eDj\xe9%4f\x88#\x9e\xbc$A1\xca X\x1f\x00lt\xe1\xa4\xf5)4\x118\xd8<\xe42\x98b\xf95\nPb`\x1537\xabs$\xed\xa9\x8b\xda\x15[*-\xb2e\x8d\xac\xeby\xe6\xda\x19\x84\x91\xf6\xd2zckB.$E\x9c\xb9\x12\x04\x85\x02n\xbc\xd0'\x0e@=\xc6]\xa9wiUh\x84e\xaei\xc3\u023b\x18V\x8aYJ0o\x11?\x1b\x10\x02\x12\x14\x13\x80d0|K\x06\u035c\xe0\xe5B\b\xa8F\x1b2kA\b\xe9<\xf9\x93\x0e^\xaa\f\xc5`\x19K\vG=MQ\xc4\xddN\x1c\xce\xfa]\x811\x06Zk\xbc\u136f\xc7o\xfe\xe6o\x1c\u0771}\xfb\xb7\u00a3\xbe\xf3\x9d\xef\xe4\x97\xda5\xbe^\xcc_\x86\u01ee\u077bt\xa6T\x8d\xbf\x1b\x14r\xbap\xd1Y\xa8\rI\xb9\x06\xaf\n\x06\x84\xa5\xa1`\x06\xaa\x15R2\x88E \xd2\xe5\x80\xe7/\xecT\x83\x9e\xd7f\xba\xa4\xb5/\xfa\x9b\xd4\rvca\t]\xb9\xa5\u06a2\x11\n{0\x80\n\t4\xc4\f\xa3\x00\xad\x9c`\x87-\xaf\xe9$\x93\x9e\x905\xa5\xe7*\xdb\x1a%p\xd4*U\x1f\x89\xa6\ue0e8\u007f\x9f\xf2\xb3\xfdW\xe0\x8f\xbbw\xb4\xa2Mp\xf7\b\xb3se\xcb\uba60qTKCV\xbdT1X\xd2\xf3\x8c\xbc\xf7\xf8\x8es\x92\x9b\u0249i\xa5\x0f\xd3\x18\x9ac\x04\xdex\xfc>\xb0A\x98*o\x14f\xefxY\x050\x13\x10#\xfe,\x18\x86\x80\xa6\x90h\x90\x04\f\xe3\xfc\xd9g\xf1\xdc\xe3\u007f\x89SG\x1f\x8a\x9d\xf6\xd4\xccE\xd80{i\xf2\xdcS\x96\x92E\xa39\x8e\xed{\xae\xc7\xdc\xc5\u05e0,{XY>\x8d#\x8f\u0743S\x87\x1ev]:\t\x94\xf9\x00\xf9\xa0\v\x80\xb1\xb0\xb0\x80o}\xeb\xdb\xefd\xe6\xdf'\xa2\xe2\x91G\x1e\xc2\xd5W\xbfb\xbd\x98\xaf\x1f\x17\xd6\xf1\xd8c\x0fc\u07fek\x00\x00\xf7\xdc\xf3\xad7\xfc\xd6o\xfd\xf37\xe5y\xee/t\x91\\\xb6\f\xa92\b\u0568\xbalN\xbd\xbb+\xd3\xff8\x90d\x97\\\u00de_\xee\xac\aQ\xf3\x05!\xeb xJ\xf0\xea\xb5\xfc\u0369V\xd8\xeb\xf8\xf7\xea\f\xcc\xd5\xeeU4\xac\xbe\x8c\x9cw\xacR\xfe\x04?tG\xa3s\x85\x9c\x05\"/\x9d\x86r\x90+*\xa4\x81\xb1%\xac\xd1\xd5\xd9\xc7\x13\xe6zd\x1b\xf1*J\xe5\xf0s\xae\xadp\x91\xceX\x9d;\xa7\u06e4\x14~\x11\xe9\x16\xdb\xdf6P3\xadO\xeb\x11\x04\x96\u038dP\xd8*$48\x15F\xffr\x0e\x83lJ\xe8\x96\xee\u0770\x81R\xe8?\fb\x84\xb7\x0e{\xf6\ty\a\xcd`\xaf\\\xadU\t/?\xf8\xa5\x84\xb5-\fO\t\x10J\xa23\xd1F\xc3\x02\xfd3\xa7q\xec\xc0~\x1c{\xe6~\xac,\x1e\a[\x83\xe6\xd84\xb6\xef\xbe\x0e\x17_\xf9\x064\xc76@\x1b\x97\b\x94f\xd9\x02\"F\xd7\t\x99\xa1\xdd\u0684\x89\xd9\xed\x18\x9f\x9aA1\xe8b\xfe\xf8\x01W\u030b>\xac. \x84\xc0\xe2\xe2\x12\u039c9u\xe5\x9dw~\xf5\x16\x00\u007f\xf9\x8do|c\xcd}\xe4z1_?~lG(\xe4\x00p\xf7\xddw\u007f\xfc\u0631cY^\x14P\xaa\xe1\x99\x03\x14/\xeaFk\x1c\xad\xb1\xa9*\xf1<\u059dJ\x91I$\x12\xf1\x90\xff\x9d\xf2L\x84P`5\x83J\vmC\xf8\xf2*,au!g\xd4\xc53k^M<\xac\xea\xc7\xda\x0e\x8c\xf5\x01f*:r)>\x04\xf6\x90\x04\xab*/\x94=\x16\r\x93\fm}\xf2<\x9b\u0485\x1a{\xe1I\xec\xa4y\b\u02e7zi\\\xf3\xd9$\x90IM\x12\x13\xc9\xdau\xef\xf6T\x94D\x02qH[\x87\xa3\xb8\xf6\u007f\x8a\xef\x1dy=PJ\xd7\xf34D\xaf8\r\x81\x0f\x15\x86\x9e<\xbf\x04.\xa2\xaa\xf7O\x05\xa7q\x19\xa0!\xc0)\x8a\u0390\x84H\xc0\xc7\xc4\tBc\xac\r\xd9\x16\xc8\xcb\xf38v\xe01\x1c~\xe8\x1e,\xce\x1f\x81.\xfbPY\x1b\x1b\xb6]\x89\x8b\xf7\xbe\x1e\xb3\xdb\xf7A\xc8\f\xba\x1cT\x8c\"F\xa2\xf8\r\x90\xa1\x1bp\x9ab\x00A@gr36\xcc\xed\u00b9\x13\xcf\xc4YG`\xc1\x94e\xa9\x1b\x8d\xe6\x96#G\x8e\xbe\x1d\xc0_\xf6\xfb\xfd\xf5b\xbe~\\X\u01d93'0;\xebl;\u007f\xf0\x83\xfdo\xff\xc4'\xfe\xf9O\x9e=;\x0f!$\x93\x10DB\u0536\xf3\xad\xce\x06\xb4;\x1bk\x8c\x860\x8f\v[k\xf77\xbe\x83\x16\x04\x92@&\tR\x917\xa9fP\u18fd4\xfb\x82>T\u022b\xfd\xfbPGMC\x9d\xf0j\xf8\xbb\x12\x86\xd7d\x93@m\x81I1\xee\u0564\x9bXtd\xf5\x05fp\xe1=kb\xec}T\xb3\xb8A\xa7\xd5\x15?;Q\xb3\xd6 \x13\xa2\xd50\u03ea\x85\x86*\xc9)\xca\xd6\xc47\x1c9\xe2\xd5\x1e \xb1\xb3M\x9eD\x05\xb3\xd8U0\v\x00_\u0607\x86\xcc\xe4\x8al\xe0}\x93T`\xab\x91\xf7\x97\xd0\xeb\xcec0X\xc4`\xb0\x84\xc1\xca9\xf4\x97Nc\xf9\xec\xb3\xe8.\x9e\x811\x06D\x02\xad\xce\x04f\xf7\\\x8d\x8b\xf7\u0744\xd9\xd9\xcb!\xd1F\xbf\u06c3\u0579\xf3\x9d\x17\"IY\rV\xb7\x15k&\xce\x1a\xbc\nU\xca\f+\x8b\xa7p\xf4\xc0}\xd0\xc5\x00\xaa\xd1r\xf1yBF\x16\x8e\x14\xa4\xb2,\u00e6M\x9bN\x03\xc0\xf4\xf44\xaf\x17\xf3\xf5\xe3\x82:\xae\xbb\xee\x06\x00\xc0\x1f\xfd\xd1g\u007f\xe6\xf4\xe9\xd3[\xbb++Ve\rA\xe1B\v\xc3(v\x91q[.\xfe\x89(|\xa9\xa9@\x13\xa3\xadt\xa8%\x04A\t\xf7\u007fd\xe4\u0094\x05\x01S2F\xac3\x18\x8a\xad\xcb\v5\x95!\xd3\u8ac5V\x99$2\xd7\xfb\xf6\x80\xe9bx\x00J\x18\n\x19N;K\xf7#K\x00\tF&\x18\x92\x18\xdc\x04\xb8I\xee\xfb\x16\xc0\xe3\xe4\u0515\xc6\x0fD}A\xaf\x89z\xbc\x83!%])s\xe54\x99\x92\x13+\xb7\xc6\x04\x13\u786e\x9b\xea\xdd\xf1\b\x14\xaaF+$$\xb3\tA\x90\u0085X\vE\xdew^\xban\u0738\x9d\x86\r\xa6VBx\xa5'\xd5\x17\x87\U0003ace3\x1e\xa6\xf1l\x95\x1a\xb5\x1e$\x1d\x19$\u0273$\x92\x90B\xc5\xfd\x85\xd1\x03,\x9d=\x8c\x85\xb3\x87\xb08\u007f\x18\xfd\x95s(\x06\xcb(\xf2\x15\x94\x83\x15\x98r\xe0\f\xb7T\x06\xa9\x9a\xe8LOc\xf3%\xfb\xb0u\xefO`\xe3\xae=\x18\x9b\xd8\b\xbd8@\xb1\xd0s\u063a\x10u\x1dAt`LX5\xbe\x90W#\x1e\xb7\x8b\xb9\xf7\u0739\x054\x1aM\x05\x12\xae\n\x03Q\xbe\u0759\u070c=\xaf|;\xa4j\xa2,\xfa5\x17\xabp\u0344n>:\x0f\n\x17\xc5\x05\"\xa0\xe1\xbejT\xb4\t\xe5\xfc7\x16\xb5\xdf\x0232\xaf.\x8c\xb8\xf7*`\xbc\x8e=\xd7\vI\xa0\xb2\r\x03\x19\xcf\x17\x0e]\xdd5\x03P\xc4P~\xe0\xc9m\x80[\x89\"2\xc0\x1b\x1dw\xfe\xbc\b\xd8\x02\x10R\xb8\x8a\ue855\xe8\xefB\xe9yP\x05]$\xbcm\xa4\x8cE\xae\xf4\xa7\x18\x82\xd6\u04c4{\f\xdd\xf5j\xa6\x8a{>R\x02J\x12\xa0\xdc\xc2$[\x12bB\x82\x1b.\x9c\xc32\x83z\xda{\x98\x93\xe3\xfb\x03\xd0\xcc~qJ^_\x1b\x98\xf2\xc2u\xc1CR\\w[\x0fn\xb1\x05\t\xef\x03n\f\x06\xbdE\xe4\xfd%t\x97N\xe2\u0729\xa7\xb1p\xea),\x9d;\x86\xbc\xbf\x04!$\x9a\xedILo\xbe\x04Yk\x02\x8d\xf68:\u04db0>\xbb\x19\xe3s[0\xb1i\x0e\xad\x89\rh\xb4\u0690B\xc1\f\n\xe8\xfe\xc0\xc1t\x1e\u02b3\u02a9\x88a*\xb7E\x11\xb8\xae\t\xf54\x8d\x90\x8b\x88\x94\x90(\xfb]\fV\x16\x9c\xddB\xd6\xf0\xe2(\x1bEf\u030c\x99\x99Mx\xfd\xeb_\xf7\x9d/\u007f\xf9\xcf\x00\x00\xb7\xde\xfa\x86\xf5\xce|\xfd\xb80\x8e\xaf~\xf5\xcf\xc4\xe7>\xf7\x05\xc3\xcc3\x1f\xf8\xc0\xed?\xfb\xdcs\x87!\xa5t\xad\x91\xc7\n\x9dO\x87\x01\x83\xb1\xf3\xf2\xd7b\xeb\xaeWE'\xbf:\xd4\xe1\xbaRA\xd2\x0fL\xfd\xc6\xdb\xc3+\x9cB,i?#\\A\x87\xf7\u0486e\b\x16\xc8\x04P\x94\xb6\x8a.C\xbd\v\xac\xb3X\x86\v\xf6\xa8\xf8\x9e\x14?\xe6\u06b6\xbb\x86\xf9\x13 \x84\xf7\x0fo\x00\u0726J\xab\x13 \x8fP\x14\xc6\x00a\b\xb4L\b\xc4\x1e\x04\x9ae-\x0e\x82W[\x9b\xd30F>\xb4 \xd10\xb0N5f\b\rC\xed\xb12U\xab\x9f 89z\x80X\x1a\x02\xd4\x11\xee}\xb0\x8efI\x1d\xe9\x1ds\r\xc0\x06V\xfb\x9cSE\xd0\xc6\x11:\"\x84\"$B\xb5w6\xb4aA\xb2\xa8\xf3\x87\b\xa4$L\x99cq\xfe9,\x9e;\x823\xc7\x1e\xc1\xe2\xd9gQ\f\x96\xa1\x8b>\x88\b\xad\xb1\r\x98\x9e\u074d\x89\r\xdb19s\x11&gw\xa1=\xb5\t\xcd\xf16\xb2\x8e\x82\x1c\xcf \x9a\xca-\x1a\xd6\xc2\xda\x12\xe5\xa0\v\u03ad\xe3\xbb3`u\x12&\xad\x84O|\xaaXU\x11+G\x02\xbf\x90\x83\xc6\u020b\x94(\u0495\xfc\x1cDkg\xfef\xc3\x02l\xd1\xe9\x8ca\u02d6-\xa7?\xf2\x91_\xb9\xeb\x1f\xff\u33fdd\xaf\xf9\xf5b\xfe\xbf\xe8\xf1\xd0C\x0f)\x00\xff\x1f{o\x1ak\xd9u\x9d\x89}k\xed}\u03bdo\xac\xc7*\xb2XU,\x92\")Q\xd4\u040eE[\x92GIv \xc5v\xcb\xee\x8e\xed\xb4\xe1\xb8\xe18v\x8c\xfe\xd5\b\x108H#\x06\xd2H\xfe\x04n\xa3\xff\x04H\x1b\xe8\xd8\b:A#\xed\x8ch\xb8\xd1vK\xeeA\xb2-Y\x94<\xc9\x16\xe7\xa9X\xa48W\xd5\x1b\xefp\xce\xde+?\xd6\x1e\xcf=\xaf\xa8?,J\uaec1G\xbeW\xf5\xea\xbd\xfb\xce;g\xed\xb5\xbf\xf5\r\xcb\xdf\xfc\xcd\u007f\xfc\xd1\x1b7n|\xea\u06b5kh\xdb\t\xeb\x8d\u0369\xb8\x88w\xd8\u07bb\x80\xf7~\xf7\xdfD;\xdd\xc1r~\x98\vbY\b\x99\xf5\x81\x8f\x10\v)F\xab\xc5\x04\x90\x86\xebf5V\"\x03\u040e\x85\xf49\x1f\xd4B\xedG\xbb\x90\xbc^\x0e\xcfV(\x84i\xf0\x9a\a\x82\xe5\xc00\xe7\xc1Q\xfd\xba\x87\xfe'\x00\x98\x04lD\xef\xfa\xa9n@\xa7A#D\x00m\t\f\x04r\f\xf4\xc1\x00\x8a\xca\xd3\x01\xc9\n\xf7;\xa6\x1d\t\x95HF1<-R\x84ra\xafs8+\x9c\xbc\n\x80\xce\xc1\xc4\xd62\xd8\xe8\x06\u028d\xc2+\x98h\x91J\xa7\x83P\xd0\x01\xc5\xcf)\xf8\x92\x13ge\xae\x16\xbe\x12_\x96\x14\f\xa1\xd7Y\v\xa5\xf8 \x02b\x1df\xbev\xf5/\xf0\xf8\x9f\xfc\xbf8\xb8\xfeu\xb8~\x01\x88\xc7ts\x0f\xb7\xdf\xf5~\xdc~\xe1!\uc77f\x0f\xbbg\xef\xc6\xc6\xf69e\xdb@@-\xd0l2\xcc\x16\x03\r }\xa7\x18}\xe2\x9dS\x86\x92\xa2A\x1a\x91\xdaB0\x81\xac(\x05\xb1\x18\xb2f\xedZ\x91\x10U\xda 3a\xba\xb1\x8d\xe9\xe6^\xf0\xac\xe9\xe1\\p\xe7'\x86x`\xef\xcc\x19\xdc}\xf7\xe5\xafN\xa7[\x8f\xe8I\xf6\u007f\xc0\xaf\xfe\xea\u007f\xb7.\xe6\xeb\xf5\u03af\xaf|\xe5\x11|\xf7w\u007fd\t\x00_\xfe\xf2W>\xf1\xf4\x99\xea\x13\xc8\x00\x00 \x00IDAT3\u03c0\x98\x05\x14x\xe5D\xea\x9c\xe7\x1d\x98\x19\xef\xfb\xf0O\xe2\xe2}\x0f\xa3\xeffy\x00V\x15r\xed\xdc\xc8T\x92C\x18\x0e\u0130\x86A\rUP+S\xd1\xcd6\x04:cUH\x14\xe4\xe2\x16\x04\x0f\xc0\xf5\xa8\a\xa2\xc3\xc6{4_ndh\x1a\xe5\xf9\x05\x8e-\xf5\xe1B)\u0261\x90\u01ee|\x85\xdaX82\x1a\x06h[1\x12\xdaw\xe8\x8d\xc2\x11zB/B\x1a\u00a0\x14\xa1\b\r\x1b\xf6\x8c\x9bS\xfawCX%\xe7\xaaJ\xadlM\x15?\x98\u007f\u015f\x83\x94\x92H\xb1\x90o\xf0hl\xaaX\x00\x9b\f8\x06y\x17NC\xf1D\xe5\xd5\xe1WrPC\xe5\x99P\x9c\x1c\x88c\xf8\a\xc1\v\xe0\x9c\x83\xb1\x13\xdcv\xc7}\xd8\u0739\x03\x1b[g\xb1w\xfb}\xb8\xfd\xd2C\xd8\u07bb\xa0\x9f\xe7z8qp\xbd\a,\xd0Z\xa3\x8c'\x13\xbdd2K\x88\r\xeb}\xd4\v\xa4\xf3\x05\xaf\x9e5\xb8\"\xa41I\f:\x19\xccLjQ\x1b\u00acD?\xb6\xed\x14g\xef\xbc\x1f/>\xf3\b\xfa~\xa1\x0e\x8c\xc6(\x13\xcb\x1ax\x11\x18c>\x1f\xbf\xde\x0f\xfd\xd0\x0f\xad;\xf3\xf5\xfa\xe6X_\xfc\xe2\x17\t\x80<\xfa\xe8\xd7>\xf8\x0f\xfe\xc1\xaf\xfd\x9d\x97^|\t\xd64\x94\xbc\x9d\x83 \xa4\xef\xe6\xb8\xe7\xa1\xef\xc7C\x1f\xf9\x8fam\xabX\xf9\x00\xd0 \"\x80M\xa2qA\x02\x9b\u00c4\x87\xc5\x10\xa4e\x90\xd1b\xee\x11\xc2p8\x1c\x00$\xccD\xa7\f9cA\u0483\xe6\xc5@\x14\x8a\xdf\xc2K\xee\xfa\v||\x05J\x11\x19M\x9a\x1b2\u05c7\xaaO\"e\xaf\xc0@\xa9\x93v\xc0F\x17\xacl\x1a\x04Q!\u0536\x9ao\x91\xf3\xe8\xbd\xd2\"\xc5\xc5\xf4$\xaa\x10\x15B\xe9\xa8(\x15B2\xf4a_\xd9\xc0bT\x1c\n\x91\x10\xd5\x1b\x9b\tTP\nb-LI\x8b5\u05db_4\x10\x13\xaf\xbf\x00\xda4\xba\x19\xf4\xda\xf12\v`\u0507\xdd;$.}}\xa4 T\xd9\x12\x1e\x1aDa\f.\xdc\xfb\x9d\xd8\u067b\b\xb6\r\xa6\x9bg\xd0Nwa\x9b\t\xbc\xeb\xd1-\xb3\xa0\u01c7\x13L\xd32\u0314AS\xbdW\xe0\xc3=\x02B\xa1A\x03&\x16\xd2\xf5jY\x1c\x94O\x86\xd4A\xd1#\xde\\a\x04\x1cB\xc9K\x83\xaf\x94PT\x84\x8e\x13[\x9c\xbf\xfb\x03h'[X\xce\x0f\xe1\xd9\x06\x91\x11\x81\x8d\x85\xf7\x82\x83\x83\x83\x97\xe2u\xfe\xbe\xef\xfb\xc1u1_\xafo\x8e\xf5w\xff\xee\u007f)\x00\xf0{\xbf\xf7{\xdf\xfb\xd8c\x8f\xefz/`c\x82%\xa9\x16\n\xd7-\xb0\xb1s\x0e\x1f\xf8\xfe\x9f\u0159\xdb\xefA7;JY\xa0\x89\xb1\x1d:\x1b\xf5\x9b6\xe9A\xf7&C,b\t\x98P1\xac\x8bc\xb4\xc21/\u05ba-\xa3\xb8\xb9\xd3\x02\xce\x00\x1aa,{\x9f\xf5\x9c\xd1#DFb\xd9N\xe9\xcaSP\u0100\xa0Q\xd6H\x06\x94\xb52!\u0224TK\x16\xa2\xf3\x01\xa1\xa6\x82+\xb6\t\xa6S\x0fqu\xc7\xd59\x82/\xbdfB\x11A\xc1\xd7N\xe3N\xaa\x1b\xffj\xc7\xc9f39^u\xf8\x93\x87\xc2jX\x8b\x1f\x19\x807\x8c\xce$\xa2\xc7L\x04g\x06\xf2\u007f\x91\x00-mi\x87\x8ec\ar\u0280i\xc0\xf0,\xf0NB\xfe\x85$oxfJz\x83d\xe4\x15\xbe^;\xddQ\xa5\xb0\bDz\x888t\x8b\xe3\xe2\x17NI9k[\x86\x9d2h\x83A\x96C\xe0rqc\x14\u061c\x18\x81\x01\x01\xc7\x0e\xe8B\x188\xeb\xafN\x85gT\x18\x8a\xd1\n\x8bI7n^\xb1\xcc\u07fe\xed\x12\xb6\xf7.\xe0\xe8\xc6\u02da\x9c\x14EV\xe1\xb3\x1ak7\xbe\u055f\xfb\xb5\x05\xee\xb7\xd9\xfa\x97\xff\xf2_\x84\x1a$;W\xae\\\xf9/\x9ey\xe6Y\xbd\xb9\xd9\x14\x93\u007f\xf5\xa5x\xe0\xe1\x1f\xc1\xbb>\xf0\t\xb8\xe5|0\x95C\xe2iG\u0447\xb2XD\xbd\xa8\r\xa5\xc1\x1b5\x19{.\xc2\xe5*\xa8\xa1\u00a1\xb7-h\u01c0\xac&\xd3Y\xab\xf8\xafX\x827j\a\x10\x1d\nW:p\xa9;\xefa\xd7.9]l\xd0\xd5\v\x98Dq\xda-e\u007f$8Z\xe4-\x1d8\b\x00M\rh\x87aZ\x85_\x8c\x91\xa0\x9f\na\n\xac4F\x89S\xc9\xf25\x0f\x8d\xbeb\xa8\x03\r\xaf7F\x15\xf1\xf1\xd3\f\x87!3\x11\xa8a\u040e\x05\xb5\\\\\u3890\x17j\u0304E\xb7\f\u07b1\xa0M\x03\xb2a\x98\xc9\xfa\xc6Q\xf8\x15m\x84\x933\x1a\xd5v\xbe\x01\xaf\x12\xf1\xe8\x963\xf4}Td\x02d\x03\x14\x17\x18NB\x80i\x18\u0366\x85\u0659\xc0n4`\u00ea\x06\xb5\xe1\xcdpbIqp3\xa4\xa9\x05m5@\xcb\bLX4\x86\xd0X}\x9d\xe9\x0f\x83N\xa2\xcc\xe9L\x14ZP\x8e\xad\x13\x81\xb5-vo\xbf\f\xa2`\xc2\x15\xec+z\ufc71\xb9\x81\xcbw_\xfe\xd1\xf85\x9ex\xe2\xd1ug\xbe^\xef\xfc\xfa\xb1\x1f\xfb\xb4\x00\xc0o\xfc\xc6\xff\xfc\x1d\x8f>\xfa\xe8G\xe6\xf3\x85\xe2\u0764Gj\x88G\xbf\x9c\xe3\xf6w}\x10\xef\xff\xf8\u007f\x8a\xb6\xdd\xc2\xe2x?\xc9\xfa3\x9dC\x1f\x06f\vf\x9b;\xd8\u062d\x87B -\xd7\xee}A\x15\xba\x02\x8f\xc4V\xd9\x00\xb4\u06c0;\x81\x1c\xf5\x00\x01\r\x03\xbd#t^s;\x99bp\xef@\x918\xa8v\xa9\v.\xc4D\xa5\xadJzM\xa4\\k\x9a\x12dR@\"e;\xef\a5\xbdpK\x04\xd4\bJ6\f\xa4\xf3`q\xc0\x12\x89\xfb\xdd\u01df\xcd\xc7\xe0\x03_\xbd\xbeX\\\x93;a9\xa0\xa3\u06b7\x86V\xc0{\xfd{f\xe8\xc0\x93\x01\xb2\x04l[`\x83\xf3\xcc`\xe0\u03d2,y9t\xdaqc\xdd\b\xf7\x02\x11p\u0483:\xc0\x04\xa1\x97x\x01;\xc0\xc5{\x05\xc55\xaa\xc2@\x94\x11\x14y\xde\xe5\xe7\x88d\aCb\xc0n2\xecn\x03\u07b6\x01v\xf3\xe9s*\x9c;\xfe\x9c\xf1\xf7\xb8\xc1)@\x9c;\xbdn\r1:\x84\xccQ\xcf\xf5\xb6^\xbc\xbe\xa4\x04-~\x99l,6\xb7\xcf\xc6<\xbb\xf0m\x19\x86\x8d,\x17Kz\xfe\xf9+\xf7\xc5\xcf~\xef{\u07ff.\xe6\xeb\xf5\u0373n\xdc\xd8\xff\xf9g\x9f}\x0e\xbd\xf3`\x13\x8a\xb1wp\xdd\x12\xa6\x9d\xe0\x81\xef\xf94\xce\xdf\xf3\xd7\xd0]?\xc8~\xe65X\x1e:&[\x17\xbd\xb2\xe0\x9b\u0615S\xf2\xa7g\x9ey\xfa\uce98\xaf\xd77\xd5z\u9957\xbe\u007f\xd9\xf5\u4703\xb5MrA\x04\x11v/\xbc\v{g\xee\x06\xf5.p\xbb\aC+\x10\x88,\x88l\xfd0\x84NX\x8a\x937l\u044d\x97\x14\xc1\xdac0\xb3\"D\x8a\xce=\xc0\x11\xad\x01\x9d\x01\xc8\xf5\xc0\xdc\xc10\u0436\x04\xdf\t\x9c\v\xc5\xcc\xc5H\xb3REIE\x1d\x91\xaa\xb0\u01d7\u0361+\x97i\x80YJ\xba\xa3\xc4\x01\xe5i\x8d\xb8r\x9b\x87S\xd1\x14\xceA\x81\x92\xe9(\xe1\xb9`\t\\\xec\x02\xad\xa6\\\xd0\v)j5\xac\xab$\xb0\x85\xf0\x89)\x0e\x94\xa1*\xcf-\x03\x9a\x98\xf1}\xad\x84\x8f\n\xd7\xc0\xe0\xbb0\x88p\xe3\xfc\xc9\r\x01;z\xba\x92yNZ\x82S\n)\\\xf4r\xa7`\xc7 u\xb5\xcd\\J\x18#\xb0\x96\xc0m(\xe4\x1bF\xf5\b%\x9eE\u0671\xb1\xe2\xe1\x17\x1b\xbfO\x03J\xaa\u007f\x86\xcd\xf0\xfe\u072b\xc8\xc8\n\xd0{8W'\x1f\u9f55sGc\xb7\x1e=g\xe25\x97p\x0fXki\xff\xc6\r\\\xbfv\xfd\x9c\x88\x9c!\xa2\xfd\x17_\xbc\x82\u02d7\xef]\xc3,\xebu\xeb\xd7s\xcf=\x93\xde\u007f\xf5\xd5\u05fe\xcby\xa78y\xf4\xb6\xf0\x0ev2\u0145{\xbf\x03\x1b\xb2\tY\xf6%\x18\x8c\xa8\xf2ccal\x9b\x02(\u02beZ\xe2CK\x81Qa9w\x81\xc3\xe69=\x9a\x94\\\xaeJL=w`\x02l\x18p\xc0\u03c95~nbT\xae\xee,\xc17\x04_\bKd\xb8I\f\x11\x96\x88Q\x13@-TTc\xb0\x12G\x97\xbc\xba\xc3?\x12\x1a\xd6\xc6\xf1b\x1f\xad\x83\x01(\xa3d\x8b\x14w6\x04k\x04\xcc\xd9\xd8K\xaa\xe8\xf9A\xcb_2:\x06\x17\x90\x89`\x8cZ\xb4\x92e`\xd3\xd4\xe2 \xe44\xfb\f\xe7 \xd1\xf1rVk\xf8\x1a\xc4a\xf3\xaa\xbf?\x91\u0489h\xbb\x01O\x03\xb5\xd00\xb810\xad\x01O\x14\xff&\x13\xb2D9JP9\xd3\x14I4\xe8\x83\x19l\rx\x83A\x9b\xac\xf3\x14\x19$TQ~\xbf|\x8b\x94\xc5\xfcu\x91\x86\xa2\x11\u07e6hO0Q\xe1\x11\xd9p3F(\xa8\xbc\xc4\x15\xa1\x8a\xaa\xa0\xf1\xca\xd0\rj\xc6utt\fb\xbe\x0f\xc0\x87\x00\xe0\xf5\xd7\u07e05f\xbe^\xef\u023a\xef\xbe\abW\xb6\xf7\xc2\vW\u03dc\x1c\x9f\x80\xd9$:\x9c\x17\x8fv\xba\x85\xdb\xefx\x00\u0187\x89>\xd5\xdcp\xf5\xe0j@l\u01cbL\xc0\xaf\x99\xa2\xb1\xd6*\xfb\xf0\xadJ!\xd5\xe54Uu\xda2\xcaA\xb7Z\x9ct \xaa/\xc3\xd9\x10\x18] \u00eb\x1b\x87\xac\xf6\xd6F@\x93\x80\x95\xaf\xee3yc\x10\xacJ\xe8k\u06eb\xb1\v\x11pb@6\t\x98\x86\x82\xde\x00l%3z\xa2\xb3\xdf\n!>^\x02Z\xb9*\x89SN\x01^\x99\x04\u0738\xc9hx\xe5\xea\x1d\x8bc(\xe4\x1c\xb0i-\x949\xc0\x99\xaa\x01c$4\x86\xdf\xfd4\\\xff\x86\x03\xb4\x13\xe06k\x14S7&\xa8\x81\x8b\x90\x0f\xa1\x84n\x18CZ\x90\x1bV\\\u007fb\xd2\xd03\xfb\xa5P5\xac\x15p\xa0\xbf\x9a\xb4A\x12\x13L\x84\xb2b\xfaR\xe9\xb7b\t\xb4\x11 >\xa3\x9b\xbcg\xe49Da\xc2\xe5\v\x8fx\xf5{\xf1\x15\xbb2\x0f\xe7\x19^\x04'''\xf4\xf5\xaf_em\x88^]\xc3,\xeb\xf5\u03ae\xc7\x1e\xfb\u068f\xccf\xb3\x8bG\x87G`2\x15M\xae\x99la{\xe7\x02\x98\fzY\x1d\xd61\x99@c\xc4j\xe4\x19B\xdeg\x1c~6\x14\x98\rC|\x93*\xc9=Um8*\v\xaf\xe8\xf3\xa1\xd1g\x02\xda5 \xe7A\a\x02t\x82V\b\x8e\x80\xa5W\u0699\x0f\x18xY\u0487q\xc9\t\x8ae\xa8\xa9V\x18|\u0280\x8e<\nU\u0230\u04e7U*\xe4\xe04\x03\x0f\xc0\x00\xb2\x05\x90\xf3\x80\a\x8c\xd5\xef\u0457\xedy\x84#\xdc\xc0\x18jU+\x14\nr\xf0'o\t\xbc\xd5@6m\xf2G\xc9\xf8u\x86L\xa8\x18\xb4f\xd8K9\xe6\xc3@'\xa9\xcfMH\x86/\x9b:\x90\x95\xc3^\xed\n\x90\x19C\u0300'V\x8f\x14\x93\xbd\xcdI\bM\fy0\xca\xc5\xf7\x1bV9\xf1\xc1\xdd\x11)\x12/\x02!A#\xccT\xec\u0152](\x83\t\"\x93\xfa\xf8\x88\x1f\xd0=\x1b\x06m\b\xfa\xce\u00c5\xfb2\xfd\xb6$x\xd8H\u212aj\x19\x9a\u16b7NN\xf7\xae\u0386\x18\xf3\xf9\xdc_\xbf~\xc3\x01\xc0\xfe\xfe\xfe\xba\x98\xaf\xd7;\xbb>\xf3\x99\xcfto\xbc\xf9\x86O\xe6LI\xfc\xc1\x98n\xecbs\xfb\x1c\x04\x94p\xc9\u071eS\u8fb8\xe0\xe9\x16\x85<(\xfa\x88C\x10\x82\xe5\x04\xfd\xd2J\xdfM+\x01\xbe\xa9#\xa5<\x1a\x95\xd2\xdeV\xb4H\u040e\x05\xf7\x02\u007f\xd4\x03 L\x04\xf0^\x14r\x8e\xaf!\x16\x04\xa2\x15\xe7\xd9\n/\xb7\x9a\"T>\xd72R\x98\xa5\b!\x93A\a\x1f\xf3\x96\xb8\xf4&g\x02\xb3\x81\xa7\x10\xec,\xba\xb9\xc9V\x18v\xf6\x801\x1e\xde3\\\fS\xe0\\\xf8U7_\b\x8a\x90\xf3,\x05\x019\xe0\xe0\x86\xb8\x99;f\n\x1bB\x19\ueb1b'UB\x19*\x87\x9c\x83\xbc\xeb\xf2\xf7J$U:\x121\x03\xdb\x04\x11\x86\x9c8\xf8N@^\a\u04d0\u0e98X+jUkC\xd2\x14\f\x01S\x03\xbf\xd3\xc0Y5\u01f2\u0308\xe1@\xbe\b\xf3H\xf4H\xa2\xc2D,w\xe1\xe2)Q \xc5\xfb\xc2q2of\xae!,\x1a\x86\xef\x04\x86\x00\x98`\xb3\xdc\xfb\x94\xad\x9a\xad\x90\x87\x16\x00\xf1\u0102\x90\x96\xc5pT\xf8\xd9\u007f\x8b\xaeu1\xff6[\u05ee]\xbb\xec\x9d\xdfr\xce)%,\x0e\xc4\xd8`\xeb\xccyL&\u06c5\xaa\xa6\x18>E\xc9?h\f3Q8\x81\x00K\x8aU\x92-\xfcP\xca\u007fB\x92\x1c\x04W\x02%GQ\xc8:\x81\x81&\x04\u0675\xa0Nt \ua056\t\v\tG\xe4\xb1/]\xd2\x16C\x81#\x16\xd0\x14\xc0d\xe0\x0f.uC\x9e\xde$\xabH#\xc9\xd0\b%\x9c\x99\xc8\xe7\xa86 ][\xefz\xc0\xa9<\x1c\x13\x026\x058Vq\x8b1\x02/\x9c\xaf\x9f\xc4\r\x82s\u0403\x97\xca\x13\x87)@\x16-\xc1l\x1a`\xa7Qs\xaa\xb2\xe8\xca`JP2\x8a\n+\x81X\u0529\xa2\xeaQ\xb1\u007fsm\xbb@\xba)\xd1n\xf8\x1d\xfa\x1e\x0e\xac!\xd7>\xc0\"\xb1\u007f&\x85UR\xfek\xc3\xc0N\x03lZ,\xc2\xe7\x9b \xed\xd7Z+\xd9Q2\xfe\"\x88rP4\xfb\xc0Z\xa5\xa0\fR2M2{C\xc1Z\n\f\x16\xde`\x18\x11\xd0\"\xdc\x1b\xbe\xb8\a\x92\xd9X\x0e\xa2\x06e(\x87\x8a\x98\xb9H\x87d\xc3h\x1b\xc5\u4b35\xebb\xbe^\xef\xecj\xdb\xf6\xfb\u06b65}\u05e15&\r\x19\xd9\x18\xec\xec]\x80m\xa6)\x99\xbc\xc4Q#\x15QF\xea,R\xd2{\xe8\x1a\x83\x8fv\xd5\xecq\x8d\a\x8fR\xd7V\xb6\x8a\xf0\xa0E\xf5_(8\xbc\xc1\xf0g\xacv\xb2\v\x0fk\xd4\u072b\x8b\xec\x12\xa6D\x8e`PEnI\xf4?\xab\x99\x9ed\u01af\x93\x14 \x83T\xddyP\xe6\x83 \xa1S\xa60\xc43\xe5\xcfE\x04\xb6\x16d\x18\xd2;x\xd7\xc3;\xa71t^\x80c\x82a\x817\x02\xe79\f\xf1\xd43\xc0s\xe0f{\x0fr\xb1#\u0542n\r\xa3i\x18\xbc\xc1\xe03\x16\xbc\xdb\xe8\xbc \x9ap\x15\xfcI*v\u04c8E3\xd5\x13\t\x891uq\x00(\x12h\xdeC9g\xf1\xab\x9a\x10d\x97!\x0e\xe0\x99\x03\xbc\x0f8|d\xbaxx\xca\xcc\x1e\xa5MZ\xf0N\v\xb1\xa4\x8c\x17P\x10\xf6Pm\x89<<\xaf\x89@\\\x1f\xd8'\x94n&a\xc9x\u007fiw+y\xd87\x99\x90n6\u0783:=\xec\xa4\xcfd^\xb1\x1b\x8a\xf1v\xe5\xecE@\xc9\x17\x06\x02\xf4\xce\xe9&\xed\xfd\xba\x98\xaf\xd7;\xbb\xdex\u336d\xae[\xe6\x1b?\xdd\xd0\x06\x1b;\xe7\xc0\xa6I7j%V\xa1<8\x1a>\xdc \xc03\xa5\x00g\xb2\x94\n0\x15\xc1\xc9\x15\xd7;\xcd6\x87A\xc0\xa3\x8ft\xe6\x1b\u01c7u\xdb\xc0\xf7\x1e\xf0\x1e\xa6#\xb4\x81M\xd1G\xfc4\f\xf1\xca\xf9\xa1\x14\xf8\x88L\x83|\x1f\u046av\xc0,\t\x0f\xb3:\x05ReEK\x10\x98\xd0\xfe\u01df'\b\xdf\xf5H_\x15\xd40\xf43\f\xea\x1c\xbc\xef![N\xa9}3\r\xb7p\x88~\xe7\x04\x11\x82k\x00!F\xb3\xa0\xe4?\xa3\xc3F\x86\xb5\f;50\xb75\xa0\xbdF;^\x19\x04\x8aV]y\x8e\xf5\xe3\xf0;\xf4\xa21\xda\x10\xc0;\x1f\x92|\xbcF\xa5En7\x97G\x15Z\x9ddo\x1a\x18a\x00K\u0639\x83a\r\x87\x96^\u0099\xc2k\xd7m\x83\xe9\xd7n\x03\x99X\xb0al\x98\xb0\xf9\x15\xc3Wp6\xf2RA\x1aC\x9c\x87\xeb:\xf4\v\xc0K\x9f|\xed\x01\xa3\xd4W\xf6\xf0\xec\x01'up\x93\xa4\xfd\x1c\xd2\x12\xfc\x86\x81\xb8\x1eB:\fe\x9fKu\x05c\x19S\xb8K\x04\x8fv\x11\x90\xa8+\xe8b\xb9\xc4k\xaf\xbd\x06\x00\xb8~\xfd\xfa\xba\x98\xaf\xd7;\xbb\xae\\y\xa1\x9b\xcd\xe6 c\xb2\x98\"\x14\x8b\xe9\xf6m0\x8dM\x8eq\ts-\x1b\xe3T\xa4\x8b\xee\x95\x011*\b\xe1\xe8\xc7\xc2\xf5\\\x8f\xa2\x87t,:e2\x83\fl\f\xa5<\x0e\x0f\a\x91\x94\x9eV\xda\r\xdd\xf9A\x0f\xb6\x04\xdb\x10\xbc\x10\xbc\x93\xdc\xd1sV6\xa6\x8e\xb3!\xd0.@\xad\x9a\u056e\x84^\f\xe4\xf6\f\t\x12\xf8:\x9b\xb3\xe6\x8c\xc8\xf8n\x15?\xd7\x18\x10\x1b\xb0cx\xeb \xe4\xd4\xfeu!\x80c8\xd1\v\xe6\xa1\xd4E/\x00,\xa7\x94$b\x8bfb\xd0N-\xec^\x03>\u05c2[^y\xad\xd5V\x1bX2D\x92\xe4\xfe\x01\x91Nv0\xe2<|\xef@\xceA\u0125\x81\xacZ\xd3\u02c8\xd50EZ7\xb0c\x000x\xbf\x83_zH/AD$ \x16\x9de\x18V\x13\xad\x9d\x06\bE\xdaZe\xa8\xb0QX\u00c7MS\x88\xf3\u07c7\x1d\x9e\xfb^}\xf0\xbd\x878W\xa8\x889X6\x0f:\xf3\xf8\u07c2\xa7\xefZ\u00b2!\x15=\x05\x02\x8d\x06\x92K\x1a\u019b\u05a0\x99n\xa9E\x05\x96\x85\x1f\f\x87a\xb9\xc5l\xb6\xc0\xd3O=\x05\x00\xb8z\xf5\xc5u1_\xaf[\xbf\x8e\x8en`{{\x0f\x00pxx8Y,\x16\xc9\xfa3\x1d\\\xd9`\xb2\xb5\v2\r|\xe7R\xe1\xaelk%&\xf6He1\xeb\rrWn\xb4=MRy\x1a\xcf\xdb\x04rr\xa4\x10*E\"\xc6R\x85\xa4,\x8e1}\x99\x81]\x8d\x9cC\x0fp\xaf\xa2\x94N$\x85\x1e\x10)\xe4c\x88B\xbe\xa7\xe6\x8e\u04b6W\xc1P\x14\xf3T\x91?\xf5\xb9\x80\x13\b/\xc1\x17\xab\x84\x85\ua23a\b\xbbTXsa\x88E\u0702!\x90\xd6\xebP\xee\u0423\xe9\bB\x06\x10\x81\xf3:\xa8sN\u09aa\x18U\x81\x92\x01O-\xb0\u05c0no`&\\c\u0660:\xfc\xa2\x00\xaa\xa2\x9a5\xa3\xe2\x94^c\u0083\x9dQ\xab\xda8\x88L\xd6\n\x18\x19\xfceoq\xec\x1a\b\fx\xbf\xd3a${\x15\xeb\x10\xe0\x9d\xa0\ac\xd94h\xd8b\xc2\fc-L\xdb\xc0X\x930q&5P\xeb%\xe6MPr\x824\xb6\x81\x99\xb4p\xddB\x87\xf2\x92g/Y\xa2 \xd9\xd5R|u\xa3\x91\x10\x9c\b\x16\r\xc1t\x04\xebD! .|\xe6\xc3\t\xaa\xd9\xdc\xc9\x16\x15\x05\x04\xc3`\x881X,\x97\xf2\xecs\xcfy\x00\xf8\xfa\xcb__\x17\xf3\xf5\xba\xf5\xeb\xf9\xe7_\bl7\xf9\xe0\xdf\xf8\x1b?q\xff\xf1\xf1\xf1@_/0\xb6A\xbb\xbd\xabFQ]_\xc3\u0525'Hx\xd0S\a\xc8HF\xfe\x86\x82\x80\x85)\x15\xb5\xe1\xfc\xb3\xf4\xe5\xa6*2\x1d\xab\xdcu\x1a\xa0\xe8\xd1\x1a\x15E\xe5l\t\x14$\xff\xd4{M\xa0q*\xe36\xa1\x80F\x95$\x99(\x80a\xf5\u0096^;P\x89\x015\x8a\x1b\xfb\x01T\xa2\x98\xb5T0\xcb\xe0\xf2\x9d\xba\x04y\xa0F!\xb0\"\xf2\xb8\xe5L\xa0\xd9\x1dQ\xb2\xa1\xd5z\xaa\f\r\u01c07\x04\x17\xd2vx\xdb\x02\xb75\x10\x9b\xb3<\x93\x87\v\rLe\x86\x1cK\xca\xd2~\x19\xd9Y\x89\x19\x863w;n>\x88CXHE\xc9D\x80\xfe\xb9\x05\xc4z\xf8n\tYv\xf0\x8d\x16Vo\x04\xd6\x03=\x04\vg1\xeb\f6\xc8`\xbbi`Mvt\xf4\x14\xe5\xff\x04\x1b\xae\xbb\xf3\x81\x9c(\xba_\xab\u0372\x81\x90\u02ef!\x89\x89\f\xbcs\xf0\xe22\xfe\x0f\xa0\xbc\xb5,\x01mC\x1a\x9d\xe7\xe3\xf0V\xed\x94)\xa9\xac\x18\xcd\xc66\xd86I,\x86\xf4;\x03\x96\xcb\x1e{{{\x97/]\xba\xf4\x9d\x00\xfe\xe0\xde{\xeeY\x17\xf3\xf5\xba\xf5+\xe2|o\xbc\xf1\xdaE\xe7\xdc^\xd7u\xa1\x13.\x86?\x93\t\x9a3\xbb@k!\xb3y\x91?\x19y{\xb9\x13\u00a0\x9e\xa6\x0e\x86D\x85B\xb6\xb6\xb6\xae\n\xb5\fA\x81S\x99\u06ab5\x92h\u0624\xeb\xc7S\x03\xd9\x16`\xe1\xc0>\x04\xfcz\xa5\xfaq\u8b09\x95\x93M\x93 \xb3gh\xaa\x0e\"\x05/|\x8b`l\xe5\xbd\u2fa9\xb8\x95\xa6\x89\x95\x81\xd7\n\xf912,\xb3\u0425\xa0\xbfQ\x12\xc4\x04\xdcgK\xb9\xe5\x98\x03\xe8\x03\x17=\xc0I\xd6k\x98\x05\x87@l\xb3caZ\u029bd\xe1s#R\xb2\xb43\xa3e%K\xf4-\xaetR\xe1\x06Q\x90\x1eMdt@\xcca\xb0\xed\xbd@Z\xb5\x11\xe6^\xe2\x88R\xf1i\x02Z\a\xb8%\xe3\x18\x84\x1e\x0e;\x04lNM\xa2%\xe68<\n\xac\xa1B\xd0\xe3\x01O\x04\t\xc2!xWX\xff\x1a0;xb@\\\xb5\xe9\u01efG\xa4\xf3\x14\u00c0\xb7\f\x0f\xa0w\x02\xe9}\xa2gF\x05\xa9m\xa60M[\xfe\x84z\x12\x15\x0f\xd7\xfb\xe5t\xb2\xd1z/\xef\a\x006\xf6-\xb6\xf1u1_\xaf\xb7a\xc5a\u0375k\u05fa\xf9|\xee\xca\a9\u0791\xa6ia67 \x13\x86\xb7ZX\x84Vs)s6X\x9d\xab\x99\x1a\xee \xe7\xa6\xc1\x103\xc16\x95eG\xe9\xad1,\x16\xe3E>\u05dfh\xea\x14:\xa8-\x03,-\xd8uh\u0200z\xafy\x96\xe1\xb5q\xb4\x9emIa\x00\f\x92|JhB\x04\xc6\x10\xc4S\xf0\xad\x11$\"z\xf5\x1a\x86\x83G\t1zA&?`\x84\xac\xd8\u007fK\x88\xd5\xdb&\xc0yH'\xa9\vN\x9d\xa1Wk\x04\xbfe4\xceN\ua409lD%\x95=\x80\x14\x97\x89\x90-\xd2E\xb0\x1a\x9e:\f\xc5NB&_|-\xca0\x93\x14\xa76\x0f\xc8\xcci\u0232!H\xe7\xe1\xbd\x16cb\r\x880N0\x99{\xcc-0\xef\x19\xfd\xb1\xc3\xc2\x03\xdbSFk\x92\xa7b\x15=\x17\xe7\xaf\x1e\x80\xf3@\x17a\xbeP\xec!z>\x122\xc9z7v\xf8\xd5\xcc \x88\x8d\x98\xf4t\xc5\x1b\f:!,\xe7\xe15\x16n\x8a\xb6\x9d`\xb2\xb9\x8b\xa3k/\x17\xf7g\xc0\u052d\xa5\u00e3c<\xf9\xd43\xc7\x000\x99L\u05dd\xf9z\xbd\x13\x98\xf9\x11\x00\xe0\u018d\x1b\xe8\xbae8FF\xa3\xa1\x10\x1c\x11d\xfa\xde\x00\u0796E\x83\x82;\x1eV\x83$R\a(\xb9xq\x0e\x83(a\x1a\x06\x06f\xe2\xf5\xb7\xa8+I\xc1/\x1e|>\x86\x1bD\xa8M\x86\x01\xbfc\xe1\x9d\xc0\xec\xf7\xabX\xbd\xf7@\x17^\x9f%\x15\xb8T\xa7\x05\xa9g\xac\xb1\x9b\x17\x0e\x02*JA\x13\xa9\xd8\r\xbcu\x89sDY\xe93\xb3\"\xfb/\xc25\x88\xf5\xf8/\v\x01\x0e]\x1d\x8c\x03\xa8\xc8\b\xac\u0664!\xb7BLm\xcd{Z{(\xc5\xe1\u01e10L\x93\x02\xf2\x1a\xfb\x9d\x8e\xbc\x17\xb7W/\x929\xf7\x80\xb2WN\x1c\xd0I*\xe2\xce\xe7\x0e96\xf5\xb2\xf4h\x16j\xbb\xe0\x9c\xe0h\xee\xb0\x14`\xa3!lZ\xed\x9e\xe3\xe5\xe4d\u02dc\xb3F\xbd\x10\xe6\xbdn\xca\rS\xa2\xcc*\x13\x86\x835E\xf9\xeb\x94<\a\x15\x9f\u007f7.$\x19\u016f\x11\x93\x87\xe0a\x9a\t\xa6\xbb\xe7B7\xae?K\x14\xd5\x1acpxt\x8cW^~e\x02\x00\xff\xf5\xaf\xfc\x8aH\x05\xfb\xad\x8b\xf9z\u0742u\xe3\u018d\x00\xb3\xbc\x81\xbe\xef\a\x1e\xe4\x91\u007fl\x82]\x88\x87\x04Iv|\x9e\xcd\b\x9e]i;$\x91\v\x92\x89T\x8d>\x04\x18\xa0d\xa9\xe0\x14\x0f\xa9\x9a\x8e\x81\x9aK!\xa3]z\xb2@\xb7\xcap\x91N\xc0\xfb.\x83\vqo\x12\x01\x16\x02,=\xc4\x0e\x1aT\xa9Y\x119\x9c(gE\n\x17\x8a\u039c\u021c\xb22A\\Y\x11\x94Cd\x91\xb2\u04e3\xcc4Ah=\xbd^w\n|\xca\xc4$\x89\xb5v)\xf0\x8d\xa07\xd9>\x9c\a\x9e\xe5\xb2\n\x85\x87\xce\x14\xd5\u0303\x8b\x80\x90\xe8\xdcX6\xe7\xe9\xc7K\u009d\xdc\xf5KTkF\xab\x85\x99\x83\x9f;\xb8\xa5\x87[xx78\xa8\x84\r\x9f\x1d\xd0\xcc=\\C\xe8'\f\xf1\x82e\xef\xd1y\u00bc\x03\xb6Z\xc6\u0532b\xe4\xd1}\x92\xf2\u0463i4lZzI\x14E\x15\x101`\f\xe0\xbc\xe2\xe1\xc80\x95Gq\xd0\x11\x00\xbd\xc0\x1d\xab\x8b\xa2\x04\xee\"\x89\x86\x85;q\xa0\xa6\xc5\xf6\x99\v 29\x9d(l\\\xd6\x1a\xbe~\xfd\x06\xb6vv\xbeOD\xdeMDO\u007f\xf9+\x8f\xf0\xea\x91m]\xcc\xd7\xebm\\\xb9[L\xa8o\x91n\x13\xdd\x00\x95\xa2\xe6{\x0f\x81WA\x87\xb6Ia8\x88\x8a\xafM%\xf6-\xd0\a\x89\x18Q\u0418fp4,\u0265:h\x00<\x14\xb4\xbe*$X\xc6Fv#\xcb+l!\x9b\x06|\xe4\x82JD*\xdb[\x9a{\xe0\x10\xc0n\xe9\x94\x18\x8a,\xe5\"Z\xee%\xe9\x8c\x10(\x10\xf92J\u0751\x97@6\u0556_\xa5\xf5oe*%\x80\x9cx\xd0\xccg\tyX\xbd\xa8\xb5\xac8\x0f:\xea\x01\x03\xb8M\x13\xca\aeXb\x18Y\x11\v\xb8\x94\x87\x88\xdce\nj\x1dV\x91\aR\xed\xa8\x12:\xd3\xf85bW\x1eA\x1d\xd7\v\u0731\x83\x9bi!G\x9f3Y%\xf8\xbe\xe4\x03\x00\xc1\xf4\x82f\xee\xe1C87y\xc5\u0717\x0e\xe8\xe7\x1e\xf3F\xb0i\x19\x1b\x96\xd4y\xb3\xb8\x8e\xd1q\u0449(\x1f\x1e\x02\x1f\xa5\xf6.\x18|1A\x1cU\xa7\b\xef\x83\xef\xcaR '\x0en\xe1\xd5\x0e\x80\xc2\rCq\x98\xeba\xed\x04[\xb7]\x00\xb3\x85x\x970\xf7\xc0\u28ae\xefq\xed\xda\xf5\xb3\u007f\xfe\xe7_9\a\xe0\xe9?\xfd\xd3?\xfb\x96rN\\\x17\xf3o\x83\xb5\xb5\xb5\x05\x00\xd8\xdd=\x83\xa6\xb1\x15\x94\x91Q\b\a\x17Zg\xf1Y\x99W\x9e\xe3%\f\v1\x92\xb5\u0245\x97\x85\xbeIb\x89I\xe1%=\x90\x0f\u055e +\x8aCY\x1dv\x9e\xd2\xcc{\xc9](H\xbbt\xf4\x12\xb3\x12\x10\xea\x06\x8c\x03\xe8\u062b\xf9\xd56\xe7\xe1\x1b\xe5\xee\xb9T|Fiz\xacR\x14v\xa7\x98Z_\xbd&\x1a\xf7\xa1\xc90\x05\xad\x82D\x9d\x00\xc7\x0e\xb2\x10\x90SJ^\xec(\x97\x02\xf4\xe1\x1d\xea\xf5\xf3=\x11x\xcahL\xceT\xa5\xe2\u0691T\a\xaej\x10-8\xd5Q\xb7\x86\xbe\x90F\x11\t\x1f\xf7\x92\xdf\aT\x9c5?v\xf0G\x0eXx\xf5l/TW\xb9\xb3\x0f\xc6`a\u00f0K\x81\x9f{,6\xb5;\xe7\u008fg\xd6\t:\xe7\xd0y\xc6f\xc3hM\x11\x10R^\xe0b\xa0\x1c\xd9A>X\xf8:\x0f\xf4\xbd\xa0\xef\xbd\xd2\x1d\xbdW\xe8m.\xa0.\x04\x0ez\xa9g\x0f\xa44\"\xdbN\xb0}\xf6\"\xda\xcdm\u030fn\f\u0384D]\xef\xd0\xf7\xee]\x8f|\xf9O\x1e\x04\xf0\xa5\x97_~e]\xcc\xd7\xeb\u05ae\xf3\xe7\xcf\x03\x00.^\xbc\xd0L\xa7\x1b\xa6\n\a\x0e\x0f]\xdf-\xe1l\x0f\xd9d\u040c\x13\u034b|\xf4\xba\x88\xe7\xe7,d)\x8b'\xb3\x0e\xfe\xa4\xc8\n\x95\xa0^\fv\x86`\x89r\xf2\xec\u0597\n\x10\x8d\x90\xd1O\xa9\xdc2\x98\xd9\xc5\xe3\xbf\x10@N\v\xa4\x84\x82.\xbd\x84\x87\x1a\x80\u04ce\u03c8\xc0\x1c(\u03dc6\xa3\xf2\xb2\xe8\x9c\aa\x10R\x85\x86Rm\x8aM\xd9\xe50y\x84\xa0\x8c\xb2\xab\xc5P\x05D\xaf\x1d\xe6Qx[\xc6\xe0\n\x86\x17\xe5];\x0e~[>lT\xc7\x0e\x1d\x01\x1e\x16\xdc0,\x11\x1a\x124&\xe4rV\xae\x88X\x11\x14\xc5\xea\xee\xb3\xcd\x14\xa8\xc4\u05fddc4\t\xb1|\x11s\x0f\x17\u018b`\xe9\x05\xb3\x85G\u007f\xe4`\x97\x02\xeb\xea\xefYN;d@Ae\xa7\xddy\xdf\x10\x1c\xa9\x1f\v\xdb\xfc\xba\x9d\a\x0e\x17\x1eK'\xd8j\x18\x9b\r%\xc36?82\xa9s\x80\xa0\xf3@\u702e\x03\xba\xa5G\xb7\xe8\xe1\xfa\x108\xed\x05f\xee@}T\ud19d\xaa\xa0\u062a\xca\x13\x90\xdeac\xeb,v\xce]\xc6\xec\xe0\x9a\n\x95(:4\x12\x11\x91;8<4_\xf9\u029f\xee\x01\xc0\x9b\u05ee\U0007a62f\xd7-]\x97/\xdf\x05\x00\xb8\xff\xfe\xf7\xbch\x8c\xb9\xd64\xed\x9d\xfd\xa2\xcb\xcf\x05\x11\xdcb\x8e\xc5\xec\x00n\n\xc8\x06CN\xfaB\xf4\xa2\xc5\\\xbcW\xe2o\xe9~H\xc8\x11k\x94'\x9a\x12\n\xba\x17\xc0\x05\u05fb&(\xf6R\\[=\u007f\xac\xbaX*\xf1p\xac\u01b6y\x19\xf4\xbf\xf1k\xb9\x80\x89\xfb\xe8\xa1\x12\xbbv\xfd;\uf05e\xb5\xa80<\x98\x18<\r\xa1\xc8Bu\xb0\x05Q\x96J\xa6\x02?\n\xe9Ws\b*\xe2\u0688\xea\xd7.\xe9\xe8\x0f\xc8\u0703\x0f\x1cp\x02\xf8>\x9ayi\x01\xf1\x84\",B\x92\xa8\xca\xce<\x16\x8d\xc7b\x9b\xd0A\xb0\x00`z\x825:\x18l\r\x05\u0719j%\xfe\x00W\x8f\xa9N\\0c\xbcD\a\u00c8YQ\xc2\xfe\xbd\bz'\x989\xc1\xac\xd7\xeez2w0\xbdO\x1d9\x95\x1e\xe0X\xfd\xfdD\x1c\x9a;\xa0\x9dy,\f\xa9\xf0H\xa8\"\u0590\x00\x8b^\xd09\x8f\xce\x01\x1bF\x1d\x19\xf1\xb2~\x8c\x00\x00 \x00IDAT\xbd\u03ff\xf7\xde\x01\xb3\xcea\xd1y\xb8^\xe05\xd5\x0e\xce\xeb\xc9\u0487\x19\x89]z\xd8pj\x90h#_\xdcx\n\a\xe9\x89\xcb-\xe6\x98l\x9e\xc1\xd9K\x0f\xe2\xb5\xe7\xfe\"5/\xf1\x04\xd6\u0616\xbf\xfe\xf5W\xf0\xe0\xbb\xef{XD\x1a\"Z~+\u0541u8\u0177\xc1z\xdf\xfb\x1e\n\xb38z\xcc;\xf7\xfc\xf6\xf6\xb6\xfa\xaf\x14\x86L\xbe_`v\xed58\xe9\xd0oY\xb8\t\x87pa\xed\xd0<\xbc\xfac@\xbd\xc3\xd3s\x1bR\\$\xfc9r\xc0L\u0228,:\xea!\xfb\rU\x06\xc0\xcaG\xd5\xe7\u0240\x12\x87S\x86~]\xe8r\x9d\xc0\xf7\x02\xd7+\x03$B\xdc\xec\xf5\xe3\xae\a\x163\xe0\xe4\x06p4\x03fN\xd0I\x0e7F\xe2<\x97\x85\x9aV\xe97$\xab\xaf\xbcP\xe6D\xf6\x8b\x17\x81s\x0e]\xef\xd1y\x8f\xbe\xf7\xf0\xc7\x02wBp\x1d\xc1{J\x9f\x1b_'\xc5\xea\x1a\xac\x03\xd8\x01\xdc\t\xda\x13\a\xd3\xe7!d\xe7\x05\xb3Np\xbc\xf48Zz\x9ct\x82E/\x8a/\x17\xb8\xb9H9\x89(\nZP\xcc\xc6k\x9c\xdf\x04\xcey,\x9d\xc7q'\xd8_x\x1cu\x82\xce\t\xcc\xc2\xc3\xf4\xa2F`R\xc8\xe7e\x04\f\v\x03W.\x14\xbev\xe9\xd1\u0303\xaf\x8a[\xa5\xd3pPv\x1eu\x0e7\xe6\x0e\a\v\x87\xe3\xa5\xc7I\xe7q\xb0\xd4?;Z\n\x16N}\u1f68\x8a\xd9Z\x03n4$\xda:\x82\xedC\x01\x17\x02\x87\x1f\x8cD\xe1\x1d\x16$=\x82x\a\xe9{X3\xc5\u079d\xf7c\xb2\xb9\v\xef\\:\xbfH\xd8\xd0Ofs\x1c\x9f\xcc>p\xfd\u06ab\x97\xbf\xd5\xea\xc0\xba\x98\u007f\x1b\xac\xe9t;\xbd\xff\xc0\xbb\x1f\x90\xdd\xdd\x1d\xb8\xbe\x97\x12\xb7p}\x8f\xe37^\x86_.\x81\xb6A\xbfi\xe0Z\n\x1d\"\x82\x90\xc3\xd5>\x18a\xe8T\xce2)\x14p\xa6p\xf4g\no\x99;\x1c\xe1\x199e\x92I\x83\x02\xee\a\x03\xd8!\xf7\xbdt\x00t\v\x8f~\xe9\u0447\xff\xfb\x98\xff(\x9a\u00e9\xff\x97\xf0 \x03\x98\t\xba\x03\xe0\xc6\xc2\xe0ZG8\xea\t\v\x1f%\xf4T\xc0%\xa5 ^*+\xf0\xe8\xab\x18i\x9a\xf1T\x12\xdd\b\x9d\xf3\xe8{\x87\xcei\x81u \xf4\vF7c\xb8\x9eV\x87\x8f\xe1\xd8\x1fO\ni\x18\x1d^\xbbY\n\x9a\x93\x9c\xd1Z\xb2F\x97N\x8b\xfa\xc1B\xdfN:\x85,\xa2\x16)\xbfI*R^j\xa6J,\xee\xcb^p\xb8\xf0\xb81\xf78X8,\\\xa0\xeby\x80;\x0f^\x86k\xeasW\x9eSz\xa4\x1e\x8bH\xa9\xc2\xd7\xe1g3\xf3\xb0s\u5967\xc3P\xf1\u03e3\x1dD\xe7\x04'K\x8f\xa3\xa5\xd3\xcdj\xa9\x1bX6\x0fCrP\x8c7\x1a;\xc0v!{\xd5\xd7\xe0\xbf\xf4\x1e\xe2\xf4M/\x8c$\x9bg\xdf-\xb1{\xee2\xce\xdcy?|\u07e5P\xedxk.\x97=\x98\u0307\u007f\xef3\xff\xfa\x01\x00x\xf4\u047f\xfa\x96\xc1\xcd\xd70\u02f7\u067a\xfb\ueedfi\u0513\x99\x04\xd9\xe0\xd9\xf7=n\xbc\xf8,\xdcb\x06\xbb\xb5\x8b\xaea\xf4\xdb\x04C\x0e4\xcfT1\a\a\x8e\x14<\x92\x14zL\x05K,\x9d\x95\ubf00\x02\xad\xa0\xf4\xac3j\xd6\u02f0\x1b\xc7\x00F\xa9\x1a\xdfb8\xd7;\xc1\xe2\xc4A\x0e: \xf0\x9e9\xc8\u096a\x109L\xc2\a\x8c\xdd\xce\xbf\xef\x97\xd8\u07bb\x80\xf3w\u007f\x00\xaf_\xf9j`\xf4P\xe2\x9e\v\x80W_\u007f\x03\u007f\xf5\xb5\xc7.\x02\xc0\xfb\xdf\xffAY\x17\xf3\xf5z\x87\xba\xf4\xe9\x1f:\xe7~\xa1i\xec\x8ew^}\u02a1\xc7\u0323W_\xc2rv\x8c\t\x1b\x104,\x19[\xd0\xe0\x85\xb9\x1e\x93\x1d{\x80\x03\v!\xa3\x00\x11W\xc9L\x16\u0285\x8e(\x17x)\xcdGiP\a\x06\x05{\u0629\x97\x03\xd0\xe4+\xee\xb5\xe8\x1c\xcd\x1c\xfa\xfd\x1e\x93\x13\x8f\xb6\x0f\x1d#ibO5[\x95\xb0\x01\xf9\u8ded\xf8\xf9\xf4\xa4\aL\x83~\x83\x94E\xb2\x04f\x860eB\ub056\x05\x86\x82*r\xe8\xeb\x8e2\x18\"\xc0\x13\xa1\xa0\xc6b\xe2\xc0\xe8`\xb0\x14\x03\xcc<\u06a5\x86YP\x1c\xbe\rmi\u00b55^\a\u007f\x1eY|K\x02P\a4'N\u00ec\x1b\xca\xf4\x93\xc1\xcb\x12\xd1n\xbds\x02\xe34\xf9\xa7\t'%\x13\x8d\xc8\u0086\xd8-=\xbaN\xf9\xdf.\xea\x97L\x10|E\xcfz/\xb0s\x0f\x13^\xff0R\xaf\u0718\xaa\x01w\xf8\x05s\xfcf\x81'n\x96\x1evF\xe8ZN\xa7\x86\xc1\xa0[.p\xfd\xf9'\xd0\u03cea\x8c\xa9\ak\x02HCXn\x19\xf4\x8d\xde\xf0\xa9\x93\x11\x1d\xf6a\xee\x80\xc3\x1e\xbe\x93@ P\xec\u060b\xfa\\y_\x02/\xf5\xf0-\xf1@\x12\xcb-\xc0\x14\x01\xb68\\\n\xae\xcf=\xf6\xe7^y\xceR\xe6F\xaa\xf5*\xf7yhXU3\xd4\xd9qe\x1c^\xb4\"H\x96\xb1\xbd\xa0\x9dy\xd8P\x1c\xd3\xeb\x93\x1c\xf2 \"Xz\xe0\xc43\x8e\xbcv\xde3o0\x13\x83\x13X\x9c\x88\xc5B\f\xfa\x98\xfaN\x00\xf5\x80\x9d9p\xa0\xe1\xb1S\x88a$ \xaf\n4\xa3\x04I \xb1q\xaa\xd0\v\x00\xa6\xf3\xb0\x01n)\x9fX*\xf1w\u0526\u00e8\x1b\xd5\x02\u007f\x1e\xf9;\xaf\x83\xe2&\f=\xd9\xcb*l5J0\xad7\xd2*z/\x15\xf4\xf0\xf3\x85M\x89\xe7>o*\xde\x01\xbe\x0f\xf7\x1a\x06\xe1\x1b\xf9\x9e\xa1\b\xd5t\x92\xba}v\x8a\x93s\xc4\xca#\x93%\x06G\xa7$\xa2\xb0\x891U7\xa3w\x1d\xce]x\x0f6vnG\xdf-\xf2s\x02\xed\xe2_~\xf95\xbc\xfe\xfa\x9b\xffa|-\x8f>\xfaW\xebb\xbe^\xb7~=\xfc\xf0w>\xb2\xb3\xb3\xdd5\x8dzP\x88wZ<\xbd\xc7\xc1+W\xb0\u007f\xf5\xa9\x9c\xb2\x1e\x8bvx\x13K\xe8\xa7\f\xc7\x01;\x17U.\xf6^\xd09\xa0?\xec\xd1\xdd\xe80_(7\xf9h\xeep8s8\x98\xf58\x98{\x9c,\x04\xb3\xdec\xde\v\x96}\x80%\x9c\xaa4]`\u007f\xf4^\xa1\x94y'8Xx\xbc9s\u061f;\xccc\x11G\x9d\x0fMPf\x04\xfb1,gP.\x05+JL\xf2\xc1\x9b;*\x06\x97\n\xb7p\xef\x87_\xa4*\x86\x19\x13g,`\xb0\x80A/\x9c\xb4\xb2E\x9e\x05\x9a\xb9S\b\xc0\xe5b\x13\x8f.C\xf8\xa3*\x95\x9c\x95\xba\xe4\x03-\xb0\x1c.\x04\xaby;\xf7h\xe6\xaeH\x10\x02\x06\xc9\u007f(\xffKE7N\xa5\x9d/e+\x83\xf2E\u0645v\xe5\n\xf5\x10\x86{\xf2*\u06fe\x18SS\u044dK6k\u031b\x8dRE\xcd\u00a39r\xaa\u0685\x069\x8b\xf39\x1c\xa3\f\x9e.6\xaaf\xe1`\x17>\f\x8cI-\x1bb\x17\x1d\xe9N\xd5\xc9 \x8cU}Q\xd0\xc3&\xedS5\x17l\x9d9\x8f3w\xdc\x03b\x0e\xf3\xa5\xc0.\x12\xc1\xa2\xebppp\xf0\x9f\x1f\x1d\xbcy)\xc0\x97\xebb\xbe^\xb7~}\xfa\xd3\u007f\xf3_\xbd\xfb\xdd\xef\uedb7\xb6 \xe2\xc5\xfb\xc8Y&\xcc\xf7\xaf\xe3\u0367\xfe2t\ub738\xd2U\xe0/\x03\xdex\x1d\x86\x86\xa1gT\b.\x17\x1e\xcb\xeb\x1d\xe6\xd7:\x1c\xcd\x1c\xf6\xe7\x1e\xfb3\x87\x1b3\x87\xfd\x93\x1e\u05ce{\\\x9b9\\\x9f\xe9\xe0\xf2\xc6\xc2c?\f\xe1\x0e\x97\xf5\xdb~\xf8\xb3\xa5\x93\"\x86\xae\x1e\x98\"tb*`\x89\xbe\x1b8\u0144\xe4\x94a\x9dW\x00\x99|\xaeLv\xee\u041c\xf8\"\xfc\xad\xf2\u072f\x8b\xf9\xb7\xd1\xfa\xdc\xe7\xfeM|\xf7\xf0\x81\a\x1ex,\x18\xec\x93\x1e=\x1d@\x8c~~\x8ck\xcf?\x0e\xd7-S\u01e2\x1d\xa0\xd3\xf3\xb6\x0f\x82\v\x118xx\x1e\x1c\xa8\xc3d\u035c8\x98\x13\x95\xd5\xfb\x88\u007fz\x95a\xf7=\xb0\U001024e0Z<(D.\x87\v\x8f\x93\xa5`\xdey5\x99Bf<\x8e\xc0\xb3\t\x1aQ\x88%;\xf5\r\xd9\x18\xc3\x0e\xbb\xa2\u03608\xf2\x17\x1bDs\xa2\xdd4R\x105a5e3\xe3\xd442\xc5$\xafE\xd6tR\r.\xc9I\x8d\x8d\xaf\xbc\xea1P\x04`\xef\xf3\t\u0123\xb0\x8b\x11e\x9a\u031c\xfa\xe9\f.\x97/f\x18\xe3_y\x14\x91\x82\b`\x16N!\x90N\xf2fYz,\xa4\r`0\x9f(\xbd\x04\u02bc\xcd\xc4%\xaf\xbfQ\xb4\xca5'\x0eX\xf4\xa1y\xf0\xa9\xa1\xc8\n\xd6p\xedz\x0f;\xeb\x95YS\x0e\xbf\u3f03\xa0\x05\x9d9\xf1\xc4KK\xa2tm\x12S\x86R\x8c\\\x9c%\x9d\xbb\xf8^L\xb7\xf7\u0f7e\x9eHGt\xce\xe3\xf5\xd7\xdf\u011f\xfd\xf9_\xfcd\xfc:\u007f\xf0\x87\x9f_\x17\xf3\xf5\xba5\xeb\xe3\x1f\xff\xe1\u0521L\xa7\x93\xff}cc\n\xdb4\x19\x13\x06\xe0]\x8f\xa3W_\xc4\xec\xcd\xd7@\xe0\u0288\x88\xc4\xeb0\xc8\xf5\xc1|\xcb\xc3G\xbb\\\x1e\x84\xe0:\xf5\u07d8\u0303\xcf4\xe5#u\nA\xa6\xfa-w\x87\x92\xa9u\xc3r\xb7\x12@\xa4t9v\x12X,\x85\xb0u\xd8\x05\x16\xb62\u547f\xac\xca$\xb9`q\x1f\x86\x8b\x9dO\xf4MB\xa6>&D\xa7t(\x1c\x90\x00\xf8\xc1\x1f\xf8\x18~\xff\xf7?\xb3.\xe6\xebuk\u05f9s\xb7\xff\xf1\xddw_F\xdb4U\xcc\x16\xb1\xc1\xec\xfa\x1b\xd8\u007f\xe9Y\x95H\u01ee(\x98ei\u01e2]\xbab\x8c^9\xce(>c\xaaL\x1c\xf2A\xa0\x05}\xe6\xd1,\xfch\x81\x1a\x0e\xff\x860\x80\xc88\x04\x90:{\xa7\xf0\x822=h\xe0'^\x1f\xab\x85\xea\xae0\x16\xfe\u0215O\xf3\xba\x82sL.\f\x17\x17\xbeN\xfe\x19r\x97\x87\xb5+\xe2\xb9K\x9f\xd9\x1f\x82\x84\xeb\x0f\x85Q\xd5\xd7\xe128{\xac\xf4\xea\x06\xc1\x9d\xcf\xd0G\xb1\x91f\xbeuY\u0425F>\n\xf8E\x06\u05d7\n\xf8J7\x86|Z\xa1*\xf7\x94\xea\xd3C\x89\xa6\xac\b\b\xa4\xee\u02a5t\x12\x0e\xb4J\x0eZO\xe7\x82e\x80\x0e@3\"\x13\xe4\xfa\x9d\xc0\xc4al\u0090d\xe5^-\x19WD\xa5NW*x'\xb2[\x12\x9b\xcaG\u058a\xee\xe0g/\xbe\a;{\x17\xe1\xbd\xcb\x1b\x1a\x11\x8c\xb1x\xf3\xcdk\xf8\xccg>\xfb)\x11\xd9\x01\x80\x8f}\xec\xe3\xebb\xbe^\xb7f=\xf8\xe0C\x00\x80\x9f\xfa\xa9\x9f>\xd8\xdb\xdb\xfbB\u06f6`\u00c1k\xabC\xcf\xe5\xc91n\\}\x1a\u02d3\xa3\x18\xe1[\r\xb1H\x04pN\x99\x06\xe2A\x81s.&c\xc2%\x83\x80{\xc1$\x14\xf4lBU?\xectJSJ\xa7\xb4\x91\x11\xdePJ\xe2\x00.\x19<\xb0\x82\xa2\xed_\xc9o\x96\u02ba5}\xdf\xc2@\x8a\x05hO<\xec\u04af4\xa1c\xf0/8\f\xf3\xe6n\u0415\a\x16\x8b\x8c`\xf9E\x9b\x1f\v\u06eaD\xb6\xa8\x86\xc1k\x9e\x9d\xa8|\xdd\xe7\x93\a\xf9P\xec:\x19\ud307\x8c\x9c\xea4Q|\xbe]ze\x89\xf8b\x17\x93\x9b\x1f \xe8\xb4\x1dz\xe0\x9f^}\xef\xb8\x11\x10\xb41\b\xc3\x15\x9e;U\xbe\x96\xa6\x95\xc1K\xc7v\x92\xbfF0\u02eaY/>\xe1\xec\xbe4v\v\xc5\xdb\xc7\x01k\xf8\xfb\xf8\n\x15\xf2\xe3tO8\xd7a\xb2q\x06\xe7\xef\xf9\x0e\xdd\xfc\xbcK/\x9c\x8d\xc1\xc1\xe11^}\xed\xb5\xef\xfbG\xff\xe8\u007f\xfay\x00\xf8\xc1\x1f\xfc\u063a\x98\xaf\u05ed]Dtt\xd7]w}\xfe\xe2\xc5\v`f0s1\xe8\x13\x1c\xbc\xf4,\xf6_z\x16\xc6\xd8,n\xf1>)\xe7\xbc\xf8<\x14r\x1e\xe4\x94\xc6\xe7M\xb0\xc1\x1d\u0d26WS\xa5f.\xc1r\x14+\x18\xab\xa1\x12\xd7\x1cU\xe1\xd7E \xc8\xf0\xb9\xf7\xa7\x88XV\xc1\xe1\xb2\x1e\x92\x14\x03O\xc9\xe3M\n\x02\"vY\xb0c\x9c`\x12\x06\x99+\xf3\xbf\x016-\b\xdd\xf1R\x8a\x84\xc8\xe0\a\xe3d\xe5\x1fJ\xb1C\b#\xa5<\xd5s\x88\x81\xca*b\xfeN\u007f~^\xe6\x0e\x9dD\xa9\x9a6\xc0C\xa3\x90\aF\xfc\xb1\n\t)\a\xbe\xbdv\xe5\xa7\u007f\x8dr\x97X1\x1b\x1b\xd1l\r\u060ai\x86\x13?\xe2 J\x10\xa7\xb3\x06\xbb\x90L\xf1\x14\x9d\t\u0639\xb2W\xf4z\x06\x8f\x98\xd8]\x87\xc1e\xa4\x12\"D\xcb\xd5\xd9\xdbTZx\xe6{\xae\xb8\xc1\xa2\xea\xd3\xf5\x1d\x8cmq\xe9\x81\x0fcs\xe7|\x8a\xac\x8b\u0670ll\xf7\xd2K/\xe3\v_\xf8\xd2/\x8a\u021d\x00p\xe5\u02b3\xb4.\xe6\xebuK\u05af\xfc\xca\u007fE\x00p\xe9\xd2\u017f\xb8\xef\xbew)\x9c\x12&\xfeD\x00\x1b\x8b\xa3\xd7^\xc4\xfe\x95'\xc0\xd6Vj\xf8H\x0f\x13x\x888\x888\xc0\xb9\x14\xa8\x9b\n:\x90\x94\x82\x1c\xe0\x05\xd3\t&'\x0ev\xa6V\xba\x15d1H\xa5\xf7#X\xb9\f\xba9v\x81\xc5\xe2O\xa3\xcb\xe5b(R\b\x8aV*L\xd1*\xa6D\x8b\x88o\xe7\x0e\xddvZ\xe0J\xd1\f\r\u00c4(C3\xe4jy+W\xcaI\xaa\x8bz\xd9\xd9S\xd1\b\x13%\u07d5\x15nf\x81\xfbG\x0f\x97\xf8\u0112\x00v\xe1t\x18:\xac_\x18H\xff\xa9 \xf6\x84\x8d\xc4v\x82&Z\xc8V\xf0\x04\x9d\x82w\xadZ\x13\x97\x11v\xe9\xe4B\x83kV~\xc5\xe81\xe0\xf3\xa0\xd8,\u00bc\x82\tv\xa9\xe2 .6\xad\xfc&\x89:\x1b\xa3\xb2\xa9\xb0\u01e5p\x8f\xb31\xfa1(\xdd\xf3\\\xec\xf4\xe2k\x1e;\xe0\xe1\\\x87\x9dsw\xe3\xc2\xfd\x0f\u00c7\xe1\u007f<\x1a6\xed\xc4^\xbb\xbe\x8f\x17^\xb8\xfa\xf0o\xfd\xe6?\xfeY\x00\xf8\xd1\x1f\xfd\xeb$\"\xebb\xbe^o\xff\xfa\xb9\x9f\xfb9\x01\x80_\xfa\xa5_|\xf5\xce;\xef|\xacm\xda\xec\xdd\x1dD\x14\x8b\xc3\x1b\xb8\xf1\xc2Sp\xf3\xe3\f\xc1 \xe3\xe6)\xbd\u073b\u0421\xbb\xc0\xb4\x90\xba\xdb\xf5\n\x85\x18'\xb0\xbd\xa0YxL\x0e\x9dJ\xe6\xe3\xb16\u05e4\xf1\x8e\xfa\x94\x8e\x90]\xe0\x97\xdf\xec\xe8_\xbd\x16I^\x1d2\u0491&\xaf\x16\xd4dA*\xbeV\xbb\xd0P\x05\x19qy\x8c\u03efYFW\xc1\xac\xd8DE\x9b\x1b\xd4\xf3\"T5\x16:\x1e\xebn\xe9\xf4\x83\a\x05\xf6\x8dv\xe2\xc1\xaa\xa0W/\x18ve\x98\xf7MN<\xc5&\xd9,|R\u050e\xa4\x88\xdc\xf4ZW\xaf\xad \xa3\xa4\x82=\x8c\x8d\xca^\x0f\xd9K\x05ZX\xa9Sv\x8e]\n\x9a\xc0\xa3\x1fK,\x11`esY\xb9FD\xf5\xe6\x01\xaa\xff,J\xfb\xe3\xe6D:\x87\xe9\xbb\x05\xect\x13\x17\xde\xf5\x1f\xa0\x9dn%\u07bb\x04\xdeU\xd3N\xdd\xd3O?\x83/\u007f\xe5+\u007f[D.>\xfa\xe8c\xfes\x9f\xfb\xb7f]\xcc\xd7\xebm_\x1f\xfa\xd0w)&j'\xcf\x186\xff\xfc\xfc\x9d\xe7\x035\x91**\xd7\xf5\xe7\x1e\xc3\xd1+/\xc04\xadv\xe0\xa5\xf1G\x14S{e\x1c\b<\xc8{eYt\xf1\x18\x1ce\xeb\xc1;\xc5i\x81\xb1\v\x8f\xc9A\x8f&J\xb7\x8b\a\xcf\xd7\xf4o\fO\xc7\xe5\u0411:\r:&\x8f\x82_>\xa80\x05$\x91\xeb\xd6\bH?\x14\xfc\f\xb1\xf3\xa285sI\xf8\xb9\x14\xafKB!\xb4\xa1\x9b,a\x1d\xf6\xa5(iX\x1d\xa9\xda`(%\xe2\x14\xf0\x0f\x8d\xb4\xd3\xe5F\x83<\f.C\xb2\xb9\xd3\xd7s\x1a#h\xac\xb8\x9b\x0e\x85@\xe8\x94O:\xfd\x0fW\x85U\x18\u02cf\x1a\x9c\xc8(\xc7\xe3\xb1\xcfg\x01\b\xd0\xcc=\xda\xc3\xc0s\x97b\xd0.\x999U~C\xa9\xe1\xc4B\xec\x15\xa1\xc2\xc8]\x8f\x12\xfd \"\x8a'T\xa6,\xff\x0f\xafD|\x8f3\xe7\xef\xc5\xd9K\x0f\xc2\xfb\x0e\xd9\x17\x18h\xda\xd6\\\xbb~\x03O<\xf1\xe4w\xfd\x93\u007f\xf2\xbf\xfe4\x00|\xe2\x13?,\xebb\xbe^\xb7d\xfd\xea\xaf\xfe\xb7-\x00\\\xbct\xf1s\x97.]\xd2b\xce\xf9\xcc\xcd\xc6`\xff\xc5gp\xe3\xca\x13`c\xab\x87(S\f3\xd4\"\u0781\x9c\x16\x00vJ\xe9\xe3h\x0eUL\xdd(\u061e\u0699C\xbb\xdf\x05N\xf4\xc0s|\x80qc\x88\x84\x14\xf6\xb0\xb4\xc2C\xce_\x84N\x03\x89cM-\xe3L\xab\xe8\xa2\"^,\xbc\xde\xe4\xa5\x12\xbeo{\x1c\u0516\xa8\x94\xf0\u02b4XH\xe5\xd8WBN\xe3\xfc\xbcS^\xa3d:\xa0\x10\xad\x0e\x15\x8bo\x1e1e\xd3\xf9`C\x90\xa9\x8a6\rC\x05r\x93\x1a\f\xd2Aj\xb3Tj#\xc9i\a#y\v\x10\xfe\x94\xfa\x9e\xb8\xfa%\xf5\x05\x95\x8fx,\xd2\x19W'\x95\xf9\u03dc\xdeO4vB\xc9>\xe8\xc4\x14f@Y\xe1)\xc3\x13\xc9\u0419\x11\x12\xfc\x85\xa2w\x8b\xcfP\x1f\t\xd80\x9c\xeb\xb0y\xe6<\xce\xdd\xf5\xbej`\"\x04\x80\x19M;\x91\xc7\x1f\u007f\x02\x9f\xff\xfc\xe7?%\"[\x00\xfco\xff\xf6\xffA\xebb\xbe^o\xfbz\xf7\xbb\x1fp\x00\xf0\xf7\xfe\xde\u007f\xf3\xdc\xed\xb7\x9f\xfb\xea\xe6\xe6\x14q,\x19\x8d\xb7\xba\x93C\xbc\xf9\xd4_\xa2;\xba\x0e\xd3\xd8|T%$\xc3\"}\x8b\xb8\xb9\xcb\x0eX)am\xd10Ka\x16\xea}\xba\xa7J\xe8>\x9d\x98R\xfa7W \x8a\x14\x9b\\:qb\x10[\x18\xed\f\xbc\x87w^\a\x9f(\xf3R)\xcd\f\xc8Z\x9c9\u007f\x0f\xa6\xdbg\x83\xcd@\xaa\xf80\xb6\xa5\xfd\xfd\x03<\xfb\xecs\x9f\xfe\xb5_\xfb\x1f\x1f\x06\x80\x9f\xf9\x99\x9f\x95u1_\xaf\xb7}\xfd\xc2/\xfc\xa2\xbb\xed\xb6\xdb\xccd\xb2\xf9\xc4m\xb7\xdd\xf6\xff\xdd}\xf9.\xf4}/\u027c?@\x02\xaf=\xf6e\x1c\xbe\xf4,l3\t\xceq>\x1dU\xe3\xfb\xd2;\xf8\xbeW[\\\xef\x8b\xe3o-\x91/\xebP,\x90f.h\x0e\x1dh\u9aeeQd\xbcq\x8d\x0f\xbd\xe9$u\xbb4Zf\x8ax\f\xa1\x9a7\"7\xb9\xbb\xa5\xc6\xc8++\\\xaf\x05\x9b}\x10\x13\x85anb\xb0,\x94}\x81\"H\x19\xa1;&?\x024\xc8\xc8&\x82z H2\b`\xae\x03W\a\xf0svd\xa4\xbe\xe0\xca{\xa8\x0f\xf9|\xd5\xd9+A\xc4\x1c\xa9\xf8s\x1a\x9c\x16\xc5\x10z\xe9\xb1{\xe7\xdd\xd8;\u007f\xafr\xe1#t\x13\u00a4A\x8cg\x9e}\x16\xaf\xbc\xf2\xea/\x8b\xc8\xc6\x1afY\xaf[\xb2\x88\b\xbf\xfe\xeb\xbfF\x00\xf0S?\xf5\x93\u007fy\xf1\u2965xob\"\x9a@\r\x85N^\xff:\xae_y\x02\xd2/a-g\xe7\xba8\f\r\xc5\\\\\x0f\xdfw\u06a5\x8fv\xd6T\b\x8f\x8a\x01\x97\x17\x98\xb9\xba\u5c53\x95;N\x06tD\t\x1d\x99\x06<\f9\x8c\x94\xc3\x1bP\x93\xffd\xb5\x8dEYOO\xeb\u042b\xfa\x19\x1c\v9t\xda\xe4\x94niB\xb0\xb1Y\x043\xad\xd8\xfe\x06j!\xb9\x01\xbd\xaf\x1c\x02\f`\xa5\xea\xba\xd1\xc8\xfb\xe5\xbf\x1b\x1c[\xa4\xd8\x00L\x1f\x95\xa7\x92\xb1\xf3Y\x98e\f\xf6\x85\xb8!\xc488._\xaf\xe4L%\f\x83\xa7Qdq\xa6\x8f\a\x89Ho\xb9Jf\x8aT\xc1\xcf)t[\n3.h\xf0\a\xa1\xf0\x81\b\xefk\x016 6A\xe5i*A\x9c\xe6\xd4r\x1a\xf6S\xe1\u0260\x11\x82yc(\xad\x99=A\x83\xa2\x8d\u00d9\xf3wb\xef\xfc]yK\x8a\xd0\f1\x88\rn\\\xbf\x81\xabW\xaf\xfe\xf0\xff\xfd\u007f\xfd\x9f\xbb\x00\xf0\xc5/\xfe\x11\xad\x8b\xf9z\xbd\xed\xeb\xe3\x1f\xff\x98\x03\x80\x1f\xf9\x91\x1f\xfb\xfc\xe5\xcbw}\xf5\xfc\xf9\xdb\xd1w\u02fe\xa4Uy\xd7\xe3\xfa\xb3\x8f\xa2?\xdeGc\x1b\x18\x04\xaaWY\f\xc5C|_\x99\x11U\x02\xf5\xd8\xed\xc6G\xa5\xe8\xdac\x92\x85\x9diA''\x95\xd7I*(\xa5wy\x18\xf4\xd1P\xc82R@\u0190\x02\x19\x83~G\xf3\u03a4\x1a\x8cR\xb4\x9c\xf5\x99\u007f\x1e\xfd[\x9a\x90\xc0\x13\xa7\xadTl<\xa3\x85\xfc\x1b\x01\x9aO\x83(d\x84:B\xb5\x1b\x19I\x18\x86\x16p\x8bYJ\xa2*\u018d11X:\x81\r\xb2\xfd\xa4\xac\x8c[aAK\xadh\x84+\u01bac\x9b#N\t|\xaeOP+\xe8Q\x18jK\xf5\xb3\x87\u035b\t\x9eB\x91M]=\x03\xc4\xca\xfd\xe6P\xd0\xd9d?\x18\xc4 \xf1\u0708\x94\xe6]\x12/\br\xb7\x1d\x87\xd7>\xd0:M#\x98\x9e\xd9\xc6\u0785{a'\x1bJS,n\"6\x16\xce{\xbc\xf0\xc2\vw\xbd\xf0\xc2\xd5\xef\x02\x80\xef\xfd\xde\xef\x97u1_\xaf\xb7}\xbd\xe7=\x0f\xc9#\x8f\xfc1\x11\xd1\xebw\xdcq\xfb\xffs\xee\xecYx\xef\vb\xb9>\xba7\xae<\x89\u064d7u\x10JE@3\xe7\aL1G\xa5(\xd2\xe0!\x1d\x01Z\x93qU\xc4H\xe1\xb5sl\x8e\xbd\x8a\x8a\x06Tp):6re\xfaN\x81O\xd3\xd8\xd9\xff4\xcd=U\x8a\xc8\xf4\xc5eDj*\x03)}`\xe7D\xb7\xc6f\xe6\xd0\x1e\xf5)\r\x88J\u067f\x94\xd4I\x19\x96\xbd\u0453\xc0J!\xfel\xff\xee\xdf\xfd\x9bu1_\xaf\xb7\u007f}\xe4#\xdf#\x00\xf03\u007f\xeb?\xf9\u02fd\xbd\xbd\xeb\x8d1\x94\xe4\x99\xe1f\x9f\xddx\x1dG\xaf^\x85\x13\x0f\xb0Y\xc1\xbf\xd3\xc3\xe9\x1d\xc4wY}W\xe9\xb0\v\x81J\x10\xc2\xe815\x14\x1e\"\x8dm;V\xbbU\xc8\xd0]\xaf@/\xfa<8,\x83\x12\x12\xaf\xbb\xc4%\xe4\x14\xfa\x9fHE7\x8c\x83\xac\x92Yq\xca>TI\xe9\xb9W\xf6\x8aI\x83\xcf\xfc\x99\x9c\xe4\xfbC\xea\xdc\x18LR\x1f\bV>(m$\xcbPb\xbay\u05df\xbas\n\x19\x9e\u02c0\x9d\x17\x97\xc8\u012e<0\x91\xeaW*\x83\x83K,\xd82\u0632CQ\xa7!\x14\xb4B\x16\\9\xfdH\xc1<\x1a\v\xd2(0\x12\x80\t$\xa1|3\a\xf8#\x8a\u07b8\xf0K\xa6*\xfb4m\xac\x83\x81\x01\x11'\xd4=J\xffS\\!)\xa4c\r\xc1X\x02Y\x82\xa0\u01d9K\x97\xb1s\xf6N\xf5t\x8e\u015c\t\xcc\x16\xc4\x16\xf3\xf9\x1cO>\xf9\xd4GD\xa4\x01\x80\xcf}\xees\xebb\xbe^\xb7n}\xe8\xe1\x0f\xff\xdb\v\x17\xee|~oo\x17}\xdfgO\v\x01\xdcb\x86\xebW\x9e\x84[\xccA\u01aaA\u007f\xc1Z\xa0\xf4Pz8\xd7\u00fb\x1e+\x86\xaaT\f\xa0\xca\xce8P\xfe\xa2\xb8\x86\x9d\xa0=\u0283\xc5\x15\xf1G\x90\xf0\x93_\xc5P\xa4\xea\xe2\x8a?/\xa8\x8bc\xf6-\xabX\xb6\xa4\x0en\x98@A\x85\x95\x00\xb9\x82\xe5\xe2\xf2\xd00\xc1+.G\xd9}ckL55\xb0\x88\x1d\u0242\xab\x93DkH&BA\u9be3Mnd\x10\x85\x84\x9f(\xf6\xa2\xb7\u45a7\xe9\x04\xc6\u0520r\xcaah\xe8\xb78\xfc)e\xa4\x87\x8fT\xd9\xf45\x83M\x04\a\xa8\xab<\x19\u0122\x9aN\f\x12\x06\xf4Qz_@Q\xb2\x12*\x121s\xb5\xb5\xe0\xb09H\xe8V\x98\x04l\td\b\x04\x87\x8d\xdb\xce\xe0\u031d\x97al\x1b\xf2I\xf3\xa9\xc2X\x8b\xc5b\x81'\x9ex\xe2\xd2\x17\xbe\xf0\a\xef\x06\x80\xbf\xff\xf7\xff\xfbu1_\xaf\xb7\u007f=\xf3\u0313\xf1A8\xb9x\xf1\xe2\x1fmnm\xa6@\x80\xe8$\xd7-\x17\xb8\xf6\xdcc\xe8f'*\x87\xa6\u0324\b'\xe2\x80C\u01a3jW\u3728\xbb\xd3\xe8R\u0211\xd5\u0485\xa2\xe7\xb2_\xf7\xe4XM\x9ed\xa5\x98K\xea\x80\xe9\x14%\f\x8d1%\x86\xe1\b7+-C*x]*\xb3\xfa\xb5\x80Q\u022b\xcb`\x12\xfb\xf8\x82\xc5\"\xa7\x15lz\x8b\xc2.\xab\x88\xd1h\\\xdb\x10Y\xa2jf\xaa8x\xac\x87\x14:q\x1fT\xa2\x8a\xa3\x93\u01ea-\x02\x9dVvW\xdfJ\xa0\xa5R8\t\xaa\u079ep\x9a\xccW/:G\u0604\u00b9\xa0l\x00L\xf8\t\x9cT4\xcfT\u04a5(\xe2\x12\xc2\u028bBO#\x9d\u007f\x86Z\x8a\xcf#\x82p\b\xb1f=\x8cRCZ\xe4\x01\x90e\x9c\xbb|?\xa6[g\xe0\\\x9f\x8b9\x11\xd86Xv=^~\xf9\xe5\xc9g>\xf3\xd9O\xc5\xd7\xf8\x87\xdf\x04\xc1\x15\xebb\xfem\xbe\x1ex\xe0\xc1\xf4\xfeG?\xfa\xe1?\x9aN\xa7G\xc6\xc4\xcc\xc30\xc8\xf3\x1eG\xaf\\\xc5\xc9\x1b/\xa9\x10\x83\xb9\xa8)\x02\x1f\x06R\xca=\xef\xe1]\a\x1fb\xb6\xea\xb0\xc7\xfc\x9c\x97\xf1g\xe4<\xa8\xf3\u025f\x1b\"\xe0e\xe8\xd0\x175\xf7\x90\x12\xcd/\x17M\x00xK5\xcc\x18>]\xb8\x14\xd6|\xc4\u0560\x86R\x0e\x9e\xads\v\nf\x18\x8e\xa6H\xa8M\xd9\xc2\x00\x00 \x00IDAT8)\xbcXV\xeclO\u00cf\xdf\u00bf@\xc6\xe1\u007f9\xa5\xa9\x97B\xa8e\x96>\xd1\x15c\x88E3\xd37\x13\x95\x95n\x84\xbb=\x80\x97\x86.\x8b\xa5W\xfa)\xad\xf6MN\x1e#\u007f\x9d\xfcS\f\xc8\x18u\xe2\fp\x8a0\xa7\xcf\xe3\xa1\xe3b8\x19\x96\xfe\xfbz\x8f\xac\xc2\\\x91\xd1R\xe3\xff\xf9\xdeT>>\xc1\x18F\xc3\x046\x04j(\xcfTHp\xf6]\xef\xc6\xd6\xde\xed\x99\tC\xf1k[x\x0f,\x16K\xbc\xf0\xc2\xd5_\x14\xd1v\xe4\a~\xe0c\xebb\xbe^\xb7n\xfd\xec\xcf\xfe\xed/\xdc\u007f\xdf\xfd\xf3\xad\xadM\xb8\xbe\x17}(\x14W\\\x9e\x1c\xe0\xe0\x85'\x01\xef\xc0\x86S\"\x83\x88\x04?\xf3l\xbe\xe5]\x97\xa0\x96\x88G\xe6\u0388*\x0eu6\xb6\xaa\x8b#\xa0I\xf0\xed\xb1\x03\xf7z\x02PEcY@G\xf0\xd813\xaa\xb1z)\x03\u0339\xc4\ah\x1c+\x18\xfa\x81Se\xbaNE\x96\xe5[\xe1*CE\x10\x9d\xf2\xe7\xc5\xffK|\xa8\xe2\xce\xe5\x01\xb0\x9c\xe67&\x85\xd4\xdf\x15)J\xc9#\aI\xf1\xba\xf2\xbdG\xf6\x17\x19\x19gF\xd8'\xceB\xeaKwsc\x97\x15\x9az(\xe4\xc4\f\x84\x82\xee\r%\xd8#\xcd-\x80\"\x14e\xe0\u0452\x9c\xc5hpU\a\x11t\x81\x01C\x05\xc5QBRJct\xf0\u026d\x01Y*\xf2p\x1d\xb6\u039d\xc7\xf6\xd9\xf3`b\xddD\x8a\xae\xde6\xad\x1c\x1e\x1e\xe2\xd1G\x1f\xbd\xf8\xf9\xcf\u007f\xee\xaf}\xb3<\xdf\xebb\xfe\xef\xc1\xfa\xa7\xff\xf4\u007f\x8b7\xe3\v\x17/\xdc\xf9\xc5\xe9\xa4\xd5\xea\x1a\x8f\xad\x04t\xb3c\xbc\xf9\xcc\xd7\xe0\xbb\x05\x989\xfb\x92\xc7F,>\x04\u041b\xdd\xf7\u02d0+\xba\xda1V&V\xa5\xb1\xb6HV]\u01b4\xa2\x85Gs\uc495k\xeavob\xfe$\x83.x\xd4\xc1\xae<\xdd\xcbi8\xb5TM5%\xbea\u0465\xcap\xa3\xa8\xf39+S(\x19:\x0f\u07ac\x1b\x1f\xf9{\x1a\x9e.$'n\x14\x19\x11\xa7\xa62E\x05k\xf8\xa7v\xa16\xb3\x11\xb2\xc8\tH\xa74\xd3R\xf2UJ)S1\xad\xa6\xb7\x8a\x1b\x1a\xf9\xf3\xe1) u\xe2\x041\f\xd70\x94\xde\u007f\xf0\xbd\xef\xfd\xe2d2\u0566&\xa5\xa2\x13|\xdf\xe3\xe0\xe5+\x98_\u007f]\x99\x03\xc9\xf1\x90\xaa\"\x1d\xe5\xfd\xcew5v>\f/(\x9eB*\xe2\xdbb\x06g\xe4g\xb3\x13\xb43\x87\xf6\u0105\xa1\xe7M\x9c\xb8V\xa8\u007fr\xd3#\xbe\xd0\xcd\x0e\xffR8\rR\r\xe5$\xde{\x194\x11_\x17UFP\xdf\x10\xbcpj\xbd\xa3\x9b\xd7\u0081mp\xec\x8c\xc7\x10\x9c$\xc4q\x92=r\"\xa7<\u57be\xb5\xbeE\xc6@\x962TCd\x10\xed<\xdc\xedFH\xe8%\xbd4P\x01\xc50\x84\b\xce0\x96\x1b\x16\x8e\xf5c\x98\x907;2'\xc8E\x9c\x03\xee\x1e\xf9\xe6\x8cA\xe0g\xb5\x1b\xe4\xc6D\u007f\u007f\u0094\xbd]\x02\x8b\xa5\x1a\xf6\x8aR\x16\xcf\xdcu/\u068d\xcd\xc4j\x89\xd1sD\x1c\u063a\x1eW\xaf^\xfd\u8e98\xaf\xd7-[\xef\u007f\u007f>\t>\xf4\xde\xf7\xfe\xebK\x97.\xa1i,\xbc\xb8P\xd4\xf4A\x99\xdfx\x037^x*Q\xc4R\u0716\xe4\x87\"&O\x88\xef\xe1\xfb%\x10x\xe7\t\x8fL\x83\xa6\xa2\xc8\xfb\x12w\x8e\f\x11\x9f\x86\xa2\x14\x859\xc7N\xa9s\x812&\xb4*\nO\x1e\xd6TW{Yq\u05ebq\xf3\x9a\x98!#\x85\x8b\xc6an)7\x10\x1a\xc0\xf7rJm\x96Uo\x93\xb1#\xc3J=\x1c\x16w\x1a$,\x15\xc5\xea4\xdb\xdc\xc0\x8fO\xc3\xda\x12\x16\"T\xac\xf1\x15\xcf\xf2JDu\x9a\x1b\x1a\xa1\xb6>\xa7Qx\xa9d\xe0\xd0\xe0\x8ax\xd6\xee\xdc4\x16\xbce\x80-\x86oY?\x87\x00c\x18&\f\xe2I2\u03fb\xf6\uf29b\x8c:\x03Q\u0237\x8dM\xc8*\xbd_\xcd}\xa2\x10\x89\u00d1\xcd\x1b\xf5\x04\x8d3\xa4\b\xd1\x10\x11v\xee\xb8\x18\xc4C9\x10#\xfeLM;\xa57^\u007f\x13\x8f?\xfe\u0136\x88l\x03\x99l\xb0.\xe6\xeb\xf5\xb6\xae/\u007f\xf9K\x04\x00?\xf6\xd7?\xfdg\xf7\xde{\xf7\xd3M\xd3hDVR\xdd1\xe6\x87\xfb\xb8\xf6\xdcc qJ\x1b\xa3\x82\xf6\a\xa9\xfe\vx\x88\xef\xe0]W\xe0+EWKuzs\xec\xce5\xe5G\x87q\xa5l\x9ez\u581bE\xf0p\x19\xaad\xe8f\x92\x14Z%\x91\x8c\u06a7\x8eu\u01b2\x8aU\x8f\xd6\u027a\xf3\x8b\xf8\xf9P\x12Ie'\xff\x8d,\xba9\x12S\xa6\xf7\xe4\x14zI\x85o\x05\xe2\"*\x04WaP\xeb\xc7\xe0\xa2\xe1\xf5\x93\xe2@D\xd5\ub5caX(\xab\xf6\x03\xdf\u0211$\x16X\xd6n\xb8\x9dXl\xec\xb6\xd8>\xdb\xe2\xccn\x8b\xad-\x8b\xa6a\xb4\x86\u0476\x8c\xa6UL\xdb2\xea\xc0\x0fP\x96\xebG\x8f\x97\xb2s\xe7\x12#\xaf\xef\x17\x1f\u031c\r\v\x98\x00\t,\x96\xd8\x1c$\xff\xf3P\u0427{g\xd1n\x9d\xd1\xe6\"]\x1f=c\x18cp2\x9b\xe1\xf0\xf0\xf0\xae\xbf\xfa\xab\xbf\xf8\x00\x00\xfc\xf1\x1f\u007fi]\xcc\xd7\xeb\xed_\x1f\xfe\xf0G\x03M\x9b\xbaK\x97\xee\xfa\xbd\xe9t\xa2\x8f\xacw\xc1\x82\x9f\xd1\xcd\xe7\u063f\xfa4\x96\xfb\xaf\x83\xad\xc9).T\x14\xe4\xf8p\x06E\xa8s]H5/\xf3\u054ad\x9a\x92\xba\xe8\x8a.\xdd\xe70\t\ntE\xd3\x05VF\x80\n\x84Vs2\xa5\xd0\x12\xae\x18\xb7~\x03\xfc\xe9(u\x8c\xc3\u0541\x04i\xd0c\x16'\x848\x00\x1cD\xbfU\x1c\xc7R\x19:\xdc0d\x9c\xaaBc/\xa0\x1c\xfcRNQ\x1a\xe2\xff2,\xfcaX\xb8\xaa\x16- \xa14\a\xac\x8d\u0525\fz\xc6MR\xb6o\x86\xb9W\x1ba\xcd!\x8f~\xf0d\bm\xcb\xd8\xd80\xd887\xc5\xd6\xde\x14\xbb\x9b\rv\xce4\xd8\u07b6\xd8h\x19\x8d\x01\x8c%\xd8\t\xc3\x1a\x0e\x8c\u0161\xd9\x0eU\xb9\xaf\\\x9aq\x85W\x10\xa3\x12\x95\x88$A\xb6Oh,\x83\x1b\x02O,LksFn\x81\xbd{\xefa\xa6\x1b\xd8>\u007fIgH\xdeW\x87\x18f\x03\xef\x81\xfd\xfd\xfd3\xbf\xf3;\xff\xe2\x12\x00\xfc\xb3\u007f\xf6\xdbx\xea\xa9\xc7\xd7\xc5|\xbdn\xddz\xcf{\xde\xf3G\x0f<\xf0\x80>`\xde\x05\x99\xa6b\xc8'o\xbe\x82\x83\xaf?\acl\xa8\u0252\x1f\xcb\x02\x1fW\xec\\\xe1\x96\xca|\xab:\xfe\x8f\xb4\x99\x1e\x95?y\xea\"]\xc6\xd1c.e,\x9c\xe9\x9fS\u0462\x0f3\xccV \x90\\\xfch%\x03\x13\x99\xdf|\x1a\xb6]R\xe2X\v\x87p\x8ex\x13*,\vF\v\x1c\u0764 \xca*\x82Q\xc09\xaa\xf5\xa1J\x81+\x18\fr\x19\xc5F\xa3\xd7\xc93\xe0\rF\xc83\xc5FC#\xdb\x16\x8d\x1b\x98\xd1\n5h\xc0R\x1a3\xa3/60\x1a\x02YD\xb0\x960i\x18v\x8baw,l\xdb\xc0\xb0\x81\x99\x18\xd8M\x06\x1bE\xc4\r+\xef\x9b-\x83,\xaf\xe0\xe1U\xe6I:\xb5D\x99~hB0 \x06\x91\x84\xd9+\x81\f\x83\xdb\u0415\x97A\xd8\xe1g\xf0\xe2\xc1\xd6b\xe7\xceK*\xa4\xf3!\xa0%\u078fLX.\xbbn:\xdd\u061b\xcdN>\x01\x00?\xf1\x13?\xce\xefy\xcfC\xebb\xbe^o\xff\xfa\x87\xff\xf0\xd7\t\x00\xee\xbd\xf7\xdeG.^\xbc\xf8jc\x9bp\xe3\xea\x83\xc0\xd6\xe0\xe4\xfa\x1b\xd8\u007f\xf1Y\x18\u02e3]nv\xec\b\x959\xf0\xce!\xbe\xa0r\xdf\xe4\x1c.\xb5\xba3\xc2.)\xa9'\f\xeb\xa2\x19\x94\x84\x81\x95\u0400!B\xb4\xc2\x1d\xaf_\xaf\u0704\x0f]\xff\xd5X0\x03\r`\tg\x19\xae\x89\xafC\x8a\r\x81\x060\r\x12\x1bf\x15\xe2\x19\xf1\xfd\xa5\xba\x97EQP\xca\x19\xc4\xf0\u02d4\xbe&\xf1\xfa(;$~\\\x0fM\x85W7\x9b\xb1\xba^l)+\x93\x05\x1a\x83\u042bv\u007f\x15\x98!\xca\xef3k17\x13\x02\xefZ\xa0\t\x12\"c\xd5\x17h\xa3\x05\xb5\x16`\x1dp2\xb4\x93G\xfc\xfd\x13\xaa\xe3I9\xbbH\x94\xc4D\x81)\xb4\xa3\xe1\xda\x10)\x83\x85\x98@\r\ubc35\x8a\r,\f\xf5E@\xc6`\xe7\xf6\xf3`k\x03\xa6N\x15m\xd36\x8d\\\xbf~\x1dO=\xf5\xcc\x1e\x00\xfc\xf2/\xff\x1d\u007fxx}]\xcc\xd7\xeb\xed_?\xfe\xe3\x9f\x16\x00\xf8\u0527\xfe\xa3\x97\u03de\xbd\xed\xf7766re\x10\xbd\x1d\x96\xb3\x13\x1c\xbc|\x05\xdd\xecP]\xe9Rvc=K\f\xed9\xe0{H\x10\x11\x95\xb2\xe7\x8a\xee7r&\u03f0\x01\xe5\x80\xe5\x10t\x11y\xd3\xe4D\v\x91\x89l\x8a\xd3\a\x00\x8f=\xfe\u013a3_\xaf[\xb3\xbe\xf6\xb5\xaf\x12\x00\xdcs\xcf\xe5G\xee\xba\ubbbe,\xb0\"\x0eD\x8c\xfdW_\xc0\xe1+\u03e3i\x9a\xe0c\x11\x1e\x8eA\u01d6\xb2\x15\xc5\xc3E\x9f\x8c\x02\xfa .`\x05\xa2\xd5\xe3\xfc \u0693nR\xefF}\xb4G>Y\x04+_|\xb5\u03d5S\x99}eU\x8f\xe2\x92\u0254\xb1\xb9\xa7C\xba\u026e\x85m\xb9:\xfa\v\x8d\x9f\x16\b7{\xd1R\xc3\xff\x03\xa3/*w4:E\x84\x946\xa7|\r\x1a&lX\xc6dj\xd0L\x18\xb6\xe54|\xf4\xa1\xb8\xa7\xa4 \x1a\xbb\xe8\xe3q|+\xe3\x8f\x11\xf5\xd1\xc0\xb9<'%\x05\xac\xdcX\x02m\x19\xd0\x06\xe3\x14!+hja6\x1b\x98I\x8bf2E\xd3Na\xdb\x16Mka\f\xd73\x0f*7\xf6\xe8\x8cX\x9b~I\xc8\x00U\u02a3r\u02a9\xd5\u007f[Z\xd5P\xe0\x9e\x97,\x18\x81\xc0\xb4-\xectR\x04GSv\xdc\x14\b\x11\xe1\xe5W^Y\xfe\xee\xef\xfe\xee\x12\x00\xbe\xf4\x0e2Z\xd6\xc5\xfc\u07f3\xf5\x81\x0f|\x87\x00\xc0/\xfc\xc2/]\xdd\xdd\xdd\xfd\xc3\xcd\xcd)\xbc\x12\xcaCm ,\x0e\xf7\xb1\xff\xea\x15\xf8\xff\x9f\xbd7\x8f\xb7\xac*\xafE\xc7\xf7\u0379\xd6\xde\xfbtTA!\x14\x05\x04J\x1a\xa1 \x16\x02\u04bdkh\x05\x1b\x82\x1a\x8d\xb9\x11\x8d\x06\tQ\xaf\xbe\xe73\xd7\x17\xafz\x93\x97\u0118\xe4&\xf16&1/O\xa3\x98\\rc\xf3\x8c\x82J\xb0\uf0c8 J+}[\rU\xa7\xdf\u035as~\xf7\x8f9\xe7Zs\xad\xbdNU\xde\xfd\x03\xcab\xcf\xdf\xef\xfc\xaa\xea\xd49\xbb_c~s|\xe3\x1b\xc3\f\xfdh\u007f\xfa\xf1\x16$\xa6G>$\xd7\x06\xaf\xe8\xaa\x11Jc\xd2i\x8c\x01\xb6\xd4*\xd3v\xb8\x93\x8a\x86AK\x15\x9c\x0e5\xa1\xc9SW\x8d2i&a\xb4\x13\x1d5\xb9_\xa5\xbc \xe4\aht\xa6\x15\xba\x8a\u0419Q\xe8L+hE\x15\x17\xbd\x06\xc3R\u056bM\x93\u0644\x8a\x925\x0e\x13\xf1\xb5^\x83\u0268\xf9e\x85\xc6q\x87\x19\u074c\x90+\x82\xee1\xb29\x8d\xbc\xc3\xc8\x14\x95\x94QJ\xbbT\x81\r\xb2\x16\x19^\xc7\xf5V\xdf\xf5&]EcL\x98\xe2\x00\xa4=\x06\xcd(\u007f2h\v\xe0p\xfeT\x81N\xa0BXC\xe9\x0e\xb2\xbc\x87\xac\xd3\x01)\xed\xfd[h\xfc\xb5\xabT3TV\xfa\xc4\xec\x11Ny\x1f\x16\xad\x19\x943\x90q\u057f\x89\xb2D\xa1\xaa\x91\x1a\xab|\xeb\x13\x86T\xd6I\x9e\x8e\x84&h\xa5\xdc\x1a\x8eF|\xff\xfd\xf73\x00\xec\u0639s\x02\xe6\x93\xf5\u052d#\x8e8\\\x13\xd1#\xb3\xb3\xb37\x1cu\xd4Q0\xa3\x91Kydk\n\xcc?z/\x06\v;\xa1X\xfb\x12&U\x12D\x02@\xa8\x94qE\x99b*\xe1\x1a\xaf\x9c\x93d\x99\x9a\xe2\xa4}n?\x1eiym\x81t{\xc4|\"ii\x83\xee\xb5\x15\x8c\x95\xcf5sP]Li\xe8\x0342M\xd0\x04\xe4\x1d\x86\x9e\xd3P\x1d\xdf@s%\x8d\x91p4h\xabZe\x1c\xf2ZmZb\xe5\xdc\xd0\xc0K\x8b\x9fJ\xc2\xd9g\x8a\xd0U\x80V\x04\xd6\x04\x9e\u0460\xf5\x19t\x87\x91k\x86V\xa1R\xe6\u051aaO\xc6_\xe3\xc8\x1d\x1d\"\xd3MZ\xf6\xd0\x12\x90\xa0*\xc92\xf2\u0291i\x05\xear\xcdc\xb1^\xea\x87[\xeb\x06\xc0-\x15\x88\nJu\xc1y\xc7\xef\f@K\xb0E\x9d\xb6\x8a\xcf\u0445MKE3\xad\x9c|`\aPV\xe2>\x1d\xd1\x17&\"\x95\x04\xd79\x81\x90\x82\xeat\xab\t\xe0z\xe6(\x0f\x87#\x1cr\u0221\xcf9\xe6\xd8cO\x04\x80\x13O<\x91&`>YO\xd9z\xc3\x1b\xde@\x00p\xcc1\xc7\u0733n\xdd:\x80\xa0D\x9cP\x19@\xc0\xd8\xf5\xf8\xfdX\x99\u07c6,\xefTC\x87\x89\xee<\x1e\u0465\xf4\x96\xb65\x99\"\xb5\x8d\xaaK+\xea\xd6\x12\u071b\xd3\xf5.\x02\x9b\x932\x84\xbaV\xd1\u05fa\x9aT\x13z\x8f_\xe6k_g5W\x12\x02\xb2,4\xecf\x14\xb8\xabj\xb9\x11\xaa\xa7\xa0\xa6T5\x04\xd3\x12j\xbc7xlS+J\xed\x90\"\xf5\x83K\xa4\v$\xc5s\xffxY\x13::\xd2\x04\xf0^#\xd3\njZA\xf5\x14t\x06t\xb4\x0fapLp\u068f\xd3\xd7\x01y\xcf\xc3U\xe5\xc9E*\x8bc\xec\u1d4d\xbd\x06\xa5\x00\xce\x18\xd4U~\u0693\x9atT\x83\xaa\x12\x01r\xf2\xd59\xa7\x16\x02\x04h\rR:\x8c\xf3S\x12#\xc7`j\x8e\xf4'v2\x01\xb8UG\x81s5v\x1ap\xceS\x85Rg\t}\xea\x96R\xe0\xbc\xeb\x1fZ\f\x9c\x8e\xb1\x89DT\x14\x85\x9d\x9d\x9b\xa5^o\xea(\x00\x98\x9b\x9b\x9b\x80\xf9d=uk\u077a\x03\x1c\x00\x9cw\xde/\xdc\xc1\u0337\xe7y\x0eg\v\x11g|\xe3Gi,\xee|\f\xbb\xb7=\xe8\xa5cTM\xdd\u0544\x89R\xc9\x1a\x05\xce'\x11\x89\tm\xa7\x14\x8c\u0491Lj\x16\xeb5\xee 6\x16IU\xe0\xe4\x1d\x15\xa9\x15\x1c\xc7i\x1a)9\x01\x19s\u05d6\xf6\f\xe5\u06a4\x8f\xe7vuF\xe0\x0e\x81g\x94\x97\u01e5A\u011a\xa0\xa6\x95\a\xa9\xb4\xa1\xb8FSQ\u068e\x0e-\x9e\\5\xb9dT\x0fQ5\x06Z{\x96\xe4\x1b\u00e4\x80NF\xd0\u0468J3h\x86A9\x81\t\xe0\xf085\xc3\xd3/Lp\n\xb0:q*DK?\xa39\xfa\xb4\xc6ND\x8d\u05d6\x92\x97\x93\x13\x9e\x9a\xa7\x14\xa8\xc3\xe1\x90Q\x97s\x96\xbe)\xb1\x9bA\x04\xea2D\xa1\x8cx\xf3AQ\x1cr\xf0\xc2\u0670T\x1f\xb5\xbc\xfe\x8cr\xa8\x88\x99\xa02\xdf\xf8\x14\xaa\xac\x1f\xc4:\xd8d\xb2\x13hX\x00K\xa8\xcc\xf3^5\x80\x84T\xc1\xe4\xc7\xfe\xad1\x18\r}\xf8\xeah4\x9a\xd0,\x93\xf5\u052ds\xce9\xc7\x01\xc0)\xa7\x9cv\xffA\a\x1d\xf4\xc0\xec\xcc\f\x8c1\u039a\"8!\x12\xcch\x88\xed\x0f\u078ea\u007f\x1e*\xcb\u00a7%H\xbe\\\xe5']\x06\x068\a\x17\xc2+\x90D\xb6\x8d\x83\x9c\xd4t\xd4\xf5\u03a4\xd7\x00\xebL!\xef0\xf2\x8e\x1f\u91a2\xbaN\xba\xea?%\xf2f\xaa\xf3\xc92>u\xb9&\xa9\x90L\x161\x03:\xf3\x928\x9a\u0460\x9e*G\xe3\xd3\xdf\xd5S\x8c\u038cB\x96yN\u0595\xd4\u0178;\xc9\xda>-\rZ\x02i;\x93jz\u9997U\u0515g\x9a\xa1\x94\x97\xfa0\x13\xb8\xcb@O\x87\x14\x1f@r\x0f\x8c\xc4\x04M\x9e*\"\xf2rO\xa7\xa9\xee\xf9\xbe'=\xa5\x94n\r{5*\x88'\x18\xad\xbd\x82\x85\xbb\xcaS,\x94\x06\x83H\t\x98\xfe-Hc\x00}u\x9e\u6002Q\x99c\xc5Sa\u0512K\xf2z5\xe8'o\xc9\xe2)\x16Q(\xbb\x9eN\x04\xce\xf9l\xd0\xd42\xb7\xa2p<\xedb\x84\xa0:\xbd$\x90C\xea\xc2\"\x11\xb2\u01a2(F\x02\x00\xa6(&`>YO\xdd:\u3333\u4aab~C\x11\xd1\u02a6M\x9b\xee:l\xd3a0\u0188\xb3\x06\u058c\xe0\x9c\x05k\x8d\xc7\xef\xfd!\x16w=\x06\xdd\xe9\xc2\x11`\x93(\xb3\x94\xe2\xf0 \xee\x12C\xa2\xb5\x9cI\xea\xf6\xb3c\xf0!^>\x96k\xdf\xc0\u02fb\xaa\xa4\x0f\\\x18\x84\x19\x93\xc6Q\u04c0\xbc\xc1?\xb7\xc8\xeeh\rV_\xe0\xc7\xc8YyP\xe4Y\xed'-\x93\xe9\u0258\x80\u011a\x90\xcfhtr\x86\xd6\x04\xd1T\x8d\x9c'\r`\u0683\x9aE\x92>\xa04\x8d\xbbHZ&\xe5+\xc0\x12\xf6\x01\xc4Y^\xa90\xa8C\xa0\x19\xe5\xb9\xe18\x80\xc5\x04\xf4\xfc\xf7\x88\xc3\xfb\xe7\x82\x12I\x13D\xb7\xbc\n\xb2vw\x81\xd0\xf4\xea\x19\u007fK\\\xb2)\xaa\x0eC\xcdy\xae\u0725\x80\x99(^\xa89\xd1+~\x03\xa7\x8c\xc0\x91\xdf&\xa0\xa3\b:\xba+&'\x99\xca\x06(\xbc\a\xa1\x8a\x8e\xbf\xc8\xda\xd36\xfe\xbd\x8c6\xb9\xa86\x11\xa9'\xa1\xc6\x13\xd1\xc8:Xbd\u0769R\xcbN\xa9\xe82\xa6T\x85\xd4#\xff#n\x02\xe6\x93\xf5\u052e#\x8f<\xd2\x01\xc0\xb1\xc7\x1e\xfb/Z\xeb\x95,\x8c\x83\xfa\xe1\x1f\vf\x85\u015d\x8fa\xfb\x83\xb7\xc3:\x03\xce\x14(\v\xfa\xdc\xd8LK\xa4g^\xa2hC\xac\x9c\xad\u05ffM[\xd2\x16 M\x1cR\xbdicO\x81\xa7\xb5\a\x84\x10\xc2.k\x17\x8d\xb5\xbf\x8c+\xa6\xa5\xb5:o\xdeH\xa4\x05\xb4\"\xcf\xefv\xa8.QoT\xa6\xdcc\xa8)\xafl\x81\"X\x15\u031b\x90\xd2Bk\xf9\x9cP\xc3tP\xd6d\x9fR\x18\r4/\x90\x11\xb2\x8e\xaf\xca\x19!\xfalZ\x81z\xaa\x9a\xf0\f\x0f\x96;\f\xee( $F\x95U\xb6\n\x03F\rm\xfd\xf8\xabKk\x9cp$y.u\u0263V\xecO8=\x06\x05\xae\x9c\x92\xa8\xc2\xf4P4.\xa4\xf1o\x06u\xd9[\xd4R\x10\xa5\xc0\xf7?)\x9eLP\xc9\x05k\x9f5\xf6\xef\a8|V\u00c0\x10$-\"\xa8Rf\xc1\xf7c$\xfa\xbd\x130\xb4\x82\u0551\x83\x03\x81\xb3,\xf9]i|\xac\xbc1\x1c1=\xed\xd7\xf4\x04\u031f\xa1\xeb\xcc3\xbd\r\xf3\x9b\xdf\xfc\x96\x1f\xaf_\u007f\xe0\x83\xddn7T-\x0eb\x8d\u709d\xc5\x03\xb7}\r\xfd\xe5\x1d\xc8z=pF\x90\x8e\x82\xcb\bN{\x1f\x10\x1f\xfb\x85r\x04\xdaK\x14M9\xfe\\\xa75\xc6\xf5\xe0m\x93\x98\x1c\x9ax4\xa7\xc0=\x0e2\xc0\xa4:o\xd8\xd9\x12\u045e ~\x8f\xf5qZ\u1ae0\x85\xe6\x1e\x033\x1e\xfc\xaa\r\"5\x8f\rn}\x99o4R\xee\x83\x16\x9c\n\x13\xa2\xdc\u019f7\x06i\xa8v\xa6G\xb3!\u062c<\u02de\x02\x00\xc9\b\xbaC\u0202\xf2\x8e\x18\xa0@e\xa0\x1e\xcf\xe9\xa1J\x11\\\x8fa\b\xb0\xae\xbe)\xfaf\xe8\xb8\u007f\xb8\xb4\x9e[\xc6#D\x9b\x9a\x17\x9f\f\xe77\x1a\xee\x12hN\x039\x97\xbf(\x8d\x91\u007f\xa1\x9a\x8d|\xf5w\x11\xff{\xe1I\x92?\x02\xfa\xd70\xce>p\xdd\n\xd8KE\xeb\xd6\xc9\x16\xe13\x8a\xd8@\x0f\x95x\x00\xef\xf8\x15\xef\xdcY\xa0?tX\xec[\x14\xd6\u007f\x86I\xe9F\x82\x91\xff\U000948cf]t\xd6w\u775bT\xe6\x93\xf5\x14\xaf\xf3\u03ff0\xba(\xfed\xfd\xfau?\u0770a\x03\xac\xb5\xe2]\xf7\x83\"\x85\x15\x9e|\xf8n,l\xbf\xcf\x1b\xf8+\xf6\x13\x99D\xb0\f\xd8\f\xb0\xba2w\x92\xc0=W\x9as\xc1\xda\x01\fI\x85\x9aL\xceHP\x88P\xa0:hFA\xe5\fR\xf1\x18\xbd7\xb6\xb6\x9c)\u017f\u05a7U\x82\xdeXi\x02g\x04L)\xa0\xa3\xead1\u01951\x04?\x19*]*9WI\xc3\x15\x924\xf9\xba\xfa\x1c5\x0f\x1bYc\u04d1f\x0f\x00\xa1\x19\x9c\xb3w\xfe\x8bw\xa1}\xf5K\x19\x97A\x105\x13*\b\\N0\x8a`\u04f4\xa1\x14`\xa9\xfd\xddi\xdb\xf4Z\u01cc\u04aa<#p\x87\x81\x19\r\x9aR\xa8\xfb\xa47NQ2~\x88+\x1fZ9\xe0\x13\xdfW\xff\x99\x92`(\u6e1a\ue31f\x1b\x0f\u8f8fc\xadC!\x82\u00b9Z\xfb\xa44\xe5\x92J\x8e(\"0\xd6ayP`a\xa5\xc0\xa8\xf0\tMD\xde;\xc67\xfc%\t\x88\x0e-Sq\x12\xa8\x97,\\O\x135\xcbd=\xb5+\xfd\u031dx\xe2\t;gg\xe7 \"\xe4-C\xfd\\=+\x85a\u007f\x05\x0f\xff\u4ef0v\b\xd6Y\xa9.\x88\xb2A\x973\xac\xe6Ro]F\xd1%\xdaqjuR\x94\x1aE[ce\xb9\xb27\xa5)\x055\xa3\xa03\xafn\x88\x95W\x1d`\xd0N\u153a\xe0\xbd\x1bps\x1cl\xe9\x84\nW%\xb7/T\x9bq\xa9\xf5\"\x15\x83\xa75(\xe3j\u011f\xd1Ry\x03k\xfd\x8d\xd64\x83\xa0f4\xf2)\x15T#\t\xf0T\xa7\xe6\x86lN*\x15H\v\xc5\xd36d\u009a\xc19{\xf9\\\x87\xf7\x98\x19\x9dn\x16\x04\x01\xf7\x18\u064c\xaa,\xb7\xa3\xbae\xec\xfe\xd6\xf2i,\xdd\xd3\xf7t|\x800Aw\x152\xe5\a\xa9\x88\b\x92\x93\xaf\x80U5);v\x86\x10\u007f\xa5\xbb.\xc3i\xef\xc4S\x029\xd57\u023dGUS\xe3tB5\x1f.\xad\x83zeV\x83:\x9c\xf0\u048d\xd3F\xe3\xce\xd6\x1cD\u04be\xdav\xe2`\xc5\xc1\x88\xf8\u07ae\x02l\x87\xe1\xf2\xe0K\u00fe\xf9\u8303-\x1c\x9c\x15\x18\b\xac\b\xcc\xc8a4t\xb0&j\xca\x05\xd6\n\x8c\x15\f\x06\x0e\x8b+\x06\v+\x06\xab\x03\v\x91@\xb7\u01e0\n88[T\xba$\xaaNP\xd69\xe9t;\u0635{\xd7\x03\xfdA\xff\x16\x00\u063e}\xbb\x9b\x80\xf9d=m\xeb\xdcs\u03fbijjzg\xa7\xd3A)7ta\u0519\xbd-\xee\x8e{o\v\x12=F\x9a,L\xd6\a\u43ba\x04\xa3\xf7\xe0\xf3]K\x9f\x97\x96\x01\xa2\xca\xdd\xce{\x88$\x84j\x87\x90\xcd)\xe8\x8e\x0f\xfeu\x8d\xea\x97\x1a\xb7O\x89- \x89\xec\x85b\t:\xe4\xdc7\u0290S\xf0\xcfn\x199\x97\xf6\x84#\u0584,\xd0Aec\x98\x81\xf1\x12to\xdc\xfe\x9e+c\u02bd\u05ca\x8a\xaf?\u00df\nr\xaei\xb5\xdb6\r\x06!\xeby\x8e?\xea\xf7K\x1fo^\xab\x12o\xb6\x8eS9\u0478\u007f\xbc\x1f\xcca\u042c\x02\xa6\xfdI!\x86HS\xb2\x11Hi\xd4YW\xec\xa4\xf3_\xf1?\x1c\x93?\xf9\xc1\xf7s\xac8\xff\xfeG\x13\xb1\x98\x02d\x1c\xc4\xf8\x11|'\x9e\x901\x01\xe0\v#\x18\x0e-F\x85Aa\x1c\x8c\x15\x14F\xb0\xb2j\xb0\xb4R\xa0?p0\xae\x1a\xed\x0f\x01\xb9\xfe\xb1:\a[\x8cJs8F\x95\xc0%\u21080\u055b\xeao\u077a\xb5\x0f\x00\x87\x1f~\xf8\x843\x9f\xac\xa7o\x1du\xd4\xe6\x1b7m:l\xc7\xdc\xdc\x01\xb0\xd6W\xd5\xe2,\x98\x00\x9de\x18\xae.\xe1\xf1\x9f\xde\x02\x16\v\u036aVF\xb1\x03\xf4\u04075\xdb\xcc\xf3\u65774j\xe0\"\u0524F\xa4V\xa9I\xfcD\xaa\xc47<\xdc\x17Okd3\n\u0228\xd6\xe8\xaa\xe1\f\x8d\xfbp\xcbX5\x99\xd6\xc2\xe1\xd7\x19\xe0\x8c@\n\xbe2\xe7\x16\xf0M\x1c\x1e\x9b@\xcc\xe4\x95-\xd2\xe3\xaa\u008d\x8a\x8a1\u007f,\u00b8\xba\x86Z\xcf\x0f)\xb0\x11\x13\xb2\x0eA\xa9\xa0\x9bf\x02z\xec\xf9}\x1e\xefC\xa4\xb5\xb3\xf8\x97\x14\xbd\x8c\u045b\xd3\xe8L)t\x82>=\x866H\x8b\x87\x0e\xed\xf5TQ\x1f\xb5\xcd4AM\xb1\xaf\xca3\xaeM\xbf\x8fW\xf4\xf5\x9eE\x9bs\xbb\x930\x18\x95y\xf9eMJn\x05\u0537\x90\x91\x85\x14\x0e\x12\xaa\xf1H\xa1\x18\xe5i@\n!\xcc\u00d1\xc3p\xe80\x1a9\x8c\n\x87\xfe\xd0a0r\xb0\x12\xde\u007f\x92@[\x95.\xbb~\xc3q\x16f\xb0Z\xf5\x17\xe2)\t\x028G\x04\xe0\xd0C\x0f\xd5\xcf\u007f\xfeY\x1a\x00\xb6n\xdd:\x01\xf3\xc9z\xea\xd7\xea\xeaR\u025fo\xde|\xf4\xad\xddn\xb7\xf4\x87vA/\xabX\xc1Z\x83\xf9m\x0fb\xb0\xb2\ryG#SA\xcd!\x04v\x04e\x04\xd9\xd0_\xfdN\xc5\xea\u070d\xe5\x97Q\xb3\t\x88(WKR\x85\xd8?\x1e!\n\xd3\xfbA/\xad\b\xd9\\\x06\xdd\xf5\xd5y=\x88\x81\u01a3gbe-\xcd\u071b\x06\xe5C\x04\xce\xd9Osj?%X\xaf\x14\xc7C\x96K\x15\rR\xab^\x82\xe91l\x90\xff\xf9F\xf1\u06aa\x90\xf4d\x10gU\x05kW\xc8\x1c\x1c\x10uTph\x02M\xd79\xe9\xb5n!\x16\x9b\x19y\a\xc8|Z!\xd7\u0790K\x01Aw\x1e\xbcT\x80\x16E\v\xb5l\x9a\t\x81\x15$\x9dY7\xf0\xe4=\xae\x01\xb4\xb4%\x12\u057a\xa6\x91\xb0\xa1\xb1S\x013Aw\xbd<\x95\t\xd0\xca\a\x99\xa0o\x81\xbe\x81+\x9c7\u010a\x95\xbe\x00\x8e\x04\x96\x91\x18i\x01\xd6\t\x06#A\u007f\xe8\xd0\x1f8\x8c\x8c\v\x1e\xe7^\xd6\xc9YH5\xe2\xaa\x1f\xa0\x14C\xac\xc1p1\x04N4\xe4\x87\xceY\xd7\xebu\xe1\x9c\xdc\x0f\xe0^_\x99o\x9ap\xe6\x93\xf5\u052f\xa9\xa9\xd9\xf2\xef[\xb7n\xfd\xfa\xd4TO\xb4\u05be\xba\x15\a'\x16\xcc\f\xa52,=\xf9\x04\xb6=r;\xf4\\\x86,gh\x95\x00\xad\x13pa\xc1C\vK\x0eF\t\f\xd5u\xbbcQo\xa9~;\xb5\xa4\xd5\x04d\x1e\x10kV,\"\xd0S\f\xbd>\x87\xed\xb2\xd7GG:\xa6v\x1f\xd2N\x8d\a\xb4\x8a\xfe&e\x85\xa7\x025\xa0B\xfa\x8c\xa65=KJxJ\x9bg%\xb5OP=\x05\x9aU\xde\xe8JUz\xfc\xb6\a\xd4v\u016fE\xc2pF\xd0S\f\xa5\xa9\xc2S(\xd4\xdauk\xe14\x94\xaf|\xbd\x8b\x93o\x80\xd6+Q\x19\x9bYoU:\x96\x9bT\x00\xa5.{\xfe8\xfa\x83D\x80\xe1\x90A\u065a\xd8\xd3(\xa6\xa3\xe41\xe7\xb0?y\xfa\tS\u028f\xb8'`\xd8\u6552\x9ef\xcaSN\xf2\xbf\xc2~z\x95\xf3\x8af\xa2\xb1I\x9e\xda!\xa1\u04a4'3\xa6Y\x97\xc1\xeb3`\xca\xd3@\x92h\xddkV\xb7\x90*\x90[\u0195;\x12\x93}\x8ad\u01f1\x01t\x9d\xaf\xdc]NXq\x82%\xe30\xd4@\x911LF0\xda\xcbb\x8d\x06\xa0\xb8z\xadu\bmV\xfe\xab\fW\xa1\u051f?$\r\x05\xc7N\xef\xb2K \xa5`\x8b\x11\xe6\x1f\xbc\x1b\xb6\x18\xfa\x1f\f\xca\x18\t\xee\xa0J)\x1c|\xf0\xc1\xc3\xcb.\xbbt\x01\x00\xce>\xfb\u0327\xf5Z\xd6\x138\x9b\xac\xb8\xba\xdd\xfc\u01a3\x8e:\n\x8f>\xfa\x18\x86\xc3a\xe9\x12GD\x10(\x8c\xfa\xab\x98\u007f\xe2\x11\x8c\xfa\xab\xfe\xfb\xcaA\xcd*P\xe1\xe0\xfa6\xc4o\x95\x1a\\X;\x80X\x03 \x03\x93\x06\xb3\x06\x83\xcb\v>\xba\x06z\x05\x01Cu\x14\x9c\x10`\x05\xb0\x9e\x1b\x85b\by\xef\x13JIi\xac\xee|\x02\xcb\xdb\x1e\x868\a\xa5\xf32\x95HB\xf3s\xe3!\u03e2\xf5\xeb\xd7\xfft\xfd\xfa\r_\a\x80\x13OYO\xeb\x1a\x0eW\xd1\xe9La\u02d6\x93\x16n\xbd\xf5G\xcb\xff\xf2/zf8\x18\x02\xf0\u04c2\x95\xf3-ai\xc7\xe3X~r\x1bf7l\x84+\x86\xd0\x19!\x9f\xd3\xe8;\x81\x1b\xc5\x04\x1a\x02\xc8\xf9\v\xac\x18\xa1pE\x88\xfe\xd2 \xe8\xb2\u05258%)\xe4+'\u0470\x8e\x80\x91\x03\x93?:\xc3V\x01\x10D\xf5 `\u0342l\xda\u00ac\x8e`\n\a\xb2\x0e,>$\x83\\\xa4\x05\x18\f\x05\"\r0WG|\xf6\xea\x15\"\x04\x8a\x85\x92\xe0\x04)C\x12j2:T\x91b\u0360\x8bT\x16)B@\xc6\x1ex\x87\xce\xff\xdb\x010\x91\xa2\xf0\x95\xa6OWJ#\x86\xaa\xe3>\xa9\xb0\xc1\xc4\u02b1\xc3\xc0\xb4\xcf\u03ecB\x9fi\x9cFj\x99\xb8tR\x0fe\x02\x00\x0e\xaf\x81\xf4\x18n\xd9\u07ce\x15\x81qRZ\xfd\x8e7=\x93\xb4#&d\xd3\nj]\xe6O\n\xae\x9e\xa3]\xca\x12]\xe0\xb3\x1dPX\x815\x0e\x19\x01\xb9B\xeb\b\u007f\x93\x11s\x02\x14\x85\xc5\xe2b\x81]\xf3#\f\v\a\x8aJ'?\xc5S\xc6\xd3\xc1Q2\x1c\xdc4O\xf0^+U?\xb7\xaa\u04a3\xcbbT\x1f)\xad\x01g\xb0\xed\xf6\x1b1X\xd8\x05V\xc1\x1f>\xbc\x98\xe2,\x9c\xb54w\xc0\x1c6o\xde\xfc#\n;\xd8!\x87\x1c6\xa1Y&\xeb\xe9]\x9d\xce\x14\x00\xe0\xbc\xf3.\xd8\x01\xd0u\x9dN\x0eV\\\x82m\xe4]\x89\x19K\xdb\x1f\xc3\xf2\xce'\xa0t\x06\x12\x81\"\xa0\xdbc\xe8\x19U\x1an\x95Lp9@d\xe1l\x01S\f`\x8aU\x14\xa3U\x183\x805C\x883\xc12\xd7\x02\xec d\x01k \xa6\x803\x05l\xe1\xfft\xa3\x11\xccp\b;\x1c\xc2\x0e\a\xb0\xc3\x01\xa4\x18B\xe5\x06\xbak\xe0\xdc\b\xd6\x19X\xb1!\xe9\xc8\x02A^im\x01kG~,[lI\u00b3\xf6\xc7j\u0242\u0331\u64ce\xb2I\n\x12P\xcd\xc3[\xea\xfcC\xb3\x92\x95\xa4:\xcf\"7\x14\x9c\x1f\x11}\xd1\xdb\u87e4Q\x9c1\xc2\xfe\xe3m\x87g5\x90Q-\x10[Z\x06\x98\x9a \xe6ds\x93+\x93\xb3fFv(\xa8=\r\xe2\x04&4b\xb3\u0408\xf6z?\a8\xaf\xf9v\xf1\xcb\xf8?\xad\x11\xd80\u0623\x9c\x94\xdav\xa4^\xee)\xb1\x1f\xfen\x1d0\x18Y<\xb9{\x88\x1dO\xf61\x18\xda\xd0@\x0e\x8d\xf9\xa8|R\x04V\x9e6\x8b7A\xd2\xd0\rIr4\t\x96\xe7\xcc\xc1\xc6!\x86\x91\x10\xcaD\xa1\x9dw\u0782\xc7n\xfa\x1a\xec\xa8\xef]\x13\x9d\xc0Yo\xeflM\x81<\xd7\xc8\xf3|\xfe\xf4\xd3O\xbda_\xb9\x8e'`>YI\xe1E\xab\x87\x1f~\xf8]\xd3\xd3\xd3 f\xdf\xedOB\x1eH+\xac\xcc\xef\xc4\xf2\xce\xed\xbe\x92\x0e\x95\x17A\xd0\xe9)`JyYXc\xea\xaf\xdc\x10\x9c\x83u\x06\xce\x198[\xc0Y\x03gM\x00\xd8 gd$\xf3\xde!\x8a.\x06_XS\xe6\x8c:k\xe1\x8c\x05\x91 \x9fV\xc8z\xbe\x8a-\x9d\xf4\xa2\xe1W\xb0*ub\xe1\u0107N\x1bW\xc0\xb1\v`\xc0a|\xbf\x81\xadR\x85mV\xb4\n\xd5hri\xce*\xa5\xb1\xcde\xd3NU\u0464\n\xa5\xea\xa2\rZkWe\x96D\xf5M)\xcf\xe9\x97\x1cxJ\xe4\x8f;\x9f\x8c\xa9E\x9a\x8e\x84)\xf5\x92\xfa\x86k\xaf\xba\xa9\xf4\xf3!\xb2-\xe8\xb7]\xf4-d@\xf5\x18\x1cl\x82\xe3\xd4e\xf0g\xf3TMi-+\xc1\x06B\x90\xb1\x0f\x98P\x8d\x87]\xfe3\xa1\x87\x00`4\xb2\xd8=?\xc2\xee\xf9\x01\x8a\xc2\xf8p\x8d\x92\xd3\xf6@L*\x84N$\xc0]?\x85T\xb6\xb9\x84DvJ\x95\x92\x89\x98\xfdO\t@J\xa3?\xff$\x1e\xb9\xe9+Xy\xf2q\xb0\xca\xfc\t\xc1\x85\xfe\x8e\xb30\xa6\xc0\xf4\xf44\x0e;\xec\xb0]\x97]\xf6\x8aoN\xc0|\xb2\xf6\xc9U\x14\u0177\x0e\xdbxX\xe0\x1d\x15\xca(s\x02\x88\x14\xcc`\x80\x95\xf9\x9d0\xa3Q\xc0Z_\x8du\x14\u041bQp\xb9\x97\f6r\x18*\u03d6\b\x80%\xd8\xfa\xafJ\x96X\xaf\n\u02f3vR\xc6E\xa0\xf6Gg\x01\xe7\x84\u03acB7\x8c\xbb;F\xd9\x18\x15\b\x1c\v\xac\n\x80$\x0eV\f\x80\x02\x8a\x02\x9f\x9dq\xbdQW\x17\x0f\x06k\x01jt\x12\xa9\xe5\xe2I\xa3\xd0B\xdaE\x8f*_t\xf6\x80.M\fo\x94\xcd\xd1+>\x86P\xd0\x14\x97\x89GT\x93\x82\xd4E\xd6\u037e/5.\xf0Z*O\xec\xefR\xe0\xcecfh\xfa:\xa3\xca\x1a\x05|\xd5\xee\u008d\xaaYU\xf3)\x8f\xef\x8b\rU\xb9\xb5\xc1'\xc5\xfa\u05eb\x9e(\xd5|\xd5\xc2\xf0\x8f\x8b\x01I\x82\xfe\xd0b\xe7\xee\x02\xf3\v#8k\xc1\\\x8d\u06f3\xf6\xcd\xe1\xb2\xe3*\xf5\xbc\xd9J8%\x89\u02c3\x84\x8a\u07a7/)\xed7\x030\u0574\xee\xc4\n\xfd\xdd\u06f1\xf8\xe8}\x10k\x03\xd0Gu\x90\x83\xb5\x06\xa6(033\x83\xe3\x8e;\xf6>\"z\x12\x00>\xf9\xc9\u007f\x9c\x80\xf9d\xed\x1b\xeb\xee\xbb\xef\x04\x00l9\xe9\xa4\xe5\u00cf8\xbc\xac\u0309\t\x04\xf6U\"\xfcD\xdd\xf2\xae\x1d\x18,-&\x86C\xfeb\xec*`jF\x01yt\xe6\xab\xa6o\xba\nBn\xe1e\xb0v\nP\xb2WP\xeb\xccO\xf5=E !P\x18\x8d'\x178\xf51J\u0217\xb5\xa6\xcb0]\x8eA;\xfe\xfdp\x80\xb5a\u042c\x11\xfc \xe2*Z\x05\rN[\x00q\x95n\xdc9\xc1j\xdfb\xe7\xae\x02\x8b+\x05\x00\a\u05be\xe1\xcd\x01\x80)\x18a\x89s\x15\x98\xa7\x13f\xd13\x87\xabH=\x0e\x95\xb8\xd2\x04\x9d{\xa9\"\x10\xc2:\x90\xc8E\x89`G\x03\x98a?)*$4a\r\x8ab\x88\xa8\xf0\u06bcy\xf3W\xe2\xcf\x1c}\xf4\xd1\x130\x9f\xac}c\x1dw\x9c\x97(\x9eq\u05bfy\xa8?\x18}+\xeftA\xac\xaa\xd4rT\x8d\xa3\x95\x85y\fVV\xc2\xff\a\b\vWc'gt\xa7\x19\xc4\xf0\xa6]e\xe8n\xc2\xf1\x12jy\x90e&X);\b\x00 \x15\x18\x94\x19\x8b\xb1rNS_\xc4\x1f\xbfy\x8a\xa1;\x04\x1d\x8e\xe3.1\xfdB\xd4\xc0\x97G\xec\b\x9e\x1e\xe0\xd3@\aB\xaa\x85oC\xf1*\xe0Y\x1az\xe9f\xba{\xa9\r\x0f\xf7\xe7\x0f\x02T\x02e\x19\x87GU\x15lC\x83\x8f;>v\r-@\xdc\x04ri\x99\x19\xaa\x019\xd5O;)xQ!\xa0U\vg=\xfd\x9d\bw\x12\x1e\xdd\u007f\x99\x0ec\xd0e\xac\x1a\x81)B\x90w\xe0\u015dqej\x0f\xa5\xe1\x13\xc9\xccB\xd4us\xa05\xac\x93\xe05\xee?\x13\xab}\x8b\x9d\v\x05\x96\x87\x16\xc4\x02V\xe2#\xf1\xcaCb\xf2\x9eK#\xfd\x87jm\x87\xca)\x80\t\xa4\x18:S\xc8r\r\x1d\xfcW\x1cE\xe9hu2c\xa51Z^\x84\u9bc2X%/\x9a\x835~~\"\x16'\x87\x1ez\xc8\xee\xf8:\x9fz\xea\xe9O\xfb5(e\x92\xa0\x13\nt\x8ab\nn\x90\u0546\x16\xdd\x12\xe3g\u060a\xef\xa1P\xa2,\x15'Py\x17\x8b\x8f?\x80\xc5G\xef\x87\xeet\xcaW\xcb9\vS\f\x83\x84\xd6?\x15c\f\xb2,\xfb\xf1\x04\xcc'k_^J\xb2\x1e\xf4\xd4\\\xf0Z\xf1\x17%S\f\x8c@p\x94c8i\xda\xc4V\xc0\xc6 \x9fW9\xa3\x00\x11\x8c\xfa^\xe2\xc6\xde\xc9\xc8W\xa4H\x94-\x11rC\x05fC,\x1a\xc7H\x9c\xb8W\u0109\xcbF\x8ee\x82 \x90\fP=B\xc7\x10\xdcH\xbc\xe2F\x82\x1b^\x11\xa7\x0e\t\x02\vk\rP\x10lt\xe3\x8b<)5\xaba\x97T\xb8\xf5\xd9~\u007f\"\xa9\xa8\x89V+\x98N\xb0\xf6-<\xdd\xe38\x86\x02KH&\"HHj\xb2\x9a\xd1\xe9*d\xaa\xf1\x1c\xc7\xfeY\xa5\xdeT\xed\aJz\vi\xd6k\xe5\xd3\x02\x01\x8a\xc2ai\xd5`q\xd5\xfaA\x9c.\xc1A\xa13p`\xeb\xfb\rF\x01\x85\x16\x8c2\xf2\xcd\xd88^\x1fv\xb5\xb8\xb9\t\x04b\x1a\x94\x17*0\xadK#C\x89\x1c6'\x87\xca\x10\x8b\x94o\x14W\x95\xb8\x94\xf7S}\xb4\xd2\xcd\x01e3\x99\x88\xa1\u0201(\x9c|\xe2\xe7\x96c\x8f&\xc8B\x9d\x8f\x92\xab\x1c\xd4}\xf3\x95\x15\u00cd\x06\xd8\xfd\xc0\x9d\x18,\xecB\x16\f\xe7\x9c\bL1\x825E\xf9\xd2+\xa5h\u00c6\r\u0634\u9c3f\u0717.\xdcI\x03t\xb2\x00\x00\x8f\xce\xfb\xa0\x8a!\xe0\n\x95Cwz(5\xbb\x9cp\xc2\"P\x9d\x1eDe(\x8c\r\x9ab\x8c!\x98\xa7?\x04\xdc!\xe8\x1eC+\u007f\xaeO\x8d\x8d\xa8\x9cLta`\xc8+\x14\x9c\xf3\x15\xb5\xb1\x16\xc6\x1aX\xe3\x1bm\xb1\x11\uab03\x18\xaf?/\xbf\x1f\xa5\x8e6<\x98\x1eCu\t\xb9\xf6r;\u07d8\x8b\x9e\x1fA\x12I^\u007fn\x8d\x81\x1d\x8d<'Z\xb3i$\xa4\u0588\xd1\xcc*V\xa0\xf1\xc9:\x91\x96\x89\xc3\xe6\x16\xe9\xf3:\x05\x04\xcb>\x0e-R$\xc2\xc1\xf5\x11\xde,J\xcf0f\xa78\xf8VI\xbd\xa1\x97\x10+^bQM\xf5P\xc9Q\a\xba*\xe9@F\xc1\x87\xb3\x82\xe5\x15\x83\xed\xbbGxr~\x84A\xdfxgB+X\xe9\x10\xe6g\x15\x16f\x18\xcb=\xc6j\a\xe8\xe7\x04\x13\x8f\x1aQ1b\x05b\x91\f\v\xc5\x10\x90\xcay\x90\x12\xba\xa7\xd4}\x97\xaed\x95N\\\xe5\f\x95\xb1\xf7\x92WTy\xe2\xc4Ppjf\xc4&\xee\x9a\xd1KE\a5\x14\xa5\xf9\x11\x1e\xe0]\x98\x9aR\xe1\xe4`k\x01\u05b1\xa0\x10\xe8N\x17\u02cf=\x80\x9dw\xdc\f\x8aY\xb8\x10?\xec6\x1a\u052a\xf2\x03\x0e8\x00'\x9d\xb4\xe5;\xaf~\xf5\xbf\xfd2\x00|\xf4\xa3\x1f\xa1}\xe1\x1a\x9eT\xe6\x93\x05\x00\xd8=\xf4\u0235\x00\x18C\x1aJg\xb59\xf5*\xf4\u01c2\xbb\xb3(\xa8\x8b\xa20\xc8\x1a\xc1\x03\xa9C\xac\x8b\x00\x94\x937\xb4\n\xea\x87\xf2\x8c\v\x01\xbb\xc8!W\xbc\xafq\xc0\xd0z\x10\u0395 S\xec+kix\x17Z4-I\x93O\xb6\x1fUW#\x87\xac\xf0\xaa\x898\xaa\x0f\x17=Fbc\xcd\xc2Y\x02F#@\x00\x95\xe5\xe5 \t\t\xb5\xba\xff\x95`\xbf\xb6J\xb0^F3\xbc\x9e]Y\xb8\"!=\x92\xecN\xc7\x00:\x8c\xee\xb4*#\xdd(\x95\xcd5n[\x12\xa9f\xa4\x87\xbc\x9dkh\x16\xbb\n\x83\xe1\x04##X\\5X^\xb1\x18\x8dl\t\xc2\x12\x1f_\xdc\x178\xfe\x9b*\xf0\x1e\ubf3a\xc6\xf7\xa4\xb2\u0265\x1a\xabS*JJ O\xaa\xf0*\x14\xa3\xf1\xbc\x82&\x8c\x9d\x8f<\bV\xaa\xac\u0108\x00g\v\xcc\x1e|\x18\xd6o\xfc9\xc0\x19T\u04cf\xa8\x94\vc\x9d\xbf0,B\xe2\xa9\x16\xf2a\xd1\xcez\xa7\x0f\x82\x83\x83\xf5^\xe7#\x83bP\xc0\x0e-z$\u0202\u06d2\x18T\u0561\x95\xd2B \xe9\xc0\u008a\x84\x01\x14\t\xb4\xb8\xaf8U\xc7Ws*\x84/\u0107U\x14\x82\xd1\xc0\x86\xa9R\xcf\u04fbh\xa6dm\xe0\x9d]\b\x9c\x96\x92r(\x9b|\x0ep&\x04)X?0\xe3\x8aP\xc9Z\x01Y\a\x8a\xa3\xed\x85\xff?\a\xc1\xd0\tL\x11\x86glh\u0205\xaf\x11\x01\u00d1\xc3\xea\x8a\xc5j\xdfb0\xb0\xe8\x0f\xfc\u07d7W\r\x16\x96\r\x96V\f\x86#\ak|pC\u007f\xe00\xbf\xe0\xc7\xde\x17\x17\v\xec\xda=\u0136\x9d}\xcc/\x8e0\x18\x85\xdb\xe8[X#\xd5LVt\u038a\xbd\x8exR\xb1\xc90VR\xb1\x8f\xd9\xc1DM6\x85\xca[q\u5552\xf9\x04#\xd5ap\xaeJ\xc30j&8\xa5\xf9$TQ/\xacB\xb0v\xbc\xad\xf0E\x89\xe3B\x9c\xfcd\x12d\x1c>'\xe1q\u0692\xc2\x0f\x15:3\x1c\bB\x89q\\\xe2\xb5C\xe4C\x9b\x8b\x95\x05 \x19\xdb/\x86\xab0\u5d27\xff\xe1\r\x1b6\xe0\x94S\xb6\xfe\xc3\x15W\xbc\xf1\x06\x00\xf8\x9b\xbf\xf9k\u0697\xae\xdfIe>Y\xf8\xf1\xbd\xf7\xe1\xa4go\xc6\t[\x9e;\xf5\xd5;\x1f;\xf9\x87\u07f8\x01K\xf3\xbb\u041b\x9e\t@\xee\xa7\xe4\x9c1\x98y\xd6&\xcc\x1c\xbc1|\u0429\x96r\x1f\xf4n\x151\x13)W\xeb`\x04@\x16\xe4w\u05abc\x14\xfb\xc6\x15\xe9\xc0\x8f:\a%\xc0\xb4\x06:\xca\x03\x8e\x8bMX\xc4\x01%*/0W\xfaySP(\x04\xa1DPL0\x93o\n\xc6)?[m>\xce:\xf4\x97-h\xca!\xcb\x18D\xde\x1f\x06\xca\xfbs\b\xf9\xd8;(\x8b(\x87p\x0e\x15\x9d\x13\x1eC\xc3\b\xb7\xa4\xfeK\xccw(\u04da\n#X\xb5\xbeJ\xcc\xc3\tB\xc2\xc4g\xa1\x01\x03\a3\x12\xac\x8c\b\xc5\u040f\x9cKR\x95\x1b'\xc8\x14a\xaa\xab\xa0\xd97\xf7V\xfa\x06\xab}\x13\xaa2\x82\xb1\xe15\xabq\xedR6n)\xf5+\x97\xd4i\x91\u01a8\xa1\xb4/PU\xbc\xd4H\xf2\xa9\xf2[\x91\x84;\x8c\xadTb\x99~+n\b\xd1@\x8b\t\u03b0\xaf\xa9-\xfb\r\xbcv\x18\xf3\x958\x91@IP\xef\xc4SS\xb0\xe8\x15\x00:X\x05\x1b'\xb0\xb1!\x90\x98l\xc5S\x8dw_\xd4\xe8\xce\xccy\x96\xc9\x1aXk1\x1a\xf6\u02e6\xa7\b\x9c\u059aO=\xf5y\x0f\\y\xe5\x15\xff7\x11\x15\xef~\xf7\xbb\xb2+\xaf\xbc\xaa\x98\x80\xf9d\xed\x13\xeb\xd1G\x1f\xc6\xf7\xbf\u007f#Nz\xf6f\x00\xc0*0\xfd\xc5O\xfcw|\xff+_\xf4MIq\xa5`W\x9c\x03\xeb\x1c3\x87\x1e\r5\xb5\x0e\xa6X\xf5\x95.\xb3?\xaa\x82@*\x83\x90*\xe9\x8e\xc28X\xe7+(f@2\a\xd1\x02\t\xc1\x13\xba\xa3||\x99V\x81&A\xa0W\xa2\x02\xa5\xba\xea\xa5\xd4LK\xe2\xc2\xe8\xabp0\u01d3|#\xc5GJn\xdc)@\x8a\xe8#\x13\xaa\xf3U\x83\xfe\x12\x83f3?5\xc8\x02h\x80\x11\x142\xe45\xe9\xe5m\x05`)\u00c4\xb9\n\xa2\xaf5\xfc\xaa\xb6\x00\xacu\x81\x86\x16,\xf7-V\xad\x03\xeb\u0434c\x81c`\xa4\b#\x0eC;V`D`FR#\x92)\xf8\xc7\x14\x00\x86}\vf\x82\xb5\x02\x13\xaai\x8bJy\xc3A@\xed\x15-R\u6596`\x1cOP\"\xed\xa3\xa2\x8d\xac\xcfR\xcd\x14\xab\xe8\x98e\x1a\xfdf\x12\x95J\xbd\xf1\xd9\xcc\fM\xfe+\x00\xb7\x8fi\xe3\xa4Z'\x90\xadxwo\xf8\xe6\xca\x17=>\xe4\xe8\x89n\x1d\xe0\x1cC3\x82\xaa(<\u007f\xf8M\xb3\x90\xa81\x0f\x1e-I\xaf\x85\xc2\xedw\xbb=(\x02\x06K\xf30E\x81b\u0507\rMO\xa5\x94Xk\xe9\xb4\xd3N\u0165\x97\xbe\xf4\x1f\x8f?~\u02dd\x00\xf0\xf6\xb7\xbf\u077c\xef}\xef\xc7\x04\xcc'k\x9fXw\xdf}\x17^\xf6\xb2_\x8a\xbcs\xefw\xff\xe0\x0f\xfe\xe8S\x1f\xbb\x1a;\x9fx\x04\xdd\xee4\x9cu\xa5\xc1\x96\x19\r0u\u0421\x98;j\v\x06#\v\xed\x1c\xf2L\xc3\x19\x83\x1dw\u07c6'\xee\xba\x15B\x8cl\xfa\x00p\xd6\x05\xe7=@\xf5\xa0\xf2.\xa6f\xa6\u041b\x9a\x02e30N\x83\x95F\xa65\xa8\x97Au\xbd\x91\x94\xb0@LQU\xf6\xc2U\x05(\x95\x9a\xa2\xe4Y\xa3a\x1e\x04\xcc\x0eJ\x92\xb0\x8b8`\x14mX\x15 \xdaW\xf2\xb6\xec\x82\xf91\xf6\xc1R\x01\xce\b\xdd\\{\xe3\x1a.\x94\xb2\a>\xfb\xe71w\xe4\xf1\x18\fG`\x00\x86\x18\xa3\x95%\xdc\xf7\xc3\xef\xe1\x81\xef]\x0f;\x1a@uz`\xa5\xc1:\x87\xd29T\x96C\xe5\x1ddy\a\u0719\x02\xeb.\x14w\xa0\x14\xa3;5\x8d\x83\x8f<\x06S\a\x1d\x84\xa9u\ab\xf6Y\x9b\xc0*\x83s~\xf8\xc3k\x83\xebcIH\xc0:\x0e\x15Q\xe0\xb4]\x90\x1aV\xc7\xe8\xf0\xe3\x04\f\x01\x8c\"\xd7\x1e\xa4n\x10A\xd1\x17,,\x10d\x16\xe8u3Tv\xb2\x94\x1a\xf0y^\xb9\xdcT\xa8\x1a)\x97d\x80'}\x88V0\x18X\xac\x0e,V\xfb\x06\xc3\xc2\x05\xef\x9a \xcfVH@U\xca\u01a3$I=\xf5\xb1\xdb\x16\x8a\"\xfdy\xa97.\xd3a\x9dd\x8c\x145\xa3\x17Jm\x1a\xc2Tn\xec_\x06\xb9h\t\xe2T}\x0f\x8d\xe9Ij\xd9\x10R)\"S\xa5\vo\xfen\x93\xdbI\xbd\xc8%U\u0144!3\xcd@\x0e?\xbe/\xce\xc7\rJ\xe8$\xc7\u03c2\t\x83\xc4q\xaa\x94\x90\xbew\u1e72Bwj\x06\x18\xae\xe2'\xd7\xfd\x1d\x1e\xfd\xc9\xf7a\xc5\xc1\x98Q\b\xe6Vp\xceI\xaf\xd7\u034e;\xeeXw\xc9%\x17\xbf\x9b\x88\u6bff\xfe\xf3|\xe1\x85\x17\xbbo|\xe3kx\xc1\v\u039d\x80\xf9d=\xbd+\x1d\xc1\x17\x91\xb9\xff\xf2_>\xf0\xc1\xab\xaf\xfe\xf8ko\xbe\xf9\x87%\x8a8k\xabtwkp\xe0\xe6\x13q\xc4\xff\xf6R\xe8N\xd7\u02f5\x04\xb0C\x03\xeb4\xa66\x1e\x8b\r\xc7<\x01[\f\xfdE`\n\xd8b\b;\x1a\u0099\x11\xccR\x1f\xabf\x04gF\xb0\xa3\x01l1\x808\x03\xd69\ue7daC65\x8dC\x8f?\x15']r9\xd6\x1fz\x04\u020c\x82\xe1V<27\x89\x00jbQ\xa2\u0328\xa0E\x82\xb6:\x82*;It\U00061135\x9e\xb6\x98\x17\x82\x13\x8d\x19E\xd0\xe29[AU\u0757\x8d3\xa9\xc2\x0flc0&V\xd1\xe2\x04\x8b\xcb\x06\xbb\x17F\x18\x1a\a\xe7\u01bd\xbcSO\x97\x1a\xb2\xb9:pS\x92\xe99\xaec\x97\xba\x87n\x82\x92\xb4\x86\x85oi\xbf[\xfe\x117\x14.i#/1\x8c\x19\xc6u\x1bB*\xa5\x9a\x91\xf6\xa2\x1a\xad\x12\x03\x92c\x88D\u4f9aN\xc2$)\x9b\xdf\xe24\x1c\xf2d\xcb'\xc2\xfe}\xd1\u481c\x9f\xd8u\x89\xad\xb2\n\xdd\v#\xfe\xcb5\xf9\u007f\xaa\x14,L\nyo\x1an\xb0\x8c\x9f|\xe1\xefq\xdfw\xbf\xe4\xfb.\xc5\b\x90\xe0a.\"D\xa0\x13N8\x01/x\xc1\v\xfe\xf2%/\xb9\xf4\xf3\x00p\xf1\xc5/v\x1f\xff\xf8\xc7\xf69 \x9f\x80\xf93\x14\xc8/\xbd\xf4\xa5\n\x80\x15\x91\r\xef\u007f\xff\xfb\xae\xf9\xdc\u7bbd\xf0\x96[n\xad\x95\x83Q\x1b\xedL\x81\xe9\x83\x0e\xc5\xe6\v_\x8d\xf5\u01dc\x8cbe9\xd0\b\x04\xe7,Hi\x1cr\xd2\xd9\xd8p\xfc\xa9!\xb1\xd7W\xb4\xce\x14a\xaar\x003XE\xb1\xba\x8cbe\x01\xab\xbb\x1e\xc7\xf2\xf6\a1\xd8\xfd\x04\x9c-\xc0Y\x17*\x9f\x82\xcb7`q\x95\xd1\xe9\x17\xc8U2\xf5\u01c9\xa7GI\xe2F\xf8\x960\xd4S9,R\xe0\xaaG\xc6b8r\xe8\x0f\x9cW\u007f8\xa0\x13=;J\v\x19\x1f\xf8\u03240\xb2\n\xf3K\x0e#kq\x00\x1cz\x04\xe8tz\xb2\u00b32->r\xe5\xde\x0124e\x9d`a\xa9\xc0\xce\xf9\x11\x8cI%\x84\x187xI\xfe#\x86\x05c\xac9\xd9tkL\x01\xbce\x8b\x8b\xc8\xc8\xd5w\xa9\xa1\x1cI\xff,\xe9\x91D\xcf]\x01\xb8\x00\xcd,\xd0D\x96\x12y\xfc\x12\xf4\x03\x80\x97Fb\xb5\xe7\x13D)\xb0V\x10\xad!PX\x19\x12F\xf3\x0e\xbd\x91A\xb7\xe3\xd0\xc9\x14\xb4\x0e\xca\x18\xaa&2]h\x86:\v\x14\xd6z9\x9c\x13\fG\x0eK+\x06\xc6:\x9f'\xd9B%4\xc1\xb9\x1ct\xaaH\xe3\xf2\xb9q\x02\x88\x92\x00\x9c$X\x8b\x14\xc4S~\xba\xd9xL\x8c\xcb\xca\xe9Kj\xfcn\xba\xebPL\xbb\xa7\x8a\x87\xa7j\xac\x1e\xa1\x01Zj\xc8\xc3mH\xc2\x1e\x11\xd5\x19\xa3\x9a+e\x83M\x8a\x8b\u00ddH\xf0\xed\xc9\x19\xd0a\x1a\u05c9\xf2Q\x85\xc4\xc1\x06\x82\xc0`\xaf%\x0f\x12X\xa1\xf43\x18g\x13|\xb9\x9eu{\x18-\xed\xc6\x1d\xd7\x06 \x17\x17r=\x87\xe5\xfb+\x00fgg\xf1\xdc\xe7\xfe\xfc\xb6\xb7\xbd\xed\xadW\xfe\xe9\x9f\xfe\x19\x00\xe0?\xfc\x87\xdf\xdeg\x81|\x02\xe6\u03e0u\xcd5\u007f\x9fR+\a\xbf\xef}\u007f\x10\x80\xfc\xa6\xda%\xc5\xca'\x01\x883\u041d9l\xbe\xf0U8\xfa\xfc_\x02)\r7\x1a\x822\x9f2\xcc\xc6V\xa92\xd6\xc1\x9aA96^\xbb>%\x89\x14\x82\x97\b\xeaN\x17\xb3\x87\x1c\xdd\x18\xfcqp\u01a0\xb0\x84\xa5\x15\u03c1\xf6z\xde\xcat\fD\x02\xc00\x01\xc6x\xe0\x1e\x15\x1eH\x87A\xc3\x1dKiV\b\x8a\b\xcf\xdfZ\xf2&_D\xec7%\xad\x81\\A\xb1\x0e\t\b\x04\xe3\bK\xcb\x05VV\t\x99fd\xc1\x0f[\xc5\xd0\xdf \xf4\xb1\xce\u06fd\x8e\x02\x95\x02\x04\x90\x0f\xd5z\x15\xa9\xd6R\x9d\x02\x15\xe8\xb4\xf0\r\xcdP\x89FQ\x9c\x84f\xa3jDRjnE\xf5)\x9a`f\x85\x10\x9b\u059cl\xad)rP\x81x\xadzO\xe4\x83\u008d\xff\x8f\x15\xb74@\xbf\xad!\xba\xb71\x9b\x90p\xa5D\xa0)\x80\x94\x00V\xa8|n\x12U;>\x85\xd9\x039G\u03df\xf0\xb9\f=\x14'\x9e\x03\xcf;9\x06\xbb\x9e\xc0\x1d\xd7}\x1c\x0f~\xefKeM_\fW}\x97\x84|\x91\xd2\xe9tp\xdey\xe7\xe25\xafy\xcd;\x8e<\xf2\xa8[\x01\xe0w~\xe7\xbd\xf4\u05b7\xfe\xef\xb2/_\xe3\x130\u007f\x06\xac[n\xb9\x19\xd7^{m\t'\u007f\xfc\xc7\u007f\xf4;_\xfc\xe2\xf5\x17\xdc|\xf3\xcd5 \xf71q\n\xceZ\xa8n\x0f\xc7\\\xfcj\x1c\u007f\xe9\x1b@*\x87\x19\xae\x86\x80g\xf1A\x12\x91\xdaH\x06y\xe0\xc4\xfb\x83K\x92\xba#i\x9b,\xd2\x16\xa6\xfcW\x1c\xc0\x11x\x89\x1a\x93\xaf\xa0\x17\xfb\x0eC\v\xf4:\x82,\xf3#\xf9)7\xed\xac\xa00\x0e\xfd\x81E\u007f\xe8\x82D/\x02\x0e'r\xba`\x9b\u01de\x04\x96\x8c\xe1Dy)\x89\xd6\x10\xc5A\x1aWy~H\xa2\xcb\x1e\x8e\x1c\x86C_\x067)\x13)'$i\\\x14\xd2L\x91\x93:s\xd1`\x90\xbd,\x12\xa8\x95\xb2\x8d\x1c\x8e\x9a\u0084\x12:%275uH\xa3\ua9b1\f\xb9\x06E\x938coU\xd1\xd4\x00\x00 \x00IDAT\xa5\x96\xb9\x14'\xad8\xa1`\xa8QqK\xbd\xc0\xde\xdb$\rS\xbb;{\xb5\xefx\u007ft\x8d`\xc9+1\t\xaa2H#\n\ue4e0\xd0\xecDp\\\f'P.Mi\xa0\xb3\fYg\n\x8b\x0f\u0789\xdb?\xf71'\x02\xd1\xcf]u\xd5o\xfc\xee]w\xdd\u0163\xd1(9\xd52\x98\x19\xd6\x14\u0226f\xb0\xf5\x97\u07c2\xe7\xbd\xee\xdf\xc3\xe9\x0eVvn\ai\r\xb1\xa6\xd2A\xd7xP\n\u0578\xb7\"\x8d\xbe\xe1\xa5\xc4\u03c6\xe0]\x17\xc2'B\xb5\x1e\xbd5@R\x1e\xab)N\xc7P\xacJ=\xd8G\x85\x82\xef|Q\xa5E\xce\x00\x9d\xc7n-%\x13\x8a*T\xe7\x1a\xa45\xa0\x14\x88t\u0253\x97\x0f?\x04B\xb7Z\x1f\xc6\xd9\xf0HE\u0101\x95\xb4c\x17\xef3\r\x9b\x93\xf1&\x1e\xa8\x85zH&dk\u07d2jH\xa7tMlJ\xfa\x12\x15\n% \\\x01r\xcd\xf0\xb2\xe2\xcb+\xcd_Y\xd1S\xfaC\t\x8dRo\xa26\x00\xbaI\xfb\xb4\x1f6\xea\x89MkT\xe1\u9a40\xe1\a\xc6r\xf6T\xcb\xc8*82\u07bf'd\x8d\x86\xb8W\x18\x01\n\xe7S\x83@\xc1\xfe\x98*k`!B\xd6\xed\x82l\x81\a\xbeu\x1d\xee\xba\xe1\x1f\xb1\xf0\xf0O\xa1t\x0e\x10\xf9\xc1 3\x02AP\x14\x85LMO\xd1\xc5\x17\xbf\x10o|\xe3\x15\xef\xbf\u4497\xfc\a\x00\xb8\xf5\u059b\xf5s\x9f\xfb<\xf3\xb3r\xadO\xc0|?_\x11\xc8\x01\xe0\x83\x1f\xfc\xafo\xbe\xf1\xc6\x1b\x8f\u0736m[\xedx\u034aa\n\x83\xee\xf4\x1cN\xbf\xfcmx\xdek\xdf\t\u05dd\xc2\xca\xe2\"T\xa7\x9b\\t\xae2\x92J\bQ\x0f\x8c\x14\x9aR\f\xd2\x1a\u0119\xbf<\x03\x90;k \xc6@|\x84{Y\x95\xc7x\xb8\xb1+>\x98g\x11\xd7K\xdd\nP\x13\xb8\xf3\x1dN_\x89+\rRY\xa0U\x94\x0f\x9d\xe6\xa4\u04a6\u0291\xd6S%\xd4Z5\x8a\xf8\tG)\xfd_\xfc\xe9\xc3k\xc5)\x89\xabk\x80T\x1aRD\ud217\x0e\u05d0\xb4P!@5\x0f\x934\x16+\x86\x84\xc6h\x97&\xa5CM\xfe=\x8d\x91\xe3\xea1D.\x1c\xc9@O\xeb\xd0\xd1^\x165\x03\xa3k\xdc~rPI\x8b\x80\x12\xed=\x90k\x06r\xae\xf8z\xa5\x18\xb0\n \xeb\xa78\x01(\x12\x14\x16\x18\x05-y\x15:\xc5a(\u0281\x88\x91O\xf50X\u0609\xfb\xbe\xfci\xdc\xf7\x8d\xcfa\xb0\xb8\v*\xcb\x01\x10\x8c\x19z;\nq(\x8aBz\xdd.\xbd\xf0\xa2\x8bp\xe5\x95W\xfe\xe1%\x97\xbc\xf8\u075e\x9a\xfc\xc1\xcf\x14\x90O\xc0\xfc\x19\xb4D\xe4\xc8_\xfe\xe5W\xbd\xe2\xe1\x87\x1fFEM\xfa)8\xb1\x16Y\xa7\x8b3.\u007f\x1b\u03ba\xf2=pY\a\v\x8bK`\xad\xa1:]\x00\x80eU\x19O\xa5\xf3\x87AM\xe0\x91@\x81\x02\x9dA\xac|\xe5\x1a~\x9e\xadop\x8a5\xc1\xf9\xceU!\xbd\xa0\xe4v\x83\xe1S\n\xe0\xc9\xc6C\xb5\xe0\xe5\x00\x82\xac\x00f(\xed\x81\\\x02\x1fZ\xa3\x02D\xea`\x1a\x13s\x9a\x00\x19\x833b\xa3/\xda\xc1J\x04?)O\x02\xe0\u069eR\x8b\xe1\xack\xb2\u06c1\x1c\xa8\xf3\xdbq\u04e1\x96\xffo%\xa2\x1b\x8d\u0438\v\xd5F\xec\x13\n\x05i\xa5\x9fV\xe1\xa8O\xdf\xd3\xf8Sjm\\\x8a\x8c?4\xda\x03aN\xb5\x83Ju\xa6\xd1\xe4e\xa3\xa9\xab\xa2\x04? &\x86\x8d\xea*r(,P\u0113Yz\xe2\x01\x00\xe7@\xa4\xa0\xf2\x0e\x96\x1e\xbb\x1fw|\xeecx\xf8\xc6/\xc1\x16#\xb0\u03bd\xe3\xa45\xb0\xa3!\b\x0e\xc6Z\xbbn\xdd:u\xfe\xf9\xe7\xe2\xcdo~\xf3\u007f\xbc\xe0\x82\x8b~\x1f\x00>\xfc\xe1\xff\x87\xb6n=\xd5\xfc\xac]\xe3\x130\u07cf\xd7O~r\x1b\xb6l9\x19\x00\xf0\xf1\x8f\u007f\uc94f>\xfa\xe81\xbbv\xed\xae\xae+\xf2\xb2\fq\x82\x93.|9\xcex\xfd;\xa0z\x1d\xac\xce/\x87\xa9z\x02\xe9\xcc\xdb\xd0f\xc6s\xec\xc1\xb1NP)\t(P#>E\xa0\xb2\xc0\xa52b\xcc\x03.g\f\xe8,T\xe5.\x96\xc6U\xa3TB|@\xb4aM\xa5\xe5TQ0\x15~q\x05\x86\xf0\xee}~s\t\u0380$e\x80p\x1a6\r4|\xc8\xd3L\xd14\xe6>z\u03d0\x94\xdar\x92\xca\u0696\xc6\xd0+\x81?\xaeZ\xbe\xf5*=\x89\x9a\xab=\xb7\xc8l$\xf6\xba2N\xba\x97\xda\xf6Fu^r\xe1L\x15\xa5B\x95\u007fw)gL\xbcV\x9ae\xb34\xec\n\xdah\x95t\x83l&\xf7\xd5\x1fI\xf3w\tQh\x1a7\x81\xb4\x1a\x8f\xcb\x06\x0f{\x0e`\x0e\u0170\x81n1\x8e`\x85\u0293\x0f#\x89\x00\x14\a\xad3\xa8N\x0f;\xee\xfc\x01\xee\xf8\xa7\x0f\xe3\xb1\x1f}\xcfG\xc7\xe9\f\x80O`\xb2f\b\x88\x85)\n\u0670\xe1 u\xdai\xa7\xed~\xfd\xeb_\xff\x9f.\xb8\xe0\xa2\xf7\x03\xc0\xaf\xfd\xdaki\xe3\xc6\xc3\xe4g\xf1z\x9f\x80\xf9~\xbc\xb6l9\x19\"BD$\xb7\xdd\xf6\xe33\a\x83!Dd\b\xa0\x13/0g-\x0e:\xfc(<\xffW\u078c\xe9\x03\xd7aq\xf7\nD$\xf0\x92\xc1\xc7C)\x90RP\xd1\x1e\x15i2=UG\xf8hO\x1a*\xeb\x18\xd2SzgST\x97\x04g\xc2\x04\x14\xa9\xbc0\xd3[n\f\xcd4\xea\xbc4\u0772TT8)\x15\x18\xe2Z@\xb1\x95\x17\xa8\xa8\x8d\x84d\xaem$^)!-\xdcx\x12\xa9W\xbb\x91\xe4n\xa4Q\xa9\u05ea\xda \x17\x045~!\xcd\x1aM9!\x97\xe3,G\u0273\n%tJC\u007f!\x82:\x1e\xc8\x18\xef\\\u06948\xa9\xe7\x12Q\v\u04a4\\uc*\xbe\xf93\xe5\x8f&\xf4\xcd8\xcd\xef\r\x00\xd2\xe0\x8a\xa6\x99\x155\xeaWj\xdb\\J\x95K]iRe`V\u07c8\x13\xb2\xad1O{\x00\xdbT&)mO{|@u\xaf\x8bQ\x97\xccsz\xa7\xe5f\xe2\xc1Z%_\x12(\x13\xc5\xde\xf91>O'\x02#\x04\x03\x05C\x0e\xa2t\xb0V\xf0fl\xf1\xa4E\x8a\x91\xe7=\xd8a\x1f\xf7}\xf5\xb3\xb8\xe3\u068fa\xf7\xc3?\x85\xd2\x1d\u007f\xaa\n[\x89\xb5\x8583 \u034c\x13O>\t\xe7\x9cs\xceg\xde\xf3\x9ew\xfd\x9f\x87\x1ez\xf8\xfd\x00\xf0\xaew\xfd6\x9d}\xf6Yr\u9957\xfd\xcc^\xef\x130\u07cf\xd7\xfd\xf7\xdfO\x00\xa4(\x86'\x0e\x87\u00e3\x17\x17\x17\xc1\xccdm\xf4iv\xc8r\x8d\u00f7\x9c\x8a|z\x16\v\xfd\x81?\xc6\x06\xdbP'M\x1e\xb5\x91\x05\xb9V\xc1\xab\x02\xa8\xc7\b\x1d\x97\xfc\xbcC9\x86/\xa5\xa7t%\xed\xa3\xa6\xa1\x9f\xa4\xbc\xb0\x946\"13\xa2\x04\xb4\xf8\bc\xd2\x10\u0575t\x94\xec\x0e\u049c%O\xe2\u07e9^V\xd6\xce H(\x8b\xb5\baj\x96\xe4q\x8a\xb2\xac\xdd\u00c8y\xed%L\x9e{\x94(rL\u04a31\xfb\x15\xa0\x95%\xa9\xfb\xbd4\x8a\u548f\x96\xd6B\x1a\x82q\x9a\xa5\xc9\xe2\xd4\xda\xce\r\x11P\xaa\x9e\xe1&M\x13$\x8b\xb1\x1a\xd7T\x9d\xb9\x84\xaasX\xf4\xcd1a,_H`\x89!*\x03\x87f5\xfb@(\x88#\xa8L#\u02fbXz\xe2A\xdc\xfd\x85kp\xff7\xfe\t\x83\xa5y\xa8\xac[\xebS8;\x92b\u0627^7\xc7\x19g\x9c\x81\xcb.\xbb\xec#o}\xeb\u06ee\xf8\xe0\a\xff\x02\x17]t\xa1\xfa\xe7\u007f\xbe\xc1\x12\x91\xfc\xac_\xef\x130\u07cf\u05ed\xb7\xde\n\x00\xf8\xeew\xbf3\u06b6\xed\t\x93$\x8c\xfb\x0f\xb9\x00y\xa7\x87\xf5\a\x1f\x8a,Wp\xcb\x16\xb6\xf4\x84\x1e\xbf\xc0\xc7*\xb8\xe4\xf8.i\u015ap\xc4\x12\xc0\x9dR\x1e=\x863KmN\xbd<-\xd4F\xbe\xa9Fs\x8f\xc9\xff\"\xf7\x1a\xdd\fE\xa4\x1a3O\xe5\x13\x89\x96\xbc\xae\x90\xa9N\r\t\x05_\xca\xdc\u028a|\u0301\xb0\xd1\xe0ly\x81\xa8\x85\x18\x1a\x93\"6\x90\xb9m\xf0\xa6\xed\xd0@\x18\xf7\xe8*\xc1vM\xe2\x1a5#.iT\xeac-\x80\x96;\u07db\u0405\x92\xcfN\t2\x04d\u0283\xb9&oM\x1b\u007fVQ\xf5Yt$p\xe2-~c\x18\x92\x84\xe9Md\xfe\xf5c&(\ue049Q\xf4W\xf0\xc8M_\u015d\xd7^\x8dm\xb7\xdf\bg\r\x98\xb3*l\x1a\x04g\x8d\f\a\xabt\xf0\x86\x83p\xca)[\x17.\xbb\xec\x17\xdf\xfe\xa67\xbd\xe5o\x01\xe0O\xfe\u43f2w\xbe\xf3\xb7\v\"\xda/\xae\xf7\t\x98\xef\xc7\ub847\x1e\x02\x00\xdc~\xfb\x1d\xb4\xb8\xb8T\xe5D\xa6\xd8\xe9\x04\x9c\xe5\xc1\a\xc4WK.a4\xdcZ\xc7p\xaa\x83\xebZ\xd7\xc3x\x85G5>\xb5f\xce\x1a\x80\xbef\xe9\x9aR\xda\x01\xa0]\xf2\u007fI<\xa9\xaf\xf6\x1458\xe0D_\xbd'\xc1s\x8b\x11UIaP;\xbe\xd5\x14\x1fi\x1a\x8fT\xd5p\n\xacT/\xe21\xa6\xf2\xdc\xd3\xc6\u0664J\xd2j\xba\xe1\u007f\x024\x95#\xed\xef\u025e\xda\a\xa9\x8c\xb3mci\xda\xd8R\vM\xa3\u0607HDJ\xc5\x03\xbd #\xf2\xa1\x12a\xe0G U\xe0r\x8d\u0593\xe4\xc4%Py\a:?\x00\xa6\xbf\x84\x9dw\u078c{\xbe\xf4I<\xf0\x8d\xcfbe\xc7c`\x95y\u014a\xf3\u039d\x9e\xa6rR\x8c\x86t\xc4\xe1\x9bp\xce9g\xcf_y\xe5\x1b_~\xdey\x17|\r\x00~\xef\xf7~\x976o\xde\\\xecO\xd7\xfb\x04\xcc\xf7\xe3\xd5\xef\x0f\x00\x00\xcb\xcb+0\u01b46\x02\xfb\xab\xcb\u8bec\x04\x06\x84a}\xf9\\S-H;\x05\\\a\xa5\xe4\xfbM\u0395\u05a8\xea\xeb\xf5jThP\"[\xab\x98XnX\x8dx'\x01\x81\xb3\u0271\xdf5C\u0712Z85\x9cj\xf3\v\xa7\x96J;\xf9y\xda\x03\r\x9d\xe2\x0e\xed\x85\xf2Hi\x8a6\x00LM\xb6\xa8\xc1\xd9K\xe3\xf5\x96\xc6\f}\xbbU@\x02\xcc2\x0e\xf6m?\x9b\x9a;\x8eY\xd36\xfe\xa4\x96\u075b \xa1\n\xf7i@\xf1\xb8@\x94\xf8\xd3\v` q\x0e\xcd[\n\xa3jZ\xa7Q\x81\x00!\x9f\x9e\x83\xd8\x02\xbb\xef\xbd\r\xf7~\xed3\xb8\xe7\x8b\xd7`\xe1\xe1{\x82\x0f\x0e{7c[\xf8\x01\xb8\x80\xff\xa6\x18\xd2a\x87m\xc4%\x97\\\xfc\xf0o\xfe\xe6Uo8\xe5\x94S\xbf\x06\x00g\x9f}6\x1dq\xc4\x11\xf2\xcaW\xfe2&`>Y?\x13kzz\x1a\x00\xb0n\xdd\x01\xd0ZS\x1b\x98[\x01\x1e\xbb\xfb6<\xfb\xdc_\x84\xca2\xc0\x8cJ\xa0qu\xf4+\x8bT'-<\xed\x1eh\x81\xf1\n\x93BVg2Q\x1a\xf9\xe1d#`\xd4\xef75dt\xf0\xde\x1c\xa4\xe3\b~x\xbc\x8d*\xb8\x1cj\xa2\x06O,\xb4f\xb5\xdd\x046\xa0\xddKdOTC:H\xda\xe4\xe2\xa9\xed\xa4\u04e0^\xa2\x94\x9dZ\xee\xdf5*zY\u3157f%\x1e\x01\xbf\xa5\xe1K\r\u03bby;{z\xee\x94\xd0m\x8a\xbc\u02e1\xa2\x94/\xf7wl\xc5W\xe2&\x98_9T\x8a\x14'\xa8\xbd\xd7\x11\u01f9\xd3\x05\xeb\f\xbb\xef\xbf\x13\x0f~\xe3\x9f\xf0\xd3/}\x02;\xef\xb9\r\xce\x14\t3\xe7\x1b\xf7\xc4\u02a3\xb83B\x04\u06b2\xe5D\x9c~\xfa\xe9\x9f\xfd\u0407>\xf8V\xa2\xfc!\x00x\xc5+^N\xaf}\xed\xe5\xf2\xf2\x97\xff\xd2~w\xbdO\xc0|?^g\x9du&>\xf0\x01\xe0E/\xba\xa4\xf3\x0f\xff\xf0?r\x9f\xe03~Y\xfe\xf0\xf3\xff\x88\xe7\\\xfcj\xac?~\v\x86\xa3\x11\x8ci\ua269\x9e\u053e\x06pK\xa3Z\x17\xa9Q\xcc\xe9\xa19\x0e\x1d6\xc2\x1a*q\x9f\xa2\xa4\"\x0e\xa0j\xa5Q\x95\xa2r\x1etX\xeb\u030f\xb1\xc6\xdfZ\x15\xf6\xbfF\f\xb2'*\xa9\xf5\xb4\xd22h\x93\x16\xff\xae\x85\xedi\xbb\u03f1\xf9$Z\x9b\xc7\x1es\x14h>\xb6\xa4\x1a\x8eT\x9a\uc067\xdf\x13\x8d\x1e\xe9\x16\u037e\x12\xd7\fd\u025b\xee\xc4\x0f\xf9\xd8p\x92\xaa;$W\x03K.\x8c\xe9#PcJi\xa8\xbc\x8b\xfe\xeem\xb8\xef\xeb\x9f\xc5=_\xbc\x06\xdbn\xfb\x1e\u0330\xdf\xf2\xfa\x87\xe9_\x888k\xe9\xc0\x03\xd7\xd3\xc9'\x9f\x8c\xf3\xcf?\xef\xaf\xdf\xfd\xee\xf7\xbe\x93\x88\x16\x01\xe0\x8f\xff\xf8\xfdt\xee\xb9\xe7\xca\x19g\x9c\xb5_^\xef4\x81\xbc\xfdw\xddz\xeb\x0f\xe9\xb9\xcf=EDD\xbf\xf0\x85\x17}\xfe\xc6\x1b\xbf\u007f\xd1\xc2\xc2B\x01 k\xfe\xec9\xaf\xfb?\xf0\xa2w}\x00\xab\x05\xb0k~\x11&\t@p\xad\xf9\xedT\x06\u8d8dl73}\u04df+\x81<\x06\u0460R\u03a4\xe0\xe5\x12\x00\x8c`\xdeVIK\x8b\xeap\f@\xf1\xaf\xb4_\xc5\xda \xb9\xa7\n\xbc\xf5\xff\xa5\xae\xf2\xc0\x1a\x8f3\xd5~G\xa0N)\x13Yc\xd3L)\x1d\xfaW<^iy({\xba\x8dh\xa6\x16\u04d5\xe2\xfb\xc0I\u04d9#\x80\aKZ\x1d\xee\xa0pQ^X\xf5`\u01ac\u0723\xc6'\xdc9\xb3\x02k\r\xcer\x10\x80\xc7~\xf0u\xfc\xe4\xd3\u007f\x8d\a\xbf\xfd\x05\f\x97\xe6[@\xb5\xbcv\x84\x92\v\xcf\u060f\xe0w\x15\xa1\u02c4\x9c\xa3\xb4P0r\xc0\xc8\tFNj@.\xd2\xdc\xc0\xc2ILk\xe4\xbd\x19\xe8\xde\x14\x88\b\x8b\x0f\u078d\x9b>\xfc>|\xed}W\xe1\xee/^\xe3\x81|,\xfeNy\x97O\u71cb\x0e\x1e\x9dLmj\xf6\xd6\x03L\xf5\n\xdc\x04N\xdco\x9cT\xdbW\x89\xc2\xe8=|'Ck\r\u055d\x02 \x18,\xec\u0093w\u0742\a\xbe\xfd\x05\x89\xc7\u007f\xf4]\xac>\xf9\xc4\x1a\xaf?\x05\x1fr\xb2\xb6\x18\xb9u\xeb\xd7g\xc7<\xfb\xd9\u063c\xf9\u87dey\xe6\xf3\xff\xdb\xdb\xdf\xfe[\u007fCD%\xa1\xfew\u007fw5]~\xf9\xeb\xe4\x99t}O\xc0|?_\x9f\xfc\xe4?\"J\xb0\xbe\xfa\xd5/\x9fu\xd5Uo\xfa\xd4\xddw\u07fdqO\xbf\xb3\xf5\x97\u07ccs\xff\xaf\xff\x86a\xbf\x0f\xe3\xbc\xe6\xc0%~\xdee\xf5\x89\xb4\x8a[;\x977\xf5\aA\x00s\xae\x02\xdek\r\xb8\xe8\u0451zm\xd5\xf4\xdb4\x0e\xf0.i\u6943N\xa9\x94\xb2)\xb3k\x1bY\x97\x96*|\xefT\xc5\u068a\x17\x91q*\xa6mx\x96\x1a\xb4Jk\xc61\xa1\xe6E\xd2\xd4\xfbKc6\xaa\x91i\f\x91\x8a\u058a?\xdf\u059c\xe6@\xa3\xa8D\xaa\x19u\xe21\xc4\u00c6\xc1\x1e\x13\xbc\xe6\u0460Q$\xd26Toz\x131\xf2\xde\f\xc4\x19,\x1b'\x9cp\xc2\xe3\x17\\p\xde'\xae\xbc\xf27\xff\x84\x88\x1eM\u007f\xe7\xc6\x1b\xbf\x87\xe7?\xff\xccg\u0735>\x01\xf3g\xc0\xfa\xad\xdfz\ab(\xed\u55ff\xe6=\xd7_\xff\u03ff\xbfc\u01ce1\xfca\xe5#\xe3\x9e\xf5\x9c\xad\xb8\xf4?}\n\a\x1c\xbd\x19+\xbb\x97|\xb2O\xe9\xa1RM\xbb\xa4\x81p\xcdj=\x8eo\xa3\x99l\x8fj\x80\xa4\xe4\xe0\x13\x80\xb1\rpX\x8b\n\xdf\xe3\x9c\u0358\u007f\xeb\xdaMPZk\x8eH\xc6\xf9c\xd9\x03\xc5Q\xbb\xfd\xda\xff'\u05b9\te\xd5\u49db\xf7W5\x1b\x83\xdb\xe0\x1a\x9b\x95\xb4\x9cL\u0186_\xd1p/\xa0\xea=\xe2F\u056e\x89\x02\x95\xe2}T\xac\xab\xde,\x17\x14)#G\xb0.\xd17%Fk\xe9f\xcb\xf1\x15P\ny\xb7\v3\x1aa\xe7Oo\xc3#?\xf8:\x1e\xf8\xe6ux\xe2\xf6\x9bP\xac.\xb5\x03Sp\xe3,CK 8\xe4Y\a\xe3\xb8\xe3\x8e\xdbu\xce9g\xff\x8f\xdf\xff\xfd\xf7\xfd\x15\x11\u0756\xfe\u03bd\xf7\u0783g?\xfb\xd8g\xecu>\x01\xf3g\xc0\xfa\xc8G\xfe_\xfc\xfa\xaf\xbf1\x80\x89\x1cp\uee7f\xf0\xc9o~\xf3\x9b\x17:\xd7\xeeq\xca\xcc8\xe1\u016f\xc1\x19W\xbe\x17sG\x1e\x8b\xe1\xb0@Q\x14\x10g\xe1b-^*Y\xa8\x01\xec\xd5m\xa9\x84\x03\x88\xba\xe3X\u5e44#\x8f|y\xe4mC&\xd1X\xc5\f\xaa\uedd5{nC\xf9\xa6\xcdk\v\xa72\xc6}\xaf\xc5\xe7\xa0e\x02\xb26\xfe)\xf5\r\xa3\xb4}\xa5\xca\u05e6e\a\x8aI;M@\x8f\x9e.\xdeU\xb0\xb1\xb1H;\xdf.\xc9k]\xbe\xee\u912bT NR\u077f\"Ow\xe9\xa0\x15\x8f\x16\u0205\x93\x92B\x89\u0787\"\xd28uH\xa9\x18W\xd1\x06\x81\t\xac2\xe8N\x0ek,\x1e\xbf\xed{\xb8\xef\x9b\xd7\xe1\xc1\xef\u0740\x9d\xf7\xfc\b\xb6\x18\xb5\xa2Q\x19p\x12\xde\xebLkt{\x1d\x9cx\xc2\t\u063a\xf5\xb9?\xb8\xe0\xfc\xf3\xdf\xf1\xcaW\xbd\xfa\xeb\xe9\xaf\xfd\xdd\xdf]\x8d\xcb/\u007f\xdd3\xfe:\x9f\x80\xf93d\xfd\xf8\u01f7\u2913\x9e\v\x00\xf8\xda\u05fe\xb2\xf5\xfd\xef\u007f\xff\u05ef\xbf\xfe\x86\xb9Vr84\x167m=\a[^q%\x8e8\xfbE\xe8\x1e\xf8,\x18\xe3P\f\ap\u0468\xab\x85w\x8d\x00V\xafM\xa5\xf4\xb3\x8eG\xf8\xf8;&\xe1\xc7K\x87\xbb\xa4t\x96\x96t\x84\xb1\xea\xbcm\x80\xa6\r\xe9Z\x88\xf65\xbdRP\xc9\xef\x9a\x00\xdb\x1c\xe0\u065b>[jS\xad\xd5\xf3\xad\x03yx\xf6m\x8a\x97\xb0\xf9U:q\n\x95\xaf\xff\xa6kP[Q:\x18+\xed\u0606\xb4e\xe5N5\xc0\x8f\xf7i\xa4\xd2RF\x8f\x1eA4.KN\x19\xa8d\x89\x11\xc0\xe3\xaeKD\xe0,\x83\xce;p\xd6b\xdb\x1d?\xc4\xdd_\xfe\x14\xee\xff\xe6ux\xf2\xbe\xdb\xd1\xf4\a\x8a\x0f\xa0\x04p?\xf5C\x9dN\x8e\x99\xe9\x19l\u06b4\t\xcf{\xde)\v'\x9ex\u009f\xfc\xd6o\xbd\xf3CD\xb4\v\x00>\xfe\xf1\x8f\xf1k_\xfbknreO\xc0\xfc\x19\xb9n\xba\xe9\xfbt\xdai\xa7\v\x00|\xe2\x13\xff\xf0\x92\xff\xfc\x9f\xff\xeb5\xdf\xfe\xf6wf\xdb>\x16\x14F\xfa\xa7\xd6o\xc0\xc6\u7783\x13^\xf6F\x1cv\xea\xb9PS3\xb0\xc6\xc1\fVk\x8d\xae\x8a\xb2\x90\x06\x8f^\x81I\x12(_\x1bXI\xc1\xbcf\xb0DU\xd5O\r\xad\xf2ZMKip\xed\xcd\x1fn\xca'E\x9a\xbe1\x82*\xbb\xa1\x82cn\xb1*H=l\u02a1\x9e\xf0}\xa6\xf1\xfec\x94]J\xa8d\u02f0\x86\xe4a\xa6\x1b\x9dC}X\b\t\xe0\u01e0\xb44\x06/Fw\xc6\u7903\xc3c\xf4\b72\xde\xe5\xb0R\xdf\\R\x8a\xab&-M^\u0426\xb5B\xa9Ya\x8dNo\n\"\x82'\xef\xbb\x1dw|\xe1\xbf\xe3\xbeo~\x1e\xbb\x1f\xb8\x13f4h1\x81!\x1f$\xce\f\x11'\xe2\x84\xe6\xe6f1;;\x83C\x0e9\x14g\x9f}\xe6\u03a3\x8f>\xfa/^x\xf1%\u007f{\u0496\x93\x1e\x04\x80W\xbe\xf2\x15\xea\x13\x9f\xf8\x94\xdd_\u0331&`>Y\xff\xcb\xeb\xaf\xfe\xea/\xf8Moz\x8b\x03\x80\xab\xaf\xfe\u0605\x1f\xf9\xc8G\xae\xf9\xcew\xbe\xbba4\x1a\x19\xa5\x94\xb2\u05b5\xea3f\x0f9\x1c\x87\x9dz.\x8e\xb9\xe8Wp\xe8\xd6s\xa0{3(\x06\xabp\x81\x96i~\xa4\u04a37S\x134+d\xa5\x06\xa7]w\xf1\xab6\x95\xa6\xba\xa5\xc9\x17\xd7\x14\x19M\xab\xdb=\xad\x06h1\x118\xdcge\x0e\x15\x81\x8f\xcaA\xa7X\xc4:Y;u'\x1d\xb2\xa9\x01:\u0579\xf9\x96t\xb9\xbd6C}\x90\x03\x95\x9bb\xc6\x04\x15\xc0\x19\xa5\xc5,\xd5\f\u04cc\xabd\xa4\xae\xda&\x91\xe4\x8d\xd4\r\xba\xa4\x02o$\x9b\x05\xa5\xd2$q0\u0387C\xe4\xdd\x0e\x96\x1f\u007f\bw\xdf\xf0I\xfc\xf8\u068fc\xe7Oo\x83\xb4T\xe2Q\x99\xa2\x98\xc59g\x8c)p\xd0A\af\x1b6\x1c\x8c\x83\x0f>x\xfb\x19g<\xff\xd6\xd3N;\xf5\u00ff\xf2+\xbfz\x1d\x11-\xc7\u07fb\xfa\xea\x8f\xd2\xeb^\xf7z\x99\\\xc5\x130\x9f\xac\xb0>\xf4\xa1\xbf\xe4\xdf\xfc\xcd7;\x00\xf8\xf4\xa7?y\xc1\xd5W_\xfd\x0f\xdf\xfa\u05b77\xec\xdc\xf9$\x98\u0649\b\xa7>.13\x93\x94\xc6\xf4\xc1\x1b\xb1\xf9\u0717\xe1\x84\u02ee\xc0\xfag\x9f\xfc?\u06fb\xd2\xe0:\xaa3{\uef7d\xbcE\xfb\xd3\xf2$\u02ca6\x8c\x1d/x\x19\xc6\xc66v\x8c\x1c\x98\x94\xcb\xd4\f\x1e\x02\xe4G25E\xe18\x19\xa8\u0250T`H\x82a\x96\x84Jf\x8a\u0270XP@\xa8\n!\xc9\x04\xc8x\x02\x89\a\x13\x1b\xe3\x15\x19[\xc6c\xcb\xd6bY\x8b%\xdbOz\u04b3\x96\xb7t\xf7\xbd\xf3\xa3\xbb_w?=9T*\x10\x92\xf4\xf7G\xb6\xf4\xd4oQ\xdfs\xbf{\xbe\xf3\x9d\x0f\x86a@OM[G\xe5\x1c\x8b\u05dc\xbc\xd3[\xfa\x83\x8bs\xc7\fj\x06\xee6}\v\xa0DNES\xe4aT\x80Y\\\r?\xc0\x02p\x80\xdb\x04t\x99\xda\xca\x0e\x93;\xd6sN\x10N\x929s\xd7\x103\xb2~GuCs\x00\xde\xfe\xbf\xbd9\xe4\xb6\xf0\xbb\xaf\u0248\xa3\xef'\xd9l\xdetx\xb4\u01aaZ\x80k\xda\xc9\xdat\x89\xbb{\x96{\x8a\xc1b\xc6)\x04\x96~\xdcV\xbc\x10\x97g\x8b\xd3[`\x1e\x9f$E\x85\x12\n \x99\xb8\x82\xc1\xf7\xf6\xa1\xfd\xa7O\xa1\xef\u0777\xf2r\xe2\x84R\xd3\b\x8b1\b\xce\rn\x18,\x12)CCC\x03\xaa\xab\xab/,\\\xb8\xf0\xf5\x96\x96\x96\xc7ZZ6\x9es\xff\xde7\xbf\xf9\x10Y\xb6l\x99\xb8\xed\xb6\xbf\xf6\x17\xaf\x0f\xe6~\xe4\u01b7\xbe\xf5M\xf2\xe8\xa3\xff$\x00\xa0\xad\xed\xf0\x86\x1d;\x9e\xf9\xcf\xfd\xfb\x0f,s/\x01\xaf\u0305\xe4\xe4\xa2\xc45\x9d&\x97\x1b\xcf*'0\xcb88\u0324C\x90\x876\u0235\x17\x80\u02e6\xd56\xf9\xa2\xc4\xecj\x14 \x969\x94p\x81\"q\x15\x05\x85\xd7\u070b\xe4Q\x9c\xe4\xd0\x14\x94\x98\xf2=B\xecY\x1e\xf6\xa7 r\xe4\x92\xe6\xc6B@\xac\xe767\x99,\x03\xef\xca\xfeM\x1bY1\xc3\u01c6\xbbOA\xc8\xd5\xec\v\xab\x17\x80xL\xbe$\xd7H;\xee\xca\u0429e\x8aEe\x19JH\x8561\x81\xe1\xe3\xef\xa0\xe3\xcdW\xd0\xf5\xf6N$\xc7F\xf2\x838\xa1`\x8cZ\x9b\tGEy\x05\xe6\u039d\x8b\x9a\x9a\xe8\xb1\r\x1b6\xec\u07f6\ud2ed\x8a\x12<\xed\xfe\xbd\x05\v\xaeEkk+\u05ad\xfb\x94\xbf`}0\xf7\xe3j\xf1\xe0\x83_'\xdf\xfe\xf6cV3\xa5\xa8\u07fe\xfd\xe1\xc7\xf6\xed\xdb\xf7\u064e\x8e3\x88\xc7\u3982\u015d\xa1Sj6n\x00\xe0Z\x06\xc1\xb2J\xd4\u07f8\tsW\u0742\xaa\xeb\u05a00Z\vC3`his\xaa}\x0e\xaa\x12\xe1:\xda\xc3\xd5\xe5\txG\xb3[w\xa6c\x80\ubc3c\xd9\xd6~kX\xb4\x10\xb3\xdf\xd0\xf9\x9a\x98\xf2\xb5\xc5S7\x9dB\\\xad\xed\"\xbf.\xfb>bg\x8ea\xe4\\\a\x92c1\xa4\xa7&\xc0\r}\xc6\xe7I)\u02f6\u061b_\xad\xb1mB\x18\xe9t\x9a\x97\x95\x95\xc9s\xe6\xd4`\xfe\xfc\xf9\xf1\x95+\xff\xfc\xdf\xee\xbf\xffk\xdf%\x84d\xc7\x02}\xe7;\xffJ\x1ex\xe0\x1f}y\xa1\x0f\xe6~|T\xf1\xea\xab?\xc3\xee\u077b\xc9SO\xed\xc8.\xbcw\xde\u0673\xf1\xe5\x97\u007f\xf2\x8d\xe3\xc7O\xac\xef\xec\xec\xc4\xe8\u8a1d\x9cR\x0f\x8d`\x1d\xbd\x05\u7812\x84py\r\xe6,[\x83\xba\x1bnA\xe5\u0095(\xaem\x02Q$\xe8i\u00f4\b\xe0\x1c\x82\xebV\xd6\xeed\xa6\xe6\x14!W\xcb\xd1U-\x02\xf3\xd3(\xf4K\xd5\x00\x00\v\xecIDAT\"\x1e\x83+K\x8d\xe1\xc9\xfc\x89\xfd\xe2g\aL\x9b\xe20r&M\xb8\x9b\x99f{\x1dW\x1b\xd6\xecH\xfeL\x12;+[\xb4~n\xb8\xb2\xf3|\x1c8r\b!\x02\xaf2\x881\x06EU!)\x12\x88\x00\u04898&c\x171q\xb1\x0f\xa3\xbd\x1d\x88u\x9d\xc4\u04296\\\x19\ua0de\x9a\xc2\f{\a\xf7\xe9\x8b8~\xf2\x0emC@\b\x11\x9a\x96\xe1\xa1P\x98\u035bw\r\xea\xea\xea\x06\x97-[\xba\xf3\xcb_\xfe\u04bfG\"\x95=\xeekuvv`\u07bc\x05\xfe\xe2\xf2\xc1\u070f\xdfG\xb4\xb6>\x8d\xad[\xb7\xb9\x8e\xf9B~\xe9\xa5\x1f\u07bdk\u05ee;\xfb\xfb\a\u059dF\xb2lR.yd\x83e\xd6\xf8\xca*\x80:\x1b\x94p\x9aw(1\x1b\xf8)\x01\xb3(-JMb\x852\n\x89\x02Z:\x83\x89K\x03&h\xf7\x9e\xc1X\xdfY\x8c\xf5wc|\xa0\v\x13\x17\a\xbd\xe3\xe0(3yn\xeb\x14E\x89W\xc6#\xf2\fN\x15B\x80R\x02YV \xcb\x12\x1a\x1b\x1b\xd1\xdc\xdc<\x19\x8dV\xb5\xdeu\u05dd?Y\xb5jM\x9b\xfb\xf1\xdf\xff\xfe\xe3\xb8\uffbf\xf7\x17\x90\x0f\xe6~|\x9c\xe2\x95W\xfe\v[\xb6\u070e#G\x0ea\u03de\xbd\xec\x81\a\x1e\xb4\x95/U/\xbf\xfc\u04a7\xdb\xdbO\xdc\xdd\xd6vt\xfd\xa9S\xa7\x90H$\x90N\xa7=L\xc5L\n\xc603hj\x82<\xa1\x14L\x0e@\t\x17A\n\x85!\a\v\xa0\x84\x8b\xa0\x16\x95!\x14\xa9B\xb8j.\xc2\x15s\x10(.\x85\x1a.B\xb0\xb8\x14\xc1\x92\n\xa8\x85%\x90\x14\x15\xce \x04\x0eC7\xcci\xedB\x98\x13L\x05\xcf\x0e\f\xa6\xd4\xd2e\u00dc\x96\x03 ;\xcb\xd46\xb0\u02b5\x9b\xe5B@\xe3f\xe1\xd5\x00\xcd\u038c\x13v\xeaL\b\xe0\x18E\xb9\xc6\u06f9\xac\xa9,>\u01b1\x036\v\xae\xb6\xbe\x9c\x11\xc7!\xd11,s\rL&f\x87'\x17\x02\f\xe6&\x96\x99\x9e\u0115\xe1~\x8c\xf5w\"~\xfe,F{;\x90\x18\xee\xc3\xc4\xf0\x00&b\x17\xc0u\x87\xf3\xa6L\u029aY\x99\xb2A\xe21\xf52\x9d\x10E\xdeF,\xc30\x04!\x84\x84B!\x14\x15\x15\xa2\xb1\xb1\x11\x8b\x17/>\xdd\xd4\xd4\xf8\x8b\xa5K\x97\xbd|\xd3M-\xed\x00\xb0~\xfd\x8dt\u06f6m\xb8\xf3\xce\xcf\xf9\xea\x14\x1f\xcc\xfd\xf8C\x897\xde\xf8\x05}\xe3\x8d_\xb2'\x9ex\xd2V\xbe\x84\u007f\xf0\x83\x176\x1f=\xfa\u07b7\x8e\x1e=\xba``\xa0\x1f\xb1X\f\x9a\xa6\xe7-\t\xba\xb3C\x13\xe0I6\xd3\x16\x82Cp\xd7\fw\xca \xa9A\u0221\x02H\x81\x10\xa4@\x10J\xa8\x00\x81\xc2R\x84\"QD\x1a\xe6#\u04bc\b\xa5\x9f\xb8\x16\xe1\xb2JH\x8a\nI\x92 I\xd41\xc4\x12\x00\xb8\x01\xce-B\xc5eW\xeb1\x8d\xb2\xa8\ffm2 \x04\x19\x01d,x\xd2\f\xb3\u02d2[\x1bD\x96\n\xe2\xe6\tA\b\x93'2\xbf\xaf\xc3\xd0\xd20\xd2Ip]\x03\xd7M\x1baSJHA\xc0A\xb9n\x82\xb3\xaeA\x18:\fC\x03\x84\x80\x1a.\x82\x1c\f\x9b\x12A-\x8d\xf4D\x02S\xf1\u02d8\x8c\rc\xf2R?\x12\xc3\x03\x98\x8a_F*1\x8aTb\x14\xc9\u0118\xc7\a\x85P\x06\xcaXv\x93\xb3\v\x964\x0f\x80C\x88\x19\x12Ka\x06!\x04(**FYY\x19\xae\xb9\xa6\x19MM\x8d?^\xb0`\xc1\xd3\u06f6}\xb9\x8b\x102l?]k\xeb\xd3l\xeb\xd6m\xba\xbf2|0\xf7\xe3\x0f4\xac\x81\xd1n\xe5\vmm\xdd\xf1\xb9\u00c7\x0f\xdf\u007f\xf2\xe4\xff-\x1d\x19\x19\xc1\xf0\xf002\x99\x8cA\b\x04\xa5L2\v\x9d9\x1c\xac\xc5E\x10\xf7\x84g\xe7\xa2\x10\xdc\u021b5RJ!\a\xc3P\vK\x10,-G\u025cFT^\xb3\b%\xd1Z\x14\x94U \\Z\t\xb5\xa8\x14r(\fI\t\x80I2d\x89\x81P\xe6iN2\v\x8f\xe6f\xc2u\x03\x84\xeb\xa0\xe0\xa000\x9d\xd611\x95\xc4\u0115+\x98\x1a\x1f\xc5\xd4D\x02\xa9\xa9\t\xe8\xa9$2\xa9\x142\x13cHO\x8cCKN\xc2H\xa7`d\xd204\xf3\xab\x9eJ\x82k\xa6m\xb00\f\ap\xadZ\x02\xb1\xc0\x94s\xdd,\x06\x1b\xe6\xfb\xb4\x1b\xb3\f-\x03\xaee\xa0k\x19\xf3\u07fav\xf5\x05\x9d\x95\x8bRPP\xc7\xc7\x1c\x8e\u01ce;\x03'\xc43(\x9b\xeb\xban\b\xc1%UUI$\x12AYY\x19\xae\xbdv~b\xf9\xf2\xa5\xaf/_\xbe\xec_n\xbe\xf93\x1e>\xfc\xb5\xd7^!\xd5\xd5Q\xb1j\xd5\x1a\u007f1\xf8`\xee\xc7\x1fC\xec\xdc\xf9sr\xeb\xad\u007f)r8\u04ed\x1d\x1d\x1d[\xbb\xba\xba\xe7\x0f\r\r\x05c\xb1\x18\xe2\xf11!\x047\b\xa1T\bn+(H.\x1d\xe3\xf6Gw\xeeT\xe2\x92\xf59\xed\xa3B\x18.\x87?\x02I\r\x80\xc92\x98\xacB\t\x86\xa0\x14\x14\xa1\xb8\xbc\x1a\x85\x955\b\x16\x95@\r\x86!)*\x18\xa5Y!$#\x020t\x18\x99\f2\xa9i\xd3\xe27\x93\x82\xd0\u04d8\xba2\x8exl\x04\x93\x93W\x90\x9e\x9e\x86\xaee\xc0\r\xdd\x04^+\x03\xe7\u0724v\x84\xf8\xe8Tw6\x10\x13W\xb3\x8eS\xb4\x9c\xc9w\xbb5\xdd\xc4\xf1+\x067\x83J\x12#\x95\x95\x95(++CAA\xc1x]]]\xfb\xfa\xf5\xeb\xf7\xdes\xcf\u059f\x12B:\xdc\xd7{\xf0\xc1\xaf\x93{\xef\xbdW\xd4\xd4\xd4\xfa7\xbf\x0f\xe6~\xfc\xb1\xc5\xd3O?\x85S\xa7N\x91'\x9ex\u049d\xa9\xb3C\x87\x0e\u073as\xe7\xceM\xdd\xdd=\xab\x93\xc9\xe4\x82X,\x86\x81\x81ALOOA\xd7uLO'!\xc4\a2\xac\xbd\u028dLr\xe7\xd2\xffN\x16E\xde\xd1l\x1f\xe5\x02\xf5H\x02]_\xad\xb6y\u4302\xcb97y\u078d\xfd\x18\xce\x058\xe7\x90$\t\xaa\xaa\xa2\xa8\xa8\b\xd1h\x14\x91H\xd9XII\xc9\u19a6\xa6C\x1b7\xb6\x1c\xfd\u0527n\xdaE\b\xf1\xf0\xdfo\xbe\xf9+|\xfa\xd3\u007f\xe1\xdf\xec>\x98\xfb\xf1\xa7\x10\xb3\xa9\x18\x84\xe0\u05fe\xf8\xe2\x8b\x1b\xdb\xdb\xdb\xe7\uaeb6\xe2\u0295\x89\xf2s\xe7\xceM\x85\xc3\xe1\u56a6\x05{{\xcf#\x91H \x93I\xc308\f\xc3@&\x93\xf9\xe3\\x\xb9Y2!\x1e\xd31\xea\xea\xc1w\x17D\xed,;\xdf\x06f\u007f\x9fR{\xec\x9a\xd5\xf9i\xa9V\x18cP\xd5\x00**\xcaQ[[\v\u01a4\xe9`0\xd0Y]]=\xac\xaa\u02ae\xdbn\xdbrv\u035a\xb5\xbf\xca\u05d5\xb9k\xd7/q\xcb-\x9f\xf1on\x1f\xcc\xfd\xf8S\x8c\x8b\x17\x87\x10\x8d\xd6`p\xb0\x8f\xd4\xd6~B\xe4\x1c\xfb\xab\x00\x94\xec\u077b7\xd9\xdb\xdb3\xaf\xaf\xaf\xaf\xee\u0295\xc9\x06Bp\xfd\xc8H\x8c\xc6b#)JiEQQ\u046a\u02d7/c``\x10\x13\x13\x13\u0434\f4M\x83\xae\x1b0\f\x03\x9a\xa6\x9b<\xb7\xdbf\xe0Cj\x11\xbf\x9a\x89\x96\x99\a\x93\x19\xf3D\xb3\t\xf2l\xb9\xbdG\xcbm6\xfa0f\xd3%\xc4j\xa42m\x87\u0740\x9d}FB!\u02e6R\xc56\xb7b\x8cZ\xe0mf\u07a5\xa5%\xa8\xad\xadE0\x18\ucaac\xac\xec\f\x04\x82GC\xa1`\xe7\xbcy\u05cc\xb6\xb4l8\x1f\x8d\xd6^$\x84$\xec\xabvv\x9e!\xf3\xe6\xcd\x17\x00\xb0c\xc7S\u063cy3\xe6\u0319\xeb\xdf\xd0>\x98\xfb\xf1\xa7\x1c==\x9dhj\x9a\a!\x04v\xee\xfc9\x89\xc5b\xec\xc9'\x9f\x16\u01cf\x1f7\xf2\x03\xa6\xa8\xb0\xeeK\xbd\xa3\xe3T\xb8\xaf\xaf\u007fN[[[@Q\xe4\u0159Lf\xe5\u0673g\xb5\xe9\xe9diII\xf1\xba\x8b\x17/\x97\x0e\f\f`||\x1c\xba\xae!\x93\u0450L\x9a\xfe/6\xd8Sk B~\x80\xcf\xef\xed2\xc3\xfb\u071e=*\x04r\x8b\xb7\xb2,\x83Rj6\xf5\xe4\\U\x96e(\xb2\x9c\x05W\x0f\xc7M\x88w,\x9b\x95=\xeb\xba\x0e\u039d\xe9M\xf6\xefp\xceA)\x81$IP\x14\x15\xb2,\x811\x06J\x19dYBqq\xb1\x88F\xa3\xa4\xa4\xa48\x1d\x8f\xc7\x0f\x8c\x8d\x8d\x9fkhh\b44\u05031\xe98\xe7\xbcm\xf5\xea\x1b\x86W\xaf^;F\b\x19\xcd}\xcf\xf7\xddw\xaf\xb4b\xc5r\xb1l\xd92\xbed\xc9R\xf1\xfa\xeb\xff\x83M\x9b6\xfb7\xb0\x0f\xe6~\xf8q\xb5\fW\xe0\u0529\xf7iOO/y\xfb\xed}(,\f\xd3D\xe2\n}\xfc\xf1\xffH\xff\x86\xdf\v\x02\x10\xa9\u0514|\xe4\xc8\xe1\u04b6\xb6cJEE\xf9\xc6\u04e7;\x16\x8d\x8c\u0116\x8d\x8c\x8c.\x1e\x1a\x1a\n'\x12\xe3\xd40\xcc\x06\x97t:\x8d\xa9\xa9)LM%a\xaa\r\t4M\x87\xa6i\xf9\x93k\x80\u0232\fIbfc\x90p\x18sU\r\xa0\xa8\xa8\x10\x81@\x00\x92$\x81s\x81d2\t\x00P\x14\x05\xc1`\x00\x92$\x9bEXY\x02!$I\b\x9d,..DAA\x01\x14EE \xa0BUU(\x8a\n\xc6X\xf6\x89UU\xa5\xc1`\x80^\xb80\xb4\xef\xfc\xf9\xf3\xa7\xc2\xe10K\xa7\u04d9\xea\xea\xea\xe6`0T\xdc\xdf\xdfwZQ\x14c\xee\u0739\xa4\xbe\xbe\x1e\xc5\xc5E\b\x85B2\x80\xc1c\xc7\xda\xf7LNN&\u05acY%777\x19\r\r\r\xf1H\xa4j\n\xf6\xdc\rB\x92\xb9\xeb~\xfb\xf6\x87\x95T*i\xd4\xd7\u05cbU\xabV\x8a\xa5KW\xf8\xdap\x1f\xcc\xfd\xf0\xe3\u00cb\xae\xae3\u063d\xfb\xd7\u0636\xedK\xbf\xf1\xb1\xd3\xd3\x13U\x87\x0e\x1d^\xb7\u007f\xff\x81\x8at:\xb5H\b\\\xdf\xdd\u074dX,\x16\xe6\\\xd4%\x12\t#\x95JrEQKB\xa1\x90\xb5A8\x14\rc\fB\b$\x12\t=\x9dNO\xaa\xaaJM\xe0UH(\x14\x82,+\xa3\x15\x15\x91X}}=\"\x91\x88$\x84\xb8\xd4\xd9\xd9\xf9v:\x9d\x89777K\xcd\xcdM(..\x86$1Z\\\\\"\x15\x16\x16\xbe;22z|\xf5\xea\x1b\fYV\xd9\aY\x8b\x84\x90\xe9<\x9b\x98G\xfe\xf9\xdb\xc4\x0f\u007f\xf8\"\u05ad[\x87\xba\xba\x06\xff\xa6\xf2\xc1\xdc\x0f?>>\xd1\xde\xfe\x1e\x1e}\xf4\x9f\xf1\uaaef}\x90\x93@\xf9\x89\x13\xc7n>r\xa4-}\xe6\xcc\x19\xbd\xb2\xb2\xe2\x9a\xf2\xf2\xc8\n\xceE\x88s\xce3\x99\x8c\xb0\xb2c\x99\x10\x92\xec\xed=\xff\xf6\x85\v\x17\x06\xeb\xea\xeaX]]\x1d\xa9\xae\x8e\xb2\x86\x86\x06\xb2h\u0452vB\xc8\u064f\xe3\xe71<<\x88\xeaj_&\xe8\x87\x1f~\xfc\x81\xc7\xd0\xd0\xc0\xc7\xf2u\xdd\u007f\xff\xdfbp\xb0\xdf\xff\x03\xf9\xf1\xa1\xc7\xff\x03 \x99\rH\xa6\x0e6\x92\x00\x00\x00\x00IEND\xaeB`\x82") - -// dashboardDockerfile is the Dockerfile required to build an dashboard container -// to aggregate various private network services under one easily accessible page. -var dashboardDockerfile = ` -FROM mhart/alpine-node:latest - -WORKDIR /usr/app - -RUN \ - npm install connect serve-static && \ - \ - echo 'var connect = require("connect");' > server.js && \ - echo 'var serveStatic = require("serve-static");' >> server.js && \ - echo 'connect().use(serveStatic("/dashboard")).listen(80, function(){' >> server.js && \ - echo ' console.log("Server running on 80...");' >> server.js && \ - echo '});' >> server.js - -ADD {{.Network}}.json /dashboard/{{.Network}}.json -ADD {{.Network}}-cpp.json /dashboard/{{.Network}}-cpp.json -ADD {{.Network}}-harmony.json /dashboard/{{.Network}}-harmony.json -ADD {{.Network}}-parity.json /dashboard/{{.Network}}-parity.json -ADD {{.Network}}-python.json /dashboard/{{.Network}}-python.json -ADD index.html /dashboard/index.html -ADD puppeth.png /dashboard/puppeth.png - -EXPOSE 80 - -CMD ["node", "./server.js"] -` - -// dashboardComposefile is the docker-compose.yml file required to deploy and -// maintain an service aggregating dashboard. -var dashboardComposefile = ` -version: '2' -services: - dashboard: - build: . - image: {{.Network}}/dashboard{{if not .VHost}} - ports: - - "{{.Port}}:80"{{end}} - environment: - - ETHSTATS_PAGE={{.EthstatsPage}} - - EXPLORER_PAGE={{.ExplorerPage}} - - WALLET_PAGE={{.WalletPage}} - - FAUCET_PAGE={{.FaucetPage}}{{if .VHost}} - - VIRTUAL_HOST={{.VHost}}{{end}} - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" - restart: always -` - -// deployDashboard deploys a new dashboard container to a remote machine via SSH, -// docker and docker-compose. If an instance with the specified network name -// already exists there, it will be overwritten! -func deployDashboard(client *sshClient, network string, conf *config, config *dashboardInfos, nocache bool) ([]byte, error) { - // Generate the content to upload to the server - workdir := fmt.Sprintf("%d", rand.Int63()) - files := make(map[string][]byte) - - dockerfile := new(bytes.Buffer) - template.Must(template.New("").Parse(dashboardDockerfile)).Execute(dockerfile, map[string]interface{}{ - "Network": network, - }) - files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() - - composefile := new(bytes.Buffer) - template.Must(template.New("").Parse(dashboardComposefile)).Execute(composefile, map[string]interface{}{ - "Network": network, - "Port": config.port, - "VHost": config.host, - "EthstatsPage": config.ethstats, - "ExplorerPage": config.explorer, - "FaucetPage": config.faucet, - }) - files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() - - statsLogin := fmt.Sprintf("yournode:%s", conf.ethstats) - if !config.trusted { - statsLogin = "" - } - indexfile := new(bytes.Buffer) - bootCpp := make([]string, len(conf.bootnodes)) - for i, boot := range conf.bootnodes { - bootCpp[i] = "required:" + strings.TrimPrefix(boot, "enode://") - } - bootHarmony := make([]string, len(conf.bootnodes)) - for i, boot := range conf.bootnodes { - bootHarmony[i] = fmt.Sprintf("-Dpeer.active.%d.url=%s", i, boot) - } - bootPython := make([]string, len(conf.bootnodes)) - for i, boot := range conf.bootnodes { - bootPython[i] = "'" + boot + "'" - } - template.Must(template.New("").Parse(dashboardContent)).Execute(indexfile, map[string]interface{}{ - "Network": network, - "NetworkID": conf.Genesis.Config.ChainID, - "NetworkTitle": strings.Title(network), - "EthstatsPage": config.ethstats, - "ExplorerPage": config.explorer, - "FaucetPage": config.faucet, - "GethGenesis": network + ".json", - "Bootnodes": conf.bootnodes, - "BootnodesFlat": strings.Join(conf.bootnodes, ","), - "Ethstats": statsLogin, - "Ethash": conf.Genesis.Config.Ethash != nil, - "CppGenesis": network + "-cpp.json", - "CppBootnodes": strings.Join(bootCpp, " "), - "HarmonyGenesis": network + "-harmony.json", - "HarmonyBootnodes": strings.Join(bootHarmony, " "), - "ParityGenesis": network + "-parity.json", - "PythonGenesis": network + "-python.json", - "PythonBootnodes": strings.Join(bootPython, ","), - "Homestead": conf.Genesis.Config.HomesteadBlock, - "Tangerine": conf.Genesis.Config.EIP150Block, - "Spurious": conf.Genesis.Config.EIP155Block, - "Byzantium": conf.Genesis.Config.ByzantiumBlock, - "Constantinople": conf.Genesis.Config.ConstantinopleBlock, - "ConstantinopleFix": conf.Genesis.Config.PetersburgBlock, - }) - files[filepath.Join(workdir, "index.html")] = indexfile.Bytes() - - // Marshal the genesis spec files for go-ethereum and all the other clients - genesis, _ := conf.Genesis.MarshalJSON() - files[filepath.Join(workdir, network+".json")] = genesis - files[filepath.Join(workdir, "puppeth.png")] = dashboardMascot - - // Upload the deployment files to the remote server (and clean up afterwards) - if out, err := client.Upload(files); err != nil { - return out, err - } - defer client.Run("rm -rf " + workdir) - - // Build and deploy the dashboard service - if nocache { - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network)) - } - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network)) -} - -// dashboardInfos is returned from a dashboard status check to allow reporting -// various configuration parameters. -type dashboardInfos struct { - host string - port int - trusted bool - - ethstats string - explorer string - faucet string -} - -// Report converts the typed struct into a plain string->string map, containing -// most - but not all - fields for reporting to the user. -func (info *dashboardInfos) Report() map[string]string { - return map[string]string{ - "Website address": info.host, - "Website listener port": strconv.Itoa(info.port), - "Ethstats service": info.ethstats, - "Explorer service": info.explorer, - "Faucet service": info.faucet, - } -} - -// checkDashboard does a health-check against a dashboard container to verify if -// it's running, and if yes, gathering a collection of useful infos about it. -func checkDashboard(client *sshClient, network string) (*dashboardInfos, error) { - // Inspect a possible ethstats container on the host - infos, err := inspectContainer(client, fmt.Sprintf("%s_dashboard_1", network)) - if err != nil { - return nil, err - } - if !infos.running { - return nil, ErrServiceOffline - } - // Resolve the port from the host, or the reverse proxy - port := infos.portmap["80/tcp"] - if port == 0 { - if proxy, _ := checkNginx(client, network); proxy != nil { - port = proxy.port - } - } - if port == 0 { - return nil, ErrNotExposed - } - // Resolve the host from the reverse-proxy and configure the connection string - host := infos.envvars["VIRTUAL_HOST"] - if host == "" { - host = client.server - } - // Run a sanity check to see if the port is reachable - if err = checkPort(host, port); err != nil { - log.Warn("Dashboard service seems unreachable", "server", host, "port", port, "err", err) - } - // Container available, assemble and return the useful infos - return &dashboardInfos{ - host: host, - port: port, - ethstats: infos.envvars["ETHSTATS_PAGE"], - explorer: infos.envvars["EXPLORER_PAGE"], - faucet: infos.envvars["FAUCET_PAGE"], - }, nil -} diff --git a/cmd/puppeth/module_ethstats.go b/cmd/puppeth/module_ethstats.go deleted file mode 100644 index abed4db5fc50..000000000000 --- a/cmd/puppeth/module_ethstats.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "fmt" - "math/rand" - "path/filepath" - "strconv" - "strings" - "text/template" - - "github.com/ethereum/go-ethereum/log" -) - -// ethstatsDockerfile is the Dockerfile required to build an ethstats backend -// and associated monitoring site. -var ethstatsDockerfile = ` -FROM puppeth/ethstats:latest - -RUN echo 'module.exports = {trusted: [{{.Trusted}}], banned: [{{.Banned}}], reserved: ["yournode"]};' > lib/utils/config.js -` - -// ethstatsComposefile is the docker-compose.yml file required to deploy and -// maintain an ethstats monitoring site. -var ethstatsComposefile = ` -version: '2' -services: - ethstats: - build: . - image: {{.Network}}/ethstats - container_name: {{.Network}}_ethstats_1{{if not .VHost}} - ports: - - "{{.Port}}:3000"{{end}} - environment: - - WS_SECRET={{.Secret}}{{if .VHost}} - - VIRTUAL_HOST={{.VHost}}{{end}}{{if .Banned}} - - BANNED={{.Banned}}{{end}} - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" - restart: always -` - -// deployEthstats deploys a new ethstats container to a remote machine via SSH, -// docker and docker-compose. If an instance with the specified network name -// already exists there, it will be overwritten! -func deployEthstats(client *sshClient, network string, port int, secret string, vhost string, trusted []string, banned []string, nocache bool) ([]byte, error) { - // Generate the content to upload to the server - workdir := fmt.Sprintf("%d", rand.Int63()) - files := make(map[string][]byte) - - trustedLabels := make([]string, len(trusted)) - for i, address := range trusted { - trustedLabels[i] = fmt.Sprintf("\"%s\"", address) - } - bannedLabels := make([]string, len(banned)) - for i, address := range banned { - bannedLabels[i] = fmt.Sprintf("\"%s\"", address) - } - - dockerfile := new(bytes.Buffer) - template.Must(template.New("").Parse(ethstatsDockerfile)).Execute(dockerfile, map[string]interface{}{ - "Trusted": strings.Join(trustedLabels, ", "), - "Banned": strings.Join(bannedLabels, ", "), - }) - files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() - - composefile := new(bytes.Buffer) - template.Must(template.New("").Parse(ethstatsComposefile)).Execute(composefile, map[string]interface{}{ - "Network": network, - "Port": port, - "Secret": secret, - "VHost": vhost, - "Banned": strings.Join(banned, ","), - }) - files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() - - // Upload the deployment files to the remote server (and clean up afterwards) - if out, err := client.Upload(files); err != nil { - return out, err - } - defer client.Run("rm -rf " + workdir) - - // Build and deploy the ethstats service - if nocache { - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network)) - } - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network)) -} - -// ethstatsInfos is returned from an ethstats status check to allow reporting -// various configuration parameters. -type ethstatsInfos struct { - host string - port int - secret string - config string - banned []string -} - -// Report converts the typed struct into a plain string->string map, containing -// most - but not all - fields for reporting to the user. -func (info *ethstatsInfos) Report() map[string]string { - return map[string]string{ - "Website address": info.host, - "Website listener port": strconv.Itoa(info.port), - "Login secret": info.secret, - "Banned addresses": strings.Join(info.banned, "\n"), - } -} - -// checkEthstats does a health-check against an ethstats server to verify whether -// it's running, and if yes, gathering a collection of useful infos about it. -func checkEthstats(client *sshClient, network string) (*ethstatsInfos, error) { - // Inspect a possible ethstats container on the host - infos, err := inspectContainer(client, fmt.Sprintf("%s_ethstats_1", network)) - if err != nil { - return nil, err - } - if !infos.running { - return nil, ErrServiceOffline - } - // Resolve the port from the host, or the reverse proxy - port := infos.portmap["3000/tcp"] - if port == 0 { - if proxy, _ := checkNginx(client, network); proxy != nil { - port = proxy.port - } - } - if port == 0 { - return nil, ErrNotExposed - } - // Resolve the host from the reverse-proxy and configure the connection string - host := infos.envvars["VIRTUAL_HOST"] - if host == "" { - host = client.server - } - secret := infos.envvars["WS_SECRET"] - config := fmt.Sprintf("%s@%s", secret, host) - if port != 80 && port != 443 { - config += fmt.Sprintf(":%d", port) - } - // Retrieve the IP banned list - banned := strings.Split(infos.envvars["BANNED"], ",") - - // Run a sanity check to see if the port is reachable - if err = checkPort(host, port); err != nil { - log.Warn("Ethstats service seems unreachable", "server", host, "port", port, "err", err) - } - // Container available, assemble and return the useful infos - return ðstatsInfos{ - host: host, - port: port, - secret: secret, - config: config, - banned: banned, - }, nil -} diff --git a/cmd/puppeth/module_explorer.go b/cmd/puppeth/module_explorer.go deleted file mode 100644 index 3812f9fdb963..000000000000 --- a/cmd/puppeth/module_explorer.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "fmt" - "html/template" - "math/rand" - "path/filepath" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/log" -) - -// explorerDockerfile is the Dockerfile required to run a block explorer. -var explorerDockerfile = ` -FROM puppeth/blockscout:latest - -ADD genesis.json /genesis.json -RUN \ - echo 'geth --cache 512 init /genesis.json' > explorer.sh && \ - echo $'geth --networkid {{.NetworkID}} --syncmode "full" --gcmode "archive" --port {{.EthPort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --http --http.api "net,web3,eth,debug,txpool" --http.corsdomain "*" --http.vhosts "*" --ws --ws.origins "*" --exitwhensynced' >> explorer.sh && \ - echo $'exec geth --networkid {{.NetworkID}} --syncmode "full" --gcmode "archive" --port {{.EthPort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --http --http.api "net,web3,eth,debug,txpool" --http.corsdomain "*" --http.vhosts "*" --ws --ws.origins "*" &' >> explorer.sh && \ - echo '/usr/local/bin/docker-entrypoint.sh postgres &' >> explorer.sh && \ - echo 'sleep 5' >> explorer.sh && \ - echo 'mix do ecto.drop --force, ecto.create, ecto.migrate' >> explorer.sh && \ - echo 'mix phx.server' >> explorer.sh - -ENTRYPOINT ["/bin/sh", "explorer.sh"] -` - -// explorerComposefile is the docker-compose.yml file required to deploy and -// maintain a block explorer. -var explorerComposefile = ` -version: '2' -services: - explorer: - build: . - image: {{.Network}}/explorer - container_name: {{.Network}}_explorer_1 - ports: - - "{{.EthPort}}:{{.EthPort}}" - - "{{.EthPort}}:{{.EthPort}}/udp"{{if not .VHost}} - - "{{.WebPort}}:4000"{{end}} - environment: - - ETH_PORT={{.EthPort}} - - ETH_NAME={{.EthName}} - - BLOCK_TRANSFORMER={{.Transformer}}{{if .VHost}} - - VIRTUAL_HOST={{.VHost}} - - VIRTUAL_PORT=4000{{end}} - volumes: - - {{.Datadir}}:/opt/app/.ethereum - - {{.DBDir}}:/var/lib/postgresql/data - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" - restart: always -` - -// deployExplorer deploys a new block explorer container to a remote machine via -// SSH, docker and docker-compose. If an instance with the specified network name -// already exists there, it will be overwritten! -func deployExplorer(client *sshClient, network string, bootnodes []string, config *explorerInfos, nocache bool, isClique bool) ([]byte, error) { - // Generate the content to upload to the server - workdir := fmt.Sprintf("%d", rand.Int63()) - files := make(map[string][]byte) - - dockerfile := new(bytes.Buffer) - template.Must(template.New("").Parse(explorerDockerfile)).Execute(dockerfile, map[string]interface{}{ - "NetworkID": config.node.network, - "Bootnodes": strings.Join(bootnodes, ","), - "Ethstats": config.node.ethstats, - "EthPort": config.node.port, - }) - files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() - - transformer := "base" - if isClique { - transformer = "clique" - } - composefile := new(bytes.Buffer) - template.Must(template.New("").Parse(explorerComposefile)).Execute(composefile, map[string]interface{}{ - "Network": network, - "VHost": config.host, - "Ethstats": config.node.ethstats, - "Datadir": config.node.datadir, - "DBDir": config.dbdir, - "EthPort": config.node.port, - "EthName": getEthName(config.node.ethstats), - "WebPort": config.port, - "Transformer": transformer, - }) - files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() - files[filepath.Join(workdir, "genesis.json")] = config.node.genesis - - // Upload the deployment files to the remote server (and clean up afterwards) - if out, err := client.Upload(files); err != nil { - return out, err - } - defer client.Run("rm -rf " + workdir) - - // Build and deploy the boot or seal node service - if nocache { - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network)) - } - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network)) -} - -// explorerInfos is returned from a block explorer status check to allow reporting -// various configuration parameters. -type explorerInfos struct { - node *nodeInfos - dbdir string - host string - port int -} - -// Report converts the typed struct into a plain string->string map, containing -// most - but not all - fields for reporting to the user. -func (info *explorerInfos) Report() map[string]string { - report := map[string]string{ - "Website address ": info.host, - "Website listener port ": strconv.Itoa(info.port), - "Ethereum listener port ": strconv.Itoa(info.node.port), - "Ethstats username": info.node.ethstats, - } - return report -} - -// checkExplorer does a health-check against a block explorer server to verify -// whether it's running, and if yes, whether it's responsive. -func checkExplorer(client *sshClient, network string) (*explorerInfos, error) { - // Inspect a possible explorer container on the host - infos, err := inspectContainer(client, fmt.Sprintf("%s_explorer_1", network)) - if err != nil { - return nil, err - } - if !infos.running { - return nil, ErrServiceOffline - } - // Resolve the port from the host, or the reverse proxy - port := infos.portmap["4000/tcp"] - if port == 0 { - if proxy, _ := checkNginx(client, network); proxy != nil { - port = proxy.port - } - } - if port == 0 { - return nil, ErrNotExposed - } - // Resolve the host from the reverse-proxy and the config values - host := infos.envvars["VIRTUAL_HOST"] - if host == "" { - host = client.server - } - // Run a sanity check to see if the devp2p is reachable - p2pPort := infos.portmap[infos.envvars["ETH_PORT"]+"/tcp"] - if err = checkPort(host, p2pPort); err != nil { - log.Warn("Explorer node seems unreachable", "server", host, "port", p2pPort, "err", err) - } - if err = checkPort(host, port); err != nil { - log.Warn("Explorer service seems unreachable", "server", host, "port", port, "err", err) - } - // Assemble and return the useful infos - stats := &explorerInfos{ - node: &nodeInfos{ - datadir: infos.volumes["/opt/app/.ethereum"], - port: infos.portmap[infos.envvars["ETH_PORT"]+"/tcp"], - ethstats: infos.envvars["ETH_NAME"], - }, - dbdir: infos.volumes["/var/lib/postgresql/data"], - host: host, - port: port, - } - return stats, nil -} diff --git a/cmd/puppeth/module_faucet.go b/cmd/puppeth/module_faucet.go deleted file mode 100644 index a4f6e65694df..000000000000 --- a/cmd/puppeth/module_faucet.go +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "html/template" - "math/rand" - "path/filepath" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" -) - -// faucetDockerfile is the Dockerfile required to build a faucet container to -// grant crypto tokens based on GitHub authentications. -var faucetDockerfile = ` -FROM ethereum/client-go:alltools-latest - -ADD genesis.json /genesis.json -ADD account.json /account.json -ADD account.pass /account.pass - -EXPOSE 8080 30303 30303/udp - -ENTRYPOINT [ \ - "faucet", "--genesis", "/genesis.json", "--network", "{{.NetworkID}}", "--bootnodes", "{{.Bootnodes}}", "--ethstats", "{{.Ethstats}}", "--ethport", "{{.EthPort}}", \ - "--faucet.name", "{{.FaucetName}}", "--faucet.amount", "{{.FaucetAmount}}", "--faucet.minutes", "{{.FaucetMinutes}}", "--faucet.tiers", "{{.FaucetTiers}}", \ - "--account.json", "/account.json", "--account.pass", "/account.pass" \ - {{if .CaptchaToken}}, "--captcha.token", "{{.CaptchaToken}}", "--captcha.secret", "{{.CaptchaSecret}}"{{end}}{{if .NoAuth}}, "--noauth"{{end}} \ - {{if .TwitterToken}}, "--twitter.token.v1", "{{.TwitterToken}}"{{end}} \ -]` - -// faucetComposefile is the docker-compose.yml file required to deploy and maintain -// a crypto faucet. -var faucetComposefile = ` -version: '2' -services: - faucet: - build: . - image: {{.Network}}/faucet - container_name: {{.Network}}_faucet_1 - ports: - - "{{.EthPort}}:{{.EthPort}}" - - "{{.EthPort}}:{{.EthPort}}/udp"{{if not .VHost}} - - "{{.ApiPort}}:8080"{{end}} - volumes: - - {{.Datadir}}:/root/.faucet - environment: - - ETH_PORT={{.EthPort}} - - ETH_NAME={{.EthName}} - - FAUCET_AMOUNT={{.FaucetAmount}} - - FAUCET_MINUTES={{.FaucetMinutes}} - - FAUCET_TIERS={{.FaucetTiers}} - - CAPTCHA_TOKEN={{.CaptchaToken}} - - CAPTCHA_SECRET={{.CaptchaSecret}} - - TWITTER_TOKEN={{.TwitterToken}} - - NO_AUTH={{.NoAuth}}{{if .VHost}} - - VIRTUAL_HOST={{.VHost}} - - VIRTUAL_PORT=8080{{end}} - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" - restart: always -` - -// deployFaucet deploys a new faucet container to a remote machine via SSH, -// docker and docker-compose. If an instance with the specified network name -// already exists there, it will be overwritten! -func deployFaucet(client *sshClient, network string, bootnodes []string, config *faucetInfos, nocache bool) ([]byte, error) { - // Generate the content to upload to the server - workdir := fmt.Sprintf("%d", rand.Int63()) - files := make(map[string][]byte) - - dockerfile := new(bytes.Buffer) - template.Must(template.New("").Parse(faucetDockerfile)).Execute(dockerfile, map[string]interface{}{ - "NetworkID": config.node.network, - "Bootnodes": strings.Join(bootnodes, ","), - "Ethstats": config.node.ethstats, - "EthPort": config.node.port, - "CaptchaToken": config.captchaToken, - "CaptchaSecret": config.captchaSecret, - "FaucetName": strings.Title(network), - "FaucetAmount": config.amount, - "FaucetMinutes": config.minutes, - "FaucetTiers": config.tiers, - "NoAuth": config.noauth, - "TwitterToken": config.twitterToken, - }) - files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() - - composefile := new(bytes.Buffer) - template.Must(template.New("").Parse(faucetComposefile)).Execute(composefile, map[string]interface{}{ - "Network": network, - "Datadir": config.node.datadir, - "VHost": config.host, - "ApiPort": config.port, - "EthPort": config.node.port, - "EthName": getEthName(config.node.ethstats), - "CaptchaToken": config.captchaToken, - "CaptchaSecret": config.captchaSecret, - "FaucetAmount": config.amount, - "FaucetMinutes": config.minutes, - "FaucetTiers": config.tiers, - "NoAuth": config.noauth, - "TwitterToken": config.twitterToken, - }) - files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() - - files[filepath.Join(workdir, "genesis.json")] = config.node.genesis - files[filepath.Join(workdir, "account.json")] = []byte(config.node.keyJSON) - files[filepath.Join(workdir, "account.pass")] = []byte(config.node.keyPass) - - // Upload the deployment files to the remote server (and clean up afterwards) - if out, err := client.Upload(files); err != nil { - return out, err - } - defer client.Run("rm -rf " + workdir) - - // Build and deploy the faucet service - if nocache { - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network)) - } - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network)) -} - -// faucetInfos is returned from a faucet status check to allow reporting various -// configuration parameters. -type faucetInfos struct { - node *nodeInfos - host string - port int - amount int - minutes int - tiers int - noauth bool - captchaToken string - captchaSecret string - twitterToken string -} - -// Report converts the typed struct into a plain string->string map, containing -// most - but not all - fields for reporting to the user. -func (info *faucetInfos) Report() map[string]string { - report := map[string]string{ - "Website address": info.host, - "Website listener port": strconv.Itoa(info.port), - "Ethereum listener port": strconv.Itoa(info.node.port), - "Funding amount (base tier)": fmt.Sprintf("%d Ethers", info.amount), - "Funding cooldown (base tier)": fmt.Sprintf("%d mins", info.minutes), - "Funding tiers": strconv.Itoa(info.tiers), - "Captha protection": fmt.Sprintf("%v", info.captchaToken != ""), - "Using Twitter API": fmt.Sprintf("%v", info.twitterToken != ""), - "Ethstats username": info.node.ethstats, - } - if info.noauth { - report["Debug mode (no auth)"] = "enabled" - } - if info.node.keyJSON != "" { - var key struct { - Address string `json:"address"` - } - if err := json.Unmarshal([]byte(info.node.keyJSON), &key); err == nil { - report["Funding account"] = common.HexToAddress(key.Address).Hex() - } else { - log.Error("Failed to retrieve signer address", "err", err) - } - } - return report -} - -// checkFaucet does a health-check against a faucet server to verify whether -// it's running, and if yes, gathering a collection of useful infos about it. -func checkFaucet(client *sshClient, network string) (*faucetInfos, error) { - // Inspect a possible faucet container on the host - infos, err := inspectContainer(client, fmt.Sprintf("%s_faucet_1", network)) - if err != nil { - return nil, err - } - if !infos.running { - return nil, ErrServiceOffline - } - // Resolve the port from the host, or the reverse proxy - port := infos.portmap["8080/tcp"] - if port == 0 { - if proxy, _ := checkNginx(client, network); proxy != nil { - port = proxy.port - } - } - if port == 0 { - return nil, ErrNotExposed - } - // Resolve the host from the reverse-proxy and the config values - host := infos.envvars["VIRTUAL_HOST"] - if host == "" { - host = client.server - } - amount, _ := strconv.Atoi(infos.envvars["FAUCET_AMOUNT"]) - minutes, _ := strconv.Atoi(infos.envvars["FAUCET_MINUTES"]) - tiers, _ := strconv.Atoi(infos.envvars["FAUCET_TIERS"]) - - // Retrieve the funding account information - var out []byte - keyJSON, keyPass := "", "" - if out, err = client.Run(fmt.Sprintf("docker exec %s_faucet_1 cat /account.json", network)); err == nil { - keyJSON = string(bytes.TrimSpace(out)) - } - if out, err = client.Run(fmt.Sprintf("docker exec %s_faucet_1 cat /account.pass", network)); err == nil { - keyPass = string(bytes.TrimSpace(out)) - } - // Run a sanity check to see if the port is reachable - if err = checkPort(host, port); err != nil { - log.Warn("Faucet service seems unreachable", "server", host, "port", port, "err", err) - } - // Container available, assemble and return the useful infos - return &faucetInfos{ - node: &nodeInfos{ - datadir: infos.volumes["/root/.faucet"], - port: infos.portmap[infos.envvars["ETH_PORT"]+"/tcp"], - ethstats: infos.envvars["ETH_NAME"], - keyJSON: keyJSON, - keyPass: keyPass, - }, - host: host, - port: port, - amount: amount, - minutes: minutes, - tiers: tiers, - captchaToken: infos.envvars["CAPTCHA_TOKEN"], - captchaSecret: infos.envvars["CAPTCHA_SECRET"], - noauth: infos.envvars["NO_AUTH"] == "true", - twitterToken: infos.envvars["TWITTER_TOKEN"], - }, nil -} diff --git a/cmd/puppeth/module_nginx.go b/cmd/puppeth/module_nginx.go deleted file mode 100644 index 1b1ae61ff598..000000000000 --- a/cmd/puppeth/module_nginx.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "fmt" - "html/template" - "math/rand" - "path/filepath" - "strconv" - - "github.com/ethereum/go-ethereum/log" -) - -// nginxDockerfile is theis the Dockerfile required to build an nginx reverse- -// proxy. -var nginxDockerfile = `FROM jwilder/nginx-proxy` - -// nginxComposefile is the docker-compose.yml file required to deploy and maintain -// an nginx reverse-proxy. The proxy is responsible for exposing one or more HTTP -// services running on a single host. -var nginxComposefile = ` -version: '2' -services: - nginx: - build: . - image: {{.Network}}/nginx - container_name: {{.Network}}_nginx_1 - ports: - - "{{.Port}}:80" - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" - restart: always -` - -// deployNginx deploys a new nginx reverse-proxy container to expose one or more -// HTTP services running on a single host. If an instance with the specified -// network name already exists there, it will be overwritten! -func deployNginx(client *sshClient, network string, port int, nocache bool) ([]byte, error) { - log.Info("Deploying nginx reverse-proxy", "server", client.server, "port", port) - - // Generate the content to upload to the server - workdir := fmt.Sprintf("%d", rand.Int63()) - files := make(map[string][]byte) - - dockerfile := new(bytes.Buffer) - template.Must(template.New("").Parse(nginxDockerfile)).Execute(dockerfile, nil) - files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() - - composefile := new(bytes.Buffer) - template.Must(template.New("").Parse(nginxComposefile)).Execute(composefile, map[string]interface{}{ - "Network": network, - "Port": port, - }) - files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() - - // Upload the deployment files to the remote server (and clean up afterwards) - if out, err := client.Upload(files); err != nil { - return out, err - } - defer client.Run("rm -rf " + workdir) - - // Build and deploy the reverse-proxy service - if nocache { - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network)) - } - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network)) -} - -// nginxInfos is returned from an nginx reverse-proxy status check to allow -// reporting various configuration parameters. -type nginxInfos struct { - port int -} - -// Report converts the typed struct into a plain string->string map, containing -// most - but not all - fields for reporting to the user. -func (info *nginxInfos) Report() map[string]string { - return map[string]string{ - "Shared listener port": strconv.Itoa(info.port), - } -} - -// checkNginx does a health-check against an nginx reverse-proxy to verify whether -// it's running, and if yes, gathering a collection of useful infos about it. -func checkNginx(client *sshClient, network string) (*nginxInfos, error) { - // Inspect a possible nginx container on the host - infos, err := inspectContainer(client, fmt.Sprintf("%s_nginx_1", network)) - if err != nil { - return nil, err - } - if !infos.running { - return nil, ErrServiceOffline - } - // Container available, assemble and return the useful infos - return &nginxInfos{ - port: infos.portmap["80/tcp"], - }, nil -} diff --git a/cmd/puppeth/module_node.go b/cmd/puppeth/module_node.go deleted file mode 100644 index 734dd0405128..000000000000 --- a/cmd/puppeth/module_node.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "math/rand" - "path/filepath" - "strconv" - "strings" - "text/template" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" -) - -// nodeDockerfile is the Dockerfile required to run an Ethereum node. -var nodeDockerfile = ` -FROM ethereum/client-go:latest - -ADD genesis.json /genesis.json -{{if .Unlock}} - ADD signer.json /signer.json - ADD signer.pass /signer.pass -{{end}} -RUN \ - echo 'geth --cache 512 init /genesis.json' > geth.sh && \{{if .Unlock}} - echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}} - echo $'exec geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --nat extip:{{.IP}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--miner.etherbase {{.Etherbase}} --mine --miner.threads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --miner.gaslimit {{.GasLimit}} --miner.gasprice {{.GasPrice}}' >> geth.sh - -ENTRYPOINT ["/bin/sh", "geth.sh"] -` - -// nodeComposefile is the docker-compose.yml file required to deploy and maintain -// an Ethereum node (bootnode or miner for now). -var nodeComposefile = ` -version: '2' -services: - {{.Type}}: - build: . - image: {{.Network}}/{{.Type}} - container_name: {{.Network}}_{{.Type}}_1 - ports: - - "{{.Port}}:{{.Port}}" - - "{{.Port}}:{{.Port}}/udp" - volumes: - - {{.Datadir}}:/root/.ethereum{{if .Ethashdir}} - - {{.Ethashdir}}:/root/.ethash{{end}} - environment: - - PORT={{.Port}}/tcp - - TOTAL_PEERS={{.TotalPeers}} - - LIGHT_PEERS={{.LightPeers}} - - STATS_NAME={{.Ethstats}} - - MINER_NAME={{.Etherbase}} - - GAS_LIMIT={{.GasLimit}} - - GAS_PRICE={{.GasPrice}} - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" - restart: always -` - -// deployNode deploys a new Ethereum node container to a remote machine via SSH, -// docker and docker-compose. If an instance with the specified network name -// already exists there, it will be overwritten! -func deployNode(client *sshClient, network string, bootnodes []string, config *nodeInfos, nocache bool) ([]byte, error) { - kind := "sealnode" - if config.keyJSON == "" && config.etherbase == "" { - kind = "bootnode" - bootnodes = make([]string, 0) - } - // Generate the content to upload to the server - workdir := fmt.Sprintf("%d", rand.Int63()) - files := make(map[string][]byte) - - lightFlag := "" - if config.peersLight > 0 { - lightFlag = fmt.Sprintf("--light.maxpeers=%d --light.serve=50", config.peersLight) - } - dockerfile := new(bytes.Buffer) - template.Must(template.New("").Parse(nodeDockerfile)).Execute(dockerfile, map[string]interface{}{ - "NetworkID": config.network, - "Port": config.port, - "IP": client.address, - "Peers": config.peersTotal, - "LightFlag": lightFlag, - "Bootnodes": strings.Join(bootnodes, ","), - "Ethstats": config.ethstats, - "Etherbase": config.etherbase, - "GasLimit": uint64(1000000 * config.gasLimit), - "GasPrice": uint64(1000000000 * config.gasPrice), - "Unlock": config.keyJSON != "", - }) - files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() - - composefile := new(bytes.Buffer) - template.Must(template.New("").Parse(nodeComposefile)).Execute(composefile, map[string]interface{}{ - "Type": kind, - "Datadir": config.datadir, - "Ethashdir": config.ethashdir, - "Network": network, - "Port": config.port, - "TotalPeers": config.peersTotal, - "Light": config.peersLight > 0, - "LightPeers": config.peersLight, - "Ethstats": getEthName(config.ethstats), - "Etherbase": config.etherbase, - "GasLimit": config.gasLimit, - "GasPrice": config.gasPrice, - }) - files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() - - files[filepath.Join(workdir, "genesis.json")] = config.genesis - if config.keyJSON != "" { - files[filepath.Join(workdir, "signer.json")] = []byte(config.keyJSON) - files[filepath.Join(workdir, "signer.pass")] = []byte(config.keyPass) - } - // Upload the deployment files to the remote server (and clean up afterwards) - if out, err := client.Upload(files); err != nil { - return out, err - } - defer client.Run("rm -rf " + workdir) - - // Build and deploy the boot or seal node service - if nocache { - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network)) - } - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network)) -} - -// nodeInfos is returned from a boot or seal node status check to allow reporting -// various configuration parameters. -type nodeInfos struct { - genesis []byte - network int64 - datadir string - ethashdir string - ethstats string - port int - enode string - peersTotal int - peersLight int - etherbase string - keyJSON string - keyPass string - gasLimit float64 - gasPrice float64 -} - -// Report converts the typed struct into a plain string->string map, containing -// most - but not all - fields for reporting to the user. -func (info *nodeInfos) Report() map[string]string { - report := map[string]string{ - "Data directory": info.datadir, - "Listener port": strconv.Itoa(info.port), - "Peer count (all total)": strconv.Itoa(info.peersTotal), - "Peer count (light nodes)": strconv.Itoa(info.peersLight), - "Ethstats username": info.ethstats, - } - if info.gasLimit > 0 { - // Miner or signer node - report["Gas price (minimum accepted)"] = fmt.Sprintf("%0.3f GWei", info.gasPrice) - report["Gas ceil (target maximum)"] = fmt.Sprintf("%0.3f MGas", info.gasLimit) - - if info.etherbase != "" { - // Ethash proof-of-work miner - report["Ethash directory"] = info.ethashdir - report["Miner account"] = info.etherbase - } - if info.keyJSON != "" { - // Clique proof-of-authority signer - var key struct { - Address string `json:"address"` - } - if err := json.Unmarshal([]byte(info.keyJSON), &key); err == nil { - report["Signer account"] = common.HexToAddress(key.Address).Hex() - } else { - log.Error("Failed to retrieve signer address", "err", err) - } - } - } - return report -} - -// checkNode does a health-check against a boot or seal node server to verify -// whether it's running, and if yes, whether it's responsive. -func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error) { - kind := "bootnode" - if !boot { - kind = "sealnode" - } - // Inspect a possible bootnode container on the host - infos, err := inspectContainer(client, fmt.Sprintf("%s_%s_1", network, kind)) - if err != nil { - return nil, err - } - if !infos.running { - return nil, ErrServiceOffline - } - // Resolve a few types from the environmental variables - totalPeers, _ := strconv.Atoi(infos.envvars["TOTAL_PEERS"]) - lightPeers, _ := strconv.Atoi(infos.envvars["LIGHT_PEERS"]) - gasLimit, _ := strconv.ParseFloat(infos.envvars["GAS_LIMIT"], 64) - gasPrice, _ := strconv.ParseFloat(infos.envvars["GAS_PRICE"], 64) - - // Container available, retrieve its node ID and its genesis json - var out []byte - if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 geth --exec admin.nodeInfo.enode --cache=16 attach", network, kind)); err != nil { - return nil, ErrServiceUnreachable - } - enode := bytes.Trim(bytes.TrimSpace(out), "\"") - - if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 cat /genesis.json", network, kind)); err != nil { - return nil, ErrServiceUnreachable - } - genesis := bytes.TrimSpace(out) - - keyJSON, keyPass := "", "" - if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 cat /signer.json", network, kind)); err == nil { - keyJSON = string(bytes.TrimSpace(out)) - } - if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 cat /signer.pass", network, kind)); err == nil { - keyPass = string(bytes.TrimSpace(out)) - } - // Run a sanity check to see if the devp2p is reachable - port := infos.portmap[infos.envvars["PORT"]] - if err = checkPort(client.server, port); err != nil { - log.Warn(fmt.Sprintf("%s devp2p port seems unreachable", strings.Title(kind)), "server", client.server, "port", port, "err", err) - } - // Assemble and return the useful infos - stats := &nodeInfos{ - genesis: genesis, - datadir: infos.volumes["/root/.ethereum"], - ethashdir: infos.volumes["/root/.ethash"], - port: port, - peersTotal: totalPeers, - peersLight: lightPeers, - ethstats: infos.envvars["STATS_NAME"], - etherbase: infos.envvars["MINER_NAME"], - keyJSON: keyJSON, - keyPass: keyPass, - gasLimit: gasLimit, - gasPrice: gasPrice, - } - stats.enode = string(enode) - - return stats, nil -} diff --git a/cmd/puppeth/puppeth.go b/cmd/puppeth/puppeth.go deleted file mode 100644 index 415542b60cc9..000000000000 --- a/cmd/puppeth/puppeth.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// puppeth is a command to assemble and maintain private networks. -package main - -import ( - "math/rand" - "os" - "strings" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/urfave/cli/v2" -) - -// main is just a boring entry point to set up the CLI app. -func main() { - app := cli.NewApp() - app.Name = "puppeth" - app.Usage = "assemble and maintain private Ethereum networks" - app.Flags = []cli.Flag{ - &cli.StringFlag{ - Name: "network", - Usage: "name of the network to administer (no spaces or hyphens, please)", - }, - &cli.IntFlag{ - Name: "loglevel", - Value: 3, - Usage: "log level to emit to the screen", - }, - } - app.Before = func(c *cli.Context) error { - // Set up the logger to print everything and the random generator - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true)))) - rand.Seed(time.Now().UnixNano()) - - return nil - } - app.Action = runWizard - app.Run(os.Args) -} - -// runWizard start the wizard and relinquish control to it. -func runWizard(c *cli.Context) error { - network := c.String("network") - if strings.Contains(network, " ") || strings.Contains(network, "-") || strings.ToLower(network) != network { - log.Crit("No spaces, hyphens or capital letters allowed in network name") - } - makeWizard(c.String("network")).run() - return nil -} diff --git a/cmd/puppeth/ssh.go b/cmd/puppeth/ssh.go deleted file mode 100644 index a20b3bfda209..000000000000 --- a/cmd/puppeth/ssh.go +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "net" - "os" - "os/user" - "path/filepath" - "strings" - - "github.com/ethereum/go-ethereum/log" - "golang.org/x/crypto/ssh" - "golang.org/x/crypto/ssh/agent" - "golang.org/x/term" -) - -// sshClient is a small wrapper around Go's SSH client with a few utility methods -// implemented on top. -type sshClient struct { - server string // Server name or IP without port number - address string // IP address of the remote server - pubkey []byte // RSA public key to authenticate the server - client *ssh.Client - logger log.Logger -} - -const EnvSSHAuthSock = "SSH_AUTH_SOCK" - -// dial establishes an SSH connection to a remote node using the current user and -// the user's configured private RSA key. If that fails, password authentication -// is fallen back to. server can be a string like user:identity@server:port. -func dial(server string, pubkey []byte) (*sshClient, error) { - // Figure out username, identity, hostname and port - hostname := "" - hostport := server - username := "" - identity := "id_rsa" // default - - if strings.Contains(server, "@") { - prefix := server[:strings.Index(server, "@")] - if strings.Contains(prefix, ":") { - username = prefix[:strings.Index(prefix, ":")] - identity = prefix[strings.Index(prefix, ":")+1:] - } else { - username = prefix - } - hostport = server[strings.Index(server, "@")+1:] - } - if strings.Contains(hostport, ":") { - hostname = hostport[:strings.Index(hostport, ":")] - } else { - hostname = hostport - hostport += ":22" - } - logger := log.New("server", server) - logger.Debug("Attempting to establish SSH connection") - - user, err := user.Current() - if err != nil { - return nil, err - } - if username == "" { - username = user.Username - } - - // Configure the supported authentication methods (ssh agent, private key and password) - var ( - auths []ssh.AuthMethod - conn net.Conn - ) - if conn, err = net.Dial("unix", os.Getenv(EnvSSHAuthSock)); err != nil { - log.Warn("Unable to dial SSH agent, falling back to private keys", "err", err) - } else { - client := agent.NewClient(conn) - auths = append(auths, ssh.PublicKeysCallback(client.Signers)) - } - if err != nil { - path := filepath.Join(user.HomeDir, ".ssh", identity) - if buf, err := os.ReadFile(path); err != nil { - log.Warn("No SSH key, falling back to passwords", "path", path, "err", err) - } else { - key, err := ssh.ParsePrivateKey(buf) - if err != nil { - fmt.Printf("What's the decryption password for %s? (won't be echoed)\n>", path) - blob, err := term.ReadPassword(int(os.Stdin.Fd())) - fmt.Println() - if err != nil { - log.Warn("Couldn't read password", "err", err) - } - key, err := ssh.ParsePrivateKeyWithPassphrase(buf, blob) - if err != nil { - log.Warn("Failed to decrypt SSH key, falling back to passwords", "path", path, "err", err) - } else { - auths = append(auths, ssh.PublicKeys(key)) - } - } else { - auths = append(auths, ssh.PublicKeys(key)) - } - } - auths = append(auths, ssh.PasswordCallback(func() (string, error) { - fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", username, server) - blob, err := term.ReadPassword(int(os.Stdin.Fd())) - - fmt.Println() - return string(blob), err - })) - } - // Resolve the IP address of the remote server - addr, err := net.LookupHost(hostname) - if err != nil { - return nil, err - } - if len(addr) == 0 { - return nil, errors.New("no IPs associated with domain") - } - // Try to dial in to the remote server - logger.Trace("Dialing remote SSH server", "user", username) - keycheck := func(hostname string, remote net.Addr, key ssh.PublicKey) error { - // If no public key is known for SSH, ask the user to confirm - if pubkey == nil { - fmt.Println() - fmt.Printf("The authenticity of host '%s (%s)' can't be established.\n", hostname, remote) - fmt.Printf("SSH key fingerprint is %s [MD5]\n", ssh.FingerprintLegacyMD5(key)) - fmt.Printf("Are you sure you want to continue connecting (yes/no)? ") - - for { - text, err := bufio.NewReader(os.Stdin).ReadString('\n') - switch { - case err != nil: - return err - case strings.TrimSpace(text) == "yes": - pubkey = key.Marshal() - return nil - case strings.TrimSpace(text) == "no": - return errors.New("users says no") - default: - fmt.Println("Please answer 'yes' or 'no'") - continue - } - } - } - // If a public key exists for this SSH server, check that it matches - if bytes.Equal(pubkey, key.Marshal()) { - return nil - } - // We have a mismatch, forbid connecting - return errors.New("ssh key mismatch, re-add the machine to update") - } - client, err := ssh.Dial("tcp", hostport, &ssh.ClientConfig{User: username, Auth: auths, HostKeyCallback: keycheck}) - if err != nil { - return nil, err - } - // Connection established, return our utility wrapper - c := &sshClient{ - server: hostname, - address: addr[0], - pubkey: pubkey, - client: client, - logger: logger, - } - if err := c.init(); err != nil { - client.Close() - return nil, err - } - return c, nil -} - -// init runs some initialization commands on the remote server to ensure it's -// capable of acting as puppeth target. -func (client *sshClient) init() error { - client.logger.Debug("Verifying if docker is available") - if out, err := client.Run("docker version"); err != nil { - if len(out) == 0 { - return err - } - return fmt.Errorf("docker configured incorrectly: %s", out) - } - client.logger.Debug("Verifying if docker-compose is available") - if out, err := client.Run("docker-compose version"); err != nil { - if len(out) == 0 { - return err - } - return fmt.Errorf("docker-compose configured incorrectly: %s", out) - } - return nil -} - -// Close terminates the connection to an SSH server. -func (client *sshClient) Close() error { - return client.client.Close() -} - -// Run executes a command on the remote server and returns the combined output -// along with any error status. -func (client *sshClient) Run(cmd string) ([]byte, error) { - // Establish a single command session - session, err := client.client.NewSession() - if err != nil { - return nil, err - } - defer session.Close() - - // Execute the command and return any output - client.logger.Trace("Running command on remote server", "cmd", cmd) - return session.CombinedOutput(cmd) -} - -// Stream executes a command on the remote server and streams all outputs into -// the local stdout and stderr streams. -func (client *sshClient) Stream(cmd string) error { - // Establish a single command session - session, err := client.client.NewSession() - if err != nil { - return err - } - defer session.Close() - - session.Stdout = os.Stdout - session.Stderr = os.Stderr - - // Execute the command and return any output - client.logger.Trace("Streaming command on remote server", "cmd", cmd) - return session.Run(cmd) -} - -// Upload copies the set of files to a remote server via SCP, creating any non- -// existing folders in the mean time. -func (client *sshClient) Upload(files map[string][]byte) ([]byte, error) { - // Establish a single command session - session, err := client.client.NewSession() - if err != nil { - return nil, err - } - defer session.Close() - - // Create a goroutine that streams the SCP content - go func() { - out, _ := session.StdinPipe() - defer out.Close() - - for file, content := range files { - client.logger.Trace("Uploading file to server", "file", file, "bytes", len(content)) - - fmt.Fprintln(out, "D0755", 0, filepath.Dir(file)) // Ensure the folder exists - fmt.Fprintln(out, "C0644", len(content), filepath.Base(file)) // Create the actual file - out.Write(content) // Stream the data content - fmt.Fprint(out, "\x00") // Transfer end with \x00 - fmt.Fprintln(out, "E") // Leave directory (simpler) - } - }() - return session.CombinedOutput("/usr/bin/scp -v -tr ./") -} diff --git a/cmd/puppeth/testdata/stureby_aleth.json b/cmd/puppeth/testdata/stureby_aleth.json deleted file mode 100644 index d18ba3854aa5..000000000000 --- a/cmd/puppeth/testdata/stureby_aleth.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "sealEngine": "Ethash", - "params": { - "accountStartNonce": "0x0", - "maximumExtraDataSize": "0x20", - "homesteadForkBlock": "0x2710", - "daoHardforkBlock": "0x0", - "EIP150ForkBlock": "0x3a98", - "EIP158ForkBlock": "0x59d8", - "byzantiumForkBlock": "0x7530", - "constantinopleForkBlock": "0x9c40", - "constantinopleFixForkBlock": "0x9c40", - "istanbulForkBlock": "0xc350", - "minGasLimit": "0x1388", - "maxGasLimit": "0x7fffffffffffffff", - "tieBreakingGas": false, - "gasLimitBoundDivisor": "0x400", - "minimumDifficulty": "0x20000", - "difficultyBoundDivisor": "0x800", - "durationLimit": "0xd", - "blockReward": "0x4563918244f40000", - "networkID": "0x4cb2e", - "chainID": "0x4cb2e", - "allowFutureBlocks": false - }, - "genesis": { - "nonce": "0x0000000000000000", - "difficulty": "0x20000", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x59a4e76d", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x0000000000000000000000000000000000000000000000000000000b4dc0ffee", - "gasLimit": "0x47b760" - }, - "accounts": { - "0000000000000000000000000000000000000001": { - "balance": "0x1", - "precompiled": { - "name": "ecrecover", - "linear": { - "base": 3000, - "word": 0 - } - } - }, - "0000000000000000000000000000000000000002": { - "balance": "0x1", - "precompiled": { - "name": "sha256", - "linear": { - "base": 60, - "word": 12 - } - } - }, - "0000000000000000000000000000000000000003": { - "balance": "0x1", - "precompiled": { - "name": "ripemd160", - "linear": { - "base": 600, - "word": 120 - } - } - }, - "0000000000000000000000000000000000000004": { - "balance": "0x1", - "precompiled": { - "name": "identity", - "linear": { - "base": 15, - "word": 3 - } - } - }, - "0000000000000000000000000000000000000005": { - "balance": "0x1", - "precompiled": { - "name": "modexp", - "startingBlock": "0x7530" - } - }, - "0000000000000000000000000000000000000006": { - "balance": "0x1", - "precompiled": { - "name": "alt_bn128_G1_add", - "startingBlock": "0x7530" - } - }, - "0000000000000000000000000000000000000007": { - "balance": "0x1", - "precompiled": { - "name": "alt_bn128_G1_mul", - "startingBlock": "0x7530" - } - }, - "0000000000000000000000000000000000000008": { - "balance": "0x1", - "precompiled": { - "name": "alt_bn128_pairing_product", - "startingBlock": "0x7530" - } - }, - "0000000000000000000000000000000000000009": { - "balance": "0x1", - "precompiled": { - "name": "blake2_compression", - "startingBlock": "0xc350" - } - } - } -} \ No newline at end of file diff --git a/cmd/puppeth/testdata/stureby_geth.json b/cmd/puppeth/testdata/stureby_geth.json deleted file mode 100644 index 79f03469af8c..000000000000 --- a/cmd/puppeth/testdata/stureby_geth.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "config": { - "chainId": 314158, - "homesteadBlock": 10000, - "eip150Block": 15000, - "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "eip155Block": 23000, - "eip158Block": 23000, - "byzantiumBlock": 30000, - "constantinopleBlock": 40000, - "petersburgBlock": 40000, - "istanbulBlock": 50000, - "ethash": {} - }, - "nonce": "0x0", - "timestamp": "0x59a4e76d", - "extraData": "0x0000000000000000000000000000000000000000000000000000000b4dc0ffee", - "gasLimit": "0x47b760", - "difficulty": "0x20000", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase": "0x0000000000000000000000000000000000000000", - "alloc": { - "0000000000000000000000000000000000000001": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000002": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000003": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000004": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000005": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000006": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000007": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000008": { - "balance": "0x1" - }, - "0000000000000000000000000000000000000009": { - "balance": "0x1" - } - }, - "number": "0x0", - "gasUsed": "0x0", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" -} \ No newline at end of file diff --git a/cmd/puppeth/testdata/stureby_parity.json b/cmd/puppeth/testdata/stureby_parity.json deleted file mode 100644 index e9229f99b7ea..000000000000 --- a/cmd/puppeth/testdata/stureby_parity.json +++ /dev/null @@ -1,213 +0,0 @@ -{ - "name": "stureby", - "dataDir": "stureby", - "engine": { - "Ethash": { - "params": { - "minimumDifficulty": "0x20000", - "difficultyBoundDivisor": "0x800", - "durationLimit": "0xd", - "blockReward": { - "0x0": "0x4563918244f40000", - "0x7530": "0x29a2241af62c0000", - "0x9c40": "0x1bc16d674ec80000" - }, - "difficultyBombDelays": { - "0x7530": "0x2dc6c0", - "0x9c40": "0x1e8480" - }, - "homesteadTransition": "0x2710", - "eip100bTransition": "0x7530" - } - } - }, - "params": { - "accountStartNonce": "0x0", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "gasLimitBoundDivisor": "0x400", - "networkID": "0x4cb2e", - "chainID": "0x4cb2e", - "maxCodeSize": "0x6000", - "maxCodeSizeTransition": "0x0", - "eip98Transition": "0x7fffffffffffffff", - "eip150Transition": "0x3a98", - "eip160Transition": "0x59d8", - "eip161abcTransition": "0x59d8", - "eip161dTransition": "0x59d8", - "eip155Transition": "0x59d8", - "eip140Transition": "0x7530", - "eip211Transition": "0x7530", - "eip214Transition": "0x7530", - "eip658Transition": "0x7530", - "eip145Transition": "0x9c40", - "eip1014Transition": "0x9c40", - "eip1052Transition": "0x9c40", - "eip1283Transition": "0x9c40", - "eip1283DisableTransition": "0x9c40", - "eip1283ReenableTransition": "0xc350", - "eip1344Transition": "0xc350", - "eip1884Transition": "0xc350", - "eip2028Transition": "0xc350" - }, - "genesis": { - "seal": { - "ethereum": { - "nonce": "0x0000000000000000", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" - } - }, - "difficulty": "0x20000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x59a4e76d", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x0000000000000000000000000000000000000000000000000000000b4dc0ffee", - "gasLimit": "0x47b760" - }, - "nodes": [], - "accounts": { - "0000000000000000000000000000000000000001": { - "balance": "0x1", - "builtin": { - "name": "ecrecover", - "pricing": { - "linear": { - "base": 3000, - "word": 0 - } - } - } - }, - "0000000000000000000000000000000000000002": { - "balance": "0x1", - "builtin": { - "name": "sha256", - "pricing": { - "linear": { - "base": 60, - "word": 12 - } - } - } - }, - "0000000000000000000000000000000000000003": { - "balance": "0x1", - "builtin": { - "name": "ripemd160", - "pricing": { - "linear": { - "base": 600, - "word": 120 - } - } - } - }, - "0000000000000000000000000000000000000004": { - "balance": "0x1", - "builtin": { - "name": "identity", - "pricing": { - "linear": { - "base": 15, - "word": 3 - } - } - } - }, - "0000000000000000000000000000000000000005": { - "balance": "0x1", - "builtin": { - "name": "modexp", - "pricing": { - "modexp": { - "divisor": 20 - } - }, - "activate_at": "0x7530" - } - }, - "0000000000000000000000000000000000000006": { - "balance": "0x1", - "builtin": { - "name": "alt_bn128_add", - "pricing": { - "0x0": { - "price": { - "alt_bn128_const_operations": { - "price": 500 - } - } - }, - "0xc350": { - "price": { - "alt_bn128_const_operations": { - "price": 150 - } - } - } - }, - "activate_at": "0x7530" - } - }, - "0000000000000000000000000000000000000007": { - "balance": "0x1", - "builtin": { - "name": "alt_bn128_mul", - "pricing": { - "0x0": { - "price": { - "alt_bn128_const_operations": { - "price": 40000 - } - } - }, - "0xc350": { - "price": { - "alt_bn128_const_operations": { - "price": 6000 - } - } - } - }, - "activate_at": "0x7530" - } - }, - "0000000000000000000000000000000000000008": { - "balance": "0x1", - "builtin": { - "name": "alt_bn128_pairing", - "pricing": { - "0x0": { - "price": { - "alt_bn128_pairing": { - "base": 100000, - "pair": 80000 - } - } - }, - "0xc350": { - "price": { - "alt_bn128_pairing": { - "base": 45000, - "pair": 34000 - } - } - } - }, - "activate_at": "0x7530" - } - }, - "0000000000000000000000000000000000000009": { - "balance": "0x1", - "builtin": { - "name": "blake2_f", - "pricing": { - "blake2_f": { - "gas_per_round": 1 - } - }, - "activate_at": "0xc350" - } - } - } -} \ No newline at end of file diff --git a/cmd/puppeth/wizard.go b/cmd/puppeth/wizard.go deleted file mode 100644 index 6e5ca41d68fa..000000000000 --- a/cmd/puppeth/wizard.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "fmt" - "math/big" - "net" - "net/url" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/console/prompt" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/log" - "github.com/peterh/liner" - "golang.org/x/term" -) - -// config contains all the configurations needed by puppeth that should be saved -// between sessions. -type config struct { - path string // File containing the configuration values - bootnodes []string // Bootnodes to always connect to by all nodes - ethstats string // Ethstats settings to cache for node deploys - - Genesis *core.Genesis `json:"genesis,omitempty"` // Genesis block to cache for node deploys - Servers map[string][]byte `json:"servers,omitempty"` -} - -// servers retrieves an alphabetically sorted list of servers. -func (c config) servers() []string { - servers := make([]string, 0, len(c.Servers)) - for server := range c.Servers { - servers = append(servers, server) - } - sort.Strings(servers) - - return servers -} - -// flush dumps the contents of config to disk. -func (c config) flush() { - os.MkdirAll(filepath.Dir(c.path), 0755) - - out, _ := json.MarshalIndent(c, "", " ") - if err := os.WriteFile(c.path, out, 0644); err != nil { - log.Warn("Failed to save puppeth configs", "file", c.path, "err", err) - } -} - -type wizard struct { - network string // Network name to manage - conf config // Configurations from previous runs - - servers map[string]*sshClient // SSH connections to servers to administer - services map[string][]string // Ethereum services known to be running on servers - - lock sync.Mutex // Lock to protect configs during concurrent service discovery -} - -// prompts the user for input with the given prompt string. Returns when a value is entered. -// Causes the wizard to exit if ctrl-d is pressed -func promptInput(p string) string { - for { - text, err := prompt.Stdin.PromptInput(p) - if err != nil { - if err != liner.ErrPromptAborted { - log.Crit("Failed to read user input", "err", err) - } - } else { - return text - } - } -} - -// read reads a single line from stdin, trimming if from spaces. -func (w *wizard) read() string { - text := promptInput("> ") - return strings.TrimSpace(text) -} - -// readString reads a single line from stdin, trimming if from spaces, enforcing -// non-emptyness. -func (w *wizard) readString() string { - for { - text := promptInput("> ") - if text = strings.TrimSpace(text); text != "" { - return text - } - } -} - -// readDefaultString reads a single line from stdin, trimming if from spaces. If -// an empty line is entered, the default value is returned. -func (w *wizard) readDefaultString(def string) string { - text := promptInput("> ") - if text = strings.TrimSpace(text); text != "" { - return text - } - return def -} - -// readDefaultYesNo reads a single line from stdin, trimming if from spaces and -// interpreting it as a 'yes' or a 'no'. If an empty line is entered, the default -// value is returned. -func (w *wizard) readDefaultYesNo(def bool) bool { - for { - text := promptInput("> ") - if text = strings.ToLower(strings.TrimSpace(text)); text == "" { - return def - } - if text == "y" || text == "yes" { - return true - } - if text == "n" || text == "no" { - return false - } - log.Error("Invalid input, expected 'y', 'yes', 'n', 'no' or empty") - } -} - -// readURL reads a single line from stdin, trimming if from spaces and trying to -// interpret it as a URL (http, https or file). -func (w *wizard) readURL() *url.URL { - for { - text := promptInput("> ") - uri, err := url.Parse(strings.TrimSpace(text)) - if err != nil { - log.Error("Invalid input, expected URL", "err", err) - continue - } - return uri - } -} - -// readInt reads a single line from stdin, trimming if from spaces, enforcing it -// to parse into an integer. -func (w *wizard) readInt() int { - for { - text := promptInput("> ") - if text = strings.TrimSpace(text); text == "" { - continue - } - val, err := strconv.Atoi(strings.TrimSpace(text)) - if err != nil { - log.Error("Invalid input, expected integer", "err", err) - continue - } - return val - } -} - -// readDefaultInt reads a single line from stdin, trimming if from spaces, enforcing -// it to parse into an integer. If an empty line is entered, the default value is -// returned. -func (w *wizard) readDefaultInt(def int) int { - for { - text := promptInput("> ") - if text = strings.TrimSpace(text); text == "" { - return def - } - val, err := strconv.Atoi(strings.TrimSpace(text)) - if err != nil { - log.Error("Invalid input, expected integer", "err", err) - continue - } - return val - } -} - -// readDefaultBigInt reads a single line from stdin, trimming if from spaces, -// enforcing it to parse into a big integer. If an empty line is entered, the -// default value is returned. -func (w *wizard) readDefaultBigInt(def *big.Int) *big.Int { - for { - text := promptInput("> ") - if text = strings.TrimSpace(text); text == "" { - return def - } - val, ok := new(big.Int).SetString(text, 0) - if !ok { - log.Error("Invalid input, expected big integer") - continue - } - return val - } -} - -// readDefaultFloat reads a single line from stdin, trimming if from spaces, enforcing -// it to parse into a float. If an empty line is entered, the default value is returned. -func (w *wizard) readDefaultFloat(def float64) float64 { - for { - text := promptInput("> ") - if text = strings.TrimSpace(text); text == "" { - return def - } - val, err := strconv.ParseFloat(strings.TrimSpace(text), 64) - if err != nil { - log.Error("Invalid input, expected float", "err", err) - continue - } - return val - } -} - -// readPassword reads a single line from stdin, trimming it from the trailing new -// line and returns it. The input will not be echoed. -func (w *wizard) readPassword() string { - fmt.Printf("> ") - text, err := term.ReadPassword(int(os.Stdin.Fd())) - if err != nil { - log.Crit("Failed to read password", "err", err) - } - fmt.Println() - return string(text) -} - -// readAddress reads a single line from stdin, trimming if from spaces and converts -// it to an Ethereum address. -func (w *wizard) readAddress() *common.Address { - for { - text := promptInput("> 0x") - if text = strings.TrimSpace(text); text == "" { - return nil - } - // Make sure it looks ok and return it if so - if len(text) != 40 { - log.Error("Invalid address length, please retry") - continue - } - bigaddr, _ := new(big.Int).SetString(text, 16) - address := common.BigToAddress(bigaddr) - return &address - } -} - -// readDefaultAddress reads a single line from stdin, trimming if from spaces and -// converts it to an Ethereum address. If an empty line is entered, the default -// value is returned. -func (w *wizard) readDefaultAddress(def common.Address) common.Address { - for { - // Read the address from the user - text := promptInput("> 0x") - if text = strings.TrimSpace(text); text == "" { - return def - } - // Make sure it looks ok and return it if so - if len(text) != 40 { - log.Error("Invalid address length, please retry") - continue - } - bigaddr, _ := new(big.Int).SetString(text, 16) - return common.BigToAddress(bigaddr) - } -} - -// readJSON reads a raw JSON message and returns it. -func (w *wizard) readJSON() string { - var blob json.RawMessage - - for { - text := promptInput("> ") - reader := strings.NewReader(text) - if err := json.NewDecoder(reader).Decode(&blob); err != nil { - log.Error("Invalid JSON, please try again", "err", err) - continue - } - return string(blob) - } -} - -// readIPAddress reads a single line from stdin, trimming if from spaces and -// returning it if it's convertible to an IP address. The reason for keeping -// the user input format instead of returning a Go net.IP is to match with -// weird formats used by ethstats, which compares IPs textually, not by value. -func (w *wizard) readIPAddress() string { - for { - // Read the IP address from the user - fmt.Printf("> ") - text := promptInput("> ") - if text = strings.TrimSpace(text); text == "" { - return "" - } - // Make sure it looks ok and return it if so - if ip := net.ParseIP(text); ip == nil { - log.Error("Invalid IP address, please retry") - continue - } - return text - } -} diff --git a/cmd/puppeth/wizard_dashboard.go b/cmd/puppeth/wizard_dashboard.go deleted file mode 100644 index b64bdca0b98b..000000000000 --- a/cmd/puppeth/wizard_dashboard.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - - "github.com/ethereum/go-ethereum/log" -) - -// deployDashboard queries the user for various input on deploying a web-service -// dashboard, after which is pushes the container. -func (w *wizard) deployDashboard() { - // Select the server to interact with - server := w.selectServer() - if server == "" { - return - } - client := w.servers[server] - - // Retrieve any active dashboard configurations from the server - infos, err := checkDashboard(client, w.network) - if err != nil { - infos = &dashboardInfos{ - port: 80, - host: client.server, - } - } - existed := err == nil - - // Figure out which port to listen on - fmt.Println() - fmt.Printf("Which port should the dashboard listen on? (default = %d)\n", infos.port) - infos.port = w.readDefaultInt(infos.port) - - // Figure which virtual-host to deploy the dashboard on - infos.host, err = w.ensureVirtualHost(client, infos.port, infos.host) - if err != nil { - log.Error("Failed to decide on dashboard host", "err", err) - return - } - // Port and proxy settings retrieved, figure out which services are available - available := make(map[string][]string) - for server, services := range w.services { - for _, service := range services { - available[service] = append(available[service], server) - } - } - for _, service := range []string{"ethstats", "explorer", "faucet"} { - // Gather all the locally hosted pages of this type - var pages []string - for _, server := range available[service] { - client := w.servers[server] - if client == nil { - continue - } - // If there's a service running on the machine, retrieve it's port number - var port int - switch service { - case "ethstats": - if infos, err := checkEthstats(client, w.network); err == nil { - port = infos.port - } - case "explorer": - if infos, err := checkExplorer(client, w.network); err == nil { - port = infos.port - } - case "faucet": - if infos, err := checkFaucet(client, w.network); err == nil { - port = infos.port - } - } - if page, err := resolve(client, w.network, service, port); err == nil && page != "" { - pages = append(pages, page) - } - } - // Prompt the user to chose one, enter manually or simply not list this service - defLabel, defChoice := "don't list", len(pages)+2 - if len(pages) > 0 { - defLabel, defChoice = pages[0], 1 - } - fmt.Println() - fmt.Printf("Which %s service to list? (default = %s)\n", service, defLabel) - for i, page := range pages { - fmt.Printf(" %d. %s\n", i+1, page) - } - fmt.Printf(" %d. List external %s service\n", len(pages)+1, service) - fmt.Printf(" %d. Don't list any %s service\n", len(pages)+2, service) - - choice := w.readDefaultInt(defChoice) - if choice < 0 || choice > len(pages)+2 { - log.Error("Invalid listing choice, aborting") - return - } - var page string - switch { - case choice <= len(pages): - page = pages[choice-1] - case choice == len(pages)+1: - fmt.Println() - fmt.Printf("Which address is the external %s service at?\n", service) - page = w.readString() - default: - // No service hosting for this - } - // Save the users choice - switch service { - case "ethstats": - infos.ethstats = page - case "explorer": - infos.explorer = page - case "faucet": - infos.faucet = page - } - } - // If we have ethstats running, ask whether to make the secret public or not - if w.conf.ethstats != "" { - fmt.Println() - fmt.Println("Include ethstats secret on dashboard (y/n)? (default = yes)") - infos.trusted = w.readDefaultYesNo(true) - } - // Try to deploy the dashboard container on the host - nocache := false - if existed { - fmt.Println() - fmt.Printf("Should the dashboard be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultYesNo(false) - } - if out, err := deployDashboard(client, w.network, &w.conf, infos, nocache); err != nil { - log.Error("Failed to deploy dashboard container", "err", err) - if len(out) > 0 { - fmt.Printf("%s\n", out) - } - return - } - // All ok, run a network scan to pick any changes up - w.networkStats() -} diff --git a/cmd/puppeth/wizard_ethstats.go b/cmd/puppeth/wizard_ethstats.go deleted file mode 100644 index 95cab9da4633..000000000000 --- a/cmd/puppeth/wizard_ethstats.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "sort" - - "github.com/ethereum/go-ethereum/log" -) - -// deployEthstats queries the user for various input on deploying an ethstats -// monitoring server, after which it executes it. -func (w *wizard) deployEthstats() { - // Select the server to interact with - server := w.selectServer() - if server == "" { - return - } - client := w.servers[server] - - // Retrieve any active ethstats configurations from the server - infos, err := checkEthstats(client, w.network) - if err != nil { - infos = ðstatsInfos{ - port: 80, - host: client.server, - secret: "", - } - } - existed := err == nil - - // Figure out which port to listen on - fmt.Println() - fmt.Printf("Which port should ethstats listen on? (default = %d)\n", infos.port) - infos.port = w.readDefaultInt(infos.port) - - // Figure which virtual-host to deploy ethstats on - if infos.host, err = w.ensureVirtualHost(client, infos.port, infos.host); err != nil { - log.Error("Failed to decide on ethstats host", "err", err) - return - } - // Port and proxy settings retrieved, figure out the secret and boot ethstats - fmt.Println() - if infos.secret == "" { - fmt.Printf("What should be the secret password for the API? (must not be empty)\n") - infos.secret = w.readString() - } else { - fmt.Printf("What should be the secret password for the API? (default = %s)\n", infos.secret) - infos.secret = w.readDefaultString(infos.secret) - } - // Gather any banned lists to ban from reporting - if existed { - fmt.Println() - fmt.Printf("Keep existing IP %v in the banned list (y/n)? (default = yes)\n", infos.banned) - if !w.readDefaultYesNo(true) { - // The user might want to clear the entire list, although generally probably not - fmt.Println() - fmt.Printf("Clear out the banned list and start over (y/n)? (default = no)\n") - if w.readDefaultYesNo(false) { - infos.banned = nil - } - // Offer the user to explicitly add/remove certain IP addresses - fmt.Println() - fmt.Println("Which additional IP addresses should be in the banned list?") - for { - if ip := w.readIPAddress(); ip != "" { - infos.banned = append(infos.banned, ip) - continue - } - break - } - fmt.Println() - fmt.Println("Which IP addresses should not be in the banned list?") - for { - if ip := w.readIPAddress(); ip != "" { - for i, addr := range infos.banned { - if ip == addr { - infos.banned = append(infos.banned[:i], infos.banned[i+1:]...) - break - } - } - continue - } - break - } - sort.Strings(infos.banned) - } - } - // Try to deploy the ethstats server on the host - nocache := false - if existed { - fmt.Println() - fmt.Printf("Should the ethstats be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultYesNo(false) - } - trusted := make([]string, 0, len(w.servers)) - for _, client := range w.servers { - if client != nil { - trusted = append(trusted, client.address) - } - } - if out, err := deployEthstats(client, w.network, infos.port, infos.secret, infos.host, trusted, infos.banned, nocache); err != nil { - log.Error("Failed to deploy ethstats container", "err", err) - if len(out) > 0 { - fmt.Printf("%s\n", out) - } - return - } - // All ok, run a network scan to pick any changes up - w.networkStats() -} diff --git a/cmd/puppeth/wizard_explorer.go b/cmd/puppeth/wizard_explorer.go deleted file mode 100644 index 1df9cbc0f322..000000000000 --- a/cmd/puppeth/wizard_explorer.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/log" -) - -// deployExplorer creates a new block explorer based on some user input. -func (w *wizard) deployExplorer() { - // Do some sanity check before the user wastes time on input - if w.conf.Genesis == nil { - log.Error("No genesis block configured") - return - } - if w.conf.ethstats == "" { - log.Error("No ethstats server configured") - return - } - // Select the server to interact with - server := w.selectServer() - if server == "" { - return - } - client := w.servers[server] - - // Retrieve any active node configurations from the server - infos, err := checkExplorer(client, w.network) - if err != nil { - infos = &explorerInfos{ - node: &nodeInfos{port: 30303}, - port: 80, - host: client.server, - } - } - existed := err == nil - - infos.node.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", " ") - infos.node.network = w.conf.Genesis.Config.ChainID.Int64() - - // Figure out which port to listen on - fmt.Println() - fmt.Printf("Which port should the explorer listen on? (default = %d)\n", infos.port) - infos.port = w.readDefaultInt(infos.port) - - // Figure which virtual-host to deploy ethstats on - if infos.host, err = w.ensureVirtualHost(client, infos.port, infos.host); err != nil { - log.Error("Failed to decide on explorer host", "err", err) - return - } - // Figure out where the user wants to store the persistent data - fmt.Println() - if infos.node.datadir == "" { - fmt.Printf("Where should node data be stored on the remote machine?\n") - infos.node.datadir = w.readString() - } else { - fmt.Printf("Where should node data be stored on the remote machine? (default = %s)\n", infos.node.datadir) - infos.node.datadir = w.readDefaultString(infos.node.datadir) - } - // Figure out where the user wants to store the persistent data for backend database - fmt.Println() - if infos.dbdir == "" { - fmt.Printf("Where should postgres data be stored on the remote machine?\n") - infos.dbdir = w.readString() - } else { - fmt.Printf("Where should postgres data be stored on the remote machine? (default = %s)\n", infos.dbdir) - infos.dbdir = w.readDefaultString(infos.dbdir) - } - // Figure out which port to listen on - fmt.Println() - fmt.Printf("Which TCP/UDP port should the archive node listen on? (default = %d)\n", infos.node.port) - infos.node.port = w.readDefaultInt(infos.node.port) - - // Set a proper name to report on the stats page - fmt.Println() - if infos.node.ethstats == "" { - fmt.Printf("What should the explorer be called on the stats page?\n") - infos.node.ethstats = w.readString() + ":" + w.conf.ethstats - } else { - fmt.Printf("What should the explorer be called on the stats page? (default = %s)\n", infos.node.ethstats) - infos.node.ethstats = w.readDefaultString(infos.node.ethstats) + ":" + w.conf.ethstats - } - // Try to deploy the explorer on the host - nocache := false - if existed { - fmt.Println() - fmt.Printf("Should the explorer be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultYesNo(false) - } - if out, err := deployExplorer(client, w.network, w.conf.bootnodes, infos, nocache, w.conf.Genesis.Config.Clique != nil); err != nil { - log.Error("Failed to deploy explorer container", "err", err) - if len(out) > 0 { - fmt.Printf("%s\n", out) - } - return - } - // All ok, run a network scan to pick any changes up - log.Info("Waiting for node to finish booting") - time.Sleep(3 * time.Second) - - w.networkStats() -} diff --git a/cmd/puppeth/wizard_faucet.go b/cmd/puppeth/wizard_faucet.go deleted file mode 100644 index 65d4e8b8ed4c..000000000000 --- a/cmd/puppeth/wizard_faucet.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "fmt" - - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/log" -) - -// deployFaucet queries the user for various input on deploying a faucet, after -// which it executes it. -func (w *wizard) deployFaucet() { - // Select the server to interact with - server := w.selectServer() - if server == "" { - return - } - client := w.servers[server] - - // Retrieve any active faucet configurations from the server - infos, err := checkFaucet(client, w.network) - if err != nil { - infos = &faucetInfos{ - node: &nodeInfos{port: 30303, peersTotal: 25}, - port: 80, - host: client.server, - amount: 1, - minutes: 1440, - tiers: 3, - } - } - existed := err == nil - - infos.node.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", " ") - infos.node.network = w.conf.Genesis.Config.ChainID.Int64() - - // Figure out which port to listen on - fmt.Println() - fmt.Printf("Which port should the faucet listen on? (default = %d)\n", infos.port) - infos.port = w.readDefaultInt(infos.port) - - // Figure which virtual-host to deploy ethstats on - if infos.host, err = w.ensureVirtualHost(client, infos.port, infos.host); err != nil { - log.Error("Failed to decide on faucet host", "err", err) - return - } - // Port and proxy settings retrieved, figure out the funding amount per period configurations - fmt.Println() - fmt.Printf("How many Ethers to release per request? (default = %d)\n", infos.amount) - infos.amount = w.readDefaultInt(infos.amount) - - fmt.Println() - fmt.Printf("How many minutes to enforce between requests? (default = %d)\n", infos.minutes) - infos.minutes = w.readDefaultInt(infos.minutes) - - fmt.Println() - fmt.Printf("How many funding tiers to feature (x2.5 amounts, x3 timeout)? (default = %d)\n", infos.tiers) - infos.tiers = w.readDefaultInt(infos.tiers) - if infos.tiers == 0 { - log.Error("At least one funding tier must be set") - return - } - // Accessing the reCaptcha service requires API authorizations, request it - if infos.captchaToken != "" { - fmt.Println() - fmt.Println("Reuse previous reCaptcha API authorization (y/n)? (default = yes)") - if !w.readDefaultYesNo(true) { - infos.captchaToken, infos.captchaSecret = "", "" - } - } - if infos.captchaToken == "" { - // No previous authorization (or old one discarded) - fmt.Println() - fmt.Println("Enable reCaptcha protection against robots (y/n)? (default = no)") - if !w.readDefaultYesNo(false) { - log.Warn("Users will be able to requests funds via automated scripts") - } else { - // Captcha protection explicitly requested, read the site and secret keys - fmt.Println() - fmt.Printf("What is the reCaptcha site key to authenticate human users?\n") - infos.captchaToken = w.readString() - - fmt.Println() - fmt.Printf("What is the reCaptcha secret key to verify authentications? (won't be echoed)\n") - infos.captchaSecret = w.readPassword() - } - } - // Accessing the Twitter API requires a bearer token, request it - if infos.twitterToken != "" { - fmt.Println() - fmt.Println("Reuse previous Twitter API token (y/n)? (default = yes)") - if !w.readDefaultYesNo(true) { - infos.twitterToken = "" - } - } - if infos.twitterToken == "" { - // No previous twitter token (or old one discarded) - fmt.Println() - fmt.Println() - fmt.Printf("What is the Twitter API app Bearer token?\n") - infos.twitterToken = w.readString() - } - // Figure out where the user wants to store the persistent data - fmt.Println() - if infos.node.datadir == "" { - fmt.Printf("Where should data be stored on the remote machine?\n") - infos.node.datadir = w.readString() - } else { - fmt.Printf("Where should data be stored on the remote machine? (default = %s)\n", infos.node.datadir) - infos.node.datadir = w.readDefaultString(infos.node.datadir) - } - // Figure out which port to listen on - fmt.Println() - fmt.Printf("Which TCP/UDP port should the light client listen on? (default = %d)\n", infos.node.port) - infos.node.port = w.readDefaultInt(infos.node.port) - - // Set a proper name to report on the stats page - fmt.Println() - if infos.node.ethstats == "" { - fmt.Printf("What should the node be called on the stats page?\n") - infos.node.ethstats = w.readString() + ":" + w.conf.ethstats - } else { - fmt.Printf("What should the node be called on the stats page? (default = %s)\n", infos.node.ethstats) - infos.node.ethstats = w.readDefaultString(infos.node.ethstats) + ":" + w.conf.ethstats - } - // Load up the credential needed to release funds - if infos.node.keyJSON != "" { - if key, err := keystore.DecryptKey([]byte(infos.node.keyJSON), infos.node.keyPass); err != nil { - infos.node.keyJSON, infos.node.keyPass = "", "" - } else { - fmt.Println() - fmt.Printf("Reuse previous (%s) funding account (y/n)? (default = yes)\n", key.Address.Hex()) - if !w.readDefaultYesNo(true) { - infos.node.keyJSON, infos.node.keyPass = "", "" - } - } - } - for i := 0; i < 3 && infos.node.keyJSON == ""; i++ { - fmt.Println() - fmt.Println("Please paste the faucet's funding account key JSON:") - infos.node.keyJSON = w.readJSON() - - fmt.Println() - fmt.Println("What's the unlock password for the account? (won't be echoed)") - infos.node.keyPass = w.readPassword() - - if _, err := keystore.DecryptKey([]byte(infos.node.keyJSON), infos.node.keyPass); err != nil { - log.Error("Failed to decrypt key with given password") - infos.node.keyJSON = "" - infos.node.keyPass = "" - } - } - // Check if the user wants to run the faucet in debug mode (noauth) - noauth := "n" - if infos.noauth { - noauth = "y" - } - fmt.Println() - fmt.Printf("Permit non-authenticated funding requests (y/n)? (default = %v)\n", infos.noauth) - infos.noauth = w.readDefaultString(noauth) != "n" - - // Try to deploy the faucet server on the host - nocache := false - if existed { - fmt.Println() - fmt.Printf("Should the faucet be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultYesNo(false) - } - if out, err := deployFaucet(client, w.network, w.conf.bootnodes, infos, nocache); err != nil { - log.Error("Failed to deploy faucet container", "err", err) - if len(out) > 0 { - fmt.Printf("%s\n", out) - } - return - } - // All ok, run a network scan to pick any changes up - w.networkStats() -} diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go deleted file mode 100644 index ac17bc7b271c..000000000000 --- a/cmd/puppeth/wizard_genesis.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "math/big" - "math/rand" - "net/http" - "os" - "path/filepath" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" -) - -// makeGenesis creates a new genesis struct based on some user input. -func (w *wizard) makeGenesis() { - // Construct a default genesis block - genesis := &core.Genesis{ - Timestamp: uint64(time.Now().Unix()), - GasLimit: 4700000, - Difficulty: big.NewInt(524288), - Alloc: make(core.GenesisAlloc), - Config: ¶ms.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - }, - } - // Figure out which consensus engine to choose - fmt.Println() - fmt.Println("Which consensus engine to use? (default = clique)") - fmt.Println(" 1. Ethash - proof-of-work") - fmt.Println(" 2. Clique - proof-of-authority") - - choice := w.read() - switch { - case choice == "1": - // In case of ethash, we're pretty much done - genesis.Config.Ethash = new(params.EthashConfig) - genesis.ExtraData = make([]byte, 32) - - case choice == "" || choice == "2": - // In the case of clique, configure the consensus parameters - genesis.Difficulty = big.NewInt(1) - genesis.Config.Clique = ¶ms.CliqueConfig{ - Period: 15, - Epoch: 30000, - } - fmt.Println() - fmt.Println("How many seconds should blocks take? (default = 15)") - genesis.Config.Clique.Period = uint64(w.readDefaultInt(15)) - - // We also need the initial list of signers - fmt.Println() - fmt.Println("Which accounts are allowed to seal? (mandatory at least one)") - - var signers []common.Address - for { - if address := w.readAddress(); address != nil { - signers = append(signers, *address) - continue - } - if len(signers) > 0 { - break - } - } - // Sort the signers and embed into the extra-data section - for i := 0; i < len(signers); i++ { - for j := i + 1; j < len(signers); j++ { - if bytes.Compare(signers[i][:], signers[j][:]) > 0 { - signers[i], signers[j] = signers[j], signers[i] - } - } - } - genesis.ExtraData = make([]byte, 32+len(signers)*common.AddressLength+65) - for i, signer := range signers { - copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:]) - } - - default: - log.Crit("Invalid consensus engine choice", "choice", choice) - } - // Consensus all set, just ask for initial funds and go - fmt.Println() - fmt.Println("Which accounts should be pre-funded? (advisable at least one)") - for { - // Read the address of the account to fund - if address := w.readAddress(); address != nil { - genesis.Alloc[*address] = core.GenesisAccount{ - Balance: new(big.Int).Lsh(big.NewInt(1), 256-7), // 2^256 / 128 (allow many pre-funds without balance overflows) - } - continue - } - break - } - fmt.Println() - fmt.Println("Should the precompile-addresses (0x1 .. 0xff) be pre-funded with 1 wei? (advisable yes)") - if w.readDefaultYesNo(true) { - // Add a batch of precompile balances to avoid them getting deleted - for i := int64(0); i < 256; i++ { - genesis.Alloc[common.BigToAddress(big.NewInt(i))] = core.GenesisAccount{Balance: big.NewInt(1)} - } - } - // Query the user for some custom extras - fmt.Println() - fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)") - genesis.Config.ChainID = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536)))) - - // All done, store the genesis and flush to disk - log.Info("Configured new genesis block") - - w.conf.Genesis = genesis - w.conf.flush() -} - -// importGenesis imports a Geth genesis spec into puppeth. -func (w *wizard) importGenesis() { - // Request the genesis JSON spec URL from the user - fmt.Println() - fmt.Println("Where's the genesis file? (local file or http/https url)") - url := w.readURL() - - // Convert the various allowed URLs to a reader stream - var reader io.Reader - - switch url.Scheme { - case "http", "https": - // Remote web URL, retrieve it via an HTTP client - res, err := http.Get(url.String()) - if err != nil { - log.Error("Failed to retrieve remote genesis", "err", err) - return - } - defer res.Body.Close() - reader = res.Body - - case "": - // Schemaless URL, interpret as a local file - file, err := os.Open(url.String()) - if err != nil { - log.Error("Failed to open local genesis", "err", err) - return - } - defer file.Close() - reader = file - - default: - log.Error("Unsupported genesis URL scheme", "scheme", url.Scheme) - return - } - // Parse the genesis file and inject it successful - var genesis core.Genesis - if err := json.NewDecoder(reader).Decode(&genesis); err != nil { - log.Error("Invalid genesis spec", "err", err) - return - } - log.Info("Imported genesis block") - - w.conf.Genesis = &genesis - w.conf.flush() -} - -// manageGenesis permits the modification of chain configuration parameters in -// a genesis config and the export of the entire genesis spec. -func (w *wizard) manageGenesis() { - // Figure out whether to modify or export the genesis - fmt.Println() - fmt.Println(" 1. Modify existing configurations") - fmt.Println(" 2. Export genesis configurations") - fmt.Println(" 3. Remove genesis configuration") - - choice := w.read() - switch choice { - case "1": - // Fork rule updating requested, iterate over each fork - fmt.Println() - fmt.Printf("Which block should Homestead come into effect? (default = %v)\n", w.conf.Genesis.Config.HomesteadBlock) - w.conf.Genesis.Config.HomesteadBlock = w.readDefaultBigInt(w.conf.Genesis.Config.HomesteadBlock) - - fmt.Println() - fmt.Printf("Which block should EIP150 (Tangerine Whistle) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP150Block) - w.conf.Genesis.Config.EIP150Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP150Block) - - fmt.Println() - fmt.Printf("Which block should EIP155 (Spurious Dragon) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP155Block) - w.conf.Genesis.Config.EIP155Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP155Block) - - fmt.Println() - fmt.Printf("Which block should EIP158/161 (also Spurious Dragon) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP158Block) - w.conf.Genesis.Config.EIP158Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP158Block) - - fmt.Println() - fmt.Printf("Which block should Byzantium come into effect? (default = %v)\n", w.conf.Genesis.Config.ByzantiumBlock) - w.conf.Genesis.Config.ByzantiumBlock = w.readDefaultBigInt(w.conf.Genesis.Config.ByzantiumBlock) - - fmt.Println() - fmt.Printf("Which block should Constantinople come into effect? (default = %v)\n", w.conf.Genesis.Config.ConstantinopleBlock) - w.conf.Genesis.Config.ConstantinopleBlock = w.readDefaultBigInt(w.conf.Genesis.Config.ConstantinopleBlock) - if w.conf.Genesis.Config.PetersburgBlock == nil { - w.conf.Genesis.Config.PetersburgBlock = w.conf.Genesis.Config.ConstantinopleBlock - } - fmt.Println() - fmt.Printf("Which block should Petersburg come into effect? (default = %v)\n", w.conf.Genesis.Config.PetersburgBlock) - w.conf.Genesis.Config.PetersburgBlock = w.readDefaultBigInt(w.conf.Genesis.Config.PetersburgBlock) - - fmt.Println() - fmt.Printf("Which block should Istanbul come into effect? (default = %v)\n", w.conf.Genesis.Config.IstanbulBlock) - w.conf.Genesis.Config.IstanbulBlock = w.readDefaultBigInt(w.conf.Genesis.Config.IstanbulBlock) - - fmt.Println() - fmt.Printf("Which block should Berlin come into effect? (default = %v)\n", w.conf.Genesis.Config.BerlinBlock) - w.conf.Genesis.Config.BerlinBlock = w.readDefaultBigInt(w.conf.Genesis.Config.BerlinBlock) - - fmt.Println() - fmt.Printf("Which block should London come into effect? (default = %v)\n", w.conf.Genesis.Config.LondonBlock) - w.conf.Genesis.Config.LondonBlock = w.readDefaultBigInt(w.conf.Genesis.Config.LondonBlock) - - out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", " ") - fmt.Printf("Chain configuration updated:\n\n%s\n", out) - - w.conf.flush() - - case "2": - // Save whatever genesis configuration we currently have - fmt.Println() - fmt.Printf("Which folder to save the genesis spec into? (default = current)\n") - fmt.Printf(" Will create %s.json\n", w.network) - - folder := w.readDefaultString(".") - if err := os.MkdirAll(folder, 0755); err != nil { - log.Error("Failed to create spec folder", "folder", folder, "err", err) - return - } - out, _ := json.MarshalIndent(w.conf.Genesis, "", " ") - - // Export the native genesis spec used by puppeth and Geth - gethJson := filepath.Join(folder, fmt.Sprintf("%s.json", w.network)) - if err := os.WriteFile(gethJson, out, 0644); err != nil { - log.Error("Failed to save genesis file", "err", err) - return - } - log.Info("Saved native genesis chain spec", "path", gethJson) - - case "3": - // Make sure we don't have any services running - if len(w.conf.servers()) > 0 { - log.Error("Genesis reset requires all services and servers torn down") - return - } - log.Info("Genesis block destroyed") - - w.conf.Genesis = nil - w.conf.flush() - default: - log.Error("That's not something I can do") - return - } -} diff --git a/cmd/puppeth/wizard_intro.go b/cmd/puppeth/wizard_intro.go deleted file mode 100644 index adac943cc367..000000000000 --- a/cmd/puppeth/wizard_intro.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/ethereum/go-ethereum/log" -) - -// makeWizard creates and returns a new puppeth wizard. -func makeWizard(network string) *wizard { - return &wizard{ - network: network, - conf: config{ - Servers: make(map[string][]byte), - }, - servers: make(map[string]*sshClient), - services: make(map[string][]string), - } -} - -// run displays some useful infos to the user, starting on the journey of -// setting up a new or managing an existing Ethereum private network. -func (w *wizard) run() { - fmt.Println("+-----------------------------------------------------------+") - fmt.Println("| Welcome to puppeth, your Ethereum private network manager |") - fmt.Println("| |") - fmt.Println("| This tool lets you create a new Ethereum network down to |") - fmt.Println("| the genesis block, bootnodes, miners and ethstats servers |") - fmt.Println("| without the hassle that it would normally entail. |") - fmt.Println("| |") - fmt.Println("| Puppeth uses SSH to dial in to remote servers, and builds |") - fmt.Println("| its network components out of Docker containers using the |") - fmt.Println("| docker-compose toolset. |") - fmt.Println("+-----------------------------------------------------------+") - fmt.Println() - - // Make sure we have a good network name to work with fmt.Println() - // Docker accepts hyphens in image names, but doesn't like it for container names - if w.network == "" { - fmt.Println("Please specify a network name to administer (no spaces, hyphens or capital letters please)") - for { - w.network = w.readString() - if !strings.Contains(w.network, " ") && !strings.Contains(w.network, "-") && strings.ToLower(w.network) == w.network { - fmt.Printf("\nSweet, you can set this via --network=%s next time!\n\n", w.network) - break - } - log.Error("I also like to live dangerously, still no spaces, hyphens or capital letters") - } - } - log.Info("Administering Ethereum network", "name", w.network) - - // Load initial configurations and connect to all live servers - w.conf.path = filepath.Join(os.Getenv("HOME"), ".puppeth", w.network) - - blob, err := os.ReadFile(w.conf.path) - if err != nil { - log.Warn("No previous configurations found", "path", w.conf.path) - } else if err := json.Unmarshal(blob, &w.conf); err != nil { - log.Crit("Previous configuration corrupted", "path", w.conf.path, "err", err) - } else { - // Dial all previously known servers - for server, pubkey := range w.conf.Servers { - log.Info("Dialing previously configured server", "server", server) - client, err := dial(server, pubkey) - if err != nil { - log.Error("Previous server unreachable", "server", server, "err", err) - } - w.lock.Lock() - w.servers[server] = client - w.lock.Unlock() - } - w.networkStats() - } - // Basics done, loop ad infinitum about what to do - for { - fmt.Println() - fmt.Println("What would you like to do? (default = stats)") - fmt.Println(" 1. Show network stats") - if w.conf.Genesis == nil { - fmt.Println(" 2. Configure new genesis") - } else { - fmt.Println(" 2. Manage existing genesis") - } - if len(w.servers) == 0 { - fmt.Println(" 3. Track new remote server") - } else { - fmt.Println(" 3. Manage tracked machines") - } - if len(w.services) == 0 { - fmt.Println(" 4. Deploy network components") - } else { - fmt.Println(" 4. Manage network components") - } - - choice := w.read() - switch { - case choice == "" || choice == "1": - w.networkStats() - - case choice == "2": - if w.conf.Genesis == nil { - fmt.Println() - fmt.Println("What would you like to do? (default = create)") - fmt.Println(" 1. Create new genesis from scratch") - fmt.Println(" 2. Import already existing genesis") - - choice := w.read() - switch { - case choice == "" || choice == "1": - w.makeGenesis() - case choice == "2": - w.importGenesis() - default: - log.Error("That's not something I can do") - } - } else { - w.manageGenesis() - } - case choice == "3": - if len(w.servers) == 0 { - if w.makeServer() != "" { - w.networkStats() - } - } else { - w.manageServers() - } - case choice == "4": - if len(w.services) == 0 { - w.deployComponent() - } else { - w.manageComponents() - } - default: - log.Error("That's not something I can do") - } - } -} diff --git a/cmd/puppeth/wizard_netstats.go b/cmd/puppeth/wizard_netstats.go deleted file mode 100644 index 7b5671e6dfa4..000000000000 --- a/cmd/puppeth/wizard_netstats.go +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "os" - "sort" - "strings" - "sync" - - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/log" - "github.com/olekukonko/tablewriter" -) - -// networkStats verifies the status of network components and generates a protip -// configuration set to give users hints on how to do various tasks. -func (w *wizard) networkStats() { - if len(w.servers) == 0 { - log.Info("No remote machines to gather stats from") - return - } - // Clear out some previous configs to refill from current scan - w.conf.ethstats = "" - w.conf.bootnodes = w.conf.bootnodes[:0] - - // Iterate over all the specified hosts and check their status - var pend sync.WaitGroup - - stats := make(serverStats) - for server, pubkey := range w.conf.Servers { - pend.Add(1) - - // Gather the service stats for each server concurrently - go func(server string, pubkey []byte) { - defer pend.Done() - - stat := w.gatherStats(server, pubkey, w.servers[server]) - - // All status checks complete, report and check next server - w.lock.Lock() - defer w.lock.Unlock() - - delete(w.services, server) - for service := range stat.services { - w.services[server] = append(w.services[server], service) - } - stats[server] = stat - }(server, pubkey) - } - pend.Wait() - - // Print any collected stats and return - stats.render() -} - -// gatherStats gathers service statistics for a particular remote server. -func (w *wizard) gatherStats(server string, pubkey []byte, client *sshClient) *serverStat { - // Gather some global stats to feed into the wizard - var ( - genesis string - ethstats string - bootnodes []string - ) - // Ensure a valid SSH connection to the remote server - logger := log.New("server", server) - logger.Info("Starting remote server health-check") - - stat := &serverStat{ - services: make(map[string]map[string]string), - } - if client == nil { - conn, err := dial(server, pubkey) - if err != nil { - logger.Error("Failed to establish remote connection", "err", err) - stat.failure = err.Error() - return stat - } - client = conn - } - stat.address = client.address - - // Client connected one way or another, run health-checks - logger.Debug("Checking for nginx availability") - if infos, err := checkNginx(client, w.network); err != nil { - if err != ErrServiceUnknown { - stat.services["nginx"] = map[string]string{"offline": err.Error()} - } - } else { - stat.services["nginx"] = infos.Report() - } - logger.Debug("Checking for ethstats availability") - if infos, err := checkEthstats(client, w.network); err != nil { - if err != ErrServiceUnknown { - stat.services["ethstats"] = map[string]string{"offline": err.Error()} - } - } else { - stat.services["ethstats"] = infos.Report() - ethstats = infos.config - } - logger.Debug("Checking for bootnode availability") - if infos, err := checkNode(client, w.network, true); err != nil { - if err != ErrServiceUnknown { - stat.services["bootnode"] = map[string]string{"offline": err.Error()} - } - } else { - stat.services["bootnode"] = infos.Report() - - genesis = string(infos.genesis) - bootnodes = append(bootnodes, infos.enode) - } - logger.Debug("Checking for sealnode availability") - if infos, err := checkNode(client, w.network, false); err != nil { - if err != ErrServiceUnknown { - stat.services["sealnode"] = map[string]string{"offline": err.Error()} - } - } else { - stat.services["sealnode"] = infos.Report() - genesis = string(infos.genesis) - } - logger.Debug("Checking for explorer availability") - if infos, err := checkExplorer(client, w.network); err != nil { - if err != ErrServiceUnknown { - stat.services["explorer"] = map[string]string{"offline": err.Error()} - } - } else { - stat.services["explorer"] = infos.Report() - } - logger.Debug("Checking for faucet availability") - if infos, err := checkFaucet(client, w.network); err != nil { - if err != ErrServiceUnknown { - stat.services["faucet"] = map[string]string{"offline": err.Error()} - } - } else { - stat.services["faucet"] = infos.Report() - } - logger.Debug("Checking for dashboard availability") - if infos, err := checkDashboard(client, w.network); err != nil { - if err != ErrServiceUnknown { - stat.services["dashboard"] = map[string]string{"offline": err.Error()} - } - } else { - stat.services["dashboard"] = infos.Report() - } - // Feed and newly discovered information into the wizard - w.lock.Lock() - defer w.lock.Unlock() - - if genesis != "" && w.conf.Genesis == nil { - g := new(core.Genesis) - if err := json.Unmarshal([]byte(genesis), g); err != nil { - log.Error("Failed to parse remote genesis", "err", err) - } else { - w.conf.Genesis = g - } - } - if ethstats != "" { - w.conf.ethstats = ethstats - } - w.conf.bootnodes = append(w.conf.bootnodes, bootnodes...) - - return stat -} - -// serverStat is a collection of service configuration parameters and health -// check reports to print to the user. -type serverStat struct { - address string - failure string - services map[string]map[string]string -} - -// serverStats is a collection of server stats for multiple hosts. -type serverStats map[string]*serverStat - -// render converts the gathered statistics into a user friendly tabular report -// and prints it to the standard output. -func (stats serverStats) render() { - // Start gathering service statistics and config parameters - table := tablewriter.NewWriter(os.Stdout) - - table.SetHeader([]string{"Server", "Address", "Service", "Config", "Value"}) - table.SetAlignment(tablewriter.ALIGN_LEFT) - table.SetColWidth(40) - - // Find the longest lines for all columns for the hacked separator - separator := make([]string, 5) - for server, stat := range stats { - if len(server) > len(separator[0]) { - separator[0] = strings.Repeat("-", len(server)) - } - if len(stat.address) > len(separator[1]) { - separator[1] = strings.Repeat("-", len(stat.address)) - } - if len(stat.failure) > len(separator[1]) { - separator[1] = strings.Repeat("-", len(stat.failure)) - } - for service, configs := range stat.services { - if len(service) > len(separator[2]) { - separator[2] = strings.Repeat("-", len(service)) - } - for config, value := range configs { - if len(config) > len(separator[3]) { - separator[3] = strings.Repeat("-", len(config)) - } - for _, val := range strings.Split(value, "\n") { - if len(val) > len(separator[4]) { - separator[4] = strings.Repeat("-", len(val)) - } - } - } - } - } - // Fill up the server report in alphabetical order - servers := make([]string, 0, len(stats)) - for server := range stats { - servers = append(servers, server) - } - sort.Strings(servers) - - for i, server := range servers { - // Add a separator between all servers - if i > 0 { - table.Append(separator) - } - // Fill up the service report in alphabetical order - services := make([]string, 0, len(stats[server].services)) - for service := range stats[server].services { - services = append(services, service) - } - sort.Strings(services) - - if len(services) == 0 { - if stats[server].failure != "" { - table.Append([]string{server, stats[server].failure, "", "", ""}) - } else { - table.Append([]string{server, stats[server].address, "", "", ""}) - } - } - for j, service := range services { - // Add an empty line between all services - if j > 0 { - table.Append([]string{"", "", "", separator[3], separator[4]}) - } - // Fill up the config report in alphabetical order - configs := make([]string, 0, len(stats[server].services[service])) - for service := range stats[server].services[service] { - configs = append(configs, service) - } - sort.Strings(configs) - - for k, config := range configs { - for l, value := range strings.Split(stats[server].services[service][config], "\n") { - switch { - case j == 0 && k == 0 && l == 0: - table.Append([]string{server, stats[server].address, service, config, value}) - case k == 0 && l == 0: - table.Append([]string{"", "", service, config, value}) - case l == 0: - table.Append([]string{"", "", "", config, value}) - default: - table.Append([]string{"", "", "", "", value}) - } - } - } - } - } - table.Render() -} diff --git a/cmd/puppeth/wizard_network.go b/cmd/puppeth/wizard_network.go deleted file mode 100644 index d015e06ebb10..000000000000 --- a/cmd/puppeth/wizard_network.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "strings" - - "github.com/ethereum/go-ethereum/log" -) - -// manageServers displays a list of servers the user can disconnect from, and an -// option to connect to new servers. -func (w *wizard) manageServers() { - // List all the servers we can disconnect, along with an entry to connect a new one - fmt.Println() - - servers := w.conf.servers() - for i, server := range servers { - fmt.Printf(" %d. Disconnect %s\n", i+1, server) - } - fmt.Printf(" %d. Connect another server\n", len(w.conf.Servers)+1) - - choice := w.readInt() - if choice < 0 || choice > len(w.conf.Servers)+1 { - log.Error("Invalid server choice, aborting") - return - } - // If the user selected an existing server, drop it - if choice <= len(w.conf.Servers) { - server := servers[choice-1] - client := w.servers[server] - - delete(w.servers, server) - if client != nil { - client.Close() - } - delete(w.conf.Servers, server) - w.conf.flush() - - log.Info("Disconnected existing server", "server", server) - w.networkStats() - return - } - // If the user requested connecting a new server, do it - if w.makeServer() != "" { - w.networkStats() - } -} - -// makeServer reads a single line from stdin and interprets it as -// username:identity@hostname to connect to. It tries to establish a -// new SSH session and also executing some baseline validations. -// -// If connection succeeds, the server is added to the wizards configs! -func (w *wizard) makeServer() string { - fmt.Println() - fmt.Println("What is the remote server's address ([username[:identity]@]hostname[:port])?") - - // Read and dial the server to ensure docker is present - input := w.readString() - - client, err := dial(input, nil) - if err != nil { - log.Error("Server not ready for puppeth", "err", err) - return "" - } - // All checks passed, start tracking the server - w.servers[input] = client - w.conf.Servers[input] = client.pubkey - w.conf.flush() - - return input -} - -// selectServer lists the user all the currently known servers to choose from, -// also granting the option to add a new one. -func (w *wizard) selectServer() string { - // List the available server to the user and wait for a choice - fmt.Println() - fmt.Println("Which server do you want to interact with?") - - servers := w.conf.servers() - for i, server := range servers { - fmt.Printf(" %d. %s\n", i+1, server) - } - fmt.Printf(" %d. Connect another server\n", len(w.conf.Servers)+1) - - choice := w.readInt() - if choice < 0 || choice > len(w.conf.Servers)+1 { - log.Error("Invalid server choice, aborting") - return "" - } - // If the user requested connecting to a new server, go for it - if choice <= len(w.conf.Servers) { - return servers[choice-1] - } - return w.makeServer() -} - -// manageComponents displays a list of network components the user can tear down -// and an option -func (w *wizard) manageComponents() { - // List all the components we can tear down, along with an entry to deploy a new one - fmt.Println() - - var serviceHosts, serviceNames []string - for server, services := range w.services { - for _, service := range services { - serviceHosts = append(serviceHosts, server) - serviceNames = append(serviceNames, service) - - fmt.Printf(" %d. Tear down %s on %s\n", len(serviceHosts), strings.Title(service), server) - } - } - fmt.Printf(" %d. Deploy new network component\n", len(serviceHosts)+1) - - choice := w.readInt() - if choice < 0 || choice > len(serviceHosts)+1 { - log.Error("Invalid component choice, aborting") - return - } - // If the user selected an existing service, destroy it - if choice <= len(serviceHosts) { - // Figure out the service to destroy and execute it - service := serviceNames[choice-1] - server := serviceHosts[choice-1] - client := w.servers[server] - - if out, err := tearDown(client, w.network, service, true); err != nil { - log.Error("Failed to tear down component", "err", err) - if len(out) > 0 { - fmt.Printf("%s\n", out) - } - return - } - // Clean up any references to it from out state - services := w.services[server] - for i, name := range services { - if name == service { - w.services[server] = append(services[:i], services[i+1:]...) - if len(w.services[server]) == 0 { - delete(w.services, server) - } - } - } - log.Info("Torn down existing component", "server", server, "service", service) - return - } - // If the user requested deploying a new component, do it - w.deployComponent() -} - -// deployComponent displays a list of network components the user can deploy and -// guides through the process. -func (w *wizard) deployComponent() { - // Print all the things we can deploy and wait or user choice - fmt.Println() - fmt.Println("What would you like to deploy? (recommended order)") - fmt.Println(" 1. Ethstats - Network monitoring tool") - fmt.Println(" 2. Bootnode - Entry point of the network") - fmt.Println(" 3. Sealer - Full node minting new blocks") - fmt.Println(" 4. Explorer - Chain analysis webservice") - fmt.Println(" 5. Faucet - Crypto faucet to give away funds") - fmt.Println(" 6. Dashboard - Website listing above web-services") - - switch w.read() { - case "1": - w.deployEthstats() - case "2": - w.deployNode(true) - case "3": - w.deployNode(false) - case "4": - w.deployExplorer() - case "5": - w.deployFaucet() - case "6": - w.deployDashboard() - default: - log.Error("That's not something I can do") - } -} diff --git a/cmd/puppeth/wizard_nginx.go b/cmd/puppeth/wizard_nginx.go deleted file mode 100644 index 8397b7fd57ff..000000000000 --- a/cmd/puppeth/wizard_nginx.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - - "github.com/ethereum/go-ethereum/log" -) - -// ensureVirtualHost checks whether a reverse-proxy is running on the specified -// host machine, and if yes requests a virtual host from the user to host a -// specific web service on. If no proxy exists, the method will offer to deploy -// one. -// -// If the user elects not to use a reverse proxy, an empty hostname is returned! -func (w *wizard) ensureVirtualHost(client *sshClient, port int, def string) (string, error) { - proxy, _ := checkNginx(client, w.network) - if proxy != nil { - // Reverse proxy is running, if ports match, we need a virtual host - if proxy.port == port { - fmt.Println() - fmt.Printf("Shared port, which domain to assign? (default = %s)\n", def) - return w.readDefaultString(def), nil - } - } - // Reverse proxy is not running, offer to deploy a new one - fmt.Println() - fmt.Println("Allow sharing the port with other services (y/n)? (default = yes)") - if w.readDefaultYesNo(true) { - nocache := false - if proxy != nil { - fmt.Println() - fmt.Printf("Should the reverse-proxy be rebuilt from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultYesNo(false) - } - if out, err := deployNginx(client, w.network, port, nocache); err != nil { - log.Error("Failed to deploy reverse-proxy", "err", err) - if len(out) > 0 { - fmt.Printf("%s\n", out) - } - return "", err - } - // Reverse proxy deployed, ask again for the virtual-host - fmt.Println() - fmt.Printf("Proxy deployed, which domain to assign? (default = %s)\n", def) - return w.readDefaultString(def), nil - } - // Reverse proxy not requested, deploy as a standalone service - return "", nil -} diff --git a/cmd/puppeth/wizard_node.go b/cmd/puppeth/wizard_node.go deleted file mode 100644 index c38750875aad..000000000000 --- a/cmd/puppeth/wizard_node.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" -) - -// deployNode creates a new node configuration based on some user input. -func (w *wizard) deployNode(boot bool) { - // Do some sanity check before the user wastes time on input - if w.conf.Genesis == nil { - log.Error("No genesis block configured") - return - } - if w.conf.ethstats == "" { - log.Error("No ethstats server configured") - return - } - // Select the server to interact with - server := w.selectServer() - if server == "" { - return - } - client := w.servers[server] - - // Retrieve any active node configurations from the server - infos, err := checkNode(client, w.network, boot) - if err != nil { - if boot { - infos = &nodeInfos{port: 30303, peersTotal: 512, peersLight: 256} - } else { - infos = &nodeInfos{port: 30303, peersTotal: 50, peersLight: 0, gasLimit: 10, gasPrice: 1} - } - } - existed := err == nil - - infos.genesis, _ = json.MarshalIndent(w.conf.Genesis, "", " ") - infos.network = w.conf.Genesis.Config.ChainID.Int64() - - // Figure out where the user wants to store the persistent data - fmt.Println() - if infos.datadir == "" { - fmt.Printf("Where should data be stored on the remote machine?\n") - infos.datadir = w.readString() - } else { - fmt.Printf("Where should data be stored on the remote machine? (default = %s)\n", infos.datadir) - infos.datadir = w.readDefaultString(infos.datadir) - } - if w.conf.Genesis.Config.Ethash != nil && !boot { - fmt.Println() - if infos.ethashdir == "" { - fmt.Printf("Where should the ethash mining DAGs be stored on the remote machine?\n") - infos.ethashdir = w.readString() - } else { - fmt.Printf("Where should the ethash mining DAGs be stored on the remote machine? (default = %s)\n", infos.ethashdir) - infos.ethashdir = w.readDefaultString(infos.ethashdir) - } - } - // Figure out which port to listen on - fmt.Println() - fmt.Printf("Which TCP/UDP port to listen on? (default = %d)\n", infos.port) - infos.port = w.readDefaultInt(infos.port) - - // Figure out how many peers to allow (different based on node type) - fmt.Println() - fmt.Printf("How many peers to allow connecting? (default = %d)\n", infos.peersTotal) - infos.peersTotal = w.readDefaultInt(infos.peersTotal) - - // Figure out how many light peers to allow (different based on node type) - fmt.Println() - fmt.Printf("How many light peers to allow connecting? (default = %d)\n", infos.peersLight) - infos.peersLight = w.readDefaultInt(infos.peersLight) - - // Set a proper name to report on the stats page - fmt.Println() - if infos.ethstats == "" { - fmt.Printf("What should the node be called on the stats page?\n") - infos.ethstats = w.readString() + ":" + w.conf.ethstats - } else { - fmt.Printf("What should the node be called on the stats page? (default = %s)\n", infos.ethstats) - infos.ethstats = w.readDefaultString(infos.ethstats) + ":" + w.conf.ethstats - } - // If the node is a miner/signer, load up needed credentials - if !boot { - if w.conf.Genesis.Config.Ethash != nil { - // Ethash based miners only need an etherbase to mine against - fmt.Println() - if infos.etherbase == "" { - fmt.Printf("What address should the miner use?\n") - for { - if address := w.readAddress(); address != nil { - infos.etherbase = address.Hex() - break - } - } - } else { - fmt.Printf("What address should the miner use? (default = %s)\n", infos.etherbase) - infos.etherbase = w.readDefaultAddress(common.HexToAddress(infos.etherbase)).Hex() - } - } else if w.conf.Genesis.Config.Clique != nil { - // If a previous signer was already set, offer to reuse it - if infos.keyJSON != "" { - if key, err := keystore.DecryptKey([]byte(infos.keyJSON), infos.keyPass); err != nil { - infos.keyJSON, infos.keyPass = "", "" - } else { - fmt.Println() - fmt.Printf("Reuse previous (%s) signing account (y/n)? (default = yes)\n", key.Address.Hex()) - if !w.readDefaultYesNo(true) { - infos.keyJSON, infos.keyPass = "", "" - } - } - } - // Clique based signers need a keyfile and unlock password, ask if unavailable - if infos.keyJSON == "" { - fmt.Println() - fmt.Println("Please paste the signer's key JSON:") - infos.keyJSON = w.readJSON() - - fmt.Println() - fmt.Println("What's the unlock password for the account? (won't be echoed)") - infos.keyPass = w.readPassword() - - if _, err := keystore.DecryptKey([]byte(infos.keyJSON), infos.keyPass); err != nil { - log.Error("Failed to decrypt key with given password") - return - } - } - } - // Establish the gas dynamics to be enforced by the signer - fmt.Println() - fmt.Printf("What gas limit should full blocks target (MGas)? (default = %0.3f)\n", infos.gasLimit) - infos.gasLimit = w.readDefaultFloat(infos.gasLimit) - - fmt.Println() - fmt.Printf("What gas price should the signer require (GWei)? (default = %0.3f)\n", infos.gasPrice) - infos.gasPrice = w.readDefaultFloat(infos.gasPrice) - } - // Try to deploy the full node on the host - nocache := false - if existed { - fmt.Println() - fmt.Printf("Should the node be built from scratch (y/n)? (default = no)\n") - nocache = w.readDefaultYesNo(false) - } - if out, err := deployNode(client, w.network, w.conf.bootnodes, infos, nocache); err != nil { - log.Error("Failed to deploy Ethereum node container", "err", err) - if len(out) > 0 { - fmt.Printf("%s\n", out) - } - return - } - // All ok, run a network scan to pick any changes up - log.Info("Waiting for node to finish booting") - time.Sleep(3 * time.Second) - - w.networkStats() -} diff --git a/go.mod b/go.mod index a370b0dcfa23..cf3d7e2e98fc 100644 --- a/go.mod +++ b/go.mod @@ -61,7 +61,6 @@ require ( golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 golang.org/x/sys v0.2.0 - golang.org/x/term v0.1.0 golang.org/x/text v0.4.0 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/tools v0.1.12 diff --git a/go.sum b/go.sum index 0413347a14a0..3c7e9202f62e 100644 --- a/go.sum +++ b/go.sum @@ -550,8 +550,6 @@ golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= From 5c8cc10d1e05c23ff1108022f4150749e73c0ca1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 1 Feb 2023 10:08:25 -0500 Subject: [PATCH 508/715] core: improve ambiguous block validation message (#26582) --- core/block_validator.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index 813ac0a4384d..7c202292f974 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -60,14 +60,14 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { return err } if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash { - return fmt.Errorf("uncle root hash mismatch: have %x, want %x", hash, header.UncleHash) + return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash) } if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash { - return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash) + return fmt.Errorf("transaction root hash mismatch (header value %x, calculated %x)", header.TxHash, hash) } if header.WithdrawalsHash != nil { if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash { - return fmt.Errorf("withdrawals root hash mismatch: have %x, want %x", hash, *header.WithdrawalsHash) + return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash) } } if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { From a8cf4399a90ce856bb9b5e24ff8249e1012ed3fe Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 2 Feb 2023 10:52:26 +0100 Subject: [PATCH 509/715] eth/catalyst: return invalid params instead of invalid payload params (#26591) --- core/beacon/errors.go | 1 + eth/catalyst/api.go | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/beacon/errors.go b/core/beacon/errors.go index 7a30d09bb064..24dc52278dcd 100644 --- a/core/beacon/errors.go +++ b/core/beacon/errors.go @@ -80,6 +80,7 @@ var ( UnknownPayload = &EngineAPIError{code: -38001, msg: "Unknown payload"} InvalidForkChoiceState = &EngineAPIError{code: -38002, msg: "Invalid forkchoice state"} InvalidPayloadAttributes = &EngineAPIError{code: -38003, msg: "Invalid payload attributes"} + InvalidParams = &EngineAPIError{code: -32602, msg: "Invalid parameters"} STATUS_INVALID = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: INVALID}, PayloadID: nil} STATUS_SYNCING = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: SYNCING}, PayloadID: nil} diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 96964b619522..c56e8bbaccaf 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -168,7 +168,7 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { // and return its payloadID. func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { if payloadAttributes != nil && payloadAttributes.Withdrawals != nil { - return beacon.STATUS_INVALID, fmt.Errorf("withdrawals not supported in V1") + return beacon.STATUS_INVALID, beacon.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1")) } return api.forkchoiceUpdated(update, payloadAttributes) } @@ -177,7 +177,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa func (api *ConsensusAPI) ForkchoiceUpdatedV2(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { if payloadAttributes != nil { if err := api.verifyPayloadAttributes(payloadAttributes); err != nil { - return beacon.STATUS_INVALID, beacon.InvalidPayloadAttributes.With(err) + return beacon.STATUS_INVALID, beacon.InvalidParams.With(err) } } return api.forkchoiceUpdated(update, payloadAttributes) From d0a4989a8def7e6bad182d1513e8d4a093c1672d Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 2 Feb 2023 12:52:19 +0100 Subject: [PATCH 510/715] cmd, eth, node: deprecate personal namespace (#26390) * eth: cmd: deprecate personal namespace * eth: cmd: move deprecation to node * node: disable toml of enablepersonal * node: disable personal on ipc as well * Update node/node.go Co-authored-by: Martin Holst Swende * console: error -> warn * node: less roulette --------- Co-authored-by: Martin Holst Swende --- cmd/geth/consolecmd.go | 4 ++-- cmd/geth/consolecmd_test.go | 2 +- cmd/geth/main.go | 1 + cmd/utils/flags.go | 10 ++++++++++ console/console.go | 3 ++- node/config.go | 3 +++ node/node.go | 20 ++++++++++++++++---- 7 files changed, 35 insertions(+), 8 deletions(-) diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index 83c6b66a8a60..23f6fd277c61 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -77,7 +77,7 @@ func localConsole(ctx *cli.Context) error { // Attach to the newly started node and create the JavaScript console. client, err := stack.Attach() if err != nil { - return fmt.Errorf("Failed to attach to the inproc geth: %v", err) + return fmt.Errorf("failed to attach to the inproc geth: %v", err) } config := console.Config{ DataDir: utils.MakeDataDir(ctx), @@ -87,7 +87,7 @@ func localConsole(ctx *cli.Context) error { } console, err := console.New(config) if err != nil { - return fmt.Errorf("Failed to start the JavaScript console: %v", err) + return fmt.Errorf("failed to start the JavaScript console: %v", err) } defer console.Stop(false) diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index a5a23ccdfd65..c5bdfa6ec8c4 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -30,7 +30,7 @@ import ( ) const ( - ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0" + ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0" httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0" ) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index e3ffcc5151b2..9998670e5dd4 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -65,6 +65,7 @@ var ( utils.USBFlag, utils.SmartCardDaemonPathFlag, utils.OverrideShanghai, + utils.EnablePersonal, utils.EthashCacheDirFlag, utils.EthashCachesInMemoryFlag, utils.EthashCachesOnDiskFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 597fc5603fc9..78b3cbee60b8 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -785,6 +785,11 @@ var ( Usage: "Allow for unprotected (non EIP155 signed) transactions to be submitted via RPC", Category: flags.APICategory, } + EnablePersonal = &cli.BoolFlag{ + Name: "rpc.enabledeprecatedpersonal", + Usage: "Enables the (deprecated) personal namespace", + Category: flags.APICategory, + } // Network Settings MaxPeersFlag = &cli.IntFlag{ @@ -1466,6 +1471,10 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { cfg.JWTSecret = ctx.String(JWTSecretFlag.Name) } + if ctx.IsSet(EnablePersonal.Name) { + cfg.EnablePersonal = true + } + if ctx.IsSet(ExternalSignerFlag.Name) { cfg.ExternalSigner = ctx.String(ExternalSignerFlag.Name) } @@ -1853,6 +1862,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.EthDiscoveryURLs = SplitAndTrim(urls) } } + // Override any default configs for hard coded networks. switch { case ctx.Bool(MainnetFlag.Name): diff --git a/console/console.go b/console/console.go index f72c3507244a..cdee53684ecf 100644 --- a/console/console.go +++ b/console/console.go @@ -215,7 +215,7 @@ func (c *Console) initExtensions() error { } // Compute aliases from server-provided modules. - aliases := map[string]struct{}{"eth": {}, "personal": {}} + aliases := map[string]struct{}{"eth": {}} for api := range apis { if api == "web3" { continue @@ -260,6 +260,7 @@ func (c *Console) initPersonal(vm *goja.Runtime, bridge *bridge) { if personal == nil || c.prompter == nil { return } + log.Warn("Enabling deprecated personal namespace") jeth := vm.NewObject() vm.Set("jeth", jeth) jeth.Set("openWallet", personal.Get("openWallet")) diff --git a/node/config.go b/node/config.go index e2099ee0f6ab..43ac824a0767 100644 --- a/node/config.go +++ b/node/config.go @@ -199,6 +199,9 @@ type Config struct { // JWTSecret is the path to the hex-encoded jwt secret. JWTSecret string `toml:",omitempty"` + + // EnablePersonal enables the deprecated personal namespace. + EnablePersonal bool `toml:"-"` } // IPCEndpoint resolves an IPC endpoint based on a configured value, taking into diff --git a/node/node.go b/node/node.go index 4d9072e2c96b..760e34d33597 100644 --- a/node/node.go +++ b/node/node.go @@ -376,13 +376,25 @@ func (n *Node) obtainJWTSecret(cliParam string) ([]byte, error) { // startup. It's not meant to be called at any time afterwards as it makes certain // assumptions about the state of the node. func (n *Node) startRPC() error { - if err := n.startInProc(); err != nil { + // Filter out personal api + var apis []rpc.API + for _, api := range n.rpcAPIs { + if api.Namespace == "personal" { + if n.config.EnablePersonal { + log.Warn("Deprecated personal namespace activated") + } else { + continue + } + } + apis = append(apis, api) + } + if err := n.startInProc(apis); err != nil { return err } // Configure IPC. if n.ipc.endpoint != "" { - if err := n.ipc.start(n.rpcAPIs); err != nil { + if err := n.ipc.start(apis); err != nil { return err } } @@ -510,8 +522,8 @@ func (n *Node) stopRPC() { } // startInProc registers all RPC APIs on the inproc server. -func (n *Node) startInProc() error { - for _, api := range n.rpcAPIs { +func (n *Node) startInProc(apis []rpc.API) error { + for _, api := range apis { if err := n.inprocHandler.RegisterName(api.Namespace, api.Service); err != nil { return err } From d9699c8238307d5c3081c12078f78527468d7dbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 3 Feb 2023 12:26:29 +0200 Subject: [PATCH 511/715] accounts, build, mobile: remove Andriod and iOS support --- .github/CODEOWNERS | 2 - .travis.yml | 69 ------ Makefile | 12 - accounts/abi/bind/bind.go | 178 +-------------- accounts/abi/bind/bind_test.go | 405 --------------------------------- accounts/abi/bind/template.go | 140 +----------- build/ci.go | 250 +------------------- build/mvn.pom | 57 ----- build/mvn.settings | 24 -- build/pod.podspec | 22 -- build/tools/tools.go | 4 - cmd/abigen/main.go | 7 +- go.mod | 1 - go.sum | 1 - mobile/accounts.go | 221 ------------------ mobile/android_test.go | 261 --------------------- mobile/big.go | 128 ----------- mobile/bind.go | 213 ----------------- mobile/common.go | 251 -------------------- mobile/context.go | 80 ------- mobile/discover.go | 104 --------- mobile/doc.go | 61 ----- mobile/ethclient.go | 315 ------------------------- mobile/ethereum.go | 157 ------------- mobile/geth.go | 253 -------------------- mobile/geth_android.go | 23 -- mobile/geth_ios.go | 23 -- mobile/geth_other.go | 23 -- mobile/init.go | 34 --- mobile/interface.go | 276 ---------------------- mobile/interface_test.go | 90 -------- mobile/logger.go | 28 --- mobile/p2p.go | 74 ------ mobile/params.go | 83 ------- mobile/primitives.go | 116 ---------- mobile/types.go | 377 ------------------------------ mobile/vm.go | 56 ----- 37 files changed, 13 insertions(+), 4406 deletions(-) delete mode 100644 build/mvn.pom delete mode 100644 build/mvn.settings delete mode 100644 build/pod.podspec delete mode 100644 mobile/accounts.go delete mode 100644 mobile/android_test.go delete mode 100644 mobile/big.go delete mode 100644 mobile/bind.go delete mode 100644 mobile/common.go delete mode 100644 mobile/context.go delete mode 100644 mobile/discover.go delete mode 100644 mobile/doc.go delete mode 100644 mobile/ethclient.go delete mode 100644 mobile/ethereum.go delete mode 100644 mobile/geth.go delete mode 100644 mobile/geth_android.go delete mode 100644 mobile/geth_ios.go delete mode 100644 mobile/geth_other.go delete mode 100644 mobile/init.go delete mode 100644 mobile/interface.go delete mode 100644 mobile/interface_test.go delete mode 100644 mobile/logger.go delete mode 100644 mobile/p2p.go delete mode 100644 mobile/params.go delete mode 100644 mobile/primitives.go delete mode 100644 mobile/types.go delete mode 100644 mobile/vm.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 89ddbc170242..780f2a800ec1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,7 +5,6 @@ accounts/usbwallet @karalabe accounts/scwallet @gballet accounts/abi @gballet @MariusVanDerWijden cmd/clef @holiman -cmd/puppeth @karalabe consensus @karalabe core/ @karalabe @holiman @rjl493456442 eth/ @karalabe @holiman @rjl493456442 @@ -14,7 +13,6 @@ eth/tracers/ @s1na graphql/ @gballet @s1na les/ @zsfelfoldi @rjl493456442 light/ @zsfelfoldi @rjl493456442 -mobile/ @karalabe @ligi node/ @fjl p2p/ @fjl @zsfelfoldi rpc/ @fjl @holiman diff --git a/.travis.yml b/.travis.yml index 1dc2c20a7a04..9209f1cba704 100644 --- a/.travis.yml +++ b/.travis.yml @@ -120,75 +120,6 @@ jobs: - go run build/ci.go install -dlgo -arch arm64 -cc aarch64-linux-gnu-gcc - go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - # This builder does the Android Maven and Azure uploads - - stage: build - if: type = push - os: linux - dist: bionic - addons: - apt: - packages: - - openjdk-8-jdk - env: - - azure-android - - maven-android - - GO111MODULE=on - git: - submodules: false # avoid cloning ethereum/tests - before_install: - # Install Android and it's dependencies manually, Travis is stale - - export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 - - curl https://dl.google.com/android/repository/commandlinetools-linux-6858069_latest.zip -o android.zip - - unzip -q android.zip -d $HOME/sdk && rm android.zip - - mv $HOME/sdk/cmdline-tools $HOME/sdk/latest && mkdir $HOME/sdk/cmdline-tools && mv $HOME/sdk/latest $HOME/sdk/cmdline-tools - - export PATH=$PATH:$HOME/sdk/cmdline-tools/latest/bin - - export ANDROID_HOME=$HOME/sdk - - - yes | sdkmanager --licenses >/dev/null - - sdkmanager "platform-tools" "platforms;android-15" "platforms;android-19" "platforms;android-24" "ndk-bundle" - - # Install Go to allow building with - - curl https://dl.google.com/go/go1.19.5.linux-amd64.tar.gz | tar -xz - - export PATH=`pwd`/go/bin:$PATH - - export GOROOT=`pwd`/go - - export GOPATH=$HOME/go - script: - # Build the Android archive and upload it to Maven Central and Azure - - mkdir -p $GOPATH/src/github.com/ethereum - - ln -s `pwd` $GOPATH/src/github.com/ethereum/go-ethereum - - go run build/ci.go aar -signer ANDROID_SIGNING_KEY -signify SIGNIFY_KEY -deploy https://oss.sonatype.org -upload gethstore/builds - - # This builder does the OSX Azure, iOS CocoaPods and iOS Azure uploads - - stage: build - if: type = push - os: osx - go: 1.19.x - env: - - azure-osx - - azure-ios - - cocoapods-ios - - GO111MODULE=on - git: - submodules: false # avoid cloning ethereum/tests - script: - - go run build/ci.go install -dlgo - - go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - - # Build the iOS framework and upload it to CocoaPods and Azure - - gem uninstall cocoapods -a -x - - gem install cocoapods - - - mv ~/.cocoapods/repos/master ~/.cocoapods/repos/master.bak - - sed -i '.bak' 's/repo.join/!repo.join/g' $(dirname `gem which cocoapods`)/cocoapods/sources_manager.rb - - if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git clone --depth=1 https://github.com/CocoaPods/Specs.git ~/.cocoapods/repos/master && pod setup --verbose; fi - - - xctool -version - - xcrun simctl list - - # Workaround for https://github.com/golang/go/issues/23749 - - export CGO_CFLAGS_ALLOW='-fmodules|-fblocks|-fobjc-arc' - - go run build/ci.go xcode -signer IOS_SIGNING_KEY -signify SIGNIFY_KEY -deploy trunk -upload gethstore/builds - # These builders run the tests - stage: build os: linux diff --git a/Makefile b/Makefile index e97acbef23e6..e6286da7fbae 100644 --- a/Makefile +++ b/Makefile @@ -16,18 +16,6 @@ geth: all: $(GORUN) build/ci.go install -android: - $(GORUN) build/ci.go aar --local - @echo "Done building." - @echo "Import \"$(GOBIN)/geth.aar\" to use the library." - @echo "Import \"$(GOBIN)/geth-sources.jar\" to add javadocs" - @echo "For more info see https://stackoverflow.com/questions/20994336/android-studio-how-to-attach-javadoc" - -ios: - $(GORUN) build/ci.go xcode --local - @echo "Done building." - @echo "Import \"$(GOBIN)/Geth.framework\" to use the library." - test: all $(GORUN) build/ci.go test diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index dac43f70e234..05cca8e90b3a 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -22,7 +22,6 @@ package bind import ( "bytes" - "errors" "fmt" "go/format" "regexp" @@ -39,8 +38,6 @@ type Lang int const ( LangGo Lang = iota - LangJava - LangObjC ) func isKeyWord(arg string) bool { @@ -221,11 +218,6 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] if evmABI.HasReceive() { receive = &tmplMethod{Original: evmABI.Receive} } - // There is no easy way to pass arbitrary java objects to the Go side. - if len(structs) > 0 && lang == LangJava { - return "", errors.New("java binding for tuple arguments is not supported yet") - } - contracts[types[i]] = &tmplContract{ Type: capitalise(types[i]), InputABI: strings.ReplaceAll(strippedABI, "\"", "\\\""), @@ -298,8 +290,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] // bindType is a set of type binders that convert Solidity types to some supported // programming language types. var bindType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{ - LangGo: bindTypeGo, - LangJava: bindTypeJava, + LangGo: bindTypeGo, } // bindBasicTypeGo converts basic solidity types(except array, slice and tuple) to Go ones. @@ -342,86 +333,10 @@ func bindTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { } } -// bindBasicTypeJava converts basic solidity types(except array, slice and tuple) to Java ones. -func bindBasicTypeJava(kind abi.Type) string { - switch kind.T { - case abi.AddressTy: - return "Address" - case abi.IntTy, abi.UintTy: - // Note that uint and int (without digits) are also matched, - // these are size 256, and will translate to BigInt (the default). - parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(kind.String()) - if len(parts) != 3 { - return kind.String() - } - // All unsigned integers should be translated to BigInt since gomobile doesn't - // support them. - if parts[1] == "u" { - return "BigInt" - } - - namedSize := map[string]string{ - "8": "byte", - "16": "short", - "32": "int", - "64": "long", - }[parts[2]] - - // default to BigInt - if namedSize == "" { - namedSize = "BigInt" - } - return namedSize - case abi.FixedBytesTy, abi.BytesTy: - return "byte[]" - case abi.BoolTy: - return "boolean" - case abi.StringTy: - return "String" - case abi.FunctionTy: - return "byte[24]" - default: - return kind.String() - } -} - -// pluralizeJavaType explicitly converts multidimensional types to predefined -// types in go side. -func pluralizeJavaType(typ string) string { - switch typ { - case "boolean": - return "Bools" - case "String": - return "Strings" - case "Address": - return "Addresses" - case "byte[]": - return "Binaries" - case "BigInt": - return "BigInts" - } - return typ + "[]" -} - -// bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping -// from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly -// mapped will use an upscaled type (e.g. BigDecimal). -func bindTypeJava(kind abi.Type, structs map[string]*tmplStruct) string { - switch kind.T { - case abi.TupleTy: - return structs[kind.TupleRawName+kind.String()].Name - case abi.ArrayTy, abi.SliceTy: - return pluralizeJavaType(bindTypeJava(*kind.Elem, structs)) - default: - return bindBasicTypeJava(kind) - } -} - // bindTopicType is a set of type binders that convert Solidity types to some // supported programming language topic types. var bindTopicType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{ - LangGo: bindTopicTypeGo, - LangJava: bindTopicTypeJava, + LangGo: bindTopicTypeGo, } // bindTopicTypeGo converts a Solidity topic type to a Go one. It is almost the same @@ -441,28 +356,10 @@ func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { return bound } -// bindTopicTypeJava converts a Solidity topic type to a Java one. It is almost the same -// functionality as for simple types, but dynamic types get converted to hashes. -func bindTopicTypeJava(kind abi.Type, structs map[string]*tmplStruct) string { - bound := bindTypeJava(kind, structs) - - // todo(rjl493456442) according solidity documentation, indexed event - // parameters that are not value types i.e. arrays and structs are not - // stored directly but instead a keccak256-hash of an encoding is stored. - // - // We only convert strings and bytes to hash, still need to deal with - // array(both fixed-size and dynamic-size) and struct. - if bound == "String" || bound == "byte[]" { - bound = "Hash" - } - return bound -} - // bindStructType is a set of type binders that convert Solidity tuple types to some supported // programming language struct definition. var bindStructType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{ - LangGo: bindStructTypeGo, - LangJava: bindStructTypeJava, + LangGo: bindStructTypeGo, } // bindStructTypeGo converts a Solidity tuple type to a Go one and records the mapping @@ -511,74 +408,10 @@ func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { } } -// bindStructTypeJava converts a Solidity tuple type to a Java one and records the mapping -// in the given map. -// Notably, this function will resolve and record nested struct recursively. -func bindStructTypeJava(kind abi.Type, structs map[string]*tmplStruct) string { - switch kind.T { - case abi.TupleTy: - // We compose a raw struct name and a canonical parameter expression - // together here. The reason is before solidity v0.5.11, kind.TupleRawName - // is empty, so we use canonical parameter expression to distinguish - // different struct definition. From the consideration of backward - // compatibility, we concat these two together so that if kind.TupleRawName - // is not empty, it can have unique id. - id := kind.TupleRawName + kind.String() - if s, exist := structs[id]; exist { - return s.Name - } - var fields []*tmplField - for i, elem := range kind.TupleElems { - field := bindStructTypeJava(*elem, structs) - fields = append(fields, &tmplField{Type: field, Name: decapitalise(kind.TupleRawNames[i]), SolKind: *elem}) - } - name := kind.TupleRawName - if name == "" { - name = fmt.Sprintf("Class%d", len(structs)) - } - structs[id] = &tmplStruct{ - Name: name, - Fields: fields, - } - return name - case abi.ArrayTy, abi.SliceTy: - return pluralizeJavaType(bindStructTypeJava(*kind.Elem, structs)) - default: - return bindBasicTypeJava(kind) - } -} - // namedType is a set of functions that transform language specific types to // named versions that may be used inside method names. var namedType = map[Lang]func(string, abi.Type) string{ - LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") }, - LangJava: namedTypeJava, -} - -// namedTypeJava converts some primitive data types to named variants that can -// be used as parts of method names. -func namedTypeJava(javaKind string, solKind abi.Type) string { - switch javaKind { - case "byte[]": - return "Binary" - case "boolean": - return "Bool" - default: - parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String()) - if len(parts) != 4 { - return javaKind - } - switch parts[2] { - case "8", "16", "32", "64": - if parts[3] == "" { - return capitalise(fmt.Sprintf("%sint%s", parts[1], parts[2])) - } - return capitalise(fmt.Sprintf("%sint%ss", parts[1], parts[2])) - - default: - return javaKind - } - } + LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") }, } // alias returns an alias of the given string based on the aliasing rules @@ -593,8 +426,7 @@ func alias(aliases map[string]string, n string) string { // methodNormalizer is a name transformer that modifies Solidity method names to // conform to target language naming conventions. var methodNormalizer = map[Lang]func(string) string{ - LangGo: abi.ToCamelCase, - LangJava: decapitalise, + LangGo: abi.ToCamelCase, } // capitalise makes a camel-case string which starts with an upper case character. diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 5fa803849df6..cbbce7b30889 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -2115,408 +2115,3 @@ func TestGolangBindings(t *testing.T) { t.Fatalf("failed to run binding test: %v\n%s", err, out) } } - -// Tests that java binding generated by the binder is exactly matched. -func TestJavaBindings(t *testing.T) { - var cases = []struct { - name string - contract string - abi string - bytecode string - expected string - }{ - { - "test", - ` - pragma experimental ABIEncoderV2; - pragma solidity ^0.5.2; - - contract test { - function setAddress(address a) public returns(address){} - function setAddressList(address[] memory a_l) public returns(address[] memory){} - function setAddressArray(address[2] memory a_a) public returns(address[2] memory){} - - function setUint8(uint8 u8) public returns(uint8){} - function setUint16(uint16 u16) public returns(uint16){} - function setUint32(uint32 u32) public returns(uint32){} - function setUint64(uint64 u64) public returns(uint64){} - function setUint256(uint256 u256) public returns(uint256){} - function setUint256List(uint256[] memory u256_l) public returns(uint256[] memory){} - function setUint256Array(uint256[2] memory u256_a) public returns(uint256[2] memory){} - - function setInt8(int8 i8) public returns(int8){} - function setInt16(int16 i16) public returns(int16){} - function setInt32(int32 i32) public returns(int32){} - function setInt64(int64 i64) public returns(int64){} - function setInt256(int256 i256) public returns(int256){} - function setInt256List(int256[] memory i256_l) public returns(int256[] memory){} - function setInt256Array(int256[2] memory i256_a) public returns(int256[2] memory){} - - function setBytes1(bytes1 b1) public returns(bytes1) {} - function setBytes32(bytes32 b32) public returns(bytes32) {} - function setBytes(bytes memory bs) public returns(bytes memory) {} - function setBytesList(bytes[] memory bs_l) public returns(bytes[] memory) {} - function setBytesArray(bytes[2] memory bs_a) public returns(bytes[2] memory) {} - - function setString(string memory s) public returns(string memory) {} - function setStringList(string[] memory s_l) public returns(string[] memory) {} - function setStringArray(string[2] memory s_a) public returns(string[2] memory) {} - - function setBool(bool b) public returns(bool) {} - function setBoolList(bool[] memory b_l) public returns(bool[] memory) {} - function setBoolArray(bool[2] memory b_a) public returns(bool[2] memory) {} - }`, - `[{"constant":false,"inputs":[{"name":"u16","type":"uint16"}],"name":"setUint16","outputs":[{"name":"","type":"uint16"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"b_a","type":"bool[2]"}],"name":"setBoolArray","outputs":[{"name":"","type":"bool[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"a_a","type":"address[2]"}],"name":"setAddressArray","outputs":[{"name":"","type":"address[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"bs_l","type":"bytes[]"}],"name":"setBytesList","outputs":[{"name":"","type":"bytes[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"u8","type":"uint8"}],"name":"setUint8","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"u32","type":"uint32"}],"name":"setUint32","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"b","type":"bool"}],"name":"setBool","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i256_l","type":"int256[]"}],"name":"setInt256List","outputs":[{"name":"","type":"int256[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"u256_a","type":"uint256[2]"}],"name":"setUint256Array","outputs":[{"name":"","type":"uint256[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"b_l","type":"bool[]"}],"name":"setBoolList","outputs":[{"name":"","type":"bool[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"bs_a","type":"bytes[2]"}],"name":"setBytesArray","outputs":[{"name":"","type":"bytes[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"a_l","type":"address[]"}],"name":"setAddressList","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i256_a","type":"int256[2]"}],"name":"setInt256Array","outputs":[{"name":"","type":"int256[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"s_a","type":"string[2]"}],"name":"setStringArray","outputs":[{"name":"","type":"string[2]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"s","type":"string"}],"name":"setString","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"u64","type":"uint64"}],"name":"setUint64","outputs":[{"name":"","type":"uint64"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i16","type":"int16"}],"name":"setInt16","outputs":[{"name":"","type":"int16"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i8","type":"int8"}],"name":"setInt8","outputs":[{"name":"","type":"int8"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"u256_l","type":"uint256[]"}],"name":"setUint256List","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i256","type":"int256"}],"name":"setInt256","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i32","type":"int32"}],"name":"setInt32","outputs":[{"name":"","type":"int32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"b32","type":"bytes32"}],"name":"setBytes32","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"s_l","type":"string[]"}],"name":"setStringList","outputs":[{"name":"","type":"string[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"u256","type":"uint256"}],"name":"setUint256","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"bs","type":"bytes"}],"name":"setBytes","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"a","type":"address"}],"name":"setAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i64","type":"int64"}],"name":"setInt64","outputs":[{"name":"","type":"int64"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"b1","type":"bytes1"}],"name":"setBytes1","outputs":[{"name":"","type":"bytes1"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`, - `608060405234801561001057600080fd5b5061265a806100206000396000f3fe608060405234801561001057600080fd5b50600436106101e1576000357c0100000000000000000000000000000000000000000000000000000000900480637fcaf66611610116578063c2b12a73116100b4578063da359dc81161008e578063da359dc814610666578063e30081a014610696578063e673eb32146106c6578063fba1a1c3146106f6576101e1565b8063c2b12a73146105d6578063c577796114610606578063d2282dc514610636576101e1565b80639a19a953116100f05780639a19a95314610516578063a0709e1914610546578063a53b1c1e14610576578063b7d5df31146105a6576101e1565b80637fcaf66614610486578063822cba69146104b657806386114cea146104e6576101e1565b806322722302116101835780635119655d1161015d5780635119655d146103c65780635be6b37e146103f65780636aa482fc146104265780637173b69514610456576101e1565b806322722302146103365780632766a755146103665780634d5ee6da14610396576101e1565b806316c105e2116101bf57806316c105e2146102765780631774e646146102a65780631c9352e2146102d65780631e26fd3314610306576101e1565b80630477988a146101e6578063118a971814610216578063151f547114610246575b600080fd5b61020060048036036101fb9190810190611599565b610726565b60405161020d9190611f01565b60405180910390f35b610230600480360361022b919081019061118d565b61072d565b60405161023d9190611ca6565b60405180910390f35b610260600480360361025b9190810190611123565b61073a565b60405161026d9190611c69565b60405180910390f35b610290600480360361028b9190810190611238565b610747565b60405161029d9190611d05565b60405180910390f35b6102c060048036036102bb919081019061163d565b61074e565b6040516102cd9190611f6d565b60405180910390f35b6102f060048036036102eb91908101906115eb565b610755565b6040516102fd9190611f37565b60405180910390f35b610320600480360361031b91908101906113cf565b61075c565b60405161032d9190611de5565b60405180910390f35b610350600480360361034b91908101906112a2565b610763565b60405161035d9190611d42565b60405180910390f35b610380600480360361037b9190810190611365565b61076a565b60405161038d9190611da8565b60405180910390f35b6103b060048036036103ab91908101906111b6565b610777565b6040516103bd9190611cc1565b60405180910390f35b6103e060048036036103db91908101906111f7565b61077e565b6040516103ed9190611ce3565b60405180910390f35b610410600480360361040b919081019061114c565b61078b565b60405161041d9190611c84565b60405180910390f35b610440600480360361043b9190810190611279565b610792565b60405161044d9190611d27565b60405180910390f35b610470600480360361046b91908101906112e3565b61079f565b60405161047d9190611d64565b60405180910390f35b6104a0600480360361049b9190810190611558565b6107ac565b6040516104ad9190611edf565b60405180910390f35b6104d060048036036104cb9190810190611614565b6107b3565b6040516104dd9190611f52565b60405180910390f35b61050060048036036104fb919081019061148b565b6107ba565b60405161050d9190611e58565b60405180910390f35b610530600480360361052b919081019061152f565b6107c1565b60405161053d9190611ec4565b60405180910390f35b610560600480360361055b919081019061138e565b6107c8565b60405161056d9190611dc3565b60405180910390f35b610590600480360361058b91908101906114b4565b6107cf565b60405161059d9190611e73565b60405180910390f35b6105c060048036036105bb91908101906114dd565b6107d6565b6040516105cd9190611e8e565b60405180910390f35b6105f060048036036105eb9190810190611421565b6107dd565b6040516105fd9190611e1b565b60405180910390f35b610620600480360361061b9190810190611324565b6107e4565b60405161062d9190611d86565b60405180910390f35b610650600480360361064b91908101906115c2565b6107eb565b60405161065d9190611f1c565b60405180910390f35b610680600480360361067b919081019061144a565b6107f2565b60405161068d9190611e36565b60405180910390f35b6106b060048036036106ab91908101906110fa565b6107f9565b6040516106bd9190611c4e565b60405180910390f35b6106e060048036036106db9190810190611506565b610800565b6040516106ed9190611ea9565b60405180910390f35b610710600480360361070b91908101906113f8565b610807565b60405161071d9190611e00565b60405180910390f35b6000919050565b61073561080e565b919050565b610742610830565b919050565b6060919050565b6000919050565b6000919050565b6000919050565b6060919050565b610772610852565b919050565b6060919050565b610786610874565b919050565b6060919050565b61079a61089b565b919050565b6107a76108bd565b919050565b6060919050565b6000919050565b6000919050565b6000919050565b6060919050565b6000919050565b6000919050565b6000919050565b6060919050565b6000919050565b6060919050565b6000919050565b6000919050565b6000919050565b6040805190810160405280600290602082028038833980820191505090505090565b6040805190810160405280600290602082028038833980820191505090505090565b6040805190810160405280600290602082028038833980820191505090505090565b60408051908101604052806002905b60608152602001906001900390816108835790505090565b6040805190810160405280600290602082028038833980820191505090505090565b60408051908101604052806002905b60608152602001906001900390816108cc5790505090565b60006108f082356124f2565b905092915050565b600082601f830112151561090b57600080fd5b600261091e61091982611fb5565b611f88565b9150818385602084028201111561093457600080fd5b60005b83811015610964578161094a88826108e4565b845260208401935060208301925050600181019050610937565b5050505092915050565b600082601f830112151561098157600080fd5b813561099461098f82611fd7565b611f88565b915081818352602084019350602081019050838560208402820111156109b957600080fd5b60005b838110156109e957816109cf88826108e4565b8452602084019350602083019250506001810190506109bc565b5050505092915050565b600082601f8301121515610a0657600080fd5b6002610a19610a1482611fff565b611f88565b91508183856020840282011115610a2f57600080fd5b60005b83811015610a5f5781610a458882610e9e565b845260208401935060208301925050600181019050610a32565b5050505092915050565b600082601f8301121515610a7c57600080fd5b8135610a8f610a8a82612021565b611f88565b91508181835260208401935060208101905083856020840282011115610ab457600080fd5b60005b83811015610ae45781610aca8882610e9e565b845260208401935060208301925050600181019050610ab7565b5050505092915050565b600082601f8301121515610b0157600080fd5b6002610b14610b0f82612049565b611f88565b9150818360005b83811015610b4b5781358601610b318882610eda565b845260208401935060208301925050600181019050610b1b565b5050505092915050565b600082601f8301121515610b6857600080fd5b8135610b7b610b768261206b565b611f88565b9150818183526020840193506020810190508360005b83811015610bc15781358601610ba78882610eda565b845260208401935060208301925050600181019050610b91565b5050505092915050565b600082601f8301121515610bde57600080fd5b6002610bf1610bec82612093565b611f88565b91508183856020840282011115610c0757600080fd5b60005b83811015610c375781610c1d8882610f9a565b845260208401935060208301925050600181019050610c0a565b5050505092915050565b600082601f8301121515610c5457600080fd5b8135610c67610c62826120b5565b611f88565b91508181835260208401935060208101905083856020840282011115610c8c57600080fd5b60005b83811015610cbc5781610ca28882610f9a565b845260208401935060208301925050600181019050610c8f565b5050505092915050565b600082601f8301121515610cd957600080fd5b6002610cec610ce7826120dd565b611f88565b9150818360005b83811015610d235781358601610d098882610fea565b845260208401935060208301925050600181019050610cf3565b5050505092915050565b600082601f8301121515610d4057600080fd5b8135610d53610d4e826120ff565b611f88565b9150818183526020840193506020810190508360005b83811015610d995781358601610d7f8882610fea565b845260208401935060208301925050600181019050610d69565b5050505092915050565b600082601f8301121515610db657600080fd5b6002610dc9610dc482612127565b611f88565b91508183856020840282011115610ddf57600080fd5b60005b83811015610e0f5781610df588826110aa565b845260208401935060208301925050600181019050610de2565b5050505092915050565b600082601f8301121515610e2c57600080fd5b8135610e3f610e3a82612149565b611f88565b91508181835260208401935060208101905083856020840282011115610e6457600080fd5b60005b83811015610e945781610e7a88826110aa565b845260208401935060208301925050600181019050610e67565b5050505092915050565b6000610eaa8235612504565b905092915050565b6000610ebe8235612510565b905092915050565b6000610ed2823561253c565b905092915050565b600082601f8301121515610eed57600080fd5b8135610f00610efb82612171565b611f88565b91508082526020830160208301858383011115610f1c57600080fd5b610f278382846125cd565b50505092915050565b600082601f8301121515610f4357600080fd5b8135610f56610f518261219d565b611f88565b91508082526020830160208301858383011115610f7257600080fd5b610f7d8382846125cd565b50505092915050565b6000610f928235612546565b905092915050565b6000610fa68235612553565b905092915050565b6000610fba823561255d565b905092915050565b6000610fce823561256a565b905092915050565b6000610fe28235612577565b905092915050565b600082601f8301121515610ffd57600080fd5b813561101061100b826121c9565b611f88565b9150808252602083016020830185838301111561102c57600080fd5b6110378382846125cd565b50505092915050565b600082601f830112151561105357600080fd5b8135611066611061826121f5565b611f88565b9150808252602083016020830185838301111561108257600080fd5b61108d8382846125cd565b50505092915050565b60006110a28235612584565b905092915050565b60006110b68235612592565b905092915050565b60006110ca823561259c565b905092915050565b60006110de82356125ac565b905092915050565b60006110f282356125c0565b905092915050565b60006020828403121561110c57600080fd5b600061111a848285016108e4565b91505092915050565b60006040828403121561113557600080fd5b6000611143848285016108f8565b91505092915050565b60006020828403121561115e57600080fd5b600082013567ffffffffffffffff81111561117857600080fd5b6111848482850161096e565b91505092915050565b60006040828403121561119f57600080fd5b60006111ad848285016109f3565b91505092915050565b6000602082840312156111c857600080fd5b600082013567ffffffffffffffff8111156111e257600080fd5b6111ee84828501610a69565b91505092915050565b60006020828403121561120957600080fd5b600082013567ffffffffffffffff81111561122357600080fd5b61122f84828501610aee565b91505092915050565b60006020828403121561124a57600080fd5b600082013567ffffffffffffffff81111561126457600080fd5b61127084828501610b55565b91505092915050565b60006040828403121561128b57600080fd5b600061129984828501610bcb565b91505092915050565b6000602082840312156112b457600080fd5b600082013567ffffffffffffffff8111156112ce57600080fd5b6112da84828501610c41565b91505092915050565b6000602082840312156112f557600080fd5b600082013567ffffffffffffffff81111561130f57600080fd5b61131b84828501610cc6565b91505092915050565b60006020828403121561133657600080fd5b600082013567ffffffffffffffff81111561135057600080fd5b61135c84828501610d2d565b91505092915050565b60006040828403121561137757600080fd5b600061138584828501610da3565b91505092915050565b6000602082840312156113a057600080fd5b600082013567ffffffffffffffff8111156113ba57600080fd5b6113c684828501610e19565b91505092915050565b6000602082840312156113e157600080fd5b60006113ef84828501610e9e565b91505092915050565b60006020828403121561140a57600080fd5b600061141884828501610eb2565b91505092915050565b60006020828403121561143357600080fd5b600061144184828501610ec6565b91505092915050565b60006020828403121561145c57600080fd5b600082013567ffffffffffffffff81111561147657600080fd5b61148284828501610f30565b91505092915050565b60006020828403121561149d57600080fd5b60006114ab84828501610f86565b91505092915050565b6000602082840312156114c657600080fd5b60006114d484828501610f9a565b91505092915050565b6000602082840312156114ef57600080fd5b60006114fd84828501610fae565b91505092915050565b60006020828403121561151857600080fd5b600061152684828501610fc2565b91505092915050565b60006020828403121561154157600080fd5b600061154f84828501610fd6565b91505092915050565b60006020828403121561156a57600080fd5b600082013567ffffffffffffffff81111561158457600080fd5b61159084828501611040565b91505092915050565b6000602082840312156115ab57600080fd5b60006115b984828501611096565b91505092915050565b6000602082840312156115d457600080fd5b60006115e2848285016110aa565b91505092915050565b6000602082840312156115fd57600080fd5b600061160b848285016110be565b91505092915050565b60006020828403121561162657600080fd5b6000611634848285016110d2565b91505092915050565b60006020828403121561164f57600080fd5b600061165d848285016110e6565b91505092915050565b61166f816123f7565b82525050565b61167e816122ab565b61168782612221565b60005b828110156116b95761169d858351611666565b6116a68261235b565b915060208501945060018101905061168a565b5050505050565b60006116cb826122b6565b8084526020840193506116dd8361222b565b60005b8281101561170f576116f3868351611666565b6116fc82612368565b91506020860195506001810190506116e0565b50849250505092915050565b611724816122c1565b61172d82612238565b60005b8281101561175f57611743858351611ab3565b61174c82612375565b9150602085019450600181019050611730565b5050505050565b6000611771826122cc565b80845260208401935061178383612242565b60005b828110156117b557611799868351611ab3565b6117a282612382565b9150602086019550600181019050611786565b50849250505092915050565b60006117cc826122d7565b836020820285016117dc8561224f565b60005b848110156118155783830388526117f7838351611b16565b92506118028261238f565b91506020880197506001810190506117df565b508196508694505050505092915050565b6000611831826122e2565b8084526020840193508360208202850161184a85612259565b60005b84811015611883578383038852611865838351611b16565b92506118708261239c565b915060208801975060018101905061184d565b508196508694505050505092915050565b61189d816122ed565b6118a682612266565b60005b828110156118d8576118bc858351611b5b565b6118c5826123a9565b91506020850194506001810190506118a9565b5050505050565b60006118ea826122f8565b8084526020840193506118fc83612270565b60005b8281101561192e57611912868351611b5b565b61191b826123b6565b91506020860195506001810190506118ff565b50849250505092915050565b600061194582612303565b836020820285016119558561227d565b60005b8481101561198e578383038852611970838351611bcd565b925061197b826123c3565b9150602088019750600181019050611958565b508196508694505050505092915050565b60006119aa8261230e565b808452602084019350836020820285016119c385612287565b60005b848110156119fc5783830388526119de838351611bcd565b92506119e9826123d0565b91506020880197506001810190506119c6565b508196508694505050505092915050565b611a1681612319565b611a1f82612294565b60005b82811015611a5157611a35858351611c12565b611a3e826123dd565b9150602085019450600181019050611a22565b5050505050565b6000611a6382612324565b808452602084019350611a758361229e565b60005b82811015611aa757611a8b868351611c12565b611a94826123ea565b9150602086019550600181019050611a78565b50849250505092915050565b611abc81612409565b82525050565b611acb81612415565b82525050565b611ada81612441565b82525050565b6000611aeb8261233a565b808452611aff8160208601602086016125dc565b611b088161260f565b602085010191505092915050565b6000611b218261232f565b808452611b358160208601602086016125dc565b611b3e8161260f565b602085010191505092915050565b611b558161244b565b82525050565b611b6481612458565b82525050565b611b7381612462565b82525050565b611b828161246f565b82525050565b611b918161247c565b82525050565b6000611ba282612350565b808452611bb68160208601602086016125dc565b611bbf8161260f565b602085010191505092915050565b6000611bd882612345565b808452611bec8160208601602086016125dc565b611bf58161260f565b602085010191505092915050565b611c0c81612489565b82525050565b611c1b816124b7565b82525050565b611c2a816124c1565b82525050565b611c39816124d1565b82525050565b611c48816124e5565b82525050565b6000602082019050611c636000830184611666565b92915050565b6000604082019050611c7e6000830184611675565b92915050565b60006020820190508181036000830152611c9e81846116c0565b905092915050565b6000604082019050611cbb600083018461171b565b92915050565b60006020820190508181036000830152611cdb8184611766565b905092915050565b60006020820190508181036000830152611cfd81846117c1565b905092915050565b60006020820190508181036000830152611d1f8184611826565b905092915050565b6000604082019050611d3c6000830184611894565b92915050565b60006020820190508181036000830152611d5c81846118df565b905092915050565b60006020820190508181036000830152611d7e818461193a565b905092915050565b60006020820190508181036000830152611da0818461199f565b905092915050565b6000604082019050611dbd6000830184611a0d565b92915050565b60006020820190508181036000830152611ddd8184611a58565b905092915050565b6000602082019050611dfa6000830184611ab3565b92915050565b6000602082019050611e156000830184611ac2565b92915050565b6000602082019050611e306000830184611ad1565b92915050565b60006020820190508181036000830152611e508184611ae0565b905092915050565b6000602082019050611e6d6000830184611b4c565b92915050565b6000602082019050611e886000830184611b5b565b92915050565b6000602082019050611ea36000830184611b6a565b92915050565b6000602082019050611ebe6000830184611b79565b92915050565b6000602082019050611ed96000830184611b88565b92915050565b60006020820190508181036000830152611ef98184611b97565b905092915050565b6000602082019050611f166000830184611c03565b92915050565b6000602082019050611f316000830184611c12565b92915050565b6000602082019050611f4c6000830184611c21565b92915050565b6000602082019050611f676000830184611c30565b92915050565b6000602082019050611f826000830184611c3f565b92915050565b6000604051905081810181811067ffffffffffffffff82111715611fab57600080fd5b8060405250919050565b600067ffffffffffffffff821115611fcc57600080fd5b602082029050919050565b600067ffffffffffffffff821115611fee57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561201657600080fd5b602082029050919050565b600067ffffffffffffffff82111561203857600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561206057600080fd5b602082029050919050565b600067ffffffffffffffff82111561208257600080fd5b602082029050602081019050919050565b600067ffffffffffffffff8211156120aa57600080fd5b602082029050919050565b600067ffffffffffffffff8211156120cc57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff8211156120f457600080fd5b602082029050919050565b600067ffffffffffffffff82111561211657600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561213e57600080fd5b602082029050919050565b600067ffffffffffffffff82111561216057600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561218857600080fd5b601f19601f8301169050602081019050919050565b600067ffffffffffffffff8211156121b457600080fd5b601f19601f8301169050602081019050919050565b600067ffffffffffffffff8211156121e057600080fd5b601f19601f8301169050602081019050919050565b600067ffffffffffffffff82111561220c57600080fd5b601f19601f8301169050602081019050919050565b6000819050919050565b6000602082019050919050565b6000819050919050565b6000602082019050919050565b6000819050919050565b6000602082019050919050565b6000819050919050565b6000602082019050919050565b6000819050919050565b6000602082019050919050565b6000819050919050565b6000602082019050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b600061240282612497565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b60008160010b9050919050565b6000819050919050565b60008160030b9050919050565b60008160070b9050919050565b60008160000b9050919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600063ffffffff82169050919050565b600067ffffffffffffffff82169050919050565b600060ff82169050919050565b60006124fd82612497565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b60008160010b9050919050565b6000819050919050565b60008160030b9050919050565b60008160070b9050919050565b60008160000b9050919050565b600061ffff82169050919050565b6000819050919050565b600063ffffffff82169050919050565b600067ffffffffffffffff82169050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b838110156125fa5780820151818401526020810190506125df565b83811115612609576000848401525b50505050565b6000601f19601f830116905091905056fea265627a7a723058206fe37171cf1b10ebd291cfdca61d67e7fc3c208795e999c833c42a14d86cf00d6c6578706572696d656e74616cf50037`, - ` -// This file is an automatically generated Java binding. Do not modify as any -// change will likely be lost upon the next re-generation! - -package bindtest; - -import org.ethereum.geth.*; -import java.util.*; - -public class Test { - // ABI is the input ABI used to generate the binding from. - public final static String ABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"u16\",\"type\":\"uint16\"}],\"name\":\"setUint16\",\"outputs\":[{\"name\":\"\",\"type\":\"uint16\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b_a\",\"type\":\"bool[2]\"}],\"name\":\"setBoolArray\",\"outputs\":[{\"name\":\"\",\"type\":\"bool[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a_a\",\"type\":\"address[2]\"}],\"name\":\"setAddressArray\",\"outputs\":[{\"name\":\"\",\"type\":\"address[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bs_l\",\"type\":\"bytes[]\"}],\"name\":\"setBytesList\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u8\",\"type\":\"uint8\"}],\"name\":\"setUint8\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u32\",\"type\":\"uint32\"}],\"name\":\"setUint32\",\"outputs\":[{\"name\":\"\",\"type\":\"uint32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b\",\"type\":\"bool\"}],\"name\":\"setBool\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i256_l\",\"type\":\"int256[]\"}],\"name\":\"setInt256List\",\"outputs\":[{\"name\":\"\",\"type\":\"int256[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u256_a\",\"type\":\"uint256[2]\"}],\"name\":\"setUint256Array\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b_l\",\"type\":\"bool[]\"}],\"name\":\"setBoolList\",\"outputs\":[{\"name\":\"\",\"type\":\"bool[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bs_a\",\"type\":\"bytes[2]\"}],\"name\":\"setBytesArray\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a_l\",\"type\":\"address[]\"}],\"name\":\"setAddressList\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i256_a\",\"type\":\"int256[2]\"}],\"name\":\"setInt256Array\",\"outputs\":[{\"name\":\"\",\"type\":\"int256[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"s_a\",\"type\":\"string[2]\"}],\"name\":\"setStringArray\",\"outputs\":[{\"name\":\"\",\"type\":\"string[2]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"s\",\"type\":\"string\"}],\"name\":\"setString\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u64\",\"type\":\"uint64\"}],\"name\":\"setUint64\",\"outputs\":[{\"name\":\"\",\"type\":\"uint64\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i16\",\"type\":\"int16\"}],\"name\":\"setInt16\",\"outputs\":[{\"name\":\"\",\"type\":\"int16\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i8\",\"type\":\"int8\"}],\"name\":\"setInt8\",\"outputs\":[{\"name\":\"\",\"type\":\"int8\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u256_l\",\"type\":\"uint256[]\"}],\"name\":\"setUint256List\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i256\",\"type\":\"int256\"}],\"name\":\"setInt256\",\"outputs\":[{\"name\":\"\",\"type\":\"int256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i32\",\"type\":\"int32\"}],\"name\":\"setInt32\",\"outputs\":[{\"name\":\"\",\"type\":\"int32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b32\",\"type\":\"bytes32\"}],\"name\":\"setBytes32\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"s_l\",\"type\":\"string[]\"}],\"name\":\"setStringList\",\"outputs\":[{\"name\":\"\",\"type\":\"string[]\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"u256\",\"type\":\"uint256\"}],\"name\":\"setUint256\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bs\",\"type\":\"bytes\"}],\"name\":\"setBytes\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"a\",\"type\":\"address\"}],\"name\":\"setAddress\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"i64\",\"type\":\"int64\"}],\"name\":\"setInt64\",\"outputs\":[{\"name\":\"\",\"type\":\"int64\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"b1\",\"type\":\"bytes1\"}],\"name\":\"setBytes1\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes1\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"; - - // BYTECODE is the compiled bytecode used for deploying new contracts. - public final static String BYTECODE = "0x608060405234801561001057600080fd5b5061265a806100206000396000f3fe608060405234801561001057600080fd5b50600436106101e1576000357c0100000000000000000000000000000000000000000000000000000000900480637fcaf66611610116578063c2b12a73116100b4578063da359dc81161008e578063da359dc814610666578063e30081a014610696578063e673eb32146106c6578063fba1a1c3146106f6576101e1565b8063c2b12a73146105d6578063c577796114610606578063d2282dc514610636576101e1565b80639a19a953116100f05780639a19a95314610516578063a0709e1914610546578063a53b1c1e14610576578063b7d5df31146105a6576101e1565b80637fcaf66614610486578063822cba69146104b657806386114cea146104e6576101e1565b806322722302116101835780635119655d1161015d5780635119655d146103c65780635be6b37e146103f65780636aa482fc146104265780637173b69514610456576101e1565b806322722302146103365780632766a755146103665780634d5ee6da14610396576101e1565b806316c105e2116101bf57806316c105e2146102765780631774e646146102a65780631c9352e2146102d65780631e26fd3314610306576101e1565b80630477988a146101e6578063118a971814610216578063151f547114610246575b600080fd5b61020060048036036101fb9190810190611599565b610726565b60405161020d9190611f01565b60405180910390f35b610230600480360361022b919081019061118d565b61072d565b60405161023d9190611ca6565b60405180910390f35b610260600480360361025b9190810190611123565b61073a565b60405161026d9190611c69565b60405180910390f35b610290600480360361028b9190810190611238565b610747565b60405161029d9190611d05565b60405180910390f35b6102c060048036036102bb919081019061163d565b61074e565b6040516102cd9190611f6d565b60405180910390f35b6102f060048036036102eb91908101906115eb565b610755565b6040516102fd9190611f37565b60405180910390f35b610320600480360361031b91908101906113cf565b61075c565b60405161032d9190611de5565b60405180910390f35b610350600480360361034b91908101906112a2565b610763565b60405161035d9190611d42565b60405180910390f35b610380600480360361037b9190810190611365565b61076a565b60405161038d9190611da8565b60405180910390f35b6103b060048036036103ab91908101906111b6565b610777565b6040516103bd9190611cc1565b60405180910390f35b6103e060048036036103db91908101906111f7565b61077e565b6040516103ed9190611ce3565b60405180910390f35b610410600480360361040b919081019061114c565b61078b565b60405161041d9190611c84565b60405180910390f35b610440600480360361043b9190810190611279565b610792565b60405161044d9190611d27565b60405180910390f35b610470600480360361046b91908101906112e3565b61079f565b60405161047d9190611d64565b60405180910390f35b6104a0600480360361049b9190810190611558565b6107ac565b6040516104ad9190611edf565b60405180910390f35b6104d060048036036104cb9190810190611614565b6107b3565b6040516104dd9190611f52565b60405180910390f35b61050060048036036104fb919081019061148b565b6107ba565b60405161050d9190611e58565b60405180910390f35b610530600480360361052b919081019061152f565b6107c1565b60405161053d9190611ec4565b60405180910390f35b610560600480360361055b919081019061138e565b6107c8565b60405161056d9190611dc3565b60405180910390f35b610590600480360361058b91908101906114b4565b6107cf565b60405161059d9190611e73565b60405180910390f35b6105c060048036036105bb91908101906114dd565b6107d6565b6040516105cd9190611e8e565b60405180910390f35b6105f060048036036105eb9190810190611421565b6107dd565b6040516105fd9190611e1b565b60405180910390f35b610620600480360361061b9190810190611324565b6107e4565b60405161062d9190611d86565b60405180910390f35b610650600480360361064b91908101906115c2565b6107eb565b60405161065d9190611f1c565b60405180910390f35b610680600480360361067b919081019061144a565b6107f2565b60405161068d9190611e36565b60405180910390f35b6106b060048036036106ab91908101906110fa565b6107f9565b6040516106bd9190611c4e565b60405180910390f35b6106e060048036036106db9190810190611506565b610800565b6040516106ed9190611ea9565b60405180910390f35b610710600480360361070b91908101906113f8565b610807565b60405161071d9190611e00565b60405180910390f35b6000919050565b61073561080e565b919050565b610742610830565b919050565b6060919050565b6000919050565b6000919050565b6000919050565b6060919050565b610772610852565b919050565b6060919050565b610786610874565b919050565b6060919050565b61079a61089b565b919050565b6107a76108bd565b919050565b6060919050565b6000919050565b6000919050565b6000919050565b6060919050565b6000919050565b6000919050565b6000919050565b6060919050565b6000919050565b6060919050565b6000919050565b6000919050565b6000919050565b6040805190810160405280600290602082028038833980820191505090505090565b6040805190810160405280600290602082028038833980820191505090505090565b6040805190810160405280600290602082028038833980820191505090505090565b60408051908101604052806002905b60608152602001906001900390816108835790505090565b6040805190810160405280600290602082028038833980820191505090505090565b60408051908101604052806002905b60608152602001906001900390816108cc5790505090565b60006108f082356124f2565b905092915050565b600082601f830112151561090b57600080fd5b600261091e61091982611fb5565b611f88565b9150818385602084028201111561093457600080fd5b60005b83811015610964578161094a88826108e4565b845260208401935060208301925050600181019050610937565b5050505092915050565b600082601f830112151561098157600080fd5b813561099461098f82611fd7565b611f88565b915081818352602084019350602081019050838560208402820111156109b957600080fd5b60005b838110156109e957816109cf88826108e4565b8452602084019350602083019250506001810190506109bc565b5050505092915050565b600082601f8301121515610a0657600080fd5b6002610a19610a1482611fff565b611f88565b91508183856020840282011115610a2f57600080fd5b60005b83811015610a5f5781610a458882610e9e565b845260208401935060208301925050600181019050610a32565b5050505092915050565b600082601f8301121515610a7c57600080fd5b8135610a8f610a8a82612021565b611f88565b91508181835260208401935060208101905083856020840282011115610ab457600080fd5b60005b83811015610ae45781610aca8882610e9e565b845260208401935060208301925050600181019050610ab7565b5050505092915050565b600082601f8301121515610b0157600080fd5b6002610b14610b0f82612049565b611f88565b9150818360005b83811015610b4b5781358601610b318882610eda565b845260208401935060208301925050600181019050610b1b565b5050505092915050565b600082601f8301121515610b6857600080fd5b8135610b7b610b768261206b565b611f88565b9150818183526020840193506020810190508360005b83811015610bc15781358601610ba78882610eda565b845260208401935060208301925050600181019050610b91565b5050505092915050565b600082601f8301121515610bde57600080fd5b6002610bf1610bec82612093565b611f88565b91508183856020840282011115610c0757600080fd5b60005b83811015610c375781610c1d8882610f9a565b845260208401935060208301925050600181019050610c0a565b5050505092915050565b600082601f8301121515610c5457600080fd5b8135610c67610c62826120b5565b611f88565b91508181835260208401935060208101905083856020840282011115610c8c57600080fd5b60005b83811015610cbc5781610ca28882610f9a565b845260208401935060208301925050600181019050610c8f565b5050505092915050565b600082601f8301121515610cd957600080fd5b6002610cec610ce7826120dd565b611f88565b9150818360005b83811015610d235781358601610d098882610fea565b845260208401935060208301925050600181019050610cf3565b5050505092915050565b600082601f8301121515610d4057600080fd5b8135610d53610d4e826120ff565b611f88565b9150818183526020840193506020810190508360005b83811015610d995781358601610d7f8882610fea565b845260208401935060208301925050600181019050610d69565b5050505092915050565b600082601f8301121515610db657600080fd5b6002610dc9610dc482612127565b611f88565b91508183856020840282011115610ddf57600080fd5b60005b83811015610e0f5781610df588826110aa565b845260208401935060208301925050600181019050610de2565b5050505092915050565b600082601f8301121515610e2c57600080fd5b8135610e3f610e3a82612149565b611f88565b91508181835260208401935060208101905083856020840282011115610e6457600080fd5b60005b83811015610e945781610e7a88826110aa565b845260208401935060208301925050600181019050610e67565b5050505092915050565b6000610eaa8235612504565b905092915050565b6000610ebe8235612510565b905092915050565b6000610ed2823561253c565b905092915050565b600082601f8301121515610eed57600080fd5b8135610f00610efb82612171565b611f88565b91508082526020830160208301858383011115610f1c57600080fd5b610f278382846125cd565b50505092915050565b600082601f8301121515610f4357600080fd5b8135610f56610f518261219d565b611f88565b91508082526020830160208301858383011115610f7257600080fd5b610f7d8382846125cd565b50505092915050565b6000610f928235612546565b905092915050565b6000610fa68235612553565b905092915050565b6000610fba823561255d565b905092915050565b6000610fce823561256a565b905092915050565b6000610fe28235612577565b905092915050565b600082601f8301121515610ffd57600080fd5b813561101061100b826121c9565b611f88565b9150808252602083016020830185838301111561102c57600080fd5b6110378382846125cd565b50505092915050565b600082601f830112151561105357600080fd5b8135611066611061826121f5565b611f88565b9150808252602083016020830185838301111561108257600080fd5b61108d8382846125cd565b50505092915050565b60006110a28235612584565b905092915050565b60006110b68235612592565b905092915050565b60006110ca823561259c565b905092915050565b60006110de82356125ac565b905092915050565b60006110f282356125c0565b905092915050565b60006020828403121561110c57600080fd5b600061111a848285016108e4565b91505092915050565b60006040828403121561113557600080fd5b6000611143848285016108f8565b91505092915050565b60006020828403121561115e57600080fd5b600082013567ffffffffffffffff81111561117857600080fd5b6111848482850161096e565b91505092915050565b60006040828403121561119f57600080fd5b60006111ad848285016109f3565b91505092915050565b6000602082840312156111c857600080fd5b600082013567ffffffffffffffff8111156111e257600080fd5b6111ee84828501610a69565b91505092915050565b60006020828403121561120957600080fd5b600082013567ffffffffffffffff81111561122357600080fd5b61122f84828501610aee565b91505092915050565b60006020828403121561124a57600080fd5b600082013567ffffffffffffffff81111561126457600080fd5b61127084828501610b55565b91505092915050565b60006040828403121561128b57600080fd5b600061129984828501610bcb565b91505092915050565b6000602082840312156112b457600080fd5b600082013567ffffffffffffffff8111156112ce57600080fd5b6112da84828501610c41565b91505092915050565b6000602082840312156112f557600080fd5b600082013567ffffffffffffffff81111561130f57600080fd5b61131b84828501610cc6565b91505092915050565b60006020828403121561133657600080fd5b600082013567ffffffffffffffff81111561135057600080fd5b61135c84828501610d2d565b91505092915050565b60006040828403121561137757600080fd5b600061138584828501610da3565b91505092915050565b6000602082840312156113a057600080fd5b600082013567ffffffffffffffff8111156113ba57600080fd5b6113c684828501610e19565b91505092915050565b6000602082840312156113e157600080fd5b60006113ef84828501610e9e565b91505092915050565b60006020828403121561140a57600080fd5b600061141884828501610eb2565b91505092915050565b60006020828403121561143357600080fd5b600061144184828501610ec6565b91505092915050565b60006020828403121561145c57600080fd5b600082013567ffffffffffffffff81111561147657600080fd5b61148284828501610f30565b91505092915050565b60006020828403121561149d57600080fd5b60006114ab84828501610f86565b91505092915050565b6000602082840312156114c657600080fd5b60006114d484828501610f9a565b91505092915050565b6000602082840312156114ef57600080fd5b60006114fd84828501610fae565b91505092915050565b60006020828403121561151857600080fd5b600061152684828501610fc2565b91505092915050565b60006020828403121561154157600080fd5b600061154f84828501610fd6565b91505092915050565b60006020828403121561156a57600080fd5b600082013567ffffffffffffffff81111561158457600080fd5b61159084828501611040565b91505092915050565b6000602082840312156115ab57600080fd5b60006115b984828501611096565b91505092915050565b6000602082840312156115d457600080fd5b60006115e2848285016110aa565b91505092915050565b6000602082840312156115fd57600080fd5b600061160b848285016110be565b91505092915050565b60006020828403121561162657600080fd5b6000611634848285016110d2565b91505092915050565b60006020828403121561164f57600080fd5b600061165d848285016110e6565b91505092915050565b61166f816123f7565b82525050565b61167e816122ab565b61168782612221565b60005b828110156116b95761169d858351611666565b6116a68261235b565b915060208501945060018101905061168a565b5050505050565b60006116cb826122b6565b8084526020840193506116dd8361222b565b60005b8281101561170f576116f3868351611666565b6116fc82612368565b91506020860195506001810190506116e0565b50849250505092915050565b611724816122c1565b61172d82612238565b60005b8281101561175f57611743858351611ab3565b61174c82612375565b9150602085019450600181019050611730565b5050505050565b6000611771826122cc565b80845260208401935061178383612242565b60005b828110156117b557611799868351611ab3565b6117a282612382565b9150602086019550600181019050611786565b50849250505092915050565b60006117cc826122d7565b836020820285016117dc8561224f565b60005b848110156118155783830388526117f7838351611b16565b92506118028261238f565b91506020880197506001810190506117df565b508196508694505050505092915050565b6000611831826122e2565b8084526020840193508360208202850161184a85612259565b60005b84811015611883578383038852611865838351611b16565b92506118708261239c565b915060208801975060018101905061184d565b508196508694505050505092915050565b61189d816122ed565b6118a682612266565b60005b828110156118d8576118bc858351611b5b565b6118c5826123a9565b91506020850194506001810190506118a9565b5050505050565b60006118ea826122f8565b8084526020840193506118fc83612270565b60005b8281101561192e57611912868351611b5b565b61191b826123b6565b91506020860195506001810190506118ff565b50849250505092915050565b600061194582612303565b836020820285016119558561227d565b60005b8481101561198e578383038852611970838351611bcd565b925061197b826123c3565b9150602088019750600181019050611958565b508196508694505050505092915050565b60006119aa8261230e565b808452602084019350836020820285016119c385612287565b60005b848110156119fc5783830388526119de838351611bcd565b92506119e9826123d0565b91506020880197506001810190506119c6565b508196508694505050505092915050565b611a1681612319565b611a1f82612294565b60005b82811015611a5157611a35858351611c12565b611a3e826123dd565b9150602085019450600181019050611a22565b5050505050565b6000611a6382612324565b808452602084019350611a758361229e565b60005b82811015611aa757611a8b868351611c12565b611a94826123ea565b9150602086019550600181019050611a78565b50849250505092915050565b611abc81612409565b82525050565b611acb81612415565b82525050565b611ada81612441565b82525050565b6000611aeb8261233a565b808452611aff8160208601602086016125dc565b611b088161260f565b602085010191505092915050565b6000611b218261232f565b808452611b358160208601602086016125dc565b611b3e8161260f565b602085010191505092915050565b611b558161244b565b82525050565b611b6481612458565b82525050565b611b7381612462565b82525050565b611b828161246f565b82525050565b611b918161247c565b82525050565b6000611ba282612350565b808452611bb68160208601602086016125dc565b611bbf8161260f565b602085010191505092915050565b6000611bd882612345565b808452611bec8160208601602086016125dc565b611bf58161260f565b602085010191505092915050565b611c0c81612489565b82525050565b611c1b816124b7565b82525050565b611c2a816124c1565b82525050565b611c39816124d1565b82525050565b611c48816124e5565b82525050565b6000602082019050611c636000830184611666565b92915050565b6000604082019050611c7e6000830184611675565b92915050565b60006020820190508181036000830152611c9e81846116c0565b905092915050565b6000604082019050611cbb600083018461171b565b92915050565b60006020820190508181036000830152611cdb8184611766565b905092915050565b60006020820190508181036000830152611cfd81846117c1565b905092915050565b60006020820190508181036000830152611d1f8184611826565b905092915050565b6000604082019050611d3c6000830184611894565b92915050565b60006020820190508181036000830152611d5c81846118df565b905092915050565b60006020820190508181036000830152611d7e818461193a565b905092915050565b60006020820190508181036000830152611da0818461199f565b905092915050565b6000604082019050611dbd6000830184611a0d565b92915050565b60006020820190508181036000830152611ddd8184611a58565b905092915050565b6000602082019050611dfa6000830184611ab3565b92915050565b6000602082019050611e156000830184611ac2565b92915050565b6000602082019050611e306000830184611ad1565b92915050565b60006020820190508181036000830152611e508184611ae0565b905092915050565b6000602082019050611e6d6000830184611b4c565b92915050565b6000602082019050611e886000830184611b5b565b92915050565b6000602082019050611ea36000830184611b6a565b92915050565b6000602082019050611ebe6000830184611b79565b92915050565b6000602082019050611ed96000830184611b88565b92915050565b60006020820190508181036000830152611ef98184611b97565b905092915050565b6000602082019050611f166000830184611c03565b92915050565b6000602082019050611f316000830184611c12565b92915050565b6000602082019050611f4c6000830184611c21565b92915050565b6000602082019050611f676000830184611c30565b92915050565b6000602082019050611f826000830184611c3f565b92915050565b6000604051905081810181811067ffffffffffffffff82111715611fab57600080fd5b8060405250919050565b600067ffffffffffffffff821115611fcc57600080fd5b602082029050919050565b600067ffffffffffffffff821115611fee57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561201657600080fd5b602082029050919050565b600067ffffffffffffffff82111561203857600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561206057600080fd5b602082029050919050565b600067ffffffffffffffff82111561208257600080fd5b602082029050602081019050919050565b600067ffffffffffffffff8211156120aa57600080fd5b602082029050919050565b600067ffffffffffffffff8211156120cc57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff8211156120f457600080fd5b602082029050919050565b600067ffffffffffffffff82111561211657600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561213e57600080fd5b602082029050919050565b600067ffffffffffffffff82111561216057600080fd5b602082029050602081019050919050565b600067ffffffffffffffff82111561218857600080fd5b601f19601f8301169050602081019050919050565b600067ffffffffffffffff8211156121b457600080fd5b601f19601f8301169050602081019050919050565b600067ffffffffffffffff8211156121e057600080fd5b601f19601f8301169050602081019050919050565b600067ffffffffffffffff82111561220c57600080fd5b601f19601f8301169050602081019050919050565b6000819050919050565b6000602082019050919050565b6000819050919050565b6000602082019050919050565b6000819050919050565b6000602082019050919050565b6000819050919050565b6000602082019050919050565b6000819050919050565b6000602082019050919050565b6000819050919050565b6000602082019050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b600061240282612497565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b60008160010b9050919050565b6000819050919050565b60008160030b9050919050565b60008160070b9050919050565b60008160000b9050919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600063ffffffff82169050919050565b600067ffffffffffffffff82169050919050565b600060ff82169050919050565b60006124fd82612497565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b60008160010b9050919050565b6000819050919050565b60008160030b9050919050565b60008160070b9050919050565b60008160000b9050919050565b600061ffff82169050919050565b6000819050919050565b600063ffffffff82169050919050565b600067ffffffffffffffff82169050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b838110156125fa5780820151818401526020810190506125df565b83811115612609576000848401525b50505050565b6000601f19601f830116905091905056fea265627a7a723058206fe37171cf1b10ebd291cfdca61d67e7fc3c208795e999c833c42a14d86cf00d6c6578706572696d656e74616cf50037"; - - // deploy deploys a new Ethereum contract, binding an instance of Test to it. - public static Test deploy(TransactOpts auth, EthereumClient client) throws Exception { - Interfaces args = Geth.newInterfaces(0); - String bytecode = BYTECODE; - return new Test(Geth.deployContract(auth, ABI, Geth.decodeFromHex(bytecode), client, args)); - } - - // Internal constructor used by contract deployment. - private Test(BoundContract deployment) { - this.Address = deployment.getAddress(); - this.Deployer = deployment.getDeployer(); - this.Contract = deployment; - } - - // Ethereum address where this contract is located at. - public final Address Address; - - // Ethereum transaction in which this contract was deployed (if known!). - public final Transaction Deployer; - - // Contract instance bound to a blockchain address. - private final BoundContract Contract; - - // Creates a new instance of Test, bound to a specific deployed contract. - public Test(Address address, EthereumClient client) throws Exception { - this(Geth.bindContract(address, ABI, client)); - } - - // setAddress is a paid mutator transaction binding the contract method 0xe30081a0. - // - // Solidity: function setAddress(address a) returns(address) - public Transaction setAddress(TransactOpts opts, Address a) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setAddress(a);args.set(0,arg0); - - return this.Contract.transact(opts, "setAddress" , args); - } - - // setAddressArray is a paid mutator transaction binding the contract method 0x151f5471. - // - // Solidity: function setAddressArray(address[2] a_a) returns(address[2]) - public Transaction setAddressArray(TransactOpts opts, Addresses a_a) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setAddresses(a_a);args.set(0,arg0); - - return this.Contract.transact(opts, "setAddressArray" , args); - } - - // setAddressList is a paid mutator transaction binding the contract method 0x5be6b37e. - // - // Solidity: function setAddressList(address[] a_l) returns(address[]) - public Transaction setAddressList(TransactOpts opts, Addresses a_l) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setAddresses(a_l);args.set(0,arg0); - - return this.Contract.transact(opts, "setAddressList" , args); - } - - // setBool is a paid mutator transaction binding the contract method 0x1e26fd33. - // - // Solidity: function setBool(bool b) returns(bool) - public Transaction setBool(TransactOpts opts, boolean b) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBool(b);args.set(0,arg0); - - return this.Contract.transact(opts, "setBool" , args); - } - - // setBoolArray is a paid mutator transaction binding the contract method 0x118a9718. - // - // Solidity: function setBoolArray(bool[2] b_a) returns(bool[2]) - public Transaction setBoolArray(TransactOpts opts, Bools b_a) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBools(b_a);args.set(0,arg0); - - return this.Contract.transact(opts, "setBoolArray" , args); - } - - // setBoolList is a paid mutator transaction binding the contract method 0x4d5ee6da. - // - // Solidity: function setBoolList(bool[] b_l) returns(bool[]) - public Transaction setBoolList(TransactOpts opts, Bools b_l) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBools(b_l);args.set(0,arg0); - - return this.Contract.transact(opts, "setBoolList" , args); - } - - // setBytes is a paid mutator transaction binding the contract method 0xda359dc8. - // - // Solidity: function setBytes(bytes bs) returns(bytes) - public Transaction setBytes(TransactOpts opts, byte[] bs) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBinary(bs);args.set(0,arg0); - - return this.Contract.transact(opts, "setBytes" , args); - } - - // setBytes1 is a paid mutator transaction binding the contract method 0xfba1a1c3. - // - // Solidity: function setBytes1(bytes1 b1) returns(bytes1) - public Transaction setBytes1(TransactOpts opts, byte[] b1) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBinary(b1);args.set(0,arg0); - - return this.Contract.transact(opts, "setBytes1" , args); - } - - // setBytes32 is a paid mutator transaction binding the contract method 0xc2b12a73. - // - // Solidity: function setBytes32(bytes32 b32) returns(bytes32) - public Transaction setBytes32(TransactOpts opts, byte[] b32) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBinary(b32);args.set(0,arg0); - - return this.Contract.transact(opts, "setBytes32" , args); - } - - // setBytesArray is a paid mutator transaction binding the contract method 0x5119655d. - // - // Solidity: function setBytesArray(bytes[2] bs_a) returns(bytes[2]) - public Transaction setBytesArray(TransactOpts opts, Binaries bs_a) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBinaries(bs_a);args.set(0,arg0); - - return this.Contract.transact(opts, "setBytesArray" , args); - } - - // setBytesList is a paid mutator transaction binding the contract method 0x16c105e2. - // - // Solidity: function setBytesList(bytes[] bs_l) returns(bytes[]) - public Transaction setBytesList(TransactOpts opts, Binaries bs_l) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBinaries(bs_l);args.set(0,arg0); - - return this.Contract.transact(opts, "setBytesList" , args); - } - - // setInt16 is a paid mutator transaction binding the contract method 0x86114cea. - // - // Solidity: function setInt16(int16 i16) returns(int16) - public Transaction setInt16(TransactOpts opts, short i16) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setInt16(i16);args.set(0,arg0); - - return this.Contract.transact(opts, "setInt16" , args); - } - - // setInt256 is a paid mutator transaction binding the contract method 0xa53b1c1e. - // - // Solidity: function setInt256(int256 i256) returns(int256) - public Transaction setInt256(TransactOpts opts, BigInt i256) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBigInt(i256);args.set(0,arg0); - - return this.Contract.transact(opts, "setInt256" , args); - } - - // setInt256Array is a paid mutator transaction binding the contract method 0x6aa482fc. - // - // Solidity: function setInt256Array(int256[2] i256_a) returns(int256[2]) - public Transaction setInt256Array(TransactOpts opts, BigInts i256_a) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBigInts(i256_a);args.set(0,arg0); - - return this.Contract.transact(opts, "setInt256Array" , args); - } - - // setInt256List is a paid mutator transaction binding the contract method 0x22722302. - // - // Solidity: function setInt256List(int256[] i256_l) returns(int256[]) - public Transaction setInt256List(TransactOpts opts, BigInts i256_l) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBigInts(i256_l);args.set(0,arg0); - - return this.Contract.transact(opts, "setInt256List" , args); - } - - // setInt32 is a paid mutator transaction binding the contract method 0xb7d5df31. - // - // Solidity: function setInt32(int32 i32) returns(int32) - public Transaction setInt32(TransactOpts opts, int i32) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setInt32(i32);args.set(0,arg0); - - return this.Contract.transact(opts, "setInt32" , args); - } - - // setInt64 is a paid mutator transaction binding the contract method 0xe673eb32. - // - // Solidity: function setInt64(int64 i64) returns(int64) - public Transaction setInt64(TransactOpts opts, long i64) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setInt64(i64);args.set(0,arg0); - - return this.Contract.transact(opts, "setInt64" , args); - } - - // setInt8 is a paid mutator transaction binding the contract method 0x9a19a953. - // - // Solidity: function setInt8(int8 i8) returns(int8) - public Transaction setInt8(TransactOpts opts, byte i8) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setInt8(i8);args.set(0,arg0); - - return this.Contract.transact(opts, "setInt8" , args); - } - - // setString is a paid mutator transaction binding the contract method 0x7fcaf666. - // - // Solidity: function setString(string s) returns(string) - public Transaction setString(TransactOpts opts, String s) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setString(s);args.set(0,arg0); - - return this.Contract.transact(opts, "setString" , args); - } - - // setStringArray is a paid mutator transaction binding the contract method 0x7173b695. - // - // Solidity: function setStringArray(string[2] s_a) returns(string[2]) - public Transaction setStringArray(TransactOpts opts, Strings s_a) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setStrings(s_a);args.set(0,arg0); - - return this.Contract.transact(opts, "setStringArray" , args); - } - - // setStringList is a paid mutator transaction binding the contract method 0xc5777961. - // - // Solidity: function setStringList(string[] s_l) returns(string[]) - public Transaction setStringList(TransactOpts opts, Strings s_l) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setStrings(s_l);args.set(0,arg0); - - return this.Contract.transact(opts, "setStringList" , args); - } - - // setUint16 is a paid mutator transaction binding the contract method 0x0477988a. - // - // Solidity: function setUint16(uint16 u16) returns(uint16) - public Transaction setUint16(TransactOpts opts, BigInt u16) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setUint16(u16);args.set(0,arg0); - - return this.Contract.transact(opts, "setUint16" , args); - } - - // setUint256 is a paid mutator transaction binding the contract method 0xd2282dc5. - // - // Solidity: function setUint256(uint256 u256) returns(uint256) - public Transaction setUint256(TransactOpts opts, BigInt u256) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBigInt(u256);args.set(0,arg0); - - return this.Contract.transact(opts, "setUint256" , args); - } - - // setUint256Array is a paid mutator transaction binding the contract method 0x2766a755. - // - // Solidity: function setUint256Array(uint256[2] u256_a) returns(uint256[2]) - public Transaction setUint256Array(TransactOpts opts, BigInts u256_a) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBigInts(u256_a);args.set(0,arg0); - - return this.Contract.transact(opts, "setUint256Array" , args); - } - - // setUint256List is a paid mutator transaction binding the contract method 0xa0709e19. - // - // Solidity: function setUint256List(uint256[] u256_l) returns(uint256[]) - public Transaction setUint256List(TransactOpts opts, BigInts u256_l) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setBigInts(u256_l);args.set(0,arg0); - - return this.Contract.transact(opts, "setUint256List" , args); - } - - // setUint32 is a paid mutator transaction binding the contract method 0x1c9352e2. - // - // Solidity: function setUint32(uint32 u32) returns(uint32) - public Transaction setUint32(TransactOpts opts, BigInt u32) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setUint32(u32);args.set(0,arg0); - - return this.Contract.transact(opts, "setUint32" , args); - } - - // setUint64 is a paid mutator transaction binding the contract method 0x822cba69. - // - // Solidity: function setUint64(uint64 u64) returns(uint64) - public Transaction setUint64(TransactOpts opts, BigInt u64) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setUint64(u64);args.set(0,arg0); - - return this.Contract.transact(opts, "setUint64" , args); - } - - // setUint8 is a paid mutator transaction binding the contract method 0x1774e646. - // - // Solidity: function setUint8(uint8 u8) returns(uint8) - public Transaction setUint8(TransactOpts opts, BigInt u8) throws Exception { - Interfaces args = Geth.newInterfaces(1); - Interface arg0 = Geth.newInterface();arg0.setUint8(u8);args.set(0,arg0); - - return this.Contract.transact(opts, "setUint8" , args); - } -} -`, - }, - } - for i, c := range cases { - binding, err := Bind([]string{c.name}, []string{c.abi}, []string{c.bytecode}, nil, "bindtest", LangJava, nil, nil) - if err != nil { - t.Fatalf("test %d: failed to generate binding: %v", i, err) - } - // Remove empty lines - removeEmptys := func(input string) string { - lines := strings.Split(input, "\n") - var index int - for _, line := range lines { - if strings.TrimSpace(line) != "" { - lines[index] = line - index += 1 - } - } - lines = lines[:index] - return strings.Join(lines, "\n") - } - binding = removeEmptys(binding) - expect := removeEmptys(c.expected) - if binding != expect { - t.Fatalf("test %d: generated binding mismatch, has %s, want %s", i, binding, c.expected) - } - } -} diff --git a/accounts/abi/bind/template.go b/accounts/abi/bind/template.go index 855c8ead87ca..c22eb4ae8432 100644 --- a/accounts/abi/bind/template.go +++ b/accounts/abi/bind/template.go @@ -75,8 +75,7 @@ type tmplStruct struct { // tmplSource is language to template mapping containing all the supported // programming languages the package can generate to. var tmplSource = map[Lang]string{ - LangGo: tmplSourceGo, - LangJava: tmplSourceJava, + LangGo: tmplSourceGo, } // tmplSourceGo is the Go source template that the generated Go contract binding @@ -570,140 +569,3 @@ var ( {{end}} {{end}} ` - -// tmplSourceJava is the Java source template that the generated Java contract binding -// is based on. -const tmplSourceJava = ` -// This file is an automatically generated Java binding. Do not modify as any -// change will likely be lost upon the next re-generation! - -package {{.Package}}; - -import org.ethereum.geth.*; -import java.util.*; - -{{$structs := .Structs}} -{{range $contract := .Contracts}} -{{if not .Library}}public {{end}}class {{.Type}} { - // ABI is the input ABI used to generate the binding from. - public final static String ABI = "{{.InputABI}}"; - {{if $contract.FuncSigs}} - // {{.Type}}FuncSigs maps the 4-byte function signature to its string representation. - public final static Map {{.Type}}FuncSigs; - static { - Hashtable temp = new Hashtable(); - {{range $strsig, $binsig := .FuncSigs}}temp.put("{{$binsig}}", "{{$strsig}}"); - {{end}} - {{.Type}}FuncSigs = Collections.unmodifiableMap(temp); - } - {{end}} - {{if .InputBin}} - // BYTECODE is the compiled bytecode used for deploying new contracts. - public final static String BYTECODE = "0x{{.InputBin}}"; - - // deploy deploys a new Ethereum contract, binding an instance of {{.Type}} to it. - public static {{.Type}} deploy(TransactOpts auth, EthereumClient client{{range .Constructor.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception { - Interfaces args = Geth.newInterfaces({{(len .Constructor.Inputs)}}); - String bytecode = BYTECODE; - {{if .Libraries}} - - // "link" contract to dependent libraries by deploying them first. - {{range $pattern, $name := .Libraries}} - {{capitalise $name}} {{decapitalise $name}}Inst = {{capitalise $name}}.deploy(auth, client); - bytecode = bytecode.replace("__${{$pattern}}$__", {{decapitalise $name}}Inst.Address.getHex().substring(2)); - {{end}} - {{end}} - {{range $index, $element := .Constructor.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type $structs) .Type}}({{.Name}});args.set({{$index}},arg{{$index}}); - {{end}} - return new {{.Type}}(Geth.deployContract(auth, ABI, Geth.decodeFromHex(bytecode), client, args)); - } - - // Internal constructor used by contract deployment. - private {{.Type}}(BoundContract deployment) { - this.Address = deployment.getAddress(); - this.Deployer = deployment.getDeployer(); - this.Contract = deployment; - } - {{end}} - - // Ethereum address where this contract is located at. - public final Address Address; - - // Ethereum transaction in which this contract was deployed (if known!). - public final Transaction Deployer; - - // Contract instance bound to a blockchain address. - private final BoundContract Contract; - - // Creates a new instance of {{.Type}}, bound to a specific deployed contract. - public {{.Type}}(Address address, EthereumClient client) throws Exception { - this(Geth.bindContract(address, ABI, client)); - } - - {{range .Calls}} - {{if gt (len .Normalized.Outputs) 1}} - // {{capitalise .Normalized.Name}}Results is the output of a call to {{.Normalized.Name}}. - public class {{capitalise .Normalized.Name}}Results { - {{range $index, $item := .Normalized.Outputs}}public {{bindtype .Type $structs}} {{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}}; - {{end}} - } - {{end}} - - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - public {{if gt (len .Normalized.Outputs) 1}}{{capitalise .Normalized.Name}}Results{{else if eq (len .Normalized.Outputs) 0}}void{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}}{{end}}{{end}} {{.Normalized.Name}}(CallOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception { - Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}}); - {{range $index, $item := .Normalized.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type $structs) .Type}}({{.Name}});args.set({{$index}},arg{{$index}}); - {{end}} - - Interfaces results = Geth.newInterfaces({{(len .Normalized.Outputs)}}); - {{range $index, $item := .Normalized.Outputs}}Interface result{{$index}} = Geth.newInterface(); result{{$index}}.setDefault{{namedtype (bindtype .Type $structs) .Type}}(); results.set({{$index}}, result{{$index}}); - {{end}} - - if (opts == null) { - opts = Geth.newCallOpts(); - } - this.Contract.call(opts, results, "{{.Original.Name}}", args); - {{if gt (len .Normalized.Outputs) 1}} - {{capitalise .Normalized.Name}}Results result = new {{capitalise .Normalized.Name}}Results(); - {{range $index, $item := .Normalized.Outputs}}result.{{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}} = results.get({{$index}}).get{{namedtype (bindtype .Type $structs) .Type}}(); - {{end}} - return result; - {{else}}{{range .Normalized.Outputs}}return results.get(0).get{{namedtype (bindtype .Type $structs) .Type}}();{{end}} - {{end}} - } - {{end}} - - {{range .Transacts}} - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - public Transaction {{.Normalized.Name}}(TransactOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type $structs}} {{.Name}}{{end}}) throws Exception { - Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}}); - {{range $index, $item := .Normalized.Inputs}}Interface arg{{$index}} = Geth.newInterface();arg{{$index}}.set{{namedtype (bindtype .Type $structs) .Type}}({{.Name}});args.set({{$index}},arg{{$index}}); - {{end}} - return this.Contract.transact(opts, "{{.Original.Name}}" , args); - } - {{end}} - - {{if .Fallback}} - // Fallback is a paid mutator transaction binding the contract fallback function. - // - // Solidity: {{.Fallback.Original.String}} - public Transaction Fallback(TransactOpts opts, byte[] calldata) throws Exception { - return this.Contract.rawTransact(opts, calldata); - } - {{end}} - - {{if .Receive}} - // Receive is a paid mutator transaction binding the contract receive function. - // - // Solidity: {{.Receive.Original.String}} - public Transaction Receive(TransactOpts opts) throws Exception { - return this.Contract.rawTransact(opts, null); - } - {{end}} -} -{{end}} -` diff --git a/build/ci.go b/build/ci.go index bd265865fd22..06aaae2da38a 100644 --- a/build/ci.go +++ b/build/ci.go @@ -31,8 +31,6 @@ Available commands are: importkeys -- imports signing keys from env debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package nsis -- creates a Windows NSIS installer - aar [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an Android archive - xcode [ -local ] [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an iOS XCode framework purge [ -store blobstore ] [ -days threshold ] -- purges old archives from the blobstore For all commands, -n prevents execution of external programs (dry run mode). @@ -40,7 +38,6 @@ For all commands, -n prevents execution of external programs (dry run mode). package main import ( - "bufio" "bytes" "encoding/base64" "flag" @@ -50,7 +47,6 @@ import ( "os/exec" "path" "path/filepath" - "regexp" "runtime" "strconv" "strings" @@ -126,12 +122,12 @@ var ( // Note: the following Ubuntu releases have been officially deprecated on Launchpad: // wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy, hirsuite, impish debDistroGoBoots = map[string]string{ - "trusty": "golang-1.11", // EOL: 04/2024 - "xenial": "golang-go", // EOL: 04/2026 - "bionic": "golang-go", // EOL: 04/2028 - "focal": "golang-go", // EOL: 04/2030 - "jammy": "golang-go", // EOL: 04/2032 - "kinetic": "golang-go", // EOL: 07/2023 + "trusty": "golang-1.11", // EOL: 04/2024 + "xenial": "golang-go", // EOL: 04/2026 + "bionic": "golang-go", // EOL: 04/2028 + "focal": "golang-go", // EOL: 04/2030 + "jammy": "golang-go", // EOL: 04/2032 + "kinetic": "golang-go", // EOL: 07/2023 //"lunar": "golang-go", // EOL: 01/2024 } @@ -179,10 +175,6 @@ func main() { doDebianSource(os.Args[2:]) case "nsis": doWindowsInstaller(os.Args[2:]) - case "aar": - doAndroidArchive(os.Args[2:]) - case "xcode": - doXCodeFramework(os.Args[2:]) case "purge": doPurge(os.Args[2:]) default: @@ -994,236 +986,6 @@ func doWindowsInstaller(cmdline []string) { } } -// Android archives - -func doAndroidArchive(cmdline []string) { - var ( - local = flag.Bool("local", false, `Flag whether we're only doing a local build (skip Maven artifacts)`) - signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. ANDROID_SIGNING_KEY)`) - signify = flag.String("signify", "", `Environment variable holding the signify signing key (e.g. ANDROID_SIGNIFY_KEY)`) - deploy = flag.String("deploy", "", `Destination to deploy the archive (usually "https://oss.sonatype.org")`) - upload = flag.String("upload", "", `Destination to upload the archive (usually "gethstore/builds")`) - ) - flag.CommandLine.Parse(cmdline) - env := build.Env() - tc := new(build.GoToolchain) - - // Sanity check that the SDK and NDK are installed and set - if os.Getenv("ANDROID_HOME") == "" { - log.Fatal("Please ensure ANDROID_HOME points to your Android SDK") - } - - // Build gomobile. - install := tc.Install(GOBIN, "golang.org/x/mobile/cmd/gomobile@latest", "golang.org/x/mobile/cmd/gobind@latest") - install.Env = append(install.Env) - build.MustRun(install) - - // Ensure all dependencies are available. This is required to make - // gomobile bind work because it expects go.sum to contain all checksums. - build.MustRun(tc.Go("mod", "download")) - - // Build the Android archive and Maven resources - build.MustRun(gomobileTool("bind", "-ldflags", "-s -w", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile")) - - if *local { - // If we're building locally, copy bundle to build dir and skip Maven - os.Rename("geth.aar", filepath.Join(GOBIN, "geth.aar")) - os.Rename("geth-sources.jar", filepath.Join(GOBIN, "geth-sources.jar")) - return - } - meta := newMavenMetadata(env) - build.Render("build/mvn.pom", meta.Package+".pom", 0755, meta) - - // Skip Maven deploy and Azure upload for PR builds - maybeSkipArchive(env) - - // Sign and upload the archive to Azure - archive := "geth-" + archiveBasename("android", params.ArchiveVersion(env.Commit)) + ".aar" - os.Rename("geth.aar", archive) - - if err := archiveUpload(archive, *upload, *signer, *signify); err != nil { - log.Fatal(err) - } - // Sign and upload all the artifacts to Maven Central - os.Rename(archive, meta.Package+".aar") - if *signer != "" && *deploy != "" { - // Import the signing key into the local GPG instance - key := getenvBase64(*signer) - gpg := exec.Command("gpg", "--import") - gpg.Stdin = bytes.NewReader(key) - build.MustRun(gpg) - keyID, err := build.PGPKeyID(string(key)) - if err != nil { - log.Fatal(err) - } - // Upload the artifacts to Sonatype and/or Maven Central - repo := *deploy + "/service/local/staging/deploy/maven2" - if meta.Develop { - repo = *deploy + "/content/repositories/snapshots" - } - build.MustRunCommand("mvn", "gpg:sign-and-deploy-file", "-e", "-X", - "-settings=build/mvn.settings", "-Durl="+repo, "-DrepositoryId=ossrh", - "-Dgpg.keyname="+keyID, - "-DpomFile="+meta.Package+".pom", "-Dfile="+meta.Package+".aar") - } -} - -func gomobileTool(subcmd string, args ...string) *exec.Cmd { - cmd := exec.Command(filepath.Join(GOBIN, "gomobile"), subcmd) - cmd.Args = append(cmd.Args, args...) - cmd.Env = []string{ - "PATH=" + GOBIN + string(os.PathListSeparator) + os.Getenv("PATH"), - } - for _, e := range os.Environ() { - if strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "PATH=") || strings.HasPrefix(e, "GOBIN=") { - continue - } - cmd.Env = append(cmd.Env, e) - } - cmd.Env = append(cmd.Env, "GOBIN="+GOBIN) - return cmd -} - -type mavenMetadata struct { - Version string - Package string - Develop bool - Contributors []mavenContributor -} - -type mavenContributor struct { - Name string - Email string -} - -func newMavenMetadata(env build.Environment) mavenMetadata { - // Collect the list of authors from the repo root - contribs := []mavenContributor{} - if authors, err := os.Open("AUTHORS"); err == nil { - defer authors.Close() - - scanner := bufio.NewScanner(authors) - for scanner.Scan() { - // Skip any whitespace from the authors list - line := strings.TrimSpace(scanner.Text()) - if line == "" || line[0] == '#' { - continue - } - // Split the author and insert as a contributor - re := regexp.MustCompile("([^<]+) <(.+)>") - parts := re.FindStringSubmatch(line) - if len(parts) == 3 { - contribs = append(contribs, mavenContributor{Name: parts[1], Email: parts[2]}) - } - } - } - // Render the version and package strings - version := params.Version - if isUnstableBuild(env) { - version += "-SNAPSHOT" - } - return mavenMetadata{ - Version: version, - Package: "geth-" + version, - Develop: isUnstableBuild(env), - Contributors: contribs, - } -} - -// XCode frameworks - -func doXCodeFramework(cmdline []string) { - var ( - local = flag.Bool("local", false, `Flag whether we're only doing a local build (skip Maven artifacts)`) - signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. IOS_SIGNING_KEY)`) - signify = flag.String("signify", "", `Environment variable holding the signify signing key (e.g. IOS_SIGNIFY_KEY)`) - deploy = flag.String("deploy", "", `Destination to deploy the archive (usually "trunk")`) - upload = flag.String("upload", "", `Destination to upload the archives (usually "gethstore/builds")`) - ) - flag.CommandLine.Parse(cmdline) - env := build.Env() - tc := new(build.GoToolchain) - - // Build gomobile. - build.MustRun(tc.Install(GOBIN, "golang.org/x/mobile/cmd/gomobile@latest", "golang.org/x/mobile/cmd/gobind@latest")) - - // Build the iOS XCode framework - bind := gomobileTool("bind", "-ldflags", "-s -w", "--target", "ios", "-v", "github.com/ethereum/go-ethereum/mobile") - - if *local { - // If we're building locally, use the build folder and stop afterwards - bind.Dir = GOBIN - build.MustRun(bind) - return - } - - // Create the archive. - maybeSkipArchive(env) - archive := "geth-" + archiveBasename("ios", params.ArchiveVersion(env.Commit)) - if err := os.MkdirAll(archive, 0755); err != nil { - log.Fatal(err) - } - bind.Dir, _ = filepath.Abs(archive) - build.MustRun(bind) - build.MustRunCommand("tar", "-zcvf", archive+".tar.gz", archive) - - // Sign and upload the framework to Azure - if err := archiveUpload(archive+".tar.gz", *upload, *signer, *signify); err != nil { - log.Fatal(err) - } - // Prepare and upload a PodSpec to CocoaPods - if *deploy != "" { - meta := newPodMetadata(env, archive) - build.Render("build/pod.podspec", "Geth.podspec", 0755, meta) - build.MustRunCommand("pod", *deploy, "push", "Geth.podspec", "--allow-warnings") - } -} - -type podMetadata struct { - Version string - Commit string - Archive string - Contributors []podContributor -} - -type podContributor struct { - Name string - Email string -} - -func newPodMetadata(env build.Environment, archive string) podMetadata { - // Collect the list of authors from the repo root - contribs := []podContributor{} - if authors, err := os.Open("AUTHORS"); err == nil { - defer authors.Close() - - scanner := bufio.NewScanner(authors) - for scanner.Scan() { - // Skip any whitespace from the authors list - line := strings.TrimSpace(scanner.Text()) - if line == "" || line[0] == '#' { - continue - } - // Split the author and insert as a contributor - re := regexp.MustCompile("([^<]+) <(.+)>") - parts := re.FindStringSubmatch(line) - if len(parts) == 3 { - contribs = append(contribs, podContributor{Name: parts[1], Email: parts[2]}) - } - } - } - version := params.Version - if isUnstableBuild(env) { - version += "-unstable." + env.Buildnum - } - return podMetadata{ - Archive: archive, - Version: version, - Commit: env.Commit, - Contributors: contribs, - } -} - // Binary distribution cleanups func doPurge(cmdline []string) { diff --git a/build/mvn.pom b/build/mvn.pom deleted file mode 100644 index 7670246ba9f1..000000000000 --- a/build/mvn.pom +++ /dev/null @@ -1,57 +0,0 @@ - - 4.0.0 - - org.ethereum - geth - {{.Version}} - aar - - Android Ethereum Client - Android port of the go-ethereum libraries and node - https://github.com/ethereum/go-ethereum - 2015 - - - - GNU Lesser General Public License, Version 3.0 - https://www.gnu.org/licenses/lgpl-3.0.en.html - repo - - - - - Ethereum - https://ethereum.org - - - - - karalabe - Péter Szilágyi - peterke@gmail.com - https://github.com/karalabe - - https://www.gravatar.com/avatar/2ecbf0f5b4b79eebf8c193e5d324357f?s=256 - - - - - {{range .Contributors}} - - {{.Name}} - {{.Email}} - {{end}} - - - - GitHub Issues - https://github.com/ethereum/go-ethereum/issues/ - - - - https://github.com/ethereum/go-ethereum - - diff --git a/build/mvn.settings b/build/mvn.settings deleted file mode 100644 index 406b409b9b5d..000000000000 --- a/build/mvn.settings +++ /dev/null @@ -1,24 +0,0 @@ - - - - ossrh - ${env.ANDROID_SONATYPE_USERNAME} - ${env.ANDROID_SONATYPE_PASSWORD} - - - - - ossrh - - true - - - gpg - - - - - diff --git a/build/pod.podspec b/build/pod.podspec deleted file mode 100644 index 2c14c280c7c9..000000000000 --- a/build/pod.podspec +++ /dev/null @@ -1,22 +0,0 @@ -Pod::Spec.new do |spec| - spec.name = 'Geth' - spec.version = '{{.Version}}' - spec.license = { :type => 'GNU Lesser General Public License, Version 3.0' } - spec.homepage = 'https://github.com/ethereum/go-ethereum' - spec.authors = { {{range .Contributors}} - '{{.Name}}' => '{{.Email}}',{{end}} - } - spec.summary = 'iOS Ethereum Client' - spec.source = { :git => 'https://github.com/ethereum/go-ethereum.git', :commit => '{{.Commit}}' } - - spec.platform = :ios - spec.ios.deployment_target = '9.0' - spec.ios.vendored_frameworks = 'Frameworks/Geth.framework' - - spec.prepare_command = <<-CMD - curl https://gethstore.blob.core.windows.net/builds/{{.Archive}}.tar.gz | tar -xvz - mkdir Frameworks - mv {{.Archive}}/Geth.framework Frameworks - rm -rf {{.Archive}} - CMD -end diff --git a/build/tools/tools.go b/build/tools/tools.go index fd2681a28b37..506e26eeff74 100644 --- a/build/tools/tools.go +++ b/build/tools/tools.go @@ -24,8 +24,4 @@ import ( _ "github.com/fjl/gencodec" _ "github.com/golang/protobuf/protoc-gen-go" _ "golang.org/x/tools/cmd/stringer" - - // Tool imports for mobile build. - _ "golang.org/x/mobile/cmd/gobind" - _ "golang.org/x/mobile/cmd/gomobile" ) diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 83b6c5e4289f..221f45c07849 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -65,7 +65,7 @@ var ( } langFlag = &cli.StringFlag{ Name: "lang", - Usage: "Destination language for the bindings (go, java, objc)", + Usage: "Destination language for the bindings (go)", Value: "go", } aliasFlag = &cli.StringFlag{ @@ -102,11 +102,6 @@ func abigen(c *cli.Context) error { switch c.String(langFlag.Name) { case "go": lang = bind.LangGo - case "java": - lang = bind.LangJava - case "objc": - lang = bind.LangObjC - utils.Fatalf("Objc binding generation is uncompleted") default: utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.String(langFlag.Name)) } diff --git a/go.mod b/go.mod index cf3d7e2e98fc..8860447f089a 100644 --- a/go.mod +++ b/go.mod @@ -58,7 +58,6 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa golang.org/x/crypto v0.1.0 - golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 golang.org/x/sys v0.2.0 golang.org/x/text v0.4.0 diff --git a/go.sum b/go.sum index 3c7e9202f62e..400bcce8c9d1 100644 --- a/go.sum +++ b/go.sum @@ -464,7 +464,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= diff --git a/mobile/accounts.go b/mobile/accounts.go deleted file mode 100644 index d9eab93a741d..000000000000 --- a/mobile/accounts.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the accounts package to support client side key -// management on mobile platforms. - -package geth - -import ( - "errors" - "time" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -const ( - // StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB - // memory and taking approximately 1s CPU time on a modern processor. - StandardScryptN = int(keystore.StandardScryptN) - - // StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB - // memory and taking approximately 1s CPU time on a modern processor. - StandardScryptP = int(keystore.StandardScryptP) - - // LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB - // memory and taking approximately 100ms CPU time on a modern processor. - LightScryptN = int(keystore.LightScryptN) - - // LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB - // memory and taking approximately 100ms CPU time on a modern processor. - LightScryptP = int(keystore.LightScryptP) -) - -// Account represents a stored key. -type Account struct{ account accounts.Account } - -// Accounts represents a slice of accounts. -type Accounts struct{ accounts []accounts.Account } - -// Size returns the number of accounts in the slice. -func (a *Accounts) Size() int { - return len(a.accounts) -} - -// Get returns the account at the given index from the slice. -func (a *Accounts) Get(index int) (account *Account, _ error) { - if index < 0 || index >= len(a.accounts) { - return nil, errors.New("index out of bounds") - } - return &Account{a.accounts[index]}, nil -} - -// Set sets the account at the given index in the slice. -func (a *Accounts) Set(index int, account *Account) error { - if index < 0 || index >= len(a.accounts) { - return errors.New("index out of bounds") - } - a.accounts[index] = account.account - return nil -} - -// GetAddress retrieves the address associated with the account. -func (a *Account) GetAddress() *Address { - return &Address{a.account.Address} -} - -// GetURL retrieves the canonical URL of the account. -func (a *Account) GetURL() string { - return a.account.URL.String() -} - -// KeyStore manages a key storage directory on disk. -type KeyStore struct{ keystore *keystore.KeyStore } - -// NewKeyStore creates a keystore for the given directory. -func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore { - return &KeyStore{keystore: keystore.NewKeyStore(keydir, scryptN, scryptP)} -} - -// HasAddress reports whether a key with the given address is present. -func (ks *KeyStore) HasAddress(address *Address) bool { - return ks.keystore.HasAddress(address.address) -} - -// GetAccounts returns all key files present in the directory. -func (ks *KeyStore) GetAccounts() *Accounts { - return &Accounts{ks.keystore.Accounts()} -} - -// DeleteAccount deletes the key matched by account if the passphrase is correct. -// If a contains no filename, the address must match a unique key. -func (ks *KeyStore) DeleteAccount(account *Account, passphrase string) error { - return ks.keystore.Delete(account.account, passphrase) -} - -// SignHash calculates a ECDSA signature for the given hash. The produced signature -// is in the [R || S || V] format where V is 0 or 1. -func (ks *KeyStore) SignHash(address *Address, hash []byte) (signature []byte, _ error) { - return ks.keystore.SignHash(accounts.Account{Address: address.address}, common.CopyBytes(hash)) -} - -// SignTx signs the given transaction with the requested account. -func (ks *KeyStore) SignTx(account *Account, tx *Transaction, chainID *BigInt) (*Transaction, error) { - if chainID == nil { // Null passed from mobile app - chainID = new(BigInt) - } - signed, err := ks.keystore.SignTx(account.account, tx.tx, chainID.bigint) - if err != nil { - return nil, err - } - return &Transaction{signed}, nil -} - -// SignHashPassphrase signs hash if the private key matching the given address can -// be decrypted with the given passphrase. The produced signature is in the -// [R || S || V] format where V is 0 or 1. -func (ks *KeyStore) SignHashPassphrase(account *Account, passphrase string, hash []byte) (signature []byte, _ error) { - return ks.keystore.SignHashWithPassphrase(account.account, passphrase, common.CopyBytes(hash)) -} - -// SignTxPassphrase signs the transaction if the private key matching the -// given address can be decrypted with the given passphrase. -func (ks *KeyStore) SignTxPassphrase(account *Account, passphrase string, tx *Transaction, chainID *BigInt) (*Transaction, error) { - if chainID == nil { // Null passed from mobile app - chainID = new(BigInt) - } - signed, err := ks.keystore.SignTxWithPassphrase(account.account, passphrase, tx.tx, chainID.bigint) - if err != nil { - return nil, err - } - return &Transaction{signed}, nil -} - -// Unlock unlocks the given account indefinitely. -func (ks *KeyStore) Unlock(account *Account, passphrase string) error { - return ks.keystore.TimedUnlock(account.account, passphrase, 0) -} - -// Lock removes the private key with the given address from memory. -func (ks *KeyStore) Lock(address *Address) error { - return ks.keystore.Lock(address.address) -} - -// TimedUnlock unlocks the given account with the passphrase. The account stays -// unlocked for the duration of timeout (nanoseconds). A timeout of 0 unlocks the -// account until the program exits. The account must match a unique key file. -// -// If the account address is already unlocked for a duration, TimedUnlock extends or -// shortens the active unlock timeout. If the address was previously unlocked -// indefinitely the timeout is not altered. -func (ks *KeyStore) TimedUnlock(account *Account, passphrase string, timeout int64) error { - return ks.keystore.TimedUnlock(account.account, passphrase, time.Duration(timeout)) -} - -// NewAccount generates a new key and stores it into the key directory, -// encrypting it with the passphrase. -func (ks *KeyStore) NewAccount(passphrase string) (*Account, error) { - account, err := ks.keystore.NewAccount(passphrase) - if err != nil { - return nil, err - } - return &Account{account}, nil -} - -// UpdateAccount changes the passphrase of an existing account. -func (ks *KeyStore) UpdateAccount(account *Account, passphrase, newPassphrase string) error { - return ks.keystore.Update(account.account, passphrase, newPassphrase) -} - -// ExportKey exports as a JSON key, encrypted with newPassphrase. -func (ks *KeyStore) ExportKey(account *Account, passphrase, newPassphrase string) (key []byte, _ error) { - return ks.keystore.Export(account.account, passphrase, newPassphrase) -} - -// ImportKey stores the given encrypted JSON key into the key directory. -func (ks *KeyStore) ImportKey(keyJSON []byte, passphrase, newPassphrase string) (account *Account, _ error) { - acc, err := ks.keystore.Import(common.CopyBytes(keyJSON), passphrase, newPassphrase) - if err != nil { - return nil, err - } - return &Account{acc}, nil -} - -// ImportECDSAKey stores the given encrypted JSON key into the key directory. -func (ks *KeyStore) ImportECDSAKey(key []byte, passphrase string) (account *Account, _ error) { - privkey, err := crypto.ToECDSA(common.CopyBytes(key)) - if err != nil { - return nil, err - } - acc, err := ks.keystore.ImportECDSA(privkey, passphrase) - if err != nil { - return nil, err - } - return &Account{acc}, nil -} - -// ImportPreSaleKey decrypts the given Ethereum presale wallet and stores -// a key file in the key directory. The key file is encrypted with the same passphrase. -func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (account *Account, _ error) { - acc, err := ks.keystore.ImportPreSaleKey(common.CopyBytes(keyJSON), passphrase) - if err != nil { - return nil, err - } - return &Account{acc}, nil -} diff --git a/mobile/android_test.go b/mobile/android_test.go deleted file mode 100644 index 2ddf5d9d91ed..000000000000 --- a/mobile/android_test.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2016 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 geth - -import ( - "os" - "os/exec" - "path/filepath" - "runtime" - "testing" - "time" - - "github.com/cespare/cp" -) - -// androidTestClass is a Java class to do some lightweight tests against the Android -// bindings. The goal is not to test each individual functionality, rather just to -// catch breaking API and/or implementation changes. -const androidTestClass = ` -package go; - -import android.test.InstrumentationTestCase; -import android.test.MoreAsserts; - -import java.math.BigInteger; -import java.util.Arrays; - -import org.ethereum.geth.*; - -public class AndroidTest extends InstrumentationTestCase { - public AndroidTest() {} - - public void testAccountManagement() { - // Create an encrypted keystore with light crypto parameters. - KeyStore ks = new KeyStore(getInstrumentation().getContext().getFilesDir() + "/keystore", Geth.LightScryptN, Geth.LightScryptP); - - try { - // Create a new account with the specified encryption passphrase. - Account newAcc = ks.newAccount("Creation password"); - - // Export the newly created account with a different passphrase. The returned - // data from this method invocation is a JSON encoded, encrypted key-file. - byte[] jsonAcc = ks.exportKey(newAcc, "Creation password", "Export password"); - - // Update the passphrase on the account created above inside the local keystore. - ks.updateAccount(newAcc, "Creation password", "Update password"); - - // Delete the account updated above from the local keystore. - ks.deleteAccount(newAcc, "Update password"); - - // Import back the account we've exported (and then deleted) above with yet - // again a fresh passphrase. - Account impAcc = ks.importKey(jsonAcc, "Export password", "Import password"); - - // Create a new account to sign transactions with - Account signer = ks.newAccount("Signer password"); - - Transaction tx = new Transaction( - 1, new Address("0x0000000000000000000000000000000000000000"), - new BigInt(0), 0, new BigInt(1), null); // Random empty transaction - BigInt chain = new BigInt(1); // Chain identifier of the main net - - // Sign a transaction with a single authorization - Transaction signed = ks.signTxPassphrase(signer, "Signer password", tx, chain); - - // Sign a transaction with multiple manually cancelled authorizations - ks.unlock(signer, "Signer password"); - signed = ks.signTx(signer, tx, chain); - ks.lock(signer.getAddress()); - - // Sign a transaction with multiple automatically cancelled authorizations - ks.timedUnlock(signer, "Signer password", 1000000000); - signed = ks.signTx(signer, tx, chain); - } catch (Exception e) { - fail(e.toString()); - } - } - - public void testInprocNode() { - Context ctx = new Context(); - - try { - // Start up a new inprocess node - Node node = new Node(getInstrumentation().getContext().getFilesDir() + "/.ethereum", new NodeConfig()); - node.start(); - - // Retrieve some data via function calls (we don't really care about the results) - NodeInfo info = node.getNodeInfo(); - info.getName(); - info.getListenerAddress(); - info.getProtocols(); - - // Retrieve some data via the APIs (we don't really care about the results) - EthereumClient ec = node.getEthereumClient(); - ec.getBlockByNumber(ctx, -1).getNumber(); - - NewHeadHandler handler = new NewHeadHandler() { - @Override public void onError(String error) {} - @Override public void onNewHead(final Header header) {} - }; - ec.subscribeNewHead(ctx, handler, 16); - } catch (Exception e) { - fail(e.toString()); - } - } - - // Tests that recovering transaction signers works for both Homestead and EIP155 - // signatures too. Regression test for go-ethereum issue #14599. - public void testIssue14599() { - try { - byte[] preEIP155RLP = new BigInteger("f901fc8032830138808080b901ae60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b561ca0c5689ed1ad124753d54576dfb4b571465a41900a1dff4058d8adf16f752013d0a01221cbd70ec28c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884", 16).toByteArray(); - preEIP155RLP = Arrays.copyOfRange(preEIP155RLP, 1, preEIP155RLP.length); - - byte[] postEIP155RLP = new BigInteger("f86b80847735940082520894ef5bbb9bba2e1ca69ef81b23a8727d889f3ef0a1880de0b6b3a7640000802ba06fef16c44726a102e6d55a651740636ef8aec6df3ebf009e7b0c1f29e4ac114aa057e7fbc69760b522a78bb568cfc37a58bfdcf6ea86cb8f9b550263f58074b9cc", 16).toByteArray(); - postEIP155RLP = Arrays.copyOfRange(postEIP155RLP, 1, postEIP155RLP.length); - - Transaction preEIP155 = new Transaction(preEIP155RLP); - Transaction postEIP155 = new Transaction(postEIP155RLP); - - preEIP155.getFrom(null); // Homestead should accept homestead - preEIP155.getFrom(new BigInt(4)); // EIP155 should accept homestead (missing chain ID) - postEIP155.getFrom(new BigInt(4)); // EIP155 should accept EIP 155 - - try { - postEIP155.getFrom(null); - fail("EIP155 transaction accepted by Homestead"); - } catch (Exception e) {} - } catch (Exception e) { - fail(e.toString()); - } - } -} -` - -// TestAndroid runs the Android java test class specified above. -// -// This requires the gradle command in PATH and the Android SDK whose path is available -// through ANDROID_HOME environment variable. To successfully run the tests, an Android -// device must also be available with debugging enabled. -// -// This method has been adapted from golang.org/x/mobile/bind/java/seq_test.go/runTest -func TestAndroid(t *testing.T) { - // Skip tests on Windows altogether - if runtime.GOOS == "windows" { - t.Skip("cannot test Android bindings on Windows, skipping") - } - // Make sure all the Android tools are installed - if _, err := exec.Command("which", "gradle").CombinedOutput(); err != nil { - t.Skip("command gradle not found, skipping") - } - if sdk := os.Getenv("ANDROID_HOME"); sdk == "" { - // Android SDK not explicitly given, try to auto-resolve - autopath := filepath.Join(os.Getenv("HOME"), "Android", "Sdk") - if _, err := os.Stat(autopath); err != nil { - t.Skip("ANDROID_HOME environment var not set, skipping") - } - os.Setenv("ANDROID_HOME", autopath) - } - if _, err := exec.Command("which", "gomobile").CombinedOutput(); err != nil { - t.Log("gomobile missing, installing it...") - if out, err := exec.Command("go", "get", "golang.org/x/mobile/cmd/gomobile").CombinedOutput(); err != nil { - t.Fatalf("install failed: %v\n%s", err, string(out)) - } - t.Log("initializing gomobile...") - start := time.Now() - if _, err := exec.Command("gomobile", "init").CombinedOutput(); err != nil { - t.Fatalf("initialization failed: %v", err) - } - t.Logf("initialization took %v", time.Since(start)) - } - // Create and switch to a temporary workspace - workspace := t.TempDir() - - pwd, err := os.Getwd() - if err != nil { - t.Fatalf("failed to get current working directory: %v", err) - } - if err := os.Chdir(workspace); err != nil { - t.Fatalf("failed to switch to temporary workspace: %v", err) - } - defer os.Chdir(pwd) - - // Create the skeleton of the Android project - for _, dir := range []string{"src/main", "src/androidTest/java/org/ethereum/gethtest", "libs"} { - err = os.MkdirAll(dir, os.ModePerm) - if err != nil { - t.Fatal(err) - } - } - // Generate the mobile bindings for Geth and add the tester class - gobind := exec.Command("gomobile", "bind", "-javapkg", "org.ethereum", "github.com/ethereum/go-ethereum/mobile") - if output, err := gobind.CombinedOutput(); err != nil { - t.Logf("%s", output) - t.Fatalf("failed to run gomobile bind: %v", err) - } - cp.CopyFile(filepath.Join("libs", "geth.aar"), "geth.aar") - - if err = os.WriteFile(filepath.Join("src", "androidTest", "java", "org", "ethereum", "gethtest", "AndroidTest.java"), []byte(androidTestClass), os.ModePerm); err != nil { - t.Fatalf("failed to write Android test class: %v", err) - } - // Finish creating the project and run the tests via gradle - if err = os.WriteFile(filepath.Join("src", "main", "AndroidManifest.xml"), []byte(androidManifest), os.ModePerm); err != nil { - t.Fatalf("failed to write Android manifest: %v", err) - } - if err = os.WriteFile("build.gradle", []byte(gradleConfig), os.ModePerm); err != nil { - t.Fatalf("failed to write gradle build file: %v", err) - } - if output, err := exec.Command("gradle", "connectedAndroidTest").CombinedOutput(); err != nil { - t.Logf("%s", output) - t.Errorf("failed to run gradle test: %v", err) - } -} - -const androidManifest = ` - - - -` - -const gradleConfig = `buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' - } -} -allprojects { - repositories { jcenter() } -} -apply plugin: 'com.android.library' -android { - compileSdkVersion 'android-19' - buildToolsVersion '21.1.2' - defaultConfig { minSdkVersion 15 } -} -repositories { - flatDir { dirs 'libs' } -} -dependencies { - compile 'com.android.support:appcompat-v7:19.0.0' - compile(name: "geth", ext: "aar") -} -` diff --git a/mobile/big.go b/mobile/big.go deleted file mode 100644 index af5f9d89168a..000000000000 --- a/mobile/big.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the math/big package. - -package geth - -import ( - "errors" - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -// A BigInt represents a signed multi-precision integer. -type BigInt struct { - bigint *big.Int -} - -// NewBigInt allocates and returns a new BigInt set to x. -func NewBigInt(x int64) *BigInt { - return &BigInt{big.NewInt(x)} -} - -// NewBigIntFromString allocates and returns a new BigInt set to x -// interpreted in the provided base. -func NewBigIntFromString(x string, base int) *BigInt { - b, success := new(big.Int).SetString(x, base) - if !success { - return nil - } - return &BigInt{b} -} - -// GetBytes returns the absolute value of x as a big-endian byte slice. -func (bi *BigInt) GetBytes() []byte { - return bi.bigint.Bytes() -} - -// String returns the value of x as a formatted decimal string. -func (bi *BigInt) String() string { - return bi.bigint.String() -} - -// GetInt64 returns the int64 representation of x. If x cannot be represented in -// an int64, the result is undefined. -func (bi *BigInt) GetInt64() int64 { - return bi.bigint.Int64() -} - -// SetBytes interprets buf as the bytes of a big-endian unsigned integer and sets -// the big int to that value. -func (bi *BigInt) SetBytes(buf []byte) { - bi.bigint.SetBytes(common.CopyBytes(buf)) -} - -// SetInt64 sets the big int to x. -func (bi *BigInt) SetInt64(x int64) { - bi.bigint.SetInt64(x) -} - -// Sign returns: -// -// -1 if x < 0 -// 0 if x == 0 -// +1 if x > 0 -func (bi *BigInt) Sign() int { - return bi.bigint.Sign() -} - -// SetString sets the big int to x. -// -// The string prefix determines the actual conversion base. A prefix of "0x" or -// "0X" selects base 16; the "0" prefix selects base 8, and a "0b" or "0B" prefix -// selects base 2. Otherwise the selected base is 10. -func (bi *BigInt) SetString(x string, base int) { - bi.bigint.SetString(x, base) -} - -// BigInts represents a slice of big ints. -type BigInts struct{ bigints []*big.Int } - -// NewBigInts creates a slice of uninitialized big numbers. -func NewBigInts(size int) *BigInts { - return &BigInts{ - bigints: make([]*big.Int, size), - } -} - -// Size returns the number of big ints in the slice. -func (bi *BigInts) Size() int { - return len(bi.bigints) -} - -// Get returns the bigint at the given index from the slice. -func (bi *BigInts) Get(index int) (bigint *BigInt, _ error) { - if index < 0 || index >= len(bi.bigints) { - return nil, errors.New("index out of bounds") - } - return &BigInt{bi.bigints[index]}, nil -} - -// Set sets the big int at the given index in the slice. -func (bi *BigInts) Set(index int, bigint *BigInt) error { - if index < 0 || index >= len(bi.bigints) { - return errors.New("index out of bounds") - } - bi.bigints[index] = bigint.bigint - return nil -} - -// GetString returns the value of x as a formatted string in some number base. -func (bi *BigInt) GetString(base int) string { - return bi.bigint.Text(base) -} diff --git a/mobile/bind.go b/mobile/bind.go deleted file mode 100644 index e32d864aa58a..000000000000 --- a/mobile/bind.go +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the bind package. - -package geth - -import ( - "math/big" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" -) - -// Signer is an interface defining the callback when a contract requires a -// method to sign the transaction before submission. -type Signer interface { - Sign(addr *Address, unsignedTx *Transaction) (tx *Transaction, _ error) -} - -type MobileSigner struct { - sign bind.SignerFn -} - -func (s *MobileSigner) Sign(addr *Address, unsignedTx *Transaction) (signedTx *Transaction, _ error) { - sig, err := s.sign(addr.address, unsignedTx.tx) - if err != nil { - return nil, err - } - return &Transaction{sig}, nil -} - -// CallOpts is the collection of options to fine tune a contract call request. -type CallOpts struct { - opts bind.CallOpts -} - -// NewCallOpts creates a new option set for contract calls. -func NewCallOpts() *CallOpts { - return new(CallOpts) -} - -func (opts *CallOpts) IsPending() bool { return opts.opts.Pending } -func (opts *CallOpts) GetGasLimit() int64 { return 0 /* TODO(karalabe) */ } - -// GetContext cannot be reliably implemented without identity preservation (https://github.com/golang/go/issues/16876) -// Even then it's awkward to unpack the subtleties of a Go context out to Java. -// func (opts *CallOpts) GetContext() *Context { return &Context{opts.opts.Context} } - -func (opts *CallOpts) SetPending(pending bool) { opts.opts.Pending = pending } -func (opts *CallOpts) SetGasLimit(limit int64) { /* TODO(karalabe) */ } -func (opts *CallOpts) SetContext(context *Context) { opts.opts.Context = context.context } -func (opts *CallOpts) SetFrom(addr *Address) { opts.opts.From = addr.address } - -// TransactOpts is the collection of authorization data required to create a -// valid Ethereum transaction. -type TransactOpts struct { - opts bind.TransactOpts -} - -// NewTransactOpts creates a new option set for contract transaction. -func NewTransactOpts() *TransactOpts { - return new(TransactOpts) -} - -// NewKeyedTransactOpts is a utility method to easily create a transaction signer -// from a single private key. -func NewKeyedTransactOpts(keyJson []byte, passphrase string, chainID *big.Int) (*TransactOpts, error) { - key, err := keystore.DecryptKey(keyJson, passphrase) - if err != nil { - return nil, err - } - auth, err := bind.NewKeyedTransactorWithChainID(key.PrivateKey, chainID) - if err != nil { - return nil, err - } - return &TransactOpts{*auth}, nil -} - -func (opts *TransactOpts) GetFrom() *Address { return &Address{opts.opts.From} } -func (opts *TransactOpts) GetNonce() int64 { return opts.opts.Nonce.Int64() } -func (opts *TransactOpts) GetValue() *BigInt { return &BigInt{opts.opts.Value} } -func (opts *TransactOpts) GetGasPrice() *BigInt { return &BigInt{opts.opts.GasPrice} } -func (opts *TransactOpts) GetGasLimit() int64 { return int64(opts.opts.GasLimit) } - -// GetSigner cannot be reliably implemented without identity preservation (https://github.com/golang/go/issues/16876) -// func (opts *TransactOpts) GetSigner() Signer { return &signer{opts.opts.Signer} } - -// GetContext cannot be reliably implemented without identity preservation (https://github.com/golang/go/issues/16876) -// Even then it's awkward to unpack the subtleties of a Go context out to Java. -//func (opts *TransactOpts) GetContext() *Context { return &Context{opts.opts.Context} } - -func (opts *TransactOpts) SetFrom(from *Address) { opts.opts.From = from.address } -func (opts *TransactOpts) SetNonce(nonce int64) { opts.opts.Nonce = big.NewInt(nonce) } -func (opts *TransactOpts) SetSigner(s Signer) { - opts.opts.Signer = func(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { - sig, err := s.Sign(&Address{addr}, &Transaction{tx}) - if err != nil { - return nil, err - } - return sig.tx, nil - } -} -func (opts *TransactOpts) SetValue(value *BigInt) { opts.opts.Value = value.bigint } -func (opts *TransactOpts) SetGasPrice(price *BigInt) { opts.opts.GasPrice = price.bigint } -func (opts *TransactOpts) SetGasLimit(limit int64) { opts.opts.GasLimit = uint64(limit) } -func (opts *TransactOpts) SetContext(context *Context) { opts.opts.Context = context.context } - -// BoundContract is the base wrapper object that reflects a contract on the -// Ethereum network. It contains a collection of methods that are used by the -// higher level contract bindings to operate. -type BoundContract struct { - contract *bind.BoundContract - address common.Address - deployer *types.Transaction -} - -// DeployContract deploys a contract onto the Ethereum blockchain and binds the -// deployment address with a wrapper. -func DeployContract(opts *TransactOpts, abiJSON string, bytecode []byte, client *EthereumClient, args *Interfaces) (contract *BoundContract, _ error) { - // Deploy the contract to the network - parsed, err := abi.JSON(strings.NewReader(abiJSON)) - if err != nil { - return nil, err - } - addr, tx, bound, err := bind.DeployContract(&opts.opts, parsed, common.CopyBytes(bytecode), client.client, args.objects...) - if err != nil { - return nil, err - } - return &BoundContract{ - contract: bound, - address: addr, - deployer: tx, - }, nil -} - -// BindContract creates a low level contract interface through which calls and -// transactions may be made through. -func BindContract(address *Address, abiJSON string, client *EthereumClient) (contract *BoundContract, _ error) { - parsed, err := abi.JSON(strings.NewReader(abiJSON)) - if err != nil { - return nil, err - } - return &BoundContract{ - contract: bind.NewBoundContract(address.address, parsed, client.client, client.client, client.client), - address: address.address, - }, nil -} - -func (c *BoundContract) GetAddress() *Address { return &Address{c.address} } -func (c *BoundContract) GetDeployer() *Transaction { - if c.deployer == nil { - return nil - } - return &Transaction{c.deployer} -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. -func (c *BoundContract) Call(opts *CallOpts, out *Interfaces, method string, args *Interfaces) error { - results := make([]interface{}, len(out.objects)) - copy(results, out.objects) - if err := c.contract.Call(&opts.opts, &results, method, args.objects...); err != nil { - return err - } - copy(out.objects, results) - return nil -} - -// Transact invokes the (paid) contract method with params as input values. -func (c *BoundContract) Transact(opts *TransactOpts, method string, args *Interfaces) (tx *Transaction, _ error) { - rawTx, err := c.contract.Transact(&opts.opts, method, args.objects...) - if err != nil { - return nil, err - } - return &Transaction{rawTx}, nil -} - -// RawTransact invokes the (paid) contract method with raw calldata as input values. -func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (tx *Transaction, _ error) { - rawTx, err := c.contract.RawTransact(&opts.opts, calldata) - if err != nil { - return nil, err - } - return &Transaction{rawTx}, nil -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (c *BoundContract) Transfer(opts *TransactOpts) (tx *Transaction, _ error) { - rawTx, err := c.contract.Transfer(&opts.opts) - if err != nil { - return nil, err - } - return &Transaction{rawTx}, nil -} diff --git a/mobile/common.go b/mobile/common.go deleted file mode 100644 index 124712b4b1f2..000000000000 --- a/mobile/common.go +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the common package. - -package geth - -import ( - "encoding/hex" - "errors" - "fmt" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" -) - -// Hash represents the 32 byte Keccak256 hash of arbitrary data. -type Hash struct { - hash common.Hash -} - -// NewHashFromBytes converts a slice of bytes to a hash value. -func NewHashFromBytes(binary []byte) (hash *Hash, _ error) { - h := new(Hash) - if err := h.SetBytes(common.CopyBytes(binary)); err != nil { - return nil, err - } - return h, nil -} - -// NewHashFromHex converts a hex string to a hash value. -func NewHashFromHex(hex string) (hash *Hash, _ error) { - h := new(Hash) - if err := h.SetHex(hex); err != nil { - return nil, err - } - return h, nil -} - -// SetBytes sets the specified slice of bytes as the hash value. -func (h *Hash) SetBytes(hash []byte) error { - if length := len(hash); length != common.HashLength { - return fmt.Errorf("invalid hash length: %v != %v", length, common.HashLength) - } - copy(h.hash[:], hash) - return nil -} - -// GetBytes retrieves the byte representation of the hash. -func (h *Hash) GetBytes() []byte { - return h.hash[:] -} - -// SetHex sets the specified hex string as the hash value. -func (h *Hash) SetHex(hash string) error { - hash = strings.ToLower(hash) - if len(hash) >= 2 && hash[:2] == "0x" { - hash = hash[2:] - } - if length := len(hash); length != 2*common.HashLength { - return fmt.Errorf("invalid hash hex length: %v != %v", length, 2*common.HashLength) - } - bin, err := hex.DecodeString(hash) - if err != nil { - return err - } - copy(h.hash[:], bin) - return nil -} - -// GetHex retrieves the hex string representation of the hash. -func (h *Hash) GetHex() string { - return h.hash.Hex() -} - -// String implements Stringer interface for printable representation of the hash. -func (h *Hash) String() string { - return h.GetHex() -} - -// Hashes represents a slice of hashes. -type Hashes struct{ hashes []common.Hash } - -// NewHashes creates a slice of uninitialized Hashes. -func NewHashes(size int) *Hashes { - return &Hashes{ - hashes: make([]common.Hash, size), - } -} - -// NewHashesEmpty creates an empty slice of Hashes values. -func NewHashesEmpty() *Hashes { - return NewHashes(0) -} - -// Size returns the number of hashes in the slice. -func (h *Hashes) Size() int { - return len(h.hashes) -} - -// Get returns the hash at the given index from the slice. -func (h *Hashes) Get(index int) (hash *Hash, _ error) { - if index < 0 || index >= len(h.hashes) { - return nil, errors.New("index out of bounds") - } - return &Hash{h.hashes[index]}, nil -} - -// Set sets the Hash at the given index in the slice. -func (h *Hashes) Set(index int, hash *Hash) error { - if index < 0 || index >= len(h.hashes) { - return errors.New("index out of bounds") - } - h.hashes[index] = hash.hash - return nil -} - -// Append adds a new Hash element to the end of the slice. -func (h *Hashes) Append(hash *Hash) { - h.hashes = append(h.hashes, hash.hash) -} - -// Address represents the 20 byte address of an Ethereum account. -type Address struct { - address common.Address -} - -// NewAddressFromBytes converts a slice of bytes to a hash value. -func NewAddressFromBytes(binary []byte) (address *Address, _ error) { - a := new(Address) - if err := a.SetBytes(common.CopyBytes(binary)); err != nil { - return nil, err - } - return a, nil -} - -// NewAddressFromHex converts a hex string to a address value. -func NewAddressFromHex(hex string) (address *Address, _ error) { - a := new(Address) - if err := a.SetHex(hex); err != nil { - return nil, err - } - return a, nil -} - -// SetBytes sets the specified slice of bytes as the address value. -func (a *Address) SetBytes(address []byte) error { - if length := len(address); length != common.AddressLength { - return fmt.Errorf("invalid address length: %v != %v", length, common.AddressLength) - } - copy(a.address[:], address) - return nil -} - -// GetBytes retrieves the byte representation of the address. -func (a *Address) GetBytes() []byte { - return a.address[:] -} - -// SetHex sets the specified hex string as the address value. -func (a *Address) SetHex(address string) error { - address = strings.ToLower(address) - if len(address) >= 2 && address[:2] == "0x" { - address = address[2:] - } - if length := len(address); length != 2*common.AddressLength { - return fmt.Errorf("invalid address hex length: %v != %v", length, 2*common.AddressLength) - } - bin, err := hex.DecodeString(address) - if err != nil { - return err - } - copy(a.address[:], bin) - return nil -} - -// GetHex retrieves the hex string representation of the address. -func (a *Address) GetHex() string { - return a.address.Hex() -} - -// String returns a printable representation of the address. -func (a *Address) String() string { - return a.GetHex() -} - -// Addresses represents a slice of addresses. -type Addresses struct{ addresses []common.Address } - -// NewAddresses creates a slice of uninitialized addresses. -func NewAddresses(size int) *Addresses { - return &Addresses{ - addresses: make([]common.Address, size), - } -} - -// NewAddressesEmpty creates an empty slice of Addresses values. -func NewAddressesEmpty() *Addresses { - return NewAddresses(0) -} - -// Size returns the number of addresses in the slice. -func (a *Addresses) Size() int { - return len(a.addresses) -} - -// Get returns the address at the given index from the slice. -func (a *Addresses) Get(index int) (address *Address, _ error) { - if index < 0 || index >= len(a.addresses) { - return nil, errors.New("index out of bounds") - } - return &Address{a.addresses[index]}, nil -} - -// Set sets the address at the given index in the slice. -func (a *Addresses) Set(index int, address *Address) error { - if index < 0 || index >= len(a.addresses) { - return errors.New("index out of bounds") - } - a.addresses[index] = address.address - return nil -} - -// Append adds a new address element to the end of the slice. -func (a *Addresses) Append(address *Address) { - a.addresses = append(a.addresses, address.address) -} - -// EncodeToHex encodes b as a hex string with 0x prefix. -func EncodeToHex(b []byte) string { - return hexutil.Encode(b) -} - -// DecodeFromHex decodes a hex string with 0x prefix. -func DecodeFromHex(s string) ([]byte, error) { - return hexutil.Decode(s) -} diff --git a/mobile/context.go b/mobile/context.go deleted file mode 100644 index 76b4c54642a6..000000000000 --- a/mobile/context.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the golang.org/x/net/context package to support -// client side context management on mobile platforms. - -package geth - -import ( - "context" - "time" -) - -// Context carries a deadline, a cancellation signal, and other values across API -// boundaries. -type Context struct { - context context.Context - cancel context.CancelFunc -} - -// NewContext returns a non-nil, empty Context. It is never canceled, has no -// values, and has no deadline. It is typically used by the main function, -// initialization, and tests, and as the top-level Context for incoming requests. -func NewContext() *Context { - return &Context{ - context: context.Background(), - } -} - -// WithCancel returns a copy of the original context with cancellation mechanism -// included. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func (c *Context) WithCancel() *Context { - child, cancel := context.WithCancel(c.context) - return &Context{ - context: child, - cancel: cancel, - } -} - -// WithDeadline returns a copy of the original context with the deadline adjusted -// to be no later than the specified time. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func (c *Context) WithDeadline(sec int64, nsec int64) *Context { - child, cancel := context.WithDeadline(c.context, time.Unix(sec, nsec)) - return &Context{ - context: child, - cancel: cancel, - } -} - -// WithTimeout returns a copy of the original context with the deadline adjusted -// to be no later than now + the duration specified. -// -// Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. -func (c *Context) WithTimeout(nsec int64) *Context { - child, cancel := context.WithTimeout(c.context, time.Duration(nsec)) - return &Context{ - context: child, - cancel: cancel, - } -} diff --git a/mobile/discover.go b/mobile/discover.go deleted file mode 100644 index 0fbc86de261a..000000000000 --- a/mobile/discover.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the accounts package to support client side enode -// management on mobile platforms. - -package geth - -import ( - "errors" - - "github.com/ethereum/go-ethereum/p2p/enode" -) - -// Enode represents a host on the network. -type Enode struct { - node *enode.Node -} - -// NewEnode parses a node designator. -// -// There are two basic forms of node designators -// - incomplete nodes, which only have the public key (node ID) -// - complete nodes, which contain the public key and IP/Port information -// -// For incomplete nodes, the designator must look like one of these -// -// enode:// -// -// -// For complete nodes, the node ID is encoded in the username portion -// of the URL, separated from the host by an @ sign. The hostname can -// only be given as an IP address, DNS domain names are not allowed. -// The port in the host name section is the TCP listening port. If the -// TCP and UDP (discovery) ports differ, the UDP port is specified as -// query parameter "discport". -// -// In the following example, the node URL describes -// a node with IP address 10.3.58.6, TCP listening port 30303 -// and UDP discovery port 30301. -// -// enode://@10.3.58.6:30303?discport=30301 -func NewEnode(rawurl string) (*Enode, error) { - node, err := enode.Parse(enode.ValidSchemes, rawurl) - if err != nil { - return nil, err - } - return &Enode{node}, nil -} - -// Enodes represents a slice of accounts. -type Enodes struct{ nodes []*enode.Node } - -// NewEnodes creates a slice of uninitialized enodes. -func NewEnodes(size int) *Enodes { - return &Enodes{ - nodes: make([]*enode.Node, size), - } -} - -// NewEnodesEmpty creates an empty slice of Enode values. -func NewEnodesEmpty() *Enodes { - return NewEnodes(0) -} - -// Size returns the number of enodes in the slice. -func (e *Enodes) Size() int { - return len(e.nodes) -} - -// Get returns the enode at the given index from the slice. -func (e *Enodes) Get(index int) (enode *Enode, _ error) { - if index < 0 || index >= len(e.nodes) { - return nil, errors.New("index out of bounds") - } - return &Enode{e.nodes[index]}, nil -} - -// Set sets the enode at the given index in the slice. -func (e *Enodes) Set(index int, enode *Enode) error { - if index < 0 || index >= len(e.nodes) { - return errors.New("index out of bounds") - } - e.nodes[index] = enode.node - return nil -} - -// Append adds a new enode element to the end of the slice. -func (e *Enodes) Append(enode *Enode) { - e.nodes = append(e.nodes, enode.node) -} diff --git a/mobile/doc.go b/mobile/doc.go deleted file mode 100644 index a4d4949ee923..000000000000 --- a/mobile/doc.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2016 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 geth contains the simplified mobile APIs to go-ethereum. -// -// The scope of this package is *not* to allow writing a custom Ethereum client -// with pieces plucked from go-ethereum, rather to allow writing native dapps on -// mobile platforms. Keep this in mind when using or extending this package! -// -// # API limitations -// -// Since gomobile cannot bridge arbitrary types between Go and Android/iOS, the -// exposed APIs need to be manually wrapped into simplified types, with custom -// constructors and getters/setters to ensure that they can be meaningfully used -// from Java/ObjC too. -// -// With this in mind, please try to limit the scope of this package and only add -// essentials without which mobile support cannot work, especially since manually -// syncing the code will be unwieldy otherwise. In the long term we might consider -// writing custom library generators, but those are out of scope now. -// -// Content wise each file in this package corresponds to an entire Go package -// from the go-ethereum repository. Please adhere to this scoping to prevent this -// package getting unmaintainable. -// -// Wrapping guidelines: -// -// Every type that is to be exposed should be wrapped into its own plain struct, -// which internally contains a single field: the original go-ethereum version. -// This is needed because gomobile cannot expose named types for now. -// -// Whenever a method argument or a return type is a custom struct, the pointer -// variant should always be used as value types crossing over between language -// boundaries might have strange behaviors. -// -// Slices of types should be converted into a single multiplicative type wrapping -// a go slice with the methods `Size`, `Get` and `Set`. Further slice operations -// should not be provided to limit the remote code complexity. Arrays should be -// avoided as much as possible since they complicate bounds checking. -// -// If a method has multiple return values (e.g. some return + an error), those -// are generated as output arguments in ObjC. To avoid weird generated names like -// ret_0 for them, please always assign names to output variables if tuples. -// -// Note, a panic *cannot* cross over language boundaries, instead will result in -// an undebuggable SEGFAULT in the process. For error handling only ever use error -// returns, which may be the only or the second return. -package geth diff --git a/mobile/ethclient.go b/mobile/ethclient.go deleted file mode 100644 index 00bcb3a2b9bc..000000000000 --- a/mobile/ethclient.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2016 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 . - -// Contains a wrapper for the Ethereum client. - -package geth - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" -) - -// EthereumClient provides access to the Ethereum APIs. -type EthereumClient struct { - client *ethclient.Client -} - -// NewEthereumClient connects a client to the given URL. -func NewEthereumClient(rawurl string) (client *EthereumClient, _ error) { - rawClient, err := ethclient.Dial(rawurl) - return &EthereumClient{rawClient}, err -} - -// GetBlockByHash returns the given full block. -func (ec *EthereumClient) GetBlockByHash(ctx *Context, hash *Hash) (block *Block, _ error) { - rawBlock, err := ec.client.BlockByHash(ctx.context, hash.hash) - return &Block{rawBlock}, err -} - -// GetBlockByNumber returns a block from the current canonical chain. If number is <0, the -// latest known block is returned. -func (ec *EthereumClient) GetBlockByNumber(ctx *Context, number int64) (block *Block, _ error) { - if number < 0 { - rawBlock, err := ec.client.BlockByNumber(ctx.context, nil) - return &Block{rawBlock}, err - } - rawBlock, err := ec.client.BlockByNumber(ctx.context, big.NewInt(number)) - return &Block{rawBlock}, err -} - -// GetHeaderByHash returns the block header with the given hash. -func (ec *EthereumClient) GetHeaderByHash(ctx *Context, hash *Hash) (header *Header, _ error) { - rawHeader, err := ec.client.HeaderByHash(ctx.context, hash.hash) - return &Header{rawHeader}, err -} - -// GetHeaderByNumber returns a block header from the current canonical chain. If number is <0, -// the latest known header is returned. -func (ec *EthereumClient) GetHeaderByNumber(ctx *Context, number int64) (header *Header, _ error) { - if number < 0 { - rawHeader, err := ec.client.HeaderByNumber(ctx.context, nil) - return &Header{rawHeader}, err - } - rawHeader, err := ec.client.HeaderByNumber(ctx.context, big.NewInt(number)) - return &Header{rawHeader}, err -} - -// GetTransactionByHash returns the transaction with the given hash. -func (ec *EthereumClient) GetTransactionByHash(ctx *Context, hash *Hash) (tx *Transaction, _ error) { - // TODO(karalabe): handle isPending - rawTx, _, err := ec.client.TransactionByHash(ctx.context, hash.hash) - return &Transaction{rawTx}, err -} - -// GetTransactionSender returns the sender address of a transaction. The transaction must -// be included in blockchain at the given block and index. -func (ec *EthereumClient) GetTransactionSender(ctx *Context, tx *Transaction, blockhash *Hash, index int) (sender *Address, _ error) { - addr, err := ec.client.TransactionSender(ctx.context, tx.tx, blockhash.hash, uint(index)) - return &Address{addr}, err -} - -// GetTransactionCount returns the total number of transactions in the given block. -func (ec *EthereumClient) GetTransactionCount(ctx *Context, hash *Hash) (count int, _ error) { - rawCount, err := ec.client.TransactionCount(ctx.context, hash.hash) - return int(rawCount), err -} - -// GetTransactionInBlock returns a single transaction at index in the given block. -func (ec *EthereumClient) GetTransactionInBlock(ctx *Context, hash *Hash, index int) (tx *Transaction, _ error) { - rawTx, err := ec.client.TransactionInBlock(ctx.context, hash.hash, uint(index)) - return &Transaction{rawTx}, err -} - -// GetTransactionReceipt returns the receipt of a transaction by transaction hash. -// Note that the receipt is not available for pending transactions. -func (ec *EthereumClient) GetTransactionReceipt(ctx *Context, hash *Hash) (receipt *Receipt, _ error) { - rawReceipt, err := ec.client.TransactionReceipt(ctx.context, hash.hash) - return &Receipt{rawReceipt}, err -} - -// SyncProgress retrieves the current progress of the sync algorithm. If there's -// no sync currently running, it returns nil. -func (ec *EthereumClient) SyncProgress(ctx *Context) (progress *SyncProgress, _ error) { - rawProgress, err := ec.client.SyncProgress(ctx.context) - if rawProgress == nil { - return nil, err - } - return &SyncProgress{*rawProgress}, err -} - -// NewHeadHandler is a client-side subscription callback to invoke on events and -// subscription failure. -type NewHeadHandler interface { - OnNewHead(header *Header) - OnError(failure string) -} - -// SubscribeNewHead subscribes to notifications about the current blockchain head -// on the given channel. -func (ec *EthereumClient) SubscribeNewHead(ctx *Context, handler NewHeadHandler, buffer int) (sub *Subscription, _ error) { - // Subscribe to the event internally - ch := make(chan *types.Header, buffer) - rawSub, err := ec.client.SubscribeNewHead(ctx.context, ch) - if err != nil { - return nil, err - } - // Start up a dispatcher to feed into the callback - go func() { - for { - select { - case header := <-ch: - handler.OnNewHead(&Header{header}) - - case err := <-rawSub.Err(): - if err != nil { - handler.OnError(err.Error()) - } - return - } - } - }() - return &Subscription{rawSub}, nil -} - -// State Access - -// GetBalanceAt returns the wei balance of the given account. -// The block number can be <0, in which case the balance is taken from the latest known block. -func (ec *EthereumClient) GetBalanceAt(ctx *Context, account *Address, number int64) (balance *BigInt, _ error) { - if number < 0 { - rawBalance, err := ec.client.BalanceAt(ctx.context, account.address, nil) - return &BigInt{rawBalance}, err - } - rawBalance, err := ec.client.BalanceAt(ctx.context, account.address, big.NewInt(number)) - return &BigInt{rawBalance}, err -} - -// GetStorageAt returns the value of key in the contract storage of the given account. -// The block number can be <0, in which case the value is taken from the latest known block. -func (ec *EthereumClient) GetStorageAt(ctx *Context, account *Address, key *Hash, number int64) (storage []byte, _ error) { - if number < 0 { - return ec.client.StorageAt(ctx.context, account.address, key.hash, nil) - } - return ec.client.StorageAt(ctx.context, account.address, key.hash, big.NewInt(number)) -} - -// GetCodeAt returns the contract code of the given account. -// The block number can be <0, in which case the code is taken from the latest known block. -func (ec *EthereumClient) GetCodeAt(ctx *Context, account *Address, number int64) (code []byte, _ error) { - if number < 0 { - return ec.client.CodeAt(ctx.context, account.address, nil) - } - return ec.client.CodeAt(ctx.context, account.address, big.NewInt(number)) -} - -// GetNonceAt returns the account nonce of the given account. -// The block number can be <0, in which case the nonce is taken from the latest known block. -func (ec *EthereumClient) GetNonceAt(ctx *Context, account *Address, number int64) (nonce int64, _ error) { - if number < 0 { - rawNonce, err := ec.client.NonceAt(ctx.context, account.address, nil) - return int64(rawNonce), err - } - rawNonce, err := ec.client.NonceAt(ctx.context, account.address, big.NewInt(number)) - return int64(rawNonce), err -} - -// Filters - -// FilterLogs executes a filter query. -func (ec *EthereumClient) FilterLogs(ctx *Context, query *FilterQuery) (logs *Logs, _ error) { - rawLogs, err := ec.client.FilterLogs(ctx.context, query.query) - if err != nil { - return nil, err - } - // Temp hack due to vm.Logs being []*vm.Log - res := make([]*types.Log, len(rawLogs)) - for i := range rawLogs { - res[i] = &rawLogs[i] - } - return &Logs{res}, nil -} - -// FilterLogsHandler is a client-side subscription callback to invoke on events and -// subscription failure. -type FilterLogsHandler interface { - OnFilterLogs(log *Log) - OnError(failure string) -} - -// SubscribeFilterLogs subscribes to the results of a streaming filter query. -func (ec *EthereumClient) SubscribeFilterLogs(ctx *Context, query *FilterQuery, handler FilterLogsHandler, buffer int) (sub *Subscription, _ error) { - // Subscribe to the event internally - ch := make(chan types.Log, buffer) - rawSub, err := ec.client.SubscribeFilterLogs(ctx.context, query.query, ch) - if err != nil { - return nil, err - } - // Start up a dispatcher to feed into the callback - go func() { - for { - select { - case log := <-ch: - handler.OnFilterLogs(&Log{&log}) - - case err := <-rawSub.Err(): - if err != nil { - handler.OnError(err.Error()) - } - return - } - } - }() - return &Subscription{rawSub}, nil -} - -// Pending State - -// GetPendingBalanceAt returns the wei balance of the given account in the pending state. -func (ec *EthereumClient) GetPendingBalanceAt(ctx *Context, account *Address) (balance *BigInt, _ error) { - rawBalance, err := ec.client.PendingBalanceAt(ctx.context, account.address) - return &BigInt{rawBalance}, err -} - -// GetPendingStorageAt returns the value of key in the contract storage of the given account in the pending state. -func (ec *EthereumClient) GetPendingStorageAt(ctx *Context, account *Address, key *Hash) (storage []byte, _ error) { - return ec.client.PendingStorageAt(ctx.context, account.address, key.hash) -} - -// GetPendingCodeAt returns the contract code of the given account in the pending state. -func (ec *EthereumClient) GetPendingCodeAt(ctx *Context, account *Address) (code []byte, _ error) { - return ec.client.PendingCodeAt(ctx.context, account.address) -} - -// GetPendingNonceAt returns the account nonce of the given account in the pending state. -// This is the nonce that should be used for the next transaction. -func (ec *EthereumClient) GetPendingNonceAt(ctx *Context, account *Address) (nonce int64, _ error) { - rawNonce, err := ec.client.PendingNonceAt(ctx.context, account.address) - return int64(rawNonce), err -} - -// GetPendingTransactionCount returns the total number of transactions in the pending state. -func (ec *EthereumClient) GetPendingTransactionCount(ctx *Context) (count int, _ error) { - rawCount, err := ec.client.PendingTransactionCount(ctx.context) - return int(rawCount), err -} - -// Contract Calling - -// CallContract executes a message call transaction, which is directly executed in the VM -// of the node, but never mined into the blockchain. -// -// blockNumber selects the block height at which the call runs. It can be <0, in which -// case the code is taken from the latest known block. Note that state from very old -// blocks might not be available. -func (ec *EthereumClient) CallContract(ctx *Context, msg *CallMsg, number int64) (output []byte, _ error) { - if number < 0 { - return ec.client.CallContract(ctx.context, msg.msg, nil) - } - return ec.client.CallContract(ctx.context, msg.msg, big.NewInt(number)) -} - -// PendingCallContract executes a message call transaction using the EVM. -// The state seen by the contract call is the pending state. -func (ec *EthereumClient) PendingCallContract(ctx *Context, msg *CallMsg) (output []byte, _ error) { - return ec.client.PendingCallContract(ctx.context, msg.msg) -} - -// SuggestGasPrice retrieves the currently suggested gas price to allow a timely -// execution of a transaction. -func (ec *EthereumClient) SuggestGasPrice(ctx *Context) (price *BigInt, _ error) { - rawPrice, err := ec.client.SuggestGasPrice(ctx.context) - return &BigInt{rawPrice}, err -} - -// EstimateGas tries to estimate the gas needed to execute a specific transaction based on -// the current pending state of the backend blockchain. There is no guarantee that this is -// the true gas limit requirement as other transactions may be added or removed by miners, -// but it should provide a basis for setting a reasonable default. -func (ec *EthereumClient) EstimateGas(ctx *Context, msg *CallMsg) (gas int64, _ error) { - rawGas, err := ec.client.EstimateGas(ctx.context, msg.msg) - return int64(rawGas), err -} - -// SendTransaction injects a signed transaction into the pending pool for execution. -// -// If the transaction was a contract creation use the TransactionReceipt method to get the -// contract address after the transaction has been mined. -func (ec *EthereumClient) SendTransaction(ctx *Context, tx *Transaction) error { - return ec.client.SendTransaction(ctx.context, tx.tx) -} diff --git a/mobile/ethereum.go b/mobile/ethereum.go deleted file mode 100644 index d5058e4e20ab..000000000000 --- a/mobile/ethereum.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the go-ethereum root package. - -package geth - -import ( - "errors" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" -) - -// Subscription represents an event subscription where events are -// delivered on a data channel. -type Subscription struct { - sub ethereum.Subscription -} - -// Unsubscribe cancels the sending of events to the data channel -// and closes the error channel. -func (s *Subscription) Unsubscribe() { - s.sub.Unsubscribe() -} - -// CallMsg contains parameters for contract calls. -type CallMsg struct { - msg ethereum.CallMsg -} - -// NewCallMsg creates an empty contract call parameter list. -func NewCallMsg() *CallMsg { - return new(CallMsg) -} - -func (msg *CallMsg) GetFrom() *Address { return &Address{msg.msg.From} } -func (msg *CallMsg) GetGas() int64 { return int64(msg.msg.Gas) } -func (msg *CallMsg) GetGasPrice() *BigInt { return &BigInt{msg.msg.GasPrice} } -func (msg *CallMsg) GetValue() *BigInt { return &BigInt{msg.msg.Value} } -func (msg *CallMsg) GetData() []byte { return msg.msg.Data } -func (msg *CallMsg) GetTo() *Address { - if to := msg.msg.To; to != nil { - return &Address{*msg.msg.To} - } - return nil -} - -func (msg *CallMsg) SetFrom(address *Address) { msg.msg.From = address.address } -func (msg *CallMsg) SetGas(gas int64) { msg.msg.Gas = uint64(gas) } -func (msg *CallMsg) SetGasPrice(price *BigInt) { msg.msg.GasPrice = price.bigint } -func (msg *CallMsg) SetValue(value *BigInt) { msg.msg.Value = value.bigint } -func (msg *CallMsg) SetData(data []byte) { msg.msg.Data = common.CopyBytes(data) } -func (msg *CallMsg) SetTo(address *Address) { - if address == nil { - msg.msg.To = nil - return - } - msg.msg.To = &address.address -} - -// SyncProgress gives progress indications when the node is synchronising with -// the Ethereum network. -type SyncProgress struct { - progress ethereum.SyncProgress -} - -func (p *SyncProgress) GetStartingBlock() int64 { return int64(p.progress.StartingBlock) } -func (p *SyncProgress) GetCurrentBlock() int64 { return int64(p.progress.CurrentBlock) } -func (p *SyncProgress) GetHighestBlock() int64 { return int64(p.progress.HighestBlock) } -func (p *SyncProgress) GetSyncedAccounts() int64 { return int64(p.progress.SyncedAccounts) } -func (p *SyncProgress) GetSyncedAccountBytes() int64 { return int64(p.progress.SyncedAccountBytes) } -func (p *SyncProgress) GetSyncedBytecodes() int64 { return int64(p.progress.SyncedBytecodes) } -func (p *SyncProgress) GetSyncedBytecodeBytes() int64 { return int64(p.progress.SyncedBytecodeBytes) } -func (p *SyncProgress) GetSyncedStorage() int64 { return int64(p.progress.SyncedStorage) } -func (p *SyncProgress) GetSyncedStorageBytes() int64 { return int64(p.progress.SyncedStorageBytes) } -func (p *SyncProgress) GetHealedTrienodes() int64 { return int64(p.progress.HealedTrienodes) } -func (p *SyncProgress) GetHealedTrienodeBytes() int64 { return int64(p.progress.HealedTrienodeBytes) } -func (p *SyncProgress) GetHealedBytecodes() int64 { return int64(p.progress.HealedBytecodes) } -func (p *SyncProgress) GetHealedBytecodeBytes() int64 { return int64(p.progress.HealedBytecodeBytes) } -func (p *SyncProgress) GetHealingTrienodes() int64 { return int64(p.progress.HealingTrienodes) } -func (p *SyncProgress) GetHealingBytecode() int64 { return int64(p.progress.HealingBytecode) } - -// Topics is a set of topic lists to filter events with. -type Topics struct{ topics [][]common.Hash } - -// NewTopics creates a slice of uninitialized Topics. -func NewTopics(size int) *Topics { - return &Topics{ - topics: make([][]common.Hash, size), - } -} - -// NewTopicsEmpty creates an empty slice of Topics values. -func NewTopicsEmpty() *Topics { - return NewTopics(0) -} - -// Size returns the number of topic lists inside the set -func (t *Topics) Size() int { - return len(t.topics) -} - -// Get returns the topic list at the given index from the slice. -func (t *Topics) Get(index int) (hashes *Hashes, _ error) { - if index < 0 || index >= len(t.topics) { - return nil, errors.New("index out of bounds") - } - return &Hashes{t.topics[index]}, nil -} - -// Set sets the topic list at the given index in the slice. -func (t *Topics) Set(index int, topics *Hashes) error { - if index < 0 || index >= len(t.topics) { - return errors.New("index out of bounds") - } - t.topics[index] = topics.hashes - return nil -} - -// Append adds a new topic list to the end of the slice. -func (t *Topics) Append(topics *Hashes) { - t.topics = append(t.topics, topics.hashes) -} - -// FilterQuery contains options for contract log filtering. -type FilterQuery struct { - query ethereum.FilterQuery -} - -// NewFilterQuery creates an empty filter query for contract log filtering. -func NewFilterQuery() *FilterQuery { - return new(FilterQuery) -} - -func (fq *FilterQuery) GetFromBlock() *BigInt { return &BigInt{fq.query.FromBlock} } -func (fq *FilterQuery) GetToBlock() *BigInt { return &BigInt{fq.query.ToBlock} } -func (fq *FilterQuery) GetAddresses() *Addresses { return &Addresses{fq.query.Addresses} } -func (fq *FilterQuery) GetTopics() *Topics { return &Topics{fq.query.Topics} } - -func (fq *FilterQuery) SetFromBlock(fromBlock *BigInt) { fq.query.FromBlock = fromBlock.bigint } -func (fq *FilterQuery) SetToBlock(toBlock *BigInt) { fq.query.ToBlock = toBlock.bigint } -func (fq *FilterQuery) SetAddresses(addresses *Addresses) { fq.query.Addresses = addresses.addresses } -func (fq *FilterQuery) SetTopics(topics *Topics) { fq.query.Topics = topics.topics } diff --git a/mobile/geth.go b/mobile/geth.go deleted file mode 100644 index 7dee93b77ca5..000000000000 --- a/mobile/geth.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the node package to support client side node -// management on mobile platforms. - -package geth - -import ( - "encoding/json" - "fmt" - "path/filepath" - - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/eth/filters" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/ethstats" - "github.com/ethereum/go-ethereum/internal/debug" - "github.com/ethereum/go-ethereum/les" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/nat" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rpc" -) - -// NodeConfig represents the collection of configuration values to fine tune the Geth -// node embedded into a mobile process. The available values are a subset of the -// entire API provided by go-ethereum to reduce the maintenance surface and dev -// complexity. -type NodeConfig struct { - // Bootstrap nodes used to establish connectivity with the rest of the network. - BootstrapNodes *Enodes - - // MaxPeers is the maximum number of peers that can be connected. If this is - // set to zero, then only the configured static and trusted peers can connect. - MaxPeers int - - // EthereumEnabled specifies whether the node should run the Ethereum protocol. - EthereumEnabled bool - - // EthereumNetworkID is the network identifier used by the Ethereum protocol to - // decide if remote peers should be accepted or not. - EthereumNetworkID int64 // uint64 in truth, but Java can't handle that... - - // EthereumGenesis is the genesis JSON to use to seed the blockchain with. An - // empty genesis state is equivalent to using the mainnet's state. - EthereumGenesis string - - // EthereumDatabaseCache is the system memory in MB to allocate for database caching. - // A minimum of 16MB is always reserved. - EthereumDatabaseCache int - - // EthereumNetStats is a netstats connection string to use to report various - // chain, transaction and node stats to a monitoring server. - // - // It has the form "nodename:secret@host:port" - EthereumNetStats string - - // Listening address of pprof server. - PprofAddress string -} - -// defaultNodeConfig contains the default node configuration values to use if all -// or some fields are missing from the user's specified list. -var defaultNodeConfig = &NodeConfig{ - BootstrapNodes: FoundationBootnodes(), - MaxPeers: 25, - EthereumEnabled: true, - EthereumNetworkID: 1, - EthereumDatabaseCache: 16, -} - -// NewNodeConfig creates a new node option set, initialized to the default values. -func NewNodeConfig() *NodeConfig { - config := *defaultNodeConfig - return &config -} - -// AddBootstrapNode adds an additional bootstrap node to the node config. -func (conf *NodeConfig) AddBootstrapNode(node *Enode) { - conf.BootstrapNodes.Append(node) -} - -// EncodeJSON encodes a NodeConfig into a JSON data dump. -func (conf *NodeConfig) EncodeJSON() (string, error) { - data, err := json.Marshal(conf) - return string(data), err -} - -// String returns a printable representation of the node config. -func (conf *NodeConfig) String() string { - return encodeOrError(conf) -} - -// Node represents a Geth Ethereum node instance. -type Node struct { - node *node.Node -} - -// NewNode creates and configures a new Geth node. -func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { - // If no or partial configurations were specified, use defaults - if config == nil { - config = NewNodeConfig() - } - if config.MaxPeers == 0 { - config.MaxPeers = defaultNodeConfig.MaxPeers - } - if config.BootstrapNodes == nil || config.BootstrapNodes.Size() == 0 { - config.BootstrapNodes = defaultNodeConfig.BootstrapNodes - } - - if config.PprofAddress != "" { - debug.StartPProf(config.PprofAddress, true) - } - - // Create the empty networking stack - nodeConf := &node.Config{ - Name: clientIdentifier, - Version: params.VersionWithMeta, - DataDir: datadir, - KeyStoreDir: filepath.Join(datadir, "keystore"), // Mobile should never use internal keystores! - P2P: p2p.Config{ - NoDiscovery: true, - DiscoveryV5: true, - BootstrapNodesV5: config.BootstrapNodes.nodes, - ListenAddr: ":0", - NAT: nat.Any(), - MaxPeers: config.MaxPeers, - }, - } - - rawStack, err := node.New(nodeConf) - if err != nil { - return nil, err - } - - debug.Memsize.Add("node", rawStack) - - var genesis *core.Genesis - if config.EthereumGenesis != "" { - // Parse the user supplied genesis spec if not mainnet - genesis = new(core.Genesis) - if err := json.Unmarshal([]byte(config.EthereumGenesis), genesis); err != nil { - rawStack.Close() - return nil, fmt.Errorf("invalid genesis spec: %v", err) - } - // If we have the Ropsten testnet, hard code the chain configs too - if config.EthereumGenesis == RopstenGenesis() { - genesis.Config = params.RopstenChainConfig - if config.EthereumNetworkID == 1 { - config.EthereumNetworkID = 3 - } - } - // If we have the Sepolia testnet, hard code the chain configs too - if config.EthereumGenesis == SepoliaGenesis() { - genesis.Config = params.SepoliaChainConfig - if config.EthereumNetworkID == 1 { - config.EthereumNetworkID = 11155111 - } - } - // If we have the Rinkeby testnet, hard code the chain configs too - if config.EthereumGenesis == RinkebyGenesis() { - genesis.Config = params.RinkebyChainConfig - if config.EthereumNetworkID == 1 { - config.EthereumNetworkID = 4 - } - } - // If we have the Goerli testnet, hard code the chain configs too - if config.EthereumGenesis == GoerliGenesis() { - genesis.Config = params.GoerliChainConfig - if config.EthereumNetworkID == 1 { - config.EthereumNetworkID = 5 - } - } - } - // Register the Ethereum protocol if requested - if config.EthereumEnabled { - ethConf := ethconfig.Defaults - ethConf.Genesis = genesis - ethConf.SyncMode = downloader.LightSync - ethConf.NetworkId = uint64(config.EthereumNetworkID) - ethConf.DatabaseCache = config.EthereumDatabaseCache - lesBackend, err := les.New(rawStack, ðConf) - if err != nil { - rawStack.Close() - return nil, fmt.Errorf("ethereum init: %v", err) - } - // Register log filter RPC API. - filterSystem := filters.NewFilterSystem(lesBackend.ApiBackend, filters.Config{ - LogCacheSize: ethConf.FilterLogCacheSize, - }) - rawStack.RegisterAPIs([]rpc.API{{ - Namespace: "eth", - Service: filters.NewFilterAPI(filterSystem, true), - }}) - // If netstats reporting is requested, do it - if config.EthereumNetStats != "" { - if err := ethstats.New(rawStack, lesBackend.ApiBackend, lesBackend.Engine(), config.EthereumNetStats); err != nil { - rawStack.Close() - return nil, fmt.Errorf("netstats init: %v", err) - } - } - } - return &Node{rawStack}, nil -} - -// Close terminates a running node along with all it's services, tearing internal state -// down. It is not possible to restart a closed node. -func (n *Node) Close() error { - return n.node.Close() -} - -// Start creates a live P2P node and starts running it. -func (n *Node) Start() error { - // TODO: recreate the node so it can be started multiple times - return n.node.Start() -} - -// GetEthereumClient retrieves a client to access the Ethereum subsystem. -func (n *Node) GetEthereumClient() (client *EthereumClient, _ error) { - rpc, err := n.node.Attach() - if err != nil { - return nil, err - } - return &EthereumClient{ethclient.NewClient(rpc)}, nil -} - -// GetNodeInfo gathers and returns a collection of metadata known about the host. -func (n *Node) GetNodeInfo() *NodeInfo { - return &NodeInfo{n.node.Server().NodeInfo()} -} - -// GetPeersInfo returns an array of metadata objects describing connected peers. -func (n *Node) GetPeersInfo() *PeerInfos { - return &PeerInfos{n.node.Server().PeersInfo()} -} diff --git a/mobile/geth_android.go b/mobile/geth_android.go deleted file mode 100644 index cfdf1c28c97f..000000000000 --- a/mobile/geth_android.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2016 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 android -// +build android - -package geth - -// clientIdentifier is a hard coded identifier to report into the network. -var clientIdentifier = "GethDroid" diff --git a/mobile/geth_ios.go b/mobile/geth_ios.go deleted file mode 100644 index aab839727fa5..000000000000 --- a/mobile/geth_ios.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2016 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 ios -// +build ios - -package geth - -// clientIdentifier is a hard coded identifier to report into the network. -var clientIdentifier = "iGeth" diff --git a/mobile/geth_other.go b/mobile/geth_other.go deleted file mode 100644 index c5cad4a7ba8e..000000000000 --- a/mobile/geth_other.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2016 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 !android && !ios -// +build !android,!ios - -package geth - -// clientIdentifier is a hard coded identifier to report into the network. -var clientIdentifier = "GethMobile" diff --git a/mobile/init.go b/mobile/init.go deleted file mode 100644 index 94f5baf28be7..000000000000 --- a/mobile/init.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2016 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 . - -// Contains initialization code for the mobile library. - -package geth - -import ( - "os" - "runtime" - - "github.com/ethereum/go-ethereum/log" -) - -func init() { - // Initialize the logger - log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) - - // Initialize the goroutine count - runtime.GOMAXPROCS(runtime.NumCPU()) -} diff --git a/mobile/interface.go b/mobile/interface.go deleted file mode 100644 index 132f7ac9a5a0..000000000000 --- a/mobile/interface.go +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2016 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 . - -// Contains perverted wrappers to allow crossing over empty interfaces. - -package geth - -import ( - "errors" - "math/big" - - "github.com/ethereum/go-ethereum/common" -) - -// Interface represents a wrapped version of Go's interface{}, with the capacity -// to store arbitrary data types. -// -// Since it's impossible to get the arbitrary-ness converted between Go and mobile -// platforms, we're using explicit getters and setters for the conversions. There -// is of course no point in enumerating everything, just enough to support the -// contract bindings requiring client side generated code. -type Interface struct { - object interface{} -} - -// NewInterface creates a new empty interface that can be used to pass around -// generic types. -func NewInterface() *Interface { - return new(Interface) -} - -func (i *Interface) SetBool(b bool) { i.object = &b } -func (i *Interface) SetBools(bs *Bools) { i.object = &bs.bools } -func (i *Interface) SetString(str string) { i.object = &str } -func (i *Interface) SetStrings(strs *Strings) { i.object = &strs.strs } -func (i *Interface) SetBinary(binary []byte) { b := common.CopyBytes(binary); i.object = &b } -func (i *Interface) SetBinaries(binaries *Binaries) { i.object = &binaries.binaries } -func (i *Interface) SetAddress(address *Address) { i.object = &address.address } -func (i *Interface) SetAddresses(addrs *Addresses) { i.object = &addrs.addresses } -func (i *Interface) SetHash(hash *Hash) { i.object = &hash.hash } -func (i *Interface) SetHashes(hashes *Hashes) { i.object = &hashes.hashes } -func (i *Interface) SetInt8(n int8) { i.object = &n } -func (i *Interface) SetInt16(n int16) { i.object = &n } -func (i *Interface) SetInt32(n int32) { i.object = &n } -func (i *Interface) SetInt64(n int64) { i.object = &n } -func (i *Interface) SetInt8s(bigints *BigInts) { - ints := make([]int8, 0, bigints.Size()) - for _, bi := range bigints.bigints { - ints = append(ints, int8(bi.Int64())) - } - i.object = &ints -} -func (i *Interface) SetInt16s(bigints *BigInts) { - ints := make([]int16, 0, bigints.Size()) - for _, bi := range bigints.bigints { - ints = append(ints, int16(bi.Int64())) - } - i.object = &ints -} -func (i *Interface) SetInt32s(bigints *BigInts) { - ints := make([]int32, 0, bigints.Size()) - for _, bi := range bigints.bigints { - ints = append(ints, int32(bi.Int64())) - } - i.object = &ints -} -func (i *Interface) SetInt64s(bigints *BigInts) { - ints := make([]int64, 0, bigints.Size()) - for _, bi := range bigints.bigints { - ints = append(ints, bi.Int64()) - } - i.object = &ints -} -func (i *Interface) SetUint8(bigint *BigInt) { n := uint8(bigint.bigint.Uint64()); i.object = &n } -func (i *Interface) SetUint16(bigint *BigInt) { n := uint16(bigint.bigint.Uint64()); i.object = &n } -func (i *Interface) SetUint32(bigint *BigInt) { n := uint32(bigint.bigint.Uint64()); i.object = &n } -func (i *Interface) SetUint64(bigint *BigInt) { n := bigint.bigint.Uint64(); i.object = &n } -func (i *Interface) SetUint8s(bigints *BigInts) { - ints := make([]uint8, 0, bigints.Size()) - for _, bi := range bigints.bigints { - ints = append(ints, uint8(bi.Uint64())) - } - i.object = &ints -} -func (i *Interface) SetUint16s(bigints *BigInts) { - ints := make([]uint16, 0, bigints.Size()) - for _, bi := range bigints.bigints { - ints = append(ints, uint16(bi.Uint64())) - } - i.object = &ints -} -func (i *Interface) SetUint32s(bigints *BigInts) { - ints := make([]uint32, 0, bigints.Size()) - for _, bi := range bigints.bigints { - ints = append(ints, uint32(bi.Uint64())) - } - i.object = &ints -} -func (i *Interface) SetUint64s(bigints *BigInts) { - ints := make([]uint64, 0, bigints.Size()) - for _, bi := range bigints.bigints { - ints = append(ints, bi.Uint64()) - } - i.object = &ints -} -func (i *Interface) SetBigInt(bigint *BigInt) { i.object = &bigint.bigint } -func (i *Interface) SetBigInts(bigints *BigInts) { i.object = &bigints.bigints } - -func (i *Interface) SetDefaultBool() { i.object = new(bool) } -func (i *Interface) SetDefaultBools() { i.object = new([]bool) } -func (i *Interface) SetDefaultString() { i.object = new(string) } -func (i *Interface) SetDefaultStrings() { i.object = new([]string) } -func (i *Interface) SetDefaultBinary() { i.object = new([]byte) } -func (i *Interface) SetDefaultBinaries() { i.object = new([][]byte) } -func (i *Interface) SetDefaultAddress() { i.object = new(common.Address) } -func (i *Interface) SetDefaultAddresses() { i.object = new([]common.Address) } -func (i *Interface) SetDefaultHash() { i.object = new(common.Hash) } -func (i *Interface) SetDefaultHashes() { i.object = new([]common.Hash) } -func (i *Interface) SetDefaultInt8() { i.object = new(int8) } -func (i *Interface) SetDefaultInt8s() { i.object = new([]int8) } -func (i *Interface) SetDefaultInt16() { i.object = new(int16) } -func (i *Interface) SetDefaultInt16s() { i.object = new([]int16) } -func (i *Interface) SetDefaultInt32() { i.object = new(int32) } -func (i *Interface) SetDefaultInt32s() { i.object = new([]int32) } -func (i *Interface) SetDefaultInt64() { i.object = new(int64) } -func (i *Interface) SetDefaultInt64s() { i.object = new([]int64) } -func (i *Interface) SetDefaultUint8() { i.object = new(uint8) } -func (i *Interface) SetDefaultUint8s() { i.object = new([]uint8) } -func (i *Interface) SetDefaultUint16() { i.object = new(uint16) } -func (i *Interface) SetDefaultUint16s() { i.object = new([]uint16) } -func (i *Interface) SetDefaultUint32() { i.object = new(uint32) } -func (i *Interface) SetDefaultUint32s() { i.object = new([]uint32) } -func (i *Interface) SetDefaultUint64() { i.object = new(uint64) } -func (i *Interface) SetDefaultUint64s() { i.object = new([]uint64) } -func (i *Interface) SetDefaultBigInt() { i.object = new(*big.Int) } -func (i *Interface) SetDefaultBigInts() { i.object = new([]*big.Int) } - -func (i *Interface) GetBool() bool { return *i.object.(*bool) } -func (i *Interface) GetBools() *Bools { return &Bools{*i.object.(*[]bool)} } -func (i *Interface) GetString() string { return *i.object.(*string) } -func (i *Interface) GetStrings() *Strings { return &Strings{*i.object.(*[]string)} } -func (i *Interface) GetBinary() []byte { return *i.object.(*[]byte) } -func (i *Interface) GetBinaries() *Binaries { return &Binaries{*i.object.(*[][]byte)} } -func (i *Interface) GetAddress() *Address { return &Address{*i.object.(*common.Address)} } -func (i *Interface) GetAddresses() *Addresses { return &Addresses{*i.object.(*[]common.Address)} } -func (i *Interface) GetHash() *Hash { return &Hash{*i.object.(*common.Hash)} } -func (i *Interface) GetHashes() *Hashes { return &Hashes{*i.object.(*[]common.Hash)} } -func (i *Interface) GetInt8() int8 { return *i.object.(*int8) } -func (i *Interface) GetInt16() int16 { return *i.object.(*int16) } -func (i *Interface) GetInt32() int32 { return *i.object.(*int32) } -func (i *Interface) GetInt64() int64 { return *i.object.(*int64) } -func (i *Interface) GetInt8s() *BigInts { - val := i.object.(*[]int8) - bigints := NewBigInts(len(*val)) - for i, v := range *val { - bigints.Set(i, &BigInt{new(big.Int).SetInt64(int64(v))}) - } - return bigints -} -func (i *Interface) GetInt16s() *BigInts { - val := i.object.(*[]int16) - bigints := NewBigInts(len(*val)) - for i, v := range *val { - bigints.Set(i, &BigInt{new(big.Int).SetInt64(int64(v))}) - } - return bigints -} -func (i *Interface) GetInt32s() *BigInts { - val := i.object.(*[]int32) - bigints := NewBigInts(len(*val)) - for i, v := range *val { - bigints.Set(i, &BigInt{new(big.Int).SetInt64(int64(v))}) - } - return bigints -} -func (i *Interface) GetInt64s() *BigInts { - val := i.object.(*[]int64) - bigints := NewBigInts(len(*val)) - for i, v := range *val { - bigints.Set(i, &BigInt{new(big.Int).SetInt64(v)}) - } - return bigints -} -func (i *Interface) GetUint8() *BigInt { - return &BigInt{new(big.Int).SetUint64(uint64(*i.object.(*uint8)))} -} -func (i *Interface) GetUint16() *BigInt { - return &BigInt{new(big.Int).SetUint64(uint64(*i.object.(*uint16)))} -} -func (i *Interface) GetUint32() *BigInt { - return &BigInt{new(big.Int).SetUint64(uint64(*i.object.(*uint32)))} -} -func (i *Interface) GetUint64() *BigInt { - return &BigInt{new(big.Int).SetUint64(*i.object.(*uint64))} -} -func (i *Interface) GetUint8s() *BigInts { - val := i.object.(*[]uint8) - bigints := NewBigInts(len(*val)) - for i, v := range *val { - bigints.Set(i, &BigInt{new(big.Int).SetUint64(uint64(v))}) - } - return bigints -} -func (i *Interface) GetUint16s() *BigInts { - val := i.object.(*[]uint16) - bigints := NewBigInts(len(*val)) - for i, v := range *val { - bigints.Set(i, &BigInt{new(big.Int).SetUint64(uint64(v))}) - } - return bigints -} -func (i *Interface) GetUint32s() *BigInts { - val := i.object.(*[]uint32) - bigints := NewBigInts(len(*val)) - for i, v := range *val { - bigints.Set(i, &BigInt{new(big.Int).SetUint64(uint64(v))}) - } - return bigints -} -func (i *Interface) GetUint64s() *BigInts { - val := i.object.(*[]uint64) - bigints := NewBigInts(len(*val)) - for i, v := range *val { - bigints.Set(i, &BigInt{new(big.Int).SetUint64(v)}) - } - return bigints -} -func (i *Interface) GetBigInt() *BigInt { return &BigInt{*i.object.(**big.Int)} } -func (i *Interface) GetBigInts() *BigInts { return &BigInts{*i.object.(*[]*big.Int)} } - -// Interfaces is a slices of wrapped generic objects. -type Interfaces struct { - objects []interface{} -} - -// NewInterfaces creates a slice of uninitialized interfaces. -func NewInterfaces(size int) *Interfaces { - return &Interfaces{objects: make([]interface{}, size)} -} - -// Size returns the number of interfaces in the slice. -func (i *Interfaces) Size() int { - return len(i.objects) -} - -// Get returns the bigint at the given index from the slice. -// Notably the returned value can be changed without affecting the -// interfaces itself. -func (i *Interfaces) Get(index int) (iface *Interface, _ error) { - if index < 0 || index >= len(i.objects) { - return nil, errors.New("index out of bounds") - } - return &Interface{object: i.objects[index]}, nil -} - -// Set sets the big int at the given index in the slice. -func (i *Interfaces) Set(index int, object *Interface) error { - if index < 0 || index >= len(i.objects) { - return errors.New("index out of bounds") - } - i.objects[index] = object.object - return nil -} diff --git a/mobile/interface_test.go b/mobile/interface_test.go deleted file mode 100644 index 4bd1af47aa1d..000000000000 --- a/mobile/interface_test.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2019 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 geth - -import ( - "fmt" - "math/big" - "reflect" - "testing" - - "github.com/ethereum/go-ethereum/common" -) - -func TestInterfaceGetSet(t *testing.T) { - var tests = []struct { - method string - input interface{} - expect interface{} - }{ - {"Bool", true, true}, - {"Bool", false, false}, - {"Bools", &Bools{[]bool{false, true}}, &Bools{[]bool{false, true}}}, - {"String", "go-ethereum", "go-ethereum"}, - {"Strings", &Strings{strs: []string{"hello", "world"}}, &Strings{strs: []string{"hello", "world"}}}, - {"Binary", []byte{0x01, 0x02}, []byte{0x01, 0x02}}, - {"Binaries", &Binaries{[][]byte{{0x01, 0x02}, {0x03, 0x04}}}, &Binaries{[][]byte{{0x01, 0x02}, {0x03, 0x04}}}}, - {"Address", &Address{common.HexToAddress("deadbeef")}, &Address{common.HexToAddress("deadbeef")}}, - {"Addresses", &Addresses{[]common.Address{common.HexToAddress("deadbeef"), common.HexToAddress("cafebabe")}}, &Addresses{[]common.Address{common.HexToAddress("deadbeef"), common.HexToAddress("cafebabe")}}}, - {"Hash", &Hash{common.HexToHash("deadbeef")}, &Hash{common.HexToHash("deadbeef")}}, - {"Hashes", &Hashes{[]common.Hash{common.HexToHash("deadbeef"), common.HexToHash("cafebabe")}}, &Hashes{[]common.Hash{common.HexToHash("deadbeef"), common.HexToHash("cafebabe")}}}, - {"Int8", int8(1), int8(1)}, - {"Int16", int16(1), int16(1)}, - {"Int32", int32(1), int32(1)}, - {"Int64", int64(1), int64(1)}, - {"Int8s", &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}, &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}}, - {"Int16s", &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}, &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}}, - {"Int32s", &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}, &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}}, - {"Int64s", &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}, &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}}, - {"Uint8", NewBigInt(1), NewBigInt(1)}, - {"Uint16", NewBigInt(1), NewBigInt(1)}, - {"Uint32", NewBigInt(1), NewBigInt(1)}, - {"Uint64", NewBigInt(1), NewBigInt(1)}, - {"Uint8s", &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}, &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}}, - {"Uint16s", &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}, &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}}, - {"Uint32s", &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}, &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}}, - {"Uint64s", &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}, &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}}, - {"BigInt", NewBigInt(1), NewBigInt(1)}, - {"BigInts", &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}, &BigInts{[]*big.Int{big.NewInt(1), big.NewInt(2)}}}, - } - - args := NewInterfaces(len(tests)) - - callFn := func(receiver interface{}, method string, arg interface{}) interface{} { - rval := reflect.ValueOf(receiver) - rval.MethodByName(fmt.Sprintf("Set%s", method)).Call([]reflect.Value{reflect.ValueOf(arg)}) - res := rval.MethodByName(fmt.Sprintf("Get%s", method)).Call(nil) - if len(res) > 0 { - return res[0].Interface() - } - return nil - } - - for index, c := range tests { - // In theory the change of iface shouldn't effect the args value - iface, _ := args.Get(index) - result := callFn(iface, c.method, c.input) - if !reflect.DeepEqual(result, c.expect) { - t.Errorf("Interface get/set mismatch, want %v, got %v", c.expect, result) - } - // Check whether the underlying value in args is still zero - iface, _ = args.Get(index) - if iface.object != nil { - t.Error("Get operation is not write safe") - } - } -} diff --git a/mobile/logger.go b/mobile/logger.go deleted file mode 100644 index 7078c4fd2c83..000000000000 --- a/mobile/logger.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2016 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 geth - -import ( - "os" - - "github.com/ethereum/go-ethereum/log" -) - -// SetVerbosity sets the global verbosity level (between 0 and 6 - see logger/verbosity.go). -func SetVerbosity(level int) { - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(level), log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) -} diff --git a/mobile/p2p.go b/mobile/p2p.go deleted file mode 100644 index a80d9fff2e15..000000000000 --- a/mobile/p2p.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2016 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 . - -// Contains wrappers for the p2p package. - -package geth - -import ( - "errors" - - "github.com/ethereum/go-ethereum/p2p" -) - -// NodeInfo represents pi short summary of the information known about the host. -type NodeInfo struct { - info *p2p.NodeInfo -} - -func (ni *NodeInfo) GetID() string { return ni.info.ID } -func (ni *NodeInfo) GetName() string { return ni.info.Name } -func (ni *NodeInfo) GetEnode() string { return ni.info.Enode } -func (ni *NodeInfo) GetIP() string { return ni.info.IP } -func (ni *NodeInfo) GetDiscoveryPort() int { return ni.info.Ports.Discovery } -func (ni *NodeInfo) GetListenerPort() int { return ni.info.Ports.Listener } -func (ni *NodeInfo) GetListenerAddress() string { return ni.info.ListenAddr } -func (ni *NodeInfo) GetProtocols() *Strings { - protos := []string{} - for proto := range ni.info.Protocols { - protos = append(protos, proto) - } - return &Strings{protos} -} - -// PeerInfo represents pi short summary of the information known about pi connected peer. -type PeerInfo struct { - info *p2p.PeerInfo -} - -func (pi *PeerInfo) GetID() string { return pi.info.ID } -func (pi *PeerInfo) GetName() string { return pi.info.Name } -func (pi *PeerInfo) GetCaps() *Strings { return &Strings{pi.info.Caps} } -func (pi *PeerInfo) GetLocalAddress() string { return pi.info.Network.LocalAddress } -func (pi *PeerInfo) GetRemoteAddress() string { return pi.info.Network.RemoteAddress } - -// PeerInfos represents a slice of infos about remote peers. -type PeerInfos struct { - infos []*p2p.PeerInfo -} - -// Size returns the number of peer info entries in the slice. -func (pi *PeerInfos) Size() int { - return len(pi.infos) -} - -// Get returns the peer info at the given index from the slice. -func (pi *PeerInfos) Get(index int) (info *PeerInfo, _ error) { - if index < 0 || index >= len(pi.infos) { - return nil, errors.New("index out of bounds") - } - return &PeerInfo{pi.infos[index]}, nil -} diff --git a/mobile/params.go b/mobile/params.go deleted file mode 100644 index 2f4240b2e4f4..000000000000 --- a/mobile/params.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the params package. - -package geth - -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/params" -) - -// MainnetGenesis returns the JSON spec to use for the main Ethereum network. It -// is actually empty since that defaults to the hard coded binary genesis block. -func MainnetGenesis() string { - return "" -} - -// RopstenGenesis returns the JSON spec to use for the Ropsten test network. -func RopstenGenesis() string { - enc, err := json.Marshal(core.DefaultRopstenGenesisBlock()) - if err != nil { - panic(err) - } - return string(enc) -} - -// SepoliaGenesis returns the JSON spec to use for the Sepolia test network. -func SepoliaGenesis() string { - enc, err := json.Marshal(core.DefaultSepoliaGenesisBlock()) - if err != nil { - panic(err) - } - return string(enc) -} - -// RinkebyGenesis returns the JSON spec to use for the Rinkeby test network -func RinkebyGenesis() string { - enc, err := json.Marshal(core.DefaultRinkebyGenesisBlock()) - if err != nil { - panic(err) - } - return string(enc) -} - -// GoerliGenesis returns the JSON spec to use for the Goerli test network -func GoerliGenesis() string { - enc, err := json.Marshal(core.DefaultGoerliGenesisBlock()) - if err != nil { - panic(err) - } - return string(enc) -} - -// FoundationBootnodes returns the enode URLs of the P2P bootstrap nodes operated -// by the foundation running the V5 discovery protocol. -func FoundationBootnodes() *Enodes { - nodes := &Enodes{nodes: make([]*enode.Node, len(params.MainnetBootnodes))} - for i, url := range params.MainnetBootnodes { - var err error - nodes.nodes[i], err = enode.Parse(enode.ValidSchemes, url) - if err != nil { - panic("invalid node URL: " + err.Error()) - } - } - return nodes -} diff --git a/mobile/primitives.go b/mobile/primitives.go deleted file mode 100644 index 7e1ab26ef039..000000000000 --- a/mobile/primitives.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2016 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 . - -// Contains various wrappers for primitive types. - -package geth - -import ( - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common" -) - -// Strings represents s slice of strs. -type Strings struct{ strs []string } - -// Size returns the number of strs in the slice. -func (s *Strings) Size() int { - return len(s.strs) -} - -// Get returns the string at the given index from the slice. -func (s *Strings) Get(index int) (str string, _ error) { - if index < 0 || index >= len(s.strs) { - return "", errors.New("index out of bounds") - } - return s.strs[index], nil -} - -// Set sets the string at the given index in the slice. -func (s *Strings) Set(index int, str string) error { - if index < 0 || index >= len(s.strs) { - return errors.New("index out of bounds") - } - s.strs[index] = str - return nil -} - -// String implements the Stringer interface. -func (s *Strings) String() string { - return fmt.Sprintf("%v", s.strs) -} - -// Bools represents a slice of bool. -type Bools struct{ bools []bool } - -// Size returns the number of bool in the slice. -func (bs *Bools) Size() int { - return len(bs.bools) -} - -// Get returns the bool at the given index from the slice. -func (bs *Bools) Get(index int) (b bool, _ error) { - if index < 0 || index >= len(bs.bools) { - return false, errors.New("index out of bounds") - } - return bs.bools[index], nil -} - -// Set sets the bool at the given index in the slice. -func (bs *Bools) Set(index int, b bool) error { - if index < 0 || index >= len(bs.bools) { - return errors.New("index out of bounds") - } - bs.bools[index] = b - return nil -} - -// String implements the Stringer interface. -func (bs *Bools) String() string { - return fmt.Sprintf("%v", bs.bools) -} - -// Binaries represents a slice of byte slice -type Binaries struct{ binaries [][]byte } - -// Size returns the number of byte slice in the slice. -func (bs *Binaries) Size() int { - return len(bs.binaries) -} - -// Get returns the byte slice at the given index from the slice. -func (bs *Binaries) Get(index int) (binary []byte, _ error) { - if index < 0 || index >= len(bs.binaries) { - return nil, errors.New("index out of bounds") - } - return common.CopyBytes(bs.binaries[index]), nil -} - -// Set sets the byte slice at the given index in the slice. -func (bs *Binaries) Set(index int, binary []byte) error { - if index < 0 || index >= len(bs.binaries) { - return errors.New("index out of bounds") - } - bs.binaries[index] = common.CopyBytes(binary) - return nil -} - -// String implements the Stringer interface. -func (bs *Binaries) String() string { - return fmt.Sprintf("%v", bs.binaries) -} diff --git a/mobile/types.go b/mobile/types.go deleted file mode 100644 index f3f92e4d4ac3..000000000000 --- a/mobile/types.go +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the core/types package. - -package geth - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rlp" -) - -type jsonEncoder interface { - EncodeJSON() (string, error) -} - -// encodeOrError tries to encode the object into json. -// If the encoding fails the resulting error is returned. -func encodeOrError(encoder jsonEncoder) string { - enc, err := encoder.EncodeJSON() - if err != nil { - return err.Error() - } - return enc -} - -// A Nonce is a 64-bit hash which proves (combined with the mix-hash) that -// a sufficient amount of computation has been carried out on a block. -type Nonce struct { - nonce types.BlockNonce -} - -// GetBytes retrieves the byte representation of the block nonce. -func (n *Nonce) GetBytes() []byte { - return n.nonce[:] -} - -// GetHex retrieves the hex string representation of the block nonce. -func (n *Nonce) GetHex() string { - return fmt.Sprintf("%#x", n.nonce[:]) -} - -// String returns a printable representation of the nonce. -func (n *Nonce) String() string { - return n.GetHex() -} - -// Bloom represents a 256 bit bloom filter. -type Bloom struct { - bloom types.Bloom -} - -// GetBytes retrieves the byte representation of the bloom filter. -func (b *Bloom) GetBytes() []byte { - return b.bloom[:] -} - -// GetHex retrieves the hex string representation of the bloom filter. -func (b *Bloom) GetHex() string { - return fmt.Sprintf("%#x", b.bloom[:]) -} - -// String returns a printable representation of the bloom filter. -func (b *Bloom) String() string { - return b.GetHex() -} - -// Header represents a block header in the Ethereum blockchain. -type Header struct { - header *types.Header -} - -// NewHeaderFromRLP parses a header from an RLP data dump. -func NewHeaderFromRLP(data []byte) (*Header, error) { - h := &Header{ - header: new(types.Header), - } - if err := rlp.DecodeBytes(common.CopyBytes(data), h.header); err != nil { - return nil, err - } - return h, nil -} - -// EncodeRLP encodes a header into an RLP data dump. -func (h *Header) EncodeRLP() ([]byte, error) { - return rlp.EncodeToBytes(h.header) -} - -// NewHeaderFromJSON parses a header from a JSON data dump. -func NewHeaderFromJSON(data string) (*Header, error) { - h := &Header{ - header: new(types.Header), - } - if err := json.Unmarshal([]byte(data), h.header); err != nil { - return nil, err - } - return h, nil -} - -// EncodeJSON encodes a header into a JSON data dump. -func (h *Header) EncodeJSON() (string, error) { - data, err := json.Marshal(h.header) - return string(data), err -} - -// String returns a printable representation of the header. -func (h *Header) String() string { - return encodeOrError(h) -} - -func (h *Header) GetParentHash() *Hash { return &Hash{h.header.ParentHash} } -func (h *Header) GetUncleHash() *Hash { return &Hash{h.header.UncleHash} } -func (h *Header) GetCoinbase() *Address { return &Address{h.header.Coinbase} } -func (h *Header) GetRoot() *Hash { return &Hash{h.header.Root} } -func (h *Header) GetTxHash() *Hash { return &Hash{h.header.TxHash} } -func (h *Header) GetReceiptHash() *Hash { return &Hash{h.header.ReceiptHash} } -func (h *Header) GetBloom() *Bloom { return &Bloom{h.header.Bloom} } -func (h *Header) GetDifficulty() *BigInt { return &BigInt{h.header.Difficulty} } -func (h *Header) GetNumber() int64 { return h.header.Number.Int64() } -func (h *Header) GetGasLimit() int64 { return int64(h.header.GasLimit) } -func (h *Header) GetGasUsed() int64 { return int64(h.header.GasUsed) } -func (h *Header) GetTime() int64 { return int64(h.header.Time) } -func (h *Header) GetExtra() []byte { return h.header.Extra } -func (h *Header) GetMixDigest() *Hash { return &Hash{h.header.MixDigest} } -func (h *Header) GetNonce() *Nonce { return &Nonce{h.header.Nonce} } -func (h *Header) GetHash() *Hash { return &Hash{h.header.Hash()} } - -// Headers represents a slice of headers. -type Headers struct{ headers []*types.Header } - -// Size returns the number of headers in the slice. -func (h *Headers) Size() int { - return len(h.headers) -} - -// Get returns the header at the given index from the slice. -func (h *Headers) Get(index int) (header *Header, _ error) { - if index < 0 || index >= len(h.headers) { - return nil, errors.New("index out of bounds") - } - return &Header{h.headers[index]}, nil -} - -// Block represents an entire block in the Ethereum blockchain. -type Block struct { - block *types.Block -} - -// NewBlockFromRLP parses a block from an RLP data dump. -func NewBlockFromRLP(data []byte) (*Block, error) { - b := &Block{ - block: new(types.Block), - } - if err := rlp.DecodeBytes(common.CopyBytes(data), b.block); err != nil { - return nil, err - } - return b, nil -} - -// EncodeRLP encodes a block into an RLP data dump. -func (b *Block) EncodeRLP() ([]byte, error) { - return rlp.EncodeToBytes(b.block) -} - -// NewBlockFromJSON parses a block from a JSON data dump. -func NewBlockFromJSON(data string) (*Block, error) { - b := &Block{ - block: new(types.Block), - } - if err := json.Unmarshal([]byte(data), b.block); err != nil { - return nil, err - } - return b, nil -} - -// EncodeJSON encodes a block into a JSON data dump. -func (b *Block) EncodeJSON() (string, error) { - data, err := json.Marshal(b.block) - return string(data), err -} - -// String returns a printable representation of the block. -func (b *Block) String() string { - return encodeOrError(b) -} - -func (b *Block) GetParentHash() *Hash { return &Hash{b.block.ParentHash()} } -func (b *Block) GetUncleHash() *Hash { return &Hash{b.block.UncleHash()} } -func (b *Block) GetCoinbase() *Address { return &Address{b.block.Coinbase()} } -func (b *Block) GetRoot() *Hash { return &Hash{b.block.Root()} } -func (b *Block) GetTxHash() *Hash { return &Hash{b.block.TxHash()} } -func (b *Block) GetReceiptHash() *Hash { return &Hash{b.block.ReceiptHash()} } -func (b *Block) GetBloom() *Bloom { return &Bloom{b.block.Bloom()} } -func (b *Block) GetDifficulty() *BigInt { return &BigInt{b.block.Difficulty()} } -func (b *Block) GetNumber() int64 { return b.block.Number().Int64() } -func (b *Block) GetGasLimit() int64 { return int64(b.block.GasLimit()) } -func (b *Block) GetGasUsed() int64 { return int64(b.block.GasUsed()) } -func (b *Block) GetTime() int64 { return int64(b.block.Time()) } -func (b *Block) GetExtra() []byte { return b.block.Extra() } -func (b *Block) GetMixDigest() *Hash { return &Hash{b.block.MixDigest()} } -func (b *Block) GetNonce() int64 { return int64(b.block.Nonce()) } -func (b *Block) GetHash() *Hash { return &Hash{b.block.Hash()} } -func (b *Block) GetHeader() *Header { return &Header{b.block.Header()} } -func (b *Block) GetUncles() *Headers { return &Headers{b.block.Uncles()} } -func (b *Block) GetTransactions() *Transactions { return &Transactions{b.block.Transactions()} } -func (b *Block) GetTransaction(hash *Hash) *Transaction { - return &Transaction{b.block.Transaction(hash.hash)} -} - -// Transaction represents a single Ethereum transaction. -type Transaction struct { - tx *types.Transaction -} - -// NewContractCreation creates a new transaction for deploying a new contract with -// the given properties. -func NewContractCreation(nonce int64, amount *BigInt, gasLimit int64, gasPrice *BigInt, data []byte) *Transaction { - return &Transaction{types.NewContractCreation(uint64(nonce), amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))} -} - -// NewTransaction creates a new transaction with the given properties. Contracts -// can be created by transacting with a nil recipient. -func NewTransaction(nonce int64, to *Address, amount *BigInt, gasLimit int64, gasPrice *BigInt, data []byte) *Transaction { - if to == nil { - return &Transaction{types.NewContractCreation(uint64(nonce), amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))} - } - return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))} -} - -// NewTransactionFromRLP parses a transaction from an RLP data dump. -func NewTransactionFromRLP(data []byte) (*Transaction, error) { - tx := &Transaction{ - tx: new(types.Transaction), - } - if err := rlp.DecodeBytes(common.CopyBytes(data), tx.tx); err != nil { - return nil, err - } - return tx, nil -} - -// EncodeRLP encodes a transaction into an RLP data dump. -func (tx *Transaction) EncodeRLP() ([]byte, error) { - return rlp.EncodeToBytes(tx.tx) -} - -// NewTransactionFromJSON parses a transaction from a JSON data dump. -func NewTransactionFromJSON(data string) (*Transaction, error) { - tx := &Transaction{ - tx: new(types.Transaction), - } - if err := json.Unmarshal([]byte(data), tx.tx); err != nil { - return nil, err - } - return tx, nil -} - -// EncodeJSON encodes a transaction into a JSON data dump. -func (tx *Transaction) EncodeJSON() (string, error) { - data, err := json.Marshal(tx.tx) - return string(data), err -} - -// String returns a printable representation of the transaction. -func (tx *Transaction) String() string { - return encodeOrError(tx) -} - -func (tx *Transaction) GetData() []byte { return tx.tx.Data() } -func (tx *Transaction) GetGas() int64 { return int64(tx.tx.Gas()) } -func (tx *Transaction) GetGasPrice() *BigInt { return &BigInt{tx.tx.GasPrice()} } -func (tx *Transaction) GetValue() *BigInt { return &BigInt{tx.tx.Value()} } -func (tx *Transaction) GetNonce() int64 { return int64(tx.tx.Nonce()) } - -func (tx *Transaction) GetHash() *Hash { return &Hash{tx.tx.Hash()} } -func (tx *Transaction) GetCost() *BigInt { return &BigInt{tx.tx.Cost()} } - -func (tx *Transaction) GetTo() *Address { - if to := tx.tx.To(); to != nil { - return &Address{*to} - } - return nil -} - -func (tx *Transaction) WithSignature(sig []byte, chainID *BigInt) (signedTx *Transaction, _ error) { - var signer types.Signer = types.HomesteadSigner{} - if chainID != nil { - signer = types.NewEIP155Signer(chainID.bigint) - } - rawTx, err := tx.tx.WithSignature(signer, common.CopyBytes(sig)) - return &Transaction{rawTx}, err -} - -// Transactions represents a slice of transactions. -type Transactions struct{ txs types.Transactions } - -// Size returns the number of transactions in the slice. -func (txs *Transactions) Size() int { - return len(txs.txs) -} - -// Get returns the transaction at the given index from the slice. -func (txs *Transactions) Get(index int) (tx *Transaction, _ error) { - if index < 0 || index >= len(txs.txs) { - return nil, errors.New("index out of bounds") - } - return &Transaction{txs.txs[index]}, nil -} - -// Receipt represents the results of a transaction. -type Receipt struct { - receipt *types.Receipt -} - -// NewReceiptFromRLP parses a transaction receipt from an RLP data dump. -func NewReceiptFromRLP(data []byte) (*Receipt, error) { - r := &Receipt{ - receipt: new(types.Receipt), - } - if err := rlp.DecodeBytes(common.CopyBytes(data), r.receipt); err != nil { - return nil, err - } - return r, nil -} - -// EncodeRLP encodes a transaction receipt into an RLP data dump. -func (r *Receipt) EncodeRLP() ([]byte, error) { - return rlp.EncodeToBytes(r.receipt) -} - -// NewReceiptFromJSON parses a transaction receipt from a JSON data dump. -func NewReceiptFromJSON(data string) (*Receipt, error) { - r := &Receipt{ - receipt: new(types.Receipt), - } - if err := json.Unmarshal([]byte(data), r.receipt); err != nil { - return nil, err - } - return r, nil -} - -// EncodeJSON encodes a transaction receipt into a JSON data dump. -func (r *Receipt) EncodeJSON() (string, error) { - data, err := json.Marshal(r.receipt) - return string(data), err -} - -// String returns a printable representation of the receipt. -func (r *Receipt) String() string { - return encodeOrError(r) -} - -func (r *Receipt) GetStatus() int { return int(r.receipt.Status) } -func (r *Receipt) GetPostState() []byte { return r.receipt.PostState } -func (r *Receipt) GetCumulativeGasUsed() int64 { return int64(r.receipt.CumulativeGasUsed) } -func (r *Receipt) GetBloom() *Bloom { return &Bloom{r.receipt.Bloom} } -func (r *Receipt) GetLogs() *Logs { return &Logs{r.receipt.Logs} } -func (r *Receipt) GetTxHash() *Hash { return &Hash{r.receipt.TxHash} } -func (r *Receipt) GetContractAddress() *Address { return &Address{r.receipt.ContractAddress} } -func (r *Receipt) GetGasUsed() int64 { return int64(r.receipt.GasUsed) } diff --git a/mobile/vm.go b/mobile/vm.go deleted file mode 100644 index 72093e3d5b90..000000000000 --- a/mobile/vm.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the core/types package. - -package geth - -import ( - "errors" - - "github.com/ethereum/go-ethereum/core/types" -) - -// Log represents a contract log event. These events are generated by the LOG -// opcode and stored/indexed by the node. -type Log struct { - log *types.Log -} - -func (l *Log) GetAddress() *Address { return &Address{l.log.Address} } -func (l *Log) GetTopics() *Hashes { return &Hashes{l.log.Topics} } -func (l *Log) GetData() []byte { return l.log.Data } -func (l *Log) GetBlockNumber() int64 { return int64(l.log.BlockNumber) } -func (l *Log) GetTxHash() *Hash { return &Hash{l.log.TxHash} } -func (l *Log) GetTxIndex() int { return int(l.log.TxIndex) } -func (l *Log) GetBlockHash() *Hash { return &Hash{l.log.BlockHash} } -func (l *Log) GetIndex() int { return int(l.log.Index) } - -// Logs represents a slice of VM logs. -type Logs struct{ logs []*types.Log } - -// Size returns the number of logs in the slice. -func (l *Logs) Size() int { - return len(l.logs) -} - -// Get returns the log at the given index from the slice. -func (l *Logs) Get(index int) (log *Log, _ error) { - if index < 0 || index >= len(l.logs) { - return nil, errors.New("index out of bounds") - } - return &Log{l.logs[index]}, nil -} From 877d2174fb898daefeb7e9c944a68d1c3a98c923 Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Sun, 5 Feb 2023 15:11:25 +0100 Subject: [PATCH 512/715] core/vm: improve EVM instance reusability (#26341) This change improves reusability of the EVM struct. Two methods are added: - SetBlockContext(...) - SetTracer(...) Other attributes like the TransactionContext and the StateDB can already be updated. BlockContext and Tracer are partially not updateable right now. This change fixes it and opens the potential to reuse an EVM struct in more ways. Co-authored-by: Felix Lange --- core/vm/evm.go | 10 +++- core/vm/instructions.go | 6 +- core/vm/instructions_test.go | 12 ++-- core/vm/interpreter.go | 110 ++++++++++++++++------------------- 4 files changed, 69 insertions(+), 69 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index f6a1557e821b..bc7b0ab964fa 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -133,7 +133,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), } - evm.interpreter = NewEVMInterpreter(evm, config) + evm.interpreter = NewEVMInterpreter(evm) return evm } @@ -160,6 +160,14 @@ func (evm *EVM) Interpreter() *EVMInterpreter { return evm.interpreter } +// SetBlockContext updates the block context of the EVM. +func (evm *EVM) SetBlockContext(blockCtx BlockContext) { + evm.Context = blockCtx + num := blockCtx.BlockNumber + timestamp := blockCtx.Time + evm.chainRules = evm.chainConfig.Rules(num, blockCtx.Random != nil, timestamp) +} + // Call executes the contract associated with the addr with the given input as // parameters. It also handles any necessary value transfer required and takes // the necessary steps to create accounts and reverses the state in case of an diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 886ff6323d50..77b6e02bfcc7 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -824,9 +824,9 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance) interpreter.evm.StateDB.Suicide(scope.Contract.Address()) - if interpreter.cfg.Debug { - interpreter.cfg.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) - interpreter.cfg.Tracer.CaptureExit([]byte{}, 0, nil) + if interpreter.evm.Config.Debug { + interpreter.evm.Config.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + interpreter.evm.Config.Tracer.CaptureExit([]byte{}, 0, nil) } return nil, errStopToken } diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index b4144a66fae9..61f001a692c3 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -203,7 +203,7 @@ func TestAddMod(t *testing.T) { var ( env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) stack = newstack() - evmInterpreter = NewEVMInterpreter(env, env.Config) + evmInterpreter = NewEVMInterpreter(env) pc = uint64(0) ) tests := []struct { @@ -293,7 +293,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) { env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) stack = newstack() scope = &ScopeContext{nil, stack, nil} - evmInterpreter = NewEVMInterpreter(env, env.Config) + evmInterpreter = NewEVMInterpreter(env) ) env.interpreter = evmInterpreter @@ -534,7 +534,7 @@ func TestOpMstore(t *testing.T) { env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) stack = newstack() mem = NewMemory() - evmInterpreter = NewEVMInterpreter(env, env.Config) + evmInterpreter = NewEVMInterpreter(env) ) env.interpreter = evmInterpreter @@ -560,7 +560,7 @@ func BenchmarkOpMstore(bench *testing.B) { env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) stack = newstack() mem = NewMemory() - evmInterpreter = NewEVMInterpreter(env, env.Config) + evmInterpreter = NewEVMInterpreter(env) ) env.interpreter = evmInterpreter @@ -583,7 +583,7 @@ func TestOpTstore(t *testing.T) { env = NewEVM(BlockContext{}, TxContext{}, statedb, params.TestChainConfig, Config{}) stack = newstack() mem = NewMemory() - evmInterpreter = NewEVMInterpreter(env, env.Config) + evmInterpreter = NewEVMInterpreter(env) caller = common.Address{} to = common.Address{1} contractRef = contractRef{caller} @@ -625,7 +625,7 @@ func BenchmarkOpKeccak256(bench *testing.B) { env = NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) stack = newstack() mem = NewMemory() - evmInterpreter = NewEVMInterpreter(env, env.Config) + evmInterpreter = NewEVMInterpreter(env) ) env.interpreter = evmInterpreter mem.Resize(32) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 7b040aac9e11..0ab520b90f0e 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -29,10 +29,7 @@ type Config struct { Tracer EVMLogger // Opcode logger NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages - - JumpTable *JumpTable // EVM instruction table, automatically populated if unset - - ExtraEips []int // Additional EIPS that are to be enabled + ExtraEips []int // Additional EIPS that are to be enabled } // ScopeContext contains the things that are per-call, such as stack and memory, @@ -45,8 +42,8 @@ type ScopeContext struct { // EVMInterpreter represents an EVM interpreter type EVMInterpreter struct { - evm *EVM - cfg Config + evm *EVM + table *JumpTable hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes hasherBuf common.Hash // Keccak256 hasher result array shared aross opcodes @@ -56,53 +53,48 @@ type EVMInterpreter struct { } // NewEVMInterpreter returns a new instance of the Interpreter. -func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { +func NewEVMInterpreter(evm *EVM) *EVMInterpreter { // If jump table was not initialised we set the default one. - if cfg.JumpTable == nil { - switch { - case evm.chainRules.IsShanghai: - cfg.JumpTable = &shanghaiInstructionSet - case evm.chainRules.IsMerge: - cfg.JumpTable = &mergeInstructionSet - case evm.chainRules.IsLondon: - cfg.JumpTable = &londonInstructionSet - case evm.chainRules.IsBerlin: - cfg.JumpTable = &berlinInstructionSet - case evm.chainRules.IsIstanbul: - cfg.JumpTable = &istanbulInstructionSet - case evm.chainRules.IsConstantinople: - cfg.JumpTable = &constantinopleInstructionSet - case evm.chainRules.IsByzantium: - cfg.JumpTable = &byzantiumInstructionSet - case evm.chainRules.IsEIP158: - cfg.JumpTable = &spuriousDragonInstructionSet - case evm.chainRules.IsEIP150: - cfg.JumpTable = &tangerineWhistleInstructionSet - case evm.chainRules.IsHomestead: - cfg.JumpTable = &homesteadInstructionSet - default: - cfg.JumpTable = &frontierInstructionSet - } - var extraEips []int - if len(cfg.ExtraEips) > 0 { - // Deep-copy jumptable to prevent modification of opcodes in other tables - cfg.JumpTable = copyJumpTable(cfg.JumpTable) - } - for _, eip := range cfg.ExtraEips { - if err := EnableEIP(eip, cfg.JumpTable); 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) - } - } - cfg.ExtraEips = extraEips + var table *JumpTable + switch { + 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 } - - return &EVMInterpreter{ - evm: evm, - cfg: cfg, + 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} } // Run loops and evaluates the contract's code with the given input data and returns @@ -160,13 +152,13 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( }() contract.Input = input - if in.cfg.Debug { + if in.evm.Config.Debug { defer func() { if err != nil { if !logged { - in.cfg.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) + in.evm.Config.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) } else { - in.cfg.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err) + in.evm.Config.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err) } } }() @@ -176,14 +168,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // the execution of one of the operations or until the done flag is set by the // parent context. for { - if in.cfg.Debug { + if in.evm.Config.Debug { // Capture pre-execution values for tracing. logged, pcCopy, gasCopy = false, pc, contract.Gas } // Get the operation from the jump table and validate the stack to ensure there are // enough stack items available to perform the operation. op = contract.GetOp(pc) - operation := in.cfg.JumpTable[op] + operation := in.table[op] cost = operation.constantGas // For tracing // Validate stack if sLen := stack.len(); sLen < operation.minStack { @@ -221,15 +213,15 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( return nil, ErrOutOfGas } // Do tracing before memory expansion - if in.cfg.Debug { - in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) + if in.evm.Config.Debug { + in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) logged = true } if memorySize > 0 { mem.Resize(memorySize) } - } else if in.cfg.Debug { - in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) + } else if in.evm.Config.Debug { + in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) logged = true } // execute the operation From 9826cd65bc708792a34ff4ef02b7279c2d3263cb Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 6 Feb 2023 10:21:40 +0100 Subject: [PATCH 513/715] eth/catalyst: implement engine_getPayloadBodiesByHash/Range methods (#26232) This change implements engine_getPayloadBodiesByHash and engine_getPayloadBodiesByRange, according to the specification at https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#specification-4 . Co-authored-by: Martin Holst Swende --- core/beacon/types.go | 6 ++ eth/catalyst/api.go | 60 ++++++++++++ eth/catalyst/api_test.go | 195 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 260 insertions(+), 1 deletion(-) diff --git a/core/beacon/types.go b/core/beacon/types.go index 656115c78542..4c1218d16038 100644 --- a/core/beacon/types.go +++ b/core/beacon/types.go @@ -229,3 +229,9 @@ func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadE } return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees} } + +// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1 +type ExecutionPayloadBodyV1 struct { + TransactionData []hexutil.Bytes `json:"transactions"` + Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` +} diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index c56e8bbaccaf..0706cccdc85e 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -88,6 +88,8 @@ var caps = []string{ "engine_getPayloadV2", "engine_newPayloadV1", "engine_newPayloadV2", + "engine_getPayloadBodiesByHashV1", + "engine_getPayloadBodiesByRangeV1", } type ConsensusAPI struct { @@ -756,3 +758,61 @@ func (api *ConsensusAPI) heartbeat() { func (api *ConsensusAPI) ExchangeCapabilities([]string) []string { return caps } + +// GetPayloadBodiesV1 implements engine_getPayloadBodiesByHashV1 which allows for retrieval of a list +// of block bodies by the engine api. +func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*beacon.ExecutionPayloadBodyV1 { + var bodies = make([]*beacon.ExecutionPayloadBodyV1, len(hashes)) + for i, hash := range hashes { + block := api.eth.BlockChain().GetBlockByHash(hash) + bodies[i] = getBody(block) + } + return bodies +} + +// GetPayloadBodiesByRangeV1 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range +// of block bodies by the engine api. +func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count uint64) ([]*beacon.ExecutionPayloadBodyV1, error) { + if start == 0 || count == 0 || count > 1024 { + return nil, beacon.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count)) + } + // limit count up until current + current := api.eth.BlockChain().CurrentBlock().NumberU64() + end := start + count + if end > current { + end = current + } + var bodies []*beacon.ExecutionPayloadBodyV1 + for i := start; i < end; i++ { + block := api.eth.BlockChain().GetBlockByNumber(i) + bodies = append(bodies, getBody(block)) + } + return bodies, nil +} + +func getBody(block *types.Block) *beacon.ExecutionPayloadBodyV1 { + if block == nil { + return nil + } + + var ( + body = block.Body() + txs = make([]hexutil.Bytes, len(body.Transactions)) + withdrawals = body.Withdrawals + ) + + for j, tx := range body.Transactions { + data, _ := tx.MarshalBinary() + txs[j] = hexutil.Bytes(data) + } + + // Post-shanghai withdrawals MUST be set to empty slice instead of nil + if withdrawals == nil && block.Header().WithdrawalsHash != nil { + withdrawals = make([]*types.Withdrawal, 0) + } + + return &beacon.ExecutionPayloadBodyV1{ + TransactionData: txs, + Withdrawals: withdrawals, + } +} diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index d9280e99d673..3725575596b0 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -41,6 +41,7 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" ) @@ -475,8 +476,9 @@ func TestFullAPI(t *testing.T) { setupBlocks(t, ethservice, 10, parent, callback) } -func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Block, callback func(parent *types.Block)) { +func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Block, callback func(parent *types.Block)) []*types.Block { api := NewConsensusAPI(ethservice) + var blocks []*types.Block for i := 0; i < n; i++ { callback(parent) @@ -504,7 +506,9 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Bl t.Fatal("Finalized block should be updated") } parent = ethservice.BlockChain().CurrentBlock() + blocks = append(blocks, parent) } + return blocks } func TestExchangeTransitionConfig(t *testing.T) { @@ -1225,3 +1229,192 @@ func TestNilWithdrawals(t *testing.T) { } } } + +func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { + genesis, preMergeBlocks := generateMergeChain(10, false) + n, ethservice := startEthService(t, genesis, preMergeBlocks) + + var ( + parent = ethservice.BlockChain().CurrentBlock() + // This EVM code generates a log when the contract is created. + logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") + ) + + callback := func(parent *types.Block) { + statedb, _ := ethservice.BlockChain().StateAt(parent.Root()) + nonce := statedb.GetNonce(testAddr) + tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) + ethservice.TxPool().AddLocal(tx) + } + + postMergeBlocks := setupBlocks(t, ethservice, 10, parent, callback) + return n, ethservice, append(preMergeBlocks, postMergeBlocks...) +} + +func TestGetBlockBodiesByHash(t *testing.T) { + node, eth, blocks := setupBodies(t) + api := NewConsensusAPI(eth) + defer node.Close() + + tests := []struct { + results []*types.Body + hashes []common.Hash + }{ + // First pow block + { + results: []*types.Body{eth.BlockChain().GetBlockByNumber(0).Body()}, + hashes: []common.Hash{eth.BlockChain().GetBlockByNumber(0).Hash()}, + }, + // Last pow block + { + results: []*types.Body{blocks[9].Body()}, + hashes: []common.Hash{blocks[9].Hash()}, + }, + // First post-merge block + { + results: []*types.Body{blocks[10].Body()}, + hashes: []common.Hash{blocks[10].Hash()}, + }, + // Pre & post merge blocks + { + results: []*types.Body{blocks[0].Body(), blocks[9].Body(), blocks[14].Body()}, + hashes: []common.Hash{blocks[0].Hash(), blocks[9].Hash(), blocks[14].Hash()}, + }, + // unavailable block + { + results: []*types.Body{blocks[0].Body(), nil, blocks[14].Body()}, + hashes: []common.Hash{blocks[0].Hash(), {1, 2}, blocks[14].Hash()}, + }, + // same block multiple times + { + results: []*types.Body{blocks[0].Body(), nil, blocks[0].Body(), blocks[0].Body()}, + hashes: []common.Hash{blocks[0].Hash(), {1, 2}, blocks[0].Hash(), blocks[0].Hash()}, + }, + } + + for k, test := range tests { + result := api.GetPayloadBodiesByHashV1(test.hashes) + for i, r := range result { + if !equalBody(test.results[i], r) { + t.Fatalf("test %v: invalid response: expected %+v got %+v", k, test.results[i], r) + } + } + } +} + +func TestGetBlockBodiesByRange(t *testing.T) { + node, eth, blocks := setupBodies(t) + api := NewConsensusAPI(eth) + defer node.Close() + + tests := []struct { + results []*types.Body + start uint64 + count uint64 + }{ + // Genesis + { + results: []*types.Body{blocks[0].Body()}, + start: 1, + count: 1, + }, + // First post-merge block + { + results: []*types.Body{blocks[9].Body()}, + start: 10, + count: 1, + }, + // Pre & post merge blocks + { + results: []*types.Body{blocks[7].Body(), blocks[8].Body(), blocks[9].Body(), blocks[10].Body()}, + start: 8, + count: 4, + }, + // unavailable block + { + results: []*types.Body{blocks[18].Body()}, + start: 19, + count: 3, + }, + // after range + { + results: make([]*types.Body, 0), + start: 20, + count: 2, + }, + } + + for k, test := range tests { + result, err := api.GetPayloadBodiesByRangeV1(test.start, test.count) + if err != nil { + t.Fatal(err) + } + if len(result) == len(test.results) { + for i, r := range result { + if !equalBody(test.results[i], r) { + t.Fatalf("test %v: invalid response: expected %+v got %+v", k, test.results[i], r) + } + } + } else { + t.Fatalf("invalid length want %v got %v", len(test.results), len(result)) + } + } +} + +func TestGetBlockBodiesByRangeInvalidParams(t *testing.T) { + node, eth, _ := setupBodies(t) + api := NewConsensusAPI(eth) + defer node.Close() + + tests := []struct { + start uint64 + count uint64 + }{ + // Genesis + { + start: 0, + count: 1, + }, + // No block requested + { + start: 1, + count: 0, + }, + // Genesis & no block + { + start: 0, + count: 0, + }, + // More than 1024 blocks + { + start: 1, + count: 1025, + }, + } + + for _, test := range tests { + result, err := api.GetPayloadBodiesByRangeV1(test.start, test.count) + if err == nil { + t.Fatalf("expected error, got %v", result) + } + } +} + +func equalBody(a *types.Body, b *beacon.ExecutionPayloadBodyV1) bool { + if a == nil && b == nil { + return true + } else if a == nil || b == nil { + return false + } + var want []hexutil.Bytes + for _, tx := range a.Transactions { + data, _ := tx.MarshalBinary() + want = append(want, hexutil.Bytes(data)) + } + aBytes, errA := rlp.EncodeToBytes(want) + bBytes, errB := rlp.EncodeToBytes(b.TransactionData) + if errA != errB { + return false + } + return bytes.Equal(aBytes, bBytes) +} From bd726f86b8210aa88e666230f005552b70b55bd6 Mon Sep 17 00:00:00 2001 From: delihiros Date: Mon, 6 Feb 2023 19:18:50 +0900 Subject: [PATCH 514/715] readme: fix broken link (#26612) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff58887383aa..8d104e150e9f 100644 --- a/README.md +++ b/README.md @@ -363,7 +363,7 @@ Please make sure your contributions adhere to our coding guidelines: * Commit messages should be prefixed with the package(s) they modify. * E.g. "eth, rpc: make trace configs optional" -Please see the [Developers' Guide](https://geth.ethereum.org/docs/developers/devguide) +Please see the [Developers' Guide](https://geth.ethereum.org/docs/developers/geth-developer/dev-guide) for more details on configuring your environment, managing project dependencies, and testing procedures. From 8e92881a3dd3a0dff98c54267ecdf4a01d6c74a6 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 6 Feb 2023 07:25:42 -0500 Subject: [PATCH 515/715] rpc: fix off-by-one in ipc endpoint length check (#26614) This change fixes a minor flaw in the check for ipc endpoint length. The max_path_size is the max path that an ipc endpoint can have, which is 208. However, that size concerns the null-terminated pathname, so we need to account for an extra null-character too. --- rpc/ipc_unix.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rpc/ipc_unix.go b/rpc/ipc_unix.go index 249a9cf044dc..9876347708a6 100644 --- a/rpc/ipc_unix.go +++ b/rpc/ipc_unix.go @@ -31,8 +31,9 @@ import ( // ipcListen will create a Unix socket on the given endpoint. func ipcListen(endpoint string) (net.Listener, error) { - if len(endpoint) > int(max_path_size) { - log.Warn(fmt.Sprintf("The ipc endpoint is longer than %d characters. ", max_path_size), + // account for null-terminator too + if len(endpoint)+1 > int(max_path_size) { + log.Warn(fmt.Sprintf("The ipc endpoint is longer than %d characters. ", max_path_size-1), "endpoint", endpoint) } From 918aed4e314f1db27191c0b0611ff02d3759122c Mon Sep 17 00:00:00 2001 From: raulk Date: Mon, 6 Feb 2023 12:41:29 +0000 Subject: [PATCH 516/715] core/vm: add bn256ScalarMul testcase for zero scalar value (#26607) EIP-196 allows a zero value in the scalar argument to precompile `0x07`. This change adds a test for that case. --- core/vm/testdata/precompiles/bn256ScalarMul.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/vm/testdata/precompiles/bn256ScalarMul.json b/core/vm/testdata/precompiles/bn256ScalarMul.json index 2a28f6304bfa..b0427fcc0555 100644 --- a/core/vm/testdata/precompiles/bn256ScalarMul.json +++ b/core/vm/testdata/precompiles/bn256ScalarMul.json @@ -124,5 +124,12 @@ "Name": "cdetrio15", "Gas": 6000, "NoBenchmark": true + }, + { + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "zeroScalar", + "Gas": 6000, + "NoBenchmark": true } ] \ No newline at end of file From 10c14847afd43b76636600f6ab4670e778160747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Mon, 6 Feb 2023 15:10:46 +0100 Subject: [PATCH 517/715] README: remove text about GPU mining (#26609) Co-authored-by: Felix Lange --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 8d104e150e9f..2a9006eaf925 100644 --- a/README.md +++ b/README.md @@ -321,12 +321,8 @@ also need to configure a miner to process transactions and create new blocks for #### Running a private miner -Mining on the public Ethereum network is a complex task as it's only feasible using GPUs, -requiring an OpenCL or CUDA enabled `ethminer` instance. For information on such a -setup, please consult the [EtherMining subreddit](https://www.reddit.com/r/EtherMining/) -and the [ethminer](https://github.com/ethereum-mining/ethminer) repository. -In a private network setting, however, a single CPU miner instance is more than enough for +In a private network setting a single CPU miner instance is more than enough for practical purposes as it can produce a stable stream of blocks at the correct intervals without needing heavy resources (consider running on a single thread, no need for multiple ones either). To start a `geth` instance for mining, run it with all your usual flags, extended From 8860b3975429d0b1160a51796aac7e53e04af952 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 6 Feb 2023 10:28:40 -0500 Subject: [PATCH 518/715] all: prepare for path-based trie storage (#26603) This PR moves some trie-related db accessor methods to a different file, and also removes the schema type. Instead of the schema type, a string is used to distinguish between hashbased/pathbased db accessors. This also moves some code from trie package to rawdb package. This PR is intended to be a no-functionality-change prep PR for #25963 . --------- Co-authored-by: Gary Rong --- cmd/geth/snapshot.go | 4 +- core/rawdb/accessors_state.go | 48 ++--- core/rawdb/accessors_trie.go | 263 +++++++++++++++++++++++++ core/rawdb/schema.go | 16 +- core/state/pruner/pruner.go | 4 +- core/state/snapshot/conversion.go | 12 +- core/state/snapshot/generate_test.go | 4 +- core/state/snapshot/snapshot.go | 4 +- core/state/sync.go | 2 +- core/state/sync_test.go | 6 +- eth/protocols/eth/handler_test.go | 2 +- eth/protocols/snap/sync.go | 18 +- eth/protocols/snap/sync_test.go | 10 +- les/downloader/downloader.go | 2 +- les/downloader/statesync.go | 3 +- tests/fuzzers/stacktrie/trie_fuzzer.go | 2 +- trie/database.go | 10 +- trie/schema.go | 96 --------- trie/sync.go | 10 +- trie/trie_test.go | 4 +- 20 files changed, 336 insertions(+), 184 deletions(-) create mode 100644 core/rawdb/accessors_trie.go delete mode 100644 trie/schema.go diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index a556f36a416a..ae60fb72e522 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -399,7 +399,7 @@ func traverseRawState(ctx *cli.Context) error { // Check the present for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { - blob := rawdb.ReadTrieNode(chaindb, node) + blob := rawdb.ReadLegacyTrieNode(chaindb, node) if len(blob) == 0 { log.Error("Missing trie node(account)", "hash", node) return errors.New("missing account") @@ -436,7 +436,7 @@ func traverseRawState(ctx *cli.Context) error { // Check the present for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { - blob := rawdb.ReadTrieNode(chaindb, node) + blob := rawdb.ReadLegacyTrieNode(chaindb, node) if len(blob) == 0 { log.Error("Missing trie node(storage)", "hash", node) return errors.New("missing storage") diff --git a/core/rawdb/accessors_state.go b/core/rawdb/accessors_state.go index 41e21b6ca40b..39900df23e94 100644 --- a/core/rawdb/accessors_state.go +++ b/core/rawdb/accessors_state.go @@ -28,6 +28,17 @@ func ReadPreimage(db ethdb.KeyValueReader, hash common.Hash) []byte { return data } +// WritePreimages writes the provided set of preimages to the database. +func WritePreimages(db ethdb.KeyValueWriter, preimages map[common.Hash][]byte) { + for hash, preimage := range preimages { + if err := db.Put(preimageKey(hash), preimage); err != nil { + log.Crit("Failed to store trie preimage", "err", err) + } + } + preimageCounter.Inc(int64(len(preimages))) + preimageHitCounter.Inc(int64(len(preimages))) +} + // ReadCode retrieves the contract code of the provided code hash. func ReadCode(db ethdb.KeyValueReader, hash common.Hash) []byte { // Try with the prefixed code scheme first, if not then try with legacy @@ -48,12 +59,6 @@ func ReadCodeWithPrefix(db ethdb.KeyValueReader, hash common.Hash) []byte { return data } -// ReadTrieNode retrieves the trie node of the provided hash. -func ReadTrieNode(db ethdb.KeyValueReader, hash common.Hash) []byte { - data, _ := db.Get(hash.Bytes()) - return data -} - // HasCode checks if the contract code corresponding to the // provided code hash is present in the db. func HasCode(db ethdb.KeyValueReader, hash common.Hash) bool { @@ -74,23 +79,6 @@ func HasCodeWithPrefix(db ethdb.KeyValueReader, hash common.Hash) bool { return ok } -// HasTrieNode checks if the trie node with the provided hash is present in db. -func HasTrieNode(db ethdb.KeyValueReader, hash common.Hash) bool { - ok, _ := db.Has(hash.Bytes()) - return ok -} - -// WritePreimages writes the provided set of preimages to the database. -func WritePreimages(db ethdb.KeyValueWriter, preimages map[common.Hash][]byte) { - for hash, preimage := range preimages { - if err := db.Put(preimageKey(hash), preimage); err != nil { - log.Crit("Failed to store trie preimage", "err", err) - } - } - preimageCounter.Inc(int64(len(preimages))) - preimageHitCounter.Inc(int64(len(preimages))) -} - // WriteCode writes the provided contract code database. func WriteCode(db ethdb.KeyValueWriter, hash common.Hash, code []byte) { if err := db.Put(codeKey(hash), code); err != nil { @@ -98,23 +86,9 @@ func WriteCode(db ethdb.KeyValueWriter, hash common.Hash, code []byte) { } } -// WriteTrieNode writes the provided trie node database. -func WriteTrieNode(db ethdb.KeyValueWriter, hash common.Hash, node []byte) { - if err := db.Put(hash.Bytes(), node); err != nil { - log.Crit("Failed to store trie node", "err", err) - } -} - // DeleteCode deletes the specified contract code from the database. func DeleteCode(db ethdb.KeyValueWriter, hash common.Hash) { if err := db.Delete(codeKey(hash)); err != nil { log.Crit("Failed to delete contract code", "err", err) } } - -// DeleteTrieNode deletes the specified trie node from the database. -func DeleteTrieNode(db ethdb.KeyValueWriter, hash common.Hash) { - if err := db.Delete(hash.Bytes()); err != nil { - log.Crit("Failed to delete trie node", "err", err) - } -} diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go new file mode 100644 index 000000000000..e24021302584 --- /dev/null +++ b/core/rawdb/accessors_trie.go @@ -0,0 +1,263 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see + +package rawdb + +import ( + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "golang.org/x/crypto/sha3" +) + +// HashScheme is the legacy hash-based state scheme with which trie nodes are +// stored in the disk with node hash as the database key. The advantage of this +// scheme is that different versions of trie nodes can be stored in disk, which +// is very beneficial for constructing archive nodes. The drawback is it will +// store different trie nodes on the same path to different locations on the disk +// with no data locality, and it's unfriendly for designing state pruning. +// +// Now this scheme is still kept for backward compatibility, and it will be used +// for archive node and some other tries(e.g. light trie). +const HashScheme = "hashScheme" + +// PathScheme is the new path-based state scheme with which trie nodes are stored +// in the disk with node path as the database key. This scheme will only store one +// version of state data in the disk, which means that the state pruning operation +// is native. At the same time, this scheme will put adjacent trie nodes in the same +// area of the disk with good data locality property. But this scheme needs to rely +// on extra state diffs to survive deep reorg. +const PathScheme = "pathScheme" + +// nodeHasher used to derive the hash of trie node. +type nodeHasher struct{ sha crypto.KeccakState } + +var hasherPool = sync.Pool{ + New: func() interface{} { return &nodeHasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} }, +} + +func newNodeHasher() *nodeHasher { return hasherPool.Get().(*nodeHasher) } +func returnHasherToPool(h *nodeHasher) { hasherPool.Put(h) } + +func (h *nodeHasher) hashData(data []byte) (n common.Hash) { + h.sha.Reset() + h.sha.Write(data) + h.sha.Read(n[:]) + return n +} + +// ReadAccountTrieNode retrieves the account trie node and the associated node +// hash with the specified node path. +func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) ([]byte, common.Hash) { + data, err := db.Get(accountTrieNodeKey(path)) + if err != nil { + return nil, common.Hash{} + } + hasher := newNodeHasher() + defer returnHasherToPool(hasher) + return data, hasher.hashData(data) +} + +// HasAccountTrieNode checks the account trie node presence with the specified +// node path and the associated node hash. +func HasAccountTrieNode(db ethdb.KeyValueReader, path []byte, hash common.Hash) bool { + data, err := db.Get(accountTrieNodeKey(path)) + if err != nil { + return false + } + hasher := newNodeHasher() + defer returnHasherToPool(hasher) + return hasher.hashData(data) == hash +} + +// WriteAccountTrieNode writes the provided account trie node into database. +func WriteAccountTrieNode(db ethdb.KeyValueWriter, path []byte, node []byte) { + if err := db.Put(accountTrieNodeKey(path), node); err != nil { + log.Crit("Failed to store account trie node", "err", err) + } +} + +// DeleteAccountTrieNode deletes the specified account trie node from the database. +func DeleteAccountTrieNode(db ethdb.KeyValueWriter, path []byte) { + if err := db.Delete(accountTrieNodeKey(path)); err != nil { + log.Crit("Failed to delete account trie node", "err", err) + } +} + +// ReadStorageTrieNode retrieves the storage trie node and the associated node +// hash with the specified node path. +func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) { + data, err := db.Get(storageTrieNodeKey(accountHash, path)) + if err != nil { + return nil, common.Hash{} + } + hasher := newNodeHasher() + defer returnHasherToPool(hasher) + return data, hasher.hashData(data) +} + +// HasStorageTrieNode checks the storage trie node presence with the provided +// node path and the associated node hash. +func HasStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte, hash common.Hash) bool { + data, err := db.Get(storageTrieNodeKey(accountHash, path)) + if err != nil { + return false + } + hasher := newNodeHasher() + defer returnHasherToPool(hasher) + return hasher.hashData(data) == hash +} + +// WriteStorageTrieNode writes the provided storage trie node into database. +func WriteStorageTrieNode(db ethdb.KeyValueWriter, accountHash common.Hash, path []byte, node []byte) { + if err := db.Put(storageTrieNodeKey(accountHash, path), node); err != nil { + log.Crit("Failed to store storage trie node", "err", err) + } +} + +// DeleteStorageTrieNode deletes the specified storage trie node from the database. +func DeleteStorageTrieNode(db ethdb.KeyValueWriter, accountHash common.Hash, path []byte) { + if err := db.Delete(storageTrieNodeKey(accountHash, path)); err != nil { + log.Crit("Failed to delete storage trie node", "err", err) + } +} + +// ReadLegacyTrieNode retrieves the legacy trie node with the given +// associated node hash. +func ReadLegacyTrieNode(db ethdb.KeyValueReader, hash common.Hash) []byte { + data, err := db.Get(hash.Bytes()) + if err != nil { + return nil + } + return data +} + +// HasLegacyTrieNode checks if the trie node with the provided hash is present in db. +func HasLegacyTrieNode(db ethdb.KeyValueReader, hash common.Hash) bool { + ok, _ := db.Has(hash.Bytes()) + return ok +} + +// WriteLegacyTrieNode writes the provided legacy trie node to database. +func WriteLegacyTrieNode(db ethdb.KeyValueWriter, hash common.Hash, node []byte) { + if err := db.Put(hash.Bytes(), node); err != nil { + log.Crit("Failed to store legacy trie node", "err", err) + } +} + +// DeleteLegacyTrieNode deletes the specified legacy trie node from database. +func DeleteLegacyTrieNode(db ethdb.KeyValueWriter, hash common.Hash) { + if err := db.Delete(hash.Bytes()); err != nil { + log.Crit("Failed to delete legacy trie node", "err", err) + } +} + +// HasTrieNode checks the trie node presence with the provided node info and +// the associated node hash. +func HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) bool { + switch scheme { + case HashScheme: + return HasLegacyTrieNode(db, hash) + case PathScheme: + if owner == (common.Hash{}) { + return HasAccountTrieNode(db, path, hash) + } + return HasStorageTrieNode(db, owner, path, hash) + default: + panic(fmt.Sprintf("Unknown scheme %v", scheme)) + } +} + +// ReadTrieNode retrieves the trie node from database with the provided node info +// and associated node hash. +// hashScheme-based lookup requires the following: +// - hash +// +// pathScheme-based lookup requires the following: +// - owner +// - path +func ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) []byte { + switch scheme { + case HashScheme: + return ReadLegacyTrieNode(db, hash) + case PathScheme: + var ( + blob []byte + nHash common.Hash + ) + if owner == (common.Hash{}) { + blob, nHash = ReadAccountTrieNode(db, path) + } else { + blob, nHash = ReadStorageTrieNode(db, owner, path) + } + if nHash != hash { + return nil + } + return blob + default: + panic(fmt.Sprintf("Unknown scheme %v", scheme)) + } +} + +// WriteTrieNode writes the trie node into database with the provided node info +// and associated node hash. +// hashScheme-based lookup requires the following: +// - hash +// +// pathScheme-based lookup requires the following: +// - owner +// - path +func WriteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, node []byte, scheme string) { + switch scheme { + case HashScheme: + WriteLegacyTrieNode(db, hash, node) + case PathScheme: + if owner == (common.Hash{}) { + WriteAccountTrieNode(db, path, node) + } else { + WriteStorageTrieNode(db, owner, path, node) + } + default: + panic(fmt.Sprintf("Unknown scheme %v", scheme)) + } +} + +// DeleteTrieNode deletes the trie node from database with the provided node info +// and associated node hash. +// hashScheme-based lookup requires the following: +// - hash +// +// pathScheme-based lookup requires the following: +// - owner +// - path +func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, scheme string) { + switch scheme { + case HashScheme: + DeleteLegacyTrieNode(db, hash) + case PathScheme: + if owner == (common.Hash{}) { + DeleteAccountTrieNode(db, path) + } else { + DeleteStorageTrieNode(db, owner, path) + } + default: + panic(fmt.Sprintf("Unknown scheme %v", scheme)) + } +} diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 5a670b408694..fd5ab1ad4c44 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -100,12 +100,14 @@ var ( CodePrefix = []byte("c") // CodePrefix + code hash -> account code skeletonHeaderPrefix = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header + // Path-based trie node scheme. + trieNodeAccountPrefix = []byte("A") // trieNodeAccountPrefix + hexPath -> trie node + trieNodeStoragePrefix = []byte("O") // trieNodeStoragePrefix + accountHash + hexPath -> trie node + PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage configPrefix = []byte("ethereum-config-") // config prefix for the db genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db - // Chain index prefixes (use `i` + single byte to avoid mixing data types). - // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress BloomBitsIndexPrefix = []byte("iB") @@ -236,3 +238,13 @@ func configKey(hash common.Hash) []byte { func genesisStateSpecKey(hash common.Hash) []byte { return append(genesisPrefix, hash.Bytes()...) } + +// accountTrieNodeKey = trieNodeAccountPrefix + nodePath. +func accountTrieNodeKey(path []byte) []byte { + return append(trieNodeAccountPrefix, path...) +} + +// storageTrieNodeKey = trieNodeStoragePrefix + accountHash + nodePath. +func storageTrieNodeKey(accountHash common.Hash, path []byte) []byte { + return append(append(trieNodeStoragePrefix, accountHash.Bytes()...), path...) +} diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 214699208471..b435ab609765 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -276,7 +276,7 @@ func (p *Pruner) Prune(root common.Hash) error { // Ensure the root is really present. The weak assumption // is the presence of root can indicate the presence of the // entire trie. - if !rawdb.HasTrieNode(p.db, root) { + if !rawdb.HasLegacyTrieNode(p.db, root) { // The special case is for clique based networks(rinkeby, goerli // and some other private networks), it's possible that two // consecutive blocks will have same root. In this case snapshot @@ -290,7 +290,7 @@ func (p *Pruner) Prune(root common.Hash) error { // as the pruning target. var found bool for i := len(layers) - 2; i >= 2; i-- { - if rawdb.HasTrieNode(p.db, layers[i].Root()) { + if rawdb.HasLegacyTrieNode(p.db, layers[i].Root()) { root = layers[i].Root() found = true log.Info("Selecting middle-layer as the pruning target", "root", root, "depth", i) diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index 43fee456d8e9..ebad28fc7365 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -43,7 +43,7 @@ type trieKV struct { type ( // trieGeneratorFn is the interface of trie generation which can // be implemented by different trie algorithm. - trieGeneratorFn func(db ethdb.KeyValueWriter, scheme trie.NodeScheme, owner common.Hash, in chan (trieKV), out chan (common.Hash)) + trieGeneratorFn func(db ethdb.KeyValueWriter, scheme string, owner common.Hash, in chan (trieKV), out chan (common.Hash)) // leafCallbackFn is the callback invoked at the leaves of the trie, // returns the subtrie root with the specified subtrie identifier. @@ -52,12 +52,12 @@ type ( // GenerateAccountTrieRoot takes an account iterator and reproduces the root hash. func GenerateAccountTrieRoot(it AccountIterator) (common.Hash, error) { - return generateTrieRoot(nil, nil, it, common.Hash{}, stackTrieGenerate, nil, newGenerateStats(), true) + return generateTrieRoot(nil, "", it, common.Hash{}, stackTrieGenerate, nil, newGenerateStats(), true) } // GenerateStorageTrieRoot takes a storage iterator and reproduces the root hash. func GenerateStorageTrieRoot(account common.Hash, it StorageIterator) (common.Hash, error) { - return generateTrieRoot(nil, nil, it, account, stackTrieGenerate, nil, newGenerateStats(), true) + return generateTrieRoot(nil, "", it, account, stackTrieGenerate, nil, newGenerateStats(), true) } // GenerateTrie takes the whole snapshot tree as the input, traverses all the @@ -243,7 +243,7 @@ func runReport(stats *generateStats, stop chan bool) { // generateTrieRoot generates the trie hash based on the snapshot iterator. // It can be used for generating account trie, storage trie or even the // whole state which connects the accounts and the corresponding storages. -func generateTrieRoot(db ethdb.KeyValueWriter, scheme trie.NodeScheme, it Iterator, account common.Hash, generatorFn trieGeneratorFn, leafCallback leafCallbackFn, stats *generateStats, report bool) (common.Hash, error) { +func generateTrieRoot(db ethdb.KeyValueWriter, scheme string, it Iterator, account common.Hash, generatorFn trieGeneratorFn, leafCallback leafCallbackFn, stats *generateStats, report bool) (common.Hash, error) { var ( in = make(chan trieKV) // chan to pass leaves out = make(chan common.Hash, 1) // chan to collect result @@ -361,11 +361,11 @@ func generateTrieRoot(db ethdb.KeyValueWriter, scheme trie.NodeScheme, it Iterat return stop(nil) } -func stackTrieGenerate(db ethdb.KeyValueWriter, scheme trie.NodeScheme, owner common.Hash, in chan trieKV, out chan common.Hash) { +func stackTrieGenerate(db ethdb.KeyValueWriter, scheme string, owner common.Hash, in chan trieKV, out chan common.Hash) { var nodeWriter trie.NodeWriteFunc if db != nil { nodeWriter = func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { - scheme.WriteTrieNode(db, owner, path, hash, blob) + rawdb.WriteTrieNode(db, owner, path, hash, blob, scheme) } } t := trie.NewStackTrieWithOwner(nodeWriter, owner) diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 3b44d4d481fd..bb9e231bc13b 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -117,12 +117,12 @@ func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) { accIt := snap.AccountIterator(common.Hash{}) defer accIt.Release() - snapRoot, err := generateTrieRoot(nil, nil, accIt, common.Hash{}, stackTrieGenerate, + snapRoot, err := generateTrieRoot(nil, "", accIt, common.Hash{}, stackTrieGenerate, func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { storageIt, _ := snap.StorageIterator(accountHash, common.Hash{}) defer storageIt.Release() - hash, err := generateTrieRoot(nil, nil, storageIt, accountHash, stackTrieGenerate, nil, stat, false) + hash, err := generateTrieRoot(nil, "", storageIt, accountHash, stackTrieGenerate, nil, stat, false) if err != nil { return common.Hash{}, err } diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index f8f52056dd7e..0f3fa2c7a4f0 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -776,14 +776,14 @@ func (t *Tree) Verify(root common.Hash) error { } defer acctIt.Release() - got, err := generateTrieRoot(nil, nil, acctIt, common.Hash{}, stackTrieGenerate, func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { + got, err := generateTrieRoot(nil, "", acctIt, common.Hash{}, stackTrieGenerate, func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { storageIt, err := t.StorageIterator(root, accountHash, common.Hash{}) if err != nil { return common.Hash{}, err } defer storageIt.Release() - hash, err := generateTrieRoot(nil, nil, storageIt, accountHash, stackTrieGenerate, nil, stat, false) + hash, err := generateTrieRoot(nil, "", storageIt, accountHash, stackTrieGenerate, nil, stat, false) if err != nil { return common.Hash{}, err } diff --git a/core/state/sync.go b/core/state/sync.go index b40e75f487f6..61097c6462d4 100644 --- a/core/state/sync.go +++ b/core/state/sync.go @@ -27,7 +27,7 @@ import ( ) // NewStateSync create a new state trie download scheduler. -func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error, scheme trie.NodeScheme) *trie.Sync { +func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error, scheme string) *trie.Sync { // Register the storage slot callback if the external callback is specified. var onSlot func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error if onLeaf != nil { diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 62eba60fa01c..d3b77da9b422 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -663,14 +663,14 @@ func TestIncompleteStateSync(t *testing.T) { for i, path := range addedPaths { owner, inner := trie.ResolvePath([]byte(path)) hash := addedHashes[i] - val := scheme.ReadTrieNode(dstDb, owner, inner, hash) + val := rawdb.ReadTrieNode(dstDb, owner, inner, hash, scheme) if val == nil { t.Error("missing trie node") } - scheme.DeleteTrieNode(dstDb, owner, inner, hash) + rawdb.DeleteTrieNode(dstDb, owner, inner, hash, scheme) if err := checkStateConsistency(dstDb, srcRoot); err == nil { t.Errorf("trie inconsistency not caught, missing: %v", path) } - scheme.WriteTrieNode(dstDb, owner, inner, hash, val) + rawdb.WriteTrieNode(dstDb, owner, inner, hash, val, scheme) } } diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 201dc98b6aec..b4d2574c383e 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -524,7 +524,7 @@ func testGetNodeData(t *testing.T, protocol uint, drop bool) { // Reconstruct state tree from the received data. reconstructDB := rawdb.NewMemoryDatabase() for i := 0; i < len(data); i++ { - rawdb.WriteTrieNode(reconstructDB, hashes[i], data[i]) + rawdb.WriteLegacyTrieNode(reconstructDB, hashes[i], data[i]) } // Sanity check whether all state matches. diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 1193af6769d7..052d8eaca72f 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -418,7 +418,7 @@ type SyncPeer interface { // - The peer delivers a refusal to serve the requested state type Syncer struct { db ethdb.KeyValueStore // Database to store the trie nodes into (and dedup) - scheme trie.NodeScheme // Node scheme used in node database + scheme string // Node scheme used in node database root common.Hash // Current state trie root being synced tasks []*accountTask // Current account task set being synced @@ -486,7 +486,7 @@ type Syncer struct { // NewSyncer creates a new snapshot syncer to download the Ethereum state over the // snap protocol. -func NewSyncer(db ethdb.KeyValueStore, scheme trie.NodeScheme) *Syncer { +func NewSyncer(db ethdb.KeyValueStore, scheme string) *Syncer { return &Syncer{ db: db, scheme: scheme, @@ -746,7 +746,7 @@ func (s *Syncer) loadSyncStatus() { }, } task.genTrie = trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { - s.scheme.WriteTrieNode(task.genBatch, owner, path, hash, val) + rawdb.WriteTrieNode(task.genBatch, owner, path, hash, val, s.scheme) }) for accountHash, subtasks := range task.SubTasks { for _, subtask := range subtasks { @@ -757,7 +757,7 @@ func (s *Syncer) loadSyncStatus() { }, } subtask.genTrie = trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { - s.scheme.WriteTrieNode(subtask.genBatch, owner, path, hash, val) + rawdb.WriteTrieNode(subtask.genBatch, owner, path, hash, val, s.scheme) }, accountHash) } } @@ -816,7 +816,7 @@ func (s *Syncer) loadSyncStatus() { SubTasks: make(map[common.Hash][]*storageTask), genBatch: batch, genTrie: trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { - s.scheme.WriteTrieNode(batch, owner, path, hash, val) + rawdb.WriteTrieNode(batch, owner, path, hash, val, s.scheme) }), }) log.Debug("Created account sync task", "from", next, "last", last) @@ -1842,7 +1842,7 @@ func (s *Syncer) processAccountResponse(res *accountResponse) { } // Check if the account is a contract with an unknown storage trie if account.Root != emptyRoot { - if !s.scheme.HasTrieNode(s.db, res.hashes[i], nil, account.Root) { + if !rawdb.HasTrieNode(s.db, res.hashes[i], nil, account.Root, s.scheme) { // If there was a previous large state retrieval in progress, // don't restart it from scratch. This happens if a sync cycle // is interrupted and resumed later. However, *do* update the @@ -2015,7 +2015,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { root: acc.Root, genBatch: batch, genTrie: trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { - s.scheme.WriteTrieNode(batch, owner, path, hash, val) + rawdb.WriteTrieNode(batch, owner, path, hash, val, s.scheme) }, account), }) for r.Next() { @@ -2031,7 +2031,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { root: acc.Root, genBatch: batch, genTrie: trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { - s.scheme.WriteTrieNode(batch, owner, path, hash, val) + rawdb.WriteTrieNode(batch, owner, path, hash, val, s.scheme) }, account), }) } @@ -2078,7 +2078,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) { if i < len(res.hashes)-1 || res.subTask == nil { tr := trie.NewStackTrieWithOwner(func(owner common.Hash, path []byte, hash common.Hash, val []byte) { - s.scheme.WriteTrieNode(batch, owner, path, hash, val) + rawdb.WriteTrieNode(batch, owner, path, hash, val, s.scheme) }, account) for j := 0; j < len(res.hashes[i]); j++ { tr.Update(res.hashes[i][j][:], res.slots[i][j]) diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 9b99d7e7a2d0..4cdfb9be6ed5 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -623,7 +623,7 @@ func TestSyncBloatedProof(t *testing.T) { } } -func setupSyncer(scheme trie.NodeScheme, peers ...*testPeer) *Syncer { +func setupSyncer(scheme string, peers ...*testPeer) *Syncer { stateDb := rawdb.NewMemoryDatabase() syncer := NewSyncer(stateDb, scheme) for _, peer := range peers { @@ -1366,7 +1366,7 @@ func getCodeByHash(hash common.Hash) []byte { } // makeAccountTrieNoStorage spits out a trie, along with the leafs -func makeAccountTrieNoStorage(n int) (trie.NodeScheme, *trie.Trie, entrySlice) { +func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) @@ -1398,7 +1398,7 @@ func makeAccountTrieNoStorage(n int) (trie.NodeScheme, *trie.Trie, entrySlice) { // makeBoundaryAccountTrie constructs an account trie. Instead of filling // accounts normally, this function will fill a few accounts which have // boundary hash. -func makeBoundaryAccountTrie(n int) (trie.NodeScheme, *trie.Trie, entrySlice) { +func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { var ( entries entrySlice boundaries []common.Hash @@ -1459,7 +1459,7 @@ func makeBoundaryAccountTrie(n int) (trie.NodeScheme, *trie.Trie, entrySlice) { // makeAccountTrieWithStorageWithUniqueStorage creates an account trie where each accounts // has a unique storage set. -func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) (trie.NodeScheme, *trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { +func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) (string, *trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) @@ -1514,7 +1514,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) } // makeAccountTrieWithStorage spits out a trie, along with the leafs -func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (trie.NodeScheme, *trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { +func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (string, *trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) diff --git a/les/downloader/downloader.go b/les/downloader/downloader.go index b005aa6a492f..a6ebf1d2a5cc 100644 --- a/les/downloader/downloader.go +++ b/les/downloader/downloader.go @@ -226,7 +226,7 @@ func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain Bl headerProcCh: make(chan []*types.Header, 1), quitCh: make(chan struct{}), stateCh: make(chan dataPack), - SnapSyncer: snap.NewSyncer(stateDb, nil), + SnapSyncer: snap.NewSyncer(stateDb, rawdb.HashScheme), stateSyncStart: make(chan *stateSync), //syncStatsState: stateSyncStats{ // processed: rawdb.ReadFastTrieProgress(stateDb), diff --git a/les/downloader/statesync.go b/les/downloader/statesync.go index 8816d936f722..4dacade3fae9 100644 --- a/les/downloader/statesync.go +++ b/les/downloader/statesync.go @@ -298,11 +298,10 @@ type codeTask struct { func newStateSync(d *Downloader, root common.Hash) *stateSync { // Hack the node scheme here. It's a dead code is not used // by light client at all. Just aim for passing tests. - scheme := trie.NewDatabase(rawdb.NewMemoryDatabase()).Scheme() return &stateSync{ d: d, root: root, - sched: state.NewStateSync(root, d.stateDB, nil, scheme), + sched: state.NewStateSync(root, d.stateDB, nil, rawdb.HashScheme), keccak: sha3.NewLegacyKeccak256().(crypto.KeccakState), trieTasks: make(map[string]*trieTask), codeTasks: make(map[common.Hash]*codeTask), diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 3af16bf81df7..6ac6feee9111 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -152,7 +152,7 @@ func (f *fuzzer) fuzz() int { spongeB = &spongeDb{sponge: sha3.NewLegacyKeccak256()} dbB = trie.NewDatabase(rawdb.NewDatabase(spongeB)) trieB = trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { - dbB.Scheme().WriteTrieNode(spongeB, owner, path, hash, blob) + rawdb.WriteTrieNode(spongeB, owner, path, hash, blob, dbB.Scheme()) }) vals kvs useful bool diff --git a/trie/database.go b/trie/database.go index 469c33fc84dd..477179b27b65 100644 --- a/trie/database.go +++ b/trie/database.go @@ -405,7 +405,7 @@ func (db *Database) Node(hash common.Hash) ([]byte, error) { memcacheDirtyMissMeter.Mark(1) // Content unavailable in memory, attempt to retrieve from disk - enc := rawdb.ReadTrieNode(db.diskdb, hash) + enc := rawdb.ReadLegacyTrieNode(db.diskdb, hash) if len(enc) != 0 { if db.cleans != nil { db.cleans.Set(hash[:], enc) @@ -571,7 +571,7 @@ func (db *Database) Cap(limit common.StorageSize) error { for size > limit && oldest != (common.Hash{}) { // Fetch the oldest referenced node and push into the batch node := db.dirties[oldest] - rawdb.WriteTrieNode(batch, oldest, node.rlp()) + rawdb.WriteLegacyTrieNode(batch, oldest, node.rlp()) // If we exceeded the ideal batch size, commit and reset if batch.ValueSize() >= ethdb.IdealBatchSize { @@ -703,7 +703,7 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane return err } // If we've reached an optimal batch size, commit and start over - rawdb.WriteTrieNode(batch, hash, node.rlp()) + rawdb.WriteLegacyTrieNode(batch, hash, node.rlp()) if callback != nil { callback(hash) } @@ -919,6 +919,6 @@ func (db *Database) CommitPreimages() error { } // Scheme returns the node scheme used in the database. -func (db *Database) Scheme() NodeScheme { - return &hashScheme{} +func (db *Database) Scheme() string { + return rawdb.HashScheme } diff --git a/trie/schema.go b/trie/schema.go deleted file mode 100644 index ed049faa5ce0..000000000000 --- a/trie/schema.go +++ /dev/null @@ -1,96 +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 . - -package trie - -import ( - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/ethdb" -) - -const ( - HashScheme = "hashScheme" // Identifier of hash based node scheme - - // Path-based scheme will be introduced in the following PRs. - // PathScheme = "pathScheme" // Identifier of path based node scheme -) - -// NodeScheme describes the scheme for interacting nodes in disk. -type NodeScheme interface { - // Name returns the identifier of node scheme. - Name() string - - // HasTrieNode checks the trie node presence with the provided node info and - // the associated node hash. - HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash) bool - - // ReadTrieNode retrieves the trie node from database with the provided node - // info and the associated node hash. - ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash) []byte - - // WriteTrieNode writes the trie node into database with the provided node - // info and associated node hash. - WriteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, node []byte) - - // DeleteTrieNode deletes the trie node from database with the provided node - // info and associated node hash. - DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash) - - // IsTrieNode returns an indicator if the given database key is the key of - // trie node according to the scheme. - IsTrieNode(key []byte) (bool, []byte) -} - -type hashScheme struct{} - -// Name returns the identifier of hash based scheme. -func (scheme *hashScheme) Name() string { - return HashScheme -} - -// HasTrieNode checks the trie node presence with the provided node info and -// the associated node hash. -func (scheme *hashScheme) HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash) bool { - return rawdb.HasTrieNode(db, hash) -} - -// ReadTrieNode retrieves the trie node from database with the provided node info -// and associated node hash. -func (scheme *hashScheme) ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash) []byte { - return rawdb.ReadTrieNode(db, hash) -} - -// WriteTrieNode writes the trie node into database with the provided node info -// and associated node hash. -func (scheme *hashScheme) WriteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, node []byte) { - rawdb.WriteTrieNode(db, hash, node) -} - -// DeleteTrieNode deletes the trie node from database with the provided node info -// and associated node hash. -func (scheme *hashScheme) DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash) { - rawdb.DeleteTrieNode(db, hash) -} - -// IsTrieNode returns an indicator if the given database key is the key of trie -// node according to the scheme. -func (scheme *hashScheme) IsTrieNode(key []byte) (bool, []byte) { - if len(key) == common.HashLength { - return true, key - } - return false, nil -} diff --git a/trie/sync.go b/trie/sync.go index 199766983577..46478b033a63 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -155,7 +155,7 @@ func (batch *syncMemBatch) hasCode(hash common.Hash) bool { // unknown trie hashes to retrieve, accepts node data associated with said hashes // and reconstructs the trie step by step until all is done. type Sync struct { - scheme NodeScheme // Node scheme descriptor used in database. + scheme string // Node scheme descriptor used in database. database ethdb.KeyValueReader // Persistent database to check for existing entries membatch *syncMemBatch // Memory buffer to avoid frequent database writes nodeReqs map[string]*nodeRequest // Pending requests pertaining to a trie node path @@ -165,7 +165,7 @@ type Sync struct { } // NewSync creates a new trie data download scheduler. -func NewSync(root common.Hash, database ethdb.KeyValueReader, callback LeafCallback, scheme NodeScheme) *Sync { +func NewSync(root common.Hash, database ethdb.KeyValueReader, callback LeafCallback, scheme string) *Sync { ts := &Sync{ scheme: scheme, database: database, @@ -191,7 +191,7 @@ func (s *Sync) AddSubTrie(root common.Hash, path []byte, parent common.Hash, par return } owner, inner := ResolvePath(path) - if s.scheme.HasTrieNode(s.database, owner, inner, root) { + if rawdb.HasTrieNode(s.database, owner, inner, root, s.scheme) { return } // Assemble the new sub-trie sync request @@ -349,7 +349,7 @@ func (s *Sync) Commit(dbw ethdb.Batch) error { // Dump the membatch into a database dbw for path, value := range s.membatch.nodes { owner, inner := ResolvePath([]byte(path)) - s.scheme.WriteTrieNode(dbw, owner, inner, s.membatch.hashes[path], value) + rawdb.WriteTrieNode(dbw, owner, inner, s.membatch.hashes[path], value, s.scheme) } for hash, value := range s.membatch.codes { rawdb.WriteCode(dbw, hash, value) @@ -474,7 +474,7 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { chash = common.BytesToHash(node) owner, inner = ResolvePath(child.path) ) - if s.scheme.HasTrieNode(s.database, owner, inner, chash) { + if rawdb.HasTrieNode(s.database, owner, inner, chash, s.scheme) { return } // Locally unknown node, schedule for retrieval diff --git a/trie/trie_test.go b/trie/trie_test.go index 76307ba78686..a7577040bcd1 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -898,7 +898,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { // Another sponge is used for the stacktrie commits stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} stTrie := NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { - db.Scheme().WriteTrieNode(stackTrieSponge, owner, path, hash, blob) + rawdb.WriteTrieNode(stackTrieSponge, owner, path, hash, blob, db.Scheme()) }) // Fill the trie with elements for i := 0; i < count; i++ { @@ -957,7 +957,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) { // Another sponge is used for the stacktrie commits stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} stTrie := NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { - db.Scheme().WriteTrieNode(stackTrieSponge, owner, path, hash, blob) + rawdb.WriteTrieNode(stackTrieSponge, owner, path, hash, blob, db.Scheme()) }) // Add a single small-element to the trie(s) key := make([]byte, 5) From 3a5aceed8fcfeee32c0539d60e921146a79ac53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Mon, 6 Feb 2023 16:37:58 +0100 Subject: [PATCH 519/715] beacon/engine: move core/beacon to beacon/engine (#26616) This PR moves core/beacon to beacon/engine so that beacon-chain related code has its own top level package which also can house the the beacon lightclient-code. --- {core/beacon => beacon/engine}/errors.go | 2 +- .../engine}/gen_blockparams.go | 2 +- {core/beacon => beacon/engine}/gen_ed.go | 2 +- {core/beacon => beacon/engine}/gen_epe.go | 2 +- {core/beacon => beacon/engine}/types.go | 2 +- eth/catalyst/api.go | 114 +++++++-------- eth/catalyst/api_test.go | 130 +++++++++--------- eth/catalyst/queue.go | 10 +- les/catalyst/api.go | 44 +++--- les/catalyst/api_test.go | 10 +- miner/payload_building.go | 24 ++-- miner/payload_building_test.go | 4 +- miner/stress/beacon/main.go | 20 +-- 13 files changed, 183 insertions(+), 183 deletions(-) rename {core/beacon => beacon/engine}/errors.go (99%) rename {core/beacon => beacon/engine}/gen_blockparams.go (99%) rename {core/beacon => beacon/engine}/gen_ed.go (99%) rename {core/beacon => beacon/engine}/gen_epe.go (98%) rename {core/beacon => beacon/engine}/types.go (99%) diff --git a/core/beacon/errors.go b/beacon/engine/errors.go similarity index 99% rename from core/beacon/errors.go rename to beacon/engine/errors.go index 24dc52278dcd..b2f31139256f 100644 --- a/core/beacon/errors.go +++ b/beacon/engine/errors.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package beacon +package engine import ( "github.com/ethereum/go-ethereum/common" diff --git a/core/beacon/gen_blockparams.go b/beacon/engine/gen_blockparams.go similarity index 99% rename from core/beacon/gen_blockparams.go rename to beacon/engine/gen_blockparams.go index a7df96e091c1..0dd2b52597ad 100644 --- a/core/beacon/gen_blockparams.go +++ b/beacon/engine/gen_blockparams.go @@ -1,6 +1,6 @@ // Code generated by github.com/fjl/gencodec. DO NOT EDIT. -package beacon +package engine import ( "encoding/json" diff --git a/core/beacon/gen_ed.go b/beacon/engine/gen_ed.go similarity index 99% rename from core/beacon/gen_ed.go rename to beacon/engine/gen_ed.go index 397504da7f05..336dfc6cc755 100644 --- a/core/beacon/gen_ed.go +++ b/beacon/engine/gen_ed.go @@ -1,6 +1,6 @@ // Code generated by github.com/fjl/gencodec. DO NOT EDIT. -package beacon +package engine import ( "encoding/json" diff --git a/core/beacon/gen_epe.go b/beacon/engine/gen_epe.go similarity index 98% rename from core/beacon/gen_epe.go rename to beacon/engine/gen_epe.go index 0b4d8598f7a1..cc66cef6cd3e 100644 --- a/core/beacon/gen_epe.go +++ b/beacon/engine/gen_epe.go @@ -1,6 +1,6 @@ // Code generated by github.com/fjl/gencodec. DO NOT EDIT. -package beacon +package engine import ( "encoding/json" diff --git a/core/beacon/types.go b/beacon/engine/types.go similarity index 99% rename from core/beacon/types.go rename to beacon/engine/types.go index 4c1218d16038..58f72631194f 100644 --- a/core/beacon/types.go +++ b/beacon/engine/types.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package beacon +package engine import ( "fmt" diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 0706cccdc85e..7019daf9b28f 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -24,9 +24,9 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" @@ -168,24 +168,24 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { // // If there are payloadAttributes: we try to assemble a block with the payloadAttributes // and return its payloadID. -func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { +func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { if payloadAttributes != nil && payloadAttributes.Withdrawals != nil { - return beacon.STATUS_INVALID, beacon.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1")) + return engine.STATUS_INVALID, engine.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1")) } return api.forkchoiceUpdated(update, payloadAttributes) } // ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes. -func (api *ConsensusAPI) ForkchoiceUpdatedV2(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { +func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { if payloadAttributes != nil { if err := api.verifyPayloadAttributes(payloadAttributes); err != nil { - return beacon.STATUS_INVALID, beacon.InvalidParams.With(err) + return engine.STATUS_INVALID, engine.InvalidParams.With(err) } } return api.forkchoiceUpdated(update, payloadAttributes) } -func (api *ConsensusAPI) verifyPayloadAttributes(attr *beacon.PayloadAttributes) error { +func (api *ConsensusAPI) verifyPayloadAttributes(attr *engine.PayloadAttributes) error { if !api.eth.BlockChain().Config().IsShanghai(attr.Timestamp) { // Reject payload attributes with withdrawals before shanghai if attr.Withdrawals != nil { @@ -200,14 +200,14 @@ func (api *ConsensusAPI) verifyPayloadAttributes(attr *beacon.PayloadAttributes) return nil } -func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { +func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { api.forkchoiceLock.Lock() defer api.forkchoiceLock.Unlock() log.Trace("Engine API request received", "method", "ForkchoiceUpdated", "head", update.HeadBlockHash, "finalized", update.FinalizedBlockHash, "safe", update.SafeBlockHash) if update.HeadBlockHash == (common.Hash{}) { log.Warn("Forkchoice requested update to zero hash") - return beacon.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this? + return engine.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this? } // Stash away the last update to warn the user if the beacon client goes offline api.lastForkchoiceLock.Lock() @@ -221,7 +221,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payl if block == nil { // If this block was previously invalidated, keep rejecting it here too if res := api.checkInvalidAncestor(update.HeadBlockHash, update.HeadBlockHash); res != nil { - return beacon.ForkChoiceResponse{PayloadStatus: *res, PayloadID: nil}, nil + return engine.ForkChoiceResponse{PayloadStatus: *res, PayloadID: nil}, nil } // If the head hash is unknown (was not given to us in a newPayload request), // we cannot resolve the header, so not much to do. This could be extended in @@ -230,7 +230,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payl header := api.remoteBlocks.get(update.HeadBlockHash) if header == nil { log.Warn("Forkchoice requested unknown head", "hash", update.HeadBlockHash) - return beacon.STATUS_SYNCING, nil + return engine.STATUS_SYNCING, nil } // Header advertised via a past newPayload request. Start syncing to it. // Before we do however, make sure any legacy sync in switched off so we @@ -241,9 +241,9 @@ func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payl } log.Info("Forkchoice requested sync to new head", "number", header.Number, "hash", header.Hash()) if err := api.eth.Downloader().BeaconSync(api.eth.SyncMode(), header); err != nil { - return beacon.STATUS_SYNCING, err + return engine.STATUS_SYNCING, err } - return beacon.STATUS_SYNCING, nil + return engine.STATUS_SYNCING, nil } // Block is known locally, just sanity check that the beacon client does not // attempt to push us back to before the merge. @@ -255,27 +255,27 @@ func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payl ) if td == nil || (block.NumberU64() > 0 && ptd == nil) { log.Error("TDs unavailable for TTD check", "number", block.NumberU64(), "hash", update.HeadBlockHash, "td", td, "parent", block.ParentHash(), "ptd", ptd) - return beacon.STATUS_INVALID, errors.New("TDs unavailable for TDD check") + return engine.STATUS_INVALID, errors.New("TDs unavailable for TDD check") } if td.Cmp(ttd) < 0 { log.Error("Refusing beacon update to pre-merge", "number", block.NumberU64(), "hash", update.HeadBlockHash, "diff", block.Difficulty(), "age", common.PrettyAge(time.Unix(int64(block.Time()), 0))) - return beacon.ForkChoiceResponse{PayloadStatus: beacon.INVALID_TERMINAL_BLOCK, PayloadID: nil}, nil + return engine.ForkChoiceResponse{PayloadStatus: engine.INVALID_TERMINAL_BLOCK, PayloadID: nil}, nil } if block.NumberU64() > 0 && ptd.Cmp(ttd) >= 0 { log.Error("Parent block is already post-ttd", "number", block.NumberU64(), "hash", update.HeadBlockHash, "diff", block.Difficulty(), "age", common.PrettyAge(time.Unix(int64(block.Time()), 0))) - return beacon.ForkChoiceResponse{PayloadStatus: beacon.INVALID_TERMINAL_BLOCK, PayloadID: nil}, nil + return engine.ForkChoiceResponse{PayloadStatus: engine.INVALID_TERMINAL_BLOCK, PayloadID: nil}, nil } } - valid := func(id *beacon.PayloadID) beacon.ForkChoiceResponse { - return beacon.ForkChoiceResponse{ - PayloadStatus: beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &update.HeadBlockHash}, + valid := func(id *engine.PayloadID) engine.ForkChoiceResponse { + return engine.ForkChoiceResponse{ + PayloadStatus: engine.PayloadStatusV1{Status: engine.VALID, LatestValidHash: &update.HeadBlockHash}, PayloadID: id, } } if rawdb.ReadCanonicalHash(api.eth.ChainDb(), block.NumberU64()) != update.HeadBlockHash { // Block is not canonical, set head. if latestValid, err := api.eth.BlockChain().SetCanonical(block); err != nil { - return beacon.ForkChoiceResponse{PayloadStatus: beacon.PayloadStatusV1{Status: beacon.INVALID, LatestValidHash: &latestValid}}, err + return engine.ForkChoiceResponse{PayloadStatus: engine.PayloadStatusV1{Status: engine.INVALID, LatestValidHash: &latestValid}}, err } } else if api.eth.BlockChain().CurrentBlock().Hash() == update.HeadBlockHash { // If the specified head matches with our local head, do nothing and keep @@ -299,10 +299,10 @@ func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payl finalBlock := api.eth.BlockChain().GetBlockByHash(update.FinalizedBlockHash) if finalBlock == nil { log.Warn("Final block not available in database", "hash", update.FinalizedBlockHash) - return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("final block not available in database")) + return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not available in database")) } else if rawdb.ReadCanonicalHash(api.eth.ChainDb(), finalBlock.NumberU64()) != update.FinalizedBlockHash { log.Warn("Final block not in canonical chain", "number", block.NumberU64(), "hash", update.HeadBlockHash) - return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("final block not in canonical chain")) + return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not in canonical chain")) } // Set the finalized block api.eth.BlockChain().SetFinalized(finalBlock) @@ -312,11 +312,11 @@ func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payl safeBlock := api.eth.BlockChain().GetBlockByHash(update.SafeBlockHash) if safeBlock == nil { log.Warn("Safe block not available in database") - return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("safe block not available in database")) + return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("safe block not available in database")) } if rawdb.ReadCanonicalHash(api.eth.ChainDb(), safeBlock.NumberU64()) != update.SafeBlockHash { log.Warn("Safe block not in canonical chain") - return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain")) + return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain")) } // Set the safe block api.eth.BlockChain().SetSafe(safeBlock) @@ -341,7 +341,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payl payload, err := api.eth.Miner().BuildPayload(args) if err != nil { log.Error("Failed to build payload", "err", err) - return valid(nil), beacon.InvalidPayloadAttributes.With(err) + return valid(nil), engine.InvalidPayloadAttributes.With(err) } api.localBlocks.put(id, payload) return valid(&id), nil @@ -351,7 +351,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payl // ExchangeTransitionConfigurationV1 checks the given configuration against // the configuration of the node. -func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.TransitionConfigurationV1) (*beacon.TransitionConfigurationV1, error) { +func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config engine.TransitionConfigurationV1) (*engine.TransitionConfigurationV1, error) { log.Trace("Engine API request received", "method", "ExchangeTransitionConfiguration", "ttd", config.TerminalTotalDifficulty) if config.TerminalTotalDifficulty == nil { return nil, errors.New("invalid terminal total difficulty") @@ -368,7 +368,7 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.Transit } if config.TerminalBlockHash != (common.Hash{}) { if hash := api.eth.BlockChain().GetCanonicalHash(uint64(config.TerminalBlockNumber)); hash == config.TerminalBlockHash { - return &beacon.TransitionConfigurationV1{ + return &engine.TransitionConfigurationV1{ TerminalTotalDifficulty: (*hexutil.Big)(ttd), TerminalBlockHash: config.TerminalBlockHash, TerminalBlockNumber: config.TerminalBlockNumber, @@ -376,11 +376,11 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.Transit } return nil, fmt.Errorf("invalid terminal block hash") } - return &beacon.TransitionConfigurationV1{TerminalTotalDifficulty: (*hexutil.Big)(ttd)}, nil + return &engine.TransitionConfigurationV1{TerminalTotalDifficulty: (*hexutil.Big)(ttd)}, nil } // GetPayloadV1 returns a cached payload by id. -func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableData, error) { +func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.ExecutableData, error) { data, err := api.getPayload(payloadID) if err != nil { return nil, err @@ -389,33 +389,33 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.Execu } // GetPayloadV2 returns a cached payload by id. -func (api *ConsensusAPI) GetPayloadV2(payloadID beacon.PayloadID) (*beacon.ExecutionPayloadEnvelope, error) { +func (api *ConsensusAPI) GetPayloadV2(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { return api.getPayload(payloadID) } -func (api *ConsensusAPI) getPayload(payloadID beacon.PayloadID) (*beacon.ExecutionPayloadEnvelope, error) { +func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID) data := api.localBlocks.get(payloadID) if data == nil { - return nil, beacon.UnknownPayload + return nil, engine.UnknownPayload } return data, nil } // NewPayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. -func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { +func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.PayloadStatusV1, error) { if params.Withdrawals != nil { - return beacon.PayloadStatusV1{Status: beacon.INVALID}, fmt.Errorf("withdrawals not supported in V1") + return engine.PayloadStatusV1{Status: engine.INVALID}, fmt.Errorf("withdrawals not supported in V1") } return api.newPayload(params) } // NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. -func (api *ConsensusAPI) NewPayloadV2(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { +func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.PayloadStatusV1, error) { return api.newPayload(params) } -func (api *ConsensusAPI) newPayload(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { +func (api *ConsensusAPI) newPayload(params engine.ExecutableData) (engine.PayloadStatusV1, error) { // The locking here is, strictly, not required. Without these locks, this can happen: // // 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to @@ -433,10 +433,10 @@ func (api *ConsensusAPI) newPayload(params beacon.ExecutableData) (beacon.Payloa defer api.newPayloadLock.Unlock() log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash) - block, err := beacon.ExecutableDataToBlock(params) + block, err := engine.ExecutableDataToBlock(params) if err != nil { log.Debug("Invalid NewPayload params", "params", params, "error", err) - return beacon.PayloadStatusV1{Status: beacon.INVALIDBLOCKHASH}, nil + return engine.PayloadStatusV1{Status: engine.INVALIDBLOCKHASH}, nil } // Stash away the last update to warn the user if the beacon client goes offline api.lastNewPayloadLock.Lock() @@ -448,7 +448,7 @@ func (api *ConsensusAPI) newPayload(params beacon.ExecutableData) (beacon.Payloa if block := api.eth.BlockChain().GetBlockByHash(params.BlockHash); block != nil { log.Warn("Ignoring already known beacon payload", "number", params.Number, "hash", params.BlockHash, "age", common.PrettyAge(time.Unix(int64(block.Time()), 0))) hash := block.Hash() - return beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &hash}, nil + return engine.PayloadStatusV1{Status: engine.VALID, LatestValidHash: &hash}, nil } // If this block was rejected previously, keep rejecting it if res := api.checkInvalidAncestor(block.Hash(), block.Hash()); res != nil { @@ -473,11 +473,11 @@ func (api *ConsensusAPI) newPayload(params beacon.ExecutableData) (beacon.Payloa ) if ptd.Cmp(ttd) < 0 { log.Warn("Ignoring pre-merge payload", "number", params.Number, "hash", params.BlockHash, "td", ptd, "ttd", ttd) - return beacon.INVALID_TERMINAL_BLOCK, nil + return engine.INVALID_TERMINAL_BLOCK, nil } if parent.Difficulty().BitLen() > 0 && gptd != nil && gptd.Cmp(ttd) >= 0 { log.Error("Ignoring pre-merge parent block", "number", params.Number, "hash", params.BlockHash, "td", ptd, "ttd", ttd) - return beacon.INVALID_TERMINAL_BLOCK, nil + return engine.INVALID_TERMINAL_BLOCK, nil } if block.Time() <= parent.Time() { log.Warn("Invalid timestamp", "parent", block.Time(), "block", block.Time()) @@ -493,7 +493,7 @@ func (api *ConsensusAPI) newPayload(params beacon.ExecutableData) (beacon.Payloa if !api.eth.BlockChain().HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { api.remoteBlocks.put(block.Hash(), block.Header()) log.Warn("State not available, ignoring new payload") - return beacon.PayloadStatusV1{Status: beacon.ACCEPTED}, nil + return engine.PayloadStatusV1{Status: engine.ACCEPTED}, nil } log.Trace("Inserting block without sethead", "hash", block.Hash(), "number", block.Number) if err := api.eth.BlockChain().InsertBlockWithoutSetHead(block); err != nil { @@ -514,14 +514,14 @@ func (api *ConsensusAPI) newPayload(params beacon.ExecutableData) (beacon.Payloa api.eth.Downloader().Cancel() } hash := block.Hash() - return beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &hash}, nil + return engine.PayloadStatusV1{Status: engine.VALID, LatestValidHash: &hash}, nil } // delayPayloadImport stashes the given block away for import at a later time, // either via a forkchoice update or a sync extension. This method is meant to // be called by the newpayload command when the block seems to be ok, but some // prerequisite prevents it from being processed (e.g. no parent, or snap sync). -func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (beacon.PayloadStatusV1, error) { +func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (engine.PayloadStatusV1, error) { // Sanity check that this block's parent is not on a previously invalidated // chain. If it is, mark the block as invalid too. if res := api.checkInvalidAncestor(block.ParentHash(), block.Hash()); res != nil { @@ -536,7 +536,7 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (beacon.PayloadS // some strain from the forkchoice update. if err := api.eth.Downloader().BeaconExtend(api.eth.SyncMode(), block.Header()); err == nil { log.Debug("Payload accepted for sync extension", "number", block.NumberU64(), "hash", block.Hash()) - return beacon.PayloadStatusV1{Status: beacon.SYNCING}, nil + return engine.PayloadStatusV1{Status: engine.SYNCING}, nil } // Either no beacon sync was started yet, or it rejected the delivered // payload as non-integratable on top of the existing sync. We'll just @@ -553,7 +553,7 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (beacon.PayloadS // and cannot afford concurrent out-if-band modifications via imports. log.Warn("Ignoring payload while snap syncing", "number", block.NumberU64(), "hash", block.Hash()) } - return beacon.PayloadStatusV1{Status: beacon.SYNCING}, nil + return engine.PayloadStatusV1{Status: engine.SYNCING}, nil } // setInvalidAncestor is a callback for the downloader to notify us if a bad block @@ -568,7 +568,7 @@ func (api *ConsensusAPI) setInvalidAncestor(invalid *types.Header, origin *types // checkInvalidAncestor checks whether the specified chain end links to a known // bad ancestor. If yes, it constructs the payload failure response to return. -func (api *ConsensusAPI) checkInvalidAncestor(check common.Hash, head common.Hash) *beacon.PayloadStatusV1 { +func (api *ConsensusAPI) checkInvalidAncestor(check common.Hash, head common.Hash) *engine.PayloadStatusV1 { api.invalidLock.Lock() defer api.invalidLock.Unlock() @@ -610,8 +610,8 @@ func (api *ConsensusAPI) checkInvalidAncestor(check common.Hash, head common.Has lastValid = &common.Hash{} } failure := "links to previously rejected block" - return &beacon.PayloadStatusV1{ - Status: beacon.INVALID, + return &engine.PayloadStatusV1{ + Status: engine.INVALID, LatestValidHash: lastValid, ValidationError: &failure, } @@ -619,7 +619,7 @@ func (api *ConsensusAPI) checkInvalidAncestor(check common.Hash, head common.Has // invalid returns a response "INVALID" with the latest valid hash supplied by latest or to the current head // if no latestValid block was provided. -func (api *ConsensusAPI) invalid(err error, latestValid *types.Header) beacon.PayloadStatusV1 { +func (api *ConsensusAPI) invalid(err error, latestValid *types.Header) engine.PayloadStatusV1 { currentHash := api.eth.BlockChain().CurrentBlock().Hash() if latestValid != nil { // Set latest valid hash to 0x0 if parent is PoW block @@ -630,7 +630,7 @@ func (api *ConsensusAPI) invalid(err error, latestValid *types.Header) beacon.Pa } } errorMsg := err.Error() - return beacon.PayloadStatusV1{Status: beacon.INVALID, LatestValidHash: ¤tHash, ValidationError: &errorMsg} + return engine.PayloadStatusV1{Status: engine.INVALID, LatestValidHash: ¤tHash, ValidationError: &errorMsg} } // heartbeat loops indefinitely, and checks if there have been beacon client updates @@ -761,8 +761,8 @@ func (api *ConsensusAPI) ExchangeCapabilities([]string) []string { // GetPayloadBodiesV1 implements engine_getPayloadBodiesByHashV1 which allows for retrieval of a list // of block bodies by the engine api. -func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*beacon.ExecutionPayloadBodyV1 { - var bodies = make([]*beacon.ExecutionPayloadBodyV1, len(hashes)) +func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engine.ExecutionPayloadBodyV1 { + var bodies = make([]*engine.ExecutionPayloadBodyV1, len(hashes)) for i, hash := range hashes { block := api.eth.BlockChain().GetBlockByHash(hash) bodies[i] = getBody(block) @@ -772,9 +772,9 @@ func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*beaco // GetPayloadBodiesByRangeV1 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range // of block bodies by the engine api. -func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count uint64) ([]*beacon.ExecutionPayloadBodyV1, error) { +func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count uint64) ([]*engine.ExecutionPayloadBodyV1, error) { if start == 0 || count == 0 || count > 1024 { - return nil, beacon.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count)) + return nil, engine.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count)) } // limit count up until current current := api.eth.BlockChain().CurrentBlock().NumberU64() @@ -782,7 +782,7 @@ func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count uint64) ([]*beac if end > current { end = current } - var bodies []*beacon.ExecutionPayloadBodyV1 + var bodies []*engine.ExecutionPayloadBodyV1 for i := start; i < end; i++ { block := api.eth.BlockChain().GetBlockByNumber(i) bodies = append(bodies, getBody(block)) @@ -790,7 +790,7 @@ func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count uint64) ([]*beac return bodies, nil } -func getBody(block *types.Block) *beacon.ExecutionPayloadBodyV1 { +func getBody(block *types.Block) *engine.ExecutionPayloadBodyV1 { if block == nil { return nil } @@ -811,7 +811,7 @@ func getBody(block *types.Block) *beacon.ExecutionPayloadBodyV1 { withdrawals = make([]*types.Withdrawal, 0) } - return &beacon.ExecutionPayloadBodyV1{ + return &engine.ExecutionPayloadBodyV1{ TransactionData: txs, Withdrawals: withdrawals, } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 3725575596b0..ae3ad08e7af9 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -25,13 +25,13 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" beaconConsensus "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -105,7 +105,7 @@ func TestEth2AssembleBlock(t *testing.T) { t.Fatalf("error signing transaction, err=%v", err) } ethservice.TxPool().AddLocal(tx) - blockParams := beacon.PayloadAttributes{ + blockParams := engine.PayloadAttributes{ Timestamp: blocks[9].Time() + 5, } // The miner needs to pick up on the txs in the pool, so a few retries might be @@ -117,7 +117,7 @@ func TestEth2AssembleBlock(t *testing.T) { // assembleWithTransactions tries to assemble a block, retrying until it has 'want', // number of transactions in it, or it has retried three times. -func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributes, want int) (execData *beacon.ExecutableData, err error) { +func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params *engine.PayloadAttributes, want int) (execData *engine.ExecutableData, err error) { for retries := 3; retries > 0; retries-- { execData, err = assembleBlock(api, parentHash, params) if err != nil { @@ -141,7 +141,7 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) { // Put the 10th block's tx in the pool and produce a new block api.eth.TxPool().AddRemotesSync(blocks[9].Transactions()) - blockParams := beacon.PayloadAttributes{ + blockParams := engine.PayloadAttributes{ Timestamp: blocks[8].Time() + 5, } // The miner needs to pick up on the txs in the pool, so a few retries might be @@ -157,14 +157,14 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) { defer n.Close() api := NewConsensusAPI(ethservice) - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: blocks[5].Hash(), SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, } if resp, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { t.Errorf("fork choice updated should not error: %v", err) - } else if resp.PayloadStatus.Status != beacon.INVALID_TERMINAL_BLOCK.Status { + } else if resp.PayloadStatus.Status != engine.INVALID_TERMINAL_BLOCK.Status { t.Errorf("fork choice updated before total terminal difficulty should be INVALID") } } @@ -180,10 +180,10 @@ func TestEth2PrepareAndGetPayload(t *testing.T) { // Put the 10th block's tx in the pool and produce a new block ethservice.TxPool().AddLocals(blocks[9].Transactions()) - blockParams := beacon.PayloadAttributes{ + blockParams := engine.PayloadAttributes{ Timestamp: blocks[8].Time() + 5, } - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: blocks[8].Hash(), SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, @@ -208,7 +208,7 @@ func TestEth2PrepareAndGetPayload(t *testing.T) { t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions)) } // Test invalid payloadID - var invPayload beacon.PayloadID + var invPayload engine.PayloadID copy(invPayload[:], payloadID[:]) invPayload[0] = ^invPayload[0] _, err = api.GetPayloadV1(invPayload) @@ -259,12 +259,12 @@ func TestInvalidPayloadTimestamp(t *testing.T) { for i, test := range tests { t.Run(fmt.Sprintf("Timestamp test: %v", i), func(t *testing.T) { - params := beacon.PayloadAttributes{ + params := engine.PayloadAttributes{ Timestamp: test.time, Random: crypto.Keccak256Hash([]byte{byte(123)}), SuggestedFeeRecipient: parent.Coinbase(), } - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: parent.Hash(), SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, @@ -303,13 +303,13 @@ func TestEth2NewBlock(t *testing.T) { tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) ethservice.TxPool().AddLocal(tx) - execData, err := assembleWithTransactions(api, parent.Hash(), &beacon.PayloadAttributes{ + execData, err := assembleWithTransactions(api, parent.Hash(), &engine.PayloadAttributes{ Timestamp: parent.Time() + 5, }, 1) if err != nil { t.Fatalf("Failed to create the executable data %v", err) } - block, err := beacon.ExecutableDataToBlock(*execData) + block, err := engine.ExecutableDataToBlock(*execData) if err != nil { t.Fatalf("Failed to convert executable data to block %v", err) } @@ -323,7 +323,7 @@ func TestEth2NewBlock(t *testing.T) { t.Fatalf("Chain head shouldn't be updated") } checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: block.Hash(), SafeBlockHash: block.Hash(), FinalizedBlockHash: block.Hash(), @@ -345,13 +345,13 @@ func TestEth2NewBlock(t *testing.T) { ) parent = preMergeBlocks[len(preMergeBlocks)-1] for i := 0; i < 10; i++ { - execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributes{ + execData, err := assembleBlock(api, parent.Hash(), &engine.PayloadAttributes{ Timestamp: parent.Time() + 6, }) if err != nil { t.Fatalf("Failed to create the executable data %v", err) } - block, err := beacon.ExecutableDataToBlock(*execData) + block, err := engine.ExecutableDataToBlock(*execData) if err != nil { t.Fatalf("Failed to convert executable data to block %v", err) } @@ -363,7 +363,7 @@ func TestEth2NewBlock(t *testing.T) { t.Fatalf("Chain head shouldn't be updated") } - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: block.Hash(), SafeBlockHash: block.Hash(), FinalizedBlockHash: block.Hash(), @@ -488,10 +488,10 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Bl if err != nil { t.Fatalf("can't execute payload: %v", err) } - if execResp.Status != beacon.VALID { + if execResp.Status != engine.VALID { t.Fatalf("invalid status: %v", execResp.Status) } - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: payload.BlockHash, SafeBlockHash: payload.ParentHash, FinalizedBlockHash: payload.ParentHash, @@ -518,7 +518,7 @@ func TestExchangeTransitionConfig(t *testing.T) { // invalid ttd api := NewConsensusAPI(ethservice) - config := beacon.TransitionConfigurationV1{ + config := engine.TransitionConfigurationV1{ TerminalTotalDifficulty: (*hexutil.Big)(big.NewInt(0)), TerminalBlockHash: common.Hash{}, TerminalBlockNumber: 0, @@ -527,7 +527,7 @@ func TestExchangeTransitionConfig(t *testing.T) { t.Fatal("expected error on invalid config, invalid ttd") } // invalid terminal block hash - config = beacon.TransitionConfigurationV1{ + config = engine.TransitionConfigurationV1{ TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty), TerminalBlockHash: common.Hash{1}, TerminalBlockNumber: 0, @@ -536,7 +536,7 @@ func TestExchangeTransitionConfig(t *testing.T) { t.Fatal("expected error on invalid config, invalid hash") } // valid config - config = beacon.TransitionConfigurationV1{ + config = engine.TransitionConfigurationV1{ TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty), TerminalBlockHash: common.Hash{}, TerminalBlockNumber: 0, @@ -545,7 +545,7 @@ func TestExchangeTransitionConfig(t *testing.T) { t.Fatalf("expected no error on valid config, got %v", err) } // valid config - config = beacon.TransitionConfigurationV1{ + config = engine.TransitionConfigurationV1{ TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty), TerminalBlockHash: preMergeBlocks[5].Hash(), TerminalBlockNumber: 6, @@ -595,25 +595,25 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { }) ethservice.TxPool().AddRemotesSync([]*types.Transaction{tx}) var ( - params = beacon.PayloadAttributes{ + params = engine.PayloadAttributes{ Timestamp: parent.Time() + 1, Random: crypto.Keccak256Hash([]byte{byte(i)}), SuggestedFeeRecipient: parent.Coinbase(), } - fcState = beacon.ForkchoiceStateV1{ + fcState = engine.ForkchoiceStateV1{ HeadBlockHash: parent.Hash(), SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, } - payload *beacon.ExecutableData - resp beacon.ForkChoiceResponse + payload *engine.ExecutableData + resp engine.ForkChoiceResponse err error ) for i := 0; ; i++ { if resp, err = api.ForkchoiceUpdatedV1(fcState, ¶ms); err != nil { t.Fatalf("error preparing payload, err=%v", err) } - if resp.PayloadStatus.Status != beacon.VALID { + if resp.PayloadStatus.Status != engine.VALID { t.Fatalf("error preparing payload, invalid status: %v", resp.PayloadStatus.Status) } // give the payload some time to be built @@ -634,10 +634,10 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { if err != nil { t.Fatalf("can't execute payload: %v", err) } - if execResp.Status != beacon.VALID { + if execResp.Status != engine.VALID { t.Fatalf("invalid status: %v", execResp.Status) } - fcState = beacon.ForkchoiceStateV1{ + fcState = engine.ForkchoiceStateV1{ HeadBlockHash: payload.BlockHash, SafeBlockHash: payload.ParentHash, FinalizedBlockHash: payload.ParentHash, @@ -652,7 +652,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { } } -func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributes) (*beacon.ExecutableData, error) { +func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *engine.PayloadAttributes) (*engine.ExecutableData, error) { args := &miner.BuildPayloadArgs{ Parent: parentHash, Timestamp: params.Timestamp, @@ -685,7 +685,7 @@ func TestEmptyBlocks(t *testing.T) { if err != nil { t.Fatal(err) } - if status.Status != beacon.VALID { + if status.Status != engine.VALID { t.Errorf("invalid status: expected VALID got: %v", status.Status) } if !bytes.Equal(status.LatestValidHash[:], payload.BlockHash[:]) { @@ -701,7 +701,7 @@ func TestEmptyBlocks(t *testing.T) { if err != nil { t.Fatal(err) } - if status.Status != beacon.INVALID { + if status.Status != engine.INVALID { t.Errorf("invalid status: expected INVALID got: %v", status.Status) } // Expect 0x0 on INVALID block on top of PoW block @@ -719,7 +719,7 @@ func TestEmptyBlocks(t *testing.T) { if err != nil { t.Fatal(err) } - if status.Status != beacon.SYNCING { + if status.Status != engine.SYNCING { t.Errorf("invalid status: expected SYNCING got: %v", status.Status) } if status.LatestValidHash != nil { @@ -727,8 +727,8 @@ func TestEmptyBlocks(t *testing.T) { } } -func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon.ExecutableData { - params := beacon.PayloadAttributes{ +func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *engine.ExecutableData { + params := engine.PayloadAttributes{ Timestamp: parent.Time() + 1, Random: crypto.Keccak256Hash([]byte{byte(1)}), SuggestedFeeRecipient: parent.Coinbase(), @@ -743,7 +743,7 @@ func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon // setBlockhash sets the blockhash of a modified ExecutableData. // Can be used to make modified payloads look valid. -func setBlockhash(data *beacon.ExecutableData) *beacon.ExecutableData { +func setBlockhash(data *engine.ExecutableData) *engine.ExecutableData { txs, _ := decodeTransactions(data.Transactions) number := big.NewInt(0) number.SetUint64(data.Number) @@ -802,7 +802,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Block) {}) commonAncestor = ethserviceA.BlockChain().CurrentBlock() - var invalidChain []*beacon.ExecutableData + var invalidChain []*engine.ExecutableData // create a valid payload (P1) //payload1 := getNewPayload(t, apiA, commonAncestor) //invalidChain = append(invalidChain, payload1) @@ -830,15 +830,15 @@ func TestTrickRemoteBlockCache(t *testing.T) { if err != nil { panic(err) } - if status.Status == beacon.VALID { + if status.Status == engine.VALID { t.Error("invalid status: VALID on an invalid chain") } // Now reorg to the head of the invalid chain - resp, err := apiB.ForkchoiceUpdatedV1(beacon.ForkchoiceStateV1{HeadBlockHash: payload.BlockHash, SafeBlockHash: payload.BlockHash, FinalizedBlockHash: payload.ParentHash}, nil) + resp, err := apiB.ForkchoiceUpdatedV1(engine.ForkchoiceStateV1{HeadBlockHash: payload.BlockHash, SafeBlockHash: payload.BlockHash, FinalizedBlockHash: payload.ParentHash}, nil) if err != nil { t.Fatal(err) } - if resp.PayloadStatus.Status == beacon.VALID { + if resp.PayloadStatus.Status == engine.VALID { t.Error("invalid status: VALID on an invalid chain") } time.Sleep(100 * time.Millisecond) @@ -864,7 +864,7 @@ func TestInvalidBloom(t *testing.T) { if err != nil { t.Fatal(err) } - if status.Status != beacon.INVALIDBLOCKHASH { + if status.Status != engine.INVALIDBLOCKHASH { t.Errorf("invalid status: expected VALID got: %v", status.Status) } } @@ -882,7 +882,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { ) // Test parent already post TTD in FCU - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: parent.Hash(), SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, @@ -891,7 +891,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { if err != nil { t.Fatalf("error sending forkchoice, err=%v", err) } - if resp.PayloadStatus != beacon.INVALID_TERMINAL_BLOCK { + if resp.PayloadStatus != engine.INVALID_TERMINAL_BLOCK { t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status) } @@ -911,7 +911,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { if err != nil { t.Fatalf("error sending NewPayload, err=%v", err) } - if resp2 != beacon.INVALID_TERMINAL_BLOCK { + if resp2 != engine.INVALID_TERMINAL_BLOCK { t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status) } } @@ -929,7 +929,7 @@ func TestSimultaneousNewBlock(t *testing.T) { parent = preMergeBlocks[len(preMergeBlocks)-1] ) for i := 0; i < 10; i++ { - execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributes{ + execData, err := assembleBlock(api, parent.Hash(), &engine.PayloadAttributes{ Timestamp: parent.Time() + 5, }) if err != nil { @@ -962,14 +962,14 @@ func TestSimultaneousNewBlock(t *testing.T) { t.Fatal(testErr) } } - block, err := beacon.ExecutableDataToBlock(*execData) + block, err := engine.ExecutableDataToBlock(*execData) if err != nil { t.Fatalf("Failed to convert executable data to block %v", err) } if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1 { t.Fatalf("Chain head shouldn't be updated") } - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: block.Hash(), SafeBlockHash: block.Hash(), FinalizedBlockHash: block.Hash(), @@ -1020,19 +1020,19 @@ func TestWithdrawals(t *testing.T) { // 10: Build Shanghai block with no withdrawals. parent := ethservice.BlockChain().CurrentHeader() - blockParams := beacon.PayloadAttributes{ + blockParams := engine.PayloadAttributes{ Timestamp: parent.Time + 5, Withdrawals: make([]*types.Withdrawal, 0), } - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: parent.Hash(), } resp, err := api.ForkchoiceUpdatedV2(fcState, &blockParams) if err != nil { t.Fatalf("error preparing payload, err=%v", err) } - if resp.PayloadStatus.Status != beacon.VALID { - t.Fatalf("unexpected status (got: %s, want: %s)", resp.PayloadStatus.Status, beacon.VALID) + if resp.PayloadStatus.Status != engine.VALID { + t.Fatalf("unexpected status (got: %s, want: %s)", resp.PayloadStatus.Status, engine.VALID) } // 10: verify state root is the same as parent @@ -1053,14 +1053,14 @@ func TestWithdrawals(t *testing.T) { // 10: verify locally built block if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil { t.Fatalf("error validating payload: %v", err) - } else if status.Status != beacon.VALID { + } else if status.Status != engine.VALID { t.Fatalf("invalid payload") } // 11: build shanghai block with withdrawal aa := common.Address{0xaa} bb := common.Address{0xbb} - blockParams = beacon.PayloadAttributes{ + blockParams = engine.PayloadAttributes{ Timestamp: execData.ExecutionPayload.Timestamp + 5, Withdrawals: []*types.Withdrawal{ { @@ -1094,7 +1094,7 @@ func TestWithdrawals(t *testing.T) { } if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil { t.Fatalf("error validating payload: %v", err) - } else if status.Status != beacon.VALID { + } else if status.Status != engine.VALID { t.Fatalf("invalid payload") } @@ -1133,27 +1133,27 @@ func TestNilWithdrawals(t *testing.T) { aa := common.Address{0xaa} type test struct { - blockParams beacon.PayloadAttributes + blockParams engine.PayloadAttributes wantErr bool } tests := []test{ // Before Shanghai { - blockParams: beacon.PayloadAttributes{ + blockParams: engine.PayloadAttributes{ Timestamp: parent.Time + 2, Withdrawals: nil, }, wantErr: false, }, { - blockParams: beacon.PayloadAttributes{ + blockParams: engine.PayloadAttributes{ Timestamp: parent.Time + 2, Withdrawals: make([]*types.Withdrawal, 0), }, wantErr: true, }, { - blockParams: beacon.PayloadAttributes{ + blockParams: engine.PayloadAttributes{ Timestamp: parent.Time + 2, Withdrawals: []*types.Withdrawal{ { @@ -1167,21 +1167,21 @@ func TestNilWithdrawals(t *testing.T) { }, // After Shanghai { - blockParams: beacon.PayloadAttributes{ + blockParams: engine.PayloadAttributes{ Timestamp: parent.Time + 5, Withdrawals: nil, }, wantErr: true, }, { - blockParams: beacon.PayloadAttributes{ + blockParams: engine.PayloadAttributes{ Timestamp: parent.Time + 5, Withdrawals: make([]*types.Withdrawal, 0), }, wantErr: false, }, { - blockParams: beacon.PayloadAttributes{ + blockParams: engine.PayloadAttributes{ Timestamp: parent.Time + 5, Withdrawals: []*types.Withdrawal{ { @@ -1195,7 +1195,7 @@ func TestNilWithdrawals(t *testing.T) { }, } - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: parent.Hash(), } @@ -1224,7 +1224,7 @@ func TestNilWithdrawals(t *testing.T) { } if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil { t.Fatalf("error validating payload: %v", err) - } else if status.Status != beacon.VALID { + } else if status.Status != engine.VALID { t.Fatalf("invalid payload") } } @@ -1400,7 +1400,7 @@ func TestGetBlockBodiesByRangeInvalidParams(t *testing.T) { } } -func equalBody(a *types.Body, b *beacon.ExecutionPayloadBodyV1) bool { +func equalBody(a *types.Body, b *engine.ExecutionPayloadBodyV1) bool { if a == nil && b == nil { return true } else if a == nil || b == nil { diff --git a/eth/catalyst/queue.go b/eth/catalyst/queue.go index 5c60f70e44b3..b7213dd591aa 100644 --- a/eth/catalyst/queue.go +++ b/eth/catalyst/queue.go @@ -19,8 +19,8 @@ package catalyst import ( "sync" + "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/miner" ) @@ -38,7 +38,7 @@ const maxTrackedHeaders = 10 // payloadQueueItem represents an id->payload tuple to store until it's retrieved // or evicted. type payloadQueueItem struct { - id beacon.PayloadID + id engine.PayloadID payload *miner.Payload } @@ -58,7 +58,7 @@ func newPayloadQueue() *payloadQueue { } // put inserts a new payload into the queue at the given id. -func (q *payloadQueue) put(id beacon.PayloadID, payload *miner.Payload) { +func (q *payloadQueue) put(id engine.PayloadID, payload *miner.Payload) { q.lock.Lock() defer q.lock.Unlock() @@ -70,7 +70,7 @@ func (q *payloadQueue) put(id beacon.PayloadID, payload *miner.Payload) { } // get retrieves a previously stored payload item or nil if it does not exist. -func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutionPayloadEnvelope { +func (q *payloadQueue) get(id engine.PayloadID) *engine.ExecutionPayloadEnvelope { q.lock.RLock() defer q.lock.RUnlock() @@ -86,7 +86,7 @@ func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutionPayloadEnvelope } // has checks if a particular payload is already tracked. -func (q *payloadQueue) has(id beacon.PayloadID) bool { +func (q *payloadQueue) has(id engine.PayloadID) bool { q.lock.RLock() defer q.lock.RUnlock() diff --git a/les/catalyst/api.go b/les/catalyst/api.go index b5957583289d..c9db514fcc70 100644 --- a/les/catalyst/api.go +++ b/les/catalyst/api.go @@ -21,9 +21,9 @@ import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" @@ -70,43 +70,43 @@ func NewConsensusAPI(les *les.LightEthereum) *ConsensusAPI { // // If there are payloadAttributes: we return an error since block creation is not // supported in les mode. -func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) { +func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { if heads.HeadBlockHash == (common.Hash{}) { log.Warn("Forkchoice requested update to zero hash") - return beacon.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this? + return engine.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this? } if err := api.checkTerminalTotalDifficulty(heads.HeadBlockHash); err != nil { if header := api.les.BlockChain().GetHeaderByHash(heads.HeadBlockHash); header == nil { // TODO (MariusVanDerWijden) trigger sync - return beacon.STATUS_SYNCING, nil + return engine.STATUS_SYNCING, nil } - return beacon.STATUS_INVALID, err + return engine.STATUS_INVALID, err } // If the finalized block is set, check if it is in our blockchain if heads.FinalizedBlockHash != (common.Hash{}) { if header := api.les.BlockChain().GetHeaderByHash(heads.FinalizedBlockHash); header == nil { // TODO (MariusVanDerWijden) trigger sync - return beacon.STATUS_SYNCING, nil + return engine.STATUS_SYNCING, nil } } // SetHead if err := api.setCanonical(heads.HeadBlockHash); err != nil { - return beacon.STATUS_INVALID, err + return engine.STATUS_INVALID, err } if payloadAttributes != nil { - return beacon.STATUS_INVALID, errors.New("not supported") + return engine.STATUS_INVALID, errors.New("not supported") } return api.validForkChoiceResponse(), nil } // GetPayloadV1 returns a cached payload by id. It's not supported in les mode. -func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableData, error) { - return nil, beacon.GenericServerError.With(errors.New("not supported in light client mode")) +func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.ExecutableData, error) { + return nil, engine.GenericServerError.With(errors.New("not supported in light client mode")) } // ExecutePayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. -func (api *ConsensusAPI) ExecutePayloadV1(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) { - block, err := beacon.ExecutableDataToBlock(params) +func (api *ConsensusAPI) ExecutePayloadV1(params engine.ExecutableData) (engine.PayloadStatusV1, error) { + block, err := engine.ExecutableDataToBlock(params) if err != nil { return api.invalid(), err } @@ -118,7 +118,7 @@ func (api *ConsensusAPI) ExecutePayloadV1(params beacon.ExecutableData) (beacon. } */ // TODO (MariusVanDerWijden) we should return nil here not empty hash - return beacon.PayloadStatusV1{Status: beacon.SYNCING, LatestValidHash: nil}, nil + return engine.PayloadStatusV1{Status: engine.SYNCING, LatestValidHash: nil}, nil } parent := api.les.BlockChain().GetHeaderByHash(params.ParentHash) if parent == nil { @@ -136,20 +136,20 @@ func (api *ConsensusAPI) ExecutePayloadV1(params beacon.ExecutableData) (beacon. merger.ReachTTD() } hash := block.Hash() - return beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &hash}, nil + return engine.PayloadStatusV1{Status: engine.VALID, LatestValidHash: &hash}, nil } -func (api *ConsensusAPI) validForkChoiceResponse() beacon.ForkChoiceResponse { +func (api *ConsensusAPI) validForkChoiceResponse() engine.ForkChoiceResponse { currentHash := api.les.BlockChain().CurrentHeader().Hash() - return beacon.ForkChoiceResponse{ - PayloadStatus: beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: ¤tHash}, + return engine.ForkChoiceResponse{ + PayloadStatus: engine.PayloadStatusV1{Status: engine.VALID, LatestValidHash: ¤tHash}, } } // invalid returns a response "INVALID" with the latest valid hash set to the current head. -func (api *ConsensusAPI) invalid() beacon.PayloadStatusV1 { +func (api *ConsensusAPI) invalid() engine.PayloadStatusV1 { currentHash := api.les.BlockChain().CurrentHeader().Hash() - return beacon.PayloadStatusV1{Status: beacon.INVALID, LatestValidHash: ¤tHash} + return engine.PayloadStatusV1{Status: engine.INVALID, LatestValidHash: ¤tHash} } func (api *ConsensusAPI) checkTerminalTotalDifficulty(head common.Hash) error { @@ -193,7 +193,7 @@ func (api *ConsensusAPI) setCanonical(newHead common.Hash) error { // ExchangeTransitionConfigurationV1 checks the given configuration against // the configuration of the node. -func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.TransitionConfigurationV1) (*beacon.TransitionConfigurationV1, error) { +func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config engine.TransitionConfigurationV1) (*engine.TransitionConfigurationV1, error) { log.Trace("Engine API request received", "method", "ExchangeTransitionConfiguration", "ttd", config.TerminalTotalDifficulty) if config.TerminalTotalDifficulty == nil { return nil, errors.New("invalid terminal total difficulty") @@ -207,7 +207,7 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.Transit if config.TerminalBlockHash != (common.Hash{}) { if hash := api.les.BlockChain().GetCanonicalHash(uint64(config.TerminalBlockNumber)); hash == config.TerminalBlockHash { - return &beacon.TransitionConfigurationV1{ + return &engine.TransitionConfigurationV1{ TerminalTotalDifficulty: (*hexutil.Big)(ttd), TerminalBlockHash: config.TerminalBlockHash, TerminalBlockNumber: config.TerminalBlockNumber, @@ -216,5 +216,5 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.Transit return nil, fmt.Errorf("invalid terminal block hash") } - return &beacon.TransitionConfigurationV1{TerminalTotalDifficulty: (*hexutil.Big)(ttd)}, nil + return &engine.TransitionConfigurationV1{TerminalTotalDifficulty: (*hexutil.Big)(ttd)}, nil } diff --git a/les/catalyst/api_test.go b/les/catalyst/api_test.go index 2af90dfc6e69..54757f61dae0 100644 --- a/les/catalyst/api_test.go +++ b/les/catalyst/api_test.go @@ -20,10 +20,10 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/downloader" @@ -84,7 +84,7 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) { defer n.Close() api := NewConsensusAPI(lesService) - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: blocks[5].Hash(), SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, @@ -101,7 +101,7 @@ func TestExecutePayloadV1(t *testing.T) { defer n.Close() api := NewConsensusAPI(lesService) - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: postBlocks[0].Hash(), SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, @@ -130,7 +130,7 @@ func TestExecutePayloadV1(t *testing.T) { BaseFee: block.BaseFee(), }, nil, nil, nil, trie.NewStackTrie(nil)) - _, err := api.ExecutePayloadV1(beacon.ExecutableData{ + _, err := api.ExecutePayloadV1(engine.ExecutableData{ ParentHash: fakeBlock.ParentHash(), FeeRecipient: fakeBlock.Coinbase(), StateRoot: fakeBlock.Root(), @@ -153,7 +153,7 @@ func TestExecutePayloadV1(t *testing.T) { if headHeader.Number.Uint64() != fakeBlock.NumberU64()-1 { t.Fatal("Unexpected chain head update") } - fcState = beacon.ForkchoiceStateV1{ + fcState = engine.ForkchoiceStateV1{ HeadBlockHash: fakeBlock.Hash(), SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, diff --git a/miner/payload_building.go b/miner/payload_building.go index 75bca67cbb32..4c36dd8d19da 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -23,8 +23,8 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -42,14 +42,14 @@ type BuildPayloadArgs struct { } // Id computes an 8-byte identifier by hashing the components of the payload arguments. -func (args *BuildPayloadArgs) Id() beacon.PayloadID { +func (args *BuildPayloadArgs) Id() engine.PayloadID { // Hash hasher := sha256.New() hasher.Write(args.Parent[:]) binary.Write(hasher, binary.BigEndian, args.Timestamp) hasher.Write(args.Random[:]) hasher.Write(args.FeeRecipient[:]) - var out beacon.PayloadID + var out engine.PayloadID copy(out[:], hasher.Sum(nil)[:8]) return out } @@ -60,7 +60,7 @@ func (args *BuildPayloadArgs) Id() beacon.PayloadID { // the revenue. Therefore, the empty-block here is always available and full-block // will be set/updated afterwards. type Payload struct { - id beacon.PayloadID + id engine.PayloadID empty *types.Block full *types.Block fullFees *big.Int @@ -70,7 +70,7 @@ type Payload struct { } // newPayload initializes the payload object. -func newPayload(empty *types.Block, id beacon.PayloadID) *Payload { +func newPayload(empty *types.Block, id engine.PayloadID) *Payload { payload := &Payload{ id: id, empty: empty, @@ -108,7 +108,7 @@ func (payload *Payload) update(block *types.Block, fees *big.Int, elapsed time.D // Resolve returns the latest built payload and also terminates the background // thread for updating payload. It's safe to be called multiple times. -func (payload *Payload) Resolve() *beacon.ExecutionPayloadEnvelope { +func (payload *Payload) Resolve() *engine.ExecutionPayloadEnvelope { payload.lock.Lock() defer payload.lock.Unlock() @@ -118,23 +118,23 @@ func (payload *Payload) Resolve() *beacon.ExecutionPayloadEnvelope { close(payload.stop) } if payload.full != nil { - return beacon.BlockToExecutableData(payload.full, payload.fullFees) + return engine.BlockToExecutableData(payload.full, payload.fullFees) } - return beacon.BlockToExecutableData(payload.empty, big.NewInt(0)) + return engine.BlockToExecutableData(payload.empty, big.NewInt(0)) } // ResolveEmpty is basically identical to Resolve, but it expects empty block only. // It's only used in tests. -func (payload *Payload) ResolveEmpty() *beacon.ExecutionPayloadEnvelope { +func (payload *Payload) ResolveEmpty() *engine.ExecutionPayloadEnvelope { payload.lock.Lock() defer payload.lock.Unlock() - return beacon.BlockToExecutableData(payload.empty, big.NewInt(0)) + return engine.BlockToExecutableData(payload.empty, big.NewInt(0)) } // ResolveFull is basically identical to Resolve, but it expects full block only. // It's only used in tests. -func (payload *Payload) ResolveFull() *beacon.ExecutionPayloadEnvelope { +func (payload *Payload) ResolveFull() *engine.ExecutionPayloadEnvelope { payload.lock.Lock() defer payload.lock.Unlock() @@ -146,7 +146,7 @@ func (payload *Payload) ResolveFull() *beacon.ExecutionPayloadEnvelope { } payload.cond.Wait() } - return beacon.BlockToExecutableData(payload.full, payload.fullFees) + return engine.BlockToExecutableData(payload.full, payload.fullFees) } // buildPayload builds the payload according to the provided parameters. diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index 8d6ffaff13a2..43b9db4161f5 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -21,9 +21,9 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" - "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/params" ) @@ -47,7 +47,7 @@ func TestBuildPayload(t *testing.T) { if err != nil { t.Fatalf("Failed to build payload %v", err) } - verify := func(outer *beacon.ExecutionPayloadEnvelope, txs int) { + verify := func(outer *engine.ExecutionPayloadEnvelope, txs int) { payload := outer.ExecutionPayload if payload.ParentHash != b.chain.CurrentBlock().Hash() { t.Fatal("Unexpect parent hash") diff --git a/miner/stress/beacon/main.go b/miner/stress/beacon/main.go index bd500453d2b3..9b6d5e6d9357 100644 --- a/miner/stress/beacon/main.go +++ b/miner/stress/beacon/main.go @@ -27,11 +27,11 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/beacon" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -142,7 +142,7 @@ func newNode(typ nodetype, genesis *core.Genesis, enodes []*enode.Node) *ethNode } } -func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) (*beacon.ExecutableData, error) { +func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) (*engine.ExecutableData, error) { if n.typ != eth2MiningNode { return nil, errors.New("invalid node type") } @@ -150,12 +150,12 @@ func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) if timestamp <= parentTimestamp { timestamp = parentTimestamp + 1 } - payloadAttribute := beacon.PayloadAttributes{ + payloadAttribute := engine.PayloadAttributes{ Timestamp: timestamp, Random: common.Hash{}, SuggestedFeeRecipient: common.HexToAddress("0xdeadbeef"), } - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: parentHash, SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, @@ -168,7 +168,7 @@ func (n *ethNode) assembleBlock(parentHash common.Hash, parentTimestamp uint64) return n.api.GetPayloadV1(*payload.PayloadID) } -func (n *ethNode) insertBlock(eb beacon.ExecutableData) error { +func (n *ethNode) insertBlock(eb engine.ExecutableData) error { if !eth2types(n.typ) { return errors.New("invalid node type") } @@ -194,18 +194,18 @@ func (n *ethNode) insertBlock(eb beacon.ExecutableData) error { } } -func (n *ethNode) insertBlockAndSetHead(parent *types.Header, ed beacon.ExecutableData) error { +func (n *ethNode) insertBlockAndSetHead(parent *types.Header, ed engine.ExecutableData) error { if !eth2types(n.typ) { return errors.New("invalid node type") } if err := n.insertBlock(ed); err != nil { return err } - block, err := beacon.ExecutableDataToBlock(ed) + block, err := engine.ExecutableDataToBlock(ed) if err != nil { return err } - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: block.ParentHash(), SafeBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{}, @@ -319,7 +319,7 @@ func (mgr *nodeManager) run() { nodes = append(nodes, mgr.getNodes(eth2NormalNode)...) //nodes = append(nodes, mgr.getNodes(eth2LightClient)...) for _, node := range nodes { - fcState := beacon.ForkchoiceStateV1{ + fcState := engine.ForkchoiceStateV1{ HeadBlockHash: parentBlock.Hash(), SafeBlockHash: oldest.Hash(), FinalizedBlockHash: oldest.Hash(), @@ -362,7 +362,7 @@ func (mgr *nodeManager) run() { log.Error("Failed to assemble the block", "err", err) continue } - block, _ := beacon.ExecutableDataToBlock(*ed) + block, _ := engine.ExecutableDataToBlock(*ed) nodes := mgr.getNodes(eth2MiningNode) nodes = append(nodes, mgr.getNodes(eth2NormalNode)...) From 37e3208e33a5697fec90a3a0ce428cc4912d4365 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 6 Feb 2023 18:15:13 +0100 Subject: [PATCH 520/715] build: upgrade to golangci-lint v1.51.1 (#26618) --- build/checksums.txt | 47 +++++++++++++++++++++++++-------------------- build/ci.go | 2 +- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index a5c29353797f..ca6bd4f6de74 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -15,24 +15,29 @@ e4032e7c52ebc48bad5c58ba8de0759b6091d9b1e59581a8a521c8c9d88dbe93 go1.19.5.linux 167db91a2e40aeb453d3e59d213ecab06f62e1c4a84d13a06ccda1d999961caa go1.19.5.windows-amd64.zip 85a75555e82d8aa6f486d8d29491c593389682acce9f0c270090d5938eee30ef go1.19.5.windows-arm64.zip -20cd1215e0420db8cfa94a6cd3c9d325f7b39c07f2415a02d111568d8bc9e271 golangci-lint-1.49.0-darwin-amd64.tar.gz -cabb1a4c35fe1dadbe5a81550a00871281a331e7660cd85ae16e936a7f0f6cfc golangci-lint-1.49.0-darwin-arm64.tar.gz -f834c3b09580cf763b5d30b0c33c83cb13d7a822b5ed5d724143f121ffe28c97 golangci-lint-1.49.0-freebsd-386.tar.gz -4ca91c9f3aa79a71da441b7220a3e799365ff7a24caf9f04fcda12066c5ab0f7 golangci-lint-1.49.0-freebsd-amd64.tar.gz -37de789245248eea375d05080e11b4662a08762c353752575167611e65658454 golangci-lint-1.49.0-freebsd-armv6.tar.gz -3abed2bd3a8134b501fdc9cc9a0e60d616c86389e4fcdd1f79ceae7458974378 golangci-lint-1.49.0-freebsd-armv7.tar.gz -ef2860d90d83aee6713f697f23372cd93ac41a16439fdcb3c4ac86ba0f306860 golangci-lint-1.49.0-linux-386.tar.gz -5badc6e9fee2003621efa07e385910d9a88c89b38f6c35aded153193c5125178 golangci-lint-1.49.0-linux-amd64.tar.gz -b57ed03d29b8ca69be9925edd67ea305b6013cd5c97507d205fbe2979f71f2b5 golangci-lint-1.49.0-linux-arm64.tar.gz -4a41cff3af7f5304751f7bbf4ea617c14ebc1f88481a28a013e61b06d1f7102c golangci-lint-1.49.0-linux-armv6.tar.gz -14a9683af483ee7052dd0ce7d6140e0b502d6001bea3de606b8e7cce2c673539 golangci-lint-1.49.0-linux-armv7.tar.gz -33edf757bc2611204fdb40b212900866a57ded4eea62c1b19c10bfc375359afa golangci-lint-1.49.0-linux-mips64.tar.gz -280f7902f90d162566f1691a300663dd8db6e225e65384fe66b6fb2362e0b314 golangci-lint-1.49.0-linux-mips64le.tar.gz -103bcb7ce6c668e0a7e95e5c5355892d74f5d15391443430472e66d652906a15 golangci-lint-1.49.0-linux-ppc64le.tar.gz -4636ff9b01ddb18a2c1a953fc134207711b0a5d874d04ac66f915e9cfff0e8e0 golangci-lint-1.49.0-linux-riscv64.tar.gz -029e0844931a2d3edc771d67e17fe17928f04f80c1a9aa165160a543e8a7e8d4 golangci-lint-1.49.0-linux-s390x.tar.gz -e9cb6f691e62a4d8b28dd52d2eab57cca72acfd5083b3c5417a72d2eb64def09 golangci-lint-1.49.0-windows-386.zip -d058dfb0c7fbd73be70f285d3f8d4d424192fe9b19760ddbb0b2c4b743b8656c golangci-lint-1.49.0-windows-amd64.zip -c049d80297228db7065eabeac5114f77f04415dcd9b944e8d7c6426d9dd6e9dd golangci-lint-1.49.0-windows-arm64.zip -ec9164bab7134ddb94f51c17fd37c109b0801ecd5494b6c0e27ca7898fbd7469 golangci-lint-1.49.0-windows-armv6.zip -68fd9e880d98073f436c58b6f6d2c141881ef49b06ca31137bc19da4e4e3b996 golangci-lint-1.49.0-windows-armv7.zip +fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz +75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz +e06b3459aaed356e1667580be00b05f41f3b2e29685d12cdee571c23e1edb414 golangci-lint-1.51.1-freebsd-386.tar.gz +623ce2d0fa4d35cc2e8d69fa7334227ab592380962a13b4d9cdc77cf41db2008 golangci-lint-1.51.1-freebsd-amd64.tar.gz +131365feb0584cc2736c43192fa673ca50e5b6b765456990cb379ecfb787e568 golangci-lint-1.51.1-freebsd-armv6.tar.gz +98fb627927cbb654f5bf85dcffc5f646666b2ce96ea0fed977c9fb28abd51532 golangci-lint-1.51.1-freebsd-armv7.tar.gz +b36a99702fa762c15840261bc0fb41b4b1b16b8b19b8c0941bae98c85bb0f8b8 golangci-lint-1.51.1-linux-386.tar.gz +17aeb26c76820c22efa0e1838b0ab93e90cfedef43fbfc9a2f33f27eb9e5e070 golangci-lint-1.51.1-linux-amd64.tar.gz +9744bc34e7b8d82ca788b667bfb7155a39b4be9aef43bf9f10318b1372cea338 golangci-lint-1.51.1-linux-arm64.tar.gz +0dda8dbeb2ff7455a044ec8e347f2fc6d655d2e99d281b3b95e88167031c673d golangci-lint-1.51.1-linux-armv6.tar.gz +0512f311b11d43b8b22989d929f0fe8a2e1e5ebe497f1eb0ff73a0fc3d188fd1 golangci-lint-1.51.1-linux-armv7.tar.gz +d767108dcf84a8eaa844df3454cb0f75a492f4e7102ecc2b0a3545cfe073a566 golangci-lint-1.51.1-linux-loong64.tar.gz +3bd56c54daec16585b2668e0dfabb27af2c2b38cc0fdb46923e2521e1634846b golangci-lint-1.51.1-linux-mips64.tar.gz +f72f5adfa2219e15d2414c9a2966f86e74556cf17a85c727a7fb7770a16cf814 golangci-lint-1.51.1-linux-mips64le.tar.gz +e605521dac98096d8737e1997c954f41f1d0d8275b8731f62783d410c23574b9 golangci-lint-1.51.1-linux-ppc64le.tar.gz +2f683217b814339e74d61ca700922d8407f15addd6d4c5e8b156fbab79f26a87 golangci-lint-1.51.1-linux-riscv64.tar.gz +d98528292b65971a3594e5880530e7624597dc9806fcfccdfbe39be411713d63 golangci-lint-1.51.1-linux-s390x.tar.gz +9bb2d0fe9e692ed0aea4f2537e3e6862b2f6768fe2849a84f4a6ad09da9fd971 golangci-lint-1.51.1-netbsd-386.tar.gz +34cafdcd11ae73ae88d66c33eb8449f5c976fc3e37b44774dbe9c71caa95e592 golangci-lint-1.51.1-netbsd-amd64.tar.gz +f8b4e1e47ac17caafe8a5f32f975a2b6a7cb14c27c0f73c1fb15c20ca91c2e03 golangci-lint-1.51.1-netbsd-armv6.tar.gz +c4f58b7e227b9fd41f0e9310dc83f4a4e7d026598e2f6e95b78761081a6d9bd2 golangci-lint-1.51.1-netbsd-armv7.tar.gz +6710e2f5375dc75521c1a17980a6cbbe6ff76c2f8b852964a8af558899a97cf5 golangci-lint-1.51.1-windows-386.zip +722d7b87b9cdda0a3835d5030b3fc5385c2eba4c107f63f6391cfb2ac35f051d golangci-lint-1.51.1-windows-amd64.zip +eb57f9bcb56646f2e3d6ccaf02ec227815fb05077b2e0b1bf9e755805acdc2b9 golangci-lint-1.51.1-windows-arm64.zip +bce02f7232723cb727755ee11f168a700a00896a25d37f87c4b173bce55596b4 golangci-lint-1.51.1-windows-armv6.zip +cf6403f84707ce8c98664736772271bc8874f2e760c2fd0f00cf3e85963507e9 golangci-lint-1.51.1-windows-armv7.zip diff --git a/build/ci.go b/build/ci.go index 06aaae2da38a..094ae0a77bce 100644 --- a/build/ci.go +++ b/build/ci.go @@ -333,7 +333,7 @@ func doLint(cmdline []string) { // downloadLinter downloads and unpacks golangci-lint. func downloadLinter(cachedir string) string { - const version = "1.49.0" + const version = "1.51.1" csdb := build.MustLoadChecksums("build/checksums.txt") arch := runtime.GOARCH From 91cb6f863a965481e51d5d9c0e5ccd54796fd967 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 6 Feb 2023 14:52:51 -0500 Subject: [PATCH 521/715] tests: update (#26548) This updates the reference tests to the latest version. Co-authored-by: Felix Lange --- core/block_validator.go | 12 ++++++++++-- core/state_processor_test.go | 3 +++ tests/block_test_util.go | 8 ++++++++ tests/gen_btheader.go | 6 ++++++ tests/init.go | 18 ++++++++++++++++++ tests/state_test.go | 8 ++++---- tests/testdata | 2 +- 7 files changed, 50 insertions(+), 7 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index 7c202292f974..3704158c11b3 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -50,11 +50,13 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin // header's transaction and uncle roots. The headers are assumed to be already // validated at this point. func (v *BlockValidator) ValidateBody(block *types.Block) error { - // Check whether the block's known, and if not, that it's linkable + // Check whether the block is already imported. if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) { return ErrKnownBlock } - // Header validity is known at this point, check the uncles and transactions + + // Header validity is known at this point. Here we verify that uncles, transactions + // and withdrawals given in the block body match the header. header := block.Header() if err := v.engine.VerifyUncles(v.bc, block); err != nil { return err @@ -65,11 +67,17 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash { return fmt.Errorf("transaction root hash mismatch (header value %x, calculated %x)", header.TxHash, hash) } + // Withdrawals are present after the Shanghai fork. if header.WithdrawalsHash != nil { + // Withdrawals list must be present in body after Shanghai. + if block.Withdrawals() == nil { + return fmt.Errorf("missing withdrawals in block body") + } if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash { return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash) } } + if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { return consensus.ErrUnknownAncestor diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 305948d54c0d..821b85e9bcd5 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -423,5 +423,8 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr } header.Root = common.BytesToHash(hasher.Sum(nil)) // Assemble and return the final block for sealing + if config.IsShanghai(header.Time) { + return types.NewBlockWithWithdrawals(header, txs, nil, receipts, []*types.Withdrawal{}, trie.NewStackTrie(nil)) + } return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index df4f08a76412..8da95a640a10 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -24,6 +24,7 @@ import ( "fmt" "math/big" "os" + "reflect" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -87,6 +88,7 @@ type btHeader struct { GasUsed uint64 Timestamp uint64 BaseFeePerGas *big.Int + WithdrawalsRoot *common.Hash } type btHeaderMarshaling struct { @@ -275,6 +277,12 @@ func validateHeader(h *btHeader, h2 *types.Header) error { if h.Timestamp != h2.Time { return fmt.Errorf("timestamp: want: %v have: %v", h.Timestamp, h2.Time) } + if !reflect.DeepEqual(h.BaseFeePerGas, h2.BaseFee) { + return fmt.Errorf("baseFeePerGas: want: %v have: %v", h.BaseFeePerGas, h2.BaseFee) + } + if !reflect.DeepEqual(h.WithdrawalsRoot, h2.WithdrawalsHash) { + return fmt.Errorf("withdrawalsRoot: want: %v have: %v", h.WithdrawalsRoot, h2.WithdrawalsHash) + } return nil } diff --git a/tests/gen_btheader.go b/tests/gen_btheader.go index 4387f8db41c8..985ea692d751 100644 --- a/tests/gen_btheader.go +++ b/tests/gen_btheader.go @@ -34,6 +34,7 @@ func (b btHeader) MarshalJSON() ([]byte, error) { GasUsed math.HexOrDecimal64 Timestamp math.HexOrDecimal64 BaseFeePerGas *math.HexOrDecimal256 + WithdrawalsRoot *common.Hash } var enc btHeader enc.Bloom = b.Bloom @@ -53,6 +54,7 @@ func (b btHeader) MarshalJSON() ([]byte, error) { enc.GasUsed = math.HexOrDecimal64(b.GasUsed) enc.Timestamp = math.HexOrDecimal64(b.Timestamp) enc.BaseFeePerGas = (*math.HexOrDecimal256)(b.BaseFeePerGas) + enc.WithdrawalsRoot = b.WithdrawalsRoot return json.Marshal(&enc) } @@ -76,6 +78,7 @@ func (b *btHeader) UnmarshalJSON(input []byte) error { GasUsed *math.HexOrDecimal64 Timestamp *math.HexOrDecimal64 BaseFeePerGas *math.HexOrDecimal256 + WithdrawalsRoot *common.Hash } var dec btHeader if err := json.Unmarshal(input, &dec); err != nil { @@ -132,5 +135,8 @@ func (b *btHeader) UnmarshalJSON(input []byte) error { if dec.BaseFeePerGas != nil { b.BaseFeePerGas = (*big.Int)(dec.BaseFeePerGas) } + if dec.WithdrawalsRoot != nil { + b.WithdrawalsRoot = dec.WithdrawalsRoot + } return nil } diff --git a/tests/init.go b/tests/init.go index a36ab4d9d435..db037e3e1a06 100644 --- a/tests/init.go +++ b/tests/init.go @@ -268,6 +268,24 @@ var Forks = map[string]*params.ChainConfig{ TerminalTotalDifficulty: big.NewInt(0), ShanghaiTime: u64(0), }, + "MergeToShanghaiAtTime15k": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + LondonBlock: big.NewInt(0), + ArrowGlacierBlock: big.NewInt(0), + MergeNetsplitBlock: big.NewInt(0), + TerminalTotalDifficulty: big.NewInt(0), + ShanghaiTime: u64(15_000), + }, } // AvailableForks returns the set of defined fork names diff --git a/tests/state_test.go b/tests/state_test.go index a68321e76236..7dd2f678c683 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -56,11 +56,11 @@ func TestState(t *testing.T) { // Uses 1GB RAM per tested fork st.skipLoad(`^stStaticCall/static_Call1MB`) - // Not yet supported TODO - st.skipLoad(`^stEIP3540/`) - st.skipLoad(`^stEIP3860/`) - // Broken tests: + // + // The stEOF tests are generated with EOF as part of Shanghai, which + // is erroneous. Therefore, these tests are skipped. + st.skipLoad(`^EIPTests/stEOF/`) // Expected failures: // For Istanbul, older tests were moved into LegacyTests diff --git a/tests/testdata b/tests/testdata index 24fa31adb30f..bac70c50a579 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit 24fa31adb30f71ee700b27decb5204e53a11d9f3 +Subproject commit bac70c50a579197af68af5fc6d8c7b6163b92c52 From cefc0fa00fb4fa289104cbeb7cc809e07bbf35b8 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 7 Feb 2023 21:32:27 +0800 Subject: [PATCH 522/715] accounts/abi: fix integer encoding/decoding (#26568) This PR fixes this abi encoder/decoder to be more stringent. --- accounts/abi/error_handling.go | 10 +- accounts/abi/unpack.go | 72 ++++++++++----- accounts/abi/unpack_test.go | 162 +++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+), 22 deletions(-) diff --git a/accounts/abi/error_handling.go b/accounts/abi/error_handling.go index 7add7072925e..c106e9ac4321 100644 --- a/accounts/abi/error_handling.go +++ b/accounts/abi/error_handling.go @@ -23,7 +23,15 @@ import ( ) var ( - errBadBool = errors.New("abi: improperly encoded boolean value") + errBadBool = errors.New("abi: improperly encoded boolean value") + errBadUint8 = errors.New("abi: improperly encoded uint8 value") + errBadUint16 = errors.New("abi: improperly encoded uint16 value") + errBadUint32 = errors.New("abi: improperly encoded uint32 value") + errBadUint64 = errors.New("abi: improperly encoded uint64 value") + errBadInt8 = errors.New("abi: improperly encoded int8 value") + errBadInt16 = errors.New("abi: improperly encoded int16 value") + errBadInt32 = errors.New("abi: improperly encoded int32 value") + errBadInt64 = errors.New("abi: improperly encoded int64 value") ) // formatSliceString formats the reflection kind with the given slice size diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index b6ca0a038480..1e778a6ff0db 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -19,6 +19,7 @@ package abi import ( "encoding/binary" "fmt" + "math" "math/big" "reflect" @@ -33,43 +34,72 @@ var ( ) // ReadInteger reads the integer based on its kind and returns the appropriate value. -func ReadInteger(typ Type, b []byte) interface{} { +func ReadInteger(typ Type, b []byte) (interface{}, error) { + ret := new(big.Int).SetBytes(b) + if typ.T == UintTy { + u64, isu64 := ret.Uint64(), ret.IsUint64() switch typ.Size { case 8: - return b[len(b)-1] + if !isu64 || u64 > math.MaxUint8 { + return nil, errBadUint8 + } + return byte(u64), nil case 16: - return binary.BigEndian.Uint16(b[len(b)-2:]) + if !isu64 || u64 > math.MaxUint16 { + return nil, errBadUint16 + } + return uint16(u64), nil case 32: - return binary.BigEndian.Uint32(b[len(b)-4:]) + if !isu64 || u64 > math.MaxUint32 { + return nil, errBadUint32 + } + return uint32(u64), nil case 64: - return binary.BigEndian.Uint64(b[len(b)-8:]) + if !isu64 { + return nil, errBadUint64 + } + return u64, nil default: // the only case left for unsigned integer is uint256. - return new(big.Int).SetBytes(b) + return ret, nil } } + + // big.SetBytes can't tell if a number is negative or positive in itself. + // On EVM, if the returned number > max int256, it is negative. + // A number is > max int256 if the bit at position 255 is set. + if ret.Bit(255) == 1 { + ret.Add(MaxUint256, new(big.Int).Neg(ret)) + ret.Add(ret, common.Big1) + ret.Neg(ret) + } + i64, isi64 := ret.Int64(), ret.IsInt64() switch typ.Size { case 8: - return int8(b[len(b)-1]) + if !isi64 || i64 < math.MinInt8 || i64 > math.MaxInt8 { + return nil, errBadInt8 + } + return int8(i64), nil case 16: - return int16(binary.BigEndian.Uint16(b[len(b)-2:])) + if !isi64 || i64 < math.MinInt16 || i64 > math.MaxInt16 { + return nil, errBadInt16 + } + return int16(i64), nil case 32: - return int32(binary.BigEndian.Uint32(b[len(b)-4:])) + if !isi64 || i64 < math.MinInt32 || i64 > math.MaxInt32 { + return nil, errBadInt32 + } + return int32(i64), nil case 64: - return int64(binary.BigEndian.Uint64(b[len(b)-8:])) + if !isi64 { + return nil, errBadInt64 + } + return i64, nil default: // the only case left for integer is int256 - // big.SetBytes can't tell if a number is negative or positive in itself. - // On EVM, if the returned number > max int256, it is negative. - // A number is > max int256 if the bit at position 255 is set. - ret := new(big.Int).SetBytes(b) - if ret.Bit(255) == 1 { - ret.Add(MaxUint256, new(big.Int).Neg(ret)) - ret.Add(ret, common.Big1) - ret.Neg(ret) - } - return ret + + return ret, nil } } @@ -234,7 +264,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) { case StringTy: // variable arrays are written at the end of the return bytes return string(output[begin : begin+length]), nil case IntTy, UintTy: - return ReadInteger(t, returnOutput), nil + return ReadInteger(t, returnOutput) case BoolTy: return readBool(returnOutput) case AddressTy: diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 363e0cd5943e..6dd2db0d583d 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/hex" "fmt" + "math" "math/big" "reflect" "strconv" @@ -943,3 +944,164 @@ func TestOOMMaliciousInput(t *testing.T) { } } } + +func TestPackAndUnpackIncompatibleNumber(t *testing.T) { + var encodeABI Arguments + uint256Ty, err := NewType("uint256", "", nil) + if err != nil { + panic(err) + } + encodeABI = Arguments{ + {Type: uint256Ty}, + } + + maxU64, ok := new(big.Int).SetString(strconv.FormatUint(math.MaxUint64, 10), 10) + if !ok { + panic("bug") + } + maxU64Plus1 := new(big.Int).Add(maxU64, big.NewInt(1)) + cases := []struct { + decodeType string + inputValue *big.Int + err error + expectValue interface{} + }{ + { + decodeType: "uint8", + inputValue: big.NewInt(math.MaxUint8 + 1), + err: errBadUint8, + }, + { + decodeType: "uint8", + inputValue: big.NewInt(math.MaxUint8), + err: nil, + expectValue: uint8(math.MaxUint8), + }, + { + decodeType: "uint16", + inputValue: big.NewInt(math.MaxUint16 + 1), + err: errBadUint16, + }, + { + decodeType: "uint16", + inputValue: big.NewInt(math.MaxUint16), + err: nil, + expectValue: uint16(math.MaxUint16), + }, + { + decodeType: "uint32", + inputValue: big.NewInt(math.MaxUint32 + 1), + err: errBadUint32, + }, + { + decodeType: "uint32", + inputValue: big.NewInt(math.MaxUint32), + err: nil, + expectValue: uint32(math.MaxUint32), + }, + { + decodeType: "uint64", + inputValue: maxU64Plus1, + err: errBadUint64, + }, + { + decodeType: "uint64", + inputValue: maxU64, + err: nil, + expectValue: uint64(math.MaxUint64), + }, + { + decodeType: "uint256", + inputValue: maxU64Plus1, + err: nil, + expectValue: maxU64Plus1, + }, + { + decodeType: "int8", + inputValue: big.NewInt(math.MaxInt8 + 1), + err: errBadInt8, + }, + { + decodeType: "int8", + inputValue: big.NewInt(math.MinInt8 - 1), + err: errBadInt8, + }, + { + decodeType: "int8", + inputValue: big.NewInt(math.MaxInt8), + err: nil, + expectValue: int8(math.MaxInt8), + }, + { + decodeType: "int16", + inputValue: big.NewInt(math.MaxInt16 + 1), + err: errBadInt16, + }, + { + decodeType: "int16", + inputValue: big.NewInt(math.MinInt16 - 1), + err: errBadInt16, + }, + { + decodeType: "int16", + inputValue: big.NewInt(math.MaxInt16), + err: nil, + expectValue: int16(math.MaxInt16), + }, + { + decodeType: "int32", + inputValue: big.NewInt(math.MaxInt32 + 1), + err: errBadInt32, + }, + { + decodeType: "int32", + inputValue: big.NewInt(math.MinInt32 - 1), + err: errBadInt32, + }, + { + decodeType: "int32", + inputValue: big.NewInt(math.MaxInt32), + err: nil, + expectValue: int32(math.MaxInt32), + }, + { + decodeType: "int64", + inputValue: new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(1)), + err: errBadInt64, + }, + { + decodeType: "int64", + inputValue: new(big.Int).Sub(big.NewInt(math.MinInt64), big.NewInt(1)), + err: errBadInt64, + }, + { + decodeType: "int64", + inputValue: big.NewInt(math.MaxInt64), + err: nil, + expectValue: int64(math.MaxInt64), + }, + } + for i, testCase := range cases { + packed, err := encodeABI.Pack(testCase.inputValue) + if err != nil { + panic(err) + } + ty, err := NewType(testCase.decodeType, "", nil) + if err != nil { + panic(err) + } + decodeABI := Arguments{ + {Type: ty}, + } + decoded, err := decodeABI.Unpack(packed) + if err != testCase.err { + t.Fatalf("Expected error %v, actual error %v. case %d", testCase.err, err, i) + } + if err != nil { + continue + } + if !reflect.DeepEqual(decoded[0], testCase.expectValue) { + t.Fatalf("Expected value %v, actual value %v", testCase.expectValue, decoded[0]) + } + } +} From 31d401ea687066465846ec4a0d2388ef80e4b0cc Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 7 Feb 2023 15:44:27 +0100 Subject: [PATCH 523/715] rpc: remove DecimalOrHex type (#26629) It's the same as math.HexOrDecimal64, which has more uses across the codebase. --- internal/ethapi/api.go | 2 +- rpc/types.go | 21 --------------------- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4fa5b9e67e36..58f65f86d794 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -88,7 +88,7 @@ type feeHistoryResult struct { } // FeeHistory returns the fee market history. -func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { +func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, int(blockCount), lastBlock, rewardPercentiles) if err != nil { return nil, err diff --git a/rpc/types.go b/rpc/types.go index 9dda067e7f2f..55d11fbaaf14 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -243,24 +243,3 @@ func BlockNumberOrHashWithHash(hash common.Hash, canonical bool) BlockNumberOrHa RequireCanonical: canonical, } } - -// DecimalOrHex unmarshals a non-negative decimal or hex parameter into a uint64. -type DecimalOrHex uint64 - -// UnmarshalJSON implements json.Unmarshaler. -func (dh *DecimalOrHex) UnmarshalJSON(data []byte) error { - input := strings.TrimSpace(string(data)) - if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' { - input = input[1 : len(input)-1] - } - - value, err := strconv.ParseUint(input, 10, 64) - if err != nil { - value, err = hexutil.DecodeUint64(input) - } - if err != nil { - return err - } - *dh = DecimalOrHex(value) - return nil -} From 2f73f4f028e4bce5e804583d8ccd0cf5ecaf27be Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 7 Feb 2023 19:16:53 +0100 Subject: [PATCH 524/715] eth/catalyst,miner: include withdrawals in payload id calculation (#26554) According to the spec the payloadID needs to be random or dependent on all arguments, to prevent two payloads from clashing. This change adds withdrawals into the payload derivation. --------- Co-authored-by: lightclient@protonmail.com Co-authored-by: Martin Holst Swende Co-authored-by: Felix Lange --- eth/catalyst/api_test.go | 2 + miner/payload_building.go | 2 + miner/payload_building_test.go | 77 ++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index ae3ad08e7af9..96613ac164d8 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -1041,6 +1041,7 @@ func TestWithdrawals(t *testing.T) { Timestamp: blockParams.Timestamp, FeeRecipient: blockParams.SuggestedFeeRecipient, Random: blockParams.Random, + Withdrawals: blockParams.Withdrawals, }).Id() execData, err := api.GetPayloadV2(payloadID) if err != nil { @@ -1087,6 +1088,7 @@ func TestWithdrawals(t *testing.T) { Timestamp: blockParams.Timestamp, FeeRecipient: blockParams.SuggestedFeeRecipient, Random: blockParams.Random, + Withdrawals: blockParams.Withdrawals, }).Id() execData, err = api.GetPayloadV2(payloadID) if err != nil { diff --git a/miner/payload_building.go b/miner/payload_building.go index 4c36dd8d19da..f84d908e86d6 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" ) // BuildPayloadArgs contains the provided parameters for building payload. @@ -49,6 +50,7 @@ func (args *BuildPayloadArgs) Id() engine.PayloadID { binary.Write(hasher, binary.BigEndian, args.Timestamp) hasher.Write(args.Random[:]) hasher.Write(args.FeeRecipient[:]) + rlp.Encode(hasher, args.Withdrawals) var out engine.PayloadID copy(out[:], hasher.Sum(nil)[:8]) return out diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index 43b9db4161f5..b2f1d68f3c61 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) @@ -79,3 +80,79 @@ func TestBuildPayload(t *testing.T) { t.Fatal("Unexpected payload data") } } + +func TestPayloadId(t *testing.T) { + ids := make(map[string]int) + for i, tt := range []*BuildPayloadArgs{ + &BuildPayloadArgs{ + Parent: common.Hash{1}, + Timestamp: 1, + Random: common.Hash{0x1}, + FeeRecipient: common.Address{0x1}, + }, + // Different parent + &BuildPayloadArgs{ + Parent: common.Hash{2}, + Timestamp: 1, + Random: common.Hash{0x1}, + FeeRecipient: common.Address{0x1}, + }, + // Different timestamp + &BuildPayloadArgs{ + Parent: common.Hash{2}, + Timestamp: 2, + Random: common.Hash{0x1}, + FeeRecipient: common.Address{0x1}, + }, + // Different Random + &BuildPayloadArgs{ + Parent: common.Hash{2}, + Timestamp: 2, + Random: common.Hash{0x2}, + FeeRecipient: common.Address{0x1}, + }, + // Different fee-recipient + &BuildPayloadArgs{ + Parent: common.Hash{2}, + Timestamp: 2, + Random: common.Hash{0x2}, + FeeRecipient: common.Address{0x2}, + }, + // Different withdrawals (non-empty) + &BuildPayloadArgs{ + Parent: common.Hash{2}, + Timestamp: 2, + Random: common.Hash{0x2}, + FeeRecipient: common.Address{0x2}, + Withdrawals: []*types.Withdrawal{ + &types.Withdrawal{ + Index: 0, + Validator: 0, + Address: common.Address{}, + Amount: 0, + }, + }, + }, + // Different withdrawals (non-empty) + &BuildPayloadArgs{ + Parent: common.Hash{2}, + Timestamp: 2, + Random: common.Hash{0x2}, + FeeRecipient: common.Address{0x2}, + Withdrawals: []*types.Withdrawal{ + &types.Withdrawal{ + Index: 2, + Validator: 0, + Address: common.Address{}, + Amount: 0, + }, + }, + }, + } { + id := tt.Id().String() + if prev, exists := ids[id]; exists { + t.Errorf("ID collision, case %d and case %d: id %v", prev, i, id) + } + ids[id] = i + } +} From 00a9b80b5cca71a279a19c960e5ce731eb46627e Mon Sep 17 00:00:00 2001 From: halilylm <65048618+halilylm@users.noreply.github.com> Date: Wed, 8 Feb 2023 12:37:33 +0300 Subject: [PATCH 525/715] light: fix receiver name from Python style to Go (#26631) Co-authored-by: Halil Yildirim --- light/txpool_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/light/txpool_test.go b/light/txpool_test.go index 53732acfa8c8..077008806348 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -36,19 +36,19 @@ type testTxRelay struct { send, discard, mined chan int } -func (self *testTxRelay) Send(txs types.Transactions) { - self.send <- len(txs) +func (r *testTxRelay) Send(txs types.Transactions) { + r.send <- len(txs) } -func (self *testTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) { +func (r *testTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) { m := len(mined) if m != 0 { - self.mined <- m + r.mined <- m } } -func (self *testTxRelay) Discard(hashes []common.Hash) { - self.discard <- len(hashes) +func (r *testTxRelay) Discard(hashes []common.Hash) { + r.discard <- len(hashes) } const poolTestTxs = 1000 From 8c18b48bf15f19a702d823fe50205dca58fc83a9 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 8 Feb 2023 10:39:17 +0100 Subject: [PATCH 526/715] log: allow tabs in log messages (#26630) * log: allow tabs in log messages This fixes a regression where panic reports in RPC handlers were quoted because they contain tab characters. * Update format.go --- log/format.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log/format.go b/log/format.go index 42525ea6d296..d7e2f820afe7 100644 --- a/log/format.go +++ b/log/format.go @@ -492,8 +492,8 @@ func escapeString(s string) string { func escapeMessage(s string) string { needsQuoting := false for _, r := range s { - // Carriage return and Line feed are ok - if r == 0xa || r == 0xd { + // Allow CR/LF/TAB. This is to make multi-line messages work. + if r == '\r' || r == '\n' || r == '\t' { continue } // We quote everything below (0x20) and above~ (0x7E), From 9842301376b4328421e8a6163f12766dfa6641f8 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 8 Feb 2023 19:14:34 +0800 Subject: [PATCH 527/715] all: remove database commit callback, rework noderesolver (#26637) This change ports some changes from the main PBSS PR: - get rid of callback function in `trie.Database.Commit` which is not required anymore - rework the `nodeResolver` in `trie.Iterator` to make it compatible with multiple state scheme - some other shallow changes in tests and typo-fixes --- cmd/geth/snapshot.go | 4 +- core/blockchain.go | 8 ++-- core/blockchain_repair_test.go | 6 +-- core/blockchain_sethead_test.go | 2 +- core/blockchain_snapshot_test.go | 2 +- core/chain_makers.go | 2 +- core/dao_test.go | 8 ++-- core/genesis.go | 2 +- core/state/iterator_test.go | 63 ++++++++++++++++++-------- core/state/pruner/pruner.go | 2 +- core/state/snapshot/generate.go | 21 +++++---- core/state/snapshot/generate_test.go | 4 +- core/state/statedb_test.go | 8 ++-- core/state/sync_test.go | 2 +- eth/protocols/eth/handler_test.go | 2 +- light/postprocess.go | 4 +- tests/fuzzers/stacktrie/trie_fuzzer.go | 2 +- trie/database.go | 11 ++--- trie/encoding_test.go | 6 +-- trie/iterator.go | 26 +++++++---- trie/iterator_test.go | 4 +- trie/stacktrie_test.go | 2 - trie/trie_test.go | 56 +++++++---------------- 23 files changed, 127 insertions(+), 120 deletions(-) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index ae60fb72e522..7175bb953dee 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -165,6 +165,8 @@ block is used. } ) +// Deprecation: this command should be deprecated once the hash-based +// scheme is deprecated. func pruneState(ctx *cli.Context) error { stack, config := makeConfigNode(ctx) defer stack.Close() @@ -433,7 +435,7 @@ func traverseRawState(ctx *cli.Context) error { nodes += 1 node := storageIter.Hash() - // Check the present for non-empty hash node(embedded node doesn't + // Check the presence for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { blob := rawdb.ReadLegacyTrieNode(chaindb, node) diff --git a/core/blockchain.go b/core/blockchain.go index ebb985e9b28d..c049f8955a15 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -945,14 +945,14 @@ func (bc *BlockChain) Stop() { recent := bc.GetBlockByNumber(number - offset) log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) - if err := triedb.Commit(recent.Root(), true, nil); err != nil { + if err := triedb.Commit(recent.Root(), true); err != nil { log.Error("Failed to commit recent state trie", "err", err) } } } if snapBase != (common.Hash{}) { log.Info("Writing snapshot state to disk", "root", snapBase) - if err := triedb.Commit(snapBase, true, nil); err != nil { + if err := triedb.Commit(snapBase, true); err != nil { log.Error("Failed to commit recent state trie", "err", err) } } @@ -1343,7 +1343,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } // If we're running an archive node, always flush if bc.cacheConfig.TrieDirtyDisabled { - return bc.triedb.Commit(root, false, nil) + return bc.triedb.Commit(root, false) } // Full but not archive node, do proper garbage collection bc.triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive @@ -1379,7 +1379,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/TriesInMemory) } // Flush an entire trie and restart the counters - bc.triedb.Commit(header.Root, true, nil) + bc.triedb.Commit(header.Root, true) bc.lastWrite = chosen bc.gcproc = 0 } diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 1b3f1b718782..0fdd5ae27999 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1803,7 +1803,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { t.Fatalf("Failed to import canonical chain start: %v", err) } if tt.commitBlock > 0 { - chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil) + chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), false) if snapshots { if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil { t.Fatalf("Failed to flatten snapshots: %v", err) @@ -1918,7 +1918,7 @@ func TestIssue23496(t *testing.T) { if _, err := chain.InsertChain(blocks[:1]); err != nil { t.Fatalf("Failed to import canonical chain start: %v", err) } - chain.stateCache.TrieDB().Commit(blocks[0].Root(), true, nil) + chain.stateCache.TrieDB().Commit(blocks[0].Root(), false) // Insert block B2 and commit the snapshot into disk if _, err := chain.InsertChain(blocks[1:2]); err != nil { @@ -1932,7 +1932,7 @@ func TestIssue23496(t *testing.T) { if _, err := chain.InsertChain(blocks[2:3]); err != nil { t.Fatalf("Failed to import canonical chain start: %v", err) } - chain.stateCache.TrieDB().Commit(blocks[2].Root(), true, nil) + chain.stateCache.TrieDB().Commit(blocks[2].Root(), false) // Insert the remaining blocks if _, err := chain.InsertChain(blocks[3:]); err != nil { diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index 1750cb4e63dc..fa55c6252d15 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -2004,7 +2004,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { t.Fatalf("Failed to import canonical chain start: %v", err) } if tt.commitBlock > 0 { - chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil) + chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), false) if snapshots { if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil { t.Fatalf("Failed to flatten snapshots: %v", err) diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index b5aa7844b4f6..110d2d1e3c77 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -99,7 +99,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo startPoint = point if basic.commitBlock > 0 && basic.commitBlock == point { - chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), true, nil) + chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), false) } if basic.snapshotBlock > 0 && basic.snapshotBlock == point { // Flushing the entire snap tree into the disk, the diff --git a/core/chain_makers.go b/core/chain_makers.go index de63f234ac14..3518929f8e71 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -312,7 +312,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse if err != nil { panic(fmt.Sprintf("state write error: %v", err)) } - if err := statedb.Database().TrieDB().Commit(root, false, nil); err != nil { + if err := statedb.Database().TrieDB().Commit(root, false); err != nil { panic(fmt.Sprintf("trie write error: %v", err)) } return block, b.receipts diff --git a/core/dao_test.go b/core/dao_test.go index 632eafe4d5c8..4ae86b50ff1f 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -83,7 +83,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import contra-fork chain for expansion: %v", err) } - if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true, nil); err != nil { + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } bc.Stop() @@ -106,7 +106,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import pro-fork chain for expansion: %v", err) } - if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true, nil); err != nil { + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } bc.Stop() @@ -131,7 +131,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import contra-fork chain for expansion: %v", err) } - if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true, nil); err != nil { + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) @@ -149,7 +149,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import pro-fork chain for expansion: %v", err) } - if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, true, nil); err != nil { + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) diff --git a/core/genesis.go b/core/genesis.go index 62096541f984..5ab28001d89f 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -157,7 +157,7 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database) error { } // Commit newly generated states into disk if it's not empty. if root != types.EmptyRootHash { - if err := triedb.Commit(root, true, nil); err != nil { + if err := triedb.Commit(root, true); err != nil { return err } } diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index 7669ac97a215..ab06cb422fb3 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -17,17 +17,17 @@ package state import ( - "bytes" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" ) // Tests that the node iterator indeed walks over the entire database contents. func TestNodeIteratorCoverage(t *testing.T) { // Create some arbitrary test state to iterate db, sdb, root, _ := makeTestState() - sdb.TrieDB().Commit(root, false, nil) + sdb.TrieDB().Commit(root, false) state, err := New(root, sdb, nil) if err != nil { @@ -40,29 +40,54 @@ func TestNodeIteratorCoverage(t *testing.T) { hashes[it.Hash] = struct{}{} } } - // Cross check the iterated hashes and the database/nodepool content - for hash := range hashes { - if _, err = sdb.TrieDB().Node(hash); err != nil { - _, err = sdb.ContractCode(common.Hash{}, hash) - } - if err != nil { - t.Errorf("failed to retrieve reported node %x", hash) - } - } - for _, hash := range sdb.TrieDB().Nodes() { - if _, ok := hashes[hash]; !ok { - t.Errorf("state entry not reported %x", hash) + // Check in-disk nodes + var ( + seenNodes = make(map[common.Hash]struct{}) + seenCodes = make(map[common.Hash]struct{}) + ) + it := db.NewIterator(nil, nil) + for it.Next() { + ok, hash := isTrieNode(sdb.TrieDB().Scheme(), it.Key(), it.Value()) + if !ok { + continue } + seenNodes[hash] = struct{}{} } - it := db.NewIterator(nil, nil) + it.Release() + + // Check in-disk codes + it = db.NewIterator(nil, nil) for it.Next() { - key := it.Key() - if bytes.HasPrefix(key, []byte("secure-key-")) { + ok, hash := rawdb.IsCodeKey(it.Key()) + if !ok { continue } - if _, ok := hashes[common.BytesToHash(key)]; !ok { - t.Errorf("state entry not reported %x", key) + if _, ok := hashes[common.BytesToHash(hash)]; !ok { + t.Errorf("state entry not reported %x", it.Key()) } + seenCodes[common.BytesToHash(hash)] = struct{}{} } it.Release() + + // Cross check the iterated hashes and the database/nodepool content + for hash := range hashes { + _, ok := seenNodes[hash] + if !ok { + _, ok = seenCodes[hash] + } + if !ok { + t.Errorf("failed to retrieve reported node %x", hash) + } + } +} + +// isTrieNode is a helper function which reports if the provided +// database entry belongs to a trie node or not. +func isTrieNode(scheme string, key, val []byte) (bool, common.Hash) { + if scheme == rawdb.HashScheme { + if len(key) == common.HashLength { + return true, common.BytesToHash(key) + } + } + return false, common.Hash{} } diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index b435ab609765..d1ffc4f9448f 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -363,7 +363,7 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err } headBlock := rawdb.ReadHeadBlock(db) if headBlock == nil { - return errors.New("Failed to load head block") + return errors.New("failed to load head block") } // Initialize the snapshot tree in recovery mode to handle this special case: // - Users run the `prune-state` command multiple times diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 3ed303cdfc75..a2be1c24b2a0 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -359,19 +359,22 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi } // We use the snap data to build up a cache which can be used by the // main account trie as a primary lookup when resolving hashes - var snapNodeCache ethdb.Database + var resolver trie.NodeResolver if len(result.keys) > 0 { - snapNodeCache = rawdb.NewMemoryDatabase() - snapTrieDb := trie.NewDatabase(snapNodeCache) - snapTrie := trie.NewEmpty(snapTrieDb) + mdb := rawdb.NewMemoryDatabase() + tdb := trie.NewDatabase(mdb) + snapTrie := trie.NewEmpty(tdb) for i, key := range result.keys { snapTrie.Update(key, result.vals[i]) } - root, nodes, _ := snapTrie.Commit(false) - if nodes != nil { - snapTrieDb.Update(trie.NewWithNodeSet(nodes)) + root, nodes, err := snapTrie.Commit(false) + if err == nil && nodes != nil { + tdb.Update(trie.NewWithNodeSet(nodes)) + tdb.Commit(root, false) + } + resolver = func(owner common.Hash, path []byte, hash common.Hash) []byte { + return rawdb.ReadTrieNode(mdb, owner, path, hash, tdb.Scheme()) } - snapTrieDb.Commit(root, false, nil) } // Construct the trie for state iteration, reuse the trie // if it's already opened with some nodes resolved. @@ -400,7 +403,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi start = time.Now() internal time.Duration ) - nodeIt.AddResolver(snapNodeCache) + nodeIt.AddResolver(resolver) for iter.Next() { if last != nil && bytes.Compare(iter.Key, last) > 0 { diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index bb9e231bc13b..e79c919c174b 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -203,7 +203,7 @@ func (t *testHelper) Commit() common.Hash { t.nodes.Merge(nodes) } t.triedb.Update(t.nodes) - t.triedb.Commit(root, false, nil) + t.triedb.Commit(root, false) return root } @@ -391,7 +391,7 @@ func TestGenerateCorruptAccountTrie(t *testing.T) { root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 // Delete an account trie leaf and ensure the generator chokes - helper.triedb.Commit(root, false, nil) + helper.triedb.Commit(root, false) helper.diskdb.Delete(common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7").Bytes()) snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index a39c83d2d1a1..8aa59e3ee592 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -55,7 +55,7 @@ func TestUpdateLeaks(t *testing.T) { } root := state.IntermediateRoot(false) - if err := state.Database().TrieDB().Commit(root, false, nil); err != nil { + if err := state.Database().TrieDB().Commit(root, false); err != nil { t.Errorf("can not commit trie %v to persistent database", root.Hex()) } @@ -106,7 +106,7 @@ func TestIntermediateLeaks(t *testing.T) { if err != nil { t.Fatalf("failed to commit transition state: %v", err) } - if err = transState.Database().TrieDB().Commit(transRoot, false, nil); err != nil { + if err = transState.Database().TrieDB().Commit(transRoot, false); err != nil { t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) } @@ -114,7 +114,7 @@ func TestIntermediateLeaks(t *testing.T) { if err != nil { t.Fatalf("failed to commit final state: %v", err) } - if err = finalState.Database().TrieDB().Commit(finalRoot, false, nil); err != nil { + if err = finalState.Database().TrieDB().Commit(finalRoot, false); err != nil { t.Errorf("can not commit trie %v to persistent database", finalRoot.Hex()) } @@ -948,7 +948,7 @@ func TestFlushOrderDataLoss(t *testing.T) { if err := statedb.TrieDB().Cap(1024); err != nil { t.Fatalf("failed to cap trie dirty cache: %v", err) } - if err := statedb.TrieDB().Commit(root, false, nil); err != nil { + if err := statedb.TrieDB().Commit(root, false); err != nil { t.Fatalf("failed to commit state trie: %v", err) } // Reopen the state trie from flushed disk and verify it diff --git a/core/state/sync_test.go b/core/state/sync_test.go index d3b77da9b422..84b7bf84e02f 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -174,7 +174,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { // Create a random state to copy _, srcDb, srcRoot, srcAccounts := makeTestState() if commit { - srcDb.TrieDB().Commit(srcRoot, false, nil) + srcDb.TrieDB().Commit(srcRoot, false) } srcTrie, _ := trie.New(trie.StateTrieID(srcRoot), srcDb.TrieDB()) diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index b4d2574c383e..51850c60eae2 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -111,7 +111,7 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, panic(err) } for _, block := range bs { - chain.StateCache().TrieDB().Commit(block.Root(), false, nil) + chain.StateCache().TrieDB().Commit(block.Root(), false) } txconfig := txpool.DefaultConfig txconfig.Journal = "" // Don't litter the disk with test journals diff --git a/light/postprocess.go b/light/postprocess.go index 181916deb9a3..61eec3609bfd 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -221,7 +221,7 @@ func (c *ChtIndexerBackend) Commit() error { if err := c.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { return err } - if err := c.triedb.Commit(root, false, nil); err != nil { + if err := c.triedb.Commit(root, false); err != nil { return err } } @@ -467,7 +467,7 @@ func (b *BloomTrieIndexerBackend) Commit() error { if err := b.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { return err } - if err := b.triedb.Commit(root, false, nil); err != nil { + if err := b.triedb.Commit(root, false); err != nil { return err } } diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 6ac6feee9111..1d200e9e47a8 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -190,7 +190,7 @@ func (f *fuzzer) fuzz() int { dbA.Update(trie.NewWithNodeSet(nodes)) } // Flush memdb -> disk (sponge) - dbA.Commit(rootA, false, nil) + dbA.Commit(rootA, false) // Stacktrie requires sorted insertion sort.Sort(vals) diff --git a/trie/database.go b/trie/database.go index 477179b27b65..74247d59c4f8 100644 --- a/trie/database.go +++ b/trie/database.go @@ -632,7 +632,7 @@ func (db *Database) Cap(limit common.StorageSize) error { // // Note, this method is a non-synchronized mutator. It is unsafe to call this // concurrently with other mutators. -func (db *Database) Commit(node common.Hash, report bool, callback func(common.Hash)) error { +func (db *Database) Commit(node common.Hash, report bool) error { // Create a database batch to flush persistent data out. It is important that // outside code doesn't see an inconsistent state (referenced data removed from // memory cache during commit but not yet in persistent storage). This is ensured @@ -650,7 +650,7 @@ func (db *Database) Commit(node common.Hash, report bool, callback func(common.H nodes, storage := len(db.dirties), db.dirtiesSize uncacher := &cleaner{db} - if err := db.commit(node, batch, uncacher, callback); err != nil { + if err := db.commit(node, batch, uncacher); err != nil { log.Error("Failed to commit trie from trie database", "err", err) return err } @@ -687,7 +687,7 @@ func (db *Database) Commit(node common.Hash, report bool, callback func(common.H } // commit is the private locked version of Commit. -func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleaner, callback func(common.Hash)) error { +func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleaner) error { // If the node does not exist, it's a previously committed node node, ok := db.dirties[hash] if !ok { @@ -696,7 +696,7 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane var err error node.forChilds(func(child common.Hash) { if err == nil { - err = db.commit(child, batch, uncacher, callback) + err = db.commit(child, batch, uncacher) } }) if err != nil { @@ -704,9 +704,6 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane } // If we've reached an optimal batch size, commit and start over rawdb.WriteLegacyTrieNode(batch, hash, node.rlp()) - if callback != nil { - callback(hash) - } if batch.ValueSize() >= ethdb.IdealBatchSize { if err := batch.Write(); err != nil { return err diff --git a/trie/encoding_test.go b/trie/encoding_test.go index 16393313f743..e8fe4f3c6bb4 100644 --- a/trie/encoding_test.go +++ b/trie/encoding_test.go @@ -78,17 +78,17 @@ func TestHexKeybytes(t *testing.T) { } func TestHexToCompactInPlace(t *testing.T) { - for i, keyS := range []string{ + for i, key := range []string{ "00", "060a040c0f000a090b040803010801010900080d090a0a0d0903000b10", "10", } { - hexBytes, _ := hex.DecodeString(keyS) + hexBytes, _ := hex.DecodeString(key) exp := hexToCompact(hexBytes) sz := hexToCompactInPlace(hexBytes) got := hexBytes[:sz] if !bytes.Equal(exp, got) { - t.Fatalf("test %d: encoding err\ninp %v\ngot %x\nexp %x\n", i, keyS, got, exp) + t.Fatalf("test %d: encoding err\ninp %v\ngot %x\nexp %x\n", i, key, got, exp) } } } diff --git a/trie/iterator.go b/trie/iterator.go index b13651fc0439..aa621cd54a22 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -22,9 +22,15 @@ import ( "errors" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" ) +// NodeResolver is used for looking up trie nodes before reaching into the real +// persistent layer. This is not mandatory, rather is an optimization for cases +// where trie nodes can be recovered from some external mechanism without reading +// from disk. In those cases, this resolver allows short circuiting accesses and +// returning them from memory. +type NodeResolver func(owner common.Hash, path []byte, hash common.Hash) []byte + // Iterator is a key-value trie iterator that traverses a Trie. type Iterator struct { nodeIt NodeIterator @@ -107,8 +113,8 @@ type NodeIterator interface { // to the value after calling Next. LeafProof() [][]byte - // AddResolver sets an intermediate database to use for looking up trie nodes - // before reaching into the real persistent layer. + // AddResolver sets a node resolver to use for looking up trie nodes before + // reaching into the real persistent layer. // // This is not required for normal operation, rather is an optimization for // cases where trie nodes can be recovered from some external mechanism without @@ -118,7 +124,7 @@ type NodeIterator interface { // Before adding a similar mechanism to any other place in Geth, consider // making trie.Database an interface and wrapping at that level. It's a huge // refactor, but it could be worth it if another occurrence arises. - AddResolver(ethdb.KeyValueReader) + AddResolver(NodeResolver) } // nodeIteratorState represents the iteration state at one particular node of the @@ -137,7 +143,7 @@ type nodeIterator struct { path []byte // Path to the current node err error // Failure set in case of an internal error in the iterator - resolver ethdb.KeyValueReader // Optional intermediate resolver above the disk layer + resolver NodeResolver // optional node resolver for avoiding disk hits } // errIteratorEnd is stored in nodeIterator.err when iteration is done. @@ -165,7 +171,7 @@ func newNodeIterator(trie *Trie, start []byte) NodeIterator { return it } -func (it *nodeIterator) AddResolver(resolver ethdb.KeyValueReader) { +func (it *nodeIterator) AddResolver(resolver NodeResolver) { it.resolver = resolver } @@ -369,7 +375,7 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by func (it *nodeIterator) resolveHash(hash hashNode, path []byte) (node, error) { if it.resolver != nil { - if blob, err := it.resolver.Get(hash); err == nil && len(blob) > 0 { + if blob := it.resolver(it.trie.owner, path, common.BytesToHash(hash)); len(blob) > 0 { if resolved, err := decodeNode(hash, blob); err == nil { return resolved, nil } @@ -385,7 +391,7 @@ func (it *nodeIterator) resolveHash(hash hashNode, path []byte) (node, error) { func (it *nodeIterator) resolveBlob(hash hashNode, path []byte) ([]byte, error) { if it.resolver != nil { - if blob, err := it.resolver.Get(hash); err == nil && len(blob) > 0 { + if blob := it.resolver(it.trie.owner, path, common.BytesToHash(hash)); len(blob) > 0 { return blob, nil } } @@ -589,7 +595,7 @@ func (it *differenceIterator) NodeBlob() []byte { return it.b.NodeBlob() } -func (it *differenceIterator) AddResolver(resolver ethdb.KeyValueReader) { +func (it *differenceIterator) AddResolver(resolver NodeResolver) { panic("not implemented") } @@ -704,7 +710,7 @@ func (it *unionIterator) NodeBlob() []byte { return (*it.items)[0].NodeBlob() } -func (it *unionIterator) AddResolver(resolver ethdb.KeyValueReader) { +func (it *unionIterator) AddResolver(resolver NodeResolver) { panic("not implemented") } diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 2664dab2d265..1fb6a97ea901 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -337,7 +337,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { _, nodes, _ := tr.Commit(false) triedb.Update(NewWithNodeSet(nodes)) if !memonly { - triedb.Commit(tr.Hash(), true, nil) + triedb.Commit(tr.Hash(), false) } wantNodeCount := checkIteratorNoDups(t, tr.NodeIterator(nil), nil) @@ -429,7 +429,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { root, nodes, _ := ctr.Commit(false) triedb.Update(NewWithNodeSet(nodes)) if !memonly { - triedb.Commit(root, true, nil) + triedb.Commit(root, false) } barNodeHash := common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e") var ( diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index 215c97cfcdf7..3e6cc8cd5785 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -255,7 +255,6 @@ func TestValLength56(t *testing.T) { func TestUpdateSmallNodes(t *testing.T) { st := NewStackTrie(nil) nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) - kvs := []struct { K string V string @@ -284,7 +283,6 @@ func TestUpdateVariableKeys(t *testing.T) { t.SkipNow() st := NewStackTrie(nil) nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) - kvs := []struct { K string V string diff --git a/trie/trie_test.go b/trie/trie_test.go index a7577040bcd1..aa9db5063540 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -86,7 +86,7 @@ func testMissingNode(t *testing.T, memonly bool) { root, nodes, _ := trie.Commit(false) triedb.Update(NewWithNodeSet(nodes)) if !memonly { - triedb.Commit(root, true, nil) + triedb.Commit(root, false) } trie, _ = New(TrieID(root), triedb) @@ -791,29 +791,23 @@ func (b *spongeBatch) Reset() {} func (b *spongeBatch) Replay(w ethdb.KeyValueWriter) error { return nil } // TestCommitSequence tests that the trie.Commit operation writes the elements of the trie -// in the expected order, and calls the callbacks in the expected order. +// in the expected order. // The test data was based on the 'master' code, and is basically random. It can be used // to check whether changes to the trie modifies the write order or data in any way. func TestCommitSequence(t *testing.T) { for i, tc := range []struct { - count int - expWriteSeqHash []byte - expCallbackSeqHash []byte + count int + expWriteSeqHash []byte }{ - {20, common.FromHex("873c78df73d60e59d4a2bcf3716e8bfe14554549fea2fc147cb54129382a8066"), - common.FromHex("ff00f91ac05df53b82d7f178d77ada54fd0dca64526f537034a5dbe41b17df2a")}, - {200, common.FromHex("ba03d891bb15408c940eea5ee3d54d419595102648d02774a0268d892add9c8e"), - common.FromHex("f3cd509064c8d319bbdd1c68f511850a902ad275e6ed5bea11547e23d492a926")}, - {2000, common.FromHex("f7a184f20df01c94f09537401d11e68d97ad0c00115233107f51b9c287ce60c7"), - common.FromHex("ff795ea898ba1e4cfed4a33b4cf5535a347a02cf931f88d88719faf810f9a1c9")}, + {20, common.FromHex("873c78df73d60e59d4a2bcf3716e8bfe14554549fea2fc147cb54129382a8066")}, + {200, common.FromHex("ba03d891bb15408c940eea5ee3d54d419595102648d02774a0268d892add9c8e")}, + {2000, common.FromHex("f7a184f20df01c94f09537401d11e68d97ad0c00115233107f51b9c287ce60c7")}, } { addresses, accounts := makeAccounts(tc.count) // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} db := NewDatabase(rawdb.NewDatabase(s)) trie := NewEmpty(db) - // Another sponge is used to check the callback-sequence - callbackSponge := sha3.NewLegacyKeccak256() // Fill the trie with elements for i := 0; i < tc.count; i++ { trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) @@ -822,16 +816,10 @@ func TestCommitSequence(t *testing.T) { root, nodes, _ := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) - db.Commit(root, false, func(c common.Hash) { - // And spongify the callback-order - callbackSponge.Write(c[:]) - }) + db.Commit(root, false) if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) { t.Errorf("test %d, disk write sequence wrong:\ngot %x exp %x\n", i, got, exp) } - if got, exp := callbackSponge.Sum(nil), tc.expCallbackSeqHash; !bytes.Equal(got, exp) { - t.Errorf("test %d, call back sequence wrong:\ngot: %x exp %x\n", i, got, exp) - } } } @@ -839,24 +827,18 @@ func TestCommitSequence(t *testing.T) { // but uses random blobs instead of 'accounts' func TestCommitSequenceRandomBlobs(t *testing.T) { for i, tc := range []struct { - count int - expWriteSeqHash []byte - expCallbackSeqHash []byte + count int + expWriteSeqHash []byte }{ - {20, common.FromHex("8e4a01548551d139fa9e833ebc4e66fc1ba40a4b9b7259d80db32cff7b64ebbc"), - common.FromHex("450238d73bc36dc6cc6f926987e5428535e64be403877c4560e238a52749ba24")}, - {200, common.FromHex("6869b4e7b95f3097a19ddb30ff735f922b915314047e041614df06958fc50554"), - common.FromHex("0ace0b03d6cb8c0b82f6289ef5b1a1838306b455a62dafc63cada8e2924f2550")}, - {2000, common.FromHex("444200e6f4e2df49f77752f629a96ccf7445d4698c164f962bbd85a0526ef424"), - common.FromHex("117d30dafaa62a1eed498c3dfd70982b377ba2b46dd3e725ed6120c80829e518")}, + {20, common.FromHex("8e4a01548551d139fa9e833ebc4e66fc1ba40a4b9b7259d80db32cff7b64ebbc")}, + {200, common.FromHex("6869b4e7b95f3097a19ddb30ff735f922b915314047e041614df06958fc50554")}, + {2000, common.FromHex("444200e6f4e2df49f77752f629a96ccf7445d4698c164f962bbd85a0526ef424")}, } { prng := rand.New(rand.NewSource(int64(i))) // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} db := NewDatabase(rawdb.NewDatabase(s)) trie := NewEmpty(db) - // Another sponge is used to check the callback-sequence - callbackSponge := sha3.NewLegacyKeccak256() // Fill the trie with elements for i := 0; i < tc.count; i++ { key := make([]byte, 32) @@ -875,16 +857,10 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { root, nodes, _ := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) - db.Commit(root, false, func(c common.Hash) { - // And spongify the callback-order - callbackSponge.Write(c[:]) - }) + db.Commit(root, false) if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) { t.Fatalf("test %d, disk write sequence wrong:\ngot %x exp %x\n", i, got, exp) } - if got, exp := callbackSponge.Sum(nil), tc.expCallbackSeqHash; !bytes.Equal(got, exp) { - t.Fatalf("test %d, call back sequence wrong:\ngot: %x exp %x\n", i, got, exp) - } } } @@ -920,7 +896,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { root, nodes, _ := trie.Commit(false) // Flush memdb -> disk (sponge) db.Update(NewWithNodeSet(nodes)) - db.Commit(root, false, nil) + db.Commit(root, false) // And flush stacktrie -> disk stRoot, err := stTrie.Commit() if err != nil { @@ -968,7 +944,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) { root, nodes, _ := trie.Commit(false) // Flush memdb -> disk (sponge) db.Update(NewWithNodeSet(nodes)) - db.Commit(root, false, nil) + db.Commit(root, false) // And flush stacktrie -> disk stRoot, err := stTrie.Commit() if err != nil { From 0c9eb8c9a47285526078beef4ab5aed5a90ab938 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Wed, 8 Feb 2023 07:04:40 -0800 Subject: [PATCH 528/715] eth/catalyst: make getPayloadBodiesByRange take hex inputs (#26624) Co-authored-by: Martin Holst Swende Co-authored-by: Marius van der Wijden --- eth/catalyst/api.go | 12 ++++++------ eth/catalyst/api_test.go | 34 +++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 7019daf9b28f..15b53985a9da 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -772,18 +772,18 @@ func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engin // GetPayloadBodiesByRangeV1 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range // of block bodies by the engine api. -func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count uint64) ([]*engine.ExecutionPayloadBodyV1, error) { +func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBodyV1, error) { if start == 0 || count == 0 || count > 1024 { return nil, engine.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count)) } // limit count up until current current := api.eth.BlockChain().CurrentBlock().NumberU64() - end := start + count - if end > current { - end = current + last := uint64(start) + uint64(count) - 1 + if last > current { + last = current } - var bodies []*engine.ExecutionPayloadBodyV1 - for i := start; i < end; i++ { + bodies := make([]*engine.ExecutionPayloadBodyV1, 0, uint64(count)) + for i := uint64(start); i <= last; i++ { block := api.eth.BlockChain().GetBlockByNumber(i) bodies = append(bodies, getBody(block)) } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 96613ac164d8..f7881415a434 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -1311,9 +1311,14 @@ func TestGetBlockBodiesByRange(t *testing.T) { tests := []struct { results []*types.Body - start uint64 - count uint64 + start hexutil.Uint64 + count hexutil.Uint64 }{ + { + results: []*types.Body{blocks[9].Body()}, + start: 10, + count: 1, + }, // Genesis { results: []*types.Body{blocks[0].Body()}, @@ -1334,16 +1339,27 @@ func TestGetBlockBodiesByRange(t *testing.T) { }, // unavailable block { - results: []*types.Body{blocks[18].Body()}, + results: []*types.Body{blocks[18].Body(), blocks[19].Body()}, start: 19, count: 3, }, - // after range + // unavailable block { - results: make([]*types.Body, 0), + results: []*types.Body{blocks[19].Body()}, start: 20, count: 2, }, + { + results: []*types.Body{blocks[19].Body()}, + start: 20, + count: 1, + }, + // whole range unavailable + { + results: make([]*types.Body, 0), + start: 22, + count: 2, + }, } for k, test := range tests { @@ -1354,11 +1370,11 @@ func TestGetBlockBodiesByRange(t *testing.T) { if len(result) == len(test.results) { for i, r := range result { if !equalBody(test.results[i], r) { - t.Fatalf("test %v: invalid response: expected %+v got %+v", k, test.results[i], r) + t.Fatalf("test %d: invalid response: expected \n%+v\ngot\n%+v", k, test.results[i], r) } } } else { - t.Fatalf("invalid length want %v got %v", len(test.results), len(result)) + t.Fatalf("test %d: invalid length want %v got %v", k, len(test.results), len(result)) } } } @@ -1369,8 +1385,8 @@ func TestGetBlockBodiesByRangeInvalidParams(t *testing.T) { defer node.Close() tests := []struct { - start uint64 - count uint64 + start hexutil.Uint64 + count hexutil.Uint64 }{ // Genesis { From 095e365fac84bac918cda4c8f7da427bf6c60077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 9 Feb 2023 10:03:00 +0200 Subject: [PATCH 529/715] all: remove support for Ropsten (#26644) --- README.md | 13 ---------- cmd/checkpoint-admin/README.md | 2 +- cmd/clef/README.md | 2 +- cmd/clef/main.go | 2 +- cmd/devp2p/README.md | 2 +- cmd/devp2p/nodesetcmd.go | 2 -- cmd/geth/consolecmd_test.go | 10 ++++---- cmd/geth/main.go | 6 +---- cmd/utils/flags.go | 37 ++------------------------ core/blockchain_test.go | 9 ++++++- core/forkid/forkid_test.go | 25 ------------------ core/genesis.go | 16 ------------ core/genesis_alloc.go | 1 - core/genesis_test.go | 11 ++++---- eth/protocols/eth/handler.go | 2 +- les/commons.go | 2 +- miner/stress/1559/main.go | 4 +-- miner/stress/beacon/main.go | 4 +-- miner/stress/ethash/main.go | 4 +-- params/bootnodes.go | 9 ------- params/config.go | 47 ---------------------------------- tests/difficulty_test.go | 24 +++++++++++++++-- 22 files changed, 55 insertions(+), 179 deletions(-) diff --git a/README.md b/README.md index 2a9006eaf925..9835b0045895 100644 --- a/README.md +++ b/README.md @@ -132,19 +132,6 @@ called [*Rinkeby*](https://www.rinkeby.io) which is operated by members of the c $ geth --rinkeby console ``` -### Full node on the Ropsten test network - -In addition to Görli and Rinkeby, Geth also supports the ancient Ropsten testnet. The -Ropsten test network is based on the Ethash proof-of-work consensus algorithm. As such, -it has certain extra overhead and is more susceptible to reorganization attacks due to the -network's low difficulty/security. - -```shell -$ geth --ropsten console -``` - -*Note: Older Geth configurations store the Ropsten database in the `testnet` subdirectory.* - ### Configuration As an alternative to passing the numerous flags to the `geth` binary, you can also pass a diff --git a/cmd/checkpoint-admin/README.md b/cmd/checkpoint-admin/README.md index 43e3785ec2fa..7c0c657eb5cb 100644 --- a/cmd/checkpoint-admin/README.md +++ b/cmd/checkpoint-admin/README.md @@ -86,7 +86,7 @@ checkpoint-admin status --rpc ### Enable checkpoint oracle in your private network -Currently, only the Ethereum mainnet and the default supported test networks (ropsten, rinkeby, goerli) activate this feature. If you want to activate this feature in your private network, you can overwrite the relevant checkpoint oracle settings through the configuration file after deploying the oracle contract. +Currently, only the Ethereum mainnet and the default supported test networks (rinkeby, goerli) activate this feature. If you want to activate this feature in your private network, you can overwrite the relevant checkpoint oracle settings through the configuration file after deploying the oracle contract. * Get your node configuration file `geth dumpconfig OTHER_COMMAND_LINE_OPTIONS > config.toml` * Edit the configuration file and add the following information diff --git a/cmd/clef/README.md b/cmd/clef/README.md index 27c62817f925..3891e554029a 100644 --- a/cmd/clef/README.md +++ b/cmd/clef/README.md @@ -29,7 +29,7 @@ GLOBAL OPTIONS: --loglevel value log level to emit to the screen (default: 4) --keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore") --configdir value Directory for Clef configuration (default: "$HOME/.clef") - --chainid value Chain id to use for signing (1=mainnet, 3=Ropsten, 4=Rinkeby, 5=Goerli) (default: 1) + --chainid value Chain id to use for signing (1=mainnet, 4=Rinkeby, 5=Goerli) (default: 1) --lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength --nousb Disables monitoring for and managing USB hardware wallets --pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm") diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 7dc12a14ac61..2788ddc33b9e 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -99,7 +99,7 @@ var ( chainIdFlag = &cli.Int64Flag{ Name: "chainid", Value: params.MainnetChainConfig.ChainID.Int64(), - Usage: "Chain id to use for signing (1=mainnet, 3=Ropsten, 4=Rinkeby, 5=Goerli)", + Usage: "Chain id to use for signing (1=mainnet, 4=Rinkeby, 5=Goerli)", } rpcPortFlag = &cli.IntFlag{ Name: "http.port", diff --git a/cmd/devp2p/README.md b/cmd/devp2p/README.md index 7b90bbeb806a..0a61304c2be4 100644 --- a/cmd/devp2p/README.md +++ b/cmd/devp2p/README.md @@ -44,7 +44,7 @@ set to standard output. The following filters are supported: - `-limit ` limits the output set to N entries, taking the top N nodes by score - `-ip ` filters nodes by IP subnet - `-min-age ` filters nodes by 'first seen' time -- `-eth-network ` filters nodes by "eth" ENR entry +- `-eth-network ` filters nodes by "eth" ENR entry - `-les-server` filters nodes by LES server support - `-snap` filters nodes by snap protocol support diff --git a/cmd/devp2p/nodesetcmd.go b/cmd/devp2p/nodesetcmd.go index 2cf104592834..2faa2882e518 100644 --- a/cmd/devp2p/nodesetcmd.go +++ b/cmd/devp2p/nodesetcmd.go @@ -233,8 +233,6 @@ func ethFilter(args []string) (nodeFilter, error) { filter = forkid.NewStaticFilter(params.RinkebyChainConfig, params.RinkebyGenesisHash) case "goerli": filter = forkid.NewStaticFilter(params.GoerliChainConfig, params.GoerliGenesisHash) - case "ropsten": - filter = forkid.NewStaticFilter(params.RopstenChainConfig, params.RopstenGenesisHash) case "sepolia": filter = forkid.NewStaticFilter(params.SepoliaChainConfig, params.SepoliaGenesisHash) default: diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index c5bdfa6ec8c4..46bdf3c90d9f 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -30,7 +30,7 @@ import ( ) const ( - ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0" + ipcAPIs = "admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0" httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0" ) @@ -38,10 +38,10 @@ const ( // memory and disk IO. If the args don't set --datadir, the // child g gets a temporary data directory. func runMinimalGeth(t *testing.T, args ...string) *testgeth { - // --ropsten to make the 'writing genesis to disk' faster (no accounts) + // --goerli to make the 'writing genesis to disk' faster (no accounts) // --networkid=1337 to avoid cache bump // --syncmode=full to avoid allocating fast sync bloom - allArgs := []string{"--ropsten", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0", + allArgs := []string{"--goerli", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0", "--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64", "--datadir.minfreedisk", "0"} return runGeth(t, append(allArgs, args...)...) @@ -61,7 +61,7 @@ func TestConsoleWelcome(t *testing.T) { geth.SetTemplateFunc("gover", runtime.Version) geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") }) geth.SetTemplateFunc("niltime", func() string { - return time.Unix(0, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") + return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") }) geth.SetTemplateFunc("apis", func() string { return ipcAPIs }) @@ -132,7 +132,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") }) attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase }) attach.SetTemplateFunc("niltime", func() string { - return time.Unix(0, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") + return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") }) attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") }) attach.SetTemplateFunc("datadir", func() string { return geth.Datadir }) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 9998670e5dd4..5ba070249897 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -274,9 +274,6 @@ func main() { func prepare(ctx *cli.Context) { // If we're running a known preset, log it for convenience. switch { - case ctx.IsSet(utils.RopstenFlag.Name): - log.Info("Starting Geth on Ropsten testnet...") - case ctx.IsSet(utils.RinkebyFlag.Name): log.Info("Starting Geth on Rinkeby testnet...") @@ -310,8 +307,7 @@ func prepare(ctx *cli.Context) { // If we're a full node on mainnet without --cache specified, bump default cache allowance if ctx.String(utils.SyncModeFlag.Name) != "light" && !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) { // Make sure we're not on any supported preconfigured testnet either - if !ctx.IsSet(utils.RopstenFlag.Name) && - !ctx.IsSet(utils.SepoliaFlag.Name) && + if !ctx.IsSet(utils.SepoliaFlag.Name) && !ctx.IsSet(utils.RinkebyFlag.Name) && !ctx.IsSet(utils.GoerliFlag.Name) && !ctx.IsSet(utils.DeveloperFlag.Name) { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 78b3cbee60b8..d69be1a42a2b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -127,7 +127,7 @@ var ( } NetworkIdFlag = &cli.Uint64Flag{ Name: "networkid", - Usage: "Explicitly set network id (integer)(For testnets: use --ropsten, --rinkeby, --goerli instead)", + Usage: "Explicitly set network id (integer)(For testnets: use --rinkeby, --goerli, --sepolia instead)", Value: ethconfig.Defaults.NetworkId, Category: flags.EthCategory, } @@ -136,11 +136,6 @@ var ( Usage: "Ethereum mainnet", Category: flags.EthCategory, } - RopstenFlag = &cli.BoolFlag{ - Name: "ropsten", - Usage: "Ropsten network: pre-configured proof-of-stake test network", - Category: flags.EthCategory, - } RinkebyFlag = &cli.BoolFlag{ Name: "rinkeby", Usage: "Rinkeby network: pre-configured proof-of-authority test network", @@ -998,7 +993,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server. var ( // TestnetFlags is the flag group of all built-in supported testnets. TestnetFlags = []cli.Flag{ - RopstenFlag, RinkebyFlag, GoerliFlag, SepoliaFlag, @@ -1020,11 +1014,6 @@ var ( // then a subdirectory of the specified datadir will be used. func MakeDataDir(ctx *cli.Context) string { if path := ctx.String(DataDirFlag.Name); path != "" { - if ctx.Bool(RopstenFlag.Name) { - // Maintain compatibility with older Geth configurations storing the - // Ropsten database in `testnet` instead of `ropsten`. - return filepath.Join(path, "ropsten") - } if ctx.Bool(RinkebyFlag.Name) { return filepath.Join(path, "rinkeby") } @@ -1080,8 +1069,6 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { switch { case ctx.IsSet(BootnodesFlag.Name): urls = SplitAndTrim(ctx.String(BootnodesFlag.Name)) - case ctx.Bool(RopstenFlag.Name): - urls = params.RopstenBootnodes case ctx.Bool(SepoliaFlag.Name): urls = params.SepoliaBootnodes case ctx.Bool(RinkebyFlag.Name): @@ -1525,18 +1512,6 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) { cfg.DataDir = ctx.String(DataDirFlag.Name) case ctx.Bool(DeveloperFlag.Name): cfg.DataDir = "" // unless explicitly requested, use memory databases - case ctx.Bool(RopstenFlag.Name) && cfg.DataDir == node.DefaultDataDir(): - // Maintain compatibility with older Geth configurations storing the - // Ropsten database in `testnet` instead of `ropsten`. - legacyPath := filepath.Join(node.DefaultDataDir(), "testnet") - if common.FileExist(legacyPath) { - log.Warn("Using the deprecated `testnet` datadir. Future versions will store the Ropsten chain in `ropsten`.") - cfg.DataDir = legacyPath - } else { - cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten") - } - - cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten") case ctx.Bool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir(): cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") case ctx.Bool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir(): @@ -1733,7 +1708,7 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) { // SetEthConfig applies eth-related command line flags to the config. func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // Avoid conflicting network flags - CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, SepoliaFlag) + CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RinkebyFlag, GoerliFlag, SepoliaFlag) CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light") CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer if ctx.String(GCModeFlag.Name) == "archive" && ctx.Uint64(TxLookupLimitFlag.Name) != 0 { @@ -1871,12 +1846,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { } cfg.Genesis = core.DefaultGenesisBlock() SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash) - case ctx.Bool(RopstenFlag.Name): - if !ctx.IsSet(NetworkIdFlag.Name) { - cfg.NetworkId = 3 - } - cfg.Genesis = core.DefaultRopstenGenesisBlock() - SetDNSDiscoveryDefaults(cfg, params.RopstenGenesisHash) case ctx.Bool(SepoliaFlag.Name): if !ctx.IsSet(NetworkIdFlag.Name) { cfg.NetworkId = 11155111 @@ -2219,8 +2188,6 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { switch { case ctx.Bool(MainnetFlag.Name): genesis = core.DefaultGenesisBlock() - case ctx.Bool(RopstenFlag.Name): - genesis = core.DefaultRopstenGenesisBlock() case ctx.Bool(SepoliaFlag.Name): genesis = core.DefaultSepoliaGenesisBlock() case ctx.Bool(RinkebyFlag.Name): diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 5554361dbf0c..ae77d0b7f669 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4049,7 +4049,14 @@ func TestCreateThenDeletePreByzantium(t *testing.T) { // We use Ropsten chain config instead of Testchain config, this is // deliberate: we want to use pre-byz rules where we have intermediate state roots // between transactions. - testCreateThenDelete(t, params.RopstenChainConfig) + testCreateThenDelete(t, ¶ms.ChainConfig{ + ChainID: big.NewInt(3), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(10), + EIP158Block: big.NewInt(10), + ByzantiumBlock: big.NewInt(1_700_000), + }) } func TestCreateThenDeletePostByzantium(t *testing.T) { testCreateThenDelete(t, params.TestChainConfig) diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index c4b46bf411d0..e0bd1dd38944 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -78,31 +78,6 @@ func TestCreation(t *testing.T) { {20000000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}}, // Future Gray Glacier block }, }, - // Ropsten test cases - { - params.RopstenChainConfig, - params.RopstenGenesisHash, - []testcase{ - {0, 0, ID{Hash: checksumToBytes(0x30c7ddbc), Next: 10}}, // Unsynced, last Frontier, Homestead and first Tangerine block - {9, 0, ID{Hash: checksumToBytes(0x30c7ddbc), Next: 10}}, // Last Tangerine block - {10, 0, ID{Hash: checksumToBytes(0x63760190), Next: 1700000}}, // First Spurious block - {1699999, 0, ID{Hash: checksumToBytes(0x63760190), Next: 1700000}}, // Last Spurious block - {1700000, 0, ID{Hash: checksumToBytes(0x3ea159c7), Next: 4230000}}, // First Byzantium block - {4229999, 0, ID{Hash: checksumToBytes(0x3ea159c7), Next: 4230000}}, // Last Byzantium block - {4230000, 0, ID{Hash: checksumToBytes(0x97b544f3), Next: 4939394}}, // First Constantinople block - {4939393, 0, ID{Hash: checksumToBytes(0x97b544f3), Next: 4939394}}, // Last Constantinople block - {4939394, 0, ID{Hash: checksumToBytes(0xd6e2149b), Next: 6485846}}, // First Petersburg block - {6485845, 0, ID{Hash: checksumToBytes(0xd6e2149b), Next: 6485846}}, // Last Petersburg block - {6485846, 0, ID{Hash: checksumToBytes(0x4bc66396), Next: 7117117}}, // First Istanbul block - {7117116, 0, ID{Hash: checksumToBytes(0x4bc66396), Next: 7117117}}, // Last Istanbul block - {7117117, 0, ID{Hash: checksumToBytes(0x6727ef90), Next: 9812189}}, // First Muir Glacier block - {9812188, 0, ID{Hash: checksumToBytes(0x6727ef90), Next: 9812189}}, // Last Muir Glacier block - {9812189, 0, ID{Hash: checksumToBytes(0xa157d377), Next: 10499401}}, // First Berlin block - {10499400, 0, ID{Hash: checksumToBytes(0xa157d377), Next: 10499401}}, // Last Berlin block - {10499401, 0, ID{Hash: checksumToBytes(0x7119b6b3), Next: 0}}, // First London block - {11000000, 0, ID{Hash: checksumToBytes(0x7119b6b3), Next: 0}}, // Future London block - }, - }, // Rinkeby test cases { params.RinkebyChainConfig, diff --git a/core/genesis.go b/core/genesis.go index 5ab28001d89f..1b9ec20ed99d 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -189,8 +189,6 @@ func CommitGenesisState(db ethdb.Database, triedb *trie.Database, hash common.Ha switch hash { case params.MainnetGenesisHash: genesis = DefaultGenesisBlock() - case params.RopstenGenesisHash: - genesis = DefaultRopstenGenesisBlock() case params.RinkebyGenesisHash: genesis = DefaultRinkebyGenesisBlock() case params.GoerliGenesisHash: @@ -423,8 +421,6 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { return g.Config case ghash == params.MainnetGenesisHash: return params.MainnetChainConfig - case ghash == params.RopstenGenesisHash: - return params.RopstenChainConfig case ghash == params.SepoliaGenesisHash: return params.SepoliaChainConfig case ghash == params.RinkebyGenesisHash: @@ -533,18 +529,6 @@ func DefaultGenesisBlock() *Genesis { } } -// DefaultRopstenGenesisBlock returns the Ropsten network genesis block. -func DefaultRopstenGenesisBlock() *Genesis { - return &Genesis{ - Config: params.RopstenChainConfig, - Nonce: 66, - ExtraData: hexutil.MustDecode("0x3535353535353535353535353535353535353535353535353535353535353535"), - GasLimit: 16777216, - Difficulty: big.NewInt(1048576), - Alloc: decodePrealloc(ropstenAllocData), - } -} - // DefaultRinkebyGenesisBlock returns the Rinkeby network genesis block. func DefaultRinkebyGenesisBlock() *Genesis { return &Genesis{ diff --git a/core/genesis_alloc.go b/core/genesis_alloc.go index 16df390575c2..542dcc4120c2 100644 --- a/core/genesis_alloc.go +++ b/core/genesis_alloc.go @@ -22,7 +22,6 @@ package core // nolint: misspell const mainnetAllocData = "\xfa\x04]X\u0793\r\x83b\x011\x8e\u0189\x9agT\x06\x908'\x80t2\x80\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0793\x17bC\x0e\xa9\u00e2nWI\xaf\xdbp\xda_x\u077b\x8c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0793\x1d\x14\x80K9\x9cn\xf8\x0edWoev`\x80O\xec\v\x89\u3bb5sr@\xa0\x00\x00\u07932@5\x87\x94{\x9f\x15b*h\xd1\x04\xd5M3\xdb\xd1\u0349\x043\x87Oc,\xc6\x00\x00\u0793I~\x92\xcd\xc0\xe0\xb9c\xd7R\xb2)j\u02c7\u0682\x8b$\x89\n\x8fd\x9f\xe7\xc6\x18\x00\x00\u0793K\xfb\xe1Tk\xc6\xc6[\\~\xaaU0K8\xbb\xfe\xc6\u04c9lk\x93[\x8b\xbd@\x00\x00\u0793Z\x9c\x03\xf6\x9d\x17\xd6l\xbb\x8a\xd7!\x00\x8a\x9e\xbb\xb86\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u0793]\x0e\xe8\x15^\xc0\xa6\xffh\bU,\xa5\xf1k\xb5\xbe2:\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u0793v\"\xd8J#K\xb8\xb0x#\x0f\u03c4\xb6z\u9a2c\xae\x89%\xe1\xccQ\x99R\xf8\x00\x00\u0793{\x9f\xc3\x19\x05\xb4\x99K\x04\xc9\xe2\xcf\xdc^'pP?B\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u0793\u007fJ#\xca\x00\xcd\x04=%\u0088\x8c\x1a\xa5h\x8f\x81\xa3D\x89)\xf0\xa9[\xfb\xf7)\x00\x00\u0793\x869\u06bb\u3bac\x88{]\xc0\xe4>\x13\xbc\u0487\xd7l\x89\x10\xd0\xe3\xc8}n,\x00\x00\u0793\x89P\x86y\xab\xf8\xc7\x1b\xf6x\x16\x87\x12\x0e>j\x84XM\x89a\x94\x04\x9f0\xf7 \x00\x00\u0793\x8f\xc7\u02ed\xff\xbd\r\u007f\xe4O\x8d\xfd`\xa7\x9dr\x1a\x1c\x9c\x8965\u026d\xc5\u07a0\x00\x00\u0793\x95`\xa3\xdebxh\xf9\x1f\xa8\xbf\xe1\xc1\xb7\xaf\xaf\b\x18k\x89\x1cg\xf5\xf7\xba\xa0\xb0\x00\x00\u0793\x96\x97G\xf7\xa5\xb3\x06E\xfe\x00\xe4I\x01CZ\xce$\xcc7\x89\\(=A\x03\x94\x10\x00\x00\u0793\x9am}\xb3&g\x9bw\xc9\x03\x91\xa7Gm#\x8f;\xa3>\x89\n\xdaUGK\x814\x00\x00\u0793\x9e\xef\n\b\x86\x05n?i!\x18S\xb9\xb7E\u007f7\x82\u4262\xa8x\x06\x9b(\xe0\x00\x00\u0793\x9f\xdb\xf4N\x1fJcb\xb7i\u00daG_\x95\xa9l+\u01c9\x1e\x93\x12\x83\xcc\xc8P\x00\x00\u07d3\xa5y\u007fR\xc9\u054f\x18\x9f6\xb1\xd4]\x1b\xf6\x04\x1f/k\x8a\x01'\u0473F\x1a\xcd\x1a\x00\x00\u0793\xaaS\x81\xb2\x13\x8e\xbe\xff\xc1\x91\xd5\xd8\u00d1u;p\x98\u04895\xab\xb0\x9f\xfe\u07b6\x80\x00\u0793\xaa\xda%\xea\"\x86p\x9a\xbbB-A\x92?\u04c0\xcd\x04\u01c9#=\xf3)\x9far\x00\x00\u0793\xac\xbf\xb2\xf2ZT\x85\xc79\xefp\xa4N\xee\xeb|e\xa6o\x89\x05k\xc7^-c\x10\x00\x00\u07d3\xac\xc6\xf0\x82\xa4B\x82\x87d\xd1\x1fX\u0589J\xe4\b\xf0s\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u0793\xb2w\xb0\x99\xa8\xe8f\xca\x0e\xc6[\u02c7(O\xd1B\xa5\x82\x89j\xcb=\xf2~\x1f\x88\x00\x00\u0753\xbd\xd4\x01:\xa3\x1c\x04al+\xc9x_'\x88\xf9\x15g\x9b\x88\xb9\xf6]\x00\xf6<\x00\x00\u0793\xc2}c\xfd\xe2K\x92\xee\x8a\x1e~\xd5\xd2m\x8d\xc5\xc8;\x03\x89lk\x93[\x8b\xbd@\x00\x00\u0553\xc4\x0f\xe2\tT#P\x9b\x9f\u0677T21X\xaf#\x10\xf3\x80\u0793\xd7^\xd6\fwO\x8b:ZQs\xfb\x183\xadq\x05\xa2\u0649l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d3\u05cd\x89\xb3_G'\x16\xec\xea\xfe\xbf`\x05'\u04e1\xf9i\x8a\x05\xe0T\x9c\x962\xe1\xd8\x00\x00\u0793\xda\xe2{5\v\xae \xc5e!$\xaf]\x8b\\\xba\x00\x1e\xc1\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u0793\xdc\x01\xcb\xf4Ix\xa4.\x8d\xe8\xe46\xed\xf9B\x05\u03f6\xec\x89O\x0f\xeb\xbc\u068c\xb4\x00\x00\u07d3\u607c-\x10\xdbb\u0785\x84\x83$I\"P4\x8e\x90\xbf\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d3\xf4c\xe17\xdc\xf6%\xfb\U000fc8de\u0298\u04b9h\xcf\u007f\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\x01\x00\a9K\x8bue\xa1e\x8a\xf8\x8c\xe4cI\x915\u05b7\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x01\r\xf1\xdfK\xed#v\r-\x1c\x03x\x15\x86\xdd\xf7\x91\x8eT\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\x01\x0fJ\x98\u07e1\xd9y\x9b\xf5\u01d6\xfbU\x0e\xfb\xe7\xec\xd8w\x8a\x01\xb2\xf2\x92#b\x92\xc7\x00\x00\u07d4\x01\x15PW\x00/k\r\x18\xac\xb98\x8d;\xc8\x12\x9f\x8fz \x89H\xa4\xa9\x0f\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x01k`\xbbmg\x92\x8c)\xfd\x03\x13\xc6f\u068f\x16\x98\xd9\u0149lk\x93[\x8b\xbd@\x00\x00\u07d4\x01l\x85\xe1a;\x90\x0f\xa3W\xb8(;\x12\x0ee\xae\xfc\xdd\b\x89+]\x97\x84\xa9|\xd5\x00\x00\u07d4\x01\x84\x92H\x8b\xa1\xa2\x924\"G\xb3\x18U\xa5Y\x05\xfe\xf2i\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x01\x8f \xa2{'\xecD\x1a\xf7#\xfd\x90\x99\xf2\u02f7\x9dbc\x89uy*\x8a\xbd\xef|\x00\x00\u07d4\x01\x91\xebT~{\xf6\x97k\x9b\x1bWuFv\x1d\xe6V\"\xe2\x89lkLM\xa6\u077e\x00\x00\u07d4\x01\x9dp\x95y\xffK\xc0\x9f\xdc\xdd\xe41\xdc\x14G\xd2\xc2`\xbc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x01\xa2Z_Z\xf0\x16\x9b0\x86L;\xe4\xd7V<\xcdD\xf0\x9e\x89M\x85<\x8f\x89\b\x98\x00\x00\xe0\x94\x01\xa7\xd9\xfa}\x0e\xb1\x18\\g\xe5M\xa8<.u\xdbi\u37ca\x01\x9dJ\xdd\xd0\u063c\x96\x00\x00\u07d4\x01\xa8\x18\x13ZAB\x10\xc3|b\xb6%\xac\xa1\xa5F\x11\xac6\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\x01\xb1\xca\xe9\x1a;\x95Y\xaf\xb3<\xdcmh\x94B\xfd\xbf\xe07\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x01\xb5\xb5\xbcZ\x11\u007f\xa0\x8b4\xed\x1d\xb9D\x06\bYz\xc5H\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x01\xbb\xc1Og\xaf\x069\xaa\xb1D\x1ej\b\xd4\xceqb\t\x0f\x89F\xfc\xf6\x8f\xf8\xbe\x06\x00\x00\xe0\x94\x01\xd08\x15\xc6\x1fAkq\xa2a\n-\xab\xa5\x9f\xf6\xa6\xde[\x8a\x02\x05\xdf\xe5\v\x81\xc8.\x00\x00\u07d4\x01\u0559\xee\r_\x8c8\xab-9.,e\xb7L<\xe3\x18 \x89\x1b\xa5\xab\xf9\xe7y8\x00\x00\u07d4\x01\xe4\x05!\x12%0\u066c\x91\x11<\x06\xa0\x19\vmc\x85\v\x89Hz\x9a0E9D\x00\x00\u07d4\x01\xe6A]X{\x06T\x90\xf1\xed\u007f!\xd6\xe0\xf3\x86\xeegG\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x01\xe8d\xd3Tt\x1bB>oB\x85\x17$F\x8ct\xf5\xaa\x9c\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x01\xed_\xba\x8d.\xabg:\xec\x04-0\xe4\xe8\xa6\x11\xd8\xc5Z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x01\xfb\x8e\xc1$%\xa0O\x81>F\xc5L\x05t\x8c\xa6\xb2\x9a\xa9\x89\x0e\x15s\x03\x85F|\x00\x00\u07d4\x01\xff\x1e\xb1\u07adP\xa7\xf2\xf9c\x8f\xde\xe6\xec\xcf:{*\u0209 \x86\xac5\x10R`\x00\x00\u07d4\x02\x03b\u00ed\xe8x\u0290\u05b2\u0609\xa4\xccU\x10\xee\xd5\xf3\x898\x88\xe8\xb3\x11\xad\xb3\x80\x00\u07d4\x02\x03\xae\x01\xd4\xc4\x1c\xae\x18e\xe0K\x1f[S\xcd\xfa\xec\xae1\x896\x89\xcd\u03b2\x8c\xd7\x00\x00\u07d4\x02\b\x93a\xa3\xfetQ\xfb\x1f\x87\xf0\x1a-\x86fS\xdc\v\a\x89\x02*\xc7H2\xb5\x04\x00\x00\u07d4\x02\x1fi\x04=\xe8\x8cI\x17\xca\x10\xf1\x84(\x97\xee\xc0X\x9c|\x89kD\u03f8\x14\x87\xf4\x00\x00\u07d4\x02)\x0f\xb5\xf9\xa5\x17\xf8(E\xac\xde\xca\x0f\xc8F\x03\x9b\xe23\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x029\xb4\xf2\x1f\x8e\x05\xcd\x01Q++\xe7\xa0\xe1\x8am\x97F\a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x02Gr\x12\xff\xddu\xe5\x15VQ\xb7e\x06\xb1dfq\xa1\xeb\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x02J\t\x8a\xe7\x02\xbe\xf5@l\x9c\"\xb7\x8b\xd4\xeb,\u01e2\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x02K\xdd,{\xfdP\x0e\xe7@O\u007f\xb3\xe9\xfb1\xdd \xfb\u0449\t\xc2\x00vQ\xb2P\x00\x00\u07d4\x02Sg\x96\x03\x04\xbe\xee4Y\x11\x18\xe9\xac-\x13X\xd8\x02\x1a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x02V\x14\x9f[Pc\xbe\xa1N\x15f\x1f\xfbX\xf9\xb4Y\xa9W\x89&)\xf6n\fS\x00\x00\x00\u07d4\x02`=z;\xb2\x97\xc6|\x87~]4\xfb\u0579\x13\xd4\xc6:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x02a\xad:\x17*\xbf\x13\x15\xf0\xff\xec2p\x98j\x84\t\xcb%\x89\v\b!;\u03cf\xfe\x00\x00\u07d4\x02d2\xaf7\xdcQ\x13\xf1\xf4mH\nM\u0c80R#~\x89\x13I\xb7\x86\xe4\v\xfc\x00\x00\u07d4\x02f\xab\x1ck\x02\x16#\v\x93\x95D=_\xa7^hEh\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x02u\x1d\u018c\xb5\xbdsp'\xab\xf7\u0777s\x90\xcdw\xc1k\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x02w\x8e9\x0f\xa1u\x10\xa3B\x8a\xf2\x87\fBsT}8l\x8a\x03lw\x80\x18\x8b\xf0\xef\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x037|\x0eUkd\x01\x03(\x9aa\x89\u1baecI4g\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03IcM\u00a9\xe8\f?w!\xee+PF\xae\xaa\xed\xfb\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x03U\xbc\xac\xbd!D\x1e\x95\xad\xee\xdc0\xc1r\x18\u0224\b\u0389\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x03n\xef\xf5\xba\x90\xa6\x87\x9a\x14\xdf\xf4\xc5\x04;\x18\xca\x04`\u0249\x05k\xc7^-c\x10\x00\x00\xe0\x94\x03qKA\u04a6\xf7Q\x00\x8e\xf8\xddM+)\xae\u02b8\xf3n\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x03r\xe8RX.\t44J\x0f\xed!x0M\xf2]F(\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03r\xeeU\b\xbf\x81c\xed(N^\xef\x94\xceMsg\xe5\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x03}\xd0V\xe7\xfd\xbdd\x1d\xb5\xb6\xbe\xa2\xa8x\n\x83\xfa\u1009\a\x96\xe3\xea?\x8a\xb0\x00\x00\xe0\x94\x03\x83#\xb1\x84\xcf\xf7\xa8*\xe2\u1f67y?\xe41\x9c\xa0\xbf\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x03\x87y\xca-\xbef>c\xdb?\xe7V\x83\xea\x0e\xc6.#\x83\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\x03\x8eE\xea\xdd=\x88\xb8\u007f\xe4\u06b0fh\x05\"\xf0\xdf\xc8\xf9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x03\x92T\x9ar\u007f\x81eT)\u02d2\x8bR\x9f%\xdfM\x13\x85\x89\x01lC\xa0\xee\xa0t\x00\x00\u07d4\x03\x94\xb9\x0f\xad\xb8`O\x86\xf4?\xc1\xe3]1$\xb3*Y\x89\x89)j\xa1@'\x8ep\x00\x00\u0794\x03\x9ezN\xbc(N,\xcdB\xb1\xbd\xd6\v\xd6Q\x1c\x0fw\x06\x88\xf0\x15\xf2W6B\x00\x00\u07d4\x03\x9e\xf1\xceR\xfeyc\xf1f\u0562u\u0131\x06\x9f\xe3\xa82\x89\x15\xaf9\u4ab2t\x00\x00\u07d4\x03\xa2l\xfcL\x181op\u055e\x9e\x1ay\xee>\x8b\x96/L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x03\xaab(\x81#m\xd0\xf4\x94\f$\xc3$\xff\x8b{~!\x86\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4\x03\xafz\xd9\xd5\"<\xf7\xc8\xc1? \xdfg\xeb\xe5\xff\u017bA\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x03\xb0\xf1|\xd4F\x9d\xdc\u03f7\xdai~\x82\xa9\x1a_\x9ewt\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x03\xb4\x1bQ\xf4\x1d\xf2\r\xd2y\xba\xe1\x8c\x12w_w\xadw\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x03\xbe[F)\xae\xfb\xbc\xab\x9d\xe2m9Wl\xb7\xf6\x91\xd7d\x89\n\xdf0\xbap\u0217\x00\x00\u07d4\x03\xc6G\xa9\xf9)\xb0x\x1f\xe9\xae\x01\u02a3\xe1\x83\xe8vw~\x89\x18*\xb7\xc2\f\xe5$\x00\x00\u07d4\x03\xc9\x1d\x92\x946\x03\xe7R >\x054\x0eV`\x13\xb9\x00E\x89+|\xc2\xe9\xc3\"\\\x00\x00\u07d4\x03\xcbLOE\x16\xc4\xffy\xa1\xb6$O\xbfW.\x1c\u007f\xeay\x89\x94\x89#z\u06daP\x00\x00\u07d4\x03\u02d8\u05ec\xd8\x17\u079d\x88m\"\xfa\xb3\xf1\xb5}\x92\xa6\b\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x03\u031d-!\xf8k\x84\xac\x8c\xea\xf9q\u06e7\x8a\x90\xe6%p\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\x03\xd1rO\xd0\x0eT\xaa\xbc\xd2\xde*\x91\xe8F+\x10I\xdd:\x89\x8f\x1d\\\x1c\xae7@\x00\x00\u07d4\x03\xde\xdf\xcd\v<.\x17\xc7\x05\xda$\x87\x90\uf626\xbdWQ\x89Hz\x9a0E9D\x00\x00\u07d4\x03\u8c04SuW\xe7\t\xea\xe2\xe1\u1966\xbc\xe1\xef\x83\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x03\xeam&\u0400\xe5z\xee9&\xb1\x8e\x8e\xd7:N[(&\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x03\xeb<\xb8`\xf6\x02\x8d\xa5T\xd3D\xa2\xbbZP\n\xe8\xb8o\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x03\xeb\xc6?\xdaf`\xa4e\x04^#_\xben\\\xf1\x95s_\x89\a\xb0l\xe8\u007f\xddh\x00\x00\xe0\x94\x03\xefj\xd2\x0f\xf7\xbdO\x00+\xacX\xd4uD\u03c7\x9a\xe7(\x8a\x01u\xc7X\u0439n\\\x00\x00\u07d4\x03\xf7\xb9 \b\x81:\xe0\xa6v\xeb!(\x14\xaf\xab5\"\x10i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\x11p\xf5\x81\u0780\xe5\x8b*\x04\\\x8f|\x14\x93\xb0\x01\xb7\u02c90\xc8\xeca2\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\x04i\xe8\xc4@E\v\x0eQ&&\xfe\x81~gT\xa8\x15(0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04m'K\x1a\xf6\x15\xfbPZvJ\xd8\u0767p\xb1\xdb/=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x04}Z&\u05ed\x8f\x8ep`\x0fp\xa3\x98\u076a\x1c-\xb2o\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x04~\x87\xc8\xf7\xd1\xfc\xe3\xb0\x13S\xa8Xb\xa9H\xac\x04\x9f>\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x04\u007f\x9b\xf1R\x9d\xaf\x87\xd4\a\x17^o\x17\x1b^Y\xe9\xff>\x89#<\x8f\xe4'\x03\xe8\x00\x00\xe0\x94\x04\x85'2\xb4\xc6R\xf6\xc2\u53b3e\x87\xe6\nb\xda\x14\u06ca\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x04\x8a\x89p\xeaAE\xc6MU\x17\xb8\xde[F\xd0YZ\xad\x06\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x04\x9c]K\xc6\xf2]NEli{R\xa0x\x11\xcc\u045f\xb1\x89\x10D\x00\xa2G\x0eh\x00\x00\u07d4\x04\xa1\xca\xda\x1c\xc7Q\b/\xf8\u0692\x8e<\xfa\x00\b \xa9\xe9\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x04\xa8\n\xfa\xd5>\xf1\xf8Ae\xcf\xd8R\xb0\xfd\xf1\xb1\xc2K\xa8\x89\x03$\xe9d\xb3\xec\xa8\x00\x00\u07d4\x04\xaa\xfc\x8a\xe5\xceoI\x03\u021d\u007f\xac\x9c\xb1\x95\x12\"Gw\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x04\xbaK\xb8q@\x02,!Jo\xacB\xdbZ\x16\u0755@E\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x04\xba\x8a?\x03\xf0\x8b\x89P\x95\x99M\xdaa\x9e\u06ac\xee>z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\xc2\xc6K\xb5L>\xcc\xd0U\x85\xe1\x0e\xc6\xf9\x9a\f\xdb\x01\xa3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x04\xceE\xf6\x00\xdb\x18\xa9\u0405\x1b)\xd99>\xbd\xaa\xfe=\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x04\u05b8\xd4\u0686t\a\xbb\x99wI\u07bb\xcd\xc0\xb3XS\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x04\xd78\x96\xcfe\x93\xa6\x91\x97*\x13\xa6\xe4\x87\x1f\xf2\xc4+\x13\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x04\xd8*\xf9\xe0\x1a\x93m\x97\xf8\xf8Y@\xb9p\xf9\xd4\u06d96\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x04\xe5\xf5\xbc|\x92?\xd1\xe3\x175\xe7.\xf9h\xfdg\x11\fn\x89WU\x1d\xbc\x8ebL\x00\x00\u07d4\x04\xec\xa5\x01c\n\xbc\xe3R\x18\xb1t\x95k\x89\x1b\xa2^\xfb#\x8966\x9e\xd7t}&\x00\x00\u07d4\x05\x05\xa0\x8e\"\xa1\t\x01Z\"\xf6\x850STf*U1\u0549\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\x05\x14\x95L\xe8\x81\xc807\x03d\x00\x89lO\xd1\xee$nx\x00\x00\u07d4\x05\x1dBBv\xb2\x129fQ\x86\x13=e;\xb8\xb1\x86/\x89\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x05!\xbc:\x9f\x87\x11\xfe\xcb\x10\xf5\a\x97\xd7\x10\x83\xe3A\ub749\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x05#mL\x90\xd0e\xf9\u34c3X\xaa\xff\xd7w\xb8j\xecI\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x05*X\xe05\xf1\xfe\x9c\xdd\x16\x9b\xcf \x97\x03E\xd1+\x9cQ\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x05.\xab\x1fa\xb6\xd4U\x17(?A\xd1D\x18$\x87\x87I\u0409\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x053n\x9ar'(\xd9c\xe7\xa1\xcf'Y\xfd\x02tS\x0f\u02891\xa2D?\x88\x8ay\x80\x00\u07d4\x054q\u035aA\x92[9\x04\xa5\xa8\xff\xca6Y\xe04\xbe#\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4\x056\x1d\x8e\xb6\x94\x1dN\x90\xfb~\x14\x18\xa9Z2\xd5%w2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x05B:T\xc8\xd0\xf9p~pAs\xd9#\xb9F\xed\xc8\xe7\x00\x89\x06\xea\x03\u00bf\x8b\xa5\x80\x00\u07d4\x05D\f[\a;R\x9bH) \x9d\xff\x88\t\x0e\a\xc4\xf6\xf5\x89E\u04977\xe2/ \x00\x00\u07d4\x05Z\xb6X\xc6\xf0\xedO\x87^\xd6t.K\xc7)-\x1a\xbb\xf0\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\u07d4\x05[\xd0,\xaf\x19\xd6 +\xbc\u0703m\x18{\xd1\xc0\x1c\xf2a\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x05^\xacO\x1a\xd3\xf5\x8f\v\xd0$\u058e\xa6\r\xbe\x01\u01af\xb3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x05fQU\xccI\xcb\xf6\xaa\xbd\u056e\x92\xcb\xfa\xad\x82\xb8\xc0\xc1\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x05f\x86\a\x8f\xb6\xbc\xf9\xba\n\x8a\x8d\xc6:\x90o_\xea\xc0\xea\x89\x1b\x18\x1eK\xf24<\x00\x00\u07d4\x05iks\x91k\xd3\x03>\x05R\x1e2\x11\xdf\xec\x02n\x98\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x05k\x15F\x89O\x9a\x85\xe2\x03\xfb3m\xb5i\xb1l%\xe0O\x89\t.\xdb\t\xff\b\u0600\x00\u07d4\x05yI\xe1\xca\x05pF\x9eL\xe3\u0190\xaea:k\x01\xc5Y\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x05}\u049f-\x19\xaa=\xa4#'\xeaP\xbc\xe8o\xf5\xc9\x11\u0649\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x05\u007f\u007f\x81\xcdz@o\xc4Y\x94@\x8bPI\x91,Vdc\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x05\x91]N\"Zf\x81b\xae\xe7\xd6\xc2_\xcf\xc6\xed\x18\xdb\x03\x89\x03\x98\xc3ry%\x9e\x00\x00\u07d4\x05\x96\xa2}\xc3\xee\x11_\xce/\x94\xb4\x81\xbc z\x9e&\x15%\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x05\xa80rC\x02\xbc\x0fn\xbd\xaa\x1e\xbe\xee\xb4nl\xe0\v9\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\x05\xae\u007f\u053b\u0300\xca\x11\xa9\n\x1e\u01e3\x01\xf7\xcc\u0303\u06c91T\xc9r\x9d\x05x\x00\x00\u07d4\x05\xbbd\xa9\x16\xbef\xf4`\xf5\xe3\xb6C2\x11\r \x9e\x19\xae\x89\u3bb5sr@\xa0\x00\x00\xe0\x94\x05\xbfO\xcf\xe7r\xe4[\x82dC\x85.l5\x13P\xcer\xa2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\x05\xc6@\x04\xa9\xa8&\xe9N^N\xe2g\xfa*v2\xddNo\x8a\x03m\xc4.\xbf\xf9\v\u007f\x80\x00\xe0\x94\x05\xc76\xd3e\xaa7\xb5\xc0\xbe\x9c\x12\u022d\\\xd9\x03\xc3,\xf9\x8a\x01E^{\x80\n\x86\x88\x00\x00\xe0\x94\x05\xcbl;\x00r\xd3\x11ga\xb52\xb2\x18D;S\xe8\xf6\u014a\x1e\x02\xc3\xd7\xfc\xa9\xb6(\x00\x00\u07d4\x05\xd0\xf4\xd7(\xeb\xe8.\x84\xbfYu\x15\xadA\xb6\v\xf2\x8b9\x89\u3bb5sr@\xa0\x00\x00\u07d4\x05\u058d\xada\u04fb\u07f3\xf7y&\\IGJ\xff?\xcd0\x89\x02\"\xc5]\xc1Q\x9d\x80\x00\u07d4\x05\xe6q\xdeU\xaf\xec\x96K\aM\xe5t\xd5\x15\x8d]!\xb0\xa3\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x05\xe9{\tI,\u058fc\xb1+\x89.\xd1\xd1\x1d\x15,\x0e\u02897\b\xba\xed=h\x90\x00\x00\u07d4\x05\xf3c\x1fVd\xbd\xad]\x012\xc88\x8d6\xd7\u0612\t\x18\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x06\t\xd8:l\xe1\xff\u0276\x90\xf3\xe9\xa8\x1e\x98>\x8b\xdcM\x9d\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\u07d4\x06\x1e\xa4\x87|\u0409D\xebd\u0096n\x9d\xb8\xde\xdc\xfe\xc0k\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x06%\xd0`V\x96\x8b\x00\"\x06\xff\x91\x98\x01@$+\xfa\xa4\x99\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x06(\xbf\xbeU5x/\xb5\x88@k\xc9f`\xa4\x9b\x01\x1a\xf5\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\x061\u044b\xbb\xbd0\xd9\xe1s+\xf3n\xda\xe2\u0389\x01\xab\x80\x89\xa3\xf9\x88U\xec9\x90\x00\x00\u07d4\x061\xdc@\xd7NP\x95\xe3r\x9e\xdd\xf4\x95D\xec\xd49og\x89\b\xacr0H\x9e\x80\x00\x00\xe0\x94\x067Y\xdd\x1cN6.\xb1\x93\x98\x95\x1f\xf9\xf8\xfa\xd1\xd3\x10h\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x06_\xf5u\xfd\x9c\x16\xd3\xcbo\u058f\xfc\x8fH?\xc3.\xc85\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x06a\x8e\x9dWb\xdfb\x02\x86\x01\xa8\x1dD\x87\u05a0\xec\xb8\x0e\x89Hz\x9a0E9D\x00\x00\xe0\x94\x06fG\xcf\xc8]#\xd3v\x05W= \x8c\xa1T\xb2D\xd7l\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x06xeJ\xc6v\x1d\xb9\x04\xa2\xf7\xe8Y^\xc1\xea\xacsC\b\x89/\x98\xb2\x9c(\x18\xf8\x00\x00\u07d4\x06\x86\n\x93RYU\xffbI@\xfa\xdc\xff\xb8\xe1I\xfdY\x9c\x89lh\xcc\u041b\x02,\x00\x00\xe0\x94\x06\x8c\xe8\xbdn\x90*E\u02c3\xb5\x15A\xb4\x0f9\xc4F\x97\x12\x8a\x01\x1c\x0f\x9b\xadJF\xe0\x00\x00\u07d4\x06\x8e)\xb3\xf1\x91\xc8\x12\xa699\x18\xf7\x1a\xb93\xaehG\xf2\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x06\x8eeWf\xb9D\xfb&6\x19e\x87@\xb8P\xc9J\xfa1\x89\x01\xe8\u007f\x85\x80\x9d\xc0\x00\x00\u0794\x06\x96N-\x17\xe9\x18\x9f\x88\xa8 96\xb4\n\xc9nS<\x06\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x06\x99L\xd8:\xa2d\n\x97\xb2`\vA3\x9d\x1e\r>\xdel\x89\r\x8drkqw\xa8\x00\x00\u07d4\x06\x9e\u042bz\xa7}\xe5q\xf1a\x06\x05\x1d\x92\xaf\xe1\x95\xf2\u0409\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x06\xac&\xad\x92\u02c5\x9b\u0550]\xdc\xe4&j\xa0\xecP\xa9\u0149*\x03I\x19\u07ff\xbc\x00\x00\u07d4\x06\xb0\xc1\xe3\u007fZ^\u013b\xf5\b@T\x8f\x9d:\xc0(\x88\x97\x89\xd8\u0602\u148e}\x00\x00\u07d4\x06\xb0\xff\x83@s\xcc\xe1\xcb\xc9\xeaU~\xa8{`Yc\u8d09\x10CV\x1a\x88)0\x00\x00\xe0\x94\x06\xb1\x06d\x9a\xa8\xc4!\xdd\xcd\x1b\x8c2\xcd\x04\x18\xcf0\xda\x1f\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x06\xb5\xed\xe6\xfd\xf1\xd6\xe9\xa3G!7\x9a\xea\xa1|q=\xd8*\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x06\xcb\xfa\b\xcd\xd4\xfb\xa77\xba\xc4\a\xbe\x82$\xf4\xee\xf3X(\x89 +\xe5\xe88.\x8b\x80\x00\u07d4\x06\xd6\xcb0\x84\x81\xc36\xa6\xe1\xa2%\xa9\x12\xf6\xe65Y@\xa1\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x06\xdc\u007f\x18\xce\xe7\xed\xab[yS7\xb1\xdfj\x9e\x8b\u062eY\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x06\xf6\x8d\xe3\xd79\xdbA\x12\x1e\xac\xf7y\xaa\xda=\xe8v!\a\x89\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\x06\xf7\u070d\x1b\x94b\xce\xf6\xfe\xb13h\xa7\xe3\x97K\t\u007f\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\a\x01\xf9\xf1G\xecHhV\xf5\xe1\xb7\x1d\xe9\xf1\x17\xe9\x9e!\x05\x89\te\xdaq\u007f\u0578\x00\x00\u07d4\a\r]6L\xb7\xbb\xf8\"\xfc,\xa9\x1a5\xbd\xd4A\xb2\x15\u0549lk\x93[\x8b\xbd@\x00\x00\xe0\x94\a\x1d\xd9\r\x14\xd4\x1fO\xf7\xc4\x13\xc2B8\xd35\x9c\xd6\x1a\a\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\u07d4\a&\xc4.\x00\xf4T\x04\x83n\xb1\xe2\x80\xd0s\xe7\x05\x96\x87\xf5\x89X\x00>?\xb9G\xa3\x80\x00\xe0\x94\a'\xbe\n*\x00! H\xb5R\x0f\xbe\xfb\x95>\xbc\x9dT\xa0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\a)\xa8\xa4\xa5\xba#\xf5y\xd0\x02[\x1a\xd0\xf8\xa0\xd3\\\xdf\u048a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4\a)\xb4\xb4|\t\xeb\x16\x15\x84d\u022a\u007f\xd9i\vC\x889\x89lh\xcc\u041b\x02,\x00\x00\u0794\a4\xa0\xa8\x1c\x95b\xf4\xd9\xe9\xe1\n\x85\x03\xda\x15\xdbF\xd7n\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\a\xa7\xef[G\x00\x00\xe0\x94\ap\xc6\x1b\xe7\x87r#\f\xb5\xa3\xbb$)\xa7&\x14\xa0\xb36\x8a\x01n\u0899\xb7\x13A\x80\x00\u07d4\ar><0\xe8\xb71\xeeEj)\x1e\xe0\u7630 Jw\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\as\xee\xac\xc0P\xf7G \xb4\xa1\xbdW\x89[\x1c\xce\xebI]\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\a\x80\r/\x80h\xe4H\u01daOi\xb1\xf1^\xf6\x82\xaa\xe5\xf6\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\u07d4\a\xa8\xda\xde\xc1BW\x1a}S\xa4)pQxm\a,\xbaU\x89\x01;m\xa1\x13\x9b\u0680\x00\u07d4\a\xaf\x93\x8c\x127\xa2|\x900\tM\xcf$\aP$n=,\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\a\xb1\xa3\x06\xcbC\x12\xdffH,,\xaer\xd1\xe0a@\x0f\u034a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\a\xb7\xa5p3\xf8\xf1\x130\xe4f^\x18]#N\x83\xec\x14\v\x89\xea~\xe9*\f\x9a\v\x80\x00\u07d4\a\xbc,\xc8\xee\xdc\x01\x97\a\x00\xef\xc9\xc4\xfb6s^\x98\xcdq\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\a\xd4\x12\x17\xba\u0725\xe0\xe6\x03'\xd8E\xa3FO\x0f'\xf8J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\a\xd43N\u00c5\xe8\xaaT\xee\xda\xea\xdb0\x02/\f\u07e4\xab\x89\x8e\x91\xd5 \xf2\xeby\x00\x00\u07d4\a\xda\xe6\"c\r\x1168\x193\u04adk\"\xb89\xd8!\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\a\xdc+\xf8;\u01af\x19\xa8B\xff\xeaf\x1a\xf5\xb4\x1bg\xfd\xa1\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\a\u070c\x8b\x92z\xdb\xed\xfa\x8f]c\x9bCR5\x1f/6\u0489\x11\n\xed;U0\xdb\x00\x00\u07d4\a\xdd\xd0B,\x86\xefe\xbf\f\u007f\xc3E(b\xb1\"\x8b\b\xb8\x89o\xf5\u04aa\x8f\x9f\xcf\x00\x00\u07d4\a\xe1\x16,\xea\xe3\xcf!\xa3\xf6-\x10Y\x900.0\u007fN;\x89R\xf1\x03\xed\xb6k\xa8\x00\x00\u07d4\a\xe2\xb4\xcd\xee\xd9\u0407\xb1.Um\x9ew\f\x13\xc0\x99a_\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\a\xfe\xefT\xc16\x85\b)\xba\xdcKI\xc3\xf2\xa7<\x89\xfb\x9e\x89\x06hZ\xc1\xbf\xe3,\x00\x00\u07d4\b\x05FP\x8a=&\x82\u0239\x88O\x13c{\x88G\xb4M\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\t\bv\xba\xad\xfe\xe6\\=6;\xa5S\x12t\x8c\xfa\x87=\x89\\*\x997\x1c\xff\xe1\x00\x00\u07d4\b\x16o\x021?\xea\u12f0D\xe7\x87|\x80\x8bU\xb5\xbfX\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\b)\xd0\xf7\xbb|Dl\xfb\xb0\u07ad\xb29M\x9d\xb7$\x9a\x87\x89\x02,\xa3X|\xf4\xeb\x00\x00\u07d4\b0m\xe5\x19\x81\u7b21\x85hY\xb7\xc7xijki\xf9\x89\xadx\xeb\u016cb\x00\x00\x00\xe0\x94\b7S\x9b_jR*H,\xdc\u04e9\xbbpC\xaf9\xbd\u048a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\b8\xa7v\x8d\x9c*\u028b\xa2y\xad\xfe\xe4\xb1\xf4\x91\xe3&\xf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\bA\x16R\xc8qq6\t\xaf\x00b\xa8\xa1(\x1b\xf1\xbb\xcf\u0649K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\bM\x102Tu\x9b4<\xb2\xb9\xc2\xd8\xff\x9e\x1a\xc5\xf1E\x96\x8a\x01\x9b\xff/\xf5yh\xc0\x00\x00\u07d4\bPO\x05d?\xabY\x19\xf5\xee\xa5Y%\u05e3\xed}\x80z\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\b[J\xb7]\x83b\xd9\x14C\\\xed\xee\x1d\xaa+\x1e\xe1\xa2;\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\b[\xa6_\xeb\xe2>\xef\xc2\xc8\x02fj\xb1&#\x82\xcf\u0114\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\bt\x98\xc0FFh\xf3\x11P\xf4\xd3\u013c\u0765\"\x1b\xa1\x02\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\bw\uebabx\xd5\xc0\x0e\x83\xc3+-\x98\xfay\xadQH/\x89\x17\xd2-q\xdab&\x00\x00\u0794\b\x93j7\u07c5\xb3\xa1X\xca\xfd\x9d\xe0!\xf5\x817h\x13G\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\b\xa9\xa4N\x1fA\xde=\xbb\xa7\xa3c\xa3\xabA,\x12L\xd1^\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\b\xb7\xbd\u03d4MUp\x83\x8b\xe7\x04`$:\x86\x94HXX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xb8E6\xb7L\x8c\x01T=\xa8\x8b\x84\u05cb\xb9WG\xd8\"\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\b\xc2\xf26\xacJ\xdc\xd3\xfd\xa9\xfb\xc6\xe4S\"S\xf9\xda;\xec\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\b\xc8\x02\xf8wX4\x9f\xa0>k\xc2\xe2\xfd\a\x91\x19~\ua689lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xc9\U0007fd89\xfd\xf8\x04\xd7i\xf8!#6\x02\x15\xaf\xf9;\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\b\xca\u0215&A\xd8\xfcRn\xc1\xabO-\xf8&\xa5\xe7q\x0f\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\b\xcc\xdaP\xe4\xb2j\x0f\xfc\x0e\xf9.\x92\x051\a\x06\xbe\xc2\u01ca\x01Iul8W\xc6\x00\x00\x00\u07d4\b\u0406M\xc3/\x9a\xcb6\xbfN\xa4G\xe8\xddg&\x90j\x15\x89lnY\xe6|xT\x00\x00\u07d4\b\xd4&\u007f\xeb\x15\u0697\x00\xf7\xcc\xc3\xc8J\x89\x18\xbf\x17\xcf\u0789a\t=|,m8\x00\x00\xe0\x94\b\xd41\x1c\x9c\x1b\xba\xf8\u007f\xab\xe1\xa1\xd0\x14c\x82\x8d]\x98\u038a\x13\x0e\xe8\xe7\x17\x90D@\x00\x00\u07d4\b\xd5N\x83\xadHj\x93L\xfa\xea\u20e3>\xfd\"|\x0e\x99\x898S\x05\x83$^\xdc\x00\x00\u07d4\b\xd9~\xad\xfc\xb7\xb0d\xe1\xcc\xd9\u0217\x9f\xbe\xe5\xe7z\x97\x19\x89\x0el]\xa8\xd6z\xc1\x80\x00\u07d4\b\xda:z\x0fE!a\u03fc\xec1\x1b\xb6\x8e\xbf\xde\xe1~\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\b\xe3\x8e\xe0\xceH\xc9\xcad\\\x10\x19\xf7;SUX\x1cV\xe6\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\b\xef?\xa4\xc4<\xcd\xc5{\"\xa4\xb9\xb23\x1a\x82\xe58\x18\xf2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\t\td\x8c\x18\xa3\xce[\xaez\x04~\xc2\xf8h\xd2L\u0768\x1d\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\t\f\xd6{`\xe8\x1dT\xe7\xb5\xf6\a\x8f>\x02\x1b\xa6[\x9a\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\f\xeb\xef),>\xb0\x81\xa0_\u062a\xf7\u04db\xf0{\x89\u0509\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\t\x0f\xa96{\xdaW\xd0\xd3%:\n\x8f\xf7l\xe0\xb8\xe1\x9as\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\x14n\xa3\x88Qv\xf0w\x82\xe1\xfe0\xdc\xe3\xce$\u011e\x1f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\t!`_\x99\x16N;\xcc(\xf3\x1c\xae\xcex\x971\x82V\x1d\x89+\ai*\x90e\xa8\x00\x00\xe0\x94\t&\x1f\x9a\xcbE\x1c7\x88\x84O\f\x14Q\xa3[\xadP\x98\xe3\x8a\x01\u056d'P) `\x00\x00\xe0\x94\t'\"\x04\x92\x19K.\u069f\u013b\xe3\x8f%\u0581\xdf\xd3l\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\t*\xcbbK\b\xc0U\x10\x18\x9b\xbb\xe2\x1ee$\xd6D\u032d\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\t.\x81UX@-g\xf9\rk\xfem\xa0\xb2\xff\xfa\x91EZ\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\tP0\xe4\xb8&\x92\xdc\xf8\xb8\u0411$\x94\xb9\xb3x\xec\x93(\x89H\xa4zu\x80\x00\u07d4\t\x89\xc2\x00D\v\x87\x89\x91\xb6\x9d`\x95\xdf\xe6\x9e3\xa2.p\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\t\x90\xe8\x1c\u05c5Y\x9e\xa26\xbd\x19f\xcfRc\x02\xc3[\x9c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\t\x98\xd8'1\x15\xb5j\xf4%\xff\xc8>!\x8c\x1e\n\xfe\x89(\u01c8\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\t\xaeI\xe3\u007f\x12\x1d\xf5\xdc\x15\x8c\xfd\xe8\x06\xf1s\xa0k\f\u007f\x89\xd80\x9e&\xab\xa1\xd0\x00\x00\u07d4\t\xaf\xa7;\xc0G\xefF\xb9w\xfd\x97c\xf8r\x86\xa6\xbeh\u0189\x1b/\xb5\xe8\xf0jf\x00\x00\u07d4\t\xb4f\x86\x96\xf8j\b\x0f\x8b\xeb\xb9\x1d\xb8\xe6\xf8p\x15\x91Z\x89#\x8f\xf7\xb3O`\x01\x00\x00\xe0\x94\t\xb5\x9b\x86\x98\xa7\xfb\xd3\xd2\xf8\xc7:\x00\x89\x88\xde>@k+\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94\t\xb7\xa9\x88\xd1?\xf8\x91\x86so\x03\xfd\xf4au\xb5=\x16\xe0\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\t\xc1w\xf1\xaeD$\x11\u076c\xf1\x87\xd4m\xb9V\x14\x83`\xe7\x8a\x01\xe5.3l\xde\"\x18\x00\x00\xe0\x94\t\u020f\x91~Mj\xd4s\xfa\x12\u93a3\xc4G*^\xd6\u068a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\t\u0438\xcd\a|i\xd9\xf3-\x9c\xcaC\xb3\xc2\b\xa2\x1e\u050b\x89\b!\xd2!\xb5)\x1f\x80\x00\xe0\x94\t\xd6\xce\xfdu\xb0\u0133\xf8\xf1\u0587\xa5\"\xc9a#\xf1\xf59\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\t\xe47\xd4H\x86\x12(\xa22\xb6.\xe8\xd3ye\xa9\x04\ud70a\x04\x98\xcf@\x1d\xf8\x84.\x80\x00\u07d4\t\xee\x12\xb1\xb4+\x05\xaf\x9c\xf2\a\xd5\xfc\xac%[.\xc4\x11\xf2\x89\x031\xcd\xddG\xe0\xfe\x80\x00\u07d4\t\xf3\xf6\x01\xf6\x05D\x11@Xl\xe0eo\xa2J\xa5\xb1\u066e\x89Sswo\xe8\xc4T\x00\x00\u07d4\t\xf9W[\xe5}\x00G\x93\u01e4\ub137\x15\x87\xf9|\xbbj\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n\x06P\x86\x1fx^\xd8\xe4\xbf\x10\x05\xc4P\xbb\xd0n\xb4\x8f\xb6\x89\xa6A;y\x14N~\x00\x00\u07d4\n\x06\xfa\xd7\xdc\u05e4\x92\xcb\xc0S\xee\xab\xdei4\xb3\x9d\x867\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\n\a}\xb1?\xfe\xb0\x94\x84\xc2\x17p\x9dX\x86\xb8\xbf\x9cZ\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\n\x0e\u0366cow\x16\xef\x19saF\x87\xfd\x89\xa8 \xa7\x06\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\n)\xa8\xa4\xd5\xfd\x95\x00u\xff\xb3Mw\xaf\xeb-\x82;\u0589\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n*\u0795\xb2\xe8\xc6m\x8a\xe6\xf0\xbad\xcaW\u05c3\xbemD\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\n+O\xc5\xd8\x1a\xceg\xdcK\xba\x03\xf7\xb4UA=F\xfe=\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\n-\xcbzg\x17\x01\u06f8\xf4\x95r\x80\x88&Xs5l\x8e\x89\b?\x16\xce\b\xa0l\x00\x00\u07d4\n=\xe1U\xd5\xec\xd8\xe8\x1c\x1f\xf9\xbb\xf07\x83\x01\xf8\xd4\xc6#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\nG\xad\x90Y\xa2I\xfc\x93k&b5=\xa6\x90_u\u00b9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\nH)ov1p\x8c\x95\u04b7Iu\xbcJ\xb8\x8a\xc19*\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\nJ\x01\x19\x95\u0181\xbc\x99\x9f\xddyuN\x9a2J\xe3\xb3y\x8a\b\xc1\x9a\xb0n\xb8\x9a\xf6\x00\x00\u07d4\nX\xfd\xddq\x89\x8d\xe7s\xa7O\xda\xe4^{\xd8N\xf46F\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\n[y\xd8\xf2;d\x83\xdb\u2f6ab\xb1\x06L\xc7cf\xae\x89j\u0202\x10\tR\u01c0\x00\u07d4\ne.*\x8bw\xbd\x97\xa7\x90\xd0\xe9\x13a\u0248\x90\u06f0N\x8965\u026d\xc5\u07a0\x00\x00\u07d4\nn\xber;n\xd1\xf9\xa8ji\xdd\xdah\xdcGF\\+\x1b\x89@=-\xb5\x99\xd5\xe4\x00\x00\u07d4\nw\xe7\xf7+C{WO\x00\x12\x8b!\xf2\xac&Q3R\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\n\x91\u007f;\\\xb0\xb8\x83\x04\u007f\u0676Y=\xbc\xd5W\xf4S\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\n\x93\x1bD\x9e\xa8\xf1,\xdb\xd5\xe2\xc8\xccv\xba\xd2\xc2|\x069\x89\x01?\x9e\x8cy\xfe\x05\x80\x00\u0794\n\x98\x04\x13x\x03\xbahh\xd9:U\xf9\x98_\xcdT\x04Q\u4239\x8b\xc8)\xa6\xf9\x00\x00\u07d4\n\x9a\xb2c\x8b\x1c\xfdeM%\u06b0\x18\xa0\xae\xbd\u07c5\xfdU\x89\x01.\x8c\xb5\xfeLJ\x80\x00\u07d4\n\xb3f\xe6\xe7\u056b\xbc\xe6\xb4JC\x8di\xa1\u02bb\x90\xd13\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\n\xb4(\x1e\xbb1\x85\x90\xab\xb8\x9a\x81\xdf\a\xfa:\xf9\x04%\x8a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\n\xb5\x9d9\a\x02\xc9\xc0Y\xdb\x14\x8e\xb4\xf3\xfc\xfa}\x04\xc7\xe7\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\n\xbf\xb3\x9b\x11HmyW(f\x19[\xa2lc\vg\x84\u06ca\x19\xba\x877\xf9i(\xf0\x00\x00\u07d4\n\u029aV&\x91;\b\xcf\u0266m@P\x8d\xceR\xb6\x0f\x87\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\n\xd3\xe4M<\x00\x1f\xa2\x90\xb3\x93ap0TA\b\xacn\xb9\x89j\xbd\xa0\xbc0\xb2\u07c0\x00\u07d4\n\xec.Bn\xd6\xcc\f\xf3\xc2I\xc1\x89~\xacG\xa7\xfa\xa9\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\n\xf6_\x14xNU\xa6\xf9Vg\xfds%*\x1c\x94\a-*\x89\nv;\x8e\x02\xd4O\x80\x00\u07d4\n\xf6\xc8\xd59\xc9mP%\x9e\x1b\xa6q\x9e\x9c\x80`\xf3\x88\u008965\u026d\xc5\u07a0\x00\x00\u07d4\v\x069\x0f$7\xb2\x0e\u0123\xd3C\x1b2y\xc6X>^\u05c9\n\x84Jt$\xd9\xc8\x00\x00\u07d4\v\v8b\x11*\xee\u00e04\x92\xb1\xb0_D\x0e\xcaT%n\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\v\x0e\x05[(\xcb\xd0=\xc5\xffD\xaad\xf3\xdc\xe0O^c\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\x11\x9d\xf9\x9ck\x8d\xe5\x8a\x1e,?)zgD\xbfU\"w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\x14\x89\x19\x99\xa6\\\x9e\xf73\b\xef\xe3\x10\f\xa1\xb2\x0e\x81\x92\x89+^:\xf1k\x18\x80\x00\x00\u07d4\v!\x13PE4d*\x1d\xaf\x10.\xee\x10\xb9\xeb\xdev\xe2a\x89\x94,\xdd|\x95\xf2\xbd\x80\x00\xe0\x94\v(\x8aZ\x8bu\xf3\xdcA\x91\xeb\x04W\xe1\xc8=\xbd M%\x8a\x01\a\x14\xe7{\xb4:\xb4\x00\x00\u07d4\v6\x9e\x00.\x1bLy\x13\xfc\xf0\x0f-^\x19\u0141eG\x8f\x89\x03\u007fe\x16(\x8c4\x00\x00\u07d4\vC\xbd#\x91\x02U\x81\u0615l\xe4*\a%y\u02ff\xcb\x14\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u07d4\vP|\xf5SV\x8d\xaa\xf6U\x04\xaeN\xaa\x17\xa8\xea<\xdb\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v]f\xb1<\x87\xb3\x92\xe9M\x91\xd5\xf7l\rE\nU(C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v^ \x11\xeb\xc2Z\x00\u007f!6)`I\x8a\xfb\x8a\xf2\x80\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vd\x9d\xa3\xb9j\x10,\xdcm\xb6R\xa0\xc0}e\xb1\xe4C\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vi \xa6K6;\x8d]\x90\x80$\x94\xcfVKT|C\r\x89A\rXj \xa4\xc0\x00\x00\u07d4\vp\x11\x01\xa4\x10\x9f\x9c\xb3`\xdcW\xb7tBg=^Y\x83\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\vq\xf5T\x12$i\uf5ce/\x1f\xef\xd7\u02f4\x10\x98'r\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\xe0\x94\v{\xb3B\xf0\x1b\u0248\x8ej\x9a\xf4\xa8\x87\xcb\xf4\xc2\xdd,\xaf\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\v}3\x93q\xe5\xbeg'\xe6\xe31\xb5\x82\x1f\xa2K\u06ddZ\x89.\u007f\x81\x86\x82b\x01\x00\x00\u07d4\v\u007f\xc9\xdd\xf7\x05v\xf63\x06i\xea\xaaq\xb6\xa81\xe9\x95(\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\v\x80\xfcp(,\xbd\xd5\xfd\xe3[\xf7\x89\x84\xdb;\xdb\x12\x01\x88\x8968\x02\x1c\xec\u06b0\x00\x00\u07d4\v\x92M\xf0\a\xe9\xc0\x87\x84\x17\xcf\xe6;\x97n\xa1\xa3\x82\xa8\x97\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\v\x93\xfc\xa4\xa4\xf0\x9c\xac \xdb`\xe0e\xed\xcc\xcc\x11\u0976\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\v\x9d\xf8\x0f\xbe# \t\xda\xcf\n\xa8\xca\u0153v\xe2Gb\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xa6\xe4j\xf2Z\x13\xf5qi%Z4\xa4\xda\xc7\xce\x12\xbe\x04\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\v\xa8p[\xf5\\\xf2\x19\xc0\x95k^?\xc0\x1cDt\xa6\xcd\xc1\x89\x05%\xe0Y]Mk\x80\x00\u07d4\v\xafn\u0379\x1a\xcb6\x06\xa85|\v\xc4\xf4\\\xfd-~o\x8965\u026d\xc5\u07a0\x00\x00\u07d4\v\xb0_r$\xbbX\x04\x85eV\xc0~\xea\xdb\ud1fa\x8f|\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\v\xb0\xc1&\x82\xa2\xf1\\\x9bWA\xb28\\\xbeA\xf04\x06\x8e\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\v\xb2\\\xa7\u0448\xe7\x1eMi={\x17\a\x17\xd6\xf8\xf0\xa7\n\x89\x12C\x02\xa8/\xad\xd7\x00\x00\u07d4\v\xb2e\x0e\xa0\x1a\xcau[\xc0\xc0\x17\xb6K\x1a\xb5\xa6m\x82\xe3\x89Hz\x9a0E9D\x00\x00\u07d4\v\xb5Lr\xfdf\x10\xbf\xa463\x97\xe0 8K\x02+\fI\x89Hz\x9a0E9D\x00\x00\u07d4\v\xb7\x16\n\xba)7b\xf8sO>\x03&\xff\u0264\xca\xc1\x90\x8965\u026d\xc5\u07a0\x00\x00\u07d4\v\xc9\\\xb3-\xbbWL\x83/\xa8\x17J\x815m8\xbc\x92\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xd6}\xbd\xe0z\x85n\xbd\x89;^\xdcO:[\xe4 &\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xdb\xc5L\u023d\xbb\xb4\x02\xa0\x89\x11\xe2#*T`\u0386k\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\v\xddX\xb9n|\x91m\xd2\xfb05o*\xeb\xfa\xaf\x1d\x860\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\v\u1f39\x03C\xfa\xe501s\xf4a\xbd\x91JH9\x05l\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\v\xe1\xfd\xf6&\xeea\x89\x10-p\xd1;1\x01,\x95\xcd\x1c\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\v\xe2\xb9J\xd9P\xa2\xa6&@\xc3[\xfc\xcdlg\xda\xe4P\xf6\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\v\u681eC\a\xfeH\xd4\x12\xb8\u0461\xa8(M\xceHba\x8a\x04\x0f\xbf\xf8\\\x0180\x00\x00\u07d4\v\xef\xb5G\a\xf6\x1b,\x9f\xb0G\x15\xab\x02n\x1b\xb7 B\xbd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\v\xf0dB\x8f\x83bg\"\xa7\xb5\xb2j\x9a\xb2\x04!\xa7r>\x89\a?u\u0460\x85\xba\x00\x00\u07d4\v\xfb\xb6\x92]\xc7^R\xcf&\x84\"K\xbe\x05P\xfe\xa6\x85\u04c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\f\b\x80\x06\xc6K0\xc4\u076f\xbc6\xcb_\x05F\x9e\xb6(4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f s\xbaD\xd3\u077d\xb69\xc0N\x19\x109\xa7\x17\x16#\u007f\x89M\x85<\x8f\x89\b\x98\x00\x00\xe0\x94\f\",|A\u0270H\xef\xcc\xe0\xa22CCb\xe1-g;\x8a\x02\x1e\x83Yivw8\x00\x00\xe0\x94\f(\b\xb9Q\ud787-{2y\x0f\xccY\x94\xaeA\xff\u070a\x15\x99n[<\u05b3\xc0\x00\x00\u07d4\f(\x84~O\t\xdf\xce_\x9b%\xaf|NS\x0fY\u0200\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f-\\\x92\x058\xe9S\u02af$\xf0s\u007fUL\u0192wB\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f0\xca\xcc?r&\x9f\x8bO\x04\xcf\a=+\x05\xa8=\x9a\u0449lyt\x12?d\xa4\x00\x00\u07d4\f29\xe2\xe8A$-\xb9\x89\xa6\x15\x18\xc2\"G\xe8\xc5R\b\x89\x0eJ\xf6G\x174d\x00\x00\xe0\x94\fH\r\xe9\xf7F\x10\x02\x90\x8bI\xf6\x0f\xc6\x1e+b\xd3\x14\v\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\fH\xaeb\xd1S\x97\x88\xeb\xa0\x13\xd7^\xa6\vd\xee\xbaN\x80\x89w\xfb\xdcC\xe00\x99\x80\x00\u07d4\fU\x89\xa7\xa8\x9b\x9a\xd1[\x02u\x190AYH\xa8u\xfb\xef\x89\x06\u0519\xeclc8\x00\x00\u07d4\fg\x03=\xd8\xee\u007f\f\x8a\xe54\xd4*Q\xf7\xd9\xd4\xf7\x97\x8f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\fhE\xbfA\xd5\xee'<>\u6d70\u059fo\xd5\xea\xbb\xf7\x89\xa2\xa1\xb9h.X\t\x00\x00\xe0\x94\f\u007f\x86\x9f\x8e\x90\xd5?\xdc\x03\u8c81\x9b\x01k\x9d\x18\xeb&\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\f\x86\x92\xee\xff*S\xd6\xd1h\x8e\xd5j\x9d\u06fdh\u06bb\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f\x8ff\xc6\x01{\xce[ 4r\x04\xb6\x02\xb7C\xba\u05cd`\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\f\x8f\xd7w^T\xa6\xd9\u0263\xbf\x89\x0ev\x1fewi?\xf0\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\f\x92Z\xd5\xeb5,\x8e\xf7m\f\"-\x11[\a\x91\xb9b\xa1\x89\xacc]\u007f\xa3N0\x00\x00\u07d4\f\x96~0a\xb8zu>\x84P~\xb6\t\x86x,\x8f0\x13\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\f\xa1*\xb0\xb9fl\xf0\xce\xc6g\x1a\x15)/&SGj\xb2\x8a,x'\xc4-\"\xd0|\x00\x00\u07d4\f\xa6p\xeb,\x8b\x96\u02e3y!\u007fY)\u00b8\x92\xf3\x9e\xf6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\f\xae\x10\x8em\xb9\x9b\x9ecxv\xb0d\xc60>\u068ae\u0209\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\f\xbd\x92\x1d\xbe\x12\x15c\xb9\x8ahq\xfe\xcb\x14\xf1\xcc~\x88\u05c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\f\xbf\x87p\xf0\xd1\b.\\ \u016e\xad4\xe5\xfc\xa9\xaez\xe2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\f\xc6\u007f\x82s\xe1\xba\xe0\x86\u007f\xd4.\x8b\x81\x93\xd7&y\xdb\xf8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\f\u05a1A\x91\x8d\x12k\x10m\x9f.\xbfi\xe1\x02\xdeM2w\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\f\xda\x12\xbfr\xd4a\xbb\xc4y\xeb\x92\xe6I\x1d\x05~kZ\u044a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\f\u0716\v\x99\x8c\x14\x19\x98\x16\r\xc1y\xb3l\x15\u0484p\xed\x89\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\f\xfb\x17#5\xb1l\x87\xd5\x19\xcd\x14uS\r W\u007f^\x0e\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\r\x1f*Wq>\xbcn\x94\xde)\x84n\x88D\xd3vfWc\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\r2e\xd3\u7f79=^\x8e\x8b\x1c\xa4\u007f!\ny>\u030e\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\r5@\x8f\"ef\x11o\xb8\xac\u06a9\xe2\xc9\u055bvh?\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\rU\x1e\xc1\xa2\x13<\x98\x1d_\u01a8\xc8\x17?\x9e|OG\xaf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r]\x98V\\d|\xa5\xf1w\xa2\xad\xb9\xd3\x02/\xac(\u007f!\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\re\x80\x14\xa1\x99\x06\x1c\xf6\xb3\x943\x14\x03\x03\xc2\x0f\xfdNZ\x8a\x01\xbc\x85\xdc*\x89\xbb \x00\x00\u07d4\rg\x87\x06\xd07\x18\u007f>\"\xe6\xf6\x9b\x99\xa5\x92\xd1\x1e\xbcY\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\ri\x10\f9\\\xe6\xc5\xea\xad\xf9]\x05\xd8r\x83~\xde\xdd!\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\rt~\u559b\xf7\x9dW8\x1do\xe3\xa2@l\xd0\xd8\xce'\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\r\x80#\x92\x9d\x91r4\xae@Q+\x1a\xab\xb5\xe8\xa4Q'q\x89\b\x05\xe9\x9f\xdc\xc5\xd0\x00\x00\xe0\x94\r\x8a\xab\x8ft\xea\x86,\xdfvh\x05\x00\x9d?>B\xd8\xd0\v\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\r\x8c@\xa7\x9e\x18\x99O\xf9\x9e\xc2Q\xee\x10\u0408\u00d1.\x80\x89\x066d\xfc\u04bb\xc4\x00\x00\u07d4\r\x8e\xd7\xd0\xd1V83\x0e\xd7\xe4\xea\u032b\x8aE\x8dus~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r\x92X/\u06e0^\xab\xc3\xe5\x158\xc5m\xb8\x817\x85\xb3(\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\r\x94C\xa7\x94h\xa5\xbb\xf7\xc1\xe5\xb9\x15\xb3d\x87\xf9\x16\x1f\x19\x84m\x10\x1431\x8a\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\r\xbdA|7+\x8b\r\x01\xbc\xd9Dpk\xd3.`\xae(\u0449\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\r\xc1\x00\xb1\a\x01\x1c\u007f\xc0\xa13\x96\x12\xa1l\xce\xc3(R\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\r\u03dd\x8c\x98\x04E\x9fd|\x14\x13\x8e\xd5\x0f\xadV;AT\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4\r\xcf\xe87\xea\x1c\xf2\x8ce\xfc\xce\u00fe\xf1\xf8NY\xd1P\xc0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\r\xd4\xe6t\xbb\xad\xb1\xb0\u0702D\x98q=\xce;QV\xda)\x89\t79SM(h\x00\x00\u07d4\r\xfb\u0501pP\xd9\x1d\x9db\\\x02\x05<\xf6\x1a>\xe2\x85r\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\x0e\x02N\u007f\x02\x9cj\xaf:\x8b\x91\x0f^\b\bs\xb8W\x95\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0e\tdl\x99\xafC\x8e\x99\xfa'L\xb2\xf9\xc8V\xcbe\xf76\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x0e\f\x9d\x00^\xa0\x16\u0095\xcdy\\\xc9!>\x87\xfe\xbc3\xeb\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\x0e\rf3\xdb\x1e\f\u007f#Jm\xf1c\xa1\x0e\n\xb3\x9c \x0f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x0e\x11\xd7z\x89w\xfa\xc3\r&\x84E\xe51\x14\x9b1T\x1a$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\x12=}\xa6\xd1\xe6\xfa\xc2\u072d\xd2p)$\v\xb3\x90R\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0e\x18\x01\xe7\vbb\x86\x1b\x114\u033c9\x1fV\x8a\xfc\x92\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x0e \x94\xac\x16T\xa4k\xa1\xc4\u04e4\v\xb8\xc1}\xa7\U000d6209\x13h?\u007f<\x15\xd8\x00\x00\u07d4\x0e!\xaf\x1b\x8d\xbf'\xfc\xf6?7\xe0G\xb8z\x82\\\xbe|'\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x0e.PJ-\x11\"\xb5\xa9\xfe\xee\\\xb1E\x1b\xf4\u00ac\xe8{\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x0e/\x8e(\xa6\x81\xf7|X;\xd0\xec\xde\x16cK\xdd~\x00\u0349\x05'8\xf6Y\xbc\xa2\x00\x00\u07d4\x0e2\x02\x19\x83\x8e\x85\x9b/\x9f\x18\xb7.=@s\xcaP\xb3}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e3\xfc\xbb\xc0\x03Q\v\xe3W\x85\xb5*\x9c]!k\xc0\x05\xf4\x89e\xea=\xb7UF`\x00\x00\u07d4\x0e6\x96\xcf\x1fB\x17\xb1c\u047c\x12\xa5\xeas\x0f\x1c2\xa1J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x0e9\x0fD\x05=\xdf\xce\xf0\xd6\b\xb3^M\x9c,\xbe\x98q\xbb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x0e:(\xc1\u07ef\xb0P[\xdc\xe1\x9f\xe0%\xf5\x06\xa6\xd0\x1c\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e=\xd7\xd4\xe4)\xfe90\xa6A@5\xf5+\xdcY\x9dxM\x89\x02,\xa3X|\xf4\xeb\x00\x00\u07d4\x0eGey\x03Rek\xc6Vh,$\xfc^\xf3\xe7j#\u01c9\x02\x86\xd7\xfc\f\xb4\xf5\x00\x00\u07d4\x0eI\x88\x00Dqw\xb8\u022f\xc3\xfd\xfa\u007fi\xf4\x05\x1b\xb6)\x89t\x05\xb6\x9b\x8d\xe5a\x00\x00\u07d4\x0ek\xaa\xa3\u07b9\x89\xf2\x89b\x00vf\x86\x18\xe9\xac3(e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x0el\xd6d\xad\x9c\x1e\xd6K\xf9\x87I\xf4\x06D\xb6&\xe3y,\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\xe0\x94\x0em\xfdU;.\x87=*\xec\x15\xbd_\xbb?\x84r\xd8\u04d4\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\x0en\xc3\x137bq\xdf\xf5T#\xabT\"\xcc:\x8b\x06\xb2+\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x0en\u0399\x11\x1c\xad\x19a\xc7H\xed=\xf5\x1e\xddi\u04a3\xb1\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x0e\x83\xb8PH\x1a\xb4MI\xe0\xa2)\xa2\xe4d\x90,iS\x9b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0e\x89\xed\xdd?\xa0\xd7\x1d\x8a\xb0\xff\x8d\xa5X\x06\x86\xe3\xd4\xf7O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\x90\x96\xd3C\xc0`\xdbX\x1a\x12\x01\x12\xb2x`~\xc6\xe5+\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x0e\x9cQ\x18d\xa1w\xf4\x9b\xe7\x82\x02w?`H\x9f\xe0NR\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x0e\xa2\xa2\x101+>\x86~\xe0\xd1\xcch,\xe1\xd6f\xf1\x8e\u054a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x0e\xb1\x89\xef,-Wb\xa9c\u05b7\xbd\xf9i\x8e\xa8\u7d0a\x89Hz\x9a0E9D\x00\x00\xe0\x94\x0e\xb5\xb6b\xa1\xc7\x18`\x8f\xd5/\f%\xf97\x880\x17\x85\x19\x8a\x01J7(\x1aa.t\x00\x00\xe0\x94\x0e\xc4f\x96\xff\xac\x1fX\x00_\xa8C\x98$\xf0\x8e\xed\x1d\xf8\x9b\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x0e\xc5\n\xa8#\xf4e\xb9FK\v\xc0\u0125w$\xa5U\xf5\u058a\f\x83\xd1Bj\u01f1\xf0\x00\x00\u07d4\x0e\xc50\x8b1(.!\x8f\xc9\xe7Y\xd4\xfe\xc5\xdb7\b\xce\u01096C\xaady\x86\x04\x00\x00\u07d4\x0e\xcc\xf6\x17\x84O\xd6\x1f\xbab\xcb\x0eD[z\u018b\xcc\x1f\xbe\x89\x14\xfeO\xe65e\xc6\x00\x00\u07d4\x0e\u04fb:N\xb5T\xcf\u0297\x94}WU\a\xcd\xfdm!\u0609\x1d\xb3 _\xcc#\u0540\x00\u07d4\x0e\xd7l,;]P\xff\x8f\xb5\v>\xea\xcdh\x15\x90\xbe\x1c-\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0e\u0680\xf4\xed\aJ\xeaiz\xed\xdf(;c\xdb\xca=\xc4\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4\x0e\xddKX\x0f\xf1\x0f\xe0lJ\x03\x11b9\xef\x96b+\xae5\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x0e\xe3\x91\xf0^\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x0f\x92\x9c\xf8\x95\xdb\x01z\xf7\x9f>\xad\"\x16\xb1\xbdi\xc3}\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x0f\xa0\x10\xce\fs\x1d;b\x8e6\xb9\x1fW\x13\x00\u477e\xab\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\x0f\xa5\xd8\u0173\xf2\x94\xef\u0515\xabi\xd7h\xf8\x18rP\x85H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x0f\xa6\u01f0\x97=\v\xae)@T\x0e$}6'\xe3|\xa3G\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x0f\xad\x05P|\u070f$\xb2\xbeL\xb7\xfa]\x92}\u06d1\x1b\x88\x89\xa2\xdf\x13\xf4A\xf0\t\x80\x00\u07d4\x0f\xb5\xd2\xc6s\xbf\xb1\xdd\xca\x14\x1b\x98\x94\xfdm?\x05\xdag \x89\x05k\xc7^-c\x10\x00\x00\u07d4\x0f\u0260\xe3AE\xfb\xfd\xd2\xc9\u04a4\x99\xb6\x17\u05e0)i\xb9\x89\t\xc2\x00vQ\xb2P\x00\x00\xe0\x94\x0f\xcf\xc4\x06P\b\xcf\xd3#0_b\x86\xb5zM\xd7\xee\xe2;\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x0f\xdde@#\x95\u07db\u045f\xeeE\a\xefSE\xf7E\x10L\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x0f\xecN\xe0\xd7\xca\x18\x02\x90\xb6\xbd \xf9\x99#B\xf6\x0f\xf6\x8d\x89\x12 \u007f\x0e\xdc\xe9q\x80\x00\u07d4\x0f\ue06c3\x1e\xfd\x8f\x81\x16\x1cW8+\xb4P{\xb9\xeb\xec\x89\x15\xaf\x88\r\x8c\u06c3\x00\x00\u07d4\x0f\xfe\xa0mq\x13\xfbj\xec(i\xf4\xa9\u07f0\x90\a\xfa\xce\xf4\x89\f8F\x81\xb1\xe1t\x00\x00\u07d4\x10\tq\x98\xb4\xe7\xee\x91\xff\x82\xcc/;\xd9_\xeds\xc5@\xc0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x10\vM\tw\xfc\xba\xd4\u07bd^d\xa0Iz\xea\xe5\x16\x8f\xab\x89\x11\f\x90s\xb5$Z\x00\x00\xe0\x94\x10\x1a\nd\xf9\xaf\xccD\x8a\x8a\x13\rM\xfc\xbe\xe8\x957\xd8T\x8a\x037\xfe_\xea\xf2\u0440\x00\x00\u07d4\x10,G}i\xaa\u06e9\xa0\xb0\xf6+tY\xe1\u007f\xbb\x1c\x15a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x101\xe0\xec\xb5I\x85\xae!\xaf\x17\x93\x95\r\xc8\x11\x88\x8f\xde|\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x104d\x14\xbe\xc6\xd3\xdc\xc4NP\xe5MT\u00b8\xc3sN>\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x108\x98X\xb8\x00\xe8\xc0\xec2\xf5\x1e\xd6\x1a5YF\xcc@\x9b\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x10Y\xcb\xc6>6\xc4>\x88\xf3\x00\b\xac\xa7\xce\x05\x8e\ua816\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\x10n\xd5\xc7\x19\xb5&\x14w\x89\x04%\xaeuQ\xdcY\xbd%\\\x8a\x02\x89jX\xc9[\xe5\x88\x00\x00\u07d4\x10q\x1c=\xda21x\x85\xf0\xa2\xfd\x8a\xe9.\x82\x06\x9b\r\v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x10sy\xd4\xc4gFO#[\xc1\x8eU\x93\x8a\xad>h\x8a\u05c9\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x10v!-Ou\x8c\x8e\xc7\x12\x1c\x1c}t%I&E\x92\x84\x8a\ai[Y\xb5\xc1{L\x00\x00\u07d4\x10x\xd7\xf6\x1b\x0eV\xc7N\xe6c[.\x18\x19\xef\x1e=\x87\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x10z\x03\xcf\bB\xdb\u07b0a\x8f\xb5\x87\xcai\x18\x9e\xc9/\xf5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x10\x80\xc1\xd85\x8a\x15\xbc\x84\xda\xc8%\x89\u0392\xb9\x81\x89t\xc1\xfa\xb8\xad\xb4T\x00\x00\u07d4\x10\xe1\xe37x\x85\xc4-}\xf2\x18R.\xe7vh\x87\xc0^j\x89\x10C\xc4<\xde\x1d9\x80\x00\u07d4\x10\u342d+\xa3=\x82\xb3s\x88\u041cED\u01b0\"]\xe5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x10\xf4\xbf\xf0\u02a5\x02|\nj-\xcf\xc9R\x82M\xe2\x94\t\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11\x00\x1b\x89\xed\x87>:\xae\xc1\x15V4\xb4h\x16C\x98c#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x11\x027\u03d1\x17\xe7g\x92/\u0121\xb7\x8dyd\u0682\xdf \x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x11\x11\xe5\xdb\xf4^o\x90mb\x86o\x17\b\x10\x17\x88\xdd\xd5q\x89F{\xe6S>\xc2\xe4\x00\x00\xe0\x94\x11\x17+'\x8d\xddD\xee\xa2\xfd\xf4\xcb\x1d\x16\x96#\x91\xc4S\u064a\xc6/=\x9b\xfdH\x95\xf0\x00\x00\u07d4\x11&4\xb4\xec0\xffxn\x02AY\xf7\x96\xa5y9\xea\x14N\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x110l}WX\x867x\x0f\xc9\xfd\xe8\xe9\x8e\xcb\x00\x8f\x01d\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x116\x12\xbc;\xa0\xeeH\x98\xb4\x9d\xd2\x023\x90_/E\x8fb\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x11A_\xaba\xe0\xdf\u0539\x06v\x14\x1aUz\x86\x9b\xa0\xbd\xe9\x89o\x05\xb5\x9d; \x00\x00\x00\u07d4\x11L\xbb\xbfo\xb5*\xc4\x14\xbe~\xc6\x1f{\xb7\x14\x95\xce\x1d\xfa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x11L\xfe\xfeP\x17\r\xd9z\xe0\x8f\nDTIx\u0159T\x8d\x89.\u0207\xe7\xa1J\x1c\x00\x00\u07d4\x11a\b\xc1 \x84a.\xed\xa7\xa9=\xdc\xf8\xd2`.'\x9e\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11d\u02aa\x8c\u0157z\xfe\x1f\xad\x8a}`(\xce-W)\x9b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x11gZ%UF\a\xa3\xb6\xc9*\x9e\xe8\xf3ou\xed\xd3\xe36\x89\b\xa9\xab\xa5W\xe3l\x00\x00\u07d4\x11j\t\xdff\xcb\x15\x0e\x97W\x8e)\u007f\xb0n\x13\x04\f\x89<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11o\xef^`\x16B\xc9\x18\u02c9\x16\x0f\xc2);\xa7\x1d\xa96\x89+|\xc2\xe9\xc3\"\\\x00\x00\u07d4\x11xP\x1f\xf9J\xdd\x1cX\x81\xfe\x88a6\xf6\xdf\xdb\xe6\x1a\x94\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x11y\xc6\r\xbd\x06\x8b\x15\v\aM\xa4\xbe#\x03; \u0185X\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\x11}\x9a\xa3\xc4\xd1;\xee\x12\xc7P\x0f\t\xf5\xdd\x1cf\xc4e\x04\x89\v*\xd3\x04\x90\xb2x\x00\x00\xe0\x94\x11}\xb867\u007f\xe1TU\xe0,.\xbd\xa4\v\x1c\xebU\x1b\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x11\x8c\x18\xb2\xdc\xe1p\xe8\xf4Eu;\xa5\xd7Q<\xb7cm-\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\x11\x8f\xbdu;\x97\x929Z\xefzMx\xd2c\xcd\u02ab\xd4\xf7\x8963\x03\"\xd5#\x8c\x00\x00\xe0\x94\x11\x92\x83x\xd2}U\xc5 \xce\xed\xf2L\xeb\x1e\x82-\x89\r\xf0\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x11\x9a\xa6M[}\x18\x1d\xae\x9d<\xb4I\x95\\\x89\xc1\xf9c\xfa\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\x11\xc05\x8a\xa6G\x9d\xe2\x18f\xfe!\a\x19$\xb6^p\xf8\xb9\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\xe0\x94\x11\xd2$z\"\x1ep\xc2\xd6m\x17\xee\x13\x8d8\xc5_\xfb\x86@\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x11\u05c4JG\x1e\xf8\x9a\x8d\x87uUX<\xee\xbd\x149\xea&\x8a\x02#i\u6e80\u0188\x00\x00\u07d4\x11\xdda\x85\u0668\xd7=\xdf\u06a7\x1e\x9bwtC\x1cM\xfe\u008965\u026d\xc5\u07a0\x00\x00\u07d4\x11\xe7\x99~\u0750E\x03\xd7}\xa6\x03\x8a\xb0\xa4\xc84\xbb\xd5c\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\x11\xec\x00\xf8I\xb61\x9c\xf5\x1a\xa8\u074ff\xb3U)\xc0\xbew\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x11\ufe22\x04Q\x16\x1bdJ\x8c\u03bb\xc1\xd3C\xa3\xbb\xcbR\x89\xadx\xeb\u016cb\x00\x00\x00\xe0\x94\x11\xfe\xfb]\xc1\xa4Y\x8a\xa7\x12d\fQwu\u07e1\xd9\x1f\x8c\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x12\x0f\x9d\xe6\xe0\xaf~\xc0*\a\xc6\t\u0284G\xf1W\xe64L\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x12\x10\xf8\v\u06c2l\x17Tb\xab\a\x16\xe6\x9eF\xc2J\xd0v\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x12\x13N\u007fk\x01{\xf4\x8e\x85Z9\x9c\xa5\x8e.\x89/\xa5\u020965\u026d\xc5\u07a0\x00\x00\u07d4\x12\x170t\x98\x01S\xae\xaaK\r\xcb\xc7\x13.\xad\xce\xc2\x1bd\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4\x12\x1f\x85[p\x14\x9a\xc84s\xb9po\xb4MG\x82\x8b\x98;\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x12'\xe1\nM\xbf\x9c\xac\xa3\x1b\x17\x80#\x9fUv\x15\xfc5\xc1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x12-\xcf\xd8\x1a\u0779}\x1a\x0eI%\u0135I\x80n\x9f;\xeb\x89R 5\xccn\x01!\x00\x00\u07d4\x12/V\x12%I\xd1h\xa5\xc5\xe2g\xf5&b\xe5\xc5\xcc\xe5\u0209\n\ad\a\xd3\xf7D\x00\x00\xe0\x94\x121o\xc7\xf1x\xea\xc2.\xb2\xb2Z\xed\xea\xdf=u\xd0\x01w\x8a\x04<3\xbe\x05\xf6\xbf\xb9\x80\x00\xe0\x94\x127Y\xf33\xe1>0i\xe2\x03KO\x059\x89\x18\x11\x9d6\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x12\\\xc5\xe4\xd5k+\xcc.\xe1\xc7\t\xfb\x9eh\xfb\x17t@\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x12c#\x88\xb2v^\xe4E+P\x16\x1d\x1f\xff\xd9\x1a\xb8\x1fJ\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\u07d4\x12h\x97\xa3\x11\xa1J\xd4;x\xe0\x92\x01\x00\xc4Bk\xfdk\u07494\xc7&\x89?-\x94\x80\x00\u07d4\x12m\x91\xf7\xad\x86\u07bb\x05W\xc6\x12\xca'n\xb7\xf9m\x00\xa1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x12}?\xc5\x00;\xf6<\r\x83\xe99W\x83e\x15\xfd'\x90E\x89\x06\x10\xc9\".nu\x00\x00\xe0\x94\x12}\xb1\xca\xdf\x1bw\x1c\xbdtu\xe1\xb2ri\x0fU\x8c\x85e\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x12\x84\xf0\xce\xe9\xd2\xff)\x89\xb6Ut\xd0o\xfd\x9a\xb0\xf7\xb8\x05\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x12\x8b\x90\x8f\xe7C\xa44 =\xe2\x94\xc4A\xc7\xe2\n\x86\xeag\x89&\xab\x14\xe0\xc0\xe1<\x00\x00\xe0\x94\x12\x93\u01cc}jD;\x9dt\xb0\xba^\xe7\xbbG\xfdA\x85\x88\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\x12\x96\xac\xde\xd1\xe0c\xaf9\xfe\x8b\xa0\xb4\xb6=\xf7\x89\xf7\x05\x17\x89\x05k\xf9\x1b\x1ae\xeb\x00\x00\u07d4\x12\xaa}\x86\xdd\xfb\xad0\x16\x92\xfe\xac\x8a\b\xf8A\xcb!\\7\x89\amA\xc6$\x94\x84\x00\x00\xe0\x94\x12\xaf\xbc\xba\x14'\xa6\xa3\x9e{\xa4\x84\x9fz\xb1\xc45\x8a\xc3\x1b\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x12\xb5\xe2\x89E\xbb)i\xf9\xc6Lc\xcc\x05\xb6\xf1\xf8\xd6\xf4\u054a\x01\xa2\x9e\x86\x91;t\x05\x00\x00\u0794\x12\u03cb\x0eFR\x13!\x1a[S\u07f0\xdd'\x1a(,\x12\u0248\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x12\xd2\a\x90\xb7\xd3\xdb\u060c\x81\xa2y\xb8\x12\x03\x9e\x8a`;\u0409V\xf9\x85\u04c6D\xb8\x00\x00\xe0\x94\x12\xd6\re\xb7\xd9\xfcH\x84\v\xe5\xf8\x91\xc7E\xcev\xeeP\x1e\x8a\x04\x85\xe58\x8d\fv\x84\x00\x00\u0794\x12\xd9\x1a\x92\xd7O\xc8a\xa7)dm\xb1\x92\xa1%\xb7\x9fSt\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\x12\u992d*\xd5t\x84\xddp\x05e\xbd\xdbFB;\u067d1\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x12\xf3,\n\x1f-\xaa\xb6v\xfei\xab\xd9\xe0\x185-L\xcdE\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x12\xf4`\xaedl\xd2x\x0f\xd3\\P\xa6\xafK\x9a\xcc\xfa\x85\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x12\xff\xc1\x12\x86\x05\xcb\f\x13p\x9ar\x90Po&\x90\x97q\x93\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x13\x03$F\xe7\xd6\x10\xaa\x00\xec\x8cV\u0275t\xd3l\xa1\xc0\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\x1cy,\x19}\x18\xbd\x04]p$\x93|\x1f\x84\xb6\x0fD8\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13\x1d\xf8\xd30\xeb|\xc7\x14}\nUWo\x05\u078d&\xa8\xb7\x89\n1\x06+\xee\xedp\x00\x00\u07d4\x13\x1f\xae\xd1%a\xbbz\xee\x04\xe5\x18Z\xf8\x02\xb1\xc3C\x8d\x9b\x89\v\xdf\x0e\u0733\x90\xc9\xc8V\b\xb7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13!\xcc\xf2\x979\xb9t\xe5\xa5\x16\xf1\x8f:\x846q\xe3\x96B\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13'\xd7Y\xd5n\n\xb8z\xf3~\xcfc\xfe\x01\xf3\x10\xbe\x10\n\x89#\xbc<\xdbh\xa1\x80\x00\x00\u07d4\x13)\xdd\x19\xcdK\xaa\x9f\xc6C\x10\xef\xec\xea\xb2!\x17%\x1f\x12\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x137\x1f\x92\xa5n\xa88\x1eC\x05\x9a\x95\x12\x8b\xdcMC\u0166\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x13O\x15\xe1\xe3\x9cSCY0\xaa\xed\xf3\xe0\xfeV\xfd\xe8C\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x13Ac\xbe\x9f\xbb\xe1\xc5in\xe2U\xe9\v\x13%C\x95\xc3\x18\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x13\\\xec\xd9U\xe5y\x83pv\x920\x15\x93\x03\u0671\x83\x9ff\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x13]\x17\x19\xbf\x03\xe3\xf8f1$y\xfe3\x81\x18\xcd8~p\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x13^\xb8\xc0\xe9\xe1\x01\xde\xed\xec\x11\xf2\xec\xdbf\xae\x1a\xae\x88g\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x13`\xe8}\xf2Li\xeemQ\xc7nsv\u007f\xfe\x19\xa2\x13\x1c\x89\x04\xfc\xc1\xa8\x90'\xf0\x00\x00\u07d4\x13l\x83K\xf1\x112m s\x95)[.X>\xa7\xf35r\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x13mKf+\xbd\x10\x80\xcf\xe4D[\x0f\xa2\x13\x86D5\xb7\xf1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13oI\a\u02b4\x1e'\bK\x98E\x06\x9f\xf2\xfd\f\x9a\xdey\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13t\xfa\xcd{?\x8dhd\x9d`\xd4U\x0e\xe6\x9f\xf0HA3\x89\x0e\x9e\xd6\xe1\x11r\xda\x00\x00\u07d4\x13|\xf3A\xe8Ql\x81X\x14\xeb\xcds\xe6V\x9a\xf1L\xf7\xbc\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x13\x84\x8bF\xeau\xbe\xb7\xea\xa8_Y\xd8f\xd7\u007f\xd2L\xf2\x1a\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x13\x9d51\u0252*\xd5bi\xf60\x9a\xa7\x89\xfb$\x85\xf9\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x13\x9eG\x97d\xb4\x99\xd6f \x8cJ\x8a\x04z\x97\x041c\u0749 w!*\xffm\xf0\x00\x00\u07d4\x13\xa5\xee\xcb80]\xf9Iq\xef-\x9e\x17\x9a\xe6\u03ba\xb37\x89\x11\u3ac3\x95\xc6\xe8\x00\x00\u07d4\x13\xac\xad\xa8\x98\n\xff\xc7PI!\xbe\x84\xebID\xc8\xfb\xb2\xbd\x89V\u04aa:\\\t\xa0\x00\x00\u07d4\x13\xb9\xb1\a\x15qL\t\xcf\xd6\x10\u03dc\x98F\x05\x1c\xb1\xd5\x13\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x13\xce3-\xffe\xa6\xab\x938\x97X\x8a\xa2>\x00\t\x80\xfa\x82\x89\x0e\x02\x056\xf0(\xf0\x00\x00\u07d4\x13\xd6z~%\xf2\xb1,\u06c5XP\t\xf8\xac\u011b\x96s\x01\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x13\xde\xe0>7\x99\x95-\a8\x84=K\xe8\xfc\n\x80?\xb2\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\xe0/\xb4H\xd6\xc8J\xe1}\xb3\x10\xad(m\x05a`\u0695\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x13\xe3!r\x8c\x9cWb\x80X\xe9?\xc8f\xa02\xdd\v\u0690\x89&\xbc\xca#\xfe.\xa2\x00\x00\u07d4\x13\xec\x81\"\x84\x02n@\x9b\xc0f\xdf\xeb\xf9\u0564\xa2\xbf\x80\x1e\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\x14\x01)\xea\xa7f\xb5\xa2\x9f[:\xf2WND\t\xf8\xf6\xd3\xf1\x8a\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u07d4\x14\x05\x18\xa3\x19K\xad\x13P\xb8\x94\x9ee\x05e\u07bem\xb3\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x14\x06\x85M\x14\x9e\b\x1a\xc0\x9c\xb4\xcaV\r\xa4c\xf3\x120Y\x89Hz\x9a0E9D\x00\x00\u07d4\x14\f\xa2\x8f\xf3;\x9ff\xd7\xf1\xfc\x00x\xf8\xc1\xee\xf6\x9a\x1b\xc0\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x14\x0f\xbaX\xdb\xc0H\x03\xd8L!0\xf0\x19x\xf9\xe0\xc71)\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\x14\x1a^9\xee/h\n`\x0f\xbfo\xa2\x97\u0790\xf3\"\\\u074a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x14%N\xa1&\xb5-\x01B\xda\n~\x18\x8c\xe2U\xd8\xc4qx\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\x14+\x87\xc5\x04?\xfbZ\x91\xdf\x18\xc2\xe1\t\xce\xd6\xfeJq\u06c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x14\x87\xf5\xa5$\u0288Q^\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4\x14\xa75 f6D\x04\xdbP\xf0\xd0\u05cduJ\"\x19\x8e\xf4\x89e\xea=\xb7UF`\x00\x00\u07d4\x14\xab\x16K;RL\x82\u05ab\xfb\xc0\u0783\x11&\xae\x8d\x13u\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x14\xb1`>\xc6+ \x02 3\xee\xc4\xd6\xd6eZ\xc2J\x01Z\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x14\xc6;\xa2\u0731\xddM\xf3=\u06b1\x1cO\x00\a\xfa\x96\xa6-\x8a\x03HA\xb6\x05z\xfa\xb0\x00\x00\xe0\x94\x14\xcd\u077c\x8b\t\xe6gZ\x9e\x9e\x05\t\x1c\xb9\"8\u00de\x1e\x8a\x01\x14x\xb7\xc3\n\xbc0\x00\x00\u07d4\x14\xd0\n\xad9\xa0\xa7\u045c\xa0SP\xf7\xb07'\xf0\x8d\xd8.\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x14\xee\xc0\x9b\xf0>5+\xd6\xff\x1b\x1e\x87k\xe6d\xce\xff\xd0\u03c9\x01\x16\xdc:\x89\x94\xb3\x00\x00\u07d4\x14\xf2!\x15\x95\x18x;\u0127\x06go\xc4\xf3\xc5\xee@X)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x14\xfc\xd19\x1e}s/Avl\xda\u0344\xfa\x1d\xeb\x9f\xfd\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x0e=\xbc\xbc\xfc\x84\xcc\xf8\x9bsBwc\xa5e\xc2>`\u0409\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\x15\x18b{\x885\x1f\xed\xe7\x96\xd3\xf3\b3d\xfb\u0508{\f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u0794\x15\"J\xd1\xc0\xfa\xceF\xf9\xf5V\xe4wJ0%\xad\x06\xbdR\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x15/+\xd2)\xdd\xf3\xcb\x0f\xda\xf4U\xc1\x83 \x9c\x0e\x1e9\xa2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x15/N\x86\x0e\xf3\xee\x80jP'w\xa1\xb8\xdb\xc9\x1a\x90vh\x89 \x86\xac5\x10R`\x00\x00\u07d4\x15<\b\xaa\x8b\x96\xa6\x11\xefc\xc0%>*C4\x82\x9eW\x9d\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\x15<\xf2\x84,\xb9\u0787l'o\xa6Gg\u0468\xec\xf5s\xbb\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15>\xf5\x8a\x1e.z>\xb6\xb4Y\xa8\n\xb2\xa5G\xc9A\x82\xa2\x8a\x14T+\xa1*3|\x00\x00\x00\u07d4\x15DY\xfa/!1\x8e44D\x97\x89\xd8&\xcd\xc1W\f\xe5\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15G\xb9\xbfz\xd6bt\xf3A8'#\x1b\xa4\x05\ue308\xc1\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\x15H\xb7p\xa5\x11\x8e\u0787\u06e2\xf6\x903\u007fam\u60eb\x89\x1c\x99V\x85\u0fc7\x00\x00\u07d4\x15R\x83P\xe0\xd9g\n.\xa2\u007f{J3\xb9\xc0\xf9b\x1d!\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x15[7y\xbbmV4./\u0681{[-\x81\xc7\xf4\x13'\x89\x02\xb8\xaa:\al\x9c\x00\x00\u07d4\x15e\xaf\x83~\xf3\xb0\xbdN+#V\x8dP#\xcd4\xb1d\x98\x89\x15Q\xe9rJ\u013a\x00\x00\u07d4\x15f\x91\x80\xde\u2558\x86\x9b\b\xa7!\xc7\xd2LL\x0e\xe6?\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x15r\xcd\xfa\xb7*\x01\u0396\x8ex\xf5\xb5D\x8d\xa2\x98S\xfb\u074a\x01\x12blI\x06\x0f\xa6\x00\x00\xe0\x94\x15uY\xad\xc5Wd\xccm\xf7\x93#\t%4\xe3\xd6dZf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x15x\xbd\xbc7\x1bM$8E3\x05V\xff\xf2\xd5\xefM\xffg\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x15~\xb3\xd3\x11;\u04f5\x97qM:\x95N\xdd\x01\x89\x82\xa5\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x84\xa2\xc0f\xb7\xa4U\xdb\u05ae(\a\xa73N\x83\xc3_\xa5\x89\a\f\x1c\xc7;\x00\xc8\x00\x00\u07d4\x15\x87F\x86\xb6s=\x10\xd7\x03\xc9\xf9\xbe\xc6\xc5.\xb8b\x8dg\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x15\x8a\ra\x92S\xbfD2\xb5\xcd\x02\u01f8b\xf7\u00b7V6\x89\a[\xac|[\x12\x18\x80\x00\u07d4\x15\x98\x12y\x82\xf2\xf8\xad;k\x8f\xc3\xcf'\xbfax\x01\xba+\x89\t`\xdbwh\x1e\x94\x00\x00\xe0\x94\x15\x9a\xdc\xe2z\xa1\vG#d)\xa3JZ\xc4,\xad[d\x16\x8a\x06\xbf\x90\xa9n\xdb\xfaq\x80\x00\u07d4\x15\xa0\xae\xc3\u007f\xf9\xff=T\t\xf2\xa4\xf0\xc1!*\xac\xcb\x02\x96\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x15\xaaS\r\xc3iX\xb4\xed\xb3\x8e\xeem\xd9\xe3\xc7}L\x91E\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15\xac\xb6\x15h\xecJ\xf7\xea(\x198a\x81\xb1\x16\xa6\xc5\xeep\x8a\x06\x90\x83l\n\xf5\xf5`\x00\x00\u07d4\x15\xb9o0\xc2;\x86d\xe7I\x06Q\x06k\x00\xc49\x1f\xbf\x84\x89\x16B\xe9\xdfHv)\x00\x00\u07d4\x15\xc7\xed\xb8\x11\x8e\xe2{4\"\x85\xebY&\xb4z\x85[\u01e5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x15\u0654hPz\xa0A?\xb6\r\xca*\xdc\u007fV\x9c\xb3kT\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x15\u06f4\x8c\x980\x97d\xf9\x9c\xed6\x92\xdc\xca5\xee0k\xac\x8a\x1f\u00c4+\xd1\xf0q\xc0\x00\x00\xe0\x94\x15\u072f\xcc+\xac\xe7\xb5[T\xc0\x1a\x1cQF&\xbfa\xeb\u060a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x15\u3d44\x05kb\xc9s\xcf^\xb0\x96\xf1s>T\xc1\\\x91\x892\xc7Z\x02#\xdd\xf3\x00\x00\u07d4\x15\xeb\xd1\xc7\xca\u04af\xf1\x92u\xc6W\xc4\xd8\b\xd0\x10\xef\xa0\xf5\x89\n\xdf0\xbap\u0217\x00\x00\u07d4\x15\xee\x0f\xc6>\xbf\x1b\x1f\u011d{\xb3\x8f\x88c\x82:.\x17\u0489g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x15\xf1\xb3R\x11\rh\x90\x1d\x8fg\xaa\xc4jl\xfa\xfe\x03\x14w\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x15\xf2\xb7\xb1d2\xeeP\xa5\xf5[A#/c4\xedX\xbd\xc0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x16\x01\x9aM\xaf\xabC\xf4\u067fAc\xfa\xe0\x84}\x84\x8a\xfc\xa2\x89\x01[\xc7\x019\xf7J\x00\x00\u07d4\x16\x02&\xef\xe7\xb5:\x8a\xf4b\xd1\x17\xa0\x10\x80\x89\xbd\xec\xc2\u0449\n\xdf0\xbap\u0217\x00\x00\u07d4\x16\f\xebo\x98\x0e\x041_S\xc4\xfc\x98\x8b+\xf6\x9e(M}\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\xe0\x94\x16\x1c\xafZ\x97*\u0383y\xa6\u0420J\xe6\xe1c\xfe!\xdf+\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x16\x1d&\xefgY\xba[\x9f \xfd\xcdf\xf1a2\xc3RA^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16!\x10\xf2\x9e\xac_}\x02\xb5C\xd8\xdc\u057bY\xa5\xe3;s\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x16+\xa5\x03'b\x14\xb5\t\xf9u\x86\xbd\x84!\x10\xd1\x03\xd5\x17\x8a\x01\xe7\xff\u0609\\\"h\x00\x00\u07d4\x16-v\xc2\xe6QJ:\xfbo\xe3\xd3\u02d3\xa3\\Z\xe7\x83\xf1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16;\xadJ\x12+E}d\xe8\x15\nA>\xaeM\a\x02>k\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u07d4\x16<\u023e\"vF\xcb\tq\x91Y\xf2\x8e\u041c]\xc0\xdc\xe0\x89Hz\x9a0E9D\x00\x00\u07d4\x16=\xcas\xd7\xd6\xea?>`b2*\x874\x18\f\vx\uf25ft \x03\xcb}\xfc\x00\x00\u07d4\x16Mz\xac>\xec\xba\uc86dQ\x91\xb7S\xf1s\xfe\x12\xec3\x89(VR\xb8\xa4hi\x00\x00\u07d4\x16Rl\x9e\u07d4>\xfaOm\x0f\v\xae\x81\xe1\x8b1\xc5@y\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x16S\x05\xb7\x872.%\xdcj\xd0\xce\xfelo3Fx\xd5i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16e\xab\x179\xd7\x11\x19\xeea2\xab\xbd\x92j'\x9f\xe6yH\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x16k\xf6\u06b2-\x84\x1bHl8\xe7\xbaj\xb3:\x14\x87\ud30a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x16v\x99\xf4\x8ax\xc6\x15Q%\x15s\x99X\x993\x12WO\a\x89\x02\x1d;\xd5^\x80<\x00\x00\u07d4\x16x\xc5\xf2\xa5\"92%\x19ca\x89OS\xccu/\xe2\xf3\x89h\xf3e\xae\xa1\xe4@\x00\x00\u07d4\x16|\xe7\xdee\xe8G\bYZRT\x97\xa3\xeb^ZfPs\x89\x1f1Gsfo\xc4\x00\x00\u07d4\x16~>:\xe2\x003HE\x93\x92\xf7\xdf\xceD\xaf|!\xadY\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x16\x80\xce\xc5\x02\x1e\xe90P\xf8\xae\x12rQ\x83\x9et\xc1\xf1\xfd\x8a\x02\xc6\x14a\xe5\xd7C\u0580\x00\u07d4\x16\x81j\xac\x0e\xde\r-<\xd4B\xday\xe0c\x88\x0f\x0f\x1dg\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x16\x8bP\x19\xb8\x18i\x16D\x83_\xe6\x9b\xf2)\xe1q\x12\xd5,\x8a\x05\xed\xe2\x0f\x01\xa4Y\x80\x00\x00\u07d4\x16\x8b\xde\xc8\x18\xea\xfcm)\x92\xe5\xefT\xaa\x0e\x16\x01\xe3\xc5a\x8967Pz0\xab\xeb\x00\x00\u07d4\x16\x8d0\xe5?\xa6\x81\t+R\xe9\xba\xe1Z\r\xcbA\xa8\u027b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x16\x9b\xbe\xfcA\xcf\xd7\xd7\u02f8\xdf\xc60 \xe9\xfb\x06\u0515F\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xa5\x8e\x98]\xcc\xd7\a\xa5\x94\u0453\xe7\u0327\x8b]\x02xI\x89I\xb9\u029aiC@\x00\x00\u07d4\x16\xa9\xe9\xb7:\u92c6M\x17(y\x8b\x87f\xdb\xc6\xea\x8d\x12\x893\xe7\xb4K\r\xb5\x04\x00\x00\u07d4\x16\xaaR\xcb\vUG#\xe7\x06\x0f!\xf3'\xb0\xa6\x83\x15\xfe\xa3\x89\r\x8drkqw\xa8\x00\x00\u07d4\x16\xab\xb8\xb0!\xa7\x10\xbd\u01ce\xa54\x94\xb2\x06\x14\xffN\xaf\xe8\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x16\xaf\xa7\x87\xfc\x9f\x94\xbd\xffiv\xb1\xa4/C\n\x8b\xf6\xfb\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xba\xe5\xd2N\xff\x91w\x8c\u064bM:\x1c\xc3\x16/D\xaaw\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\x16\xbc@!Z\xbb\u066e](\v\x95\xb8\x01\vE\x14\xff\x12\x92\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x16\xbeu\u9299Z9R\"\xd0\v\u05df\xf4\xb6\xe68\u144a\a\x9f\x90\\o\xd3N\x80\x00\x00\u07d4\x16\xc1\xbf[}\xc9\xc8<\x17\x9e\xfa\xcb\xcf.\xb1t\xe3V\x1c\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x16\u01f3\x1e\x8c7b\x82\xac\"qr\x8c1\xc9^5\xd9R\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xf3\x13\u03ca\xd0\x00\x91J\n\x17m\u01a44+y\xec%8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x16\xff\xac\x84\x03)@\xf0\x12\x1a\tf\x8b\x85\x8a~y\xff\xa3\xbb\x89\xd2J\xdan\x10\x87\x11\x00\x00\xe0\x94\x17\x03\xb4\xb2\x92\xb8\xa9\xde\xdd\xed\xe8\x1b\xb2]\x89\x17\x9fdF\xb6\x8a\x04+e\xa4U\xe8\xb1h\x00\x00\u07d4\x17\x04\x93\x11\x10\x1d\x81~\xfb\x1de\x91\x0ff6b\xa6\x99\u024c\x89lh\xcc\u041b\x02,\x00\x00\u07d4\x17\x04\xce\xfc\xfb\x131\xeczx8\x8b)9>\x85\xc1\xafy\x16\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17\n\x88\xa8\x99\u007f\x92\xd287\x0f\x1a\xff\xde\xe64pP\xb0\x13\x89\xa2\xacw5\x14\x880\x00\x00\u07d4\x17\x10\x8d\xab,P\xf9\x9d\xe1\x10\u1cf3\xb4\u0342\xf5\xdf(\xe7\x895 ;g\xbc\xca\xd0\x00\x00\xe0\x94\x17\x12[Y\xacQ\xce\xe0)\xe4\xbdx\xd7\xf5\x94}\x1e\xa4\x9b\xb2\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4\x17\x1a\u0660K\xed\u0238a\xe8\xedK\xdd\xf5qx\x13\xb1\xbbH\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17\x1c\xa0*\x8bmb\xbfL\xa4~\x90i\x14\a\x98a\x97,\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x17\"\xc4\xcb\xe7\n\x94\xb6U\x9dBP\x84\xca\xee\xd4\xd6\xe6n!\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x17X\vvotSR\\\xa4\u01a8\x8b\x01\xb5\x05p\xea\b\x8c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x17X\x9al\x00jT\xca\xd7\x01\x03\x12:\xae\n\x82\x13_\u07b4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x17Z\x18::#_\xfb\xb0;\xa85gRg\"\x94\x17\xa0\x91\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x17_\xee\xea*\xa4\xe0\xef\xda\x12\xe1X\x8d/H2\x90\xed\xe8\x1a\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x17e6\x1c.\xc2\xf86\x16\u0383c\xaa\xe2\x10%\xf2Vo@\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x17gR\\_Z\"\xed\x80\xe9\xd4\xd7q\x0f\x03b\u049e\xfa3\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x17v%`\xe8*\x93\xb3\xf5\"\xe0\xe5$\xad\xb8a,:tp\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x17}\xaex\xbc\x01\x13\xd8\u04dcD\x02\xf2\xa6A\xae*\x10Z\xb8\x89b\x92BV \xb4H\x00\x00\xe0\x94\x17\x84\x94\x8b\xf9\x98H\u021eDV8PM\u0598'\x1bY$\x8a\x01GLA\r\x87\xba\xee\x00\x00\u07d4\x17\x88\u069bW\xfd\x05\xed\xc4\xff\x99\xe7\xfe\xf3\x01Q\x9c\x8a\n\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\x8e\xafk\x85T\xc4]\xfd\xe1kx\xce\f\x15\u007f.\xe3\x13Q\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\x17\x96\x1dc;\xcf \xa7\xb0)\xa7\xd9K}\xf4\xda.\xc5B\u007f\x89\fo\xf0p\U000532c0\x00\u07d4\x17\x96\xbc\xc9{\x8a\xbcq\u007fKJ|k\x106\xea!\x82c\x9f\x89\x13A\xf9\x1c\xd8\xe3Q\x00\x00\u07d4\x17\x99=1*\xa1\x10iW\x86\x8fjU\xa5\xe8\xf1/w\xc8C\x89\x18e\xe8\x14\xf4\x14.\x80\x00\u07d4\x17\x9a\x82^\x0f\x1fn\x98S\tf\x84e\xcf\xfe\xd46\xf6\xae\xa9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x17\xb2\xd6\xcfe\xc6\xf4\xa3G\xdd\xc6W&U5M\x8aA+)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xb8\a\xaf\xa3\xdd\xd6G\xe7#T.{R\xfe\xe3\x95'\xf3\x06\x89\x15\xaf@\xff\xa7\xfc\x01\x00\x00\u07d4\x17\xc0G\x86W\xe1\xd3\xd1z\xaa3\x1d\xd4)\xce\u03d1\xf8\xae]\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\x17\xc0\xfe\xf6\x98l\xfb.@A\xf9\x97\x9d\x99@\xb6\x9d\xff=\xe2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x17\u0511\x8d\xfa\xc1]w\xc4\u007f\x9e\xd4\x00\xa8P\x19\rd\xf1Q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xd5!\xa8\xd9w\x90#\xf7\x16M#<;d \xff\xd2#\xed\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x17\xd91\xd4\xc5b\x94\u073ew\xc8e[\xe4i_\x00mJ<\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xdfIQ\x8ds\xb1)\xf0\xda6\xb1\u0274\f\xb6d \xfd\u01ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x17\xe4\xa0\xe5+\xac>\xe4N\xfe\tT\xe7S\u0538]dN\x05\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xe5\x84\xe8\x10\xe5gp,a\xd5]CK4\u0375\xee0\xf6\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x17\xe8.px\xdcO\xd9\xe8y\xfb\x8aPf\u007fS\xa5\xc5E\x91\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x17\xe8o;[0\xc0\xbaY\xf2\xb2\xe8XB[\xa8\x9f\n\x10\xb0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x17\xee\x9fT\xd4\xdd\xc8Mg\x0e\xff\x11\xe5Je\x9f\xd7/DU\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94\x17\xefJ\xcc\x1b\xf1G\xe3&t\x9d\x10\xe6w\xdc\xff\xd7o\x9e\x06\x8a\bwQ\xf4\xe0\xe1\xb50\x00\x00\u07d4\x17\xf1F2\xa7\xe2\x82\v\xe6\xe8\xf6\u07c25X(=\xad\xab-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x17\xf5#\xf1\x17\xbc\x9f\xe9x\xaaH\x1e\xb4\xf5V\x17\x117\x1b\u0209li\xf7>)\x13N\x00\x00\u07d4\x17\xfd\x9bU\x1a\x98\xcba\xc2\xe0\u007f\xbfA\xd3\xe8\u02650\u02e5\x89\x01v\x8c0\x81\x93\x04\x80\x00\u07d4\x18\x04x\xa6U\u05cd\x0f;\fO +aH[\xc4\x00/\u0549lk\x93[\x8b\xbd@\x00\x00\u07d4\x18\x13l\x9d\xf1g\xaa\x17\xb6\xf1\x8e\"\xa7\x02\u020fK\u0082E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x18\x15'\x9d\xff\x99R\xda;\xe8\xf7rI\xdb\xe2\"C7{\xe7\x8a\x01\x01|\xb7n{&d\x00\x00\u07d4\x18\x1f\xbb\xa8R\xa7\xf5\x01x\xb1\xc7\xf0>\xd9\xe5\x8dT\x16))\x89$\x1a\x9bOaz(\x00\x00\xe0\x94\x18'\x03\x9f\tW\x02\x94\b\x8f\xdd\xf0G\x16\\3\u65a4\x92\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\x18-\xb8R\x93\xf6\x06\u8248\xc3pL\xb3\xf0\xc0\xbb\xbf\xcaZ\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x18H\x00<%\xbf\u052a\x90\xe7\xfc\xb5\u05f1k\xcd\f\xff\xc0\u060965\u026d\xc5\u07a0\x00\x00\xe0\x94\x18JO\v\xebq\xff\xd5X\xa6\xb6\xe8\xf2(\xb7\x87\x96\xc4\xcf>\x8a\x02\x8a\x85t%Fo\x80\x00\x00\xe0\x94\x18M\x86\xf3Fj\xe6h;\x19r\x99\x82\xe7\xa7\u1903G\xb2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x18Q\xa0c\xcc\xdb0T\x90w\xf1\xd19\xe7-\xe7\x97\x11\x97\u0549lk\x93[\x8b\xbd@\x00\x00\u07d4\x18UF\xe8v\x8dPhs\x81\x8a\xc9u\x1c\x1f\x12\x11j;\xef\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x18X\xcf\x11\xae\xa7\x9fS\x98\xad+\xb2\"g\xb5\xa3\xc9R\xeat\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\xe0\x94\x18Z\u007f\u012c\xe3h\xd23\xe6 \xb2\xa4Y5f\x12\x92\xbd\xf2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x18d\xa3\u01f4\x81UD\x8cT\u020cp\x8f\x16g\tsm1\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x18j\xfd\xc0\x85\xf2\xa3\xdc\xe4a^\xdf\xfb\xad\xf7\x1a\x11x\x0fP\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x18k\x95\xf8\xe5\xef\xfd\xdc\xc9O\x1a1[\xf0)];\x1e\xa5\x88\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x18}\x9f\f\a\xf8\xebt\xfa\xaa\xd1^\xbc{\x80Dt\x17\xf7\x82\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x18\x95\xa0\xebJCrr/\xcb\u016f\xe6\x93o(\x9c\x88\xa4\x19\x891T\xc9r\x9d\x05x\x00\x00\u07d4\x18\x99\xf6\x9fe;\x05\xa5\xa6\xe8\x1fH\a\x11\u041b\xbf\x97X\x8c\x89i\xfb\x13=\xf7P\xac\x00\x00\u07d4\x18\xa6\xd2\xfcR\xbes\b@#\xc9\x18\x02\xf0[\xc2JK\xe0\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x18\xb0@|\xda\xd4\xceR`\x06#\xbd^\x1fj\x81\xaba\xf0&\x89\x11Q\xcc\xf0\xc6T\u0180\x00\u07d4\x18\xb8\xbc\xf9\x83!\xdaa\xfbN>\xac\xc1\xecT\x17'-\xc2~\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\x18\xc6r:gS)\x9c\xb9\x14G}\x04\xa3\xbd!\x8d\xf8\xc7u\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x18\xe1\x13\xd8\x17|i\x1aa\xbexXR\xfa[\xb4z\uef6f\x89Hz\x9a0E9D\x00\x00\xe0\x94\x18\xe4\xceGH;S\x04\n\u06eb5\x17,\x01\xefdPn\f\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\xe0\x94\x18\xe52C\x98\x1a\xab\xc8v}\xa1\fsD\x9f\x13\x91V\x0e\xaa\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x18\xfa\x86%\xc9\u0704>\x00\x15\x9e\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94\x193\xe34\xc4\x0f:\u02ed\f\v\x85\x11X i$\xbe\xca:\x8a\x01\x99^\xaf\x01\xb8\x96\x18\x80\x00\xe0\x94\x197\xc5\xc5\x15\x05uS\u033dF\u0546dU\xcef)\x02\x84\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u07d4\x19:\xc6Q\x83e\x18\x00\xe25\x80\xf8\xf0\xea\u04fbY~\xb8\xa4\x89\x02\xb6*\xbc\xfb\x91\n\x00\x00\u07d4\x19=7\xed4}\x1c/N55\r\x9aDK\xc5|\xa4\xdbC\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\x19@\u0713d\xa8R\x16_GAN'\xf5\x00$E\xa4\xf1C\x8a\x02L-\xffj<|H\x00\x00\u07d4\x19E\xfe7\u007f\xe6\u0537\x1e>y\x1fo\x17\xdb$<\x9b\x8b\x0f\x89vy\u7fb9\x886\x00\x00\u07d4\x19Jk\xb3\x02\xb8\xab\xa7\xa5\xb5y\u07d3\xe0\xdf\x15t\x96v%\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x19L\ubd12\x98\x82\xbf;K\xf9\x86L+\x1b\x0fb\u0083\xf9\x89\x1e\xf8aS\x1ft\xaa\x00\x00\u07d4\x19O\xf4J\xef\xc1{\xd2\x0e\xfdz LG\xd1b\f\x86\xdb]\x89\xa2\x99\th\u007fj\xa4\x00\x00\xe0\x94\x19O\xfex\xbb\xf5\xd2\r\u044a\x1f\x01\xdaU.\x00\xb7\xb1\x1d\xb1\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x19S1>*\xd7F#\x9c\xb2'\x0fH\xaf4\u063b\x9cDe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19W\x1a+\x8f\x81\u01bc\xf6j\xb3\xa1\x00\x83)V\x17\x15\x00\x03\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\xe0\x94\x19h}\xaa9\xc3h\x13\x9bn{\xe6\r\xc1u:\x9f\f\xbe\xa3\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x19l\x02!\nE\n\xb0\xb3cpe_qz\xa8{\xd1\xc0\x04\x89\x0e\x10\xac\xe1W\xdb\xc0\x00\x00\u07d4\x19n\x85\xdf~s+J\x8f\x0e\xd06#\xf4\u06dd\xb0\xb8\xfa1\x89\x01%\xb9/\\\xef$\x80\x00\u07d4\x19s+\xf9s\x05]\xbd\x91\xa4S:\u06a2\x14\x9a\x91\u04c3\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19vr\xfd9\xd6\xf2F\xcef\xa7\x90\xd1:\xa9\"\xd7\x0e\xa1\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x19y\x8c\xbd\xa7\x15\ua69b\x9dj\xab\x94,U\x12\x1e\x98\xbf\x91\x89A\rXj \xa4\xc0\x00\x00\u07d4\x19\x8b\xfc\xf1\xb0z\xe3\b\xfa,\x02\x06\x9a\xc9\xda\xfeq5\xfbG\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x19\x8e\xf1\xec2Z\x96\xcc5Lrf\xa08\xbe\x8b\\U\x8fg\x8a\x80\xd1\xe47>\u007f!\xda\x00\x00\xe0\x94\x19\x91\x8a\xa0\x9e}IN\x98\xff\xa5\xdbP5\b\x92\xf7\x15j\u018a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x19\xb3k\f\x87\xeafN\xd8\x03\x18\xdcw\xb6\x88\xdd\xe8}\x95\xa5\x89i\x9fI\x98\x020=\x00\x00\u07d4\x19\u07d4E\xa8\x1c\x1b=\x80J\xea\xebon NB6f?\x89\x02\x06\xd9NjI\x87\x80\x00\u07d4\x19\xe5\u07a37\n,tj\xae4\xa3|S\x1fA\xda&N\x83\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x19\xe7\xf3\xeb{\xf6\u007f5\x99 \x9e\xbe\b\xb6*\xd32\u007f\x8c\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\x19\xe9Nb\x00P\xaa\xd7f\xb9\xe1\xba\xd91#\x83\x12\u053fI\x89\x81\xe3-\xf9r\xab\xf0\x00\x00\u07d4\x19\xec\xf2\xab\xf4\f\x9e\x85{%/\xe1\xdb\xfd=L]\x8f\x81n\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x19\xf5\xca\xf4\xc4\x0ei\b\x81<\aE\xb0\xae\xa9Xm\x9d\xd91\x89#\xfe\xd9\xe1\xfa+`\x00\x00\u07d4\x19\xf6C\xe1\xa8\xfa\x04\xae\x16\x00`(\x13\x833\xa5\x9a\x96\u0787\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x19\xf9\x9f,\vF\u0389\x06\x87]\xc9\xf9\n\xe1\x04\xda\xe3U\x94\x89\xf4WZ]M\x16*\x00\x00\u07d4\x19\xff$O\xcf\xe3\xd4\xfa/O\u065f\x87\xe5[\xb3\x15\xb8\x1e\xb6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1a\x04\xce\xc4 \xadC\"\x15$mw\xfe\x17\x8d3\x9e\u0435\x95\x89\x11!a\x85\u009fp\x00\x00\xe0\x94\x1a\x04\xd58\x9e\xb0\x06\xf9\u0388\f0\xd1SS\xf8\xd1\x1cK1\x8a\x03\x9d\x84\xb2\x18m\xc9\x10\x00\x00\u07d4\x1a\bA\xb9*\u007fpuV\x9d\xc4b~kv\u02b0Z\u0791\x89Rf<\u02b1\xe1\xc0\x00\x00\xe0\x94\x1a\b]C\xec\x92AN\xa2{\x91O\xe7g\xb6\xd4k\x1e\xefD\x8a\x06A\xe8\xa15c\xd8\xf8\x00\x00\u07d4\x1a\t\xfd\xc2\u01e2\x0e#WK\x97\u019e\x93\u07bag\xd3r \x89lO\xd1\xee$nx\x00\x00\u07d4\x1a\n\x1d\u07f01\xe5\xc8\xcc\x1dF\xcf\x05\x84-P\xfd\xdcq0\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1a\x1c\x9a&\xe0\xe0$\x18\xa5\xcfh}\xa7Z'\\b,\x94@\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x1a \x1bC'\u03a7\xf3\x99\x04bF\xa3\xc8~n\x03\xa3\u0368\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a$4\xccwD\"\u050dS\u055c]V,\u0384\a\xc9K\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\x1a%\xe1\u017c~_P\xec\x16\xf8\x88_!\x0e\xa1\xb98\x80\x0e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x1a&\x94\xec\a\xcf^Mh\xba@\xf3\xe7\xa1LS\xf3\x03\x8cn\x8966\xcd\x06\xe2\xdb:\x80\x00\u07d4\x1a5 E5\x82\xc7\x18\xa2\x1cB7[\xc5\as%RS\xe1\x89*\xd3s\xcef\x8e\x98\x00\x00\xe0\x94\x1a7n\x1b-/Y\ai\xbb\x85\x8dEu2\rN\x14\x99p\x8a\x01\x06q%v9\x1d\x18\x00\x00\u07d4\x1a:3\x0eO\xcbi\xdb\xef^i\x01x;\xf5\x0f\xd1\xc1SB\x89\u3bb5sr@\xa0\x00\x00\u07d4\x1aN\u01a0\xae\u007fZ\x94'\xd2=\xb9rL\r\f\xff\xb2\xab/\x89\t\xb4\x1f\xbf\x9e\n\xec\x00\x00\u07d4\x1aP^b\xa7N\x87\xe5wG>O:\xfa\x16\xbe\xdd<\xfaR\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x1a^\xe53\xac\xbf\xb3\xa2\xd7m[hRw\xb7\x96\xc5j\x05+\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1adJP\xcb\u00ae\xe8#\xbd+\xf2C\xe8%\xbeMG\xdf\x02\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\x1apD\xe28?\x87\b0[I[\xd1\x17k\x92\xe7\xef\x04:\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1ay\xc7\xf4\x03\x9cg\xa3\x9du\x13\x88L\xdc\x0e,4\"$\x90\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1a\x89\x89\x9c\xbe\xbd\xbbd\xbb&\xa1\x95\xa6<\bI\x1f\u035e\xee\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1a\x8a\\\xe4\x14\u079c\xd1r\x93~7\xf2\u055c\xffq\xceW\xa0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1a\x95\xa8\xa8\b.FR\xe4\x17\r\xf9'\x1c\xb4\xbbC\x05\xf0\xb2\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x1a\x95\u0277Tk]\x17\x86\u00c5\x8f\xb1#dF\xbc\f\xa4\u0389j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1a\x98~?\x83\xdeu\xa4/\x1b\xde|\x99|\x19!{J_$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1a\x9ep/8]\xcd\x10^\x8b\x9f\xa4(\xee\xa2\x1cW\xffR\x8a\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1a\xa1\x02\x1fU\n\xf1X\xc7Gf\x8d\xd1;F1`\xf9Z@\x89O\xb0Y\x1b\x9b08\x00\x00\u07d4\x1a\xa2v\x99\xca\u068d\u00e7oy3\xaaf\xc7\x19\x19\x04\x0e\x88\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x1a\xa4\x02p\xd2\x1e\\\u0786\xb61m\x1a\xc3\xc53IKy\xed\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1a\xb5:\x11\xbc\xc6=\u07ea@\xa0+\x9e\x18d\x96\u037b\x8a\xff\x89l?*\xac\x80\f\x00\x00\x00\u07d4\x1a\xbcN%;\b\n\xebCy\x84\xab\x05\xbc\xa0\x97\x9a\xa4>\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a\xc0\x89\u00fcM\x82\xf0j \x05\x1a\x9ds-\xc0\xe74\xcba\x89%\xf6\x9dc\xa6\xce\x0e\x00\x00\xe0\x94\x1a\xd4V>\xa5xk\xe1\x15\x995\xab\xb0\xf1\u0547\x9c>sr\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1a\xd7- \xa7n\u007f\xcckv@X\xf4\x8dA}Io\xa6\u0349lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1a\xda\xf4\xab\xfa\x86}\xb1\u007f\x99\xafj\xbe\xbfpz<\xf5]\xf6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1a\xf6\x03C6\x0e\v-u%R\x107W \xdf!\xdb\\}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1a\xfc\u0145\x89l\xd0\xed\xe1)\xee-\xe5\xc1\x9e\xa8\x11T\vd\x89\xaf*\xba\f\x8e[\xef\x80\x00\u07d4\x1b\x05\xeajj\u022f|\xb6\xa8\xb9\x11\xa8\xcc\xe8\xfe\x1a*\xcf\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\v1\xaf\xffKm\xf3e:\x94\xd7\xc8yx\xae5\xf3J\xae\x89\x139\x10E?\xa9\x84\x00\x00\u07d4\x1b\r\ah\x17\xe8\u058e\xe2\xdfN\x1d\xa1\xc1\x14-\x19\x8cD5\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\x1b\x13\ro\xa5\x1d\\H\xec\x8d\x1dR\u070a\"{\xe8s\\\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b#\u02c6cUHq\xfb\xbe\r\x9e`9~\xfbo\xae\xdc>\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1b&9X\x8bU\xc3D\xb0#\xe8\xde_\xd4\b{\x1f\x04\x03a\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x1b9 \xd0\x01\xc4>r\xb2N|\xa4o\x0f\xd6\xe0\xc2\n_\xf2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1b<\xb8\x1eQ\x01\x1bT\x9dx\xbfr\v\r\x92J\xc7c\xa7\u008av\x95\xa9, \xd6\xfe\x00\x00\x00\u07d4\x1bC#,\xcdH\x80\xd6\xf4o\xa7Q\xa9l\xd8$s1XA\x89\x04V9\x18$O@\x00\x00\u07d4\x1bK\xbc\xb1\x81e!\x1b&[(\a\x16\xcb?\x1f!!v\xe8\x89\x19\x9a\xd3}\x03\xd0`\x80\x00\u07d4\x1bM\a\xac\u04c1\x83\xa6\x1b\xb2x=+{\x17\x8d\xd5\x02\xac\x8d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1bckzIo\x04MsYYn5:\x10F\x16Cok\x89\x13\x88\xea\x95\xc3?\x1d\x00\x00\u07d4\x1bd\x95\x89\x12@\xe6NYD\x93\xc2f!q\xdb^0\xce\x13\x89\tX\x87\u0595\xedX\x00\x00\u07d4\x1bf\x10\xfbh\xba\xd6\xed\x1c\xfa\xa0\xbb\xe3:$\xeb.\x96\xfa\xfb\x89\b=lz\xabc`\x00\x00\u07d4\x1by\x903\xefm\xc7\x12x\"\xf7EB\xbb\"\xdb\xfc\t\xa3\b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x1b~\xd9t\xb6\xe24\u0381$t\x98B\x9a[\u0520\xa2\xd19\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\x82o\xb3\xc0\x12\xb0\xd1Y\u253a[\x8aI\x9f\xf3\xc0\xe0<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\x8a\xa0\x16\f\u05df\x00_\x88Q\nqI\x13\xd7\n\u04fe3\x89\n\xef\xfb\x83\a\x9a\xd0\x00\x00\xe0\x94\x1b\x8b\xd6\xd2\xec\xa2\x01\x85\xa7\x8e}\x98\xe8\xe1\x85g\x8d\xacH0\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\x1b\x9b-\u0096\x0eL\xb9@\x8ft\x05\x82|\x9bY\a\x16\x12\xfd\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1b\xa9\"\x8d8\x87'\xf3\x89\x15\x0e\xa0;s\xc8-\xe8\xeb.\t\x8a\x01\x89t\xfb\xe1w\xc9(\x00\x00\u07d4\x1b\xa9\xf7\x99~S\x87\xb6\xb2\xaa\x015\xac$R\xfe6\xb4\xc2\r\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\x1b\xba\x03\xffkJ\u057f\x18\x18J\xcb!\xb1\x88\xa3\x99\xe9\xebJ\x89a\t=|,m8\x00\x00\u07d4\x1b\xbc\x19\x9eXg\x90\xbe\x87\xaf\xed\xc8I\xc0G&t\\]{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x1b\xbc`\xbc\xc8\x0e\\\xdc5\xc5Aj\x1f\n@\xa8=\xae\x86{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xc4L\x87a#\x1b\xa1\xf1\x1f_\xaa@\xfaf\x9a\x01>\x12\u0389\v\tR\xc4Z\xea\xad\x00\x00\u07d4\x1b\xcf4A\xa8f\xbd\xbe\x960\t\xce3\xc8\x1c\xbb\x02a\xb0,\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\x1b\u048c\xd5\u01ca\xeeQ5|\x95\xc1\xef\x925\xe7\xc1\x8b\xc8T\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xd8\xeb\xaavt\xbb\x18\u1458\xdb$OW\x03\x13\a_C\x89\b!\xab\rD\x14\x98\x00\x00\u07d4\x1b\xd9\t\xac\rJ\x11\x02\xec\x98\xdc\xf2\u0329j\n\xdc\u05e9Q\x89\x01\x16Q\xac>zu\x80\x00\u07d4\x1b\xe3T,6\x13hte\xf1Zp\xae\xeb\x81f+e\u0328\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1b\xeaM\xf5\x12/\xaf\u07b3`~\xdd\xda\x1e\xa4\xff\u06da\xbf*\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d4\x1b\xecM\x02\u0385\xfcH\xfe\xb6$\x89\x84\x1d\x85\xb1pXj\x9b\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\x1b\xf9t\u0650OE\u0381\xa8E\xe1\x1e\xf4\xcb\xcf'\xafq\x9e\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x1c\x04VI\xcdS\xdc#T\x1f\x8e\xd4\xd3A\x81(\b\xd5\u075c\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x1c\x12\x8b\xd6\u0365\xfc\xa2uu\xe4\xb4;2S\xc8\xc4\x17*\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\x13\u04c67\xb9\xa4|\xe7\x9d7\xa8oP\xfb@\x9c\x06\a(\x89Hz\x9a0E9D\x00\x00\u07d4\x1c \x10\xbdf-\xf4\x17\xf2\xa2q\x87\x9a\xfb\x13\xefL\x88\xa3\xae\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x1c%z\u0525Q\x05\xea;X\xed7K\x19\x8d\xa2f\xc8_c\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x1c.6\a\xe1'\xca\xca\x0f\xbd\\YH\xad\xad}\xd80\xb2\x85\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x1c5l\xfd\xb9_\xeb\xb7\x14c;(\xd5\xc12\u0744\xa9\xb46\x89\x01Z\xf1\u05cbX\xc4\x00\x00\u07d4\x1c5\xaa\xb6\x88\xa0\u034e\xf8.vT\x1b\xa7\xac9R\u007ft;\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x1c>\xf0]\xae\x9d\xcb\u0509\xf3\x02D\bf\x9d\xe2D\xc5*\x02\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x1cJ\xf0\xe8c\xd2el\x865\xbco\xfe\xc8\u0759(\x90\x8c\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c`\x19\x93x\x92\a\xf9e\xbb\x86\\\xbbL\xd6W\xcc\xe7o\xc0\x89\x05T\x1ap7P?\x00\x00\u07d4\x1cc\xfa\x9e,\xbb\xf21a\xda3\xa1\xda}\xf7\r\x1b\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1c\xb6\xb2\xd7\xcf\xc5Y\xb7\xf4\x1eoV\xab\x95\xc7\xc9X\xcd\x0eL\x89Hz\x9a0E9D\x00\x00\u07d4\x1c\xc1\xd3\xc1O\x0f\xb8d\x0e6rM\xc42)\xd2\xeaz\x1eH\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x1c\xc9\bv\x00A\t\xcdy\xa3\u07a8f\u02c4\n\xc3d\xba\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xd1\xf0\xa3\x14\u02f2\x00\xde\n\f\xb1\xef\x97\xe9 p\x9d\x97\u0089lk\x93[\x8b\xbd@\x00\x00\u0794\x1c\xdaA\x1b\xd5\x16;\xae\xca\x1eU\x85c`\x1c\xe7 \xe2N\xe1\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1c\xe8\x1d1\xa7\x920\"\xe1%\xbfH\xa3\xe06\x93\xb9\x8d\xc9\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xeb\xf0\x98]\u007fh\n\xaa\x91\\D\xccb\xed\xb4\x9e\xab&\x9e\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1c\xedg\x15\xf8b\xb1\xff\x86\x05\x82\x01\xfc\xceP\x82\xb3nb\xb2\x8a\x01j^`\xbe\xe2s\xb1\x00\x00\u07d4\x1c\xf0L\xb1C\x80\x05\x9e\xfd?#\x8be\u057e\xb8j\xfa\x14\u0609\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1c\xf1\x05\xab#\x02;ULX>\x86\u05d2\x11y\xee\x83\x16\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1c\xf2\xebz\x8c\xca\u00ad\xea\xef\x0e\xe8sG\xd55\u04f9@X\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1c\xfc\xf7Q\u007f\f\bE\x97 \x94+dz\u0452\xaa\x9c\x88(\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\x1d\t\xad$\x12i\x1c\u0141\xc1\xab6\xb6\xf9CL\xd4\xf0\x8bT\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\x1d\x15|Xv\xc5\xca\xd5S\xc9\x12\xca\xf6\xce-Rw\xe0\\s\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x1d&\x15\xf8\xb6\xcaP\x12\xb6c\xbd\u0414\xb0\xc5\x13|w\x8d\u07ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1d)\u01ea\xb4+ H\u04b2R%\u0518\u06e6z\x03\xfb\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0794\x1d4\x1f\xa5\xa3\xa1\xbd\x05\x1f}\xb8\a\xb6\xdb/\u01faO\x9bE\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1d4N\x96%g\xcb'\xe4M\xb9\xf2\xfa\u01f6\x8d\xf1\xc1\xe6\xf7\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x1d6h0c\xb7\xe9\xeb\x99F-\xab\xd5i\xbd\xdc\xe7\x16\x86\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1d7aky?\x94\x91\x188\xac\x8e\x19\xee\x94I\u07d2\x1e\u0109QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94\x1d9[0\xad\xda\x1c\xf2\x1f\t\x1aOJ{u3q\x18\x94A\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x1dEXn\xb8\x03\xca!\x90e\v\xf7H\xa2\xb1t1+\xb5\a\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1dW.\xdd-\x87\xca'\x1ag\x14\xc1Z;7v\x1d\u0320\x05\x89\x06\xeb\xd5*\x8d\xdd9\x00\x00\u07d4\x1dc0\x97\xa8R%\xa1\xffC!\xb1)\x88\xfd\xd5\\+8D\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x1di\xc8=(\xff\x04t\xce\xeb\xea\xcb:\xd2'\xa1D\xec\u78ca\x01(\xcc\x03\x92\nb\u0480\x00\u07d4\x1d\x96\xbc\u0544W\xbb\xf1\xd3\u00a4o\xfa\xf1m\xbf}\x83hY\x89\tIr\t\xd8F~\x80\x00\u07d4\x1d\x9ej\xaf\x80\x19\xa0_#\x0e]\xef\x05\xaf]\x88\x9b\xd4\xd0\xf2\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x1d\xab\x17.\xff\xa6\xfb\xeeSL\x94\xb1~yN\xda\xc5OU\xf8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x1d\xb9\xac\x9a\x9e\xae\xec\nR7W\x05\fq\xf4rx\xc7-P\x89Hz\x9a0E9D\x00\x00\u07d4\x1d\xbe\x8e\x1c+\x8a\x00\x9f\x85\xf1\xad<\xe8\r.\x055\x0e\u3709\aW\rn\x9e\xbb\xe4\x00\x00\u07d4\x1d\xc7\xf7\xda\xd8]\xf5?\x12q\x15$\x03\xf4\xe1\xe4\xfd\xb3\xaf\xa0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1d\u03bc\xb7em\xf5\u072a3h\xa0U\xd2/\x9e\xd6\xcd\xd9@\x89\x1b\x18\x1eK\xf24<\x00\x00\xe0\x94\x1d\xd7tA\x84J\xfe\x9c\xc1\x8f\x15\xd8\xc7{\xcc\xfbe^\xe04\x8a\x01\x06\xebEW\x99D\x88\x00\x00\u07d4\x1d\xde\xfe\xfd5\xab\x8fe\x8b$q\xe5G\x90\xbc\x17\xaf\x98\u07a4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1d\xee\xc0\x1a\xbe\\\r\x95-\xe9\x10l=\xc3\x069\xd8P\x05\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\x1d\xf6\x91\x16rg\x9b\xb0\xef5\t\x03\x8c\f'\xe3\x94\xfd\xfe0\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\x1d\xfa\xee\ar\x12\xf1\xbe\xaf\x0eo/\x18@Sz\xe1T\xad\x86\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x1e\x06\r\xc6\xc5\xf1\u02cc\xc7\xe1E.\x02\xee\x16u\b\xb5eB\x8a\x02\xb1O\x02\xc8d\xc7~\x00\x00\xe0\x94\x1e\x13\xecQ\x14,\ubde2`\x83A,<\xe3QD\xbaV\xa1\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x1e\x1aH(\x11\x9b\xe3\t\xbd\x88#nMH+PM\xc5W\x11\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\x1e\x1a\ud178leb\u02cf\xa1\xebo\x8f;\xc9\u072eny\x89\xf4\xd2\u0744%\x9b$\x00\x00\u07d4\x1e\x1ccQwj\xc3\x10\x919~\xcf\x16\x00-\x97\x9a\x1b-Q\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x1e\x1dz_$h\xb9N\xa8&\x98-\xbf!%yR*\xb7\xdf\n\u02ac\x9e\xee\xd3Y09\xe5\xacuy\x8a+\x14F\xddj\xef\xe4\x1c\x00\x00\u07d4\x1e{^M\x1fW+\xec\xf2\xc0\x0f\xc9\f\xb4v{Jn3\u0509\x06\x1f\xc6\x10u\x93\xe1\x00\x00\u07d4\x1e\x8eh\x9b\x02\x91|\xdc)$]\f\x9ch\xb0\x94\xb4\x1a\x9e\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xa34\xb5u\b\a\xeat\xaa\u016b\x86\x94\xec_(\xaaw\u03c9\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\x1e\xa4qU\x04\u01af\x10{\x01\x94\xf4\xf7\xb1\xcbo\xcc\xcdoK\x89 \x041\x97\xe0\xb0'\x00\x00\u07d4\x1e\xa4\x92\xbc\xe1\xad\x10~3\u007fK\u0527\xac\x9a{\xab\xcc\u036b\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x1e\xa6\xbf/\x15\xae\x9c\x1d\xbcd\u06a7\xf8\xeaM\r\x81\xaa\xd3\xeb\x89\u3bb5sr@\xa0\x00\x00\u07d4\x1e\xb4\xbfs\x15j\x82\xa0\xa6\x82 \x80\xc6\xed\xf4\x9cF\x9a\xf8\xb9\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\x1e\xba\xcbxD\xfd\xc3\"\xf8\x05\x90O\xbf\x19b\x80-\xb1S|\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x1e\xc4\xecKw\xbf\x19\u0411\xa8h\xe6\xf4\x91T\x18\x05A\xf9\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xd0n\xe5\x16b\xa8lcE\x88\xfbb\xdcC\xc8\xf2~|\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1e\u063b?\x06w\x8b\x03\x9e\x99a\xd8\x1c\xb7\x1as\xe6x|\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x1e\xda\bNye\x00\xba\x14\xc5\x12\x1c\r\x90\x84of\xe4\xbeb\x89\x1c\xfd\xd7F\x82\x16\xe8\x00\x00\u07d4\x1e\xeel\xbe\xe4\xfe\x96\xadaZ\x9c\xf5\x85zdy@\u07ccx\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4\x1e\xf2\u073f\xe0\xa5\x00A\x1d\x95n\xb8\u0213\x9c=l\xfef\x9d\x89*\x11)\u0413g \x00\x00\xe0\x94\x1e\xf5\xc9\xc76P\u03fb\xde\\\x88U1\xd4'\xc7\xc3\xfeUD\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x1f\x04\x12\xbf\xed\u0356N\x83}\t,q\xa5\xfc\xba\xf3\x01&\xe2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\x17O@\xa0Dr4\xe6fS\x91Mu\xbc\x00>V\x90\u0709\b\xacr0H\x9e\x80\x00\x00\u07d4\x1f!\x86\xde\xd2>\f\xf9R\x16\x94\xe4\xe1dY>i\n\x96\x85\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x1f*\xfc\n\xed\x11\xbf\xc7\x1ew\xa9\ae{6\xeav\xe3\xfb\x99\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\x1f9Y\xfc)\x11\x10\xe8\x822\xc3kvg\xfcx\xa3ya?\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x1f=\xa6\x8f\xe8~\xafC\xa8)\xabm~\u0166\xe0\t\xb2\x04\xfb\x89\x1e\x16\x01u\x8c,~\x00\x00\u07d4\x1fI\xb8m\r9EY\x06\x98\xa6\xaa\xf1g<7u\\\xa8\r\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\x1f_;4\xbd\x13K'\x81\xaf\xe5\xa0BJ\u0144l\xde\xfd\x11\x89\x05]\xe6\xa7y\xbb\xac\x00\x00\u07d4\x1fo\x0004\x97R\x06\x1c\x96\a+\xc3\xd6\xeb5I \x8dk\x89\x01K\x8d\xe1\xeb\x88\u06c0\x00\u07d4\x1f}\x8e\x86\xd6\xee\xb0%E\xaa\xd9\x0e\x912{\xd3i\xd7\xd2\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\x81\x16\xbd\n\xf5W\x0e\xaf\fV\u011cz\xb5\xe3zX\x04X\x89lk\x93[\x8b\xbd@\x00\x00\u0794\x1f\x88\xf8\xa13\x8f\xc7\xc1\tv\xab\xcd?\xb8\u04c5T\xb5\uc708\xb9\xf6]\x00\xf6<\x00\x00\u07d4\x1f\x9c2hE\x8d\xa3\x01\xa2\xbeZ\xb0\x82W\xf7{\xb5\xa9\x8a\xa4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x1f\xa21\x9f\xed\x8c-F*\xdf.\x17\xfe\xecjo0Qn\x95\x89\x06\xca\xe3\x06!\xd4r\x00\x00\u07d4\x1f\xb4c\xa08\x99\x83\xdf}Y?{\xddmxI\u007f\xed\x88y\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x1f\xb7\xbd1\r\x95\xf2\xa6\u067a\xaf\x8a\x8aC\n\x9a\x04E:\x8b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x1f\xcc|\xe6\xa8HX\x95\xa3\x19\x9e\x16H\x1fr\xe1\xf7b\xde\xfe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x1f\xcf\xd1\xd5\u007f\x87\"\x90V\f\xb6-`\x0e\x1d\xef\xbe\xfc\xcc\x1c\x89P\xc5\xe7a\xa4D\b\x00\x00\u0794\x1f\u0496\xbe\x03\xads|\x92\xf9\u0186\x9e\x8d\x80\xa7\x1cW\x14\xaa\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x1f\xdd\xd8_\u024b\xe9\xc4\x04Ya\xf4\x0f\x93\x80^\xccEI\xe5\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4 \x01\xbe\xf7{f\xf5\x1e\x15\x99\xb0/\xb1\x10\x19J\x00\x99\xb7\x8d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4 \x02d\xa0\x9f\x8ch\xe3\xe6b\x97\x95(\x0fV%O\x86@\u0409\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \x03qy\a\xa7%`\xf40\u007f\x1b\xee\xccT6\xf4=!\xe7\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4 \r\xfc\vq\xe3Y\xb2\xb4eD\n6\xa6\xcd\xc3Rw0\a\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4 \x13L\xbf\xf8\x8b\xfa\xdcFkR\xec\ua9d8W\x89\x1d\x83\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4 \x14&\x1f\x01\b\x9fSyV0\xba\x9d\xd2O\x9a4\xc2\xd9B\x89Hz\x9a0E9D\x00\x00\u07d4 \x16\x89]\xf3,\x8e\xd5G\x82iF\x84#\xae\xa7\xb7\xfb\xceP\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \x18\x1cKA\xf6\xf9r\xb6iX!_\x19\xf5p\xc1]\xdf\xf1\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4 \x18d\xa8\xf7\x84\xc2'{\v|\x9e\xe74\xf7\xb3w\xea\xb6H\x89\xf2(\x14\x00\xd1\xd5\xec\x00\x00\u07d4 \xb8\x1a\xe59&\xac\xe9\xf7\xd7AZ\x05\f\x03\x1dX_ \x89\x12\u007f\x19\xe8>\xb3H\x00\x00\xe0\x94 \x1d\x9e\xc1\xbc\v\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4 \xa1RV\xd5\f\xe0X\xbf\x0e\xacC\xaaS:\xa1n\u0273\x80\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4 \xa2\x9cPy\xe2k?\x181\x8b\xb2\xe5\x0e\x8e\x8b4n[\xe8\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4 \xa8\x16\x80\xe4e\xf8\x87\x90\xf0\aO`\xb4\xf3_]\x1ej\xa5\x89Ea\x80'\x8f\fw\x80\x00\u07d4 \xb9\xa9\u6f48\x80\u0659J\xe0\r\u0439(*\v\xea\xb8\x16\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4 \u0084\xba\x10\xa2\b0\xfc=i\x9e\xc9}-\xfa'\xe1\xb9^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4 \xd1A\u007f\x99\xc5i\u3fb0\x95\x85e0\xfe\x12\xd0\xfc\uaa89@\x15\xf9K\x11\x83i\x80\x00\u07d4 \u074f\u02f4n\xa4o\u3066\x8b\x8c\xa0\xea[\xe2\x1f\u9949lk\x93[\x8b\xbd@\x00\x00\xe0\x94 \xff>\u078c\xad\xb5\xc3{H\xcb\x14X\x0f\xb6^#\t\n{\x8a\b\xe4\xd3\x16\x82v\x86@\x00\x00\xe0\x94!\x008\x1d`\xa5\xb5J\xdc\t\u0456\x83\xa8\xf6\u057bK\xfb\u02ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94!\x18\xc1\x16\xab\f\xdfo\xd1\x1dT\xa40\x93\a\xb4w\xc3\xfc\x0f\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94!\x1b)\xce\xfcy\xae\x97gD\xfd\xeb\u03bd<\xbb2\xc5\x13\x03\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4! l\xe2.\xa4\x80\xe8Y@\xd3\x13\x14\xe0\xd6ONM:\x04\x8965\u026d\xc5\u07a0\x00\x00\u07d4!2\xc0Qj.\x17\x17J\xc5G\xc4;{\x00 \xd1\xebLY\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94!@\x8bMz,\x0en\xcaAC\xf2\xca\u037b\u033a\x12\x1b\u060a\x04<3\xc1\x93ud\x80\x00\x00\u07d4!Kt9U\xa5\x12\xden\r\x88j\x8c\xbd\x02\x82\xbe\xe6\u04a2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!L\x89\u017d\x8e}\"\xbcWK\xb3^H\x95\x02\x11\xc6\xf7v\x89\x01\x06T\xf2X\xfd5\x80\x00\xe0\x94!Ti\x14\xdf\u04ef*\xddA\xb0\xff>\x83\xff\xdat\x14\xe1\xe0\x8a\x01C\x95\xe78ZP.\x00\x00\u07d4!X.\x99\xe5\x02\xcb\xf3\xd3\xc2;\xdf\xfbv\xe9\x01\xacmV\xb2\x89\x05k\xc7^-c\x10\x00\x00\u07d4!Y$\b\x13\xa70\x95\xa7\xeb\xf7\u00f3t>\x80(\xae_\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!`\xb4\xc0,\xac\n\x81\u0791\b\xdeCE\x90\xa8\xbf\xe6\x875\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94!nA\x86N\xf9\x8f\x06\r\xa0\x8e\xca\xe1\x9a\xd1\x16j\x17\xd06\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4!\x84o/\xdfZA\xed\x8d\xf3n^\xd8TM\xf7Y\x88\xec\xe3\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94!\xa6\xdbe'F{\xc6\xda\xd5K\xc1n\x9f\xe2\x95;g\x94\xed\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4!\xa6\xfe\xb6\xab\x11\xc7f\xfd\xd9w\xf8\xdfA!\x15_G\xa1\xc0\x89\x03\x19\xcf8\xf1\x00X\x00\x00\u07d4!\xb1\x82\xf2\xda+8D\x93\xcf_5\xf8=\x9d\x1e\xe1O*!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!\xbf\xe1\xb4\\\xac\xdebt\xfd\x86\b\u0661x\xbf>\xebn\u0709l\xee\x06\u077e\x15\xec\x00\x00\u07d4!\xc0s\x80HOl\xbc\x87$\xad2\xbc\x86L;Z\xd5\x00\xb7\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94!\u00e8\xbb\xa2g\xc8\u0322{\x1a\x9a\xfa\xba\xd8o`z\xf7\b\x8a\x01\xe4\xa3lI\u06580\x00\x00\u07d4!\xcem[\x90\x18\xce\xc0J\u0596yD\xbe\xa3\x9e\x800\xb6\xb8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4!\xd0'\x05\xf3\xf6I\x05\xd8\x0e\xd9\x14y\x13\xea\x8cs\a\u0595\x89I\xed\xb1\xc0\x98\x876\x00\x00\u07d4!\xd1?\f@$\xe9g\xd9G\a\x91\xb5\x0f\"\xde:\xfe\xcf\x1b\x89\xf1Z\xd3^.1\xe5\x00\x00\xe0\x94!\xdb\u06c1z\r\x84\x04\u01bd\xd6\x15\x047N\x9cC\xc9!\x0e\x8a\x02\x1e\x18\xb9\xe9\xabE\xe4\x80\x00\xe0\x94!\xdf\x1e\xc2KNK\xfey\xb0\xc0\x95\u03ba\xe1\x98\xf2\x91\xfb\u044a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94!\xdf-\u036ft\xb2\xbf\x804\x04\xddM\xe6\xa3^\xab\xec\x1b\xbd\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4!\xe2\x19\u021c\xa8\xac\x14\xaeL\xbaa0\xee\xb7}\x9em9b\x89*\u035f\xaa\xa08\xee\x00\x00\u07d4!\xe5\u04ba\xe9\x95\xcc\xfd\b\xa5\xc1k\xb5$\xe1\xf60D\x8f\x82\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4!\xe5\xd7s 0L \x1c\x1eS\xb2a\xa1#\u0421\x06>\x81\x89\x04\xb6\xfa\x9d3\xddF\x00\x00\xe0\x94!\xea\xe6\xfe\xff\xa9\xfb\xf4\u0347OG9\xac\xe50\u033eY7\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4!\xec\xb2\u07e6Wy\xc7Y-\x04\x1c\xd2\x10Z\x81\xf4\xfdNF\x8965\u026d\xc5\u07a0\x00\x00\u07d4!\uff20\x9b5\x80\xb9\x8es\xf5\xb2\xf7\xf4\xdc\v\xf0,R\x9c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4!\xfd\v\xad\xe5\xf4\xeftt\xd0X\xb7\xf3\xd8T\xcb\x13\x00RN\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94!\xfdG\xc5%`\x12\x19\x8f\xa5\xab\xf11\xc0mj\xa1\x96_u\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4!\xfdl]\x97\xf9\xc6\x00\xb7h!\xdd\xd4\xe7v5\x0f\xce+\xe0\x89lj\u04c2\xd4\xfba\x00\x00\u07d4\"\r\u018d\xf0\x19\xb6\xb0\u033f\xfbxKZZ\xb4\xb1]@`\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\"\x0e+\x92\xc0\xf6\xc9\x02\xb5\x13\xd9\xf1\xe6\xfa\xb6\xa8\xb0\xde\xf3\u05c9+^:\xf1k\x18\x80\x00\x00\u07d4\"V\x1cY1\x14560\x9c\x17\xe82X{b\\9\v\x9a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\"W\xfc\xa1jn\\*d|<)\xf3l\xe2)\xab\x93\xb1~\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\"]5\xfa\xed\xb3\x91\u01fc-\xb7\xfa\x90q\x16\x04\x05\x99m\x00\x89\t\x18T\xfc\x18bc\x00\x00\u07d4\"_\x9e\xb3\xfbo\xf3\xe9\xe3\xc8D~\x14\xa6n\x8dO7y\xf6\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\"r\x18n\xf2}\xcb\xe2\xf5\xfc70P\xfd\xae\u007f*\xce#\x16\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4\"s\xba\u05fcNHv\"\xd1u\xefzf\x98\x8bj\x93\xc4\xee\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\"v&K\xec\x85&\xc0\xc0\xf2pgz\xba\xf4\xf0\xe4A\xe1g\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\"\x82B\xf83n\xec\xd8$.\x1f\x00\x0fA\x93~q\xdf\xfb\xbf\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\"\x84*\xb80\xdaP\x99\x13\xf8\x1d\xd1\xf0O\x10\xaf\x9e\xdd\x1cU\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\"\x94O\xbc\xa9\xb5yc\bN\xb8M\xf7\xc8_\xb9\xbc\u07f8V\x89\xfc\x11\x8f\uf43a8\x80\x00\u07d4\"\x9c\xc4q\x1bbu^\xa2\x96DZ\u00f7\u007f\xc63\x82\x1c\xf2\x89\x02#\xe8\xb0R\x192\x80\x00\u0794\"\x9eC\r\xe2\xb7OD&Q\xdd\u0377\x01v\xbc\x05L\xadT\x88\xbb\xf9\x81\xbcJ\xaa\x80\x00\u07d4\"\x9fO\x1a*OT\atP[G\a\xa8\x1d\xe4D\x10%[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\"\x9f\xf8\v\xf5p\x80\t\xa9\xf79\xe0\xf8\xb5`\x91@\x16\u0566\x89\x12\x11\xec\xb5m\x13H\x80\x00\u07d4\"\xa2X\x12\xabV\xdc\xc4#\x17^\xd1\u062d\xac\xce3\xcd\x18\x10\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94\"\xb9j\xb2\xca\xd5]\xb1\x00\xb50\x01\xf9\xe4\xdb7\x81\x04\xc8\a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\"\xbd\xff\xc2@\xa8\x8f\xf7C\x1a\xf3\xbf\xf5\x0e\x14\xda7\xd5\x18>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\"\xce4\x91Y\xee\xb1D\xef\x06\xff&6X\x8a\xefy\xf6(2\x89\n1\x06+\xee\xedp\x00\x00\u07d4\"\xdbU\x9f,<\x14u\xa2\xe6\xff\xe8:YyY\x91\x96\xa7\xfa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\"\xe1QX\xb5\xee>\x86\xeb\x032\xe3\u6a6cl\u0675^\u0349\b\xacr0H\x9e\x80\x00\x00\u07d4\"\xe2H\x8e-\xa2jI\xae\x84\xc0\x1b\xd5K!\xf2\x94x\x91\u0189]\u0212\xaa\x111\xc8\x00\x00\u07d4\"\xe5\x12\x14\x9a\x18\xd3i\xb7\x86\xc9\xed\xab\xaf\x1d\x89N\xe0.g\x14a\\\x00\x00\u07d4\"\xeb}\xb0\xbaV\xb0\xf8\xb8\x16\u0332\x06\xe6\x15\xd9)\x18[\r\x89\x04])s~\"\xf2\x00\x00\u07d4\"\xee\xd3'\xf8\xeb\x1d\x138\xa3\xcb{\x0f\x8aK\xaaY\a\u0355\x89\x01E]_Hw\b\x80\x00\xe0\x94\"\xf0\x04\u07cd\xe9\xe6\xeb\xf5#\u032c\xe4W\xac\xcb&\xf9r\x81\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794\"\xf2\xdc\xffZ\u05cc>\xb6\x85\v\\\xb9Q\x12{e\x95\"\u623e -j\x0e\xda\x00\x00\u07d4\"\xf3\xc7y\xddy\x02>\xa9*x\xb6\\\x1a\x17\x80\xf6-\\J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\"\xfe\x88M\x907)\x1bMR\xe6(Z\xe6\x8d\xea\v\xe9\xff\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\x06\u07d3\x1a\x94\rX\xc0\x16e\xfaM\b\x00\x80,\x02\xed\xfe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94#\t\xd3@\x91D[22Y\v\xd7\x0fO\x10\x02[,\x95\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4#\x12\x00F\xf6\x83!\x02\xa7R\xa7fVi\x1c\x86>\x17\u5709\x11\xe0\xe4\xf8\xa5\v\xd4\x00\x00\u07d4#\x1a\x15\xac\xc1\x99\u021f\xa9\xcb\"D\x1c\xc7\x030\xbd\xcc\xe6\x17\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4#\x1d\x94\x15]\xbc\xfe*\x93\xa3\x19\xb6\x17\x1fc\xb2\v\u04b6\xfa\x89\xcf\x14{\xb9\x06\xe2\xf8\x00\x00\u07d4#(2\xcdYw\xe0\nL0\xd0\x16?.$\xf0\x88\xa6\xcb\t\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4#,m\x03\xb5\xb6\xe6q\x1e\xff\xf1\x90\xe4\x9c(\xee\xf3l\x82\xb0\x89Hz\x9a0E9D\x00\x00\xe0\x94#,\xb1\xcdI\x99<\x14J?\x88\xb3a\x1e#5i\xa8k\u058a\x03L`lB\u042c`\x00\x00\u07d4#,\xe7\x82Pb%\xfd\x98`\xa2\xed\xc1Jz0Gsm\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4#/R]U\x85\x9b}N`\x8d H\u007f\xaa\xdb\x00)15\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94#4\u0150\u01e4\x87i\x100E\u0176SL\x8a4i\xf4J\x8a\x03\xb1\x99\a=\xf7-\xc0\x00\x00\u07d4#7n\u02bftl\xe53!\xcfB\xc8fI\xb9+g\xb2\xff\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#7\x8fB\x92m\x01\x84\xb7\x93\xb0\xc8'\xa6\xdd>=3O\u0349\x03\t'\xf7L\x9d\xe0\x00\x00\u07d4#8B\xb1\xd0i/\xd1\x11@\xcfZ\u0364\xbf\x960\xba\xe5\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#9\xe9I(p\xaf\xea%7\xf3\x89\xac/\x83\x83\x02\xa3<\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#;\xdd\xdd]\xa9HR\xf4\xad\xe8\xd2\x12\x88V\x82\xd9\ak\u0189\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#OF\xba\xb7?\xe4]1\xbf\x87\xf0\xa1\xe0Fa\x99\xf2\ubb09\x1aJ\xba\"\\ t\x00\x00\u07d4#U\x1fV\x97_\xe9+1\xfaF\x9cI\xeaf\xeefb\xf4\x1e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4#V\x95B\xc9}V`\x18\xc9\a\xac\xfc\xf3\x91\xd1@g\xe8~\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94#_\xa6l\x02^\xf5T\x00p\xeb\xcf\r7-\x81w\xc4g\xab\x8a\a\x12\x9e\x1c\xdf7>\xe0\x00\x00\xe0\x94#r\xc4\xc1\u0253\x9fz\xafl\xfa\xc0@\x90\xf0\x04t\x84\n\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4#s\f5z\x91\x02nD\xb1\xd0\xe2\xfc*Q\xd0q\xd8\xd7{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#v\xad\xa9\x033\xb1\u0441\bL\x97\xe6E\xe8\x10\xaa[v\xf1\x89(\xa8WBTf\xf8\x00\x00\u07d4#x\xfdC\x82Q\x1e\x96\x8e\u0452\x10g7\xd3$\xf4T\xb55\x8965\u026d\xc5\u07a0\x00\x00\u07d4#\x82\xa9\u050e\xc8>\xa3e(\x90\xfd\x0e\u7710{[-\xc1\x89\a?u\u0460\x85\xba\x00\x00\u07d4#\x83\xc2\"\xe6~\x96\x91\x90\xd3!\x9e\xf1M\xa3xP\xe2lU\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\x8akv5%/RDHl\n\xf0\xa7: s\x85\xe09\x89JD\x91\xbdm\xcd(\x00\x00\u07d4#\x9as>k\x85Z\u0152\xd6c\x15a\x86\xa8\xa1t\xd2D\x9e\x89X\xbe7X\xb2A\xf6\x00\x00\xe0\x94#\xab\t\xe7?\x87\xaa\x0f;\xe0\x13\x9d\xf0\xc8\xebk\xe5cO\x95\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94#\xab\xd9\xe9>yW\xe5\xb66\xbeey\x05\x1c\x15\xe5\xce\v\x0e\x8a\x03\xa3\xc8\xf7\xcb\xf4,8\x00\x00\u07d4#\xb1\u0111\u007f\xbd\x93\xee=H8\x93\x06\x95s\x84\xa5Il\xbf\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94#\xba8d\xdaX=\xabV\xf4 \x87<7g\x96\x90\xe0/\x00\x8a\x02\x13BR\r_\xec \x00\x00\u07d4#\xc5Z\xebW9\x87o\n\xc8\xd7\xeb\xea\x13\xber\x96\x85\xf0\x00\x89Hz\x9a0E9D\x00\x00\u07d4#\u025b\xa0\x87D\x8e\x19\xc9p\x1d\xf6n\f\xabR6\x831\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xcc\xc3\u01ac\xd8\\.F\fO\xfd\xd8+\xc7]\xc8I\xea\x14\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4#\xcd%\x98\xa2\x0e\x14\x9e\xad*\u0593yWn\xce\xdb`\u3389lk\x93[\x8b\xbd@\x00\x00\u07d4#\u07cfH\xee\x00\x92V\xeay~\x1f\xa3i\xbe\xeb\xcfk\xc6c\x89|\xd3\xfa\xc2m\x19\x81\x80\x00\u07d4#\xe2\u01a8\xbe\x8e\n\u03e5\xc4\xdf^6\x05\x8b\xb7\u02ecZ\x81\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xeaf\x9e5d\x81\x9a\x83\xb0\xc2l\x00\xa1m\x9e\x82olF\x89M\x8dl\xa9h\xca\x13\x00\x00\u07d4#\xebo\xd8Vq\xa9\x06:\xb7g\x8e\xbe&Z \xf6\x1a\x02\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4#\xf9\xec\xf3\xe5\xdd\u0723\x88\x15\xd3\xe5\x9e\xd3K[\x90\xb4\xa3S\x89\v\x17\x81\xa3\xf0\xbb \x00\x00\u07d4#\xfa~\xb5\x1aH\"\x95\x98\xf9~v+\xe0\x86\x96R\xdf\xfcf\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94$\x03\x05rs\x13\xd0\x1esT,w_\xf5\x9d\x11\xcd5\xf8\x19\x8a\x01A\x88Vf\x80\u007f\\\x80\x00\u07d4$\x04k\x91\u069ba\xb6)\u02cb\x8e\xc0\xc3Q\xa0~\a\x03\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4$\x0eU\x9e'J\xae\xf0\xc2X\x99\x8c\x97\x9fg\x1d\x11s\xb8\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94$\x13aU\x9f\xee\xf8\x0e\xf170!S\xbd\x9e\xd2\xf2]\xb3\xef\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94$;;\xcaj)\x93Y\xe8\x86\xce3\xa3\x03A\xfa\xfeMW=\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4$<\x84\xd1$ W\f\xc4\xef;\xab\xa1\xc9Y\u0083$\x95 \x89\u007f\x1fi\x93\xa8S\x04\x00\x00\xe0\x94$CJ>2\xe5N\xcf'/\xe3G\v_oQ/gU \x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4$HYo\x91\xc0\x9b\xaa0\xbc\x96\x10j-7\xb5p^](\x89lk\x93[\x8b\xbd@\x00\x00\u0794$Xn\xc5E\x175\xee\xaa\xebG\r\xc8sj\xaeu/\x82\xe5\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4$X\xd6U_\xf9\x8a\x12\x9c\xce@7\x95=\x00 n\xffB\x87\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4$b\x91\x16[Y3-\xf5\xf1\x8c\xe5\u0248V\xfa\xe9X\x97\u0589\\(=A\x03\x94\x10\x00\x00\u07d4$g\u01a5\u0196\xed\xe9\xa1\xe5B\xbf\x1a\xd0k\xccK\x06\xac\xa0\x89\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4$v\xb2\xbbu\x1c\xe7H\xe1\xa4\xc4\xff{#\v\xe0\xc1]\"E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4$z\n\x11\xc5\u007f\x03\x83\xb9I\xdeT\vf\xde\xe6\x86\x04\xb0\xa1\x899\xfb\xae\x8d\x04-\xd0\x00\x00\u07d4$\x87\xc3\u013e\x86\xa2r=\x91|\x06\xb4XU\x01p\xc3\xed\xba\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\x89\xac\x12i4\xd4\u05a9M\xf0\x87C\xda{v\x91\xe9y\x8e\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\x9d\xb2\x9d\xbc\x19\xd1#]\xa7)\x8a\x04\b\x1c1WB\u9b09a\xac\xff\x81\xa7\x8a\xd4\x00\x00\u07d4$\xa4\xeb6\xa7\xe4\x98\xc3o\x99\x97\\\x1a\x8dr\x9f\u05b3\x05\u05c9\r\xfcx!\x0e\xb2\xc8\x00\x00\u07d4$\xa7P\xea\xe5\x87G\x11\x11m\xd7\xd4{q\x86\u0399\r1\x03\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4$\xaa\x11Q\xbbv_\xa3\xa8\x9c\xa5\x0e\xb6\xe1\xb1\xc7\x06A\u007f\u0509\xa8\r$g~\xfe\xf0\x00\x00\u0794$\xac\xa0\x8d[\xe8^\xbb\x9f12\xdf\xc1\xb6 \x82N\xdf\xed\xf9\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4$\xb2\xbe\x11\x8b\x16\u0632\x17Gi\xd1{L\xf8O\a\u0294m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4$\xb8\xb4F\u07bd\x19G\x95]\u0404\xf2\xc5D\x933F\u04ed\x89\xeaim\x90@9\xbd\x80\x00\u07d4$\xb9^\xbe\xf7\x95\x00\xba\xa0\xed\xa7.w\xf8wA]\xf7\\3\x891T\xc9r\x9d\x05x\x00\x00\u07d4$\xb9\xe6dOk\xa4\xcd\xe1&'\r\x81\xf6\xab`\xf2\x86\xdf\xf4\x89\a?u\u0460\x85\xba\x00\x00\u07d4$\xbdY\x04\x05\x90\x91\xd2\xf9\xe1-j&\xa0\x10\xca\"\xab\x14\xe8\x89e\xea=\xb7UF`\x00\x00\u07d4$\xc0\u020bT\xa3TG\t\x82\x8a\xb4\xab\x06\x84\x05Y\xf6\xc5\u2250\xf54`\x8ar\x88\x00\x00\u07d4$\xc1\x17\xd1\u04b3\xa9z\xb1\x1aFy\u025awJ\x9e\xad\xe8\u044965\u026d\xc5\u07a0\x00\x00\u07d4$\xcf\xf0\xe93j\x9f\x80\xf9\xb1\u02d6\x8c\xafk\x1d\x1cI2\xa4\x89\n\xdaUGK\x814\x00\x00\u07d4$\u06aa\xdd\xf7\xb0k\xbc\ua6c0Y\x00\x85\xa8\x85gh+N\x89\x11K \x15\u04bb\xd0\x00\x00\u07d4$\xdc\xc2K\xd9\xc7!\f\xea\u03f3\r\xa9\x8a\xe0JM{\x8a\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4$\xf7E\r\xdb\xf1\x8b\x02\x0f\xeb\x1a 2\xd9\xd5Kc>\xdf7\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4$\xfcs\xd2\a\x93\t\x8e\t\u076bW\x98Pb$\xfa\x1e\x18P\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4$\xfd\x9al\x87L/\xab?\xf3n\x9a\xfb\xf8\xce\r2\xc7\u0792\x89Hz\x9a0E9D\x00\x00\u07d4%\n@\xce\xf3 #\x97\xf2@F\x95H\xbe\xb5bj\xf4\xf2<\x89\x05\x03\xb2\x03\xe9\xfb\xa2\x00\x00\u07d4%\niC\av\xf64w\x03\xf9R\x97\x83\x95Za\x97\xb6\x82\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4%\x0e\xb7\xc6o\x86\x9d\xdfI\u0685\xf39>\x98\f\x02\x9a\xa44\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%\x10j\xb6u]\xf8mkc\xa1\x87p;\f\xfe\xa0\u5520\x89\x01|@Z\xd4\x1d\xb4\x00\x00\xe0\x94%\x18_2Z\xcf-dP\x06\x98\xf6\\v\x9d\xdfh0\x16\x02\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4%\x1c\x12r,hy\"y\x92\xa3\x04\xeb5v\xcd\x18CN\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\x1eh8\xf7\xce\u0173\x83\xc1\xd9\x01F4\x12t\xda\xf8\xe5\x02\x89\a\xff\x1c\xcbua\xdf\x00\x00\u07d4%%\x9d\x97Z!\xd8:\xe3\x0e3\xf8\x00\xf5?7\u07e0\x198\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4%({\x81_\\\x828\ns\xb0\xb1?\xba\xf9\x82\xbe$\xc4\u04c9\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94%+eU\xaf\u0700\xf2\xd9m\x97-\x17\u06c4\xeaZ\xd5!\xac\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4%8S)6\x81<\x91\xe6S(O\x01|\x80\u00f8\xf8\xa3o\x89l\x87T\xc8\xf3\f\b\x00\x00\xe0\x94%>2\xb7N\xa4I\n\xb9&\x06\xfd\xa0\xaa%{\xf2=\u02cb\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94%?\x1et*,\uc1b0\u05f3\x06\xe5\xea\xcbl\xcb/\x85T\x8a\x04>^\xde\x1f\x87\x8c \x00\x00\u07d4%A1J\v@\x8e\x95\xa6\x94DIwq*Pq5\x91\xab\x89X\x9e\x1a]\xf4\u05f5\x00\x00\u07d4%L\x1e\xccc\f(w\u0780\x95\xf0\xa8\u06e1\xe8\xbf\x1fU\f\x89\\(=A\x03\x94\x10\x00\x00\u07d4%Z\xbc\x8d\b\xa0\x96\xa8\x8f=j\xb5_\xbcsR\xbd\u0739\u0389\x04t6\x821>\u0780\x00\u07d4%[\xdddt\u0302b\xf2j\"\u00cfE\x94\x0e\x1c\ue99b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%`\xb0\x9b\x89\xa4\xaehI\xedZ<\x99XBf1qDf\x89\\(=A\x03\x94\x10\x00\x00\u07d4%a\xa18\xdc\xf8;\xd8\x13\xe0\xe7\xf1\bd+\xe3\xde=o\x05\x8964\xf4\x84\x17@\x1a\x00\x00\u0794%a\xec\x0f7\x92\x18\xfe^\xd4\xe0(\xa3\xf7D\xaaAuLr\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u0794%b\x92\xa1\x91\xbd\xda4\xc4\xdakk\u0591G\xbfu\u2a6b\x88\xc2\xff.\r\xfb\x03\x80\x00\u07d4%i~\xf2\f\u032ap\xd3-7o\x82r\xd9\xc1\a\f=x\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4%o\xa1P\u0307\xb5\x05j\a\xd0\x04\xef\xc8E$s\x9eb\xb5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4%r\x1c\x87\xb0\xdc!7|r\x00\xe5$\xb1J\"\xf0\xafi\xfb\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4%\x899\xbb\xf0\f\x9d\xe9\xafS8\xf5\xd7\x14\xab\xf6\xd0\xc1\xc6q\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94%\x90\x12hp\xe0\xbd\xe8\xa6c\xab\x04\nr\xa5W=\x8dA\u008a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4%\x9e\xc4\xd2e\xf3\xabSk|p\xfa\x97\xac\xa1Bi,\x13\xfc\x89\x01\x1b\x1b[\xea\x89\xf8\x00\x00\xe0\x94%\xa5\x00\xee\xeczf*\x84\x15R\xb5\x16\x8bp{\r\xe2\x1e\x9e\x8a\x02\x1f/o\x0f\xc3\xc6\x10\x00\x00\xe0\x94%\xa5\xa4M8\xa2\xf4Lj\x9d\xb9\u037ck\x1e.\x97\xab\xb5\t\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4%\xa7L*\xc7]\u023a\xa8\xb3\x1a\x9c|\xb4\xb7\x82\x9b$V\u0689lk\x93[\x8b\xbd@\x00\x00\xe0\x94%\xad\xb8\xf9o9I,\x9b\xb4|^\u0708bNF\aV\x97\x8a\x05\xa9\x94\v\xc5hyP\x00\x00\u07d4%\xae\xe6\x8d\t\xaf\xb7\x1d\x88\x17\xf3\xf1\x84\xecV/x\x97\xb74\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\xb0S;\x81\xd0*a{\x92)\xc7\xec]o/g.[Z\x8965\u026d\xc5\u07a0\x00\x00\u07d4%\xb7\x8c\x9f\xad\x85\xb43C\xf0\xbf\xcd\x0f\xac\x11\u0254\x9c\xa5\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4%\xbcI\xef(\x8c\xd1e\xe5%\xc6a\xa8\x12\u03c4\xfb\xec\x8f3\x89\x12Y!\xae\xbd\xa9\xd0\x00\x00\u07d4%\xbd\xfa>\xe2o8Ia{#\x00bX\x8a\x97\xe3\xca\xe7\x01\x8965\xe6\x19\xbb\x04\xd4\x00\x00\u07d4%\xc1\xa3~\xe5\xf0\x82e\xa1\xe1\r=\x90\xd5G)U\xf9x\x06\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4%\xc6\xe7O\xf1\xd9(\u07d8\x13z\xf4\u07c40\xdf$\xf0|\u05c9\x15$VU\xb1\x02X\x00\x00\xe0\x94%\xcf\xc4\xe2\\5\xc1;i\xf7\xe7}\xbf\xb0\x8b\xafXuk\x8d\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94%\xda\u0515\xa1\x1a\x86\xb9\xee\xec\xe1\xee\xec\x80^W\xf1W\xfa\xff\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94%\xe07\xf0\n\x18'\v\xa5\xec4 \"\x9d\xdb\n,\u33e2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4%\xe6a\xc99\x86:\xcc\x04No\x17\xb5i\x8c\xce7\x9e\xc3\u0309JD\x91\xbdm\xcd(\x00\x00\u07d4&\x04\x8f\xe8M\x9b\x01\nb\xe71b~I\xbc.\xb7?@\x8f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4&\x06\u00f3\xb4\xca\x1b\t\x14\x98`,\xb1\x97\x8b\xf3\xb9R!\xc0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4&\n#\x0eDe\a~\v\x14\xeeDB\xa4\x82\u0570\xc9\x14\xbf\x89Z\xf6\x06\xa0k[\x11\x80\x00\u07d4&\r\xf8\x94:\x8c\x9a]\xbayE2\u007f\xd7\xe0\x83|\x11\xad\a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4&\x14\xf4-]\xa8D7ux\xe6\xb4H\xdc$0[\xef+\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\x15\x10\x0e\xa7\xe2[\xba\x9b\xcat`X\xaf\xbb\xb4\xff\xbeBD\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4&\x15u\xe9\xcfY\xc8\"o\xa7\xaa\xf9\x1d\xe8o\xb7\x0fZ\u00ee\x89\x10C\xa4CjR?\x00\x00\xe0\x94&\x1e\x0f\xa6LQ\x13te\xee\xcf[\x90\xf1\x97\xf7\x93\u007f\xdb\x05\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4&*\x8b\xfd}\x9d\xc5\xdd:\u05c1a\xb6\xbbV\b$76U\x89?j\x83\x84\a+v\x00\x00\xe0\x94&*\xedK\xc0\xf4\xa4\xb2\xc6\xfb5y>\x83ZI\x18\x9c\xdf\xec\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94&-\xc16L\xcfm\xf8\\C&\x8e\xe1\x82UM\xaei.)\x8a\x01\v /\xect\xce\xd8\x00\x00\u07d4&8\x140\x9d\xe4\xe65\xcfX^\r6Tw\xfc@\xe6l\xf7\x89\a\xea(2uw\b\x00\x00\u07d4&9\xee\xe9\x87<\xee\xc2o\u0314T\xb5H\xb9\xe7\xc5J\xa6\\\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94&>W\xda\xcb\xe0\x14\x9f\x82\xfee\xa2fH\x98\x86o\xf5\xb4c\x8a\b\v\xfb\xef\xcb_\v\xc0\x00\x00\u07d4>\x19\xc0m_\x14z\xa5\x97$\x8e\xb4l\xf7\xbe\xfad\xa5\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4&L\xc8\bj\x87\x10\xf9\x1b!r\t\x05\x91,\u05d6J\xe8h\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94&S\x83\u058bR\xd04\x16\x1b\xfa\xb0\x1a\xe1\xb0G\x94/\xbc2\x8a\x04rq\xde\xe2\rt\\\x00\x00\u07d4&Y\xfa\xcb\x1e\x83CeS\xb5\xb4)\x89\xad\xb8\a_\x99S\xed\x89\x01\x97evw\x1a^\x00\x00\xe0\x94&o-\xa7\xf0\b^\xf3\xf3\xfa\t\xba\xee#+\x93\xc7D\xdb.\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4&qH\xfdr\xc5Ob\nY/\xb9'\x991\x9c\xc4S+\\\x89\x169\u46fa\x16(\x00\x00\xe0\x94&xJ\u0791\u0228:\x8e9e\x8c\x8d\x82wA<\u0319T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4&z~n\x82\xe1\xb9\x1dQ\xde\u0776D\xf0\xe9m\xbb\x1f\u007f~\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4&\x80q=@\x80\x8e*P\xed\x011P\xa2\xa6\x94\xb9j\u007f\x1d\x89a\t=|,m8\x00\x00\u07d4&\x97\xb39\x81;\f-\x96K$q\xeb\x1c`oN\u02d6\x16\x89>\x8e\xf7\x95\u0610\xc8\x00\x00\u07d4&\xa6\x8e\xab\x90Z\x8b=\xce\x00\xe3\x170\x82%\u06b1\xb9\xf6\xb8\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4&\xb1\x1d\x06e\x88\xcet\xa5r\xa8Zc(s\x92\x12\xaa\x8b@\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xba\xbfB\xb2g\xfd\xcf8a\xfd\xd4#j^GHH\xb3X\x8965\u026d\xc5\u07a0\x00\x00\u07d4&\xc0\x05Kp\r:|-\xcb\xe2uh\x9dOL\xad\x16\xa35\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xc2\xff\xc3\x0e\xfd\xc5'>v\x18:\x16\xc2i\x8dnS\x12\x86\x89*\x11)\u0413g \x00\x00\u07d4&\u025f\x88I\u0240+\x83\xc8a!\u007f\xd0z\x9e\x84\u0377\x9d\x89\x10CV\x1a\x88)0\x00\x00\u07d4&\xcf\xff\xd0R\x15+\xb3\xf9W\xb4x\xd5\xf9\x8b#:|+\x92\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4&\u0521h\x91\xf5)\"x\x92\x17\xfc\u0606\xf7\xfc\xe2\x96\xd4\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4&\xd4\xec\x17\xd5\u03b2\u0214\xbd\u015d\nji]\xad+C\u0309\x9f\x1fxv\x1d4\x1a\x00\x00\u07d4&\xe8\x01\xb6,\x82q\x91\xddh\xd3\x1a\x01\x19\x90\x94\u007f\xd0\xeb\xe0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4&\xe9\xe2\xadr\x97\x02bd\x17\xef%\xde\r\xc8\x00\xf7\xa7y\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4&\xf9\xf7\xce\xfd~9K\x9d9$A+\xf2\u0083\x1f\xaf\x1f\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94&\xfe\x17L\xbfRfP\xe0\xcd\x00\x9b\xd6\x12e\x02\u038ehM\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\xe0\x94&\xff\nQ\xe7\xce\u0384\x00'ix\xdb\xd6#n\xf1b\xc0\xe6\x8a\x15.\x18V'T\nP\x00\x00\u07d4'\x10\x1a\x0fV\u04da\x88\u0168O\x9b2L\xdd\xe3>\\\xb6\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'\x14L\xa9\xa7w\x1a\x83j\xd5\x0f\x80?d\xd8i\xb2\xae+ \x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4'\x14i\x13V:\xa7E\xe2X\x840\xd94\x8e\x86\xea|5\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4'\x1d=H\x1c\xb8\x8evq\xad!iI\xb66^\x060=\xe0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4' \xf9\xcaBn\xf2\xf2\xcb\xd2\xfe\xcd9\x92\fO\x1a\x89\xe1m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'*\x13\x1aZejz:\xca5\u023d \"\"\xa7Y\"X\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4'D\xffgFA!\xe3Z\xfc)\"\x17qd\xfa/\xcb\x02g\x89\x05k\xc7^-c\x10\x00\x00\u07d4'J=w\x1a=p\x97\x96\xfb\xc4\xd5\xf4\x8f\xce/\xe3\x8cy\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4'Mi\x17\x0f\xe7\x14\x14\x01\x88+\x88j\xc4a\x8cj\xe4\x0e\u06c93\xc5I\x901r\f\x00\x00\u07d4'R\x1d\xeb;n\xf1An\xa4\u01c1\xa2\xe5\u05f3n\xe8\x1ca\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'Xu\xffO\xbb\f\xf3\xa40!1'H\u007fv\b\xd0L\xba\x89\x1b\x1c\x01\x0evmX\x00\x00\u07d4'j\x00n0(\xec\xd4L\xdbb\xba\nw\u0394\xeb\xd9\xf1\x0f\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4'k\x05!\xb0\xe6\x8b'}\xf0\xbb2\xf3\xfdH2cP\xbf\xb2\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4'o\xd7\xd2O\x8f\x88?Zz()[\xf1qQ\u01e8K\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'p\xf1N\xfb\x16]\u07bay\xc1\v\xb0\xaf1\xc3\x1eY3L\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4'vw\xab\xa1\xe5,;S\xbf\xa2\a\x1dN\x85\x9a\n\xf7\xe8\xe1\x8965\u026d\xc5\u07a0\x00\x00\u07d4'\x82Ff\xd2x\xd7\x04#\xf0=\xfe\x1d\u01e3\xf0/C\u2d4966\xc2^f\xec\xe7\x00\x00\u07d4'\x83\f_`#\xaf\xaa\xf7\x97Egl J\x0f\xac\u0360\xba\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94'\x84\x90?\x1d|\x1b\\\xd9\x01\xf8\x87]\x14\xa7\x9b<\xbe*V\x8a\x04\xbd\xa7\xe9\xd7J\xd5P\x00\x00\u07d4'\x8c\v\xdec\x0e\u00d3\xb1\xe7&\u007f\xc9\xd7\xd9p\x19\xe4\x14[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4'\x98q\x10\"\x1a\x88\b&\xad\xb2\xe7\xab^\xcax\xc6\xe3\x1a\xec\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94'\xac\a;\xe7\x9c\xe6W\xa9:\xa6\x93\xeeC\xbf\x0f\xa4\x1f\xef\x04\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4'\xb1iN\xaf\xa1e\xeb\xd7\xcc{\u025et\x81J\x95\x14\x19\u0709+^:\xf1k\x18\x80\x00\x00\u07d4'\xb6(\x16\xe1\xe3\xb8\u045by\xd1Q=]\xfa\x85[\f:*\x89\x05j\xf5\xc1\xfdiP\x80\x00\u07d4'\xbf\x94<\x163\xfe2\xf8\xbc\xcc\xdbc\x02\xb4\a\xa5rND\x892\xf8Lm\xf4\b\xc0\x80\x00\u07d4'\xbf\x9fD\xba}\x05\xc35@\u00e5;\xb0,\xbb\xff\xe7\xc3\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4'\xc2\xd7\xcaPM\xaa=\x90f\xdc\t\x13}\xc4/:\xaa\xb4R\x89 \x86\xac5\x10R`\x00\x00\u07d4'\xd1X\xac=>\x11\t\xabnW\x0e\x90\xe8]8\x92\xcdv\x80\x89\x05k\xc7^-c\x10\x00\x00\u07d4'\xe69\x89\xca\x1e\x90;\xc6 \xcf\x1b\x9c?g\xb9\xe2\xaee\x81\x89Hz\x9a0E9D\x00\x00\xe0\x94'\xf0<\xf1\xab\xc5\xe1\xb5\x1d\xbcDK(\x9eT,\x9d\u07f0\xe6\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4'\xfc\x85\xa4\x9c\xff\x90\xdb\xcf\xda\u071d\xdd@\u05b9\xa2!\nl\x89\x05k\xc7^-c\x10\x00\x00\u07d4(\x05A^\x1d\u007f\xde\xc6\xde\u07f8\x9eR\x1d\x10Y-t<\x10\x89\x05k\xc7^-c\x10\x00\x00\u07d4(\a>\xfc\x17\xd0\\\xab1\x95\xc2\xdb3+a\x98Gw\xa6\x12\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x12P\xa2\x91!'\nN\xe5\u05cd$\xfe\xaf\xe8,p\xba:\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x13\xd2c\xfc_\xf2G\x9e\x97\x05\x95\u05b6\xb5`\xf8\xd6\xd6\u0449lk\x93[\x8b\xbd@\x00\x00\u07d4(.\x80\xa5T\x87ZVy\x9f\xa0\xa9\u007fU\x10\u7557LN\x8965\u026d\xc5\u07a0\x00\x00\u07d4(3\x96\xce<\xac9\x8b\xcb\xe7\"\u007f2>x\xff\x96\u0407g\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4(4\x9f~\xf9t\xeaU\xfe6\xa1X;4\xce\xc3\xc4Pe\xf0\x89\f\xb63\u051eeY\x00\x00\u07d4(6\x120F\xb2\x84\xe5\xef\x10+\xfd\"\xb1v^P\x81\x16\xad\x89\x16S\xfb\xb5\xc4'\xe4\x00\x00\u07d4(<#\x14(<\x92\u0530d\xf0\xae\xf9\xbbRF\xa7\x00\u007f9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4(>\x11 7I\xb1\xfaO2\xfe\xbbq\xe4\x9d\x13Y\x198*\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94(>bR\xb4\xef\xcfFT9\x1a\xcbu\xf9\x03\u015bx\xc5\xfb\x8a\x02\x8a\x85t%Fo\x80\x00\x00\xe0\x94(Q\x0en\xff\x1f\xc8)\xb6WoC(\xbc98\xecze\x80\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4(X\xac\xac\xaf!\xea\x81\u02b7Y\x8f\xdb\xd8kE.\x9e\x8e\x15\x89$\x1a\x9bOaz(\x00\x00\u07d4(Z\xe5\x1b\x95\x00\u014dT\x13e\xd9ui\xf1K\xb2\xa3p\x9b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(f\xb8\x1d\xec\xb0.\xe7\n\xe2P\xce\xe5\xcd\xc7{Y\u05f6y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(i\x06\xb6\xbdIr\xe3\xc7\x16U\xe0K\xaf6&\f|\xb1S\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4(k\x18ma\xea\x1f\u05cd\x990\xfe\x12\xb0e7\xb0\\=Q\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94(t\xf3\xe2\x98]_{@f'\xe1{\xaaw+\x01\xab\u031e\x8a\x01F\x05\x04\x10v_8\x00\x00\xe0\x94(|\xf9\u0410.\xf8\x19\xa7\xa5\xf1ID[\xf1w^\xe8\xc4|\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4(\x81\x8e\x18\xb6\x10\x00\x13!\xb3\x1d\xf6\xfe}(\x15\u036d\xc9\xf5\x8965\u026d\xc5\u07a0\x00\x00\u07d4(\x86\x83$3~\x11\xba\x10l\xb4\x81\u0696/:\x84S\x80\x8d\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94(\x90K\xb7\xc40)C\xb7\t\xb1Myp\xe4+\x83$\u184a\x02\x1f\x97\x84j\a-~\x00\x00\u07d4(\x95\xe8\t\x99\xd4\x06\xadY.+&'7\xd3_}\xb4\xb6\x99\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4(\x96r\x80!N!\x8a\x12\f]\xda7\x04\x1b\x11\x1e\xa3mt\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4(\xa3\xda\t\xa8\x19H\x19\xae\x19\x9f.m\x9d\x13\x04\x81~(\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4(\xab\x16_\xfbi\xed\xa0\xc5I\xae8\xe9\x82o_\u007f\x92\xf8S\x89FM\xf6\xd7\xc8DY\x00\x00\u07d4(\xb7u\x85\xcb=U\xa1\x99\xab)\x1d:\x18\u018f\u8684\x8a\x89j@v\xcfy\x95\xa0\x00\x00\xe0\x94(\xd4\xeb\xf4\x1e=\x95\xf9\xbb\x9a\x89u#\\\x1d\x009>\x80\x00\u07d4)\nV\xd4\x1fn\x9e\xfb\xdc\xea\x03B\u0dd2\x9a\x8c\xdf\xcb\x05\x89\x12\xa5\xf5\x81h\xee`\x00\x00\u07d4)\x15bK\xcbg\x917\xb8\xda\xe9\xabW\xd1\x1bI\x05\xea\xeeK\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4)\x1e\xfe\x00\x81\xdc\xe8\xc1G\x99\xf7\xb2\xa46\x19\xc0\u00f3\xfc\x1f\x89A\rXj \xa4\xc0\x00\x00\u07d4)\x1f\x92\x9c\xa5\x9bT\xf8D>=Mu\xd9]\xee$<\xefx\x89\x1b\x1a\b\x927\a=\x00\x00\xe0\x94))\x8c\xcb\xdf\xf6\x89\xf8\u007f\xe4\x1a\xa6\xe9\x8f\u07f5=\xea\xf3z\x8a\x041\\2\xd7\x1a\x9e`\x00\x00\u07d4)/\"\x8b\n\x94t\x8c\x8e\xeca-$o\x98\x93c\xe0\x8f\b\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4)3\x84\xc4+o\x8f)\x05\xceR\xb7 \\\"t7la+\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4)4\xc0\xdf{\xbc\x17+l\x18k\vrTz\u038b\xf7TT\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4)<#\x06\xdf6\x04\xaeO\xda\r z\xbasog\xde\a\x92\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94)I\xfd\x1d\xef\\v\xa2\x86\xb3\x87$$\x80\x9a\a\xdb9f\xf3\x8a\x01\x1b\xd9\x06\u06a0\xc9C\x80\x00\u07d4)OIK?.\x14\xa3\xf8\xab\x00\x00\x00\u07d4)U\xc3W\xfd\x8fu\xd5\x15\x9a=\xfai\u0178z5\x9d\ua309lk\x93[\x8b\xbd@\x00\x00\u07d4)a\xfb9\x1ca\x95|\xb5\xc9\xe4\a\u0762\x938\u04f9,\x80\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4)h\x1d\x99\x12\xdd\xd0~\xaa\xbb\x88\xd0]\x90\xf7f\xe8bA}\x8965\u026d\xc5\u07a0\x00\x00\u07d4)kq\xc0\x01X\x19\xc2B\xa7\x86\x1eo\xf7\xed\xed\x8a_q\xe3\x89lh\xcc\u041b\x02,\x00\x00\u07d4)mf\xb5!W\x1aNA\x03\xa7\xf5b\xc5\x11\xe6\xaas-\x81\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4)o\x00\xde\x1d\u00fb\x01\xd4z\x8c\xcd\x1e]\x1d\u0661\xebw\x91\x8965\u026d\xc5\u07a0\x00\x00\u07d4)s\x85\xe8\x864FV\x85\xc21\xa3\x14\xa0\xd5\xdc\xd1F\xaf\x01\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4)v=\xd6\u069a|\x16\x11s\x88\x83!\ub9b6<\x8f\xb8E\x89\x11\xc7\xea\x16.x \x00\x00\u07d4)yt\x11t\xa8\xc1\xea\v\u007f\x9e\xdfe\x81w\x85\x94\x17\xf5\x12\x89\x19\x01\x96l\x84\x96\x83\x80\x00\u07d4)z\x88\x92\x1b_\xca\x10\u5edd\xed`\x02T7\xae\"\x16\x94\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94)}]\xbe\"//\xb5%1\xac\xbd\v\x01=\xc4F\xacsh\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4)\x82N\x94\xccCH\xbc\x962y\xdc\xdfG9\x17\x152L\u04c9i*\xe8\x89p\x81\xd0\x00\x00\u07d4)\x82\xd7j\x15\xf8G\xddA\xf1\x92*\xf3h\xfeg\x8d\x0eh\x1e\x89\x05k\xc7^-c\x10\x00\x00\u07d4)\x88\x87\xba\xb5|[\xa4\xf0aR)\xd7R_\xa1\x13\xb7\ua249\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94)\x8e\xc7kD\r\x88\a\xb3\xf7\x8b_\x90\x97\x9b\xeeB\xedC\u06ca\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4)\x93h`\x90B\xa8X\xd1\xec\xdf\x1f\xc0\xad\xa5\xea\xce\xca)\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4)\x9e\v\xcaU\xe0i\u0785\x04\xe8\x9a\xcan\xca!\u04ca\x9a]\x89\x03\x027\x9b\xf2\xca.\x00\x00\u07d4)\xac+E\x84T\xa3l~\x96\xc7:\x86g\"*\x12$,q\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94)\xad\u03c3\xb6\xb2\n\u01a44\xab\xb1\x99<\xbd\x05\xc6\x0e\xa2\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94)\xae\xf4\x8d\xe8\xc9\xfb\xadK\x9eL\xa9pyzU3\xebr-\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4)\xb3\xf5a\xeezn%\x94\x1e\x98\xa52[x\xad\u01d7\x85\xf3\x89\x05k\xc7^-c\x10\x00\x00\u07d4)\xbd\xc4\xf2\x8d\xe0\x18\x0fC<&\x94\xebt\xf5PL\xe9C7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4)\u0300M\x92+\xe9\x1fY\t\xf3H\xb0\xaa\xa5\xd2\x1b`x0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94)\xda>5\xb2;\xb1\xf7/\x8e\"X\xcf\u007fU3Y\xd2K\xac\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94)\xe6y\x90\xe1\xb6\xd5.\x10U\xff\xe0I\xc51\x95\xa8\x15B\u03ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4)\uab82v\x17b\xf4\xd2\xdbS\xa9\u018b\x0fk\vmNf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4)\xeb~\xef\xda\xe9\xfe\xb4I\xc6?\xf5\xf2y\xd6u\x10\xeb\x14\"\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4)\xf0\xed\xc6\x038\xe7\x11 \x85\xa1\xd1\x14\u068cB\u038fU\u0589\xa0Z\u007f\x0f\xd8%x\x00\x00\u07d4)\xf8\xfb\xa4\xc3\ar\xb0W\xed\xbb\xe6*\xe7B\f9\x05r\xe1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94)\xf9(l\x0es\x8d\x17!\xa6\x91\u01b9Z\xb3\u0667\x97\xed\xe8\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4*\b^%\xb6Hb\xf5\xe6\x8dv\x8e+\x0fz\x85)\x85\x8e\xee\x89k\x88:\xcdWf\xcd\x00\x00\u07d4**\xb6\xb7Lz\xf1\xd9Gk\xb5\xbc\xb4RG\x97\xbe\xdc5R\x8965\u026d\xc5\u07a0\x00\x00\u07d4*9\x19\nO\u0783\u07f3\xdd\xcbL_\xbb\x83\xaclIu\\\x8965\u026d\xc5\u07a0\x00\x00\u07d4*@\r\xff\x85\x94\xder(\xb4\xfd\x15\xc3#\"\xb7[\xb8}\xa8\x89\x051\xa1\u007f`z-\x00\x00\xe0\x94*D\xa7!\x8f\xe4Me\xa1\xb4\xb7\xa7\u0671\xc2\xc5,\x8c>4\x8a\r-\x06\xc3\x05\xa1\xebW\x80\x00\u07d4*F\xd3Swqv\xff\x8e\x83\xff\xa8\x00\x1fOp\xf9s:\xa5\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4*Y_\x16\xee\xe4\xcb\f\x17\u0662\xd99\xb3\xc1\x0flgrC\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4*Y\xe4~\xa5\xd8\xf0\xe7\xc0(\xa3\xe8\xe0\x93\xa4\x9c\x1bP\xb9\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4*[\xa9\xe3L\u054d\xa5L\x9a'\x12f:;\xe2t\xc8\xe4{\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94*^:@\xd2\xcd\x03%vm\xe7:=g\x18\x96\xb3b\xc7;\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94*cY\x0e\xfe\x99\x86\xc3\xfe\xe0\x9b\n\n3\x8b\x15\xbe\xd9\x1f!\x8a\x01^\x1cN\x05\xee&\xd0\x00\x00\u07d4*gf\n\x13h\xef\xcdbn\xf3k+\x1b`\x19\x80\x94\x1c\x05\x89\a?u\u0460\x85\xba\x00\x00\u07d4*t+\x89\x10\x94\x1e\t2\x83\n\x1d\x96\x92\xcf\u0484\x94\xcf@\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4*tl\xd4@'\xaf>\xbd7\xc3x\xc8^\xf7\xf7T\xab_(\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4*\x81\xd2|\xb6\xd4w\x0f\xf4\xf3\u0123\xba\x18\xe5\xe5\u007f\aQ|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4*\x91\xa9\xfe\xd4\x1b}\x0e\\\xd2\xd81X\xd3\xe8\xa4\x1a\x9a-q\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94*\x9cW\xfe{k\x13\x8a\x92\rgo{\x1a%\x10\x80\xff\xb9\x8a4\xf0\x86\xf3\xb3;h@\x00\x00\u07d4+p\x1d\x16\xc0\xd3\xcc\x1eL\xd8TE\xe6\xad\x02\ue92c\x01-\x89 \x86\xac5\x10R`\x00\x00\xe0\x94+q|\xd42\xa3#\xa4e\x909\x84\x8d;\x87\xde&\xfc\x95F\x8ai\xe1\r\xe7fv\u0400\x00\x00\u07d4+t\xc3s\xd0K\xfb\x0f\xd6\n\x18\xa0\x1a\x88\xfb\xe8Gp\u5309\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4+w\xa4\u060c\rV\xa3\xdb\xe3\xba\xe0J\x05\xf4\xfc\u0477W\xe1\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94+\x84\x88\xbd-<\x19z=&\x15\x18\x15\xb5\xa7\x98\xd2qh\u070a\x01j\x1f\x9f_\xd7\xd9`\x00\x00\u07d4+\x8a\r\xee\\\xb0\xe1\xe9~\x15\xcf\xcan\x19\xad!\xf9\x95\ufb49\x1bUC\x8d\x9a$\x9b\x00\x00\xe0\x94+\x8f\xe4\x16n#\xd1\x19c\xc0\x93+\x8a\u078e\x01E\xea\ap\x8a\t(\x96R\x9b\xad\u0708\x00\x00\xe0\x94+\x99\xb4.OBa\x9e\xe3k\xaa~J\xf2\xd6^\xac\xfc\xba5\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4+\xab\x0f\xbe(\u0544 \xb5 6w\n\x12\xf9\x95*\xeai\x11\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4+\xad\xe9\x1d\x15E\x17b\x0f\u05349\xac\x97\x15zA\x02\xa9\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4+\xaf\x8dn\"\x11t\x12H \xeeI+\x94Y\xecO\xad\xaf\xbb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4+\xaf\xbf\x9e\x9e\xd2\xc2\x19\xf7\xf2y\x13t\xe7\xd0\\\xb0gw\xe7\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\xe0\x94+\xb3f\xb9\xed\xcb\r\xa6\x80\xf0\xe1\v;n(t\x81\x90\xd6\u00ca\x01:b\u05f5v@d\x00\x00\xe0\x94+\xb6\xf5x\xad\xfb\u7ca1\x16\xb3UO\xac\xf9\x96\x98\x13\xc3\x19\x8a\x01\x91'\xa19\x1e\xa2\xa0\x00\x00\u07d4+\xbeb\xea\xc8\f\xa7\xf4\xd6\xfd\xee~}\x8e(\xb6:\xcfw\x0e\x89\x81\xe3-\xf9r\xab\xf0\x00\x00\u07d4+\xbeg*\x18WP\x8fc\x0f*^\xdbV=\x9e\x9d\xe9(\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4+\xc4)\xd6\x18\xa6jL\xf8-\xbb-\x82N\x93V\xef\xfa\x12j\x89lj\xccg\u05f1\xd4\x00\x00\u07d4+\xd2R\xe0\xd72\xff\x1d|x\xf0\xa0.l\xb2T#\xcf\x1b\x1a\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4+\xdd\x03\xbe\xbb\xee';l\xa1\x05\x9b4\x99\x9a[\xbda\xbby\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,\x04\x11\\>R\x96\x1b\r\xc0\xb0\xbf1\xfb\xa4ToYf\xfd\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94,\x06\u0752+aQJ\xaf\xed\xd8D\x88\xc0\u008em\xcf\x0e\x99\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94,\f\xc3\xf9QH,\u0222\x92X\x15hN\xb9\xf9N\x06\x02\x00\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4,\x0e\xe14\u0633aE\xb4{\xee\u7bcd'8\xdb\xda\b\xe8\x89\n\xe5os\x0em\x84\x00\x00\u07d4,\x0f[\x9d\xf46%y\x8e~\x03\xc1\xa5\xfdjm\t\x1a\xf8+\x89\x01\xb0\xfc\xaa\xb2\x000\x00\x00\u07d4,\x12\x8c\x95\xd9W!Q\x01\xf0C\u074f\u0142EmA\x01m\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4,\x18\x00\xf3_\xa0->\xb6\xff[%(_^J\xdd\x13\xb3\x8d\x891\"\u04ed\xaf\xde\x10\x00\x00\u07d4,\x1c\x19\x11N=m\xe2xQHK\x8d'\x15\xe5\x0f\x8a\x10e\x89\x05k\xc7^-c\x10\x00\x00\u07d4,\x1c\xc6\xe1\x8c\x15$\x88\xba\x11\xc2\xcc\x1b\xce\xfa-\xf3\x06\xab\u0449Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94,\x1d\xf8\xa7oH\xf6\xb5K\u03dc\xafV\xf0\xee\x1c\xf5z\xb3=\x8a\x02$\u007fu\x00\x89\xdaX\x00\x00\u07d4,!G\x94z\xe3?\xb0\x98\xb4\x89\xa5\xc1k\xff\xf9\xab\xcdN*\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4,#OP\\\xa8\xdc\xc7}\x9b~\x01\xd2W\xc3\x18\xcc\x199m\x89\x05k\xc7^-c\x10\x00\x00\u07d4,$(\xe4\xa6it\xed\xc8\"\xd5\xdb\xfb$\x1b'(\aQX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,-\x15\xff9V\x1c\x1br\xed\xa1\xcc\x02\u007f\xfe\xf27C\xa1D\x89\u0500\xed\x9e\xf3+@\x00\x00\u07d4,-\xb2\x8c3\t7^\xea1\x82\x1b\x84\xd4\b\x93\x0e\xfa\x1a\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4,Z-\n\xbd\xa0;\xbe!W\x81\xb4\xff)l\x8ca\xbd\xba\xf6\x89\x01\xa8\xe5oH\xc0\"\x80\x00\u07d4,[}{\x19Z7\x1b\xf9\xab\u0774/\xe0O/\x1d\x9a\x99\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4,]\xf8ffj\x19K&\u03bb@~J\x1f\xd7> \x8d^\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94,`?\xf0\xfe\x93alCW>\xf2y\xbf\xea@\x88\x8dj\xe7\x8a\x01\x00\xf4\xb6\xd6gW\x90\x00\x00\xe0\x94,hF\xa1\xaa\x99\x9a\"F\xa2\x87\x05`\x00\xbaM\u02e8\xe6=\x8a\x02\x1f/o\x0f\xc3\xc6\x10\x00\x00\u0794,j\xfc\xd4\x03|\x1e\xd1O\xa7O\xf6u\x8e\tE\xa1\x85\xa8\xe8\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4,ki\x9d\x9e\xad4\x9f\x06\u007fEq\x1a\aJd\x1d\xb6\xa8\x97\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,o\\\x12L\u01c9\xf8\xbb9\x8e?\x88\x97Q\xbcK`-\x9e\x89\x01Y\xf2\v\xed\x00\xf0\x00\x00\u07d4,\x83\xae\xb0/\xcf\x06}e\xa4p\x82\xfd\x97x3\xab\x1c\uc449\b'8#%\x8a\xc0\x00\x00\xe0\x94,\x89\xf5\xfd\xca=\x15T\t\xb68\xb9\x8at.U\xebFR\xb7\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4,\x96HI\xb1\xf6\x9c\xc7\u03a4D%8\xed\x87\xfd\xf1l\xfc\x8f\x89lk\x93[\x8b\xbd@\x00\x00\u0794,\x9f\xa7,\x95\xf3}\b\xe9\xa3`\t\u7930\u007f)\xba\xd4\x1a\x88\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4,\xafk\xf4\xec}Z\x19\xc5\xe0\x89z^\xeb\x01\x1d\xce\xceB\x10\x89\a\x93H5\xa01\x16\x00\x00\u07d4,\xb4\xc3\xc1k\xb1\xc5^|kz\x19\xb1'\xa1\xac\x93\x90\xcc\t\x89\xb8'\x94\xa9$O\f\x80\x00\xe0\x94,\xb5IZPS6\xc2FT\x10\xd1\xca\xe0\x95\xb8\xe1\xba\\\u074a\x04<3\xc1\x93ud\x80\x00\x00\u07d4,\xb6\x15\a:@\xdc\u06d9\xfa\xa8HW.\x98{;\x05n\xfb\x89+X\xad\u06c9\xa2X\x00\x00\u07d4,\xbam]\r\xc2\x04\xea\x8a%\xad\xa2\xe2oVu\xbd_/\u0709H#\xef}\u06da\xf3\x80\x00\u07d4,\xbb\fs\u07d1\xb9\x17@\xb6i;wJ}\x05\x17~\x8eX\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4,\xcbfIM\n\xf6\x89\xab\xf9H=6]x$D\xe7\u07ad\x8965\u026d\xc5\u07a0\x00\x00\u07d4,\xcc\x1f\x1c\xb5\xf4\xa8\x00.\x18k \x88]\x9d\xbc\x03\f\b\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,\u03c0\xe2\x18\x98\x12^\xb4\xe8\a\u0342\xe0\x9b\x9d(Y/n\x89lk\x93[\x8b\xbd@\x00\x00\u07d4,\u0456\x94\u0452j\x0f\xa9\x18\x9e\u07ba\xfcg\x1c\xf1\xb2\u02a5\x8965\u026d\xc5\u07a0\x00\x00\u07d4,\u04d34\xac~\xacyrW\xab\xe3sa\x95\xf5\xb4\xb5\xce\x0f\x89\x05kGx^7&\x00\x00\u07d4,\u05de\xb5 '\xb1,\x18\x82\x8e>\xaa\xb2\x96\x9b\xfc\u0487\xe9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4,\xd8xfV\x8d\xd8\x1a\xd4}\x9d:\u0404nZePss\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4,\xdb9De\x06\x16\xe4|\xb1\x82\xe0`2/\xa1Hyx\u0389b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4,\xe1\x1a\x92\xfa\xd0$\xff+>\x87\xe3\xb5B\xe6\xc6\r\xcb\u0656\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4-\x03&\xb2?\x04\t\xc0\xc0\xe9#hc\xa13\aZ\x94\xba\x18\x89\vg\x9b\xe7[\xe6\xae\x00\x00\u07d4-\r\xecQ\xa6\xe8s0\xa6\xa8\xfa*\x0fe\u060dJ\xbc\xdfs\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4-#vkok\x05s}\xad\x80\xa4\x19\xc4\x0e\xdaMw\x10>\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4-+\x03#Y\xb3c\x96O\xc1\x1aQ\x82c\xbf\xd0T1\xe8g\x89\b\x1c\x1d\xf7b\x9ep\x00\x00\u07d4-4\x80\xbf\be\aJr\xc7u\x9e\xe5\x13{Mp\xc5\x1c\xe9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4-5\xa9\xdfbu\u007f\u007f\xfa\xd1\x04\x9a\xfb\x06\xcaJ\xfcFLQ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4-@U\x8b\x06\xf9\n9#\x14U\x92\x12;gt\xe4n1\xf4\x8965\u026d\xc5\u07a0\x00\x00\u07d4-Bi\x12\xd0Y\xfa\xd9t\v.9\n.\xea\xc0To\xf0\x1b\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4-S-\xf4\xc69\x11\xd1\u0391\xf6\xd1\xfc\xbf\xf7\x96\x0fx\xa8\x85\x89Z\x85\x96\x8aXx\u0680\x00\u07d4-S\x91\xe98\xb3HX\u03d6[\x84\x051\xd5\xef\xdaA\v\t\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94-[B\xfcY\xeb\xda\r\xfdf\xae\x91K\u008c\x1b\nn\xf8:\x8a+\u0235\x9f\xdc\xd86c\x80\x00\u07d4-]s5\xac\xb06+G\u07e3\xa8\xa4\xd3\xf5\x94\x95D\u04c0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-a\xbf\xc5hs\x92<+\x00\t]\xc3\xea\xa0\xf5\x90\u062e\x0f\x8a\x04ef\xdf\xf8\xceU`\x00\x00\u07d4-e\x11\xfdz8\x00\xb2hT\xc7\xec9\xc0\u0735\xf4\xc4\xe8\xe8\x89\x15\xad\u077a/\x9ew\x00\x00\u07d4-}\\@\u076f\xc4P\xb0Jt\xa4\u06bc+\xb5\xd6e\x00.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4-\x89\xa8\x00jO\x13z \xdc+\xecF\xfe.\xb3\x12\xea\x96T\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4-\x8cR2\x9f8\u04a2\xfa\x9c\xba\xf5\u0143\xda\xf1I\v\xb1\x1c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4-\x8e\x06\x18\x92\xa5\xdc\xce!\x96j\xe1\xbb\a\x88\xfd>\x8b\xa0Y\x89\r\x8e\\\xe6\x17\xf2\xd5\x00\x00\u07d4-\x8e[\xb8\xd3R\x16\x95\xc7~|\x83N\x02\x91\xbf\xac\xeet\b\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4-\x90\xb4\x15\xa3\x8e.\x19\xcd\xd0/\U000ed069z\xf7\xcb\xf6r\x89\x05\xf3\xc7\xf6A1\xe4\x00\x00\u07d4-\x9b\xado\x1e\xe0*p\xf1\xf1=\xef\\\u0332z\x9a'@1\x89a\t=|,m8\x00\x00\u07d4-\x9c_\xec\u04b4O\xbbj\x1e\xc72\xea\x05\x9fO\x1f\x9d+\\\x896\xca2f\x1d\x1a\xa7\x00\x00\xe0\x94-\xa6\x17iP\t\xccW\xd2j\u0510\xb3*]\xfb\xeb\x93N^\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4-\xa7k|9\xb4 \u323a,\x10 \xb0\x85k\x02pd\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4-\u01ddn\u007fU\xbc\xe2\xe2\xd0\xc0*\xd0|\uca3bR\x93T\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\xe0\x94-\xca\x0eD\x9a\xb6F\xdb\xdf\u04d3\xa9fb\x96\v\u02b5\xae\x1e\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4-\xd3%\xfd\xff\xb9{\x19\x99R\x84\xaf\xa5\xab\xdbWJ\x1d\xf1j\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4-\xd5x\xf7@}\xfb\xd5H\xd0^\x95\xcc\u00dcHT)bj\x89\u3bb5sr@\xa0\x00\x00\u07d4-\xd8\xee\xef\x87\x19J\xbc,\xe7X]\xa1\xe3[|\xeax\f\xb7\x8965\xc6 G9\u0640\x00\u07d4-\xdf@\x90Wi\xbc\xc4&\xcb,)8\xff\xe0w\xe1\u8758\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4-\xe0\x96D\x00\u0082\xbd\u05ca\x91\x9ck\xf7|k_yay\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-\xe3\x1a\xfd\x18\x9a\x13\xa7o\xf6\xfes\xea\xd9\xf7K\xb5\u0126)\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4-\xec\x982\x9d\x1f\x96\u00e5\x9c\xaay\x81uTR\xd4\xdaI\u0549\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94-\ue422\x8f\x19-gj\x87s#+V\xf1\x8f#\x9e/\xad\x8a\x03\xef\xa7\xe7G\xb6\u046d\x00\x00\xe0\x94.\b\x80\xa3E\x96#\a \xf0Z\xc8\xf0e\xaf\x86\x81\u0736\u008a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4.\fW\xb4qP\xf9Z\xa6\xa7\xe1j\xb9\xb1\xcb\xf5C(\x97\x9a\x89\x05k\xc7^-c\x10\x00\x00\u07d4.\x10\x91\v\xa6\xe0\xbc\x17\xe0UUf\x14\u02c7\t\x0fM~[\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94.$\xb5\x97\x87;\xb1A\xbd\xb27\xea\x8aZ\xb7Gy\x9a\xf0-\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4.(\x10\xde\xe4J\xe4\xdf\xf3\xd8cB\xab\x12fW\xd6S\xc36\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4.,\xbdz\xd8%G\xb4\xf5\xff\x8b:\xb5o\x94*dE\xa3\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4.-~\xa6k\x9fG\xd8\xccR\xc0\x1cR\xb6\u147c}G\x86\x89\xd8\xd4`,&\xbfl\x00\x00\u07d4.C\x93H\u07caBw\xb2*v\x84W\xd1\x15\x8e\x97\xc4\t\x04\x89*\x1e\x9f\xf2o\xbfA\x00\x00\xe0\x94.F\xfc\xeej;\xb1E\xb5\x94\xa2C\xa3\x91?\xce]\xado\xba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794.G\xf2\x87\xf4\x98#7\x13\x85\r1&\x82<\xc6}\xce\xe2U\x88\u029d\x9e\xa5X\xb4\x00\x00\u07d4.N\u1b99j\xa0\xa1\xd9$(\xd0fR\xa6\xbe\xa6\xd2\xd1]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.R\x91+\xc1\x0e\xa3\x9dT\xe2\x93\xf7\xae\u05b9\x9a\x0fLs\xbe\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4.a\x9fW\xab\xc1\u91ea\x93j\xe3\xa2&Ib\xe7\xeb-\x9a\x89(\xfb\x9b\x8a\x8aSP\x00\x00\u07d4.d\xa8\xd7\x11\x11\xa2/L]\xe1\xe09\xb36\xf6\x8d9\x8a|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.i3T=O,\xc0\vSP\xbd\x80h\xba\x92C\u05be\xb0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94.~\x05\xe2\x9e\u0767\xe4\xae%\xc5\x175C\xef\xd7\x1fm=\x80\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4.\u007fFU \xec5\xcc#\u058eue\x1b\xb6h\x95D\xa1\x96\x898\xec[r\x1a\x1a&\x80\x00\u07d4.\x8e\xb3\nqn_\xe1\\t#>\x03\x9b\xfb\x11\x06\xe8\x1d\x12\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94.\x98$\xb5\xc12\x11\x1b\xca$\xdd\xfb\xa7\xe5u\xa5\xcdr\x96\xc1\x8a\x03\xa4\x84Qnm\u007f\xfe\x00\x00\u07d4.\xa5\xfe\xe6?3z7nK\x91\x8e\xa8!H\xf9MH\xa6&\x89e\x0f\x8e\r\u0493\xc5\x00\x00\u07d4.\xafN*F\xb7\x89\xcc\u0088\xc8\xd1\xd9)N?\xb0\x858\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4.\xaf\xf9\xf8\xf8\x110d\u04d5z\xc6\xd6\xe1\x1e\xeeB\xc8\x19]\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4.\xba\fn\xe5\xa1\x14\\\x1cW9\x84\x96:`]\x88\nz \x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4.\xc9X\"\xeb\x88{\xc1\x13\xb4q*M\xfd\u007f\x13\xb0\x97\xb5\xe7\x8965\u026d\xc5\u07a0\x00\x00\u07d4.\xcaj<]\x9fD\x9d\tV\xbdC\xfa{M{\xe8CYX\x89lk\xdaip\x9c\xc2\x00\x00\xe0\x94.\xca\xc5\x04\xb23\x86n\xb5\xa4\xa9\x9e{\u0490\x13Y\xe4;=\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4.\xeb\xf5\x942\xb5(\x92\xf98\v\xd1@\xaa\x99\xdc\xf8\xad\f\x0f\x89\b=lz\xabc`\x00\x00\u07d4.\xee\xd5\x04q\xa1\xa2\xbfS\xee0\xb1#.n\x9d\x80\xef\x86m\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4.\xefk\x14\x17\u05f1\x0e\xcf\xc1\x9b\x12:\x8a\x89\xe7>RlX\x89 \x86\xac5\x10R`\x00\x00\u07d4.\xf8i\xf05\vW\xd54x\xd7\x01\xe3\xfe\xe5)\xbc\x91\x1cu\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4.\xf9\xe4eqj\xca\u03f8\xc8%/\xa8\xe7\xbcyi\xeb\xf6\u4255\x9e\xb1\xc0\xe4\xae \x00\x00\xe0\x94.\xfcLd}\xacj\xca\xc3Uw\xad\"\x17X\xfe\xf6ao\xaa\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4/\x13eu&\xb1w\xca\xd5G\u00d0\x8c\x84\x0e\xffd{E\u0649?v\x84\x9c\xf1\xee,\x80\x00\u07d4/\x18}ZpMZ3\x8c[(v\xa0\x90\xdc\xe9d(N)\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94/%#\u0303O\x00\x86\x05$\x02bb\x96gQ\x86\xa8\u508a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4/(*\xbb\xb6\u0523\xc3\xcd;\\\xa8\x12\xf7d>\x800_\x06\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4/+\xba\x1b\x17\x96\x82\x1avo\xced\xb8O(\xech\xf1Z\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4/1]\x90\x16\xe8\xee_Sf\x81 /\x90\x84\xb02TMM\x898<\xd1+\x9e\x86<\x00\x00\u07d4/M\xa7SC\x0f\xc0\x9es\xac\xbc\xcd\xcd\xe9\xdad\u007f+]7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4/P\x80\xb8?~-\xc0\xa1\xdd\x11\xb0\x92\xad\x04+\xffx\x8fL\x89\xb4\xf8\xfby#\x1d+\x80\x00\u07d4/a\uf941\x9dp_+\x1eN\xe7T\xae\xb8\xa8\x19Pju\x89O%\x91\xf8\x96\xa6P\x00\x00\xe0\x94/f\xbf\xbf\"b\xef\u030d+\xd0DO\u0170ib\x98\xff\x1e\x8a\x02\x1a\xd95\xf7\x9fv\xd0\x00\x00\u07d4/m\xce\x130\u015e\xf9!`!TW-MK\xac\xbd\x04\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4/}2\x90\x85\x1b\xe5\u01b4\xb4?}Et2\x9fa\xa7\x92\u00c9\x05k\xc7^-c\x10\x00\x00\u07d4/\x858\x17\xaf\u04f8\xf3\xb8n\x9f`\xeew\xb5\xd9ws\xc0\xe3\x89N\xae\xeaD\xe3h\xb9\x00\x00\u07d4/\xa4\x91\xfbY \xa6WN\xbd(\x9f9\xc1\xb2C\r-\x9aj\x89lk\x93[\x8b\xbd@\x00\x00\u07d4/\xb5f\xc9K\xbb\xa4\xe3\xcbg\xcd\xda}_\xadq1S\x91\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4/\xbbPJ]\xc5'\xd3\xe3\xeb\x00\x85\xe2\xfc<}\xd58\xcbz\x89C\u00b1\x8a\xec<\n\x80\x00\u07d4/\xbc\x85y\x8aX5\x98\xb5\"\x16mn\x9d\xda\x12\x1db}\xbc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4/\xbc\xef3\x84\xd4 \xe4\xbfa\xa0f\x99\x90\xbcpT\U00065bc9lk\x93[\x8b\xbd@\x00\x00\xe0\x94/\xc8.\xf0v\x93#A&Oaz\f\x80\xddW\x1ej\xe99\x8a\x01\x84$\xf5\xf0\xb1\xb4\xe0\x00\x00\u07d4/\u075by\u07cd\xf50\xadc\xc2\x0eb\xafC\x1a\xe9\x92\x16\xb8\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4/\xe0\x02?W\"e\x0f:\x8a\xc0\x10\t\x12^t\xe3\xf8.\x9b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4/\xe0\xccBKS\xa3\x1f\t\x16\xbe\b\xec\x81\xc5\v\xf8\xea\xb0\xc1\x89 \x86\xac5\x10R`\x00\x00\u07d4/\xe1:\x8d\a\x85\u0787X\xa5\xe4\x18v\xc3n\x91l\xf7Pt\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4/\xea\x1b/\x83O\x02\xfcT3?\x8a\x80\x9f\x048\xe5\x87\n\xa9\x89\x01\x18T\xd0\xf9\xce\xe4\x00\x00\u07d4/\xee6\xa4\x9e\xe5\x0e\xcfqo\x10G\x91VFw\x9f\x8b\xa0?\x899B\"\xc4\u0686\xd7\x00\x00\u07d4/\xef\x81G\x8aK.\x80\x98\xdb_\xf3\x87\xba!S\xf4\xe2+y\x896'\xe8\xf7\x127<\x00\x00\u07d4/\xf1`\xc4Or\xa2\x99\xb5\xec-q\xe2\x8c\xe5Dm/\u02ef\x89\x13\x84\x00\xec\xa3d\xa0\x00\x00\u07d4/\xf1\xcaU\xfd\x9c\xec\x1b\x1f\xe9\U00029af7LQ<\x1e*\xaa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94/\xf5\u02b1,\r\x95\u007f\xd33\xf3\x82\xee\xb7Q\a\xa6L\xb8\xe8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94/\xf80\xcfU\xfb\x00\u0560\xe05\x14\xfe\xcdD1K\xd6\xd9\xf1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4/\xfe\x93\xec\x1aV6\xe9\xee4\xafp\xdf\xf5&\x82\xe6\xffpy\x89lk\x93[\x8b\xbd@\x00\x00\u07d40\x03y\x88p&q\xac\xbe\x89,\x03\xfeW\x88\xaa\x98\xaf(z\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d40$\x8dX\xe4\x14\xb2\x0f\xed:lH+Y\xd9\xd8\xf5\xa4\xb7\xe2\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4019\xbcYd\x03\xd5\u04d3\x1fwLf\u013aFtT\u06c9\\%\xe1J\xea(?\x00\x00\u079408\x00\x87xie\x14\x9e\x81B;\x15\xe3\x13\xba2\xc5\u01c3\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d40:0\xacB\x86\xae\x17\xcfH=\xad{\x87\fk\xd6M{J\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d40?\xba\xeb\xbeF\xb3[n[t\x94j_\x99\xbc\x15\x85\xca\xe7\x89/\x9a\xc0i_[\xba\x00\x00\u07d40ADZ3\xba\x15\x87A\x16\r\x9c4N\xb8\x8e\\0o\x94\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d40H\x01d\xbc\xd8It\xeb\xc0\xd9\f\x9b\x9a\xfa\xb6&\xcd\x1cs\x89+^:\xf1k\x18\x80\x00\x00\u07d40N\u019atTW!\xd71j\xefM\u03f4\x1a\u015e\xe2\xf0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x940Q\x182\x91\x8d\x804\xa7\xbe\xe7.\xf2\xbf\xeeD\x0e\u02fc\xf6\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d40Q?\u029f6\xfdx\x8c\xfe\xa7\xa3@\xe8m\xf9\x82\x94\xa2D\x89\x18;_\x03\xb1G\x9c\x00\x00\u07d40U\xef\xd2`)\xe0\xd1\x1b\x93\r\xf4\xf5;\x16,\x8c?\xd2\u0389\x1b\x1a\b\x927\a=\x00\x00\u07d40]&\xc1\v\xdc\x10?k\x9c!'.\xb7\xcb-\x91\b\xc4~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d40_x\xd6\x18\xb9\x90\xb4)[\xac\x8a-\xfa&(\x84\xf8\x04\xea\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x940d\x89\x9a\x96\x1a>\x1d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d40\x98\xb6]\xb9>\xca\xca\xf75\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d40\uc4d2$J!\b\u0247\xbc\\\xdd\xe0\ud7c3z\x81{\x89T\x99%\xf6\xc9\xc5%\x00\x00\xe0\x940\xed\x11\xb7{\xc1~^f\x94\u023c[nG\x98\xf6\x8d\x9c\xa7\x8a\x1eo\xb3B\x1f\xe0)\x9e\x00\x00\u07d40\xf7\xd0%\xd1o{\xee\x10U\x80Ho\x9fV\x1c{\xae?\xef\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x940\xfb\xe5\x88_\x9f\xcc\xe9\xea^\u06c2\xedJ\x11\x96\xdd%\x9a\xed\x8a\x01\x19\xe4\u007f!8\x1f@\x00\x00\u07d41\x04}p?c\xb94$\xfb\xbdn/\x1f\x9et\xde\x13\xe7\t\x89\x9a\x81f\xf7\u6ca7\x80\x00\u07d411?\xfdc[\xf2\xf32HA\xa8\x8c\a\xed\x14aD\xce\xeb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d41Y\xe9\fH\xa9\x15\x90J\xdf\u24b2/\xa5\xfd^ryk\x896\xaf\xe9\x8f&\x06\x10\x00\x00\u07d41]\xb7C\x9f\xa1\u0574#\xaf\xa7\xddq\x98\xc1\xcft\xc9\x18\xbc\x89 \x86\xac5\x10R`\x00\x00\u07d41^\xf2\xdab\x0f\xd30\xd1.\xe5]\xe5\xf3)\xa6\x96\xe0\xa9h\x89\b!\xab\rD\x14\x98\x00\x00\u07d41n\x92\xa9\x1b\xbd\xa6\x8b\x9e/\x98\xb3\xc0H\x93N<\xc0\xb4\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d41n\xb4\xe4}\xf7\x1bB\xe1mo\xe4h%\xb72{\xaf1$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d41q\x87~\x9d\x82\f\xc6\x18\xfc\t\x19\xb2\x9e\xfd3?\xdaI4\x8965\u026d\xc5\u07a0\x00\x00\u07d41|\xf4\xa2<\xb1\x91\xcd\xc5c\x12\u009d\x15\xe2\x10\xb3\xb9\xb7\x84\x89\a\xcef\xc5\x0e(@\x00\x00\u07d41\x8b.\xa5\xf0\xaa\xa8y\xc4\xd5\xe5H\xac\x9d\x92\xa0\xc6t\x87\xb7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d41\x8cv\xec\xfd\x8a\xf6\x8dpUSR\xe1\xf6\x01\xe3Y\x88\x04-\x89\x1b1\x19.h\xc7\xf0\x00\x00\u07d41\x8f\x1f\x8b\xd2 \xb0U\x8b\x95\xfb3\x10\x0f\xfd\xbbd\r|\xa6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d41\xaa;\x1e\xbe\x8cM\xbc\xb6\xa7\b\xb1\xd7H1\xe6\x0eIv`\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d41\xab\b\x89f\xec\xc7\"\x92X\xf6\t\x8f\xceh\xcf9\xb3\x84\x85\x8965\u026d\xc5\u07a0\x00\x00\xe0\x941\xadM\x99F\xef\t\xd8\xe9\x88\xd9F\xb1\"\u007f\x91A\x90\x176\x8a\x04\xd8S\xc8\xf8\x90\x89\x80\x00\x00\xe0\x941\xb4;\x01]\x00\x81d~h\x00\x00\u07d424\x86\xcad\xb3uGO\xb2\xb7Y\xa9\xe7\xa15\x85\x9b\xd9\xf6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d427I\xa3\xb9q\x95\x9eF\u0234\x82-\xca\xfa\xf7\xaa\xf9\xbdn\x89\x01\x16q\xa5\xb2Ep\x00\x00\u07d42:\xadA\xdfKo\xc8\xfe\u038c\x93\x95\x8a\xa9\x01\xfah\bC\x894\x95tD\xb8@\xe8\x00\x00\xe0\x942;<\xfe>\xe6+\xbd\xe2\xa2a\xe5<\xb3\xec\xc0X\x10\xf2\u018a\x02\ub3b1\xa1r\u0738\x00\x00\u07d42?\xca^\xd7\u007fi\x9f\x9d\x990\xf5\xce\xef\xf8\xe5oY\xf0<\x89Hz\x9a0E9D\x00\x00\u07d42H\\\x81\x87(\xc1\x97\xfe\xa4\x87\xfb\xb6\xe8)\x15\x9e\xba\x83p\x899!\xb4\x13\xbcN\xc0\x80\x00\xe0\x942P\xe3\xe8X\xc2j\xde\u032d\xf3jVc\xc2*\xa8LAp\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x942Y\xbd/\xdd\xfb\xbco\xba\u04f6\xe8t\xf0\xbb\xc0,\xda\x18\xb5\x8a\x02\x84`VI[\r\x18\x80\x00\u07d42uIo\xd4\u07491\xfdi\xfb\n\v\x04\xc4\xd1\xff\x87\x9e\xf5\x89\x18-~L\xfd\xa08\x00\x00\u07d42{\xb4\x9euOo\xb4\xf73\xc6\xe0o9\x89\xb4\xf6]K\xee\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d42\x82y\x1do\xd7\x13\xf1\xe9OK\xfdV^\xaax\xb3\xa0Y\x9d\x89Hz\x9a0E9D\x00\x00\u07d42\x83\xeb\u007f\x917\xdd9\xbe\xd5_\xfek\x8d\xc8E\xf3\xe1\xa0y\x89\x03\x97\n\xe9!Ux\x00\x00\u07d42\x86\t\x97\xd70\xb2\xd8;s$\x1a%\xd3f}Q\xc9\b\xef\x89\x1b\x1a\b\x927\a=\x00\x00\xe0\x942\x86\u047cez1,\x88G\xd9<\xb3\xcbyP\xf2\xb0\xc6\xe3\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x942\xa2\r\x02\x8e,b\x18\xb9\xd9[D\\w\x15$cj\"\xef\x8a\x02\x02\xfe\xfb\xf2\xd7\xc2\xf0\x00\x00\u07d42\xa7\x06\x91%\\\x9f\xc9y\x1aOu\u0238\x1f8\x8e\n%\x03\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d42\xb7\xfe\xeb\xc5\u015b\xf6^\x86\x1cL\v\xe4*v\x11\xa5T\x1a\x89w\u9aa8R\\\x10\x00\x00\xe0\x942\xba\x9a}\x04#\xe0:R_\xe2\xeb\xebf\x1d \x85w\x8b\u060a\x04<3\xc1\x93ud\x80\x00\x00\u07d42\xbb.\x96\x93\xe4\xe0\x854M/\r\xbdF\xa2\x83\u3807\xfd\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x942\xc2\xfd\u2daa\xbb\x80\u5ba2\xb9I\xa2\x17\xf3\xcb\t\"\x83\x8a\x010a`\xaf\xdf 7\x80\x00\u07d42\xd9P\xd5\xe9>\xa1\u0574\x8d\xb4qO\x86{\x03 \xb3\x1c\x0f\x897\b\xba\xed=h\x90\x00\x00\u07d42\u06f6qlT\xe81e\x82\x9aJ\xbb6uxI\xb6\xe4}\x8965\u026d\xc5\u07a0\x00\x00\u07d42\xebd\xbe\x1b]\xed\xe4\b\u01bd\xef\xben@\\\x16\xb7\xed\x02\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d42\xef\\\xdcg\x1d\xf5V*\x90\x1a\xee]\xb7\x16\xb9\xbev\xdc\xf6\x89lk\x93[\x8b\xbd@\x00\x00\u07d42\xf2\x9e\x87'\xa7LkC\x01\xe3\xff\xff\x06\x87\xc1\xb8p\xda\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d42\xfa\x0e\x86\xcd\b}\u058di1\x90\xf3-\x931\t\t\xedS\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d42\xfb\xee\xd6\xf6&\xfc\xdf\xd5\x1a\xca\xfbs\v\x9e\xef\xf6\x12\xf5d\x89lk\x93[\x8b\xbd@\x00\x00\u07943\x00\xfb\x14\x9a\xde\xd6[\u02e6\xc0N\x9c\u05b7\xa0;\x89;\xb1\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x943\x01\xd9\xca/;\xfe\x02by\xcdh\x19\xf7\x9a)=\x98\x15n\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\xe0\x943\b\xb04f\xc2z\x17\xdf\xe1\xaa\xfc\xeb\x81\xe1m)4Vo\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07943\x1a\x1c&\xcci\x94\xcd\xd3\xc1K\xec\xe2v\xff\xffK\x9d\xf7|\x88\xfaz\xed\xdfO\x06\x80\x00\xe0\x943&\xb8\x8d\xe8\x06\x18DT\xc4\v'\xf3\t\xd9\xddm\u03f9x\x8a\x03\xca\\f\u067cD0\x00\x00\xe0\x943)\xeb;\xafCE\xd6\x00\xce\xd4\x0en\x99ueo\x117B\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d432\r\xd9\x0f+\xaa\x11\r\xd34\x87*\x99\x8f\x14\x84&E<\x8965f3\xeb\xd8\xea\x00\x00\u07d436\xc3\xefn\x8bP\xee\x90\xe07\xb1d\xb7\xa8\xea_\xaa\xc6]\x89\x0e\u0223\xa7\x1c\"T\x00\x00\xe0\x9438\fo\xffZ\xcd&Q0\x96)\u06daq\xbf? \u017a\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d43:\xd1Yd\x01\xe0Z\xea-6\xcaG1\x8e\xf4\xcd,\xb3\u07c9\x9d\xc0\\\xce(\u00b8\x00\x00\u07d43C@\xeeK\x9c\u0701\xf8P\xa7Q\x16\xd5\x0e\u9d98%\xbf\x89lk\x93[\x8b\xbd@\x00\x00\u07d43H\x1e\x85n\xbe\u050e\xa7\b\xa2t&\xef(\xe8g\xf5|\u0449\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x943V[\xa9\xda,\x03\xe7x\xce\x12)O\b\x1d\xfe\x81\x06M$\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07943X\x1c\xee#0\x88\xc0\x86\r\x94N\f\xf1\u03ab\xb8&\x1c.\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d43XX\xf7I\xf1i\u02bc\xfeR\xb7\x96\xe3\xc1\x1e\xc4~\xa3\u0089\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x943^\"\x02[zw\u00e0t\u01cb\x8e=\xfe\a\x13A\x94n\x8a\x02'\xcas\n\xb3\xf6\xac\x00\x00\u07d43b\x9b\xd5/\x0e\x10{\xc0q\x17ld\xdf\x10\x8fdw}I\x89\x01\xcf\xddth!n\x80\x00\u07d43{;\u07c6\xd7\x13\xdb\xd0{]\xbf\xcc\x02+z{\x19F\xae\x89\xd7\xc1\x98q\x0ef\xb0\x00\x00\u07d43|\xfe\x11W\xa5\u0191 \x10\xddV\x153y\x17i\u00b6\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d43\xb36\xf5\xba^\xdb{\x1c\xcc~\xb1\xa0\u0644\xc1#\x1d\x0e\u0709lk\x93[\x8b\xbd@\x00\x00\u07d43\xc4\a\x13;\x84\xb3\xcaL=\xed\x1fFX\x90\f8\x10\x16$\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\xe0\x943\xd1r\xab\a\\Q\xdb\x1c\xd4\n\x8c\xa8\xdb\xff\r\x93\xb8C\xbb\x8a\x016x\x05\x10\xd1-\xe3\x80\x00\u07d43\xe9\xb7\x18#\x95.\x1ff\x95\x8c'\x8f\u008b\x11\x96\xa6\u0164\x89\x05k\xc7^-c\x10\x00\x00\u07d43\xeakxU\xe0[\a\xab\x80\u06b1\xe1M\xe9\xb6I\xe9\x9bl\x89\x1c\xd6\xfb\xadW\xdb\xd0\x00\x00\u07d43\xf1R#1\rD\u078bf6h_:L=\x9cVU\xa5\x89\r\x94b\xc6\xcbKZ\x00\x00\u07d43\xf4\xa6G\x1e\xb1\xbc\xa6\xa9\xf8[;Hr\xe1\aU\xc8+\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d43\xfbWzM!O\xe0\x10\xd3,\xca|>\xed\xa6?\x87\xce\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d43\xfdq\x8f\v\x91\xb5\xce\u020a]\xc1^\xec\xf0\xec\xef\xa4\xef=\x89\x17r$\xaa\x84Lr\x00\x00\u07d44\x14\x80\u030c\xb4v\xf8\xd0\x1f\xf3\b\x12\xe7\xc7\x0e\x05\xaf\xaf]\x89lk\x93[\x8b\xbd@\x00\x00\u07d44'-^ut1]\xca\u9afd1{\xac\x90(\x9dGe\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x9440\xa1c\x81\xf8i\xf6\xeaT#\x91XU\xe8\x00\x885%\xa9\x8a\x03\xca\\f\u067cD0\x00\x00\u07d441\x86%\x81\x8e\xc1?\x11\x83Z\xe9sS\xce7}oY\n\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d449<]\x91\xb9\xdeYr\x03\xe7[\xacC\t\xb5\xfa=(\u00c9\n\x84Jt$\xd9\xc8\x00\x00\u07d449\x99\x8b$|\xb4\xbf\x8b\xc8\nm+5'\xf1\xdf\xe9\xa6\u0489\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d44C}\x14ed\v\x13l\xb5\x84\x1c?\x93O\x9b\xa0\xb7\t}\x89\t`\xdbwh\x1e\x94\x00\x00\u07d44J\x8d\xb0\x86\xfa\xedN\xfc7\x13\x1b:\"\xb0x-\xadp\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x944fM\"\x0f\xa7\xf3yX\x02J32\u0584\xbc\xc6\xd4\u023d\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d44f\xf6~9cl\x01\xf4;:!\xa0\xe8R\x93%\xc0\x86$\x89-\xb1\x16vP\xac\xd8\x00\x00\u07d44\x856\x1e\xe6\xbf\x06\xefe\b\xcc\xd2=\x94d\x1f\x81M>/\x89lk\x93[\x8b\xbd@\x00\x00\u07d44\x85\xf6!%d3\xb9\x8aB\x00\xda\xd8W\xef\xe5Y7\uc609lk\x93[\x8b\xbd@\x00\x00\u07d44\x95\x8aF\xd3\x0e0\xb2s\xec\xc6\xe5\xd3X\xa2\x12\xe50~\x8c\x89lk\x93[\x8b\xbd@\x00\x00\u07d44\x97\xddf\xfd\x11\x80q\xa7\x8c,\xb3n@\xb6e\x1c\xc8%\x98\x89\x05\xf1\x01kPv\xd0\x00\x00\xe0\x944\x9a\x81k\x17\xab='\xbb\xc0\xae\x00Q\xf6\xa0p\xbe\x1f\xf2\x9d\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d44\x9d,\x91\x8f\u041e(\a1\x8ef\xceC)\t\x17k\xd5\v\x89<\xb7\x1fQ\xfcU\x80\x00\x00\u07d44\xa0C\x1f\xff^\xad\x92\u007f\xb6`\f\x1e\xa8\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d44\xff&\xeb`\xa8\u0469ZH\x9f\xae\x13n\xe9\x1dNX\bL\x89 \x86\xac5\x10R`\x00\x00\u07d44\xffX)R\xff$E\x8f{\x13\xd5\x1f\vO\x98p\"\xc1\xfe\x89\x98\x06\xde=\xa6\xe9x\x00\x00\u07d45\x10k\xa9N\x85c\u0533\xcb<\\i,\x10\xe6\x04\xb7\xce\u0609lk\x93[\x8b\xbd@\x00\x00\xe0\x945\x14_b\x03\x97\u019c\xb8\xe0\tb\x96\x1f\x0fH\x86d9\x89\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d45\x14t0\xc3\x10e\x00\u77e2\xf5\x02F.\x94p<#\xb1\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x945\x17\x87\x845\x05\xf8\xe4\xef\xf4ef\xcc\u695fM\x1c_\xe7\x8a\x01\xf5q\x89\x87fKH\x00\x00\xe0\x945\x1f\x16\xe5\xe0sZ\xf5gQ\xb0\xe2%\xb2B\x11q9@\x90\x8a\x02\xd4\xca\x05\xe2\xb4<\xa8\x00\x00\xe0\x945$\xa0\x00#N\xba\xaf\a\x89\xa14\xa2\xa4\x178<\xe5(*\x8a\x011yU\x94}\x8e,\x00\x00\u07d45&\xee\xce\x1ak\xdc>\xe7\xb4\x00\xfe\x93[HF?1\xbe\u05c9\x04w\x87\x9bm\x140\x00\x00\u07d45*x_J\x92\x162PL\xe5\xd0\x15\xf8\xd7FO\xa3\xdb\x14\xe7r\x92\x13\u03aa7\x8c\t^\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d45\xaf\x04\n\f\xc23zv\xaf(\x81T\xc7V\x1e\x1a#3I\x8965\u026d\xc5\u07a0\x00\x00\u07d45\xb0>\xa4$W6\xf5{\x85\xd2\xebyb\x8f\x03m\xdc\xd7\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d45\xbd$he\xfa\xb4\x90\xac\bz\xc1\xf1\xd4\xf2\xc1\r\f\xda\x03\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x945\xbff\x88R/5Fz\u007fu0#\x14\xc0+\xa1v\x80\x0e\x8a\x03\xafA\x82\x02\xd9T\xe0\x00\x00\u07d45\u022d\xc1\x11%C+;w\xac\xd6F%\xfeX\xeb\xee\x9df\x89lk\x93[\x8b\xbd@\x00\x00\u07d45\u0497\x0fI\xdc\xc8\x1e\xa9\xeep~\x9c\x8a\n\xb2\xa8\xbbtc\x89N\x10\x03\xb2\x8d\x92\x80\x00\x00\u07d45\xe0\x96\x12\r\xea\xa5\xc1\xec\xb1d^,\u02cbN\xdb\xd9)\x9a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d45\xea!c\xa3\x8c\u07da\x12?\x82\xa5\xec\x00%\x8d\xae\v\xc7g\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d45\xf1\xda\x12{\x837o\x1b\x88\xc8*3Y\xf6z^g\xddP\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d45\xf2\x94\x9c\xf7\x8b\xc2\x19\xbbO\x01\x90|\xf3\xb4\xb3\u04c6T\x82\x89\x0f\xb5\xc8l\x92\xe44\x00\x00\u07d45\xf5\x86\x01I\xe4\xbb\xc0K\x8a\u0172r\xbeU\xad\x1a\xcaX\xe0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d46\x02E\x8d\xa8omj\x9d\x9e\xb0=\xaf\x97\xfeV\x19\xd4B\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x057-\x93\xa9\x01\t\x88\x01\x8f\x9f1]\x03.\u0448\x0f\xa1\x89\x1b\x1b\xcfQ\x89j}\x00\x00\u07d46\x16\xd4H\x98_]2\xae\xfa\x8b\x93\xa9\x93\xe0\x94\xbd\x85I\x86\x89\v\"\u007fc\xbe\x81<\x00\x00\u07d46\x16\xfbF\xc8\x15x\xc9\xc8\xebM;\xf8\x80E\x1a\x887\x9d}\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d46\x1cu\x93\x16\x96\xbc=B}\x93\xe7lw\xfd\x13\xb2A\xf6\xf4\x89\x1d\xc5\xd8\xfc&m\xd6\x00\x00\u07d46\x1d\x9e\xd8\v[\xd2|\xf9\xf1\"o&u2X\xee_\x9b?\x89\xbfi\x14\xba}r\xc2\x00\x00\u07d46\x1f;\xa9\xed\x95kw\x0f%}6r\xfe\x1f\xf9\xf7\xb0$\f\x89 \x86\xac5\x10R`\x00\x00\u07d46\"|\u07e0\xfd;\x9d~jtF\x85\xf5\xbe\x9a\xa3f\xa7\xf0\x89\n\xc2s\x0e\xe9\xc6\xc1\x80\x00\u07d46/\xbc\xb1\x06b7\n\x06\x8f\xc2e&\x02\xa2Wy7\xcc\xe6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d460\xc5\xe5e\u03aa\x8a\x0f\x0f\xfe2\x87^\xae*l\xe6<\x19\x89\t7r+7t\xd0\x00\x00\u07d463\x9f\x84\xa5\u00b4L\xe5=\xfd\xb6\xd4\xf9}\xf7\x82\x12\xa7\u07c9\x11o\x18\xb8\x17\x15\xa0\x00\x00\u07d464:\xec\xa0{n\u054a\x0eb\xfaN\xcbI\x8a\x12O\xc9q\x89\x10CV\x1a\x88)0\x00\x00\u07d46au@4\x81\xe0\xab\x15\xbbQF\x15\u02f9\x89\xeb\u018f\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d46ro;\x88Z$\xf9)\x96\u0681b^\u022d\x16\xd8\xcb\xe6\x89S\xafu\u0441HW\x80\x00\xe0\x946s\x95C\x99\xf6\u07feg\x18\x18%\x9b\xb2x\xe2\xe9.\xe3\x15\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d46u\x8e\x04\x9c\u064b\u03a1\"w\xa6v\xf9)sb\x89\x00#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d46\u007fY\u0302yS)8NA\xe1(1\x15\xe7\x91\xf2j\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x81\x0f\xf9\xd2\x13\xa2q\xed\xa2\xb8\xaay\x8b\xe6T\xfaK\xbe\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d46\x8cT\x14\xb5k\x84U\x17\x1f\xbf\ab \xc1\u02e4\xb5\xca1\x89\x1e>\xf9\x11\xe8=r\x00\x00\xe0\x946\x90$k\xa3\xc8\x06y\xe2.\xacD\x12\xa1\xae\xfc\xe6\xd7\u0342\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d46\x92\x8bU\xbc\x86\x15\t\xd5\x1c\x8c\xf1\xd5F\xbf\xecn>\x90\xaf\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d46\x98\"\xf5W\x8b@\xdd\x1fDqpk\"\u0357\x13R\xdak\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d46\x9e\xf7a\x19_:7>$\xec\xe6\xcd\"R\x0f\xe0\xb9\xe8n\x89\x1c\xff\xaf\xc9M\xb2\b\x80\x00\u07d46\xa0\x8f\xd6\xfd\x1a\xc1|\xe1^\xd5~\xef\xb1*+\u2048\xbf\x89Hz\x9a0E9D\x00\x00\u07d46\xa0\xe6\x1e\x1b\xe4\u007f\xa8~0\xd3(\x88\xee\x030\x90\x1c\xa9\x91\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x946\xb2\xc8^:\xee\xeb\xb7\rc\u0124s\f\xe2\xe8\xe8\x8a6$\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x946\xbfC\xff5\u07d0\x90\x88$3l\x9b1\xce3\x06~/P\x8aIr\x15\x10\xc1\xc1\xe9H\x00\x00\u07d46\xbf\xe1\xfa;{p\xc1r\xeb\x04/h\x19\xa8\x97%\x95A>\x8965\u026d\xc5\u07a0\x00\x00\xe0\x946\xc5\x10\xbf\x8dnV\x9b\xf2\xf3}G&]\xbc\xb5\x02\xff+\u038a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x946\xd8]\xc3h1V\xe6;\xf8\x80\xa9\xfa\xb7x\x8c\xf8\x14:'\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d46\u07cf\x88<\x12s\xec\x8a\x17\x1fz3\xcf\xd6I\xb1\xfe`u\x89\fRHJ\xc4\x16\x89\x00\x00\xe0\x946\xe1Va\f\xd8\xffd\xe7\x80\u061d\x00T8\\\xa7gU\xaa\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d46\xfe\xc6,,B^!\x9b\x18D\x8a\xd7W\x00\x9d\x8cT\x02o\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d47\x00\xe3\x02t$\xd99\xdb\xde]B\xfbx\xf6\xc4\xdb\xec\x1a\x8f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d47\x02\xe7\x04\xcc!at9\xadN\xa2zW\x14\xf2\xfd\xa1\xe92\x8965\u026d\xc5\u07a0\x00\x00\u07d47\x035\fMo\xe374,\xdd\xc6[\xf1\xe28k\xf3\xf9\xb2\x89m\x81!\xa1\x94\xd1\x10\x00\x00\xe0\x947\b\xe5\x9d\xe6\xb4\x05P\x88x)\x02\xe0W\x9cr\x01\xa8\xbfP\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d47\x126~^U\xa9mZ\x19\x16\x8fn\xb2\xbc~\x99q\xf8i\x8965\u026d\xc5\u07a0\x00\x00\u07d47\x19Zc]\xccb\xf5jq\x80I\xd4~\x8f\x9f\x96\x83(\x91\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d47'4\x1f&\xc1 \x01\xe3x@^\xe3\x8b-\x84d\xecq@\x89lk\x93[\x8b\xbd@\x00\x00\u07d47.E:kb\x9f'g\x8c\u022e\xb5\xe5|\xe8^\xc0\xae\xf9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d474\xcb\x18t\x91\xed\xe7\x13\xae[;-\x12(J\xf4k\x81\x01\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d477!n\xe9\x1f\x17w2\xfbX\xfa@\x97&r\a\xe2\xcfU\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d47M;\xbb\x057Q\xf9\xf6\x8d\xdb\a\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d48r\xf4\x8d\xc5\xe3\xf8\x17\xbck*\xd2\xd00\xfc^\x04q\x19=\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d48~\xea\xfdk@\t\u07af\x8b\u0578Zr\x98:\x8d\xcc4\x87\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d48\x81\xde\xfa\xe1\xc0{<\xe0Lx\xab\xe2k\f\u070ds\xf0\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d48\x83\xbe\xcc\b\xb9\xbeh\xad;\b6\xaa\u00f6 \xdc\x00\x17\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d48\x85\xfe\xe6q\a\xdc:\xa9\x8a\x1d\x99:t\xdf\\\xd7T\xb9\x8dR\x9a\x89a\t=|,m8\x00\x00\u07d48\xe4m\xe4E<8\xe9A\xe7\x93\x0fC0O\x94\xbb{+\xe8\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d48\xe7\u06e8\xfdO\x1f\x85\r\xbc&I\xd8\xe8O\tR\xe3\xeb<\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d48\xe8\xa3\x1a\xf2\xd2e\xe3\x1a\x9f\xff-\x8fF(m\x12E\xa4g\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d48\xeao[Z{\x88AuQ\xb4\x12=\xc1'\xdf\xe94-\xa6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d48\xee\xc6\xe2\x17\xf4\xd4\x1a\xa9 \xe4$\xb9RQ\x97\x04\x1c\xd4\u0189\xf0\r%\xeb\x92.g\x00\x00\xe0\x948\xf3\x87\xe1\xa4\xedJs\x10n\xf2\xb4b\xe4t\xe2\xe3\x14:\u040a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d49\x11a\xb0\xe4<0 f\u898d,\xe7\xe1\x99\xec\xdb\x1dW\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x949\x15\uad6b.Yw\xd0u\xde\xc4}\x96\xb6\x8bK\\\xf5\x15\x8a\r\a\x01\x81\x85\x12\x0f@\x00\x00\u07d49\x1aw@\\\t\xa7+^\x846#z\xaa\xf9]h\xda\x17\t\x89\x02\xa9&J\xf3\u0479\x00\x00\u07d49\x1f \x17m\x126\rrMQG\n\x90p6uYJM\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d49$3\xd2\u0383\xd3\xfbJv\x02\u0323\xfa\xcaN\xc1@\xa4\xb0\x89\x02\xc3\xc4e\xcaX\xec\x00\x00\xe0\x949?x;\\\u06c6\"\x1b\xf0)O\xb7\x14\x95\x9c{E\x89\x9c\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d49?\xf4%^\\e\x8f.\u007f\x10\xec\xbd)%rg\x1b\xc2\u0489lk\x93[\x8b\xbd@\x00\x00\u07d49A2`\x0fAU\xe0\u007fME\xbc>\xb8\xd9\xfbr\xdc\u05c4\x89\x9fn\x92\xed\xea\a\xd4\x00\x00\u07d49Q\xe4\x8e<\x86\x9ekr\xa1C\xb6\xa4Ph\u0379\xd4f\u0409\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x949T\xbd\xfe\v\xf5\x87\u0195\xa3\x05\xd9$L=[\xdd\xda\u027b\x8a\x04\x10'\x83'\xf9\x85`\x80\x00\u07d49]m%U \xa8\xdb)\xab\xc4}\x83\xa5\u06ca\x1a}\xf0\x87\x89\x05k\xc7^-c\x10\x00\x00\u07d49ck%\x81\x1b\x17j\xbf\xcf\xee\xcad\xbc\x87E/\x1f\xdf\xf4\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d49i\xb4\xf7\x1b\xb8u\x1e\xdeC\xc0\x166:zaOv\x11\x8e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x949x/\xfe\x06\xacx\x82*<:\x8a\xfe0^P\xa5a\x88\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d49zn\xf8v:\x18\xf0\x0f\xac!~\x05\\\r0\x94\x10\x10\x11\x89lk\x93[\x8b\xbd@\x00\x00\u07d49|\u06cc\x80\xc6yP\xb1\x8deB)a\x0e\x93\xbf\xa6\xee\x1a\x89?\x95\xc8\xe0\x82\x15!\x00\x00\u07d49\x82O\x8b\xce\xd1v\xfd>\xa2.\u01a4\x93\xd0\xcc\xc3?\xc1G\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d49\x93l'\x19E\v\x94 \xcc%\"\u03d1\xdb\x01\xf2'\xc1\xc1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d49\x95\xe0\x96\xb0\x8aZrh\x00\xfc\xd1}\x9cd\xc6N\b\x8d+\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d49\x9a\xa6\xf5\xd0x\xcb\tp\x88+\u0259 \x06\xf8\xfb\xdf4q\x8965\u026d\xc5\u07a0\x00\x00\u07d49\xaa\x05\xe5m}28T!\u03d36\xe9\r=\x15\xa9\xf8Y\x89\x01h\u048e?\x00(\x00\x00\u07d49\xaa\xf0\x85M\xb6\xeb9\xbc{.C\x84jv\x17\x1c\x04E\u0789dI\xe8NG\xa8\xa8\x00\x00\u07d49\xb1\xc4q\xae\x94\xe1!dE.\x81\x1f\xbb\xe2\xb3\xcdru\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d49\xb2\x992t\x90\xd7/\x9a\x9e\xdf\xf1\x1b\x83\xaf\xd0\xe9\xd3\xc4P\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d49\xba\u018d\x94xY\xf5\x9e\x92&\b\x9c\x96\xd6.\x9f\xbe<\u0789\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x949\xbf\xd9xh\x9b\xec\x04\x8f\xc7v\xaa\x15$\u007f^\x1d|9\xa2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d49\xc7s6|\x88%\xd3YlhoB\xbf\r\x141\x9e?\x84\x89\a?u\u0460\x85\xba\x00\x00\u07d49\u05291@,\fy\xc4W\x18o$\u07c7)\u03d5p1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d49\xd6\xca\xca\"\xbc\xcdjr\xf8~\xe7\u05b5\x9e\v\xde!\xd7\x19\x89l\x87T\xc8\xf3\f\b\x00\x00\u07d49\xe0\xdbM`V\x8c\x80\v\x8cU\x00\x02l%\x94\xf5v\x89`\x8965\u026d\xc5\u07a0\x00\x00\xe0\x949\xeeO\xe0\x0f\xbc\xeddph\xd4\xf5|\x01\xcb\"\xa8\v\xcc\u044a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d49\xf1\x983\x1eK!\xc1\xb7`\xa3\x15_J\xb2\xfe\x00\xa7F\x19\x89lk\x93[\x8b\xbd@\x00\x00\u07d49\xf4Fc\xd9%a\t\x1b\x82\xa7\r\xcfY=u@\x05\x97:\x89\n\u05cb.\xdc!Y\x80\x00\u07d4:\x03U\x94\xc7GGmB\xd1\xee\x96l6\"L\xdd\"I\x93\x89\x13J\xf7Ei\xf9\xc5\x00\x00\u07d4:\x04W(G\xd3\x1e\x81\xf7v\\\xa5\xbf\xc9\xd5W\x15\x9f6\x83\x89\a6-\r\xab\xea\xfd\x80\x00\xe0\x94:\x06\xe3\xbb\x1e\xdc\xfd\fD\xc3\aM\xe0\xbb`k\x04\x98\x94\xa2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794:\x10\x88\x8b~\x14\x9c\xae',\x010,2}\n\xf0\x1a\v$\x88\xeb\xec!\xee\x1d\xa4\x00\x00\u07d4:1\b\xc1\u6023;3l!\x13\x134@\x9d\x97\xe5\xad\xec\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4:6\x8e\xfeJ\u05c6\xe2c\x95\xec\x9f\u01adi\x8c\xae)\xfe\x01\x89\"E\x89\x96u\xf9\xf4\x00\x00\u07d4:=\xd1\x04\xcd~\xb0O!\x93/\xd43\xeaz\xff\u04d3i\xf5\x89\x13aO#\xe2B&\x00\x00\u07d4:B\x97\xda\xc4.\x1eO\xb8\xcb1\xec\xddC\xaew<\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94:\x99`&m\xf6I cS\x8a\x99\xf4\x87\xc9P\xa3\xa5\uc78a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4:\x9b\x11\x10)\xce\x1f \xc9\x10\x9czt\xee\xee\xf3OO.\xb2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4:\x9eTA\xd4K$;\xe5[u\x02z\x1c\ub7ac\xf5\r\xf2\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94:\xa0z4\xa1\xaf\u0216}=\x13\x83\xb9kb\u03d6\xd5\xfa\x90\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94:\xa4,!\xb9\xb3\x1c>'\xcc\xd1~\t\x9a\xf6y\xcd\xf5i\a\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4:\xa9H\xea\x029wU\xef\xfb/\x9d\xc99-\xf1\x05\x8f~3\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4:\xad\xf9\x8ba\xe5\u0216\xe7\xd1\x00\xa39\x1d2P\"]a\u07c9\f\xafg\x007\x01h\x00\x00\u07d4:\xaeHr\xfd\x90\x93\xcb\xca\xd1@o\x1e\x80x\xba\xb5\x03Y\xe2\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4:\xbb\x8a\xdf\xc6\x04\xf4\x8dY\x84\x81\x1d\u007f\x1dR\xfe\xf6u\x82p\x89\xf2\x97\x19\xb6o\x11\f\x00\x00\u07d4:\xc2\xf0\xff\x16\x12\xe4\xa1\xc3F\xd53\x82\xab\xf6\u0622[\xaaS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4:\xc9\xdczCj\xe9\x8f\xd0\x1cz\x96!\xaa\x8e\x9d\v\x8bS\x1d\x89a\t=|,m8\x00\x00\xe0\x94:\xd0aI\xb2\x1cU\xff\x86|\xc3\xfb\x97@\u04bc\xc7\x10\x121\x8a)\xb7d2\xb9DQ \x00\x00\u07d4:\xd7\x02C\u060b\xf0@\x0fW\xc8\xc1\xfdW\x81\x18H\xaf\x16*\x89.\x9e\xe5\u00c6S\xf0\x00\x00\u07d4:\xd9\x15\xd5P\xb7#AV \xf5\xa9\xb5\xb8\x8a\x85\xf3\x82\xf05\x8965\u026d\xc5\u07a0\x00\x00\u07d4:\xe1`\xe3\xcd`\xae1\xb9\xd6t-h\xe1Nv\xbd\x96\xc5\x17\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4:\xe6+\xd2q\xa7`c\u007f\xady\xc3\x1c\x94\xffb\xb4\xcd\x12\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4:\xeaN\x82\xd2@\x02H\xf9\x98q\xa4\x1c\xa2W\x06\r:\"\x1b\x8965\u026d\xc5\u07a0\x00\x00\u07d4:\xf6[>(\x89ZJ\x00\x11S9\x1d\x1ei\xc3\x1f\xb9\xdb9\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4;\a\xdbZ5\u007fZ\xf2HL\xbc\x9dw\xd7;\x1f\xd0Q\x9f\u01c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4;\n\u032fK`|\xfea\xd1s4\xc2\x14\xb7\\\xde\xfd\xbd\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\x13c\x1a\x1b\x89\xcbVeH\x89\x9a\x1d`\x91\\\xdc\xc4 [\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\x15\x90\x99\aR\a\u0180vc\xb1\xf0\xf7\xed\xa5J\xc8\xcc\xe3\x89j\xc4\xe6[i\xf9-\x80\x00\u07d4;\x197\xd5\u74f8\x9bc\xfb\x8e\xb5\xf1\xb1\xc9\xcak\xa0\xfa\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\"\xda*\x02q\xc8\xef\xe1\x02S'scji\xb1\xc1~\t\x89\x1b6\xa6DJ>\x18\x00\x00\u07d4;\"\u07a3\xc2_\x1bY\u01fd'\xbb\x91\u04e3\xea\xec\xef9\x84\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94;#g\xf8IK_\xe1\x8dh<\x05]\x89\x99\x9c\x9f=\x1b4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4;,E\x99\x0e!GDQ\xcfOY\xf0\x19U\xb31\xc7\xd7\u0249lk\x93[\x8b\xbd@\x00\x00\xe0\x94;A\x00\xe3\ns\xb0\xc74\xb1\x8f\xfa\x84&\u045b\x191/\x1a\x8a\v\xb5\u046ap\n\xfd\x90\x00\x00\u07d4;B\xa6m\x97\x9fX(4tz\x8b`B\x8e\x9bN\xec\xcd#\x89!\xa1\u01d0\xfa\xdcX\x00\x00\u07d4;Gh\xfdq\xe2\xdb,\xbe\u007f\xa0PH<'\xb4\xeb\x93\x1d\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;Vj\x8a\xfa\u0456\x82\xdc,\xe8g\x9a<\xe4D\xa5\xb0\xfdO\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94;\\%\x1d\u007f\u05c9;\xa2\t\xfeT\x1c\xec\xd0\xce%:\x99\r\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4;^\x8b\x17w\xca\x18A\x896\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94;\x93\xb1a6\xf1\x1e\xaf\x10\x99l\x95\x99\r;'9\xcc\xea_\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4;\xabK\x01\xa7\xc8K\xa1?\uea70\xbb\x19\x1bw\xa3\xaa\u0723\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4;\xb55\x98\xcc \xe2\x05]\xc5S\xb0I@J\u0277\xdd\x1e\x83\x89!W\x1d\xf7|\x00\xbe\x00\x00\u07d4;\xbc\x13\xd0J\xcc\xc0pz\xeb\u072e\xf0\x87\u0438~\v^\u327e\xd1\xd0&=\x9f\x00\x00\x00\u07d4;\xc6\xe3\xeezV\u038f\x14\xa3u2Y\x0fcqk\x99f\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\xc8]ls[\x9c\xdaK\xba_H\xb2K\x13\xe7\x0600{\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4;\xd6$\xb5H\xcbe\x976\x90~\u062a<\fp^$\xb5u\x89lk\x93[\x8b\xbd@\x00\x00\u07d4;\u0660m\x1b\xd3lN\xdd'\xfc\r\x1f[\b\x8d\xda\xe3\xc7*\x89\x1b\x1azB\v\xa0\r\x00\x00\u0794;\u077c\x814\xf7}UY\u007f\xc9|&\xd2f\x98\t\x06\x04\ub23e -j\x0e\xda\x00\x00\xe0\x94;\xf8n\u0623\x15>\xc93xj\x02\xac\t\x03\x01\x85^Wk\x8a_J\x8c\x83u\xd1U@\x00\x00\u07d4;\xfb\u04c4|\x17\xa6\x1c\xf3\xf1{R\xf8\ub879`\xb3\U000df262\xa1]\tQ\x9b\xe0\x00\x00\u07d4<\x03\xbb\xc0#\xe1\xe9?\xa3\xa3\xa6\xe4(\xcf\f\xd8\xf9^\x1e\u0189Rf<\u02b1\xe1\xc0\x00\x00\u07d4<\f=\ufb1c\xeaz\xcc1\x9a\x96\xc3\v\x8e\x1f\xed\xabEt\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4<\x15\xb3Q\x1d\xf6\xf04.sH\u0309\xaf9\xa1h\xb7s\x0f\x8965\u026d\xc5\u07a0\x00\x00\u07d4<\x1f\x91\xf3\x01\xf4\xb5e\xbc\xa2GQ\xaa\x1fv\x13\"p\x9d\u0749a\t=|,m8\x00\x00\xe0\x94<(l\xfb0\x14n_\u05d0\xc2\xc8T\x15RW\x8d\xe34\u060a\x02)\x1b\x11\xaa0n\x8c\x00\x00\u07d4<2.a\x1f\u06c2\rG\xc6\xf8\xfcd\xb6\xfa\xd7L\xa9_^\x89\r%\x8e\xce\x1b\x13\x15\x00\x00\u07d4\xa5\xe5\xbfb\xbb\u0309\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4<\x86\x9c\tie#\xce\xd8$\xa0pAF\x05\xbbv#\x1f\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4<\x92V\x19\u02731DF?\x057\u06165\x87\x06\xc5 \xb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\x98YK\xf6\x8bW5\x1e\x88\x14\xae\x9em\xfd-%J\xa0o\x89\x10CV\x1a\x88)0\x00\x00\u07d4<\xad\xeb=>\xed?b1\x1dRU>p\xdfJ\xfc\xe5o#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94<\xae\xdbS\x19\xfe\x80eC\xc5nP!\xd3r\xf7\x1b\xe9\x06.\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4<\xaf\xaf^bPV\x15\x06\x8a\xf8\xeb\"\xa1:\u0629\xe5Pp\x89lf\x06E\xaaG\x18\x00\x00\u07d4<\xb1y\xcbH\x01\xa9\x9b\x95\u00f0\xc3$\xa2\xbd\xc1\x01\xa6S`\x89\x01h\u048e?\x00(\x00\x00\u07d4<\xb5a\u0386BK5\x98\x91\xe3d\xec\x92_\xfe\xff'}\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xcbq\xaah\x80\xcb\v\x84\x01-\x90\xe6\a@\xec\x06\xac\u05cf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\xce\xf8\x86yW9G\xe9I\x97y\x8a\x1e2~\b`:e\x89+\xc9\x16\u059f;\x02\x00\x00\xe0\x94<\xd1\xd9s\x1b\xd5H\xc1\xddo\u03a6\x1b\xebu\xd9\x17T\xf7\u04ca\x01\x16\x1d\x01\xb2\x15\xca\xe4\x80\x00\u07d4<\u04e6\xe95y\xc5mIAq\xfcS>z\x90\xe6\xf5\x94d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4<\u05b7Y<\xbe\xe7x0\xa8\xb1\x9d\b\x01\x95\x8f\xcdK\xc5z\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4<\xd7\xf7\xc7\xc257\x80\xcd\xe0\x81\xee\xecE\x82+%\xf2\x86\f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xe1\u0717\xfc\u05f7\xc4\u04e1\x8aI\xd6\xf2\xa5\xc1\xb1\xa9\x06\u05c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4<\xea0*G*\x94\x03y\xdd9\x8a$\xea\xfd\xba\u07c8\xady\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94<\xec\xa9k\xb1\xcd\xc2\x14\x02\x9c\xbc^\x18\x1d9\x8a\xb9M=A\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4<\xf4\x84RO\xbd\xfa\xda\xe2m\xc1\x85\xe3++c\x0f\xd2\xe7&\x89\x18TR\xcb*\x91\xc3\x00\x00\u07d4<\xf9\xa1\xd4e\xe7\x8bp9\xe3iDx\xe2b{6\xfc\xd1A\x89J`S*\xd5\x1b\xf0\x00\x00\u07d4<\xfb\xf0fVYpc\x9e\x13\r\xf2\xa7\xd1k\x0e\x14\xd6\t\x1c\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94=\th\x8d\x93\xad\a\xf3\xab\xe6\x8cr'#\xcdh\t\x90C^\x8a\x06ZL\xe9\x9fv\x9en\x00\x00\u07d4=1X{_\u0546\x98Ex\x87%\xa6c)\nI\xd3g\x8c\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4=?\xadI\xc9\xe5\xd2u\x9c\x8e\x8eZzM`\xa0\xdd\x13V\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4=WO\xcf\x00\xfa\xe1\u064c\u023f\x9d\u07e1\xb3\x95;\x97A\xbc\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4=Z\x8b+\x80\xbe\x8b5\xd8\xec\xf7\x89\xb5\xedz\au\xc5\al\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4=f\xcdK\xd6M\\\x8c\x1b^\xea(\x1e\x10m\x1cZ\xad#s\x89i\xc4\xf3\xa8\xa1\x10\xa6\x00\x00\u0794=j\xe0S\xfc\xbc1\x8do\xd0\xfb\xc3S\xb8\xbfT.h\r'\x88\xc6s\xce<@\x16\x00\x00\u07d4=o\xf8,\x93w\x05\x9f\xb3\r\x92\x15r?`\xc7u\u0211\xfe\x89\r\x8e\\\xe6\x17\xf2\xd5\x00\x00\u07d4=y\xa8S\xd7\x1b\xe0b\x1bD\xe2\x97Yel\xa0u\xfd\xf4\t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4=~\xa5\xbf\x03R\x81\x00\xed\x8a\xf8\xae\xd2e>\x92\x1bng%\x8965\u026d\xc5\u07a0\x00\x00\u07d4=\x81?\xf2\xb6\xedW\xb97\u06bf+8\x1d\x14\x8aA\x1f\xa0\x85\x89\x05k\xc7^-c\x10\x00\x00\u07d4=\x88\x143\xf0J}\r'\xf8ID\xe0\x8aQ-\xa3UR\x87\x89A\rXj \xa4\xc0\x00\x00\u07d4=\x89\xe5\x05\xcbF\xe2\x11\xa5?2\xf1g\xa8w\xbe\xc8\u007fK\n\x89\x01[5W\xf1\x93\u007f\x80\x00\xe0\x94=\x8d\a#r\x1es\xa6\xc0\xd8`\xaa\x05W\xab\xd1L\x1e\xe3b\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4=\x8f9\x88\x1b\x9e\xdf\xe9\x12'\xc3?\xa4\xcd\xd9\x1eg\x85D\xb0\x89\x04\xab\a\xbaC\xad\xa9\x80\x00\u07d4=\x9dk\xe5\u007f\xf8>\x06Y\x85fO\x12VD\x83\xf2\xe6\x00\xb2\x89n\xac\xe4?#\xbd\x80\x00\x00\u07d4=\xa3\x9c\xe3\xefJz9f\xb3.\xe7\xeaN\xbc#5\xa8\xf1\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4=\xaa\x01\u03b7\x0e\xaf\x95\x91\xfaR\x1b\xa4\xa2~\xa9\xfb\x8e\xdeJ\x89Zc\xd2\u027cvT\x00\x00\u07d4=\xb5\xfejh\xbd6\x12\xac\x15\xa9\x9aa\xe5U\x92\x8e\xec\xea\xf3\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4=\xb9\xed\u007f\x02L~&7/\xea\xcf+\x05\b\x03D^8\x10\x89E\xb1H\xb4\x99j0\x00\x00\u07d4=\xbf\r\xbf\xd7x\x90\x80\x053\xf0\x9d\xea\x83\x01\xb9\xf0%\u04a6\x8965\u026d\xc5\u07a0\x00\x00\u07d4=\xce\U0005c18b\x15\xd3N\xdaBn\xc7\xe0K\x18\xb6\x01p\x02\x89lh\xcc\u041b\x02,\x00\x00\xe0\x94=\xd1.Uj`76\xfe\xbaJo\xa8\xbdJ\xc4]f*\x04\x8a#u{\x91\x83\xe0x(\x00\x00\u07d4=\u078b\x15\xb3\u033a\xa5x\x01\x12\xc3\xd6t\xf3\x13\xbb\xa6\x80&\x89`\x1dQZ>O\x94\x00\x00\xe0\x94=\xde\xdb\xe4\x89#\xfb\xf9\xe56\xbf\x9f\xfb\aG\xc9\xcd\u04de\xef\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4=\xea\xe43'\x91?b\x80\x8f\xaa\x1bbv\xa2\xbdch\xea\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4=\xf7b\x04\x9e\u068a\u0192}\x90Lz\xf4/\x94\xe5Q\x96\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>\x04\r@\u02c0\xba\x01%\xf3\xb1_\xde\xfc\xc8?0\x05\xda\x1b\x898E$\xccp\xb7x\x00\x00\u07d4>\v\x8e\xd8n\xd6i\xe1'#\xafur\xfb\xac\xfe\x82\x9b\x1e\x16\x89QM\xe7\xf9\xb8\x12\xdc\x00\x00\xe0\x94>\f\xbejm\xcba\xf1\x10\xc4[\xa2\xaa6\x1d\u007f\xca\xd3\xdas\x8a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4>\x19KN\xce\xf8\xbbq\x1e\xa2\xff$\xfe\xc4\xe8{\xd02\xf7\u0449\x8b\x9d\xc1\xbc\x1a\x03j\x80\x00\xe0\x94>\x1b\"0\xaf\xbb\xd3\x10\xb4\x92jLwmZ\u705cf\x1d\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4>\x1cS0\x0eL\x16\x89\x12\x16<~\x99\xb9]\xa2h\xad(\n\x896b2\\\u044f\xe0\x00\x00\u07d4>\x1c\x96 c\xe0\xd5)YA\xf2\x10\u0723\xabS\x1e\xec\x88\t\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4>,\xa0\xd24\xba\xf6\a\xadFj\x1b\x85\xf4\xa6H\x8e\xf0\n\xe7\x89\x04\xda!\xa3H=V\x80\x00\u07d4>/&#^\x13zs$\xe4\xdc\x15K]\xf5\xafF\xea\x1aI\x89\x017\xaa\xd8\x03-\xb9\x00\x00\xe0\x94>1a\xf1\xea/\xbf\x12ny\xda\x18\x01\u0695\x12\xb3y\x88\u024a\nm\xd9\f\xaeQ\x14H\x00\x00\xe0\x94>6\xc1rS\xc1\x1c\xf3\x89t\xed\r\xb1\xb7Y\x16\r\xa67\x83\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4><\u04fe\xc0e\x91\xd64o%Kb\x1e\xb4\x1c\x89\x00\x8d1\x895\u07fe\u069f74\x00\x00\u07d4>E\xbdU\u06d0`\xec\xed\x92;\xb9\xcbs<\xb3W?\xb51\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4>M\x13\xc5Z\x84\xe4n\xd7\xe9\u02d0\xfd5^\x8a\u0651\u33c965\u026d\xc5\u07a0\x00\x00\u07d4>N\x92e\"<\x9782L\xf2\v\xd0`\x06\xd0\a>\u06cc\x89\a?u\u0460\x85\xba\x00\x00\xe0\x94>O\xbdf\x10\x15\xf6F\x1e\xd6s\\\xef\xef\x01\xf3\x14E\xde:\x8a\x03n4)\x98\xb8\xb0 \x00\x00\xe0\x94>S\xff!\a\xa8\u07be3(I:\x92\xa5\x86\xa7\xe1\xf4\x97X\x8a\x04\xe6\x9c*q\xa4\x05\xab\x00\x00\u07d4>Z9\xfd\xdap\xdf\x11&\xab\r\u011asx1\x1aSz\x1f\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\xe0\x94>Z\xbd\t\xceZ\xf7\xba\x84\x87\xc3Y\xe0\xf2\xa9:\x98k\v\x18\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4>\\\xb8\x92\x8cAx%\xc0:;\xfc\xc5!\x83\xe5\xc9\x1eB\u05c9\xe71\xd9\xc5,\x96/\x00\x00\u07d4>^\x93\xfbL\x9c\x9d\x12F\xf8\xf2G5\x8e\"\xc3\xc5\xd1{j\x89\b!\xab\rD\x14\x98\x00\x00\u07d4>a\x83P\xfa\x01ez\xb0\xef>\xba\xc8\xe3p\x12\xf8\xfc+o\x89\x98\x06\xde=\xa6\xe9x\x00\x00\u07d4>c\xce;$\xca(e\xb4\u0166\x87\xb7\xae\xa3Y~\xf6\xe5H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>f\xb8GiVj\xb6yE\xd5\xfa\x8175V\xbc\u00e1\xfa\x89\b=lz\xabc`\x00\x00\xe0\x94>v\xa6-\xb1\x87\xaat\xf68\x17S;0l\xea\xd0\xe8\u03be\x8a\x06\x9bZ\xfa\xc7P\xbb\x80\x00\x00\u07d4>z\x96k]\xc3W\xff\xb0~\x9f\xe0g\xc4W\x91\xfd\x8e0I\x89\x034-`\xdf\xf1\x96\x00\x00\xe0\x94>\x81w!u#~\xb4\xcb\xe0\xfe-\xca\xfd\xad\xff\xebj\x19\x99\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4>\x83I\xb6\u007fWED\x9fe\x93g\u066dG\x12\xdb[\x89Z\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4>\x83TO\x00\x82U%r\u01c2\xbe\xe5\xd2\x18\xf1\xef\x06J\x9d\x89\x05l\xd5_\xc6M\xfe\x00\x00\u07d4>\x84\xb3\\[\"ePpa\xd3\vo\x12\xda\x03?\xe6\xf8\xb9\x89a\t=|,m8\x00\x00\u07d4>\x86A\xd4\x87E\xba2/_\xd6\xcbP\x12N\xc4f\x88\u01e6\x9a\u007f\xae\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4>\x91N0\x18\xac\x00D\x93A\u011d\xa7\x1d\x04\xdf\xee\xedb!\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4>\x94\x10\u04f9\xa8~\xd5\xe4Q\xa6\xb9\x1b\xb8\x92?\xe9\x0f\xb2\xb5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4>\x94\xdfS\x13\xfaR\x05p\xef#+\xc31\x1d_b/\xf1\x83\x89lk\x93[\x8b\xbd@\x00\x00\u0794>\x9b4\xa5\u007f3u\xaeY\xc0\xa7^\x19\u0136A\"\x8d\x97\x00\x88\xf8i\x93)g~\x00\x00\u07d4>\xad\xa8\xc9/V\x06~\x1b\xb7<\xe3x\xdaV\xdc,\xdf\xd3e\x89w\xcd\xe9:\xeb\rH\x00\x00\xe0\x94>\xaf\by\xb5\xb6\xdb\x15\x9bX\x9f\x84W\x8bjt\xf6\xc1\x03W\x8a\x01\x898\xb6q\xfae\xa2\x80\x00\u07d4>\xaf1k\x87a]\x88\xf7\xad\xc7|X\xe7\x12\xedMw\x96k\x89\x05m\xbcL\xee$d\x80\x00\u07d4>\xb8\xb3;!\xd2<\u0686\xd8(\x88\x84\xabG\x0e\x16F\x91\xb5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4>\xb9\xef\x06\xd0\xc2Y\x04\x03\x19\x94~\x8czh\x12\xaa\x02S\u0609\t\r\x97/22<\x00\x00\u07d4>\u030e\x16h\xdd\xe9\x95\xdcW\x0f\xe4\x14\xf4B\x11\xc54\xa6\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4>\u03752\xe3\x97W\x96b\xb2\xa4aA\u73c25\x93j_\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4>\xeeo\x1e\x966\vv\x89\xb3\x06\x9a\xda\xf9\xaf\x8e\xb6\f\u404965\u026d\xc5\u07a0\x00\x00\xe0\x94?\b\u066d\x89O\x81>\x8e!H\xc1`\xd2K5:\x8et\xb0\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4?\f\x83\xaa\xc5qybsN\\\xea\xea\xec\u04db(\xad\x06\xbe\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94?\x10\x80\x02\x82\u0477\xdd\u01cf\xa9-\x820\aN\x1b\xf6\xae\xae\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4?\x123qO M\xe9\xdeN\xe9m\a;6\x8d\x81\x97\x98\x9f\x89\x02\x17\xc4\x10t\xe6\xbb\x00\x00\u07d4?\x17:\xa6\xed\xf4i\u0445\xe5\x9b\xd2j\xe4#k\x92\xb4\xd8\xe1\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4?\x1b\xc4 \xc5<\x00,\x9e\x90\x03|D\xfej\x8e\xf4\xdd\xc9b\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4?#a\b\xee\xc7\"\x89\xba\u00e6\\\u0483\xf9^\x04\x1d\x14L\x8964\xbf9\xab\x98x\x80\x00\u07d4?-\xa0\x93\xbb\x16\xeb\x06O\x8b\xfa\x9e0\xb9)\xd1_\x8e\x1cL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?-\xd5]\xb7\xea\xb0\xeb\xeee\xb3>\xd8 ,\x1e\x99.\x95\x8b\x89,s\xc97t,P\x00\x00\u07d4?/8\x14\x91y|\xc5\xc0\u0502\x96\xc1O\xd0\xcd\x00\xcd\xfa-\x89+\x95\xbd\xcc9\xb6\x10\x00\x00\u07d4?0\u04fc\x9f`\"2\xbcrB\x88\xcaF\xcd\v\a\x88\xf7\x15\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4?<\x8ea\xe5`L\xef\x06\x05\xd46\xdd\"\xac\u0346\"\x17\xfc\x89Hz\x9a0E9D\x00\x00\u07d4??F\xb7\\\xab\xe3{\xfa\u0307`(\x1fCA\xca\u007fF=\x89 \xacD\x825\xfa\xe8\x80\x00\u07d4?G)c\x19x\x83\xbb\xdaZ\x9b}\xfc\xb2-\xb1\x14@\xad1\x89\x1a\x19d<\xb1\xef\xf0\x80\x00\u07d4?L\xd19\x9f\x8a4\xed\u06da\x17\xa4q\xfc\x92+Xp\xaa\xfc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4?U\x1b\xa9<\xd5F\x93\xc1\x83\xfb\x9a\xd6\re\xe1`\x96s\u0249lk\x93[\x8b\xbd@\x00\x00\xe0\x94?bzv\x9ej\x95\x0e\xb8p\x17\xa7\u035c\xa2\bq\x13h1\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4?m\xd3e\x0e\xe4(\u0737u\x95S\xb0\x17\xa9j\x94(j\u0249Hz\x9a0E9D\x00\x00\u07d4?tr7\x80o\xed?\x82\x8ahR\xeb\bg\xf7\x90'\xaf\x89\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4?u\xaea\xcc\x1d\x80Be;[\xae\xc4D>\x05\x1c^z\xbd\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4?\xb7\u0457\xb3\xbaO\xe0E\xef\xc2=P\xa1E\x85\xf5X\u0672\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94?\xbc\x1eE\x18\xd74\x00\xc6\xd0F5\x949\xfbh\xea\x1aI\xf4\x8a\x03y\v\xb8U\x13v@\x00\x00\u07d4?\xbe\xd6\xe7\xe0\u029c\x84\xfb\xe9\xeb\u03ddN\xf9\xbbIB\x81e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?\u043bGy\x8c\xf4L\u07feM3=\xe67\xdfJ\x00\xe4\\\x89\x05lUy\xf7\"\x14\x00\x00\xe0\x94?\xe4\x0f\xbd\x91\x9a\xad(\x18\xdf\x01\xeeM\xf4lF\x84*\xc59\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4?\xe8\x01\xe6\x135\xc5\x14\r\xc7\xed\xa2\xefR\x04F\nP\x120\x89lk\x93[\x8b\xbd@\x00\x00\u07d4?\xf86\xb6\xf5{\x90\x1bD\f0\xe4\xdb\xd0e\xcf7\xd3\u050c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4?\xfc\xb8p\xd4\x02=%]Qg\u0625\a\xce\xfc6kh\xba\x89#4^\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4@s\xfaI\xb8q\x17\u02d0\x8c\xf1\xabQ-\xa7T\xa92\xd4w\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4@\x8ai\xa4\a\x15\xe1\xb3\x13\xe15N`\b\x00\xa1\xe6\xdc\x02\xa5\x89\x01\u7e11\u0312T\x00\x00\u07d4@\x9b\xd7P\x85\x82\x1c\x1d\xe7\f\xdc;\x11\xff\xc3\xd9#\xc7@\x10\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4@\x9dZ\x96.\xde\uefa1x\x01\x8c\x0f8\xb9\u0372\x13\xf2\x89\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4@\xa31\x19[\x97s%\u00aa(\xfa/B\xcb%\xec<%<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4@\xa7\xf7(g\xa7\u0706w\v\x16+uW\xa44\xedP\xcc\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d4@\xab\n>\x83\xd0\u022c\x93f\x91\x05 \xea\xb1w+\xac;\x1a\x894\xf1\f-\xc0^|\x00\x00\u07d4@\xabf\xfe!>\xa5l:\xfb\x12\xc7[\xe3?\x8e2\xfd\b]\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94@\xadt\xbc\v\xce*E\xe5/6\xc3\u07bb\x1b:\xda\x1bv\x19\x8a\x01p\x16-\xe1\t\xc6X\x00\x00\u07d4@\u03c9\x05\x91\xea\u484f\x81*)T\xcb)_c3'\xe6\x89\x02\x9b\xf76\xfcY\x1a\x00\x00\u07d4@\u03d0\xef[v\x8c]\xa5\x85\x00,\xcb\xe6avP\xd8\xe87\x8963\x03\"\xd5#\x8c\x00\x00\xe0\x94@\xd4]\x9dv%\xd1QV\xc92\xb7q\xca{\x05'\x13\tX\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4@\xdb\x1b\xa5\x85\xce4S\x1e\xde\xc5IHI9\x13\x81\xe6\xcc\u04c9a\t=|,m8\x00\x00\xe0\x94@\xdfI^\xcf?\x8bL\xef*l\x18\x99W$\x8f\u813c+\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4@\xe0\xdb\xf3\xef\uf404\xea\x1c\xd7\xe5\x03\xf4\v;J\x84C\xf6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4@\xe2D\n\xe1B\u02006j\x12\xc6\xd4\x10/K\x844\xb6*\x8965\u026d\xc5\u07a0\x00\x00\u07d4@\xe3\u0083\xf7\xe2M\xe0A\f\x12\x1b\xee`\xa5`\u007f>)\xa6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94@\xeaPD\xb2\x04\xb20v\xb1\xa5\x80;\xf1\xd3\f\x0f\x88\x87\x1a\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94@\xed\xdbD\x8di\x0e\xd7.\x05\xc2%\xd3O\xc85\x0f\xa1\xe4\u014a\x01{x\x83\xc0i\x16`\x00\x00\xe0\x94@\xf4\xf4\xc0ls,\xd3[\x11\x9b\x89;\x12~}\x9d\aq\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4A\x01\x0f\u023a\xf8C}\x17\xa0Ci\x80\x9a\x16\x8a\x17\xcaV\xfb\x89\x05k\xc7^-c\x10\x00\x00\u07d4A\x03)\x96q\xd4gc\x97\x8f\xa4\xaa\x19\xee4\xb1\xfc\x95'\x84\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4A\x03<\x1bm\x05\xe1\u0289\xb0\x94\x8f\xc6DS\xfb\xe8z\xb2^\x89Hz\x9a0E9D\x00\x00\u07d4A\t\x8a\x81E#\x17\xc1\x9e>\xef\v\xd1#\xbb\xe1x\xe9\xe9\u0289\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4A\x16\x10\xb1x\xd5a}\xfa\xb94\u0493\xf5\x12\xa9>\\\x10\xe1\x89\t79SM(h\x00\x00\u07d4A\x1c\x83\x1c\xc6\xf4O\x19e\xecWW\xabN[<\xa4\xcf\xfd\x1f\x89\x17\n\x0fP@\xe5\x04\x00\x00\xe0\x94A*h\xf6\xc6EU\x9c\xc9w\xfcId\x04z \x1d\x1b\xb0\xe2\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4A?K\x02f\x9c\xcf\xf6\x80k\xc8&\xfc\xb7\xde\xca;\x0e\xa9\xbc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4AE\x99\t.\x87\x9a\xe2Sr\xa8MsZ\xf5\xc4\xe5\x10\xcdm\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4AHV\x12\xd04F\xecL\x05\xe5$NV?\x1c\xba\xe0\xf1\x97\x894\x95tD\xb8@\xe8\x00\x00\u07d4A]\tj\xb0b\x93\x18?<\x03=%\xf6\xcfqx\xac;\u01c9\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4Af\xfc\b\u0285\xf7f\xfd\xe81F\x0e\x9d\xc9<\x0e!\xaal\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Ag\x84\xaf`\x960\xb0p\u051a\x8b\xcd\x12#\\d(\xa4\b\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Ag\xcdH\xe73A\x8e\x8f\x99\xff\xd14\x12\x1cJJ\xb2x\u0109\xc5S%\xcat\x15\xe0\x00\x00\u07d4Al\x86\xb7 \x83\xd1\xf8\x90}\x84\xef\xd2\xd2\u05c3\xdf\xfa>\xfb\x89lj\xccg\u05f1\xd4\x00\x00\u07d4AsA\x9d\\\x9fc)U\x1d\xc4\xd3\xd0\u03ac\x1bp\x1b\x86\x9e\x89\x04\xc5>\xcd\xc1\x8a`\x00\x00\u07d4At\xfa\x1b\xc1*;q\x83\u02eb\xb7z\vYU{\xa5\xf1\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4Axj\x10\xd4G\xf4\x84\xd32D\u0337\xfa\u034bB{[\x8c\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Az<\u0454\x96S\nmB\x04\u00f5\xa1|\xe0\xf2\a\xb1\xa5\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4A~N&\x88\xb1\xfdf\xd8!R\x9eF\xedOB\xf8\xb3\xdb=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94A\x9aq\xa3l\x11\xd1\x05\xe0\xf2\xae\xf5\xa3\xe5\x98\a\x8e\x85\xc8\v\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94A\x9b\xdes\x16\xcc\x1e\u0495\u0205\xac\xe3B\u01db\xf7\xee3\xea\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4A\xa2\xf2\xe6\xec\xb8c\x94\xec\x0e3\x8c\x0f\xc9~\x9cU\x83\xde\u0489l\xee\x06\u077e\x15\xec\x00\x00\u07d4A\xa8\u0083\x00\x81\xb1\x02\xdfn\x011e|\a\xabc[T\u0389lj\xccg\u05f1\xd4\x00\x00\u07d4A\xa8\xe26\xa3\x0emc\xc1\xffdM\x13*\xa2\\\x89S~\x01\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4A\xa9\xa4\x04\xfc\x9f[\xfe\xe4\x8e\xc2e\xb1%#3\x8e)\xa8\xbf\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4A\xad6\x9fu\x8f\xef8\xa1\x9a\xa3\x14\x93y\x83,\x81\x8e\xf2\xa0\x8966\x9e\xd7t}&\x00\x00\u07d4A\xb2\xd3O\xde\v\x10)&+Ar\xc8\x1c\x15\x90@[\x03\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4A\xb2\xdb\u05dd\u069b\x86Ojp0'T\x19\u00dd>\xfd;\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4A\xc3\xc26u4\xd1;\xa2\xb3?\x18\\\xdb\xe6\xacC\xc2\xfa1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4A\u02d8\x96D_p\xa1\n\x14!R\x96\xda\xf6\x14\xe3,\xf4\u0549g\x8a\x93 b\xe4\x18\x00\x00\u07d4A\xcey\x95\t5\xcf\xf5[\xf7\x8eL\xce\xc2\xfec\x17\x85\u06d5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4A\u04f71\xa3&\xe7hX\xba\xa5\xf4\xbd\x89\xb5{6\x93#C\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\xe0\x94A\xe4\xa2\x02u\xe3\x9b\xdc\xef\xebe\\\x03\"tKvQ@\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4A\xed-\x8ep\x81H,\x91\x9f\xc2=\x8f\x00\x91\xb3\xc8,F\x85\x89F:\x1ev[\u05ca\x00\x00\xe0\x94A\xf2~tK\u049d\xe2\xb0Y\x8f\x02\xa0\xbb\x9f\x98\xe6\x81\ua90a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\u07d4A\xf4\x89\xa1\xect{\u009c>_\x9d\x8d\xb9xw\xd4\u0474\xe9\x89\a?u\u0460\x85\xba\x00\x00\u07d4B\x0f\xb8n}+Q@\x1f\xc5\xe8\xc7 \x15\xde\xcbN\xf8\xfc.\x8965\u026d\xc5\u07a0\x00\x00\u07d4B\x16\x84\xba\xa9\xc0\xb4\xb5\xf5S8\xe6\xf6\xe7\xc8\xe1F\xd4\x1c\xb7\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4B9\x96Y\xac\xa6\xa5\xa8c\xea\"E\xc93\xfe\x9a5\xb7\x88\x0e\x89n\xce2\xc2l\x82p\x00\x00\xe0\x94B;\xcaG\xab\xc0\fpW\xe3\xad4\xfc\xa6>7_\xbd\x8bJ\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4B<1\a\xf4\xba\xceANI\x9cd9\nQ\xf7F\x15\xca^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B<\xc4YL\xf4\xab\xb66\x8d\xe5\x9f\u04b1#\a4a!C\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94BD\xf13\x11X\xb9\xce&\xbb\xe0\xb9#k\x92\x03\xca5\x144\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794BQw\xebt\xad\n\x9d\x9aWR\"\x81G\xeemcV\xa6\u6239\x8b\xc8)\xa6\xf9\x00\x00\u07d4BW%\xc0\xf0\x8f\b\x11\xf5\xf0\x06\xee\xc9\x1c\\\\\x12k\x12\xae\x89\b!\xab\rD\x14\x98\x00\x00\xe0\x94BX\xfdf/\xc4\xce2\x95\xf0\xd4\xed\x8f{\xb1D\x96\x00\xa0\xa9\x8a\x01lE.\xd6\b\x8a\xd8\x00\x00\xe0\x94B\\\x18\x16\x86\x8fww\xcc+\xa6\xc6\u048c\x9e\x1eylR\xb3\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4B\\3\x8a\x13%\xe3\xa1W\x8e\xfa)\x9eW\u0646\xebGO\x81\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94BbY\xb0\xa7Vp\x1a\x8bf5(R!V\xc0(\x8f\x0f$\x8a\x02\x18\xae\x19k\x8dO0\x00\x00\u07d4Bm\x15\xf4\a\xa0\x115\xb1:kr\xf8\xf2R\v51\xe3\x02\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Box\xf7\r\xb2Y\xac\x854\x14[)4\xf4\xef\x10\x98\xb5\u0609\x13\x84\x00\xec\xa3d\xa0\x00\x00\u07d4Bs-\x8e\xf4\x9f\xfd\xa0K\x19x\x0f\xd3\xc1\x84i\xfb7A\x06\x89\x17\v\x00\xe5\u4a7e\x00\x00\u07d4Bt\x17\xbd\x16\xb1\xb3\xd2-\xbb\x90-\x8f\x96W\x01o$\xa6\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Btj\xee\xa1O'\xbe\xff\f\r\xa6BS\xf1\xe7\x97\x18\x90\xa0\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4B{F*\xb8NP\x91\xf4\x8aF\xeb\f\u0712\xdd\xcb&\xe0x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B~GQ\u00fa\xbex\xcf\xf8\x83\b\x86\xfe\xbc\x10\xf9\x90\x8dt\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94B~\xc6h\xac\x94\x04\xe8\x95\u0306\x15\x11\xd1b\nI\x12\xbe\x98\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4B\x80\xa5\x8f\x8b\xb1\v\x94@\u0794\xf4+OY! \x82\x01\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4B\x8a\x1e\xe0\xed3\x1dyR\u033e\x1cyt\xb2\x85+\u0453\x8a\x89w\xb7JN\x8d\xe5e\x00\x00\u0794B\x9c\x06\xb4\x87\xe8Tj\xbd\xfc\x95\x8a%\xa3\xf0\xfb\xa5?o\x00\x88\xbbdJ\xf5B\x19\x80\x00\xe0\x94B\xa9\x8b\xf1`'\xceX\x9cN\xd2\xc9X1\xe2rB\x05\x06N\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4B\xc6\xed\xc5\x15\xd3UW\x80\x8d\x13\xcdD\xdc\xc4@\v%\x04\xe4\x89\n\xba\x14\u015b\xa72\x00\x00\u07d4B\xce\xcf\u0492\x10y\xc2\xd7\xdf?\b\xb0z\xa3\xbe\xee^!\x9a\x8965\u026d\xc5\u07a0\x00\x00\u07d4B\u04669\x9b0\x16\xa8Y\u007f\x8bd\t'\xb8\xaf\xbc\xe4\xb2\x15\x89\xa1\x8b\xce\xc3H\x88\x10\x00\x00\u07d4B\xd3I@\xed\xd2\xe7\x00]F\xe2\x18\x8eL\xfe\u0383\x11\xd7M\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4B\u04e5\xa9\x01\xf2\xf6\xbd\x93V\xf1\x12\xa7\x01\x80\xe5\xa1U\v`\x892$\xf4'#\xd4T\x00\x00\u07d4B\u05b2c\xd9\xe9\xf4\x11lA\x14$\xfc\x99Ux;\xa1\xc5\x1b\x81\x0f\xc4g\u057aM\xeaB\xf7\xa9\x88^i\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94C>\xb9J3\x90\x86\xed\x12\u067d\xe9\xcd\x1dE\x86\x03\xc9}\u058a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4CI\"Zb\xf7\n\xeaH\n\x02\x99\x15\xa0\x1eSy\xe6O\xa5\x89\x8c\xd6~#4\xc0\xd8\x00\x00\u07d4CT\"\x1eb\xdc\t\xe6@d6\x16:\x18^\xf0m\x11J\x81\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94CTC\xb8\x1d\xfd\xb9\xbd\x8cg\x87\xbc%\x18\xe2\xd4~W\xc1_\x8a\x01C\x8d\x93\x97\x88\x1e\xf2\x00\x00\u07d4Ca\u0504o\xaf\xb3w\xb6\xc0\xeeI\xa5\x96\xa7\x8d\xdf5\x16\xa3\x89\xc2\x12z\xf8X\xdap\x00\x00\xe0\x94Cd0\x9a\x9f\xa0p\x95`\x0fy\xed\xc6Q \xcd\xcd#\xdcd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Cg\xaeK\f\xe9d\xf4\xa5J\xfdK\\6\x84\x96\xdb\x16\x9e\x9a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Ct\x89(\xe8\xc3\xecD6\xa1\u0412\xfb\xe4:\xc7I\xbe\x12Q\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4Cv{\xf7\xfd*\xf9[r\xe91-\xa9D<\xb1h\x8eCC\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94Cy\x838\x8a\xb5\x9aO\xfc!_\x8e\x82iF\x10)\xc3\xf1\xc1\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4C\x89\x8cI\xa3MP\x9b\xfe\xd4\xf7`A\xee\x91\xca\xf3\xaaj\xa5\x89\x10CV\x1a\x88)0\x00\x00\u07d4C\x8c/T\xff\x8eb\x9b\xab6\xb1D+v\v\x12\xa8\x8f\x02\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\x98b\x8e\xa6c-9>\x92\x9c\xbd\x92\x84d\xc5h\xaaJ\f\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4C\x9d//Q\x10\xa4\u054b\x17W\x93P\x15@\x87@\xfe\xc7\xf8\x89\u03e5\xc5\x15\x0fL\x88\x80\x00\u07d4C\x9d\xee?vy\xff\x100s?\x93@\xc0\x96hkI9\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xb0y\xba\xf0ry\x99\xe6k\xf7C\u057c\xbfwl;\t\"\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xbc-M\xdc\xd6X;\xe2\u01fc\tK(\xfbr\xe6+\xa8;\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xc7\xeb\u0173\xe7\xaf\x16\xf4}\xc5az\xb1\x0e\x0f9\xb4\xaf\xbb\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4C\u02d6R\x81\x8coMg\x96\xb0\xe8\x94\t0ly\xdbcI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4C\xcc\b\xd0s*\xa5\x8a\xde\xf7a\x9b\xedFU\x8a\xd7wAs\x89\xf0\xe7\u0730\x12*\x8f\x00\x00\xe0\x94C\u0567\x1c\xe8\xb8\xf8\xae\x02\xb2\xea\xf8\xea\xf2\xca(@\xb9?\xb6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794C\xdb\u007f\xf9Z\bm(\ubff8/\xb8\xfb_#\n^\xbc\u0348\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4C\xe7\xec\x84cX\xd7\xd0\xf97\xad\x1c5\v\xa0i\u05ffr\xbf\x89\x06p\xaeb\x92\x14h\x00\x00\u07d4C\xf1o\x1eu\xc3\xc0j\x94x\xe8\u0157\xa4\n<\xb0\xbf\x04\u0309\x9d\xf7\u07e8\xf7`H\x00\x00\u07d4C\xf4p\xede\x9e)\x91\xc3u\x95~]\xde\u017d\x1d8\"1\x89\x05k\xc7^-c\x10\x00\x00\u07d4C\xf7\xe8n8\x1e\xc5\x1e\u0110m\x14v\u02e9z=\xb5\x84\xe4\x8965\u026d\xc5\u07a0\x00\x00\u07d4C\xff8t>\xd0\xcdC0\x8c\x06e\t\u030e~r\xc8b\xaa\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94C\xff\x88S\xe9\x8e\xd8@k\x95\x00\n\u0684\x83b\u05a09*\x8a\x04\xae\v\x1cM.\x84\xd0\x00\x00\u07d4D\t\x88f\xa6\x9bh\xc0\xb6\xbc\x16\x82)\xb9`5\x87\x05\x89g\x89\n1\x06+\xee\xedp\x00\x00\u07d4D\x19\xaca\x8d]\xea|\xdc`w o\xb0}\xbd\xd7\x1c\x17\x02\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4D\x1aR\x00\x16a\xfa\xc7\x18\xb2\u05f3Q\xb7\xc6\xfbR\x1az\xfd\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94D\x1a\u0282c\x13$\xac\xbf\xa2F\x8b\xda2[\xbdxG{\xbf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4D\x1f7\xe8\xa0)\xfd\x02H/(\x9cI\xb5\xd0m\x00\xe4\b\xa4\x89\x12\x11\xec\xb5m\x13H\x80\x00\u07d4D \xaa5F[\xe6\x17\xad$\x98\xf3p\xde\n<\xc4\xd20\xaf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4D#/\xf6m\xda\xd1\xfd\x84\x12f8\x006\xaf\xd7\xcf}\u007fB\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4D%\rGn\x06$\x84\xe9\b\n9g\xbf:Js*\xd7?\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4D)\xa2\x9f\xee\x19\x84Pg,\f\x1d\a1b%\v\xecdt\x896*\xaf\x82\x02\xf2P\x00\x00\u07d4D5RS\xb2wH\xe3\xf3O\xe9\xca\xe1\xfbq\x8c\x8f$\x95)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4D8\xe8\x80\xcb'f\xb0\xc1\u03ae\xc9\xd2A\x8f\u03b9R\xa0D\x89\a?\xa0s\x90?\b\x00\x00\u07d4DL\xafy\xb7\x138\ue6a7\xc73\xb0*\u02a7\xdc\x02YH\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4D\\\xb8\xde^=\xf5 \xb4\x99\xef\u0240\xf5+\xff@\xf5\\v\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Dj\x809\xce\u03dd\xceHy\xcb\xca\xf3I;\xf5E\xa8\x86\x10\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4Dt)\x9d\x0e\xe0\x90\u0710x\x9a\x14\x86H\x9c=\rd^m\x8965\u026d\xc5\u07a0\x00\x00\u07d4D\x8b\xf4\x10\xad\x9b\xbc/\xec\xc4P\x8d\x87\xa7\xfc.K\x85a\xad\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4D\x90\x1e\r\x0e\b\xac=^\x95\xb8\xec\x9d^\x0f\xf5\xf1.\x03\x93\x89\x16\xa1\xf9\xf5\xfd}\x96\x00\x00\xe0\x94D\x93\x12<\x02\x1e\xce;3\xb1\xa4R\xc9&\x8d\xe1@\a\xf9\u04ca\x01je\x02\xf1Z\x1eT\x00\x00\xe0\x94D\x9a\xc4\xfb\xe3\x83\xe3g8\x85^6JW\xf4q\xb2\xbf\xa11\x8a)\xb7d2\xb9DQ \x00\x00\u07d4D\xa0\x1f\xb0J\xc0\xdb,\xce]\xbe(\x1e\x1cF\xe2\x8b9\xd8x\x89lj\xccg\u05f1\xd4\x00\x00\u07d4D\xa6=\x18BE\x87\xb9\xb3\a\xbf\xc3\xc3d\xae\x10\xcd\x04\xc7\x13\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94D\xa8\x98\x9e20\x81!\xf7$f\x97\x8d\xb3\x95\xd1\xf7l:K\x8a\x01\x88P)\x9fB\xb0j\x00\x00\u07d4D\xc1\x11\v\x18\x87\x0e\xc8\x11x\xd9=!X8\xc5Q\u050ed\x89\n\xd6\xf9\x85\x93\xbd\x8f\x00\x00\u07d4D\xc1Ge\x12|\xde\x11\xfa\xb4l],\xf4\u0532\x89\x00#\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94D\xc5N\xaa\x8a\xc9@\xf9\xe8\x0f\x1et\xe8/\xc1O\x16v\x85j\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4D\xcdwSZ\x89?\xa7\xc4\xd5\xeb:$\x0ey\u0419\xa7--\x89,s\xc97t,P\x00\x00\u07d4D\u07faP\xb8)\xbe\xcc_O\x14\u0470J\xab3 \xa2\x95\xe5\x8965\u026d\xc5\u07a0\x00\x00\u07d4D\xe2\xfd\xc6y\xe6\xbe\xe0\x1e\x93\xefJ:\xb1\xbc\xce\x01*\xbc|\x89\x16=\x19I\x00\xc5E\x80\x00\xe0\x94D\xf6/*\xaa\xbc)\xad:k\x04\xe1\xffo\x9c\xe4R\xd1\xc1@\x8a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4D\xff\xf3{\xe0\x1a8\x88\u04f8\xb8\u1200\xa7\xdd\xef\xee\xea\u04c9\x0e\f[\xfc}\xae\x9a\x80\x00\u07d4E\x06\xfe\x19\xfaK\x00k\xaa9\x84R\x9d\x85\x16\xdb++P\xab\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\x1b6\x99G[\xed]y\x05\xf8\x90Z\xa3Eo\x1e\u05c8\xfc\x89\x8a\xc7#\x04\x89\xe8\x00\x00\x00\u0794E\x1bpp%\x9b\u06e2q\x00\xe3n#B\x8aS\xdf\xe3\x04\u9239\x8b\xc8)\xa6\xf9\x00\x00\u07d4E'+\x8fb\xe9\xf9\xfa\x8c\xe0D \u1ba3\xeb\xa9hn\xac\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94E+d\u06ce\xf7\xd6\u07c7\u01c8c\x9c\"\x90\xbe\x84\x82\xd5u\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4E>5\x9a3\x97\x94LZ'Z\xb1\xa2\xf7\n^Z?i\x89\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4EI\xb1Yy%_~e\xe9\x9b\rV\x04\u06d8\xdf\xca\u023f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4EKa\xb3D\xc0\xef\x96Qy#\x81U\xf2w\u00c2\x9d\v8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94EO\x01A\xd7!\xd3<\xbd\xc4\x10\x18\xbd\x01\x11\x9a\xa4xH\x18\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4ES3\x90\xe3@\xfe\r\xe3\xb3\xcf_\xb9\xfc\x8e\xa5R\xe2\x9eb\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4ES\x96\xa4\xbb\u067a\u8bdf\xb7\xc4\xd6MG\x1d\xb9\xc2E\x05\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4E[\x92\x96\x92\x1at\xd1\xfcAa\u007fC\xb80>o>\xd7l\x89\u3bb5sr@\xa0\x00\x00\u07d4E\\\xb8\xee9\xff\xbcu#1\xe5\xae\xfcX\x8e\xf0\xeeY4T\x8965F:x\r\xef\x80\x00\u07d4Ej\u0b24\x8e\xbc\xfa\xe1f\x06\x02PR_c\x96^v\x0f\x89\x10CV\x1a\x88)0\x00\x00\u07d4Eo\x8dtf\x82\xb2$g\x93I\x06M\x1b6\x8c|\x05\xb1v\x89\u0213\u041c\x8fQP\x00\x00\u07d4Ep)\xc4i\xc4T\x8d\x16\x8c\xec>e\x87.D(\xd4+g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Eq\xdeg+\x99\x04\xba\xd8t6\x92\xc2\x1cO\xdc\xeaL.\x01\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Ex\x1b\xbew\x14\xa1\xc8\xf7;\x1cty!\xdfO\x84'\x8bp\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E{\xce\xf3}\xd3\xd6\v-\xd0\x19\xe3\xfea\xd4k?\x1erR\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94E\x8e<\u025e\x94xD\xa1\x8ejB\x91\x8f\xef~\u007f_^\xb3\x8a\a\xb5?y\xe8\x88\xda\xc0\x00\x00\u07d4E\x93\x93\xd6:\x06>\xf3r\x1e\x16\xbd\x9f\xdeE\ue77dw\xfb\x89j\xba\u05a3\xc1S\x05\x00\x00\u07d4E\xa5p\xdc\xc2\t\f\x86\xa6\xb3\xea)\xa6\bc\xdd\xe4\x1f\x13\xb5\x89\f\x9a\x95\xee)\x86R\x00\x00\u07d4E\xa8 \xa0g/\x17\xdct\xa0\x81\x12\xbcd?\xd1\x16w6\u00c9\n\xd6\xc4;(\x15\xed\x80\x00\u07d4E\xb4q\x05\xfeB\xc4q-\xcen*!\xc0[\xff\xd5\xeaG\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\xbb\x82\x96R\u063f\xb5\x8b\x85'\xf0\xec\xb6!\u009e!.\u00c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\xc0\u045f\v\x8e\x05O\x9e\x8986\xd5\xec\xaey\x01\xaf(\x12\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4E\xc4\xec\xb4\xee\x89\x1e\xa9\x84\xa7\xc5\xce\xfd\x8d\xfb\x001\v(P\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4E\u028d\x95f\b\xf9\xe0\n/\x99t\x02\x86@\x88\x84ef\x8f\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\u0298b\x00;N@\xa3\x17\x1f\xb5\xca\xfa\x90(\xca\xc8\xde\x19\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4E\xd1\xc9\xee\xdf|\xabA\xa7y\x05{y9_T(\xd8\x05(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4E\u0535M7\xa8\xcfY\x98!#_\x06/\xa9\xd1p\xed\u8909\x11\x90g;_\u0690\x00\x00\xe0\x94E\xdb\x03\xbc\xcf\u05a5\xf4\xd0&k\x82\xa2*6\x87\x92\xc7}\x83\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4E\xe3\xa9>r\x14J\u0686\f\xbcV\xff\x85\x14Z\xda8\xc6\u0689WG=\x05\u06ba\xe8\x00\x00\u07d4E\u6378\u06fa\xba_\xc2\xcb3|b\xbc\xd0\xd6\x1b\x05\x91\x89\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94E\u6379L}\n\xb7\xacA\x85zq\xd6qG\x87\x0fNq\x8aT\xb4\v\x1f\x85+\xda\x00\x00\x00\u07d4E\xf4\xfc`\xf0\x8e\xac\xa1\x05\x98\xf03c)\x80\x1e<\x92\xcbF\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4F\rSU\xb2\xce\xebnb\x10}\x81\xe5\x12p\xb2k\xf4V \x89l\xb7\xe7Hg\xd5\xe6\x00\x00\xe0\x94F\"O2\xf4\xec\xe5\u0206p\x90\xd4@\x9dU\xe5\v\x18C-\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4F'\xc6\x06\x84&q\xab\u0782\x95\xee]\xd9L\u007fT\x954\xf4\x89\x0f\x89_\xbd\x872\xf4\x00\x00\u07d4F+g\x8bQ\xb5\x84\xf3\xedz\xda\a\v\\\u065c\v\xf7\xb8\u007f\x89\x05k\xc7^-c\x10\x00\x00\u07d4FM\x9c\x89\xcc\xe4\x84\xdf\x00\x02w\x19\x8e\xd8\a_\xa65r\u0449\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4FPNj!Z\xc8;\xcc\xf9V\xbe\xfc\x82\xabZg\x93q\u0209\x1c!(\x05\u00b4\xa5\x00\x00\xe0\x94FQ\xdcB\x0e\b\xc3);'\xd2Ix\x90\xebP\":\xe2\xf4\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4FS\x1e\x8b\x1b\xde\t\u007f\u07c4\x9dm\x11\x98\x85`\x8a\x00\x8d\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4Fb\x92\xf0\xe8\rC\xa7\x87t'u\x90\xa9\xebE\x96\x12\x14\xf4\x894\x95tD\xb8@\xe8\x00\x00\xe0\x94Fb\xa1v^\xe9!\x84-\u0708\x89\x8d\x1d\xc8bu\x97\xbd~\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Fe\xe4s\x96\xc7\u06d7\xeb*\x03\xd9\bc\xd5\u053a1\x9a\x94\x89 \x86\xac5\x10R`\x00\x00\u07d4Fo\xdak\x9bX\xc5S'P0j\x10\xa2\xa8\xc7h\x10;\a\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4Fq$\xae\u007fE/&\xb3\xd5t\xf6\b\x88\x94\xfa]\x1c\xfb;\x89\x92^\x06\xee\xc9r\xb0\x00\x00\u0794Fr*6\xa0\x1e\x84\x1d\x03\xf7\x80\x93^\x91}\x85\u0566z\xbd\x88\xce\xc7o\x0eqR\x00\x00\u07d4Fw\x9aVV\xff\x00\xd7>\xac:\xd0\u00cbl\x850\x94\xfb@\x89\f\x82S\xc9lj\xf0\x00\x00\u07d4Fw\xb0N\x03C\xa3!1\xfdj\xbb9\xb1\xb6\x15k\xba=[\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4F}Y\x88$\x9ahaG\x16e\x98@\xed\n\xe6\xf6\xf4W\xbc\x89\x15\x01\xa4\x8c\xef\xdf\xde\x00\x00\u07d4F~\x0e\xd5O;v\xae\x066\x17n\aB\b\x15\xa0!sn\x89lk\x93[\x8b\xbd@\x00\x00\u07d4F~\xa1\x04E\x82~\xf1\xe5\x02\xda\xf7k\x92\x8a \x9e\r@2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94F\u007f\xbfAD\x16\x00u\u007f\xe1X0\xc8\xcd_O\xfb\xbb\xd5`\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94F\x93Xp\x932\xc8+\x88~ \xbc\xdd\xd0\"\x0f\x8e\u06e7\u040a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4F\x97\xba\xaf\x9c\xcb`?\xd3\x040h\x9dCTE\xe9\u024b\xf5\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4F\xa3\v\x8a\x80\x891!tE\xc3\xf5\xa9>\x88,\x03E\xb4&\x89\r\x8d\xb5\xeb\u05f2c\x80\x00\u07d4F\xa40\xa2\u0528\x94\xa0\u062a?\xea\xc6\x156\x14\x15\xc3\xf8\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4F\xaaP\x18pg~\u007f\nPHv\xb4\xe8\x80\x1a\n\xd0\x1cF\x89+^:\xf1k\x18\x80\x00\x00\u07d4F\xbf\u0172\a\xeb \x13\xe2\xe6\x0fw_\xec\xd7\x18\x10\u0159\f\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4F\xc1\xaa\"D\xb9\u0229W\u028f\xacC\x1b\x05\x95\xa3\xb8h$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4F\xd8\x061(B\x03\xf6(\x8e\xcdNWX\xbb\x9dA\xd0]\xbe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\n\xc5\xd1\xf3\xef\xe2\x8f8\x02\xaf\x92[W\x1ec\x86\x8b9}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\x10\x10\xdaI/@\x18\x83;\b\x8d\x98r\x90\x1e\x06\x12\x91t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4G\x12T\x02e\xcb\xee\u00c4p\"\u015f\x1b1\x8dC@\n\x9e\x89\xbd\xbcA\xe04\x8b0\x00\x00\xe0\x94G\x14\u03e4\xf4k\u05bdps}u\x87\x81\x97\xe0\x8f\x88\xe61\x8a\x02\u007f>\u07f3Nn@\x00\x00\u07d4G H\xcc`\x9a\xeb$!e\uaa87\x05\x85\f\xf3\x12]\xe0\x8965\u026d\xc5\u07a0\x00\x00\u07d4G!\x92)\xe8\xcdVe\x9ae\u00a9C\xe2\u075a\x8fK\xfd\x89\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4G7\xd0B\xdcj\xe7>\xc7:\xe2Qz\u03a2\xfd\xd9d\x87\u014965\u026d\xc5\u07a0\x00\x00\u07d4GAX\xa1\xa9\xdci<\x13?e\xe4{\\:\xe2\xf7s\xa8o\x89\n\xdaUGK\x814\x00\x00\u07d4GE\xab\x18\x1a6\xaa\x8c\xbf\"\x89\xd0\xc4Qe\xbc~\xbe#\x81\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4GPf\xf9\xad&eQ\x96\xd5SS'\xbb\xeb\x9by)\xcb\x04\x89\xa4\xccy\x95c\u00c0\x00\x00\xe0\x94GR!\x8eT\xdeB?\x86\xc0P\x193\x91z\xea\b\xc8\xfe\u054a\x04<3\xc1\x93ud\x80\x00\x00\u07d4GZa\x93W-JNY\u05fe\t\u02d6\r\u074cS\x0e/\x89$,\xf7\x8c\xdf\a\xff\x80\x00\u07d4Gd\x8b\xed\x01\xf3\xcd2I\bNc]\x14\u06a9\xe7\xec<\x8a\x89\n\x84Jt$\xd9\xc8\x00\x00\u07d4Gh\x84\x10\xff%\xd6T\xd7.\xb2\xbc\x06\xe4\xad$\xf83\xb0\x94\x89\b\xb2\x8da\xf3\u04ec\x00\x00\u07d4GkU\x99\b\x9a?\xb6\xf2\x9clr\xe4\x9b.G@\ua00d\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4Gs\x0f_\x8e\xbf\x89\xacr\xef\x80\xe4l\x12\x19P8\xec\xdcI\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94G{$\xee\u80deO\u045d\x12P\xbd\vfEyJa\u028a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4G\x81\xa1\nM\xf5\uef02\xf4\xcf\xe1\a\xba\x1d\x8av@\xbdf\x89a\t=|,m8\x00\x00\u07d4G\x88Z\xba\xbe\xdfM\x92\x8e\x1c\x88\x83\xa6a\x9cl(\x11\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94G\xe2]\xf8\x82%8\xa8Yk(\xc67\x89kM\x14<5\x1d\x8a\x11\v\xe9\xeb$\xb8\x81P\x00\x00\u07d4G\xf4ik\xd4b\xb2\r\xa0\x9f\xb8>\xd2\x03\x98\x18\xd7v%\xb3\x89\b\x13\xcaV\x90m4\x00\x00\u07d4G\xfe\xf5\x85\x84FRH\xa0\x81\r`F>\xe9>Zn\xe8\u04c9\x0fX\xcd>\x12i\x16\x00\x00\u07d4G\xffo\xebC! `\xbb\x15\x03\u05e3\x97\xfc\b\xf4\xe7\x03R\x89lk\x93[\x8b\xbd@\x00\x00\u07d4G\xff\xf4,g\x85Q\xd1A\xebu\xa6\xee9\x81\x17\xdf>J\x8d\x89\x05k\xea\xe5\x1f\xd2\xd1\x00\x00\u07d4H\x01\x0e\xf3\xb8\xe9^?0\x8f0\xa8\xcb\u007fN\xb4\xbf`\xd9e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4H\n\xf5 v\x00\x9c\xa77\x81\xb7\x0eC\xb9Y\x16\xa6\"\x03\xab\x892\x19r\xf4\b=\x87\x80\x00\u07d4H\x0f1\xb9\x891\x1eA$\u01a7F_ZD\tM6\xf9\u04097\x90\xbb\x85Q7d\x00\x00\xe0\x94H\x11\x15)j\xb7\xdbRI/\xf7\xb6G\xd63)\xfb\\\xbck\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4H\x1e:\x91\xbf\xdc/\x1c\x84(\xa0\x11\x9d\x03\xa4\x16\x01A~\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4H(\xe4\xcb\xe3N\x15\x10\xaf\xb7,+\ueb0aE\x13\xea\xeb\u0649\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94H)\x82\xac\x1f\x1cm\x17!\xfe\xec\u0679\xc9l\xd9I\x80PU\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4H0,1\x1e\xf8\xe5\xdcfAX\xddX<\x81\x19Mn\rX\x89\xb6gl\xe0\xbc\xcb\\\x00\x00\u07d4H;\xa9\x904\xe9\x00\xe3\xae\xdfaI\x9d;+\xce9\xbe\xb7\xaa\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4HT\x8bK\xa6+\xcb/\r4\xa8\x8d\u019ah\x0eS\x9c\xf0F\x89\x05l\xf1\u02fbt2\x00\x00\u07d4Hc\x84\x979&Zc\xb0\xa2\xbf#jY\x13\xe6\xf9Y\xce\x15\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4He\x9d\x8f\x8c\x9a/\xd4Oh\u06a5]#\xa6\b\xfb\xe5\x00\u0709lk\x93[\x8b\xbd@\x00\x00\xe0\x94Hf\x9e\xb5\xa8\x01\u0637_\xb6\xaaX\xc3E\x1bpX\xc2C\xbf\x8a\x06\x8dB\xc18\u06b9\xf0\x00\x00\u07d4Hjl\x85\x83\xa8D\x84\xe3\xdfC\xa1#\x83\u007f\x8c~#\x17\u0409\x11\x87\xc5q\xab\x80E\x00\x00\u07d4Hz\xdf}p\xa6t\x0f\x8dQ\xcb\xddh\xbb?\x91\u0125\xceh\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4H~\x10\x85\x02\xb0\xb1\x89\uf70cm\xa4\xd0\xdbba\xee\xc6\xc0\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94H\x88\xfb%\xcdP\u06f9\xe0H\xf4\x1c\xa4}x\xb7\x8a'\xc7\u064a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u0794H\x934\u00b6\x95\xc8\xee\a\x94\xbd\x86B\x17\xfb\x9f\xd8\xf8\xb15\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4H\xa3\r\xe1\xc9\x19\xd3\xfd1\x80\xe9}_+*\x9d\xbd\x96M-\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4H\xbf\x14\u05f1\xfc\x84\xeb\xf3\xc9k\xe1/{\xce\x01\xaai\xb0>\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4H\xc2\ue465\aV\xd8\u039a\xbe\xebu\x89\xd2,o\xee]\xfb\x89\xae\x8ez\v\xb5u\xd0\x00\x00\u07d4H\xc5\u0197\v\x91a\xbb\x1c{z\xdf\xed\x9c\xde\u078a\x1b\xa8d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94H\xd2CKz}\xbb\xff\b\";c\x87\xb0]\xa2\xe5\t1&\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4H\xd4\xf2F\x8f\x96?\u05da\x00a\x98\xbbg\x89]-Z\xa4\u04c9K\xe4\xe7&{j\xe0\x00\x00\u07d4H\xe0\xcb\xd6\u007f\x18\xac\xdbzb\x91\xe1%M\xb3.\trs\u007f\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4H\xf6\n5HO\xe7y+\u030a{c\x93\xd0\u0761\xf6\xb7\x17\x89\xc3(\t>a\xee@\x00\x00\u07d4H\xf8\x83\xe5g\xb46\xa2{\xb5\xa3\x12M\xbc\x84\xde\xc7u\xa8\x00\x89)\xd7n\x86\x9d\u0340\x00\x00\xe0\x94I\x01E\xaf\xa8\xb5E\"\xbb!\xf3R\xf0m\xa5\xa7\x88\xfa\x8f\x1d\x8a\x01\xf4lb\x90\x1a\x03\xfb\x00\x00\u07d4I\t\xb3\x19\x98\xea\xd4\x14\xb8\xfb\x0e\x84k\xd5\xcb\xde995\xbe\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4I\x12\xd9\x02\x93\x16v\xff9\xfc4\xfe<<\xc8\xfb!\x82\xfaz\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4I\x13o\xe6\xe2\x8btS\xfc\xb1kk\xbb\u9aac\xba\x837\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94I\x15a\u06cbo\xaf\xb9\x00~b\xd0P\u0082\xe9,Kk\u020a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4I\x18]\xd7\xc262\xf4lu\x94s\ubb96`\b\xcd5\x98\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4I,\xb5\xf8a\xb1\x87\xf9\xdf!\xcdD\x85\xbe\xd9\vP\xff\xe2-\x89\x1b\x19\xe5\vD\x97|\x00\x00\u07d4I-\xe4j\xaf\x8f\x1dp\x8dY\u05da\xf1\xd0:\xd2\xcb`\x90/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I.p\xf0M\x18@\x8c\xb4\x1e%`70Pk5\xa2\x87k\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4I:g\xfe#\xde\xccc\xb1\r\xdau\xf3(v\x95\xa8\x1b\u056b\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4I=H\xbd\xa0\x15\xa9\xbf\xcf\x16\x03\x93n\xabh\x02L\xe5Q\xe0\x89\x018\xa3\x88\xa4<\x00\x00\x00\xe0\x94IBV\xe9\x9b\x0f\x9c\xd6\xe5\xeb\xca8\x99\x862R\x90\x01e\u020a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4IM\xecM^\xe8\x8a'q\xa8\x15\xf1\xeerd\x94/\xb5\x8b(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I[d\x1b\x1c\u07a3b\u00f4\u02fd\x0f\\\xc5\v\x1e\x17k\x9c\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94Ih\xa2\xce\xdbEuU\xa19)Z\xea(wnT\x00<\x87\x8a\x02#\x1a\xef\u0266b\x8f\x00\x00\u07d4Im6U4S\n_\xc1W|\nRA\u02c8\xc4\xdapr\x89a\t=|,m8\x00\x00\xe0\x94In1\x95\x92\xb3A\xea\xcc\xd7x\u0767\xc8\x19mT\xca\xc7u\x8a\x01\xf5q\x89\x87fKH\x00\x00\u07d4IoXC\xf6\xd2L\u064d%^L#\xd1\xe1\xf0#\"uE\x89_\x17\x9f\u0526\xee\t\x80\x00\xe0\x94Ip\u04ec\xf7+[\x1f2\xa7\x00<\xf1\x02\xc6N\xe0TyA\x8a\x1d\xa5jK\b5\xbf\x80\x00\x00\u07d4Iw\xa7\x93\x9d\t9h\x94U\xce&9\xd0\xeeZL\xd9\x10\xed\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4Iy\x19N\xc9\xe9}\xb9\xbe\xe84;|w\xd9\xd7\xf3\xf1\u071f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Iy4c\xe1h\x10\x83\u05ab\xd6\xe7%\u057b\xa7E\xdc\xcd\xe8\x89\x1d\x98\xe9LNG\x1f\x00\x00\u07d4I\x81\xc5\xfff\xccN\x96\x80%\x1f\xc4\xcd/\xf9\a\xcb2xe\x89(\xa8WBTf\xf8\x00\x00\u07d4I\x89\u007f\xe92\xbb\xb3\x15L\x95\u04fc\xe6\xd9;ms)\x04\u0749\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4I\x89\xe1\xab^|\xd0\aF\xb3\x93\x8e\xf0\xf0\xd0d\xa2\x02[\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4I\x8a\xbd\xeb\x14\xc2k{r4\xd7\x0f\u03ae\xf3a\xa7m\xffr\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4I\xa6E\xe0f}\xfd{2\xd0u\xcc$g\u074ch\t\a\u0109\a\x06\x01\x95\x8f\u02dc\x00\x00\xe0\x94I\xb7N\x16\x92e\xf0\x1a\x89\xecL\x90r\u0164\xcdr\xe4\xe85\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4I\xbd\xbc{\xa5\xab\xeb\xb68\x9e\x91\xa3(R \xd3E\x1b\xd2S\x8965\u026d\xc5\u07a0\x00\x00\u07d4I\xc9A\xe0\xe5\x01\x87&\xb7)\x0f\xc4s\xb4q\xd4\x1d\xae\x80\u0449\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94I\xc9w\x1f\xca\x19\u0579\xd2E\u0211\xf8\x15\x8f\xe4\x9fG\xa0b\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4I\xcf\x1eT\xbe61\x06\xb9 r\x9d-\v\xa4o\bg\x98\x9a\x89\x0e\x87?D\x13<\xb0\x00\x00\u07d4I\xd2\u008e\xe9\xbcT^\xaa\xf7\xfd\x14\xc2|@s\xb4\xbb_\x1a\x89O\xe9\xb8\x06\xb4\r\xaf\x00\x00\u07d4I\xdd\xee\x90.\x1d\f\x99\u0471\x1a\xf3\u030a\x96\xf7\x8eM\xcf\x1a\x89\n\u03a5\xe4\xc1\x8cS\x00\x00\u07d4I\xf0(9[Z\x86\xc9\xe0\u007fwxc\x0eL.=7:w\x89\x06\xa7JP8\u06d1\x80\x00\xe0\x94J\x19 5\xe2a\x9b$\xb0p\x9dVY\x0e\x91\x83\xcc\xf2\xc1\u064a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4J@S\xb3\x1d\x0e\xe5\u06ef\xb1\xd0k\u05ec\u007f\xf3\",G\u0589K\xe4\xe7&{j\xe0\x00\x00\u07d4JC\x01p\x15-\xe5\x17&3\u0742b\xd1\a\xa0\xaf\xd9j\x0f\x89\xabM\xcf9\x9a:`\x00\x00\u07d4JG\xfc>\x17\u007fVz\x1e8\x93\xe0\x00\xe3k\xba#R\n\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4JR\xba\xd2\x03W\"\x8f\xaa\x1e\x99k\xedy\f\x93gK\xa7\u0409Hz\x9a0E9D\x00\x00\u07d4JS\xdc\xdbV\xceL\xdc\xe9\xf8.\xc0\xeb\x13\xd6sR\xe7\u020b\x89\u3bb5sr@\xa0\x00\x00\u07d4J_\xae;\x03r\xc20\xc1%\xd6\xd4p\x14\x037\xab\x91VV\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4Jq\x90a\xf5(T\x95\xb3{\x9d~\xf8\xa5\x1b\a\xd6\u6b2c\x89\n\xd4\xc81j\v\f\x00\x00\u07d4Js8\x92\x98\x03\x1b\x88\x16\u0329FB\x1c\x19\x9e\x18\xb3C\u0589\"8h\xb8y\x14o\x00\x00\u07d4Js]\"G\x927m3\x13g\xc0\x93\xd3\x1c\x87\x944\x15\x82\x89f\xff\xcb\xfd^Z0\x00\x00\u07d4Jt\x94\xcc\xe4HU\u0300X(B\xbe\x95\x8a\r\x1c\x00r\ue242\x1a\xb0\xd4AI\x80\x00\x00\u07d4Ju\xc3\xd4\xfao\u033d]\u0567\x03\xc1Sy\xa1\xe7\x83\u9dc9b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94J\x81\xab\xe4\x98L|k\xefc\u0598 \xe5WC\xc6\x1f \x1c\x8a\x03d\x01\x00N\x9a\xa3G\x00\x00\u07d4J\x82iO\xa2\x9d\x9e!2\x02\xa1\xa2\t(]\xf6\xe7E\xc2\t\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4J\x83\\%\x82LG\xec\xbf\u01d49\xbf?\\4\x81\xaau\u0349K\xe4\xe7&{j\xe0\x00\x00\u07d4J\x91\x802C\x91Y\xbb1[g%\xb6\x83\r\xc86\x97s\x9f\x89\x12\xa3.\xf6x3L\x00\x00\u07d4J\x97\xe8\xfc\xf4c^\xa7\xfc^\x96\xeeQu.\u00c8qk`\x89\x1d\x99E\xab+\x03H\x00\x00\u07d4J\x9a&\xfd\n\x8b\xa1\x0f\x97}\xa4\xf7|1\x90\x8d\xabJ\x80\x16\x89a\t=|,m8\x00\x00\u07d4J\xa1H\xc2\xc34\x01\xe6j+Xnew\u0132\x92\xd3\xf2@\x89\v\xb8`\xb2\x85\xf7t\x00\x00\u07d4J\xa6\x93\xb1\"\xf3\x14H*G\xb1\x1c\xc7|h\xa4\x97\x87ab\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4J\xb2\xd3O\x04\x83O\xbftyd\x9c\xab\x92=,G%\xc5S\x89\xbe\xd1\xd0&=\x9f\x00\x00\x00\u07d4J\xc0vs\xe4/d\xc1\xa2^\xc2\xfa-\x86\xe5\xaa+4\xe09\x89lk\x93[\x8b\xbd@\x00\x00\u07d4J\u016c\xad\x00\v\x88w!L\xb1\xae\x00\xea\u0263}Y\xa0\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4J\u0250ZL\xb6\xab\x1c\xfdbTn\xe5\x91s\x00\xb8|O\u07897\b\xba\xed=h\x90\x00\x00\u07d4J\u03e9\xd9N\xdaf%\xc9\u07e5\xf9\xf4\xf5\xd1\a\xc4\x03\x1f\u07c9\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4J\xd0G\xfa\xe6~\xf1b\xfeh\xfe\xdb\xc2};e\xca\xf1\f6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4J\xd9]\x18\x8dddp\x9a\xdd%U\xfbM\x97\xfe\x1e\xbf1\x1f\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\u07d4J\xdb\xf4\xaa\xe0\xe3\xefD\xf7\xddM\x89\x85\u03ef\tn\u010e\x98\x89\b!\xab\rD\x14\x98\x00\x00\u07d4J\xe2\xa0M9\t\xefENTL\xcf\xd6\x14\xbf\xef\xa7\x10\x89\xae\x89\x18\x01\x15\x9d\xf1\xee\xf8\x00\x00\xe0\x94J\xe90\x82\xe4Q\x87\xc2a`\xe6g\x92\xf5\u007f\xad5Q\xc7:\x8a\x04\x96\x15 \xda\xff\x82(\x00\x00\u07d4J\xf0\xdb\a{\xb9\xba^D>!\xe1H\xe5\x9f7\x91\x05\u0152\x89 \x86\xac5\x10R`\x00\x00\u07d4K\x06\x19\xd9\u062a1:\x951\xac}\xbe\x04\xca\rjZ\u0476\x89lk\x93[\x8b\xbd@\x00\x00\u07d4K\v\u062c\xfc\xbcS\xa6\x01\v@\xd4\u040d\xdd-\x9dib-\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4K\x19\xeb\f5K\xc199`\xeb\x06\x06;\x83\x92o\rg\xb2\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4K)C|\x97\xb4\xa8D\xbeq\u0323\xb6H\xd4\xca\x0f\u075b\xa4\x89\b$q\x984\u03ec\x00\x00\u07d4K1\xbfA\xab\xc7\\\x9a\xe2\u034f\u007f5\x16;n+tPT\x89\x14\xb5P\xa0\x13\xc78\x00\x00\u07d4K:|\u00e7\u05f0\x0e\xd5(\"!\xa6\x02Y\xf2[\xf6S\x8a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94K:\xab3^\xbb\xfa\xa8p\xccM`^}.t\xc6h6\x9f\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4K\xcd\xc1\x8a`\x00\x00\u07d4K`\xa3\xe2S\xbf8\xc8\xd5f \x10\xbb\x93\xa4s\xc9e\xc3\xe5\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4Kt\xf5\xe5\x8e.\xdfv\xda\xf7\x01Q\x96J\v\x8f\x1d\xe0f<\x89\x11\x90\xaeID\xba\x12\x00\x00\u07d4Kv!f\xdd\x11\x18\xe8Ci\xf8\x04\xc7_\x9c\xd6W\xbfs\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Ky.)h>\xb5\x86\u353b3Rl`\x01\xb3\x97\x99\x9e\x89 \x86\xac5\x10R`\x00\x00\u07d4K\x90N\x93K\xd0\u030b p_\x87\x9e\x90[\x93\xea\f\xcc0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94K\x92\x06\xbakT\x9a\x1a\u007f\x96\x9e\x1d]\xba\x86u9\xd1\xfag\x8a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4K\x98N\xf2lWn\x81Z.\xae\xd2\xf5\x17\u007f\a\u06f1\xc4v\x89T\x91YV\xc4\t`\x00\x00\u07d4K\x9e\x06\x8f\xc4h\tv\xe6\x15\x04\x91)\x85\xfd\\\xe9K\xab\r\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4K\xa0\xd9\xe8\x96\x01w+IhG\xa2\xbbC@\x18g\x87\xd2e\x8965\u026d\xc5\u07a0\x00\x00\u07d4K\xa5:\xb5I\xe2\x01m\xfa\"<\x9e\u0563\x8f\xad\x91(\x8d\a\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94K\xa8\xe0\x11\u007f\xc0\xb6\xa3\xe5k$\xa3\xa5\x8f\xe6\xce\xf4B\xff\x98\x8a\x011\xbe\xb9%\xff\xd3 \x00\x00\u07d4K\xac\x84j\xf4\x16\x9f\x1d\x95C\x1b4\x1d\x88\x00\xb2!\x80\xaf\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4K\xb6\xd8k\x83\x14\xc2-\x8d7\xeaQm\x00\x19\xf1V\xaa\xe1-\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94K\xb9e\\\xfb*6\xea|cz{\x85\x9bJ1T\xe2n\xbe\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\xe0\x94K\xbc\xbf8\xb3\xc9\x01c\xa8K\x1c\u04a9;X\xb2\xa34\x8d\x87\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94K\xd6\xdd\f\xff#@\x0e\x170\xba{\x89E\x04W}\x14\xe7J\x8a+\xa0\xcc\xdd\xd0\xdfs\xb0\x00\x00\u07d4K\xe8b\x8a\x81T\x87N\x04\x8d\x80\xc1B\x18\x10\"\xb1\x80\xbc\xc1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4K\xe9\rA!)\u0564\xd0BCa\xd6d\x9dNG\xa6#\x16\x897\b\xba\xed=h\x90\x00\x00\xe0\x94K\xea(\x8e\xeaB\u0115^\xb9\xfa\xad*\x9f\xafG\x83\xcb\u076c\x8a\x06\x18\xbe\x16c\u012fI\x00\x00\u07d4K\xf4G\x97\x99\xef\x82\xee\xa2\tC7OV\xa1\xbfT\x00\x1e^\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4K\xf8\xbf\x1d5\xa211Wd\xfc\x80\x01\x80\x9a\x94\x92\x94\xfcI\x89\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\u07d4K\xf8\xe2oL'\x90\xdae3\xa2\xac\x9a\xba\xc3\u019a\x19\x943\x89\n\u05ce\xbcZ\xc6 \x00\x00\u0794L\n\xcaP\x8b<\xaf^\xe0(\xbcp}\xd1\xe8\x00\xb88\xf4S\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94L\v\x15\x15\xdf\xce\u05e1>\x13\xee\x12\xc0\xf5#\xaePO\x03+\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4L\x13\x98\f2\xdc\xf3\x92\vx\xa4\xa7\x903\x12\x90|\x1b\x12?\x89\x03A\x00\x15\xfa\xae\f\x00\x00\u07d4L\x15y\xaf3\x12\xe4\xf8\x8a\xe9\x95\xcc9W\xd2R\xce\v\xf0\xc8}[O\"4g.p\x89\x87\x86x2n\xac\x90\x00\x00\u07d4LB1y\x82i\x1d\x10\x89\x05k\xc7^-c\x10\x00\x00\u07d4LZ\xfe@\xf1\x8f\xfcH\u04e1\xae\xc4\x1f\u009d\xe1y\xf4\u0497\x89lk\x93[\x8b\xbd@\x00\x00\u07d4L[=\xc0\xe2\xb96\x0f\x91(\x9b\x1f\xe1<\xe1,\x0f\xbd\xa3\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Lfk\x86\xf1\xc5\ue324\x12\x85\xf5\xbd\xe4\xf7\x90R\b\x14\x06\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Lik\xe9\x9f:i\x04@\xc3CjY\xa7\xd7\xe97\u05ba\r\x89\xbb\x91%T\"c\x90\x00\x00\u07d4Lj$\x8f\xc9}p]\xefI\\\xa2\aY\x16\x9e\xf0\xd3dq\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4Lj\x9d\xc2\u02b1\n\xbb.|\x13p\x06\xf0\x8f\ucd77y\xe1\x89\x1b\r\x04 /G\xec\x00\x00\u07d4Lk\x93\xa3\xbe\xc1cIT\f\xbf\xca\xe9l\x96!\xd6dP\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Lu\x98\x13\xad\x13\x86\xbe\xd2\u007f\xfa\xe9\xe4\x81^60\u0323\x12\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Lv\f\xd9\xe1\x95\xeeO-k\xce%\x00\xff\x96\xda|C\ue44a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4Lv{e\xfd\x91\x16\x1fO\xbd\xccji\xe2\xf6\xadq\x1b\xb9\x18\x89'\b\x01\xd9F\xc9@\x00\x00\u07d4L~.+w\xad\f\xd6\xf4J\xcb(a\xf0\xfb\x8b(u\x0e\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4L\x85\xed6/$\xf6\xb9\xf0L\xdf\xcc\xd0\"\xaeSQG\u02f9\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4L\x93[\xb2Pw\x8b0\x9b==\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4L\xee\x90\x1bJ\u0231V\xc5\xe2\xf8\xa6\xf1\xbe\xf5r\xa7\xdc\xeb~\x8965\u026d\xc5\u07a0\x00\x00\u07d4L\xef\xbe#\x98\xe4}R\u73743L\x8bivu\U00053b89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4L\xf5S{\x85\x84/\x89\xcf\xee5\x9e\xaeP\x0f\xc4I\xd2\x11\x8f\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94M\bG\x1dh\x00z\xff*\xe2y\xbc^?\xe4\x15o\xbb\xe3\u078a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4M \x01\x10\x12@\b\xd5ov\x98\x12VB\f\x94jo\xf4\\\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4M$\xb7\xacG\xd2\xf2}\xe9\tt\xba=\xe5\xea\xd2\x03TK\u0349\x05k\xc7^-c\x10\x00\x00\u0794M)\xfcR:,\x16)S!!\u0699\x98\u9d6b\x9d\x1bE\x88\xdbD\xe0I\xbb,\x00\x00\u07d4M8\xd9\x0f\x83\xf4Q\\\x03\xccx2j\x15M5\x8b\u0602\xb7\x89\n\ad\a\xd3\xf7D\x00\x00\u07d4ML\xf5\x80t)a^0\xcd\xfa\xce\x1eZ\xaeM\xad0U\xe6\x89 \x86\xac5\x10R`\x00\x00\u07d4MW\xe7\x16\x87l\f\x95\xef^\xae\xbd5\xc8\xf4\x1b\x06\x9bk\xfe\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Mg\U000ab159\xfe\xf5\xfcA9\x99\xaa\x01\xfd\u007f\xcep\xb4=\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Mn\x8f\xe1\t\xcc\xd2\x15\x8eM\xb1\x14\x13/\xe7_\xec\u023e[\x89\x01[5W\xf1\x93\u007f\x80\x00\xe0\x94Mq\xa6\xeb=\u007f2~\x184'\x8e(\v\x03\x9e\xdd\xd3\x1c/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4M|\xfa\xa8L\xb31\x06\x80\n\x8c\x80/\xb8\xaaF8\x96\u0159\x89a\t=|,m8\x00\x00\u07d4M\x80\x10\x93\xc1\x9c\xa9\xb8\xf3B\xe3<\xc9\xc7{\xbdL\x83\x12\u03c9\x12\xb3\xe7\xfb\x95\u0364\x80\x00\u07d4M\x82\x88\x94u/o%\x17]\xaf!w\tD\x87\x95Ko\x9f\x89O!+\xc2\u011c\x83\x80\x00\xe0\x94M\x82\xd7p\f\x12;\xb9\x19A\x9b\xba\xf0Fy\x9ck\x0e,f\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4M\x83m\x9d;\x0e,\xbdM\xe0PYo\xaaI\f\xff\xb6\r]\x89\x10CV\x1a\x88)0\x00\x00\u07d4M\x86\x97\xaf\x0f\xbf,\xa3n\x87h\xf4\xaf\"\x135phZ`\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4M\x92y\x96 )\xa8\xbdEc\x977\xe9\x8bQ\x1e\xff\aL!\x89Hz\x9a0E9D\x00\x00\u07d4M\x93io\xa2HY\xf5\u0493\x9a\xeb\xfaT\xb4\xb5\x1a\xe1\xdc\u0309\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4M\x9cw\xd0u\f^o\xbc$\u007f/\u05d2thl\xb3S\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4M\xa5\xed\u0188\xb0\xcbb\xe1@=\x17\x00\xd9\u0739\x9f\xfe?\u04c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94M\xa8\x03\ai\x84K\xc3A\x86\xb8\\\xd4\xc74\x88I\xffI\xe9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4M\xb1\xc4:\x0f\x83M}\x04x\xb8\x96\ag\xec\x1a\xc4L\x9a\xeb\x89/Q\x810V'7\x00\x00\u07d4M\xb2\x12\x84\xbc\xd4\xf7\x87\xa7Ue\x00\xd6\xd7\xd8\xf3f#\xcf5\x89i(7Ow\xa3c\x00\x00\u07d4M\xc3\xda\x13\xb2\xb4\xaf\xd4O]\r1\x89\xf4D\xd4\xdd\xf9\x1b\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4M\u013f^u\x89\xc4{(7\x8du\x03\u03d6H\x80a\u06fd\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4M\xc9\u057bK\x19\xce\u0354\xf1\x9e\xc2] \x0e\xa7/%\xd7\xed\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94M\xcd\x11\x81X\x18\xae)\xb8]\x016sI\xa8\xa7\xfb\x12\xd0k\x8a\x01\xacB\x86\x10\x01\x91\xf0\x00\x00\u07d4M\xcfb\xa3\xde?\x06\x1d\xb9\x14\x98\xfda\x06\x0f\x1fc\x98\xffs\x89lj\xccg\u05f1\xd4\x00\x00\u07d4M\xd11\xc7J\x06\x8a7\xc9\n\xde\xd4\xf3\t\xc2@\x9fdx\u04c9\x15\xaf9\u4ab2t\x00\x00\xe0\x94M\u0767Xk\"7\xb0S\xa7\xf3(\x9c\xf4`\xdcW\xd3z\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4M\xe3\xfe4\xa6\xfb\xf64\xc0Q\x99\u007fG\xcc\u007fHy\x1fX$\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4M\xf1@\xbaye\x85\xddT\x891[\xcaK\xbah\n\u06f8\x18\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4N\x02\ay\xb5\xdd\xd3\xdf\"\x8a\x00\xcbH\xc2\xfc\x97\x9d\xa6\xae8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4N\v\xd3$s\xc4\xc5\x1b\xf2VT\xde\xf6\x9fy|k)\xa22\x89V\xc9]\xe8\xe8\xca\x1d\x00\x00\u07d4N\"%\xa1\xbbY\xbc\x88\xa21ft\xd33\xb9\xb0\xaf\xcafU\x89\bg\x0e\x9e\xc6Y\x8c\x00\x00\u07d4N#\x10\x19\x1e\xad\x8d;\xc6H\x98s\xa5\xf0\xc2\xeck\x87\u1f8965\u026d\xc5\u07a0\x00\x00\u07d4N#-S\xb3\u6f8f\x89Sa\xd3\x1c4\xd4v+\x12\xc8.\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4N+\xfaJFo\x82g\x1b\x80\x0e\xeeBj\xd0\f\a\x1b\xa1p\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4N>\xda\u0506M\xabd\xca\xe4\xc5Azvw@S\xdcd2\x89 \b\xfbG\x8c\xbf\xa9\x80\x00\u07d4NC\x18\xf5\xe1>\x82JT\xed\xfe0\xa7\xedO&\xcd=\xa5\x04\x89lk\x93[\x8b\xbd@\x00\x00\u07d4N[w\xf9\x06aY\xe6\x15\x93?-\xdatw\xfaNG\xd6H\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94Nf\x00\x80b\x89EJ\u03630\xa2\xa3U`\x10\u07ec\xad\xe6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Ns\xcf#y\xf1$\x86\x0fs\xd6\xd9\x1b\xf5\x9a\xcc\\\xfc\x84[\x89\x02,\xa3X|\xf4\xeb\x00\x00\xe0\x94Nz\xa6~\x12\x18>\xf9\xd7F\x8e\xa2\x8a\xd29\xc2\xee\xf7\x1bv\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\xe0\x94N{TGM\x01\xfe\xfd8\x8d\xfc\xd5;\x9ff&$A\x8a\x05\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94N\x89.\x80\x81\xbf6\xe4\x88\xfd\xdb;&0\xf3\xf1\xe8\xda0\u048a\x02\x8a\xba0u$Q\xfc\x00\x00\xe0\x94N\x8amcH\x9c\xcc\x10\xa5\u007f\x88_\x96\xeb\x04\xec\xbbT`$\x8a\x03\xea\xe3\x13\x0e\u0316\x90\x00\x00\u07d4N\x8eG\xae;\x1e\xf5\f\x9dT\xa3\x8e\x14 \x8c\x1a\xbd6\x03\u0089y(\xdb\x12vf\f\x00\x00\u0794N\x90\u03312X\xac\xaa\x9fO\xeb\xc0\xa3B\x92\xf9Y\x91\xe20\x88\xdbD\xe0I\xbb,\x00\x00\u07d4N\xa5n\x11\x12d\x1c\x03\x8d\x05e\xa9\u0096\xc4c\xaf\xef\xc1~\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\xe0\x94N\xa7\x0f\x041?\xaee\xc3\xff\"J\x05\\=-\xab(\xdd\u07ca\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4N\xb1EKW8\x05\u022c\xa3~\xde\xc7\x14\x9aA\xf6\x12\x02\xf4\x89\x10CV\x1a\x88)0\x00\x00\u07d4N\xb8{\xa8x\x8e\xba\r\xf8~[\x9b\xd5\n\x8eE6\x80\x91\xc1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4N\xbcV)\xf9\xa6\xa6k,\xf36:\u0109\\\x03H\u8fc7\x8967\tlK\xcci\x00\x00\u07d4N\xc7h)^\xea\xba\xfcB\x95\x84\x15\xe2+\xe2\x16\xcd\xe7v\x18\x89\x03;\x1d\xbc9\xc5H\x00\x00\u07d4N\xcc\x19\x94\x8d\xd9\u0347\xb4\xc7 \x1a\xb4\x8eu\x8f(\xe7\xccv\x89\x1b\x1d\xaba\u04ead\x00\x00\u07d4N\xd1M\x81\xb6\v#\xfb%\x05M\x89%\u07e5s\u072eah\x89\x12nr\xa6\x9aP\xd0\x00\x00\xe0\x94N\xe1<\rA \vF\u045d\xee\\K\xce\xc7\x1d\x82\xbb\x8e8\x8a\x01\xab\xee\x13\u033e\ufbc0\x00\u07d4N\xea\xd4\n\xad\x8cs\xef\b\xfc\x84\xbc\n\x92\xc9\t/j6\xbf\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4N\xeb\xe8\f\xb6\xf3\xaeY\x04\xf6\xf4\xb2\x8d\x90\u007f\x90q\x89\xfc\xab\x89lj\xccg\u05f1\xd4\x00\x00\u07d4N\xeb\xf1 ]\f\xc2\f\xeel\u007f\x8f\xf3\x11_V\u050f\xba&\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4N\xf1\xc2\x14c:\xd9\xc0p;N#t\xa2\xe3>>B\x92\x91\x89Hz\x9a0E9D\x00\x00\u07d4N\xfc\xd9\u01df\xb43L\xa6${\n3\xbd\x9c\xc32\b\xe2r\x89Hz\x9a0E9D\x00\x00\xe0\x94O\x06$k\x8dK\u0496a\xf4>\x93v\"\x01\u0486\x93Z\xb1\x8a\x01\x059O\xfcF6\x11\x00\x00\u07d4O\x15+/\xb8e\x9dCwn\xbb\x1e\x81g:\xa8Ai\xbe\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4O\x17\u007f\x9dV\x95=\xedq\xa5a\x1f93\"\xc3\x02y\x89\\\x89\rU\uf422\xda\x18\x00\x00\u07d4O\x1a-\xa5JLm\xa1\x9d\x14$\x12\xe5n\x81WA\xdb#%\x89\x05k\xc7^-c\x10\x00\x00\u07d4O#\xb6\xb8\x17\xff\xa5\xc6d\xac\xda\u05db\xb7\xb7&\xd3\n\xf0\xf9\x89_h\xe8\x13\x1e\u03c0\x00\x00\xe0\x94O&i\f\x99+z1*\xb1.\x13\x85\xd9J\xcdX(\x8e{\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4O+G\xe2wZ\x1f\xa7\x17\x8d\xad\x92\x98Z[\xbeI;\xa6\u0589\n\u05ce\xbcZ\xc6 \x00\x00\u07d4O:HT\x91\x11E\xea\x01\xc6D\x04K\xdb.Z\x96\n\x98/\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4O?,g0i\xac\x97\xc2\x026\a\x15)\x81\xf5\xcd`c\xa0\x89 \x86\xac5\x10R`\x00\x00\xe0\x94OJ\x9b\xe1\f\xd5\xd3\xfb]\xe4\x8c\x17\xbe)o\x89V\x90d[\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4OR\xadap\xd2[*.\x85\x0e\xad\xbbRA?\xf20>\u007f\x89\xa4\xccy\x95c\u00c0\x00\x00\u07d4OX\x01\xb1\xeb0\xb7\x12\u0620WZ\x9aq\xff\x96]O4\xeb\x89\x10CV\x1a\x88)0\x00\x00\u07d4O]\xf5\xb9CW\u0794\x86\x04\xc5\x1bx\x93\xcd\xdf`v\xba\xad\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\u07d4Od\xa8^\x8e\x9a@I\x8c\fu\xfc\xeb\x037\xfbI\b>^\x8965\u026d\xc5\u07a0\x00\x00\u07d4Og9m%S\xf9\x98x_pN\a\xa69\x19}\u0454\x8d\x89\x10DrR\x1b\xa78\x00\x00\u07d4OmG7\u05e9@8$\x87&H\x86i|\xf7c\u007f\x80\x15\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4Os0\toy\xed&N\xe0\x12\u007f]0\xd2\xf7?!\xcb\u007f\x04\x89\x04\x82\xfe&\f\xbc\xa9\x00\x00\u07d4O\xeeP\xc5\xf9\x88 k\t\xa5sF\x9f\xb1\u0434.\xbbm\u0389l\xee\x06\u077e\x15\xec\x00\x00\u07d4O\xf6v\xe2\u007fh\x1a\x98-\x8f\xd9\xd2\x0ed\x8b=\xce\x05\xe9E\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4O\xf6\u007f\xb8\u007fn\xfb\xa9'\x990\u03fd\x1bz4L\u057a\x8bN\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94PFf\u03891\x17^\x11\xa5\xed\x11\xc1\u072a\x06\xe5\u007fNf\x8a\x02\u007f>\u07f3Nn@\x00\x00\u0794PXM\x92\x06\xa4l\xe1\\0\x11\x17\xee(\xf1\\0\xe6\x0eu\x88\xb9\xf6]\x00\xf6<\x00\x00\xe0\x94PZ3\xa1\x864\xddH\x00i)\x13N\x00\x00\u07d4P\u0286\xb5\xeb\x1d\x01\x87M\xf8\xe5\xf3IE\u051cl\x1a\xb8H\x8965\u026d\xc5\u07a0\x00\x00\u07d4P\u0357\xe97\x8b\\\xf1\x8f\x179c#l\x99Q\xeft8\xa5\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4P\u073c'\xbc\xad\x98@\x93\xa2\x12\xa9\xb4\x17\x8e\xab\xe9\x01ua\x89\a\xe3by\v\\\xa4\x00\x00\u07d4P\xe10#\xbd\x9c\xa9j\xd4\xc5?\xdf\xd4\x10\xcbk\x1fB\v\u07c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94P\xe1\xc8\xec\x98A[\xefD&\x18p\x87\x99C{\x86\xe6\xc2\x05\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4P\xf8\xfaK\xb9\xe2g|\x99\nN\xe8\xcep\xdd\x15#%\x1eO\x89\x01i=#\x16Ok\x00\x00\u07d4P\xfb6\xc2q\a\xee,\xa9\xa3#n'F\u0321\x9a\xcekI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4P\xfe\xf2\x96\x95U\x88\u02aet\xc6.\xc3*#\xa4T\xe0\x9a\xb8\x89A\x1d\xff\xab\xc5\a8\x00\x00\u07d4Q\x02\xa4\xa4 w\xe1\x1cX\xdfGs\u3b14F#\xa6m\x9f\x89lp\x15\xfdR\xed@\x80\x00\u07d4Q\x03\x93w\xee\xd0\xc5s\xf9\x86\xc5\xe8\xa9_\xb9\x9aY\xe93\x0f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Q\x03\xbc\t\x93>\x99!\xfdS\xdcSo\x11\xf0]\rG\x10}\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94Q\x04\xec\xc0\xe30\xdd\x1f\x81\xb5\x8a\xc9\u06f1\xa9\xfb\xf8\x8a<\x85\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4Q\r\x81Y\u0314Wh\xc7E\a\x90\xba\a>\xc0\xd9\xf8\x9e0\x89\x8a\xc7#\x04\x89\xe8\x00\x00\x00\u07d4Q\x0e\xdaV\x01I\x9a\r^\x1a\x00k\xff\xfd\x836r\xf2\xe2g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x12dF\xab=\x802U~\x8e\xbaeY}u\xfa\u0701\\\x89\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\xe0\x94Q\x18U}`\r\x05\xc2\xfc\xbf8\x06\xff\xbd\x93\xd0 %\xd70\x8a\x02g\u04ebd#\xf5\x80\x00\x00\u07d4Q\x1e\x0e\xfb\x04\xacN?\xf2\xe6U\x0eI\x82\x95\xbf\xcdV\xff\u0549$=M\x18\"\x9c\xa2\x00\x00\u07d4Q!\x16\x81{\xa9\xaa\xf8C\xd1P|e\xa5\xead\n{\x9e\xec\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4Q&F\ri,q\u026fo\x05WM\x93\x99\x83h\xa27\x99\x89\x02\u0465\x1c~\x00P\x00\x00\u07d4Q'\u007f\xe7\xc8\x1e\xeb\xd2R\xa0=\xf6\x9ak\x9f2n'\"\a\x89\x03@.y\u02b4L\x80\x00\u07d4Q)oPD'\r\x17pvF\x12\x9c\x86\xaa\xd1d^\xad\xc1\x89H|r\xb3\x10\xd4d\x80\x00\xe0\x94Q+\x91\xbb\xfa\xa9\xe5\x81\xefh?\xc9\r\x9d\xb2*\x8fI\xf4\x8b\x8aA\xa5\"8m\x9b\x95\xc0\x00\x00\u07d4Q5\xfb\x87W`\f\xf4tTbR\xf7M\xc0tm\x06&,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4QF2\xef\xbdd,\x04\xdel\xa3B1]@\u0750\xa2\u06e6\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4QKu\x12\u026e^\xa6<\xbf\x11q[c\xf2\x1e\x18\u0496\xc1\x89lj\xccg\u05f1\xd4\x00\x00\u07d4QS\xa0\xc3\u0211(\x81\xbf\x1c5\x01\xbfd\xb4VI\xe4\x82\"\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94QVQ\xd6\xdbO\xaf\x9e\xcd\x10:\x92\x1b\xbb\xbej\xe9p\xfd\u050a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94Q_0\xbc\x90\xcd\xf4W~\xe4}e\u05c5\xfb\xe2\xe87\u01bc\x8a\x02'\x1b^\x01\x8b\xa0X\x00\x00\u07d4Q`\xeda.\x1bH\xe7??\xc1[\xc42\x1b\x8f#\xb8\xa2K\x89\x1e\x82kB(e\xd8\x00\x00\u07d4Qa\xfdI\xe8G\xf6tU\xf1\u023bz\xbb6\xe9\x85&\r\x03\x89A\rXj \xa4\xc0\x00\x00\u07d4QiT\x02_\xca&\b\xf4}\xa8\x1c!^\xed\xfd\x84J\t\xff\x89\x14\xb5P\xa0\x13\xc78\x00\x00\u07d4Qi\xc6\n\xeeL\xee\u0444\x9a\xb3mfL\xff\x97\x06\x1e\x8e\xa8\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4Q|uC\r\xe4\x01\xc3A\x03&\x86\x11'\x90\xf4mM6\x9e\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4Q|\xd7`\x8e]\r\x83\xa2kq\u007f6\x03\xda\xc2'}\u00e4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x86]\xb1H\x88\x19Q\xf5\x12Qq\x0e\x82\xb9\xbe\r~\xad\xb2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\x89\x1b,\xcd\xd2\xf5\xa4K*\x8b\u011a]\x9b\xcadw%\x1c\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4Q\x8c\xef'\xb1\x05\x82\xb6\xd1OiH=\u06a0\xdd<\x87\xbb\\\x89 \x86\xac5\x10R`\x00\x00\u07d4Q\xa6\xd6'\xf6j\x89#\u060d`\x94\xc4qS\x80\xd3\x05|\xb6\x89>s\xd2z5\x94\x1e\x00\x00\u07d4Q\xa8\xc2\x166\x02\xa3.\xe2L\xf4\xaa\x97\xfd\x9e\xa4\x14QiA\x89\x03h\xf7\xe6\xb8g,\x00\x00\u07d4Q\xb4u\x8e\x9e\x14P\xe7\xafBh\xc3\u01f1\xe7\xbdo\\uP\x8965\u026d\xc5\u07a0\x00\x00\u07d4Q\u028b\xd4\xdcdO\xacG\xafgUc\u0540J\r\xa2\x1e\xeb\x89*\xb7\xb2`\xff?\xd0\x00\x00\u07d4Q\xd2K\xc3so\x88\xddc\xb7\" &\x88f0\xb6\ub1cd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Q\u05cb\x17\x8dp~9n\x87\x10\x96\\OA\xb1\xa1\xd9\x17\x9d\x89\x05\xfe\xe2\"\x04\x1e4\x00\x00\u07d4Q\xe3/\x14\xf4\xca^(|\xda\xc0W\xa7y^\xa9\xe0C\x99S\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Q\xe4?\xe0\xd2\\x(`\xaf\x81\xea\x89\xddy<\x13\xf0\u02f1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4Q\xe7\xb5\\/\x98 \xee\xd78\x846\x1bPf\xa5\x9boE\u0189lk\x93[\x8b\xbd@\x00\x00\xe0\x94Q\xea\x1c\t4\xe3\xd0@\"\ud715\xa0\x87\xa1P\xefp^\x81\x8a\x01Tp\x81\xe7\"M \x00\x00\u07d4Q\xee\f\xca;\xcb\x10\xcd>\x987\"\xce\xd8I=\x92l\bf\x8965f3\xeb\xd8\xea\x00\x00\xe0\x94Q\xf4f:\xb4O\xf7\x93E\xf4'\xa0\xf6\xf8\xa6\u0225?\xf24\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Q\xf5^\xf4~dV\xa4\x18\xab2\xb9\"\x1e\xd2}\xbaf\b\xee\x89\u3bb5sr@\xa0\x00\x00\xe0\x94Q\xf9\xc42\xa4\xe5\x9a\xc8b\x82\u05ad\xabL.\xb8\x91\x91`\xeb\x8ap;[\x89\u00e6\xe7@\x00\x00\u07d4R\x0ff\xa0\xe2e\u007f\xf0\xacA\x95\xf2\xf0d\xcf/\xa4\xb2BP\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4R\x10#T\xa6\xac\xa9]\x8a.\x86\xd5\u07bd\xa6\xdei4`v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\x13\xf4Y\xe0x\xad:\xb9Z\t #\x9f\xcf\x163\xdc\x04\u0289\x8c\xf2\x18|*\xfb\x18\x80\x00\u07d4R\x15\x18;\x8f\x80\xa9\xbc\x03\xd2l\xe9\x12\a\x83*\r9\xe6 \x8965\u026d\xc5\u07a0\x00\x00\xe0\x94R!Cx\xb5@\x04\x05j|\xc0\x8c\x89\x13'y\x8a\u01b2H\x8a\x037\xfe_\xea\xf2\u0440\x00\x00\xe0\x94R##\xaa\xd7\x1d\xbc\x96\xd8Z\xf9\x0f\bK\x99\xc3\xf0\x9d\ucdca\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4R>\x14\r\xc8\x11\xb1\x86\xde\xe5\xd6\u020b\xf6\x8e\x90\xb8\xe0\x96\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R?mdi\x0f\xda\u0354(SY\x1b\xb0\xff \xd3em\x95\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4RO\xb2\x10R,^#\xbbg\u07ff\x8c&\xaaam\xa4\x99U\x8965b\xa6m4#\x80\x00\u07d4RU\xdci\x15ZE\xb9p\xc6\x04\xd3\x00G\xe2\xf50i\x0e\u007f\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4R`\xdcQ\xee\a\xbd\u06ab\xab\xb9\xeetK9<\u007fG\x93\xa6\x89\x01\xd8f_\xa5\xfaL\x00\x00\u07d4Rg\xf4\xd4\x12\x92\xf3p\x86<\x90\u05d3)i\x03\x846%\u01c9K\xe4\xe7&{j\xe0\x00\x00\u07d4Rk\xb53\xb7n \xc8\xee\x1e\xbf\x12?\x1e\x9f\xf4\x14\x8e@\xbe\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4Rl\xb0\x9c\u3b63g.\xec\x1d\xebF [\xe8\x9aKV>\x89\x85\xcaa[\xf9\xc0\x10\x00\x00\u07d4Rs\x8c\x90\xd8`\xe0L\xb1/I\x8d\x96\xfd\xb5\xbf6\xfc4\x0e\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4Rz\x8c\xa1&\x863\xa6\xc99\xc5\xde\x1b\x92\x9a\ue4ae\xac\x8d\x890\xca\x02O\x98{\x90\x00\x00\u07d4R\x81\x01\xceF\xb7 \xa2!M\u036ef\x18\xa51w\xff\xa3w\x89\x1b\x96\x12\xb9\xdc\x01\xae\x00\x00\xe0\x94R\x81s4s\xe0\r\x87\xf1\x1e\x99U\u5275\x9fJ\u008ez\x8a\x8b\xd6/\xf4\xee\xc5Y \x00\x00\u07d4R\x98\xab\x18*\x195\x9f\xfc\xec\xaf\xd7\u0475\xfa!-\xed\xe6\u0749\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4R\x9a\xa0\x02\u0196*:\x85E\x02\u007f\u0630_\"\xb5\xbf\x95d\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4R\x9e\x82O\xa0rX+@2h:\xc7\xee\xcc\x1c\x04\xb4\xca\xc1\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94R\xa5\xe4\xdeC\x93\xee\xcc\xf0X\x1a\xc1\x1bR\u0183\xc7n\xa1]\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4R\xb4%|\xf4\x1bn(\x87\x8dP\xd5{\x99\x91O\xfa\x89\x87:\x89\xd5\r\u026a,Aw\x00\x00\u07d4R\xb8\xa9Y&4\xf70\v|\\Y\xa34[\x83_\x01\xb9\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\xbd\u066fYx\x85\v\xc2A\x10q\x8b7#u\x9bC~Y\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4R\xcd @;\xa7\xed\xa6\xbc0z=c\xb5\x91\x1b\x81|\x12c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794R\u04c0Q\x1d\xf1\x9d^\u0080{\xbc\xb6vX\x1bg\xfd7\xa3\x88\xb9\xf6]\x00\xf6<\x00\x00\xe0\x94R\xe1s\x13P\xf9\x83\xcc,A\x89\x84/\xde\x06\x13\xfa\xd5\f\xe1\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\u07d4R\xe4g\x832\x9av\x93\x01\xb1u\x00\x9d4gh\xf4\xc8~\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4R\xf0X\xd4aG\xe9\x00m)\xbf,\t0J\xd1\xcd\xddn\x15\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4R\xf1T#2<$\xf1\x9a\xe2\xabg7\x17\"\x9d?t}\x9b\x897\xa04\xcb\xe8\xe3\xf3\x80\x00\u07d4R\xf8\xb5\t\xfe\xe1\xa8t\xabo\x9d\x876\u007f\xbe\xaf\x15\xac\x13\u007f\x8965\u026d\xc5\u07a0\x00\x00\u07d4R\xfbF\xac]\x00\xc3Q\x8b,:\x1c\x17}D/\x81eU_\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4S\x00w\xc9\xf7\xb9\a\xff\x9c\xec\fw\xa4\x1ap\xe9\x02\x9a\xddJ\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\x03\x19\xdb\n\x8f\x93\xe5\xbb}M\xbfH\x161O\xbe\xd86\x1b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\x04}\u022c\x90\x83\xd9\x06r\xe8\xb3G<\x10\f\xcd'\x83#\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4S\va\xe4/9Bm$\b\xd4\bR\xb9\xe3J\xb5\xeb\xeb\u0149\x0e~\xeb\xa3A\vt\x00\x00\u07d4S\x0f\xfa\u00fc4\x12\xe2\xec\x0e\xa4{y\x81\xc7p\xf5\xbb/5\x89\a?u\u0460\x85\xba\x00\x00\u07d4S\x17\xec\xb0#\x05,\xa7\xf5e+\xe2\xfa\x85L\xfeEc\xdfM\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4S\x19M\x8a\xfa>\x885\x02v~\xdb\xc3\x05\x86\xaf3\xb1\x14\u04c9lk\x93[\x8b\xbd@\x00\x00\u07d4S*}\xa0\xa5\xadt\aF\x8d;\xe8\xe0~i\xc7\xddd\xe8a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4S-2\xb0\x0f0[\xcc$\xdc\xefV\x81}b/4\xfb,$\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4S4DX@\x82\xeb\xa6T\xe1\xad0\xe1Is\\o{\xa9\"\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4S8\xefp\xea\xc9\u075a\xf5\xa0P;^\xfa\xd1\x03\x9eg\xe7%\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94S9oJ&\u00b4`D\x960lTB\xe7\xfc\xba'.6\x8a\x04?/\b\xd4\x0eZ\xfc\x00\x00\xe0\x94S:s\xa4\xa2\"\x8e\xee\x05\xc4\xff\xd7\x18\xbb\xf3\xf9\xc1\xb1)\xa7\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4S<\x06\x92\x8f\x19\u0429V\xcc(\x86k\xf6\xc8\xd8\xf4\x19\x1a\x94\x89\x0f\xd8\xc1C8\xe60\x00\x00\u07d4S@e6\x1c\xb8T\xfa\xc4+\xfb\\\x9f\xcd\xe0`J\xc9\x19\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4SC\u007f\xec\xf3J\xb9\xd45\xf4\u07b8\xca\x18\x15\x19\xe2Y 5\x89\n1\x06+\xee\xedp\x00\x00\u07d4SR\x01\xa0\xa1\xd74\"\x80\x1fU\xde\xd4\u07ee\xe4\xfb\xaan;\x89\x02&!\x1fy\x15B\x80\x00\xe0\x94S`\x81\x05\xceK\x9e\x11\xf8k\xf4\x97\xff\xca;x\x96{_\x96\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4SnM\x80)\xb7?Uy\u0723>p\xb2N\xba\x89\xe1\x1d~\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Sp\rS%MC\x0f\"x\x1aJv\xa4c\x93;]k\b\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94S\u007f\x9dM1\xefp\x83\x9d\x84\xb0\xd9\u0377+\x9a\xfe\xdb\xdf5\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\xe0\x94S\x81D\x85\x03\xc0\xc7\x02T+\x1d\xe7\xcc_\xb5\xf6\xab\x1c\xf6\xa5\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94S\x94.yI\xd6x\x8b\xb7\x80\xa7\xe8\xa0y'\x81\xb1aK\x84\x8a\x03]\xebFhO\x10\xc8\x00\x00\u07d4S\x95\xa4E]\x95\xd1x\xb4S*\xa4r[\x19?\xfeQ)a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94S\x98\x9e\xd30V?\xd5}\xfe\u027d4<7`\xb0y\x93\x90\x8a\x01P\x89N\x84\x9b9\x00\x00\x00\u07d4S\xa2Dg(\x95H\x0fJ+\x1c\xdf}\xa5\xe5\xa2B\xecM\xbc\x8965\u026d\xc5\u07a0\x00\x00\u07d4S\xa7\x14\xf9\x9f\xa0\x0f\xefu\x8e#\xa2\xe7F2m\xad$|\xa7\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4S\xaf2\xc2/\uf640?\x17\x8c\xf9\v\x80/\xb5q\xc6\x1c\xb9\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4S\xc0\xbb\u007f\u020e\xa4\"\xd2\xef~T\x0e-\x8f(\xb1\xbb\x81\x83\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94S\xc5\xfe\x01\x19\xe1\xe8Hd\f\xee0\xad\ua594\x0f*]\x8b\x8a\x04\x9a\xda_\xa8\xc1\f\x88\x00\x00\u07d4S\xc9\xec\xa4\ts\xf6;\xb5\x92{\xe0\xbcj\x8a\x8b\xe1\x95\x1ft\x89lk\x93[\x8b\xbd@\x00\x00\u07d4S\u0388\xe6lZ\xf2\U0009bf4fY*V\xa3\xd1_ l2\x89\a\xa2\x8c1\xcc6\x04\x00\x00\u07d4S\xce\xc6\u0200\x92\xf7V\xef\xe5o}\xb1\x12(\xa2\xdbE\xb1\"\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4S\xe3[\x12#\x1f\x19\xc3\xfdwL\x88\xfe\xc8\xcb\xee\xdf\x14\b\xb2\x89\x1b\xc1mgN\xc8\x00\x00\x00\u07d4S\xe4\xd9im\xcb?M{?p\u072aN\xec\xb7\x17\x82\xff\\\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4S\xfa\xf1e\xbe\x03\x1e\xc1\x830\xd9\xfc\xe5\xbd\x12\x81\xa1\xaf\b\u06c9\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4T\n\x18\x19\xbd|5\x86\x1ey\x18\x04\xe5\xfb\xb3\xbc\x97\u026b\xb1\x89N\xd7\xda\xc6B0 \x00\x00\xe0\x94T\f\a(\x02\x01N\xf0\xd5a4Z\xecH\x1e\x8e\x11\xcb5p\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94T\f\xf2=\xd9\\MU\x8a'\x9dw\x8d+75\xb3\x16A\x91\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4T\x10`\xfcX\xc7P\xc4\x05\x12\xf83i\xc0\xa63@\xc1\"\xb6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4T\x13\xc9\u007f\xfaJn*{\xba\x89a\u071f\u03850\xa7\x87\u05c965\u026d\xc5\u07a0\x00\x00\u07d4T\x1d\xb2\n\x80\xcf;\x17\xf1b\x1f\x1b?\xf7\x9b\x88/P\xde\xf3\x8965\u026d\xc5\u07a0\x00\x00\u07d4T.\x80\x96\xba\xfb\x88\x16&\x06\x00.\x8c\x8a>\u0458\x14\xae\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T1\v:\xa8\x87\x03\xa7%\u07e5}\xe6\xe6F\x93Qd\x80,\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4T1\xb1\u0447Q\xb9\x8f\xc9\u220a\xc7u\x9f\x155\xa2\xdbG\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T1\xcaB~ae\xa6D\xba\xe3&\xbd\tu\n\x17\x8ce\r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T5\xc6\xc1y3\x17\xd3,\xe1;\xbaLO\xfe\xb9s\xb7\x8a\u0709\r\x8ek\x1c\x12\x85\xef\x00\x00\xe0\x94T6)\xc9\\\xde\xf4(\xad7\xd4S\u02958\xa9\xf9\t\x00\xac\x8a\t(\x96R\x9b\xad\u0708\x00\x00\u07d4T9\x1bM\x17mGl\xea\x16N_\xb55\u0197\x00\xcb%5\x89\x05l\xd5_\xc6M\xfe\x00\x00\xe0\x94T:\x8c\x0e\xfb\x8b\xcd\x15\xc5C\u29a4\xf8\aYv1\xad\xef\x8a\x01?\x80\xe7\xe1O-D\x00\x00\u07d4T?\x8cgN$b\xd8\xd5\u06a0\xe8\x01\x95\xa8p\x8e\x11\xa2\x9e\x89\x03wX\x83;:z\x00\x00\xe0\x94TK[5\x1d\x1b\xc8.\x92\x97C\x99H\xcfHa\xda\u026e\x11\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4TM\xdaB\x1d\xc1\xebs\xbb$\xe3\xe5j$\x80\x13\xb8|\x0fD\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4TW\\1\x14u\x1e\x14o\xfe\u00c7nE\xf2\x0e\xe8AJ\u07ba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4T\xb4B\x9b\x18/\x03w\xbe~bi9\xc5\xdbd@\xf7]z\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4T\xbc\xb8\xe7\xf7<\xda=s\xf4\u04cb-\bG\xe6\x00\xba\r\xf8\x89:pAX\x82\xdf\x18\x00\x00\u07d4T\xc9>\x03\xa9\xb2\xe8\xe4\xc3g(5\xa9\xeev\xf9a[\xc1N\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4T\u0388'YV\xde\xf5\xf9E\x8e;\x95\xde\xca\xcdH@!\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4T\xdb^\x06\xb4\x81]1\xcbV\xa8q\x9b\xa3:\xf2\xd7>rR\x89$R\x1e*0\x17\xb8\x00\x00\xe0\x94T\xe0\x12\x83\u030b8E8\xdddgp\xb3W\xc9`\xd6\xca\u034a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4T\xecs\x00\xb8\x1a\xc8C3\xed\x1b\x03<\xd5\u05e39r\xe24\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4T\xfe\xbc\xce \xfez\x90\x98\xa7U\xbd\x90\x98\x86\x02\xa4\x8c\b\x9e\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4U\n\xad\xae\x12!\xb0z\xfe\xa3\x9f\xba.\xd6.\x05\u5df5\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4U\f0o\x81\xef]\x95\x80\xc0l\xb1\xab \x1b\x95\xc7H\xa6\x91\x89$\x17\xd4\xc4p\xbf\x14\x00\x00\xe0\x94U\x19\x99\xdd\xd2\x05V3'\xb9\xb50xZ\xcf\xf9\xbcs\xa4\xba\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4U\x1ew\x84w\x8e\xf8\xe0H\xe4\x95\xdfI\xf2aO\x84\xa4\xf1\u0709 \x86\xac5\x10R`\x00\x00\xe0\x94U)\x83\na\xc1\xf1<\x19~U\v\xed\xdf\u05bd\x19\\\x9d\x02\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4U)\x87\xf0e\x1b\x91[.\x1eS(\xc1!\x96\rK\xddj\xf4\x89a\t=|,m8\x00\x00\u07d4U;k\x1cW\x05\x0e\x88\xcf\f1\x06{\x8dL\xd1\xff\x80\xcb\t\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4U?7\xd9$fU\x0e\x9f\xd7u\xaet6-\xf00\x17\x912\x89lk\x93[\x8b\xbd@\x00\x00\u07d4UC6\xeeN\xa1U\xf9\xf2O\x87\xbc\xa9\xcar\xe2S\xe1,\u0489\x05k\xc7^-c\x10\x00\x00\u0794UC\xddm\x16\x9e\xec\x8a!;\xbfz\x8a\xf9\xff\xd1]O\xf7Y\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4UG\xfd\xb4\xae\x11\x95>\x01)+x\a\xfa\x92#\xd0\xe4`j\x89\x05]\x11}\xcb\x1d&\x00\x00\u07d4UR\xf4\xb3\xed>\x1d\xa7\x9a/x\xbb\x13\xe8\xaeZh\xa9\xdf;\x8965\u026d\xc5\u07a0\x00\x00\u07d4U\\\xa9\xf0\\\xc14\xabT\xae\x9b\xea\x1c?\xf8z\xa8Q\x98\u0289\x05k\xc7^-c\x10\x00\x00\xe0\x94U]\x8d<\xe1y\x8a\u0290'T\xf1d\xb8\xbe*\x022\x9cl\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4U]\xf1\x93\x90\xc1m\x01)\x87r\xba\xe8\xbc:\x11R\x19\x9c\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4U^\xbe\x84\u06a4+\xa2V\xeax\x91\x05\xce\u0136\x93\xf1/\x18\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94U\u007f^e\xe0\xda3\x99\x82\x19\xadN\x99W\x05E\xb2\xa9\xd5\x11\x8a\x02U\x9c\xbb\x98XB@\x00\x00\u07d4U\x83` h\x83\xdd\x1bmJYc\x9eV)\xd0\xf0\xc6u\u0409lk\x93[\x8b\xbd@\x00\x00\u07d4U\x84B0P\xe3\xc2\x05\x1f\v\xbd\x8fD\xbdm\xbc'\xec\xb6,\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4U\x85)CI)p\xf8\xd6)\xa1Sf\xcd\xda\x06\xa9OE\x13\x89lk\x93[\x8b\xbd@\x00\x00\u0794U\x86d\x86\xec\x16\x8fy\xdb\xe0\u1af1\x88d\u0649\x91\xae,\x88\xdfn\xb0\xb2\xd3\xca\x00\x00\u07d4U\x8cTd\x9a\x8an\x94r+\xd6\xd2\x1d\x14qOqx\x054\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\x91\x940O\x14\xb1\xb9:\xfeDO\x06$\xe0S\xc2:\x00\t\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4U\x93\xc9\u0536ds\x0f\xd9<\xa6\x01Q\xc2\\.\xae\xd9<;\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4U\x97\x06\xc32\xd2\ay\xc4_\x8am\x04ji\x91Y\xb7I!\x89\x14\x9bD.\x85\xa3\u03c0\x00\u07d4U\x98\xb3\xa7\x9aH\xf3+\x1f_\xc9\x15\xb8{d]\x80]\x1a\xfe\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4U\xa3\xdfW\xb7\xaa\xec\x16\xa1b\xfdS\x16\xf3[\xec\b(!\u03c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4U\xa4\xca\xc0\u02cbX-\x9f\xef8\xc5\xc9\xff\xf9\xbdS\t=\x1f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4U\xa6\x1b\x10\x94\x80\xb5\xb2\xc4\xfc\xfd\xef\x92\xd9\x05\x84\x16\f\r5\x89\x02lVM+S\xf6\x00\x00\u07d4U\xaa]1>\xbb\bM\xa0\xe7\x80\x10\x91\u2792\xc5\xde\u00ea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\xab\x99\xb0\xe0\xe5]{\xb8t\xb7\xcf\xe84\xdec\x1c\x97\xec#\x897\xe9\x8c\xe3h\x99\xe4\x00\x00\u07d4U\xaf\t/\x94\xbajy\x91\x8b\f\xf99\xea\xb3\xf0\x1b?Q\u01c9\b \xd5\xe3\x95v\x12\x00\x00\u07d4U\xc5dfAf\xa1\xed\xf3\x91>\x01i\xf1\xcdE\x1f\xdb]\f\x89\x82\x17\xeaIP\x8el\x00\x00\xe0\x94U\xcaj\xbey\xea$\x97\xf4o\u06f804`\x10\xfeF\x9c\xbe\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4U\xca\xffK\xba\x04\xd2 \u0265\xd2\x01\x86r\xec\x85\xe3\x1e\xf8>\x89lk\x93[\x8b\xbd@\x00\x00\u07d4U\xd0W\xbc\xc0K\xd0\xf4\xaf\x96BQ:\xa5\t\v\xb3\xff\x93\xfe\x89;\xfeE,\x8e\xddL\x00\x00\u07d4U\xd4.\xb4\x95\xbfF\xa64\x99{_.\xa3b\x81I\x18\u2c09\x05\xc0\xd2e\xb5\xb2\xa8\x00\x00\u07d4U\u069d\xcd\xcaa\xcb\xfe\x1f\x13<{\xce\xfc\x86{\x9c\x81\"\xf9\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4U\xe2 \x87bb\xc2\x18\xafOVxG\x98\xc7\xe5]\xa0\x9e\x91\x89\a=\x99\xc1VE\xd3\x00\x00\u07d4U\xfd\b\u0440d\xbd ,\x0e\xc3\xd2\xcc\xe0\xce\v\x9d\x16\x9cM\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4V\x00s\nU\xf6\xb2\x0e\xbd$\x81\x1f\xaa=\xe9m\x16b\xab\xab\x89e\xea=\xb7UF`\x00\x00\u07d4V\x03$\x1e\xb8\xf0\x8fr\x1e4\x8c\x9d\x9a\xd9/H\u342a$\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4V\x056yJ\x9e+\x00I\xd1\x023\xc4\x1a\xdc_A\x8a&J\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\aY\x00Y\xa9\xfe\xc1\x88\x11I\xa4K6\x94\x9a\xef\x85\xd5`\x89lk\x93[\x8b\xbd@\x00\x00\u07d4V\v\xec\xdfR\xb7\x1f=\x88'\xd9'a\x0f\x1a\x98\x0f3qo\x89\x17GMp_V\u0400\x00\xe0\x94V\r\xa3~\x95m\x86/\x81\xa7_\u0540\xa7\x13\\\x1b$cR\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94V\x0f\xc0\x8d\a\x9f\x04~\xd8\xd7\xdfuU\x1a\xa55\x01\xf5p\x13\x8a\x01\x9b\xff/\xf5yh\xc0\x00\x00\u07d4V\x1b\xe9)\x9b>k>c\xb7\x9b\t\x16\x9d\x1a\x94\x8a\xe6\xdb\x01\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94V \xe3\xedy-/\x185\xfe_UA}Q\x11F\fj\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4V \xf4m\x14Q\xc25=bC\xa5\u0534'\x13\v\xe2\xd4\a\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94V!\x05\xe8+\t\x975\xdeI\xf6&\x92\u0307\xcd8\xa8\xed\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94V*\x8d\u02fe\xee\xf7\xb3`h]'0;\u059e\tJ\xcc\xf6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4V+\xce\u04ca\xb2\xabl\b\x0f;\x05A\xb8Enp\x82K?\x89\"\xca5\x87\xcfN\xb0\x00\x00\xe0\x94V+\xe9Z\xba\x17\xc57\x1f\u2e82\x87\x99\xb1\xf5]!w\u058a\b\x16\xd3~\x87\xb9\xd1\xe0\x00\x00\u07d4V/\x16\u05da\xbf\xce\u00d4>4\xb2\x0f\x05\xf9{\xdf\u0366\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4V7=\xaa\xb4c\x16\xfd~\x15v\xc6\x1ej\xff\xcbeY\xdd\u05c9\v\xacq]\x14l\x9e\x00\x00\u07d4V9v8\xbb<\xeb\xf1\xf6 byK^\xb9B\xf9\x16\x17\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4V:\x03\xab\x9cV\xb6\x00\xf6\xd2[f\f!\xe1c5Qzu\x8965\u026d\xc5\u07a0\x00\x00\u07d4V<\xb8\x80<\x1d2\xa2['\xb6A\x14\x85+\xd0M\x9c \u0349\v\x14\x9e\xad\n\xd9\xd8\x00\x00\u07d4VXc\x91\x04\fW\xee\xc6\xf5\xaf\xfd\x8c\u052b\xde\x10\xb5\n\u0309\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Vl\x10\xd68\u8e0bG\xd6\xe6\xa4\x14Iz\xfd\xd0\x06\x00\u0509\x05k9Bc\xa4\f\x00\x00\u07d4Vl(\xe3L8\b\xd9vo\xe8B\x1e\xbfO+\x1cO}w\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4V\x8d\xf3\x18Vi\x9b\xb5\xac\xfc\x1f\xe1\u0580\u07d9`\xcaCY\x89J\xcfUR\xf3\xb2I\x80\x00\u07d4V\x91\xdd/gE\xf2\x0e\"\xd2\xe1\u0479U\xaa)\x03\xd6VV\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4V\xa1\xd6\r@\xf5\u007f0\x8e\xeb\xf0\x87\xde\xe3\xb3\u007f\x1e|,\xba\x89>\u072e\xc8-\x06\xf8\x00\x00\u07d4V\xac \xd6;\xd8\x03Y\\\xec\x03m\xa7\xed\x1d\xc6n\n\x9e\a\x89\x03w*S\xcc\xdce\x80\x00\u07d4V\xb6\xc2=\xd2\uc434r\x8f;\xb2\xe7d\xc3\xc5\f\x85\xf1D\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\xdf\x05\xba\xd4l?\x00\xaeGn\xcf\x01{\xb8\xc8w8?\xf1\x89\n\xb1]\xaa\xefp@\x00\x00\u07d4V\xee\x19\u007fK\xbf\x9f\x1b\x06b\xe4\x1c+\xbd\x9a\xa1\xf7\x99\xe8F\x8965\u026d\xc5\u07a0\x00\x00\u07d4V\xf4\x93\xa3\xd1\b\xaa\xa2\u044d\x98\x92/\x8e\xfe\x16b\u03f7=\x89m\x81!\xa1\x94\xd1\x10\x00\x00\u07d4V\xfc\x1a{\xad@G#|\xe1\x16\x14b\x96#\x8e\a\x8f\x93\xad\x89\t\xa6?\b\xeac\x88\x00\x00\u07d4V\xfe\xbf\x9e\x10\x03\xaf\x15\xb1\xbdI\a\xec\b\x9aJ\x1b\x91\xd2h\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4W\x17\u0313\x01Q\x1dJ\x81\xb9\xf5\x83\x14\x8b\xee\xd3\xd3\u0303\t\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4W\x17\xf2\xd8\xf1\x8f\xfc\xc0\xe5\xfe$}:B\x19\x03|:d\x9c\x89\u063beI\xb0+\xb8\x00\x00\u07d4W\x19P\xea,\x90\xc1B}\x93\x9da\xb4\xf2\xdeL\xf1\u03ff\xb0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4W\x19\xf4\x9br\r\xa6\x88V\xf4\xb9\xe7\b\xf2VE\xbd\xbcKA\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4W*\xc1\xab\xa0\xde#\xaeA\xa7\xca\xe1\xdc\bB\u062b\xfc\x10;\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94W-\xd8\xcd?\xe3\x99\xd1\xd0\xec(\x121\xb7\xce\xfc \xb9\u4eca\x023\xc8\xfeBp>\x80\x00\x00\xe0\x94WI!\x83\x8c\xc7}l\x98\xb1}\x90::\xe0\xee\r\xa9[\u040a\vS(\x17\x8a\xd0\xf2\xa0\x00\x00\u07d4WJ\xd95S\x90\u421e\xf4*\xcd\x13\x8b*'\xe7\x8c\x00\xae\x89Tg\xb72\xa9\x134\x00\x00\u07d4WM\xe1\xb3\xf3\x8d\x91XF\xae7\x18VJZ\xda \xc2\xf3\xed\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94W\\\x00\u0081\x82\x10\u0085U\xa0\xff)\x01\x02\x89\xd3\xf8#\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94Ws\xb6\x02g!\xa1\xdd\x04\xb7\x82\x8c\xd6+Y\x1b\xfb4SL\x8a\x05\xb7\xacES\xdez\xe0\x00\x00\xe0\x94WwD\x1c\x83\xe0?\v\xe8\xdd4\v\xdechP\x84|b\v\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4Wx\xff\u071b\x94\u0165\x9e\"N\xb9e\xb6\u0790\xf2\"\xd1p\x89\x12-\u007f\xf3f\x03\xfc\x00\x00\u07d4Wz\xee\xe8\u053c\b\xfc\x97\xab\x15n\xd5\u007f\xb9p\x92Sf\xbe\x89\x12\r\xf1\x14rX\xbf\x00\x00\u07d4W{-\a\xe9\xcfRJ\x18\u04c9\x15Vak\x96\x06g\x00\x00\u07d4W\xd5\xfd\x0e=0I3\x0f\xfc\xdc\xd0 Ei\x17e{\xa2\u0689k\xf2\x01\x95\xf5T\xd4\x00\x00\u07d4W\u0754q\xcb\xfa&'\t\xf5\U00106f37t\xc5\xf5'\xb8\xf8\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4W\xdf#\xbe\xbd\xc6^\xb7_\ub732\xfa\xd1\xc0si++\xaf\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4X\x00\u03410\x83\x9e\x94I]-\x84\x15\xa8\xea,\x90\xe0\xc5\u02c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94X\x03\xe6\x8b4\xda\x12\x1a\xef\b\xb6\x02\xba\u06ef\xb4\xd1$\x81\u028a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\xe0\x94X\x16\xc2hww\xb6\xd7\u04a2C-Y\xa4\x1f\xa0Y\xe3\xa4\x06\x8a\x1cO\xe4:\xdb\n^\x90\x00\x00\u07d4X\x1a:\xf2\x97\xef\xa4Cj)\xaf\x00r\x92\x9a\xbf\x98&\xf5\x8b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\x1b\x9f\xd6\xea\xe3r\xf3P\x1fB\xeb\x96\x19\xee\xc8 \xb7\x8a\x84\x8a\x04+\xe2\xc0\f\xa5;\x8d\x80\x00\u07d4X\x1b\xdf\x1b\xb2v\xdb\u0746\xae\xdc\xdb9z\x01\xef\xc0\xe0\f[\x8965\u026d\xc5\u07a0\x00\x00\u07d4X\x1f4\xb5#\xe5\xb4\x1c\t\xc8|)\x8e)\x9c\xbc\x0e)\xd0f\x89=X3\xaa\xfd9u\x80\x00\xe0\x94X$\xa7\xe2(8'q40\x8c_KP\u06b6^C\xbb1\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4X+pf\x9c\x97\xaa\xb7\u0581H\xd8\xd4\xe9\x04\x11\xe2\x81\rV\x8965f3\xeb\xd8\xea\x00\x00\u07d4X.|\xc4o\x1d{Nn\x9d\x95\x86\x8b\xfd7\x05s\x17\x8fL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4X>\x83\xbaU\xe6~\x13\xe0\xe7o\x83\x92\xd8s\xcd!\xfb\xf7\x98\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Xi\xfb\x86}q\xf18\u007f\x86;i\x8d\t\xfd\xfb\x87\u011b\\\x89\u01bb\xf8X\xb3\x16\b\x00\x00\u07d4X}hI\xb1h\xf6\xc33+z\xba\xe7\xeblB\xc3\u007fH\xbf\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4X\x87\xdcj3\xdf\xedZ\xc1\xed\xef\xe3^\xf9\x1a!b1\xac\x96\x89\r\x8drkqw\xa8\x00\x00\xe0\x94X\x8e\u0650\xa2\xaf\xf4J\x94\x10]X\xc3\x05%w5\xc8h\xac\x8a\x03h\xc8b:\x8bM\x10\x00\x00\u07d4X\xae-\xdc_L\x8a\u0697\xe0l\x00\x86\x17\x17g\xc4#\xf5\u05c9WG=\x05\u06ba\xe8\x00\x00\u07d4X\xae\xd6gJ\xff\xd9\xf6B3'*W\x8d\xd98k\x99\xc2c\x89\xb8Pz\x82\a( \x00\x00\xe0\x94X\xb8\b\xa6[Q\xe63\x89i\xaf\xb9^\xc7\a5\xe4Q\xd5&\x8a\bxK\xc1\xb9\x83z8\x00\x00\u07d4X\xb8\xae\x8fc\xef5\xed\ab\xf0\xb6#=J\xc1Nd\xb6M\x89lk\x93[\x8b\xbd@\x00\x00\u07d4X\xba\x15ie\x0e[\xbb\xb2\x1d5\xd3\xe1u\xc0\u05b0\xc6Q\xa9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4X\xc5U\xbc)<\xdb\x16\xc66.\xd9z\xe9U\v\x92\xea\x18\x0e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4X\xc6P\xce\xd4\v\xb6VA\xb8\xe8\xa9$\xa09\xde\xf4hT\u07c9\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4X\xc9\aT\xd2\xf2\n\x1c\xb1\xdd3\x06%\xe0KE\xfaa\x9d\\\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\xe2\xf1\x12#\xfc\x827\xf6\x9d\x99\xc6(\x9c\x14\x8c\x06\x04\xf7B\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4X\xe5T\xaf=\x87b\x96 \xdaa\xd58\xc7\xf5\xb4\xb5LJ\xfe\x89FP\x9diE4r\x80\x00\u07d4X\xe5\xc9\xe3D\xc8\x06e\r\xac\xfc\x90M3\xed\xbaQ\a\xb0\u0789\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4X\xe6a\u043as\xd6\xcf$\t\x9aUb\xb8\b\xf7\xb3g;h\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94X\xf0[&%`P<\xa7a\xc6\x18\x90\xa4\x03_Lsr\x80\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4X\xfb\x94sd\xe7iWe6\x1e\xbb\x1e\x80\x1f\xfb\x8b\x95\xe6\u0409\n\u05ce\xbcZ\xc6 \x00\x00\u07d4Y\x01\x81\xd4E\x00{\u0407Z\xaf\x06\x1c\x8dQ\x159\x00\x83j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Y\x02\xe4J\xf7i\xa8rF\xa2\x1e\a\x9c\b\xbf6\xb0n\xfe\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4Y\n\xcb\xda7)\f\r>\xc8O\xc2\x00\rv\x97\xf9\xa4\xb1]\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94Y\f\xcbY\x11\xcfx\xf6\xf6\"\xf55\xc4t7_J\x12\xcf\u03ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y\x10\x10m\xeb\u0491\xa1\u0340\xb0\xfb\xbb\x8d\x8d\x9e\x93\xa7\xcc\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Y\x16\x17I\xfe\xdc\xf1\xc7!\xf2 -\x13\xad\xe2\xab\xcfF\v=\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94Y\x1b\xef1q\xd1\u0155w\x17\xa4\xe9\x8d\x17\xeb\x14,!NV\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y <\xc3u\x99\xb6H1*|\xc9\xe0m\xac\xb5\x89\xa9\xaej\x89\b\x0fyq\xb6@\x0e\x80\x00\u07d4Y&\x81q\xb83\xe0\xaa\x13\xc5KR\xcc\xc0B.O\xa0:\ub262\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94Y'w&\x1e;\xd8R\u010e\u0295\xb3\xa4L[\u007f-B,\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4Y0Dg\x0f\xae\xff\x00\xa5[Z\xe0Q\xeb{\xe8p\xb1\x16\x94\x89\a?u\u0460\x85\xba\x00\x00\xe0\x94Y;E\xa1\x86J\xc5\xc7\xe8\xf0\u02ae\xba\r\x87<\xd5\xd1\x13\xb2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Y_^\xdajV\xf1N%\xe0\xc6\xf3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4Z\x1a3ib\xd6\xe0\xc601\u0303\u01a5\u01a6\xf4G\x8e\u02c965\u026d\xc5\u07a0\x00\x00\u07d4Z\x1d--\x1dR\x03\x04\xb6 \x88IW\x047\xeb0\x91\xbb\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4Z&s1\xfa\xcb&-\xaa\xec\xd9\xddc\xa9p\f_RY\u07c9\x05k\xc7^-c\x10\x00\x00\xe0\x94Z(WU9\x1e\x91NX\x02_\xaaH\xcch_O\xd4\xf5\xb8\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4Z)\x16\xb8\xd2\xe8\xcc\x12\xe2\a\xabFMC>#p\xd8#\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4Z+\x1c\x85:\xeb(\xc4U9\xafv\xa0\n\xc2\u0628$(\x96\x89\x01Z\xf1\u05cbX\xc4\x00\x00\u07d4Z-\xaa\xb2\\1\xa6\x1a\x92\xa4\xc8,\x99%\xa1\xd2\xefXX^\x89\f8\r\xa9\u01d5\f\x00\x00\u07d4Z0\xfe\xac7\xac\x9fr\u05f4\xaf\x0f+\xc79R\xc7O\xd5\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4ZTh\xfa\\\xa2&\xc7S.\xcf\x06\xe1\xbc\x1cE\"]~\u0249g\x8a\x93 b\xe4\x18\x00\x00\u07d4ZVR\x857JI\xee\xddPL\x95}Q\bt\xd0\x04U\xbc\x89\x05k\xc7^-c\x10\x00\x00\u07d4Z^\xe8\xe9\xbb\x0e\x8a\xb2\xfe\xcbK3\u0494x\xbeP\xbb\xd4K\x89*\x11)\u0413g \x00\x00\xe0\x94Z_\x85\b\xda\x0e\xbe\xbb\x90\xbe\x903\xbdM\x9e'A\x05\xae\x00\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4Z`q\xbc\xeb\xfc\xbaJ\xb5\u007fM\xb9o\u01e6\x8b\xec\xe2\xba[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z`\xc9$\x16(s\xfc~\xa4\xda\u007f\x97.5\x01g7`1\x89\x04\x87\xf2w\xa8\x85y\x80\x00\u07d4Zf\x86\xb0\xf1~\a\xed\xfcY\xb7Y\xc7}[\xef\x16M8y\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4Zp\x10o \xd6?\x87Re\xe4\x8e\r5\xf0\x0e\x17\xd0+\u0249\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794Zt\xbab\xe7\xc8\x1a4t\xe2}\x89O\xed3\xdd$\xad\x95\xfe\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94Zw5\x00}p\xb0hD\u0699\x01\xcd\xfa\xdb\x11\xa2X,/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4Z\x82\xf9l\u0537\xe2\xd9=\x10\xf3\x18]\xc8\xf4=Ku\xaai\x89lc?\xba\xb9\x8c\x04\x00\x00\u07d4Z\x87\xf04\xe6\xf6\x8fNt\xff\xe6\fd\x81\x946\x03l\xf7\u05c9\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94Z\x89\x11U\xf5\x0eB\aCt\xc79\xba\xad\xf7\xdf&Q\x15:\x8a\x01\x02\xdao\xd0\xf7:<\x00\x00\u07d4Z\x9c\x8bi\xfcaMiVI\x99\xb0\r\xcbB\xdbg\xf9~\x90\x89\xb9\xe6\x15\xab\xad:w\x80\x00\xe0\x94Z\xaf\x1c1%Jn\x00_\xba\u007fZ\xb0\xecy\xd7\xfc+c\x0e\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4Z\xb1\xa5aSH\x00\x1c|w]\xc7WHf\x9b\x8b\xe4\xde\x14\x89%jr\xfb)\xe6\x9c\x00\x00\xe1\x94Z\xbf\xec%\xf7L\u06047c\x1aw1\x90i2wcV\xf9\x8b\t\xd8<\xc0\u07e1\x11w\xff\x80\x00\u07d4Z\u0090\x8b\x0f9\x8c\r\xf5\xba\xc2\xcb\x13\xcas\x14\xfb\xa8\xfa=\x89\n\xd4\xc81j\v\f\x00\x00\xe0\x94Z\u025a\u05c1j\xe9\x02\x0f\xf8\xad\xf7\x9f\xa9\x86\x9b|\xeaf\x01\x8a\x04ri\x8bA;C \x00\x00\u07d4Z\xd1,^\xd4\xfa\x82~!P\u03e0\u058c\n\xa3{\x17i\xb8\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94Z\xd5\xe4 uV\x13\x88o5\xaaV\xac@>\xeb\xdf\xe4\xb0\u040a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4Z\xdew\xfd\x81\xc2\\\n\xf7\x13\xb1\a\x02v\x8c\x1e\xb2\xf9u\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4Z\xe6N\x85;\xa0\xa5\x12\x82\u02cd\xb5.Aa^|\x9fs?\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z\xed\x0el\xfe\x95\xf9\u0580\xc7dr\xa8\x1a+h\n\u007f\x93\xe2\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4Z\xef\x16\xa2&\xddh\a\x1f$\x83\xe1\xdaBY\x83\x19\xf6\x9b,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4Z\xf4j%\xac\t\xcbsakS\xb1O\xb4/\xf0\xa5\x1c\u0772\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4Z\xf7\xc0r\xb2\u016c\xd7\x1cv\xad\xdc\xceS\\\xf7\xf8\xf95\x85\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94Z\xfd\xa9@\\\x8e\x976QEt\u0692\x8d\xe6tV\x01\t\x18\x8a\x01E\xb8\xb0#\x9aF\x92\x00\x00\u07d4[\x06\xd1\xe6\x93\f\x10Ti+y\xe3\xdb\xe6\xec\xceS\x96d \x89\v\"\u007fc\xbe\x81<\x00\x00\u07d4[%\xca\xe8m\xca\xfa*`\xe7r61\xfc_\xa4\x9c\x1a\xd8}\x89\x87\fXQ\x0e\x85 \x00\x00\u07d4[(|~sB\x99\xe7'bo\x93\xfb\x11\x87\xa6\rPW\xfe\x89\x05|\xd94\xa9\x14\xcb\x00\x00\u07d4[)\f\x01\x96|\x81.M\xc4\xc9\v\x17L\x1b@\x15\xba\xe7\x1e\x89\b \xeb4\x8dR\xb9\x00\x00\u07d4[+d\xe9\xc0X\u30a8\xb2\x99\"N\xec\xaa\x16\xe0\x9c\x8d\x92\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\xe0\x94[./\x16\x18U.\xab\r\xb9\x8a\xddUc|)Q\xf1\xfb\x19\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4[0`\x8cg\x8e\x1a\xc4d\xa8\x99L;3\xe5\xcd\xf3Iq\x12\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4[36\x96\xe0L\xca\x16\x92\xe7\x19\x86W\x9c\x92\rk)\x16\xf9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94[C\rw\x96\x96\xa3e?\xc6\x0et\xfb\u02ec\xf6\xb9\u00ba\xf1\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4[Cse\xae:\x9a/\xf9|h\xe6\xf9\nv \x18\x8c}\x19\x89l\x87T\xc8\xf3\f\b\x00\x00\u07d4[I\xaf\xcduDx8\xf6\xe7\xce\u068d!w}O\xc1\xc3\xc0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4[L\f`\xf1\x0e\u0489K\xdbB\xd9\xdd\x1d!\x05\x87\x81\n\r\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4[N\xa1m\xb6\x80\x9b\x03R\u0536\xe8\x1c9\x13\xf7jQ\xbb2\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4[[\xe0\xd8\xc6rv\xba\xab\xd8\xed\xb3\rH\xeaud\v\x8b)\x89,\xb1\xf5_\xb7\xbe\x10\x00\x00\u07d4[]Qp)2\x15b\x11\x1bC\bm\v\x045\x91\x10\x9ap\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\xe0\x94[]\x8c\x8e\xedl\x85\xac!Va\xde\x02fv\x82?\xaa\n\f\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4[mU\xf6q)g@\\e\x91)\xf4\xb1\xde\t\xac\xf2\xcb{\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4[p\u011c\u024b=\xf3\xfb\xe2\xb1Y\u007f\\\x1bcG\xa3\x88\xb7\x894\x95tD\xb8@\xe8\x00\x00\u07d4[sn\xb1\x83Sb\x9b\u0796v\xda\xdd\x16P4\xce^\xcch\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4[u\x9f\xa1\x10\xa3\x1c\x88F\x9fT\xd4K\xa3\x03\xd5}\xd3\xe1\x0f\x89[F\xdd/\x0e\xa3\xb8\x00\x00\u07d4[w\x84\xca\xea\x01y\x9c\xa3\x02'\x82vg\xce |\\\xbcv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4[x\xec\xa2\u007f\xbd\xeao&\xbe\xfb\xa8\x97+)^x\x146K\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94[\x80\v\xfd\x1b>\u0525}\x87Z\xed&\xd4/\x1aw\b\xd7*\x8a\x01Z\x82\xd1\u057b\x88\xe0\x00\x00\u07d4[\x85\xe6\x0e*\xf0TO/\x01\xc6N 2\x90\x0e\xbd8\xa3\u01c9lk\x93[\x8b\xbd@\x00\x00\u07d4[\xa2\xc6\xc3]\xfa\xec)h&Y\x19\x04\xd5DFJ\xea\xbd^\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94[\xafmt\x96 \x80>\x83H\xaf7\x10\xe5\xc4\xfb\xf2\x0f\u0214\x8a\x01\x0f@\x02a]\xfe\x90\x00\x00\u07d4[\xc1\xf9U\a\xb1\x01\x86B\xe4\\\xd9\xc0\xe2'3\xb9\xb1\xa3&\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94[\xd25GG\u007fm\t\u05f2\xa0\x05\xc5\xeee\fQ\fV\u05ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4[\xd2J\xac6\x12\xb2\f`\x9e\xb4gy\xbf\x95i\x84\a\xc5|\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4[\u0586-Q}M\xe4U\x9dN\xec\n\x06\xca\xd0^/\x94n\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4[\xe0EQ*\x02n?\x1c\xeb\xfdZ~\xc0\xcf\xc3o-\xc1k\x89\x06\x81U\xa46v\xe0\x00\x00\xe0\x94[\xf9\xf2\"nZ\xea\xcf\x1d\x80\xae\nY\xc6\xe3\x808\xbc\x8d\xb5\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4[\xfa\xfe\x97\xb1\xdd\x1dq+\xe8mA\xdfy\x89SE\x87Z\x87\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\\\x0f.Q7\x8fk\r{\xabas1X\vn9\xad<\xa5\x8a\x02\bj\xc3Q\x05&\x00\x00\x00\u07d4\\)\xf9\xe9\xa5#\xc1\xf8f\x94H\xb5\\H\xcb\xd4|%\xe6\x10\x894F\xa0\xda\xd0L\xb0\x00\x00\xe0\x94\\0\x8b\xacHW\xd3;\xae\xa0t\xf3\x95m6!\xd9\xfa(\xe1\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\\1*V\u01c4\xb1\"\t\x9bvM\x05\x9c!\xec\xe9^\x84\u0289\x05&c\u032b\x1e\x1c\x00\x00\u07d4\\1\x99m\xca\xc0\x15\xf9\xbe\x98[a\x1fF\x870\xef$M\x90\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\\24W\xe1\x87v\x1a\x82v\xe3Y\xb7\xb7\xaf?;n=\xf6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\\<\x1cd[\x91uC\x11;>l\x1c\x05M\xa1\xfet+\x9a\x89+^:\xf1k\x18\x80\x00\x00\u0794\\=\x19D\x1d\x19l\xb4Cf \xfc\xad\u007f\xbby\xb2\x9ex\x88\xc6s\xce<@\x16\x00\x00\u07d4\\?V\u007f\xaf\xf7\xba\u0475\x12\x00\"\xe8\xcb\u02a8+I\x17\xb3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\\Ch\x91\x8a\xced\t\u01de\u0280\u036a\xe49\x1d+bN\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\\FA\x97y\x1c\x8a=\xa3\xc9%Co'z\xb1;\xf2\xfa\xa2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\\H\x81\x16\\\xb4+\xb8.\x979l\x8e\xf4J\xdb\xf1s\xfb\x99\x89\x05\xfe\xe2\"\x04\x1e4\x00\x00\xe0\x94\\H\x92\x90z\a \xdfo\xd3A>c\xffv}k9\x80#\x8a\x02\xcb\x00\x9f\u04f5y\x0f\x80\x00\u07d4\\O$\xe9\x94\ud3c5\x0e\xa7\x81\x8fG\x1c\x8f\xac;\xcf\x04R\x89]\x80h\x8d\x9e1\xc0\x00\x00\u07d4\\T\x19V\\:\xadNqN\a92\x8e5!\u024f\x05\u0309\x1c\x9fx\u0489>@\x00\x00\u07d4\\a6\xe2\x18\xde\na\xa17\xb2\xb3\x96-*a\x12\xb8\t\u05c9\x0f\xf3\u06f6_\xf4\x86\x80\x00\xe0\x94\\a\xaby\xb4\b\xdd2)\xf6bY7\x05\xd7/\x1e\x14{\xb8\x8a\x04\xd0$=4\x98\u0344\x00\x00\u07d4\\m\x04\x1d\xa7\xafD\x87\xb9\xdcH\xe8\xe1\xf6\af\u0425m\xbc\x89O\a\n\x00>\x9ct\x00\x00\u07d4\\o6\xaf\x90\xab\x1aeln\xc8\xc7\xd5!Q'b\xbb\xa3\xe1\x89lh\xcc\u041b\x02,\x00\x00\u07d4\\{\x9e\u01e2C\x8d\x1eD*\x86\x0f\x8a\x02\x1e\x18\x99\xf07z\xea\x00\x00\u07d4\\\xcc\xf1P\x8b\xfd5\xc2\x050\xaad%\x00\xc1\r\xeee\xea\xed\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\\\xcer\xd0h\xc7\xc3\xf5[\x1d(\x19T^w1|\xae\x82@\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\\\xd0\xe4u\xb5D!\xbd\xfc\f\x12\xea\x8e\b+\u05e5\xaf\nj\x89\x032\xca\x1bg\x94\f\x00\x00\u07d4\\\u0548\xa1N\xc6H\xcc\xf6G)\xf9\x16z\xa7\xbf\x8b\xe6\xeb=\x8965\u026d\xc5\u07a0\x00\x00\u07d4\\\u062f`\xdee\xf2M\xc3\xceW0\xba\x92e0\"\xdcYc\x89a\t=|,m8\x00\x00\u07d4\\\xdcG\b\xf1O@\xdc\xc1Zy_}\xc8\xcb\v\u007f\xaa\x9en\x89\x1d\x1c_>\xda \xc4\x00\x00\u07d4\\\u0d86,\u0391b\xe8~\bI\xe3\x87\xcb]\xf4\xf9\x11\x8c\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\\\xe2\xe7\u03aa\xa1\x8a\xf0\xf8\xaa\xfa\u007f\xba\xd7L\u021e<\xd46\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\\\xe4@h\xb8\xf4\xa3\xfey\x9ej\x83\x11\xdb\xfd\xed\xa2\x9d\xee\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u0794\\\xeb\xe3\v*\x95\xf4\xae\xfd\xa6ee\x1d\xc0\xcf~\xf5u\x81\x99\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\\\xf1\x8f\xa7\u0227\xc0\xa2\xb3\xd5\xef\u0459\x0fd\xdd\xc5i$,\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\\\xf4N\x10T\reqd#\xb1\xbc\xb5B\xd2\x1f\xf8:\x94\u034a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\\\xf8\xc0>\xb3\xe8r\xe5\x0f|\xfd\f/\x8d;?,\xb5\x18:\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\\\xfa\x8dV\x85ue\x8c\xa4\xc1\xa5\x93\xacL]\x0eD\xc6\aE\x89\x0f\xc6o\xae7F\xac\x00\x00\u07d4\\\xfa\x98w\xf7\x19\u01dd\x9eIJ\b\xd1\xe4\x1c\xf1\x03\xfc\x87\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4]\x1d\xc38{G\xb8E\x1eU\x10l\f\xc6}m\xc7+\u007f\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4]#\x1ap\xc1\xdf\xeb6\n\xbd\x97\xf6\x16\xe2\xd1\r9\xf3\u02b5\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4]$\xbd\xbc\x1cG\xf0\xeb\x83\xd1(\xca\xe4\x8a\xc3\xf4\xb5\x02bt\a\xda'/g\x81Jk\xec\u0509\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4]\x83\xb2\x1b\xd2q#`Ckg\xa5\x97\xee3x\xdb>z\xe4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94]\x87+\x12.\x99N\xf2|q\xd7\u07b4W\xbfeB\x9e\xcal\x8a\x01\xb1\xad\xed\x81\u04d4\x10\x80\x00\xe0\x94]\x8d1\xfa\xa8d\xe2!Y\xcdoQu\xcc\xec\xc5?\xa5Mr\x8a\x05\xb6\x96\xb7\r\xd5g\x10\x00\x00\xe0\x94]\x95\x8a\x9b\u0449\u0098_\x86\u014a\x8ci\xa7\xa7\x88\x06\xe8\u068a\x02(\xf1o\x86\x15x`\x00\x00\u07d4]\xa2\xa9\xa4\xc2\xc0\xa4\xa9$\xcb\xe0\xa5:\xb9\xd0\xc6'\xa1\u03e0\x89'\xbf8\xc6TM\xf5\x00\x00\u07d4]\xa4\u0288\x93\\'\xf5\\1\x10H\x84\x0eX\x9e\x04\xa8\xa0I\x89\x04V9\x18$O@\x00\x00\u07d4]\xa5G\x85\u027d0W\\\x89\u07b5\x9d A\xd2\n9\xe1{\x89j\xa2\t\xf0\xb9\x1de\x80\x00\xe0\x94]\xb6\x9f\xe9>o\xb6\xfb\xd4P\x96k\x97#\x8b\x11\n\xd8'\x9a\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4]\xb7\xbb\xa1\xf9W?$\x11]\x8c\x8cb\xe9\u0388\x95\x06\x8e\x9f\x89\x02\xb5\xaa\xd7,e \x00\x00\xe0\x94]\xb8D\x00W\x00i\xa9W<\xab\x04\xb4\u6d955\xe2\x02\xb8\x8a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4]\xc3m\xe55\x94P\xa1\xec\t\xcb\fD\xcf+\xb4+:\xe45\x89<\x94m\x89;3\x06\x00\x00\u07d4]\xc6\xf4_\xef&\xb0n3\x021?\x88M\xafH\xe2to\xb9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94]\u0376\xb8zP\xa9\xde\x02C\x80\x00\x00\u07d4^Q\xb8\xa3\xbb\t\xd3\x03\xea|\x86\x05\x15\x82\xfd`\x0f\xb3\xdc\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794^X\xe2U\xfc\x19\x87\n\x040_\xf2\xa0F1\xf2\xff)K\xb1\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4^ZD\x19t\xa8=t\u0187\xeb\xdcc?\xb1\xa4\x9e{\x1a\u05c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^eE\x8b\xe9d\xaeD\x9fqw7\x04\x97\x97f\xf8\x89\x87a\x89\x1c\xa7\xccs[o|\x00\x00\u07d4^g\u07c9i\x10\x1a\u06bd\x91\xac\xcdk\xb1\x99\x12t\xaf\x8d\xf2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4^n\x97G\xe1b\xf8\xb4\\en\x0fl\xaez\x84\xba\xc8\x0eN\x89lk\x93[\x8b\xbd@\x00\x00\u07d4^s\x1bU\xce\xd4R\xbb??\xe8q\xdd\xc3\xed~\xe6Q\n\x8f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^t\xed\x80\xe9eW\x88\xe1\xbb&\x97R1\x96g\xfeuNZ\x89\x03\t'\xf7L\x9d\xe0\x00\x00\u07d4^w.'\xf2\x88\x00\xc5\r\u0697;\xb3>\x10v.n\xea \x89a\t=|,m8\x00\x00\u07d4^{\x8cT\xdcW\xb0@ bq\x9d\xee~\xf5\xe3~\xa3]b\x89\x9b\xf9\x81\x0f\xd0\\\x84\x00\x00\u07d4^\u007fp7\x87uX\x9f\xc6j\x81\xd3\xf6S\xe9T\xf5U`\ub243\xf2\x89\x18\x1d\x84\xc8\x00\x00\xe0\x94^\x80n\x84W0\xf8\a>l\xc9\x01\x8e\xe9\x0f\\\x05\xf9\t\xa3\x8a\x02\x01\xe9m\xac\u03af \x00\x00\u07d4^\x8eM\xf1\x8c\xf0\xafw\tx\xa8\u07cd\xac\x90\x93\x15\x10\xa6y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4^\x90\xc8Xw\x19\x87V\xb06l\x0e\x17\xb2\x8eR\xb4FPZ\x89\x14JJ\x18\xef\xebh\x00\x00\u07d4^\x95\xfe_\xfc\xf9\x98\xf9\xf9\xac\x0e\x9a\x81\u06b8>\xadw\x00=\x89\x1dB\xc2\r2y\u007f\x00\x00\u07d4^\xad)\x03z\x12\x89dx\xb1)j\xb7\x14\xe9\u02d5B\x8c\x81\x89\x03\xe0C\a-@n\x00\x00\u07d4^\xb3q\xc4\a@lB{;}\xe2q\xad<\x1e\x04&\x95y\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4^\u037a\xea\xb9\x10o\xfe]{Q\x96\x96`\x9a\x05\xba\ub16d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4^\xd0\xd63\x85Y\xefD\xdcza\xed\xeb\x89?\xa5\xd8?\xa1\xb5\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\xe0\x94^\u04fb\xc0R@\xe0\u04d9\xebm\xdf\xe6\x0fb\xdeM\x95\t\xaf\x8a)\x14\xc0$u\xf9\xd6\xd3\x00\x00\u0594^\xd3\xf1\xeb\xe2\xaegV\xb5\xd8\xdc\x19\xca\xd0,A\x9a\xa5w\x8b\x80\u07d4^\xd5a\x15\xbde\x05\xa8\x82s\xdf\\V\x83\x94p\xd2J-\xb7\x89\x03\x8ee\x91\xeeVf\x80\x00\xe0\x94^\xf8\xc9a\x86\xb3y\x84\xcb\xfe\x04\u0158@n;\n\xc3\x17\x1f\x8a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4^\xfb\xdf\xe58\x99\x99c<&`Z[\xfc,\x1b\xb5\x95\x93\x93\x89\x03\xc0W\xc9\\\xd9\b\x00\x00\xe0\x94_\x13\x15F1Fm\xcb\x13S\u0210\x93*|\x97\xe0\x87\x8e\x90\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4_\x16z\xa2B\xbcL\x18\x9a\xde\xcb:\u0127\xc4R\xcf\x19/\u03c9lkLM\xa6\u077e\x00\x00\xe0\x94_\x1c\x8a\x04\xc9\rs[\x8a\x15)\t\xae\xaeco\xb0\xce\x16e\x8a\x01{x'a\x8cZ7\x00\x00\u07d4_#\xba\x1f7\xa9lE\xbcI\x02YS\x8aT\u008b\xa3\xb0\u0549A\rXj \xa4\xc0\x00\x00\u07d4_&\xcf4Y\x9b\xc3n\xa6{\x9ez\x9f\x9bC0\xc9\xd5B\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4_)\xc9\xdev]\xde%\x85*\xf0}3\xf2\xceF\x8f\xd2\t\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_/\a\xd2\u0597\xe8\xc5g\xfc\xfd\xfe\x02\x0fI\xf3`\xbe!9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_2\x1b=\xaa\xa2\x96\xca\xdf)C\x9f\x9d\xab\x06*K\xff\xed\u0589\x04p%\x90>\xa7\xae\x00\x00\u07d4_3:;#\x10vZ\r\x182\xb9\xbeL\n\x03pL\x1c\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4_4K\x01\xc7\x19\x1a2\xd0v*\xc1\x88\xf0\xec-\xd4`\x91\x1d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94_6>\n\xb7G\xe0-\x1b;f\xab\xb6\x9e\xa5<{\xafR:\x8a\x02w\x01s8\xa3\n\xe0\x00\x00\u07d4_7[\x86`\f@\u0328\xb2gkz\x1a\x1d\x16D\xc5\xf5,\x89\x04F\x18\xd7Lb?\x00\x00\u07d4_>\x1eg9\xb0\xc6\"\x00\xe0\n\x006\x91\xd9\xef\xb28\u061f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4_H?\xfb\x8fh\n\xed\xf2\xa3\x8fx3\xaf\xdc\xdeY\xb6\x1eK\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94_J\xceL\x1c\xc13\x91\xe0\x1f\x00\xb1\x98\xe1\xf2\v_\x91\xcb\xf5\x8a\x01\x0f\x0f\xa8\xb9\u04c1\x1a\x00\x00\xe0\x94_R\x12\x82\xe9\xb2x\u070c\x03Lr\xafS\xee)\xe5D=x\x8a\x01as-/\x8f:\xe0\x00\x00\u07d4_h\xa2L~\xb4\x11vgs{39?\xb3\xc2\x14\x8aS\xb6\x89\x02\xce\u0791\x8dE<\x00\x00\u07d4_p\x8e\xaf9\xd8#\x94lQ\xb3\xa3\u9df3\xc0\x03\xe2cA\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4_t.H~:\xb8\x1a\xf2\xf9J\xfd\xbe\x1b\x9b\x8f\\\u0301\xbc\x89u\xc4E\xd4\x11c\xe6\x00\x00\u07d4_t\xed\x0e$\xff\x80\u0672\u0124K\xaa\x99uB\x8c\u05b95\x89\xa1\x8b\xce\xc3H\x88\x10\x00\x00\u07d4_v\xf0\xa3\x06&\x9cx0k=e\r\xc3\xe9\xc3p\x84\xdba\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4_w\xa1\a\xab\x12&\xb3\xf9_\x10\ue0ee\xfcl]\xff>\u0709\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4_{;\xba\xc1m\xab\x83\x1aJ\x0f\xc5;\fT\x9d\xc3l1\u0289i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94_\x93\xff\x83't\xdbQ\x14\xc5[\xb4\xbfD\xcc\U000f53d0?\x8a(\xa9\xc9\x1a&4X)\x00\x00\u07d4_\x96\x16\xc4{Jg\xf4\x06\xb9Z\x14\xfeo\xc2h9o\x17!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4_\x98\x109\xfc\xf5\x02%\xe2\xad\xf7bu!\x12\xd1\xcc&\xb6\xe3\x89\x1b\x1aAj!S\xa5\x00\x00\u07d4_\x99\u070eI\xe6\x1dW\xda\xef`j\xcd\xd9\x1bMp\a2j\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4_\xa6\x1f\x15-\xe6\x125\x16\xc7Q$)y(_yj\u01d1\x89\v\x0f\x11\x97)c\xb0\x00\x00\u07d4_\xa7\xbf\xe0C\x88a'\xd4\x01\x1d\x83V\xa4~\x94yc\xac\xa8\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94_\xa8\xa5Nh\x17lO\xe2\xc0\x1c\xf6q\xc5\x15\xbf\xbd\xd5(\xa8\x8aE\xe1U\xfa\x01\x10\xfa@\x00\x00\u07d4_\xad\x96\x0fk,\x84V\x9c\x9fMG\xbf\x19\x85\xfc\xb2\xc6]\xa6\x8965f3\xeb\xd8\xea\x00\x00\u07d4_\xc6\xc1\x14&\xb4\xa1\xea\xe7\xe5\x1d\xd5\x12\xad\x10\x90\xc6\xf1\xa8[\x89\x93\xfe\\W\xd7\x10h\x00\x00\u07d4_\u0344Th\x96\xdd\b\x1d\xb1\xa3 \xbdM\x8c\x1d\xd1R\x8cL\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4_\u0368G\xaa\xf8\xd7\xfa\x8b\xca\b\x02\x9c\xa2\x84\x91f\xaa\x15\xa3\x89!\u02b8\x12Y\xa3\xbf\x00\x00\u07d4_\xd1\xc3\xe3\x17x'l\xb4.\xa7@\xf5\xea\xe9\xc6A\xdb\xc7\x01\x89\n\x84Jt$\xd9\xc8\x00\x00\u07d4_\xd3\xd6w~\xc2b\n\xe8:\x05R\x8e\xd4%\a-<\xa8\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4_\xd9s\xaf6j\xa5\x15|Te\x9b\u03f2|\xbf\xa5\xac\x15\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4_\xe7w\x03\x80\x8f\x82>l9\x93R\x10\x8b\xdb,R|\xb8|\x89j@v\xcfy\x95\xa0\x00\x00\xe0\x94_\xecI\xc6e\xe6N\xe8\x9d\xd4A\xeet\x05n\x1f\x01\xe9(p\x8a\x01V\x9b\x9es4t\xc0\x00\x00\u07d4_\xf3&\xcd`\xfd\x13k$^)\xe9\bzj\u04e6R\u007f\r\x89e\xea=\xb7UF`\x00\x00\u07d4_\xf9=\xe6\xee\x05L\xadE\x9b-^\xb0\xf6\x87\x03\x89\xdf\xcbt\x89\v\xed\x1d\x02c\xd9\xf0\x00\x00\u07d4`\x06\xe3m\x92\x9b\xf4]\x8f\x16#\x1b\x12j\x01\x1a\xe2\x83\xd9%\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4`!\xe8Z\x88\x14\xfc\xe1\xe8*A\xab\xd1\u04f2\xda\xd2\xfa\xef\xe0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4`8t\n\xe2\x8df\xba\x93\xb0\xbe\bH+2\x05\xa0\xf7\xa0{\x89\x11!a\x85\u009fp\x00\x00\u07d4`?/\xabz\xfbn\x01{\x94v`i\xa4\xb4;8\x96I#\x89Y\xd2\xdb$\x14\u0699\x00\x00\u07d4`B'm\xf2\x98?\xe2\xbcGY\xdc\x19C\xe1\x8f\xdb\xc3Ow\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4`B\xc6D\xba\xe2\xb9o%\xf9M1\xf6x\xc9\r\xc9f\x90\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4`L\xdf\x18b\x8d\xbf\xa82\x91\x94\xd4x\xddR\x01\xee\xccK\xe7\x89\x01?0j$\t\xfc\x00\x00\u07d4`N\x94w\xeb\xf4r|t[\u02bb\xed\xcbl\xcf)\x99@\"\x8966\x9e\xd7t}&\x00\x00\u07d4`gm\x1f\xa2\x1f\xca\x05\"\x97\xe2K\xf9c\x89\u0171*p\u05c9\r\x17|Zzh\xd6\x00\x00\u07d4`gn\x92\u044b\x00\x05\t\xc6\x1d\xe5@\xe6\xc5\u0776v\xd5\t\x89A\rXj \xa4\xc0\x00\x00\u07d4`o\x17q!\xf7\x85\\!\xa5\x06#0\xc8v\"d\xa9{1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4`\x86B6\x93\r\x04\xd8@+]\xcb\xeb\x80\u007f<\xafa\x1e\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4`\xabq\xcd&\xeamnY\xa7\xa0\xf6'\xee\a\x9c\x88^\xbb\xf6\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4`\xaf\x0e\xe1\x18D<\x9b7\xd2\xfe\xadw\xf5\xe5!\u07be\x15s\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4`\xb3X\xcb=\xbe\xfa7\xf4}\xf2\xd76X@\u068e;\u024c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4`\xb8\u05b7;ySO\xb0\x8b\xb8\xcb\xce\xfa\xc7\xf3\x93\xc5{\xfe\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4`\xbeo\x95?*M%\xb6%o\xfd$#\xac\x148%.N\x89\b!\xab\rD\x14\x98\x00\x00\u0794`\xc3qO\xdd\xdbcFY\u48b1\xeaB\xc4r\x8c\u01f8\xba\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4`\xcc=D^\xbd\xf7j}z\xe5q\u0197\x1d\xffh\u0305\x85\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94`\xd5fq@\xd1&\x14\xb2\x1c\x8e^\x8a3\b.2\xdf\xcf#\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4`\xde\"\xa1Pt2\xa4{\x01\xcch\xc5*\v\xf8\xa2\xe0\u0418\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4`\xe0\xbd\u0422Y\xbb\x9c\xb0\x9d?7\xe5\u034b\x9d\xac\uafca\x89JD\x91\xbdm\xcd(\x00\x00\u07d4`\xe3\xccC\xbc\xdb\x02j\xadu\x9cpf\xf5U\xbb\xf2\xacf\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\x04+\x80\xfd`\x95\u0478{\xe2\xf0\x0f\x10\x9f\xab\xaf\xd1W\xa6\x89\x05k\xc7^-c\x10\x00\x00\u07d4a\a\xd7\x1d\xd6\xd0\xee\xfb\x11\xd4\xc9\x16@L\xb9\x8cu>\x11}\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\x0f\xd6\xeeN\xeb\xab\x10\xa8\xc5]\vK\xd2\xe7\xd6\xef\x81qV\x89\x01\x15\x95a\x06]]\x00\x00\u07d4a\x14\xb0\xea\xe5Wi\x03\xf8\v\xfb\x98\x84-$\xed\x92#\u007f\x1e\x89\x05k\xc7^-c\x10\x00\x00\u07d4a!\xaf9\x8a[-\xa6\x9fe\xc68\x1a\xec\x88\u039c\xc6D\x1f\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\u07d4a&g\xf1r\x13[\x95\v,\xd1\xde\x10\xaf\xde\xcehW\xb8s\x8965\u026d\xc5\u07a0\x00\x00\u07d4a,\xed\x8d\xc0\u071e\x89\x9e\xe4oyb33\x15\xf3\xf5^D\x89\x12^5\xf9\xcd=\x9b\x00\x00\u07d4a4\xd9B\xf07\xf2\xcc=BJ#\f`=g\xab\xd3\xed\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a:\xc5;\xe5e\xd4e6\xb8 q[\x9b\x8d:\xe6\x8aK\x95\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\u07d4a?\xabD\xb1k\xbeUMD\xaf\xd1x\xab\x1d\x02\xf3z\ua949lk\x93[\x8b\xbd@\x00\x00\u07d4aN\x8b\xef=\xd2\u015bY\xa4\x14Vt@\x10\x185\x18\x84\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4aQ\x84d\xfd\u0637<\x1b\xb6\xacm\xb6\x00eI8\xdb\xf1z\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4aT}7nSi\xbc\xf9x\xfc\x16,1\xc9\b\"3\xb8%\xd0%\xbe?{\x10V\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4a\x91\xdd\u0276J\x8e\b\x90\xb427\t\u05e0|H\xb9*d\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4a\x96\xc3\xd3\xc0\x90\x8d%Cf\xb7\xbc\xa5WE\"-\x9dM\xb1\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4a\x9f\x17\x14E\xd4+\x02\xe2\xe0p\x04\xad\x8a\xfeiO\xa5=j\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4a\xad\xf5\x92\x9a^)\x81hN\xa2C\xba\xa0\x1f}\x1f^\x14\x8a\x89\x05\xfa\xbfl\x98O#\x00\x00\u07d4a\xb1\xb8\xc0\x12\xcdLx\xf6\x98\xe4p\xf9\x02V\xe6\xa3\x0fH\u0749\n\u05ce\xbcZ\xc6 \x00\x00\u07d4a\xb3\xdf.\x9e\x9f\xd9h\x13\x1f\x1e\x88\xf0\xa0\xeb[\xd7eFM\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4a\xb9\x02\u0166s\x88X&\x82\r\x1f\xe1EI\xe4\x86_\xbd\u0089\x12$\xef\xed*\u1440\x00\u07d4a\xb9\x05\xdef?\xc1s\x86R;:(\xe2\xf7\xd07\xa6U\u0349\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4a\xba\x87\xc7~\x9bYm\xe7\xba\x0e2o\xdd\xfe\xec!c\xeff\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4a\xbf\x84\u056b\x02oX\xc8s\xf8o\xf0\xdf\u0282\xb5W3\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\xc4\xee|\x86LMk^7\xea\x131\xc2\x03s\x9e\x82k/\x89\x01\xa15;8*\x91\x80\x00\u07d4a\xc80\xf1eG\x18\xf0u\u032b\xa3\x16\xfa\xac\xb8[}\x12\v\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4a\xc8\xf1\xfaC\xbf\x84i\x99\xec\xf4{+2M\xfbkc\xfe:\x89+^:\xf1k\x18\x80\x00\x00\u07d4a\xc9\xdc\u8c98\x1c\xb4\x0e\x98\xb0@+\xc3\xeb(4\x8f\x03\xac\x89\n\xac\xac\u0679\xe2+\x00\x00\u07d4a\u03a7\x1f\xa4d\xd6*\a\x06?\x92\v\f\xc9\x17S\x973\u0609Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4a\xd1\x01\xa03\xee\x0e.\xbb1\x00\xed\xe7f\xdf\x1a\xd0$IT\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4a\xedU\x96\u0197 \u007f=U\xb2\xa5\x1a\xa7\xd5\x0f\a\xfa\t\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4a\xff\x8eg\xb3M\x9e\xe6\xf7\x8e\xb3o\xfe\xa1\xb9\xf7\xc1W\x87\xaf\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4b\x05\xc2\xd5dtp\x84\x8a8@\xf3\x88~\x9b\x01]4u\\\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4b(\xad\xe9^\x8b\xb1}\x1a\xe2;\xfb\x05\x18AMI~\x0e\xb8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94b)\xdc\xc2\x03\xb1\xed\xcc\xfd\xf0n\x87\x91\fE*\x1fMzr\x8a\x06\xe1\xd4\x1a\x8f\x9e\xc3P\x00\x00\u0794b+\xe4\xb4T\x95\xfc\xd91C\xef\xc4\x12\u0599\xd6\xcd\xc2=\u0148\xf0\x15\xf2W6B\x00\x00\u07d4b3\x1d\xf2\xa3\xcb\xee5 \xe9\x11\u07a9\xf7>\x90_\x89%\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4bVD\xc9Z\x87>\xf8\xc0l\u06de\x9fm\x8dv\x80\x04=b\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4be\xb2\xe7s\x0f6\xb7v\xb5-\f\x9d\x02\xad\xa5]\x8e<\xb6\x8965\u026d\xc5\u07a0\x00\x00\u07d4bh\n\x15\xf8\u0338\xbd\xc0/s`\xc2Z\xd8\u03f5{\x8c\u034965\u026d\xc5\u07a0\x00\x00\u07d4b\x94\xea\xe6\xe4 \xa3\xd5`\n9\xc4\x14\x1f\x83\x8f\xf8\xe7\xccH\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4b\x97\x1b\xf2cL\xee\v\xe3\u0249\x0fQ\xa5`\x99\u06f9Q\x9b\x89#\x8f\xd4,\\\xf0@\x00\x00\u07d4b\x9b\xe7\xab\x12jS\x98\xed\xd6\u069f\x18D~x\u0192\xa4\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4b\xb4\xa9\"nah\a\x1el\xbea\x11\xfe\xf0\xbcc\x8a\x03\xba\x19\x10\xbf4\x1b\x00\x00\x00\xe0\x94c\n\x91:\x901\xc9I*\xbdLA\u06f1PT\xcf\xecD\x16\x8a\x014X\xdbg\xaf5\xe0\x00\x00\xe0\x94c\fRs\x12mQ|\xe6q\x01\x81\x1c\xab\x16\xb8SL\xf9\xa8\x8a\x01\xfe\xcc\xc6%s\xbb\u04c0\x00\u07d4c\x100\xa5\xb2{\a(\x8aEio\x18\x9e\x11\x14\xf1*\x81\xc0\x89\x1b\x1azB\v\xa0\r\x00\x00\u07d4c\x10\xb0 \xfd\x98\x04IW\x99P\x92\t\x0f\x17\xf0NR\xcd\xfd\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4c+\x91I\xd7\x01x\xa7364'^\x82\u0555?'\x96{\x89%\xf2s\x93=\xb5p\x00\x00\u07d4c,\xec\xb1\f\xfc\xf3\x8e\u0246\xb4;\x87p\xad\xec\xe9 \x02!\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4c1\x02\x8c\xbbZ!H[\xc5\x1bVQB\x99;\xdb%\x82\xa9\x89\x1c\xfd\xd7F\x82\x16\xe8\x00\x00\u07d4c3O\xcf\x17E\x84\x0eK\tJ;\xb4\v\xb7o\x96\x04\xc0L\x89\u05e5\xd7\x03\xa7\x17\xe8\x00\x00\u07d4c4\nWqk\xfac\xebl\xd13r\x12\x02W[\xf7\x96\xf0\x89\va\xe0\xa2\f\x12q\x80\x00\u07d4cN\xfc$7\x11\a\xb4\xcb\xf0?y\xa9=\xfd\x93\xe41\xd5\xfd\x89B5\x82\xe0\x8e\xdc\\\x80\x00\xe0\x94c\\\x00\xfd\xf05\xbc\xa1_\xa3a\r\xf38N\x0f\xb7\x90h\xb1\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4ca.xb\xc2{X|\xfbm\xaf\x99\x12\xcb\x05\x1f\x03\n\x9f\x89\x02[\x19\u053f\xe8\xed\x00\x00\u07d4cfgU\xbdA\xb5\x98i\x97x<\x13\x040\b$+<\xb5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4c{\xe7\x1b:\xa8\x15\xffE=VB\xf70tE\vd\xc8*\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94c}g\xd8\u007fXo\nZG\x9e \xee\x13\xea1\n\x10\xb6G\x8a\n:Y&\xaf\xa1\xe70\x00\x00\u07d4c\u007fXi\xd6\xe4i_\x0e\xb9\xe2s\x11\u0107\x8a\xff33\x80\x89j\xc0Nh\xaa\xec\x86\x00\x00\u07d4c\x97|\xad}\r\xcd\xc5+\x9a\xc9\xf2\xff\xa16\xe8d(\x82\xb8\x89\x04\x10\u0546\xa2\nL\x00\x00\u07d4c\xa6\x1d\xc3\n\x8e;0\xa7c\xc4!<\x80\x1c\xbf\x98s\x81x\x8965\u026d\xc5\u07a0\x00\x00\u07d4c\xacT\\\x99\x12C\xfa\x18\xae\xc4\x1dOoY\x8eUP\x15\u0709 \x86\xac5\x10R`\x00\x00\u07d4c\xb9uMu\xd1-8@9\xeci\x06<\v\xe2\x10\xd5\xe0\u3252\v\x86\f\xc8\xec\xfd\x80\x00\u07d4c\xbbfO\x91\x17\x03v(YM\xa7\xe3\xc5\b\x9f\xd6\x18\xb5\xb5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4c\u00a3\xd25\xe5\xee\xab\xd0\u0526\xaf\u06c9\xd9F'9d\x95\x89CN\xf0[\x9d\x84\x82\x00\x00\u07d4c\xc8\xdf\xde\v\x8e\x01\xda\xdc.t\x8c\x82L\xc06\x9d\U00010cc9\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4c\xd5Z\u065b\x917\xfd\x1b \xcc+O\x03\xd4,\xba\xdd\xf34\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4c\xd8\x00H\x87u\x96\xe0\u0084\x89\xe6P\xcdJ\xc1\x80\tjI\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94c\xe4\x14`>\x80\xd4\xe5\xa0\xf5\xc1\x87t FB%\x82\b\xe4\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94c\xe8\x8e.S\x9f\xfbE\x03\x86\xb4\xe4g\x89\xb2#\xf5GlE\x8a\x01U\x17\nw\x8e%\xd0\x00\x00\u07d4c\xef/\xbc=\xaf^\xda\xf4\xa2\x95b\x9c\xcf1\xbc\xdf@8\xe5\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4c\xf0\xe5\xa7R\xf7\x9fg\x12N\xedc:\xd3\xfd'\x05\xa3\x97\u0509\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94c\xf5\xb5=y\xbf.A\x14\x89Re0\"8E\xfa\xc6\xf6\x01\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4c\xfc\x93\x00\x13\x05\xad\xfb\u0278])\xd9)\x1a\x05\xf8\xf1A\v\x8965\u026d\xc5\u07a0\x00\x00\u0794c\xfek\xccK\x8a\x98P\xab\xbeu\x8070\xc92%\x1f\x14[\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4d\x03\xd0bT\x96\x90\xc8\xe8\xb6>\xaeA\xd6\xc1\tGn%\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4d\x04+\xa6\x8b\x12\xd4\xc1Qe\x1c\xa2\x81;sR\xbdV\xf0\x8e\x89 \x86\xac5\x10R`\x00\x00\u0794d\x05\xdd\x13\xe9:\xbc\xff7~p\x0e<\x1a\x00\x86\xec\xa2})\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94d\n\xbam\xe9\x84\xd9E\x177x\x03p^\xae\xa7\t_J\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4d\v\xf8t\x15\xe0\xcf@s\x01\xe5Y\x9ah6m\xa0\x9b\xba\u0209\x1a\xbc\x9fA`\x98\x15\x80\x00\u07d4d \xf8\xbc\xc8\x16JaR\xa9\x9dk\x99i0\x05\xcc\xf7\xe0S\x8965f3\xeb\xd8\xea\x00\x00\u07d4d$\x1axD)\x0e\n\xb8U\xf1\u052au\xb5SE\x03\"$\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4d&J\xed\xd5-\xca\xe9\x18\xa0\x12\xfb\xcd\f\x03\x0e\xe6\xf7\x18!\x8965\u026d\xc5\u07a0\x00\x00\u07d4d7\x0e\x87 &E\x12Z5\xb2\a\xaf\x121\xfb`r\xf9\xa7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4d=\x9a\xee\u0531\x80\x94~\u04b9 |\xceL=\xdcU\xe1\xf7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4dC\xb8\xaec\x9d\xe9\x1c\xf7\xf0p\xa5G\x03\xb7\x18NH'l\\\x00w\xefK4\x89\x11X\xe4`\x91=\x00\x00\x00\xe0\x94d\xe2\xde! \v\x18\x99\u00e0\xc0e;P@\x13m\r\xc8B\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4d\xec\x8a[t?4y\xe7\a\xda\xe9\xee \u076aO@\xf1\u0649\n\u05ce\xbcZ\xc6 \x00\x00\u07d4e\x03\x86\v\x19\x10\b\xc1U\x83\xbf\u0201X\t\x93\x01v((\x8965\u026d\xc5\u07a0\x00\x00\u07d4e\x051\x911\x9e\x06z%\xe66\x1dG\xf3\u007fc\x18\xf84\x19\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4e\t;#\x9b\xbf\xba#\xc7w\\\xa7\xdaZ\x86H\xa9\xf5L\xf7\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4e\t\xee\xb14~\x84/\xfbA>7\x15^,\xbcs\x82s\xfd\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94e\vBUU\xe4\xe4\xc5\x17\x18\x14h6\xa2\xc1\xeew\xa5\xb4!\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4e\f\xf6}\xb0`\xcc\xe1uh\xd5\xf2\xa4#h|Idv\t\x89\x05k\xc7^-c\x10\x00\x00\u07d4e\x10\xdfB\xa5\x99\xbc\xb0\xa5\x19\u0329a\xb4\x88u\x9aogw\x89lk\x93[\x8b\xbd@\x00\x00\u07d4e6u\xb8B\xd7\u0634a\xf7\"\xb4\x11|\xb8\x1d\xac\x8ec\x9d\x89\x01\xae6\x1f\xc1E\x1c\x00\x00\u07d4eK~\x80\x87\x99\xa8=r\x87\xc6w\x06\xf2\xab\xf4\x9aId\x04\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94eORHG\xb3\xa6\xac\xc0\xd3\xd5\xf1\xf3b\xb6\x03\xed\xf6_\x96\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4eY4\u068etN\xaa=\xe3M\xbb\xc0\x89LN\xda\va\xf2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4e]\\\xd7H\x96)\xe2ANIb?\xabb\xa1~M6\x11\x89\x05\fL\xb2\xa1\f`\x00\x00\u07d4e\xaf\x8d\x8b[\x1d\x1e\xed\xfaw\xbc\xbc\x96\xc1\xb13\xf83\x06\u07c9\x05P\x05\xf0\xc6\x14H\x00\x00\u07d4e\xaf\x90\x87\xe0QgqT\x97\u0265\xa7I\x18\x94\x89\x00M\xef\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u0794e\xb4/\xae\xcc\x1e\u07f1B\x83\u0297\x9a\xf5E\xf6;0\xe6\f\x88\xfc\x93c\x92\x80\x1c\x00\x00\u0794e\xd3>\xb3\x9c\xdadS\xb1\x9ea\xc1\xfeM\xb91p\xef\x9d4\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4e\xd8\xddN%\x1c\xbc\x02\x1f\x05\xb0\x10\xf2\xd5\xdcR\f8r\xe0\x89-CW\x9a6\xa9\x0e\x00\x00\u07d4e\xea&\xea\xbb\xe2\xf6L\xcc\xcf\xe0h)\xc2]F7R\x02%\x89%\xf2s\x93=\xb5p\x00\x00\u07d4e\xeag\xad?\xb5j\xd5\xfb\x948}\u04ce\xb3\x83\x00\x1d|h\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94e\xeb\xae\xd2~\u06dd\xcc\x19W\xae\xe5\xf4R\xac!\x05\xa6\\\x0e\x8a\t7\u07ed\xae%\u26c0\x00\u07d4e\xee \xb0m\x9a\u0549\xa7\xe7\xce\x04\xb9\xf5\xf7\x95\xf4\x02\xae\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4e\xf544m/\xfbx\u007f\xa9\xcf\x18]t[\xa4)\x86\xbdn\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94e\xf5\x87\x0f&\xbc\xe0\x89g}\xfc#\xb5\x00\x1e\xe4\x92H4(\x8a\x01\x12\xb1\xf1U\xaa2\xa3\x00\x00\u07d4e\xfd\x02\xd7\x04\xa1*M\xac\xe9G\x1b\x06E\xf9b\xa8\x96q\u0209\x01\x8d\x1c\xe6\xe4'\u0340\x00\u07d4e\xff\x87O\xaf\xceM\xa3\x18\xd6\xc9=W\xe2\u00ca\rs\xe8 \x8968\x02\x1c\xec\u06b0\x00\x00\xe0\x94f\x05W\xbbC\xf4\xbe:\x1b\x8b\x85\xe7\xdf{<[\xcdT\x80W\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4f\b,u\xa8\xde1\xa59\x13\xbb\xd4M\xe3\xa07O\u007f\xaaA\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4f\x11\xceY\xa9\x8b\a*\xe9Y\xdcI\xadQ\x1d\xaa\xaa\xa1\x9dk\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4f \x1b\xd2'\xaem\u01bd\xfe\xd5\xfb\u0781\x1f\xec\xfe^\x9d\u0649 >\x9e\x84\x92x\x8c\x00\x00\u07d4f#4\x81G$\x93[y1\xdd\xcaa\x00\xe0\rFw'\u0349\"\x88&\x9d\a\x83\xd4\x00\x00\u07d4f'O\xea\x82\xcd0\xb6\u009b#5\x0eOO=1\nX\x99\x89p7\x05P\xab\x82\x98\x00\x00\u07d4f,\xfa\x03\x8f\xab7\xa0\x17E\xa3d\u1e41'\xc5\x03tm\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4f5\xb4oq\x1d-\xa6\xf0\xe1cp\u034e\xe4>\xfb,-R\x89lk\x93[\x8b\xbd@\x00\x00\u07d4f6\x04\xb0P0F\xe6$\xcd&\xa8\xb6\xfbGB\xdc\xe0*o\x89\x03\x8b\x9by~\xf6\x8c\x00\x00\u07d4f6\u05ecczH\xf6\x1d8\xb1L\xfdHe\xd3m\x14(\x05\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4f@\xcc\xf0SU\\\x13\n\xe2\xb6Vd~\xa6\xe3\x167\xb9\xab\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4fBK\xd8x[\x8c\xb4a\x10*\x90\x02\x83\xc3]\xfa\a\xefj\x89\x02.-\xb2ff\xfc\x80\x00\u07d4fL\xd6}\xcc\u026c\x82(\xb4\\U\u06cdvU\ve\x9c\u0709\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4fNC\x11\x98p\xaf\x10zD\x8d\xb1'\x8b\x04H8\xff\u036f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4fQso\xb5\x9b\x91\xfe\xe9\xc9:\xa0\xbdn\xa2\xf7\xb2Pa\x80\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4f[\x00\x0f\vw'P\xcc\x89k\x91\x8a\xacIK\x16\x80\x00\xe0\x94g]\\\xaa`\x9b\xf7\n\x18\xac\xa5\x80F]\x8f\xb71\r\x1b\xbb\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4gc F\u0732ZT\x93i(\xa9oB?3 \xcb\ud489lk\x93[\x8b\xbd@\x00\x00\u07d4ge\xdf%(\x0e\x8eO8\u0531\xcfDo\xc5\xd7\xebe\x9e4\x89\x05k\xc7^-c\x10\x00\x00\u07d4gv\xe13\xd9\xdc5L\x12\xa9Q\b{c\x96P\xf59\xa43\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4g\x85Q<\xf72\xe4~\x87g\ap\xb5A\x9b\xe1\f\xd1\xfct\x89lk\x93[\x8b\xbd@\x00\x00\u07d4g\x947\xea\xcfCxx\xdc)=H\xa3\x9c\x87\xb7B\x1a!l\x89\x03\u007f\x81\x82\x1d\xb2h\x00\x00\u07d4g\x9b\x9a\x10\x990Q~\x89\x99\t\x9c\xcf*\x91LL\x8d\xd94\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4g\xa8\x0e\x01\x90r\x1f\x949\rh\x02r\x9d\xd1,1\xa8\x95\xad\x89lk\x13u\xbc\x91V\x00\x00\u07d4g\xb8\xa6\xe9\x0f\xdf\n\x1c\xacD\x17\x930\x1e\x87P\xa9\xfayW\x890\x84\x9e\xbe\x166\x9c\x00\x00\u07d4g\xbc\x85\xe8}\xc3LN\x80\xaa\xfa\x06k\xa8\u049d\xbb\x8eC\x8e\x89\x15\xd1\xcfAv\xae\xba\x00\x00\u07d4g\xc9&\t>\x9b\x89'\x938\x10\u0642\"\xd6.+\x82\x06\xbb\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4g\xcf\xdanp\xbfvW\u04d0Y\xb5\x97\x90\xe5\x14Z\xfd\xbea\x89#\x05\r\tXfX\x00\x00\u07d4g\u0582\xa2\x82\xefs\xfb\x8dn\x90q\xe2aOG\xab\x1d\x0f^\x8965\u026d\xc5\u07a0\x00\x00\u07d4g\u05a8\xaa\x1b\xf8\xd6\xea\xf78N\x99=\xfd\xf1\x0f\n\xf6\x8aa\x89\n\xbc\xbbW\x18\x97K\x80\x00\u07d4g\u0692.\xff\xa4r\xa6\xb1$\xe8N\xa8\xf8k$\xe0\xf5\x15\xaa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4g\xdf$-$\r\u0538\a\x1dr\xf8\xfc\xf3[\xb3\x80\x9dq\xe8\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4g\xee@n\xa4\xa7\xaej:8\x1e\xb4\xed\xd2\xf0\x9f\x17KI(\x898)c_\th\xb0\x00\x00\u07d4g\xf2\xbbx\xb8\xd3\xe1\x1f|E\x8a\x10\xb5\xc8\xe0\xa1\xd3tF}\x89a\t=|,m8\x00\x00\u07d4g\xfcR}\xce\x17\x85\xf0\xfb\x8b\xc7\xe5\x18\xb1\xc6i\xf7\xec\u07f5\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4h\x02}\x19U\x8e\xd73\x9a\b\xae\xe8\xde5Y\xbe\x06>\xc2\xea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4h\x06@\x83\x8b\xd0zD{\x16\x8dm\x92;\x90\xcflC\xcd\u0289]\u0212\xaa\x111\xc8\x00\x00\u07d4h\a\xdd\u020d\xb4\x89\xb03\xe6\xb2\xf9\xa8\x15SW\x1a\xb3\xc8\x05\x89\x01\x9f\x8euY\x92L\x00\x00\xe0\x94h\rY\x11\xed\x8d\xd9\xee\xc4\\\x06\f\"?\x89\xa7\xf6 \xbb\u054a\x04<3\xc1\x93ud\x80\x00\x00\u07d4h\x11\xb5L\u0456c\xb1\x1b\x94\xda\x1d\xe2D\x82\x85\u035fh\u0649;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4h\x19\f\xa8\x85\xdaB1\x87L\x1c\xfbB\xb1X\n!s\u007f8\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94h(\x97\xbcO\x8e\x89\x02\x91 \xfc\xff\xb7\x87\xc0\x1a\x93\xe6A\x84\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4h)^\x8e\xa5\xaf\xd9\t?\xc0\xa4e\xd1W\x92+]*\xe24\x89\x01\x15NS!}\xdb\x00\x00\u07d4h.\x96'oQ\x8d1\xd7\xe5n0\u07f0\t\xc1!\x82\x01\xbd\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4h5\xc8\xe8\xb7J,\xa2\xae?J\x8d\x0fk\x95J>*\x83\x92\x89\x03B\x9c3]W\xfe\x00\x00\u07d4h63\x01\n\x88hk\xeaZ\x98\xeaS\xe8y\x97\xcb\xf7>i\x89\x05k9Bc\xa4\f\x00\x00\u07d4h=\xba6\xf7\xe9O@\xeaj\xea\ry\xb8\xf5!\xdeU\an\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4hA\x9cm\xd2\xd3\xceo\u02f3\xc7>/\xa0y\xf0`Q\xbd\xe6\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4hG;z}\x96Y\x04\xbe\u06e5V\u07fc\x17\x13l\xd5\xd44\x89\x05k\xc7^-c\x10\x00\x00\u07d4hG\x82[\xde\xe8$\x0e(\x04,\x83\xca\xd6B\U000868fd\u0709QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94hJD\xc0i3\x9d\b\xe1\x9auf\x8b\u06e3\x03\xbe\x85S2\x8a\x0e\u04b5%\x84\x1a\xdf\xc0\x00\x00\u07d4hS\x1fM\u0680\x8fS vz\x03\x114(\xca\f\xe2\xf3\x89\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4hy'\xe3\x04\x8b\xb5\x16*\xe7\xc1\\\xf7k\xd1$\xf9I{\x9e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94h\x80\x9a\xf5\xd52\xa1\x1c\x1aMn2\xaa\xc7\\LR\xb0\x8e\xad\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4h\x86\xad\xa7\xbb\xb0a{\u0684!\x91\u018c\x92.\xa3\xa8\xac\x82\x89>\xe2;\xde\x0e} \x00\x00\xe0\x94h\x88>\x15.V`\xfe\xe5\x96&\xe7\xe3\xb4\xf0Q\x10\xe6\"/\x8a\v\x94c;\xe9u\xa6*\x00\x00\u07d4h\x8aV\x9e\x96U$\xeb\x1d\n\xc3\xd3s>\xab\x90\x9f\xb3\xd6\x1e\x89G\x8e\xae\x0eW\x1b\xa0\x00\x00\xe0\x94h\x8e\xb3\x85;\xbc\xc5\x0e\xcf\xee\x0f\xa8\u007f\n\xb6\x93\u02bd\xef\x02\x8a\x06\xb1\n\x18@\x06G\xc0\x00\x00\u07d4h\xa7B_\xe0\x9e\xb2\x8c\xf8n\xb1y>A\xb2\x11\xe5{\u058d\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4h\xa8l@#\x88\xfd\xdcY\x02\x8f\xecp!\u933f\x83\x0e\xac\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\xe0\x94h\xac\u06a9\xfb\x17\xd3\xc3\t\x91\x1aw\xb0_S\x91\xfa\x03N\xe9\x8a\x01\xe5.3l\xde\"\x18\x00\x00\u07d4h\xad\xdf\x01\x9dk\x9c\xabp\xac\xb1?\v1\x17\x99\x9f\x06.\x12\x89\x02\xb5\x12\x12\xe6\xb7\u0200\x00\u07d4h\xb3\x186\xa3\n\x01j\xda\x15{c\x8a\xc1]\xa7?\x18\xcf\u0789\x01h\u048e?\x00(\x00\x00\xe0\x94h\xb6\x85G\x88\xa7\xc6Il\xdb\xf5\xf8K\x9e\xc5\xef9+x\xbb\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4h\xc0\x84\x90\u021b\xf0\u05b6\xf3 \xb1\xac\xa9\\\x83\x12\xc0\x06\b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4h\xc7\xd1q\x1b\x01\x1a3\xf1o\x1fU\xb5\xc9\x02\xcc\xe9p\xbd\u05c9\b=lz\xabc`\x00\x00\u07d4h\xc8y\x1d\xc3B\xc3sv\x9e\xa6\x1f\xb7\xb5\x10\xf2Q\xd3 \x88\x8965\u026d\xc5\u07a0\x00\x00\u07d4h\u07d4|I[\ubbb8\u8273\xf9S\xd53\x87K\xf1\x06\x89\x1d\x99E\xab+\x03H\x00\x00\u07d4h\xe8\x02'@\xf4\xaf)\xebH\xdb2\xbc\xec\xdd\xfd\x14\x8d=\xe3\x8965\u026d\xc5\u07a0\x00\x00\u07d4h\xecy\u057eqUql@\x94\x1cy\u05cd\x17\u079e\xf8\x03\x89\x1b#8w\xb5 \x8c\x00\x00\u07d4h\xee\xc1\u222c1\xb6\xea\xba~\x1f\xbdO\x04\xadW\x9ak]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4h\xf5%\x92\x1d\xc1\x1c2\x9buO\xbf>R\x9f\xc7#\xc84\u0349WG=\x05\u06ba\xe8\x00\x00\u07d4h\xf7\x19\xae4+\xd7\xfe\xf1\x8a\x05\u02f0/pZ\u04ce\u0572\x898\xeb\xad\\\u0710(\x00\x00\xe0\x94h\xf7W<\xd4W\xe1L\x03\xfe\xa4>0-04|\x10p\\\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4h\xf8\xf4QU\xe9\x8cP)\xa4\xeb\u0175'\xa9.\x9f\xa81 \x89\xf0{D\xb4\a\x93 \x80\x00\u07d4h\xfe\x13W!\x8d\tXI\xcdW\x98B\u012a\x02\xff\x88\x8d\x93\x89lk\x93[\x8b\xbd@\x00\x00\u07d4i\x02(\xe4\xbb\x12\xa8\u0535\u09d7\xb0\xc5\xcf*u\t\x13\x1e\x89e\xea=\xb7UF`\x00\x00\u07d4i\x05\x94\xd3\x06a<\xd3\xe2\xfd$\xbc\xa9\x99J\u064a=s\xf8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94i\a2ir\x9ed\x14\xb2n\xc8\xdc\x0f\xd95\xc7;W\x9f\x1e\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x94i\x19\xdd^]\xfb\x1a\xfa@G\x03\xb9\xfa\xea\x8c\xee5\xd0\rp\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4i4\x92\xa5\xc5\x13\x96\xa4\x82\x88\x16i\xcc\xf6\xd8\xd7y\xf0\tQ\x89\x12\xbfPP:\xe3\x03\x80\x00\u07d4i=\x83\xbe\tE\x9e\xf89\v.0\xd7\xf7\u008d\xe4\xb4(N\x89lk\x93[\x8b\xbd@\x00\x00\u07d4iQp\x83\xe3\x03\xd4\xfb\xb6\xc2\x11E\x14!]i\xbcF\xa2\x99\x89\x05k\xc7^-c\x10\x00\x00\u07d4iUPel\xbf\x90\xb7]\x92\xad\x91\"\xd9\r#\xcah\xcaM\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94iX\xf8;\xb2\xfd\xfb'\xce\x04\t\xcd\x03\xf9\xc5\xed\xbfL\xbe\u074a\x04<3\xc1\x93ud\x80\x00\x00\u0794i[\x0fRBu7\x01\xb2d\xa6pq\xa2\u0708\b6\xb8\u06c8\u3601\x1b\xech\x00\x00\xe0\x94i[L\xce\bXV\xd9\xe1\xf9\xff>y\x94 #5\x9e_\xbc\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94if\x06:\xa5\xde\x1d\xb5\xc6q\xf3\xddi\x9dZ\xbe!>\xe9\x02\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4it\u0224\x14\u03ae\xfd<.M\xfd\xbe\xf40V\x8d\x9a\x96\v\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\xe0\x94iximQP\xa9\xa2cQ?\x8ft\u0196\xf8\xb19|\xab\x8a\x01g\xf4\x82\xd3\u0171\xc0\x00\x00\xe0\x94iy{\xfb\x12\u027e\u0582\xb9\x1f\xbcY5\x91\xd5\xe4\x027(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94i\u007fUSk\xf8Z\xdaQ\x84\x1f\x02\x87b:\x9f\x0e\u041a\x17\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4i\x82\xfe\x8a\x86~\x93\xebJ\v\xd0QX\x93\x99\xf2\xec\x9aR\x92\x89lk\x93[\x8b\xbd@\x00\x00\u07d4i\x8a\x8ao\x01\xf9\xabh/c|yi\xbe\x88_lS\x02\xbf\x89\x01\r:\xa56\xe2\x94\x00\x00\u07d4i\x8a\xb9\xa2\xf33\x81\xe0|\fGC=\r!\xd6\xf36\xb1'\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4i\x94\xfb21\xd7\xe4\x1dI\x1a\x9dh\xd1\xfaL\xae,\xc1Y`\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\x9c\x9e\xe4q\x95Q\x1f5\xf8b\xcaL\"\xfd5\xae\x8f\xfb\xf4\x89\x04V9\x18$O@\x00\x00\u07d4i\x9f\xc6\u058aGuW<\x1d\u036e\xc80\xfe\xfdP9|N\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4i\xaf(\xb0tl\xac\r\xa1p\x84\xb99\x8c^6\xbb:\r\xf2\x896w\x03n\xdf\n\xf6\x00\x00\u07d4i\xb8\x0e\xd9\x0f\x84\x83J\xfa?\xf8.\xb9dp;V\tw\u0589\x01s\x17\x90SM\xf2\x00\x00\xe0\x94i\xb8\x1dY\x81\x14\x1e\u01e7\x14\x10`\xdf\u03cf5\x99\xff\xc6>\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4i\xbc\xfc\x1dC\xb4\xba\x19\xde{'K\xdf\xfb5\x13\x94\x12\xd3\u05c95e\x9e\xf9?\x0f\xc4\x00\x00\u07d4i\xbd%\xad\xe1\xa34lY\xc4\xe90\xdb*\x9dq^\xf0\xa2z\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\xc0\x8dtGT\xdep\x9c\xe9n\x15\xae\r\x1d9[:\"c\x8965\u026d\xc5\u07a0\x00\x00\u07d4i\xc2\xd85\xf1>\xe9\x05\x80@\x8ej2\x83\xc8\u0326\xa44\xa2\x89#\x8f\xd4,\\\xf0@\x00\x00\u07d4i\xc9N\a\u0129\xbe3\x84\xd9]\xfa<\xb9)\x00Q\x87;{\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4i\xcb>!S\x99\x8d\x86\xe5\xee \xc1\xfc\u0466\xba\uec86?\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4i\u04ddQ\b\x89\xe5R\xa3\x96\x13[\xfc\xdb\x06\xe3~8v3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94i\u064f8\xa3\xba=\xbc\x01\xfa\\,\x14'\xd8b\x83//p\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94i\xe2\xe2\xe7\x040|\xcc[\\\xa3\xf1d\xfe\xce.\xa7\xb2\xe5\x12\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4i\xffB\x90t\u02dblc\xbc\x91B\x84\xbc\xe5\xf0\xc8\xfb\xf7\u0409\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4i\xff\x89\x01\xb5Av?\x81|_)\x98\xf0-\xcf\xc1\xdf)\x97\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4j\x02:\xf5}XM\x84^i\x876\xf10\u06dd\xb4\r\xfa\x9a\x89\x05[ \x1c\x89\x00\x98\x00\x00\u07d4j\x04\xf5\xd5?\xc0\xf5\x15\xbe\x94+\x8f\x12\xa9\xcbz\xb0\xf3\x97x\x89\xa9\xaa\xb3E\x9b\xe1\x94\x00\x00\u07d4j\x05\xb2\x1cO\x17\xf9\xd7?_\xb2\xb0\u02c9\xffSV\xa6\xcc~\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\xe0\x94j\x0f\x05`f\xc2\xd5f(\x85\x02s\xd7\xec\xb7\xf8\xe6\xe9\x12\x9e\x8a\x01\x0f\r)<\u01e5\x88\x00\x00\u07d4j\x13\xd5\xe3,\x1f\xd2m~\x91\xffn\x051`\xa8\x9b,\x8a\xad\x89\x02\xe6/ \xa6\x9b\xe4\x00\x00\u07d4j.\x86F\x9a[\xf3|\xee\x82\xe8\x8bL8c\x89](\xfc\xaf\x89\x1c\"\x92f8[\xbc\x00\x00\u07d4j6\x94BL|\u01b8\xbc\u067c\u02baT\f\xc1\xf5\xdf\x18\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94jB\u0297\x1cex\u056d\xe2\x95\xc3\xe7\xf4\xad3\x1d\xd3BN\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4jD\xaf\x96\xb3\xf02\xaed\x1b\xebg\xf4\xb6\xc83B\xd3|]\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4jL\x89\a\xb6\x00$\x80W\xb1\xe4cT\xb1\x9b\u0705\x9c\x99\x1a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4jQNbB\xf6\xb6\x8c\x13~\x97\xfe\xa1\u73b5U\xa7\xe5\xf7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4jS\xd4\x1a\xe4\xa7R\xb2\x1a\xbe\xd57FI\x95:Q=\xe5\xe5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4jaY\aJ\xb5s\xe0\xeeX\x1f\x0f=\xf2\u05a5\x94b\x9bt\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4jc7\x83?\x8fjk\xf1\f\xa7\xec!\xaa\x81\x0e\xd4D\xf4\u02c97\xbd$4\\\xe8\xa4\x00\x00\u07d4jcS\xb9qX\x9f\x18\xf2\x95\\\xba(\xab\xe8\xac\xcejWa\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4jc\xfc\x89\xab\xc7\xf3n(-\x80x{{\x04\xaf\xd6U>q\x89\b\xacr0H\x9e\x80\x00\x00\u07d4jg\x9e7\x8f\xdc\xe6\xbf\xd9\u007f\xe6/\x04)Z$\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4j\x8c\xea-\xe8J\x8d\xf9\x97\xfd?\x84\xe3\b=\x93\xdeW\u0369\x89\x05k\xe0<\xa3\xe4}\x80\x00\xe0\x94j\x97Xt;`>\xea:\xa0RKB\x88\x97#\xc4\x159H\x8a\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4j\xa5s/;\x86\xfb\x8c\x81\xef\xbek[G\xb5cs\v\x06\u020965\u026d\xc5\u07a0\x00\x00\u07d4j\xb3#\xaePV\xed\nE0r\u016b\xe2\xe4/\xcf]q9\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4j\xb5\xb4\xc4\x1c\u0778)i\f/\xda\u007f \xc8^b\x9d\xd5\u0549d\u052fqL2\x90\x00\x00\u07d4j\xc4\x0fS-\xfe\xe5\x11\x81\x17\u04ad5-\xa7}Om\xa2\u0209\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4j\xc4\u053e-\xb0\u065d\xa3\xfa\xaa\xf7RZ\xf2\x82\x05\x1dj\x90\x89\x04X\xcaX\xa9b\xb2\x80\x00\u07d4j\xcd\u0723\xcd+I\x90\xe2\\\xd6\\$\x14\x9d\t\x12\t\x9ey\x89\xa2\xa1\xe0|\x9fl\x90\x80\x00\u07d4j\xd9\v\xe2R\xd9\xcdFM\x99\x81%\xfa\xb6\x93\x06\v\xa8\xe4)\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4j\u0753!\x93\xcd8IJ\xa3\xf0:\xec\xccKz\xb7\xfa\xbc\xa2\x89\x04\xdbs%Gc\x00\x00\x00\xe0\x94j\xe5\u007f'\x91|V*\x13*M\x1b\xf7\xec\n\u01c5\x83)&\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4j\xeb\x9ftt.\xa4\x91\x81=\xbb\xf0\xd6\xfc\xde\x1a\x13\x1dM\xb3\x89\x17\xe5T0\x8a\xa00\x00\x00\u07d4j\xf25\u04bb\xe0P\xe6)\x16\x15\xb7\x1c\xa5\x82\x96X\x81\x01B\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4j\xf6\xc7\xee\x99\xdf'\x1b\xa1[\xf3\x84\xc0\xb7d\xad\xcbM\xa1\x82\x8965f3\xeb\xd8\xea\x00\x00\u07d4j\xf8\xe5Yih,q_H\xadO\xc0\xfb\xb6~\xb5\x97\x95\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4j\xf9@\xf6>\u0278\xd8v'*\u0296\xfe\xf6\\\xda\xce\xcd\ua262\xa1]\tQ\x9b\xe0\x00\x00\u07d4j\xf9\xf0\xdf\uebbb_d\xbf\x91\xabw\x16i\xbf\x05)US\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4j\xff\x14f\xc2b6u\xe3\xcb\x0eu\xe4#\xd3z%\xe4B\xeb\x89]\u0212\xaa\x111\xc8\x00\x00\xe0\x94k\r\xa2Z\xf2g\u05c3l\"k\xca\xe8\xd8r\xd2\xceR\xc9A\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4k\x10\xf8\xf8\xb3\xe3\xb6\r\xe9\n\xa1-\x15_\x9f\xf5\xff\xb2,P\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\x17Y\x8a\x8e\xf5Oyz\xe5\x15\u0336Q}\x18Y\xbf\x80\x11\x89\x05k\xc7^-c\x10\x00\x00\u07d4k \xc0\x80`jy\xc7;\xd8\xe7[\x11qzN\x8d\xb3\xf1\u00c9\x10?sX\x03\xf0\x14\x00\x00\u07d4k\"\x84D\x02!\xce\x16\xa88-\xe5\xff\x02)G\"i\xde\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4k0\xf1\x829\x10\xb8m:\xcbZj\xfc\x9d\xef\xb6\xf3\xa3\v\xf8\x89\u3bb5sr@\xa0\x00\x00\u07d4k8\u0784\x1f\xad\u007fS\xfe\x02\xda\x11[\xd8j\xaff$f\xbd\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4kK\x99\xcb?\xa9\xf7\xb7L\u3903\x17\xb1\xcd\x13\t\n\x1az\x89\x03\x1b2~i]\xe2\x00\x00\u07d4kZ\xe7\xbfx\xecu\xe9\f\xb5\x03\xc7x\xcc\u04f2KO\x1a\xaf\x89+^:\xf1k\x18\x80\x00\x00\u07d4kc\xa2\u07f2\xbc\xd0\xca\xec\x00\"\xb8\x8b\xe3\f\x14Q\xeaV\xaa\x89+\xdbk\xf9\x1f\u007fL\x80\x00\u07d4kew\xf3\x90\x9aMm\xe0\xf4\x11R-Ep8d\x004\\\x89e\xea=\xb7UF`\x00\x00\u07d4kr\xa8\xf0a\xcf\xe6\x99j\xd4G\xd3\xc7,(\xc0\xc0\x8a\xb3\xa7\x89\xe7\x8cj\u01d9\x12b\x00\x00\u07d4kv\rHw\xe6\xa6'\xc1\xc9g\xbe\xe4Q\xa8P}\xdd\u06eb\x891T\xc9r\x9d\x05x\x00\x00\u07d4k\x83\xba\xe7\xb5e$EXU[\xcfK\xa8\xda \x11\x89\x1c\x17\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\x92]\xd5\xd8\xeda2\xabm\b`\xb8,D\xe1\xa5\x1f\x1f\xee\x89P; >\x9f\xba \x00\x00\xe0\x94k\x94a]\xb7Pej\u00cc~\x1c\xf2\x9a\x9d\x13g\u007fN\x15\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4k\x95\x1aC'N\xea\xfc\x8a\t\x03\xb0\xaf.\xc9+\xf1\xef\xc89\x89\x05k\xc7^-c\x10\x00\x00\u07d4k\x99%!\xec\x85#p\x84\x8a\u0597\xcc-\xf6Nc\xcc\x06\xff\x8965\u026d\xc5\u07a0\x00\x00\u07d4k\xa8\xf7\xe2_\xc2\xd8qa\x8e$\xe4\x01\x84\x19\x917\xf9\xf6\xaa\x89\x15\xafd\x86\x9ak\xc2\x00\x00\u07d4k\xa9\xb2\x1b5\x10k\xe1Y\xd1\xc1\xc2ez\xc5l\u049f\xfdD\x89\xf2\xdc}G\xf1V\x00\x00\x00\u07d4k\xafz*\x02\xaex\x80\x1e\x89\x04\xadz\xc0Q\b\xfcV\xcf\xf6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94k\xb2\xac\xa2?\xa1bm\x18\xef\xd6w\u007f\xb9}\xb0-\x8e\n\xe4\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4k\xb4\xa6a\xa3:q\xd4$\u051b\xb5\xdf(b.\xd4\xdf\xfc\xf4\x89\",\x8e\xb3\xfff@\x00\x00\u07d4k\xb5\b\x13\x14j\x9a\xddB\xee\"\x03\x8c\x9f\x1fti\xd4\u007fG\x89\n\xdaUGK\x814\x00\x00\u07d4k\xbc?5\x8af\x8d\u0461\x1f\x03\x80\xf3\xf71\bBj\xbdJ\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4k\xbd\x1eq\x93\x90\xe6\xb9\x10C\xf8\xb6\xb9\u07c9\x8e\xa8\x00\x1b4\x89llO\xa6\xc3\xdaX\x80\x00\u07d4k\xc8Z\xcdY(r.\xf5\tS1\xee\x88\xf4\x84\xb8\u03c3W\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4k\xd3\xe5\x9f#\x9f\xaf\xe4wk\xb9\xbd\xddk\ue0fa]\x9d\x9f\x8965\u026d\xc5\u07a0\x00\x00\u07d4k\xd4W\xad\xe0Qy]\xf3\xf2F\\89\xae\xd3\xc5\xde\xe9x\x8964\xbf9\xab\x98x\x80\x00\u07d4k\xe1c\x13d>\xbc\x91\xff\x9b\xb1\xa2\xe1\x16\xb8T\xea\x93:E\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4k\xe7Y^\xa0\xf0hH\x9a'\x01\xecFI\x15\x8d\xdcC\xe1x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4k\xe9\x03\x0e\xe6\xe2\xfb\u0111\xac\xa3\xde@\"\xd3\x01w+{}\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94k\xec1\x1a\xd0P\b\xb4\xaf5<\x95\x8c@\xbd\x06s\x9a?\xf3\x8a\x03w\xf6*\x0f\nbp\x00\x00\u07d4k\xf7\xb3\xc0e\xf2\xc1\xe7\xc6\xeb\t+\xa0\xd1Pf\xf3\x93\u0478\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4k\xf8o\x1e/+\x802\xa9\\Mw8\xa1\t\xd3\xd0\xed\x81\x04\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4l\x05\xe3N^\xf2\xf4.\u041d\xef\xf1\x02l\xd6k\xcbi`\xbb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4l\b\xa6\xdc\x01s\xc74)U\xd1\xd3\xf2\xc0e\xd6/\x83\xae\u01c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4l\n\xe9\xf0C\xc84\xd4Bq\xf14\x06Y=\xfe\tO8\x9f\x89RD*\xe13\xb6*\x80\x00\u07d4l\f\xc9\x17\xcb\xee}|\t\x97c\xf1Nd\xdf}4\xe2\xbf\t\x89\r\x8drkqw\xa8\x00\x00\xe0\x94l\x0eq/@\\Yr_\xe8)\xe9wK\xf4\xdf\u007fM\xd9e\x8a\f(h\x88\x9c\xa6\x8aD\x00\x00\xe0\x94l\x10\x12\x05\xb3#\xd7uD\xd6\xdcR\xaf7\xac\xa3\xce\xc6\xf7\xf1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4l\x15\xec5 \xbf\x8e\xbb\xc8 \xbd\x0f\xf1\x97x7T\x94\u03dd\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\xe0\x94l\x1d\xdd3\xc8\x19f\u0706!w`q\xa4\x12\x94\x82\xf2\xc6_\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4l%2\u007f\x8d\u02f2\xf4^V\x1e\x86\xe3]\x88P\xe5:\xb0Y\x89;\xcd\xf9\xba\xfe\xf2\xf0\x00\x00\u07d4l.\x9b\xe6\u052bE\x0f\xd1%1\xf3?\x02\x8caFt\xf1\x97\x89\xc2\x12z\xf8X\xdap\x00\x00\u07d4l5\x9eX\xa1=Ex\xa93\x8e3\\g\xe7c\x9f_\xb4\u05c9\v\xd1[\x94\xfc\x8b(\x00\x00\u07d4l=\x18pA&\xaa\x99\xee3B\xce`\xf5\xd4\xc8_\x18g\u0349\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4lGK\xc6jTx\x00f\xaaOQ.\xef\xa7s\xab\xf9\x19\u01c9\x05\x18\x83\x15\xf7v\xb8\x00\x00\u07d4lNBn\x8d\xc0\x05\u07e3Ql\xb8\xa6\x80\xb0.\ua56e\x8e\x89Hz\x9a0E9D\x00\x00\u07d4lR\xcf\b\x95\xbb5\xe6V\x16\x1eM\xc4j\xe0\xe9m\xd3\xe6,\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4lT\"\xfbK\x14\xe6\u064b`\x91\xfd\xecq\xf1\xf0\x86@A\x9d\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4l\\:T\u0367\xc2\xf1\x18\xed\xbaCN\xd8\x1en\xbb\x11\xddz\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4lc\xf8EV\u0490\xbf\u0359\xe44\ue657\xbf\xd7yWz\x89lk\x93[\x8b\xbd@\x00\x00\u07d4lc\xfc\x85\x02\x9a&T\u05db+\xeaM\xe3I\xe4REw\u0149#\xc7W\a+\x8d\xd0\x00\x00\u07d4led\xe5\xc9\xc2N\xaa\xa7D\xc9\xc7\xc9h\xc9\xe2\xc9\xf1\xfb\xae\x89I\x9bB\xa2\x119d\x00\x00\xe0\x94lg\xd6\xdb\x1d\x03Ql\x12\x8b\x8f\xf24\xbf=I\xb2m)A\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4lg\xe0\u05f6.*\bPiE\xa5\xdf\xe3\x82c3\x9f\x1f\"\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4lj\xa0\xd3\vdr\x19\x90\xb9PJ\x86?\xa0\xbf\xb5\xe5}\xa7\x89\x92^\x06\xee\xc9r\xb0\x00\x00\u07d4lqJX\xff\xf6\xe9}\x14\xb8\xa5\xe3\x05\xeb$@eh\x8b\xbd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4l\x80\rKI\xba\a%\x04`\xf9\x93\xb8\xcb\xe0\v&j%S\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4l\x80\x8c\xab\xb8\xff_\xbbc\x12\xd9\xc8\xe8J\xf8\xcf\x12\xef\bu\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94l\x82 )!\x8a\xc8\xe9\x8a&\f\x1e\x06@)4\x889\x87[\x8a\x01\x0f\x97\xb7\x87\xe1\xe3\b\x00\x00\u07d4l\x84\u02e7|m\xb4\xf7\xf9\x0e\xf1=^\xe2\x1e\x8c\xfc\u007f\x83\x14\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94l\x86\x87\xe3Aw\x10\xbb\x8a\x93U\x90!\xa1F\x9ej\x86\xbcw\x8a\x02[-\xa2x\xd9k{\x80\x00\xe0\x94l\x88,'s,\xef\\|\x13\xa6\x86\xf0\xa2\xeawUZ\u0089\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4l\xa5\xde\x00\x81}\xe0\xce\xdc\xe5\xfd\x00\x01(\xde\xde\x12d\x8b<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4l\xa6\xa12\xce\x1c\u0488\xbe\xe3\x0e\xc7\xcf\xef\xfb\x85\xc1\xf5\nT\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94l\xb1\x1e\xcb2\xd3\u0382\x96\x011\x066\xf5\xa1\f\xf7\u03db_\x8a\x04?\u851c8\x01\xf5\x00\x00\u07d4l\xc1\xc8x\xfal\u078a\x9a\v\x83\x11$~t\x1eFB\xfem\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94l\xcb\x03\xac\xf7\xf5<\xe8z\xad\xcc!\xa9\x93-\xe9\x15\xf8\x98\x04\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4l\xd2\x12\xae\xe0N\x01?=*\xba\u04a0#`k\xfb\\j\u01c9lj\xccg\u05f1\xd4\x00\x00\u07d4l\xd2(\xdcq!i0\u007f\xe2|\xebtw\xb4\x8c\xfc\x82r\xe5\x89\x044\xea\x94\u06caP\x00\x00\u07d4l\xe1\xb0\xf6\xad\xc4pQ\xe8\xab8\xb3\x9e\xdbA\x86\xb0;\xab\u0309Ay\x97\x94\xcd$\xcc\x00\x00\u07d4l\xea\xe3s=\x8f\xa4=l\xd8\f\x1a\x96\xe8\xeb\x93\x10\x9c\x83\xb7\x89\x10'\x94\xad \xdah\x00\x00\u07d4m\x05i\xe5U\x8f\xc7\xdf'f\xf2\xba\x15\u070a\xef\xfc[\xebu\x89\xd8\xe6\x00\x1el0+\x00\x00\u07d4m\x12\x0f\f\xaa\xe4O\xd9K\xca\xfeU\xe2\xe2y\uf5ba\\z\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4m\x14V\xff\xf0\x10N\xe8D\xa31G7\x8438\xd2L\xd6l\x89\a\xb0l\xe8\u007f\xddh\x00\x00\u07d4m \xef\x97\x04g\nP\v\xb2i\xb5\x83.\x85\x98\x02\x04\x9f\x01\x89\a\f\x1c\xc7;\x00\xc8\x00\x00\xe0\x94m/\x97g4\xb9\xd0\a\r\x18\x83\xcfz\u02b8\xb3\xe4\x92\x0f\xc1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4m9\xa9\u93c1\xf7i\xd7:\xad,\xea\xd2v\xac\x13\x87\xba\xbe\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4m;x6\xa2\xb9\u0619r\x1aM#{R#\x85\xdc\xe8\xdf\u034966\xc2^f\xec\xe7\x00\x00\u07d4m?+\xa8V\u033b\x027\xfava\x15k\x14\xb0\x13\xf2\x12@\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94m@\b\xb4\xa8\x88\xa8&\xf2H\xeej\v\r\xfd\xe9\xf92\x10\xb9\x8a\x01'\xfc\xb8\xaf\xae \xd0\x00\x00\u07d4m@\xca'\x82m\x97s\x1b>\x86\xef\xfc\u05f9*Aa\xfe\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4mD\x97J1\u0447\xed\xa1m\xddG\xb9\xc7\xecP\x02\xd6\x1f\xbe\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94mK\\\x05\xd0j \x95~\x17H\xabm\xf2\x06\xf3C\xf9/\x01\x8a\x02\x1f6\x06\x99\xbf\x82_\x80\x00\xe0\x94mL\xbf=\x82\x84\x83:\xe9\x93D0>\b\xb4\xd6\x14\xbf\xda;\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4mY\xb2\x1c\xd0\xe2t\x88\x04\u066b\xe0d\xea\u00be\xf0\xc9_'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4mc\u04ce\xe8\xb9\x0e\x0en\xd8\xf1\x92\xed\xa0Q\xb2\u05a5\x8b\xfd\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4mf4\xb5\xb8\xa4\x01\x95\xd9I\x02z\xf4\x82\x88\x02\t,\ued89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94m}\x1c\x94\x95\x11\xf8\x83\x03\x80\x8c`\xc5\xea\x06@\xfc\xc0&\x83\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4m\x84m\xc1&W\xe9\x1a\xf2P\bQ\x9c>\x85\u007fQp}\u0589\xf8\xd3\v\xc9#B\xf8\x00\x00\u07d4m\x91\x93\x99k\x19F\x17!\x11\x06\xd1c^\xb2l\u0136ll\x89\x15\xaa\x1e~\x9d\xd5\x1c\x00\x00\u07d4m\x99\x97P\x98\x82\x02~\xa9G#\x14$\xbe\xde\xde)e\u043a\x89l\x81\u01f3\x11\x95\xe0\x00\x00\u07d4m\xa0\xed\x8f\x1di3\x9f\x05\x9f*\x0e\x02G\x1c\xb4O\xb8\u00fb\x892\xbc8\xbbc\xa8\x16\x00\x00\u07d4m\xb7+\xfdC\xfe\xf4e\xcaV2\xb4Z\xabra@N\x13\xbf\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94m\xbe\x8a\xbf\xa1t(\x06&9\x817\x1b\xf3\xd3U\x90\x80kn\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4m\xc3\xf9+\xaa\x1d!\u06b78+\x892a\xa05o\xa7\xc1\x87\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4m\xc7\x05:q\x86\x16\xcf\u01cb\xeec\x82\xeeQ\xad\xd0\xc7\x030\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94m\xcc~d\xfc\xaf\xcb\xc2\xdcl\x0e^f,\xb3G\xbf\xfc\xd7\x02\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4m\xda_x\x8alh\x8d\u07d2\x1f\xa3\x85.\xb6\xd6\xc6\xc6)f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4m\xdb`\x92w\x9dXB\xea\xd3x\xe2\x1e\x81 \xfdLk\xc12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4m\xdf\xefc\x91U\u06ab\n\\\xb4\x95:\xa8\u016f\xaa\x88\x04S\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4m\xe0/-\xd6~\xfd\xb794\x02\xfa\x9e\xaa\xcb\xcfX\x9d.V\x89@\x13\x8b\x91~\u07f8\x00\x00\u07d4m\u4d418\\\xf7\xfc\x9f\xe8\xc7}\x13\x1f\xe2\xeew$\xc7j\x89})\x97s=\xcc\xe4\x00\x00\u07d4m\xe4\xd1R\x19\x18/\xaf:\xa2\xc5\xd4\xd2Y_\xf20\x91\xa7'\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4m\xed\xf6.t?M,*K\x87\xa7\x87\xf5BJz\xeb9<\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4m\xf2Of\x85\xa6/y\x1b\xa37\xbf?\xf6~\x91\xf3\u053c:\x89ukI\xd4\nH\x18\x00\x00\u07d4m\xf5\xc8O{\x90\x9a\xab>a\xfe\x0e\xcb\x1b;\xf2`\"*\u0489\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4m\xff\x90\xe6\xdc5\x9d%\x90\x88+\x14\x83\xed\xbc\xf8\x87\xc0\xe4#\x8965\u026d\xc5\u07a0\x00\x00\u07d4n\x01\xe4\xadV\x9c\x95\xd0\a\xad\xa3\r^-\xb1(\x88I\"\x94\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\a;f\u0478\xc6gD\u0600\x96\xa8\u0759\xec~\x02(\u0689\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\x0e\xe7\x06\x12\xc9v(}I\x9d\u07e6\xc0\xdc\xc1,\x06\xde\xea\x89\a\v\u0579V!F\x00\x00\xe0\x94n\x12\xb5\x1e\"[JCr\xe5\x9a\u05e2\xa1\xa1>\xa3\u04e17\x8a\x03\x00F\xc8\xccw_\x04\x00\x00\u07d4n\x1a\x04l\xaf[JW\xf4\xfdK\xc1sb!&\xb4\xe2\xfd\x86\x89a\t=|,m8\x00\x00\u07d4n\x1e\xa4\xb1\x83\xe2R\u027bwg\xa0\x06\u05346\x96\u02ca\xe9\x89\x0f\xf3x<\x85\xee\u0400\x00\u07d4n%[p\n\xe7\x13\x8aK\xac\xf2(\x88\xa9\xe2\xc0\n(^\xec\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n'\n\xd5)\xf1\xf0\xb8\xd9\xcbm$'\xec\x1b~-\xc6Jt\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4n.\xab\x85\u0709\xfe)\xdc\n\xa1\x852G\u06b4:R=V\x89\x04V9\x18$O@\x00\x00\u07d4n:Q\xdbt=3M/\xe8\x82$\xb5\xfe|\x00\x8e\x80\xe6$\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4nL*\xb7\xdb\x02i9\xdb\u04fch8J\xf6`\xa6\x18\x16\xb2\x89\t\r\x97/22<\x00\x00\u07d4nM.9\u0203f)\u5d07\xb1\x91\x8af\x9a\xeb\u07556\x8965\u026d\xc5\u07a0\x00\x00\u07d4n\\-\x9b\x1cTj\x86\xee\xfd]\nQ \xc9\xe4\xe70\x19\x0e\x89\n\xd2\x01\xa6yO\xf8\x00\x00\u07d4n`\xae\u19cf\x8e\u068bBLs\xe3S5J\xe6|0B\x89\xbd5\xa4\x8d\x99\x19\xe6\x00\x00\u07d4nd\xe6\x12\x9f\"N7\x8c\x0ensj~z\x06\xc2\x11\xe9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4nm[\xbb\xb9\x05;\x89\xd7D\xa2s\x16\u00a7\xb8\xc0\x9bT}\x891Rq\n\x02>m\x80\x00\u07d4nr\xb2\xa1\x18j\x8e)\x16T;\x1c\xb3jh\x87\x0e\xa5\u0457\x89\n\x15D\xbe\x87\x9e\xa8\x00\x00\u07d4nv\x1e\xaa\x0f4_w{TA\xb7:\x0f\xa5\xb5k\x85\xf2-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4ny\xed\u0504[\anL\u060d\x18\x8bnC-\xd9?5\xaa\x893\xc5I\x901r\f\x00\x00\u07d4n\x82\x12\xb7\"\xaf\xd4\b\xa7\xa7>\xd3\xe29^\xe6EJ\x030\x89\b\x9e\x91y\x94\xf7\x1c\x00\x00\u07d4n\x84\x87m\xbb\x95\xc4\vfV\xe4+\xa9\xae\xa0\x8a\x99;T\u0709;\xbc`\xe3\xb6\u02fe\x00\x00\u07d4n\x84\xc2\xfd\x18\xd8\tW\x14\xa9h\x17\x18\x9c\xa2\x1c\xcab\xba\xb1\x89\x12{lp&!\u0340\x00\u07d4n\x86m\x03-@Z\xbd\xd6\\\xf6QA\x1d\x807\x96\xc2#\x11\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94n\x89\x9eY\xa9\xb4\x1a\xb7\xeaA\xdfu\x17\x86\x0f*\xcbY\xf4\xfd\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4n\x89\xc5\x1e\xa6\xde\x13\xe0l\xdct\x8bg\xc4A\x0f\u9f2b\x03\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\x8a&h\x9fz/\xde\xfd\x00\x9c\xba\xaaS\x10%4P\u06ba\x89o!7\x17\xba\xd8\xd3\x00\x00\u07d4n\x96\xfa\xed\xa3\x05C\x02\xc4_X\xf1a2L\x99\xa3\xee\xbbb\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4n\xb0\xa5\xa9\xae\x96\xd2,\xf0\x1d\x8f\xd6H;\x9f8\xf0\x8c,\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xb3\x81\x96\x17@@X&\x8f\f<\xff5\x96\xbf\xe9\x14\x8c\x1c\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94n\xb5W\x8ak\xb7\xc3!S\x19[\r\x80 \xa6\x91HR\xc0Y\x8a\x8b\u00ab\xf4\x02!\xf4\x80\x00\x00\u07d4n\xbb^iW\xaa\x82\x1e\xf6Y\xb6\x01\x8a9:PL\xaeDP\x89lk\x93[\x8b\xbd@\x00\x00\u07d4n\xbc\xf9\x95\u007f_\xc5\u916d\xd4u\";\x04\xb8\xc1Jz\xed\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4n\xc3e\x95q\xb1\x1f\x88\x9d\xd49\xbc\xd4\xd6u\x10\xa2[\xe5~\x89\x06\xaa\xf7\xc8Qm\f\x00\x00\u07d4n\u021b9\xf9\xf5'jU>\x8d\xa3\x0en\xc1z\xa4~\xef\u01c9\x18BO_\v\x1bN\x00\x00\u07d4n\xc9m\x13\xbd\xb2M\u01e5W)?\x02\x9e\x02\xddt\xb9zU\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xca\xef\xa6\xfc>\xe54bm\xb0,o\x85\xa0\u00d5W\x1ew\x89 \x86\xac5\x10R`\x00\x00\u07d4n\u04a1+\x02\xf8\u0188\u01f5\u04e6\xea\x14\xd66\x87\u06b3\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4n\u0604E\x9f\x80\x9d\xfa\x10\x16\xe7p\xed\xaf>\x9f\xefF\xfa0\x89\xb8R\xd6x \x93\xf1\x00\x00\xe0\x94n\xdf\u007fR\x83r\\\x95>\xe6C\x17\xf6a\x88\xaf\x11\x84\xb03\x8a\x01\xb4d1\x1dE\xa6\x88\x00\x00\u07d4n\xe8\xaa\xd7\xe0\xa0e\u0605-|;\x9an_\xdcK\xf5\f\x00\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4n\xef\u0705\x0e\x87\xb7\x15\xc7'\x91w<\x03\x16\xc3U\x9bX\xa4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4n\xf9\xe8\u0276!}Vv\x9a\xf9}\xbb\x1c\x8e\x1b\x8b\xe7\x99\u0489\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4n\xfb\xa8\xfb*\u0176s\a)\xa9r\xec\"D&\xa2\x87\u00ed\x89\x0fY\x85\xfb\xcb\xe1h\x00\x00\xe0\x94n\xfd\x90\xb55\xe0\v\xbd\x88\x9f\xda~\x9c1\x84\xf8y\xa1Q\u06ca\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4o\x05\x16f\xcbO{\u04b1\x90r!\xb8)\xb5U\u05e3\xdbt\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4o\x0e\xdd#\xbc\xd8_`\x15\xf9(\x9c(\x84\x1f\xe0L\x83\xef\xeb\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4o\x13zq\xa6\xf1\x97\xdf,\xbb\xf0\x10\u073d\x89a\t=|,m8\x00\x00\u07d4p\x10\xbe-\xf5{\u042b\x9a\xe8\x19l\xd5\n\xb0\xc5!\xab\xa9\xf9\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4p#\xc7\tV\xe0J\x92\xd7\x00%\xaa\u0497\xb59\xaf5Xi\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p%\x96]+\x88\xda\x19}DY\xbe=\xc98cD\xcc\x1f1\x89l\xb7\xe7Hg\xd5\xe6\x00\x00\u07d4p(\x02\xf3m\x00%\x0f\xabS\xad\xbc\u0596\xf0\x17oc\x8aI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4pH\x19\xd2\xe4Mn\xd1\xda%\xbf\u0384\u011f\u0322V\x13\xe5\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4pJn\xb4\x1b\xa3O\x13\xad\xdd\xe7\xd2\xdb}\xf0I\x15\u01e2!\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4pJ\xb1\x15\r^\x10\xf5\xe3I\x95\b\xf0\xbfpe\x0f\x02\x8dK\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4pJ\xe2\x1dv-n\x1d\xde(\xc25\xd11\x04Yr6\xdb\x1a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4pM$<)x\xe4l,\x86\xad\xbe\xcd$n;)_\xf63\x89m\x12\x1b\xeb\xf7\x95\xf0\x00\x00\u07d4pM]\xe4\x84m9\xb5<\xd2\x1d\x1cI\xf0\x96\xdb\\\x19\xba)\x89\b=lz\xabc`\x00\x00\u07d4p]\xdd85T\x82\xb8\xc7\u04f5\x15\xbd\xa1P\r\xd7\u05e8\x17\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94pan(\x92\xfa&\x97\x05\xb2\x04k\x8f\xe3\xe7/\xa5X\x16\u04ca\x04<3\xc1\x93ud\x80\x00\x00\u07d4pg\x0f\xbb\x05\xd30\x14DK\x8d\x1e\x8ew\x00%\x8b\x8c\xaam\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\x81\xfak\xaa\xd6\u03f7\xf5\x1b,\xca\x16\xfb\x89p\x99\x1ad\xba\x89\f\xae\xc0\x05\xf6\xc0\xf6\x80\x00\xe0\x94p\x85\xae~~M\x93!\x97\xb5\u01c5\x8c\x00\xa3gF&\xb7\xa5\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4p\x86\xb4\xbd\xe3\xe3]J\xeb$\xb8%\xf1\xa2\x15\xf9\x9d\x85\xf7E\x89lh\xcc\u041b\x02,\x00\x00\u07d4p\x8a*\xf4%\u03b0\x1e\x87\xff\xc1\xbeT\xc0\xf52\xb2\x0e\xac\u0589\aE\u0503\xb1\xf5\xa1\x80\x00\u07d4p\x8e\xa7\a\xba\xe45\u007f\x1e\xbe\xa9Y\u00e2P\xac\u05aa!\xb3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794p\x8f\xa1\x1f\xe3=\x85\xad\x1b\xef\u02ee8\x18\xac\xb7\x1fj}~\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4p\x9101\x16\xd5\xf28\x9b##\x8bMej\x85\x96\u0644\u04c9;N~\x80\xaaX3\x00\x00\u07d4p\x99\xd1/n\xc6V\x89\x9b\x04\x9avW\x06]b\x99h\x92\u0209\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4p\x9f\xe9\xd2\xc1\xf1\xceB |\x95\x85\x04J`\x89\x9f5\x94/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\xa05I\xaaah\xe9~\x88\xa5\b3\nZ\v\xeatq\x1a\x89Hz\x9a0E9D\x00\x00\u07d4p\xa4\x06}D\x8c\xc2]\xc8\xe7\x0ee\x1c\xea|\xf8N\x92\x10\x9e\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4p\xab4\xbc\x17\xb6o\x9c;c\xf1Q'O*r|S\x92c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4p\xc2\x13H\x8a\x02\f<\xfb9\x01N\xf5\xbad\x04rK\u02a3\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4p\xd2^\xd2\u022d\xa5\x9c\b\x8c\xf7\r\xd2+\xf2\u06d3\xac\xc1\x8a\x899GEE\u4b7c\x00\x00\u07d4p\xe5\xe9\xdas_\xf0w$\x9d\u02da\xaf=\xb2\xa4\x8d\x94\x98\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4p\xfe\xe0\x8b\x00\xc6\xc2\xc0Jp\xc0\xce=\x92\u03ca\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u0794q\v\xe8\xfd^)\x18F\x8b\u2abe\xa8\r\x82\x845\u05d6\x12\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4q\x13]\x8f\x05\x96<\x90ZJ\a\x92)\t#Z\x89jR\ua262\xa1]\tQ\x9b\xe0\x00\x00\u07d4q\x1e\xcfw\xd7\x1b=\x0e\xa9\\\xe4u\x8a\xfe\u0379\xc11\a\x9d\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4q!?\xca14\x04 N\u02e8q\x97t\x1a\xa9\xdf\xe9c8\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94q+vQ\x02\x14\xdcb\x0fl:\x1d\u049a\xa2+\xf6\xd2\x14\xfb\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4q/\xf77\n\x13\xed6\ts\xfe\u071f\xf5\xd2\xc9:P^\x9e\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4q3\x84:x\xd99\u019dD\x86\xe1\x0e\xbc{`*4\x9f\xf7\x89\x11\xd5\xca\xcc\xe2\x1f\x84\x00\x00\u07d4qH\xae\xf32a\xd8\x03\x1f\xac?q\x82\xff5\x92\x8d\xafT\u0649\xdeB\xee\x15D\u0750\x00\x00\u07d4qcu\x8c\xbblLR^\x04\x14\xa4\n\x04\x9d\xcc\xcc\xe9\x19\xbb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4qh\xb3\xbb\x8c\x16s!\u067d\xb0#\xa6\xe9\xfd\x11\xaf\u026f\u0649a\t=|,m8\x00\x00\u07d4qirN\xe7\"q\xc54\xca\xd6B\x0f\xb0N\xe6D\u02c6\xfe\x89\x16<+@\u06e5R\x00\x00\u07d4qj\xd3\xc3:\x9b\x9a\n\x18\x96sW\x96\x9b\x94\xee}*\xbc\x10\x89\x1a!\x17\xfeA*H\x00\x00\xe0\x94qk\xa0\x1e\xad*\x91'\x065\xf9_%\xbf\xaf-\xd6\x10\xca#\x8a\ty\xe7\x01 V\xaax\x00\x00\u07d4qmP\u0320\x1e\x93\x85\x00\xe6B\x1c\xc0p\xc3P|g\u04c7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4qv,cg\x8c\x18\xd1\xc67\x8c\xe0h\xe6f8\x13\x15\x14~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4qxL\x10Q\x17\xc1\xf6\x895y\u007f\xe1Y\xab\xc7NC\xd1j\x89l\x81\u01f3\x11\x95\xe0\x00\x00\xe0\x94qyro\\q\xae\x1bm\x16\xa6\x84(\x17Nk4\xb26F\x8a\x01\x8e\xa2P\t|\xba\xf6\x00\x00\xe0\x94q|\xf9\xbe\xab680\x8d\xed~\x19^\f\x86\x13-\x16?\xed\x8a\x032n\xe6\xf8e\xf4\"\x00\x00\u07d4q\x80\xb8>\xe5WC\x17\xf2\x1c\x80r\xb1\x91\u0615\xd4aS\u00c9\x18\xef\xc8J\xd0\u01f0\x00\x00\u07d4q\x94kq\x17\xfc\x91^\xd1\a8_B\u065d\xda\xc62I\u0089lk\x93[\x8b\xbd@\x00\x00\xe0\x94q\x9e\x89\x1f\xbc\xc0\xa3>\x19\xc1-\xc0\xf0 9\xca\x05\xb8\x01\u07ca\x01OU8F:\x1bT\x00\x00\u07d4q\xc7#\n\x1d5\xbd\u0581\x9e\u0539\xa8\x8e\x94\xa0\xeb\a\x86\u0749\uc80b5=$\x14\x00\x00\u07d4q\xd2\xccm\x02W\x8ce\xf7\r\xf1\x1bH\xbe\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4r\x83\xcdFu\xdaX\u0116UaQ\xda\xfd\x80\xc7\xf9\x95\xd3\x18\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4r\x86\xe8\x9c\xd9\u078fz\x8a\x00\xc8o\xfd\xb59\x92\u0752Q\u0449i*\xe8\x89p\x81\xd0\x00\x00\u07d4r\x8f\x9a\xb0\x80\x15}\xb3\a1V\xdb\xca\x1a\x16\x9e\xf3\x17\x94\a\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4r\x94\xc9\x18\xb1\xae\xfbM%\x92~\xf9\u05d9\xe7\x1f\x93\xa2\x8e\x85\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94r\x94\uc763\x10\xbckK\xbd\xf5C\xb0\xefE\xab\xfc>\x1bM\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4r\x9a\xadF'tNS\xf5\xd6c\t\xaatD\x8b:\xcd\xf4o\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xa2\xfc\x86u\xfe\xb9r\xfaA\xb5\r\xff\u06fa\xe7\xfa*\u07f7\x89\x9a\xb4\xfcg\xb5(\xc8\x00\x00\u07d4r\xa8&\b&)G&\xa7[\xf3\x9c\u066a\x9e\a\xa3\xea\x14\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4r\xb0Yb\xfb*\u0549\xd6Z\xd1j\"U\x9e\xba\x14X\xf3\x87\x89\a?u\u0460\x85\xba\x00\x00\u07d4r\xb5c?\xe4w\xfeT.t/\xac\xfdi\f\x13xT\xf2\x16\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4r\xb7\xa0=\xda\x14\u029cf\x1a\x1dF\x9f\xd376\xf6s\xc8\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xb9\x04D\x0e\x90\xe7 \u05ac\x1c*\u05dc2\x1d\xcc\x1c\x1a\x86\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94r\xb9\nM\xc0\x97#\x94\x92\u0179w}\xcd\x1eR\xba+\xe2\u008a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4r\xbb'\u02d9\xf3\xe2\xc2\u03d0\xa9\x8fp}0\xe4\xa2\x01\xa0q\x89X\xe7\x92n\xe8X\xa0\x00\x00\xe0\x94r\xc0\x83\xbe\xad\xbd\xc2'\xc5\xfbC\x88\x15\x97\xe3.\x83\xc2`V\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4r\xcd\x04\x8a\x11\x05tH)\x83I-\xfb\x1b\xd2yB\xa6\x96\xba\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xd0=M\xfa\xb3P\f\xf8\x9b\x86\x86o\x15\xd4R\x8e\x14\xa1\x95\x89\xf3K\x82\xfd\x8e\x91 \x00\x00\u07d4r\u06bb[n\ud799\xbe\x91X\x88\xf6V\x80V8\x16\b\xf8\x89\vL\x96\xc5,\xb4\xfe\x80\x00\u07d4r\xfbI\u009d#\xa1\x89P\u0132\xdc\r\xdfA\x0fS-oS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4r\xfe\xaf\x12EyR9Td[\u007f\xaf\xff\x03x\xd1\xc8$.\x8965\u026d\xc5\u07a0\x00\x00\u07d4s\x01\xdcL\xf2mq\x86\xf2\xa1\x1b\xf8\xb0\x8b\xf2)F?d\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s\x04G\xf9|\xe9\xb2_\"\xba\x1a\xfb6\xdf'\xf9Xk\ub6c9,s\xc97t,P\x00\x00\u07d4s\x06\xde\x0e(\x8bV\xcf\u07d8~\xf0\xd3\xcc)f\a\x93\xf6\u0749\x1b\x8a\xbf\xb6.\xc8\xf6\x00\x00\xe0\x94s\r\x87c\u01a4\xfd\x82J\xb8\xb8Y\x16\x1e\xf7\xe3\xa9j\x12\x00\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4s\x12\x81sH\x95(\x01.v\xb4\x1a^(\u018b\xa4\xe3\xa9\u050965\u026d\xc5\u07a0\x00\x00\u07d4s\x13F\x12\bETUFTE\xa4Y\xb0l7s\xb0\xeb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s/\xea\xd6\x0f{\xfd\u05a9\xde\u0101%\xe3s]\xb1\xb6eO\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4sB#\xd2\u007f\xf2>Y\x06\xca\xed\"YW\x01\xbb4\x83\f\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4sG>r\x11Q\x10\xd0\xc3\xf1\x17\b\xf8nw\xbe+\xb0\x98<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4sRXm\x02\x1a\xd0\xcfw\xe0\xe9(@JY\xf3t\xffE\x82\x89\xb8Pz\x82\a( \x00\x00\u07d4sU\v\xebs+\xa9\u076f\xdaz\xe4\x06\xe1\x8f\u007f\xeb\x0f\x8b\xb2\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4s[\x97\xf2\xfc\x1b\xd2K\x12\an\xfa\xf3\xd1(\x80s\xd2\f\x8c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4s^2\x86f\xedV7\x14+3\x06\xb7|\xccT`\xe7,=\x89j\xb8\xf3xy\u0251\x00\x00\u07d4sc\u0350\xfb\xab[\xb8\u011a\xc2\x0f\xc6,9\x8f\xe6\xfbtL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4skDP=\xd2\xf6\xddTi\xffL[-\xb8\xeaO\xece\u0409\x11\x04\xeeu\x9f!\xe3\x00\x00\xe0\x94sk\xf1@,\x83\x80\x0f\x89>X1\x92X*\x13N\xb52\xe9\x8a\x02\x1e\x19\u0493\xc0\x1f&\x00\x00\xe0\x94s\x8c\xa9M\xb7\u038b\xe1\xc3\x05l\u0598\x8e\xb3v5\x9f3S\x8a\x05f[\x96\xcf5\xac\xf0\x00\x00\u07d4s\x91K\"\xfc/\x13\x15\x84$}\x82\xbeO\ucfd7\x8a\u053a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4s\x93'\t\xa9\u007f\x02\u024eQ\xb0\x911(e\x12#\x85\xae\x8e\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4s\x93\xcb\xe7\xf9\xba!e\xe5\xa7U5\x00\xb6\xe7]\xa3\xc3:\xbf\x89\x05k\xc7^-c\x10\x00\x00\u07d4s\xb4\u0519\xde?8\xbf5\xaa\xf7i\xa6\xe3\x18\xbcm\x126\x92\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94s\xbe\xddo\xda{\xa3'!\x85\b{cQ\xfc\x13=HN7\x8a\x01\x12&\xbf\x9d\xceYx\x00\x00\u07d4s\xbf\xe7q\x0f1\u02b9I\xb7\xa2`O\xbfR9\xce\xe7\x90\x15\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94s\u03c0\xae\x96\x88\xe1X\x0eh\xe7\x82\xcd\b\x11\xf7\xaaIM,\x8a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\xe0\x94s\xd7&\x9f\xf0l\x9f\xfd3uL\xe5\x88\xf7J\x96j\xbb\xbb\xba\x8a\x01e\xc9fG\xb3\x8a \x00\x00\u07d4s\xd8\xfe\xe3\u02c6M\xce\"\xbb&\u029c/\bm^\x95\xe6;\x8965\u026d\xc5\u07a0\x00\x00\u07d4s\xdf<>yU\xf4\xf2\xd8Y\x83\x1b\xe3\x80\x00\xb1\ak8\x84\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4s\u48b6\f\U0010e2ef+w~\x17Z[\x1eM\f-\x8f\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94t\n\xf1\xee\xfd3e\u05cb\xa7\xb1,\xb1\xa6s\xe0j\arF\x8a\x04+\xf0kx\xed;P\x00\x00\xe0\x94t\v\xfdR\xe0\x16g\xa3A\x9b\x02\x9a\x1b\x8eEWj\x86\xa2\u06ca\x03\x8e\xba\xd5\xcd\xc9\x02\x80\x00\x00\u07d4t\x0fd\x16\x14w\x9d\u03e8\x8e\xd1\xd4%\xd6\r\xb4*\x06\f\xa6\x896\"\xc6v\b\x10W\x00\x00\u07d4t\x12\u027c0\xb4\xdfC\x9f\x021\x00\xe69$\x06j\xfdS\xaf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4t\x16\x93\xc3\x03vP\x85\x13\b \xcc+c\xe9\xfa\x92\x13\x1b\x89A\rXj \xa4\xc0\x00\x00\u07d4t!\xce[\xe3\x81s\x8d\u0703\xf0&!\x97O\xf0hly\xb8\x89Xx\x8c\xb9K\x1d\x80\x00\x00\u07d4t1j\xdf%7\x8c\x10\xf5v\u0574\x1aoG\xfa\x98\xfc\xe3=\x89\x128\x13\x1e\\z\xd5\x00\x00\u07d4t6Q\xb5^\xf8B\x9d\xf5\f\xf8\x198\xc2P\x8d\xe5\u0207\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t=\xe5\x00&\xcag\xc9M\xf5O\x06b`\xe1\xd1J\xcc\x11\xac\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tE /\ft)z\x00N\xb3rj\xa6\xa8-\xd7\xc0/\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tK\x03\xbb\xa8X*\xe5I\x8e-\xc2-\x19\x94\x94g\xabS\xfc\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4tL\fw\xba\u007f#i \xd1\xe44\xde]\xa3>H\xeb\xf0,\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4tP\xff\u007f\x99\xea\xa9\x11bu\u07ach\xe4(\xdf[\xbc\u0639\x89lk\x93[\x8b\xbd@\x00\x00\u07d4tV\u0172\xc5Cn>W\x10\b\x93?\x18\x05\xcc\xfe4\xe9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4tZ\u04eb\xc6\xee\xeb$qh\x9bS\x9ex\x9c\xe2\xb8&\x83\x06\x89=A\x94\xbe\xa0\x11\x92\x80\x00\xe0\x94tZ\xec\xba\xf9\xbb9\xb7Jg\xea\x1c\xe6#\xde6\x84\x81\xba\xa6\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4t\\\xcf-\x81\x9e\u06fd\u07a8\x11{\\I\xed<*\x06n\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4tb\u021c\xaa\x9d\x8dx\x91\xb2T]\xef!otd\u057b!\x89\x05\xea\xedT\xa2\x8b1\x00\x00\u07d4td\x8c\xaa\xc7H\xdd\x13\\\xd9\x1e\xa1L(\xe1\xbdM\u007f\xf6\xae\x89\xa8\r$g~\xfe\xf0\x00\x00\xe0\x94tq\xf7.\xeb0\x06$\xeb(.\xabM\x03r\x00\x00\x00\xe0\x94t\x84\xd2k\xec\xc1\xee\xa8\xc61^\xc3\xee\nE\x01\x17\u0706\xa0\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4t\x86:\xce\xc7]\x03\xd5>\x86\x0ed\x00/,\x16^S\x83w\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\x89\u030a\xbeu\u0364\xef\r\x01\xce\xf2`^G\xed\xa6z\xb1\x89\a?u\u0460\x85\xba\x00\x00\u07d4t\x8c(^\xf1#?\xe4\xd3\x1c\x8f\xb17\x833r\x1c\x12\xe2z\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t\x90\x87\xac\x0fZ\x97\xc6\xfa\xd0!S\x8b\xf1\xd6\u0361\x8e\r\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\x95\xaex\xc0\xd9\x02a\xe2\x14\x0e\xf2\x061\x04s\x1a`\xd1\xed\x89\x01\xdbPq\x89%!\x00\x00\u07d4t\x9aJv\x8b_#rH\x93\x8a\x12\xc6#\x84{\xd4\xe6\x88\u0709\x03\xe73b\x87\x14 \x00\x00\u07d4t\x9a\xd6\xf2\xb5pk\xbe/h\x9aD\u0136@\xb5\x8e\x96\xb9\x92\x89\x05k\xc7^-c\x10\x00\x00\u07d4t\xa1\u007f\x06K4N\x84\xdbce\u0695\x91\xff\x16(%vC\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4t\xae\xec\x91]\xe0\x1c\u019b,\xb5\xa65o\xee\xa1FX\xc6\u0149\f\x9a\x95\xee)\x86R\x00\x00\u07d4t\xaf\xe5I\x02\xd6\x15x%v\xf8\xba\xac\x13\xac\x97\f\x05\x0fn\x89\t\xa1\xaa\xa3\xa9\xfb\xa7\x00\x00\u07d4t\xb7\xe0\"\x8b\xae\xd6YW\xae\xbbM\x91m3:\xae\x16O\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4t\xbcJ^ E\xf4\xff\x8d\xb1\x84\xcf:\x9b\f\x06Z\xd8\a\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4t\xbc\xe9\xec86-l\x94\u032c&\xd5\xc0\xe1:\x8b;\x1d@\x8965&A\x04B\xf5\x00\x00\u07d4t\xbfzZ\xb5\x92\x93\x14\x9b\\`\xcf6Bc\xe5\xeb\xf1\xaa\r\x89\x06G\f>w\x1e<\x00\x00\xe0\x94t\xc7<\x90R\x8a\x15s6\xf1\xe7\xea b\n\xe5?\xd2G(\x8a\x01\xe6:.S\x8f\x16\xe3\x00\x00\u07d4t\u0464\xd0\xc7RN\x01\x8dN\x06\xed;d\x80\x92\xb5\xb6\xaf,\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94t\xd3f\xb0{/VG}|pw\xaco\xe4\x97\xe0\xebeY\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4t\xd3zQt{\xf8\xb7q\xbf\xbfC\x9493\xd1\x00\xd2\x14\x83\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\xd6q\u065c\xbe\xa1\xabW\x90cu\xb6?\xf4+PE\x1d\x17\x8965\u026d\xc5\u07a0\x00\x00\u07d4t\xeb\xf4BVF\xe6\u03c1\xb1\t\xce{\xf4\xa2\xa6=\x84\x81_\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4t\xed3\xac\xf4?5\xb9\x8c\x920\xb9\xe6d.\xcbS0\x83\x9e\x89$\xf6\xdf\xfbI\x8d(\x00\x00\u07d4t\xef(i\xcb\xe6\b\x85`E\xd8\xc2\x04\x11\x18W\x9f\"6\xea\x89\x03<\xd6E\x91\x95n\x00\x00\u07d4t\xfcZ\x99\xc0\xc5F\x05\x03\xa1;\x05\tE\x9d\xa1\x9c\xe7\u0350\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4u\v\xbb\x8c\x06\xbb\xbf$\bC\xccux.\xe0/\b\xa9tS\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4u\x14\xad\xbd\xc6?H?0M\x8e\x94\xb6\u007f\xf30\x9f\x18\v\x82\x89!\u0120n-\x13Y\x80\x00\u0794u\x17\xf1l(\xd12\xbb@\xe3\xba6\u01ae\xf11\xc4b\xda\x17\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4u\x1a,\xa3Nq\x87\xc1c\u048e6\x18\xdb(\xb1<\x19m&\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94u\x1a\xbc\xb6\xcc\x030Y\x91\x18\x15\xc9o\u04516\n\xb0D-\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4u&\xe4\x82R\x9f\n\x14\xee\u0248q\xdd\xdd\x0er\x1b\f\u0662\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4u)\xf3y{\xb6\xa2\x0f~\xa6I$\x19\xc8L\x86vA\xd8\x1c\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94u*^\xe22a,\xd3\x00_\xb2n[Y}\xe1\x9fwk\xe6\x8a\x01'\xfc\xb8\xaf\xae \xd0\x00\x00\u07d4u,\x9f\xeb\xf4/f\xc4x{\xfa~\xb1|\xf53;\xbaPp\x89j\x99\xf2\xb5O\xddX\x00\x00\u07d4u930F\u07b1\xef\x8e\u07b9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94u\xc1\xad#\xd2?$\xb3\x84\xd0\xc3\x14\x91w\xe8f\x97a\r!\x8a\x01\\[\xcdl(\x8b\xbd\x00\x00\u07d4u\xc2\xff\xa1\xbe\xf5I\x19\xd2\t\u007fz\x14-.\x14\xf9\xb0JX\x89\x90\xf3XP@2\xa1\x00\x00\u07d4u\xd6|\xe1N\x8d)\xe8\xc2\xff\u3051{\x93\v\x1a\xff\x1a\x87\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4u\xde~\x93R\xe9\v\x13\xa5\x9aXx\xff\xec\u01c3\x1c\xacM\x82\x89\x94\x89#z\u06daP\x00\x00\u07d4u\xf7S\x9d0\x9e\x909\x98\x9e\xfe.\x8b-\xbd\x86Z\r\xf0\x88\x89\x85[[\xa6\\\x84\xf0\x00\x00\u07d4v\b\xf47\xb3\x1f\x18\xbc\vd\u04c1\xae\x86\xfd\x97\x8e\u05f3\x1f\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94v\x0f\xf35N\x0f\u0793\x8d\x0f\xb5\xb8,\xef[\xa1\\=)\x16\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4v\x1an6,\x97\xfb\xbd|Yw\xac\xba-\xa7F\x876_I\x89\t\xf7J\xe1\xf9S\xd0\x00\x00\u07d4v\x1el\xae\xc1\x89\xc20\xa1b\xec\x00e0\x19>g\u03dd\x19\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94v\x1f\x8a:*\U00028f7e\x1d\xa0\t2\x1f\xb2\x97d\xebb\xa1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4v)\x98\xe1\xd7R'\xfc\xedzp\xbe\x10\x9aL\vN\xd8d\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4v-o0\u06b9\x915\xe4\xec\xa5\x1dRC\xd6\xc8b\x11\x02\u0549\x0fI\x89A\xe6d(\x00\x00\u07d4v3\x1e0yl\xe6d\xb2p\x0e\rASp\x0e\u0706\x97w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v8\x86\xe33\xc5o\xef\xf8[\xe3\x95\x1a\xb0\xb8\x89\xce&.\x95\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v:|\xba\xb7\rzd\u0427\xe5)\x80\xf6\x81G%\x93I\f\x89 \x86\xac5\x10R`\x00\x00\u07d4v>\xec\u0c0a\u021e2\xbf\xa4\xbe\xcev\x95\x14\xd8\xcb[\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4v@\xa3\u007f\x80R\x98\x15\x15\xbc\xe0x\u0693\xaf\xa4x\x9bW4\x89lk\x93[\x8b\xbd@\x00\x00\u0794vA\xf7\xd2j\x86\xcd\xdb+\xe10\x81\x81\x0e\x01\xc9\xc8E\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94vO\xc4mB\x8bm\xbc\"\x8a\x0f_U\xc9P\x8cw.\xab\x9f\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4vPn\xb4\xa7\x80\xc9Q\xc7J\x06\xb0=;\x83b\xf0\x99\x9dq\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94v[\xe2\xe1/b\x9ecI\xb9}!\xb6*\x17\xb7\xc80\xed\xab\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94vb\x81P\xe2\x99[['\x9f\xc8>\r\xd5\xf1\x02\xa6q\xdd\x1c\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4vk7Y\xe8yN\x92m\xacG=\x91:\x8f\xb6\x1a\xd0\xc2\u0249\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4vp\xb0/,<\xf8\xfdOG0\xf38\x1aq\xeaC\x1c3\u01c9\x0e~\xeb\xa3A\vt\x00\x00\u07d4vz\x03eZ\xf3`\x84\x1e\x81\r\x83\xf5\xe6\x1f\xb4\x0fL\xd1\x13\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4vz\u0190y\x1c.#E\x10\x89\xfelp\x83\xfeU\u07b6+\x89,s\xc97t,P\x00\x00\u07d4v\u007f\xd7y}Qi\xa0_sd2\x1c\x19\x84:\x8c4\x8e\x1e\x89\x01\x04\xe7\x04d\xb1X\x00\x00\u0794v\x84o\r\xe0;Zv\x97\x1e\xad)\x8c\xdd\b\x84:K\xc6\u0188\xd7\x1b\x0f\u088e\x00\x00\xe0\x94v\x84\x98\x93N7\xe9\x05\xf1\xd0\xe7{D\xb5t\xbc\xf3\xecJ\xe8\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4v\x8c\xe0\u06a0)\xb7\xde\xd0\"\xe5\xfcWM\x11\xcd\xe3\xec\xb5\x17\x89\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\xe0\x94v\x93\xbd\xebo\xc8+[\xcar\x13U\"1u\xd4z\bKM\x8a\x04\xa8\x9fT\xef\x01!\xc0\x00\x00\u07d4v\xaa\xf8\xc1\xac\x01/\x87R\xd4\xc0\x9b\xb4f\a\xb6e\x1d\\\xa8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4v\xab\x87\xddZ\x05\xad\x83\x9aN/\xc8\xc8Z\xa6\xba\x05d\x170\x89lk\x93[\x8b\xbd@\x00\x00\u07d4v\xaf\xc2%\xf4\xfa0}\xe4\x84U+\xbe\x1d\x9d?\x15\aLJ\x89\xa2\x90\xb5\u01ed9h\x00\x00\xe0\x94v\xbe\xca\xe4\xa3\x1d6\xf3\xcbW\u007f*CYO\xb1\xab\xc1\xbb\x96\x8a\x05C\xa9\xce\x0e\x132\xf0\x00\x00\u07d4v\xc2u5\xbc\xb5\x9c\xe1\xfa-\x8c\x91\x9c\xab\xebJk\xba\x01\u0449lk\x93[\x8b\xbd@\x00\x00\u07d4v\xca\"\xbc\xb8y\x9eS'\u012a*}\tI\xa1\xfc\xce_)\x89R\xa0?\"\x8cZ\xe2\x00\x00\u07d4v\xca\u0108\x11\x1aO\u0555\xf5h\xae:\x85\x87p\xfc\x91]_\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94v\u02dc\x8bi\xf48vu\u0102S\xe24\xcb~\rt\xa4&\x8a\x01\x90\xf4H.\xb9\x1d\xae\x00\x00\u07d4v\xf8:\xc3\xda0\xf7\t&(\xc73\x9f \x8b\xfc\x14,\xb1\ue25a\x18\xff\xe7B}d\x00\x00\xe0\x94v\xf9\xad=\x9b\xbd\x04\xae\x05\\\x14w\xc0\xc3^u\x92\xcb* \x8a\b\x83?\x11\xe3E\x8f \x00\x00\u07d4v\xff\xc1W\xadk\xf8\xd5m\x9a\x1a\u007f\u077c\x0f\xea\x01\n\xab\xf4\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\x02\x8e@\x9c\xc4:;\xd3=!\xa9\xfcS\xec`n\x94\x91\x0e\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4w\f/\xb2\u0128\x17S\xac\x01\x82\xeaF\x0e\xc0\x9c\x90\xa5\x16\xf8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4w\r\x98\xd3\x1bCS\xfc\xee\xe8V\fL\u03c0>\x88\xc0\xc4\xe0\x89 \x86\xac5\x10R`\x00\x00\xe0\x94w\x13\xab\x807A\x1c\t\xbah\u007fo\x93d\xf0\xd3#\x9f\xac(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4w\x15\a\xae\xeej%]\xc2\u035d\xf5QT\x06-\b\x97\xb2\x97\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4w\x19\x88\x87\x95\xadtY$\xc7W`\u0771\x82}\xff\xd8\u0368\x89lkLM\xa6\u077e\x00\x00\u07d4w'\xaf\x10\x1f\n\xab\xa4\xd2:\x1c\xaf\xe1|n\xb5\u06b1\xc6\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4w,)\u007f\n\u0454H.\xe8\xc3\xf06\xbd\xeb\x01\xc2\x01\xd5\u0309\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94w0o\xfe.J\x8f<\xa8&\xc1\xa2I\xf7!-\xa4:\xef\xfd\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4w1A\x12}\x8c\xf3\x18\xae\xbf\x886Z\xdd=U'\xd8[j\x8966\u05ef^\u024e\x00\x00\u07d4wF\xb6\xc6i\x9c\x8f4\xca'h\xa8 \xf1\xff\xa4\xc2\a\xfe\x05\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4wQ\xf3c\xa0\xa7\xfd\x053\x19\b\t\u076f\x93@\xd8\xd1\x12\x91\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4wW\xa4\xb9\xcc=\x02G\u032a\xeb\x99\t\xa0\xe5n\x1d\xd6\xdc\u0089\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4w\\\x10\xc9>\r\xb7 [&CE\x823\xc6O\xc3?\xd7[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4wa~\xbcK\xeb\xc5\xf5\xdd\xeb\x1bzp\xcd\xebj\xe2\xff\xa0$\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4wiC\xff\xb2\xef\\\xdd5\xb8<(\xbc\x04k\xd4\xf4gp\x98\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94wp\x1e,I=\xa4|\x1bX\xf4!\xb5I]\xeeE\xbe\xa3\x9b\x8a\x01H\xf6I\xcfaB\xa5\x80\x00\u07d4wy\x8f \x12W\xb9\xc3R\x04\x95pW\xb5Ft\xae\xfaQ\u07c9\b\x13\xcaV\x90m4\x00\x00\u07d4w\x8cC\xd1\x1a\xfe;Xo\xf3t\x19-\x96\xa7\xf2=+\x9b\u007f\x89\x8b\xb4\xfc\xfa;}k\x80\x00\u07d4w\x8cy\xf4\xde\x19S\xeb\u0398\xfe\x80\x06\xd5:\x81\xfbQ@\x12\x8963\x03\"\xd5#\x8c\x00\x00\u07d4w\x92t\xbf\x18\x03\xa36\xe4\u04f0\r\u0753\xf2\xd4\xf5\xf4\xa6.\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\xa1q\"\xfa1\xb9\x8f\x17\x11\xd3*\x99\xf0>\xc3&\xf3=\b\x89\\(=A\x03\x94\x10\x00\x00\u07d4w\xa3I\a\xf3\x05\xa5L\x85\xdb\t\xc3c\xfd\xe3\xc4~j\xe2\x1f\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4w\xa7i\xfa\xfd\xec\xf4\xa68v-[\xa3\x96\x9d\xf61 \xa4\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4w\xbekd\xd7\xc73\xa46\xad\xec^\x14\xbf\x9a\xd7@+\x1bF\x8965\u026d\xc5\u07a0\x00\x00\u07d4w\xbf\xe9<\u0367P\x84~A\xa1\xaf\xfe\xe6\xb2\u0696\xe7!N\x89\x10CV\x1a\x88)0\x00\x00\u07d4w\u0126\x97\xe6\x03\xd4+\x12\x05l\xbb\xa7a\xe7\xf5\x1d\x04C\xf5\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4w\xcc\x02\xf6#\xa9\u03d8S\t\x97\xeag\xd9\\;I\x18Y\xae\x89Is\x03\xc3n\xa0\xc2\x00\x00\u07d4w\xd4?\xa7\xb4\x81\xdb\xf3\xdbS\f\xfb\xf5\xfd\xce\xd0\xe6W\x181\x89lk\x93[\x8b\xbd@\x00\x00\u07d4w\xda^lr\xfb6\xbc\xe1\xd9y\x8f{\xcd\xf1\u044fE\x9c.\x89\x016\x95\xbbl\xf9>\x00\x00\u07d4w\xf4\xe3\xbd\xf0V\x88<\xc8r\x80\xdb\xe6@\xa1\x8a\r\x02\xa2\a\x89\n\x81\x99:+\xfb[\x00\x00\u0794w\xf6\t\u0287 \xa0#&,U\xc4o-&\xfb90\xaci\x88\xf0\x15\xf2W6B\x00\x00\u07d4w\xf8\x1b\x1b&\xfc\x84\xd6\u0797\uf2df\xbdr\xa310\xccJ\x8965\u026d\xc5\u07a0\x00\x00\u07d4x\x19\xb0E\x8e1N+S\xbf\xe0\f8I_\u0539\xfd\xf8\u0589\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4x\x1b\x15\x01dz.\x06\xc0\xedC\xff\x19\u007f\xcc\xec5\xe1p\v\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4x/R\xf0\xa6v\xc7w\x16\xd5t\xc8\x1e\xc4hO\x9a\x02\n\x97\x89.\x14\xe2\x06\xb70\xad\x80\x00\u07d4x5]\xf0\xa20\xf8=\x03,p1TAM\xe3\xee\u06b5W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4x6\xf7\xefk\u01fd\x0f\xf3\xac\xafD\x9c\x84\xddk\x1e,\x93\x9f\x89\xe0\x8d\xe7\xa9,\xd9|\x00\x00\u07d4x7\xfc\xb8v\xda\x00\xd1\xeb;\x88\xfe\xb3\xdf?\xa4\x04/\xac\x82\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4x>\uc2a5\xda\xc7{.f#\xedQ\x98\xa41\xab\xba\xee\a\x89\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4x\\\x8e\xa7t\xd70D\xa74\xfay\n\x1b\x1et>w\xed|\x89\f\xf1Rd\f\\\x83\x00\x00\u07d4x`\xa3\xde8\xdf8*\xe4\xa4\xdc\xe1\x8c\f\a\xb9\x8b\xce=\xfa\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94xcCq\xe1s\x04\xcb\xf39\xb1E*L\xe48\xdcvL\u038a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4xd\u0719\x9f\xe4\xf8\xe0\x03\xc0\xf4=\xec\u00da\xae\x15\"\xdc\x0f\x89\x05\x1e\x10+\xd8\xec\xe0\x00\x00\u07d4xtj\x95\x8d\xce\xd4\xc7d\xf8vP\x8cAJh4,\uce49\x02\xbe7O\xe8\xe2\xc4\x00\x00\xe0\x94x}1?\xd3k\x05>\xee\xae\xdb\xcet\xb9\xfb\x06x32\x89\x8a\x05\xc0X\xb7\x84'\x19`\x00\x00\u07d4x\x85\x9c[T\x8bp\r\x92\x84\xce\xe4\xb6c=GJ\x8a\x04{\x92\xc4\x15B$-\n\b\xc7\x0f\x99\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4x\u03c36\xb3(\xdb=\x87\x81:G+\x9e\x89\xb7^\f\xf3\xbc\x8965\u026d\xc5\u07a0\x00\x00\u07d4x\xd4\xf8\xc7\x1c\x1eh\xa6\x9a\x98\xf5/\xcbE\u068a\xf5n\xa1\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4x\xdf&\x81\xd6\xd6\x02\xe2!B\xd5A\x16\u07a1]EIW\xaa\x89\x10'\x94\xad \xdah\x00\x00\u07d4x\xe0\x8b\xc53A<&\u2473\x14?\xfa|\u026f\xb9{x\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4x\xe8?\x80\xb3g\x8cz\nN>\x8c\x84\xdc\xcd\xe0dBbw\x89a\t=|,m8\x00\x00\u07d4x\xf5\xc7G\x85\xc5f\x8a\x83\x80r\x04\x8b\xf8\xb4SYM\u06ab\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4y\x0f\x91\xbd]\x1c\\\xc4s\x9a\xe9\x13\x00\u06c9\xe1\xc10<\x93\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\x17\u5f42\xa9y\x0f\xd6P\xd0C\xcd\xd90\xf7y\x963\u06c9\xd8\xd4`,&\xbfl\x00\x00\u07d4y\x19\xe7b\u007f\x9b}T\xea;\x14\xbbM\xd4d\x9fO9\xde\xe0\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4y\x1f`@\xb4\xe3\xe5\r\xcf5S\xf1\x82\u0357\xa9\x060\xb7]\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4y0\xc2\xd9\xcb\xfa\x87\xf5\x10\xf8\xf9\x87w\xff\x8a\x84H\xcaV)\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4yE)\u041d\x01rq5\x970\x02pu\xb8z\xd8=\xaen\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4yKQ\u00deS\xd9\xe7b\xb0a;\x82\x9aD\xb4r\xf4\xff\xf3\x89$5\xe0dxA\u0300\x00\xe0\x94yU\x1c\xed\xe3v\xf7G\xe3ql\x8dy@\rvm.\x01\x95\x8a\t\xcb7\xaf\xa4\xffxh\x00\x00\u07d4y^\xbc&&\xfc9\xb0\xc8b\x94\xe0\xe87\xdc\xf5#U0\x90\x8965\u026d\xc5\u07a0\x00\x00\u07d4yn\xbb\xf4\x9b>6\xd6v\x94\xady\xf8\xff6vz\xc6\xfa\xb0\x89\x03K\xc4\xfd\xde'\xc0\x00\x00\u07d4yo\x87\xbaaz)0\xb1g\v\xe9.\xd1(\x1f\xb0\xb3F\xe1\x89\x06\xf5\xe8o\xb5((\x00\x00\u07d4yt'\xe3\xdb\xf0\xfe\xaez%\x06\xf1-\xf1\xdc@2n\x85\x05\x8965\u026d\xc5\u07a0\x00\x00\u07d4yu\x10\xe3\x86\xf5c\x93\xce\xd8\xf4w7\x8aDLHO}\xad\x8965\u026d\xc5\u07a0\x00\x00\u07d4y{\xb7\xf1W\xd9\xfe\xaa\x17\xf7m\xa4\xf7\x04\xb7M\xc1\x03\x83A\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4y\x88\x90\x131\xe3\x87\xf7\x13\xfa\u03b9\x00\\\xb9\xb6Q6\xeb\x14\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4y\x89\u041f8&\xc3\u5bccu*\x81\x15r:\x84\xd8\tp\x89\x16\x86\xf8aL\xf0\xad\x00\x00\xe0\x94y\x95\xbd\x8c\xe2\xe0\xc6{\xf1\u01e51\xd4w\xbc\xa1\xb2\xb9ua\x8a\x01BH\xd6\x17\x82\x9e\xce\x00\x00\u07d4y\xae\xb3Ef\xb9t\xc3ZX\x81\xde\xc0 \x92}\xa7\xdf]%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\xb1 \xeb\x88\x06s#!(\x8fgZ'\xa9\"_\x1c\xd2\ub245\xa0\xbf7\xde\xc9\xe4\x00\x00\u07d4y\xb4\x8d-a7\u00c5Ma\x1c\x01\xeaBBz\x0fY{\xb7\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4y\xb8\xaa\xd8y\xdd0V~\x87x\xd2\xd21\xc8\xf3z\xb8sN\x89lk\x93[\x8b\xbd@\x00\x00\u07d4y\xbf/{n2\x8a\xaf&\xe0\xbb\t?\xa2-\xa2\x9e\xf2\xf4q\x89a\t=|,m8\x00\x00\u07d4y\xc10\xc7b\xb8v[\x19\u04ab\u0260\x83\xab\x8f:\xady@\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4y\xc1\xbe\x19q\x1fs\xbe\xe4\xe61j\xe7T\x94Y\xaa\u03a2\xe0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4y\xc6\x00/\x84R\xca\x15\u007f\x13\x17\xe8\n/\xaf$GUY\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4y\xca\xc6IO\x11\xef'\x98t\x8c\xb52\x85\xbd\x8e\"\xf9|\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4y\u03e9x\n\xe6\xd8{,1\x88?\t'i\x86\u021ag5\x8965\u026d\xc5\u07a0\x00\x00\u07d4y\u06e2VG-\xb4\xe0X\xf2\xe4\xcd\xc3\xeaN\x8aBw83\x89O%\x91\xf8\x96\xa6P\x00\x00\u07d4y\xed\x10\xcf\x1fm\xb4\x82\x06\xb5\t\x19\xb9\xb6\x97\b\x1f\xbd\xaa\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u0794y\xf0\x8e\x01\xce\t\x88\xe6<\u007f\x8f)\b\xfa\xdeC\xc7\xf9\xf5\u0248\xfc\x93c\x92\x80\x1c\x00\x00\u07d4y\xfdmH1Pf\xc2\x04\xf9e\x18i\xc1\tl\x14\xfc\x97\x81\x89lk\x93[\x8b\xbd@\x00\x00\u0794y\xff\xb4\xac\x13\x81*\vx\u0123{\x82u\">\x17k\xfd\xa5\x88\xf0\x15\xf2W6B\x00\x00\u07d4z\x05\x89\xb1C\xa8\xe5\xe1\a\u026cf\xa9\xf9\xf8Yz\xb3\u7ac9Q\xe92\xd7n\x8f{\x00\x00\u07d4z\nx\xa9\xcc9?\x91\xc3\xd9\xe3\x9ak\x8c\x06\x9f\a^k\xf5\x89Hz\x9a0E9D\x00\x00\u07d4z\x13p\xa7B\xec&\x87\xe7a\xa1\x9a\u0167\x942\x9e\xe6t\x04\x89\xa2\xa12ga\xe2\x92\x00\x00\xe0\x94z-\xfcw\x0e$6\x811\xb7\x84w\x95\xf2\x03\xf3\xd5\r[V\x8a\x02i\xfe\xc7\xf06\x1d \x00\x00\u07d4z3\x83N\x85\x83s>-R\xae\xadX\x9b\u046f\xfb\x1d\xd2V\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94z6\xab\xa5\xc3\x1e\xa0\xca~'{\xaa2\xecF\u0393\xcfu\x06\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94z8\x11\"\xba\xday\x1az\xb1\xf6\x03}\xac\x80C'S\xba\xad\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94zH\xd8w\xb6:\x8f\x8f\x93\x83\xe9\xd0\x1eS\xe8\fR\x8e\x95_\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4zO\x9b\x85\x06\x90\xc7\xc9F\x00\xdb\xee\f\xa4\xb0\xa4\x11\xe9\xc2!\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4zc\x86\x9f\xc7g\xa4\u01b1\xcd\x0e\x06I\xf3cL\xb1!\xd2K\x89\x043\x87Oc,\xc6\x00\x00\u07d4zg\xdd\x04:PO\xc2\xf2\xfcq\x94\xe9\xbe\xcfHL\xec\xb1\xfb\x89\r\x8drkqw\xa8\x00\x00\xe0\x94zk&\xf48\u0663RD\x91U\xb8\x87l\xbd\x17\xc9\u065bd\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4zmx\x1cw\u013a\x1f\xca\xdfhsA\xc1\xe3\x17\x99\xe9='\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4zph\xe1\xc37\\\x0eY\x9d\xb1\xfb\xe6\xb2\xea#\xb8\xf4\a\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4zt\xce\xe4\xfa\x0fcp\xa7\x89O\x11l\xd0\f\x11G\xb8>Y\x89+^:\xf1k\x18\x80\x00\x00\u07d4zy\xe3\x0f\xf0W\xf7\n=\x01\x91\xf7\xf5?v\x157\xaf}\xff\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94zzO\x80sW\xa4\xbb\xe6\x8e\x1a\xa8\x0692\x10\xc4\x11\u0333\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4z\x85c\x86y\x01 o?+\xf0\xfa>\x1c\x81\t\u02bc\u0345\x89\amA\xc6$\x94\x84\x00\x00\xe0\x94z\x87\x97i\n\xb7{Tp\xbf|\f\x1b\xbaa%\b\xe1\xac}\x8a\x01\xe0\x92\x96\xc37\x8d\xe4\x00\x00\u07d4z\x8c\x89\xc0\x14P\x9dV\u05f6\x810f\x8f\xf6\xa3\xec\xecsp\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94z\x94\xb1\x99\x92\u03b8\xcec\xbc\x92\xeeKZ\xde\xd1\fM\x97%\x8a\x03\x8d\x1a\x80d\xbbd\xc8\x00\x00\u07d4z\xa7\x9a\xc0C\x16\u030d\b\xf2\x00e\xba\xa6\xd4\x14(\x97\xd5N\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4z\xadM\xbc\u04ec\xf9\x97\u07d3XiV\xf7+d\u062d\x94\xee\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94z\xb2V\xb2\x04\x80\n\xf2\x017\xfa\xbc\xc9\x16\xa22Xu%\x01\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4z\xbaV\xf6:H\xbc\b\x17\u05b9p9\x03\x9az\xd6/\xae.\x89 \x86\xac5\x10R`\x00\x00\xe0\x94z\xbb\x10\xf5\xbd\x9b\xc3;\x8e\xc1\xa8-d\xb5[k\x18wuA\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4z\u010d@\xc6d\u031am\x89\xf1\xc5\xf5\xc8\n\x1cp\xe7D\u6263\x10b\xbe\xee\xd7\x00\x00\x00\u07d4z\u014fo\xfcO\x81\a\xaen07\x8eN\x9f\x99\xc5\u007f\xbb$\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4z\xd3\xf3\aao\x19\u0731C\xe6DM\xab\x9c<3a\x1fR\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4z\xd8,\xae\xa1\xa8\xb4\xed\x051\x9b\x9c\x98p\x17<\x81N\x06\xee\x89!d\xb7\xa0J\u0220\x00\x00\u07d4z\xde]f\xb9D\xbb\x86\f\x0e\xfd\xc8bv\u054fFS\xf7\x11\x89lk\x93[\x8b\xbd@\x00\x00\u07d4z\xdf\xed\xb0m\x91\xf3\xccs\x90E\v\x85U\x02p\x88<{\xb7\x89\x11x\xfa@Q]\xb4\x00\x00\u07d4z\xe1\xc1\x9eS\xc7\x1c\xeeLs\xfa\xe2\xd7\xfcs\xbf\x9a\xb5\u348965\u026d\xc5\u07a0\x00\x00\u07d4z\xe6Y\xeb;\xc4hR\xfa\x86\xfa\xc4\xe2\x1cv\x8dP8\x89E\x89\x0f\x81\f\x1c\xb5\x01\xb8\x00\x00\u07d4z\xea%\xd4+&\x12(n\x99\xc56\x97\u01bcA\x00\xe2\u06ff\x89lk\x93[\x8b\xbd@\x00\x00\u07d4z\xef{U\x1f\v\x9cF\xe7U\xc0\xf3\x8e[:s\xfe\x11\x99\xf5\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4{\v1\xffn$t^\xad\x8e\u067b\x85\xfc\v\xf2\xfe\x1dU\u0509+^:\xf1k\x18\x80\x00\x00\xe0\x94{\x0f\xea\x11v\xd5!Y3:\x14<)IC\xda6\xbb\u0774\x8a\x01\xfc}\xa6N\xa1L\x10\x00\x00\u07d4{\x11g<\xc0\x19bk)\f\xbd\xce&\x04o~m\x14\x1e!\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4{\x12!b\xc9\x13\xe7\x14l\xad\v~\xd3z\xff\xc9*\v\xf2\u007f\x89Q\xaf\tk#\x01\u0440\x00\u07d4{\x1b\xf5:\x9c\xbe\x83\xa7\u07a44W\x9f\xe7*\xac\x8d*\f\u0409\n\xd4\xc81j\v\f\x00\x00\u07d4{\x1d\xaf\x14\x89\x1b\x8a\x1e\x1b\xd4)\u0633k\x9aJ\xa1\u066f\xbf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4{\x1f\xe1\xabM\xfd\x00\x88\xcd\xd7\xf6\x01c\xefY\xec*\xee\x06\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4{%\xbb\x9c\xa8\xe7\x02!~\x933\"RP\xe5<6\x80MH\x89e\xea=\xb7UF`\x00\x00\u07d4{'\xd0\xd1\xf3\xdd<\x14\x02\x94\xd0H\x8bx>\xbf@\x15'}\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94{@\a\xc4^ZW?\u06f6\xf8\xbdtk\xf9J\xd0J<&\x8a\x038!\xf5\x13]%\x9a\x00\x00\u07d4{C\xc7\xee\xa8\xd6#U\xb0\xa8\xa8\x1d\xa0\x81\xc6Dk3\xe9\xe0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4{M*8&\x90i\xc1\x85Ww\rY\x1d$\xc5\x12\x1f^\x83\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94{au\xec\x9b\xef\xc78$\x955\xdd\xde4h\x8c\xd3n\xdf%\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94{f\x12hy\x84M\xfa4\xfee\xc9\xf2\x88\x11\u007f\xef\xb4I\xad\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4{j\x84q\x8d\xd8nc3\x84)\xac\x81\x1d|\x8a\x86\x0f!\xf1\x89a\t=|,m8\x00\x00\xe0\x94{q,z\xf1\x16v\x00jf\xd2\xfc\\\x1a\xb4\xc4y\xce`7\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4{s$-u\u029a\xd5X\xd6P)\r\xf1v\x92\xd5L\u0638\x89lnY\xe6|xT\x00\x00\u07d4{v\x1f\xeb\u007f\u03e7\xde\xd1\xf0\xeb\x05\x8fJ`\v\xf3\xa7\b\u02c9\xf9]\xd2\xec'\xcc\xe0\x00\x00\xe0\x94{\x82|\xae\u007f\xf4t\t\x18\xf2\xe00\xab&\u02d8\xc4\xf4l\xf5\x8a\x01\x94hL\v9\xde\x10\x00\x00\xe0\x94{\x892\x86B~r\xdb!\x9a!\xfcM\xcd_\xbfY(<1\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4{\x92&\xd4o\xe7Q\x94\v\xc4\x16\xa7\x98\xb6\x9c\xcf\r\xfa\xb6g\x89\u3bb5sr@\xa0\x00\x00\u07d4{\x98\xe2<\xb9k\xee\xe8\n\x16\x80i\ube8f \xed\xd5\\\u03c9\v\xa0\xc9\x15\x87\xc1J\x00\x00\u07d4{\xb0\xfd\xf5\xa6c\xb5\xfb\xa2\x8d\x9c\x90*\xf0\xc8\x11\xe2R\xf2\x98\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4{\xb9W\x1f9K\v\x1a\x8e\xbaVd\xe9\u0635\xe8@g{\xea\x89\x01\x11du\x9f\xfb2\x00\x00\xe0\x94{\xb9\x84\xc6\u06f9\xe2y\x96j\xfa\xfd\xa5\x9c\x01\xd0&'\xc8\x04\x8a\x01\xb4d1\x1dE\xa6\x88\x00\x00\u07d4{\xbb\xec^p\xbd\xea\u063b2\xb4(\x05\x98\x8e\x96H\xc0\xaa\x97\x8966\u05ef^\u024e\x00\x00\u07d4{\xca\x1d\xa6\xc8\nf\xba\xa5\xdbZ\u0245A\u013e'kD}\x89$\xcf\x04\x96\x80\xfa<\x00\x00\u07d4{\u0772\xee\x98\xde\x19\xeeL\x91\xf6a\xee\x8eg\xa9\x1d\x05K\x97\x8965\u026d\xc5\u07a0\x00\x00\u0794{\xe2\xf7h\f\x80-\xa6\x15L\x92\xc0\x19J\xe72Qzqi\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4{\xe7\xf2Eiq\x88;\x9a\x8d\xbeL\x91\xde\xc0\x8a\xc3N\x88b\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4{\xe8\u0334\xf1\x1bf\xcan\x1dW\xc0\xb59b!\xa3\x1b\xa5:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94{\xeb\x81\xfb/^\x91Rk*\xc9y^v\u019b\xcf\xf0K\xc0\x8a\x0e\xb2.yO\n\x8d`\x00\x00\u07d4|\b\x83\x05L-\x02\xbcz\x85+\x1f\x86\xc4'w\xd0\xd5\xc8V\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4|\x0f^\a C\xc9\xeet\x02B\x19~x\xccK\x98\xcd\xf9`\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|\x1d\xf2JO\u007f\xb2\u01f4r\xe0\xbb\x00l\xb2}\xcd\x16AV\x8965\u026d\xc5\u07a0\x00\x00\u07d4|)\xd4}W\xa73\xf5k\x9b!pc\xb5\x13\xdc;1Y#\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4|+\x96\x03\x88JO.FN\u03b9}\x17\x93\x8d\x82\x8b\xc0,\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4|8,\x02\x96a.N\x97\xe4@\xe0-8q';U\xf5;\x89\n\xb6@9\x12\x010\x00\x00\u07d4|>\xb7\x13\xc4\xc9\xe08\x1c\xd8\x15L|\x9a}\xb8d\\\xde\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|D\x01\xae\x98\xf1.\xf6\xde9\xae$\u03df\xc5\x1f\x80\xeb\xa1k\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|E\xf0\xf8D*V\xdb\u04dd\xbf\x15\x99\x95A\\R\xedG\x9b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94|S-\xb9\xe0\xc0l&\xfd@\xac\xc5j\xc5\\\x1e\xe9-<:\x8a?\x87\bW\xa3\xe0\xe3\x80\x00\x00\u07d4|`\xa0_zJ_\x8c\xf2xC\x916.uZ\x83A\xefY\x89f\x94\xf0\x18*7\xae\x00\x00\u07d4|`\xe5\x1f\v\xe2(\xe4\xd5o\xdd)\x92\xc8\x14\xdaw@\u01bc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4|i$\xd0|>\xf5\x89\x19f\xfe\nxV\xc8{\xef\x9d 4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94|\x8b\xb6Zo\xbbI\xbdA3\x96\xa9\xd7\xe3\x10S\xbb\xb3z\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94|\x9a\x11\f\xb1\x1f%\x98\xb2\xb2\x0e,\xa4\x002^A\xe9\xdb3\x8a\x05\x81v{\xa6\x18\x9c@\x00\x00\u07d4|\xbc\xa8\x8f\xcaj\x00`\xb9`\x98\\\x9a\xa1\xb0%4\xdc\"\b\x89\x19\x12z\x13\x91\xea*\x00\x00\u07d4|\xbe\xb9\x992\xe9~n\x02\x05\x8c\xfcb\u0432k\xc7\u0325+\x89lk\x93[\x8b\xbd@\x00\x00\u07d4|\xc2Jj\x95\x8c \xc7\xd1$\x96`\xf7Xb&\x95\v\r\x9a\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4|\xd2\x0e\u0335\x18\xb6\f\xab\t[r\x0fW\x15p\u02aaD~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4|\xd5\xd8\x1e\xab7\xe1\x1ebv\xa3\xa1\t\x12Q`~\r~8\x89\x03hM^\xf9\x81\xf4\x00\x00\u07d4|\xdft!9E\x95=\xb3\x9a\xd0\xe8\xa9x\x1a\xddy.M\x1d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4|\xe4hdF\U000547be\xd6r\x15\xeb\rZ\x1d\xd7,\x11\xb8\x89x9\xd3!\xb8\x1a\xb8\x00\x00\u07d4|\xefMC\xaaA\u007f\x9e\xf8\xb7\x87\xf8\xb9\x9dS\xf1\xfe\xa1\ue209g\x8a\x93 b\xe4\x18\x00\x00\u07d4}\x03P\xe4\v3\x8d\xdasfa\x87+\xe3?\x1f\x97R\xd7U\x89\x02\xb4\xf5\xa6\U00051500\x00\xe0\x94}\x04\xd2\xed\xc0X\xa1\xaf\xc7a\xd9\u025a\xe4\xfc\\\x85\xd4\u0226\x8aB\xa9\xc4g\\\x94g\xd0\x00\x00\u07d4}\v%^\xfbW\xe1\x0fp\b\xaa\"\xd4\x0e\x97R\xdf\xcf\x03x\x89\x01\x9f\x8euY\x92L\x00\x00\xe0\x94}\x13\xd6pX\x84\xab!W\u074d\xccpF\xca\xf5\x8e\xe9K\xe4\x8a\x1d\r\xa0|\xbb>\xe9\xc0\x00\x00\u07d4}'>c~\xf1\xea\u0101\x11\x94\x13\xb9\x1c\x98\x9d\xc5\xea\xc1\"\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4}*R\xa7\xcf\f\x846\xa8\xe0\a\x97kl&\xb7\"\x9d\x1e\x15\x89\x17\xbf\x06\xb3*$\x1c\x00\x00\u07d4}4\x805i\xe0\v\u05b5\x9f\xff\b\x1d\xfa\\\n\xb4\x19zb\x89\\\xd8|\xb7\xb9\xfb\x86\x00\x00\u07d4}4\xffY\xae\x84\nt\x13\u01baL[\xb2\xba,u\xea\xb0\x18\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4}9(R\xf3\xab\xd9/\xf4\xbb[\xb2l\xb6\bt\xf2\xbeg\x95\x8966\xc2^f\xec\xe7\x00\x00\u07d4}DRg\u015a\xb8\u04a2\xd9\xe7\t\x99\x0e\th%\x80\u011f\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94}U\x13\x97\xf7\x9a)\x88\xb0d\xaf\xd0\xef\xeb\xee\x80,w!\xbc\x8a\bW\xe0\xd6\xf1\xdav\xa0\x00\x00\u07d4}Z\xa3?\xc1KQ\x84\x1a\x06\x90n\xdb+\xb4\x9c*\x11ri\x89\x10D\x00\xa2G\x0eh\x00\x00\xe0\x94}]/s\x94\x9d\xad\xda\bV\xb2\x06\x98\x9d\xf0\a\x8dQ\xa1\xe5\x8a\x02\xc4:H\x1d\xf0M\x01wb\xed\xcb\\\xaab\x9bZ\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4~\x8f\x96\xcc)\xf5{\tu\x12\f\xb5\x93\xb7\u0743=`kS\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4~\x97*\x8a|*D\xc9;!Cl8\xd2\x1b\x92R\xc3E\xfe\x89a\t=|,m8\x00\x00\u07d4~\x99\u07fe\x98\x9d;\xa5)\u0457Q\xb7\xf41\u007f\x89S\xa3\xe2\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4~\xa0\xf9n\xe0\xa5s\xa30\xb5h\x97v\x1f=L\x010\xa8\xe3\x89Hz\x9a0E9D\x00\x00\u0794~\xa7\x91\xeb\xab\x04E\xa0\x0e\xfd\xfcNJ\x8e\x9a~ue\x13m\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4~\xab\xa05\xe2\xaf7\x93\xfdtgK\x10%@\xcf\x19\n\u0779\x89E\x02l\x83[`D\x00\x00\xe0\x94~\xb4\xb0\x18\\\x92\xb6C\x9a\b\xe72!h\xcb5<\x8awJ\x8a\x02'\x19l\xa0I\x83\xca\x00\x00\xe0\x94~\xbd\x95\xe9\xc4p\xf7(5\x83\xdcn\x9d,M\xce\v\ua3c4\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4~\u0425\xa8G\xbe\xf9\xa9\xda|\xba\x1dd\x11\xf5\xc3\x161&\x19\x89\x02(\xeb7\xe8u\x1d\x00\x00\u07d4~\xda\xfb\xa8\x98K\xafc\x1a\x82\vk\x92\xbb\xc2\xc56U\xf6\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4~\xdb\x02\xc6\x1a\"r\x87a\x1a\xd9Pici\xccNdzh\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4~\xe5\u0280]\xce#\xaf\x89\xc2\xd4D\xe7\xe4\af\xc5Lt\x04\x89\r\v\xd4\x12\xed\xbd\x82\x00\x00\xe0\x94~\xe6\x04\u01e9\xdc)\t\xce2\x1d\u6e72OWgWuU\x8a\x01+\xf9\u01d8\\\xf6-\x80\x00\u07d4~\xf1o\xd8\xd1[7\x8a\x0f\xba0k\x8d\x03\u0758\xfc\x92a\x9f\x89%\xf2s\x93=\xb5p\x00\x00\u07d4~\xf9\x8bR\xbe\xe9S\xbe\xf9\x92\xf3\x05\xfd\xa0'\xf8\x91\x1cXQ\x89\x1b\xe7\" i\x96\xbc\x80\x00\u07d4~\xfc\x90vj\x00\xbcR7,\xac\x97\xfa\xbd\x8a<\x83\x1f\x8e\u0349\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4~\xfe\xc0\xc6%<\xaf9\u007fq(|\x1c\a\xf6\xc9X+[\x86\x89\x1a,\xbc\xb8O0\u0540\x00\u07d4\u007f\x01\xdc|7G\xca`\x8f\x98=\xfc\x8c\x9b9\xe7U\xa3\xb9\x14\x89\v8l\xad_zZ\x00\x00\u07d4\u007f\x06b\xb4\x10)\x8c\x99\xf3\x11\u04e1EJ\x1e\xed\xba/\xeav\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\u007f\x06\u021dY\x80\u007f\xa6\v\xc6\x016\xfc\xf8\x14\u02ef%C\xbd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u007f\v\x90\xa1\xfd\u050f'\xb2h\xfe\xb3\x83\x82\xe5]\xdbP\xef\x0f\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\u007f\x0e\xc3\u06c0F\x92\xd4\xd1\xea2E6Z\xab\x05\x90\a[\u0109\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u007f\x0f\x04\xfc\xf3zS\xa4\xe2N\xden\x93\x10Nx\xbe\x1d<\x9e\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u007f\x13\xd7`I\x8dq\x93\xcahY\xbc\x95\xc9\x018d#\xd7l\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\u007f\x15\n\xfb\x1aw\u00b4Y(\xc2h\xc1\u9f74d\x1dG\u0609lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\x16\x19\x98\x8f7\x15\xe9O\xf1\xd2S&-\xc5X\x1d\xb3\xde\x1c\x890\xca\x02O\x98{\x90\x00\x00\u07d4\u007f\x1c\x81\xee\x16\x97\xfc\x14K|\v\xe5I;V\x15\xae\u007f\xdd\u0289\x1b\x1d\xaba\u04ead\x00\x00\u07d4\u007f#\x82\xff\xd8\xf89VFy7\xf9\xbar7F#\xf1\x1b8\x89 \x86\xac5\x10R`\x00\x00\u07d4\u007f7\t9\x1f?\xbe\xba5\x92\xd1u\xc7@\xe8z\tT\x1d\x02\x89\x1a\x05V\x90\xd9\u06c0\x00\x00\u07d4\u007f8\x9c\x12\xf3\xc6\x16OdFVlwf\x95\x03\xc2y%'\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\xe0\x94\u007f:\x1eE\xf6~\x92\u0200\xe5s\xb43y\xd7\x1e\xe0\x89\xdbT\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\u007f=r\x03\u0224G\xf7\xbf6\u060a\xe9\xb6\x06*^\xeex\xae\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\u007fF\xbb%F\r\xd7\xda\xe4!\x1c\xa7\xf1Z\xd3\x12\xfc}\xc7\\\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\u007fI\xe7\xa4&\x98\x82\xbd\x87\"\u0526\xf5f4v)b@y\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u007fI\xf2\a&G\x1a\xc1\u01e8>\xf1\x06\xe9w\\\xebf%f\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\u007fK^'\x85x\xc0F\xcc\xea\xf6W0\xa0\xe0h2\x9e\u0576\x89e\xea=\xb7UF`\x00\x00\u07d4\u007fOY;a\x8c3\v\xa2\xc3\xd5\xf4\x1e\xce\xeb\x92\xe2~Bl\x89\x96n\xdcuk|\xfc\x00\x00\u07d4\u007fT\x14\x91\u04ac\x00\xd2a/\x94\xaa\u007f\v\xcb\x01FQ\xfb\u0509\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\u007fZ\xe0Z\xe0\xf8\xcb\xe5\xdf\xe7!\xf0D\u05e7\xbe\xf4\xc2y\x97\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\u007f`:\xec\x17Y\xea_\a\xc7\xf8\xd4\x1a\x14(\xfb\xba\xf9\xe7b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u007falo\x00\x8a\u07e0\x82\xf3M\xa7\xd0e\x04`6\x80u\xfb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u007fa\xfal\xf5\xf8\x98\xb4@\xda\u016b\xd8`\rmi\x1f\xde\xf9\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94\u007fe\\g\x89\xed\xdfE\\\xb4\xb8\x80\x99r\x0698\x9e\ubb0a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u007fk(\u0204!\xe4\x85~E\x92\x81\u05c4ai$\x89\xd3\xfb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007fn\xfboC\x18\x87m.\xe6$\xe2u\x95\xf4DF\xf6\x8e\x93\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u007fq\x92\xc0\xdf\x1c}\xb6\xd9\xede\xd7\x11\x84\xd8\xe4\x15Z\x17\xba\x89\x04Sr\x8d3\x94,\x00\x00\u07d4\u007fz:!\xb3\xf5\xa6]\x81\xe0\xfc\xb7\xd5-\xd0\n\x1a\xa3m\xba\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u007f\x8d\xbc\xe1\x80\xed\x9cV65\xaa\xd2\xd9{L\xbcB\x89\x06\u0649\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\u007f\x99=\xdb~\x02\u0082\xb8\x98\xf6\x15_h\x0e\xf5\xb9\xaf\xf9\a\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\u007f\x9f\x9bV\xe4(\x9d\xfbX\xe7\x0f\xd5\xf1*\x97\xb5m5\u01a5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u007f\xa3~\xd6x\x87u\x1aG\x1f\x0e\xb3\x06\xbeD\xe0\xdb\xcd`\x89\x899vt\u007f\xe1\x1a\x10\x00\x00\u07d4\u007f\xaa0\xc3\x15\x19\xb5\x84\xe9rP\xed*<\xf38^\xd5\xfdP\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xcf[\xa6fo\x96lTH\xc1{\xf1\xcb\v\xbc\xd8\x01\x9b\x06\x89\x05k\xc3\u042e\xbeI\x80\x00\xe0\x94\u007f\xd6y\xe5\xfb\r\xa2\xa5\xd1\x16\x19M\xcbP\x83\x18\xed\u0140\xf3\x8a\x01c\x9eI\xbb\xa1b\x80\x00\x00\u07d4\u007f\u06e01\u01cf\x9c\tmb\xd0Z6\x9e\uac3c\xccU\u5257\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\u007f\xdb\u00e8D\xe4\r\x96\xb2\xf3\xa652.`e\xf4\xca\x0e\x84\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xdf\u020dx\xbf\x1b(Z\xc6O\x1a\xdb5\xdc\x11\xfc\xb09Q\x89|\x06\xfd\xa0/\xb06\x00\x00\u07d4\u007f\xea\x19b\xe3]b\x05\x97h\xc7I\xbe\u0756\u02b90\xd3x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u007f\xef\x8c8w\x9f\xb3\a\xeco\x04K\xeb\xe4\u007f<\xfa\xe7\x96\xf1\x89\t#@\xf8l\xf0\x9e\x80\x00\u07d4\u007f\xf0\xc6?p$\x1b\xec\xe1\x9bs~SA\xb1+\x10\x901\u0609\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\u007f\xfa\xbf\xbc9\f\xbeC\u0389\x18\x8f\bh\xb2}\xcb\x0f\f\xad\x8a\x01YQ\x82\"K&H\x00\x00\xe0\x94\u007f\xfd\x02\xed7\fp`\xb2\xaeS\xc0x\xc8\x01!\x90\u07fbu\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u0794\x80\x02*\x12\a\xe9\x10\x91\x1f\xc9(I\xb0i\xab\f\xda\xd0C\u04c8\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\x80\t\xa7\xcb\u0452\xb3\xae\u052d\xb9\x83\xd5(ER\xc1ltQ\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80\x0e}c\x1cnW:\x903/\x17\xf7\x1f_\u045bR\x8c\xb9\x89\b=lz\xabc`\x00\x00\u07d4\x80\x15m\x10\ufa320\u0254\x10c\r7\xe2i\xd4\t<\xea\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\x172\xa4\x81\u00c0\xe5~\xd6-l)\u0799\x8a\xf3\xfa;\x13\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x1de\xc5\x18\xb1\x1d\x0e?OG\x02!Ap\x13\xc8\xe5>\u0149\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80&CZ\xacr\x8dI{\x19\xb3\xe7\xe5|(\xc5c\x95O+\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x80-\xc3\xc4\xff-}\x92^\u215fJ\x06\u05fa`\xf10\x8c\x89\x05P\x94\f\x8f\xd3L\x00\x00\u07d4\x800\xb1\x11\u0198?\x04\x85\u076c\xa7b$\xc6\x18\x064x\x9f\x89\x04V9\x18$O@\x00\x00\u07d4\x805\xbc\xff\xae\xfd\xee\xea5\x83\fI}\x14(\x9d6 #\u0789\x10CV\x1a\x88)0\x00\x00\u07d4\x805\xfeNkj\xf2z\u44a5xQ^\x9d9\xfao\xa6[\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80C\xed\"\xf9\x97\u58a4\xc1n6D\x86\xaed\x97V\x92\u0109=I\x04\xff\xc9\x11.\x80\x00\u07d4\x80C\xfd\u043cL\x97=\x16c\xd5_\xc15P\x8e\xc5\xd4\xf4\xfa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x80L\xa9IrcOc:Q\xf3V\v\x1d\x06\xc0\xb2\x93\xb3\xb1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x80R-\u07d4N\xc5.'\xd7$\xedL\x93\xe1\xf7\xbe`\x83\u0589\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x80Y\x1aB\x17\x9f4\xe6M\x9d\xf7]\xcdF;(hoUt\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x80\\\xe5\x12\x97\xa0y;\x81 g\xf0\x17\xb3\xe7\xb2\u07db\xb1\xf9\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x80]\x84o\xb0\xbc\x02\xa73r&\u0585\xbe\x9e\xe7s\xb9\x19\x8a\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x80c7\x9a{\xf2\u02d2:\x84\xc5\t>h\xda\xc7\xf7T\x81\u0149\x11v\x10.n2\xdf\x00\x00\u07d4\x80hTX\x8e\xcc\xe5AI_\x81\u008a)\x03s\xdf\x02t\xb2\x89\x1f\x8c\xdf\\n\x8dX\x00\x00\u07d4\x80oD\xbd\xebh\x807\x01^\x84\xff!\x80I\xe3\x823*3\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\x80tF\x18\xde9jT1\x97\xeeH\x94\xab\xd0c\x98\xdd|'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80w\xc3\xe4\xc4EXn\tL\xe1\x02\x93\u007f\xa0[s{V\x8c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x90\u007fY1H\xb5|F\xc1w\xe2=%\xab\u012a\xe1\x83a\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\x97s\x16\x94NYB\xe7\x9b\x0e:\xba\u04cd\xa7F\be\x19\x89\x02\x1auJm\xc5(\x00\x00\xe0\x94\x80\xa0\xf6\xcc\x18l\xf6 \x14\x00sn\x06Z9\x1fR\xa9\xdfJ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x80\xab\xecZ\xa3n\\\x9d\t\x8f\x1b\x94(\x81\xbdZ\xca\u0196=\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xb2=8\v\x82\\F\xe098\x99\xa8UVF-\xa0\u1309lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xb4-\xe1p\xdb\xd7#\xf4T\xe8\x8fw\x16E-\x92\x98P\x92\x89\x10F#\xc0v-\xd1\x00\x00\u07d4\x80\xb7\x9f3\x83\x90\u047a\x1b77\xa2\x9a\x02W\xe5\xd9\x1e\a1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x80\xbf\x99^\u063a\x92p\x1d\x10\xfe\u011f\x9e}\x01M\xbe\xe0&\x89\x1f\x047\xca\x1a~\x12\x80\x00\u07d4\x80\xc0N\xfd1\x0fD\x04\x83\xc7?tK[\x9edY\x9c\xe3\xec\x89A\rXj \xa4\xc0\x00\x00\u07d4\x80\u00e9\xf6\x95\xb1m\xb1Yr\x86\u0473\xa8\xb7il9\xfa'\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x80\xc5>\xe7\xe35\u007f\x94\xce\rxh\x00\x9c \x8bJ\x13\x01%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x80\xcc!\xbd\x99\xf3\x90\x05\u014f\xe4\xa4H\x90\x92 !\x8ff\u02c966\xc9yd6t\x00\x00\u07d4\x80\xd5\xc4\fY\xc7\xf5N\xa3\xa5_\xcf\xd1uG\x1e\xa3P\x99\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x80\xda/\u0762\x9a\x9e'\xf9\xe1\x15\x97^i\xae\x9c\xfb\xf3\xf2~\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x80\xe7\xb3 R0\xa5f\xa1\xf0a\xd9\"\x81\x9b\xb4\xd4\u04a0\xe1\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x80\xea\x1a\xcc\x13n\xcaKh\xc8B\xa9Z\xdfk\u007f\xee~\xb8\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x80\xf0z\xc0\x9e{,<\n=\x1e\x94\x13\xa5D\xc7:A\xbe\u02c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x81\r\xb2Vu\xf4^\xa4\xc7\xf3\x17\u007f7\xce)\xe2-g\x99\x9c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81\x13\x9b\xfd\u0326V\xc40 ?r\x95\x8cT;e\x80\xd4\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x81\x14a\xa2\xb0\u0290\xba\xda\xc0j\x9e\xa1nx{3\xb1\x96\u0309\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\x81\x16M\xeb\x10\x81J\xe0\x83\x91\xf3,\bf{bH\xc2}z\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\x81\x18i1\x18A7\xd1\x19*\u020c\xd3\xe1\xe5\xd0\xfd\xb8jt\x89\x9d5\x95\xab$8\xd0\x00\x00\u0794\x81*U\xc4<\xae\xdcYr\x187\x90\x00\xceQ\rT\x886\xfd\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x81.\xa7\xa3\xb2\xc8n\xed2\xffO,sQL\xc6;\xac\xfb\u038965\u026d\xc5\u07a0\x00\x00\u07d4\x814\xdd\x1c\x9d\xf0\xd6\u0225\x81$&\xbbU\xc7a\u0283\x1f\b\x89\x06\xa2\x16\v\xb5|\xcc\x00\x00\u07d4\x81A5\u068f\x98\x11\aW\x83\xbf\x1a\xb6pb\xaf\x8d>\x9f@\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x81I\x8c\xa0{\x0f/\x17\xe8\xbb\xc7\xe6\x1a\u007fJ\xe7\xbef\xb7\x8b\x89\x05\x81\xfb\xb5\xb3;\xb0\x00\x00\u07d4\x81Um\xb2sI\xab\x8b'\x00ID\xedP\xa4n\x94\x1a\x0f_\x89\u063beI\xb0+\xb8\x00\x00\u07d4\x81U\xfalQ\xeb1\xd8\bA-t\x8a\xa0\x86\x10P\x18\x12/\x89e\xea=\xb7UF`\x00\x00\xe0\x94\x81V6\v\xbd7\ta\xce\xcakf\x91\xd7P\x06\xad L\xf2\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x81a\xd9@\xc3v\x01\x00\xb9\b\x05)\xf8\xa6\x03%\x03\x0fn\u0709\x10CV\x1a\x88)0\x00\x00\xe0\x94\x81d\xe7\x83\x14\xae\x16\xb2\x89&\xccU=,\xcb\x16\xf3V'\r\x8a\x01\xca\x13N\x95\xfb2\xc8\x00\x00\u07d4\x81e\u02b0\xea\xfbZ2\x8f\xc4\x1a\xc6M\xaeq[.\xef,e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81h\xed\xce\u007f)a\xcf)[\x9f\xcdZE\xc0l\xde\xdan\xf5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81m\x97r\xcf\x119\x91\x16\xcc\x1er\xc2lgt\xc9\xed\xd79\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x81s\xc85djg.\x01R\xbe\x10\xff\xe8Ab\xdd%nL\x89\x1a\xab\xdf!E\xb40\x00\x00\u07d4\x81t\x93\u035b\xc6#p*$\xa5o\x9f\x82\xe3\xfdH\xf3\xcd1\x89\x9eK#\xf1-L\xa0\x00\x00\u07d4\x81y\xc8\tp\x18,\u0177\xd8*M\xf0n\xa9M\xb6:%\xf3\x89'o%\x9d\xe6k\xf4\x00\x00\u07d4\x81z\xc3;\xd8\xf8GVsr\x95\x1fJ\x10\u05e9\x1c\xe3\xf40\x89\n\xd7\xc4\x06\xc6m\xc1\x80\x00\xe0\x94\x81\x8f\xfe'\x1f\u00d75e\xc3\x03\xf2\x13\xf6\xd2\u0689\x89~\xbd\x8a\x016\xe0SB\xfe\u1e40\x00\u07d4\x81\x97\x94\x81!s.c\xd9\xc1H\x19N\xca\xd4n0\xb7I\u0209\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x81\x9a\xf9\xa1\xc2s2\xb1\xc3i\xbb\xda\x1b=\xe1\xc6\xe93\xd6@\x89\x11\t\xe6T\xb9\x8fz\x00\x00\xe0\x94\x81\x9c\u06a506x\xef|\xecY\u050c\x82\x16:\xcc`\xb9R\x8a\x03\x13QT_y\x81l\x00\x00\u07d4\x81\x9e\xb4\x99\vZ\xbaUG\t=\xa1+k<\x10\x93\xdfmF\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81\xa8\x81\x96\xfa\xc5\xf2<>\x12\xa6\x9d\xecK\x88\x0e\xb7\xd9s\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x81\xbc\xcb\xff\x8fD4~\xb7\xfc\xa9['\xce|\x95$\x92\xaa\xad\x89\b@\xc1!e\xddx\x00\x00\u07d4\x81\xbdu\xab\xd8e\xe0\xc3\xf0J\vO\xdb\xcbt\xd3@\x82\xfb\xb7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x81\xc1\x8c*#\x8d\xdcL\xba#\n\a-\xd7\xdc\x10\x1eb\x02s\x89Hz\x9a0E9D\x00\x00\u07d4\x81\xc9\xe1\xae\xe2\xd36]S\xbc\xfd\u0356\xc7\xc58\xb0\xfd~\xec\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\x81\u03edv\t\x13\xd3\xc3\"\xfc\xc7{I\u00ae9\a\xe7On\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x81\xd6\x19\xffW&\xf2@_\x12\x90Lr\xeb\x1e$\xa0\xaa\xeeO\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x81\xef\u25aev\xc8`\xd1\xc5\xfb\xd3=G\xe8\u0399\x96\xd1W\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x81\xf8\xde,(=_\u052f\xbd\xa8]\xed\xf9v\x0e\xab\xbb\xb5r\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x82\f\x19)\x11\x96P[e\x05\x9d\x99\x14\xb7\t\v\xe1\u06c7\u0789\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x82\x1c\xb5\xcd\x05\xc7\uf41f\xe1\xbe`s=\x89c\xd7`\xdcA\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x82\x1dy\x8a\xf1\x99\x89\u00ee[\x84\xa7\xa7(<\xd7\xfd\xa1\xfa\xbe\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x82\x1e\xb9\t\x94\xa2\xfb\xf9K\xdc23\x91\x02\x96\xf7o\x9b\xf6\xe7\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x82$\x9f\xe7\x0fa\u01b1o\x19\xa3$\x84\x0f\xdc\x02\x021\xbb\x02\x8a\x02\x036\xb0\x8a\x93c[\x00\x00\u07d4\x82(\xeb\xc0\x87H\x0f\xd6EG\xca(\x1f^\xac\xe3\x04\x14S\xb9\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\x82)\u03b9\xf0\xd7\b9I\x8dD\xe6\xab\xed\x93\xc5\xca\x05\x9f]\x8a\x1a\x1c\x1b<\x98\x9a \x10\x00\x00\u07d4\x82.\xdf\xf66V:a\x06\xe5.\x9a%\x98\xf7\xe6\xd0\xef'\x82\x89\x01\xf4\xf9i=B\u04c0\x00\u07d4\x822\x19\xa2Yv\xbb*\xa4\xaf\x8b\xadA\xac5&\xb4\x936\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x822\xd1\xf9t.\u07cd\xd9'\xda5;*\xe7\xb4\xcb\xceu\x92\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\x824\xf4c\u0444\x85P\x1f\x8f\x85\xac\xe4\x97,\x9bc-\xbc\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\x827htg7\xcem\xa3\x12\xd5>TSN\x10o\x96|\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82;\xa7dr8\xd1\x13\xbc\xe9\x96JC\u0420\x98\x11\x8b\xfeM\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x82@t1(\x06\xdaGHCBf\xee\x00!@\u305a\u0089Q\xb1\u04c3\x92a\xac\x00\x00\u07d4\x82C\x8f\u04b3*\x9b\xddgKI\xd8\xcc_\xa2\xef\xf9x\x18G\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82HW(\xd0\xe2\x81V7X\xc7Z\xb2~\xd9\u80a0\x00-\x89\a\xf8\b\xe9)\x1el\x00\x00\u07d4\x82K<\x19)]~\xf6\xfa\xa7\xf3t\xa4y\x84\x86\xa8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82Q5\x8c\xa4\xe0`\u0775Y\xcaX\xbc\v\u077e\xb4\a\x02\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82Q5\xb1\xa7\xfc\x16\x05aL\x8a\xa4\u042cm\xba\u040fH\x0e\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\x82S\t\xa7\xd4]\x18\x12\xf5\x1en\x8d\xf5\xa7\xb9ol\x90\x88\x87\x89\x804\xf7\u0671f\xd4\x00\x00\u07d4\x82Z\u007fN\x10\x94\x9c\xb6\xf8\x96Bh\xf1\xfa_W\xe7\x12\xb4\u0109\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x82a\xfa#\f\x90\x1dC\xffW\x9fG\x80\u04d9\xf3\x1e`v\xbc\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82b\x16\x9baXp\x13N\xb4\xacl_G\x1ck\xf2\xf7\x89\xfc\x89\x19\x12z\x13\x91\xea*\x00\x00\u07d4\x82c\xec\xe5\xd7\t\xe0\u05eeq\u0328h\xed7\xcd/\xef\x80{\x895\xab\x02\x8a\xc1T\xb8\x00\x00\xe0\x94\x82l\xe5y\x052\xe0T\x8ca\x02\xa3\r>\xac\x83k\xd68\x8f\x8a\x03\xcf\xc8.7\xe9\xa7@\x00\x00\u07d4\x82n\xb7\xcds\x19\xb8-\xd0z\x1f;@\x90q\xd9n9g\u007f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x82u1\xa6\u0141z\xe3_\x82\xb0\v\x97T\xfc\xf7LU\xe22\x89\xc3(\t>a\xee@\x00\x00\u0794\x82u\xcdhL6y\u0548}\x03fN3\x83E\xdc<\xdd\xe1\x88\xdbD\xe0I\xbb,\x00\x00\u07d4\x82\x84\x92;b\u62ff|+\x9f4\x14\xd1>\xf6\xc8\x12\xa9\x04\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\x82\x8b\xa6Q\u02d3\x0e\xd9xqV)\x9a=\xe4L\u040br\x12\x89Hz\x9a0E9D\x00\x00\u07d4\x82\xa1\\\xef\x1dl\x82`\xea\xf1Y\xea?\x01\x80\xd8g}\xce\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82\xa8\xb9kl\x9e\x13\xeb\xec\x1e\x9f\x18\xac\x02\xa6\x0e\xa8\x8aH\xff\x89lk\x8c@\x8es\xb3\x00\x00\u07d4\x82\xa8\u02ff\xdf\xf0+.8\xaeK\xbf\xca\x15\xf1\xf0\xe8;\x1a\xea\x89\x04\x9b\x99\x1c'\xefm\x80\x00\u07d4\x82\xe4F\x1e\xb9\xd8I\xf0\x04\x1c\x14\x04!\x9eBr\u0110\n\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x82\xe5w\xb5\x15\xcb+\b`\xaa\xfe\x1c\xe0\x9aY\xe0\x9f\xe7\xd0@\x89 \x86\xac5\x10R`\x00\x00\u07d4\x82\xea\x01\xe3\xbf.\x83\x83nqpN\"\xa2q\x93w\xef\xd9\u00c9\xa4\xccy\x95c\u00c0\x00\x00\u07d4\x82\xf2\xe9\x91\xfd2L_]\x17v\x8e\x9fa3]\xb61\x9dl\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x82\xf3\x9b'X\xaeB'{\x86\u059fu\xe6(\xd9X\xeb\u02b0\x8a\bxg\x83&\xea\xc9\x00\x00\x00\xe0\x94\x82\xf8T\xc9\xc2\xf0\x87\xdf\xfa\x98Z\xc8 \x1ebl\xa5Fv\x86\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\x82\xffqo\xdf\x03>\xc7\xe9B\xc9\t\u0643\x18g\xb8\xb6\xe2\xef\x89a\t=|,m8\x00\x00\u07d4\x83\b\xed\n\xf7\xf8\xa3\xc1u\x1f\xaf\xc8w\xb5\xa4*\xf7\xd3X\x82\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x83\x1cD\xb3\b@G\x18K*\xd2\x18h\x06@\x907P\xc4]\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x83!\x05\x83\xc1jN\x1e\x1d\xac\x84\xeb\xd3~=\x0f|W\ub909lk\x93[\x8b\xbd@\x00\x00\u07d4\x83,T\x17k\xdfC\xd2\u027c\u05f8\b\xb8\x95V\xb8\x9c\xbf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x833\x16\x98]Gt+\xfe\xd4\x10`J\x91\x95<\x05\xfb\x12\xb0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x834vK{9zNW\x8fP6M`\xceD\x89\x9b\xff\x94\x89\x05\x03\xb2\x03\xe9\xfb\xa2\x00\x00\xe0\x94\x83;j\x8e\xc8\xda@\x81\x86\xac\x8a}*m\xd6\x15#\xe7\u0384\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x83=?\xaeT*\xd5\xf8\xb5\f\xe1\x9b\xde+\xecW\x91\x80\u020c\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\x83=\xb4,\x14\x16<{\xe4\u02b8j\u0153\xe0bf\u0599\u054a$\xe4\r+iC\xef\x90\x00\x00\xe0\x94\x83V;\xc3d\ud060\xc6\xda;V\xffI\xbb\xf2g\x82z\x9c\x8a\x03\xab\x91\xd1{ \xdeP\x00\x00\u07d4\x83zd]\xc9\\IT\x9f\x89\x9cN\x8b\u03c7S$\xb2\xf5|\x89 \x8c9J\xf1\u0208\x00\x00\u07d4\x83\x8b\xd5e\xf9\x9f\xdeH\x05?y\x17\xfe3<\xf8J\xd5H\xab\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x83\x90\x8a\xa7G\x8am\x1c\x9b\x9b\x02\x81\x14\x8f\x8f\x9f$+\x9f\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\x83\x92\xe57vq5x\x01[\xffI@\xcfC\x84\x9d}\u02e1\x89\bM\xf05]V\x17\x00\x00\xe0\x94\x83\x97\xa1\xbcG\xac\xd6GA\x81Y\xb9\x9c\xeaW\xe1\xe6S-n\x8a\x01\xf1\x0f\xa8'\xb5P\xb4\x00\x00\u07d4\x83\x98\xe0~\xbc\xb4\xf7_\xf2\x11m\xe7|\x1c*\x99\xf3\x03\xa4\u03c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xa3\x14\x883\xd9dI\x84\xf7\xc4u\xa7\x85\a\x16\ufd00\xff\x89\xb8Pz\x82\a( \x00\x00\u07d4\x83\xa4\x02C\x8e\x05\x19w=TH2k\xfba\xf8\xb2\f\xf5-\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\x83\xa9;[\xa4\x1b\xf8\x87 \xe4\x15y\f\xdc\vg\xb4\xaf4\u0109\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x83\xc2=\x8aP!$\xee\x15\x0f\b\xd7\x1d\xc6rt\x10\xa0\xf9\x01\x8a\a3\x1f;\xfef\x1b\x18\x00\x00\u07d4\x83\u0217\xa8Ki^\xeb\xe4fy\xf7\xda\x19\xd7vb\x1c&\x94\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xd52\u04cdm\xee?`\xad\u018b\x93a3\u01e2\xa1\xb0\u0749\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x83\xdb\xf8\xa1(S\xb4\n\xc6\x19\x96\xf8\xbf\x1d\xc8\xfd\xba\xdd\xd3)\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x83\xdb\xfd\x8e\xda\x01\xd0\u078e\x15\x8b\x16\u0413_\xc28\n]\u01c9 \x86\xac5\x10R`\x00\x00\u07d4\x83\xe4\x80U2|(\xb5\x93o\xd9\xf4D~s\xbd\xb2\xdd3v\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\x83\xfeZ\x1b2\x8b\xaeD\a\x11\xbe\xafj\xad`&\xed\xa6\xd2 \x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x84\x00\x8ar\xf8\x03o?\xeb\xa5B\xe3Px\xc0W\xf3*\x88%\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x84\x0e\xc8>\xa96!\xf04\xe7\xbb7b\xbb\x8e)\xde\xd4\xc4y\x89\x87\x86x2n\xac\x90\x00\x00\xe0\x94\x84\x11E\xb4H@\xc9F\xe2\x1d\xbc\x19\x02d\xb8\xe0\xd5\x02\x93i\x8a?\x87\bW\xa3\xe0\xe3\x80\x00\x00\u07d4\x84#!\a\x93+\x12\xe01\x86X5%\xce\x02:p>\xf8\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4\x84$O\xc9ZiW\xed|\x15\x04\xe4\x9f0\xb8\xc3^\xcaKy\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x841'}{\xdd\x10E}\xc0\x17@\x8c\x8d\xbb\xbdAJ\x8d\xf3\x89\x02\"\xc8\xeb?\xf6d\x00\x00\u07d4\x847Z\xfb\xf5\x9b:\x1da\xa1\xbe2\xd0u\xe0\xe1ZO\xbc\xa5\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x84;\xd3P/E\xf8\xbcM\xa3p\xb3#\xbd\xac?\xcf_\x19\xa6\x89P\x03\x9dc\xd1\x1c\x90\x00\x00\u07d4\x84P34c\rw\xf7AG\xf6\x8b.\bf\x13\xc8\xf1\xad\xe9\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x84R\x03u\x0fqH\xa9\xaa&)!\xe8mC\xbfd\x19t\xfd\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x84a\xec\u0126\xa4^\xb1\xa5\xb9G\xfb\x86\xb8\x80i\xb9\x1f\xcdo\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84g^\x91wrmE\xea\xa4k9\x92\xa3@\xba\u007fq\f\x95\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x84hl{\xadv,T\xb6g\u055f\x90\x94<\xd1M\x11z&\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\x89\xf6\xad\x1d\x9a\x94\xa2\x97x\x91V\x89\x9d\xb6AT\xf1\u06f5\x89\x13t\a\xc0<\x8c&\x80\x00\u07d4\x84\x8c\x99Jy\x00?\xe7\xb7\xc2l\xc62\x12\xe1\xfc/\x9c\x19\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\x8f\xbd)\xd6|\xf4\xa0\x13\xcb\x02\xa4\xb1v\xef$N\x9e\u6349\x01\x17*ck\xbd\xc2\x00\x00\u07d4\x84\x94\x9d\xbaU\x9ac\xbf\xc8E\xde\xd0n\x9f-\x9b\u007f\x11\xef$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\x9a\xb8\a\x90\xb2\x8f\xf1\xff\u05ba9N\xfctc\x10\\6\xf7\x89\x01\xe0+\xe4\xael\x84\x00\x00\u07d4\x84\x9b\x11oYc\x01\xc5\u063bb\xe0\xe9z\x82H\x12n9\xf3\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x84\xa7L\xee\xcf\xf6\\\xb9;/\x94\x9dw>\xf1\xad\u007f\xb4\xa2E\x89\x05\n\x9bDF\x85\xc7\x00\x00\u07d4\x84\xaa\xc7\xfa\x19\u007f\xf8\\0\xe0;zS\x82\xb9W\xf4\x1f:\xfb\x89\b\x8b#\xac\xff\u0650\x00\x00\u07d4\x84\xaf\x1b\x15sB\xd5Ch&\r\x17\x87b0\xa54\xb5K\x0e\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x84\xb0\xeek\xb87\u04e4\xc4\xc5\x01\x1c:\"\x8c\x0e\u06b4cJ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\xb4\xb7Nf#\xba\x9d\x15\x83\xe0\u03feId?\x168AI\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x84\xb6\xb6\xad\xbe/[>-h,f\xaf\x1b\u0110S@\xc3\xed\x89!\x92\xf8\xd2\"\x15\x00\x80\x00\xe0\x94\x84\xb9\x1e.)\x02\xd0^+Y\x1bA\b;\u05fe\xb2\xd5,t\x8a\x02\x15\xe5\x12\x8bE\x04d\x80\x00\u07d4\x84\xbc\xbf\"\xc0\x96\a\xac\x844\x1d.\xdb\xc0;\xfb\x179\xd7D\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x84\xbf\xce\xf0I\x1a\n\xe0iK7\u03ac\x02E\x84\xf2\xaa\x04g\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x84\xcb}\xa0P-\xf4\\\xf5a\x81{\xbd#b\xf4Q\xbe\x02\u0689Hz\x9a0E9D\x00\x00\u07d4\x84\xccxx\xda`_\xdb\x01\x9f\xab\x9bL\xcf\xc1Wp\x9c\u0765\x89Hy\x85\x13\xaf\x04\xc9\x00\x00\u07d4\x84\xdb\x14Y\xbb\x00\x81.\xa6~\xcb=\xc1\x89\xb7!\x87\xd9\xc5\x01\x89\b\x11\xb8\xfb\u0685\xab\x80\x00\u07d4\x84\u9516\x80\xbe\xcehA\xb9\xa7\xe5%\r\b\xac\xd8}\x16\u0349\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x84\xe9\u03c1f\xc3j\xbf\xa4\x90S\xb7\xa1\xad@6 &\x81\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x84\xec\x06\xf2G\x00\xfeBAL\xb9\x89|\x15L\x88\xde/a2\x89Hz\x9a0E9D\x00\x00\xe0\x94\x84\xf5\"\xf0R\x0e\xbaR\xdd\x18\xad!\xfaK\x82\x9f+\x89\u02d7\x8a\x01\fQ\x06\xd5\x13O\x13\x00\x00\u07d4\x85\v\x9d\xb1\x8f\xf8K\xf0\xc7\xdaI\xea7\x81\xd9 \x90\xad~d\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\x85\x10\xee\x93O\f\xbc\x90\x0e\x10\a\xeb8\xa2\x1e*Q\x01\xb8\xb2\x89\x05\xbf\v\xa6cOh\x00\x00\u07d4\x85\x16\xfc\xafw\u0213\x97\x0f\xcd\x1a\x95\x8b\xa9\xa0\x0eI\x04@\x19\x89\n\xa3\xeb\x16\x91\xbc\xe5\x80\x00\u07d4\x85\x1a\xa9\x1c\x82\xf4/\xad]\xd8\xe8\xbb^\xa6\x9c\x8f:Yw\u0449\b\x0eV\x1f%xy\x80\x00\u07d4\x85\x1c\rb\xbeF5\xd4w~\x805\xe3~K\xa8Q|a2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x85\x1d\u00ca\xdbE\x93r\x9av\xf3:\x86\x16\u06b6\xf5\xf5\x9aw\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x852I\b\x97\xbb\xb4\u038b\u007fk\x83~L\xba\x84\x8f\xbe\x99v\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x85>j\xba\xf4Di\xc7/\x15\x1dN\"8\x19\xac\xedN7(\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x85F\x91\xceqO2\\\xedU\xceY(\u039b\xa1/\xac\u0478\x89\xedp\xb5\xe9\xc3\xf2\xf0\x00\x00\u07d4\x85L\fF\x9c$k\x83\xb5\u0473\xec\xa4C\xb3\x9a\xf5\xee\x12\x8a\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x85]\x9a\xef,9\xc6#\r\t\u025e\xf6II\x89\xab\u61c5\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\x85c\u0113a\xb6%\xe7hw\x1c\x96\x15\x1d\xbf\xbd\x1c\x90iv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x85fa\t\x01\xaa\xce8\xb82D\xf3\xa9\xc810jg\xb9\u0709\xb0\x82\x13\xbc\xf8\xff\xe0\x00\x00\xe0\x94\x85j\xa2<\x82\xd7![\xec\x8dW\xf6\n\xd7^\xf1O\xa3_D\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x85nZ\xb3\xf6L\x9a\xb5k\x00\x93\x93\xb0\x16d\xfc\x03$\x05\x0e\x89a\t=|,m8\x00\x00\u07d4\x85n\xb2\x04$\x1a\x87\x83\x0f\xb2)\x03\x13C\xdc0\x85OX\x1a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x85s,\x06\\\xbdd\x11\x99A\xae\xd40\xacYg\vlQ\u0109'\xa5sb\xab\n\x0e\x80\x00\xe0\x94\x85x\xe1\x02\x12\xca\x14\xff\a2\xa8$\x1e7F}\xb8V2\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x85y\xda\xdf\x1a9Z4q\xe2\vov=\x9a\x0f\xf1\x9a?o\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x85\u007f\x10\v\x1aY0\"^\xfc~\x90 \u05c3'\xb4\x1c\x02\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x85\x94mV\xa4\xd3q\xa93hS\x96\x90\xb6\x0e\xc8%\x10tT\x89]\u0212\xaa\x111\xc8\x00\x00\xe0\x94\x85\x99\xcb\u0566\xa9\xdc\u0539f\xbe8}iw]\xa5\xe3C'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86$_Yf\x91\t>\xce?=<\xa2&>\xac\xe8\x19A\u0649\n1\x06+\xee\xedp\x00\x00\u07d4\x86%i!\x1e\x8cc'\xb5A^:g\xe5s\x8b\x15\xba\xafn\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x86)}s\x0f\xe0\xf7\xa9\xee$\xe0\x8f\xb1\b{1\xad\xb3\x06\xa7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86D\xcc(\x1b\xe32\xcc\xce\xd3m\xa4\x83\xfb*\aF\u067a.\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x86I\x9a\x12(\xff-~\xe3\au\x93dPo\x8e\x8c\x83\a\xa5\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x86K\xecPi\xf8U\xa4\xfdX\x92\xa6\xc4I\x1d\xb0|\x88\xff|\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86W\n\xb2Y\u0271\xc3,\x97) /w\xf5\x90\xc0}\xd6\x12\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86c\xa2A\xa0\xa8\x9ep\xe1\x82\xc8E\xe2\x10\\\x8a\xd7&K\u03ca\x03#\xb1=\x83\x98\xf3#\x80\x00\u07d4\x86g\xfa\x11U\xfe\xd72\u03f8\u0725\xa0\xd7e\xce\r\a\x05\xed\x89\x04n\xc9e\u00d3\xb1\x00\x00\u07d4\x86h\xaf\x86\x8a\x1e\x98\x88_\x93\u007f&\x15\xde\xd6u\x18\x04\xeb-\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x86t\nFd\x8e\x84Z]\x96F\x1b\x18\t\x1f\xf5{\xe8\xa1o\x8a\x14\xc0\x974\x85\xbf9@\x00\x00\xe0\x94\x86~\xbaVt\x8aY\x045\r,\xa2\xa5\u039c\xa0\vg\n\x9b\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x86\x80dt\xc3X\x04}\x94\x06\xe6\xa0\u007f@\x94[\xc82\x8eg\x8a\x01u.\xb0\xf7\x01=\x10\x00\x00\u07d4\x86\x88=T\xcd9\x15\xe5I\tU0\xf9\xab\x18\x05\xe8\xc5C-\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x86\x8c#\xbe\x874f\xd4\xc7L\"\n\x19\xb2E\xd1x~\x80\u007f\x89J\x13\xbb\xbd\x92\u020e\x80\x00\xe0\x94\x86\x92O\xb2\x11\xaa\xd2<\xf5\xce`\x0e\n\xae\x80c\x96D@\x87\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x86\x93\u9e3e\x94B^\xefyi\xbci\xf9\xd4/|\xadg\x1e\x8967\tlK\xcci\x00\x00\xe0\x94\x86\x9f\x1a\xa3\x0eDU\xbe\xb1\x82 \x91\xde\\\xad\xecy\xa8\xf9F\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x86\xa1\xea\xde\xeb0F\x13E\xd9\xefk\xd0R\x16\xfa$|\r\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86\xa5\xf8%\x9e\u0570\x9e\x18\x8c\xe3F\xee\x92\xd3J\xa5\u0753\xfa\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xb7\xbdV<\uad86\xf9bD\xf9\xdd\xc0*\u05f0\xb1K\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x86\u008bVx\xaf7\xd7'\xec\x05\xe4Dw\x90\xf1_q\xf2\xea\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xc4\xce\x06\u066c\x18[\xb1H\xd9o{z\xbes\xf4A\x00m\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x86\xc8\xd0\u0642\xb59\xf4\x8f\x980\xf9\x89\x1f\x9d`z\x94&Y\x8a\x02\xce\xd3wa\x82O\xb0\x00\x00\u07d4\x86\xc94\xe3\x8eS\xbe;3\xf2t\xd0S\x9c\xfc\xa1Y\xa4\xd0\u04494\x95tD\xb8@\xe8\x00\x00\xe0\x94\x86\xca\x01E\x95~k\r\xfe6\x87_\xbez\r\xecU\xe1z(\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x86\u02af\xac\xf3*\xa01|\x03*\xc3k\xab\xed\x97G\x91\xdc\x03\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x86\u0377\xe5\x1a\xc4Gr\xbe6\x90\xf6\x1d\x0eYvn\x8b\xfc\x18\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x86\xdfs\xbd7\u007f,\t\xdec\xc4]g\xf2\x83\xea\xef\xa0\xf4\xab\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x86\xe3\xfe\x86\xe9=\xa4\x86\xb1Bf\xea\xdf\x05l\xbf\xa4\xd9\x14C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x86\xe8g\x0e'Y\x8e\xa0\x9c8\x99\xabw\x11\u04f9\xfe\x90\x1c\x17\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x86\xefd&!\x19I\xcc7\xf4\xc7^xP6\x9d\f\xf5\xf4y\x8a\x02\xd6_2\xea\x04Z\xf6\x00\x00\u07d4\x86\xf0]\x19\x06>\x93i\xc6\x00N\xb3\xf1#\x94:|\xffN\xab\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x86\xf2>\x9c\n\xaf\u01cb\x9c@M\xcd`3\x9a\x92[\xff\xa2f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x86\xf4\xf4\n\u0644\xfb\xb8\t3\xaebn\x0eB\xf93?\xddA\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x86\xf9\\[\x11\xa2\x93\x94\x0e5\xc0\xb8\x98\u0637_\b\xaa\xb0m\x8a\x06D\xe3\xe8u\xfc\xcft\x00\x00\u07d4\x86\xff\xf2 \xe5\x93\x05\xc0\x9fH8`\xd6\xf9N\x96\xfb\xe3/W\x89\x02S[j\xb4\xc0B\x00\x00\u07d4\x87\a\x96\xab\xc0\u06c4\xaf\x82\xdaR\xa0\xedhsM\xe7\xe66\xf5\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x87\x0f\x15\xe5\u07cb\x0e\xab\xd0%iSz\x8e\xf9;Vx\\B\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\x87\x181`\xd1r\xd2\xe0\x84\xd3'\xb8k\xcb|\x1d\x8eg\x84\xef\x89\xd8\xd8X?\xa2\xd5/\x00\x00\xe0\x94\x87\x1b\x8a\x8bQ\u07a1\x98\x9aY!\xf1>\xc1\xa9U\xa5\x15\xadG\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x87%\xe8\xc7S\xb3\xac\xbf\u0725_I\x13\\3\x91\x99\x10`)\n\xa7\xf6\u0338\xf8Zx\u06c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x87Pa\xee\x12\xe8 \x04\x1a\x01\x94,\xb0\xe6[\xb4'\xb0\x00`\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\x87XJ?a;\xd4\xfa\xc7L\x1ex\v\x86\xd6\xca\xeb\x89\f\xb2\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x87d\xd0'\"\x00\t\x96\xec\xd4u\xb43)\x8e\x9fT\v\x05\xbf\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x87l?!\x8bGv\xdf<\xa9\xdb\xfb'\r\xe1R\xd9N\xd2R\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x87u\xa6\x10\xc5\x02\xb9\xf1\xe6\xadL\xda\u06cc\xe2\x9b\xffu\xf6\xe4\x89 \x86\xac5\x10R`\x00\x00\u07d4\x87vN6w\xee\xf6\x04\xcb\u015a\xed$\xab\xdcVk\t\xfc%\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\x87\x87\xd1&w\xa5\xec)\x1eW\xe3\x1f\xfb\xfa\xd1\x05\xc32K\x87\x8a\x02\xa2N\xb52\b\xf3\x12\x80\x00\u07d4\x87\x94\xbfG\xd5E@\xec\xe5\xc7\"7\xa1\xff\xb5\x11\u0777Gb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x87\xa5>\xa3\x9fY\xa3[\xad\xa85%!dU\x94\xa1\xa7\x14\u02c9g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x87\xa7\xc5\b\xefqX-\u0665Cr\xf8\x9c\xb0\x1f%/\xb1\x80\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x87\xaf%\xd3\xf6\xf8\xee\xa1S\x13\xd5\xfeEW\xe8\x10\xc5$\xc0\x83\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x87\xb1\x0f\x9c(\x00\x98\x17\x9a+v\xe9\u0390\xbea\xfc\x84M\r\x89Hz\x9a0E9D\x00\x00\u07d4\x87\xbf|\xd5\u0629)\xe1\u01c5\xf9\xe5D\x91\x06\xac#$c\u0249\x047\xb1\x1f\xccEd\x00\x00\u07d4\x87\u0118\x17\t4\xb8#=\x1a\xd1\xe7i1}\\G_/@\x897\b\xba\xed=h\x90\x00\x00\u07d4\x87\xcf6\xad\x03\xc9\xea\xe9\x05:\xbbRB\u0791\x17\xbb\x0f*\v\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x87\u05ec\x06S\xcc\xc6z\xa9\xc3F\x9e\xefCR\x19?}\xbb\x86\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\xe0\x94\x87\xe3\x06+#!\xe9\u07f0\x87\\\u311c\x9b.5\"\xd5\n\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x87\xe6\x03N\xcf#\xf8\xb5c\x9d_\x0e\xa7\n\"S\x8a\x92\x04#\x89\x11\xc7\xea\x16.x \x00\x00\u07d4\x87\xefm\x8bj|\xbf\x9b\\\x8c\x97\xf6~\xe2\xad\u00a7;?w\x89\n\xdd\x1b\xd2<\x00L\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x88F\x92\x8dh2\x89\xa2\xd1\x1d\xf8\xdbz\x94t\x98\x8e\xf0\x13H\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x88I\x80\xebEe\xc1\x04\x83\x17\xa8\xf4\u007f\u06f4a\x96[\u4049\xd8\xd6\x11\x9a\x81F\x05\x00\x00\xe0\x94\x88Jz9\u0411n\x05\xf1\xc2B\xdfU`\u007f7\u07cc_\u068a\x04\xf4\x84<\x15|\x8c\xa0\x00\x00\u07d4\x88T\x93\xbd\xa3j\x042\x97eF\xc1\xdd\xceq\xc3\xf4W\x00!\x89\v\xbfQ\r\xdf\xcb&\x00\x00\xe0\x94\x88`\x9e\nF[n\x99\xfc\xe9\a\x16mW\xe9\xda\b\x14\xf5\u020a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x88m\n\x9e\x17\xc9\xc0\x95\xaf.\xa25\x8b\x89\xecpR\x12\ue509\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\x88y~Xg^\xd5\xccL\x19\x98\a\x83\xdb\xd0\xc9V\bQS\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x88|\xacA\xcdpo3E\xf2\xd3J\xc3N\x01u*nY\t\x89 F\\\ue7617\x00\x00\u07d4\x88\x88\x8aW\xbd\x96\x87\xcb\xf9P\xae\xea\u03d7@\xdc\xc4\xd1\xefY\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u0794\x88\x89D\x83\x16\xcc\xf1N\xd8m\xf8\xe2\xf4x\xdcc\xc43\x83@\x88\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x88\x8c\x16\x14I3\x19|\xac&PM\xd7n\x06\xfdf\x00\u01c9\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x88\x8e\x94\x91p\x83\xd1R +S\x1699\x86\x9d'\x11u\xb4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x88\x90\x87\xf6o\xf2\x84\xf8\xb5\xef\xbd)I;pg3\xab\x14G\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\x88\x95\xebrb&\xed\xc3\xf7\x8c\u01a5\x15\a{2\x96\xfd\xb9^\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x88\x97Z_\x1e\xf2R\x8c0\v\x83\xc0\xc6\a\xb8\xe8}\u0593\x15\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\u07d4\x88\x9d\xa4\x0f\xb1\xb6\x0f\x9e\xa9\xbdzE>XL\xf7\xb1\xb4\xd9\xf7\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x88\x9d\xa6b\xebJ\n*\x06\x9d+\xc2K\x05\xb4\xee.\x92\xc4\x1b\x89Z,\x8cTV\xc9\xf2\x80\x00\u07d4\x88\xa1\"\xa28,R91\xfbQ\xa0\u032d;\xeb[rY\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x88\xa2\x15D0\xc0\xe4\x11G\xd3\xc1\xfe\u3cf0\x06\xf8Q\xed\xbd\x8965f3\xeb\xd8\xea\x00\x00\u07d4\x88\xb2\x17\u0337\x86\xa2T\xcfM\xc5\u007f]\x9a\xc3\xc4U\xa3\x04\x83\x892$\xf4'#\xd4T\x00\x00\xe0\x94\x88\xbcC\x01.\xdb\x0e\xa9\xf0b\xacCxC%\n9\xb7\x8f\xbb\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x88\xc2Qj|\xdb\t\xa6'mr\x97\xd3\x0fZM\xb1\xe8K\x86\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x88\xc3ad\rki7;\b\x1c\xe0\xc43\xbdY\x02\x87\xd5\xec\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x88\xd5A\xc8@\xceC\xce\xfb\xafm\x19\xafk\x98Y\xb5s\xc1E\x89\t79SM(h\x00\x00\u07d4\x88\xde\x13\xb0\x991\x87|\x91\rY1e\xc3d\u0221d\x1b\u04c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x88\xde\u017d?N\xba-\x18\xb8\xaa\xce\xfa{r\x15H\xc3\x19\xba\x89JD\x91\xbdm\xcd(\x00\x00\u07d4\x88\xe6\xf9\xb2G\xf9\x88\xf6\xc0\xfc\x14\xc5o\x1d\xe5>\u019dC\u0309\x05k\xc7^-c\x10\x00\x00\u07d4\x88\xee\u007f\x0e\xfc\x8fw\x8ckh~\xc3+\xe9\xe7\xd6\xf0 \xb6t\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x88\xf1\x04_\x19\xf2\xd3\x19\x18\x16\xb1\xdf\x18\xbbn\x145\xad\x1b8\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x89\x00\x9e\a\xe3\xfahc\xa7x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x89Wr~r\xcfb\x90 \xf4\xe0^\xdfy\x9a\xa7E\x80b\u0409wC\"\x17\xe6\x83`\x00\x00\u07d4\x89]iN\x88\v\x13\xcc\u0404\x8a\x86\xc5\xceA\x1f\x88Gk\xbf\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x89^\xc5TVD\u0dc30\xff\xfa\xb8\xdd\xea\xc9\xe83\x15l\x89 \x86\xac5\x10R`\x00\x00\u07d4\x89`\tRj,{\f\t\xa6\xf6:\x80\xbd\U0009d707\u079c\x89\xbb\xb8k\x82#\xed\xeb\x00\x00\u07d4\x89g\u05f9\xbd\xb7\xb4\xae\xd2.e\xa1]\xc8\x03\xcbz!?\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x89n3\\\xa4z\xf5yb\xfa\x0fM\xbf>E\xe6\x88\u02e5\x84\x89J/\xc0\xab`R\x12\x00\x00\u07d4\x89s\xae\xfd^\xfa\xee\x96\t]\x9e(\x8fj\x04l\x977KC\x89\a\xa4\u0120\xf32\x14\x00\x00\u07d4\x89\x8cr\xddseX\xef\x9eK\xe9\xfd\xc3O\xefT\xd7\xfc~\b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x89\x9b<$\x9f\fK\x81\xdfu\xd2\x12\x00M=m\x95/\xd2#\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x89\xab\x13\xee&mw\x9c5\xe8\xbb\x04\u034a\x90\xcc!\x03\xa9[\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\x89\xc43\xd6\x01\xfa\xd7\x14\xdaci0\x8f\xd2l\x1d\u0254+\xbf\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x89\xd7[\x8e\b1\xe4o\x80\xbc\x17A\x88\x18N\x00o\xde\x0e\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x89\u3d5a\x15\x86G7\u0513\xc1\xd2<\xc5=\xbf\x8d\xcb\x13b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x89\xfc\x8eM8k\r\v\xb4\xa7\a\xed\xf3\xbdV\r\xf1\xad\x8fN\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\x89\xfe\xe3\r\x17(\xd9l\xec\xc1\u06b3\xda.w\x1a\xfb\u03eaA\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x8a\x1c\u016c\x11\x1cI\xbf\xcf\xd8H\xf3}\xd7h\xaae\u0208\x02\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x8a \xe5\xb5\xce\xe7\xcd\x1fU\x15\xba\xce;\xf4\xf7\u007f\xfd\xe5\xcc\a\x89\x04V9\x18$O@\x00\x00\xe0\x94\x8a!}\xb3\x8b\xc3_!_\xd9)\x06\xbeBCo\xe7\xe6\xed\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x8a$:\n\x9f\xeaI\xb89TwE\xff-\x11\xaf?K\x05\"\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x8a$}\x18e\x10\x80\x9fq\xcf\xfcEYG\x1c9\x10\x85\x81!\x89a\t=|,m8\x00\x00\u07d4\x8a4p(-^**\xef\u05e7P\x94\xc8\"\xc4\xf5\xae\uf289\r(\xbc`dx\xa5\x80\x00\u07d4\x8a6\x86\x9a\xd4x\x99|\xbfm\x89$\xd2\n<\x80\x18\xe9\x85[\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8aC\x14\xfba\u0353\x8f\xc3>\x15\xe8\x16\xb1\x13\U000ac267\xfb\x89\x17vNz\xede\x10\x00\x00\u07d4\x8aOJ\u007fR\xa3U\xba\x10_\xca r\xd3\x06_\xc8\xf7\x94K\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8aX1(,\xe1Jezs\r\xc1\x88&\xf7\xf9\xb9\x9d\xb9h\x89\uaf8a[A\xc16\x00\x00\u07d4\x8a_\xb7W\x93\xd0C\xf1\xbc\xd48\x85\xe07\xbd0\xa5(\xc9'\x89\x13Snm.\x9a\xc2\x00\x00\u07d4\x8af\xab\xbc-0\xce!\xa83\xb0\u06ceV\x1dQ\x05\xe0\xa7,\x89%\xf1\xde\\v\xac\xdf\x00\x00\u07d4\x8atl]g\x06G\x11\xbf\xcah[\x95\xa4\xfe)\x1a'\x02\x8e\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8ax\n\xb8z\x91E\xfe\x10\xed`\xfaGjt\n\xf4\u02b1\u0489\x12\x1b.^ddx\x00\x00\u07d4\x8az\x06\xbe\x19\x9a:X\x01\x9d\x84j\xc9\xcb\xd4\xd9]\xd7W\u0789\xa2\xa4#\x94BV\xf4\x00\x00\u07d4\x8a\x81\x01\x14\xb2\x02]\xb9\xfb\xb5\x00\x99\xa6\xe0\u02de.\xfak\u0709g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x8a\x86\xe4\xa5\x1c\x01;\x1f\xb4\xc7k\xcf0f|x\xd5.\xed\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\x9e\u029cZ\xba\x8e\x13\x9f\x80\x03\xed\xf1\x16:\xfbp\xaa:\xa9\x89#\xc7W\a+\x8d\xd0\x00\x00\u07d4\x8a\xb89\xae\xaf*\xd3|\xb7\x8b\xac\xbb\xb63\xbc\xc5\xc0\x99\xdcF\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\u021b\u06780\x1ek\x06w\xfa%\xfc\xf0\xf5\x8f\f\u01f6\x11\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x8a\xdcS\xef\x8c\x18\xed0Qx]\x88\xe9\x96\xf3\xe4\xb2\x0e\xcdQ\x8a\b\xe4\xd3\x16\x82v\x86@\x00\x00\u07d4\x8a\xe6\xf8\vp\xe1\xf2<\x91\xfb\u0569f\xb0\xe4\x99\xd9]\xf82\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x8a\xe9\uf30a\x8a\u07e6\xaby\x8a\xb2\xcd\xc4\x05\b*\x1b\xbbp\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8a\xf6&\xa5\xf3'\xd7Pe\x89\xee\xb7\x01\x0f\xf9\xc9D` \u0489K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\x8b\x01\xda4\xd4p\xc1\xd1\x15\xac\xf4\xd8\x11\xe1\x01\xdb\x1e\x14\xec\xc7\xd3\"\xc7+\x8c\x04s\x89\x18\xb2j1>\x8a\xe9\x00\x00\xe0\x94\x8bH\xe1\x9d9\xdd5\xb6nn\x1b\xb6\xb9\xc6W\xcb,\xf5\x9d\x04\x8a\x03\xc7U\xac\x9c\x02J\x01\x80\x00\xe0\x94\x8bP^(q\xf7\u07b7\xa68\x95 \x8e\x82'\u072a\x1b\xff\x05\x8a\f\xf6\x8e\xfc0\x8dy\xbc\x00\x00\u07d4\x8bW\xb2\xbc\x83\u030dM\xe31 N\x89?/;\x1d\xb1\a\x9a\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8b\\\x91K\x12\x8b\xf1i\\\b\x89#\xfaF~y\x11\xf3Q\xfa\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\xe0\x94\x8b_)\xcc/\xaa&,\xde\xf3\x0e\xf5T\xf5\x0e\xb4\x88\x14n\xac\x8a\x01;hp\\\x97 \x81\x00\x00\u07d4\x8bpV\xf6\xab\xf3\xb1\x18\xd0&\xe9D\xd5\xc0sC<\xa4Q\u05c965\xc6 G9\u0640\x00\u07d4\x8bqE\"\xfa(9b\x04p\xed\xcf\fD\x01\xb7\x13f=\xf1\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x8bt\xa7\xcb\x1b\xb8\u014f\xce&tf\xa3\x03X\xad\xafR\u007fa\x8a\x02\xe2WxN%\xb4P\x00\x00\u07d4\x8b~\x9fo\x05\xf7\xe3dv\xa1n>q\x00\xc9\x03\x1c\xf4\x04\xaf\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8b\x81\x15ni\x869\x94<\x01\xa7Rr\xad=5\x85\x1a\xb2\x82\x89\x12\xb3\x16_e\xd3\xe5\x00\x00\u07d4\x8b\x95w\x92\x00S\xb1\xa0\x01\x890M\x88\x80\x10\xd9\xef,\xb4\xbf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8b\x98A\x86.w\xfb\xbe\x91\x94p\x93U\x83\xa9<\xf0'\xe4P\x89llS4B\u007f\x1f\x00\x00\u07d4\x8b\x99}\xbc\a\x8a\xd0)a5]\xa0\xa1Y\xf2\x92~\xd4=d\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x8b\x9f\xda}\x98\x1f\xe9\xd6B\x87\xf8\\\x94\xd8?\x90t\x84\x9f\u030a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x8b\xb0!/2\x95\xe0)\u02b1\xd9a\xb0A3\xa1\x80\x9e{\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8b\xbe\xac\xfc)\xcf\xe94\x02\xdb\xd6j\x1a\xcbvv\x85c7\xb9;\xf0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8b\xf3s\xd0v\x81L\xbcW\xe1\xc6\xd1j\x82\u017e\x13\xc7=7\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x8c\x10#\xfd\xe1WM\xb8\xbbT\xf1s\x96p\x15|\xa4}\xa6R\x8a\x01y\u03da\u00e1\xb1w\x00\x00\u07d4\x8c\x1f\xbe_\n\xea5\x9cZ\xa1\xfa\b\u0209T\x12\u028e\x05\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\"B`U\xb7o\x11\xf0\xa2\xde\x1a\u007f\x81\x9aa\x96\x85\xfe`\x89kV\x05\x15\x82\xa9p\x00\x00\u07d4\x8c+}\x8b`\x8d(\xb7\u007f\\\xaa\x9c\xd6E$*\x82>L\u0649b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\x8c/\xbe\ue3ac\xc5\xc5\xd7|\x16\xab\xd4b\ue701E\xf3K\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x8c:\x9e\xe7\x1fr\x9f#l\xba8g\xb4\u05dd\x8c\xee\xe2]\xbc\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8cP\xaa*\x92\x12\xbc\xdeVA\x8a\xe2a\xf0\xb3^z\x9d\xbb\x82\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8cT\xc7\xf8\xb9\x89nu\xd7\xd5\xf5\xc7`%\x86\x99\x95qB\xad\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x8c]\x16\xede\xe3\xed~\x8b\x96\u0297+\xc8as\xe3P\v\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8cj\xa8\x82\xee2,\xa8HW\x8c\x06\xcb\x0f\xa9\x11\xd3`\x83\x05\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\x8cj\xe7\xa0Z\x1d\xe5u\x82\xae'h Bv\xc0\xffG\xed\x03\x8a,\v\xb3\xdd0\xc4\xe2\x00\x00\x00\u07d4\x8co\x9fN[z\xe2v\xbfXI{\u05ff*}%$_d\x89\x93\xfe\\W\xd7\x10h\x00\x00\u07d4\x8cu\x95n\x8f\xedP\xf5\xa7\xdd|\xfd'\xda \x0fgF\xae\xa6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c|\xb4\xe4\x8b%\x03\x1a\xa1\xc4\xf9)%\xd61\xa8\xc3\xed\xc7a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\u007f\xa5\xca\xe8/\xed\xb6\x9a\xb1\x89\xd3\xff'\xae \x92\x93\xfb\x93\x89\x15\xaf\x88\r\x8c\u06c3\x00\x00\xe0\x94\x8c\x81A\x0e\xa85L\xc5\xc6\\A\xbe\x8b\xd5\xdes<\v\x11\x1d\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\x8c\x83\xd4$\xa3\xcf$\xd5\x1f\x01\x92=\xd5J\x18\u05b6\xfe\xde{\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8c\x90\n\x826\xb0\x8c+e@]9\xd7_ \x06*ua\xfd\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\x8c\x93\xc3\xc6\u06dd7q}\xe1e\u00e1\xb4\xfeQ\x95,\b\u0789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8c\x99\x95\x91\xfdr\xefq\x11\xef\xcaz\x9e\x97\xa25k;\x00\n\x89\xddd\xe2\xaa\ngP\x00\x00\u07d4\x8c\xa6\x98\x97F\xb0n2\xe2Hta\xb1\u0399j':\xcf\u05c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8c\xb3\xaa?\xcd!(T\xd7W\x8f\xcc0\xfd\xed\xe6t*1*\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x8c\xc0\xd7\xc0\x16\xfaz\xa9P\x11J\xa1\xdb\tH\x82\xed\xa2t\xea\x89\b\xa9\xab\xa5W\xe3l\x00\x00\u07d4\x8c\xc6R\xdd\x13\xe7\xfe\x14\u06bb\xb3m]2\r\xb9\xff\xee\x8aT\x89a\t=|,m8\x00\x00\u07d4\x8c\u02bf%\a\u007f:\xa4\x15E4MS\xbe\x1b+\x9c3\x90\x00\x89[\xe8f\xc5b\xc5D\x00\x00\u07d4\x8c\xcf:\xa2\x1a\xb7BWj\xd8\xc4\"\xf7\x1b\xb1\x88Y\x1d\ua28965\u026d\xc5\u07a0\x00\x00\u07d4\x8c\xd0\xcd\"\xe6 \xed\xa7\x9c\x04a\xe8\x96\xc9\xd1b)\x12K_z\xfb\xec\x89\a?u\u0460\x85\xba\x00\x00\u07d4\x8c\xe2/\x9f\xa3rD\x9aB\x06\x10\xb4z\xe0\xc8\xd5eH\x122\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x8c\u451d\x8a\x16T-B<\x17\x98Ng9\xfar\u03b1w\x8a\x05K@Y&\xf4\xa6=\x80\x00\u07d4\x8c\xe5\xe3\xb5\xf5\x91\xd5\uc8ca\xbf\"\x8f.<5\x13K\xda\xc0\x89}\xc3[\x84\x89|8\x00\x00\xe0\x94\x8c\xee8\xd6YW\x88\xa5n?\xb9F4\xb3\xff\xe1\xfb\xdb&\u058a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x8c\xee\xa1^\xec;\xda\xd8\x02?\x98\xec\xf2[+\x8f\xef'\xdb)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8c\xf3To\xd1\u0363=X\x84_\xc8\xfc\xfe\u02bc\xa7\xc5d*\x89\x1f\x1e9\x93,\xb3'\x80\x00\u07d4\x8c\xf6\xda\x02\x04\xdb\u0106\vF\xad\x97?\xc1\x11\x00\x8d\x9e\fF\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x8c\xfe\xde\xf1\x98\xdb\n\x91C\xf0\x91)\xb3\xfdd\u073b\x9bIV\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\x04\xa5\xeb\xfb]\xb4\t\xdb\x06\x17\xc9\xfaV1\xc1\x92\x86\x1fJ\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x8d\x06\xe4d$\\\xadaI9\xe0\xaf\bE\xe6\xd70\xe2\x03t\x89\n\u070a(\xf3\xd8}\x80\x00\u07d4\x8d\a\xd4-\x83\x1c-|\x83\x8a\xa1\x87+:\xd5\xd2w\x17h#\x89\x12\xee\x1f\x9d\xdb\xeeh\x00\x00\u07d4\x8d\v\x9e\xa5?\xd2cA^\xac\x119\x1f|\xe9\x12V\xb9\xfb\x06`\xf6\xf0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8dy\\_JV\x89\xadb\u0696\x16q\xf0(\x06R\x86\xd5T\x89o\x05\xb5\x9d; \x00\x00\x00\u07d4\x8d\u007f>a)\x9c-\xb9\xb9\xc0H|\xf6'Q\x9e\xd0\n\x91#\x89^t\xa8P^\x80\xa0\x00\x00\xe0\x94\x8d\x89\x17\v\x92\xb2\xbe,\b\xd5|H\xa7\xb1\x90\xa2\xf1Fr\x0f\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\x8d\x93\xda\u01c5\xf8\x8f\x1a\x84\xbf\x92}Se+E\xa1T\xcc\u0749\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x8d\x99R\u043bN\xbf\xa0\xef\xd0\x1a:\xa9\xe8\xe8\u007f\x05%t.\x89\xbb\x91%T\"c\x90\x00\x00\u07d4\x8d\x9a\fp\xd2& B\xdf\x10\x17\xd6\xc3\x03\x13 $w'\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\x9e\xd7\xf4U0X\xc2ox6\xa3\x80-0d\xeb\x1b6=\x89\x04\xe1\x00;(\xd9(\x00\x00\u07d4\x8d\xa1\x17\x8fU\xd9wr\xbb\x1d$\x11\x1a@JO\x87\x15\xb9]\x89/\x9a\xc3\xf6\xde\x00\x80\x80\x00\u07d4\x8d\xa1\xd3Y\xbal\xb4\xbc\xc5}zCw \xd5]\xb2\xf0\x1cr\x89\x04V9\x18$O@\x00\x00\u07d4\x8d\xab\x94\x8a\xe8\x1d\xa3\x01\xd9r\xe3\xf6\x17\xa9\x12\xe5\xa7Sq.\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x8d\xad\xdfR\xef\xbdt\u0695\xb9i\xa5GoO\xbb\xb5c\xbf\u0489-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4\x8d\xb1\x85\xfe\x1bp\xa9Jj\b\x0e~#\xa8\xbe\xdcJ\xcb\xf3K\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x8d\xb5\x8e@n -\xf9\xbcpl\xb43\xe1\x94\xf4\x0f\x82\xb4\x0f\xaa\xdb\x1f\x8b\x85a\x16\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x8d\xc1\xd5\x11\x1d\t\xaf%\xfd\xfc\xacE\\|\xec(>mgu\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8d\u0504\xff\x8a0sd\xebf\xc5%\xa5q\xaa\xc7\x01\xc5\xc3\x18\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\u05a9\xba\xe5\u007fQ\x85I\xad\xa6wFo\ua2b0O\u0674\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\xde<\xb8\x11\x85h\xefE\x03\xfe\x99\x8c\xcd\xf56\xbf\x19\xa0\x98\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8d\xde`\xeb\b\xa0\x99\xd7\u06a3V\u06aa\xb2G\r{\x02Zk\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\x8d\xf39!Kj\u0472Fc\xceq`4t\x9dn\xf88\u064a\x02TO\xaaw\x80\x90\xe0\x00\x00\xe0\x94\x8d\xf5=\x96\x19\x14q\xe0Y\xdeQ\xc7\x18\xb9\x83\xe4\xa5\x1d*\xfd\x8a\x06\u01b95\xb8\xbb\xd4\x00\x00\x00\u07d4\x8d\xfb\xaf\xbc\x0e[\\\x86\xcd\x1a\u0597\xfe\xea\x04\xf41\x88\u0796\x89\x15%+\u007f_\xa0\xde\x00\x00\u07d4\x8e\a;\xad%\xe4\"\x18a_J\x0ek.\xa8\xf8\xde\"0\xc0\x89\x82=b\x9d\x02k\xfa\x00\x00\u07d4\x8e\x0f\xee8hZ\x94\xaa\xbc\xd7\u0385{k\x14\t\x82Ou\xb8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e#\xfa\xcd\x12\xc7e\xc3j\xb8\x1am\xd3M\x8a\xa9\xe6\x89\x18\xae\x89\t\x11\u418d\xba\x9b\x00\x00\xe0\x94\x8e/\x904\xc9%G\x19\u00ceP\u026ad0^\u0596\xdf\x1e\x8a\x01\x00N.E\xfb~\xe0\x00\x00\u07d4\x8e2@\xb0\x81\x0e\x1c\xf4\a\xa5\x00\x80G@\u03cdad2\xa4\x89\x02/fU\xef\v8\x80\x00\u07d4\x8eHj\x04B\xd1q\xc8`[\xe3H\xfe\xe5~\xb5\b^\xff\r\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8eaV3k\xe2\u037e2\x14\r\xf0\x8a+\xa5_\u0425\x84c\x89\x04\t\x9e\x1dcW\x18\x00\x00\u07d4\x8eg\b\x15\xfbg\xae\xae\xa5{\x86SN\xdc\x00\xcd\xf5d\xfe\u5272\xe4\xb3#\xd9\xc5\x10\x00\x00\u07d4\x8emt\x85\xcb\u942c\xc1\xad\x0e\xe9\xe8\xcc\xf3\x9c\f\x93D\x0e\x893\xc5I\x901r\f\x00\x00\xe0\x94\x8et\xe0\u0477~\xbc\x82:\xca\x03\xf1\x19\x85L\xb1 '\xf6\u05ca\x16\xb3R\xda^\x0e\xd3\x00\x00\x00\u07d4\x8ex\xf3QE}\x01oJ\xd2u^\xc7BN\\!\xbamQ\x89\a\xea(2uw\b\x00\x00\u07d4\x8ey6\u0552\x00\x8f\xdcz\xa0N\xde\xebuZ\xb5\x13\u06f8\x9d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8e\u007f\xd28H\xf4\xdb\a\x90j}\x10\xc0K!\x80;\xb0\x82'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8e\x92\xab\xa3\x8er\xa0\x98\x17\v\x92\x95\x92FSz.UV\xc0\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x8e\x98ve$\xb0\xcf'G\xc5\r\xd4;\x95gYM\x971\u0789lD\xb7\xc2a\x82(\x00\x00\u07d4\x8e\x9b5\xadJ\n\x86\xf7XDo\xff\xde4&\x9d\x94\f\xea\u0349\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8e\x9c\b\xf78f\x1f\x96v#n\xff\x82\xbaba\xdd?H\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8e\x9cB\x92f\xdf\x05~\xfax\xdd\x1d_w\xfc@t*\xd4f\x89\x10D.\u0475l|\x80\x00\u07d4\x8e\xa6V\xe7\x1e\xc6Q\xbf\xa1|ZWY\xd8`1\xcc5\x99w\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x8e\xae)CU\x98\xba\x8f\x1c\x93B\x8c\xdb>+M1\a\x8e\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\xb1\xfb\xe4\xe5\xd3\x01\x9c\xd7\xd3\r\xae\x9c\r[Lv\xfbc1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\xb5\x17t\xaf k\x96k\x89\t\xc4Z\xa6r'H\x80,\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e\xb8\xc7\x19\x82\xa0\x0f\xb8Bu)2S\xf8\x04ED\xb6kI\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\x8e\xcb\u03ec\xbf\xaf\xe9\xf0\f9\"\xa2N,\xf0\x02gV\xca \x8a\x011\xbe\xb9%\xff\xd3 \x00\x00\u07d4\x8e\u03b2\xe1$Sl[_\xfcd\x0e\xd1O\xf1^\u0668\xcbq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8e\u042f\x11\xff(p\xda\x06\x81\x00J\xfe\x18\xb0\x13\xf7\xbd8\x82\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\x8e\xd1Cp\x1f/r(\x0f\xd0J{Ad(\x19y\xea\x87\u0248\xc2I\xfd\xd3'x\x00\x00\u07d4\x8e\xd1R\x8bD~\xd4)y\x02\xf69\xc5\x14\u0414J\x88\xf8\u0209\n\xc6\xe7z\xb6c\xa8\x00\x00\u07d4\x8e\xd4(L\x0fGD\x9c\x15\xb8\u0673$]\u8fb6\u0380\xbf\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\x8e\xde~=\xc5\aI\xc6\xc5\x0e.(\x16\x84x\xc3M\xb8\x19F\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\x8e\xe5\x843}\xdb\xc8\x0f\x9e4\x98\xdfU\xf0\xa2\x1e\xac\xb5\u007f\xb1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x8e\xeb\xec\x1ab\xc0\x8b\x05\xa7\xd1\u0551\x80\xaf\x9f\xf0\u044e?6\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x8e\xf4\u0622\xc2o\xf7\x14\xb6u\x89\x19\x80\x1c\x83\xb6\xc7\xc0\x00\x00\u07d4\x8fM\x1dAi>F,\xf9\x82\xfd\x81\u042ap\x1d:St\u0249\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8fM\x1e~Ea(J4\xfe\xf9g<\r4\xe1*\xf4\xaa\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8fO\xb1\xae\xa7\xcd\x0fW\x0e\xa5\xe6\x1b@\xa4\xf4Q\vbd\xe4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x8fV\x1bA\xb2\t\xf2H\u0229\x9f\x85\x87\x887bP`\x9c\xf3\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94\x8fX\xd84\x8f\xc1\xdcN\r\xd84;eC\xc8W\x04^\xe9@\x8a\x02\xe3\x03\x8d\xf4s\x03(\x00\x00\u07d4\x8f`\x89_\xbe\xbb\xb5\x01\u007f\xcb\xff<\u0763\x97)+\xf2[\xa6\x89\x17D\x06\xff\x9fo\u0480\x00\u07d4\x8fd\xb9\xc1$m\x85x1d1\a\xd3U\xb5\xc7_\xef]O\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\x8ff\x0f\x8b.L|\u00b4\xac\x9cG\xed(P\x8d_\x8f\x86P\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x8fi\xea\xfd\x023\xca\xdb@Y\xabw\x9cF\xed\xf2\xa0PnH\x89`\xf0f \xa8IE\x00\x00\xe0\x94\x8fq~\xc1U/LD\x00\x84\xfb\xa1\x15J\x81\xdc\x00>\xbd\xc0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\x8f\x8a\xcb\x10v\a8\x84y\xf6K\xaa\xab\xea\x8f\xf0\a\xad\xa9}\x8a\x05\xc6\xf3\b\n\xd4#\xf4\x00\x00\u07d4\x8f\x8c\xd2n\x82\xe7\xc6\xde\xfd\x02\u07ed\a\x97\x90!\xcb\xf7\x15\f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x8f\x8f7\u042d\x8f3]*q\x01\xb4\x11V\xb6\x88\xa8\x1a\x9c\xbe\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\x8f\x92\x84O(*\x92\x99\x9e\u5d28\xd7s\xd0kiM\xbd\x9f\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x8f\xact\x8fxJ\x0f\xedh\u06e43\x19\xb4*u\xb4d\x9cn\x891T\xc9r\x9d\x05x\x00\x00\u07d4\x8f\u0665\xc3:}\x9e\xdc\xe0\x99{\xdfw\xab0d$\xa1\x1e\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x8f\xef\xfa\xdb8z\x15G\xfb(M\xa9\xb8\x14\u007f>|m\xc6\u0689-b{\xe4S\x05\b\x00\x00\u07d4\x8f\xf4`Ehw#\xdc3\xe4\u0419\xa0i\x04\xf1\ubd44\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\x8f\xfa\x06!\"\xac0t\x18\x82\x1a\u06d3\x11\aZ7\x03\xbf\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x8f\xfe2)\x97\xb8\xe4\x04B-\x19\xc5J\xad\xb1\x8f[\xc8\u9dc9\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x90\x01\x94\u0131\aC\x05\u045d\xe4\x05\xb0\xacx(\x0e\xca\xf9g\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x90\x03\xd2p\x89\x1b\xa2\xdfd=\xa84\x15\x83\x195E\xe3\xe0\x00\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x90\x05z\xf9\xaaf0~\xc9\xf03\xb2\x97$\u04f2\xf4\x1e\xb6\xf9\x8a\x19\xd1\u05aa\xdb,R\xe8\x00\x00\u07d4\x90\x0f\v\x8e5\xb6h\xf8\x1e\xf2R\xb18U\xaaP\a\xd0\x12\xe7\x89\x17\n\x0fP@\xe5\x04\x00\x00\u07d4\x90\x18\xcc\x1fH\xd20\x8e%*\xb6\b\x9f\xb9\x9a|\x1dV\x94\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x90\x1d\x99\xb6\x99\xe5\u0191\x15\x19\xcb v\xb4\xc7c0\xc5M\"\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x90-t\xa1W\xf7\u04b9\xa37\x8b\x1fVp70\xe0:\x17\x19\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x904\x13\x87\x8a\xea;\xc1\bc\t\xa3\xfev\x8beU\x9e\x8c\xab\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x90If\xcc\"\x13\xb5\xb8\xcb[\xd6\b\x9e\xf9\xcd\xdb\xef~\xdf\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\x90L\xaaB\x9ca\x9d\x94\x0f\x8egA\x82j\r\xb6\x92\xb1\x97(\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x90R\xf2\xe4\xa3\xe3\xc1-\xd1\xc7\x1b\xf7\x8aN\xc3\x04=\u020b~\x89\x0e~\xeb\xa3A\vt\x00\x00\u0794\x90U&V\x8a\xc1#\xaf\xc0\xe8J\xa7\x15\x12O\xeb\xe8=\xc8|\x88\xf8i\x93)g~\x00\x00\u07d4\x90\x92\x91\x87\a\xc6!\xfd\xbd\x1d\x90\xfb\x80\xebx\u007f\xd2osP\x89\x85[[\xa6\\\x84\xf0\x00\x00\u07d4\x90\x9b^v:9\xdc\u01d5\"=s\xa1\u06f7\xd9L\xa7Z\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\x90\xac\xce\xd7\xe4\x8c\b\u01b94dm\xfa\n\xdf)\u0714\aO\x89\x03\vK\x15{\xbdI\x00\x00\u07d4\x90\xb1\xf3p\xf9\xc1\xeb\v\xe0\xfb\x8e+\x8a\xd9jAcq\u074a\x890\xca\x02O\x98{\x90\x00\x00\u07d4\x90\xb6/\x13\x1a_)\xb4UqQ>\xe7\xa7J\x8f\v#\"\x02\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x90\xbdb\xa0P\x84Ra\xfaJ\x9f|\xf2A\xeac\v\x05\ufe09\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x90\xc4\x1e\xba\x00\x8e \xcb\xe9'\xf3F`?\u0206\x98\x12Yi\x89\x02F\xdd\xf9yvh\x00\x00\u07d4\x90\u0480\x9a\xe1\xd1\xff\xd8\xf6>\xda\x01\xdeI\xddU-\xf3\u047c\x89\u063beI\xb0+\xb8\x00\x00\u07d4\x90\xdc\t\xf7\x17\xfc*[i\xfd`\xba\b\xeb\xf4\v\xf4\xe8$l\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x90\xe3\x00\xacqE\x1e@\x1f\x88\u007fnw(\x85\x16G\xa8\x0e\a\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x90\xe3Z\xab\xb2\xde\xef@\x8b\xb9\xb5\xac\xefqDW\xdf\xdebr\x89\x05l\xd5_\xc6M\xfe\x00\x00\u07d4\x90\xe7\a\x0fM\x03?\xe6\x91\f\x9e\xfeZ'\x8e\x1f\xc6#M\xef\x89\x05q8\b\x19\xb3\x04\x00\x00\u07d4\x90\xe9>M\xc1q!HyR36\x14\x00+\xe4#VI\x8e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x90\u9a68.\u06a8\x14\u0084\xd22\xb6\u9e90p\x1dIR\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\x90\xf7t\xc9\x14}\u0790\x85=\xdcC\xf0\x8f\x16\xd4U\x17\x8b\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x90\xfcS{!\x06Xf\n\x83\xba\xa9\xacJ\x84\x02\xf6WF\xa8\x89e\xea=\xb7UF`\x00\x00\u07d4\x91\x05\n\\\xff\xad\xed\xb4\xbbn\xaa\xfb\xc9\xe5\x014(\xe9l\x80\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x91\x05\x17d\xafk\x80\x8eB\x12\xc7~0\xa5W.\xaa1pp\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x91\v}Wz~9\xaa#\xac\xf6*\xd7\xf1\xef4)4\xb9h\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x91\x0e\x99eC4Lh\x15\xfb\x97\u0367\xafK\x86\x98vZ[\x89\x05\x9a\xf6\x98)\xcfd\x00\x00\u07d4\x91\x1f\xee\xa6\x1f\xe0\xedP\u0179\xe5\xa0\xd6`q9\x9d(\xbd\u0189\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x91\x1f\xf23\xe1\xa2\x11\xc0\x17,\x92\xb4l\xf9\x97\x03\x05\x82\xc8:\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x91 \xe7\x11s\xe1\xba\x19\xba\x8f\x9fO\xdb\u072a4\xe1\u05bbx\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91!\x17\x12q\x9f+\bM;8u\xa8Pi\xf4f61A\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x91#\x04\x11\x8b\x80G=\x9e\x9f\xe3\xeeE\x8f\xbea\x0f\xfd\xa2\xbb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x91Tky\xec\xf6\x9f\x93kZV\x15\b\xb0\xd7\xe5\f\u0159/\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x91V\u0440)5\x0eG\x04\b\xf1_\x1a\xa3\xbe\x9f\x04\ng\u018965\u026d\xc5\u07a0\x00\x00\u07d4\x91b\x0f>\xb3\x04\xe8\x13\u048b\x02\x97Ume\xdcN]\u5a89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\x91k\xf7\xe3\xc5E\x92\x1d2\x06\xd9\x00\xc2O\x14\x12|\xbd^p\x8a\x03\xd0\u077c}\xf2\xbb\x10\x00\x00\u0794\x91l\xf1}qA(\x05\xf4\xaf\xc3DJ\v\x8d\xd1\xd93\x9d\x16\x88\xc6s\xce<@\x16\x00\x00\u07d4\x91{\x8f\x9f:\x8d\t\xe9 ,R\u009erA\x96\xb8\x97\xd3^\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\x91\x89g\x91\x8c\u0617\xdd\x00\x05\xe3m\xc6\u0203\xefC\x8f\xc8\u01c9\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\x91\x89\x8e\xab\x8c\x05\xc0\"(\x83\xcdM\xb2;w\x95\xe1\xa2J\u05c9lk\x93[\x8b\xbd@\x00\x00\u0794\x91\x91\xf9F\x98!\x05\x16\xcfc!\xa1B\a\x0e Yvt\xed\x88\xee\x9d[\xe6\xfc\x11\x00\x00\u07d4\x91\xa4\x14\x9a,{\x1b:g\xea(\xaf\xf3G%\u0fcdu$\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x91\xa7\x87\xbcQ\x96\xf3HW\xfe\f7/M\xf3v\xaa\xa7f\x13\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91\xa8\xba\xae\xd0\x12\xea.c\x80;Y=\r\f*\xabL[\n\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x91\xac\\\xfeg\xc5J\xa7\xeb\xfb\xa4HflF\x1a;\x1f\xe2\xe1\x89\x15\xc94\x92\xbf\x9d\xfc\x00\x00\u07d4\x91\xbb?y\x02+\xf3\xc4S\xf4\xff%n&\x9b\x15\xcf,\x9c\xbd\x89RX\\\x13\xfe:\\\x00\x00\u07d4\x91\xc7^<\xb4\xaa\x89\xf3F\x19\xa1d\xe2\xa4x\x98\xf5gM\x9c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x91\xc8\f\xaa\b\x1b85\x1d*\x0e\x0e\x00\xf8\n4\xe5dt\xc1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x91\xccF\xaa7\x9f\x85jf@\xdc\xcdZd\x8ay\x02\xf8I\u0649\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x91\u04a9\xee\x1am\xb2\x0fS\x17\u0327\xfb\xe218\x95\u06ce\xf8\x8a\x01\xcc\u00e5/0n(\x00\x00\u07d4\x91\xd6n\xa6(\x8f\xaaK=`l*\xa4\\{k\x8a%'9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x91\u06f6\xaa\xad\x14\x95\x85\xbeG7\\]m\xe5\xff\t\x19\x15\x18\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x91\xe8\x81\x06R\xe8\xe6\x16\x15%\xd6;\xb7u\x1d\xc2\x0fg`v\x89'Mej\xc9\x0e4\x00\x00\u07d4\x91\xf5\x16\x14l\xda (\x17\x19\x97\x80`\u01beAI\x06|\x88\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x91\xf6$\xb2J\x1f\xa5\xa0V\xfeW\x12)\xe77\x9d\xb1K\x9a\x1e\x8a\x02\x8a\x85\x17\xc6i\xb3W\x00\x00\xe0\x94\x91\xfe\x8aLad\u07cf\xa6\x06\x99]k\xa7\xad\xca\xf1\u0213\u038a\x03\x99\x92d\x8a#\u0220\x00\x00\u07d4\x92\x1fRa\xf4\xf6\x12v\a\x06\x89&%\xc7^{\u0396\xb7\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92!\xc9\xce\x01#&et\x10\x96\xac\a#Y\x03\xad\x1f\xe2\xfc\x89\x06\xdbc3U\"b\x80\x00\u07d4\x92%\x988`\xa1\xcbF#\xc7$\x80\xac\x16'+\f\x95\xe5\xf5\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x92%\xd4jZ\x80\x949$\xa3\x9e[\x84\xb9m\xa0\xacE\x05\x81\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x92* \u01da\x1d:&\xdd8)g{\xf1\xd4\\\x8fg+\xb6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x92C\x8eR\x03\xb64o\xf8\x86\xd7\xc3b\x88\xaa\xcc\xccx\xce\u028965\u026d\xc5\u07a0\x00\x00\u07d4\x92C\xd7v-w({\x12c\x86\x88\xb9\x85N\x88\xa7i\xb2q\x8965\u026d\xc5\u07a0\x00\x00\u0794\x92K\xcez\x85<\x97\v\xb5\xec{\xb7Y\xba\xeb\x9ct\x10\x85{\x88\xbe -j\x0e\xda\x00\x00\u07d4\x92N\xfam\xb5\x95\xb7\x93\x13'~\x881\x96%\akX\n\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92U\x82&\xb3\x84bl\xadH\xe0\x9d\x96k\xf19^\xe7\xea]\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4\x92`\x82\xcb~\xedK\x19\x93\xad$ZGrg\xe1\xc3<\xd5h\x89\x14Jt\xba\u07e4\xb6\x00\x00\u07d4\x92b\t\xb7\xfd\xa5N\x8d\u06dd\x9eM=\x19\xeb\u070e\x88\u009f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92h\xd6&FV6\x11\xdc;\x83*0\xaa#\x94\xc6F\x13\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92i\x8e4Sx\xc6-\x8e\xda\x18M\x946j\x14K\f\x10[\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\x92y:\u0173rhwJq0\xde+\xbd3\x04\x05f\x17s\x89\x02,\xa3X|\xf4\xeb\x00\x00\xe0\x94\x92y\xb2\"\x8c\xec\x8f{M\xda?2\x0e\x9a\x04f\xc2\xf5\x85\u028a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x92|\xb7\xdc\x18p6\xb5B{\xc7\xe2\x00\xc5\xecE\f\x1d'\u0509\v\xb5\x9a'\x95<`\x00\x00\u07d4\x92|\u00bf\xda\x0e\b\x8d\x02\xef\xf7\v8\xb0\x8a\xa5<\xc3\tA\x89do`\xa1\xf9\x866\x00\x00\xe0\x94\x92\x84\xf9m\xdbG\xb5\x18n\xe5X\xaa12M\xf56\x1c\x0fs\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\x92\x9d6\x8e\xb4j-\x1f\xbd\xc8\xff\xa0`~\xdeK\xa8\x8fY\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xa7\u0166Cb\xe9\xf8B\xa2=\xec\xa2\x105\x85\u007f\x88\x98\x00\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\x92\xa8\x98\xd4o\x19q\x9c8\x12j\x8a<'\x86z\xe2\xce\u5589lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xa9q\xa79y\x9f\x8c\xb4\x8e\xa8G]r\xb2\xd2GAr\xe6\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x92\xaa\xe5\x97h\xed\xdf\xf8<\xfe`\xbbQ.s\n\x05\xa1a\u05c9\\\x97xA\fv\u0440\x00\u07d4\x92\xad\x1b=u\xfb\xa6}Tf=\xa9\xfc\x84\x8a\x8a\xde\x10\xfag\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xae[|~\xb4\x92\xff\x1f\xfa\x16\xddB\xad\x9c\xad@\xb7\xf8\u0709.\xe4IU\b\x98\xe4\x00\x00\u07d4\x92\xc0\xf5s\xec\xcfb\xc5H\x10\xeek\xa8\xd1\xf1\x13T+0\x1b\x89\xb7ro\x16\u0331\xe0\x00\x00\u07d4\x92\xc1?\xe0\xd6\u0387\xfdP\xe0=\uf7e6@\x05\t\xbdps\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x92\xc9L( \xdf\xcfqV\xe6\xf10\x88\xec\u754b6v\xfd\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4\x92\xcf\xd6\x01\x88\xef\u07f2\xf8\xc2\xe7\xb1i\x8a\xbb\x95&\xc1Q\x1f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\u062d\x9aMah;\x80\u0526g.\x84\xc2\rbB\x1e\x80\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x92\u0725\xe1\x02\xb3\xb8\x1b`\xf1\xa5\x04cIG\xc3t\xa8\x8c\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x92\xe454\x0e\x9d%<\x00%c\x89\xf5+\x06}U\x97Nv\x89\x0e\x87?D\x13<\xb0\x00\x00\xe0\x94\x92\xe49(\x16\xe5\xf2\xef_\xb6X7\xce\xc2\xc22\\\xc6I\"\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x92\xe6X\x1e\x1d\xa1\xf9\xb8F\xe0\x93G3=\xc8\x18\xe2\u04acf\x89\xc5S%\xcat\x15\xe0\x00\x00\u07d4\x93\x1d\xf3M\x12%\xbc\xd4\"Nch\r\\L\t\xbc\xe75\xa6\x89\x03\xaf\xb0\x87\xb8v\x90\x00\x00\u07d4\x93\x1f\xe7\x12\xf6B\a\xa2\xfdP\"r\x88CT\x8b\xfb\x8c\xbb\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x93#_4\r(c\xe1\x8d/LR\x99e\x16\x13\x8d\"\x02g\x89\x04\x00.D\xfd\xa7\xd4\x00\x00\u07d4\x93%\x82U\xb3|\u007fX\xf4\xb1\x06s\xa92\xdd:\xfd\x90\xf4\xf2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x93(\xd5\\\xcb?\xceS\x1f\x19\x93\x823\x9f\x0eWn\xe8@\xa3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x93)\xff\xdc&\x8b\xab\u0788t\xb3f@l\x81D[\x9b-5\x89\x16\xe6/\x8cs\f\xa1\x80\x00\u07d4\x93+\x9c\x04\xd4\r*\xc80\x83\xd9B\x98\x16\x9d\xae\x81\xab.\u0409lk\x93[\x8b\xbd@\x00\x00\u07d4\x9346\xc8G&U\xf6L:\xfa\xaf|Lb\x1c\x83\xa6+8\x8965\u026d\xc5\u07a0\x00\x00\u0794\x93;\xf3?\x82\x99p+:\x90&B\xc3>\v\xfa\xea\\\x1c\xa3\x88\xd2\xf1?w\x89\xf0\x00\x00\u07d4\x93@4\\\xa6\xa3\uaf77sc\xf2X`C\xf2\x948\xce\v\x89\x1c\xc8\x05\xda\r\xff\xf1\x00\x00\xe0\x94\x93@\xb5\xf6x\xe4^\xe0^\xb7\b\xbbz\xbbn\xc8\xf0\x8f\x1bk\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x93J\xf2\x1b~\xbf\xa4g\xe2\xce\xd6Z\xa3N\xdd:\x0e\xc7\x132\x8a\a\x80\x1f>\x80\xcc\x0f\xf0\x00\x00\xe0\x94\x93PiDJj\x98M\xe2\bNFi*\xb9\x9fg\x1f\xc7'\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\xe0\x94\x93P~\x9e\x81\x19\xcb\xce\u068a\xb0\x87\xe7\xec\xb0q8=i\x81\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\x93g\x8a\x00\x00\xe0\x94\x93m\xcf\x00\x01\x94\xe3\xbf\xf5\n\u0174$:;\xa0\x14\xd6a\u060a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x93o8\x13\xf5\xf6\xa1;\x8eO\xfe\xc8?\xe7\xf8&\x18jq\u0349\x1c0s\x1c\xec\x03 \x00\x00\u07d4\x93t\x86\x9dJ\x99\x11\xee\x1e\xafU\x8b\xc4\u00b6>\xc6:\xcf\u074965\u026d\xc5\u07a0\x00\x00\u07d4\x93uc\u0628\x0f\u05657\xb0\xe6m \xa0%%\xd5\u0606`\x89\x87\x86x2n\xac\x90\x00\x00\u07d4\x93v\xdc\xe2\xaf.\xc8\xdc\xdat\x1b~sEfF\x81\xd96h\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x93\x86\x8d\xdb*yM\x02\xeb\xda/\xa4\x80|v\xe3`\x98X\u0709m\xee\x15\xfc|$\xa7\x80\x00\xe0\x94\x93\x9cC\x13\xd2(\x0e\xdf^\a\x1b\xce\xd8F\x06?\n\x97]T\x8a\x19i6\x89t\xc0[\x00\x00\x00\xe0\x94\x93\xa6\xb3\xabB0\x10\xf9\x81\xa7H\x9dJ\xad%\xe2b\\WA\x8a\x04F\x80\xfej\x1e\xdeN\x80\x00\u07d4\x93\xaa\x8f\x92\xeb\xff\xf9\x91\xfc\x05^\x90ne\x1a\xc7h\xd3+\u02092\xf5\x1e\u06ea\xa30\x00\x00\u07d4\x93\xb4\xbf?\xdf\xf6\xde?NV\xbamw\x99\xdcK\x93\xa6T\x8f\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4\x93\xbc}\x9aJ\xbdD\u023b\xb8\xfe\x8b\xa8\x04\xc6\x1a\xd8\xd6Wl\x89\xd8\xd6\x11\x9a\x81F\x05\x00\x00\u07d4\x93\xc2\xe6N]\xe5X\x9e\xd2P\x06\xe8C\x19n\xe9\xb1\xcf\v>\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\x93\u020e-\x88b\x1e0\xf5\x8a\x95\x86\xbe\xd4\t\x89\x99\xebg\u074a\x06\x9bZ\xfa\xc7P\xbb\x80\x00\x00\u07d4\x93\xe0\xf3~\xcd\xfb\x00\x86\xe3\xe8b\xa9p4D{\x1eM\xec\x1a\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\xe0\x94\x93\xe3\x03A\x1a\xfa\xf6\xc1\a\xa4A\x01\u026c[6\xe9\xd6S\x8b\x8a\r\xf9\xdd\xfe\xcd\x03e@\x00\x00\u07d4\x93\xf1\x8c\xd2R`@v\x14\x88\xc5\x13\x17M\x1eycv\x8b,\x89\x82\xff\xac\x9a\u0553r\x00\x00\u07d4\x94\x0fqQ@P\x9f\xfa\xbf\x97EF\xfa\xb3\x90\"\xa4\x19R\u0489K\xe4\xe7&{j\xe0\x00\x00\u07d4\x94,k\x8c\x95[\xc0\u0608\x12g\x8a#g%\xb3'9\xd9G\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\x94=7\x86JJS}5\xc8\u0657#\xcdd\x06\xce%b\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94C\x9c\xa9\xcc\x16\x9ay\u0520\x9c\xae^gvJo\x87\x1a!\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x94D\x9c\x01\xb3*\u007f\xa5Z\xf8\x10OB\xcd\xd8D\xaa\x8c\xbc@\x8a\x03\x81\x11\xa1\xf4\xf0<\x10\x00\x00\xe0\x94\x94E\xba\\0\xe9\x89a\xb8`$a\xd08]@\xfb\xd8\x03\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x94O\a\xb9o\x90\xc5\xf0\xd7\xc0\u0140S1I\xf3\xf5\x85\xa0x\x89\x04\x02\xf4\xcf\xeeb\xe8\x00\x00\u07d4\x94T\xb3\xa8\xbf\xf9p\x9f\xd0\u1407~l\xb6\u0219t\xdb\u0589\x90\xf54`\x8ar\x88\x00\x00\u07d4\x94]\x96\xeaW>\x8d\xf7&+\xbf\xa5r\"\x9bK\x16\x01k\x0f\x89\vX\x9e\xf9\x14\xc1B\x00\x00\u07d4\x94^\x18v\x9d~\xe7'\xc7\x01?\x92\xde$\xd1\x17\x96\u007f\xf3\x17\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94a'\x81\x03;W\xb1F\xeet\xe7S\xc6r\x01\u007fS\x85\xe4\x89\xc3(\t>a\xee@\x00\x00\xe0\x94\x94dJ\xd1\x16\xa4\x1c\xe2\xca\u007f\xbe\xc6\t\xbd\xefs\x8a*\xc7\u01ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x94p\xcc6YE\x86\x82\x18!\xc5\u0256\xb6\xed\xc8;mZ2\x89\x01M\x11 \u05f1`\x00\x00\xe0\x94\x94u\xc5\x10\xec\x9a&\x97\x92GtL=\x8c;\x0e\v_D\u04ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x94~\x11\xe5\xea)\ro\u00f3\x80H\x97\x9e\f\xd4N\xc7\xc1\u007f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94\x83\u064f\x14\xa3?\xdc\x11\x8d@9U\u00995\xed\xfc_p\x89\x18\xea;4\xefQ\x88\x00\x00\u07d4\x94\x911\xf2\x89C\x92\\\xfc\x97\xd4\x1e\f\xea\v&)s\xa70\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\x94\x9f\x84\xf0\xb1\xd7\u0127\xcfI\xee\u007f\x8b,J\x13M\xe3(x\x89%\"H\u07b6\xe6\x94\x00\x00\u07d4\x94\x9f\x8c\x10{\xc7\xf0\xac\xea\xa0\xf1pR\xaa\xdb\xd2\xf9s+.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x94\xa7\u0368\xf4\x81\xf9\u061dB\xc3\x03\xae\x162\xb3\xb7\t\xdb\x1d\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x94\xa9\xa7\x16\x911| d'\x1bQ\xc95?\xbd\xed5\x01\xa8\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x94\xadK\xad\x82K\xd0\ub7a4\x9cX\u03bc\xc0\xff^\b4k\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\x94\xbb\xc6}\x13\xf8\x9e\xbc\xa5\x94\xbe\x94\xbcQp\x92\f0\xd9\xf3\x89\x04X\xff\xa3\x15\nT\x00\x00\u07d4\x94\xbe:\xe5Ob\xd6c\xb0\xd4\u031e\x1e\xa8\xfe\x95V\ua7bf\x89\x01C\x13,\xa8C\x18\x00\x00\xe0\x94\x94\xc0U\xe8X5z\xaa0\xcf A\xfa\x90Y\xce\x16J\x1f\x91\x8a\x04<%\xe0\xdc\xc1\xbd\x1c\x00\x00\xe0\x94\x94\xc7B\xfdz\x8by\x06\xb3\xbf\xe4\xf8\x90O\xc0\xbe\\v\x803\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x94\xcaV\xdew\u007f\xd4S\x17\u007f^\x06\x94\xc4x\xe6j\xff\x8a\x84\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x94\xd8\x10t\xdbZ\xe1\x97\u04bb\x13s\xab\x80\xa8}\x12\x1cK\u04ca\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x94\u06c0xs\x86\n\xac=Z\xea\x1e\x88^R\xbf\xf2\x86\x99T\x89\xae\x8ez\v\xb5u\xd0\x00\x00\u07d4\x94\xe1\xf5\u02db\x8a\xba\xce\x03\xa1\xa6B\x82VU;i\f#U\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x94\xef\x8b\xe4Pw\xc7\xd4\xc5e'@\u0794jbbOq?\x89\x05l\xf5Y:\x18\xf8\x80\x00\u07d4\x94\xf1?\x9f\b6\xa3\xee$7\xa8I\"\u0498M\xc0\xf7\xd5;\x89\xa2\xa02\x9b\u00ca\xbe\x00\x00\u07d4\x94\xf8\xf0W\xdb~`\xe6u\xad\x94\x0f\x15X\x85\u0464w4\x8e\x89\x15\xbeat\xe1\x91.\x00\x00\xe0\x94\x94\xfc\u03ad\xfe\\\x10\x9c^\xae\xafF-C\x871B\u020e\"\x8a\x01\x045a\xa8\x82\x93\x00\x00\x00\u07d4\x95\x03N\x16!\x86Q7\xcdG9\xb3F\xdc\x17\xda:'\xc3N\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\x95\fh\xa4\t\x88\x15M#\x93\xff\xf8\xda|\u0369\x96\x14\xf7,\x89\xf9AF\xfd\x8d\xcd\xe5\x80\x00\xe0\x94\x95\x0f\xe9\xc6\xca\xd5\f\x18\xf1\x1a\x9e\xd9\xc4W@\xa6\x18\x06\x12\u040a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x95!\x83\xcf\u04ce5.W\x9d6\xde\xce\u0171\x84P\xf7\xfb\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95'\x8b\b\xde\xe7\xc0\xf2\xc8\xc0\xf7\"\xf9\xfc\xbb\xb9\xa5$\x1f\u0689\x82\x93\t\xf6O\r\xb0\x00\x00\u07d4\x95,W\xd2\xfb\x19Q\a\xd4\xcd\\\xa3\x00wA\x19\u07ed/x\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x955r\xf0\xeam\xf9\xb1\x97\xca\xe4\x0eK\x8e\xcc\x05lCq\u014965\u026d\xc5\u07a0\x00\x00\u07d4\x95>\xf6R\xe7\xb7i\xf5=nxjX\x95/\xa9>\xe6\xab\u725b\ny\x1f\x12\x110\x00\x00\u07d4\x95DpF1;/:^\x19\xb9H\xfd;\x8b\xed\xc8,q|\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x95]\xb3\xb7C`\xb9\xa2hg~s\u03a8!f\x8a\xf6\xfa\u038a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\x95`\xe8\xacg\x18\xa6\xa1\xcd\xcf\xf1\x89\xd6\x03\xc9\x06>A=\xa6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x95g\xa0\u0781\x1d\xe6\xff\t[~\xe6N\u007f\x1b\x83\xc2a[\x80\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\x95h\x1c\xda\xe6\x9b I\xce\x10\x1e2\\u\x98\x92\xca\xc3\xf8\x11\x89\x9a\xe9*\x9b\xc9L@\x00\x00\xe0\x94\x95h\xb7\xdeuV(\xaf5\x9a\x84T=\xe25\x04\xe1^A\xe6\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x95i\xc6:\x92\x84\xa8\x05bm\xb3\xa3.\x9d#c\x93GaQ\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x95\x80\x9e\x8d\xa3\xfb\xe4\xb7\xf2\x81\xf0\xb8\xb1q_B\x0f}}c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95\x9fW\xfd\xedj\xe3y\x13\xd9\x00\xb8\x1e_H\xa7\x93\"\xc6'\x89\r\xdb&\x10GI\x11\x80\x00\u07d4\x95\x9f\xf1\u007f\x1dQ\xb4s\xb4@\x10\x05'U\xa7\xfa\x8cu\xbdT\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x95\xa5w\xdc.\xb3\xael\xb9\xdf\xc7z\xf6\x97\xd7\xef\xdf\xe8\x9a\x01\x89\a_a\x0fp\xed \x00\x00\u07d4\x95\xcbm\x8acy\xf9J\xba\x8b\x88ViV,MD\x8eV\xa7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x95\xd5PB{ZQLu\x1ds\xa0\xf6\u049f\xb6]\"\xed\x10\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x95\u064d\f\x10i\x90\x8f\x06zR\xac\xac+\x8bSM\xa3z\xfd\x89oY\xb60\xa9)p\x80\x00\xe0\x94\x95\xdfN4E\xd7f&$\u010e\xbat\u03de\nS\xe9\xf72\x8a\v\xdb\xc4\x1e\x03H\xb3\x00\x00\x00\u07d4\x95\xe6\xa5K-_g\xa2JHu\xafu\x10|\xa7\xea\x9f\xd2\xfa\x89Hz\x9a0E9D\x00\x00\xe0\x94\x95\xe6\xf9=\xac\"\x8b\xc7XZ%sZ\xc2\xd0v\xcc:@\x17\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x95\xe7ad$\xcd\ta\xa7\x17'$t7\xf0\x06\x92r(\x0e\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x95\xe8\n\x82\xc2\f\xbe= `$,\xb9-sX\x10\xd04\xa2\x89\x01\xc3.F?\u0539\x80\x00\u07d4\x95\xf6-\x02C\xed\xe6\x1d\xad\x9a1e\xf59\x05'\rT\xe2B\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\x95\xfbZ\xfb\x14\xc1\uf6b7\xd1y\xc5\xc3\x00P?\xd6j^\xe2\x89\x01\xda\xf7\xa0+\r\xbe\x80\x00\u07d4\x96\x10Y\"\x02\u0082\xab\x9b\u0628\x84Q\x8b>\v\xd4u\x817\x89\x0e\x87?D\x13<\xb0\x00\x00\xe0\x94\x96\x1cY\xad\xc7E\x05\u0446M\x1e\xcf\u02ca\xfa\x04\x12Y<\x93\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\x96,\r\xec\x8a=FK\xf3\x9b\x12\x15\xea\xfd&H\n\xe4\x90\u0349l\x82\xe3\xea\xa5\x13\xe8\x00\x00\u07d4\x96,\xd2*\x8e\xdf\x1eONU\xb4\xb1]\xdb\xfb]\x9dT\x19q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x963K\xfe\x04\xff\xfaY\x02\x13\xea\xb3e\x14\xf38\xb8d\xb76\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x967\xdc\x12r=\x9cxX\x85B\uac02fO?\x03\x8d\x9d\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x96N\xabK'kL\u0618>\x15\xcar\xb1\x06\x90\x0f\xe4\x1f\u0389\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x96b\xee\x02\x19&h+1\xc5\xf2\x00\xceEz\xbe\xa7ll\xe9\x89$Y\x0e\x85\x89\xebj\x00\x00\xe0\x94\x96l\x04x\x1c\xb5\xe6}\xde25\xd7\xf8b\x0e\x1a\xb6c\xa9\xa5\x8a\x10\r P\xdacQ`\x00\x00\u07d4\x96pv\xa8w\xb1\x8e\xc1ZA[\xb1\x16\xf0n\xf3&E\u06e3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96{\xfa\xf7bC\u0379@\t\xae<\x8d5\x05\xe9\xc0\x80EK\xe0\xe8\x19\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x96\x92A\x91\xb7\xdfe[3\x19\xdcma7\xf4\x81\xa7:\x0f\xf3\x89\xd9\xec\xb4\xfd \x8eP\x00\x00\u07d4\x96\x96\x05!83\x8cr/\x11@\x81\\\xf7t\x9d\r;:t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x96\xa5_\x00\xdf\xf4\x05\xdcM\xe5\xe5\x8cW\xf6\xf6\xf0\xca\xc5]/\x89jf\x167\x9c\x87\xb5\x80\x00\u07d4\x96\xaaW?\xed/#4\x10\u06eeQ\x80\x14[#\xc3\x1a\x02\xf0\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x96\xadW\x9b\xbf\xa8\u06ce\xbe\xc9\u0486\xa7.Fa\xee\xd8\xe3V\x89:\v\xa4+\xeca\x83\x00\x00\u07d4\x96\xb44\xfe\x06W\xe4*\u0302\x12\xb6\x86Q9\xde\xde\x15\x97\x9c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x96\xb9\x06\xear\x9fFU\xaf\xe3\xe5}5'|\x96}\xfa\x15w\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x96\xd6-\xfdF\b\u007fb@\x9d\x93\xdd`a\x88\xe7\x0e8\x12W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96\xd9\u0328\xf5^\xea\x00@\xecn\xb3H\xa1wK\x95\xd9>\xf4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x96\xe7\xc0\xc9\u057f\x10\x82\x1b\xf1@\xc5X\xa1E\xb7\xca\xc2\x13\x97\x899>\xf1\xa5\x12|\x80\x00\x00\u07d4\x96\xeaj\u021a+\xac\x954{Q\u06e6=\x8b\xd5\xeb\xde\xdc\xe1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x96\xea\xfb\xf2\xfboM\xb9\xa46\xa7LE\xb5eDR\xe28\x19\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x96\xebR>\x83/P\n\x01}\xe1>\xc2\u007f]6lV\x0e\xff\x89\x10\xac\u03baC\xee(\x00\x00\u07d4\x96\xf0F*\xe6\xf8\xb9`\x88\xf7\xe9\u018ct\xb9\u062d4\xb3G\x89a\t=|,m8\x00\x00\u07d4\x96\xf8 P\vp\xf4\xa3\xe3#\x9da\x9c\xff\x8f\" u\xb15\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x96\xfeY\xc3\u06f3\xaa|\xc8\xcbbH\fe\xe5nb\x04\xa7\xe2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x96\xffoP\x99h\xf3l\xb4,\xbaH\xdb2\xf2\x1fVv\xab\xf8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x97\t8R*\xfb^\x8f\x99Hs\xc9\xfb\xdc&\xe3\xb3~1L\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x97\n\xbdS\xa5O\xcaJd) |\x18-MW\xbb9\u0520\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97\r\x8b\x8a\x00\x16\xd1C\x05O\x14\x9f\xb3\xb8\xe5P\xdc\a\x97\u01c965\u026d\xc5\u07a0\x00\x00\u07d4\x97,/\x96\xaa\x00\u03ca/ Z\xbc\xf8\x93|\fu\xf5\xd8\u0649\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97?N6\x1f\xe5\xde\u0358\x9dL\x8f}|\xc9y\x908]\xaf\x89\x15\x0f\x85C\xa3\x87B\x00\x00\u07d4\x97M\x05A\xabJG\xec\u007fu6\x9c\x00i\xb6J\x1b\x81w\x10\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u0794\x97M/\x17\x89_)\x02\x04\x9d\xea\xae\xcf\t\xc3\x04e\a@-\x88\xcc\x19\u00947\xab\x80\x00\u07d4\x97R\xd1O^\x10\x93\xf0qq\x1c\x1a\xdb\xc4\xe3\xeb\x1e\\W\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97V\xe1v\xc9\xefi>\xe1\xee\u01b9\xf8\xb1Q\xd3\x13\xbe\xb0\x99\x89A\rXj \xa4\xc0\x00\x00\u07d4\x97_7d\xe9{\xbc\xcfv|\xbd;y[\xa8m\x8b\xa9\x84\x0e\x89\x12\xc1\xb6\xee\xd0=(\x00\x00\xe0\x94\x97j\x18Sj\xf4\x18tBc\b\x87\x1b\xcd\x15\x12\xa7u\xc9\xf8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x97n<\xea\xf3\xf1\xafQ\xf8\u009a\xff]\u007f\xa2\x1f\x03\x86\xd8\xee\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x97w\xcca\xcfuk\xe3\xb3\xc2\f\xd4I\x1ci\xd2u\xe7\xa1 \x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x97\x81\v\xaf\xc3~\x840c2\xaa\xcb5\xe9*\xd9\x11\xd2=$\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x97\x8cC\f\xe45\x9b\x06\xbc,\xdf\\)\x85\xfc\x95\x0eP\xd5\u0209\x1a\x05V\x90\xd9\u06c0\x00\x00\u07d4\x97\x95\xf6C\x19\xfc\x17\xdd\x0f\x82a\xf9\xd2\x06\xfbf\xb6L\xd0\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97\x99\xca!\xdb\xcfi\xbf\xa1\xb3\xf7+\xacQ\xb9\xe3\xcaX|\xf9\x89\\(=A\x03\x94\x10\x00\x00\u07d4\x97\x9c\xbf!\xdf\xec\x8a\xce?\x1c\x19m\x82\u07d6%4\xdf9O\x89\x99\x91\xd4x\xddM\x16\x00\x00\u07d4\x97\x9dh\x1ca}\xa1o!\xbc\xac\xa1\x01\xed\x16\xed\x01Z\xb6\x96\x89e\xea=\xb7UF`\x00\x00\u07d4\x97\x9f0\x15\x8bWK\x99\x9a\xab4\x81\a\xb9\xee\xd8[\x1f\xf8\xc1\x894\x95tD\xb8@\xe8\x00\x00\u07d4\x97\xa8o\x01\xce?|\xfdDA3\x0e\x1c\x9b\x19\xe1\xb1\x06\x06\xef\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x97\xb9\x1e\xfesP\xc2\xd5~~@k\xab\x18\xf3a{\xcd\xe1J\x8a\x02\x1e\x19\x99\xbb\xd5\u04be\x00\x00\u07d4\x97\xd0\xd9r^;p\xe6u\x841s\x93\x8e\xd3q\xb6,\u007f\xac\x89\t79SM(h\x00\x00\u07d4\x97\xd9\xe4jv\x04\u05f5\xa4\xeaN\xe6\x1aB\xb3\xd25\x0f\xc3\xed\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x97\xdc&\xecg\n1\xe0\"\x1d*u\xbc]\xc9\xf9\f\x1fo\u0509\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\x97\xde!\xe4!\xc3\u007f\xe4\xb8\x02_\x9aQ\xb7\xb3\x90\xb5\xdfx\x04\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\x97\xe2\x89s\xb8`\xc5g@(\x00\xfb\xb6<\xe3\x9a\x04\x8a=y\x89\x05B%:\x12l\xe4\x00\x00\u07d4\x97\xe5\xcca'\xc4\xf8\x85\xbe\x02\xf4KB\xd1\u0230\xac\x91\u44c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x97\xf1\xfeL\x80\x83\xe5\x96!*\x18w(\xdd\\\xf8\n1\xbe\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\x97\xf7v\x06W\xc1\xe2\x02u\x90\x86\x96>\xb4!\x1c_\x819\xb9\x8a\n\x8a\t\u007f\xcb=\x17h\x00\x00\xe0\x94\x97\xf9\x9bk\xa3\x13F\u0358\xa9\xfeL0\x8f\x87\u0165\x8cQQ\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x98\n\x84\xb6\x86\xfc1\xbd\xc8<\"\x10XTjq\xb1\x1f\x83\x8a\x89*AUH\xaf\x86\x81\x80\x00\u07d4\x98\x10\xe3J\x94\xdbn\xd1V\xd08\x9a\x0e+\x80\xf4\xfdk\n\x8a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\x1d\xdf\x04\x04\xe4\xd2-\xdaUj\a&\xf0\v-\x98\xab\x95i\x8965f3\xeb\xd8\xea\x00\x00\xe0\x94\x98\x1fq'u\xc0\xda\xd9u\x18\xff\xed\xcbG\xb9\xad\x1dl'b\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\x984h!\x80\xb9\x82\xd1f\xba\u06dd\x9d\x1d\x9b\xbf\x01m\x87\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x986\xb4\xd3\x04sd\x1a\xb5j\xee\xe1\x92Bv\x1drrQx\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x989sB\xec_=L\xb8w\xe5N\xf5\xd6\xf1\xd3fs\x1b\u050a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\x98Fd\x886\xa3\a\xa0W\x18O\xd5\x1fb\x8a_\x8c\x12B|\x8a\x04\vi\xbfC\xdc\xe8\xf0\x00\x00\xe0\x94\x98Jy\x85\xe3\xcc~\xb5\xc96\x91\xf6\xf8\xcc{\x8f$]\x01\xb2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x98]p\xd2\a\x89+\xed9\x85\x90\x02N$!\xb1\xcc\x11\x93Y\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x98m\xf4~v\xe4\u05e7\x89\xcd\xee\x91<\u0243\x16P\x93l\x9d\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\x98t\x80?\xe1\xf3\xa06^y\"\xb1Bp\xea\xeb\x03,\xc1\xb5\x89<\xf5\x92\x88$\xc6\xc2\x00\x00\u07d4\x98ub4\x95\xa4l\xdb\xf2YS\x0f\xf88\xa1y\x9e\u00c9\x91\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98v\x18\xc8VV |{\xac\x15\a\xc0\xff\xef\xa2\xfbd\xb0\x92\x89\x03}\xfeC1\x89\xe3\x80\x00\u07d4\x98|\x9b\xcdn?9\x90\xa5+\xe3\xed\xa4q\f'Q\x8fOr\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x98\x82\x96|\xeeh\u04a89\xfa\u062bJ|=\xdd\xf6\xc0\xad\u0209Hx\xbe\x1f\xfa\xf9]\x00\x00\u07d4\x98\x85\\}\xfb\xee3SD\x90J\x12\xc4\fs\x17\x95\xb1:T\x899\xfb\xae\x8d\x04-\xd0\x00\x00\u07d4\x98\x9c\f\xcf\xf6T\xda\x03\xae\xb1\x1a\xf7\x01\x05Ea\xd6)~\x1d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x98\xa0\xe5Lm\x9d\u023e\x96'l\xeb\xf4\xfe\xc4`\xf6#]\x85\x89j\u0202\x10\tR\u01c0\x00\u07d4\x98\xb7i\xcc0\\\xec\xfbb\x9a\x00\xc9\a\x06\x9d~\xf9\xbc:\x12\x89\x01h\u048e?\x00(\x00\x00\xe0\x94\x98\xbaN\x9c\xa7/\xdd\xc2\fi\xb49ov\xf8\x18?z*N\x8a\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\x00\u07d4\x98\xbeimQ\xe3\x90\xff\x1cP\x1b\x8a\x0fc1\xb6(\xdd\u016d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\xbe\u04e7.\xcc\xfb\xaf\xb9#H\x92\x93\xe4)\xe7\x03\xc7\xe2[\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x98\xbfJ\xf3\x81\v\x84#\x87\xdbp\xc1MF\t\x96&\x00=\x10\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x98\xc1\x0e\xbf,O\x97\u02e5\xa1\xab?*\xaf\xe1\xca\xc4#\xf8\u02c9\x10CV\x1a\x88)0\x00\x00\u07d4\x98\xc1\x9d\xba\x81\v\xa6\x11\xe6\x8f/\x83\xee\x16\xf6\xe7tO\f\x1f\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x98\xc5IJ\x03\xac\x91\xa7h\xdf\xfc\x0e\xa1\xdd\u0b3f\x88\x90\x19\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\x98\xd2\x04\xf9\b_\x8c\x8e}\xe2>X\x9bd\xc6\xef\xf6\x92\xccc\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x98\xd3s\x19\x92\xd1\xd4\x0e\x12\x11\xc7\xf75\xf2\x18\x9a\xfa\a\x02\xe0\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x98\xe2\xb6\xd6\x06\xfd-i\x91\xc9\xd6\xd4\a\u007f\xdf?\xddE\x85\u06890\xdf\x1ao\x8a\xd6(\x00\x00\u07d4\x98\xe3\xe9\v(\xfc\xca\ue087y\xb8\xd4\nUh\xc4\x11n!\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\x98\xe6\xf5G\u06c8\xe7_\x1f\x9c\x8a\xc2\xc5\xcf\x16'\xbaX\v>\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x98\xf4\xaf:\xf0\xae\xde_\xaf\xdcB\xa0\x81\xec\xc1\xf8\x9e<\xcf \x8a\x01\xfd\x934\x94\xaa_\xe0\x00\x00\u07d4\x98\xf6\xb8\xe6!=\xbc\x9aU\x81\xf4\xcc\xe6e_\x95%+\xdb\a\x89\x11Xr\xb0\xbc\xa40\x00\x00\u07d4\x99\te\r\u05719{\x8b\x8b\x0e\xb6\x94\x99\xb2\x91\xb0\xad\x12\x13\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x99\x11s`\x19G\xc2\bJb\xd69R~\x96\x15\x12W\x9a\xf9\x89 \x86\xac5\x10R`\x00\x00\u07d4\x99\x12\x9d[<\f\xdeG\xea\r\xefM\xfc\a\r\x1fJY\x95'\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x99\x17\u058dJ\xf3A\xd6Q\xe7\xf0\a\\m\xe6\xd7\x14Nt\t\x8a\x012\xd4Gl\b\xe6\xf0\x00\x00\u07d4\x99\x1a\xc7\xcap\x97\x11_& ^\xee\x0e\xf7\xd4\x1e\xb4\xe3\x11\xae\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\x99#e\xd7d\xc5\xce5@9\xdd\xfc\x91.\x02:u\xb8\xe1h\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x99&F\xac\x1a\u02ab\xf5\u076b\xa8\xf9B\x9a\xa6\xa9Nt\x96\xa7\x8967Pz0\xab\xeb\x00\x00\u07d4\x99&\x83'\xc3s3.\x06\xc3\xf6\x16B\x87\xd4U\xb9\xd5\xfaK\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99(\xffqZ\xfc:+`\xf8\xebL\u013aN\xe8\u06b6\u5749\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4\x992\xef\x1c\x85\xb7Z\x9b*\x80\x05}P\x874\xc5\x10\x85\xbe\u0309\x02\xb8?\xa50\x1dY\x00\x00\xe0\x94\x99?\x14ax`^f\xd5\x17\xbex.\xf0\xb3\xc6\x1aN\x19%\x8a\x01|\x1f\x055\u05e5\x83\x00\x00\xe0\x94\x99A7\x04\xb1\xa3.p\xf3\xbc\ri\u0748\x1c8VkT\u02ca\x05\xcckiF1\xf7\x12\x00\x00\u07d4\x99AR\xfc\x95\xd5\xc1\u028b\x88\x11:\xbb\xadMq\x0e@\xde\xf6\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x99D\xfe\xe9\xd3JJ\x88\x00#\u01c92\xc0\vY\xd5\xc8*\x82\x89(\xa8\xa5k6\x90\a\x00\x00\u07d4\x99L\u00b5\"~\xc3\xcf\x04\x85\x12F|A\xb7\xb7\xb7H\x90\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99q\xdf`\xf0\xaef\xdc\xe9\xe8\xc8N\x17\x14\x9f\t\xf9\xc5/d\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x99v\x94~\xff_j\xe5\xda\b\xddT\x11\x92\xf3x\xb4(\xff\x94\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x99}e\x92\xa3\x15\x89\xac\xc3\x1b\x99\x01\xfb\xeb<\xc3\xd6[2\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\x82\xa5\x89\x0f\xfbT\x06\u04ec\xa8\u04bf\xc1\xddp\xaa\xa8\n\xe0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\x87\x8f\x9dn\n~\u066e\u01c2\x97\xb78y\xa8\x01\x95\xaf\xe0\x89\xd7\xc1\x98q\x0ef\xb0\x00\x00\u07d4\x99\x8c\x1f\x93\xbc\xdbo\xf2<\x10\xd0\u0712G(\xb7;\xe2\xff\x9f\x896[\xf3\xa43\xea\xf3\x00\x00\u07d4\x99\x91aL[\xaaG\xddl\x96\x87FE\xf9z\xdd,=\x83\x80\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x99\x92J\x98\x16\xbb}\xdf?\xec\x18D\x82\x8e\x9a\xd7\xd0k\xf4\xe6\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\x99\x99vh\xf7\xc1\xa4\xff\x9e1\xf9\x97z\xe3\"K\u02c8z\x85\x89\x0f\xc969(\x01\xc0\x00\x00\u07d4\x99\x9cI\xc1t\xca\x13\xbc\x83l\x1e\n\x92\xbf\xf4\x8b'\x15C\u0289\xb1\xcf$\xdd\u0431@\x00\x00\u07d4\x99\xa4\xde\x19\xde\u05d0\b\xcf\xdc\xd4]\x01M.XK\x89\x14\xa8\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\x99\xa9k\xf2$.\xa1\xb3\x9e\xceo\xcc\r\x18\xae\xd0\f\x01y\xf3\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x99\xb0\x18\x93+\xca\xd3U\xb6y+%]\xb6p-\xec\x8c\xe5\u0749\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\x99\xb7C\xd1\xd9\xef\xf9\r\x9a\x194\xb4\xdb!\xd5\x19\u061bJ8\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x99\xb8\xc8$\x86\x9d\xe9\xed$\xf3\xbf\xf6\x85L\xb6\xddE\xcc?\x9f\x89e\xea=\xb7UF`\x00\x00\u07d4\x99\xc0\x17L\xf8N\a\x83\xc2 \xb4\xebj\xe1\x8f\xe7\x03\x85J\u04c9py\xa2W=\fx\x00\x00\u07d4\x99\xc1\xd9\xf4\fj\xb7\xf8\xa9/\xce/\xdc\xe4zT\xa5\x86\xc5?\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x99\xc26\x14\x1d\xae\xc87\xec\xe0O\xda\xee\x1d\x90\u03cb\xbd\xc1\x04\x89ve\x16\xac\xac\r \x00\x00\u07d4\x99\xc3\x1f\xe7HX7\x87\xcd\xd3\xe5%\xb2\x81\xb2\x18\x96\x179\xe3\x897\b\xba\xed=h\x90\x00\x00\u07d4\x99\xc4u\xbf\x02\xe8\xb9!J\xda_\xad\x02\xfd\xfd\x15\xba6\\\f\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\x99\u0203%\x85F\xcc~N\x97\x1fR.8\x99\x18\xda^\xa6:\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x99\xc9\xf9>E\xfe<\x14\x18\xc3S\xe4\u016c8\x94\xee\xf8\x12\x1e\x89\x05\x85\xba\xf1E\x05\v\x00\x00\xe0\x94\x99\xd1W\x9c\xd4&\x82\xb7dN\x1dOq(D\x1e\xef\xfe3\x9d\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\x99\u0475\x85\x96_@jB\xa4\x9a\x1c\xa7\x0fv\x9evZ?\x98\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\x99\xdf\xd0PL\x06\xc7C\xe4e4\xfd{U\xf1\xf9\xc7\xec3)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\xf4\x14|\xcck\u02c0\u0304.i\xf6\xd0\x0e0\xfaA3\u0649\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\x99\xf7\u007f\x99\x8b \xe0\xbc\xdc\xd9\xfc\x83\x86ARl\xf2Y\x18\xef\x89a\t=|,m8\x00\x00\u07d4\x99\xfa\xd5\x008\xd0\xd9\xd4\xc3\xfb\xb4\xbc\xe0V\x06\xec\xad\xcdQ!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x99\xfe\r \x12(\xa7S\x14VU\xd4(\xeb\x9f\xd9I\x85\xd3m\x89i \xbf\xf3QZ:\x00\x00\u07d4\x9a\a\x9c\x92\xa6)\xca\x15\xc8\xca\xfa.\xb2\x8d[\xc1z\xf8(\x11\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9a\r<\xee=\x98\x92\xea;7\x00\xa2\u007f\xf8A@\xd9\x02T\x93\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x9a$\u038dH\\\xc4\xc8nI\u07b3\x90\"\xf9,t0\xe6~\x89Fy\x1f\xc8N\a\xd0\x00\x00\u07d4\x9a,\xe4;]\x89\u0593k\x8e\x8c5G\x91\xb8\xaf\xff\x96$%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9a9\x01bS^9\x88w\xe4\x16x}b9\xe0uN\x93|\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9a=\xa6P#\xa10 \xd2!E\xcf\xc1\x8b\xab\x10\xbd\x19\xceN\x89\x18\xbfn\xa3FJ:\x00\x00\xe0\x94\x9a>+\x1b\xf3F\xdd\a\v\x02sW\xfe\xacD\xa4\xb2\xc9}\xb8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9aL\xa8\xb8!\x17\x89NC\xdbr\xb9\xfax\xf0\xb9\xb9:\xce\t\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x9aR.R\xc1\x95\xbf\xb7\xcf_\xfa\xae\u06d1\xa3\xbath\x16\x1d\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9aZ\xf3\x1c~\x063\x9a\u0234b\x8d|M\xb0\xce\x0fE\u0224\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\x9ac?\xcd\x11,\xce\xebv_\xe0A\x81ps*\x97\x05\u7708\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x9ac\u0445\xa7\x91)\xfd\xab\x19\xb5\x8b\xb61\xea6\xa4 TN\x89\x02F\xdd\xf9yvh\x00\x00\u07d4\x9ag\b\u0778\x90<(\x9f\x83\xfe\x88\x9c\x1e\xdc\xd6\x1f\x85D#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9ao\xf5\xf6\xa7\xaf{z\xe0\xed\x9c \xec\xecP#\u0481\xb7\x86\x89\x8a\x12\xb9\xbdjg\xec\x00\x00\xe0\x94\x9a\x82\x82m<)H\x1d\xcc+\u0495\x00G\xe8\xb6\x04\x86\xc38\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9a\x8e\xcaA\x89\xffJ\xa8\xff~\u0536\xb7\x03\x9f\t\x02!\x9b\x15\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9a\x95;[\xccp\x93y\xfc\xb5Y\u05f9\x16\xaf\u06a5\f\xad\u0309\x05k\xc7^-c\x10\x00\x00\u07d4\x9a\x99\v\x8a\xebX\x8d~\xe7\xec.\xd8\xc2\xe6Os\x82\xa9\xfe\xe2\x89\x01\xd1'\xdbi\xfd\x8b\x00\x00\u07d4\x9a\x9d\x1d\xc0\xba\xa7}n \xc3\xd8I\u01c8b\xdd\x1c\x05L\x87\x89/\xb4t\t\x8fg\xc0\x00\x00\xe0\x94\x9a\xa4\x8cf\xe4\xfbJ\u0419\x93N2\x02.\x82t'\xf2w\xba\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9a\xa80\x8fB\x91\x0eZ\xde\t\xc1\xa5\xe2\x82\xd6\xd9\x17\x10\xbd\xbf\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9a\xaa\xfa\x00gd~\u0659\x06kzL\xa5\xb4\xb3\xf3\xfe\xaao\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9a\xb9\x88\xb5\x05\xcf\xee\x1d\xbe\x9c\u044e\x9bTs\xb9\xa2\xd4\xf56\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\x9a\xb9\x8dm\xbb\x1e\xaa\xe1mE\xa0EhT\x1a\xd3\xd8\xfe\x06\u0309\x0e\xc5\x04d\xfe#\xf3\x80\x00\xe0\x94\x9a\xba+^'\xffx\xba\xaa\xb5\xcd\u0248\xb7\xbe\x85\\\xeb\xbd\u038a\x02\x1e\f\x00\x13\a\n\xdc\x00\x00\u07d4\x9a\xc4\xdaQ\xd2x\"\xd1\xe2\b\xc9n\xa6J\x1e[U)\x97#\x89\x05lUy\xf7\"\x14\x00\x00\u0794\x9a\xc8S\x97y*i\u05cf(k\x86C*\a\xae\u03b6\x0ed\x88\xc6s\xce<@\x16\x00\x00\xe0\x94\x9a\xc9\a\xee\x85\xe6\xf3\xe2#E\x99\x92\xe2V\xa4?\xa0\x8f\xa8\xb2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9a\xd4\u007f\xdc\xf9\u0354-(\xef\xfd[\x84\x11[1\xa6X\xa1>\x89\xb2Y\xec\x00\xd5;(\x00\x00\u07d4\x9a\xdb\u04fc{\n\xfc\x05\xd1\xd2\xed\xa4\x9f\xf8c\x93\x9cH\xdbF\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x9a\xdfE\x8b\xff5\x99\xee\xe1\xa2c\x98\x85\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\x9a\xf9\xdb\xe4t\"\xd1w\xf9E\xbd\xea\xd7\xe6\xd8)05b0\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x9a\xfaSkLf\xbc8\xd8u\u0133\x00\x99\xd9&\x1f\xdb8\xeb\x89\v*\x8f\x84*w\xbc\x80\x00\u07d4\x9b\x06\xad\x84\x1d\xff\xbeL\xcfF\xf1\x03\x9f\u00c6\xf3\xc3!Dn\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\x11h\u078a\xb6KGU/3\x89\x80\n\x9c\xc0\x8bFf\u03c9]\u0212\xaa\x111\xc8\x00\x00\u07d4\x9b\x18\x11\xc3\x05\x1fF\xe6d\xaeK\xc9\xc8$\u0445\x92\xc4WJ\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\x9b\x18G\x86U\xa4\x85\x1c\xc9\x06\xe6`\xfe\xaca\xf7\xf4\u023f\xfc\x89\xe2G\x8d8\x90}\x84\x00\x00\u07d4\x9b\"\xa8\r\\{3t\xa0[D`\x81\xf9}\n4\a\x9e\u007f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x9b+\xe7\xf5gT\xf5\x05\xe3D\x1a\x10\xf7\xf0\xe2\x0f\xd3\xdd\xf8I\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\x9b2\xcfOQ\x15\xf4\xb3J\x00\xa6La}\xe0c\x875C#\x89\x05\xb8\x1e\u0608 |\x80\x00\u07d4\x9bC\u0739_\xde1\x80u\xa5g\xf1\xe6\xb5v\x17\x05^\xf9\xe8\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\x9bDO\xd37\xe5\xd7R\x93\xad\xcf\xffp\xe1\xea\x01\xdb\x022\"\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9bH$\xff\x9f\xb2\xab\xdaUM\xeeO\xb8\xcfT\x91eW\x061\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9bL'\x15x\f\xa4\xe9\x9e`\xeb\xf2\x19\xf1Y\f\x8c\xadP\n\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\x9bY\xeb!;\x1eue\xe4PG\xe0N\xa07O\x10v-\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\\9\xf7\xe0\xac\x16\x8c\x8e\xd0\xed4\x04w\x11}\x1bh.\xe9\x89\x05P\x05\xf0\xc6\x14H\x00\x00\u07d4\x9b^\xc1\x8e\x83\x13\x88}\xf4a\u0490.\x81\xe6z\x8f\x11;\xb1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9bd\xd3\u034d+s\xf6hA\xb5\xc4k\xb6\x95\xb8\x8a\x9a\xb7]\x89\x01 :Ov\f\x16\x80\x00\u07d4\x9be\x8f\xb3a\xe0F\xd4\xfc\xaa\x8a\xefm\x02\xa9\x91\x11\"6%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9bfA\xb1>\x17/\xc0r\xcaK\x83'\xa3\xbc(\xa1[f\xa9\x89\x06\x81U\xa46v\xe0\x00\x00\xe0\x94\x9bh\xf6t\x16\xa6;\xf4E\x1a1\x16L\x92\xf6r\xa6\x87Y\xe9\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\x9bw6i\xe8}v\x01\x8c\t\x0f\x82U\xe5D\t\xb9\u0728\xb2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9bw\xeb\xce\xd7\xe2\x15\xf0\x92\x0e\x8c+\x87\x00$\xf6\xec\xb2\xff1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9b|\x88\x10\xcc|\u021e\x80Nm>8\x12\x18PG(w\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9b\xa5=\xc8\xc9^\x9aG/\xeb\xa2\xc4\xe3,\x1d\xc4\xdd{\xabF\x89Hz\x9a0E9D\x00\x00\xe0\x94\x9b\xac\xd3\xd4\x0f;\x82\xac\x91\xa2d\xd9\u060d\x90\x8e\xac\x86d\xb9\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9b\xb7`\xd5\u0089\xa3\xe1\xdb\x18\xdb\tSE\xcaA;\x9aC\u0089\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\x9b\xb7b\x04\x18j\xf2\xf6;\xe7\x91h`\x16\x87\xfc\x9b\xadf\x1f\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9b\xb9\xb0*&\xbf\xe1\xcc\xc3\xf0\xc6!\x9e&\x1c9\u007f\xc5\xcax\x89Hz\x9a0E9D\x00\x00\u07d4\x9b\xc5s\xbc\xda#\xb8\xb2o\x90s\xd9\f#\x0e\x8eq\xe0'\v\x896/u\xa40]\f\x00\x00\u07d4\x9b\xd7\u00caB\x100JMe>\xde\xff\x1b<\xe4_\xcexC\x89\x0fI\x89A\xe6d(\x00\x00\xe0\x94\x9b\u0600h\xe10u\xf3\xa8\xca\xc4d\xa5\xf9I\xd6\xd8\x18\xc0\xf6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9b\xd9\x05\xf1q\x9f\u01ec\xd0\x15\x9dM\xc1\xf8\xdb/!G#8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9b\xdb\u071b\x9741\xd1<\x89\xa3\xf9u~\x9b;bu\xbf\u01c9\x1b\x1a}\u03caD\u04c0\x00\u07d4\x9b\xe3\xc3)\xb6*(\xb8\xb0\x88l\xbd\x8b\x99\xf8\xbc\x93\f\xe3\xe6\x89\x04\t\xe5+H6\x9a\x00\x00\xe0\x94\x9b\xf5\x8e\xfb\xea\a\x84\xeb\x06\x8a\xde\u03e0\xbb!P\x84\xc7:5\x8a\x01:k+VHq\xa0\x00\x00\u07d4\x9b\xf6r\xd9y\xb3fR\xfcR\x82Tzjk\xc2\x12\xaeCh\x89#\x8f\xd4,\\\xf0@\x00\x00\xe0\x94\x9b\xf7\x03\xb4\x1c6$\xe1_@T\x96#\x90\xbc\xba0R\xf0\xfd\x8a\x01H>\x01S<.<\x00\x00\u07d4\x9b\xf7\x1f\u007f\xb57\xacT\xf4\xe5\x14\x94\u007f\xa7\xffg(\xf1m/\x89\x01\u03c4\xa3\n\n\f\x00\x00\u07d4\x9b\xf9\xb3\xb2\xf2<\xf4a\xebY\x1f(4\v\xc7\x19\x93\x1c\x83d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x9b\xfce\x9c\x9c`\x1e\xa4*k!\xb8\xf1p\x84\xec\x87\xd7\x02\x12\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9b\xff\xf5\r\xb3jxUU\xf0vR\xa1S\xb0\xc4+\x1b\x8bv\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\x05\xe9\xd0\xf0u\x8eyS\x03q~1\xda!<\xa1W\u618965\u026d\xc5\u07a0\x00\x00\u07d4\x9c\x1bw\x1f\t\xaf\x88*\xf0d0\x83\xde*\xa7\x9d\xc0\x97\xc4\x0e\x89\x86p\xe9\xece\x98\xc0\x00\x00\u07d4\x9c(\xa2\xc4\b`\x91\xcb]\xa2&\xa6W\xce2H\xe8\xea{o\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\x9c/\xd5@\x89\xaff]\xf5\x97\x1ds\xb8\x04a`9dsu\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c4@\x98\xbaaZ9\x8f\x11\xd0\t\x90[\x17|D\xa7\xb6\x02\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c=\x06\x92\xce\xee\xf8\n\xa4\x96\\\xee\xd2b\xff\xc7\xf0i\xf2\u0709\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9c@\\\xf6\x97\x95a8\x06^\x11\xc5\xf7U\x9eg$[\u0465\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9cE *%\xf6\xad\x00\x11\xf1\x15\xa5\xa7\"\x04\xf2\xf2\x19\x88f\x8a\x01\x0f\xcf:b\xb0\x80\x98\x00\x00\xe0\x94\x9cI\xde\xffG\b_\xc0\x97\x04\u02a2\u0728\u0087\xa9\xa17\u068a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\x9cK\xbc\xd5\xf1dJo\aX$\xdd\xfe\x85\xc5q\u05ab\xf6\x9c\x89a\x94\x04\x9f0\xf7 \x00\x00\u07d4\x9cRj\x14\x06\x83\xed\xf1C\x1c\xfa\xa1(\xa95\xe2\xb6\x14\u060b\x89\x06\x04o7\xe5\x94\\\x00\x00\xe0\x94\x9cT\xe4\xedG\x9a\x85h)\u01bbB\u069f\vi*u\xf7(\x8a\x01\x97\xa8\xf6\xddU\x19\x80\x00\x00\xe0\x94\x9cX\x1a`\xb6\x10(\xd94\x16y)\xb2-p\xb3\x13\xc3O\u040a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\x9c\\\xc1\x11\t,\x12!\x16\xf1\xa8_N\xe3\x14\bt\x1a}/\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\x9ck\u0264k\x03\xaeT\x04\xf0C\xdf\xcf!\x88>A\x10\xcc3\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9cx\x96?\xbc&<\t\xbdr\xe4\xf8\xde\xf7J\x94u\xf7\x05\\\x8a\x02\ub3b1\xa1r\u0738\x00\x00\u07d4\x9cx\xfb\xb4\xdfv\x9c\xe2\xc1V\x92\f\xfe\xdf\xda\x03:\x0e%J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x9c{m\xc5\x19\x0f\xe2\x91)c\xfc\xd5yh>\xc79Q\x16\xb0\x89*\x11)\u0413g \x00\x00\u07d4\x9c\x80\xbc\x18\xe9\xf8\u0516\x8b\x18]\xa8\u01df\xa6\xe1\x1f\xfc>#\x89\r\x02\xabHl\xed\xc0\x00\x00\xe0\x94\x9c\x98\xfd\xf1\xfd\u034b\xa8\xf4\u0170L:\xe8X~\xfd\xf0\xf6\xe6\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\x9c\x99\xa1\u0691\u0552\v\xc1N\f\xb9\x14\xfd\xf6+\x94\u02c3X\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\x9c\x99\xb6&\x06(\x1b\\\xef\xab\xf3aV\xc8\xfeb\x83\x9e\xf5\xf3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x9c\x9a\a\xa8\xe5|1r\xa9\x19\xefdx\x94tI\x0f\r\x9fQ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9c\x9d\xe4G$\xa4\x05M\xa0\xea\xa6\x05\xab\u0300&hw\x8b\xea\x89\n\xd7\xd5\xca?\xa5\xa2\x00\x00\u07d4\x9c\x9f;\x8a\x81\x1b!\xf3\xff?\xe2\x0f\xe9p\x05\x1c\xe6j\x82O\x89>\xc2\u07bc\a\u053e\x00\x00\xe0\x94\x9c\x9f\x89\xa3\x91\x0fj*\xe8\xa9\x10G\xa1z\xb7\x88\xbd\xde\xc1p\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9c\xa0B\x9f\x87O\x8d\xce\xe2\xe9\xc0b\xa9\x02\n\x84*Xz\xb9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\xa4.\u7838\x98\xf6\xa5\xcc`\xb5\xa5\u05f1\xbf\xa3\xc321\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9c\xb2\x8a\xc1\xa2\n\x10o\u007f76\x92\xc5\xceLs\xf172\xa1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9c\xcd\u0732\xcf\u00b2[\br\x9a\n\x98\xd9\xe6\xf0 .\xa2\xc1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9c\xe2\u007f$^\x02\xd1\xc3\x12\xc1\xd5\x00x\x8c\x9d\xefv\x90E;\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9c\xe56;\x13\xe8#\x8a\xa4\xdd\x15\xac\u0432\xe8\xaf\xe0\x872G\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\x9c\xf2\x92\x8b\xee\xf0\x9a@\xf9\xbf\xc9S\xbe\x06\xa2Q\x11a\x82\xfb\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9d\x06\x91\x97\xd1\xdeP\x04Z\x18o^\xc7D\xac@\u8bd1\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\x9d\x0e}\x92\xfb0XS\u05d8&;\xf1^\x97\xc7+\xf9\xd7\xe0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9d\x0f4~\x82k}\u03aa\xd2y\x06\n5\xc0\x06\x1e\xcf3K\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d u\x17B,\xc0\xd6\r\xe7\xc27\tzMO\xce \x94\f\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\x9d%\n\xe4\xf1\x10\xd7\x1c\xaf\u01f0\xad\xb5.\x8d\x9a\xcbfy\xb8\x8a\x02\x15mn\x99r\x13\xc0\x00\x00\xe0\x94\x9d+\xfc6\x10o\x03\x82P\xc0\x18\x01hW\x85\xb1l\x86\xc6\r\x8aPw\xd7]\xf1\xb6u\x80\x00\x00\xe0\x94\x9d0\xcb#{\xc0\x96\xf1p6\xfc\x80\xdd!\xcah\x99,\xa2\u064a\x06n\xe71\x8f\u070f0\x00\x00\u07d4\x9d2\x96.\xa9\x97\x00\xd92(\xe9\xdb\xda\xd2\xcc7\xbb\x99\xf0~\x89\xb4c+\xed\xd4\xde\xd4\x00\x00\u07d4\x9d4\xda\xc2[\xd1X(\xfa\xef\xaa\xf2\x8fq\aS\xb3\x9e\x89\u0709;\x1cV\xfe\xd0-\xf0\x00\x00\u07d4\x9d6\x91e\xfbp\xb8\x1a:v_\x18\x8f\xd6\f\xbe^{\th\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9d@\xe0\x12\xf6\x04%\xa3@\xd8-\x03\xa1\xc7W\xbf\xab\xc7\x06\xfb\x89\t4o:\xdd\u020d\x80\x00\u07d4\x9dAt\xaaj\xf2\x84v\xe2)\xda\xdbF\x18\b\b\xc6u\x05\xc1\x89B\x1a\xfd\xa4.\u0597\x00\x00\u07d4\x9dB\x133\x9a\x01U\x18avL\x87\xa9<\xe8\xf8_\x87\x95\x9a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9dF\f\x1b7\x9d\xdb\x19\xa8\xc8[LgG\x05\r\xdf\x17\xa8u\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\x9dG\xba[L\x85\x05\xad\x8d\xa4)4(\va\xa0\xe1\xe8\xb9q\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9dM2\x11w%n\xbd\x9a\xfb\xda0A5\xd5\x17\xc3\xdcV\x93\x89!d\xb7\xa0J\u0220\x00\x00\u07d4\x9dO\xf9\x89\xb7\xbe\u066b\x10\x9d\x10\xc8\xc7\xe5_\x02\xd7g4\xad\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\x9dQ\x15C\xb3\xd9\xdc`\xd4\u007f\t\u051d\x01\xb6\u0118\xd8 x\x8a\x02a\x97\xb9Qo\u00d4\x00\x00\u07d4\x9dn\u03e0:\xf2\xc6\xe1D\xb7\xc4i*\x86\x95\x1e\x90.\x9e\x1f\x89\xa2\xa5\xaa`\xad$?\x00\x00\u07d4\x9dvU\xe9\xf3\xe5\xba]n\x87\xe4\x12\xae\xbe\x9e\xe0\u0512G\ue24e\t1\x1c\x1d\x80\xfa\x00\x00\u07d4\x9dx1\xe84\xc2\v\x1b\xaaiz\xf1\xd8\xe0\xc6!\u016f\xff\x9a\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4\x9dx\xa9u\xb7\xdb^M\x8e(\x84\\\xfb\xe7\xe3\x14\x01\xbe\r\u0649H\xa40k\xa2\u5e5c\x8ahX\u02f5,\f\xf75\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\x9d\u007f\xdapp\xbf>\xe9\xbb\u0664\x1fU\xca\u0505J\xe6\xc2,\x8a\x02U\u02e3\xc4o\xcf\x12\x00\x00\u07d4\x9d\x81\xae\xa6\x9a\xedj\xd0p\x89\xd6\x14E4\x8c\x17\xf3K\xfc[\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9d\x91\x1f6\x82\xf3/\xe0y.\x9f\xb6\xff<\xfcG\xf5\x89\xfc\xa5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\x91;]3\x9c\x95\xd8wEV%c\xfe\xa9\x8b#\xc6\f\u0109\tA0,\u007fM#\x00\x00\u07d4\x9d\x93\xfa\xb6\xe2(E\xf8\xf4Z\aIo\x11\xdeqS\r\xeb\u01c9lO\xd1\xee$nx\x00\x00\u07d4\x9d\x99\xb1\x89\xbb\u0664\x8f\xc2\xe1n\x8f\u0363;\xb9\x9a1{\xbb\x89=\x16\xe1\vm\x8b\xb2\x00\x00\u07d4\x9d\x9cN\xfe\x9fC9\x89\xe2;\xe9@I!S)\xfaU\xb4\u02c9\r\u3c89\x03\u01b5\x80\x00\u07d4\x9d\x9eW\xfd\xe3\x0ePh\xc0>I\x84\x8e\xdc\xe3C\xb7\x02\x83X\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\x9d\xa30\"@\xaf\x05\x11\xc6\xfd\x18W\xe6\u07779Ow\xabk\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\x9d\xa4\xec@pw\xf4\xb9p{-\x9d.\xde^\xa5(+\xf1\u07c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\xa6\t\xfa:~l\xf2\xcc\x0ep\u036b\xe7\x8d\xc4\xe3\x82\xe1\x1e\x89A\rXj \xa4\xc0\x00\x00\xe0\x94\x9d\xa6\x1c\xcdb\xbf\x86\x06V\xe02]qW\xe2\xf1`\xd9;\xb5\x8a\x01\x0f\f\xa9V\xf8y\x9e\x00\x00\xe0\x94\x9d\xa6\xe0u\x98\x9ct\x19\tL\xc9\xf6\xd2\u44d3\xbb\x19\x96\x88\x8a\x02Y\xbbq\u056d\xf3\xf0\x00\x00\u07d4\x9d\xa8\xe2,\xa1\x0eg\xfe\xa4NR^GQ\xee\xac6\xa3\x11\x94\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\x9d\xb2\xe1\\\xa6\x81\xf4\xc6`H\xf6\xf9\xb7\x94\x1e\u040b\x1f\xf5\x06\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9d\xc1\x0f\xa3\x8f\x9f\xb0h\x10\xe1\x1f`\x17>\xc3\xd2\xfdju\x1e\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\x9d\xd2\x19f$\xa1\xdd\xf1J\x9d7^_\a\x15+\xaf\"\xaf\xa2\x89A\xb0^$c\xa5C\x80\x00\u07d4\x9d\xd4k\x1cm?\x05\u279co\x03~\xed\x9aYZ\xf4\xa9\xaa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9d\xdd5^cN\xe9\x92~K\u007fl\x97\xe7\xbf:/\x1ehz\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\x9d\xe2\n\xe7j\xa0\x82c\xb2\x05\xd5\x14$a\x96\x1e$\b\xd2f\x89\r\xa93\xd8\xd8\xc6p\x00\x00\u07d4\x9d\xe2\v\xc3~\u007fH\xa8\x0f\xfdz\xd8O\xfb\xf1\xa1\xab\xe1s\x8c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9d\xe78m\xde@\x1c\xe4\xc6{q\xb6U?\x8a\xa3N\xa5\xa1}\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\x9d\xeb9\x02z\xf8w\x99+\x89\xf2\xecJ\x1f\x82.\xcd\xf1&\x93\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9d\xef\xe5j\x0f\xf1\xa1\x94}\xba\t#\xf7\xdd%\x8d\x8f\x12\xfaE\x8a\x05\xb1*\ufbe8\x04\x00\x00\x00\u07d4\x9d\xf0W\xcd\x03\xa4\xe2~\x8e\x03/\x85y\x85\xfd\u007f\x01\xad\xc8\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9d\xf3*P\x1c\vx\x1c\x02\x81\x02/B\xa1)?\xfd{\x89*\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4\x9e\x01vZ\xff\b\xbc\"\x05P\xac\xa5\xea.\x1c\xe8\u5c19#\x8965\u026d\xc5\u07a0\x00\x00\u07d4\x9e \xe5\xfd6\x1e\xab\xcfc\x89\x1f[\x87\xb0\x92h\xb8\xeb7\x93\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9e#,\b\xc1M\xc1\xa6\xed\v\x8a;(h\x97{\xa5\xc1}\x10\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e#\xc5\u4dc2\xb0\n_\xad\U0006eb47\xda\xcf[\x03g\xa1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e59\x90q\xa4\xa1\x01\xe9\x19M\xaa?\t\xf0J\v_\x98p\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9e>\xb5\t'\x8f\xe0\xdc\xd8\xe0\xbb\xe7\x8a\x19N\x06\xb6\x809C\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\x9eBrrQk>g\xd4\xfc\xbf\x82\xf5\x93\x90\xd0L\x8e(\xe5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\x9eL\xec5:\xc3\u3043^<\t\x91\xf8\xfa\xa5\xb7\u0428\xe6\x8a\x02\x1e\x18\xb9\xe9\xabE\xe4\x80\x00\u07d4\x9eX\x11\xb4\v\xe1\xe2\xa1\xe1\u048c;\at\xac\xde\n\t`=\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\x9eZ1\x1d\x9fi\x89\x8a|j\x9dc`h\x048\xe6z{/\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\x9e| P\xa2'\xbb\xfd`\x93~&\x8c\xea>h\xfe\xa8\xd1\xfe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\x9e\u007fe\xa9\x0e\x85\b\x86{\xcc\xc9\x14%j\x1e\xa5t\xcf\a\xe3\x89C8t\xf62\xcc`\x00\x00\xe0\x94\x9e\x81D\xe0\x8e\x89dx\x11\xfekr\xd4E\u05a5\xf8\n\xd2D\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9e\x8fd\xdd\xcd\u9e34Q\xba\xfa\xa25\xa9\xbfQ\x1a%\xac\x91\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\x9e\x95\x1fm\xc5\xe3R\xaf\xb8\xd0B\x99\xd2G\x8aE\x12Y\xbfV\x89\x03\xe7A\x98\x81\xa7:\x00\x00\u07d4\x9e\x96\r\xcd\x03\u057a\x99\xcb\x11]\x17\xffL\t$\x8a\xd4\u043e\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9e\xafj2\x8a@v\x02N\xfakg\xb4\x8b!\xee\xdc\xc0\xf0\xb8\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\x9e\xb1\xffqy\x8f(\xd6\xe9\x89\xfa\x1e\xa0X\x8e'\xba\x86\xcb}\x89\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\x9e\xb2\x81\xc3'\x19\xc4\x0f\xdb>!m\xb0\xf3\u007f\xbcs\xa0&\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\x9e\xb3\xa7\xcb^g&Bz:6\x1c\xfa\x8dad\xdb\u043a\x16\x89+\x95\xbd\xcc9\xb6\x10\x00\x00\u07d4\x9e\xb7\x83N\x17\x1dA\xe0i\xa7yG\xfc\xa8v\"\xf0\xbaNH\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\x9e\xc0>\x02\u51f7v\x9d\xefS\x84\x13\xe9\u007f~U\xbeq\u060a\x04+\xf0kx\xed;P\x00\x00\u07d4\x9e\u02eb\xb0\xb2'\x82\xb3uD)\xe1uz\xab\xa0K\x81\x18\x9f\x89,\xa7\xbb\x06\x1f^\x99\x80\x00\u07d4\x9e\xce\x14\x00\x80\t6\xc7\xc6H_\xcd\xd3b`\x17\u041a\xfb\xf6\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4\x9e\xd4\xe6?ReB\xd4O\xdd\xd3MY\xcd%8\x8f\xfdk\u0689\u049b4\xa4cH\x94\x00\x00\u07d4\x9e\xd8\x0e\xda\u007fU\x05M\xb9\xfbR\x82E\x16\x88\xf2k\xb3t\xc1\x89\x10CV\x1a\x88)0\x00\x00\u07d4\x9e\u0710\xf4\xbe!\be!J\xb5\xb3^Z\x8d\xd7t\x15'\x9d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9e\u07acL\x02k\x93\x05M\u0171\xd6a\fo9`\xf2\xads\x89A\rXj \xa4\xc0\x00\x00\u07d4\x9e\xe9?3\x9eg&\xece\xee\xa4O\x8aK\xfe\x10\xda=2\x82\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\x9e\xe9v\f\xc2s\xd4pj\xa0\x83u\xc3\xe4o\xa20\xaf\xf3\u054a\x01\xe5.3l\xde\"\x18\x00\x00\u07d4\x9e\xeb\a\xbd+x\x90\x19^}F\xbd\xf2\a\x1bf\x17QM\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\x9e\xefD-)\x1aD}t\xc5\xd2S\u011e\xf3$\xea\xc1\xd8\xf0\x89\xb9f\b\xc8\x10;\xf0\x00\x00\u07d4\x9e\xf1\x89k\x00|2\xa1Q\x14\xfb\x89\xd7=\xbdG\xf9\x12+i\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9f\x01w\x06\xb80\xfb\x9c0\ufc20\x9fPk\x91WEu4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x10\xf2\xa0F;e\xae0\xb0p\xb3\xdf\x18\xcfF\xf5\x1e\x89\xbd\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\x9f\x19\xfa\u0223$7\xd8\n\u0183z\v\xb7\x84\x17)\xf4\x97.\x89#=\xf3)\x9far\x00\x00\u07d4\x9f\x1a\xa8\xfc\xfc\x89\xa1\xa52\x8c\xbdcD\xb7\x1f'\x8a,\xa4\xa0\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\x9f!0,\xa5\tk\xeat\x02\xb9\x1b\x0f\xd5\x06%O\x99\x9a=\x89C\x97E\x1a\x00=\xd8\x00\x00\u07d4\x9f'\x1d(U\x00\xd78F\xb1\x8fs>%\u074bO]J\x8b\x89'#\xc3F\xae\x18\b\x00\x00\u07d4\x9f4\x97\xf5\xef_\xe60\x95\x83l\x00N\xb9\xce\x02\xe9\x01;K\x89\"V\x86\x1b\xf9\xcf\b\x00\x00\xe0\x94\x9f:t\xfd^~\xdc\xc1\x16)\x93\x17\x13\x81\u02f62\xb7\xcf\xf0\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\x9fF\xe7\xc1\xe9\a\x8c\xae\x860Z\xc7\x06\v\x01F}f\x85\xee\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\x9fIl\xb2\x06\x95c\x14M\b\x11g{\xa0\xe4q:\nAC\x89<\xd2\xe0\xbfc\xa4H\x00\x00\u07d4\x9fJq\x95\xac|\x15\x1c\xa2X\xca\xfd\xa0\u02b0\x83\xe0I\xc6\x02\x89SS\x8c2\x18\\\xee\x00\x00\u07d4\x9fJ\xc9\xc9\xe7\xe2L\xb2DJ\x04T\xfa[\x9a\xd9\xd9-8S\x89-C\xf3\xeb\xfa\xfb,\x00\x00\u07d4\x9f_D\x02kWjJ\xdbA\xe9YaV\x1dA\x03\x9c\xa3\x91\x89\r\x8drkqw\xa8\x00\x00\u07d4\x9f`{?\x12F\x9fDa!\u03bf4u5kq\xb42\x8c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\x9fa\xbe\xb4o^\x85=\n\x85!\xc7Dnh\xe3L}\ts\x89\x1e[\x8f\xa8\xfe*\xc0\x00\x00\u07d4\x9fd\xa8\xe8\xda\xcfJ\xde0\xd1\x0fMY\xb0\xa3\u056b\xfd\xbft\x8966\x9e\xd7t}&\x00\x00\u07d4\x9ff.\x95'A!\xf1wVncm#\x96L\xf1\xfdho\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9fj2*mF\x99\x81Bj\xe8D\x86]~\xe0\xbb\x15\u01f3\x89\x02\xb5\xeeW\x92\x9f\u06c0\x00\u07d4\x9fy\x86\x92J\xeb\x02h|\xd6A\x89\x18\x9f\xb1g\xde\xd2\xdd\\\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\x9fz\x03\x92\xf8Ws.0\x04\xa3u\xe6\xb1\x06\x8dI\xd801\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x82E\u00eb}\x171d\x86\x1c\u04d9\x1b\x94\xf1\xba@\xa9:\x89\x9b\ny\x1f\x12\x110\x00\x00\u07d4\x9f\x83\xa2\x93\xc3$\xd4\x10l\x18\xfa\xa8\x88\x8fd\u0499\x05L\xa0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\x9f\x86\xa0f\xed\xb6\x1f\xcbXV\u0793\xb7\\\x8cy\x18d\xb9{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\x9f\x98\xeb4\xd4iy\xb0\xa6\u078b\x05\xaaS:\x89\xb8%\xdc\xf1\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\xe0\x94\x9f\x9f\xe0\xc9_\x10\xfe\xe8z\xf1\xaf r6\xc8\xf3aN\xf0/\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\x9f\xae\xa1\xc5\xe8\x1ez\xcb?\x17\xf1\xc3Q\xee.\u0649\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa0\b\x01\x98c\xc1\xa7|\x14\x99\xeb9\xbb\u05ff-\u05e3\x1c\xb9\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xa0\t\xbf\ao\x1b\xa3\xfaW\u04a7!r\x18\xbe\xd5VZzz\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa0\x1e\x94v\u07c4C\x18%\xc86\xe8\x80:\x97\xe2/\xa5\xa0\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\xa0\x1f\x12\xd7\x0fD\xaa{\x11;(\\\"\xdc\xdbE\x874T\xa7\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xa0\x1f\u0450j\x90\x85\x06\xde\xda\xe1\xe2\b\x12\x88r\xb5n\u7489\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa0\"\x82@\xf9\x9e\x1d\xe9\xcb2\xd8,\x0f/\xa9\xa3\xd4K\v\xf3\x89V\xbcu\xe2\xd61\x00\x00\x00\xe0\x94\xa0+\xdedahn\x19\xace\f\x97\r\x06r\xe7m\xcbO\u008a\x01\xe0\x92\x96\xc37\x8d\xe4\x00\x00\u07d4\xa0,\x1e4\x06O\x04u\xf7\xfa\x83\x1c\xcb%\x01L:\xa3\x1c\xa2\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xa0-\u01aa2\x8b\x88\r\u97acTh#\xfc\xcfw@G\xfb\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa0.?\x8fYY\xa7\xaa\xb7A\x86\x12\x12\x9bp\x1c\xa1\xb8\x00\x10\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa04\u007f\n\x98wc\x90\x16\\\x16m2\x96;\xf7M\xcd\n/\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa05\xa3e$x\xf8-\xbdm\x11_\xaa\x8c\xa9F\xec\x9eh\x1d\x89\x05\xf4\xe4-\u052f\xec\x00\x00\u07d4\xa0:=\xc7\xc53\xd1tB\x95\xbe\x95]a\xaf?R\xb5\x1a\xf5\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa0E\x9e\xf3i:\xac\xd1d|\xd5\u0612\x989 L\xefS\xbe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa0O*\xe0*\xdd\x14\xc1/\xafe\xcb%\x90\"\u0403\n\x8e&\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xa0l\xd1\xf3\x969l\ndFFQ\xd7\xc2\x05\xef\xaf8|\xa3\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xa0ri\x1c\x8d\xd7\xcdB7\xffr\xa7\\\x1a\x95\x06\xd0\xce[\x9e\x89\x14\x0e\xc8\x0f\xa7\xee\x88\x00\x00\u07d4\xa0r\u03beb\xa9\xe9\xf6\x1c\xc3\xfb\xf8\x8a\x9e\xfb\xfe>\x9a\x8dp\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa0v\x82\x00\v\x1b\xcf0\x02\xf8\\\x80\xc0\xfa)I\xbd\x1e\x82\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa0z\xa1mt\xae\u8a63(\x8dR\xdb\x15Q\u0553\x882\x97\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa0\x8d![[j\xacHa\xa2\x81\xac~@\vx\xfe\xf0L\xbf\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa0\x95\x19p\xdf\u0403/\xb8;\xda\x12\xc25E\xe7\x90Aul\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa0\x9fM^\xaae\xa2\xf4\xcbu\nI\x924\x01\xda\u5410\xaf\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\xe0\x94\xa0\xa0\xe6R\x04T\x1f\u029b/\xb2\x82\u0355\x13\x8f\xae\x16\xf8\t\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa0\xaa_\x02\x01\xf0M;\xbe\xb8\x98\x13/|\x11g\x94f\xd9\x01\x89\x01\xfb\xedR\x15\xbbL\x00\x00\u07d4\xa0\xaa\xdb\xd9P\x97\"p_m#X\xa5\u01df7\x97\x0f\x00\xf6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa0\xb7q\x95\x1c\xe1\xde\xee6:\xe2\xb7q\xb7>\a\u0135\xe8\x00\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa0\xde\\`\x1eif5\u0198\xb7\xae\x9c\xa4S\x9f\u01f9A\xec\x89\x12\xc3\xcb\xd7\x04\xc9w\x00\x00\u07d4\xa0\xe8\xbaf\x1bH\x15L\xf8C\xd4\u00a5\xc0\xf7\x92\xd5(\xee)\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa0\xfc~S\xc5\xeb\xd2z*\xbd\xacE&\x1f\x84\xab;Q\xae\xfb\x89\xa3\x13\xda\xec\x9b\xc0\xd9\x00\x00\xe0\x94\xa0\xff[L\xf0\x16\x02~\x83#I}D(\xd3\xe5\xa8;\x87\x95\x8a\x01e\x98\xd3\xc8>\xc0B\x00\x00\u07d4\xa1\x06F[\xbd\x19\u1dbc\xe5\r\x1b\x11W\xdcY\tZ60\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa1\x06\xe6\x92>\xddS\u028e\xd6P\x96\x8a\x91\b\xd6\xcc\xfd\x96p\x8a\x02\x02\xfe\x15\x05\xaf\uc240\x00\u07d4\xa1\t\u12f0\xa3\x9c\x9e\xf8/\xa1\x95\x97\xfc^\xd8\xe9\xebmX\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\xa1\x1a\x03\u013b&\xd2\x1e\xffg}]U\\\x80\xb2TS\xeez\x89\x03\xcb'Y\xbcA\x0f\x80\x00\u07d4\xa1\x1e\xff\xabl\xf0\xf5\x97,\xff\xe4\xd5e\x96\xe9\x89h\x14J\x8f\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xa1 M\xad_V\a(\xa3\\\r\x8f\u01d4\x81\x05{\xf7s\x86\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa1&#\xe6)\u07d3\tg\x04\xb1`\x84\xbe,\u061dV-\xa4\x8a\x01\xcc\xc92E\x11\xe4P\x00\x00\xe0\x94\xa1*l-\x98]\xaf\x0eO_ z\xe8Q\xaa\xf7)\xb32\u034a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xa13m\xfb\x96\xb6\xbc\xbeK>\xdf2\x05\xbeW#\xc9\x0f\xadR\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa1;\x9d\x82\xa9\x9b<\x9b\xbaZ\xe7.\xf2\x19\x9e\xdc};\xb3l\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xa1<\xfe\x82mm\x18A\u072eD;\xe8\u00c7Q\x816\xb5\xe8\x8a\x1d\xa5jK\b5\xbf\x80\x00\x00\xe0\x94\xa1C.\xd2\u01b7wz\x88\xe8\xd4m8\x8epG\u007f \x8c\xa5\x8a\x01\xb1\xa7\xe4\x13\xa1\x96\xc5\x00\x00\u07d4\xa1D\xf6\xb6\x0fr\xd6J!\xe30\xda\xdbb\u0619\n\xde+\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa1P%\xf5\x95\xac\xdb\xf3\x11\x0fw\u017f$G~eH\xf9\xe8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1X\x14\x8a.\x0f>\x92\xdc,\xe3\x8f\xeb\xc2\x01\a\xe3%<\x96\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1a`\x85\x1d+\x9c4\x9b\x92\xe4o\x82\x9a\xbf\xb2\x10\x945\x95\x89a\t=|,m8\x00\x00\u07d4\xa1f\xf9\x11\xc6D\xac2\x13\u049e\x0e\x1a\xe0\x10\xf7\x94\u056d&\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1m\x9e=c\x98aY\xa8\x00\xb4h7\xf4^\x8b\xb9\x80\xee\v\x89n\x11u\xdaz\xd1 \x00\x00\u07d4\xa1pp\xc2\xe9\u0169@\xa4\xec\x0eIT\xc4\xd7\xd6C\xbe\x8fI\x89lk\x17\x03;6\x1c\x80\x00\u07d4\xa1|\x9eC#\x06\x95\x18\x18\x9dR\a\xa0r\x8d\u02d20j?\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa1\x83`\xe9\x85\xf2\x06.\x8f\x8e\xfe\x02\xad,\xbc\x91\xad\x9aZ\xad\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa1\x91\x14\x05\xcfn\x99\x9e\xd0\x11\xf0\xdd\xcd*O\xf7\u008f%&\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa1\x92i\x80\a\xcc\x11\xaa`=\"\x1d_\xee\xa0v\xbc\xf7\xc3\r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\x92\xf0j\xb0R\xd5\xfd\u007f\x94\xee\xa81\x8e\x82x\x15\xfegz\x89\a\x1f\x8a\x93\xd0\x1eT\x00\x00\u07d4\xa1\x99\x81D\x96\x8a\\p\xa6AUT\xce\xfe\u0082F\x90\u0125\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa1\xa1\xf0\xfam \xb5\nyO\x02\xefR\b\\\x9d\x03j\xa6\u028965\u026d\xc5\u07a0\x00\x00\u07d4\xa1\xae\x8dE@\xd4\xdbo\xdd\xe7\x14oA[C\x1e\xb5\\y\x83\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xa1\xb4|M\x0e\xd6\x01\x88B\xe6\xcf\xc8c\n\u00e3\x14.^k\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xa1\xc4\xf4Z\x82\xe1\xc4x\xd8E\b.\xb1\x88u\xc4\xeae9\xab\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xa1\xdc\xd0\xe5\xb0Z\x97|\x96#\xe5\xae/Y\xb9\xad\xa2\xf3>1\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa1\xe48\n;\x1ft\x96s\xe2p\"\x99\x93\xeeU\xf3Vc\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\xf1\x93\xa0Y/\x1f\xeb\x9f\xdf\xc9\n\xa8\x13xN\xb8\x04q\u0249K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa1\xf2\x85@P\xf8re\x8e\xd8.R\xb0\xad{\xbc\x1c\xb9!\xf6\x89m\x03\x17\xe2\xb3&\xf7\x00\x00\u07d4\xa1\xf5\xb8@\x14\rZ\x9a\xce\xf4\x02\xac<\u00c8jh\xca\xd2H\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa1\xf7e\xc4O\xe4_y\x06w\x94HD\xbeO-B\x16_\xbd\x89\xc7\xe9\xcf\xdev\x8e\xc7\x00\x00\u07d4\xa1\xf7\xdd\xe1\xd78\xd8\xcdg\x9e\xa1\xee\x96[\xee\"K\xe7\xd0M\x89=\x18DP\xe5\xe9<\x00\x00\u07d4\xa1\xf8\u063c\xf9\x0ew\u007f\x19\xb3\xa6Iu\x9a\xd9P'\xab\xdf\u00c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\x02TrB\x80onp\xe7@X\xd6\xe5)-\xef\xc8\xc8\u0509l\x87T\xc8\xf3\f\b\x00\x00\u07d4\xa2\r\a\x1b\x1b\x000cI}y\x90\xe1$\x9d\xab\xf3l5\xf7\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa2\r\x8f\xf6\f\xaa\xe3\x1d\x02\xe0\xb6e\xfaC]v\xf7|\x94B\x89\x1a\x8a\x90\x9d\xfc\xef@\x00\x00\u07d4\xa2\x11\xda\x03\xcc\x0e1\xec\xceS\t\x99\x87\x18QU(\xa0\x90\u07c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\x14B\xab\x054\n\xdeh\xc9\x15\xf3\xc39\x9b\x99U\xf3\xf7\xeb\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xa2\"\"Y\u075c>=\xed\x12p\x84\xf8\b\xe9*\x18\x870,\x89\b\xc83\x9d\xaf\xedH\x00\x00\u07d4\xa2*\xde\r\xdb\\n\xf8\xd0\u034d\xe9M\x82\xb1\x10\x82\xcb.\x91\x897KW\xf3\xce\xf2p\x00\x00\u07d4\xa2L:\xb6!\x81\xe9\xa1[x\xc4b\x1eL|X\x81'\xbe&\x89\b\xcd\xe4:\x83\xd31\x00\x00\u07d4\xa2W\xadYK\u0603(\xa7\xd9\x0f\xc0\xa9\a\u07d5\xee\xca\xe3\x16\x89\x1c7\x86\xff8F\x93\x00\x00\u07d4\xa2[\bd7\xfd!\x92\u0420\xf6On\xd0D\xf3\x8e\xf3\xda2\x89\x12)\x0f\x15\x18\v\xdc\x00\x00\u07d4\xa2v\xb0X\u02d8\u060b\xee\xdbg\xe5CPl\x9a\r\x94p\u0609\x90\xaa\xfcv\xe0/\xbe\x00\x00\u07d4\xa2\x82\xe9i\xca\xc9\xf7\xa0\xe1\xc0\u0350\xf5\xd0\xc48\xacW\r\xa3\x89\"\a\xeb\x89\xfc'8\x00\x00\xe0\x94\xa2\x91\xe9\u01d9\rU-\u046e\x16\u03bc?\xca4,\xba\xf1\u044a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa2\x93\x19\xe8\x10i\xe5\xd6\r\xf0\x0f=\xe5\xad\xee5\x05\xec\xd5\xfb\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa2\x96\x8f\xc1\xc6K\xac\vz\xe0\u058b\xa9I\x87Mm\xb2S\xf4\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xa2\x9d[\xdat\xe0\x03GHr\xbdX\x94\xb8\x853\xffd\u00b5\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa2\x9df\x1acv\xf6m\vt\xe2\xfe\x9d\x8f&\xc0$~\xc8L\x89\xdf3\x04\a\x9c\x13\xd2\x00\x00\u07d4\xa2\xa45\xdeD\xa0\x1b\xd0\ucc9eD\xe4vD\xe4j\f\xdf\xfb\x89\x1b\x1dDZz\xff\xe7\x80\x00\u07d4\xa2\xac\xe4\u0253\xbb\x1eS\x83\xf8\xact\xe1y\x06n\x81O\x05\x91\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa2\xb7\x01\xf9\xf5\xcd\u041eK\xa6+\xae\xba\u3a02W\x10X\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa2\u0145O\xf1Y\x9f\x98\x89,W%\xd2b\xbe\x1d\xa9\x8a\xad\xac\x89\x11\t\xff30\x10\xe7\x80\x00\u07d4\xa2\xc7\xea\xff\xdc,\x9d\x93sE l\x90\x9aR\u07f1LG\x8f\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\u07d4\xa2\u04aabk\t\xd6\xd4\xe4\xb1?\u007f\xfcZ\x88\xbdz\xd3gB\x89\xfb\x80xPuS\x83\x00\x00\u07d4\xa2\u04cd\xe1\xc79\x06\xf6\xa7\xcan\xfe\xb9|\xf6\xf6\x9c\xc4!\xbe\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa2\xdce\xee%kY\xa5\xbdy)wO\x90K5\x8d\U000ed84a\x04\x83\xbc\xe2\x8b\xeb\t\xf8\x00\x00\u07d4\xa2\xe0h:\x80]\xe6\xa0^\xdb/\xfb\xb5\xe9o\x05p\xb67\u00c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa2\u1e2a\x90\x0e\x9c\x13\x9b?\xa1\"5OaV\xd9*\x18\xb1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa2\u2d54\x1e\f\x01\x94K\xfe\x1d_\xb4\xe8\xa3K\x92,\u03f1\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\xe4`\xa9\x89\xcb\x15V_\x9e\u0327\xd1!\xa1\x8eN\xb4\x05\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa2\xec\xce,I\xf7*\t\x95\xa0\xbd\xa5z\xac\xf1\xe9\xf0\x01\xe2*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xa2\xf4r\xfeO\"\xb7}\xb4\x89!\x9e\xa4\x02=\x11X*\x93)\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xa2\xf7\x98\xe0w\xb0}\x86\x12N\x14\a\xdf2\x89\r\xbbKcy\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa2\xf8k\xc0a\x88N\x9e\xef\x05d\x0e\xddQ\xa2\xf7\xc0Yli\x89llD\xfeG\xec\x05\x00\x00\u07d4\xa2\xfa\x17\xc0\xfbPl\xe4\x94\x00\x8b\x95W\x84\x1c?d\x1b\x8c\xae\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa3\x04X\x8f\r\x85\f\xd8\u04cfv\xe9\xe8<\x1b\xf6>3>\u0789\x02(V\x01!l\x8c\x00\x00\u07d4\xa3\x05\x8cQszN\x96\xc5_.\xf6\xbd{\xb3X\x16~\u00a7\x89 \xdb:\xe4H\x1a\u0500\x00\u07d4\xa3\t\xdfT\u02bc\xe7\f\x95\xec03\x14\x9c\xd6g\x8ao\xd4\u03c9\f\x1f\x12\xc7Q\x01X\x00\x00\u07d4\xa3\nER\x0eR\x06\xd9\x00@p\xe6\xaf>{\xb2\xe8\xddS\x13\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa3\x0e\n\xcbSL\x9b0\x84\xe8P\x1d\xa0\x90\xb4\xeb\x16\xa2\xc0\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3 0\x95\xed\xb7\x02\x8ehq\xce\n\x84\xf5HE\x9f\x830\n\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa3!\t\x1d0\x18\x06By\xdb9\x9d+*\x88\xa6\xf4@\xae$\x89\xadx\xeb\u016cb\x00\x00\x00\u07d4\xa3#-\x06\x8dP\x06I\x03\xc9\xeb\xc5c\xb5\x15\xac\u0237\xb0\x97\x89l\x87T\xc8\xf3\f\b\x00\x00\xe0\x94\xa3$\x1d\x89\n\x92\xba\xf5)\b\xdcJ\xa0Irk\xe4&\xeb\u04ca\x04<-\xa6a\xca/T\x00\x00\u07d4\xa3)F&\xec)\x84\xc4;C\xdaM]\x8eFi\xb1\x1dKY\x896\xa4\xcfcc\x19\xc0\x00\x00\u07d4\xa3,\xf7\xdd\xe2\f=\xd5g\x9f\xf5\xe3%\x84\\p\u0156&b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa39\xa3\xd8\xca(\x0e'\xd2A[&\xd1\xfcy2(\xb6`C\x896\U00086577\x8f\xf0\x00\x00\u07d4\xa3<\xb4P\xf9[\xb4n%\xaf\xb5\x0f\xe0_\xee\xe6\xfb\x8c\xc8\xea\x89*\x11)\u0413g \x00\x00\u07d4\xa3?p\xdaru\xef\x05q\x04\u07e7\xdbd\xf4r\xe9\xf5\xd5S\x89\x04YF\xb0\xf9\xe9\xd6\x00\x00\u07d4\xa3@v\xf8K\xd9\x17\xf2\x0f\x83B\u024b\xa7\x9eo\xb0\x8e\xcd1\x89\u3bb5sr@\xa0\x00\x00\u07d4\xa3C\x0e\x1fd\u007f2\x1e\xd3G9V##\xc7\xd6#A\vV\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xa3O\x9dV\x8b\xf7\xaf\xd9L*[\x8a_\xf5\\f\xc4\by\x99\x89\x84}P;\"\x0e\xb0\x00\x00\u07d4\xa3V\x06\xd5\x12 \xee\u007f!F\xd4\x11X.\xe4\xeeJEYn\x89\u062a\xbe\b\v\xc9@\x00\x00\u07d4\xa3VU\x1b\xb7}OE\xa6\xd7\xe0\x9f\n\b\x9ey\u0322I\u02c9\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xa3\\\x19\x13,\xac\x195Wj\xbf\xedl\x04\x95\xfb\a\x88\x1b\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3e\x91\x8b\xfe?&'\xb9\xf3\xa8gu\xd8un\x0f\u0629K\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa3n\r\x94\xb9Sd\xa8&q\xb6\b\xcb-72Ea)\t\x89\b!\xd2!\xb5)\x1f\x80\x00\u07d4\xa3u\xb4\xbc$\xa2N\x1fyu\x93\xcc0+/3\x10c\xfa\\\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa3v\"\xac\x9b\xbd\xc4\xd8+u\x01]t[\x9f\x8d\xe6Z(\uc25d\xc0\\\xce(\u00b8\x00\x00\xe0\x94\xa3y\xa5\a\fP=/\xac\x89\xb8\xb3\xaf\xa0\x80\xfdE\xedK\xec\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xa3\x80-\x8ae\x9e\x89\xa2\xc4~\x90T0\xb2\xa8'\x97\x89P\xa7\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa3\x83\x06\xcbp\xba\xa8\u4446\xbdh\xaap\xa8=$/)\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\x84vi\x1d4\x94.\xeak/v\x88\x92#\x04}\xb4az\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\x87\xceN\x96\x1axG\xf5`\a\\d\xe1YkVA\xd2\x1c\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xa3\x87\xec\xde\x0e\xe4\xc8\a\x94\x99\xfd\x8e\x03G;\u060a\xd7R*\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa3\x88:$\xf7\xf1f _\x1aj\x99I\al&\xa7nqx\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xa3\x8b[\xd8\x1a\x9d\xb9\u04b2\x1d^\xc7\xc6\x05R\xcd\x02\xedV\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa3\x90\xca\x12+\x85\x01\xee>^\a\xa8\xcaKA\x9f~M\xae\x15\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xa3\x93*1\xd6\xffu\xfb;\x12q\xac\xe7\u02a7\xd5\xe1\xff\x10Q\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xa3\x94\xadO\xd9\xe6S\x0eo\\S\xfa\xec\xbe\u0781\xcb\x17-\xa1\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xa3\x97\x9a\x92v\n\x13Z\xdfi\xd7/u\xe1gu_\x1c\xb8\u00c9\x05k\xc7^-c\x10\x00\x00\xe0\x94\xa3\x9b\xfe\xe4\xae\u027du\xbd\"\u01b6r\x89\x8c\xa9\xa1\xe9]2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa3\xa2b\xaf\u0493h\x19#\b\x92\xfd\xe8O-ZYJ\xb2\x83\x89e\xea=\xb7UF`\x00\x00\u07d4\xa3\xa2\xe3\x19\xe7\u04e1D\x8bZ\xa2F\x89S\x16\f-\xbc\xbaq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\xa5{\a\x16\x13(\x04\xd6\n\xac(\x11\x97\xff+=#{\x01\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xa3\xa9>\xf9\xdb\xea&6&=\x06\xd8I/jA\u0790|\"\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\xa3\xae\x18y\x00}\x80\x1c\xb5\xf3RqjM\u063a'!\xde=\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xa3\xba\r:6\x17\xb1\xe3\x1bNB,\xe2i\xe8s\x82\x8d]i\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\xa3\xbc\x97\x9bp\x80\t/\xa1\xf9/n\x0f\xb3G\u2359PE\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xa3\xbf\xf1\u07e9\x97\x16h6\f\r\x82\x82\x842\xe2{\xf5Ng\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa3\xc1J\xce(\xb1\x92\u02f0b\x14_\u02fdXi\xc6rq\xf6\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa3\xc3:\xfc\x8c\xb4pN#\x15=\xe2\x04\x9d5\xaeq3$r\x89+X\xad\u06c9\xa2X\x00\x00\u07d4\xa3\u0430<\xff\xbb&\x9fyj\u009d\x80\xbf\xb0}\xc7\u01ad\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa3\u0543\xa7\xb6[#\xf6\vy\x05\xf3\xe4\xaab\xaa\xc8\u007fB'\x898\xbe\xfa\x12mZ\x9f\x80\x00\u07d4\xa3\xdb6J3-\x88K\xa9;&\x17\xaeM\x85\xa1H\x9b\xeaG\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xa3\xe0Q\xfbtJ\xa3A\f;\x88\xf8\x99\xf5\xd5\u007f\x16\x8d\xf1-\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\xa3\xe3\xa6\xeaP\x95s\xe2\x1b\xd0#\x9e\xce\x05#\xa7\xb7\u061b/\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xa3\xf4\xad\x14\xe0\xbbD\xe2\xce,\x145\x9cu\xb8\xe72\xd3pT\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa3\xfa\xccP\x19\\\vI3\xc8X\x97\xfe\xcc[\xbd\x99\\4\xb8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\x03Z\xb1\xe5\x18\b!\xf0\xf3\x80\xf1\x13\x1bs\x87\xc8\u0641\u0349\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\n\xa2\xbb\xce\fr\xb4\xd0\xdf\xff\xccBq[+T\xb0\x1b\xfa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4\x19\xa9\x84\x14#c&uuV`\x894\x0e\xea\x0e\xa2\b\x19\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xa4!\u06f8\x9b:\aA\x90\x84\xad\x10\xc3\xc1]\xfe\x9b2\xd0\u008a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa4\"\xe4\xbf\v\xf7AG\u0309[\xed\x8f\x16\xd3\xce\xf3BaT\x89\x12\xef?b\xee\x116\x80\x00\u07d4\xa4%\x9f\x83E\xf7\u3a37+\x0f\xec,\xf7^2\x1f\xdaM\u0089g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xa4)\b\xe7\xfeS\x98\n\x9a\xbf@D\xe9W\xa5Kp\u973e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4)\xfa\x88s\x1f\xdd5\x0e\x8e\xcdn\xa5B\x96\xb6HO\u6549j\xc5\xc6-\x94\x86\a\x00\x00\xe0\x94\xa40\x99]\xdb\x18[\x98e\xdb\xe6%9\xad\x90\xd2.Ks\u008a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa46\xc7TS\xcc\xcaJ\x1f\x1bb\xe5\u0123\r\x86\xdd\xe4\xbeh\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa47\xfen\xc1\x03\u028d\x15\x8fc\xb34\"N\u032c[>\xa3\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4;m\xa6\xcbz\xacW\x1d\xff'\xf0\x9d9\xf8F\xf57i\xb1\x89\x14\x99\x8f2\xacxp\x00\x00\u07d4\xa4;\x81\xf9\x93V\xc0\xaf\x14\x1a\x03\x01\rw\xbd\x04,q\xc1\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4>\x19G\xa9$+5Ua\xc3\n\x82\x9d\xfe\uc881Z\xf8\x89\xd2=\x99\x96\x9f\u0591\x80\x00\u07d4\xa4H\x9aP\xea\xd5\xd5DZ{\xeeM-U6\u00a7lA\xf8\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa4O\xe8\x00\xd9o\xca\xd7;qp\xd0\xf6\x10\u02cc\x06\x82\xd6\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa4T2\xa6\xf2\xac\x9dVW{\x93\x8a7\xfa\xba\xc8\xcc|F\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4f\xd7p\u0618\xd8\xc9\xd4\x05\xe4\xa0\xe5Q\xef\xaf\xcd\xe5<\xf9\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\xe0\x94\xa4g\a1\x17X\x93\xbb\xcf\xf4\xfa\x85\u0397\xd9O\xc5\x1cK\xa8\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4kC\x87\xfbM\xcc\xe0\x11\xe7nMsT}D\x81\xe0\x9b\xe5\x89Hz\x9a0E9D\x00\x00\u07d4\xa4l\xd27\xb6>\xeaC\x8c\x8e;e\x85\xf6y\xe4\x86\b2\xac\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4wy\u063c\x1c{\xce\x0f\x01\x1c\xcb9\xefh\xb8T\xf8\u078f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa4\x82kl8\x82\xfa\xd0\xed\\\x8f\xbb%\xcc@\xccO3u\x9f\x89p\x1bC\xe3D3\xd0\x00\x00\u07d4\xa4\x87Y(E\x8e\xc2\x00]\xbbW\x8c\\\xd35\x80\xf0\xcf\x14R\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa4\x9fR:\xa5\x13d\xcb\xc7\u0655\x16=4\xebY\r\xed/\b\x89\x90'B\x1b*\x9f\xbc\x00\x00\u07d4\xa4\xa4\x9f\v\xc8h\x8c\xc9\xe6\xdc\x04\xe1\xe0\x8dR\x10&\xe6Ut\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa4\xa7\xd3\x06\xf5\x10\xcdX5\x94(\xc0\xd2\xf7\xc3`\x9dVt\u05c9\xb5\x8c\xb6\x1c<\xcf4\x00\x00\u07d4\xa4\xa8:\a8y\x9b\x97\x1b\xf2\xdep\x8c.\xbf\x91\x1c\xa7\x9e\xb2\x89 \x86\xac5\x10R`\x00\x00\u07d4\xa4\xb0\x9d\xe6\xe7\x13\xdciTnv\xef\n\xcf@\xb9O\x02A\xe6\x89\x11}\xc0b~\xc8p\x00\x00\xe0\x94\xa4\u04b4)\xf1\xadSI\xe3\x17\x04\x96\x9e\xdc_%\xee\x8a\xca\x10\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xa4\xd6\xc8.\u076eYG\xfb\xe9\xcd\xfb\xd5H\xae3\xd9\x1aq\x91\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa4\xda4E\r\"\xec\x0f\xfc\xed\xe0\x00K\x02\xf7\x87.\xe0\xb7:\x89\x05\x0fafs\xf0\x83\x00\x00\xe0\x94\xa4\xddY\xab^Q}9\x8eI\xfaS\u007f\x89\x9f\xedL\x15\xe9]\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa4\xe6#E\x1e~\x94\xe7\u86e5\xed\x95\u0228:b\xff\xc4\xea\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa4\xed\x11\xb0r\u061f\xb16u\x9f\u019bB\x8cH\xaa]L\xed\x89\x0e?\x15'\xa0<\xa8\x00\x00\u07d4\xa4\xfb\x14@\x9ag\xb4V\x88\xa8Y>\\\xc2\xcfYl\xedo\x11\x89a\t=|,m8\x00\x00\xe0\x94\xa5\x14\xd0\x0e\xddq\b\xa6\xbe\x83\x9ac\x8d\xb2AT\x18\x17A\x96\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\xe0\x94\xa5\"\xde~\xb6\xae\x12PR*Q13\xa9;\xd4(IG\\\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa5$\xa8\xcc\xccIQ\x8d\x17\n2\x82p\xa2\xf8\x813\xfb\xaf]\x89\x0f\xf7\x02-\xac\x10\x8a\x00\x00\u07d4\xa59\xb4\xa4\x01\xb5\x84\xdf\xe0\xf3D\xb1\xb4\"\xc6UC\x16~.\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa5>\xadT\xf7\x85\n\xf2\x148\xcb\xe0z\xf6\x86'\x9a1[\x86\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa5C\xa0f\xfb2\xa8f\x8a\xa0sj\f\x9c\xd4\rx\t\x87'\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa5gw\vj\xe3 \xbd\xdeP\xf9\x04\xd6c\xe7F\xa6\x1d\xac\xe6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5h\xdbMW\xe4\xd6tb\xd73\u019a\x9e\x0f\xe2n!\x83'\x89;k\xff\x92f\xc0\xae\x00\x00\u07d4\xa5i\x8059\x1eg\xa4\x90\x13\xc0\x00 yY1\x14\xfe\xb3S\x89\r\x02\xabHl\xed\xc0\x00\x00\u07d4\xa5p\":\xe3\u02a8QA\x8a\x98C\xa1\xacU\xdbH$\xf4\xfd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa5s`\xf0\x02\xe0\xd6M-tE}\x8c\xa4\x85~\xe0\v\xcd\u07c9\x123\xe22\xf6\x18\xaa\x00\x00\u07d4\xa5u\xf2\x89\x1d\xcf\u0368<\\\xf0\x14t\xaf\x11\xee\x01\xb7-\u0089\x05l\xd5_\xc6M\xfe\x00\x00\u07d4\xa5x;\xf342\xff\x82\xacI\x89\x85\xd7\xd4`\xaeg\xec6s\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xa5\x87MuF5\xa7b\xb3\x81\xa5\xc4\u01d2H:\xf8\xf2=\x1d\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\xa5\xa4\"\u007fl\xf9\x88%\xc0\u057a\xffS\x15u,\xcc\x1a\x13\x91\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa5\xabK\xd3X\x8fF\xcb'.V\xe9=\xee\u04c6\xba\x8bu=\x89HB\xf0A\x05\x87,\x80\x00\xe0\x94\xa5\xba\xd8e\t\xfb\xe0\xe0\xe3\xc0\xe9?m8\x1f\x1a\xf6\xe9\u0501\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa5\xc36\b;\x04\xf9G\x1b\x8cn\xd76y\xb7Mf\xc3c\uc263e\nL\x9d \xe2\x00\x00\u07d4\xa5\xcd\x129\x92\x19K4\xc4x\x13\x140;\x03\xc5IH\xf4\xb9\x89l\xfc\xc3\xd9\x1d\xa5c\x00\x00\u07d4\xa5\u0578\xb6-\x00-\xef\x92A7\x10\xd1;o\xf8\xd4\xfc}\u04c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xa5\xd9ni}F5\x8d\x11\x9a\xf7\x81\x9d\xc7\b\u007fj\xe4\u007f\xef\x8a\x03\x17\xbe\xe8\xaf3\x15\xa7\x80\x00\u07d4\xa5\xde^CO\xdc\xddh\x8f\x1c1\xb6\xfbQ,\xb1\x96rG\x01\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xa5\xe0\xfc<:\xff\xed=\xb6q\tG\xd1\xd6\xfb\x01\u007f>'m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5\xe9;I\xea|P\x9d\xe7\xc4Ml\xfe\xdd\xefY\x10\u07aa\xf2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa5\xe9\xcdKt%]\"\xb7\u0672z\xe8\xddC\xedn\xd0%+\x89)\x8d\xb2\xf5D\x11\u0640\x00\xe0\x94\xa5\xf0\a{5\x1flP\\\xd5\x15\u07e6\xd2\xfa\u007f\\L\u0487\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xa5\xf0u\xfd@\x135W{f\x83\u0081\xe6\xd1\x01C-\xc6\xe0\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xa5\xfe,\xe9\u007f\x0e\x8c8V\xbe\r\xe5\xf4\u0732\xce]8\x9a\x16\x89\x01=\xb0\xb8\xb6\x86>\x00\x00\u07d4\xa5\xffb\"-\x80\xc0\x13\xce\xc1\xa0\xe8\x85\x0e\xd4\xd3T\xda\xc1m\x89\vA\a\\\x16\x8b\x18\x00\x00\u07d4\xa6\t\xc2m\xd3P\xc25\xe4K+\x9c\x1d\xdd\xcc\u0429\xd9\xf87\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa6\f\x12\tuO]\x87\xb1\x81\xdaO\b\x17\xa8\x18Y\xef\x9f\u0609\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\xe0\x94\xa6\x10\x1c\x96\x1e\x8e\x1c\x15y\x8f\xfc\xd0\xe3 \x1dw\x86\xec7:\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xa6\x13Ei\x96@\x8a\xf1\xc2\xe9>\x17w\x88\xabU\x89^+2\x8a\x01Y\x19\xffG|\x88\xb8\x00\x00\u07d4\xa6\x18\x87\x81\x8f\x91J \xe3\x10w)\v\x83qZk-n\xf9\x89e\xea=\xb7UF`\x00\x00\u07d4\xa6\x1aT\xdfxJD\xd7\x1bw\x1b\x871u\t!\x13\x81\xf2\x00\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa6\x1c\u06ed\xf0K\x1eT\u0203\xde`\x05\xfc\xdf\x16\xbe\xb8\xeb/\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa69\xac\xd9k1\xbaS\xb0\u0407c\"\x9e\x1f\x06\xfd\x10^\x9d\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa6BP\x10\x04\xc9\x0e\xa9\xc9\xed\x19\x98\xba\x14\nL\xd6,o_\x89\r\x94\xfb\x8b\x10\xf8\xb1\x80\x00\u07d4\xa6D\xed\x92,\xc27\xa3\xe5\u0117\x9a\x99Tw\xf3nP\xbcb\x89\x1f\xa7=\x84]~\x96\x00\x00\u07d4\xa6F\xa9\\moY\xf1\x04\xc6T\x1dw`uz\xb3\x92\xb0\x8c\x89\u3bb5sr@\xa0\x00\x00\xe0\x94\xa6HL\u0184\xc4\xc9\x1d\xb5>\xb6\x8aM\xa4Zjk\xda0g\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa6N_\xfbpL,\x919\xd7~\xf6\x1d\x8c\u07e3\x1dz\x88\xe9\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\xe0\x94\xa6T&\xcf\xf3x\xed#%5\x13\xb1\x9fIm\xe4_\xa7\u13ca\x01\x86P\x12|\xc3\u0700\x00\x00\u07d4\xa6jIc\xb2\u007f\x1e\xe1\x93+\x17+\xe5\x96N\r:\xe5KQ\x89\t`\xdbwh\x1e\x94\x00\x00\u07d4\xa6\u007f8\x81\x95eB:\xa8_>:\xb6\x1b\xc7c\u02eb\x89\u0749sw\xb0\"\u01be\b\x00\x00\u07d4\xa6\x8c14E\xc2-\x91\x9e\xe4l\xc2\xd0\xcd\xff\x04:uX%\x89\x04\x13t\xfd!\xb0\u0600\x00\u07d4\xa6\x8e\f0\u02e3\xbcZ\x88>T\x03 \xf9\x99\xc7\xcdU\x8e\\\x89a\x9237b\xa5\x8c\x80\x00\u07d4\xa6\x90\xf1\xa4\xb2\n\xb7\xba4b\x86 \u079c\xa0@\xc4<\x19c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa6\x9d|\xd1}HB\xfe\x03\xf6*\x90\xb2\xfb\xf8\xf6\xaf{\xb3\x80\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa6\xa0\x82R\xc8YQw\xcc.`\xfc'Y>#y\xc8\x1f\xb1\x89\x01\x16Q\xac>zu\x80\x00\u07d4\xa6\xa0\xdeB\x1a\xe5Om\x17(\x13\b\xf5dm/9\xf7w]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa6\xb2\xd5s)s`\x10,\a\xa1\x8f\xc2\x1d\xf2\xe7I\x9f\xf4\xeb\x89\xd9o\u0390\u03eb\xcc\x00\x00\xe0\x94\xa6\xc9\x10\xceMIJ\x91\x9c\u036a\xa1\xfc;\x82\xaat\xba\x06\u03ca\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xa6\u3ea3\x8e\x10J\x1e'\xa4\xd8(i\xaf\xb1\xc0\xaen\xff\x8d\x89\x01\x11@\ueb4bq\x00\x00\u07d4\xa6\xee\xbb\xe4d\u04d1\x87\xbf\x80\u029c\x13\xd7 '\xec[\xa8\xbe\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa6\xf6+\x8a=\u007f\x11\"\a\x01\xab\x9f\xff\xfc\xb3'\x95\x9a'\x85\x89\x1bn)\x1f\x18\u06e8\x00\x00\u07d4\xa6\xf93\a\xf8\xbc\xe01\x95\xfe\u0387 C\xe8\xa0?{\xd1\x1a\x89\x9csK\xadQ\x11X\x00\x00\u07d4\xa7\x01\xdfy\xf5\x94\x90\x1a\xfe\x14DH^k \u00fd\xa2\xb9\xb3\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa7\x02L\xfdt,\x1e\xc1<\x01\xfe\xa1\x8d0B\xe6_\x1d]\xee\x8a\x02c\x11\x9a(\xab\u0430\x80\x00\u07d4\xa7\x18\xaa\xadY\xbf9\\\xba+#\xe0\x9b\x02\xfe\f\x89\x81bG\x8960<\x97\xe4hx\x00\x00\u07d4\xa7$|S\xd0Y\xeb|\x93\x10\xf6(\xd7\xfclj\nw?\b\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xa7%7c\xcfJu\u07d2\xca\x1evm\xc4\xee\x8a'E\x14{\x8a\x02F7p\xe9\n\x8fP\x00\x00\u07d4\xa7.\xe6f\u0133^\x82\xa5\x06\x80\x8bD<\xeb\xd5\xc62\xc7\u0749+^:\xf1k\x18\x80\x00\x00\u07d4\xa7DD\xf9\x0f\xbbT\xe5o:\u0276\xcf\u032aH\x19\xe4aJ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa7GC\x9a\xd0\u04d3\xb5\xa08a\xd7r\x962m\u8edd\xb9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xa7`{BW;\xb6\xf6\xb4\xd4\xf2<~*&\xb3\xa0\xf6\xb6\xf0\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\xa7i)\x89\n{G\xfb\x85\x91\x96\x01lo\u0742\x89\u03b7U\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u0794\xa7kt?\x98\x1bi0r\xa11\xb2+\xa5\x10\x96\\/\xef\u05c8\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xa7m?\x15bQ\xb7,\f\xcfKG\xa39<\xbdoI\xa9\u0149Hz\x9a0E9D\x00\x00\u07d4\xa7t(\xbc\xb2\xa0\xdbv\xfc\x8e\xf1\xe2\x0eF\x1a\n2\u016c\x15\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xa7u\x8c\xec\xb6\x0e\x8faL\u0396\x13~\xf7+O\xbd\awJ\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa7w^J\xf6\xa2:\xfa \x1f\xb7\x8b\x91^Q\xa5\x15\xb7\xa7(\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\xa7\u007f>\u1793\x88\xbb\xbb\"\x15\xc6#\x97\xb9e`\x13#`\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa7\x85\x9f\xc0\u007fun\xa7\xdc\xeb\xbc\xcdB\xf0X\x17X-\x97?\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa7\x96lH\x9fLt\x8az\u902a'\xa5t%\x17g\xca\xf9\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xa7\xa3\xbba9\xb0\xad\xa0\f\x1f\u007f\x1f\x9fV\u0654\xbaM\x1f\xa8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa7\xa3\xf1S\xcd\u00c8!\xc2\f]\x8c\x82A\xb2\x94\xa3\xf8+$\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa7\xa5\x17\u05ed5\x82\v\t\u0517\xfa~U@\xcd\xe9IXS\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xa7\xc9\u04c8\xeb\xd8s\xe6k\x17\x13D\x83\x97\xd0\xf3\u007f\x8b\u04e8\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa7\u073b\xa9\xb9\xbfgb\xc1EAlPjq\u3d17 \x9c\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xa7\xe7O\v\xdb'\x8f\xf0\xa8\x05\xa6Ha\x8e\xc5+\x16o\xf1\xbe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa7\xe87r\xbc \x0f\x90\x06\xaa*&\r\xba\xa8H=\xc5+0\x89\vB\xd56f7\xe5\x00\x00\xe0\x94\xa7\xef5\u0387\xed\xa6\u008d\xf2HxX\x15\x05>\xc9zPE\x8a\x01\x0f\f\xe9I\xe0\x0f\x93\x00\x00\u07d4\xa7\xf9\"\f\x80G\x82k\xd5\xd5\x18?Ngjmw\xbf\xed6\x89\bPh\x97k\xe8\x1c\x00\x00\u07d4\xa8\a\x10O'\x03\xd6y\xf8\u07af\xc4B\xbe\xfe\x84\x9eB\x95\v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\f\xb1s\x8b\xac\b\xd4\xf9\xc0\x8bM\xef\xf5\x15T_\xa8XO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa8\x19\xd2\xec\xe1\"\xe0(\xc8\xe8\xa0J\x06M\x02\xb9\x02\x9b\b\xb9\x8965\u026d\xc5\u07a0\x00\x00\u0794\xa8%\xfdZ\xbby&\xa6|\xf3k\xa2F\xa2K\xd2{\xe6\xf6\xed\x88\xf4?\xc2\xc0N\xe0\x00\x00\u07d4\xa8(U9\x86\x9d\x88\xf8\xa9aS7Uq}~\xb6Uv\xae\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xa83\x82\xb6\xe1Rg\x97J\x85P\xb9\x8fqv\xc1\xa3S\xf9\xbe\x89\xbf\xfd\xaf/\xc1\xb1\xa4\x00\x00\xe0\x94\xa8DlG\x81\xa77\xacC(\xb1\xe1[\x8a\v?\xbb\x0f\xd6h\x8a\x04\x87\x94\xd1\xf2F\x19*\x00\x00\u07d4\xa8E[A\x17e\u0590\x1e1\x1erd\x03\t\x1eB\xc5f\x83\x89\xb7:\xec;\xfe\x14P\x00\x00\xe0\x94\xa8f\x13\xe6\u0124\xc9\xc5_\\\x10\xbc\xda2\x17]\u02f4\xaf`\x8a\x02C\xd6\xc2\xe3k\xe6\xae\x00\x00\u07d4\xa8m\xb0}\x9f\x81/G\x96b-@\xe0=\x13Xt\xa8\x8at\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa8\u007fz\xbdo\xa3\x11\x94(\x96x\xef\xb6<\xf5\x84\xee^*a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xa8\x80\u2a3f\x88\xa1\xa8&H\xb4\x01W\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa8\x9d\xf3HY\xed\xd7\xc8 \u06c8w@\xd8\xff\x9e\x15\x15|{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\xa4<\x00\x91\x00al\xb4\xaeN\x03?\x1f\xc5\xd7\xe0\xb6\xf1R\x89\u0548\xd0x\xb4?M\x80\x00\u07d4\xa8\xa7\b\xe8O\x82\u06c6\xa3U\x02\x19;Ln\xe9\xa7n\xbe\x8f\x897\b\xba\xed=h\x90\x00\x00\xe0\x94\xa8\xa7\xb6\x8a\u06b4\xe3\xea\xdf\xf1\x9f\xfaX\xe3J?\xce\xc0\xd9j\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xa8\xa8\xdb\xdd\x1a\x85\u047e\xee%i\xe9\x1c\xccM\t\xae\u007fn\xa1\x8a\x01:k+VHq\xa0\x00\x00\u07d4\xa8\xac\xa7H\xf9\xd3\x12\xect\u007f\x8bex\x14&\x94\xc7\xe9\xf3\x99\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa8\xb6[\xa3\x17\x1a?w\xa65\v\x9d\xaf\x1f\x8dU\xb4\xd2\x01\xeb\x89(b\xf3\xb0\xd2\"\x04\x00\x00\u07d4\xa8\xbe\xb9\x1c+\x99\u0216J\xa9[kJ\x18K\x12i\xfc4\x83\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u0794\xa8\xc0\xb0/\xaf\x02\xcbU\x19\u0768\x84\xde{\xbc\x8c\x88\xa2\u0681\x88\xe7\xc2Q\x85\x05\x06\x00\x00\u07d4\xa8\xc1\u05aaA\xfe=e\xf6{\xd0\x1d\xe2\xa8f\xed\x1e\u066eR\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\xa8\xca\xfa\xc3\"\x80\xd0!\x02\v\xf6\xf2\xa9x(\x83\u05ea\xbe\x12\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xa8\xdb\v\x9b \x14S3A<;\fb\xf5\xf5.\u0544\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa8\xf3\u007f\n\xb3\xa1\xd4H\xa9\xe3\xce@\x96_\x97\xa6F\b:4\x89\x11\xe0\xe4\xf8\xa5\v\xd4\x00\x00\u07d4\xa8\xf8\x9d\xd5\xccnd\u05f1\xee\xac\xe0\a\x02\x02,\xd7\xd2\xf0=\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\xa9\x04v\xe2\xef\xdf\xeeO8{\x0f2\xa5\x06x\xb0\xef\xb5s\xb5\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa9\x14PF\xfa6(\xcf_\xd4\xc6\x13\x92{\xe51\xe6\xdb\x1f\u0749\x06\x12O\xee\x99;\xc0\x00\x00\u07d4\xa9\x14\u0375q\xbf\xd9=d\xdaf\xa4\xe1\b\xea\x13NP\xd0\x00\x89M\x878\x99G\x13y\x80\x00\xe0\x94\xa9\x1aZ{4\x1f\x99\xc55\x14N \xbe\x9ck;\xb4\u008eM\x8a\x01&u:\xa2$\xa7\v\x00\x00\u07d4\xa9%%Q\xa6$\xaeQ7\x19\u06beR\a\xfb\xef\xb2\xfdwI\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xa9'\u050b\xb6\u02c1K\xc6\t\xcb\u02a9\x15\x1f]E\x9a'\xe1\x89\x0e\xb95\t\x00d\x18\x00\x00\u07d4\xa9)\u023dq\xdb\f0\x8d\xac\x06\b\n\x17G\xf2\x1b\x14e\xaa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xa9K\xbb\x82\x14\u03cd\xa0\xc2\xf6h\xa2\xacs\xe8bHR\x8dK\x894\n\xad!\xb3\xb7\x00\x00\x00\u07d4\xa9Q\xb2D\xffP\u03eeY\x1d^\x1a\x14\x8d\xf6\xa98\xef*\x1a\x89^\x00\x15\x84\xdf\xcfX\x00\x00\u07d4\xa9`\xb1\xca\xdd;\\\x1a\x8el\xb3\xab\xca\xf5.\xe7\xc3\xd9\xfa\x88\x89R\x8b\xc3T^Rh\x00\x00\u07d4\xa9a\x17\x1fSB\xb1s\xddp\xe7\xbf\xe5\xb5\xca#\x8b\x13\xbc\u0749\xb8'\x94\xa9$O\f\x80\x00\u07d4\xa9u\xb0w\xfc\xb4\u030e\xfc\xbf\x83\x84Y\xb6\xfa$:AY\u0589\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xa9{\xeb:H\xc4_\x15((L\xb6\xa9_}\xe4S5\x8e\u018a\x06\x90\x83l\n\xf5\xf5`\x00\x00\u07d4\xa9~\a!DI\x9f\xe5\xeb\xbd5J\xcc~~\xfbX\x98]\b\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xa9\x86v/zO)O.\v\x172y\xad,\x81\xa2\"4X\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xa9\x8f\x10\x985\xf5\xea\xcd\x05Cd|4\xa6\xb2i\xe3\x80/\xac\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xa9\x97\xdf\u01d8j'\x05\bH\xfa\x1cd\u05e7\xd6\xe0z\u0322\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\u07d4\xa9\x99\x91\u03bd\x98\xd9\xc88\xc2_zt\x16\xd9\xe2D\xca%\r\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xa9\xa1\xcd\xc3;\xfd7o\x1c\rv\xfbl\x84\xb6\xb4\xac'Mh\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xa9\xa8\xec\xa1\x1a#\xd6F\x89\xa2\xaa>A}\xbb=3k\xb5\x9a\x89\x0e4S\xcd;g\xba\x80\x00\u07d4\xa9\xac\xf6\x00\b\x1b\xb5[\xb6\xbf\xba\xb1\x81_\xfcN\x17\xe8Z\x95\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xa9\xad\x19&\xbcf\xbd\xb31X\x8e\xa8\x197\x88SM\x98,\x98\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xa9\xaf!\xac\xbeH/\x811\x89j\"\x806\xbaQ\xb1\x94S\u00c9\x02\xb5\xe0!\x98\f\xc1\x80\x00\xe0\x94\xa9\xb2\xd2\xe0IN\xab\x18\xe0}7\xbb\xb8V\xd8\x0e\x80\xf8L\u04ca\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xa9\xbaoA;\x82\xfc\xdd\xf3\xaf\xfb\xbd\u0412\x87\xdc\xf5\x04\x15\u0289\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xa9\xbe\x88\xad\x1eQ\x8b\v\xbb\x02J\xb1\xd8\xf0\xe7?y\x0e\fv\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xa9\xbf\xc4\x10\xdd\xdb q\x1eE\xc0s\x87\xea\xb3\n\x05N\x19\xac\x89>\x99`\x1e\xdfNS\x00\x00\u07d4\xa9\u0522\xbc\xbe[\x9e\bi\xd7\x0f\x0f\xe2\xe1\u05aa\xcdE\xed\u0149\n\xc6\xe7z\xb6c\xa8\x00\x00\xe0\x94\xa9\xd6KO;\xb7\x85\a\"\xb5\x8bG\x8b\xa6\x917^\"NB\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xa9\xd6\xf8q\xcax\x1au\x9a \xac:\u06d7,\xf1()\xa2\b\x892$\xf4'#\xd4T\x00\x00\xe0\x94\xa9\xdc\x04$\u0196\x9dy\x83X\xb3\x93\xb1\x93:\x1fQ\xbe\xe0\n\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xa9\xe1\x94f\x1a\xacpN\xe9\u07a0C\x97N\x96\x92\xde\xd8J]\x89\x1a&\xa5\x14\"\xa0p\x00\x00\u07d4\xa9\xe2\x837\xe65q\x93\xd9\xe2\xcb#k\x01\xbeD\xb8\x14'\u07c9wC\"\x17\xe6\x83`\x00\x00\u07d4\xa9\xe6\xe2^ekv%Xa\x9f\x14z!\x98[\x88t\xed\xfe\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xa9\xe9\xdb\xcez,\xb06\x94y\x98\x97\xbe\xd7\xc5M\x15_\u06a8\x89\n\xb5\xae\x8f\u025de\x80\x00\u07d4\xa9\xed7{}n\xc2Yq\xc1\xa5\x97\xa3\xb0\xf3\xbe\xadW\u024f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xaa\x02\x00\xf1\xd1~\x9cT\xda\x06G\xbb\x969]W\xa7\x858\u06099>\xf1\xa5\x12|\x80\x00\x00\u07d4\xaa\f\xa3ss7\x17\x8a\f\xaa\xc3\t\x9cXK\x05lV0\x1c\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xaa\x13kG\x96+\xb8\xb4\xfbT\r\xb4\xcc\xf5\xfd\xd0B\xff\xb8\u03c9\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\xaa\x14B-o\n\xe5\xa7X\x19N\xd1W\x80\xc88\xd6\u007f\x1e\xe1\x8a\x06\t2\x05lD\x9d\xe8\x00\x00\u07d4\xaa\x16&\x9a\xac\x9c\r\x800h\xd8/\u01d1Q\xda\xdd3Kf\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xaa\x16p&\u04da\xb7\xa8V5\x94N\xd9\xed\xb2\xbf\xeb\xa1\x18P\x8a\x01\xc1\xd5\xe2\x1bO\xcfh\x00\x00\u07d4\xaa\x1b7h\xc1m\x82\x1fX\x0ev\xc8\xe4\xc8\xe8m}\u01c8S\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xaa\x1d\xf9.Q\xdf\xf7\v\x19s\xe0\xe9$\xc6b\x87\xb4\x94\xa1x\x89\x1c\xf8J0\xa0\xa0\xc0\x00\x00\u07d4\xaa,g\x00\x96\xd3\xf990S%B~\xb9U\xa8\xa6\r\xb3\u0149l\x95Y\x06\x99#-\x00\x00\u07d4\xaa15\xcbT\xf1\x02\xcb\xef\xe0\x9e\x96\x10:\x1ayg\x18\xffT\x89\x03\"\"\xd9\xc31\x94\x00\x00\u07d4\xaa2\x1f\xdb\xd4I\x18\r\xb8\xdd\xd3O\x0f\xe9\x06\xec\x18\xee\t\x14\x89%\"H\u07b6\xe6\x94\x00\x00\xe0\x94\xaa9%\xdc\"\v\xb4\xae!w\xb2\x880x\xb6\xdc4l\xa1\xb2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xaa?)`\x1a\x131t^\x05\xc4(0\xa1^q\x93\x8ab7\x89\\(=A\x03\x94\x10\x00\x00\xe0\x94\xaaG\xa4\xff\xc9y622\u025b\x99\xfa\xda\x0f'4\xb0\xae\xee\x8a\x01\xb8H\x9d\xf4\xdb\xff\x94\x00\x00\u07d4\xaaI=?O\xb8fI\x1c\xf8\xf8\x00\xef\xb7\xe22N\xd7\xcf\xe5\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xaaV\xa6]\u012b\xb7/\x11\xba\xe3+o\xbb\aDG\x91\xd5\u0249(\x94\xe9u\xbfIl\x00\x00\xe0\x94\xaaZ\xfc\xfd\x83\t\xc2\u07dd\x15\xbe^jPN}pf$\u014a\x01<\xf4\"\xe3\x05\xa17\x80\x00\u07d4\xaa\x8e\xb0\x82;\a\xb0\xe6\xd2\n\xad\xda\x0e\x95\xcf85\xbe\x19.\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xaa\x91#~t\r%\xa9/\u007f\xa1F\xfa\xa1\x8c\xe5m\xc6\xe1\xf3\x892$\xf4'#\xd4T\x00\x00\u07d4\xaa\x96\x0e\x10\xc5#\x91\xc5N\x158|\xc6z\xf8'\xb51m\u0309lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\x9b\xd4X\x955\xdb'\xfa+\xc9\x03\xca\x17\xd6y\xddeH\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\xa8\xde\xfe\x11\xe3a?\x11\x06\u007f\xb9\x83bZ\b\x99Z\x8d\xfc\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaa\xaa\xe6\x8b2\x14\x02\xc8\xeb\xc14h\xf3A\xc6<\f\xf0?\u0389Rf<\u02b1\xe1\xc0\x00\x00\u07d4\xaa\xad\x1b\xaa\xdeZ\xf0N+\x17C\x9e\x93Y\x87\xbf\x8c+\xb4\xb9\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xaa\xb0\n\xbfX(\xd7\xeb\xf2kG\u03ac\u0378\xba\x032Qf\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xaa\xbd\xb3\\\x15\x14\x98J\x03\x92\x13y?3E\xa1h\xe8\x1f\xf1\x89\x10\xca\u0216\xd29\x00\x00\x00\u07d4\xaa\xca`\xd9\xd7\x00\u7156\xbb\xbb\xb1\xf1\xe2\xf7\x0fF'\xf9\u060965\xbbw\xcbK\x86\x00\x00\u07d4\xaa\xce\u0629V;\x1b\xc3\x11\xdb\xdf\xfc\x1a\xe7\xf5u\x19\xc4D\f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\u04b7\xf8\x10f\x95\a\x8el\x13\x8e\xc8\x1at\x86\xaa\xca\x1e\xb2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaa\xe6\x1eC\xcb\r\f\x96\xb3\x06\x99\xf7~\x00\xd7\x11\u0423\x97\x9b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaa\xe72\xed\xa6Y\x88\u00e0\f\u007fG/5\x1cF;\x1c\x96\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaa\xf0#\xfe\U0009091b\xb7\x8b\xb7\xab\xc9]f\x9cP\xd5(\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xaa\xf5\xb2\a\xb8\x8b\r\xe4\xac@\xd7G\xce\xe0n\x17-\xf6\xe7E\x8a\x06\xa7\xb7\x1d\u007fQ\u0410\x00\x00\u07d4\xaa\xf9\xeeK\x88lm\x1e\x95Io\xd2t#[\xf4\xec\xfc\xb0}\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xaa\xfb{\x01:\xa1\xf8T\x1c~2{\xf6P\xad\xbd\x19L \x8f\x89I\x9e\t-\x01\xf4x\x00\x00\xe0\x94\xab\t\x863\xee\xee\f\xce\xfd\xf62\xf9WTV\xf6\u0740\xfc\x86\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xab\f\xedv.\x16a\xfa\xe1\xa9*\xfb\x14\b\x88\x94\x13yH%\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xab\x14\xd2!\xe3=TF)\x19\x8c\u0416\xedc\u07e2\x8d\x9fG\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xab \x9f\u0729y\u0426G\x01\n\xf9\xa8\xb5/\xc7\xd2\r\x8c\u044a\x01\xee\xe2S,|-\x04\x00\x00\u07d4\xab'\xbax\xc8\xe5\xe3\xda\xef1\xad\x05\xae\xf0\xff\x03%r\x1e\b\x89\x19^\xce\x00n\x02\xd0\x00\x00\u07d4\xab(q\xe5\a\u01fe9eI\x8e\x8f\xb4b\x02Z\x1a\x1cBd\x89*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xab8a\"o\xfe\xc1(\x91\x87\xfb\x84\xa0\x8e\xc3\xed\x042d\xe8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab=\x86\xbc\x82\x92~\f\xd4!\xd1F\xe0\u007f\x91\x93'\xcd\xf6\xf9\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xab>b\xe7z\x8b\"^A\x15\x92\xb1\xaf0\aR\xfeA$c\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xab>x)K\xa8\x86\xa0\xcf\xd5\xd3H\u007f\xb3\xa3\a\x8d3\x8dn\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xab@\x04\xc0@?~\xab\xb0\xeaXo!!V\xc4 =g\xf1\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xabAo\xe3\rX\xaf\xe5\xd9EL\u007f\xce\u007f\x83\v\xccu\x03V\x89\x0657\x01\xc6\x05\u06c0\x00\u07d4\xabEr\xfb\xb1\xd7+W]i\xecj\xd1s3\x87>\x85R\xfc\x89lj\xc5L\xdahG\x00\x00\u07d4\xabZy\x01av2\ts\xe8\xcd8\xf67U0\x02%1\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab]\xfc\x1e\xa2\x1a\xdcB\u03cc?n6\x1e$?\xd0\xdaa\xe5\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xabke\xea\xb8\xdf\xc9\x17\xec\x02Q\xb9\xdb\x0e\u03e0\xfa\x03(I\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xabp\x91\x93.K\u00dd\xbbU#\x80\u0293O\xd7\x16m\x1en\x89\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\xabt\x16\xff2%IQ\u02fcbN\xc7\xfbE\xfc~\u02a8r\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xab|B\xc5\xe5-d\x1a\a\xadu\t\x9cb\x92\x8b\u007f\x86b/\x89\x126\x1a\xa2\x1d\x14\xba\x00\x00\u07d4\xab}T\xc7\xc6W\x0e\xfc\xa5\xb4\xb8\xcep\xf5*Ws\xe5\xd5;\x89\x0f(:\xbe\x9d\x9f8\x00\x00\u07d4\xab~\v\x83\xed\x9aBLm\x1ejo\x87\xa4\xdb\xf0d\t\xc7\u0589\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xab\x84\xa0\xf1G\xad&T\x00\x00+\x85\x02\x9aA\xfc\x9c\xe5\u007f\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xab\x93\xb2n\xce\n\n\xa2\x13e\xaf\xed\x1f\xa9\xae\xa3\x1c\xd5Dh\x89W+{\x98sl \x00\x00\u07d4\xab\x94\x8aJ\xe3y\\\xbc\xa11&\xe1\x92S\xbd\xc2\x1d:\x85\x14\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xab\x9a\xd3n\\t\xce.\x969\x9fW\x83\x941\xd0\u77d6\xab\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\xab\xb2\xe6\xa7*@\xban\xd9\b\u037c\xec\x91\xac\xfdwx0\xd1dcG\x8a\xe0\xfcw \x89\a?u\u0460\x85\xba\x00\x00\xe0\x94\xab\u071f\x1b\xcfM\x19\xee\x96Y\x100\xe7r\xc340/}\x83\x8a\b~^\x11\xa8\x1c\xb5\xf8\x00\x00\u07d4\xab\xde\x14{*\xf7\x89\ua946T~f\xc4\xfa&d\xd3(\xa4\x89\rk`\x81\xf3L\x12\x80\x00\xe0\x94\xab\xe0|\xedj\xc5\xdd\xf9\x91\xef\xf6\xc3\xda\"jt\x1b\xd2C\xfe\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xab\xf1/\xa1\x9e\x82\xf7lq\x8f\x01\xbd\xca\x00\x03gE#\xef0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xab\xf7(\u03d3\x12\xf2!(\x02NpF\xc2Q\xf5\xdcY\x01\xed\x8a\x06A\xe8\xa15c\xd8\xf8\x00\x00\u07d4\xab\xf8\xff\xe0p\x8a\x99\xb5(\xcc\x1e\xd4\xe9\xceK\r\x060\xbe\x8c\x89z\xb5\u00ae\xee\xe68\x00\x00\u07d4\xab\xfc\xf5\xf2P\x91\xceW\x87_\xc6t\xdc\xf1\x04\xe2\xa7=\xd2\xf2\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xab\xfe\x93d%\xdc\u01f7K\x95P\x82\xbb\xaa\xf2\xa1\x1dx\xbc\x05\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xac\x02OYO\x95X\xf0ICa\x8e\xb0\xe6\xb2\xeeP\x1d\xc2r\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\x12*\x03\xcd\x05\x8c\x12._\xe1{\x87/Hw\xf9\u07d5r\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xac\x14.\xda\x11W\xb9\xa9\xa6C\x90\xdf~j\xe6\x94\xfa\u0249\x05\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\x1d\xfc\x98Kq\xa1\x99)\xa8\x1d\x81\xf0J|\xbb\x14\a7\x03\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xac!\xc1\xe5\xa3\xd7\xe0\xb5\x06\x81g\x9d\xd6\u01d2\xdb\u0287\xde\u02ca\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xac(\x89\xb5\x96o\f\u007f\x9e\xdbB\x89\\\xb6\x9d\x1c\x04\xf9#\xa2\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xac(\xb5\xed\xea\x05\xb7o\x8c_\x97\bEA'|\x96ijL\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xac,\x8e\t\xd0d\x93\xa68XC{\xd2\v\xe0\x19bE\x03e\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xac.vm\xac?d\x8fcz\xc6q?\u0770h\xe4\xa4\xf0M\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\xac9\x00)\x8d\xd1M|\xc9mJ\xbbB\x8d\xa1\xba\xe2\x13\xff\xed\x8a\x05<\xa1)t\x85\x1c\x01\x00\x00\u07d4\xac=\xa5&\xcf\u0388)s\x02\xf3LI\xcaR\r\xc2q\xf9\xb2\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xacD`\xa7nm\xb2\xb9\xfc\xd1R\xd9\xc7q\x8d\x9a\xc6\xed\x8co\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xacJ\xcf\xc3n\xd6\tJ'\xe1\x18\xec\xc9\x11\xcdG>\x8f\xb9\x1f\x89a\x91>\x14@<\f\x00\x00\u07d4\xacL\xc2V\xaet\xd6$\xac\xe8\r\xb0x\xb2 \u007fW\x19\x8fk\x89lyt\x12?d\xa4\x00\x00\u07d4\xacN\xe9\xd5\x02\xe7\xd2\xd2\xe9\x9eY\xd8\xca}_\x00\xc9KM\u058965\u026d\xc5\u07a0\x00\x00\u07d4\xacR\xb7~\x15fH\x14\xf3\x9eO'\x1b\xe6A0\x8d\x91\xd6\u0309\v\xed\x1d\x02c\xd9\xf0\x00\x00\u07d4\xacY\x99\xa8\x9d-\u0486\u0568\fm\xee~\x86\xaa\xd4\x0f\x9e\x12\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xac_br1H\r\r\x950.m\x89\xfc2\xcb\x1dO\xe7\xe3\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xac`\x8e+\xac\x9d\xd2\a(\u0494~\xff\xbb\xbf\x90\n\x9c\xe9K\x8a\x01EK\r\xb3uh\xfc\x00\x00\u07d4\xacm\x02\xe9\xa4k7\x9f\xacJ\u0271\u05f5\xd4{\xc8P\xce\x16\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xacoh\xe87\xcf\x19a\xcb\x14\xabGDm\xa1h\xa1m\u0789\x89Hz\x9a0E9D\x00\x00\u07d4\xacw\xbd\xf0\x0f\u0558[]\xb1+\xbe\xf8\x008\n\xbc*\x06w\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xac~\x03p'#\xcb\x16\xee'\xe2-\u0438\x15\xdc-\\\xae\x9f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xac\x8bP\x9a\xef\xea\x1d\xbf\xaf+\xb35\x00\xd6W\vo\xd9mQ\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xac\x8e\x87\xdd\xda^x\xfc\xbc\xb9\xfa\u007f\xc3\xce\x03\x8f\x9f}.4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xac\x9f\xffh\xc6\x1b\x01\x1e\xfb\xec\xf08\xedr\u06d7\xbb\x9er\x81\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xac\xa1\xe6\xbcd\xcc1\x80\xf6 \xe9M\u0171\xbc\xfd\x81X\xe4]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\xa2\xa883\v\x170-\xa71\xd3\r\xb4\x8a\x04\xf0\xf2\a\xc1\x89Hz\x9a0E9D\x00\x00\u07d4\xac\xaa\xdd\xcb\xf2\x86\xcb\x0e!]\xdaUY\x8f\u007f\xf0\xf4\xad\xa5\u018965\u026d\xc5\u07a0\x00\x00\u07d4\xac\xb9C8UK\u0108\u0308\xae-\x9d\x94\b\rk\u07c4\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xac\xbc-\x19\xe0l;\xab\xbb[o\x05+k\xf7\xfc7\xe0r)\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\xbd\x18U\x89\xf7\xa6\x8ag\xaaK\x1b\xd6Pw\xf8\xc6NN!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xac\xc0bp,Ya]4D\xefb\x14\xb8\x86+\x00\x9a\x02\xed\x89QO\xcb$\xff\x9cP\x00\x00\u07d4\xac\xc0\x90\x9f\xda.\xa6\xb7\xb7\xa8\x8d\xb7\xa0\xaa\xc8h\t\x1d\xdb\xf6\x89\x013v_\x1e&\u01c0\x00\u07d4\xac\xc1\u01c7\x86\xabM+;'q5\xb5\xba\x12>\x04\x00Hk\x89\x04E\x91\xd6\u007f\xec\xc8\x00\x00\u07d4\xac\xc4j*U\\t\xde\u0522\xbd\tN\x82\x1b\x97\x84;@\xc0\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xac\u015f;0\xce\xff\xc5da\xcc[\x8d\xf4\x89\x02$\x0e\x0e{\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\xce\x01\xe0\xa7\x06\x10\xdcp\xbb\x91\xe9\x92o\xa9\x95\u007f7/\xba\x89\x1d\x1c_>\xda \xc4\x00\x00\u07d4\xac\xd8\u0751\xf7\x14vLEg|c\xd8R\xe5n\xb9\xee\xce.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xac\u2af6;\x06\x04@\x9f\xbd\xe3\xe7\x16\u0487mD\xe8\xe5\u0749\b=lz\xabc`\x00\x00\xe0\x94\xac\xec\x91\xefiA\xcfc\v\xa9\xa3\u71e0\x12\xf4\xa2\xd9\x1d\u050a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xad\nJ\xe4x\xe9cn\x88\xc6\x04\xf2B\xcfT9\xc6\xd4V9\x89\xbe\xd1\xd0&=\x9f\x00\x00\x00\u07d4\xad\x17\x99\xaa\xd7`+E@\u0343/\x9d\xb5\xf1\x11P\xf1hz\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xad\x1dh\xa08\xfd%\x86\x06~\xf6\xd15\xd9b\x8ey\xc2\xc9$\x89\xfe\t\xa5'\x9e*\xbc\x00\x00\u07d4\xad*\\\x00\xf9#\xaa\xf2\x1a\xb9\xf3\xfb\x06n\xfa\n\x03\xde/\xb2\x8965\xbbw\xcbK\x86\x00\x00\u07d4\xad5e\xd5+h\x8a\xdd\xed\b\x16\x8b-8r\xd1}\n&\xae\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xad7|\xd2^\xb5>\x83\xae\t\x1a\n\x1d+E\x16\xf4\x84\xaf\u0789i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xadAM)\xcb~\xe9s\xfe\xc5N\"\xa3\x88I\x17\x86\xcfT\x02\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xadD5~\x01~$OGi1\u01f8\x18\x9e\xfe\xe8\n]\n\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xadW\xaa\x9d\x00\xd1\fC\x9b5\xef\xcc\v\xec\xac.9U\xc3\x13\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xadY\xa7\x8e\xb9\xa7J\u007f\xbd\xae\xfa\xfa\x82\xea\u0684u\xf0\u007f\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xadZ\x8dV\x01L\xfc\xb3`\xf4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xadr\x81!\x87?\x04V\xd0Q\x8b\x80\xabe\x80\xa2\x03pe\x95\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xads,\x97e\x93\xee\xc4x;N.\xcdy9yx\v\xfe\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xad}\xd0S\x85\x9e\xdf\xf1\xcbo\x9d*\xcb\xedm\xd5\xe32Bo\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xad\x80\xd8e\xb8\\4\xd2\xe6IK.z\xef\xeak\x9a\xf1\x84\u06c9\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xad\x8b\xfe\xf8\u018aH\x16\xb3\x91o5\xcb{\xfc\xd7\xd3\x04\tv\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xad\x8eH\xa3wi]\xe0\x146:R:(\xb1\xa4\fx\xf2\b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xad\x91\n#\u0585\x06\x13eJ\xf7\x863z\u04a7\bh\xacm\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xad\x92~\x03\xd1Y\x9ax\xca+\xf0\xca\u04a1\x83\xdc\xebq\xea\xc0\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xad\x92\xca\x06n\xdb|q\x1d\xfc[\x16a\x92\xd1\xed\xf8\xe7q\x85\x8a\a\x9f\x90\\o\xd3N\x80\x00\x00\u07d4\xad\x94#_\u00f3\xf4z$\x13\xaf1\u8111I\b\xef\fE\x89\x1b\x1b\x01B\xd8\x15\x84\x00\x00\u07d4\xad\x9e\x97\xa0H/5:\x05\xc0\xf7\x92\xb9w\xb6\xc7\xe8\x11\xfa_\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xad\x9fL\x89\n;Q\x1c\xeeQ\xdf\xe6\xcf\xd7\xf1\t;vA,\x89\x1bv|\xbf\xeb\f\xe4\x00\x00\u07d4\xad\xaa\x0eT\x8c\x03Z\xff\xedd\xcag\x8a\x96?\xab\xe9\xa2k\xfd\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\xad\xb9H\xb1\xb6\xfe\xfe }\xe6^\x9b\xbc-\xe9\x8e`]\vW\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xad\xc1\x9e\xc85\xaf\xe3\u5347\u0713\xa8\xa9!<\x90E\x13&\x89j\xdb\xe54\"\x82\x00\x00\x00\u07d4\xad\xc8\"\x8e\xf9(\xe1\x8b*\x80}\x00\xfb1\xfcgX\x15\xaa\x00\x00\u07d4\xad\xff\r\x1d\v\x97G\x1ev\u05c9\xd2\u470at\xf9\xbdT\xff\x89e\xea=\xb7UF`\x00\x00\u07d4\xae\x06,D\x86\x18d0u\xdez\x0004-\xce\xd6=\xba\u05c9,\xc6\u034c\u0082\xb3\x00\x00\xe0\x94\xae\x10\xe2z\x01O\r0k\xaf&mH\x97\u021a\xee\xe2\xe9t\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xae\x12k8,\xf2W\xfa\xd7\xf0\xbc}\x16)~T\xccrg\u0689\x10CV\x1a\x88)0\x00\x00\u07d4\xae\x13\xa0\x85\x11\x11\x0f2\xe5;\xe4\x12xE\xc8C\xa1\xa5|{\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xae\x17\x9aF\r\xb6c&t=$\xe6u#\xa5{$m\xaf\u007f\x8a\x01\x00\a\xae|\xe5\xbb\xe4\x00\x00\u07d4\xae\"(ey\x90y\xaa\xf4\xf0gJ\f\u06ab\x02\xa6\xd5p\xff\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xae#\x9a\xcf\xfdN\xbe.\x1b\xa5\xb4\x17\x05r\xdcy\xcce3\xec\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xae/\x9c\x19\xacv\x13e\x94C#\x93\xb0G\x1d\b\x90!d\u04c9%\xdf\x05\u01a8\x97\xe4\x00\x00\u07d4\xae4\x86\x1d4\"S\x19O\xfcfR\xdf\xdeQ\xabD\xca\xd3\xfe\x89\x19F\bhc\x16\xbd\x80\x00\u07d4\xae6\xf7E!!\x91>\x80\x0e\x0f\xcd\x1ae\xa5G\x1c#\x84o\x89\b\xe3\xf5\v\x17<\x10\x00\x00\u07d4\xae?\x98\xa4C\xef\xe0\x0f>q\x1dR]\x98\x94\u071aa\x15{\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\xe0\x94\xaeG\xe2`\x9c\xfa\xfe6\x9df\xd4\x15\xd99\xde\x05\b\x1a\x98r\x8a\x05\xba\xec\xf0%\xf9\xb6P\x00\x00\u07d4\xaeO\x12.5\xc0\xb1\xd1\xe4\x06\x92\x91E|\x83\xc0\u007f\x96_\xa3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaePU\x81L\xb8\xbe\f\x11{\xb8\xb1\xc8\u04b6;F\x98\xb7(\x89\x01\xbc\x93.\xc5s\xa3\x80\x00\u07d4\xaeS\x8cs\u0173\x8d\x8dXM~\xbd\xad\xef\xb1\\\xab\xe4\x83W\x896'\xe8\xf7\x127<\x00\x00\u07d4\xaeW\xcc\x12\x9a\x96\xa8\x99\x81\xda\xc6\r/\xfb\x87}]\xc5\xe42\x89<:#\x94\xb3\x96U\x00\x00\u07d4\xaeZ\xa1\xe6\u00b6\x0fo\xd3\xef\xe7!\xbbJq\x9c\xbe=o]\x89+$\u01b5Z^b\x00\x00\u07d4\xae\\\x9b\xda\xd3\xc5\u0221\"\x04D\xae\xa5\xc2)\xc1\x83\x9f\x1dd\x89\x19\xe2\xa4\xc8\x18\xb9\x06\x00\x00\u07d4\xae\\\xe35Z{\xa9\xb32v\f\tP\u00bcE\xa8_\xa9\xa0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xae]\"\x1a\xfc\xd3\u0493U\xf5\b\xea\xdf\xca@\x8c\xe3<\xa9\x03\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xaec[\xf781\x11\x9d-)\xc0\xd0O\xf8\xf8\xd8\u0425zF\x89Hz\x9a0E9D\x00\x00\xe0\x94\xaed\x81U\xa6X7\x0f\x92\x9b\xe3\x84\xf7\xe0\x01\x04~I\xddF\x8a\x02\xdf$\xae2\xbe D\x00\x00\xe0\x94\xaeo\fs\xfd\xd7|H\x97'Q!t\u0675\x02\x96a\x1cL\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xaep\xe6\x9d,J\n\xf8\x18\x80{\x1a'\x05\xf7\x9f\u0435\xdb\u01095e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xaew9\x12N\xd1S\x05%\x03\xfc\x10\x14\x10\xd1\xff\xd8\xcd\x13\xb7\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xaex\xbb\x84\x919\xa6\xba8\xae\x92\xa0\x9ai`\x1c\xc4\xcbb\u0449\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xae\x84\"\x10\xf4M\x14\u0124\u06d1\xfc\x9d;;P\x01O{\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xae\x84.\x81\x85\x8e\xcf\xed\xf6Plhm\xc2\x04\xac\x15\xbf\x8b$\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xae\x89T\xf8\xd6\x16m\xe5\a\xcfa)}\x0f\xc7\xcak\x9eq(\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xae\x9e\xcdk\u0755.\xf4\x97\xc0\x05\n\u0aca\x82\xa9\x18\x98\u0389\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\xae\x9f\\?\xbb\xe0\u027c\xbf\x1a\xf8\xfft\xea(\v:]\x8b\b\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xae\xad\x88\u0589Ak\x1c\x91\xf26D!7[}\x82\xd0RR\n\xfb\\Wm\x9f~\xb9>\u048a\r\xd0A \xba\t\xcf\xe6\x00\x00\u07d4\xae\xc2\u007f\xf5\xd7\xf9\xdd\u0691\x18?F\xf9\xd5%C\xb6\xcd+/\x89\x18e\x01'\xcc=\xc8\x00\x00\u07d4\xae\xe4\x9dh\xad\xed\xb0\x81\xfdCpZ_x\xc7x\xfb\x90\xdeH\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xae\xf5\xb1\"X\xa1\x8d\xec\a\xd5\xec.1et\x91\x9dy\xd6\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\xae\xfc\xfe\x88\xc8&\xcc\xf11\xd5N\xb4\ua7b8\x0ea\xe1\xee%\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xaf\x06\xf5\xfam\x12\x14\xecC\x96}\x1b\xd4\xdd\xe7J\xb8\x14\xa98\x89\x04\xc5>\xcd\xc1\x8a`\x00\x00\u07d4\xaf\x11H\xefl\x8e\x10=u0\xef\xc9\x16y\u026c'\x00\t\x93\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xaf >\"\x9d~mA\x9d\xf47\x8e\xa9\x87\x15Q_c\x14\x85\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xaf X\xc7(,\xf6|\x8c<\xf90\x13<\x89a|\xe7])\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4\xaf&\xf7\u01bfE> x\xf0\x89S\u4c80\x04\xa2\xc1\xe2\t\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xaf0\x87\xe6.\x04\xbf\x90\rZT\xdc>\x94bt\u0692B;\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf6\x14\u0736\x8a6\xe4ZN\x91\x1ebybG\"-Y[\x89z\x81\x06_\x11\x03\xbc\x00\x00\u07d4\xaf6\x15\u01c9\u0431\x15*\xd4\xdb%\xfe]\xcf\"(\x04\xcfb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xaf<\xb5\x96Y3\xe7\xda\u0603i;\x9c>\x15\xbe\xb6\x8aHs\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xafD\x93\xe8R\x1c\xa8\x9d\x95\xf5&|\x1a\xb6?\x9fEA\x1e\x1b\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xafL\xf4\x17\x85\x16\x1fW\x1d\f\xa6\x9c\x94\xf8\x02\x1fA)N\u028a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xafR\x9b\xdbE\x9c\xc1\x85\xbe\xe5\xa1\u014b\xf7\xe8\xcc\xe2\\\x15\r\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xafg\xfd>\x12\u007f\xd9\xdc6\xeb?\xcdj\x80\u01feOu2\xb2\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xafw\x1094Z40\x01\xbc\x0f\x8aY#\xb1&\xb6\rP\x9c\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94\xaf\u007fy\xcbAZ\x1f\xb8\u06fd\tF\a\xee\x8dA\xfb|Z;\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xaf\x87\xd27\x1e\xf3x\x95\u007f\xbd\x05\xba/\x1df\x93\x1b\x01\u2e09%\xf2s\x93=\xb5p\x00\x00\u07d4\xaf\x88\x0f\xc7V}U\x95\xca\xcc\xe1\\?\xc1L\x87B\xc2l\x9e\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xaf\x8e\x1d\xcb1L\x95\r6\x87CM0\x98X\xe1\xa8s\x9c\u0509\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xaf\x99-\xd6i\xc0\x88>U\x15\xd3\xf3\x11*\x13\xf6\x17\xa4\xc3g\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaf\xa1\u056d8\xfe\xd4GY\xc0[\x89\x93\xc1\xaa\r\xac\xe1\x9f@\x89\x04V9\x18$O@\x00\x00\xe0\x94\xaf\xa59XnG\x19\x17J;F\xb9\xb3\xe6c\xa7\u0475\xb9\x87\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xaf\xa6\x94n\xff\xd5\xffS\x15O\x82\x01\x02S\xdfG\xae(\f\u0309j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xaf\xc8\xeb\u860b\xd4\x10Z\xccL\x01\x8eTj\x1e\x8f\x9cx\x88\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xaf\xcc}\xbb\x83V\xd8B\xd4:\xe7\xe2<\x84\"\xb0\"\xa3\b\x03\x8a\x06o\xfc\xbf\xd5\xe5\xa3\x00\x00\x00\u07d4\xaf\xd0\x19\xff6\xa0\x91U4ki\x97H\x15\xa1\xc9\x12\xc9\n\xa4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xaf\xda\xc5\xc1\xcbV\xe2E\xbfp3\x00f\xa8\x17\uabecL\u0449\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf\xdd\x1bxab\xb81~ \xf0\xe9y\xf4\xb2\xceHmv]\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xaf\xf1\x04Z\xdf'\xa1\xaa2\x94a\xb2M\xe1\xba\u950ai\x8b\x89\x01\u03c4\xa3\n\n\f\x00\x00\u07d4\xaf\xf1\a\x96\v~\xc3N\u0590\xb6e\x02M`\x83\x8c\x19\x0fp\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xaf\xf1\x1c\xcfi\x93\x04\xd5\xf5\x86*\xf8`\x83E\x1c&\xe7\x9a\xe5\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xaf\xf1at\nm\x90\x9f\xe9\x9cY\xa9\xb7yE\xc9\x1c\xc9\x14H\x89\x03@\xaa\xd2\x1b;p\x00\x00\xe0\x94\xaf\xfc\x99\xd5\ubd28O\xe7x\x8d\x97\xdc\xe2t\xb08$\x048\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xaf\xfe\xa0G7\"\xcb\u007f\x0e\x0e\x86\xb9\xe1\x18\x83\xbfB\x8d\x8dT\x89i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xb0\t\x96\xb0Vn\xcb>rC\xb8\"y\x88\u0733R\xc2\x18\x99\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xb0\x1e8\x9b(\xa3\x1d\x8eI\x95\xbd\xd7\xd7\xc8\x1b\xee\xab\x1eA\x19\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb0-\x06(s3EE\u03a2\x92\x18\xe4\x05w`Y\x0ft#\x89\xac\xb6\xa1\xc7\xd9:\x88\x00\x00\u07d4\xb0/\xa2\x93\x87\xec\x12\xe3\u007fi\"\xacL\xe9\x8c[\t\xe0\xb0\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb06\x91k\xda\u03d4\xb6\x9eZ\x8ae`)u\xeb\x02a\x04\u0749\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb0A1\x0f\xe9\xee\u0586L\xed\u053e\xe5\x8d\xf8\x8e\xb4\xed<\xac\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb0U\xafL\xad\xfc\xfd\xb4%\xcfe\xbad1\a\x8f\a\xec\u056b\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xb0W\x11S\xdb\x1cN\u05ec\xae\xfe\x13\xec\xdf\xdbr\xe7\xe4\xf0j\x8a\x11\f\xffyj\xc1\x95 \x00\x00\u07d4\xb0n\xab\t\xa6\x10\u01a5=V\xa9F\xb2\xc44\x87\xac\x1d[-\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb0rI\xe0U\x04J\x91U5\x9a@)7\xbb\xd9T\xfeH\xb6\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xb0v\x182\x8a\x90\x13\a\xa1\xb7\xa0\xd0X\xfc\xd5xn\x9er\xfe\x8a\x06gI]JC0\xce\x00\x00\u07d4\xb0y\xbbM\x98f\x14:m\xa7*\xe7\xac\x00\"\x06)\x811\\\x89)3\x1eeX\xf0\xe0\x00\x00\u07d4\xb0{\xcc\bZ\xb3\xf7)\xf2D\x00Ah7\xb6\x996\xba\x88s\x89lm\x84\xbc\xcd\xd9\xce\x00\x00\u07d4\xb0{\xcf\x1c\xc5\xd4F.Q$\xc9e\xec\xf0\xd7\r\xc2z\xcau\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\xb0|\xb9\xc1$\x05\xb7\x11\x80uC\u0113De\xf8\u007f\x98\xbd-\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb0\u007f\u07af\xf9\x1dD`\xfel\xd0\u8870\xbd\x8d\"\xa6.\x87\x8a\x01\x1d%)\xf3SZ\xb0\x00\x00\xe0\x94\xb0\x9f\xe6\xd44\x9b\x99\xbc7\x93\x80T\x02-T\xfc\xa3f\xf7\xaf\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\xe0\x94\xb0\xaa\x00\x95\f\x0e\x81\xfa2\x10\x17>r\x9a\xaf\x16:'\xcdq\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xb0\xacN\xfff\x80\xee\x14\x16\x9c\xda\xdb\xff\xdb0\x80Om%\xf5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb0\xb3j\xf9\xae\xee\u07d7\xb6\xb0\"\x80\xf1\x14\xf19\x84\xea2`\x895e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xb0\xb7y\xb9K\xfa<.\x1fX{\u031c~!x\x92\"7\x8f\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xb0\xba\xeb0\xe3\x13wlLm$t\x02\xbaAg\xaf\u0361\u0309j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb0\xbb)\xa8a\xea\x1dBME\xac\u053f\u0112\xfb\x8e\xd8\t\xb7\x89\x04V9\x18$O@\x00\x00\xe0\x94\xb0\xc1\xb1w\xa2 \xe4\x1f|t\xd0|\u0785i\xc2\x1cu\xc2\xf9\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xb0\xc7\xceL\r\xc3\u00bb\xb9\x9c\xc1\x85{\x8aE_a\x17\x11\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb0\xce\xf8\xe8\xfb\x89\x84\xa6\x01\x9f\x01\xc6y\xf2r\xbb\xe6\x8f\\w\x89\b=lz\xabc`\x00\x00\xe0\x94\xb0\xd3+\xd7\xe4\u6577\xb0\x1a\xa3\xd0Ao\x80U}\xba\x99\x03\x8a\x03s\x9f\xf0\xf6\xe6\x130\x00\x00\xe0\x94\xb0\xd3\u0247+\x85\x05n\xa0\xc0\xe6\xd1\xec\xf7\xa7~<\u6ac5\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\xb0\xe4i\u0206Y8\x15\xb3IV8Y]\xae\xf0f_\xaeb\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xb0\xe7`\xbb\a\xc0\x81wsE\xe0W\x8e\x8b\u0218\"mN;\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1\x040\x04\xec\x19A\xa8\xcfO+\x00\xb1W\x00\u076co\xf1~\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb1\x05\xdd=\x98|\xff\xd8\x13\xe9\xc8P\n\x80\xa1\xad%}V\u0189lj\xccg\u05f1\xd4\x00\x00\u07d4\xb1\x0f\u04a6G\x10/\x88\x1ft\xc9\xfb\xc3}\xa62\x94\x9f#u\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xb1\x15\xee:\xb7d\x1e\x1a\xa6\xd0\x00\xe4\x1b\xfc\x1e\xc7!\f/2\x8a\x02\xc0\xbb=\xd3\fN \x00\x00\u07d4\xb1\x17\x8a\xd4s\x83\xc3\x1c\x814\xa1\x94\x1c\xbc\xd4t\xd0bD\xe2\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xb1\x17\x95\x89\u1779\xd4\x15W\xbb\xec\x1c\xb2L\xcc-\xec\x1c\u007f\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xb1\x19\u76a9\xb9\x16Re\x81\xcb\xf5!\xefGJ\xe8M\xcf\xf4\x89O\xba\x10\x01\xe5\xbe\xfe\x00\x00\u07d4\xb1\x1f\xa7\xfb'\n\xbc\xdfZ.\xab\x95\xaa0\u013566\uffc9+^:\xf1k\x18\x80\x00\x00\u07d4\xb1$\xbc\xb6\xff\xa40\xfc\xae.\x86\xb4_'\xe3\xf2\x1e\x81\xee\b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1)\xa5\xcbq\x05\xfe\x81\v\u0615\xdcr\x06\xa9\x91\xa4TT\x88\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\xe0\x94\xb1.\xd0{\x8a8\xadU\x066?\xc0z\vmy\x996\xbd\xaf\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb14\xc0\x049\x1a\xb4\x99(x3zQ\xec$/B(WB\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1?\x93\xaf0\xe8\xd7fs\x81\xb2\xb9[\xc1\xa6\x99\xd5\xe3\xe1)\x89\x16\u012b\xbe\xbe\xa0\x10\x00\x00\u07d4\xb1E\x92\x85\x86>\xa2\xdb7Y\xe5F\u03b3\xfb7a\xf5\x90\x9c\x89<\xd7*\x89@\x87\xe0\x80\x00\u07d4\xb1F\xa0\xb9%U<\xf0o\xca\xf5J\x1bM\xfe\xa6!)\aW\x89lnY\xe6|xT\x00\x00\xe0\x94\xb1Jz\xaa\x8fI\xf2\xfb\x9a\x81\x02\u05bb\xe4\u010a\xe7\xc0o\xb2\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb1K\xbe\xffpr\tu\xdca\x91\xb2\xa4O\xf4\x9f&r\x87<\x89\a\xc0\x86\x0eZ\x80\xdc\x00\x00\xe0\x94\xb1L\xc8\xde3\xd63\x826S\x9aH\x90 \xceFU\xa3+\u018a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb1M\xdb\x03\x86\xfb`c\x98\xb8\xccGVZ\xfa\xe0\x0f\xf1\xd6j\x89\xa1*\xff\b>f\xf0\x00\x00\u07d4\xb1S\xf8(\xdd\amJ|\x1c%t\xbb-\xee\x1aD\xa3\x18\xa8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb1T\x0e\x94\xcf\xf3F\\\xc3\u0447\xe7\xc8\u3f6f\x98FY\u2262\x15\xe4C\x90\xe33\x00\x00\u07d4\xb1X\xdbC\xfab\xd3\x0ee\xf3\u041b\xf7\x81\u01f6sr\uba89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xb1ar_\xdc\xed\xd1yR\xd5{#\xef([~K\x11i\xe8\x89\x02\xb6\xdf\xed6d\x95\x80\x00\u07d4\xb1dy\xba\x8e}\xf8\xf6>\x1b\x95\xd1I\u0345)\xd75\xc2\u0689-\xe3:j\xac2T\x80\x00\u07d4\xb1f\xe3}.P\x1a\xe7<\x84\x14+_\xfbZ\xa6U\xddZ\x99\x89l]\xb2\xa4\xd8\x15\xdc\x00\x00\u07d4\xb1\x83\xeb\xeeO\xcbB\xc2 \xe4wt\xf5\x9dlT\xd5\xe3*\xb1\x89V\xf7\xa9\xc3<\x04\xd1\x00\x00\u07d4\xb1\x88\a\x84D\x02~8g\x98\xa8\xaehi\x89\x19\xd5\xcc#\r\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xb1\x89j7\xe5\u0602Z-\x01vZ\xe5\xdeb\x99w\u0783R\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb1\x8eg\xa5\x05\n\x1d\xc9\xfb\x19\t\x19\xa3=\xa88\xefDP\x14\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb1\xa2\xb4:t3\xdd\x15\v\xb8\"'\xedQ\x9c\u05b1B\u04c2\x89\x94mb\rtK\x88\x00\x00\u07d4\xb1\xc0\u040b6\xe1\x84\xf9\x95*@7\xe3\xe5:f}\a\nN\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb1\xc3(\xfb\x98\xf2\xf1\x9a\xb6do\n|\x8cVo\xdaZ\x85@\x89\x87\x86x2n\xac\x90\x00\x00\xe0\x94\xb1\xc7Qxi9\xbb\xa0\xd6q\xa6w\xa1X\u01ab\xe7&^F\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xb1\xcdK\xdf\xd1\x04H\x9a\x02n\u025dYs\a\xa0By\xf1s\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb1\u03d4\xf8\t\x15\x05\x05_\x01\n\xb4\xba\u0196\xe0\xca\x0fg\xa1\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xb1\u05b0\x1b\x94\xd8T\xfe\x8b7J\xa6^\x89\\\xf2*\xa2V\x0e\x892\xf5\x1e\u06ea\xa30\x00\x00\xe0\x94\xb1\u06e5%\v\xa9bWU$n\x06yg\xf2\xad/\a\x91\u078a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xb1\xe2\u0755\xe3\x9a\xe9w\\U\xae\xb1?\x12\xc2\xfa#0S\xba\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb1\xe6\xe8\x10\xc2J\xb0H\x8d\xe9\xe0\x1eWH7\x82\x9f|w\u0409\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb1\xe9\xc5\xf1\xd2\x1eauzk.\xe7Y\x13\xfcZ\x1aA\x01\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\x03\u049elV\xb9&\x99\u0139-\x1fo\x84d\x8d\xc4\u03fc\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\x16\xdcY\xe2|=ry\xf5\xcd[\xb2\xbe\u03f2`n\x14\u0649\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\x1byy\xbf|\\\xa0\x1f\xa8-\xd6@\xb4\x1c9\xe6\u01bcu\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xb2#\xbf\x1f\xbf\x80H\\\xa2\xb5V}\x98\xdb{\xc3SM\xd6i\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb2-PU\xd9b15\x96\x1ej\xbd'<\x90\xde\xea\x16\xa3\xe7\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xb2-\xad\xd7\xe1\xe0R2\xa927\xba\xed\x98\xe0\u07d2\xb1\x86\x9e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb24\x03_uDF<\xe1\xe2+\xc5S\x06F\x84\xc5\x13\xcdQ\x89\r\x89\xfa=\u010d\xcf\x00\x00\u07d4\xb2G\u03dcr\xecH*\xf3\xea\xa7Ye\x8fy=g\nW\f\x891p\x8a\xe0\x04T@\x00\x00\u07d4\xb2ghA\xee\x9f-1\xc1r\xe8#\x03\xb0\xfe\x9b\xbf\x9f\x1e\t\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb2y\xc7\xd3U\u0088\x03\x92\xaa\u046a!\xee\x86|;5\a\u07c9D[\xe3\xf2\uf1d4\x00\x00\u07d4\xb2|\x1a$ L\x1e\x11\x8du\x14\x9d\xd1\t1\x1e\a\xc0s\xab\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb2\x81\x81\xa4X\xa4@\xf1\u01bb\x1d\xe8@\x02\x81\xa3\x14\x8fL5\x89\x14b\fW\xdd\xda\xe0\x00\x00\xe0\x94\xb2\x82E\x03|\xb1\x92\xf7W\x85\u02c6\xcb\xfe|\x93\r\xa2X\xb0\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xb2\x87\xf7\xf8\xd8\u00c7,\x1bXk\xcd}\n\xed\xbf~s'2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb2\x8b\xb3\x9f4fQ|\xd4o\x97\x9c\xf5\x96S\xee}\x8f\x15.\x89\x18e\x01'\xcc=\xc8\x00\x00\u07d4\xb2\x8d\xbf\xc6I\x98\x94\xf7:q\xfa\xa0\n\xbe\x0fK\xc9\u045f*\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xb2\x96\x8f}5\xf2\b\x87\x161\xc6h{?=\xae\xab\xc6al\x89\bu\xc4\u007f(\x9fv\x00\x00\u07d4\xb2\x9f[|\x190\xd9\xf9z\x11^\x06pf\xf0\xb5M\xb4K;\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb2\xa1D\xb1\xeag\xb9Q\x0f\"g\xf9\xda9\xd3\xf9=\xe2fB\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xa2\xc2\x11\x16\x12\xfb\x8b\xbb\x8e}\xd97\x8dg\xf1\xa3\x84\xf0P\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb2\xa4\x98\xf0;\xd7\x17\x8b\u0627\x89\xa0\x0fR7\xafy\xa3\xe3\xf8\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\u07d4\xb2\xaa/\x1f\x8e\x93\xe7\x97\x13\xd9,\xea\x9f\xfc\xe9\xa4\n\xf9\xc8-\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xb5\x16\xfd\u045e\u007f8d\xb6\xd2\xcf\x1b%*AV\xf1\xb0;\x89\x02\xe9\x83\xc7a\x15\xfc\x00\x00\u07d4\xb2\xb7\u0374\xffKa\u0577\xce\v\"p\xbb\xb5&\x97C\xec\x04\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb2\xbd\xbe\u07d5\x90\x84v\xd7\x14\x8a7\f\u0193t6(\x05\u007f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb2\xbf\xaaX\xb5\x19l\\\xb7\xf8\x9d\xe1_G\x9d\x188\xdeq=\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4\xb2\xc5>\xfa3\xfeJ:\x1a\x80 \\s\xec;\x1d\xbc\xad\x06\x02\x89h\x01\u06b3Y\x18\x93\x80\x00\xe0\x94\xb2\xd06\x05\x15\xf1}\xab\xa9\x0f\u02ec\x82\x05\xd5i\xb9\x15\u05ac\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xb2\xd1\xe9\x9a\xf9\x121\x85\x8epe\xdd\x19\x183\r\xc4\xc7G\u054a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\xb2\u066b\x96d\xbc\xf6\xdf <4o\u0192\xfd\x9c\xba\xb9 ^\x89\x17\xbex\x97`e\x18\x00\x00\u07d4\xb2\u0777\x86\xd3yN'\x01\x87\xd0E\x1a\xd6\u0237\x9e\x0e\x87E\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb2\xe0\x85\xfd\xdd\x14h\xba\aA['NsN\x11#\u007f\xb2\xa9\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xb2\xe9\xd7k\xf5\x0f\xc3k\xf7\u04d4Kc\xe9\u0288\x9bi\x99h\x89\x902\xeab\xb7K\x10\x00\x00\xe0\x94\xb2\xf9\xc9r\xc1\xe9swU\xb3\xff\x1b0\x88s\x83\x969[&\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xb2\xfc\x84\xa3\xe5\nP\xaf\x02\xf9M\xa08>\u055fq\xff\x01\u05ca\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xb3\x05\v\xef\xf9\xde3\xc8\x0e\x1f\xa1R%\xe2\x8f,A:\xe3\x13\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\xb3\x11\x96qJH\xdf\xf7&\xea\x943\xcd)\x12\xf1\xa4\x14\xb3\xb3\x89\x91Hx\xa8\xc0^\xe0\x00\x00\xe0\x94\xb3\x14[tPm\x1a\x8d\x04|\xdc\xdcU9*{SPy\x9a\x8a\x1bb)t\x1c\r=]\x80\x00\u07d4\xb3 \x83H6\xd1\xdb\xfd\xa9\xe7\xa3\x18M\x1a\xd1\xfdC \xcc\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3#\u073f.\xdd\xc58.\u4efb \x1c\xa3\x93\x1b\xe8\xb48\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb3$\x00\xfd\x13\xc5P\t\x17\xcb\x03{)\xfe\"\xe7\xd5\"\x8f-\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xb3%gL\x01\xe3\xf7)\rR&3\x9f\xbe\xacg\xd2!'\x9f\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xb3(%\xd5\xf3\xdb$\x9e\xf4\xe8\\\xc4\xf31S\x95\x89v\u8f09\x1b-\xf9\xd2\x19\xf5y\x80\x00\u07d4\xb3*\xf3\xd3\xe8\xd0u4I&To.2\x88{\xf9;\x16\xbd\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb3/\x1c&\x89\xa5\xcey\xf1\xbc\x97\v1XO\x1b\xcf\"\x83\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb3<\x03#\xfb\xf9\xc2l\x1d\x8a\xc4N\xf7C\x91\u0400F\x96\u0689\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb3O\x04\xb8\xdbe\xbb\xa9\xc2n\xfcL\xe6\xef\xc5\x04\x81\xf3\xd6]\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb3U}9\xb5A\x1b\x84D__T\xf3\x8fb\xd2qM\x00\x87\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xb3X\xe9|p\xb6\x05\xb1\xd7\xd7)\u07f6@\xb4<^\xaf\xd1\xe7\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xb3^\x8a\x1c\r\xac~\x0ef\u06ecsjY*\xbdD\x01%a\x88\xcf\xceU\xaa\x12\xb3\x00\x00\xe0\x94\xb3fx\x94\xb7\x86<\x06\x8a\xd3D\x87?\xcf\xf4\xb5g\x1e\x06\x89\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb3qw1\xda\xd6Q2\xday-\x87`0\xe4j\xc2'\xbb\x8a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3s\x1b\x04l\x8a\u0195\xa1'\xfdy\u0425\xd5\xfaj\xe6\xd1.\x89lO\xd1\xee$nx\x00\x00\u07d4\xb3|+\x9fPc{\xec\xe0\u0295\x92\b\xae\xfe\xe6F;\xa7 \x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb3\x88\xb5\xdf\xec\xd2\xc5\u4d56W|d%V\xdb\xfe'xU\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb3\x8cNS{]\xf90\xd6Zt\xd0C\x83\x1dkH[\xbd\xe4\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xb3\x919Wa\x94\xa0\x86a\x95\x15\x1f3\xf2\x14\n\xd1\u0306\u03ca\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xb3\x9fL\x00\xb2c\f\xab}\xb7)^\xf4=G\xd5\x01\xe1\u007f\u05c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb3\xa6K\x11vrOT\t\xe1AJ5#f\x1b\xae\xe7KJ\x89\x01ch\xffO\xf9\xc1\x00\x00\u07d4\xb3\xa6\xbdA\xf9\xd9\xc3 \x1e\x05\v\x87\x19\x8f\xbd\xa3\x994\"\x10\x89\xc4a\xe1\xdd\x10)\xb5\x80\x00\u07d4\xb3\xa8\xc2\xcb}5\x8eW9\x94\x1d\x94[\xa9\x04Z\x02:\x8b\xbb\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3\xaeT\xfb\xa0\x9d>\xe1\u05bd\xd1\xe9W\x929\x19\x02L5\xfa\x89\x03\x8d,\xeee\xb2*\x80\x00\u07d4\xb3\xb7\xf4\x93\xb4J,\x8d\x80\xecx\xb1\xcd\xc7Ze+s\xb0l\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb3\xc2(s\x1d\x18m-\xed[_\xbe\x00Lfl\x8eF\x9b\x86\x89\x01\x92t\xb2Y\xf6T\x00\x00\u07d4\xb3\xc2``\x9b\x9d\xf4\t^l]\xff9\x8e\xeb^-\xf4\x99\x85\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xb3\xc6[\x84Z\xbal\xd8\x16\xfb\xaa\xe9\x83\xe0\xe4l\x82\xaa\x86\"\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb3\xc9H\x11\xe7\x17[\x14\x8b(\x1c\x1a\x84[\xfc\x9b\xb6\xfb\xc1\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb3\xe2\x0e\xb4\xde\x18\xbd\x06\x02!h\x98\x94\xbe\u5bb2SQ\xee\x89\x03\xfc\x80\xcc\xe5\x16Y\x80\x00\u07d4\xb3\xe3\xc49\x06\x98\x80\x15f\x00\u0089.D\x8dA6\xc9-\x9b\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\xe0\x94\xb3\xf8*\x87\xe5\x9a9\xd0\u0480\x8f\aQ\xebr\xc22\x9c\xdc\u014a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb3\xfc\x1dh\x81\xab\xfc\xb8\xbe\xcc\v\xb0!\xb8\xb7;r3\u0751\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xb4\x05\x94\xc4\xf3fN\xf8I\u0326\"{\x8a%\xaai\t%\xee\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb4\x1e\xaf]Q\xa5\xba\x1b\xa3\x9b\xb4\x18\u06f5O\xabu\x0e\xfb\x1f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4$\u058d\x9d\r\x00\xce\xc1\x93\x8c\x85N\x15\xff\xb8\x80\xba\x01p\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb4%bs\x96+\xf61\xd0\x14U\\\xc1\xda\r\xcc1akI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb40g\xfep\u0675Ys\xbaX\xdcd\xdd\u007f1\x1eUBY\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb46W\xa5\x0e\xec\xbc0w\xe0\x05\xd8\xf8\xd9O7xv\xba\u0509\x01\xec\x1b:\x1f\xf7Z\x00\x00\u07d4\xb4<'\xf7\xa0\xa1\"\bK\x98\xf4\x83\x92%A\u0203l\xee,\x89&\u009eG\u0104L\x00\x00\xe0\x94\xb4A5v\x86\x9c\b\xf9Q*\xd3\x11\xfe\x92Y\x88\xa5-4\x14\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xb4F\x05U$q\xa6\xee\xe4\u06abq\xff;\xb4\x13&\xd4s\xe0\x89-~=Q\xbaS\xd0\x00\x00\u07d4\xb4GW\x1d\xac\xbb>\u02f6\xd1\xcf\v\f\x8f88\xe5#$\xe2\x89\x01\xa3\x18f\u007f\xb4\x05\x80\x00\u07d4\xb4G\x83\xc8\xe5{H\a\x93\xcb\u059aE\xd9\f{O\fH\xac\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb4H\x15\xa0\xf2\x8eV\x9d\x0e\x92\x1aJ\u078f\xb2d%&Iz\x89\x03\x027\x9b\xf2\xca.\x00\x00\u07d4\xb4Im\xdb'y\x9a\"$W\xd79y\x11g(\u8844[\x89\x8d\x81\x9e\xa6_\xa6/\x80\x00\xe0\x94\xb4RL\x95\xa7\x86\x0e!\x84\x02\x96\xa6\x16$@\x19B\x1cJ\xba\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb4\\\xca\r6\x82fbh<\xf7\u0432\xfd\xach\u007f\x02\xd0\u010965\u026d\xc5\u07a0\x00\x00\u0794\xb4d@\u01d7\xa5V\xe0L}\x91\x04f\x04\x91\xf9k\xb0v\xbf\x88\xce\xc7o\x0eqR\x00\x00\u07d4\xb4j\u0386^,P\xeaF\x98\xd2\x16\xabE]\xffZ\x11\xcdr\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4m\x11\x82\xe5\xaa\xca\xff\r&\xb2\xfc\xf7/<\x9f\xfb\xcd\xd9}\x89\xaa*`<\xdd\u007f,\x00\x00\u07d4\xb4\x89!\xc9h}U\x10tE\x84\x93n\x88\x86\xbd\xbf-\xf6\x9b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\x98\xbb\x0fR\x00\x05\xb6!jD%\xb7Z\xa9\xad\xc5-b+\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xb4\xb1\x1d\x10\x9f`\x8f\xa8\xed\xd3\xfe\xa9\xf8\xc3\x15d\x9a\xeb=\x11\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb4\xb1K\xf4TU\u042b\b\x035\x8bu$\xa7+\xe1\xa2\x04[\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb4\xb1\x85\xd9C\xee+Xc\x1e3\xdf\xf5\xafhT\xc1y\x93\xac\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\xbf$\u02c3hk\xc4i\x86\x9f\xef\xb0D\xb9\tqi\x93\xe2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb4\xc2\x00@\xcc\u0661\xa3(=\xa4\u0522\xf3e\x82\bC\xd7\xe2\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb4\xc8\x17\x0f{*\xb56\xd1\u0662[\xdd :\xe1(\x8d\xc3\u0549\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb4\xd8/.i\x94?}\xe0\xf5\xf7t8y@o\xac.\x9c\xec\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xb4\xddF\f\xd0\x16rZd\xb2.\xa4\xf8\xe0n\x06gN\x03>\x8a\x01#\x1b\xb8t\x85G\xa8\x00\x00\u07d4\xb4\xddT\x99\xda\xeb%\a\xfb-\xe1\"\x97s\x1dLr\xb1k\xb0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb5\x04l\xb3\xdc\x1d\xed\xbd6E\x14\xa2\x84\x8eD\xc1\xdeN\xd1G\x8a\x03{}\x9b\xb8 @^\x00\x00\xe0\x94\xb5\b\xf9\x87\xb2\xde4\xaeL\xf1\x93\u0785\xbf\xf6\x13\x89b\x1f\x88\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xb5\tU\xaan4\x15q\x98f\b\xbd\u0211\xc2\x13\x9fT\f\u07c9j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb5\f\x14\x9a\x19\x06\xfa\xd2xo\xfb\x13Z\xabP\x177\xe9\xe5o\x89\x15\b\x94\xe8I\xb3\x90\x00\x00\u07d4\xb5\f\x9fW\x89\xaeD\xe2\xdc\xe0\x17\xc7\x14\xca\xf0\f\x83\x00\x84\u0089\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xb5\x14\x88,\x97\x9b\xb6B\xa8\r\u04c7T\u0578\xc8)m\x9a\a\x893\xc5I\x901r\f\x00\x00\u07d4\xb5\x1d\u0734\xddN\x8a\xe6\xbe3m\xd9eIq\xd9\xfe\xc8kA\x89\x16\xd4d\xf8=\u2500\x00\u07d4\xb5\x1eU\x8e\xb5Q/\xbc\xfa\x81\xf8\u043d\x93\x8cy\xeb\xb5$+\x89&\u009eG\u0104L\x00\x00\u07d4\xb5#\xff\xf9t\x98q\xb3S\x88C\x887\xf7\xe6\xe0\u07a9\xcbk\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xb5-\xfbE\xde]t\xe3\xdf \x832\xbcW\x1c\x80\x9b\x8d\xcf2\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xb55\xf8\u06c7\x9f\xc6\u007f\xecX\x82J\\\xbenT\x98\xab\xa6\x92\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xb57\xd3jp\xee\xb8\xd3\xe5\xc8\r\xe8\x15\"\\\x11X\u02d2\u0109QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xb5;\xcb\x17L%\x184\x8b\x81\x8a\xec\xe0 6E\x96Fk\xa3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5I>\xf1srDE\xcf4\\\x03]'\x9b\xa7Y\xf2\x8dQ\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb5S\xd2]kT!\xe8\x1c*\xd0^\v\x8b\xa7Q\xf8\xf0\x10\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5Tt\xbaX\xf0\xf2\xf4\x0el\xba\xbe\xd4\xea\x17n\x01\x1f\xca\u0589j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb5U\xd0\x0f\x91\x90\xcc6w\xae\xf3\x14\xac\xd7?\xdc99\x92Y\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5W\xab\x949\xefP\xd27\xb5S\xf0%\b6JFj\\\x03\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5jx\x00(\x03\x9c\x81\xca\xf3{gu\xc6 \u7195Gd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5j\u04ae\xc6\xc8\xc3\xf1\x9e\x15\x15\xbb\xb7\u0751(RV\xb69\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5t\x13\x06\n\xf3\xf1N\xb4y\x06_\x1e\x9d\x19\xb3uz\xe8\u0309\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xb5uI\xbf\xbc\x9b\xdd\x18\xf76\xb2&P\xe4\x8as`\x1f\xa6\\\x89\x18-~L\xfd\xa08\x00\x00\xe0\x94\xb5w\xb6\xbe\xfa\x05N\x9c\x04\x04a\x85P\x94\xb0\x02\xd7\xf5{\u05ca\x18#\xf3\xcfb\x1d#@\x00\x00\u07d4\xb5{\x04\xfa#\xd1 ?\xae\x06\x1e\xacEB\xcb`\xf3\xa5v7\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\xb5\x87\f\xe3B\xd43C36s\x03\x8bGd\xa4n\x92_>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5\x87\xb4J,\xa7\x9eK\xc1\u074b\xfd\xd4: qP\xf2\xe7\xe0\x89\",\x8e\xb3\xfff@\x00\x00\u07d4\xb5\x89gm\x15\xa0DH4B0\xd4\xff'\xc9^\xdf\x12,I\x8965\u026d\xc5\u07a0\x00\x00\u0794\xb5\x8bR\x86^\xa5]\x806\xf2\xfa\xb2`\x98\xb3R\u0283~\x18\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xb5\x90k\n\u9881X\xe8\xacU\x0e9\xda\bn\xe3\x15v#\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5\xa4g\x96\x85\xfa\x14\x19l.\x920\xc8\xc4\xe3;\xff\xbc\x10\xe2\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xb5\xa5\x89\u075f@q\u06f6\xfb\xa8\x9b?]]\xae}\x96\xc1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5\xa6\x06\xf4\xdd\u02f9G\x1e\xc6\u007fe\x8c\xaf+\x00\xees\x02^\x89\xeaun\xa9*\xfct\x00\x00\u07d4\xb5\xadQW\u0769!\xe6\xba\xfa\u0350\x86\xaes\xae\x1fa\x1d?\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb5\xad\xd1\u701f}\x03\x06\x9b\xfe\x88;\n\x93\"\x10\xbe\x87\x12\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb5\xba)\x91|x\xa1\xd9\xe5\xc5\xc7\x13fl\x1eA\x1d\u007fi:\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb5\xc8\x16\xa8(<\xa4\xdfh\xa1\xa7=c\xbd\x80&\x04\x88\xdf\b\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb5\xca\xc5\xed\x03G}9\v\xb2g\xd4\xeb\xd4a\x01\xfb\xc2\xc3\u0689\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xb5\u037cA\x15@oR\u5a85\xd0\xfe\xa1p\u0497\x9c\u01fa\x89Hz\x9a0E9D\x00\x00\u0794\xb5\u0653M{)+\xcf`;(\x80t\x1e\xb7`(\x83\x83\xa0\x88\xe7\xc2Q\x85\x05\x06\x00\x00\u07d4\xb5\xddP\xa1]\xa3Ih\x89\nS\xb4\xf1?\xe1\xaf\b\x1b\xaa\xaa\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb5\xfa\x81\x84\xe4>\xd3\u0e2b\x91!da\xb3R\x8d\x84\xfd\t\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xb5\xfb~\xa2\xdd\xc1Y\x8bfz\x9dW\xdd9\xe8Z8\xf3]V\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb6\x00B\x97R\xf3\x99\xc8\r\a4tK\xae\n\x02.\xcag\u0189\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb6\x00\xfe\xabJ\xa9lSu\x04\xd9`W\"1Ai,\x19:\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xb6\x04|\u07d3-\xb3\xe4\x04_Iv\x12#AS~\u0556\x1e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb6\x15\xe9@\x14>\xb5\u007f\x87X\x93\xbc\x98\xa6\x1b=a\x8c\x1e\x8c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xb6\x1c4\xfc\xac\xdap\x1aZ\xa8p$Y\u07b0\u4b83\x8d\xf8\x8a\aiZ\x92\xc2\ro\xe0\x00\x00\xe0\x94\xb60d\xbd3U\xe6\xe0~-7p$\x12Z3wlJ\xfa\x8a\b7Z*\xbc\xca$@\x00\x00\u07d4\xb65\xa4\xbcq\xfb(\xfd\xd5\xd2\xc3\"\x98:V\u0084Bni\x89\t79SM(h\x00\x00\u07d4\xb6F\u07d8\xb4\x94BtkaR\\\x81\xa3\xb0K\xa3\x10bP\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xb6YA\xd4LP\xd2Ffg\r6Gf\xe9\x91\xc0.\x11\u0089 \x86\xac5\x10R`\x00\x00\xe0\x94\xb6[\u05c0\xc7CA\x15\x16 'VR#\xf4NT\x98\xff\x8c\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\xb6d\x11\xe3\xa0-\xed\xb7&\xfay\x10}\xc9\v\xc1\xca\xe6MH\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb6fu\x14.1\x11\xa1\xc2\xea\x1e\xb2A\x9c\xfaB\xaa\xf7\xa24\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xb6o\x92\x12K^c\x03XY\xe3\x90b\x88i\xdb\u07a9H^\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xb6rsJ\xfc\xc2$\xe2\xe6\t\xfcQ\xd4\xf0Ys'D\xc9H\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\xe0\x94\xb6w\x1b\v\xf3B\u007f\x9a\xe7\xa9>|.a\xeec\x94\x1f\xdb\b\x8a\x03\xfb&i)T\xbf\xc0\x00\x00\u07d4\xb6z\x80\xf1p\x19}\x96\xcd\xccJ\xb6\u02e6'\xb4\xaf\xa6\xe1,\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xb6\x88\x99\xe7a\rL\x93\xa255\xbc\xc4H\x94[\xa1fo\x1c\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb6\xa8)3\xc9\xea\u06bd\x98\x1e]m`\xa6\x81\x8f\xf8\x06\xe3k\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xb6\xaa\u02cc\xb3\v\xab*\xe4\xa2BF&\xe6\xe1+\x02\xd0F\x05\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xb6\xb3J&?\x10\xc3\xd2\xec\xeb\n\xccU\x9a{*\xb8\\\xe5e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb6\xbf\xe1\xc3\xef\x94\xe1\x84o\xb9\xe3\xac\xfe\x9bP\xc3\xe9\x06\x923\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xb6\xcdt2\xd5\x16\x1b\xe7\x97h\xadE\xde>Dz\a\x98 c\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb6\xceM\xc5`\xfcs\xdci\xfbzb\xe3\x88\xdb~r\xeavO\x894]\xf1i\xe9\xa3X\x00\x00\u07d4\xb6\xde\u03c2\x96\x98\x19\xba\x02\xde)\xb9\xb5\x93\xf2\x1bd\xee\xda\x0f\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\xe0\x94\xb6\xe6\xc3\"+ko\x9b\xe2\x87]*\x89\xf1'\xfbd\x10\x0f\xe2\x8a\x01\xb2\x1dS#\xcc0 \x00\x00\u07d4\xb6\xe8\xaf\xd9=\xfa\x9a\xf2\u007f9\xb4\xdf\x06\ag\x10\xbe\xe3\u07eb\x89\x01Z\xf1\u05cbX\xc4\x00\x00\xe0\x94\xb6\xf7\x8d\xa4\xf4\xd0A\xb3\xbc\x14\xbc[\xa5\x19\xa5\xba\f2\xf1(\x8a$}\xd3,?\xe1\x95\x04\x80\x00\xe0\x94\xb6\xfb9xbP\b\x14&\xa3B\xc7\rG\xeeR\x1e[\xc5c\x8a\x03-&\xd1.\x98\v`\x00\x00\u07d4\xb7\r\xba\x93\x91h+J6Nw\xfe\x99%c\x01\xa6\xc0\xbf\x1f\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\x16#\xf3Q\a\xcft1\xa8?\xb3\xd2\x04\xb2\x9e\u0c67\xf4\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xb7\x1a\x13\xba\x8e\x95\x16{\x803\x1bR\u059e7\x05O\xe7\xa8&\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\x1bb\xf4\xb4H\xc0+\x12\x01\xcb^9J\xe6'\xb0\xa5`\xee\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xb7\" \xad\xe3d\xd06\x9f--\xa7\x83\xcaGM{\x9b4\u0389\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\xe0\x94\xb7#\r\x1d\x1f\xf2\xac\xa3f\x969\x14\xa7\x9d\xf9\xf7\xc5\xea,\x98\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\xb7$\n\U000af433<\b\xae\x97d\x10>5\xdc\xe3c\x84(\x8a\x01\xca\xdd/\xe9hnc\x80\x00\u07d4\xb7'\xa9\xfc\x82\xe1\xcf\xfc\\\x17_\xa1HZ\x9b\xef\xa2\u037d\u04496'\xe8\xf7\x127<\x00\x00\u07d4\xb7,*\x01\x1c\r\xf5\x0f\xbbn(\xb2\n\xe1\xaa\xd2\x17\x88g\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb78-7\xdb\x03\x98\xacrA\f\xf9\x81=\xe9\xf8\xe1\uc36d\x8966\xc2^f\xec\xe7\x00\x00\u07d4\xb7;O\xf9\x9e\xb8\x8f\u061b\vmW\xa9\xbc3\x8e\x88o\xa0j\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xb7=jwU\x9c\x86\xcfet$)\x039K\xac\xf9n5p\x89\x04\xf1\xa7|\xcd;\xa0\x00\x00\u07d4\xb7Cr\xdb\xfa\x18\x1d\xc9$/9\xbf\x1d71\xdf\xfe+\xda\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7G\x9d\xabP\"\xc4\xd5\u06ea\xf8\xde\x17\x1bN\x95\x1d\u0464W\x89\x04V9\x18$O@\x00\x00\u07d4\xb7I\xb5N\x04\u0571\x9b\xdc\xed\xfb\x84\xdaw\x01\xabG\x8c'\xae\x89\x91Hx\xa8\xc0^\xe0\x00\x00\u07d4\xb7N\xd2f`\x01\xc1c3\xcfz\xf5\x9eJ=H`6;\x9c\x89\n~\xbd^Cc\xa0\x00\x00\u07d4\xb7QI\xe1\x85\xf6\xe3\x92pWs\x90s\xa1\x82*\xe1\xcf\r\xf2\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xb7S\xa7_\x9e\xd1\v!d:\n=\xc0Qz\xc9k\x1a@h\x89\x15\xc8\x18[,\x1f\xf4\x00\x00\xe0\x94\xb7V\xadR\xf3\xbft\xa7\xd2LgG\x1e\b\x87Ci6PL\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xb7Wn\x9d1M\xf4\x1e\xc5Pd\x94):\xfb\x1b\xd5\xd3\xf6]\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb7X\x89o\x1b\xaa\x86O\x17\xeb\xed\x16\xd9S\x88o\xeeh\xaa\xe6\x8965\u026d\xc5\u07a0\x00\x00\u0794\xb7h\xb5#N\xba:\x99h\xb3Mm\xdbH\x1c\x84\x19\xb3e]\x88\xcf\xceU\xaa\x12\xb3\x00\x00\u07d4\xb7\x82\xbf\xd1\xe2\xdep\xf4gdo\x9b\xc0\x9e\xa5\xb1\xfc\xf4P\xaf\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xb7\xa2\xc1\x03r\x8bs\x05\xb5\xaen\x96\x1c\x94\xee\x99\xc9\xfe\x8e+\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xb7\xa3\x1a|8\xf3\xdb\t2.\xae\x11\xd2'!A\xea\"\x99\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7\xa6y\x1c\x16\xebN!b\xf1Ke7\xa0+=c\xbf\xc6\x02\x89*Rc\x91\xac\x93v\x00\x00\u07d4\xb7\xa7\xf7|4\x8f\x92\xa9\xf1\x10\fk\xd8)\xa8\xacm\u007f\u03d1\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xb7\xc0w\x94ft\xba\x93A\xfbLtz]P\xf5\xd2\xdad\x15\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xb7\xc0\xd0\xcc\vM4-@b\xba\xc6$\xcc\xc3\xc7\f\xc6\xda?\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xb7\xc9\xf1+\x03\x8esCm\x17\xe1\xc1/\xfe\x1a\xec\u0373\xf5\x8c\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\xb7\xcck\x1a\xcc2\u0632\x95\xdfh\xed\x9d^`\xb8\xf6L\xb6{\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xb7\xcehK\t\xab\xdaS8\x9a\x87Si\xf7\x19X\xae\xac;\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\xb7\xd1.\x84\xa2\xe4\u01264Z\xf1\xdd\x1d\xa9\xf2PJ*\x99n\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xb7\xd2R\xee\x94\x02\xb0\xee\xf1D)_\x0ei\xf0\xdbXl\bq\x89#\xc7W\a+\x8d\xd0\x00\x00\xe0\x94\xb7\u0541\xfe\n\xf1\xec8?;\xce\x00\xaf\x91\x99\xf3\xcf_\xe0\xcc\xe2\x8c\xd1J\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\xb8R\x18\xf3B\xf8\x01.\u069f'Nc\xce!R\xb2\xdc\xfd\xab\x89\xa8\r$g~\xfe\xf0\x00\x00\u07d4\xb8UP\x10wn<\\\xb3\x11\xa5\xad\xee\xfe\x9e\x92\xbb\x9ad\xb9\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xb8_&\xdd\x0er\xd9\u009e\xba\xf6\x97\xa8\xafwG,+X\xb5\x8a\x02\x85\x19\xac\xc7\x19\fp\x00\x00\u07d4\xb8_\xf0>{_\xc4\"\x98\x1f\xae^\x99A\xda\xcb\u06bau\x84\x89Hz\x9a0E9D\x00\x00\xe0\x94\xb8f\a\x02\x1bb\xd3@\xcf&R\xf3\xf9_\xd2\xdcgi\x8b\u07ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xb8}\xe1\xbc\u0492i\xd5!\xb8v\x1c\u00dc\xfbC\x19\xd2\xea\u054965\u026d\xc5\u07a0\x00\x00\u07d4\xb8\u007fSv\xc2\xde\vl\xc3\xc1y\xc0`\x87\xaaG=kFt\x89Hz\x9a0E9D\x00\x00\u07d4\xb8\x84\xad\u060d\x83\xdcVJ\xb8\xe0\xe0,\xbd\xb69\x19\xae\xa8D\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\x8a7\xc2\u007fx\xa6\x17\xd5\xc0\x91\xb7\u0577:7a\xe6_*\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\x94x\"\u056c\u79ad\x83&\xe9T\x96\"\x1e\v\xe6\xb7=\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb8\x9c\x03n\xd7\u0112\x87\x99!\xbeA\xe1\f\xa1i\x81\x98\xa7L\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xb8\x9fF2\xdfY\t\xe5\x8b*\x99d\xf7O\xeb\x9a;\x01\xe0\u014a\x04\x88u\xbc\xc6\xe7\xcb\xeb\x80\x00\u07d4\xb8\xa7\x9c\x84\x94^G\xa9\xc3C\x86\x83\u05b5\x84,\xffv\x84\xb1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xb8\xa9y5'Y\xba\t\xe3Z\xa5\x93]\xf1u\xbf\xf6x\xa1\b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xb8\xab9\x80[\xd8!\x18Ol\xbd=$s4{\x12\xbf\x17\\\x89\x06hZ\xc1\xbf\xe3,\x00\x00\xe0\x94\xb8\xac\x11}\x9f\r\xba\x80\x90\x14E\x82:\x92\x11\x03\xa51o\x85Zew\x9d\x1b\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4\xb9\xe9\f\x11\x92\xb3\xd5\xd3\xe3\xab\a\x00\xf1\xbfe_]\xd44z\x89\x1b\x19\xe5\vD\x97|\x00\x00\u07d4\xb9\xfd83\xe8\x8e|\xf1\xfa\x98y\xbd\xf5Z\xf4\xb9\x9c\xd5\xce?\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xba\x02I\xe0\x1d\x94[\xef\x93\xee^\xc6\x19%\xe0<\\\xa5\t\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xba\x0f9\x02;\xdb)\xeb\x18b\xa9\xf9\x05\x9c\xab]0nf/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\x10\xf2vB\x90\xf8uCCr\xf7\x9d\xbfq8\x01\u02ac\x01\x893\xc5I\x901r\f\x00\x00\u07d4\xba\x151\xfb\x9ey\x18\x96\xbc\xf3\xa8\x05X\xa3Y\xf6\xe7\xc1D\xbd\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xba\x17m\xbe2I\xe3E\xcdO\xa9g\xc0\xed\x13\xb2LG\u5189\x15\xae\xf9\xf1\xc3\x1c\u007f\x00\x00\xe0\x94\xba\x1f\x0e\x03\u02da\xa0!\xf4\xdc\xeb\xfa\x94\xe5\u0209\xc9\u01fc\x9e\x8a\x06\u0450\xc4u\x16\x9a \x00\x00\u07d4\xba\x1f\xca\xf2#\x93~\xf8\x9e\x85gU\x03\xbd\xb7\xcaj\x92\x8bx\x89\"\xb1\xc8\xc1\"z\x00\x00\x00\xe0\x94\xba$\xfcCgS\xa79\xdb,\x8d@\xe6\xd4\xd0LR\x8e\x86\xfa\x8a\x02\xc0\xbb=\xd3\fN \x00\x00\u07d4\xbaB\xf9\xaa\xceL\x18E\x04\xab\xf5BWb\xac\xa2oq\xfb\u0709\x02\a\a}\u0627\x9c\x00\x00\u07d4\xbaF\x9a\xa5\u00c6\xb1\x92\x95\u0521\xb5G;T\x03S9\f\x85\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbad@\xae\xb3s{\x8e\xf0\xf1\xaf\x9b\f\x15\xf4\xc2\x14\xff\xc7\u03c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbam1\xb9\xa2a\xd6@\xb5\u07a5\x1e\xf2\x16,1\t\xf1\uba0a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xbap\xe8\xb4u\x9c\f<\x82\xcc\x00\xacN\x9a\x94\xdd[\xaf\xb2\xb8\x890C\xfa3\xc4\x12\xd7\x00\x00\u07d4\xba\x8ac\xf3\xf4\r\u4a03\x88\xbcP!/\xea\x8e\x06O\xbb\x86\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\x8eF\u059d.#C\xd8l`\xd8,\xf4, A\xa0\xc1\u0089\x05k\xc7^-c\x10\x00\x00\u07d4\xba\xa4\xb6L+\x15\xb7\x9f_ BF\xfdp\xbc\xbd\x86\xe4\xa9*\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xba\u0212,J\xcc},\xb6\xfdY\xa1N\xb4\\\xf3\xe7\x02!K\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xba\xd25\xd5\b]\u01f0h\xa6|A&w\xb0>\x186\x88L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xba\xd4B^\x17\x1c>r\x97^\xb4j\xc0\xa0\x15\xdb1Z]\x8f\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xba\xdc*\xef\x9fYQ\xa8\u05cak5\xc3\u0433\xa4\xe6\xe2\xe79\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xba\xdeCY\x9e\x02\xf8OL0\x14W\x1c\x97k\x13\xa3le\xab\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xba\xe9\xb8/r\x99c\x14\be\x9d\xd7N\x89\x1c\xb8\xf3\x86\x0f\xe5\x89j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xbb\x03f\xa7\u03fd4E\xa7\r\xb7\xfeZ\xe3H\x85uO\xd4h\x8a\x01M\xef,B\xeb\xd6@\x00\x00\u07d4\xbb\aj\xac\x92 \x80i\xea1\x8a1\xff\x8e\xeb\x14\xb7\xe9\x96\xe3\x89\b\x13\xcaV\x90m4\x00\x00\u07d4\xbb\bW\xf1\xc9\x11\xb2K\x86\u0227\x06\x81G?\u6aa1\xcc\xe2\x89\x05k\xc7^-c\x10\x00\x00\u0794\xbb\x19\xbf\x91\u02edt\xcc\xeb_\x81\x1d\xb2~A\x1b\xc2\xea\x06V\x88\xf4?\xc2\xc0N\xe0\x00\x00\xe0\x94\xbb'\u01a7\xf9\x10uGZ\xb2)a\x90@\xf8\x04\xc8\xeczj\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xbb7\x1cr\xc9\xf01l\xea+\xd9\xc6\xfb\xb4\a\x9ewT)\xef\x89_h\xe8\x13\x1e\u03c0\x00\x00\xe0\x94\xbb;\x01\v\x18\xe6\xe2\xbe\x115\x87\x10&\xb7\xba\x15\xea\x0f\xde$\x8a\x02 |\x800\x9bwp\x00\x00\xe0\x94\xbb;\x90\x05\xf4o\xd2\xca;0\x16%\x99\x92\x8cw\xd9\xf6\xb6\x01\x8a\x01\xb1\xae\u007f+\x1b\xf7\xdb\x00\x00\u07d4\xbb?\xc0\xa2\x9c\x03Mq\b\x12\xdc\xc7u\xc8\u02b9\u048diu\x899\xd4\xe8D\xd1\xcf_\x00\x00\u07d4\xbbH\xea\xf5\x16\xce-\xec>A\xfe\xb4\xc6y\xe4\x95vA\x16O\x89\xcf\x15&@\xc5\xc80\x00\x00\u07d4\xbbKJKT\x80p\xffAC,\x9e\b\xa0\xcao\xa7\xbc\x9fv\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\u07d4\xbbV\xa4\x04r<\xff \xd0hT\x88\xb0Z\x02\xcd\xc3Z\xac\xaa\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbba\x8e%\"\x1a\u0667@\xb2\x99\xed\x14\x06\xbc94\xb0\xb1m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbba\xa0K\xff\xd5|\x10G\rE\u00d1\x03\xf6FP4v\x16\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbbh#\xa1\xbd\x81\x9f\x13QU8&J-\xe0R\xb4D\"\b\x89\x01ch\xffO\xf9\xc1\x00\x00\u07d4\xbbl(J\xac\x8ai\xb7\\\u0770\x0f(\xe1EX;V\xbe\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xbbu\xcbPQ\xa0\xb0\x94KFs\xcau*\x97\x03\u007f|\x8c\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbb\x99;\x96\xee\x92Z\xda}\x99\u05c6W=?\x89\x18\f\u3a89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbb\xa3\u0180\x04$\x8eH\x95s\xab\xb2t6w\x06k$\u0227\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbb\xa4\xfa\xc3\xc4 9\xd8(\xe7B\xcd\xe0\xef\xff\xe7t\x94\x1b9\x89lj\u04c2\xd4\xfba\x00\x00\u07d4\xbb\xa8\xab\"\xd2\xfe\xdb\xcf\xc6?hL\b\xaf\xdf\x1c\x17P\x90\xb5\x89\x05_)\xf3~N;\x80\x00\u07d4\xbb\xa9v\xf1\xa1!_u\x12\x87\x18\x92\xd4_pH\xac\xd3V\u0209lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbb\xab\x00\v\x04\b\xed\x01Z7\xc0GG\xbcF\x1a\xb1N\x15\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xbb\xab\xf6d;\xebK\xd0\x1c\x12\v\xd0Y\x8a\t\x87\xd8)g\u0449\xb52\x81x\xad\x0f*\x00\x00\u07d4\xbb\xb4\xee\x1d\x82\xf2\xe1VD,\xc938\xa2\xfc(o\xa2\x88d\x89JD\x91\xbdm\xcd(\x00\x00\u07d4\xbb\xb5\xa0\xf4\x80,\x86H\x00\x9e\x8ai\x98\xaf5,\u0787TO\x89\x05-T(\x04\xf1\xce\x00\x00\u07d4\xbb\xb6C\xd2\x18{6J\xfc\x10\xa6\xfd6\x8d}U\xf5\r\x1a<\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbb\xb8\xff\xe4?\x98\u078e\xae\x18F#\xaeRd\xe4$\u0438\u05c9\x05\xd5?\xfd\xe9(\b\x00\x00\u07d4\xbb\xbdn\u02f5u(\x91\xb4\u03b3\xcc\xe7:\x8fGpY7o\x89\x01\xf3\x99\xb1C\x8a\x10\x00\x00\u07d4\xbb\xbf9\xb1\xb6y\x95\xa4\"APO\x97\x03\u04a1JQV\x96\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xbb\xc8\xea\xffc~\x94\xfc\u014d\x91\xdb\\\x89\x12\x1d\x06\xe1/\xff\x98\x80\x00\u07d4\xbc\u065e\xdc!`\xf2\x10\xa0^:\x1f\xa0\xb0CL\xed\x00C\x9b\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbc\u07ec\xb9\xd9\x02<4\x17\x18.\x91\x00\xe8\xea\x1d73\x93\xa3\x89\x034-`\xdf\xf1\x96\x00\x00\u07d4\xbc\xe1>\"2*\u03f3U\xcd!\xfd\r\xf6\f\xf9:\xdd&\u0189\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xbc\xe4\x04u\xd3E\xb0q-\xeep=\x87\xcdvW\xfc\u007f;b\x8a\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\xbc\xed\xc4&|\u02c9\xb3\x1b\xb7d\xd7!\x11q\x00\x8d\x94\xd4M\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbc\xfc\x98\xe5\xc8+j\xdb\x18\n?\xcb\x12\v\x9av\x90\xc8j?\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbd\x04;g\xc6>`\xf8A\xcc\xca\x15\xb1)\xcd\xfee\x90\xc8\xe3\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbd\x04\u007f\xf1\xe6\x9c\u01b2\x9a\xd2d\x97\xa9\xa6\xf2z\x90?\xc4\u0749.\xe4IU\b\x98\xe4\x00\x00\u07d4\xbd\b\xe0\xcd\xde\xc0\x97\xdby\x01\ua05a=\x1f\xd9\u0789Q\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbd\t\x12l\x89\x1cJ\x83\x06\x80Y\xfe\x0e\x15ylFa\xa9\xf4\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xbd\f\\\u05d9\xeb\u0106B\xef\x97\xd7N\x8eB\x90d\xfe\u4489\x11\xac(\xa8\xc7)X\x00\x00\u07d4\xbd\x17\xee\xd8+\x9a%\x92\x01\x9a\x1b\x1b<\x0f\xba\xd4\\@\x8d\"\x89\r\x8drkqw\xa8\x00\x00\u07d4\xbd\x18\x037\v\u0771)\xd29\xfd\x16\xea\x85&\xa6\x18\x8a\u5389\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xbd+p\xfe\xcc7d\x0fiQO\xc7\xf3@IF\xaa\xd8k\x11\x89A\rXj \xa4\xc0\x00\x00\u07d4\xbd0\x97\xa7\x9b<\r.\xbf\xf0\xe6\xe8j\xb0\xed\xad\xbe\xd4p\x96\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xbd2]@)\xe0\xd8r\x9fm9\x9cG\x82$\xae\x9ez\xe4\x1e\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xbdC*9\x16$\x9bG$):\xf9\x14nI\xb8(\n\u007f*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xbdG\xf5\xf7n;\x93\x0f\xd9HR\t\xef\xa0\xd4v=\xa0uh\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbdK`\xfa\xect\n!\xe3\a\x13\x91\xf9j\xa54\xf7\xc1\xf4N\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xbdK\u0571\"\xd8\xef{|\x8f\x06gE\x03 \xdb!\x16\x14.\x89 \x86\xac5\x10R`\x00\x00\u07d4\xbdQ\xee.\xa1C\u05f1\u05b7~~D\xbd\xd7\xda\x12\U00105b09G~\x06\u0332\xb9(\x00\x00\u07d4\xbdY\tN\aO\x8dy\x14*\xb1H\x9f\x14\x8e2\x15\x1f \x89\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbdZ\x8c\x94\xbd\x8b\xe6G\x06D\xf7\f\x8f\x8a3\xa8\xa5\\cA\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbd^G:\xbc\xe8\xf9zi2\xf7|/\xac\xaf\x9c\xc0\xa0\x05\x14\x89<\x92X\xa1\x06\xa6\xb7\x00\x00\u07d4\xbd_F\u02ab,=K(\x93\x96\xbb\xb0\u007f *\x06\x11>\xd4\xc3\xfb\xa1\xa8\x91;\x19@~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\x9eV\xe9\x02\xf4\xbe\x1f\xc8v\x8d\x808\xba\xc6>*\u02ff\x8e\x8965f3\xeb\xd8\xea\x00\x00\u07d4\xbd\xa4\xbe1~~K\xed\x84\xc0I^\xee2\xd6\a\xec8\xcaR\x89}2'yx\xefN\x80\x00\u07d4\xbd\xb6\v\x82:\x11s\xd4Z\a\x92$_\xb4\x96\xf1\xfd3\x01\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xba\xf6CM@\xd65[\x1e\x80\xe4\f\u012b\x9ch\xd9a\x16\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xbd\xc0,\xd43\f\x93\xd6\xfb\xdaOm\xb2\xa8]\xf2/C\xc23\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xc4aF+c\"\xb4b\xbd\xb3?\"y\x9e\x81\b\xe2A}\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xbd\xc79\xa6\x99p\v.\x8e,JL{\x05\x8a\x0eQ=\u07be\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbd\xc7Hs\xaf\x92+\x9d\xf4t\x85;\x0f\xa7\xff\v\xf8\xc8&\x95\x89\xd8\xc9F\x00c\xd3\x1c\x00\x00\u07d4\xbd\xca*\x0f\xf3E\x88\xafb_\xa8\xe2\x8f\xc3\x01Z\xb5\xa3\xaa\x00\x89~\xd7?w5R\xfc\x00\x00\u07d4\xbd\xd3%N\x1b:m\xc6\xcc,i}Eq\x1a\xca!\xd5\x16\xb2\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbd\u07e3M\x0e\xbf\x1b\x04\xafS\xb9\x9b\x82IJ\x9e=\x8a\xa1\x00\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xbd\xe4\xc7?\x96\x9b\x89\xe9\u03aef\xa2\xb5\x18DH\x0e\x03\x8e\x9a\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbd\xe9xj\x84\xe7[H\xf1\x8erm\u05cdp\xe4\xaf>\xd8\x02\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4\xbd\xed\x11a/\xb5\xc6\u0699\xd1\xe3\x0e2\v\xc0\x99Tf\x14\x1e\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xbd\xed~\a\xd0q\x1ehM\xe6Z\u0232\xabW\xc5\\\x1a\x86E\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\xbd\xf6\x93\xf83\xc3\xfeG\x17S\x18G\x88\xebK\xfeJ\xdc?\x96\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbd\xf6\xe6\x8c\f\xd7X@\x80\xe8G\xd7,\xbb#\xaa\xd4j\xeb\x1d\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbe\n/8_\t\xdb\xfc\xe9g2\xe1+\xb4\n\xc3I\x87\x1b\xa8\x89WL\x11^\x02\xb8\xbe\x00\x00\u07d4\xbe\f*\x80\xb9\xde\bK\x17(\x94\xa7l\xf4szOR\x9e\x1a\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xbe\x1c\xd7\xf4\xc4r\a\th\xf3\xbd\xe2h6k!\xee\xea\x83!\x89\xe9\x1a|\u045f\xa3\xb0\x00\x00\u07d4\xbe#F\xa2\u007f\xf9\xb7\x02\x04OP\r\xef\xf2\xe7\xff\xe6\x82EA\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xbe$q\xa6\u007f`G\x91\x87r\xd0\xe3h9%^\xd9\u0591\xae\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xbe+\"\x80R7h\xea\x8a\xc3\\\xd9\xe8\x88\xd6\nq\x93\x00\u0509lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbe+2nx\xed\x10\xe5P\xfe\xe8\xef\xa8\xf8\a\x03\x96R/Z\x8a\bW\xe0\xd6\xf1\xdav\xa0\x00\x00\xe0\x94\xbe0Zyn3\xbb\xf7\xf9\xae\xaee\x12\x95\x90f\xef\xda\x10\x10\x8a\x02M\xceT\xd3J\x1a\x00\x00\x00\u07d4\xbeG\x8e\x8e=\xdek\xd4\x03\xbb-\x1ce|C\x10\xee\x19'#\x89\x1a\xb2\xcf|\x9f\x87\xe2\x00\x00\u07d4\xbeN}\x98?.*ck\x11\x02\xecp9\xef\xeb\xc8B\u9349\x03\x93\xef\x1aQ'\xc8\x00\x00\u07d4\xbeO\xd0sap\"\xb6\u007f\\\x13I\x9b\x82\u007fv69\xe4\xe3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbeRZ3\xea\x91aw\xf1r\x83\xfc\xa2\x9e\x8b5\v\u007fS\v\x89\x8f\x01\x9a\xafF\xe8x\x00\x00\u07d4\xbeS2/C\xfb\xb5\x84\x94\xd7\xcc\xe1\x9d\xda'+$P\xe8'\x89\n\xd7\u03afB\\\x15\x00\x00\u07d4\xbeS\x82F\xddNo\f \xbfZ\xd17<;F:\x13\x1e\x86\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbeZ`h\x99\x98c\x9a\xd7[\xc1\x05\xa3qt>\xef\x0fy@\x89\x1b2|s\xe1%z\x00\x00\u07d4\xbe\\\xba\x8d7By\x86\xe8\xca&\x00\xe8X\xbb\x03\xc3YR\x0f\x89\xa00\xdc\xeb\xbd/L\x00\x00\u07d4\xbe`\x03~\x90qJK\x91~a\xf1\x93\xd84\x90g\x03\xb1:\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xbec:77\xf6\x849\xba\xc7\xc9\nR\x14 X\ue38ao\x894\n\xad!\xb3\xb7\x00\x00\x00\xe0\x94\xbee\x9d\x85\xe7\xc3O\x883\xea\u007fH\x8d\xe1\xfb\xb5\xd4\x14\x9b\xef\x8a\x01\xeb\xd2:\xd9\u057br\x00\x00\u07d4\xbes'M\x8cZ\xa4J<\xbe\xfc\x82c\xc3{\xa1!\xb2\n\u04c9\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xbe\x86\u0430C\x84\x19\u03b1\xa081\x927\xbaR\x06\xd7.F\x8964\xfb\x9f\x14\x89\xa7\x00\x00\u07d4\xbe\x8d\u007f\x18\xad\xfe]l\xc7u9I\x89\xe1\x93\f\x97\x9d\x00}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbe\x91\x86\xc3JRQJ\xbb\x91\a\x86\x0fgO\x97\xb8!\xbd[\x89\x1b\xa0\x1e\xe4\x06\x03\x10\x00\x00\u07d4\xbe\x93W\x93\xf4[p\xd8\x04]&T\xd8\xdd:\xd2K[a7\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xbe\x98\xa7\u007f\xd4\x10\x97\xb3OY\xd7X\x9b\xaa\xd0!e\x9f\xf7\x12\x890\xca\x02O\x98{\x90\x00\x00\u07d4\xbe\x9b\x8c4\xb7\x8e\xe9G\xff\x81G.\xdaz\xf9\xd2\x04\xbc\x84f\x89\b!\xab\rD\x14\x98\x00\x00\u07d4\xbe\xa0\r\xf1pg\xa4:\x82\xbc\x1d\xae\xca\xfbl\x140\x0e\x89\xe6\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xbe\xa0\xaf\xc9:\xae!\b\xa3\xfa\xc0Yb;\xf8o\xa5\x82\xa7^\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xbe\xb35\x8cP\u03dfu\xff\xc7mD<,\u007fU\aZ\x05\x89\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xbe\xb4\xfd1UYC`E\u0739\x9dI\xdc\xec\x03\xf4\fB\u0709lk\x93[\x8b\xbd@\x00\x00\u07d4\xbe\xc2\xe6\xde9\xc0|+\xaeUj\u03fe\xe2\xc4r\x8b\x99\x82\xe3\x89\x1f\x0f\xf8\xf0\x1d\xaa\xd4\x00\x00\u07d4\xbe\xc6d\x0fI\t\xb5\x8c\xbf\x1e\x80cB\x96\x1d`u\x95\tl\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xbe\xc8\xca\xf7\xeeIF\x8f\xeeU.\xff:\xc5#N\xb9\xb1}B\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbe\xce\xf6\x1c\x1cD+\xef|\xe0Ks\xad\xb2I\xa8\xba\x04~\x00\x896;V\u00e7T\xc8\x00\x00\u0794\xbe\xd4d\x9d\xf6F\u2052)\x03-\x88hUo\xe1\xe0S\u04c8\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\xbe\xd4\xc8\xf0\x06\xa2|\x1e_|\xe2\x05\xdeu\xf5\x16\xbf\xb9\xf7d\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xbe\xe8\u0430\bB\x19T\xf9-\x00\r9\x0f\xb8\xf8\xe6X\xea\xee\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbe\xec\u05af\x90\f\x8b\x06J\xfc\xc6\a?-\x85\u055a\xf1\x19V\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xbe\xef\x94!8y\xe0&\"\x14+\xeaa)\tx\x93\x9a`\u05ca\x016\x85{2\xad\x86\x04\x80\x00\xe0\x94\xbe\xf0}\x97\xc3H\x1f\x9dj\xee\x1c\x98\xf9\xd9\x1a\x18\n2D+\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xbe\xfbD\x8c\f_h?\xb6~\xe5p\xba\xf0\xdbV\x86Y\x97Q\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xbf\x05\a\f,4!\x93\x11\xc4T\x8b&\x14\xa48\x81\r\xedm\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbf\x05\xff^\xcf\r\xf2\u07c8wY\xfb\x82t\xd928\xac&}\x89+^:\xf1k\x18\x80\x00\x00\xe0\x94\xbf\t\xd7pH\xe2p\xb6b3\x0e\x94\x86\xb3\x8bC\xcdx\x14\x95\x8a\\S\x9b{\xf4\xff(\x80\x00\x00\u07d4\xbf\x17\xf3\x97\xf8\xf4o\x1b\xaeE\u0447\x14\x8c\x06\xee\xb9Y\xfaM\x896I\u0156$\xbb0\x00\x00\u07d4\xbf\x186A\xed\xb8\x86\xce`\xb8\x19\x02a\xe1OB\xd9<\xce\x01\x89\x01[5W\xf1\x93\u007f\x80\x00\u07d4\xbf*\xeaZ\x1d\xcfn\u04f5\xe829D\xe9\x83\xfe\xdf\u046c\xfb\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xbf@\x96\xbcT}\xbf\xc4\xe7H\t\xa3\x1c\x03\x9e{8\x9d^\x17\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xbfI\xc1H\x981eg\u0637\t\xc2\xe5\x05\x94\xb3f\xc6\u04cc\x89'\xbf8\xc6TM\xf5\x00\x00\u07d4\xbfLs\xa7\xed\xe7\xb1d\xfe\a!\x14\x846T\xe4\xd8x\x1d\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xbfP\xce.&K\x9f\xe2\xb0h0az\xed\xf5\x02\xb25\x1bE\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbfY\xae\xe2\x81\xfaC\xfe\x97\x19CQ\xa9\x85~\x01\xa3\xb8\x97\xb2\x89 \x86\xac5\x10R`\x00\x00\u07d4\xbfh\u048a\xaf\x1e\xee\xfe\xf6F\xb6^\x8c\xc8\u0450\xf6\xc6\u069c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xbfi%\xc0\aQ\x00\x84@\xa6s\x9a\x02\xbf+l\u06ab^:\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xbfw\x01\xfcb%\u0561x\x15C\x8a\x89A\xd2\x1e\xbc]\x05\x9d\x89e\xea=\xb7UF`\x00\x00\u07d4\xbf\x8b\x80\x05\xd66\xa4\x96d\xf7Bu\xefBC\x8a\xcde\xac\x91\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbf\x92A\x8a\fl1$M\"\x02`\xcb>\x86}\u05f4\xefI\x89\x05i\x00\xd3<\xa7\xfc\x00\x00\u07d4\xbf\x9a\xcdDE\xd9\xc9UF\x89\u02bb\xba\xb1\x88\x00\xff\x17A\u008965\u026d\xc5\u07a0\x00\x00\u07d4\xbf\x9f'\x1fz~\x12\xe3m\xd2\xfe\x9f\xac\xeb\xf3\x85\xfeaB\xbd\x89\x03f\xf8O{\xb7\x84\x00\x00\u07d4\xbf\xa8\xc8X\xdf\x10,\xb1$!\x00\x8b\n1\xc4\xc7\x19\n\xd5`\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xbf\xae\xb9\x10ga}\u03cbD\x17+\x02\xafaVt\x83]\xba\x89\b\xb5\x9e\x88H\x13\b\x80\x00\xe0\x94\xbf\xb0\xea\x02\xfe\xb6\x1d\xec\x9e\"\xa5\a\tY3\x02\x99\xc40r\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xbf\xbc\xa4\x18\xd3R\x9c\xb3\x93\b\x10b\x03*n\x11\x83\u01b2\u070a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xbf\xbe\x05\u831c\xbb\xcc\x0e\x92\xa4\x05\xfa\xc1\xd8]\xe2H\xee$\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xbf\xbf\xbc\xb6V\u0099+\xe8\xfc\u0782\x19\xfb\xc5J\xad\u055f)\x8a\x02\x1e\x18\xd2\xc8!\xc7R\x00\x00\u07d4\xbf\xc5z\xa6f\xfa\u239f\x10zI\xcbP\x89\xa4\xe2!Q\u074965\u026d\xc5\u07a0\x00\x00\u07d4\xbf\u02d70$c\x04p\r\xa9\vAS\xe7\x11Ab.\x1cA\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xbf\xd9<\x90\u009c\a\xbc_\xb5\xfcI\xae\xeaU\xa4\x0e\x13O5\x8a\x05\xed\xe2\x0f\x01\xa4Y\x80\x00\x00\xe0\x94\xbf\xe3\xa1\xfcn$\xc8\xf7\xb3%\x05`\x99\x1f\x93\u02e2\u03c0G\x8a\x10\xf0\xcf\x06M\u0552\x00\x00\x00\u07d4\xbf\u6f30\xf0\xc0xRd3$\xaa]\xf5\xfdb%\xab\xc3\u0289\x04\t\xe5+H6\x9a\x00\x00\u07d4\xbf\xf5\xdfv\x994\xb8\x94<\xa9\x13}\x0e\xfe\xf2\xfen\xbb\xb3N\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xbf\xfbi)$\x1fx\x86\x93'>p\"\xe6\x0e>\xab\x1f\xe8O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\x06O\x1d\x94t\xab\x91]V\x90l\x9f\xb3 \xa2\xc7\t\x8c\x9b\x89\x13h?\u007f<\x15\xd8\x00\x00\u07d4\xc0\a\xf0\xbd\xb6\xe7\x00\x92\x02\xb7\xaf>\xa9\t\x02i|r\x14\x13\x89\xa2\xa0\xe4>\u007f\xb9\x83\x00\x00\u07d4\xc0\n\xb0\x80\xb6C\xe1\u00ba\xe3c\xe0\u0455\xde.\xff\xfc\x1cD\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u0794\xc0 wD\x9a\x13Jz\xd1\xef~M\x92z\xff\xec\ueb75\xae\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xc0$q\xe3\xfc.\xa0S&\x15\xa7W\x1dI2\x89\xc1<6\xef\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0-n\xad\xea\xcf\x1bx\xb3\u0285\x03\\c{\xb1\xce\x01\xf4\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc03\xb12Z\n\xf4Tr\xc2U'\x85;\x1f\x1c!\xfa5\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xc03\xbe\x10\xcbHa;\xd5\xeb\xcb3\xedI\x02\xf3\x8bX0\x03\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc04[3\xf4\x9c\xe2\u007f\xe8,\xf7\xc8M\x14\x1ch\xf5\x90\xcev\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc0=\xe4*\x10\x9bezd\xe9\"$\xc0\x8d\xc1'^\x80\u0672\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0@i\u07f1\x8b\tlxg\xf8\xbe\xe7zm\xc7Gz\xd0b\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xc0A?Z|-\x9aK\x81\b(\x9e\xf6\xec\xd2qx\x15$\xf4\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xc0C\xf2E-\u02d6\x02\xefb\xbd6\x0e\x03=\xd29q\xfe\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc0OK\xd4\x04\x9f\x04F\x85\xb8\x83\xb6)Y\xaec\x1df~5\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\xc0V\u053dk\xf3\u02ec\xace\xf8\xf5\xa0\xe3\x98\v\x85'@\xae\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xc0[t\x06 \xf1s\xf1nRG\x1d\u00cb\x9cQJ\v\x15&\x89\a\x96\xe3\xea?\x8a\xb0\x00\x00\u07d4\xc0i\xef\x0e\xb3B\x99\xab\xd2\xe3-\xab\xc4yD\xb2r3H$\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\xc0l\xeb\xbb\xf7\xf5\x14\x9af\xf7\xeb\x97k>G\xd5e\x16\xda/\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc0r^\u00bd\xc3:\x1d\x82`q\u07a2\x9db\xd48Z\x8c%\x8a\b\xa0\x85\x13F:\xa6\x10\x00\x00\u07d4\xc0~8g\xad\xa0\x96\x80z\x05\x1al\x9c4\xcc;?J\xd3J\x89`\xf0f \xa8IE\x00\x00\u07d4\xc0\x89^\xfd\x05m\x9a:\x81\xc3\xdaW\x8a\xda1\x1b\xfb\x93V\u03c9\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc0\x90\xfe#\xdc\xd8k5\x8c2\xe4\x8d*\xf9\x10$%\x9fef\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc0\x9af\x17*\xea7\r\x9ac\xda\x04\xffq\xff\xbb\xfc\xff\u007f\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\x9e<\xfc\x19\xf6\x05\xff>\xc9\xc9\xc7\x0e%@\xd7\xee\x97Cf\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc0\xa0*\xb9N\xbeV\xd0E\xb4\x1bb\x9b\x98F.:\x02J\x93\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xc0\xa3\x93\b\xa8\x0e\x9e\x84\xaa\xaf\x16\xac\x01\xe3\xb0\x1dt\xbdk-\x89\afM\xddL\x1c\v\x80\x00\u07d4\xc0\xa6\u02edwi*=\x88\xd1A\xefv\x9a\x99\xbb\x9e<\x99Q\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xc0\xa7\xe8C]\xff\x14\xc2Uws\x9d\xb5\\$\u057fW\xa3\u064a\nm\xd9\f\xaeQ\x14H\x00\x00\u07d4\xc0\xae\x14\xd7$\x83./\xce'x\xde\u007f{\x8d\xaf{\x12\xa9>\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc0\xaf\xb7\u0637\x93p\xcf\xd6c\u018c\u01b9p*7\u035e\xff\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc0\xb0\xb7\xa8\xa6\xe1\xac\xdd\x05\xe4\u007f\x94\xc0\x96\x88\xaa\x16\u01ed\x8d\x89\x03{m\x02\xacvq\x00\x00\xe0\x94\xc0\xb3\xf2D\xbc\xa7\xb7\xde[H\xa5>\u06dc\xbe\xab\vm\x88\xc0\x8a\x01;\x80\xb9\x9cQ\x85p\x00\x00\u07d4\xc0\xc0M\x01\x06\x81\x0e>\xc0\xe5J\x19\U000ab157\xe6\x9aW=\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xc0\xca2w\x94.tE\x87K\xe3\x1c\xeb\x90)rqO\x18#\x89\r\x8drkqw\xa8\x00\x00\u07d4\xc0\u02ed<\xcd\xf6T\xda\"\xcb\xcf\\xe\x97\xca\x19U\xc1\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc0\xcb\xf6\x03/\xa3\x9e|F\xffw\x8a\x94\xf7\xd4E\xfe\"\xcf0\x89\x10\xce\x1d=\x8c\xb3\x18\x00\x00\u07d4\xc0\xe0\xb9\x03\b\x8e\fc\xf5=\xd0iWTR\xaf\xf5$\x10\u00c9\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc0\xe4W\xbdV\xec6\xa1$k\xfa20\xff\xf3\x8eY&\xef\"\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xc0\xed\rJ\xd1\r\xe045\xb1S\xa0\xfc%\xde;\x93\xf4R\x04\x89\xabM\xcf9\x9a:`\x00\x00\u07d4\xc0\xf2\x9e\xd0\af\x11\xb5\xe5^\x13\x05G\xe6\x8aH\xe2m\xf5\u4262\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xc1\x13(x#\\]\u06e5\xd9\xf3\"\x8bR6\xe4p \xdco\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc1\x17\r\xba\xad\xb3\xde\xe6\x19\x8e\xa5D\xba\xec\x93%\x18`\xfd\xa5\x89A\rXj \xa4\xc0\x00\x00\xe0\x94\xc1&W=\x87\xb0\x17ZR\x95\xf1\xdd\a\xc5u\u03cc\xfa\x15\xf2\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc1'\xaa\xb5\x90e\xa2\x86D\xa5k\xa3\xf1^.\xac\x13\xda)\x95\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xc1+\u007f@\u07da/{\xf9\x83f\x14\"\xab\x84\xc9\xc1\xf5\bX\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xc1,\xfb{=\xf7\x0f\xce\xca\x0e\xde&5\x00\xe2xs\xf8\xed\x16\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc1/\x88\x1f\xa1\x12\xb8\x19\x9e\xcb\xc7>\xc4\x18W\x90\xe6\x14\xa2\x0f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc18Lnq~\xbeK#\x01NQ\xf3\x1c\x9d\xf7\xe4\xe2[1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc1C\x8c\x99\xddQ\xef\x1c\xa88j\xf0\xa3\x17\xe9\xb0AEx\x88\x89\f\x1d\xaf\x81\u0623\xce\x00\x00\u07d4\xc1c\x12(\xef\xbf*.:@\x92\xee\x89\x00\xc69\xed4\xfb\u02093\xc5I\x901r\f\x00\x00\u07d4\xc1u\xbe1\x94\xe6iB-\x15\xfe\xe8\x1e\xb9\xf2\xc5lg\xd9\u0249\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc1\x82v\x86\xc0\x16\x94\x85\xec\x15\xb3\xa7\xc8\xc0\x15\x17\xa2\x87M\xe1\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xc1\x8a\xb4g\xfe\xb5\xa0\xaa\xdf\xff\x91#\x0f\xf0VFMx\xd8\x00\x89lk\x93[\x8b\xbd@\x00\x00\u0794\xc1\x95\x05CUM\x8aq0\x03\xf6b\xbba,\x10\xadL\xdf!\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xc1\xa4\x1aZ'\x19\x92&\xe4\xc7\xeb\x19\x8b\x03\x1bY\x19o\x98B\x89\nZ\xa8P\t\xe3\x9c\x00\x00\u07d4\xc1\xb2\xa0\xfb\x9c\xadE\xcdi\x91\x92\xcd'T\v\x88\xd38By\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc1\xb2\xaa\x8c\xb2\xbfb\xcd\xc1:G\xec\xc4e\u007f\xac\xaa\x99_\x98\x8967\x93\xfa\x96\u6980\x00\u07d4\xc1\xb5\x00\x01\x1c\xfb\xa9]|\xd66\xe9^l\xbfagFK%\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc1\xb9\xa5pM5\x1c\xfe\x98?y\xab\xee\xc3\u06fb\xae;\xb6)\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc1\xcb\xd2\xe23*RL\xf2\x19\xb1\r\x87\x1c\xcc \xaf\x1f\xb0\xfa\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xc1\xcd\xc6\x01\xf8\x9c\x04(\xb3\x13\x02\u0447\xe0\xdc\b\xad}\x1cW\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xc1\u052f8\xe9\xbay\x90@\x89HI\xb8\xa8!\x93u\xf1\xacx\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc1\xe1@\x9c\xa5,%CQ4\xd0\x06\u00a6\xa8T-\xfbrs\x89\x01\xdd\x1eK\xd8\xd1\xee\x00\x00\u07d4\xc1\xeb\xa5hJ\xa1\xb2L\xbac\x15\x02c\xb7\xa9\x13\x1a\xee\u008d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc1\xec\x81\xdd\x12=K|-\u0674\xd48\xa7\a,\x11\u0707L\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc1\xf3\x9b\xd3]\xd9\xce\xc37\xb9oG\xc6w\x81\x81`\xdf7\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\xc1\xff\xad\a\u06d6\x13\x8cK*S\x0e\xc1\xc7\xde)\xb8\xa0Y,\x88\xf4?\xc2\xc0N\xe0\x00\x00\xe0\x94\xc2\x1f\xa6d:\x1f\x14\xc0)\x96\xadqD\xb7Y&\xe8~\xcbK\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc24\nL\xa9L\x96x\xb7IL<\x85%(\xed\xe5\xeeR\x9f\x89\x02\xa3k\x05\xa3\xfd|\x80\x00\u07d4\xc29\xab\u07ee>\x9a\xf5E\u007fR\xed+\x91\xfd\n\xb4\xd9\xc7\x00\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2;/\x92\x1c\xe4\xa3z%\x9e\u4b4b!X\xd1]fOY\x89\x01`\x89\x95\xe8\xbd?\x80\x00\u07d4\xc2C\x99\xb4\xbf\x86\xf73\x8f\xbfd^;\"\xb0\u0dd79\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2L\u03bc#D\xcc\xe5d\x17\xfbhL\xf8\x16\x13\xf0\xf4\xb9\xbd\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xc2Rf\xc7gf2\xf1>\xf2\x9b\xe4U\ud50a\xddVw\x92\x89Hz\x9a0E9D\x00\x00\u07d4\xc2\\\xf8&U\f\x8e\xaf\x10\xaf\"4\xfe\xf9\x04\u0779R\x13\xbe\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc2f?\x81E\xdb\xfe\xc6\xc6F\xfc\\I\x96\x13E\xde\x1c\x9f\x11\x89%g\xacp9+\x88\x00\x00\u07d4\xc2pEh\x854+d\vL\xfc\x1bR\x0e\x1aTN\xe0\xd5q\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xc2sv\xf4]!\xe1^\xde;&\xf2e_\xce\xe0,\xcc\x0f*\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xc2w\x97q\xf0Smy\xa8p\x8fi1\xab\xc4K05\u964a\x047\u04ca\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xc2\xc1>r\xd2h\xe7\x15\r\u01d9\xe7\xc6\xcf\x03\u0209T\xce\u05c9%\xf2s\x93=\xb5p\x00\x00\u07d4\xc2\xcb\x1a\xda]\xa9\xa0B8s\x81G\x93\xf1aD\xef6\xb2\xf3\x89HU~;p\x17\xdf\x00\x00\u07d4\xc2\xd1w\x8e\xf6\xee_\xe4\x88\xc1E\xf3Xkn\xbb\xe3\xfb\xb4E\x89>\x1f\xf1\xe0;U\xa8\x00\x00\xe0\x94\xc2\xd9\xee\xdb\xc9\x01\x92c\xd9\xd1l\u016e\a-\x1d=\xd9\xdb\x03\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc2\xe0XJq4\x8c\xc3\x14\xb7; )\xb6#\v\x92\u06f1\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc2\xe2\u0518\xf7\r\xcd\bY\xe5\v\x02:q\nmK!3\xbd\x8989\x11\xf0\f\xbc\xe1\x00\x00\u07d4\xc2\xed_\xfd\u046d\xd8U\xa2i/\xe0b\xb5\xd6\x18t#`\u0509A\rXj \xa4\xc0\x00\x00\u07d4\xc2\xee\x91\xd3\xefX\xc9\u0465\x89\x84N\xa1\xae1%\xd6\u017ai\x894\x95tD\xb8@\xe8\x00\x00\u07d4\xc2\xfa\xfd\xd3\n\xcbmg\x06\xe9)<\xb0&A\xf9\xed\xbe\a\xb5\x89Q\x00\x86\vC\x0fH\x00\x00\u07d4\xc2\xfd\v\xf7\xc7%\xef>\x04~Z\xe1\u009f\xe1\x8f\x12\xa7)\x9c\x89Hz\x9a0E9D\x00\x00\u07d4\xc2\xfe}us\x1fcm\xcd\t\xdb\xda\x06q9;\xa0\xc8*}\x89wC\"\x17\xe6\x83`\x00\x00\u07d4\xc3\x10z\x9a\xf32-R8\xdf\x012A\x911b\x959W}\x89\x1a\xb4\xe4d\xd4\x141\x00\x00\xe0\x94\xc3\x11\v\xe0\x1d\xc9sL\xfcn\x1c\xe0\u007f\x87\xd7}\x13E\xb7\xe1\x8a\x01\x0f\f\xe9I\xe0\x0f\x93\x00\x00\u07d4\xc3 8\xcaR\xae\xe1\x97E\xbe\\1\xfc\xdcT\x14\x8b\xb2\xc4\u0409\x02\xb5\xaa\xd7,e \x00\x00\u07d4\xc3%\xc3R\x80\x1b\xa8\x83\xb3\"l_\xeb\r\xf9\xea\xe2\xd6\xe6S\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xc3.\xc7\xe4*\xd1l\xe3\xe2UZ\xd4\xc5C\x06\xed\xa0\xb2gX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc32\xdfP\xb1<\x014\x90\xa5\xd7\xc7]\xbf\xa3f\u0687\xb6\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc3:\u0373\xba\x1a\xab'P{\x86\xb1]g\xfa\xf9\x1e\xcfb\x93\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3>\u0393Z\x8fN\xf98\xea~\x1b\xac\x87\u02d2]\x84\x90\u028a\a\x03\x8c\x16x\x1fxH\x00\x00\u07d4\xc3@\xf9\xb9\x1c&r\x8c1\xd1!\xd5\xd6\xfc;\xb5m=\x86$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3F\xcb\x1f\xbc\xe2\xab(]\x8eT\x01\xf4-\xd7#M7\xe8m\x89\x04\x86\u02d7\x99\x19\x1e\x00\x00\xe0\x94\xc3H=n\x88\xac\x1fJ\xe7<\xc4@\x8dl\x03\xab\xe0\xe4\x9d\u028a\x03\x99\x92d\x8a#\u0220\x00\x00\xe0\x94\xc3H\xfcZF\x13#\xb5{\xe3\x03\u02c96\x1b\x99\x19\x13\xdf(\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xc3N;\xa12.\xd0W\x11\x83\xa2O\x94 N\xe4\x9c\x18fA\x89\x03'\xaf\uf927\xbc\x00\x00\xe0\x94\xc3[\x95\xa2\xa3s|\xb8\xf0\xf5\x96\xb3E$\x87+\xd3\r\xa24\x8a\x01\x98\xbe\x85#^-P\x00\x00\xe0\x94\xc3c\x1cv\x98\xb6\xc5\x11\x19\x89\xbfE''\xb3\xf99Zm\xea\x8a\x02C'X\x96d\x1d\xbe\x00\x00\u07d4\xc3l\vc\xbf\xd7\\/\x8e\xfb\x06\b\x83\xd8h\xcc\xcdl\xbd\xb4\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xc3uk\xcd\xcc~\xect\xed\x89j\xdf\xc35'Y0&n\b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u00c4\xacn\xe2|9\xe2\xf2x\xc2 \xbd\xfa[\xae\xd6&\xd9\u04c9 \x86\xac5\x10R`\x00\x00\u07d4\u00e0F\xe3\u04b2\xbfh\x14\x88\x82n2\xd9\xc0aQ\x8c\xfe\x8c\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\u07d4\u00e9\"j\xe2u\xdf,\xab1+\x91\x10@cJ\x9c\x9c\x9e\xf6\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u00f9(\xa7o\xadex\xf0O\x05U\xe69R\xcd!\xd1R\n\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3\xc2)s)\xa6\xfd\x99\x11~T\xfcj\xf3y\xb4\xd5VT~\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc3\xc3\xc2Q\rg\x80 HZcs]\x13\a\xecL\xa60+\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc3\xcbk6\xafD?,n%\x8bJ9U:\x81\x87G\x81\x1f\x89WG=\x05\u06ba\xe8\x00\x00\xe0\x94\xc3\xdbVW\xbbr\xf1\rX\xf21\xfd\xdf\x11\x98\n\xffg\x86\x93\x8a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\xc3\u06df\xb6\xf4lH\n\xf3De\u05d7S\xb4\xe2\xb7Jg\u038a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc3\xddX\x908\x860;\x92\x86%%z\xe1\xa0\x13\xd7\x1a\xe2\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\xe0G\x1cd\xff5\xfaR2\xcc1!\xd1\u04cd\x1a\x0f\xb7\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\xe2\f\x96\u07cdN8\xf5\v&Z\x98\xa9\x06\xd6\x1b\xc5\x1aq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc3\u31f0<\xe9\\\xcf\xd7\xfaQ\u0744\x01\x83\xbcCS(\t\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc3\xf8\xf6r\x95\xa5\xcd\x04\x93d\xd0]#P&#\xa3\xe5.\x84\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc4\x01\xc4'\xcc\xcf\xf1\r\xec\xb8d /6\xf5\x80\x83\"\xa0\xa8\x89\xb4{Q\xa6\x9c\xd4\x02\x00\x00\u07d4\xc4\b\x8c\x02_>\x85\x01?T9\xfb4@\xa1s\x01\xe5D\xfe\x89~\t\xdbM\x9f?4\x00\x00\u07d4\xc4\x14a\xa3\u03fd2\u0246UU\xa4\x8117\xc0v1#`\x8965\xc6 G9\u0640\x00\u07d4\xc4 8\x8f\xbe\xe8J\xd6V\xddh\xcd\xc1\xfb\xaa\x93\x92x\v4\x89\n-\xcac\xaa\xf4\u0140\x00\u07d4\xc4\"P\xb0\xfeB\xe6\xb7\xdc\xd5\u0210\xa6\xf0\u020f__\xb5t\x89\b\x1e\xe4\x82SY\x84\x00\x00\u07d4\xc4-j\xebq\x0e:P\xbf\xb4Ml1\t)i\xa1\x1a\xa7\xf3\x89\b\"c\xca\xfd\x8c\xea\x00\x00\xe0\x94\xc4@\xc7\xca/\x96Kir\xeffJ\"a\xdd\xe8\x92a\x9d\x9c\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xc4K\xde\xc8\xc3l\\h\xba\xa2\xdd\xf1\xd41i2)rlC\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xc4OJ\xb5\xbc`9|s~\xb0h3\x91\xb63\xf8\xa2G\x1b\x12\x1c\xa4\x89 .h\xf2\u00ae\xe4\x00\x00\u07d4\xc4h\x1es\xbb\x0e2\xf6\xb7& H1\xffi\xba\xa4\x87~2\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xc4k\xbd\xefv\xd4\xca`\xd3\x16\xc0\u007f]\x1ax\x0e;\x16_~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc4}a\v9\x92P\xf7\x0e\xcf\x13\x89\xba\xb6),\x91&O#\x89\x0f\xa7\xe7\xb5\xdf<\xd0\x00\x00\u07d4\u0100;\xb4\a\xc7b\xf9\vu\x96\xe6\xfd\u1513\x1ev\x95\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0106Q\xc1\xd9\xc1k\xffL\x95T\x88l??&C\x1foh\x89#\xab\x95\x99\xc4?\b\x00\x00\u07d4\u0109\xc8?\xfb\xb0%*\xc0\xdb\xe3R\x12\x17c\x0e\x0fI\x1f\x14\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u010bi<\xac\xef\xdb\xd6\xcb]x\x95\xa4.1\x962~&\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0113H\x9eV\u00fd\xd8)\x00}\xc2\xf9VA)\x06\xf7k\xfa\x89\x02\xa7\x91H\x8eqT\x00\x00\u07d4\u0116\u02f0E\x9aj\x01`\x0f\u0149\xa5Z2\xb4T!\u007f\x9d\x89\x0e\u0683\x8cI)\b\x00\x00\u07d4\u011c\xfa\xa9g\xf3\xaf\xbfU\x03\x10a\xfcL\xef\x88\xf8]\xa5\x84\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u0136\xe5\xf0\x9c\xc1\xb9\r\xf0x\x03\xce=M\x13vj\x9cF\xf4\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\u013e\xc9c\b\xa2\x0f\x90\u02b1\x83\x99\u0113\xfd=\x06Z\xbfE\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xc4\xc0\x1a\xfc>\x0f\x04R!\xda\x12\x84\u05c7\x85tD/\xb9\xac\x8a\x01\x92\xb5\u0249\x02J\x19\xc1\xbdo\x12\x80\x00\xe0\x94\xc5\x00\xb7 sN\xd2)8\u05cc^H\xb2\xba\x93g\xa5u\xba\x8a\a\x12\x9e\x1c\xdf7>\xe0\x00\x00\u07d4\xc5\x0f\xe4\x15\xa6A\xb0\x85lNu\xbf\x96\x05\x15D\x1a\xfa5\x8d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5\x13L\xfb\xb1\xdfz \xb0\xedpWb.\xee\u0480\x94}\xad\x89\xcd\xff\x97\xfa\xbc\xb4`\x00\x00\xe0\x94\xc5\x17\xd01\\\x87\x88\x13\xc7\x17\u132f\xa1\xea\xb2eN\x01\u068a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc5\x18y\x9aY%Wb\x13\xe2\x18\x96\xe0S\x9a\xbb\x85\xb0Z\xe3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc5\"\xe2\x0f\xbf\x04\xed\u007fk\x05\xa3{G\x18\xd6\xfc\xe0\x14.\x1a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc5$\bmF\xc8\x11+\x12\x8b/\xafo|}\x81`\xa88l\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc5-\x1a\fs\u00a1\xbe\x84\x91Q\x85\xf8\xb3O\xaa\n\xdf\x1d\xe3\x89K\xe4\xea\xb3\xfa\x0f\xa6\x80\x00\xe0\x94\xc55\x94\xc7\u03f2\xa0\x8f(L\xc9\u05e6;\xbd\xfc\v1\x972\x8a\nk#(\xff:b\xc0\x00\x00\u07d4\xc57I(\xcd\xf1\x93pTC\xb1L\xc2\r\xa4#G<\xd9\u03c9\a}\x10P\x9b\xb3\xaf\x80\x00\u07d4\xc58\xa0\xff(*\xaa_Ku\u03f6,p\x03~\xe6}O\xb5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5;P\xfd;+r\xbclC\v\xaf\x19JQU\x85\u04d8m\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xc5=y\xf7\u02dbp\x95/\xd3\x0f\xceX\xd5K\x9f\vY\xf6G\x8a\x01\x13\xe2\xd6tCE\xf8\x00\x00\u07d4\xc5I\u07c3\xc6\xf6^\xec\x0f\x1d\u0260\x93J\\_:P\xfd\x88\x89\x9d\xc0\\\xce(\u00b8\x00\x00\u07d4\xc5P\x05\xa6\xc3~\x8c\xa7\xe5C\xce%\x99s\xa3\xca\u0396\x1aJ\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5U\xb91V\xf0\x91\x01#\x80\x00\xe0\x94\u0166)\xa3\x96%R\u02ce\xde\u0609cj\xaf\xbd\f\x18\xcee\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u016e\x86\xb0\xc6\xc7\xe3\x90\x0f\x13h\x10\\VS\u007f\xaf\x8dt>\x89\n1\x06+\xee\xedp\x00\x00\u07d4\u0170\t\xba\xea\xf7\x88\xa2v\xbd5\x81:\xd6[@\v\x84\x9f;\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0175l\xd24&|(\xe8\x9cok\"f\xb0\x86\xa1/\x97\f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xc5\u01a4\x99\x8a3\xfe\xb7dCz\x8b\xe9)\xa7;\xa3J\ad\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\xe0\x94\xc5\xc7=a\xcc\xe7\xc8\xfeL\x8f\xce)\xf3\x90\x92\xcd\x19>\x0f\xff\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xc5\xc7Y\vV!\xec\xf85\x85\x88\u079bh\x90\xf2baC\U000498a1]\tQ\x9b\xe0\x00\x00\u07d4\xc5\xcd\xce\xe0\xe8]\x11}\xab\xbfSj?@i\xbfD?T\xe7\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xc5\u050c\xa2\xdb/\x85\xd8\xc5U\xcb\x0e\x9c\xfe\x82i6x?\x9e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc5\xde\x12\x03\xd3\xcc,\xea1\xc8.\xe2\xdeY\x16\x88\a\x99\xea\xfd\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xc5\xe4\x88\xcf+Vw\x939q\xf6L\xb8 -\xd0WR\xa2\xc0\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc5\xe8\x12\xf7o\x15\xf2\xe1\xf2\xf9\xbcH#H<\x88\x04cog\x89\x03\xf5\x14\x19:\xbb\x84\x00\x00\u07d4\xc5\u94d34\xf1%.\u04ba&\x81D\x87\xdf\u0498+1(\x89\x03\xcbq\xf5\x1f\xc5X\x00\x00\u07d4\xc5\xebB)^\x9c\xad\xea\xf2\xaf\x12\xde\u078a\x8dS\xc5y\xc4i\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\xc5\xed\xbb\xd2\xca\x03WeJ\xd0\xeaG\x93\xf8\xc5\xce\xcd0\xe2T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc5\xf6K\xab\xb7\x031B\xf2\x0eF\u05eab\x01\xed\x86\xf6q\x03\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc5\xf6\x87qrF\u068a \r \xe5\u9f2c`\xb6\u007f8a\x89\x01\x8d\x99?4\xae\xf1\x00\x00\u07d4\xc6\x04[<5\vL\xe9\xca\fkuO\xb4\x1ai\xb9~\x99\x00\x892$\xf4'#\xd4T\x00\x00\u07d4\xc6\v\x04eN\x00;F\x83\x04\x1f\x1c\xbdk\u00cf\xda|\xdb\u0589lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\x14F\xb7T\xc2N;\x16B\xd9\xe5\x17e\xb4\xd3\xe4k4\xb6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\x18R\x13!\xab\xaf[&Q:J\x95(\bo\"\n\xdco\x89\x01v\xb3D\xf2\xa7\x8c\x00\x00\u07d4\xc6#FW\xa8\a8A&\xf8\x96\x8c\xa1p\x8b\xb0{\xaaI<\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc6%\xf8\u024d'\xa0\x9a\x1b\u02bdQ(\xb1\u00a9HV\xaf0\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc65^\xc4v\x8cp\xa4\x9a\xf6\x95\x13\u0343\xa5\xbc\xa7\xe3\xb9\u034a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc6:\xc4\x17\x99.\x9f\x9b`8n\xd9S\xe6\xd7\xdf\xf2\xb0\x90\xe8\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xc6<\u05c8!\x18\xb8\xa9\x1e\aML\x8fK\xa9\x18Q0;\x9a\x89\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\xc6R\x87\x1d\x19$\"\u01bc#_\xa0c\xb4J~\x1dC\u3149\bg\x0e\x9e\xc6Y\x8c\x00\x00\xe0\x94\xc6gD\x1e\u007f)y\x9a\xbaadQ\xd5;?H\x9f\x9e\x0fH\x8a\x02\xf2\x9a\xceh\xad\u0740\x00\x00\u07d4\xc6j\xe4\xce\xe8\u007f\xb352\x19\xf7\u007f\x1dd\x86\u0140(\x032\x89\x01\x9a\x16\xb0o\xf8\xcb\x00\x00\u07d4\xc6t\xf2\x8c\x8a\xfd\a?\x8by\x96\x91\xb2\xf0XM\xf9B\xe8D\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u0197\xb7\x04w\u02b4.+\x8b&f\x81\xf4\xaesu\xbb%A\x8a\x01.W2\xba\xba\\\x98\x00\x00\u07d4\u019b\x85U9\xce\x1b\x04qG(\xee\xc2Z7\xf3g\x95\x1d\xe7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u019b\xe4@\x13Mb\x80\x98\x01D\xa9\xf6M\x84t\x8a7\xf3I\x89&\u009eG\u0104L\x00\x00\u07d4\u019df<\x8d`\x90\x83\x91\xc8\xd26\x19\x153\xfd\xf7wV\x13\x89\x1aJ\xba\"\\ t\x00\x00\u0794\u01a2\x86\xe0e\xc8_:\xf7H\x12\xed\x8b\u04e8\xce]%\xe2\x1d\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\u01a3\x0e\xf5\xbb3 \xf4\r\xc5\xe9\x81#\rR\xae:\xc1\x93\"\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\u01ae(}\xdb\xe1\x14\x9b\xa1m\xdc\xcaO\xe0j\xa2\uaa48\xa9\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc6\xc7\xc1\x917\x98\x97\u075c\x9d\x9a3\x83\x9cJ_b\xc0\x89\r\x89\xd8\xd8T\xb2$0h\x80\x00\xe0\x94\xc6\xcdh\xec56,Z\xd8L\x82\xadN\xdc#!%\x91-\x99\x8a\x05\xe0T\x9c\x962\xe1\xd8\x00\x00\u07d4\xc6\u0615N\x8f?\xc53\xd2\xd20\xff\x02\\\xb4\xdc\xe1O4&\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xc6\xdb\u06de\xfd^\xc1\xb3xn\x06q\xeb\"y\xb2S\xf2\x15\xed\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc6\xdf u\xeb\xd2@\xd4Hi\u00bek\u07c2\xe6=N\xf1\xf5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc6\xe2\xf5\xaf\x97\x9a\x03\xfdr:\x1bn\xfar\x83\x18\u03dc\x18\x00\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xc6\xe3$\xbe\xeb[6v^\xcdFB`\xf7\xf2`\x06\xc5\xc6.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc6\xe4\xcc\fr\x83\xfc\x1c\x85\xbcH\x13\xef\xfa\xafr\xb4\x98#\xc0\x89\x0f\x03\x1e\xc9\xc8}\xd3\x00\x00\xe0\x94\xc6\xee5\x93B)i5)\xdcA\u067bq\xa2IfX\xb8\x8e\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xc6\xfb\x1e\xe3t\x17\u0400\xa0\xd0H\x92;\u06ba\xb0\x95\xd0w\u0189\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc7\x05'\xd4D\u0110\xe9\xfc?\\\xc4Nf\xebO0k8\x0f\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7\r\x85mb\x1e\xc1E0<\nd\x00\xcd\x17\xbb\xd6\xf5\xea\xf7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xc7\x0f\xa4Uv\xbf\x9c\x86_\x988\x93\x00,AI&\xf6\x10)\x89\x15\xb4\xaa\x8e\x97\x02h\x00\x00\u07d4\xc7\x11E\xe5)\u01e7\x14\xe6y\x03\xeeb\x06\xe4\xc3\x04+g'\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xc7\x1b*=q5\u04a8_\xb5\xa5q\u073ei^\x13\xfcC\u034965\u026d\xc5\u07a0\x00\x00\u07d4\xc7\x1f\x1du\x87?3\u0732\xddK9\x87\xa1-\a\x91\xa5\xce'\x897\b\xba\xed=h\x90\x00\x00\u07d4\xc7\x1f\x92\xa3\xa5J{\x8c/^\xa4C\x05\xfc\u02c4\xee\xe21H\x89\x02\xb5\x9c\xa11\xd2\x06\x00\x00\u07d4\xc7!\xb2\xa7\xaaD\xc2\x12\x98\xe8P9\xd0\x0e.F\x0eg\v\x9c\x89\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\xc7,\xb3\x01%\x8e\x91\xbc\b\x99\x8a\x80]\u0452\xf2\\/\x9a5\x89 \t\xc5\u023fo\xdc\x00\x00\xe0\x94\xc76\x8b\x97\t\xa5\xc1\xb5\x1c\n\xdf\x18ze\xdf\x14\xe1+}\xba\x8a\x02\x02o\xc7\u007f\x03\u5b80\x00\u07d4\xc79%\x9e\u007f\x85\xf2e\x9b\xef_`\x9e\xd8k=Yl \x1e\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc7>!\x12(\"\x15\xdc\ab\xf3+~\x80}\xcd\x1az\xae>\x8a\x01v\f\xbcb;\xb3P\x00\x00\xe0\x94\xc7If\x80B\xe7\x11#\xa6H\x97^\b\xedc\x82\xf8>\x05\xe2\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xc7J9\x95\xf8\a\xde\x1d\xb0\x1a.\xb9\xc6.\x97\xd0T\x8fio\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc7Pl\x10\x19\x12\x1f\xf0\x8a,\x8c\x15\x91\xa6^\xb4\xbd\xfbJ?\x89 \x86\xac5\x10R`\x00\x00\u07d4\xc7\\7\xce-\xa0k\xbc@\b\x11Y\u01ba\x0f\x97n9\x93\xb1\x89:y#\x15\x1e\xcfX\x00\x00\u07d4\xc7]\"Y0j\xec}\xf0\"v\x8ci\x89\x9ae!\x85\xdb\u0109\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7`\x97\x1b\xbc\x18\x1cj|\xf7tA\xf2BG\u045c\xe9\xb4\u03c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xc7a0\xc7<\xb9!\x028\x02\\\x9d\xf9]\v\xe5J\xc6\u007f\xbe\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xc7e\xe0\x04v\x81\tG\x81j\xf1B\xd4m.\u7f28\xccO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc7g^VG\xb9\xd8\xda\xf4\xd3\xdf\xf1\xe5R\xf6\xb0qT\xac8\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xc7{\x01\xa6\xe9\x11\xfa\x98\x8d\x01\xa3\xab3dk\xee\xf9\xc18\xf3\x89'\x1bo\xa5\xdb\xe6\xcc\x00\x00\u07d4\u01c3z\u0420\xbf\x14\x18i7\xac\xe0lUF\xa3j\xa5OF\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u01d8\x06\x03+\xc7\xd8(\xf1\x9a\u01a6@\u018e=\x82\x0f\xa4B\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u01d9\xe3N\x88\xff\x88\xbe}\xe2\x8e\x15\xe4\xf2\xa6=\v3\xc4\u02c9\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\u01ddPb\u01d6\xddwa\xf1\xf1>U\x8ds\xa5\x9f\x82\xf3\x8b\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\u01e0\x18\xf0\x96\x8aQ\xd1\xf6`<\\I\xdcT[\xcb\x0f\xf2\x93\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u01ef\xf9\x19)yt\x89UZ/\xf1\xd1M\\iZ\x10\x83U\x8965\u026d\xc5\u07a0\x00\x00\u0794\u01f1\xc8>c ?\x95G&>\xf6(.}\xa3;n\xd6Y\x88\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\u01f3\x9b\x06\x04Q\x00\f\xa1\x04\x9b\xa1T\xbc\xfa\x00\xff\x8a\xf2b\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\u01ff\x17\xc4\xc1\x1f\x98\x94\x1fP~w\bO\xff\xbd-\xbd=\xb5\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\u01ff.\xd1\xed1)@\xeej\xde\xd1Qn&\x8eJ`HV\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xc7\xd4O\xe3,\u007f\x8c\xd5\xf1\xa9t'\xb6\xcd:\xfc\x9eE\x02>\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xc7\xd5\xc7\x05@\x81\xe9\x18\xech{Z\xb3n\x97=\x18\x13)5\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xc7\xde^\x8e\xaf\xb5\xf6+\x1a\n\xf2\x19\\\xf7\x93\u01c9L\x92h\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xc7\xe30\xcd\f\x89\n\u025f\xe7q\xfc\xc7\xe7\xb0\t\xb7A=\x8a\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc7\xea\xc3\x1a\xbc\xe6\xd5\xf1\u07a4\"\x02\xb6\xa6t\x15=\xb4z)\x89 \t\xc5\u023fo\xdc\x00\x00\xe0\x94\xc7\xecb\xb8\x04\xb1\xf6\x9b\x1e0p\xb5\xd3b\xc6/\xb3\t\xb0p\x8a\x02\xc4k\xf5A`f\x11\x00\x00\u07d4\xc7\xf7+\xb7X\x01k7G\x14\u0509\x9b\xce\"\xb4\xae\xc7\n1\x89:&\xc9G\x8f^-\x00\x00\u0794\xc8\v6\u047e\xaf\xba_\xccdM`\xacnF\xed)'\xe7\u0708\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xc8\x11\xc2\xe9\xaa\x1a\xc3F.\xba^\x88\xfc\xb5\x12\x0e\x9fn,\xa2\x89K\xe6\u0607\xbd\x87n\x00\x00\u07d4\xc8\x17\xdf\x1b\x91\xfa\xf3\x0f\xe3%\x15qr|\x97\x11\xb4]\x8f\x06\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xc8\x1f\xb7\xd2\x0f\u0480\x01\x92\xf0\xaa\xc1\x98\xd6\u05a3}?\xcb}\x89\x0e\x11I3\x1c-\xde\x00\x00\u07d4\xc8 \xc7\x11\xf0w\x05'8\a\xaa\xaam\xe4M\x0eKH\xbe.\x89\bg\x0e\x9e\xc6Y\x8c\x00\x00\u07d4\xc8#\x1b\xa5\xa4\x11\xa1>\"+)\xbf\xc1\b?v1X\xf2&\x8967\tlK\xcci\x00\x00\u07d4\xc86\xe2Jo\xcf)\x94;6\b\xe6b)\n!_e)\xea\x89\x0f\xd4Pd\xea\xee\x10\x00\x00\xe0\x94\xc8;\xa6\u0755I\xbe\x1d2\x87\xa5\xa6T\xd1\x06\xc3Lk]\xa2\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xc8>\x9djX%;\uefb7\x93\xe6\xf2\x8b\x05JXI\x1bt\x89\x0fF\u00b6\xf5\xa9\x14\x00\x00\u07d4\xc8A\x88O\xa4x_\xb7s\xb2\x8e\x97\x15\xfa\xe9\x9aQ40]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc8M\x9b\xea\n{\x9f\x14\x02 \xfd\x8b\x90\x97\u03ff\xd5\xed\xf5d\x89\x06\xab\x9e\u0091\xad}\x80\x00\u07d4\xc8RB\x8d+Xd\x97\xac\xd3\fV\xaa\x13\xfbU\x82\xf8D\x02\x893B\xd6\r\xff\x19`\x00\x00\u07d4\xc8S![\x9b\x9f-,\xd0t\x1eX^\x98{_\xb8\f!.\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xc8S%\uaca5\x9b>\xd8c\xc8j_)\x06\xa0B)\xff\xa9\x89\x19=\u007f}%=\xe0\x00\x00\u07d4\xc8^\xf2}\x82\x04\x03\x80_\xc9\xed%\x9f\xffd\xac\xb8\xd64j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc8akN\xc0\x91(\xcd\xff9\xd6\u4e6c\x86\xee\xc4q\xd5\xf2\x89\x01\r:\xa56\xe2\x94\x00\x00\xe0\x94\xc8a\x90\x90K\x8d\a\x9e\xc0\x10\xe4b\xcb\xff\xc9\b4\xff\xaa\\\x8a\x02#\x85\xa8'\xe8\x15P\x00\x00\u07d4\xc8q\r~\x8bZ;\u059aB\xfe\x0f\xa8\xb8|5\u007f\xdd\xcd\u0209\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc8sR\u06e5\x82\xee f\xb9\xc0\x02\xa9b\xe0\x03\x13Ox\xb1\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xc8|w\xe3\xc2J\xde\xcd\xcd\x108\xa3\x8bV\xe1\x8d\xea\u04f7\x02\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\xc8}:\xe3\u0607\x04\u066b\x00\t\xdc\xc1\xa0\x06q1\xf8\xba<\x89j\xc5\xc6-\x94\x86\a\x00\x00\xe0\x94\u0201N4R>8\xe1\xf9'\xa7\xdc\xe8FjDz\t6\x03\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u0202U\xed\xdc\xf5!\xc6\xf8\x1d\x97\xf5\xa4!\x81\xc9\a=N\xf1\x89\x0f\u00d0D\xd0\n*\x80\x00\u07d4\u0205\xa1\x8a\xab\xf4T\x1b{{~\xcd0\xf6\xfa\u619d\x95i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u020c\xa1\xe6\xe5\xf4\xd5X\xd17\x80\xf4\x88\xf1\rJ\xd3\x13\r4\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u020e\xecT\xd3\x05\xc9(\xcc(H\xc2\xfe\xe251\xac\xb9mI\x89lj\u04c2\xd4\xfba\x00\x00\xe0\x94\u021c\xf5\x04\xb9\xf3\xf85\x18\x1f\xd8BO\\\xcb\xc8\xe1\xbd\xdf}\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u0222\xc4\xe5\x9e\x1c\u007f\xc5H\x05X\x048\xae\xd3\xe4J\xfd\xf0\x0e\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4\u022aI\u301f\b\x99\xf2\x8a\xb5~gCp\x9dXA\x903\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\u022b\x1a<\xf4l\xb8\xb0d\xdf.\"-9`s\x94 2w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0231\x85\x05%\xd9F\xf2\xae\x84\xf3\x17\xb1Q\x88\xc56\xa5\u0706\x89\x91\x8d\xdc:B\xa3\xd4\x00\x00\u07d4\xc8\xd4\xe1Y\x9d\x03\xb7\x98\t\xe0\x13\n\x8d\u00c4\b\xf0^\x8c\u04c9\x9f\xad\x06$\x12y\x16\x00\x00\u07d4\xc8\xdd'\xf1k\xf2$P\xf5w\x1b\x9f\xe4\xedO\xfc\xb3\t6\xf4\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xc8\xdezVL\u007f@\x12\xa6\xf6\xd1\x0f\u040fG\x89\x0f\xbf\a\u0509\x10CV\x1a\x88)0\x00\x00\u07d4\xc8\xe2\xad\xebT^I\x9d\x98,\f\x11sc\u03b4\x89\u0171\x1f\x895e\x9e\xf9?\x0f\xc4\x00\x00\xe0\x94\xc8\xe5X\xa3\xc5i~o\xb2:%\x94\u0200\xb7\xa1\xb6\x8f\x98`\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xc8\xf2\xb3 \xe6\xdf\xd7\t\x06\u0157\xba\xd2\xf9P\x13\x12\u01c2Y\x89Q\x93K\x8b:W\xd0\x00\x00\u07d4\xc9\x03\x00\xcb\x1d@w\xe6\xa6\xd7\xe1i\xa4`F\x8c\xf4\xa4\x92\u05c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9\f7e\x15k\u028eH\x97\xab\x80$\x19\x15<\xbeR%\xa9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xc9\x10\xa9pUl\x97\x16\xeaS\xaff\xdd\xef\x93\x141$\x91=\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\xe0\x94\xc9\x12{\u007ff)\xee\x13\xfc?`\xbc/Dg\xa2\aE\xa7b\x8a\x03|\x9a\xa4\xe7\xceB\x1d\x80\x00\u07d4\xc9\x1b\xb5b\xe4+\xd4a0\xe2\u04eeFR\xb6\xa4\ub1bc\x0f\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\xe0\x94\xc90\x88y\x05m\xfe\x13\x8e\xf8 \x8fy\xa9\x15\u01bc~p\xa8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xc94\xbe\xca\xf7\x1f\"_\x8bJK\xf7\xb1\x97\xf4\xac\x9604\\\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc9?\xbd\xe8\xd4m+\xcc\x0f\xa9\xb3;\u063a\u007f\x80B\x12Ue\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xc9@\x89U:\xe4\xc2,\xa0\x9f\xbc\x98\xf5pu\xcf.\u0155\x04\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xc9A\x10\xe7\x1a\xfeW\x8a\xa2\x18\xe4\xfc(d\x03\xb03\n\u038d\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xc9F\u056c\xc14n\xba\nry\xa0\xac\x1dF\\\x99m\x82~\x8a\x03x=T_\xdf\n\xa4\x00\x00\u07d4\xc9J(\xfb20\xa9\xdd\xfa\x96Nw\x0f,\xe3\xc2S\xa7\xbeO\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xc9JXR\x03\xda{\xba\xfd\x93\xe1X\x84\xe6`\u0531\xea\xd8T\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xc9O|5\xc0'\xd4}\xf8\xefO\x9d\xf8Z\x92H\xa1}\xd2;\x89\x01\x9f\x8euY\x92L\x00\x00\u07d4\xc9Q\x90\f4\x1a\xbb\xb3\xba\xfb\xf7\xee )7pq\xdb\xc3j\x89\x11\xc2]\x00M\x01\xf8\x00\x00\u07d4\xc9S\xf94\xc0\xeb-\x0f\x14K\u06b0\x04\x83\xfd\x81\x94\x86\\\xe7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9f&r\x8a\xaaLO\xb3\xd3\x1c&\xdf:\xf3\x10\b\x17\x10\u0449\xb5\x0f\u03ef\xeb\xec\xb0\x00\x00\u07d4\xc9gQel\n\x8e\xf45{sD2!4\xb9\x83PJ\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\u0240Hh\u007f+\xfc\u027d\x90\xed\x18slW\xed\xd3R\xb6]\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0241\xd3\x12\u0487\xd5X\x87\x1e\u0757:\xbbv\xb9y\xe5\xc3^\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0242Xmc\xb0\xd7L \x1b\x1a\xf8A\x83r\xe3\fv\x16\xbe\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u0249CO\x82Z\xaf\x9cU/h^\xba|\x11\xdbJ_\xc7:\x89\x1b(\u014d\x96\x96\xb4\x00\x00\u07d4\u0249\xee\xc3\a\u80db\x9dr7\xcf\xda\b\x82)b\xab\u41c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u0252\xbeY\xc6r\x1c\xafN\x02\x8f\x9e\x8f\x05\xc2\\UQ[\u0509\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0255{\xa9L\x1b)\xe5'~\xc3f\"pI\x04\xc6=\xc0#\x89h>\xfcg\x82d,\x00\x00\xe0\x94\u025a\x9c\xd6\xc9\xc1\xbe54\xee\u0352\xec\xc2/\\8\xe9Q[\x8a\x01\x05Y;:\x16\x9dw\x00\x00\xe0\x94\u026c\x01\xc3\xfb\t)\x03?\f\xcc~\x1a\xcf\uaae7\x94]G\x8a\x02\xa3j\x9e\x9c\xa4\xd2\x03\x80\x00\u07d4\u0276\x98\xe8\x98\xd2\rMO@\x8eNM\x06\x19\"\xaa\x85c\a\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u0276\xb6\x86\x11\x16\x91\xeej\xa1\x97\xc7#\x1a\x88\xdc`\xbd)]\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc9\u01ec\v\u0753B\xb5\xea\xd46\t#\xf6\x8cr\xa6\xbac:\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xc9\xc8\r\xc1.{\xab\x86\xe9I\xd0\x1eL>\xd3_+\x9b\xba_\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xc9\xd7dF\u056a\xdf\xf8\vh\xb9\x1b\b\u035b\xc8\xf5U\x1a\xc1\x89&\xb4\xbd\x91\x10\xdc\xe8\x00\x00\xe0\x94\xc9\u073b\x05oM\xb7\xd9\xda9\x93b\x02\u017d\x820\xb3\xb4w\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xc9\xe0&\b\x06h(\x84\x8a\xeb(\xc76r\xa1)%\x18\x1fM\x89\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xca\x042\xcb\x15{Qy\xf0.\xbb\xa5\xc9\u0475O\xecM\x88\u028965\u026d\xc5\u07a0\x00\x00\u07d4\xca\x12,\xf0\U00094216\xb7HC\xf4\x9a\xfe\u043a\x16\x18\xee\u05c9\x1e[\x8f\xa8\xfe*\xc0\x00\x00\xe0\x94\xca\"\u0363`m\xa5\xca\xd0\x13\xb8\aG\x06\xd7\xe9\xe7!\xa5\f\x8a\x01q\x81\xc6\xfa9\x81\x94\x00\x00\u07d4\xca#\xf6-\xff\rd`\x03lb\xe8@\xae\xc5W~\v\xef\u0489\a\xa1\xfe\x16\x02w\x00\x00\x00\u07d4\xca%\xff4\x93L\x19B\xe2*N{\xd5o\x14\x02\x1a\x1a\xf0\x88\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xca7?\xe3\xc9\x06\xb8\xc6U\x9e\xe4\x9c\xcd\a\xf3|\xd4\xfbRf\x89a\t=|,m8\x00\x00\u07d4\xcaA\u032c0\x17 R\xd5\"\xcd//\x95}$\x81S@\x9f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xcaB\x88\x01N\xdd\xc5c/_\xac\xb5\xe3\x85\x17\xa8\xf8\xbc]\x98\x89\x12nr\xa6\x9aP\xd0\x00\x00\u07d4\xcaB\x88c\xa5\xca06\x98\x92\xd6\x12\x18>\xf9\xfb\x1a\x04\xbc\xea\x89Rf<\u02b1\xe1\xc0\x00\x00\u07d4\xcaI\xa5\xf5\x8a\xdb\xef\xae#\xeeY\xee\xa2A\xcf\x04\x82b.\xaa\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xcaL\xa9\xe4w\x9dS\x0e\u02ec\xd4~j\x80X\xcf\xdee\u064f\x89+^:\xf1k\x18\x80\x00\x00\u07d4\xcae~\xc0o\xe5\xbc\t\xcf#\xe5*\xf7\xf8\f\xc3h\x9en\u07890\xca\x02O\x98{\x90\x00\x00\u07d4\xcaf\xb2(\x0f\xa2\x82\u0176v1\xceU+b\xeeU\xad\x84t\x89j\xc4\"\xf54\x92\x88\x00\x00\xe0\x94\xcal\x81\x8b\xef\xd2Q6\x1e\x02t@h\xbe\x99\u062a`\xb8J\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcap\xf4\u077f\x06\x9d!C\xbdk\xbc\u007fikRx\x9b2\u7262\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xcatuvDjL\x8f0\xb0\x83@\xfe\xe1\x98\xdec\xec\x92\u03ca\x01|\x8e\x12\x06r*0\x00\x00\u07d4\xca{\xa3\xffSl~_\x0e\x158\x00\xbd8=\xb81)\x98\xe0\x89\t1\xac=k\xb2@\x00\x00\xe0\x94\u0282v\xc4w\xb4\xa0{\x80\x10{\x845\x94\x18\x96\a\xb5;\xec\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\u0284\t\b>\x01\xb3\x97\xcf\x12\x92\x8a\x05\xb6\x84U\xceb\x01\u07c9V\xbcu\xe2\xd61\x00\x00\x00\u07d4\u0298\u01d8\x8e\xfa\b\xe9%\uf719ER\x03&\xe9\xf4;\x99\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u029a\x04*j\x80o\xfc\x92\x17\x95\x00\xd2D)\xe8\xabR\x81\x17\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\u029d\xec\x02\x84\x1a\xdf\\\xc9 WjQ\x87\xed\u04bdCJ\x18\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u029f\xaa\x17T/\xaf\xbb8\x8e\xab!\xbcL\x94\u89f3G\x88\x89lk\x8f\xce\r\x18y\x80\x00\xe0\x94\u02aah\xeel\xdf\r4EJv\x9b\r\xa1H\xa1\xfa\xaa\x18e\x8a\x01\x87.\x1d\xe7\xfeR\xc0\x00\x00\u07d4\u02ad\x9d\xc2\rX\x9c\xe4(\xd8\xfd\xa3\xa9\xd5:`{y\x88\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u02b0\xd3,\xf3v\u007f\xa6\xb3S|\x842\x8b\xaa\x9fPE\x816\x8a\x01\xe5\xb8\xfa\x8f\xe2\xac\x00\x00\x00\u07d4\u02b9\xa3\x01\xe6\xbdF\xe9@5P(\xec\xcd@\xceMZ\x1a\u00c9\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u02b9\xa9z\xda\x06\\\x87\x81nh`\xa8\xf1Bo\xe6\xb3\xd7u\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\u02ba\xb6'N\xd1P\x89s~({\xe8x\xb7W\x93Hd\xe2\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\u02bd\xaf5OG \xa4f\xa7d\xa5(\xd6\x0e:H*9<\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xca\xcbg^\t\x96#T\x04\ufbfb.\u02c1R'\x1bU\xe0\x89%\xf2s\x93=\xb5p\x00\x00\u07d4\xca\xd1O\x9e\xbb\xa7f\x80\xeb\x83k\a\x9c\u007f{\xaa\xf4\x81\xedm\x89\f\xef={\xd7\xd04\x00\x00\xe0\x94\xca\xe3\xa2S\xbc\xb2\xcfN\x13\xba\x80\u0098\xab\x04\x02\xda|*\xa0\x8a\x01$\xbc\r\u0752\xe5`\x00\x00\u07d4\xca\xef\x02{\x1a\xb5\x04\xc7?A\xf2\xa1\ty\xb4t\xf9~0\x9f\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xca\xf4H\x1d\x9d\xb7\x8d\xc4\xf2_{J\u023d;\x1c\xa0\x10k1\x8a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\xca\xfd\xe8U\x86L%\x98\xda<\xaf\xc0Z\u064d\U00089380H\x8a\x03\x00\xa8\xed\x96\xffJ\x94\x00\x00\xe0\x94\xcb\r\xd7\xcfN]\x86a\xf6\x02\x89C\xa4\xb9\xb7\\\x91D6\xa7\x8a\x19i6\x89t\xc0[\x00\x00\x00\u07d4\xcb\x1b\xb6\xf1\xda^\xb1\rH\x99\xf7\xe6\x1d\x06\xc1\xb0\x0f\u07f5-\x898E$\xccp\xb7x\x00\x00\u07d4\xcb=vl\x98?\x19+\xce\xca\xc7\x0fN\xe0=\xd9\xffqMQ\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xcbB\xb4N\xb5\xfd`\xb5\x83~O\x9e\xb4rgR=\x1a\"\x9c\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xcbG\xbd0\u03e8\xecTh\xaa\xa6\xa9FB\xce\xd9\xc8\x19\xc8\u0509\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xcbH\xfe\x82e\u066fU\xebp\x06\xbc3VE\xb0\xa3\xa1\x83\xbe\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xcbJ\x91M+\xb0)\xf3._\xef\\#LO\xec--\xd5w\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xcbJ\xbf\u0082\xae\xd7n]W\xaf\xfd\xa5B\xc1\xf3\x82\xfc\xac\xf4\x8a\x01\xb9\x0f\x11\xc3\x18?\xaa\x00\x00\u07d4\xcbJ\xd0\xc7#\xdaF\xabV\xd5&\xda\f\x1d%\xc7=\xaf\xf1\n\x89\x1b\xa5\xab\xf9\xe7y8\x00\x00\u07d4\xcbK\xb1\xc6#\xba(\xdcB\xbd\xaa\xa6\xe7N\x1d*\xa1%l*\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xcbPXt\x12\x82#\x04\xeb\u02e0}\xab:\x0f\t\xff\xfe\u4189JD\x91\xbdm\xcd(\x00\x00\u07d4\xcbX\x99\v\u0350\u03ffm\x8f\t\x86\xf6\xfa`\x02v\xb9N-\x8964\xbf9\xab\x98x\x80\x00\u07d4\xcbh\xaeZ\xbe\x02\xdc\xf8\xcb\u016aq\x9c%\x81FQ\xaf\x8b\x85\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xcbty\x10\x9bC\xb2fW\xf4F_M\x18\xc6\xf9t\xbe_B\x89b\xa9\x92\xe5:\n\xf0\x00\x00\xe0\x94\xcb}+\x80\x89\xe91,\u026e\xaa's\xf3S\b\xecl*{\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u02c6\xed\xbc\x8b\xbb\x1f\x911\x02+\xe6IV^\xbd\xb0\x9e2\xa1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u02d3\x19\x9b\x9c\x90\xbcI\x15\xbd\x85\x9e=B\x86m\xc8\xc1\x87I\x89\f\x90\xdf\a\xde\xf7\x8c\x00\x00\u07d4\u02d4\xe7o\xeb\xe2\b\x11g3\xe7n\x80]H\xd1\x12\xec\x9f\u028965\u026d\xc5\u07a0\x00\x00\u07d4\u02dbQ\x03\xe4\u0389\xafOd\x91aP\xbf\xf9\xee\u02df\xaa\\\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u02e2\\zP<\xc8\xe0\xd0Iq\xca\x05\xc7b\xf9\xb7b\xb4\x8b\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u02e2\x88\xcd<\x1e\xb4\u055d\xdb\x06\xa6B\x1c\x14\xc3E\xa4{$\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u02f3\x18\x9eK\xd7\xf4_\x17\x8b\x1c0\xc7n&1MJK\n\x89\x0f\xfe\vg|e\xa9\x80\x00\xe0\x94\u02f7\xbe\x17\x95?,\u0313\u1f19\x80[\xf4U\x11CNL\x8a\n\xae[\x9d\xf5m/ \x00\x00\xe0\x94\xcb\xc0KM\x8b\x82\xca\xf6p\x99o\x16\f6)@\xd6o\xcf\x1a\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcb\u07974\xb8\xe6\xaaS\x8c)\x1dm\u007f\xac\xed\xb0\xf38\xf8W\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xcb\xe1\xb9H\x86M\x84t\xe7e\x14XX\xfc\xa4U\x0fxK\x92\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xe5/\xc53\xd7\xdd`\x8c\x92\xa2`\xb3|?E\u07b4\xeb3\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcb\xe8\x10\xfe\x0f\xec\xc9dGJ\x1d\xb9w(\xbc\x87\xe9s\xfc\xbd\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xf1j\x0f\xe2tRX\xcdR\xdb+\xf2\x19T\xc9u\xfcj\x15\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\xcb\xf3\u007f\xf8T\xa2\xf1\xceS\x93D\x94wx\x92\xd3\xeceW\x82\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcb\xfaj\xf6\u0083\xb0F\xe2w,`c\xb0\xb2\x15S\xc4\x01\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcb\xfav\xdb\x04\xce8\xfb ]7\xb8\xd3w\xcf\x13\x80\xda\x03\x17\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xcc\x03I\x85\xd3\xf2\x8c-9\xb1\xa3K\xce\xd4\u04f2\xb6\xca#N\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xcc\x04\x8d\u01f9]\xca%\xdf&\xee\xfac\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcc+_D\x8f5(\xd3\xfeA\xcc}\x1f\xa9\xc0\xdcv\xf1\xb7v\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xcc-\x04\xf0\xa4\x01q\x89\xb3@\xcaw\x19\x86A\xdc\xf6Ek\x91\x89\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94\xccA\x9f\u0651+\x85\x13VY\xe7z\x93\xbc=\xf1\x82\xd4Q\x15\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xccE\xfb:U[\xad\x80{8\x8a\x03W\xc8U _|u\xe8\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xccHAM*\xc4\xd4*Yb\xf2\x9e\xeeD\x97\t/C\x13R\x89\b\xbaR\xe6\xfcE\xe4\x00\x00\u07d4\xccJ/,\xf8l\xf3\xe43u\xf3`\xa4sF\x91\x19_\x14\x90\x89I\x15\x05;\xd1)\t\x80\x00\u07d4\xccO\x0f\xf2\xae\xb6}T\xce;\xc8\xc6Q\v\x9a\xe8>\x9d2\x8b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xccO\xaa\xc0\v\xe6b\x8f\x92\xefk\x8c\xb1\xb1\xe7j\xac\x81\xfa\x18\x89\v\"\xa2\xea\xb0\xf0\xfd\x00\x00\xe0\x94\xccO\xebr\u07d8\xff5\xa18\xe0\x17a\xd1 ?\x9b~\xdf\n\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xcc`oQ\x13\x97\xa3\x8f\u01c7+\u04f0\xbd\x03\xc7\x1b\xbdv\x8b\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xcc`\xf86\xac\xde\xf3T\x8a\x1f\xef\u0321>\u01a97\xdbD\xa0\x89\x04\xb0m\xbb\xb4\x0fJ\x00\x00\u07d4\xccl\x03\xbd`>\t\xdeT\xe9\xc4\u056cmA\xcb\xceqW$\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\xccl-\xf0\x0e\x86\xec\xa4\x0f!\xff\xda\x1ag\xa1i\x0fG|e\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94\xccm{\x12\x06\x1b\xc9m\x10M`me\xff\xa3+\x006\xeb\a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xccs\xdd5kIy\xb5y\xb4\x01\xd4\xccz1\xa2h\xdd\xceZ\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xccu\x8d\a\x1d%\xa62\n\xf6\x8c]\xc9\xc4\xf6\x95[\xa9E \x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcc{\x04\x81\xcc2\xe6\xfa\xef#\x86\xa0p\"\xbc\xb6\xd2\u00f4\xfc\x89\xabM\xcf9\x9a:`\x00\x00\xe0\x94\u0314;\xe1\",\xd1@\n#\x99\xdd\x1bE\x94E\xcfmT\xa9\x8a\x02\xa7@\xaee6\xfc\x88\x00\x00\u07d4\u0315\x19\xd1\xf3\x98_k%^\xad\xed\x12\xd5bJ\x97'!\xe1\x8965\u026d\xc5\u07a0\x00\x00\u0794\u031a\xc7\x15\xcdo&\x10\xc5+XgdV\x88B\x97\x01\x8b)\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\u0320{\xb7\x94W\x1dJ\xcf\x04\x1d\xad\x87\xf0\xd1\xef1\x85\xb3\x19\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u032b\xc6\x04\x8aSFD$\xfc\xf7n\xeb\x9en\x18\x01\xfa#\u0509\x02\xab{&\x0f\xf3\xfd\x00\x00\u07d4\u032e\r=\x85*}\xa3\x86\x0f\x066\x15L\nl\xa3\x16(\u0509\x05\xc6\xd1+k\xc1\xa0\x00\x00\u07d4\xcc\xca$\xd8\xc5mn,\a\xdb\bn\xc0~X[\xe2g\xac\x8d\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xcc\xd5!\x13-\x98l\xb9hi\x84&\"\xa7\u0762l>\xd0W\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcc\xf49u\xb7k\xfes_\xec<\xb7\xd4\xdd$\xf8\x05\xba\tb\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xcc\xf6*f?\x13S\xba.\xf8\xe6R\x1d\xc1\xec\xb6s\xec\x8e\xf7\x89\b=lz\xabc`\x00\x00\u07d4\xcc\xf7\x11\r\x1b\u0667K\xfd\x1d}}-\x9dU`~{\x83}\x890\xca\x02O\x98{\x90\x00\x00\u07d4\xcc\xfdrW`\xa6\x88#\xff\x1e\x06/L\xc9~\x13`\xe8\u0657\x89\x15\xacV\xed\xc4\xd1,\x00\x00\u07d4\xcd\x02\x0f\x8e\xdf\xcfRG\x98\xa9\xb7:d\x034\xbb\xf7/\x80\xa5\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xcd\x06\xf8\xc1\xb5\u037d(\xe2\xd9kcF\xc3\xe8Z\x04\x83\xba$\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcd\a.n\x183\x13y\x95\x19m{\xb1r_\xef\x87a\xf6U\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xcd\n\x16\x1b\xc3g\xae\t'\xa9*\xac\x9c\xf6\xe5\bg\x14\xef\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\xcd\n\xf3GN\"\xf0i\xec4\a\x87\r\xd7pD=[\x12\xb0\x89\x8e^\xb4\xeew\xb2\xef\x00\x00\u07d4\xcd\v\x02W\u70e3\xd2\xc2\u3e9dny\xb7^\xf9\x80$\u0509\x9f\xad\x06$\x12y\x16\x00\x00\u07d4\xcd\x10,\xd6\xdb=\xf1J\u05af\x0f\x87\xc7$y\x86\x1b\xfc=$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcd\x1ef\xedS\x9d\xd9/\xc4\v\xba\xa1\xfa\x16\u078c\x02\xc1ME\x89\fw\xe4%hc\xd8\x00\x00\u07d4\xcd\x1e\xd2c\xfb\xf6\xf6\xf7\xb4\x8a\xef\x8fs=2\x9dC\x82\xc7\u01c9\x01\x00\xbd3\xfb\x98\xba\x00\x00\u07d4\xcd*6\xd7S\xe9\xe0\xed\x01*XMqh\aX{A\xd5j\x89\x0e+\xa7[\v\x1f\x1c\x00\x00\u07d4\xcd2\xa4\xa8\xa2\u007f\x1c\xc69T\xaacOxW\x05s4\u01e3\x89:\xd1fWlr\xd4\x00\x00\u07d4\xcd5\xff\x01\x0e\xc5\x01\xa7!\xa1\xb2\xf0z\x9c\xa5\x87}\xfc\xf9Z\x89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4\xcdC\x06\xd7\xf6\x94z\xc1tMN\x13\xb8\xef2\xcbe~\x1c\x00\x89\x1b\x1a\xb3\x19\xf5\xecu\x00\x00\u07d4\xcdC%\x8bs\x92\xa90\x83\x9aQ\xb2\xef\x8a\xd24\x12\xf7Z\x9f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcdI\xbf\x18^p\xd0E\a\x99\x9f\x92\xa4\xdeDU1('\u040965\u026d\xc5\u07a0\x00\x00\u07d4\xcdU\x10\xa2B\u07f0\x18=\xe9%\xfb\xa8f\xe3\x12\xfa\xbc\x16W\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xcdVj\u05f8\x83\xf0\x1f\u04d9\x8a\x9aX\xa9\xde\xe4rM\u0725\x89\x030\xae\x185\xbe0\x00\x00\xe0\x94\xcdY\xf3\xdd\xe7~\t\x94\v\xef\xb6\xeeX\x03\x19e\xca\xe7\xa36\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xcdr]p\xbe\x97\xe6w\xe3\xc8\xe8\\\v&\xef1\xe9\x95PE\x89Hz\x9a0E9D\x00\x00\xe0\x94\xcd~G\x90\x94d\xd8q\xb9\xa6\xdcv\xa8\xe9\x19]\xb3H^z\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xcd~\xce\bkKa\x9b;6\x93R\xee8\xb7\x1d\xdb\x06C\x9a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xcd\u007f\t\xd7\xedf\xd0\u00cb\u016dN2\xb7\xf2\xb0\x8d\xc1\xb3\r\x89>;\xb3M\xa2\xa4p\x00\x00\u07d4\u0355)I+\\)\xe4u\xac\xb9A@+=;\xa5\x06\x86\xb0\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0355\xfaB=o\xc1 'J\xac\xde\x19\xf4\xee\xb7f\xf1\x04 \x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u035bL\xefs9\f\x83\xa8\xfdq\u05f5@\xa7\xf9\u03cb\x8c\x92\x89\x04\xe1\x00;(\xd9(\x00\x00\u07d4\u0361t\x11\t\xc0&[?\xb2\xbf\x8d^\xc9\u00b8\xa34kc\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0361\xb8\x86\u39d5\u027aw\x91N\n/\xe5go\x0f\\\u03c9\x05\xbf`\xeaB\xc2\x04\x00\x00\u07d4\u0364S\x0fK\x9b\xc5\t\x05\xb7\x9d\x17\u008f\xc4o\x954\x9b\u07c93\x10\xe0I\x11\xf1\xf8\x00\x00\u07d4\u036bF\xa5\x90 \x80do\xbf\x95B\x04 J\xe8\x84\x04\x82+\x89\x1d\x8a\x96\xe5\xc6\x06\xeb\x00\x00\u07d4\u0375\x97)\x900\x18?n-#\x853\xf4d*\xa5\x87T\xb6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xcd\xd5\u0601\xa76,\x90p\a;\u07fcu\xe7$S\xacQ\x0e\x89-\xa5\x18\xea\xe4\x8e\xe8\x00\x00\u07d4\xcd\xd6\rs\xef\xaa\xd8s\u027b\xfb\x17\x8c\xa1\xb7\x10Z\x81\xa6\x81\x89\x01\xbc\x16\xd6t\xec\x80\x00\x00\u07d4\xcd\xd9\xef\xacMm`\xbdq\xd9U\x85\xdc\xe5\u0557\x05\xc15d\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xcd\xe3m\x81\xd1(\u015d\xa1Ee!\x93\xee\u00bf\xd9e\x86\xef\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xcd\xea8o\x9d\x0f\xd8\x04\xd0(\x18\xf27\xb7\xd9\xfavF\xd3^\x89\xa3I\xd3m\x80\xecW\x80\x00\u07d4\xcd\xec\xf5gT3\u0370\xc2\xe5Zh\xdb]\x8b\xbexA\x9d\u0489\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xcd\xfd\x82\x173\x97%\xd7\xeb\xac\x11\xa66U\xf2e\xef\xf1\xcc=\x8a\x01\x0f\fid\x10\xe3\xa9\x00\x00\u07d4\xce\a\x9fQ\x88wt\xd8\x02\x1c\xb3\xb5u\xf5\x8f\x18\xe9\xac\xf9\x84\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xce\x18\x84\u077b\xb8\xe1\x0eM\xbanD\xfe\xee\u00a7\xe5\xf9/\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xce\x1b\f\xb4j\xae\xcf\u05db\x88\f\xad\x0f-\u068a\x8d\xed\u0431\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xce&\xf9\xa50_\x83\x81\tCT\xdb\xfc\x92fN\x84\xf9\x02\xb5\x89\fz\xaa\xb0Y\x1e\xec\x00\x00\u07d4\xce-\xea\xb5\x1c\n\x9a\xe0\x9c\xd2\x12\xc4\xfaL\xc5+S\xcc\r\xec\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xce.\r\xa8\x93F\x99\xbb\x1aU>U\xa0\xb8\\\x16\x945\xbe\xa3\x8a\x01\x0f\fid\x10\xe3\xa9\x00\x00\u07d4\xce:a\xf0F\x1b\x00\x93^\x85\xfa\x1e\xad\x82\xc4^Zd\u0508\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xceK\x06]\xbc\xb20G 2b\xfbH\xc1\x18\x83d\x97tp\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xceS\xc8\xcd\xd7B\x96\xac\xa9\x87\xb2\xbc\x19\u00b8u\xa4\x87I\u0409\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xce^\x04\xf0\x18Ci\xbc\xfa\x06\xac\xa6o\xfa\x91\xbfY\xfa\x0f\xb9\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xce^\xb6:{\xf4\xfb\xc2\xf6\u4ea0\u018a\xb1\xcbL\xf9\x8f\xb4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xceb\x12Z\xde\xc37\n\xc5!\x10\x95:Nv\v\xe9E\x1e;\x89\b=lz\xabc`\x00\x00\xe0\x94\xceq\bmL`%T\xb8-\xcb\xfc\xe8\x8d cMS\xccM\x8a\t(\x96R\x9b\xad\u0708\x00\x00\u07d4\u038akmP3\xb1I\x8b\x1f\xfe\xb4\x1aAU\x04\x05\xfa\x03\xa2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0397\x86\xd3q/\xa2\x00\xe9\xf6\x857\xee\xaa\x1a\x06\xa6\xf4ZK\x89a\t=|,m8\x00\x00\u07d4\u039d!\u0192\xcd<\x01\xf2\x01\x1fP_\x87\x006\xfa\x8fl\u0489\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\u03a2\x89f#\xf4\x91\x02\x87\xa2\xbd\u017e\x83\xae\xa3\xf2\xe6\xde\b\x8a\x01\xfbZ7Q\xe4\x90\xdc\x00\x00\u07d4\u03a3JM\xd9=\u066e\xfd9\x90\x02\xa9}\x99z\x1bK\x89\u0349QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\u03a4?pu\x81k`\xbb\xfc\u62d9:\xf0\x88\x12p\xf6\u0109lk\x93[\x8b\xbd@\x00\x00\u07d4\u03a8t3AS<\xb2\xf0\xb9\xc6\xef\xb8\xfd\xa8\rw\x16(%\x89\x05k\xc7^-c\x10\x00\x00\u07d4\u03b0\x89\xec\x8ax3~\x8e\xf8\x8d\xe1\x1bI\xe3\u0751\x0ft\x8f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u03b3=x\xe7Tz\x9d\xa2\xe8}Q\xae\xc5\xf3D\x1c\x87\x92:\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u03b3\x898\x1dH\xa8\xaeO\xfcH:\u043b^ L\xfd\xb1\xec\x89('\xe6\xe4\xddb\xba\x80\x00\u07d4\xce\xc6\xfce\x85?\x9c\xce_\x8e\x84Fv6.\x15y\x01_\x02\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xce\xd3\u01fe\x8d\xe7XQ@\x95*\xebP\x1d\xc1\xf8v\ucbf0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xce\xd8\x1e\xc3S?\xf1\xbf\xeb\xf3\xe3\x84>\xe7@\xad\x11u\x8d>\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xce\u0733\xa1\u0584?\xb6\xbe\xf6Ca}\xea\U000cf398\xdd_\x89\x19\xe2\xa4\xc8\x18\xb9\x06\x00\x00\u07d4\xce\xe6\x99\xc0pzx6%+)/\x04|\xe8\xad(\x9b/U\x89\x11\x9a\x1e!\xaaiV\x00\x00\u07d4\xce\xedG\xca[\x89\x9f\xd1b?!\xe9\xbdM\xb6Z\x10\u5c1d\x89\a8w@L\x1e\xee\x00\x00\u07d4\xce\xf7tQ\u07e2\xc6C\xe0\v\x15mlo\xf8N#s\xebf\x89\n1\x06+\xee\xedp\x00\x00\u07d4\xcf\x11i\x04\x1c\x17E\xe4[\x17$5\xa2\xfc\x99\xb4\x9a\xce+\x00\x89\x01\xbb\x88\xba\xab-|\x00\x00\xe0\x94\xcf\x15v\x12vN\x0f\u0596\xc8\xcb_\xba\x85\xdfL\r\xdc<\xb0\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u0794\xcf\x1b\xdby\x9b.\xa6<\xe14f\x8b\xdc\x19\x8bT\x84\x0f\x18\v\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xcf\"\x88\xefN\xbf\x88\xe8m\xb1=\x8a\x0e\v\xf5*\x05e\x82\u00c9\x89Po\xbf\x97@t\x00\x00\u07d4\xcf&Ni%\x13\t\x06\xc4\xd7\xc1\x85\x91\xaaA\xb2\xa6\u007foX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf&\xb4{\xd04\xbcP\x8elK\xcf\xd6\xc7\xd3\x004\x92Wa\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xcf.*\xd65\xe9\x86\x1a\xe9\\\xb9\xba\xfc\xca\x03kR\x81\xf5\u038a\at2!~h6\x00\x00\x00\u07d4\xcf.s@B\xa3U\xd0_\xfb.9\x15\xb1h\x11\xf4Zi^\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf4\x8f/\xe4{~A<\az{\xaf:u\xfb\xf8B\x86\x92\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xcf?\x91(\xb0r\x03\xa3\xe1\r}WU\xc0\u012b\xc6\xe2\xca\u008a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xcf?\xbf\xa1\xfd2\u05e6\xe0\xe6\xf8\xefN\xabW\xbe4\x02\\L\x899\xa1\xc0\xf7YMH\x00\x00\u07d4\xcfAftn\x1d;\xc1\xf8\xd0qK\x01\xf1~\x8ab\xdf\x14d\x896w\x03n\xdf\n\xf6\x00\x00\u07d4\xcfO\x118\xf1\xbdk\xf5\xb6\u0505\xcc\xe4\xc1\x01\u007f\u02c5\xf0}\x89/\u043cw\xc3+\xff\x00\x00\u07d4\xcfZo\x9d\xf7Uy\xc6D\xf7\x94q\x12\x15\xb3\rw\xa0\xce@\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcf^\x0e\xac\u0473\x9d\x06U\xf2\xf7u5\xeff\b\xeb\x95\v\xa0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xcfhM\xfb\x83\x04r\x93U\xb5\x83\x15\xe8\x01\x9b\x1a\xa2\xad\x1b\xac\x89\x17r$\xaa\x84Lr\x00\x00\u07d4\xcfi@\x81\xc7m\x18\xc6L\xa7\x13\x82\xbe\\\xd6;<\xb4v\xf8\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xcfnR\xe6\xb7t\x80\xb1\x86~\xfe\xc6Dm\x9f\xc3\xcc5w\xe8\x89\f\t\x01\xf6\xbd\x98y\x00\x00\u07d4\u03c8: 2\x96g\xea\"j\x1e\x9a\x92*\x12\xf2\x1f\xaa\x03\x81V\x91\x8cO\u02dc\x89\x04E\x91\xd6\u007f\xec\xc8\x00\x00\u07d4\xcf\xf7\xf8\x9aMB\x19\xa3\x82\x95%\x131V\x82\x10\xff\xc1\xc14\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xcf\xf8\xd0k\x00\xe3\xf5\f\x19\x10\x99\xadV\xbaj\xe2eq\u0348\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xcf\xfcI\xc1x~\ubcb5l\xab\xe9$\x04\xb66\x14}EX\x8a\x013\xe00\x8f@\xa3\u0680\x00\u07d4\xd0\bQ;'`J\x89\xba\x17c\xb6\xf8L\u6233F\x94[\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\x0f\x06r\x86\xc0\xfb\u0402\xf9\xf4\xa6\x10\x83\xecv\u07b3\xce\xe6\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\x15\xf6\xfc\xb8M\xf7\xbbA\x0e\x8c\x8f\x04\x89J\x88\x1d\xca\xc27\x898E$\xccp\xb7x\x00\x00\u07d4\xd0\x1a\xf9\x13O\xafRW\x17N\x8by\x18oB\xee5Nd-\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0!\b\u04ae<\xab\x10\xcb\xcf\x16W\xaf\">\x02|\x82\x10\xf6\x89lm\x84\xbc\xcd\xd9\xce\x00\x00\u07d4\xd0*\xfe\u03ce.\u00b6*\u022d Aa\xfd\x1f\xaew\x1d\x0e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd01\x919\xfb\xab.\x8e*\xcc\xc1\xd9$\u0531\x1d\xf6ilZ\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd07\xd2\x15\xd1\x1d\x1d\xf3\xd5O\xbd2\x1c\u0495\xc5F^';\x89K\xe4\xe7&{j\xe0\x00\x00\u07d4\xd0:-\xa4\x1e\x86\x8e\xd3\xfe\xf5t[\x96\xf5\xec\xa4b\xffo\u0689\xa2\xa1]\tQ\x9b\xe0\x00\x00\xe0\x94\xd0?\xc1eWj\xae\xd5%\xe5P,\x8e\x14\x0f\x8b.\x86\x969\x8a\x01sV\u0633%\x01\xc8\x00\x00\u07d4\xd0C\xa0\x11\xecBp\xee~\u0239hsu\x15\xe5\x03\xf80(\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd0K\x86\x1b=\x9a\xccV:\x90\x16\x89\x94\x1a\xb1\xe1\x86\x11a\xa2\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd0ZD|\x91\x1d\xbb'[\xfb.Z7\xe5\xa7\x03\xa5o\x99\x97\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd0_\xfb+t\xf8g O\xe51e;\x02H\xe2\x1c\x13TN\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0bX\x81q\u03d9\xbb\xebX\xf1&\xb8p\xf9\xa3r\x8da\xec\x89\xf3\xf2\v\x8d\xfai\xd0\x00\x00\u07d4\xd0c\x8e\xa5q\x89\xa6\xa6\x99\x02J\u05ccq\xd99\xc1\xc2\xff\x8c\x89\x8e\xaeVg\x10\xfc \x00\x00\xe0\x94\xd0d\x8aX\x1b5\b\xe15\xa2\x93]\x12\xc9epE\xd8q\u028a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4\xd0q\x19)f\xebi\xc3R\x0f\xca:\xa4\xdd\x04)~\xa0KN\x89\x05\xf6\x8e\x811\xec\xf8\x00\x00\u07d4\xd0q\x85 \xea\xe0\xa4\xd6-p\xde\x1b\xe0\xcaC\x1c^\xea$\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd0w]\xba*\xf4\xc3\n:x6Y9\xcdq\xc2\xf9\u0795\u0489i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xd0{\xe0\xf9\t\x97\xca\xf9\x03\u022c\x1dS\xcd\xe9\x04\xfb\x19\aA\x8968\x908\xb6\x99\xb4\x00\x00\u07d4\xd0~Q\x18d\xb1\u03d9i\xe3V\x06\x02\x82\x9e2\xfcNq\xf5\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\u0400\x94\x98\xc5H\x04z\x1e**\xa6\xa2\x9c\xd6\x1a\x0e\xe2h\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0402'_tZ,\xac\x02v\xfb\xdb\x02\u0532\xa3\xab\x17\x11\xfe\x89\x01\xa0Ui\r\x9d\xb8\x00\x00\u07d4\u040f\xc0\x9a\x000\xfd\t(\xcd2\x11\x98X\x01\x82\xa7j\xae\x9f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0413\xe8)\x81\x9f\xd2\xe2[\x978\x00\xbb=XA\xdd\x15-\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0414J\xa1\x85\xa13pa\xae \u071d\xd9l\x83\xb2\xbaF\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u0416V[|t\a\xd0e6X\x03U\xfd\xd6\xd29\x14J\xa1\x89\r\x8drkqw\xa8\x00\x00\u07d4\u041c\xb2\xe6\b-i:\x13\xe8\xd2\xf6\x8d\xd1\u0744a\xf5X@\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u0426\xc6\xf9\xe9\u0133\x83\xd7\x16\xb3\x1d\xe7\x8dVAM\xe8\xfa\x91\x89\x10CV\x1a\x88)0\x00\x00\u07d4\u0427 \x9b\x80\xcf`\xdbb\xf5}\n]}R\x1ai`fU\x89\b\xacr0H\x9e\x80\x00\x00\xe0\x94\u0428\xab\xd8\n\x19\x9bT\xb0\x8be\xf0\x1d \x9c'\xfe\xf0\x11[\x8a\x01a\xc6&\xdca\xa2\xef\x80\x00\xe0\x94\u042b\xccp\xc0B\x0e\x0e\x17/\x97\xd4;\x87\xd5\xe8\f3n\xa9\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u042es]\x91^\x94hf\xe1\xfe\xa7~^\xa4f\xb5\xca\xdd\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0431\x1do+\u0394^\fjP \u00f5'S\xf8\x03\xf9\u0449\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xd0\xc1\x01\xfd\x1f\x01\xc6?k\x1d\x19\xbc\x92\r\x9f\x93#\x14\xb16\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd0\xc5Z\xbf\x97o\xdc=\xb2\xaf\u9f99\u0519HMWl\x02\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd0\u0422\xadE\xf5\x9a\x9d\xcc\u0195\xd8_%\xcaF\xed1\xa5\xa3\x89-\x89W}}@ \x00\x00\u07d4\xd0\xd6,G\xea`\xfb\x90\xa3c\x92\t\xbb\xfd\xd4\xd93\x99\x1c\u0189\n\x84Jt$\xd9\xc8\x00\x00\u07d4\xd0\xdbEax o\\D0\xfe\x00Pc\x90<=zI\xa7\x89&I\x1eE\xa7S\xc0\x80\x00\u07d4\xd0\xe1\x94\xf3K\x1d\xb6\t(\x85\t\xcc\xd2\xe7;a1\xa2S\x8b\x8965f3\xeb\xd8\xea\x00\x00\u07d4\xd0\xe3^\x04vF\xe7Y\xf4Qp\x93\xd6@\x86BQ\u007f\bM\x89\u054f\xa4h\x18\xec\u02c0\x00\u07d4\xd0\xeeM\x02\xcf$8,0\x90\xd3\xe9\x95`\xde6xs\\\u07c9\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\xd0\xf0OR\x10\x9a\xeb\xec\x9a{\x1e\x932v\x1e\x9f\xe2\xb9{\xb5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd0\xf9Yx\x11\xb0\xb9\x92\xbb}7W\xaa%\xb4\xc2V\x1d2\xe2\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\x03\x02\xfa\xa1\x92\x9a2i\x04\xd3v\xbf\v\x8d\xc9:\xd0LL\x89a\t=|,m8\x00\x00\xe0\x94\xd1\x10\r\xd0\x0f\xe2\xdd\xf1\x81c\xad\x96M\vi\xf1\xf2\xe9e\x8a\x8a\x01C\x12\tU\xb2Pk\x00\x00\u07d4\xd1\x16\xf3\xdc\xd5\xdbtK\xd0\b\x88v\x87\xaa\x0e\xc9\xfdr\x92\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd1\x19A|Fs,\xf3M\x1a\x1a\xfby\xc3\xe7\xe2\u034e\xec\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1-w\xae\x01\xa9-5\x11{\xacpZ\xac\u0642\xd0.t\xc1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd15yK\x14\x9a\x18\xe1G\xd1nb\x1ai1\xf0\xa4\n\x96\x9a\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xd1C%8\xe3[vd\x95j\u4563*\xbd\xf0A\xa7\xa2\x1c\x8a\x04+\xf0kx\xed;P\x00\x00\u07d4\xd1C\x82g#\x17\x04\xfcr\x80\xd5c\xad\xf4v8D\xa8\a\"\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd1S\x8e\x9a\x87\u5729\xec\x8eX&\xa5\xb7\x93\xf9\x9f\x96\xc4\u00c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd1d\x85\x03\xb1\xcc\u0178\xbe\x03\xfa\x1e\xc4\xf3\xee&~j\xdf{\x8a\x01;\xef\xbfQ\xee\xc0\x90\x00\x00\xe0\x94\xd1h,!Y\x01\x8d\xc3\xd0\u007f\b$\n\x8c`m\xafe\xf8\xe1\x8a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xd1q\xc3\xf2%\x8a\xef5\xe5\x99\xc7\xda\x1a\xa0s\x00#M\xa9\xa6\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1w\x8c\x13\xfb\xd9h\xbc\b<\xb7\xd1\x02O\xfe\x1fI\xd0,\xaa\x89\xd9\xec\xb4\xfd \x8eP\x00\x00\u07d4\xd1\u007f\xbe\"\xd9\x04b\xed7(\x06p\xa2\xea\v0\x86\xa0\xd6\u0589\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\u0441\x1cU\x97i\x80\xf0\x83\x90\x1d\x8a\r\xb2i\"-\xfb\\\xfe\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\u044e\xb9\xe1\u0485\u06be\x93\xe5\u053a\xe7k\xee\xfeC\xb5!\xe8\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\u0453\xe5\x83\xd6\a\x05c\xe7\xb8b\xb9aJG\u9509\xf3\xe5\x8965f3\xeb\xd8\xea\x00\x00\u07d4\u0457\x8f.4@\u007f\xab\x1d\xc2\x18=\x95\xcf\xdab`\xb3Y\x82\x89*\xb7\xb2`\xff?\xd0\x00\x00\u07d4\u045c\xaf9\xbb7\u007f\xdf,\xf1\x9b\xd4\xfbRY\x1c&1\xa6<\x8965\u026d\xc5\u07a0\x00\x00\u0794\u0463\x96\xdc\u06b2\xc7IA0\xb3\xfd0x 4\r\xfd\x8c\x1f\x88\xf9\"P\xe2\xdf\xd0\x00\x00\xe0\x94\u0467\x1b-\bX\xe82p\b]\x95\xa3\xb1T\x96P\x03^#\x8a\x03'\xbb\t\xd0j\xa8P\x00\x00\u07d4\u046c\xb5\xad\xc1\x189s%\x8dk\x85$\xff\xa2\x8f\xfe\xb2=\xe3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u0473\u007f\x03\xcb\x10t$\xe9\xc4\xddW\\\xcdOL\xeeW\xe6\u0349lk\x93[\x8b\xbd@\x00\x00\u07d4\u0475\xa4T\xac4\x05\xbbAy \x8cl\x84\xde\x00k\u02db\xe9\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\xc4YT\xa6+\x91\x1a\xd7\x01\xff.\x90\x13\x1e\x8c\xeb\x89\xc9\\\x89K\x91\xa2\xdeE~\x88\x00\x00\u07d4\xd1\xc9np\xf0Z\xe0\xe6\xcd`!\xb2\b7P\xa7q|\xdeV\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\u0571\u007f\xfe-{\xbby\xcc}y0\xbc\xb2\xe5\x18\xfb\x1b\xbf\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd1\xda\f\x8f\xb7\xc2\x10\xe0\xf2\xeca\x8f\x85\xbd\xae}>sK\x1c\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd1\xddy\xfb\x15\x81`\xe5\xb4\xe8\xe2?1.j\x90\u007f\xbcMN\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd1\xdeZ\xad:_\xd8\x03\U00071bb6\x10<\xb8\xe1O\xe7#\xb7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd1\xe1\xf2\xb9\xc1l0\x98t\xde\xe7\xfa\xc3&u\xaf\xf1)\u00d8\x89\x03\xf2M\x8eJ\x00p\x00\x00\xe0\x94\xd1\xe5\xe24\xa9\xf4Bf\xa4\xa6$\x1a\x84\u05e1\xa5Z\u0567\xfe\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd1\xeaMr\xa6{[>\x0f1UY\xf5+\xd0aMq0i\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd1\xee\x90YW\xfe|\xc7\x0e\xc8\xf2\x86\x8bC\xfeG\xb1?\xeb\xff\x89\x02b\x9ff\xe0\xc50\x00\x00\u07d4\xd1\xf1iM\"g\x1bZ\xadj\x94\x99\\6\x9f\xbea3go\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd1\xf4\xdc\x1d\u06ca\xbb\x88H\xa8\xb1N%\xf3\xb5Z\x85\x91\xc2f\x89\r\x8drkqw\xa8\x00\x00\u07d4\xd1\xfe\u042e\xe6\xf5\xdf\xd7\xe2Wi%L<\xfa\xd1Z\xde\u032a\x89'\x92\xc8\xfcKS(\x00\x00\u07d4\xd2\x05\x1c\xb3\xcbg\x04\xf0T\x8c\u0210\xab\n\x19\xdb4\x15\xb4*\x89\x12\x1b.^ddx\x00\x00\u07d4\xd2\x06\xaa\u07736\xd4^yr\xe9<\xb0uG\x1d\x15\x89{]\x89 \x86\xac5\x10R`\x00\x00\u07d4\xd2\tH+\xb5I\xab\xc4w{\xeam\u007fe\x00b\xc9\xc5z\x1c\x89\x11e\x1a\xc3\xe7\xa7X\x00\x00\u07d4\xd2\r\xcb\vxh+\x94\xbc0\x00(\x14H\xd5W\xa2\v\xfc\x83\x890\x84\x9e\xbe\x166\x9c\x00\x00\u07d4\xd2\x10{57&\u00e2\xb4ef\xea\xa7\xd9\xf8\v]!\xdb\xe3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd2\x11\xb2\x1f\x1b\x12\xb5\ta\x81Y\r\xe0~\xf8\x1a\x89S~\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd2\x18\xef\xb4\u06d8\x1c\xddjy\u007fK\u050c|&)<\xeb@\x89\xa1Fk1\xc6C\x1c\x00\x00\xe0\x94\xd2\x1asA\xeb\x84\xfd\x15\x10T\xe5\u31fb%\xd3nI\x9c\t\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xd2$\xf8\x80\xf9G\x9a\x89\xd3/\t\xe5+\u9432\x88\x13\\\xef\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xd2/\f\xa4\xcdG\x9ef\x17u\x05;\xccI\xe3\x90\xf6p\u074a\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd21\x92\x975\x13!\x02G\x1b\xa5\x90\a\xb6dL\xc0\xc1\xde>\x8967\tlK\xcci\x00\x00\u07d4\xd25\xd1\\\xb5\xec\xee\xbba)\x9e\x0e\x82\u007f\xa8'H\x91\x1d\x89\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd2:$\xd7\xf9F\x83C\xc1C\xa4\x1ds\xb8\x8f|\xbec\xbe^\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd2=z\xff\xac\xdc>\x9f=\xaez\xfc\xb4\x00oX\xf8\xa4F\x00\x89\xc3(\t>a\xee@\x00\x00\u07d4\xd2C\x18L\x80\x1e]y\xd2\x06?5x\u06ee\x81\u7ce9\u02c9k\u0722h\x1e\x1a\xba\x00\x00\u07d4\xd2KfD\xf49\xc8\x05\x1d\xfcd\u04c1\xb8\xc8lu\xc1u8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd2K\xf1--\xdfE}\xec\xb1xt\xef\xde R\xb6\\\xbbI\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\xe0\x94\xd2Q\xf9\x03\xae\x18rrY\xee\xe8A\xa1\x89\xa1\xf5i\xa5\xfdv\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd2R\x96\v\v\xf6\xb2\x84\x8f\u07ad\x80\x13m\xb5\xf5\a\xf8\xbe\x02\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd2X\x1aU\xce#\xab\x10\u062d\x8cD7\x8fY\a\x9b\xd6\xf6X\x8a\x01\xdd\f\x88_\x9a\r\x80\x00\x00\u07d4\xd2Z\xec\xd7\xeb\x8b\xd64[\x06;]\xbd'\x1cw\xd3QD\x94\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xd2|#O\xf7\xac\xca\xce=\x99g\b\xf8\xf9\xb0Ip\xf9}6\x89Hz\x9a0E9D\x00\x00\u07d4\u0482\x98RM\xf5\xecK$\xb0\xff\xb9\u07c5\x17\n\x14Z\x9e\xb5\x89\x0f\x98\xa3\xb9\xb37\xe2\x00\x00\xe0\x94\u0483\xb8\xed\xb1\n%R\x8aD\x04\xde\x1ce\xe7A\r\xbc\xaag\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\u0484\xa5\x03\x82\xf8:am9\xb8\xa9\xc0\xf3\x96\xe0\ubfe9]\x8966\xc2^f\xec\xe7\x00\x00\u07d4\u0488\xe7\xcb{\xa9\xf6 \xab\x0ftR\xe5\bc=\x1cZ\xa2v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u049d\xc0\x8e\xfb\xb3\xd7.&?x\xabv\x10\xd0\"m\xe7k\x00\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\u04a00\xac\x89R2_\x9e\x1d\xb3x\xa7\x14\x85\xa2N\x1b\a\xb2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u04a4y@CG\xc5T:\xab)*\xe1\xbbJo\x15\x83W\xfa\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\u04a5\xa0$#\nW\xcc\xc6fv\v\x89\xb0\xe2l\xaf\u0449\u01ca\n\x96YZ\\n\x8a?\x80\x00\u07d4\u04a8\x03'\xcb\xe5\\L{\xd5\x1f\xf9\xdd\xe4\xcad\x8f\x9e\xb3\xf8\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\u04a8Oug\\b\xd8\f\x88ulB\x8e\xee+\xcb\x18T!\x89A\rXj \xa4\xc0\x00\x00\u07d4\u04ab\xd8J\x18\x10\x93\xe5\xe2)\x13oB\xd85\xe8#]\xe1\t\x89\x05k\xe0<\xa3\xe4}\x80\x00\u07d4\u04ac\r:X`^\x1d\x0f\x0e\xb3\xde%\xb2\xca\xd1)\xed`X\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u04bfg\xa7\xf3\xc6\xceV\xb7\xbeAg]\xbb\xad\xfe~\xa9:3\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd2\xdb\xeb\xe8\x9b\x03W\xae\xa9\x8b\xbe\x8eIc8\u07bb(\xe8\x05\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd2\xe2\x1e\xd5hh\xfa\xb2\x8e\tG\x92z\xda\xf2\x9f#\xeb\xadl\x89l\x18O\x13U\xd0\xe8\x00\x00\u07d4\xd2\xe8\x17s\x8a\xbf\x1f\xb4\x86X?\x80\xc3P1\x8b\xed\x86\f\x80\x89\r\x02\xce\xcf_]\x81\x00\x00\u07d4\xd2\xed\xd1\xdd\xd6\xd8m\xc0\x05\xba\xebT\x1d\"\xb6@\xd5\xc7\xca\xe5\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd2\xf1\x99\x8e\x1c\xb1X\f\xecOl\x04}\xcd=\xce\xc5L\xf7<\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd2\xf2A%]\xd7\xc3\xf7<\a\x040q\xec\b\xdd\xd9\xc5\xcd\xe5\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd2\xffg \x16\xf6;/\x859\x8fJo\xed\xbb`\xa5\r<\u0389\x12\x91$o[sJ\x00\x00\u07d4\xd3\rLC\xad\xcfU\xb2\xcbS\u0583#&A4I\x8d\x89\u038965\u026d\xc5\u07a0\x00\x00\u07d4\xd3\x0e\xe9\xa1+Mh\xab\xac\xe6\xba\u029a\u05ff\\\xd1\xfa\xf9\x1c\x89QO\xcb$\xff\x9cP\x00\x00\u07d4\xd3\x11\x8e\xa3\xc85\x05\xa9\u0613\xbbg\xe2\xde\x14-Sz>\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd3\x11\xbc\u05eaN\x9bO8?\xf3\xd0\u05b6\xe0~!\xe3p]\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd3\x15\xde\xea\x1d\x8c\x12q\xf9\xd11\x12c\xabG\xc0\a\xaf\xb6\xf5\x89\x03\xc8\x1dNeK@\x00\x00\u07d4\xd3+,y\xc3dx\xc5C\x19\x01\xf6\xd7\x00\xb0M\xbe\x9b\x88\x10\x89\x15w\x9a\x9d\xe6\xee\xb0\x00\x00\u07d4\xd3+EVF\x14Ql\x91\xb0\u007f\xa9\xf7-\xcfx|\xceN\x1c\x89\x0f\xc6o\xae7F\xac\x00\x00\u07d4\xd30r\x811\xfe\x8e:\x15Hz4W<\x93E~*\xfe\x95\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd31\xc8#\x82Z\x9eRc\xd0R\u0611]M\xcd\xe0z\\7\x89\x1e\x93\x12\x83\xcc\xc8P\x00\x00\u07d4\xd33btE\xf2\u05c7\x90\x1e\xf3;\xb2\xa8\xa3g^'\xff\xec\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd3<\xf8+\xf1LY&@\xa0\x86\b\x91L#py\u057e4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd3Mp\x8ds\x98\x02E3\xa5\xa2\xb20\x9b\x19\xd3\xc5Qq\xbb\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd3N\x03\xd3j+\xd4\u045a_\xa1b\x18\xd1\xd6\x1e?\xfa\v\x15\x89\x11X\xe4`\x91=\x00\x00\x00\u07d4\xd3Pu\xcaa\xfeY\xd1#\x96\x9c6\xa8-\x1a\xb2\xd9\x18\xaa8\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xd3g\x00\x9a\xb6X&;b\xc23:\x1c\x9eA@I\x8e\x13\x89\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd3g\x9aG\xdf-\x99\xa4\x9b\x01\u024d\x1c>\f\x98|\xe1\xe1X\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\xe0\x94\u04cf\xa2\xc4\xcc\x14z\xd0j\u0562\xf7Uy(\x1f\"\xa7\xcc\x1f\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\u04da]\xa4`9+\x94\v\u01ee8\xf1e\u007f\x8a\x01f\xc5H\b\x89\xdbw\x00\x00\xe0\x94\xd3\xd6\xe9\xfb\x82T/\u049e\xd9\xea6\t\x89\x1e\x15\x13\x96\xb6\xf7\x8a\voX\x8a\xa7\xbc\xf5\xc0\x00\x00\xe0\x94\xd3\xda\u0476\u040dE\x81\u032ee\xa8s-\xb6\xaci\xf0\u019e\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xd3\xdf;S\xcb;GU\xdeT\xe1\x80E\x1c\xc4L\x9e\x8a\u0a89#\u0114\t\xb9w\x82\x80\x00\u07d4\xd3\xf8s\xbd\x99V\x13W\x89\xab\x00\xeb\xc1\x95\xb9\"\xe9K%\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4\x02\xb4\xf6\xa0\x99\xeb\xe7\x16\xcb\x14\xdfOy\xc0\xcd\x01\xc6\a\x1b\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd4\r\x00U\xfd\x9a8H\x8a\xff\x92?\xd0=5\xecF\xd7\x11\xb3\x8a\x01\x0f\b\xed\xa8\xe5U\t\x80\x00\u07d4\xd4\x0e\xd6j\xb3\xce\xff$\xca\x05\xec\xd4q\ufd12\xc1__\xfa\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd4\x18\x87\v\xc2\xe4\xfa{\x8aa!\xae\br\xd5RG\xb6%\x01\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xd4\x1d\u007f\xb4\x9f\xe7\x01\xba\xac%qpBl\u0273\x8c\xa3\xa9\xb2\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4\xd4 U\x92\x84@U\xb3\u01e1\xf8\f\xef\xe3\xb8\xebP\x9b\xcd\xe7\x89\t\xb3\xbf\xd3B\xa9\xfc\x80\x00\u07d4\xd4+ \xbd\x03\x11`\x8bf\xf8\xa6\xd1[*\x95\xe6\xde'\u017f\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd44O}\\\xade\xd1~\\-\x0es#\x94=ob\xfe\x92\x89\x0e~\xeb\xa3A\vt\x00\x00\u07d4\xd4>\xe48\xd8=\xe9\xa3ub\xbbN(l\xb1\xbd\x19\xf4\x96M\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd4C4\xb4\xe2:\x16\x9a\f\x16\xbd!\xe8f\xbb\xa5-\x97\x05\x87\x89\x8c\xf2?\x90\x9c\x0f\xa0\x00\x00\xe0\x94\xd4M\x81\xe1\x8fF\xe2\u03f5\xc1\xfc\xf5\x04\x1b\xc8V\x97g\xd1\x00\x8a\a\xb4B\xe6\x84\xf6Z\xa4\x00\x00\u07d4\xd4OJ\xc5\xfa\xd7k\xdc\x157\xa3\xb3\xafdr1\x9bA\r\x9d\x89V\xbcu\xe2\xd61\x00\x00\x00\u07d4\xd4O^\xdf+\xcf$3\xf2\x11\xda\xdd\f\xc4P\xdb\x1b\x00\x8e\x14\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xd4Oj\u00d2;_\xd71\xa4\xc4YD\xecO~\xc5*j\xe4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd4[3A\xe8\xf1\\\x802\x93 \u00d7~;\x90\xe7\x82j~\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xd4]]\xaa\x13\x8d\xd1\xd3t\xc7\x1b\x90\x19\x91h\x11\xf4\xb2\nN\x89\x1f9\x9b\x148\xa1\x00\x00\x00\u07d4\xd4`\xa4\xb9\b\xdd+\x05gY\xb4\x88\x85\vf\xa88\xfcw\xa8\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd4g\xcf\x06L\bq\x98\x9b\x90\u0632\xeb\x14\xcc\xc6;6\b#\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd4k\xaea\xb0'\xe5\xbbB.\x83\xa3\xf9\xc9?<\x8f\xc7}'\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4o\x82#E)\x82\xa1\xee\xa0\x19\xa8\x81n\xfc-o\xc0\ah\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xd4uG\u007f\xa5c\x90\xd30\x17Q\x8dg\x11\x02\u007f\x05\U0008dfc9k\x11\x133\xd4\xfdL\x00\x00\u07d4\xd4|$.\xdf\xfe\xa0\x91\xbcT\xd5}\xf5\xd1\xfd\xb91\x01Gl\x89\x9d\xf7\u07e8\xf7`H\x00\x00\u07d4\xd4}\x86\x85\xfa\xee\x14|R\x0f\u0646p\x91u\xbf/\x88k\xef\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd4\u007fP\u07c9\xa1\xcf\xf9e\x13\xbe\xf1\xb2\xae:)q\xac\xcf,\x89-\x89W}}@ \x00\x00\u07d4\u0502\xe7\xf6\x8eA\xf28\xfeQx)\xde\x15G\u007f\xe0\xf6\xdd\x1d\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u0507\x9f\xd1+\x1f:'\xf7\xe1\tv\x1b#\xca4\xfa#\x06K\x1c\xaf\x00Qn(pJ\x82\xa4\xf8\x89Hz\x9a0E9D\x00\x00\u07d4\xd5\x00\xe4\xd1\u0242K\xa9\xf5\xb65\u03e3\xa8\xc2\u00cb\xbdL\xed\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd5\b\u04dcp\x91oj\xbcL\xc7\xf9\x99\xf0\x11\xf0w\x10X\x02\x89\x05rM$\xaf\xe7\u007f\x00\x00\u07d4\xd5\x0f\u007f\xa0>8\x98v\u04d0\x8b`\xa57\xa6pc\x04\xfbV\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xd5\x13\xa4P\x80\xff/\xeb\xe6,\u0545J\xbe)\xeeDg\xf9\x96\x89\bN\x13\xbcO\xc5\xd8\x00\x00\u07d4\xd5'o\f\xd5\xff\xd5\xff\xb6?\x98\xb5p=U\x94\xed\xe0\x83\x8b\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xd5)KfbB0;m\xf0\xb1\u020d7B\x9b\xc8\xc9e\xaa\x89\x10M\r\x00\u04b7\xf6\x00\x00\u07d4\xd5*\xec\xc6I98\xa2\x8c\xa1\xc3g\xb7\x01\xc2\x15\x98\xb6\xa0.\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\xd5\x99x\xee \xa3\x8c?I\x8dc\xd5\u007f1\xa3\x9fj\x06\x8a\x022\xb3o\xfcg*\xb0\x00\x00\u07d4\u05568\xd3\xc5\xfa\xa7q\x1b\xf0\x85t_\x9d[\xdc#\u0518\u0609lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u055d\x92\xd2\xc8p\x19\x80\xcc\a<7]r\n\xf0dt<\f\x8a\x04\x05\xfd\xf7\u5bc5\xe0\x00\x00\u07d4\u0567\xbe\xc32\xad\xde\x18\xb3\x10KW\x92Tj\xa5\x9b\x87\x9bR\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0571\x17\xec\x11n\xb8FA\x89a\xeb~\xdbb\x9c\xd0\xddi\u007f\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\u0572\x84\x04\x010\xab\xf7\xc1\xd1cq#q\xcc~(\xadf\u0689j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u0579\xd2w\u062a\xd2\x06\x97\xa5\x1fv\xe2\tx\x99k\xff\xe0U\x89\a\xc3\xfe<\aj\xb5\x00\x00\u07d4\u057d^\x84U\xc10\x16\x93W\xc4q\xe3\u6077\x99jrv\x89-\x9e(\x8f\x8a\xbb6\x00\x00\u07d4\xd5\u02e5\xb2k\xea]s\xfa\xbb\x1a\xba\xfa\xcd\xef\x85\xde\xf3h\u0309\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd5\xceU\u0476/YC\xc0?\x89\b\xe3\x1f\xe1h\x9d\x8a\x00\x00\u07d4\xd6\x06Q\xe3\x93x4#\xe5\xcc\x1b\xc5\xf8\x89\xe4N\xf7\xea$>\x89\x15\x9ev7\x11)\xc8\x00\x00\u07d4\xd6\t\xbfO\x14n\xeak\r\xc8\xe0m\xdc\xf4D\x8a\x1f\xcc\xc9\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\t\xec\v\xe7\r\n\xd2ong\xc9\xd4v+R\xeeQ\x12,\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd6\nRX\a(R\r\xf7Tk\xc1\xe2\x83)\x17\x88\u06ee\f\x8964\x89\xef?\xf0\xd7\x00\x00\u07d4\xd6\v$s!\xa3*Z\xff\xb9k\x1e'\x99'\xccXM\xe9C\x89z\xd0 \xd6\xdd\xd7v\x00\x00\u07d4\xd6\x11\x02v\xcf\xe3\x1eB\x82ZW\u007fkC]\xbc\xc1\f\xf7d\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd6\x12Y{\xc3\x17C\u01c63\xf63\xf29\xb1\xe9Bk\xd9%\x8a\x10\x17\xf7\u07d6\xbe\x17\x80\x00\x00\u07d4\xd6#J\xafE\xc6\xf2.f\xa2%\xff\xb9:\xddb\x9bN\xf8\x0f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd6.\u06d6\xfc\u259a\xaflT^\x96|\xf1\xc0\xbc\x80R\x05\x89\x04\xa5eSjZ\u0680\x00\u07d4\xd60\v2\x15\xb1\x1d\xe7b\xec\xdeKp\xb7\x92}\x01)\x15\x82\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd69]\xb5\xa4\xbbf\xe6\x0fL\xfb\xcd\xf0\x05{\xb4\xd9xb\xe2\x891T\xc9r\x9d\x05x\x00\x00\xe0\x94\xd6J-P\xf8\x85\x857\x18\x8a$\xe0\xf5\r\xf1h\x1a\xb0~\u05ca\b7Z*\xbc\xca$@\x00\x00\u07d4\xd6X\n\xb5\xedL}\xfaPo\xa6\xfed\xad\\\xe1)pw2\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd6Y\x8b\x13\x86\xe9<\\\u02d6\x02\xffK\xbb\xec\xdb\xd3p\x1d\u0109\f%\xf4\xec\xb0A\xf0\x00\x00\u07d4\xd6dM@\xe9\v\xc9\u007f\xe7\xdf\xe7\u02bd2i\xfdW\x9b\xa4\xb3\x89\b\x9e\x91y\x94\xf7\x1c\x00\x00\xe0\x94\xd6g\f\x03m\xf7T\xbeC\xda\u074fP\xfe\xea(\x9d\x06\x1f\u058a\x01D\xa2\x904H\xce\xf7\x80\x00\u07d4\xd6hR:\x90\xf0)=e\xc58\xd2\xddlWg7\x10\x19n\x89\x02$,0\xb8S\xee\x00\x00\u07d4\xd6j\xb7\x92\x94\aL\x8bb}\x84-\xabA\xe1}\xd7\f]\xe5\x8965\u026d\xc5\u07a0\x00\x00\u0794\xd6j\xcc\r\x11\xb6\x89\u03a6\xd9\xea_\xf4\x01L\"J]\xc7\u0108\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xd6m\xdf\x11Y\xcf\"\xfd\x8czK\xc8\u0540wV\xd43\xc4>\x89wC\"\x17\xe6\x83`\x00\x00\u07d4\u0587\xce\xc0\x05\x90\x87\xfd\xc7\x13\xd4\xd2\xd6^w\xda\xef\xed\xc1_\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\u0588\xe7\x85\u024f\x00\xf8K:\xa1S3U\u01e2X\xe8yH\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u05a2.Y\x8d\xab\u04ce\xa6\xe9X\xbdy\u050d\u0756\x04\xf4\u07c965\u026d\xc5\u07a0\x00\x00\u07d4\u05a7\xacM\xe7\xb5\x10\xf0\xe8\xdeQ\x9d\x97?\xa4\xc0\x1b\xa84\x00\x89e\xea=\xb7UF`\x00\x00\u07d4\u05ac\xc2 \xba.Q\xdf\xcf!\xd4C6\x1e\xeav\\\xbd5\u0609\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u05ac\xff\u043f\u065c8.{\xd5o\xf0\xe6\x14J\x9eR\xb0\x8e\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xd6\xc0\u043c\x93\xa6.%qtp\x0e\x10\xf0$\u0232?\x1f\x87\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd6\xcf\\\x1b\u03dd\xa6b\xbc\xea\"U\x90P\x99\xf9\xd6\xe8M\u030a\x01\u011eB\x01W\xd9\xc2\x00\x00\u07d4\xd6\xd05r\xa4RE\xdb\xd46\x8cO\x82\xc9W\x14\xbd!g\xe2\x89?\x00\xc3\xd6f\x86\xfc\x00\x00\u07d4\xd6\xd6wiX\xee#\x14:\x81\xad\xad\xeb\b8 \t\xe9\x96\u0089\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd6\xd9\xe3\x0f\bB\x01*qv\xa9\x17\xd9\xd2\x04\x8c\xa0s\x87Y\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd6\xe0\x9e\x98\xfe\x13\x003!\x04\xc1\xca4\xfb\xfa\xc5T6N\u0649lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\xe8\xe9z\u90db\x9e\xe5\a\xee\xdb(\xed\xfbtw\x03\x149\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd6\uea18\u052e+q\x80'\xa1\x9c\xe9\xa5\xebs\x00\xab\xe3\u0289\x01}J\xce\xeec\u06c0\x00\xe0\x94\xd6\xf1\xe5[\x16\x94\b\x9e\xbc\xb4\xfe}x\x82\xaaf\u0217av\x8a\x04<#\xbd\xbe\x92\x9d\xb3\x00\x00\u07d4\xd6\xf4\xa7\xd0N\x8f\xaf \xe8\xc6\ub15c\xf7\xf7\x8d\xd2=z\x15\x89\a$\xde\xd1\xc7H\x14\x00\x00\u07d4\xd6\xfc\x04F\u01a8\xd4\n\xe3U\x1d\xb7\xe7\x01\xd1\xfa\x87nJI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\x03\u01a4\xf1\x1d`\x19Ey\u054c'f\xa7\xef\x16\xc3\n)\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\x05%\x19uj\xf4%\x90\xf1S\x91\xb7#\xa0?\xa5d\xa9Q\x89\xfa61H\r\x01\xfd\x80\x00\u07d4\xd7\na+\xd6\u0769\xea\xb0\xdd\xdc\xffJ\xafA\"\u04cf\xea\xe4\x89\x1dF\x01b\xf5\x16\xf0\x00\x00\u07d4\xd7\n\xd2\xc4\xe9\uefe67\xefV\xbdHj\u04a1\xe5\xbc\xe0\x93\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\x14\f\x8eZC\a\xfa\xb0\xcc'\xba\u0752\x95\x01\x8b\xf8yp\x89\x05\xf1\x01kPv\xd0\x00\x00\u07d4\xd7\x16J\xa2a\xc0\x9a\u0672\xb5\x06\x8dE>\xd8\xebj\xa10\x83\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd7\x1eC\xa4Qw\xadQ\xcb\xe0\xf7!\x84\xa5\xcbP9\x17(Z\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\x1f\xb10\xf0\x15\fVRi\xe0\x0e\xfbC\x90+R\xa4U\xa6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\"W8\xdc\xf3W\x848\xf8\xe7\u0233\x83~B\xe0J&/\x89\x18+\x8c\ubec3\xaa\x00\x00\u07d4\xd7'MP\x80M\x9cw\u0693\xfaH\x01V\xef\xe5{\xa5\x01\u0789i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xd71\xbbk_<79^\t\u03ac\xcd\x14\xa9\x18\xa6\x06\a\x89\x89\u0556{\xe4\xfc?\x10\x00\x00\xe0\x94\xd7>\xd2\u0645\xb5\xf2\x1bU\xb2td;\xc6\xda\x03\x1d\x8e\u074d\x8a\nm\xd9\f\xaeQ\x14H\x00\x00\u07d4\xd7D\xac~S\x10\xbeijc\xb0\x03\xc4\v\xd097\x05a\u0189Z\x87\xe7\xd7\xf5\xf6X\x00\x00\xe0\x94\xd7Jn\x8dj\xab4\u0385\x97h\x14\xc12{\xd6\xea\a\x84\u048a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xd7ZP*[gr\x87G\x0fe\u016aQ\xb8|\x10\x15\x05r\x8910\xb4dc\x85t\x00\x00\u07d4\xd7m\xba\xeb\xc3\rN\xf6{\x03\xe6\xe6\xec\xc6\xd8N\x00MP-\x89mv\xb9\x18\x8e\x13\x85\x00\x00\u07d4\xd7q\xd9\xe0\u028a\b\xa1\x13wW1CN\xb3'\x05\x99\xc4\r\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xd7x\x8e\xf2\x86X\xaa\x06\xccS\xe1\xf3\xf0\xdeX\xe5\xc3q\xbex\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xd7x\x92\xe2';#]v\x89\xe40\xe7\xae\ud73c\xe8\xa1\xf3\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u05c1\xf7\xfc\t\x18F\x11V\x85p\xb4\x98n,r\x87+~\u0409\x01\x15\x95a\x06]]\x00\x00\u07d4\u05c5\xa8\xf1\x8c8\xb9\xbcO\xfb\x9b\x8f\xa8\xc7r{\xd6B\xee\x1c\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u05ce\xcd%\xad\xc8k\xc2\x05\x1d\x96\xf6Sd\x86kB\xa4&\xb7\x89\xd20X\xbf/&\x12\x00\x00\xe0\x94\u05cf\x84\xe3\x89D\xa0\xe0%_\xae\xceH\xbaIP\u053d9\u048a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\u05d4\x83\xf6\xa8DO%I\xd6\x11\xaf\xe0,C-\x15\xe1\x10Q\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u05d85\xe4\x04\xfb\x86\xbf\x84_\xba\t\rk\xa2^\f\x88f\xa6\x89\x82\x1a\xb0\xd4AI\x80\x00\x00\u07d4\u05da\xff\x13\xba-\xa7]F$\f\xac\n$g\xc6V\x94\x98#\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\u05dd\xb5\xabCb\x1az=\xa7\x95\xe5\x89)\xf3\xdd%\xafg\u0649lj\xccg\u05f1\xd4\x00\x00\u07d4\u05e1C\x1e\xe4S\xd1\xe4\x9a\x05P\xd1%hy\xb4\xf5\xd1\x02\x01\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\u05ed\t\xc6\xd3&WhSU\xb5\xc6\uc39fW\xb4\ube42\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u05f7@\xdf\xf8\xc4Wf\x8f\xdft\xf6\xa2f\xbf\xc1\u0737#\xf9\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xd7\u0080>\u05f0\xe0\x83sQA\x1a\x8ef7\xd1h\xbc[\x05\x8a\x06A\xda\xf5\xc9\x1b\xd95\x80\x00\u07d4\xd7\xc6&]\xea\x11\x87l\x90;q\x8eL\u062b$\xfe&[\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xca\u007f\xdc\xfe\xbeE\x88\xef\xf5B\x1d\x15\"\xb6\x13(\xdf{\xf3\x89\xd8\xe6\x00\x1el0+\x00\x00\u07d4\xd7\u037dA\xff\xf2\r\xf7'\xc7\vbU\xc1\xbav\x06\x05Th\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\xd1W\xe4\xc0\xa9d7\xa6\u0485t\x1d\xd2>\xc46\x1f\xa3k\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xd2\xc6\xfc\xa8\xad\x1fu9R\x10\xb5}\xe5\xdf\xd6s\x939\t\x89\x12nr\xa6\x9aP\xd0\x00\x00\xe0\x94\xd7\xd3\xc7Y Y\x048\xb8,>\x95\x15\xbe.\xb6\xedz\x8b\x1a\x8a\f\xb4\x9bD\xba`-\x80\x00\x00\u07d4\xd7\xd7\xf2\u02a4b\xa4\x1b;0\xa3J\xeb;\xa6\x10\x10\xe2bo\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd7\xe7J\xfd\xba\xd5^\x96\u03bcZ7O,\x8bv\x86\x80\xf2\xb0\x89\x05]\xe6\xa7y\xbb\xac\x00\x00\xe0\x94\xd7\xeb\x901b'\x1c\x1a\xfa5\xfei\xe3s\"\u0224\u049b\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xd7\xeb\u0779\xf99\x87w\x9bh\x01U7T8\xdbe\xaf\xcbj\x89\x05t\x1a\xfe\xff\x94L\x00\x00\u07d4\xd7\xef4\x0ef\xb0\u05ef\xcc\xe2\n\x19\xcb{\xfc\x81\xda3\xd9N\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xd7\xf3p\u053e\xd9\xd5|oI\u0259\xder\x9e\xe5i\xd3\xf4\xe4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd7\xfa_\xfb`H\xf9o\xb1\xab\xa0\x9e\xf8{\x1c\x11\xddp\x05\xe4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd8\x06\x9f\x84\xb5!I?G\x15\x03\u007f2&\xb2_3\xb6\x05\x86\x89g\x8a\x93 b\xe4\x18\x00\x00\u0794\xd8\x15\xe1\xd9\xf4\xe2\xb5\xe5~4\x82k|\xfd\x88\x81\xb8Th\x90\x88\xf0\x15\xf2W6B\x00\x00\u07d4\xd8\x1b\xd5K\xa2\xc4Jok\xeb\x15a\u058b\x80\xb5DNm\u0189?\x17\r~\xe4\"\xf8\x9c\x80-1({\x96q\xe8\x1c\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xd8K\x92/xA\xfcWt\xf0\x0e\x14`J\xe0\xdfB\xc8U\x1e\x89\xd9o\u0390\u03eb\xcc\x00\x00\u07d4\xd8U\xb0<\xcb\x02\x9awG\xb1\xf0s\x03\xe0\xa6dy59\u0209lk\x93[\x8b\xbd@\x00\x00\u07d4\xd8_\u07af*a\xf9]\xb9\x02\xf9\xb5\xa5<\x9b\x8f\x92f\u00ec\x89l\xf6Z~\x90G(\x00\x00\u07d4\xd8q^\xf9\x17o\x85\v.0\xeb\x8e8'\a\xf7w\xa6\xfb\xe9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd8t\xb9\u07eeEj\x92\x9b\xa3\xb1\xa2~W,\x9b,\xec\u07f3\x89\t79SM(h\x00\x00\u07d4\u0613\n9\xc7sW\xc3\n\u04e0`\xf0\v\x06\x04c1\xfdb\x89,s\xc97t,P\x00\x00\u07d4\u061b\xc2q\xb2{\xa3\xabib\xc9JU\x90\x06\xae8\xd5\xf5j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0637}\xb9\xb8\x1b\xbe\x90B{b\xf7\x02\xb2\x01\xff\u009f\xf6\x18\x892m\x1eC\x96\xd4\\\x00\x00\u07d4\xd8\xcdd\xe0(N\xecS\xaaF9\xaf\xc4u\b\x10\xb9\u007f\xabV\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd8\xd6C\x84$\x9bwg\x94\x06;V\x98x\xd5\xe3\xb50\xa4\xb2\x89\t\xa0C\u0432\xf9V\x80\x00\u07d4\xd8\xd6T \xc1\x8c#'\xccZ\xf9t%\xf8W\xe4\xa9\xfdQ\xb3\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xd8\xe5\xc9g^\xf4\xde\xed&k\x86\x95o\xc4Y\x0e\xa7\u0522}\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xd8\xe8GB\x92\xe7\xa0Q`L\xa1d\xc0pw\x83\xbb(\x85\xe8\x8a\x02\xd4\xca\x05\xe2\xb4<\xa8\x00\x00\u07d4\xd8\xebxP>\xc3\x1aT\xa9\x016x\x1a\xe1\t\x00Lt2W\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd8\xee\xf4\xcfK\xeb\x01\xee \xd1\x11t\x8ba\xcbM?d\x1a\x01\x89\x94\x89#z\u06daP\x00\x00\u07d4\xd8\xf4\xba\xe6\xf8M\x91\rm}Z\xc9\x14\xb1\xe6\x83r\xf9A5\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xd8\xf6 6\xf0;v5\xb8X\xf1\x10?\x8a\x1d\x90\x19\xa8\x92\xb6\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xd8\xf6e\xfd\x8c\xd5\u00bc\xc6\xdd\xc0\xa8\xaeR\x1eM\u01aa``\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xd8\xf9$\fU\xcf\xf05RB\x80\xc0\x9e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xd8\xfe\b\x8f\xff\u0394\x8fQ7\xee#\xb0\x1d\x95\x9e\x84\xacB#\x89\f[T\xa9O\xc0\x17\x00\x00\u07d4\xd9\x0f0\t\xdbC~N\x11\u01c0\xbe\u0209os\x8de\xef\r\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd9\x10;\xb6\xb6zU\xa7\xfe\xce-\x1a\xf6-E|!x\x94m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd9\x13\xf0w\x19Iu\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xd9D\u0226\x9f\xf2\xca\x12Ii\f\x12)\xc7\x19/6%\x10b\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xd9JW\x88*Rs\x9b\xbe*\x06G\xc8\f$\xf5\x8a+O\x1c\x89H\xb5N*\xdb\xe1+\x00\x00\xe0\x94\xd9SB\x95<\x8a!\xe8\xb65\xee\xfa\u01c1\x9b\xea0\xf1pG\x8a\x13\xf0l\u007f\xfe\xf0]@\x00\x00\u07d4\xd9\\\x90\xff\xbeT\x84\x86G\x80\xb8gIJ\x83\u0212V\xd6\xe4\x89X\xe7\x92n\xe8X\xa0\x00\x00\u07d4\xd9g\x11T\x0e.\x99\x83C\xd4\xf5\x90\xb6\xfc\x8f\xac;\xb8\xb3\x1d\x89_Z@h\xb7\x1c\xb0\x00\x00\u07d4\xd9j\xc2Pt\t\u01e3\x83\xab.\xee\x18\"\xa5\xd78\xb3kV\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xd9m\xb3;{Z\x95\f>\xfa-\xc3\x1b\x10\xba\x10\xa52\uf1c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xd9wYe\xb7\x16Gfu\xa8\xd5\x13\xeb\x14\xbb\xf7\xb0|\xd1J\x8a\x01\x13.m-#\xc5\xe4\x00\x00\u07d4\xd9{\xc8J\xbdG\xc0[\xbfE{.\xf6Y\xd6\x1c\xa5\xe5\u43c9\x06\x9d\x17\x11\x9d\u0168\x00\x00\u07d4\xd9\u007fE&\u07a9\xb1c\xf8\xe8\xe3:k\u03d2\xfb\x90}\xe6\xec\x89\x0feJ\xafM\xb2\xf0\x00\x00\u07d4\xd9\u007f\xe6\xf5?*X\xf6\xd7mu*\xdft\xa8\xa2\xc1\x8e\x90t\x89\x10\xcd\xf9\xb6\x9aCW\x00\x00\u07d4\u0659\x99\xa2I\r\x94\x94\xa50\xca\xe4\xda\xf3\x85T\xf4\xddc>\x89\x06\x81U\xa46v\xe0\x00\x00\u07d4\u065d\xf7B\x1b\x93\x82\xe4,\x89\xb0\x06\xc7\xf0\x87p*\aW\xc0\x89\x1a\x05V\x90\xd9\u06c0\x00\x00\xe0\x94\u0677\x83\xd3\x1d2\xad\xc5\x0f\xa3\xea\u02a1]\x92\xb5h\xea\xebG\x8a\a3\xaf\x907L\x1b(\x00\x00\u07d4\xd9\xd3p\xfe\xc65v\xab\x15\xb3\x18\xbf\x9eX6M\u00a3U*\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xd9\xd4/\xd1>\xbdK\xf6\x9c\xac^\x9c~\x82H:\xb4m\xd7\xe9\x8a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xd9\xe2~\xb0}\xfcq\xa7\x06\x06\f\u007f\a\x928\u0293\xe8\x859\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xd9\xe3\x85~\xfd\x1e *D\x17p\xa7w\xa4\x9d\xccE\xe2\xe0\u04c9\f\x1d\xaf\x81\u0623\xce\x00\x00\u07d4\xd9\xec.\xfe\x99\xff\\\xf0\r\x03\xa81{\x92\xa2J\xefD\x1f~\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xd9\xec\x8f\xe6\x9bw\x16\xc0\x86Z\xf8\x88\xa1\x1b+\x12\xf7 \xed3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xd9\xf1\xb2d\b\xf0\xecg\xad\x1d\ro\xe2.\x85\x15\xe1t\x06$\x89\x01M\x11 \u05f1`\x00\x00\u07d4\xd9\xf5G\xf2\xc1\xde\x0e\u064aS\xd1a\xdfWc]\xd2\x1a\x00\xbd\x89\x05V\xf6L\x1f\xe7\xfa\x00\x00\u07d4\xd9\xff\x11]\x01&l\x9fs\xb0c\xc1\xc28\xef5e\xe6;6\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\xda\x06\x04N)#&\xffil\x0091h\xceF\xff\xac9\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda*\x14\xf9r@\x15\u05d0\x14\xed\x8eY\th\x1dYaH\xf1\x89\x02\xa1\x0f\x0f\x8a\x91\xab\x80\x00\u07d4\xda*\u054ew\xde\xdd\xed\xe2\x18vF\xc4e\x94Z\x8d\xc3\xf6A\x89#\xc7W\a+\x8d\xd0\x00\x00\u07d4\xda0\x17\xc1P\xdd\r\xce\u007f\u03c8\x1b\nH\xd0\xd1\xc7V\xc4\u01c9\x05k\xf9\x1b\x1ae\xeb\x00\x00\u07d4\xda4\xb2\xea\xe3\v\xaf\xe8\xda\xec\xcd\xe8\x19\xa7\x94\u0349\xe0\x95I\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdaJ_U\u007f;\xab9\n\x92\xf4\x9b\x9b\x90\n\xf3\fF\xae\x80\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdaPU7S\u007f\xfb3\xc4\x15\xfe\xc6Ni\xba\xe0\x90\xc5\xf6\x0f\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xdai\x8dd\xc6\\\u007f+,rS\x05\x9c\xd3\u0441\u0619\xb6\xb7\x89\x10\x04\xe2\xe4_\xb7\xee\x00\x00\u07d4\xdaw2\xf0/.'.\xaf(\u07d7.\xcc\r\xde\xed\x9c\xf4\x98\x89\v \xbf\xbfig\x89\x00\x00\u07d4\xdaz\xd0%\xeb\xde%\xd2\"C\u02c3\x0e\xa1\xd3\xf6JVc#\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\u0685]SG\u007fP^\xc4\xc8\xd5\u8ed1\x80\u04c6\x81\x11\x9c\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\u0687^N/<\xab\xe4\xf3~\x0e\xae\xd7\xd1\xf6\xdc\xc6\xff\xefC\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u068b\xbe\xe1\x82\xe4U\xd2\t\x8a\xcb3\x8amE\xb4\xb1~\u0636\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0698.\x96C\xff\xec\xe7#\aZ@\xfewnZ\xce\x04\xb2\x9b\x89\b\xb8\xb6\u0259\x9b\xf2\x00\x00\u07d4\u069fUF\tF\u05ff\xb5p\xdd\xecu|\xa5w;XB\x9a\x89\x1b\x84]v\x9e\xb4H\x00\x00\u07d4\u06a1\xbdz\x91H\xfb\x86\\\xd6\x12\xdd5\xf1b\x86\x1d\x0f;\u0709\xa68\xabr\xd9,\x13\x80\x00\xe0\x94\u06a6<\xbd\xa4]\u0507\xa3\xf1\xcdJtj\x01\xbb^\x06\v\x90\x8a\x01\x04\x16\u0670*\x89$\x00\x00\u07d4\u06a7v\xa6uDi\u05f9&z\x89\xb8g%\xe7@\xda\x0f\xa0\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\u06ac\x91\xc1\xe8Y\xd5\xe5~\xd3\bKP \x0f\x97f\xe2\xc5+\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u06ac\xda\xf4\"&\xd1\\\xb1\u03d8\xfa\x15\x04\x8c\u007fL\xee\xfei\x89\x10CV\x1a\x88)0\x00\x00\xe0\x94\u06b6\xbc\u06c3\xcf$\xa0\xae\x1c\xb2\x1b;[\x83\xc2\xf3\x82I'\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\u06bb\b\x89\xfc\x04)&\xb0^\xf5{% \x91\n\xbcKAI\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06bc\"PB\xa6Y,\xfa\x13\xeb\xe5N\xfaA\x04\bx\xa5\xa2\x89\x0e\x11\xfa\xd5\xd8\\\xa3\x00\x00\u07d4\xda\xc0\xc1w\xf1\x1c\\>>x\xf2\xef\xd6c\xd12!H\x85t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda\xd16\xb8\x81x\xb4\x83zlx\x0f\xeb\xa2&\xb9\x85i\xa9L\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xda\xdb\xfa\xfd\x8bb\xb9*$\xef\xd7RV\u0743\xab\xdb\u05fb\u06c9\x01\x11du\x9f\xfb2\x00\x00\u07d4\xda\xdc\x00\xaby'`\xaa4\x15i\xfa\x9f\xf5\x98&\x84\x85JJ2\x8an\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xda\xe7 \x1e\xab\x8c\x063\x02\x93\ri9)\xd0\u007f\x95\xe7\x19b\x89\x91\xae\xc0(\xb4\x19\x81\x00\x00\u07d4\xda\xed\u052d\x10{'\x1e\x89Hl\xbf\x80\xeb\xd6!\u0757Ex\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x04\xfa\xd9\u011f\x9e\x88\v\xeb\x8f\xcf\x1d:8\x90\u4cc4o\x89CZ\xe6\xcc\fX\xe5\x00\x00\u07d4\xdb\f\u01cft\u0642{\u070ads'n\xb8O\u0717b\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x12\x93\xa5\x06\xe9\f\xad*Y\xe1\xb8V\x1f^f\x96\x1ag\x88\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb\x19\xa3\x98\"06\x8f\x01w!\x9c\xb1\f\xb2Y\u0372%|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb#\xa6\xfe\xf1\xaf{X\x1ew,\xf9\x18\x82\u07b2Qo\xc0\xa7\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb$O\x97\xd9\xc4K\x15\x8a@\xed\x96\x06\xd9\xf7\xbd8\x9131\x89\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xdb(\x8f\x80\xff\xe22\u00baG\u0314\xc7c\xcfo\u0278+\r\x89\x04\x9b\x9c\xa9\xa6\x944\x00\x00\u07d4\xdb*\f\x9a\xb6M\xf5\x8d\u07f1\u06ec\xf8\xba\r\x89\xc8[1\xb4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdb4t^\u0785v\xb4\x99\xdb\x01\xbe\xb7\xc1\xec\u0685\xcfJ\xbe\x89\x04V9\x18$O@\x00\x00\u07d4\xdb?%\x8a\xb2\xa3\xc2\xcf3\x9cD\x99\xf7ZK\xd1\xd3G.\x9e\x89QP\xae\x84\xa8\xcd\xf0\x00\x00\u07d4\xdbK\xc8;\x0ek\xaa\xdb\x11V\xc5\xcf\x06\xe0\xf7!\x80\x8cR\u01c9/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xdbc\x12-\xe7\x03}\xa4\x97\x151\xfa\u9bc5\x86x\x86\u0192\x89\x0f\x04%\xb0d\x1f4\x00\x00\u07d4\xdbl*s\xda\xc7BJ\xb0\xd01\xb6ga\x12%f\xc0\x10C\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xdbnV\f\x9b\xc6 \u053e\xa3\xa9MG\xf7\x88\v\xf4\u007f-_\x89\x04\xda\x0f\xdf\xcf\x05v\x00\x00\u07d4\xdbo\xf7\x1b=\xb0\x92\x8f\x83\x9e\x05\xa72;\xfbW\u049c\x87\xaa\x891T\xc9r\x9d\x05x\x00\x00\u07d4\xdbsF\vY\xd8\xe8PE\xd5\xe7R\xe6%Y\x87^BP.\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\xdbw\xb8\x8d\xcbq/\xd1~\xe9\x1a[\x94t\x8dr\f\x90\xa9\x94\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdb}@7\b\x1fle\xf9Gk\x06\x87\xd9\u007f\x1e\x04M\n\x1d\x89#\xc7W\a+\x8d\xd0\x00\x00\xe0\x94\u06c8.\xac\xed\xd0\xef\xf2cQ\x1b1*\u06fcY\u01b8\xb2[\x8a\x01\xedO\xdez\"6\xb0\x00\x00\u07d4\u06d3q\xb3\fL\x84NY\xe0>\x92K\xe6\x06\xa98\xd1\xd3\x10\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06e4ym\f\xebM:\x83k\x84\xc9o\x91\n\xfc\x10?[\xa0\x89\t\b\xf4\x93\xf77A\x00\x00\u07d4\u06ed\xc6\x1e\xd5\xf0F\n\u007f\x18\xe5\x1b/\xb2aM\x92d\xa0\xe0\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u06f6\xacH@'\x04\x16B\xbb\xfd\x8d\x80\xf9\xd0\xc1\xcf3\xc1\xeb\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u06fc\xbby\xbfG\x9aB\xadq\xdb\u02b7{Z\u07ea\x87,X\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xdb\xc1\xce\x0eI\xb1\xa7\x05\xd2. 7\xae\xc8x\xee\ru\xc7\x03\x89\r\x8drkqw\xa8\x00\x00\u07d4\xdb\xc1\xd0\xee+\xabS\x11@\xde\x13w\"\xcd6\xbd\xb4\xe4q\x94\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb\u015e\u0609s\u07ad1\b\x84\":\xf4\x97c\xc0P0\xf1\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u0794\xdb\xc6ie\xe4&\xff\x1a\xc8z\xd6\xebx\xc1\xd9Rq\x15\x8f\x9f\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xdb\xcb\xcdzW\ua7724\x9b\x87\x8a\xf3K\x1a\xd6B\xa7\xf1\u0449\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdb\xd5\x1c\xdf,;\xfa\xcd\xff\x10b!\xde.\x19\xadmB\x04\x14\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xdb\xd7\x1e\xfaK\x93\u0209\xe7e\x93\xde`\x9c;\x04\u02ef\xbe\b\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xdb\xf5\xf0a\xa0\xf4\x8e^ia\x879\xa7}.\xc1\x97h\xd2\x01\x89\b=lz\xabc`\x00\x00\u07d4\xdb\xf8\xb19g\xf5Q%'-\xe0V%6\xc4P\xbaVU\xa0\x89n\xf5x\xf0n\f\xcb\x00\x00\u07d4\xdb\xfb\x1b\xb4d\xb8\xa5\x8eP\r.\xd8\u0797,E\xf5\xf1\xc0\xfb\x89V\xbcu\xe2\xd61\x00\x00\x00\xe0\x94\xdc\x06~\xd3\xe1-q\x1e\xd4u\xf5\x15n\xf7\xe7\x1a\x80\xd94\xb9\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xdc\b\u007f\x93\x90\xfb\x9e\x97j\xc2:\xb6\x89TJ\tB\xec !\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xdc\x1e\xb9\xb6\xe6CQ\xf5d$P\x96E\xf8>y\xee\xe7l\xf4\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdc\x1f\x19ya_\b!@\xb8\xbbx\xc6{'\xa1\x94'\x13\xb1\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xdc#\xb2`\xfc\xc2n}\x10\xf4\xbd\x04J\xf7\x94W\x94`\xd9\u0689\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xdc)\x11\x97E\xd23s \xdaQ\xe1\x91\x00\xc9H\u0640\xb9\x15\x89\b\xacr0H\x9e\x80\x00\x00\u07d4\xdc-\x15\xa6\x9fk\xb3;$j\xef@E\aQ\xc2\xf6uj\u0489l4\x10\x80\xbd\x1f\xb0\x00\x00\u07d4\xdc=\xaeY\xed\x0f\xe1\x8bXQ\x1eo\xe2\xfbi\xb2\x19h\x94#\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xdc?\x0evr\xf7\x1f\xe7R[\xa3\v\x97U\x18: \xb9\x16j\x8a\x02\b\x9c\xf5{[>\x96\x80\x00\xe0\x94\xdcCE\u0581.\x87\n\xe9\fV\x8cg\xd2\xc5g\u03f4\xf0<\x8a\x01k5-\xa5\xe0\xed0\x00\x00\u07d4\xdcD'[\x17\x15\xba\xea\x1b\x03EsZ)\xacB\xc9\xf5\x1bO\x89?\x19\xbe\xb8\xdd\x1a\xb0\x00\x00\u07d4\xdcF\xc13%\u034e\xdf\x020\xd0h\x89d\x86\xf0\a\xbfN\xf1\x89Hz\x9a0E9D\x00\x00\u07d4\xdcQ\xb2\u071d$z\x1d\x0e[\xc3l\xa3\x15oz\xf2\x1f\xf9\xf6\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xdcS\x05\xb4\x02\n\x06\xb4\x9de||\xa3L5\xc9\x1c_,V\x8a\x01}\xf6\xc1\r\xbe\xba\x97\x00\x00\u07d4\xdcW4[8\xe0\xf0g\u0263\x1d\x9d\xea\xc5'Z\x10\x94\x93!\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdcWG}\xaf\xa4/p\\\u007f\xe4\x0e\xae\x9c\x81un\x02%\xf1\x89\x1b\x1b\x81(\xa7An\x00\x00\u07d4\xdc_Z\xd6c\xa6\xf2c2}d\xca\xc9\xcb\x13=,\x96\x05\x97\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdcp:_7\x94\xc8Ml\xb3TI\x18\xca\xe1J5\u00fdO\x89dI\xe8NG\xa8\xa8\x00\x00\xe0\x94\xdcs\x8f\xb2\x17\u03ad/iYL\b\x17\r\xe1\xaf\x10\xc4\x19\xe3\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xdcv\xe8[\xa5\v\x9b1\xec\x1e& \xbc\xe6\xe7\xc8\x05\x8c\x0e\xaf\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\u0703\xb6\xfd\rQ!1 G\a\xea\xf7.\xa0\xc8\u027e\xf9v\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u070c)\x12\xf0\x84\xa6\u0444\xaasc\x85\x13\u033c2n\x01\x02\x89F3\xbc6\xcb\xc2\xdc\x00\x00\u07d4\u0711\x1c\xf7\xdc]\u04016Vg\x05(\xe93\x8eg\x03G\x86\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0730;\xfal\x111#NV\xb7\xea|Or\x14\x87Tkz\x89Hz\x9a0E9D\x00\x00\xe0\x94\u0736M\xf47X\xc7\u03d7O\xa6`HO\xbbq\x8f\x8cg\xc1\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xdc\xc5-\x8f\x8d\x9f\xc7B\xa8\xb8'g\xf0US\x87\xc5c\xef\xff\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xdc\xcb7\x0e\u058a\xa9\"(0C\xef|\xad\x1b\x9d@?\xc3J\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdc\u0324 E\xec>\x16P\x8b`?\xd96\xe7\xfd}\xe5\xf3j\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xdc\xd1\fU\xbb\x85OuD4\xf1!\x9c,\x9a\x98\xac\xe7\x9f\x03\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xdc\u057c\xa2\x00S\x95\xb6u\xfd\xe5\x03VY\xb2k\xfe\xfcI\xee\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xdc\u06fdN&\x04\xe4\x0e\x17\x10\xccg0(\x9d\xcc\xfa\u04c9-\x89\xf9]\xd2\xec'\xcc\xe0\x00\x00\u07d4\xdc\xe3\f1\xf3\xcafr\x1e\xcb!<\x80\x9a\xabV\x1d\x9bR\xe4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdc\xf39eS\x13\x80\x161h\xfc\x11\xf6~\x89\xc6\xf1\xbc\x17\x8a\x89\x12'v\x854\x06\xb0\x80\x00\u07d4\xdc\xf6\xb6W&n\x91\xa4\xda\xe6\x03=\xda\xc1S2\u074d+4\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xdc\xf9q\x9b\xe8|oFum\xb4\x89\x1d\xb9\xb6\x11\xd2F\x9cP\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xdc\xff\xf3\xe8\xd2<*4\xb5k\u0473\xbdE\u01d3tC\"9\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xdd\x04\xee\xe7N\v\xf3\f?\x8dl,\u007fR\xe0Q\x92\x10\u07d3\x89\x04V9\x18$O@\x00\x00\xe0\x94\xdd&\xb4)\xfdC\xd8N\xc1y\x82S$\xba\u057f\xb9\x16\xb3`\x8a\x01\x16\xbf\x95\xbc\x842\x98\x00\x00\u07d4\xdd*#:\xde\xdef\xfe\x11&\xd6\xc1h#\xb6*\x02\x1f\xed\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xdd+\u07e9\x17\xc1\xf3\x10\xe6\xfa5\xaa\x8a\xf1i9\xc23\xcd}\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xdd5\xcf\xdb\u02d93\x95Sz\xec\xc9\xf5\x90\x85\xa8\xd5\u0776\xf5\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xddG\x18\x9a>d9qg\xf0b\x0eHEe\xb7b\xbf\xbb\xf4\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4\xddM\xd6\xd3`3\xb0co\u030d\t8`\x9fM\xd6OJ\x86\x89\x03@\xaa\xd2\x1b;p\x00\x00\u07d4\xddO_\xa2\x11\x1d\xb6\x8fk\xde5\x89\xb60)9[i\xa9-\x89\b\x96=\xd8\xc2\xc5\xe0\x00\x00\xe0\x94\xddc\x04/%\xed2\x88J\xd2n:\xd9Y\xeb\x94\xea6\xbfg\x8a\x04\x84\xd7\xfd\xe7\u0553\xf0\x00\x00\u07d4\xdde\xf6\xe1qc\xb5\xd2\x03d\x1fQ\xcc{$\xb0\x0f\x02\xc8\xfb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xddl\x06!\x93\xea\xc2=/\xdb\xf9\x97\xd5\x06:4k\xb3\xb4p\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdd{\u0366Y$\xaa\xa4\x9b\x80\x98J\xe1su\x02X\xb9(G\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdd\u007f\xf4A\xbao\xfe6q\xf3\xc0\u06bb\xff\x18#\xa5\x043p\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u0742T\x12\x1an\x94/\xc9\b(\xf2C\x1fQ\x1d\xad\u007f2\u6263\x9b)\xe1\xf3`\xe8\x00\x00\xe0\x94\u074a\xf9\xe7vR#\xf4DoD\xd3\xd5\t\x81\x9a==\xb4\x11\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\u0755\xdb\xe3\x0f\x1f\x18w\xc5\xddv\x84\xae\xef0*\xb6\x88Q\x92\x8a\x01\xc5\xd8\xd6\xeb>2P\x00\x00\xe0\x94\u0756|L_\x8a\xe4~&o\xb4\x16\xaa\u0456N\xe3\xe7\xe8\u00ca\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\u075bHZ;\x1c\xd3:j\x9cb\xf1\xe5\xbe\xe9'\x01\x85m%\x89\f3\x83\xed\x03\x1b~\x80\x00\xe0\x94\u0763q\xe6\x00\xd3\x06\x88\xd4q\x0e\b\x8e\x02\xfd\xf2\xb9RM_\x8a\x01w\"J\xa8D\xc7 \x00\x00\u07d4\u0764\xed*X\xa8\xdd \xa72u4{X\rq\xb9[\xf9\x9a\x89\x15\xa1<\xc2\x01\xe4\xdc\x00\x00\xe0\x94\u0764\xff}\xe4\x91\u0187\xdfEt\xdd\x1b\x17\xff\x8f$k\xa3\u044a\x04&\x84\xa4\x1a\xbf\xd8@\x00\x00\u07d4\u076bkQ\xa9\x03\v@\xfb\x95\xcf\vt\x8a\x05\x9c$\x17\xbe\u01c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\u076bu\xfb/\xf9\xfe\u02c8\xf8\x94vh\x8e+\x00\xe3g\xeb\xf9\x8a\x04\x1b\xad\x15^e\x12 \x00\x00\xe0\x94\u076b\xf1<<\x8e\xa4\xe3\xd7=x\xecqz\xfa\xfaC\x0eTy\x8a\b\xcf#\xf9\t\xc0\xfa\x00\x00\x00\u07d4\u076c1*\x96UBj\x9c\f\x9e\xfa?\xd8%Y\xefE\x05\xbf\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\u076ck\xf4\xbb\xdd}Y}\x9chm\x06\x95Y;\xed\xcc\xc7\xfa\x89.\xe4IU\b\x98\xe4\x00\x00\xe0\x94\u077d+\x93,v;\xa5\xb1\xb7\xae;6.\xac>\x8d@\x12\x1a\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\u077d\xdd\x1b\xbd8\xff\xad\xe00]0\xf0 (\xd9.\x9f:\xa8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\u077e\xe6\xf0\x94\xea\xe64 \xb0\x03\xfbGW\x14*\xeal\xd0\xfd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdd\u059c[\x9b\xf5\xebZ9\xce\xe7\xc34\x1a\x12\r\x97?\xdb4\x89k\xc1K\x8f\x8e\x1b5\x00\x00\xe0\x94\xdd\xdd{\x9en\xab@\x9b\x92&:\xc2r\u0680\x1bfO\x8aW\x8ai\xe1\r\xe7fv\u0400\x00\x00\u07d4\xdd\xe6p\xd0\x169fuv\xa2-\xd0]2F\xd6\x1f\x06\xe0\x83\x89\x01s\x17\x90SM\xf2\x00\x00\xe0\x94\xdd\xe7zG@\xba\b\xe7\xf7?\xbe:\x16t\x91)1t.\xeb\x8a\x044\xfeMC\x82\xf1\u0500\x00\u07d4\xdd\xe8\xf0\xc3\x1bt\x15Q\x1d\xce\xd1\xcd}F2>K\xd1\"2\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\xdd\xe9i\xae\xf3N\xa8z\u0099\xb7Y~)+J\x01U\u030a\x89\x102\xf2YJ\x01s\x80\x00\u07d4\xdd\xf0\xcc\xe1\xfe\x99m\x91v5\xf0\a\x12\xf4\x05 \x91\xdf\xf9\xea\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdd\xf3\xadv58\x10\xbej\x89\xd71\xb7\x87\xf6\xf1q\x88a+\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xdd\xf5\x81\n\x0e\xb2\xfb.22;\xb2\u0255\t\xab2\x0f$\xac\x8a\x03\xca\\f\u067cD0\x00\x00\xe0\x94\xdd\xf9\\\x1e\x99\xce/\x9fV\x98\x05|\x19\xd5\xc9@'\xeeJn\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u0794\xdd\xfa\xfd\xbc|\x90\xf12\x0eT\xb9\x8f7F\x17\xfb\xd0\x1d\x10\x9f\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xdd\xfc\xca\x13\xf94\xf0\u03fe#\x1d\xa109\xd7\x04u\xe6\xa1\u040968\"\x16`\xa5\xaa\x80\x00\u07d4\xde\x02~\xfb\xb3\x85\x03\"n\xd8q\t\x9c\xb3\v\xdb\x02\xaf\x135\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xde\x06\xd5\xeawzN\xb1G^`]\xbc\xbfCDN\x807\xea\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xde\a\xfb[zFN;\xa7\xfb\xe0\x9e\x9a\xcb'\x1a\xf53\x8cX\x89\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xde\x11!\x82\x9c\x9a\b(@\x87\xa4?\xbd/\xc1\x14*23\xb4\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xde\x17kR\x84\xbc\xee:\x83\x8b\xa2Og\xfc|\xbfg\u05ce\xf6\x89\x02\t\xce\b\xc9b\xb0\x00\x00\u07d4\xde!\"\x93\xf8\xf1\xd21\xfa\x10\xe6\tG\rQ,\xb8\xff\xc5\x12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde0\xe4\x9eZ\xb3\x13!M/\x01\u072b\u0389@\xb8\x1b\x1cv\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xde3\xd7\b\xa3\xb8\x9e\x90\x9e\xafe;0\xfd\u00e5\xd5\u0334\xb3\x89\t\x9c\x88\"\x9f\xd4\xc2\x00\x00\u07d4\xde7B\x99\xc1\xd0}ySs\x85\x19\x0fD.\xf9\xca$\x06\x1f\x89\a?u\u0460\x85\xba\x00\x00\u07d4\xdeB\xfc\xd2L\xe4#\x93\x830CgY_\x06\x8f\fa\a@\x89\x02r*p\xf1\xa9\xa0\x00\x00\u07d4\xdeP\x86\x8e\xb7\xe3\xc7\x197\xecs\xfa\x89\u074b\x9e\xe1\rE\xaa\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xdeU\xde\x04X\xf8P\xb3~Mx\xa6A\xdd.\xb2\u074f8\u0389\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xde[\x00_\xe8\u06ae\x8d\x1f\x05\xde>\xda\x04 f\xc6\xc4i\x1c\x89;\xa1\x91\v\xf3A\xb0\x00\x00\u07d4\xdea-\a$\xe8N\xa4\xa7\xfe\xaa=!B\xbd^\xe8-2\x01\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdem61\x06\xccb8\xd2\xf0\x92\xf0\xf07!6\xd1\xcdP\u018a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xde}\xee\"\x0f\x04W\xa7\x18}V\xc1\xc4\x1f.\xb0\n\xc5`!\x89\"%\xf3\x9c\x85\x05*\x00\x00\u07d4\u0782\u030dJ\x1b\xb1\xd9CC\x92\x96[>\x80\xba\xd3\xc0=O\x89P\x18nu\u0797\xa6\x00\x00\u07d4\u0797\xf43\a\x00\xb4\x8cImC|\x91\xca\x1d\xe9\u0130\x1b\xa4\x89\x9d\xcc\x05\x15\xb5n\f\x00\x00\u07d4\u079e\xffLy\x88\x11\xd9h\xdc\xcbF\r\x9b\x06\x9c\xf3\x02x\xe0\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\u07b1\xbc4\xd8mJM\xde%\x80\u063e\xaf\aN\xb0\xe1\xa2D\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\u07b2I]j\xca{*j-\x13\x8bn\x1aB\xe2\xdc1\x1f\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\u07b9rTGL\r/Zyp\xdc\xdb/R\xfb\x10\x98\xb8\x96\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u07b9\xa4\x9aC\x870 \xf0u\x91\x85\xe2\v\xbbL\U000c1ecf\x89\vx\xed\xb0\xbf.^\x00\x00\u07d4\u07bb\u0743\x1e\x0f \xaen7\x82R\xde\xcd\xf9/|\xf0\xc6X\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde\xc3\xee\xc2d\nu,Fn+~~\u616f\xe9\xacA\xf4\x89G\u0257SYk(\x80\x00\u07d4\xde\xc8#s\xad\xe8\xeb\xcf*\xcbo\x8b\xc2AM\u05eb\xb7\rw\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xde\u0221\xa8\x98\xf1\xb8\x95\xd80\x1f\xe6J\xb3\xad]\xe9A\xf6\x89\x89*\xb4\xf6~\x8as\x0f\x80\x00\u07d4\xde\u025e\x97/\xcaqwP\x8c\x8e\x1aG\xac\"\xd7h\xac\xab|\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xde\xd8w7\x84\a\xb9Nx\x1cN\xf4\xaf|\xfc[\xc2 \xb5\x16\x89\x141y\xd8i\x11\x02\x00\x00\u07d4\xde\xe9B\xd5\xca\xf5\xfa\xc1\x14!\xd8k\x01\vE\x8e\\9)\x90\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xde\xee&\x89\xfa\x90\x06\xb5\x9c\xf2\x85#}\xe5;:\u007f\xd0\x148\x89\x18ey\xf2\x9e %\x00\x00\u07d4\xde\xfd\xdf\u055b\x8d,\x15N\xec\xf5\xc7\xc1g\xbf\v\xa2\x90]>\x89\x05\x12\xcb^&GB\x00\x00\u07d4\xde\xfe\x91A\xf4pE\x99\x15\x9d{\"=\xe4+\xff\xd8\x04\x96\xb3\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xdf\t\x8f^N=\xff\xa5\x1a\xf27\xbd\xa8e,Os\ud726\x89\x1b6\xa6DJ>\x18\x00\x00\xe0\x94\xdf\r\ba{\xd2R\xa9\x11\u07cb\xd4\x1a9\xb8=\u07c0\x96s\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xdf\x0f\xf1\xf3\xd2z\x8e\xc9\xfb\x8fk\f\xb2T\xa6;\xba\x82$\xa5\x89\xec\xc5 )E\xd0\x02\x00\x00\u07d4\xdf\x1f\xa2\xe2\x0e1\x98^\xbe,\x0f\f\x93\xb5L\x0f\xb6z&K\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xdf!\x1c\xd2\x12\x88\xd6\xc5o\xaef\xc3\xffTb]\u0531T'\x89\x87\x86\xcdvN\x1f,\x00\x00\u07d4\xdf#k\xf6\xab\xf4\xf3)7\x95\xbf\f(q\x8f\x93\u3c73k\x89Hz\x9a0E9D\x00\x00\u07d4\xdf1\x02_VI\xd2\xc6\xee\xa4\x1e\u04fd\xd3G\x1ay\x0fu\x9a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xdf7\xc2.`:\xed\xb6\nbrS\xc4}\x8b\xa8f\xf6\xd9r\x8a\x05\x15\n\xe8J\x8c\xdf\x00\x00\x00\u07d4\xdf;r\u017dq\u0501N\x88\xa6#!\xa9=@\x11\xe3W\x8b\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdf?W\xb8\xeed4\xd0G\"=\xeft\xb2\x0fc\xf9\xe4\xf9U\x89\r\x94b\xc6\xcbKZ\x00\x00\u07d4\xdfD\xc4\u007f\xc3\x03\xacv\xe7O\x97\x19L\xcag\xb5\xbb<\x02?\x89 \t\xc5\u023fo\xdc\x00\x00\u07d4\xdfG\xa6\x1brSQ\x93\xc5a\xcc\xccu\xc3\xf3\xce\b\x04\xa2\x0e\x89\x15\x93\\\vN=x\x00\x00\u07d4\xdfG\xa8\xef\x95\xf2\xf4\x9f\x8eoX\x18AT\x14]\x11\xf7'\x97\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xdfS\x003F\xd6\\^zdk\xc04\xf2\xb7\xd3/\xcb\xe5j\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xdfW5:\xaf\xf2\xaa\xdb\n\x04\xf9\x01N\x8d\xa7\x88N\x86X\x9c\x89\bH\x86\xa6nO\xb0\x00\x00\u07d4\xdf`\xf1\x8c\x81*\x11\xedN'v\xe7\xa8\x0e\xcf^S\x05\xb3\u05890\xca\x02O\x98{\x90\x00\x00\u07d4\xdfd\x85\xc4)z\xc1R\xb2\x89\xb1\x9d\xde2\xc7~\xc4\x17\xf4}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xdff\n\x91\u06b9\xf70\xf6\x19\rP\xc89\x05aP\aV\u0289lk\x93[\x8b\xbd@\x00\x00\u07d4\xdfn\xd6\x00jj\xbe\x88n\xd3=\x95\xa4\xde(\xfc\x12\x189'\x891T\xc9r\x9d\x05x\x00\x00\u07d4\u07c5\x10y>\xee\x81\x1c-\xab\x1c\x93\xc6\xf4G?0\xfb\xef[\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u07cdH\xb1\xeb\a\xb3\xc2\x17y\x0el-\xf0M\xc3\x19\xe7\xe8H\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\u07e6\xb8\xb8\xad1\x84\xe3W\xda()Q\u05d1a\u03f0\x89\xbc\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\u07ef1\xe6\"\xc0=\x9e\x18\xa0\u0778\xbe`\xfb\xe3\xe6a\xbe\n\x8a\x02\x1e\x17\x1a>\xc9\xf7,\x00\x00\u07d4\u07f1bn\xf4\x8a\x1d}uR\xa5\xe0)\x8f\x1f\xc2:;H-\x89\\\xe8\x95\u0754\x9e\xfa\x00\x00\xe0\x94\u07f4\u052d\xe5/\u0301\x8a\xccz,k\xb2\xb0\x02$e\x8fx\x8a\x01\xa4 \xdb\x02\xbd}X\x00\x00\u07d4\u07fdB2\xc1|@z\x98\r\xb8\u007f\xfb\u036060\xe5\xc4Y\x89\x1d\xfc\u007f\x92I#S\x00\x00\u07d4\xdf\xcb\xdf\tEN\x1a^J@\xd3\xee\xf7\xc5\xcf\x1c\xd3\u0794\x86\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xdf\xdb\xce\xc1\x01K\x96\xda!X\xcaQ>\x9c\x8d;\x9a\xf1\xc3\u0409lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xdf\xde\xd2WK'\xd1a:}\x98\xb7\x15\x15\x9b\r\x00\xba\xab(\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xdf\xdfC9P\x8b\x0fnZ\xb1\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe0\x06\x04b\xc4\u007f\xf9g\x9b\xae\xf0qY\xca\xe0\x8c)\xf2t\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\r\x15;\x106\x91C\xf9\u007fT\xb8\xd4\xca\"\x9e\xb3\xe8\xf3$\x89\b=lz\xabc`\x00\x00\u07d4\xe0\x12\xdbE8'\xa5\x8e\x16\xc16V\b\xd3n\xd6Xr\x05\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x15G\xbaB\xfc\xaf\xaf\x93\x93\x8b\xec\xf7i\x9ft)\n\xf7O\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x16\xdc\x13\x8e%\x81[\x90\xbe?\xe9\xee\xe8\xff\xb2\xe1\x05bO\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0\x18Y\xf2B\xf1\xa0\xec`/\xa8\xa3\xb0\xb5v@\xec\x89\a^\x89\x1e\x16,\x17{\xe5\xcc\x00\x00\xe0\x94\xe0 \xe8cb\xb4\x87u(6\xa6\xde\v\xc0,\xd8\u061a\x8bj\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xe0#\xf0\x9b(\x87a,|\x9c\xf1\x98\x8e::`+3\x94\u0249lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0'\"\x13\xe8\xd2\xfd>\x96\xbdb\x17\xb2KK\xa0\x1bapy\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe0+t\xa4v(\xbe1[\x1fv\xb3\x15\x05J\xd4J\xe9qo\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xe02 \u0197\xbc\u048f&\xef\vt@J\x8b\xeb\x06\xb2\xba{\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xe05/\u07c1\x9b\xa2e\xf1L\x06\xa61\\J\xc1\xfe\x13\x1b.\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe08\x8a\xed\xdd?\xe2\xadV\xf8WH\xe8\x0eq\n4\xb7\xc9.\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0<\x00\xd0\x03\x88\xec\xbfO&=\n\xc7x\xbbA\xa5z@\u064966\xc9yd6t\x00\x00\u07d4\xe0I \xdcn\xcc\x1dn\xcc\bO\x88\xaa\n\xf5\u06d7\xbf\x89:\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xe0Ir\xa8<\xa4\x11+\xc8q\xc7-J\xe1al/\a(\u06c9\x0e\x81\xc7\u007f)\xa3/\x00\x00\u07d4\xe0O\xf5\xe5\xa7\u2bd9]\x88W\xce\x02\x90\xb5:+\x0e\xda]\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xe0P)\xac\xeb\axg[\xef\x17A\xab,\u0493\x1e\xf7\xc8K\x8a\x01\x0f\r\xba\xe6\x10\tR\x80\x00\u07d4\xe0V\xbf?\xf4\x1c&%o\xefQqf\x12\xb9\u04da\u0799\x9c\x89\x05k\xe7W\xa1.\n\x80\x00\u07d4\xe0a\xa4\xf2\xfcw\xb2\x96\u045a\xda#\x8eI\xa5\u02ce\xcb\xfap\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe0f>\x8c\xd6g\x92\xa6A\xf5nP\x03f\x01G\x88\x0f\x01\x8e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0f\x8f\xa8,\x14\xd6\xe8\xd9:S\x11>\xf2\x86/\xa8\x15\x81\xbc\x89//9\xfclT\x00\x00\x00\u07d4\xe0i\xc0\x173R\xb1\v\xf6\x83G\x19\xdb[\xed\x01\xad\xf9{\xbc\x89\x01\x064\xf8\xe52;\x00\x00\u07d4\xe0l)\xa8\x15\x17\xe0\u0507\xb6\u007f\xb0\xb6\xaa\xbcOW6\x83\x88\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xe0l\xb6)G\x04\xee\xa7C|/\xc3\xd3\as\xb7\xbf8\x88\x9a\x89\x01\x16\xdc:\x89\x94\xb3\x00\x00\u07d4\xe0q7\xae\r\x11m\x0353\xc4\uad16\xf8\xa9\xfb\tV\x9c\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\xe0v\xdb0\xabHoy\x19N\xbb\xc4]\x8f\xab\x9a\x92B\xf6T\x8a\x01\x06`~4\x94\xba\xa0\x00\x00\u07d4\xe0~\xbb\xc7\xf4\xdaAnB\xc8\xd4\xf8B\xab\xa1b3\xc1%\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x81\xca\x1fH\x82\xdb`C\u0569\x19\a\x03\xfd\xe0\xab;\xf5m\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\x83\xd3Hc\xe0\xe1\u007f\x92ky(\xed\xff1~\x99\x8e\x9cK\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\x8b\x9a\xbak\xd9\u048b\xc2\x05gy\xd2\xfb\xf0\xf2\x85Z=\x9d\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\x8b\u009c+H\xb1i\xff+\xdc\x16qLXnl\xb8\\\u03c9\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe0\x8c`11\x06\xe3\xf93O\xe6\xf7\xe7bM!\x110\xc0w\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xe0\x9ch\xe6\x19\x98\xd9\xc8\x1b\x14\xe4\xee\x80+\xa7\xad\xf6\xd7L\u06c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe0\x9f\xeauZ\xee\x1aD\xc0\xa8\x9f\x03\xb5\u07b7b\xba3\x00o\x89;\xa2\x89\xbc\x94O\xf7\x00\x00\xe0\x94\xe0\xa2T\xac\t\xb9r[\xeb\xc8\xe4`C\x1d\xd0s.\xbc\xab\xbf\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xe0\xaai6UU\xb7?(#3\xd1\xe3\f\x1b\xbd\a(T\xe8\x8a\x01{x\x83\xc0i\x16`\x00\x00\u07d4\xe0\xba\u064e\ue598\xdb\xf6\xd7`\x85\xb7\x92=\xe5uN\x90m\x89\t\r\x97/22<\x00\x00\u07d4\xe0\u012b\x90r\xb4\xe6\xe3eJI\xf8\xa8\xdb\x02jK3\x86\xa9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\u0380\xa4a\xb6H\xa5\x01\xfd\v\x82F\x90\u0206\x8b\x0eM\xe8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe0\xcfi\x8a\x053'\xeb\xd1k}w\x00\t/\xe2\xe8T$F\x89\x05*4\u02f6\x1fW\x80\x00\xe0\x94\xe0\xd21\xe1D\xec\x91\a8l|\x9b\x02\xf1p,\xea\xa4\xf7\x00\x8a\x01\x0f\r\xba\xe6\x10\tR\x80\x00\u07d4\xe0\xd7kqf\xb1\xf3\xa1+@\x91\xee+)\u078c\xaa}\a\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xe0\xe0\xb2\xe2\x9d\xdes\xafu\x98~\xe4Dl\x82\x9a\x18\x9c\x95\xbc\x89\b\x13\xcaV\x90m4\x00\x00\xe0\x94\xe0\xe9xu=\x98/\u007f\x9d\x1d#\x8a\x18\xbdH\x89\xae\xfeE\x1b\x8a\x02\r\u058a\xaf2\x89\x10\x00\x00\u07d4\xe0\xf3r4|\x96\xb5_}C\x06\x03K\xeb\x83&o\xd9\tf\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe0\xf9\x03\xc1\xe4\x8a\xc4!\xabHR\x8f=J&H\b\x0f\xe0C\x897\b\xba\xed=h\x90\x00\x00\u07d4\xe0\xff\v\xd9\x15D9\u0125\xb7#>)\x1d}\x86\x8a\xf5?3\x89\x15y!jQ\xbb\xfb\x00\x00\xe0\x94\xe1\n\xc1\x9cTo\xc2T|a\xc19\xf5\xd1\xf4Zff\u0570\x8a\x01\x02\xdao\xd0\xf7:<\x00\x00\xe0\x94\xe1\fT\x00\x88\x11?\xa6\xec\x00\xb4\xb2\u0202O\x87\x96\xe9n\u010a2\x0fE\t\xab\x1e\xc7\xc0\x00\x00\xe0\x94\xe1\x17:$})\xd8#\x8d\xf0\x92/M\xf2Z\x05\xf2\xafw\u00ca\bx\xc9]V\x0f0G\x80\x00\xe0\x94\xe1 >\xb3\xa7#\xe9\x9c\" \x11|\xa6\xaf\xebf\xfaBOa\x8a\x02\x00\uf49e2V\xfe\x00\x00\xe0\x94\xe11\xf8~\xfc^\xf0~C\xf0\xf2\xf4\xa7G\xb5Q\xd7P\xd9\xe6\x8a\x04<%\xe0\xdc\xc1\xbd\x1c\x00\x00\u07d4\xe13N\x99\x83y\xdf\xe9\x83\x17pby\x1b\x90\xf8\x0e\xe2-\x8d\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe15@\xec\xee\x11\xb2\x12\xe8\xb7u\u070eq\xf3t\xaa\xe9\xb3\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe1;=+\xbf\u073c\x87r\xa23\x15rL\x14%\x16|V\x88\x897\xf3y\x14\x1e\xd0K\x80\x00\u07d4\xe1D=\xbd\x95\xccA#\u007fa:HEi\x88\xa0Oh2\x82\x89\xd8\xd8X?\xa2\xd5/\x00\x00\u07d4\xe1F\x17\xf6\x02%\x01\xe9~{>-\x886\xaaa\xf0\xff-\xba\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe1I\xb5rl\xafm^\xb5\xbf*\xccA\xd4\xe2\xdc2\x8d\u1089i*\xe8\x89p\x81\xd0\x00\x00\xe0\x94\xe1T\xda\xea\xdbTX8\xcb\u01aa\fUu\x19\x02\xf5(h*\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\u07d4\xe1l\xe3Ya\xcdt\xbdY\r\x04\u012dJ\x19\x89\xe0V\x91\u0189\a\xea(2uw\b\x00\x00\u07d4\xe1r\xdf\xc8\xf8\f\xd1\xf8\u03459\xdc&\b \x14\xf5\xa8\xe3\u8262\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xe1w\xe0\xc2\x01\xd35\xba9V\x92\x9cW\x15\x88\xb5\x1cR#\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe1x\x12\xf6l^e\x94\x1e\x18lF\x92+n{/\x0e\xebF\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xe1\x80\u079e\x86\xf5{\xaf\xac\u05d0O\x98&\xb6\xb4\xb2c7\xa3\x89-\x04\x1dpZ,`\x00\x00\xe0\x94\xe1\x92H\x9b\x85\xa9\x82\xc1\x882F\xd9\x15\xb2)\xcb\x13 \u007f8\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xe1\x95\xbb\xc6,{tD\x04\x0e\xb9\x96#\x96Ovg\xb3v\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe2\x06\xfbs$\xe9\u07b7\x9e\x19\x904\x96\u0596\x1b\x9b\xe5f\x03\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xe2\aW\x8e\x1fM\u06cf\xf6\u0546{9X-q\xb9\x81*\u0149\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xe2\b\x81*h@\x98\xf3\xdaN\xfej\xba%bV\xad\xfe?\xe6\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe2\tT\xd0\xf4\x10\x8c\x82\xd4\u0732\x14\x8d&\xbb\xd9$\xf6\xdd$\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xe2\v\xb9\xf3\x96d\x19\xe1K\xbb\xaa\xaag\x89\xe9$\x96\u03e4y\x89\xbb\xd8%\x03\aRv\x00\x00\u07d4\xe2\r\x1b\xcbq(m\xc7\x12\x8a\x9f\xc7\xc6\xed\u007fs8\x92\xee\xf5\x896d\xf8\xe7\xc2J\xf4\x00\x00\u0794\xe2\x19\x12\x15\x98?3\xfd3\xe2,\u0522I\x00T\xdaS\xfd\u0708\xdbD\xe0I\xbb,\x00\x00\u07d4\xe2\x19\x8c\x8c\xa1\xb3\x99\xf7R\x15a\xfdS\x84\xa7\x13/\xbaHk\x897\b\xba\xed=h\x90\x00\x00\xe0\x94\xe2\x1cw\x8e\xf2\xa0\xd7\xf7Q\xea\x8c\aM\x1f\x81\"C\x86>N\x8a\x01\x1f\xc7\x0e,\x8c\x8a\xe1\x80\x00\xe0\x94\xe2)\xe7F\xa8?,\xe2S\xb0\xb0>\xb1G$\x11\xb5~W\x00\x8a\x016\x9f\xb9a(\xacH\x00\x00\u07d4\xe2+ \xc7x\x94F;\xafwL\xc2V\u057d\u06ff}\xdd\t\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe20\xfe\x1b\xff\x03\x18m\x02\x19\xf1]LH\x1b}Y\xbe(j\x89\x01\xfdt\x1e\x80\x88\x97\x00\x00\u07d4\xe27\xba\xa4\xdb\u0252n2\xa3\xd8]\x12d@-T\xdb\x01/\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe2A\t\xbe/Q=\x87I\x8e\x92j(d\x99uO\x9e\u051e\x890\x0e\xa8\xad\x1f'\xca\x00\x00\u07d4\xe2Fh<\u025d\xb7\u0125+\u02ec\xaa\xb0\xb3/k\xfc\x93\u05c9lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe2Z\x16{\x03\x1e\x84am\x0f\x01?1\xbd\xa9]\xcccP\xb9\x8a\x02\x8c*\xaa\u0243\xd0]\u0187st\xa8\xf4F\xee\xe9\x89\n\xb6@9\x12\x010\x00\x00\u07d4\xe2\x8b\x06\"Y\xe9n\xeb<\x8dA\x04\x94?\x9e\xb3%\x89<\xf5\x89Hz\x9a0E9D\x00\x00\xe0\x94\u237c\x8e\xfd^Ajv.\xc0\xe0\x18\x86K\xb9\xaa\x83({\x8a\x051\xf2\x00\xab>\x03\n\x80\x00\u07d4\xe2\x90K\x1a\xef\xa0V9\x8bb4\xcb5\x81\x12\x88\xd76\xdbg\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\u274a\xe4R\xdc\xf3\xb6\xacd^c\x04\t8UQ\xfa\xae\n\x89\x04Z\r\xa4\xad\xf5B\x00\x00\u07d4\xe2\xbb\xf8FA\xe3T\x1fl3\xe6\xedh:cZp\xbd\xe2\xec\x89\x1bA<\xfc\xbfY\xb7\x80\x00\u07d4\xe2\xcf6\n\xa22\x9e\xb7\x9d+\xf7\xca\x04\xa2z\x17\xc52\xe4\u0609\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xe2\xdf#\xf6\xea\x04\xbe\xcfJ\xb7\x01t\x8d\xc0\x961\x84U\\\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xe2\xe1\\`\xdd8\x1e:K\xe2Pq\xab$\x9aL\\Rd\u0689\u007fk\u011b\x81\xb57\x00\x00\u07d4\xe2\xe2nN\x1d\xcf0\xd0H\xccn\u03ddQ\xec\x12\x05\xa4\xe9&\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xe2\xeei\x1f#~\xe6R\x9beW\xf2\xfc\xdd=\xcf\fY\xecc\x8a\x01'r\x9c\x14h| \x00\x00\u07d4\xe2\xef\xa5\xfc\xa7\x958\xce`h\xbf1\xd2\xc5\x16\xd4\xd5<\b\xe5\x89\a\x1c\xc4\b\xdfc@\x00\x00\xe0\x94\xe2\xef\u0429\xbc@~\xce\x03\xd6~\x8e\xc8\xe9\u0483\xf4\x8d*I\x8a\x02\x99\xb3;\xf9\u0144\xe0\x00\x00\u07d4\xe2\xf4\r5\x8f^?\xe7F>\xc7\x04\x80\xbd.\u04d8\xa7\x06;\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe2\xf98=X\x10\xea{C\x18+\x87\x04\xb6+'\xf5\x92]9\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe2\xff\x9e\xe4\xb6\xec\xc1AA\xcct\xcaR\xa9\xe7\xa2\xee\x14\xd9\b\x89K\xe4\xe7&{j\xe0\x00\x00\xe0\x94\xe3\x02\x12\xb2\x01\x1b\xb5k\xdb\xf1\xbc5i\x0f:N\x0f\xd9\x05\xea\x8a\x01\xb2\u07dd!\x9fW\x98\x00\x00\u07d4\xe3\x03\x16\u007f=I`\xfe\x88\x1b2\x80\n+J\xef\xf1\xb0\x88\u0509lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3\x04\xa3/\x05\xa87btJ\x95B\x97o\xf9\xb7#\xfa1\xea\x89Ur\xf2@\xa3F \x00\x00\u07d4\xe3\bCR\x04y7d\xf5\xfc\xbee\xebQ\x0fZtJeZ\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3\t\x97L\xe3\x9d`\xaa\xdf.ig2Q\xbf\x0e\x04v\n\x10\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xe3\x1bN\xef\x18L$\xab\t\x8e6\xc8\x02qK\xd4t=\xd0\u0509\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3!\xbbJ\x94j\xda\xfd\xad\xe4W\x1f\xb1\\\x00C\u04de\xe3_\x89Udu8+L\x9e\x00\x00\u07d4\xe3&<\xe8\xafm\xb3\xe4gXE\x02\xedq\t\x12^\xae\"\xa5\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3+\x1cG%\xa1\x87TI\u93d7\x0e\xb3\xe5@b\xd1X\x00\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe3/\x95vmW\xb5\xcdK\x172\x89\u0587o\x9edU\x81\x94\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xe38@\u063c\xa7\u0698\xa6\xf3\u0416\xd8=\xe7\x8bp\xb7\x1e\xf8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe38\xe8Y\xfe.\x8c\x15UHH\xb7\\\xae\u0368w\xa0\xe82\x89a\xac\xff\x81\xa7\x8a\xd4\x00\x00\u07d4\xe3=\x98\x02 \xfa\xb2Y\xafj\x1fK8\xcf\x0e\xf3\xc6\xe2\xea\x1a\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe3=\xf4\u0380\u0336*v\xb1+\xcd\xfc\xec\xc4b\x89\x97:\xa9\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xe3?\xf9\x87T\x1d\xde\\\xde\u0a29m\xcc?3\xc3\xf2L\u008a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xe3A\v\xb7U|\xf9\x1dy\xfai\xd0\xdf\xea\n\xa0u@&Q\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe3Ad-@\u04af\xce.\x91\a\xc6py\xacz&`\bl\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe3TS\xee\xf2\xcc2\x89\x10CR\x8d\t\x84i\x80\x00\xe0\x94\xe5\x10\xd6y\u007f\xba=f\x93\x83Z\x84N\xa2\xadT\x06\x91\x97\x1b\x8a\x03\xae9\xd4s\x83\xe8t\x00\x00\u07d4\xe5\x14!\xf8\xee\"\x10\xc7\x1e\xd8p\xfea\x82v\u0215J\xfb\xe9\x89Hz\x9a0E9D\x00\x00\u07d4\xe5\x1e\xb8~\u007f\xb71\x1fR(\xc4y\xb4\x8e\u0247\x881\xacL\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5!V1\xb1BH\xd4Z%R\x96\xbe\xd1\xfb\xfa\x030\xff5\x89G\x03\xe6\xebR\x91\xb8\x00\x00\xe0\x94\xe5(\xa0\xe5\xa2g\xd6g\xe99:e\x84\xe1\x9b4\u071b\xe9s\x8a\x01/\x93\x9c\x99\xed\xab\x80\x00\x00\u07d4\xe54%\xd8\xdf\x1f\x11\xc3A\xffX\xae_\x148\xab\xf1\xcaS\u03c9\x11t\xa5\xcd\xf8\x8b\xc8\x00\x00\u07d4\xe5No\x9c\xffV\xe1\x9cF\x1e\xb4T\xf9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5A\x02SM\xe8\xf2>\xff\xb0\x93\xb3\x12B\xad;#?\xac\xfd\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xe5E\xee\x84\xeaH\xe5d\x16\x1e\x94\x82\u055b\xcf@j`,\xa2\x89dI\xe8NG\xa8\xa8\x00\x00\u07d4\xe5H\x1a\u007f\xedB\xb9\x01\xbb\xed x\x9b\u052d\xe5\r_\x83\xb9\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5Y\xb5\xfd3{\x9cUr\xa9\xbf\x9e\x0f%!\xf7\xd4F\xdb\xe4\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe5\\\x80R\n\x1b\x0fu[\x9a,\xd3\xce!Ov%e>\x8a\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe5mC\x13$\xc9)\x11\xa1t\x9d\xf2\x92p\x9c\x14\xb7ze\u034a\x01\xbc\x85\xdc*\x89\xbb \x00\x00\u07d4\xe5})\x95\xb0\xeb\xdf?<\xa6\xc0\x15\xeb\x04&\r\xbb\x98\xb7\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\u51f1j\xbc\x8at\b\x1e6\x13\xe1CB\xc03u\xbf\bG\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\x89\xfav\x98M\xb5\xec@\x04\xb4n\u8954\x92\xc3\aD\u0389\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xe5\x8d\xd228\xeen\xa7\xc2\x13\x8d8]\xf5\x00\xc3%\xf3v\xbe\x89b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xe5\x95?\xeaIq\x04\xef\x9a\xd2\xd4\xe5\x84\x1c'\x1f\a5\x19\u0089&)\xf6n\fS\x00\x00\x00\xe0\x94\u5587\x97F\x8e\xf7g\x10\x1bv\x1dC\x1f\xce\x14\xab\xff\u06f4\x8a\x01\xb3\xd9i\xfaA\x1c\xa0\x00\x00\u07d4\xe5\x97\xf0\x83\xa4i\xc4Y\x1c=+\x1d,w'\x87\xbe\xfe'\xb2\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xe5\x9b;\xd3\x00\x89?\x97#>\xf9G\xc4or\x17\xe3\x92\xf7\xe9\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5\xa3e4<\xc4\xeb\x1ew\x03h\xe1\xf1\x14Jw\xb82\xd7\xe0\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe5\xa3\xd7\xeb\x13\xb1\\\x10\x01w#m\x1b\xeb0\xd1~\xe1T \x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xaa\v\x83;\xb9\x16\xdc\x19\xa8\xddh?\x0e\xde$\x1d\x98\x8e\xba\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\u5def\x14i\x86\xc0\xff\x8f\x85\xd2.l\xc34\a}\x84\xe8$\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xb8&\x19l\x0e\x1b\xc1\x11\x9b\x02\x1c\xf6\xd2Y\xa6\x10\u0256p\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe5\xb9o\u026c\x03\xd4H\xc1a:\xc9\x1d\x15\x97\x81E\xdb\xdf\u0449\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\u5e40\u048e\xec\xe2\xc0o\xcal\x94s\x06\x8b7\u0526\xd6\xe9\x89%\xaf\u058c\xac+\x90\x00\x00\u07d4\u5eb4\xf0\xaf\u0629\u0463\x81\xb4Wa\xaa\x18\xf3\xd3\xcc\xe1\x05\x89Q\xbf\xd7\xc18x\xd1\x00\x00\u07d4\xe5\xbc\u020c;%on\xd5\xfeU\x0eJ\x18\x19\x8b\x943V\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xbd\xf3OL\xccH>L\xa50\xcc|\xf2\xbb\x18\xfe\xbe\x92\xb3\x89\x06\xd85\xa1\v\xbc\xd2\x00\x00\u07d4\xe5\u0713I\xcbR\xe1a\x19a\"\u03c7\xa3\x896\xe2\xc5\u007f4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xe38\x00\xa1\xb2\xe9k\xde\x101c\n\x95\x9a\xa0\a\xf2nQ\x89Hz\x9a0E9D\x00\x00\u07d4\xe5\xe3~\x19@\x8f,\xfb\xec\x834\x9d\u0501S\xa4\xa7\x95\xa0\x8f\x89\u3bb5sr@\xa0\x00\x00\u07d4\xe5\xed\xc7>bo]4A\xa4U9\xb5\xf7\xa3\x98\u0153\xed\xf6\x89.\xe4IU\b\x98\xe4\x00\x00\u07d4\xe5\xed\xf8\x12?$\x03\xce\x1a\x02\x99\xbe\xcfz\xactM\a_#\x89\n\xdaUGK\x814\x00\x00\u07d4\xe5\xf8\xefm\x97\x066\xb0\u072aO \x0f\xfd\xc9\xe7Z\xf1t\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe5\xfb1\xa5\xca\xeej\x96\xde9;\xdb\xf8\x9f\xbee\xfe\x12[\xb3\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe5\xfb\xe3I\x84\xb67\x19o3\x1cg\x9d\f\fG\xd84\x10\xe1\x89llD\xfeG\xec\x05\x00\x00\u07d4\xe6\tU\xdc\v\xc1V\xf6\xc4\x18I\xf6\xbdwk\xa4K\x0e\xf0\xa1\x89\x10C\x16'\xa0\x93;\x00\x00\u07d4\xe6\nU\xf2\u07d9m\u00ee\xdbil\b\xdd\xe09\xb2d\x1d\xe8\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe6\x11[\x13\xf9y_~\x95e\x02\xd5\aEg\u06b9E\xcek\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xe6\x1f(\t\x15\xc7t\xa3\x1d\"<\xf8\f\x06\x92f\xe5\xad\xf1\x9b\x89/\xb4t\t\x8fg\xc0\x00\x00\u07d4\xe6/\x98e\a\x12\xeb\x15\x87S\xd8)r\xb8\u9723\xf6\x18w\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe6/\x9d|d\xe8\xe2cZ\xeb\x88=\xd7;\xa6\x84\xee|\x10y\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xe6>xt\x14\xb9\x04\x84x\xa5\a35\x9e\xcd\xd7\xe3dz\xa6\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xe6FfXr\xe4\v\rz\xa2\xff\x82r\x9c\xaa\xba[\xc3\u8789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe6N\xf0\x12e\x8dT\xf8\xe8`\x9cN\x90#\xc0\x9f\xe8e\xc8;\x89\x01\x84\x93\xfb\xa6N\xf0\x00\x00\u07d4\xe6On\x1dd\x01\xb5l\akd\xa1\xb0\x86}\v/1\rN\x89\x02\u02edq\xc5:\xe5\x00\x00\u07d4\xe6g\xf6R\xf9W\u008c\x0ef\u04364\x17\xc8\f\x8c\x9d\xb8x\x89 \x9d\x92/RY\xc5\x00\x00\xe0\x94\xe6w\xc3\x1f\xd9\xcbr\x00u\u0724\x9f\x1a\xbc\xcdY\xec3\xf74\x8a\x01\xa6\u05be\xb1\xd4.\xe0\x00\x00\u07d4\xe6|,\x16e\u02038h\x81\x87b\x9fI\xe9\x9b`\xb2\u04fa\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xe6\x9al\xdb:\x8a}\xb8\xe1\xf3\f\x8b\x84\xcds\xba\xe0+\xc0\xf8\x8a\x03\x94\xfd\xc2\xe4R\xf6q\x80\x00\u07d4\xe6\x9d\x1c7\x8bw\x1e\x0f\xef\xf0Q\xdbi\xd9f\xacgy\xf4\xed\x89\x1d\xfaj\xaa\x14\x97\x04\x00\x00\u07d4\xe6\x9f\xcc&\xed\"_{.7\x984\xc5$\xd7\f\x175\u5f09lk\x93[\x8b\xbd@\x00\x00\u07d4\xe6\xa3\x01\x0f\x02\x01\xbc\x94\xffg\xa2\xf6\x99\xdf\xc2\x06\xf9\xe7gB\x89/\xa7\xcb\xf6dd\x98\x00\x00\u07d4\xe6\xa6\xf6\xddop\xa4V\xf4\xec\x15\xefz\xd5\xe5\u06f6\x8b\xd7\u0709\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe6\xb2\x0f\x98\n\xd8S\xad\x04\xcb\xfc\x88|\xe6`\x1ck\xe0\xb2L\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\u6cec?]M\xa5\xa8\x85}\v?0\xfcK+i+w\u05c9O%\x91\xf8\x96\xa6P\x00\x00\u07d4\xe6\xb9T_~\u0406\xe5R\x92F9\xf9\xa9\xed\xbb\xd5T\v>\x89\xcb\xd4{n\xaa\x8c\xc0\x00\x00\xe0\x94\xe6\xbc\xd3\n\x8f\xa18\xc5\xd9\xe5\xf6\xc7\xd2\u0680i\x92\x81-\u034a7\x0e\xa0\xd4|\xf6\x1a\x80\x00\x00\u07d4\xe6\xc8\x1f\xfc\xec\xb4~\xcd\xc5\\\vq\xe4\x85_>^\x97\xfc\x1e\x89\x12\x1e\xa6\x8c\x11NQ\x00\x00\u07d4\xe6\xcb&\vqmL\n\xb7&\xee\xeb\a\xc8pr\x04\xe2v\xae\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe6\xcb?1$\xc9\xc9\xcc84\xb1'K\xc33dV\xa3\x8b\xac\x89\x17+\x1d\xe0\xa2\x13\xff\x00\x00\xe0\x94\xe6\xd2\"\t\xff\u0438u\t\xad\xe3\xa8\xe2\xefB\x98y\u02c9\xb5\x8a\x03\xa7\xaa\x9e\x18\x99\xca0\x00\x00\u07d4\xe6\u051f\x86\xc2(\xf4sg\xa3^\x88l\xaa\xcb'\x1eS\x94)\x89\x16^\xc0\x9d\xa7\xa1\x98\x00\x00\u07d4\xe6\xe6!\xea\xab\x01\xf2\x0e\xf0\x83k|\xadGFL\xb5\xfd<\x96\x89\x11!\x93B\xaf\xa2K\x00\x00\u07d4\xe6\xe8\x861{jf\xa5\xb4\xf8\x1b\xf1d\xc58\xc2d5\x17e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe6\u98ddu\x0f\xe9\x949N\xb6\x82\x86\xe5\xeab\xa6\x99x\x82\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xe6\xec\\\xf0\u011b\x9c1~\x1epc\x15\uf7b7\xc0\xbf\x11\xa7\x8a\x03\xa4i\xf3F~\x8e\xc0\x00\x00\u07d4\xe6\xf5\xebd\x9a\xfb\x99Y\x9cAK'\xa9\xc9\xc8U5\u007f\xa8x\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xe6\xfe\n\xfb\x9d\xce\xdd7\xb2\xe2,E\x1b\xa6\xfe\xabg4\x803\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xe7\x10\xdc\u041b\x81\x01\xf9C{\xd9}\xb9\ns\xef\x99=\v\xf4\x89\x14\xee6\xc0Z\xc2R\x00\x00\u07d4\xe7'\xe6~\xf9\x11\xb8\x1fl\xf9\xc7?\xcb\xfe\xbc+\x02\xb5\xbf\u0189lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7.\x1d3\\\u009a\x96\xb9\xb1\xc0/\x00:\x16\xd9q\xe9\v\x9d\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xe71\x1c\x953\xf0\t,rH\xc9s\x9b[,\x86J4\xb1\u0389\x97\xf9}l\xc2m\xfe\x00\x00\u07d4\xe7;\xfe\xad\xa6\xf0\xfd\x01o\xbc\x84>\xbc\xf6\xe3p\xa6[\xe7\f\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xe7<\xcfCg%\xc1Q\xe2U\xcc\xf5!\f\xfc\xe5\xa4?\x13\xe3\x89\x01\x15NS!}\xdb\x00\x00\u07d4\xe7B\xb1\xe6\x06\x9a\x8f\xfc'\f\xc6\x1f\xa1d\xac\x15SE\\\x10]\x04\x88~\x14\x89\x06\x96\xd8Y\x00 \xbb\x00\x00\u07d4\xe7\\\x1f\xb1w\b\x9f>X\xb1\x06y5\xa6Yn\xf1s\u007f\xb5\x89\x05j\x87\x9f\xa7uG\x00\x00\u07d4\xe7\\;8\xa5\x8a?3\xd5V\x90\xa5\xa5\x97f\xbe\x18^\x02\x84\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe7a\xd2\u007f\xa3P,\xc7k\xb1\xa6\bt\x0e\x14\x03\u03dd\xfci\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xe7f\xf3O\xf1o<\xfc\xc9s!r\x1fC\xdd\xf5\xa3\x8b\f\xf4\x89T\x06\x923\xbf\u007fx\x00\x00\u07d4\xe7m\x94Z\xa8\x9d\xf1\xe4W\xaa4+1\x02\x8a^\x910\xb2\u03897\b\xba\xed=h\x90\x00\x00\u07d4\xe7s^\xc7e\x18\xfcj\xa9-\xa8qZ\x9e\xe3\xf6%x\x8f\x13\x89lM\x16\v\xaf\xa1\xb7\x80\x00\xe0\x94\xe7z\x89\xbdE\xdc\x04\xee\xb4\xe4\x1d{Ykp~nQ\xe7L\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xe7}}\uac96\u0234\xfa\a\xca;\xe1\x84\x16=Zm`l\x89\x05\x049\x04\xb6q\x19\x00\x00\u07d4\xe7\u007f\xeb\xab\xdf\b\x0f\x0f]\xca\x1d?Wf\xf2\xa7\x9c\x0f\xfa|\x89K\"\x9d(\xa8Ch\x00\x00\xe0\x94\u7025c\x06\xba\x1ek\xb31\x95,\"S\x9b\x85\x8a\xf9\xf7}\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\xe7\x81\xecs-@\x12\x02\xbb\x9b\xd18`\x91\r\xd6\u009a\xc0\xb6\x89C8t\xf62\xcc`\x00\x00\u07d4\xe7\x84\xdc\xc8s\xaa\x8c\x15\x13\xec&\xff6\xbc\x92\xea\xc6\xd4\xc9h\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe7\x91-L\xf4V,W=\xdc[q\xe3s\x10\xe3x\xef\x86\u0249\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xe7\x91\u0545\xb8\x996\xb2])\x8f\x9d5\xf9\xf9\xed\xc2Z)2\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7\x924\x9c\xe9\xf6\xf1O\x81\xd0g@\x96\xbe\xfa\x1f\x92!\xcd\xea\x89[]#J\r\xb48\x80\x00\u07d4\xe7\x96\xfdN\x83\x9bL\x95\xd7Q\x0f\xb7\xc5\xc7+\x83\xc6\xc3\xe3\u01c9\x1b\xc43\xf2?\x83\x14\x00\x00\xe0\x94\xe7\xa4/Y\xfe\xe0t\xe4\xfb\x13\xea\x9eW\xec\xf1\xccH(\"I\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xe7\xa4V\f\x84\xb2\x0e\x0f\xb5LIg\f)\x03\xb0\xa9lB\xa4\x89 j\xea\u01e9\x03\x98\x00\x00\u07d4\xe7\xa8\xe4q\xea\xfby\x8fET\xccnRg0\xfdV\xe6,}\x8965\u026d\xc5\u07a0\x00\x00\u07d4\u7f82\xc6Y<\x1e\xed\xdd*\xe0\xb1P\x01\xff \x1a\xb5{/\x89\x01\t\x10\xd4\xcd\xc9\xf6\x00\x00\u07d4\xe7\u01b5\xfc\x05\xfct\x8e[C\x81rdI\xa1\xc0\xad\x0f\xb0\xf1\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe7\xd1u$\xd0\v\xad\x82I|\x0f'\x15jd\u007f\xf5\x1d'\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xe7\xd2\x13\x94\u007f\u02d0J\xd78H\v\x1e\xed/\\2\x9f'\xe8\x89\x01\x03\u00f1\xd3\xe9\xc3\x00\x00\u07d4\xe7\xd6$\x06 \xf4,^\u06f2\xed\xe6\xae\xc4=\xa4\xed\x9bWW\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe7\xda`\x9d@\xcd\xe8\x0f\x00\xce[O\xfbj\xa9\u04304\x94\xfc\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe7\xf0oi\x9b\xe3\x1cD\vC\xb4\xdb\x05\x01\xec\x0e%&\x16D\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe7\xf4\xd7\xfeoV\x1f\u007f\xa1\xda0\x05\xfd6TQ\xad\x89\u07c9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe7\xfd\x8f\xd9Y\xae\xd2v~\xa7\xfa\x96\f\xe1\xdbS\xaf\x80%s\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe8\x0e\u007f\xef\x18\xa5\xdb\x15\xb0\x14s\xf3\xadkx\xb2\xa2\xf8\xac\u0649\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xe8\x13\u007f\xc1\xb2\xec|\xc7\x10:\xf9!\x89\x9bJ9\xe1\xd9Y\xa1\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\xe8\x1c-4l\n\xdfL\xc5g\b\xf69K\xa6\xc8\u0226J\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8,X\xc5yC\x1bg5F\xb5:\x86E\x9a\xca\xf1\u079b\x93\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xe84\xc6C\x18 \\\xa7\xddJ!\xab\xcb\b&l\xb2\x1f\xf0,\x8965\xc6 G9\u0640\x00\u07d4\xe86\x04\xe4\xffk\xe7\xf9o`\x18\xd3\xec0r\xecR]\xffk\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\xe0\x94\xe8E\xe3\x87\xc4\xcb\u07d8\"\x80\xf6\xaa\x01\xc4\x0eK\xe9X\u0772\x8a\x05K@\xb1\xf8R\xbd\xa0\x00\x00\u07d4\xe8H\xca~\xbf\xf5\xc2O\x9b\x9c1g\x97\xa4;\xf7\xc3V)-\x89\x06.\x11\\\x00\x8a\x88\x00\x00\u07d4\xe8KU\xb5%\xf1\x03\x9etK\x91\x8c\xb33$\x92\xe4^\xcaz\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe8O\x80v\xa0\xf2\x96\x9e\xcd3>\xef\x8d\xe4\x10B\x98b\x91\xf2\x89\x17k4O*x\xc0\x00\x00\u07d4\xe8d\xfe\xc0~\xd1!Je1\x1e\x11\xe3)\xde\x04\r\x04\xf0\xfd\x89Y\u0283\xf5\xc4\x04\x96\x80\x00\u07d4\xe8}\xba\xc66\xa3w!\xdfT\xb0\x8a2\xefIY\xb5\xe4\xff\x82\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xe8~\x9b\xbf\xbb\xb7\x1c\x1at\ft\xc7#Bm\xf5]\x06=\u064a\x01\xb1\x92\x8c\x00\u01e68\x00\x00\u07d4\xe8~\xacm`+A\t\xc9g\x1b\xf5{\x95\f,\xfd\xb9\x9dU\x89\x02\xb4\xf2\x19r\xec\xce\x00\x00\xe0\x94\u807b\xbeir-\x81\xef\xec\xaaH\u0455*\x10\xa2\xbf\xac\x8f\x8a\x03c\\\x9a\xdc]\xea\x00\x00\x00\u07d4\xe8\x92Is\x8b~\xce\xd7\xcbfjf\xe4s\xbcv\x82/U\t\x8d\x89\xb9\x1c\u0149lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8\xc3\u04f0\xe1\u007f\x97\xd1\xe7V\xe6\x84\xf9N\x14p\xf9\x9c\x95\xa1\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xe8\xc3\xf0E\xbb}8\xc9\xd2\U000d5c3a\x84\x92\xb2S#\t\x01\x8a\x01\xe7\xe4\x17\x1b\xf4\u04e0\x00\x00\u07d4\xe8\xccC\xbcO\x8a\xcf9\xbf\xf0N\xbf\xbfB\xaa\xc0j2\x84p\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xe8\xd9B\xd8/\x17^\xcb\x1c\x16\xa4\x05\xb1\x01C\xb3\xf4k\x96:\x89\x1e\xd2\xe8\xffm\x97\x1c\x00\x00\u07d4\xe8\u077e\xd72\xeb\xfeu@\x96\xfd\xe9\bk\x8e\xa4\xa4\xcd\xc6\x16\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe8\xder^\xca]\xef\x80_\xf7\x94\x1d1\xac\x1c.4-\xfe\x95\x89\x85~\ro\x1d\xa7j\x00\x00\u07d4\xe8\xe9\x85\x05\x86\xe9OR\x99\xabIK\xb8!\xa5\xf4\f\x00\xbd\x04\x89\xcf\x15&@\xc5\xc80\x00\x00\xe0\x94\xe8\xea\u047b\x90\xcc\u00ee\xa2\xb0\xdc\u0175\x80VUFU\xd1\u054a\x01\xa4\xab\xa2%\xc2\a@\x00\x00\u07d4\xe8\xea\xf1)D\t-\xc3Y\x9b9S\xfa|\xb1\xc9v\x1c\xc2F\x89a\x94\x04\x9f0\xf7 \x00\x00\xe0\x94\xe8\xedQ\xbb\xb3\xac\xe6\x9e\x06\x02K3\xf8hD\xc4sH\u06de\x8a\"\xf9\xea\x89\xf4\xa7\xd6\xc4\x00\x00\u07d4\xe8\xef\x10\r|\xe0\x89X2\xf2g\x8d\xf7-J\u03cc(\xb8\xe3\x89\x1b\x1bk\u05efd\xc7\x00\x00\u07d4\xe8\xf2\x99i\xe7\\e\xe0\x1c\xe3\xd8aT }\n\x9e|v\xf2\x89\xa2/\xa9\xa7:'\x19\x80\x00\u07d4\xe8\xfc6\xb0\x13\x1e\xc1 \xac\x9e\x85\xaf\xc1\f\xe7\vV\u0636\xba\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe9\n5L\xec\x04\u059e]\x96\xdd\xc0\xc5\x13\x8d=3\x15\n\xa0\x89\x1b\x1a}\u03caD\u04c0\x00\xe0\x94\xe9\x13>}1\x84]_+f\xa2a\x87\x92\xe8i1\x1a\xcff\x8a\x05\x17\xc0\xcb\xf9\xa3\x90\x88\x00\x00\u07d4\xe9\x1d\xac\x01\x95\xb1\x9e7\xb5\x9bS\xf7\xc0\x17\xc0\xb29[\xa4L\x89e\xea=\xb7UF`\x00\x00\u07d4\xe9\x1f\xa0\xba\xda\u0779\xa9~\x88\xd3\xf4\xdb|U\u05bbt0\xfe\x89\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\xe9#\xc0aw\xb3B~\xa4H\xc0\xa6\xff\x01\x9bT\xccT\x8d\x95\x89\x01\xf7\x80\x01Fg\xf2\x80\x00\xe0\x94\xe9=G\xa8\u0288]T\fNRo%\xd5\xc6\xf2\xc1\b\u0138\x8a\x17\xda:\x04\u01f3\xe0\x00\x00\x00\u07d4\xe9E\x8fh\xbb',\xb5g:\x04\xf7\x81\xb4\x03Uo\u04e3\x87\x89\x03N\x8b\x88\xce\xe2\xd4\x00\x00\u07d4\xe9IA\xb6\x03`\x19\xb4\x01j0\xc1\x03}Zi\x03\xba\xba\xad\x89*H\xac\xabb\x04\xb0\x00\x00\u07d4\xe9I[\xa5\x84'(\xc0\ud5fe7\xd0\xe4\"\xb9\x8di ,\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xe9M\xed\x99\u0735r\xb9\xbb\x1d\u02e3/m\xee\x91\xe0W\x98N\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\xe0\x94\xe9QyR}\uc951l\xa9\xa3\x8f!\\\x1e\x9c\xe77\xb4\u024a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xe9U\x91\x85\xf1f\xfc\x95\x13\xccq\x11aD\xce-\xeb\x0f\x1dK\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xe9^\x92\xbb\xc6\xde\a\xbf:f\x0e\xbf_\xeb\x1c\x8a5'\xe1\u0148\xfc\x93c\x92\x80\x1c\x00\x00\xe0\x94\xe9e\u06a3@9\xf7\xf0\xdfb7Z7\u5acar\xb3\x01\xe7\x8a\x01\x03\xfd\xde\u0373\xf5p\x00\x00\u07d4\xe9i\xea\x15\x95\xed\xc5\u0127\a\xcf\xde8\t)c2Q\xa2\xb0\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xe9k\x18N\x1f\x0fT\x92J\xc8t\xf6\v\xbfDptF\xb7+\x89\x9d\xcc\x05\x15\xb5n\f\x00\x00\xe0\x94\xe9m}L\xdd\x15U:NM1mmd\x80\xca<\xea\x1e8\x8a\x02\x95]\x02\xe1\xa15\xa0\x00\x00\u07d4\xe9n-8\x13\xef\xd1\x16_\x12\xf6\x02\xf9\u007fJb\x90\x9d\x1b;\xc0\xe9\xaa\"\u007f\x90\x89'\xcaK\xd7\x19\xf0\xb8\x00\x00\u07d4\xea,\x19}&\xe9\x8b\r\xa8>\x1br\u01c7a\x8c\x97\x9d=\xb0\x89\x01\x11du\x9f\xfb2\x00\x00\xe0\x94\xea7y\xd1J\x13\xf6\u01c5f\xbc\xde@5\x91A:b9\u06ca)\xb7d2\xb9DQ \x00\x00\u07d4\xeaN\x80\x9e&j\xe5\xf1<\xdb\u33dd\x04V\xe68m\x12t\x89\xf3\xf2\v\x8d\xfai\xd0\x00\x00\xe0\x94\xeaS\xc9T\xf4\xed\x97\xfdH\x10\x11\x1b\u06b6\x9e\xf9\x81\xef%\xb9\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xeaS\xd2ed\x85\x9d\x9e\x90\xbb\x0eS\xb7\xab\xf5`\xe0\x16,8\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xea`Ci\x12\xdek\xf1\x87\u04e4r\xff\x8fS3\xa0\xf7\xed\x06\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xea`T\x9e\xc7U?Q\x1d!I\xf2\xd4fl\xbd\x92C\xd9<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xeaf\xe7\xb8M\u037f6\xee\xa3\xe7[\x858*u\xf1\xa1]\x96\x89]\xbc\x91\x91&o\x11\x80\x00\u07d4\xeahlPW\t<\x17\x1cf\u06d9\xe0\x1b\x0e\xce\xcb0\x86\x83\x89\x14\u0768],\xe1G\x80\x00\u07d4\xeaj\xfe,\xc9(\xac\x83\x91\xeb\x1e\x16_\xc4\x00@\xe3t!\u7262\u007f\xa0c\xb2\xe2\xe6\x80\x00\u07d4\xeay\x05}\xab\xef^d\xe7\xb4O\u007f\x18d\x8e~S7\x18\u0489\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xea|Mm\xc7)\xcdk\x15|\x03\xad#|\xa1\x9a \x93F\u00c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\x81h\xfb\xf2%\xe7\x86E\x9c\xa6\xbb\x18\xd9c\xd2kPS\t\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xea\x81\u02868T\f\xd9\xd4\xd7=\x06\x0f,\xeb\xf2$\x1f\xfc>\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xea\x83\x17\x19yYB@A\xd9\xd7\xc6z>\xce\x1d\xbbx\xbbU\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xea\x85'\xfe\xbf\xa1\xad\xe2\x9e&A\x93)\u04d3\xb9@\xbb\xb7\u0709lj\xccg\u05f1\xd4\x00\x00\u07d4\xea\x8f0\xb6\xe4\xc5\xe6R\x90\xfb\x98d%\x9b\u0159\x0f\xa8\ue289\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xea\x94\xf3(\b\xa2\uf29b\xf0\x86\x1d\x1d$\x04\xf7\xb7\xbe%\x8a\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xea\xa4\\\xea\x02\xd8},\xc8\xfd\xa9CN-\x98[\xd4\x03\x15\x84\x89h\x1f\xc2\xccn+\x8b\x00\x00\xe0\x94\uac3d\x14\x83\t\x18l\xf8\xcb\xd1;r2\xd8\tZ\u02c3:\x8a\x02C\x9a\x88\x1cjq|\x00\x00\u07d4\uaed0\xd3y\x89\xaa\xb3\x1f\xea\xe5G\xe0\xe6\xf3\x99\x9c\xe6\xa3]\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xc0\x82~\xff\fn?\xf2\x8a}JT\xf6\\\xb7h\x9d{\x99\x89\x9a\xd9\u67ddGR\x00\x00\u07d4\xea\xc1H(&\xac\xb6\x11\x1e\x19\xd3@\xa4_\xb8QWk\xed`\x89\x01\xbe\x8b\xab\x04\u067e\x80\x00\xe0\x94\xea\xc1{\x81\xedQ\x91\xfb\b\x02\xaaT3s\x13\x83A\a\xaa\xa4\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xea\u00efW\x84\x92\u007f\u9958\xfcN\xec8\xb8\x10/7\xbcX\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xea\u01b9\x88BT.\xa1\v\xb7O&\xd7\xc7H\x8fi\x8bdR\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xea\xc7h\xbf\x14\xb8\xf9C.i\xea\xa8*\x99\xfb\xeb\x94\xcd\f\x9c\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4\xea\xd2\x1c\x1d\xec\u03ff\x1c\\\xd9f\x88\xa2Gki\xba\a\xceJ\x89\x03\xf2M\x8eJ\x00p\x00\x00\u07d4\xea\xd4\xd2\xee\xfbv\xab\xaeU3\x96\x1e\xdd\x11@\x04\x06\xb2\x98\xfc\x89\xd2U\xd1\x12\xe1\x03\xa0\x00\x00\u07d4\xea\xd6Rb\xed]\x12-\xf2\xb2u\x14\x10\xf9\x8c2\xd1#\x8fQ\x89\x05\x83\x17\xedF\xb9\xb8\x00\x00\u07d4\xea\xd7P\x16\u3801Pr\xb6\xb1\b\xbc\xc1\xb7\x99\xac\xf08>\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xea#\xaa\x05r\x00\xe7\xc9\xc1^\x8f\xf1\x90\xd0\xe6l\f\x0e\x83\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xea\xed\x16\xea\xf5\u06ab[\xf0)^^\a\u007fY\xfb\x82U\x90\v\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xea\xed\xcck\x8bib\xd5\xd9(\x8c\x15lW\x9dG\xc0\xa9\xfc\xff\x89\x04\x9b\x9c\xa9\xa6\x944\x00\x00\u07d4\xea\xf5#\x88Tn\xc3Z\xcaolc\x93\xd8\xd6\t\xde:K\xf3\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xeb\x10E\x8d\xac\xa7\x9eJk$\xb2\x9a\x8a\x8a\xdaq\x1b\u007f.\xb6\x89\u063beI\xb0+\xb8\x00\x00\u07d4\xeb\x1c\xea{E\u047dM\x0e*\x00{\u04ff\xb3Tu\x9e,\x16\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\xeb%H\x1f\u035c\"\x1f\x1a\xc7\xe5\xfd\x1e\u0353\a\xa1b\x15\xb8\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\xe0\x94\xeb.\xf3\u04cf\xe6R@<\xd4\xc9\xd8^\xd7\xf0h,\xd7\xc2\u078a\t\x0fSF\b\xa7(\x80\x00\x00\xe0\x94\xeb;\xddY\xdc\u0765\xa9\xbb*\xc1d\x1f\xd0!\x80\xf5\xf3e`\x8a\x01e\xc9fG\xb3\x8a \x00\x00\u07d4\xeb<\xe7\xfc8\x1cQ\xdb}_\xbdi/\x8f\x9e\x05\x8aLp=\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xebE?Z:\xdd\u074a\xb5gP\xfa\xdb\x0f\xe7\xf9M\x9c\x89\xe7\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xebO\x00\xe2\x836\xea\t\x94%\x88\ueb12\x18\x11\xc5\"\x14<\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xebR\xab\x10U4\x922\x9c\x1cT\x83:\xe6\x10\xf3\x98\xa6[\x9d\x89\b=lz\xabc`\x00\x00\u07d4\xebW\r\xba\x97R'\xb1\xc4-n\x8d\xea,V\u026d\x96\x06p\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xebc\x94\xa7\xbf\xa4\u0489\x11\u0565\xb2>\x93\xf3^4\f\"\x94\x89\x04:w\xaa\xbd\x00x\x00\x00\u07d4\xebh\x10i\x1d\x1a\xe0\u045eG\xbd\"\u03be\u0cfa'\xf8\x8a\x89\x87\x85c\x15\xd8x\x15\x00\x00\u07d4\xebvBL\x0f\u0557\xd3\xe3A\xa9d*\xd1\xee\x11\x8b+W\x9d\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xeb| +F+|\u0145]t\x84u_n&\xefC\xa1\x15\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xeb\x83\\\x1a\x91\x18\x17\x87\x8a3\xd1gV\x9e\xa3\xcd\u04c7\xf3(\x8965\u026d\xc5\u07a0\x00\x00\u07d4\ub268\x82g\t\t\xcf7~\x9ex(n\xe9{\xa7\x8dF\u0089+|\xc2\xe9\xc3\"\\\x00\x00\xe0\x94\xeb\x90\u01d3\xb3S\x97a\xe1\xc8\x14\xa2\x96q\x14\x86\x92\x19>\xb4\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xeb\x9c\xc9\xfe\bi\xd2\u06b5,\u01ea\xe8\xfdW\xad\xb3_\x9f\xeb\x89j\x93\xbb\x17\xaf\x81\xf8\x00\x00\xe0\x94\ub8c8\xb0\xda'\xc8{\x1c\xc0\xea\xc6\xc5{,Z\vE\x9c\x1a\x8a\x01p\xa0\xf5\x04\x0eP@\x00\x00\u07d4\xeb\xaa!m\xe9\xccZC\x03\x17\a\xd3o\xe6\u057e\xdc\x05\xbd\xf0\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xeb\xac+D\b\xefT1\xa1;\x85\b\xe8bP\x98!\x14\xe1E\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xeb\xb6,\xf8\xe2,\x88K\x1b(\xc6\xfa\x88\xfb\xbc\x17\x93\x8a\xa7\x87\x89+By\x84\x03\u0278\x00\x00\u07d4\xeb\xb7\xd2\xe1\x1b\u01b5\x8f\n\x8dE\xc2\xf6\xde0\x10W\n\u0211\x89\x01s\x17\x90SM\xf2\x00\x00\u07d4\xeb\xbbO,=\xa8\xbe>\xb6-\x1f\xfb\x1f\x95\x02a\u03d8\xec\u0689lk\x93[\x8b\xbd@\x00\x00\u07d4\xeb\xbdM\xb9\x01\x99R\u058b\x1b\x0fm\x8c\xf0h<\x008{\xb5\x89\x12\x04\x01V=}\x91\x00\x00\u07d4\xeb\xbe\xeb%\x91\x84\xa6\xe0\x1c\xcc\xfc\"\a\xbb\u0603xZ\xc9\n\x89!\x9b\xc1\xb0G\x83\xd3\x00\x00\u07d4\xeb\xd3V\x15j81#4=H\x84;\xff\xeda\x03\xe8f\xb3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xeb\xd3{%ec\xe3\fo\x92\x89\xa8\xe2p/\bR\x88\b3\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xeb\xe4l\xc3\xc3L2\xf5\xad\xd6\xc3\x19[\xb4\x86\xc4q>\xb9\x18\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xeb\xff\x84\xbb\xefB0q\xe6\x04\xc3a\xbb\xa6w\xf5Y=\xefN\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xec\t'\xba\xc7\xdc6f\x9c(5J\xb1\xbe\x83\xd7\xee\xc3\t4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\x0e\x18\xa0\x1d\xc4\xdc]\xaa\xe5g\xc3\xfaL\u007f\x8f\x9bY\x02\x05\x89\x11\x1f\xfe@JA\xe6\x00\x00\xe0\x94\xec\x116,\xec\x81\t\x85\xd0\xeb\xbd{sE\x14D\x98[6\x9f\x8a\x06ZNIWpW1\x80\x00\u07d4\xec,\xb8\xb97\x8d\xff1\xae\xc3\xc2.\x0em\xad\xff1J\xb5\u0749lk\x93[\x8b\xbd@\x00\x00\u07d4\xec0\xad\u0749[\x82\xee1\x9eT\xfb\x04\xcb+\xb09q\xf3k\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec;\x8bX\xa1'\x03\xe5\x81\xce_\xfd~!\xc5}\x1e\\f?\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xecHg\xd2\x17Z\xb5\xb9F\x93aYUFUF\x84\u0364`\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xecM\b\xaa.GIm\u0287\"]\xe3?+@\xa8\xa5\xb3o\x89\b\x90\xb0\xc2\xe1O\xb8\x00\x00\u07d4\xecX\xbc\r\f \xd8\xf4\x94efAS\xc5\xc1\x96\xfeY\u6f89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xec[\x19\x8a\x00\u03f5Z\x97\xb5\xd56D\xcf\xfa\x8a\x04\u04abE\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec]\xf2'\xbf\xa8]z\xd7kBn\x1c\xee\x96;\xc7\xf5\x19\u074965\u026d\xc5\u07a0\x00\x00\xe0\x94\xec_\xea\xfe!\f\x12\xbf\u0265\xd0Y%\xa1#\xf1\xe7?\xbe\xf8\x8a`\x8f\xcf=\x88t\x8d\x00\x00\x00\u07d4\xeci\x04\xba\xe1\xf6\x97\x90Y\x17\t\xb0`\x97\x83s?%s\xe3\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\xe0\x94\xecs\x11L^@o\u06fe\t\xb4\xfab\x1b\xd7\x0e\xd5N\xa1\xef\x8a\x050%\xcd!o\xceP\x00\x00\u07d4\xecs\x83=\xe4\xb8\x10\xbb\x02x\x10\xfc\x8fi\xf5D\xe8<\x12\u044965\u026d\xc5\u07a0\x00\x00\u07d4\xecu\xb4\xa4u\x13\x12\v\xa5\xf8`9\x81O\x19\x98\xe3\x81z\u00c9\t\xb0\xbc\xe2\xe8\xfd\xba\x00\x00\u07d4\xecv\xf1.W\xa6U\x04\x03?,\v\xceo\xc0;\xd7\xfa\n\u0109\xc2\x12z\xf8X\xdap\x00\x00\u0794\xec\x80\x14\xef\xc7\xcb\xe5\xb0\xceP\xf3V,\xf4\xe6\u007f\x85\x93\xcd2\x88\xf0\x15\xf2W6B\x00\x00\u07d4\xec\x82\xf5\r\x06G_hM\xf1\xb3\x92\xe0\r\xa3A\xaa\x14TD\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xec\x83\xe7\x98\u00d6\xb7\xa5^*\"$\xab\u0343K'\xeaE\x9c\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xec\x89\xf2\xb6x\xa1\xa1[\x914\xec^\xb7\fjb\a\x1f\xba\xf9\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xec\x8c\x1d{j\xac\xcdB\x9d\xb3\xa9\x1e\xe4\xc9\xeb\x1c\xa4\xf6\xf7<\x89\xe6d\x99\"\x88\xf2(\x00\x00\xe0\x94\xec\x98Q\xbd\x91rpa\x02g\xd6\x05\x18\xb5M<\xa2\xb3[\x17\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xec\x99\xe9]\xec\xe4o\xff\xfb\x17^\xb6@\x0f\xbe\xbb\b\ue6d5\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xec\xa5\xf5\x87\x92\xb8\xc6-*\xf5Vq~\xe3\xee0(\xbeM\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\xabZ\xba[\x82\x8d\xe1pS\x81\xf3\x8b\xc7D\xb3+\xa1\xb47\x892\xf5\x1e\u06ea\xa30\x00\x00\u07d4\xec\xaf3P\xb7\xce\x14M\x06\x8b\x18`\x10\x85,\x84\xdd\f\xe0\xf0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xec\xb9LV\x8b\xfeY\xad\xe6Pd_O&0lsl\xac\xe4\x89\x0e~\xeb\xa3A\vt\x00\x00\xe0\x94\xec\xbeB^g\r9\tN \xfbVC\xa9\xd8\x18\xee\xd26\u078a\x01\x0f\f\xf0d\xddY \x00\x00\xe0\x94\xec\xbe^\x1c\x9a\u04b1\xdc\xcf\n0_\xc9R/Fi\xdd:\xe7\x8a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xec\xcfz\x04W\xb5f\xb3F\xcag:\x18\x0fDA0!j\u00c9\x05k\xc7^-c\x10\x00\x00\u07d4\xec\u0466(\x025\x1aAV\x8d#\x030\x04\xac\xc6\xc0\x05\xa5\u04c9\x02\xb5\xe3\xaf\x16\xb1\x88\x00\x00\u07d4\xec\xd2v\xafd\u01dd\x1b\u0669+\x86\xb5\u835a\x95\xeb\x88\xf8\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xec\u0506\xfc\x19g\x91\xb9,\xf6\x12\xd3HaO\x91VH\x8b~\x8a\x02\x8a\x85t%Fo\x80\x00\x00\u07d4\xec\xda\xf92)\xb4^\xe6r\xf6]\xb5\x06\xfb^\xca\x00\xf7\xfc\xe6\x89W\x01\xf9m\xcc@\xee\x80\x00\u07d4\xec\xe1\x11g\vV<\u037e\xbc\xa5#\x84)\x0e\xcdh\xfe\\\x92\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xec\xe1\x15&\x82\xb7Y\x8f\xe2\xd1\xe2\x1e\xc1U3\x88T5\xac\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xec\xe1)\bw\xb5\x83\xe3a\xa2\xd4\x1b\x00\x93F\xe6'N%8\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xec\xf0]\a\xea\x02n~\xbfIA\x00#5\xba\xf2\xfe\xd0\xf0\x02\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xec\xf2L\xdd|\"\x92\x8cD\x1eiM\xe4\xaa1\xb0\xfa\xb5\x97x\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xec\xfd\x00M\x02\xf3l\xd4\u0634\xa8\xc1\xa9S;j\xf8\\\xd7\x16\x8a\x01\x0fA\xac\xb4\xbb;\x9c\x00\x00\xe0\x94\xed\x02\x06\xcb#1Q(\xf8\xca\xff&\xf6\xa3\v\x98Tg\xd0\"\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xed\x10e\xdb\u03dds\xc0O\xfcy\b\x87\r\x88\x14h\xc1\xe12\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xed\x12vQ;o\u0186(\xa7A\x85\xc2\xe2\f\xbb\xcax\x17\xbf\x89\nZ\xa8P\t\xe3\x9c\x00\x00\xe0\x94\xed\x12\xa1\xba\x1f\xb8\xad\xfc\xb2\r\xfa\x19X.RZ\xa3\xb7E$\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xed\x16\xce9\xfe\xef;\xd7\xf5\xd1b\x04^\x0fg\xc0\xf0\x00F\xbb\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xed\x1a\\C\xc5t\xd4\xe94)\x9b$\xf1G,\u071f\xd6\xf0\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xed\x1b$\xb6\x91-Q\xb34\xac\r\xe6\xe7q\xc7\xc0EF\x95\xea\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xed\x1f\x1e\x11Z\r`\xce\x02\xfb%\xdf\x01M(\x9e:\f\xbe}\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xed10\\1\x9f\x92s\u04d3m\x8f[/q\u9c72)c\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xed2z\x14\xd5\u03ed\u0641\x03\xfc\t\x99q\x8d~\xd7\x05(\xea\x89N\x10\x03\xb2\x8d\x92\x80\x00\x00\u07d4\xed<\xbc7\x82\u03bdg\x98\x9b0\\A3\xb2\xcd\xe3\"\x11\xeb\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xed@\x14S\x8c\xeefJ/\xbc\xb6\xdcf\x9fz\xb1m\v\xa5|\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xedA\u188f\\\xaa\x848\x80\xefN\x8b\b\xbdl3\x14\x1e\u07c9*\xd5\xdd\xfaz\x8d\x83\x00\x00\xe0\x94\xedK\xe0J\x05-z\u0333\xdc\u03901\x9d\xba@ \xab,h\x8a\a\xf3zp\xea\xf3b\x17\x80\x00\xe0\x94\xedR\xa2\xcc\bi\u071e\x9f\x84+\u0415|G\xa8\xe9\xb0\xc9\xff\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xed[LA\xe7b\xd9B@Cs\xca\xf2\x1e\xd4a]%\xe6\xc1\x89m-O=\x95%\xb4\x00\x00\u07d4\xed`\u012bnT\x02\x061~5\x94zc\xa9\xcak\x03\xe2\u02c9\x03\x1a\u066d\vF\u007f\x80\x00\u07d4\xedd\x1e\x066\x8f\xb0\xef\xaa\x17\x03\xe0\x1f\xe4\x8fJhS\t\xeb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xedfC\xc0\xe8\x88K-2\x11\x857\x85\xa0\x8b\xf8\xf3>\u049f\x89Hz\x9a0E9D\x00\x00\xe0\x94\xedp\xa3|\xdd\x1c\xbd\xa9tm\x93\x96X\xae*a\x81(\x85x\x8a\x02\bj\xc3Q\x05&\x00\x00\x00\u07d4\xedsFvn\x1agm\r\x06\xec\x82\x18g\xa2v\xa0\x83\xbf1\x89\u064a\t1\xcc-I\x00\x00\u07d4\xed\x86&\x16\xfc\xbf\xb3\xbe\xcbt\x06\xf7<\\\xbf\xf0\f\x94\aU\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xed\x9e\x03\f\xa7\\\xb1\u049e\xa0\x1d\rL\xdf\xdc\xcd8D\xb6\xe4\x89\x01\xac\xc1\x16\u03ef\xb1\x80\x00\xe0\x94\ud7bc\u02e4/\x98\x15\xe7\x823&m\xd6\xe85\xb6\xaf\xc3\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\ud7f1\xf5\xaf/\xbf\u007f\xfcP)\xce\xe4+p\xff\\'[\xf5\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xed\xa4\xb2\xfaY\u0584\xb2z\x81\r\xf8\x97\x8as\xdf0\x8ac\u0089\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xed\xb4s59y\xa2\x06\x87\x9d\xe1D\xc1\n:\xcf\x12\xa7'OV9a\xf57R\x9d\x89\xc7\u0789lk\x93[\x8b\xbd@\x00\x00\u07d4\xeer\x88\xd9\x10\x86\xd9\xe2\xeb\x91\x00\x14\u066b\x90\xa0-x\u00a0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xee|=\xed|(\xf4Y\xc9/\xe1;M\x95\xba\xfb\xab\x026}\x89%\xf2s\x93=\xb5p\x00\x00\xe0\x94\xee\x86} \x91k\xd2\xe9\xc9\xec\xe0\x8a\xa0C\x85\xdbf|\x91.\x8a\n\x96\x81c\xf0\xa5{@\x00\x00\u07d4\ue25b\x02\xcb\xcb99\xcda\xde\x13B\xd5\x04\x82\xab\xb6\x852\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xee\x90m}_\x17H%\x81t\xbeL\xbc8\x93\x03\x02\xab{B\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\ue5ea\x8a\u019e\xdfz\x98}mp\x97\x9f\x8e\xc1\xfb\xcaz\x94\x89\x14b\fW\xdd\xda\xe0\x00\x00\u07d4\xee\xa1\xe9y\x88\xdeu\xd8!\xcd(\xadh\"\xb2,\u0398\x8b1\x89\x1c0s\x1c\xec\x03 \x00\x00\xe0\x94\xee\u048c?\x06\x8e\tJ0K\x85<\x95\nh\t\xeb\xcb\x03\xe0\x8a\x03\xa9\u057a\xa4\xab\xf1\xd0\x00\x00\u07d4\xee\u04c4\xef-A\xd9\xd2\x03\x97NW\xc1#(\xeav\x0e\b\xea\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xee\xdflB\x80\xe6\xeb\x05\xb94\xac\xe4(\xe1\x1dB1\xb5\x90[\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xee\xe7a\x84~3\xfda\u0653\x87\xee\x14b\x86\x94\u047f\xd5%\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xee\xe9\xd0Rn\xda\x01\xe41\x16\xa3\x952-\u0689pW\x8f9\x8a\x02\x1e\x19\x99\xbb\xd5\u04be\x00\x00\u07d4\xee\xf1\xbb\xb1\xe5\xa8?\u0782H\xf8\x8e\xe3\x01\x8a\xfa-\x132\xeb\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xee\xfb\xa1-\xfc\x99gB\xdby\x04d\xca}';\xe6\xe8\x1b>\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xee\xfd\x05\xb0\xe3\xc4\x17\xd5[3C\x06\x04\x86\xcd\xd5\xe9*\xa7\xa6\x89M\x85<\x8f\x89\b\x98\x00\x00\u07d4\xef\r\xc7\xddzS\xd6\x12r\x8b\xcb\u04b2|\x19\xddM}fo\x89&A\x1c[5\xf0Z\x00\x00\u07d4\xef\x11RR\xb1\xb8E\u0345\u007f\x00-c\x0f\x1bo\xa3zNP\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xef\x1c\x04w\xf1\x18M`\xac\u02b3t\xd3tUz\n>\x10\xf3\x89\b=lz\xabc`\x00\x00\u07d4\xef,4\xbbH}7b\xc3\u0327\x82\xcc\xddz\x8f\xbb\n\x991\x89\t\xc2\x00vQ\xb2P\x00\x00\u07d4\xef5\xf6\u0531\a^j\xa19\x15\x1c\x97K/FX\xf7\x058\x89<;\xc3?\x94\xe5\r\x80\x00\u07d4\xef9\u0291s\xdf\x15S\x1ds\xe6\xb7*hKQ\xba\x0f+\xb4\x89V\xa0\xb4un\xe28\x00\x00\u07d4\xefF<&y\xfb'\x91d\xe2\f=&\x915\x87s\xa0\xad\x95\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xefG\xcf\a>6\xf2q\xd5\"\xd7\xfaNq \xadP\a\xa0\xbc\x89\x87\x86x2n\xac\x90\x00\x00\u07d4\xefa\x15[\xa0\t\xdc\u07be\xf1\v(\xd9\xda=\x1b\xc6\xc9\xce\u0509\x034-`\xdf\xf1\x96\x00\x00\u0794\xefix\x1f2\xff\xce34o,\x9a\xe3\xf0\x84\x93\xf3\xe8/\x89\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xefv\xa4\u034f\xeb\xcb\u0278\x18\xf1x(\xf8\xd94s\xf3\xf3\u02c9\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\uf4c1\x8fhM\xb0\xc3g^\xc8\x132\xb3\x18>\xcc(\xa4\x95\x89T\x06\x923\xbf\u007fx\x00\x00\xe0\x94\xef\x9fY\xae\xdaA\x8c\x14\x94h-\x94\x1a\xabI$\xb5\xf4\x92\x9a\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\uf9b1\xf0\xdb`57\x82h\x91\xb8\xb4\xbc\x169\x84\xbb@\u03495e\x9e\xf9?\x0f\xc4\x00\x00\u07d4\xef\xbdR\xf9}\xa5\xfd:g:F\xcb\xf30D{~\x8a\xad\\\x89\x05l<\x9b\x80\xa0\xa6\x80\x00\xe0\x94\xef\xc8\xcf\x19c\u0269Rg\xb2(\xc0\x86#\x98\x89\xf4\xdf\xd4g\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xef\u02ae\x9f\xf6M,\xd9[RI\xdc\xff\xe7\xfa\xa0\xa0\xc0\xe4M\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xef\xcc\xe0k\xd6\b\x9d\x0eE\x8e\xf5a\xf5\xa6\x89H\n\xfep\x00\x89 \x86\xac5\x10R`\x00\x00\u07d4\xef\xe0g]\xa9\x8a]\xdap\u0356\x19k\x87\xf4\xe7&\xb43H\x89?\x19\xbe\xb8\xdd\x1a\xb0\x00\x00\u07d4\xef\xe8\xff\x87\xfc&\x0e\agc\x8d\xd5\xd0/\xc4g.\x0e\xc0m\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xef\xeb\x19\x97\xaa\xd2w\xcc3C\x0ea\x11\xed\tCY@H\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xef\xee\xa0\x10uo\x81\xdaK\xa2[r\x17\x87\xf0X\x17\v\uff49\x01\u009c\x9c\xf7p\xef\x00\x00\u07d4\xef\xf5\x1dr\xad\xfa\xe1C\xed\xf3\xa4+\x1a\xecU\xa2\xcc\xdd\v\x90\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xef\xf8kQ#\xbc\xdc\x17\xedL\xe8\xe0[~\x12\xe5\x13\x93\xa1\xf7\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xef\xfc\x15\u41f1\xbe\xda\n\x8d\x13%\xbd\xb4\x17\"@\xdcT\n\x89\x03\x8599\xee\xe1\xde\x00\x00\xe0\x94\xf0\x11\x95\xd6W\xef<\x94.l\xb89I\xe5\xa2\v\\\xfa\x8b\x1e\x8a\x05ts\xd0]\xab\xae\x80\x00\x00\u07d4\xf0'\x96)Q\x01gB\x88\xc1\xd94g\x05=\x04\"\x19\xb7\x94\x89(\x1d\x90\x1fO\xdd\x10\x00\x00\u07d4\xf09h={=\"[\xc7\xd8\u07ed\xefc\x164A\xbeA\xe2\x89\x01\xdd\x1eK\xd8\xd1\xee\x00\x00\u07d4\xf0Jj7\x97\b\xb9B\x8dr*\xa2\xb0kw\xe8\x895\u03c9\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xf0M,\x91\xef\xb6\xe9\xc4_\xfb\xe7KCL\x8c_+\x02\x8f\x1f\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf0W\xaaf\xcav~\xde\x12J\x1c[\x9c\xc5\xfc\x94\xef\v\x017\x89p\xa2K\u02b6\xf4]\x00\x00\u07d4\xf0[\xa8\u05f6\x859\xd930\v\xc9(\x9c=\x94t\xd0A\x9e\x89\x06\xda'\x02M\xd9`\x00\x00\u07d4\xf0\\\xee\xabeA\x05dp\x99Qw<\x84E\xad\x9fN\u01d7\x89\x10C\x16'\xa0\x93;\x00\x00\xe0\x94\xf0_\xcdL\rs\xaa\x16~US\xc8\xc0\xd6\xd4\xf2\xfa\xa3\x97W\x8a\x02\xd2\xd6l1p\xb2\x98\x00\x00\u07d4\xf0g\xe1\xf1\u0583UjL\xc4\xfd\f\x03\x13#\x9f2\xc4\xcf\u060965\u026d\xc5\u07a0\x00\x00\u07d4\xf0g\xfb\x10\u07f2\x93\u962b\xe5d\xc0U\xe34\x8f\x9f\xbf\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0h\xdf\xe9]\x15\xcd:\u007f\x98\xff\xa6\x88\xb44hB\xbe&\x90\x89D\n\xd8\x19\xe0\x97L\x00\x00\xe0\x94\xf0j\x85J<]\xc3m\x1cI\xf4\xc8}m\xb33\xb5~J\u074a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf0y\xe1\xb1&_P\xe8\u0229\x8e\xc0\u01c1^\xb3\xae\xac\x9e\xb4\x89\x01\x16\xdc:\x89\x94\xb3\x00\x00\xe0\x94\xf0{\xd0\xe5\xc2\xcei\xc7\u0127$\xbd&\xbb\xfa\x9d*\x17\xca\x03\x8a\x01@a\xb9\xd7z^\x98\x00\x00\xe0\x94\xf0\x83*k\xb2U\x03\xee\xcaC[\xe3\x1b\v\xf9\x05\xca\x1f\xcfW\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xf0\x9b>\x87\xf9\x13\xdd\xfdW\xae\x80I\xc71\u06e9\xb66\xdf\u00c9 \xf5\xb1\uab4d\x80\x00\x00\u07d4\xf0\xb14\v\x99oo\v\xf0\xd9V\x1c\x84\x9c\xaf\u007fD0\xbe\xfa\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf0\xb1\xf9\xe2x2\xc6\xdei\x14\xd7\n\xfc#\x8ct\x99\x95\xac\xe4\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xf0\xb4i\xea\xe8\x9d@\f\xe7\xd5\xd6j\x96\x95\x03p6\xb8\x89\x03\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xf0\xb9\u0583\u03a1+\xa6\x00\xba\xac\xe2\x19\xb0\xb3\xc9~\x8c\x00\xe4\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf0\xbe\x0f\xafMy#\xfcDF\"\u0458\f\xf2\u0650\xaa\xb3\a\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0\xc0\x81\xdaR\xa9\xae6d*\xdf^\b _\x05\xc5Ah\xa6\x89\x06\x04o7\xe5\x94\\\x00\x00\u07d4\xf0\xc7\r\rm\xabvc\xaa\x9e\xd9\xce\xeaV~\xe2\u01b0'e\x89qC\x8a\u0167\x91\xa0\x80\x00\u07d4\xf0\xcb\xef\x84\xe1ic\x00\x98\xd4\xe3\x01\xb2\x02\b\xef\x05\x84j\u0249\x0e\v\x83EPkN\x00\x00\u07d4\xf0\xd2\x16c\u0630\x17n\x05\xfd\xe1\xb9\x0e\xf3\x1f\x850\xfd\xa9_\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xf0\xd5\xc3\x1c\xcbl\xbe0\xc7\xc9\xea\x19\xf2h\xd1Y\x85\x1f\x8c\x9c\x8a\x03\x89O\x0eo\x9b\x9fp\x00\x00\u07d4\xf0\xd6L\xf9\xdf\tt\x113\xd1pH_\xd2K\x00P\x11\xd5 \x89\x1b\b\x93A\xe1O\xcc\x00\x00\u07d4\xf0\xd8X\x10^\x1bd\x81\x01\xac?\x85\xa0\xf8\"+\xf4\xf8\x1dj\x89 \x86\xac5\x10R`\x00\x00\u07d4\xf0\xdcC\xf2\x05a\x91'P{+\x1c\x1c\xfd\xf3-(1\t \x89\x10^\xb7\x9b\x94\x17\b\x80\x00\u07d4\xf0\xe1\u07e4*\u07ac/\x17\xf6\xfd\xf5\x84\xc9Hb\xfdV3\x93\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf0\xe2d\x9c~j?,]\xfe3\xbb\xfb\xd9'\xca<5\nX\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf0\xe7\xfb\x9eB\nS@\xd56\xf4\x04\b4O\xea\xef\xc0j\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf1\x04b\xe5\x8f\xcc\a\U000d5121\x87c\x94Q\x16~\x85\x92\x01\x89\t4\xdd]3\xbc\x97\x00\x00\xe0\x94\xf1\x06a\xff\x94\x14\x0f >zH%rCy8\xbe\xc9\xc3\xf7\x8a\x04<3\xc1\x93ud\x80\x00\x00\u0794\xf1\x14\xff\r\x0f$\xef\xf8\x96\xed\xdeTq\u07a4\x84\x82J\x99\xb3\x88\xbe -j\x0e\xda\x00\x00\u07d4\xf1\x16\xb0\xb4h\x0fS\xabr\xc9h\xba\x80.\x10\xaa\x1b\xe1\x1d\u0209\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xf1\x1c\xf5\xd3cto\xeehd\xd3\xca3m\xd8\x06y\xbb\x87\xae\x8a\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xf1\x1e\x01\u01e9\xd1$\x99\x00_M\xaew\x16\tZ4\x17bw\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf1;\b0\x93\xbaVN-\xc61V\x8c\xf7T\r\x9a\x0e\xc7\x19\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xf1O\x0e\xb8m\xb0\xebhu?\x16\x91\x8e]K\x80t7\xbd>\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf1Qx\xff\xc4:\xa8\a\x0e\xce2~\x93\x0f\x80\x9a\xb1\xa5O\x9d\x89\n\xb6@9\x12\x010\x00\x00\u07d4\xf1V\xdc\v*\x98\x1e[U\xd3\xf2\xf0;\x814\xe31\u06ed\xb7\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf1]\x9dZ!\xb1\x92\x9ey\x03q\xa1\u007f\x16\xd9_\fie\\\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1^\x18,O\xbb\xady\xbd\x934\"B\xd4\xdc\xcf+\xe5\x89%\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf1bM\x98\ve3o\xea\u0166\xd5A%\x00\\\xfc\xf2\xaa\u02c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1g\xf5\x86\x8d\xcfB3\xa7\x83\x06\th,\xaf-\xf4\xb1\xb8\a\x89\x81\xe5B\xe1\xa78?\x00\x00\u07d4\xf1m\xe1\x89\x1d\x81\x96F\x13\x95\xf9\xb16&[;\x95F\xf6\xef\x89\x01\xb2\x8e\x1f\x98\xbb\u0380\x00\u07d4\xf1z\x92\xe06\x1d\xba\xce\xcd\xc5\xde\r\x18\x94\x95Z\xf6\xa9\xb6\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1z\xdbt\x0fE\u02fd\xe3\tN~\x13qo\x81\x03\xf5c\xbd\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1\x8b\x14\xcb\xf6iC6\xd0\xfe\x12\xac\x1f%\xdf-\xa0\xc0]\xbb\x89\xd8\xd4`,&\xbfl\x00\x00\u07d4\xf1\x9b98\x9dG\xb1\x1b\x8a,?\x1d\xa9\x12M\xec\xff\xbe\xfa\xf7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf1\x9f\x195\b9>M*\x12{ \xb2\x03\x1f9\xc8%\x81\u0189\xbd\xbdz\x83\xbd/l\x00\x00\u07d4\xf1\xa1\xf3 @yd\xfd<\x8f.,\u0224X\r\xa9O\x01\xea\x89ll!wU|D\x00\x00\u07d4\xf1\xb4\xec\xc65%\xf7C,=\x83O\xfe+\x97\x0f\xbe\xb8r\x12\x89\xa2\xa2@h\xfa\u0340\x00\x00\u07d4\U000753ef\xfa\x87\x94\xf5\n\xf8\xe8\x83\t\u01e6&TU\xd5\x1a\x8963\x03\"\xd5#\x8c\x00\x00\u07d4\xf1\xc8\u0129A\xb4b\x8c\rl0\xfd\xa5dR\u065c~\x1bd\x89N\x8c\xea\x1e\xdeu\x04\x00\x00\u07d4\xf1\xda@so\x99\xd5\xdf;\x06\x8a]t_\xaf\xc6F?\u0271\x89\x06\x96\xca#\x05\x8d\xa1\x00\x00\u07d4\xf1\u070a\xc8\x10B\xc6z\x9c\\c2!\xa8\xf76>e\x87\f\x9f(t$\u04a9`\x89J\xcfX\xe0rW\x10\x00\x00\u07d4\xf2B\u0684]B\u053fw\x9a\x00\xf2\x95\xb4\aP\xfeI\xea\x13\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf2RY\xa5\xc99\xcd%\x96l\x9bc\x03\xd3s\x1cS\u077cL\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf2^Lp\xbcFV2\u021eV%\xa82\xa7r/k\xff\xab\x89\xf3K\x82\xfd\x8e\x91 \x00\x00\u07d4\xf2k\xce\xdc\xe3\xfe\xad\u03a3\xbc>\x96\xeb\x10@\xdf\xd8\xff\u1809*\x03I\x19\u07ff\xbc\x00\x00\u07d4\xf2py%v\xf0]QD\x93\xff\xd1\xf5\xe8K\xecK-\xf8\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf2s,\xf2\xc1;\x8b\xb8\xe7I*\x98\x8f_\x89\xe3\x82s\xdd\u0209 \x86\xac5\x10R`\x00\x00\xe0\x94\xf2t.hY\xc5i\xd5\xf2\x10\x83Q\xe0\xbfM\xca5*H\xa8\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf2\x81:d\xc5&]\x02\x025\u02dc1\x9bl\x96\xf9\x06\xc4\x1e\x89\x12\xf99\u025e\u06b8\x00\x00\u07d4\xf2\x87\xffR\xf4a\x11z\xdb>\x1d\xaaq\x93-\x14\x93\xc6_.\x89\xc5S%\xcat\x15\xe0\x00\x00\u07d4\xf2\xab\x11au\x02D\xd0\xec\xd0H\xee\r>Q\xab\xb1C\xa2\xfd\x89B\xfe+\x90ss\xbc\x00\x00\u07d4\xf2\xb4\xab,\x94'\xa9\x01^\xf6\xee\xff\xf5\xed\xb6\x019\xb7\x19\u0449&\u06d9*;\x18\x00\x00\x00\u07d4\xf2\xc0>*8\x99\x8c!d\x87`\xf1\xe5\xae~\xa3\a}\x85\"\x89\x8f?q\x93\xab\a\x9c\x00\x00\u0794\xf2\u0090N\x9f\xa6d\xa1\x1e\xe2VV\xd8\xfd,\xc0\u0665\"\xa0\x88\xb9\x8b\xc8)\xa6\xf9\x00\x00\u07d4\xf2\xc3b\xb0\xef\x99\x1b\xc8/\xb3nf\xffu\x93*\xe8\u0742%\x89\x04\x02\xf4\xcf\xeeb\xe8\x00\x00\u07d4\xf2\xd0\xe9\x86\xd8\x14\xea\x13\xc8\xf4f\xa0S\x8cS\u0712&Q\xf0\x89J\xcfX\xe0rW\x10\x00\x00\xe0\x94\xf2\u04775w$\xecL\x03\x18[\x87\x9bc\xf5~&X\x91S\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xf2\xd5v<\xe0s\x12~,\xed\xdeo\xab\xa7\x86\xc7<\xa9AA\x8a\x01\xacB\x86\x10\x01\x91\xf0\x00\x00\xe0\x94\xf2\u055c\x89#u\x90s\xd6\xf4\x15\xaa\xf8\xeb\x06_\xf2\U000f614a\x01\xab,\xf7\xc9\xf8~ \x00\x00\u07d4\xf2\xe9\x9f\\\xbb\x83kz\xd3bGW\x1a0,\xbeKH\x1ci\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf2\xed>w%J\u02c3#\x1d\xc0\x86\x0e\x1a\x11$+\xa6'\u06c9kV\x05\x15\x82\xa9p\x00\x00\xe0\x94\xf2\xed\xde7\xf9\xa8\u00dd\u07a2My\xf4\x01WW\xd0k\xf7\x86\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xf2\xef\xe9e`\xc9\xd9{r\xbd6DxC\x88\\\x1d\x90\xc21\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf2\xfb\xb6\u0607\xf8\xb8\xcc:\x86\x9a\xba\x84\u007f=\x1fd\xfcc\x97\xaae\xfbS\xa8\xf0z\x0f\x89:\xae0\xe8\xbc\xee\x89|\xf28\x1fa\x9f\x15\x00\x00\u07d4\xf3@\x83\xec\xea8P\x17\xaa@\xbd\xd3^\xf7\xef\xfbL\xe7v-\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf3F\xd7\u0792t\x1c\b\xfcX\xa6M\xb5[\x06-\xde\x01-\x14\x89\x0f\xffk\x1fv\x1em\x00\x00\xe0\x94\xf3U\xd3\xec\f\xfb\x90}\x8d\xbb\x1b\xf3FNE\x81(\x19\v\xac\x8a\x01\v\x04n\u007f\r\x80\x10\x00\x00\u07d4\xf3m\xf0/\xbd\x89`sG\xaf\xce)i\xb9\xc4#jX\xa5\x06\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3s\xe9\u06ac\f\x86u\xf5;yz\x16\x0fo\xc04\xaek#\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf3{BeG\xa1d-\x8032H\x14\xf0\xed\xe3\x11O\xc2\x12\x89\x15\xbeat\xe1\x91.\x00\x00\u07d4\xf3{\xf7\x8cXu\x15G\x11\xcbd\r7\xeam(\xcf\xcb\x12Y\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xf3\x82\xdfX1U\xd8T\x8f?\x93D\f\xd5\xf6\x8c\xb7\x9d`&\x8a8u}\x02\u007f\xc1\xfd\\\x00\x00\xe0\x94\xf3\x82\xe4\xc2\x04\x10\xb9Q\b\x9e\x19\xba\x96\xa2\xfe\xe3\xd9\x1c\xce~\x8a\x01\x11\xfaV\xee\u00a88\x00\x00\xe0\x94\xf3\x8al\xa8\x01hS~\x97M\x14\xe1\xc3\xd19\x90\xa4L,\x1b\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\u07d4\xf3\x9a\x9dz\xa3X\x1d\xf0~\xe4'\x9a\xe6\xc3\x12\xef!\x036X\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf3\xb6h\xb3\xf1M\x92\x0e\xbc7\x90\x92\u06d8\x03\x1bg\xb2\x19\xb3\x89\n\xd6\xee\xdd\x17\xcf;\x80\x00\u07d4\U000fe679\x10<\xe7U\n\xa7O\xf1\xdb\x18\xe0\x9d\xfe2\xe0\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xc1\xab\u049d\xc5{A\xdc\x19-\x0e8M\x02\x1d\xf0\xb4\xf6\u0509\x97\xae\f\u07cf\x86\xf8\x00\x00\u07d4\xf3\xc4qm\x1e\xe5'\x9a\x86\xd0\x16:\x14a\x81\x81\xe1a6\u01c965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf3\u030b\xcbU\x94e\xf8\x1b\xfeX;\u05eb\n#\x06E;\x9e\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xf3\u0588\xf0k\xbd\xbfP\xf9\x93,AE\xcb\xe4\x8e\xcd\xf6\x89\x04\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf3\xdb\xcf\x13Z\u02dd\xee\x1aH\x9cY<\x02O\x03\u00bb\xae\u0389lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xde_&\xefj\xde\xd6\xf0m;\x91\x13F\xeep@\x1d\xa4\xa0\x89\x13:\xb3}\x9f\x9d\x03\x00\x00\u07d4\xf3\xdfc\xa9q\x99\x93308;>\xd7W\v\x96\u0101#4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf3\xe7OG\f}:?\x003x\x0fv\xa8\x9f>\xf6\x91\xe6\u02c9\xa3\xcf\xe61\xd1Cd\x00\x00\u07d4\xf3\xeb\x19H\xb9Q\xe2-\xf1ax)\xbf;\x8d\x86\x80\xeckh\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf3\xf1\xfa9\x18\xca4\xe2\xcf~\x84g\v\x1fM\x8e\xca\x16\r\xb3\x89$\xdc\xe5M4\xa1\xa0\x00\x00\u07d4\xf3\xf2O\u009e @?\xc0\xe8\xf5\xeb\xbbU4&\xf7\x82p\xa2\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf3\xfar5R\xa5\xd0Q.+b\xf4\x8d\xca{+\x81\x050[\x89\amA\xc6$\x94\x84\x00\x00\u07d4\xf3\xfeQ\xfd\xe3D\x13\xc73\x18\xb9\xc8T7\xfe~\x82\x0fV\x1a\x896b2\\\u044f\xe0\x00\x00\u07d4\xf4\x00\xf9=_\\~?\xc3\x03\x12\x9a\xc8\xfb\f/xd\a\xfa\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf4\v\x13O\xea\"\u01b2\x9c\x84W\xf4\x9f\x00\x0f\x9c\xdax\x9a\u06c9 \x86\xac5\x10R`\x00\x00\u07d4\xf4\x15W\xdf\u07f1\xa1\xbd\xce\xfe\xfe.\xba\x1e!\xfe\nJ\x99B\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf4\x17z\r\x85\u050b\x0e&B\x11\xce*\xa2\xef\xd3\xf1\xb4\u007f\b\x89\xc2\xcc\xca&\xb7\xe8\x0e\x80\x00\u07d4\xf4/\x90R1\xc7p\xf0\xa4\x06\xf2\xb7h\x87\u007f\xb4\x9e\xee\x0f!\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xf42\xb9\u06ef\x11\xbd\xbds\xb6Q\x9f\xc0\xa9\x04\x19\x87q\xaa\u0189\b=lz\xabc`\x00\x00\u07d4\xf4=\xa3\xa4\xe3\xf5\xfa\xb1\x04\u029b\xc1\xa0\xf7\xf3\xbbJV\xf3Q\x89lj\xccg\u05f1\xd4\x00\x00\xe0\x94\xf4G\x10\x8b\x98\xdfd\xb5~\x87\x103\x88\\\x1a\xd7\x1d\xb1\xa3\xf9\x8a\x01v\xf4\x9e\xad4\x83P\x80\x00\u07d4\xf4O\x85Q\xac\xe93r\a\x12\xc5\u0111\u0376\xf2\xf9Qsl\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u0794\xf4V\x05Z\x11\xab\x91\xfff\x8e.\xc9\"\x96\x1f*#\xe3\xdb%\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xf4V\xa7[\xb9\x96U\xa7A,\xe9}\xa0\x81\x81m\xfd\xb2\xb1\xf2\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf4[\x1d\xcb.A\xdc'\xff\xa0$\u06ad\xf6\x19\xc1\x11u\xc0\x87\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xf4c\xa9\f\xb3\xf1>\x1f\x06CB66\xbe\xab\x84\xc1#\xb0m\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf4h\x90n~\xdffJ\xb0\u063e=\x83\xebz\xb3\xf7\xff\xdcx\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xf4i\x80\u3929\u049ajn\x90`E7\xa3\x11K\xcb(\x97\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf4kk\x9c|\xb5R\x82\x9c\x1d=\xfd\x8f\xfb\x11\xaa\xba\xe7\x82\xf6\x89\x01#n\xfc\xbc\xbb4\x00\x00\u07d4\xf4v\xe1&\u007f\x86$|\xc9\b\x81o.z\xd58\x8c\x95-\xb0\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf4v\xf2\xcbr\b\xa3.\x05\x1f\xd9N\xa8f)\x92c\x82\x87\xa2\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xf4{\xb14\xda0\xa8\x12\xd0\x03\xaf\x8d\u0338\x88\xf4K\xbfW$\x8a\x01\x19Y\xb7\xfe3\x95X\x00\x00\u07d4\xf4\x83\xf6\a\xa2\x1f\xcc(\x10\n\x01\x8cV\x8f\xfb\xe1@8\x04\x10\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf4\x8e\x1f\x13\xf6\xafM\x84\xb3q\xd7\xdeK'=\x03\xa2c'\x8e\x89 \x86\xac5\x10R`\x00\x00\xe0\x94\xf4\x9cG\xb3\xef\xd8knj[\xc9A\x8d\x1f\x9f\xec\x81Ki\xef\x8a\x04<3\xc1\x93ud\x80\x00\x00\xe0\x94\xf4\x9fo\x9b\xaa\xbc\x01\x8c\x8f\x8e\x11\x9e\x01\x15\xf4\x91\xfc\x92\xa8\xa4\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf4\xa3g\xb1f\u0499\x1a+\xfd\xa9\xf5dc\xa0\x9f%,\x1b\x1d\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf4\xa5\x1f\xceJ\x1d[\x94\xb0q\x83\x89\xbaNx\x14\x13\x9c\xa78\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xf4\xa9\xd0\f\xef\xa9{zX\xef\x94\x17\xfcbg\xa5\x06\x909\xee\x89\x01.\x89(\u007f\xa7\x84\x00\x00\u07d4\xf4\xaa\xa3\xa6\x16>7\x06W{I\xc0v~\x94\x8ah\x1e\x16\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf4\xb1bn$\xf3\v\xca\xd9'!\xb2\x93r\x89U\xa6\xe7\x9c\xcd\x1d0\x00\x00\u07d4\xf5U\xa2{\xb1\xe2\xfdN,\u01c4\xca\ue493\x9f\xc0n/\u0249lk\x93[\x8b\xbd@\x00\x00\u07d4\xf5X\xa2\xb2\xdd&\u0755\x93\xaa\xe0E1\xfd<<\u00c5Kg\x89\n\xbb\xcdN\xf3wX\x00\x00\u07d4\xf5`H\xdd!\x81\u0523od\xfc\xec\xc6!T\x81\xe4*\xbc\x15\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf5dB\xf6\x0e!i\x13\x95\u043f\xfa\xa9\x19M\xca\xff\x12\u2dc9\x0e\x189\x8ev\x01\x90\x00\x00\u07d4\xf5yqJE\xeb\x8fR\xc3\xd5{\xbd\xef\xd2\xc1[./\x11\u07c9T\x91YV\xc4\t`\x00\x00\u07d4\xf5\x93\xc6R\x85\xeek\xbdf7\U000fe3c9\xad@\u0509\xf6U\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf5\x98\xdb.\t\xa8\xa5\xee}r\r+\\C\xbb\x12m\x11\xec\u0089\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xf5\x9d\xab\x1b\xf8\xdf\x112~a\xf9\xb7\xa1KV:\x96\xec5T\x8a\x01EB\xba\x12\xa37\xc0\x00\x00\xe0\x94\xf5\x9f\x9f\x02\xbb\u024e\xfe\t~\xab\xb7\x82\x10\x97\x90!\x89\x8b\xfd\x8a\x02\x1e\x17\x1a>\xc9\xf7,\x00\x00\u07d4\xf5\xa5E\x9f\xcd\xd5\xe5\xb2s\x83\r\xf8\x8e\xeaL\xb7}\xda\u07f9\x89\x04\t\xe5+H6\x9a\x00\x00\u07d4\xf5\xa7gj\xd1H\xae\x9c\x1e\xf8\xb6\xf5\xe5\xa0\xc2\xc4s\xbe\x85\v\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf5\xb0h\x98\x9d\xf2\x9c%5w\xd0@Z\xden\x0eu(\xf8\x9e\x89WG=\x05\u06ba\xe8\x00\x00\u07d4\xf5\xb6\xe9\x06\x1aN\xb0\x96\x16\aw\xe2gb\xcfH\xbd\u0635]\x89\r\xc5_\xdb\x17d{\x00\x00\u07d4\xf5\xcf\xfb\xbabN~\xb3!\xbc\x83\xc6\f\xa6\x81\x99\xb4\xe3fq\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf5\xd1ER\xb1\xdc\xe0\xd6\xdc\x1f2\r\xa6\xff\u02231\xcdo\f\x89Hz\x9a0E9D\x00\x00\xe0\x94\xf5\xd6\x1a\xc4\u0295G^[{\xff\xd5\xf2\xf6\x90\xb3\x16u\x96\x15\x8a\x06\x92\xae\x88\x97\b\x1d\x00\x00\x00\u07d4\xf5\xd9\xcf\x00\xd6X\xddEQzH\xa9\xd3\xf5\xf63T\x1aS=\x89\x06O_\xdfIOx\x00\x00\u07d4\xf5\xea\xdc\xd2\u0478ez\x12\x1f3\xc4X\xa8\xb1>v\xb6U&\x89\r\x8b\x0fZZ\xc2J\x00\x00\u07d4\xf6\a\xc2\x15\r>\x1b\x99\xf2O\xa1\xc7\xd5@\xad\xd3\\N\xbe\x1e\x89\xa7\xf1\xaa\a\xfc\x8f\xaa\x00\x00\u07d4\xf6\v\xd75T>k\xfd.\xa6\xf1\x1b\xffbs@\xbc\x03Z#\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf6\f\x1bE\xf1d\xb9X\x0e 'Z\\9\xe1\xd7\x1e5\xf8\x91\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xf6\x0fb\xd797\x95?\xef5\x16\x9e\x11\xd8r\xd2\xea1~\xec\x8a\x01!\xeah\xc1\x14\xe5\x10\x00\x00\u07d4\xf6\x12\x83\xb4\xbd\x85\x04\x05\x8c\xa3`\u94d9\x9bb\xcb\xc8\xcdg\x89\r\xd2\xd5\xfc\xf3\xbc\x9c\x00\x00\u07d4\xf6\x17\xb9g\xb9\xbdH_v\x95\xd2\xefQ\xfbw\x92\u0618\xf5\x00\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf6\x18\u0671\x04A\x14\x80\xa8c\xe6#\xfcU#-\x1aOH\xaa\x89\x0eh\x9emD\xb1f\x80\x00\u07d4\xf6\"\u5126b>\xaa\xf9\x9f+\xe4\x9eS\x80\xc5\xcb\xcf\\\u0609\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf62\xad\xffI\r\xa4\xb7-\x126\xd0KQ\x0ft\xd2\xfa\xa3\u0349K\xe4\xe7&{j\xe0\x00\x00\u07d4\xf69\xac1\u069fg'\x1b\xd1\x04\x02\xb7eN\\\xe7c\xbdG\x89\x15\xaf\x0fB\xba\xf9&\x00\x00\u07d4\xf6:W\x9b\xc3\xea\u00a9I\x04\x10\x12\x8d\xbc\xeb\xe6\xd9\u0782C\x89P\xc5\xe7a\xa4D\b\x00\x00\u07d4\xf6E\xdd|\x89\x00\x93\xe8\xe4\u022a\x92\xa6\xbb55\"\xd3\u0718\x89\aC\x9f\xa2\t\x9eX\x00\x00\xe0\x94\xf6H\xea\x89\xc2u%q\x01r\x94Ny\xed\xff\x84x\x03\xb7u\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xf6JJ\xc8\xd5@\xa9(\x9ch\xd9`\xd5\xfb|\xc4Zw\x83\x1c\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf6N\xcf!\x17\x93\x1cmSZ1\x1eO\xfe\xae\xf9\u0514\x05\xb8\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xf6O\xe0\x93\x9a\x8d\x1e\xea*\x0e\u035a\x970\xfdyX\xe31\t\x89\x01\x1d\xe1\xe6\xdbE\f\x00\x00\u07d4\xf6V\x16\xbe\x9c\x8by~t\x15\"|\x918\xfa\xa0\x89\x17B\u05c9*\xd3s\xcef\x8e\x98\x00\x00\u07d4\xf6W\xfc\xbeh.\xb4\xe8\xdb\x15.\u03c9$V\x00\vQ=\x15\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf6X\x19\xacL\xc1L\x13\u007f\x05\xddyw\xc7\xda\xe0\x8d\x1aJ\xb5\x89\x05\x87\x88\u02d4\xb1\xd8\x00\x00\u07d4\xf6{\xb8\xe2\x11\x8b\xbc\u0550'fn\xed\xf6\x94>\xc9\xf8\x80\xa5\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf6\x84d\xbfd\xf2A\x13V\xe4\xd3%\x0e\xfe\xfe\\P\xa5\xf6[\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf6\x86x[\x89r\va\x14_\ua017\x8dj\u030e\v\xc1\x96\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf6\x8c^3\xfa\x97\x13\x9d\xf5\xb2\xe68\x86\xce4\xeb\xf3\u45dc\x89\xb3\xfaAi\xe2\xd8\xe0\x00\x00\u07d4\xf6\xa8cWW\xc5\xe8\xc14\xd2\r\x02\x8c\xf7x\u03c6\t\xe4j\x89O\x1dw/\xae\xc1|\x00\x00\u07d4\xf6\xb7\x82\xf4\xdc\xd7E\xa6\xc0\xe2\xe00`\x0e\x04\xa2K%\xe5B\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\xe0\x94\xf6\xbc7\xb1\u04a3x\x8dX\x9bm\xe2\x12\xdc\x17\x13\xb2\xf6\u738a\x01\x0f\f\xf0d\xddY \x00\x00\u07d4\xf6\xc3\u010a\x1a\xc0\xa3G\x99\xf0M\xb8n\u01e9u\xfewh\xf3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf6\xd2]?=\x84m#\x9fR_\xa8\xca\xc9{\xc45x\u06ec\x890\x92\u007ft\xc9\xde\x00\x00\x00\u07d4\xf6\xea\xacp2\u0512\xef\x17\xfd`\x95\xaf\xc1\x1dcOV\xb3\x82\x89\x1b\x1bk\u05efd\xc7\x00\x00\xe0\x94\xf6\xea\xd6}\xbf[~\xb13X\xe1\x0f6\x18\x9dS\xe6C\xcf\u03ca\bxg\x83&\xea\xc9\x00\x00\x00\u07d4\xf6\xf1\xa4C\t\x05\x1ck%\xe4}\xff\x90\x9b\x17\x9b\xb9\xabY\x1c\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xf7\x03(\xef\x97b_\xe7E\xfa\xa4\x9e\xe0\xf9\u052a;\r\xfbi\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf7\n\x99\x8aq{3\x8d\x1d\u0658T@\x9b\x1a3\x8d\ue930\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7\rcz\x84\\\x06\xdbl\u0711\xe67\x1c\xe7\xc48\x8ab\x8e\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\x15R\x13D\x98\x92tK\xc6\x0f.\x04@\a\x88\xbd\x04\x1f\u0749\x03\x9f\xba\xe8\xd0B\xdd\x00\x00\xe0\x94\xf7\x1bE4\xf2\x86\xe40\x93\xb1\xe1^\xfe\xa7I\xe7Y{\x8bW\x8a\x16\x1c\x13\xd34\x1c\x87(\x00\x00\u07d4\xf74\xec\x03rM\xde\xe5\xbbRy\xaa\x1a\xfc\xf6\x1b\f\xb4H\xa1\x89\xe5\xbf,\u0270\x97\x80\x00\x00\u07d4\xf76\u0716v\x00\x128\x8f\xe8\x8bf\xc0n\xfeW\xe0\xd7\xcf\n\x89q\xd7Z\xb9\xb9 P\x00\x00\u07d4\xf7:\xc4l ;\xe1S\x81\x11\xb1Q\xec\x82 \u01c6\xd8AD\x89\x0f\xf77x\x17\xb8+\x80\x00\u07d4\xf7=\xd9\xc1B\xb7\x1b\xce\x11\xd0n0\xe7\xe7\xd02\xf2\uc71e\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf7A\x8a\xa0\xe7\x13\xd2H\"\x87v\xb2\xe7CB\"\xaeu\u3949lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7Nn\x14S\x82\xb4\u06c2\x1f\xe0\xf2\u0643\x88\xf4V\t\u019f\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xf7P\f\x16o\x8b\xea/\x824v\x06\xe5\x02K\xe9\xe4\xf4\u0399\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7W\xfc\x87 \xd3\xc4\xfaRw\a^`\xbd\\A\x1a\xeb\xd9w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7[\xb3\x9cy\x97y\xeb\xc0J3m&\r\xa61F\xed\x98\u0409\x01Z\xf1\u05cbX\xc4\x00\x00\xe0\x94\xf7h\xf3!\xfdd3\xd9kO5M<\xc1e,\x172\xf5\u007f\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf7oi\xce\xe4\xfa\xa0\xa6;0\xae\x1ex\x81\xf4\xf7\x15ep\x10\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf7w6\x1a=\u062bb\xe5\xf1\xb9\xb0GV\x8c\xc0\xb5UpL\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf7|{\x84QI\xef\xba\x19\xe2a\xbc|u\x15y\b\xaf\xa9\x90\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf7\u007f\x95\x87\xffz-r\x95\xf1\xf5q\u0206\xbd3\x92jR|\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xf7\x82X\xc1$\x81\xbc\xdd\u06f7*\x8c\xa0\xc0C\tra\xc6\u0149\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\x98\xd1m\xa4\xe4`\xc4`\xcdH_\xae\x0f\xa0Y\x97\b\ub08965\u026d\xc5\u07a0\x00\x00\u07d4\xf7\xa1\xad\xe2\xd0\xf5)\x12=\x10U\xf1\x9b\x17\x91\x9fV!Ng\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf7\xac\xff\x93K\x84\xda\ti\xdc7\xa8\xfc\xf6C\xb7\xd7\xfb\xedA\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xf7\xb1Q\xcc^W\x1c\x17\xc7e9\xdb\xe9\x96L\xbbo\xe5\xdey\x89tq|\xfbh\x83\x10\x00\x00\u07d4\xf7\xb2\x9b\x82\x19\\\x88-\xabx\x97\u00ae\x95\xe7w\x10\xf5xu\x89w5Aa2\xdb\xfc\x00\x00\u07d4\xf7\xbcLD\x91\rZ\xed\xd6n\xd25U8\xa6\xb1\x93\xc3a\xec\x89\x05A\xde,-\x8db\x00\x00\u07d4\xf7\xc0\f\xdb\x1f\x02\x03\x10\u056c\xab{Ij\xaaD\xb7y\b^\x89Z\x87\xe7\xd7\xf5\xf6X\x00\x00\u07d4\xf7\xc1\xb4C\x96\x8b\x11{]\u0677UW/\xcd9\xca^\xc0K\x89\x18\xb9h\u0092\xf1\xb5\x00\x00\xe0\x94\xf7\xc5\x0f\x92*\xd1ka\xc6\u047a\xa0E\xed\x81h\x15\xba\u010f\x8a\x02\xa99j\x97\x84\xad}\x00\x00\u07d4\xf7\xc7\b\x01Pq\xd4\xfb\n:*\t\xa4]\x15c\x96\xe34\x9e\x89\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf7\xcb\u06e6\xbel\xfeh\xdb\xc2<+\x0f\xf50\xee\x05\"o\x84\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf7\xd0\xd3\x10\xac\xea\x18@a8\xba\xaa\xbb\xfe\x05q\xe8\r\xe8_\x89Hz\x9a0E9D\x00\x00\u07d4\xf7\u05ef LV\xf3\x1f\xd9C\x98\xe4\r\xf1\x96K\u063f\x12<\x89\b!\xd2!\xb5)\x1f\x80\x00\u07d4\xf7\xdc%\x11\x96\xfb\u02f7|\x94}|\x19F\xb0\xffe\x02\x1c\xea\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf7\xe4Z\x12\xaaq\x1cp\x9a\xce\xfe\x95\xf3;xa-*\xd2*\x8a\x0e\x06U\xe2\xf2k\xc9\x18\x00\x00\u07d4\xf7\xf4\x89\x8cLRm\x95_!\xf0U\xcbnG\xb9\x15\xe5\x19d\x89|\b`\xe5\xa8\r\xc0\x00\x00\u07d4\xf7\xf9\x1ez\xcb[\x81)\xa3\x06\x87|\xe3\x16\x8eoC\x8bf\xa1\x89\t\x8a}\x9b\x83\x14\xc0\x00\x00\u07d4\xf7\xfcE\xab\xf7oP\x88\xe2\u5d68\xd12\xf2\x8aMN\xc1\xc0\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\x06:\xf4\xcc\x1d\xd9a\x9a\xb5\u063f\xf3\xfc\xd1\xfa\xa8H\x82!\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\bnBf\x1e\xa9)\xd2\u0761\xablt\x8c\xe3\x05]\x11\x1e\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xf8\bw\x86\xb4-\xa0N\xd6\xd1\xe0\xfe&\xf6\xc0\xee\xfe\x1e\x9fZ\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xf8\r6\x19p/\xa5\x83\x8cH9\x18Y\xa89\xfb\x9c\xe7\x16\x0f\x89l\a\xa7\u0471np\x00\x00\u07d4\xf8\x14y\x9fm\xdfM\xcb)\xc7\xee\x87\x0eu\xf9\xcc-52m\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xf8\x15\xc1\n\x03-\x13\xc3K\x89v\xfan;\xd2\xc9\x13\x1a\x8b\xa9\x89Hz\x9a0E9D\x00\x00\u07d4\xf8\x16\"\xe5WW\xda\xeafu\x97]\xd958\xda}\x16\x99\x1e\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8$\xee3\x1eJ\xc3\xccXv\x939[W\xec\xf6%\xa6\xc0\u0089V\xc9]\xe8\xe8\xca\x1d\x00\x00\u07d4\xf8'\xd5n\xd2\xd3' \u052b\xf1\x03\xd6\xd0\xefM;\xcdU\x9b\x89\x01l\x80\x06W\x91\xa2\x80\x00\u07d4\xf8)\x85\x91R>P\xb1\x03\xf0\xb7\x01\xd6#\xcb\xf0\xf7EV\xf6\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf8H\xfc\xe9\xaba\x1c}\x99 n#\xfa\u019a\u0508\xb9O\xe1\x89\x02\xa1\x12\x9d\t6r\x00\x00\u07d4\xf8O\t\n\xdf?\x8d\xb7\u1533P\xfb\xb7u\x00i\x9ff\xfd\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf8Q\xb0\x10\xf63\xc4\n\xf1\xa8\xf0js\ubeabe\az\xb5\x89\xee\x86D/\xcd\x06\xc0\x00\x00\u07d4\xf8X\x17\x1a\x04\xd3W\xa1;IA\xc1n~U\xdd\u0514\x13)\x89\x02F\xa5!\x8f*\x00\x00\x00\u07d4\xf8[\xab\x1c\xb3q\x0f\xc0_\xa1\x9f\xfa\xc2.gR\x1a\v\xa2\x1d\x89l\x955\u007f\xa6\xb3l\x00\x00\u07d4\xf8j>\xa8\a\x1fp\x95\xc7\u06ca\x05\xaePz\x89)\u06f8v\x89\x126\xef\xcb\u02f3@\x00\x00\u07d4\xf8pL\x16\xd2\xfd[\xa3\xa2\xc0\x1d\x0e\xb2\x04\x84\xe6\xec\xfa1\t\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf8p\x99_\xe1\xe5\"2\x1duC7\xa4\\\f\x9d{8\x95\x1c\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf8s\xe5ze\xc9;n\x18\xcbu\xf0\xdc\a}[\x893\xdc\\\x89\n\xad\xec\x98?\xcf\xf4\x00\x00\u07d4\xf8ua\x9d\x8a#\xe4]\x89\x98\u0444\u0500\xc0t\x89p\x82*\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf8{\xb0{(\x9d\xf70\x1eT\xc0\xef\xdaj,\xf2\x91\xe8\x92\x00\x89K\xe4\xe7&{j\xe0\x00\x00\u0794\xf8\x89\x00\xdbsyU\xb1Q\x9b\x1a}\x17\n\x18\x86L\xe5\x90\xeb\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xf8\x8bX\xdb7B\vFL\v\xe8\x8bE\xee+\x95)\x0f\x8c\xfa\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf8\x96+u\xdb]$\xc7\xe8\xb7\xce\xf1\x06\x8c>g\u03bb0\xa5\x89\x0f-\xc7\xd4\u007f\x15`\x00\x00\u07d4\xf8\xa0e\xf2\x87\xd9\x1dw\xcdbj\xf3\x8f\xfa\"\r\x9bU*+\x89g\x8a\x93 b\xe4\x18\x00\x00\u07d4\xf8\xa4\x9c\xa29\f\x1fm\\\x0ebQ;\a\x95qt?|\u0189\xa2\xa1]\tQ\x9b\xe0\x00\x00\u07d4\xf8\xa5\f\xee.h\x8c\xee\u3b24\u0522\x97%\xd4\a,\u0103\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xacJ9\xb5<\x110x \x97;D\x13e\xcf\xfeYof\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xae\x85{g\xa4\xa2\x89:?\xbe|z\x87\xff\x1c\x01\u01a6\xe7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xf8\xbf\x9c\x04\x87NZw\xf3\x8fL8R~\x80\xc6v\xf7\xb8\x87\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xc7\xf3J8\xb3\x18\x01\xdaC\x064w\xb1+'\xd0\xf2\x03\xff\x89\x1a\u04ba\xbao\xefH\x00\x00\u07d4\xf8\xca3l\x8e\x91\xbd \xe3\x14\xc2\v-\xd4`\x8b\x9c\x8b\x94Y\x89-\u071b\u0173,x\x00\x00\u07d4\xf8\xd1t$\xc7g\xbe\xa3\x12\x05s\x9a+W\xa7'r\x14\uef89\x02F\xdd\xf9yvh\x00\x00\u07d4\xf8\xd5-\xcc_\x96\xcc(\x00{>\u02f4\t\xf7\xe2*dl\xaa\x89\b\x16\x90\xe1\x81(H\x00\x00\u07d4\xf8\xdc\xe8g\xf0\xa3\x9c[\xef\x9e\xeb\xa6\t\"\x9e\xfa\x02g\x8bl\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf8\xf2&\x14*B\x844\xab\x17\xa1\x86J%\x97\xf6J\xab/\x06\x89\tY\x8b/\xb2\xe9\xf2\x80\x00\u07d4\xf8\xf6d^\r\xeedK=\xad\x81\xd5q\uf6ef\x84\x00!\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9\x01\xc0\x0f\xc1\u06c8\xb6\x9cK\xc3%+\\\xa7\x0e\xa6\xee\\\xf6\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf9=[\xcb\x06D\xb0\xcc\xe5\xfc\u0763C\xf5\x16\x8f\xfa\xb2\x87}\x89\vb\a\xb6}&\xf9\x00\x00\u07d4\xf9W\x0e\x92L\x95\u07bbpa6\x97\x92\xcf.\xfe\u00a8-^\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xf9d \x86\xb1\xfb\xaea\xa6\x80M\xbe_\xb1^\xc2\u04b57\xf4\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9d\x88i\x85\x90\xdc;,UVB\xb8q4\x8d\xfa\x06z\u0549\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf9d\u064d(\x170\xba5\xb2\xe3\xa3\x14yn{B\xfe\xdfg\x89S\xb0\x87`\x98\xd8\f\x00\x00\u07d4\xf9e\ri\x89\xf1\x99\xab\x1c\xc4ycm\xed0\xf2A\x02\x1fe\x89.\x14\x1e\xa0\x81\xca\b\x00\x00\xe0\x94\xf9h\x83X$Y\x90\x8c\x82v'\xe8o(\xe6F\xf9\xc7\xfcz\x8a\x01\u0127\x877\xcd\u03f8\x00\x00\u07d4\xf9kL\x00voSsj\x85t\xf8\"\xe6GL/!\xda-\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xf9r\x9dH(,\x9e\x87\x16m^\xef-\x01\xed\xa9\xdb\xf7\x88!\x89\x05k\x83\xdd\xc7(T\x80\x00\u07d4\xf9v~N\xcbJY\x80Ru\b\u05fe\xc3\xd4^Ld\x9c\x13\x89g\x8a\x93 b\xe4\x18\x00\x00\xe0\x94\xf9x\xb0%\xb6B3U\\\xc3\xc1\x9a\xda\u007fA\x99\xc94\x8b\xf7\x8aT\xb4\v\x1f\x85+\xda\x00\x00\x00\u07d4\xf9{V\xeb\u0577z\xbc\x9f\xba\u02eb\u0514\xb9\xd2\xc2!\xcd\x03\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xf9\x81\x1f\xa1\x9d\xad\xbf\x02\x9f\x8b\xfeV\x9a\xdb\x18\"\x8c\x80H\x1a\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xf9\x82Ps\fLa\xc5\u007f\x12\x985\xf2h\b\x94yEB\xf3\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xf9\x894gr\x99^\xc1\x90o\xaf\xfe\xba*\u007f\xe7\u079ck\xab\x8a\x01je\x02\xf1Z\x1eT\x00\x00\u07d4\xf9\x98\xca4\x11s\nl\xd1\x0etU\xb0A\x0f\xb0\xf6\xd3\xff\x80\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xf9\x9a\xeeDKW\x83\xc0\x93\xcf\xff\xd1\xc4c,\xf9\x90\x9f\xbb\x91\x1d/\x81\x92\xf8B\t\x89\x90\xf54`\x8ar\x88\x00\x00\u07d4\xf9\xbf\xb5\x9dS\x8a\xfcHt\xd4\xf5\x94\x1b\b\xc9s\x0e8\xe2K\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\u07d4\xf9\xdd#\x90\b\x18/\xb5\x19\xfb0\xee\xdd \x93\xfe\xd1c\x9b\xe8\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xf9\u07ba\xec\xb5\xf39\xbe\xeaH\x94\xe5 K\xfa4\r\x06\u007f%\x89ZB\x84Fs\xb1d\x00\x00\xe0\x94\xf9\xe3tG@lA!\x97\xb2\u2bbc\x00\x1dn0\u024c`\x8a\x01\xc4y\xbbCI\xc0\xee\x00\x00\u07d4\xf9\xe7\"/\xaa\xf0\xf4\xda@\xc1\u0124\x0607:\t\xbe\u05f6\x89\x9bO\u0730\x94V$\x00\x00\u07d4\xf9\xec\xe0\"\xbc\xcd,\x924i\x11\xe7\x9d\xd5\x03\x03\xc0\x1e\x01\x88\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfa\x00\xc3v\xe8\x9c\x05\u81c1z\x9d\xd0t\x8d\x96\xf3A\xaa\x89\x89\x10M\r\x00\u04b7\xf6\x00\x00\u07d4\xfa\f\x1a\x98\x8c\x8a\x17\xad5(\xeb(\xb3@\x9d\xaaX\"_&\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xfa\x10_\x1a\x11\xb6\xe4\xb1\xf5`\x12\xa2y\"\xe2\xac-\xa4\x81/\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xfa\x14/\xe4~\u0697\xe6P;8k\x18\xa2\xbe\xdds\u0335\xb1\x89.\x15:\xd8\x15H\x10\x00\x00\u07d4\xfa\x14\xb5f#J\xbe\xe70B\xc3\x1d!qq\x82\u02e1J\xa1\x89\x11\xc7\xea\x16.x \x00\x00\u07d4\xfa\x19\xd6\xf7\xa5\x0fO\a\x98\x93\xd1g\xbf\x14\xe2\x1d\x00s\u0456\x89\x1c\xbb:?\xf0\x8d\b\x00\x00\u07d4\xfa\x1f\x19q\xa7u\xc3PO\xefPy\xf6@\xc2\u013c\xe7\xac\x05\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfa'\x9b\xfd\x87g\xf9V\xbf\u007f\xa0\xbdV`\x16\x8d\xa7V\x86\xbd\x89\x90\xf54`\x8ar\x88\x00\x00\xe0\x94\xfa'\xccI\xd0\vl\x98s6\xa8u\xae9\xdaX\xfb\x04\x1b.\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xfa(2\x99`=\x87X\xe8\u02b0\x82\x12],\x8f}DT)\x8a\x01[\xca\xcb\x1e\x05\x01\xae\x80\x00\u07d4\xfa+\xbc\xa1]?\u37ca2\x8e\x91\xf9\r\xa1Oz\xc6%=\x89\n\u05ce\xbcZ\xc6 \x00\x00\xe0\x94\xfa/\u049d\x03\xfe\xe9\xa0x\x93\xdf:&\x9fV\xb7/.\x1ed\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xfa3U2\x85\xa9sq\x9a\r_\x95o\xf8a\xb2\u061e\xd3\x04\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfa:\fK\x90?n\xa5.\xa7\xab{\x88c\xb6\xa6\x16\xadfP\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfa:\x1a\xa4H\x8b5\x1a\xa7V\f\xf5\xeec\n/\xd4\\2\"\x89/\xa4~j\xa74\r\x00\x00\u07d4\xfaA\tq\xad\"\x9c06\xf4\x1a\u03c5/*\u0259(\x19P\x89\u0633\x11\xa8\xdd\xfa|\x00\x00\u07d4\xfaD\xa8U\xe4\x04\xc8m\f\xa8\xef3$%\x1d\xfb4\x9cS\x9e\x89T\"S\xa1&\xce@\x00\x00\xe0\x94\xfaR\x01\xfe\x13B\xaf\x110{\x91B\xa0A$<\xa9./\t\x8a 8\x11j:\xc0C\x98\x00\x00\xe0\x94\xfa`\x86\x8a\xaf\xd4\xffL\\W\x91K\x8e\u054bBWs\u07e9\x8a\x01\xcf\xe5\xc8\b\xf3\x9f\xbc\x00\x00\u07d4\xfag\xb6{O7\xa0\x15\t\x15\x11\x0e\xde\a;\x05\xb8S\xbd\xa2\x89#\x19\xba\x94sq\xad\x00\x00\u07d4\xfah\xe0\xcb>\xdfQ\xf0\xa6\xf2\x11\u0272\xcb^\a<\x9b\xff\xe6\x89\x0f\xc969(\x01\xc0\x00\x00\xe0\x94\xfaj7\xf0\x18\xe9yg\x93\u007f\xc5\xe8a{\xa1\u05c6\xdd_w\x8a\x04<0\xfb\b\x84\xa9l\x00\x00\u07d4\xfav\x06C[5l\xee%{\xd2\xfc\xd3\xd9\xea\xcb<\xd1\xc4\xe1\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xfaz\xdff\v\x8d\x99\xce\x15\x93=|_\a/<\xbe\xb9\x9d3\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\xfa\x86\xca'\xbf(T\u0648p\x83\u007f\xb6\xf6\xdf\xe4\xbfdS\xfc\x89\x11u~\x85%\xcf\x14\x80\x00\u07d4\xfa\x8c\xf4\xe6'i\x8c]W\x88\xab\xb7\x88\x04\x17\xe7P#\x13\x99\x89\xe6\x1a6\x96\xee\xf6\x10\x00\x00\u07d4\xfa\x8e;\x1f\x13C9\x00s}\xaa\xf1\xf6)\x9cH\x87\xf8[_\x89&\u009eG\u0104L\x00\x00\u07d4\xfa\x9e\xc8\xef\xe0\x86\x86\xfaX\xc1\x813Xr\xbai\x85`\ucac9lj\xccg\u05f1\xd4\x00\x00\u07d4\xfa\xad\x90]\x84|{#A\x8a\xee\xcb\xe3\xad\u06cd\xd3\xf8\x92J\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xfa\xae\xba\x8f\xc0\xbb\xdaU<\xa7.0\xef=s.&\xe8 A\x89H\x8d(*\xaf\xc9\xf6\x80\x00\u07d4\xfa\xb4\x87P\r\xf2\x0f\xb8>\xbe\xd9\x16y\x1dV\x17r\xad\xbe\xbf\x89lkLM\xa6\u077e\x00\x00\u07d4\xfa\xc5\u0294u\x80x\xfb\xfc\xcd\x19\xdb5X\xda~\u8827h\x897(\xa6+\r\xcf\xf6\x00\x00\u07d4\xfa\xd9j\xb6\xacv\x8a\xd5\t\x94R\xacGw\xbd\x1aG\xed\u010f\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xfa\xe7g\x19\xd9~\xacA\x87\x04(\xe9@'\x9d\x97\xddW\xb2\xf6\x8a\x14\u06f2\x19\\\xa2(\x90\x00\x00\u07d4\xfa\u8053pG\x89Zf\f\xf2)v\x0f'\xe6h(\xd6C\x89\t\xdd\xc1\xe3\xb9\x01\x18\x00\x00\u07d4\xfa\xe9,\x13p\xe9\u115a]\xf8;V\xd0\xf5\x86\xaa;@L\x89\x05\u0174\xf3\xd8C\x98\x00\x00\xe0\x94\xfa\xf5\xf0\xb7\xb6\xd5X\xf5\t\r\x9e\xa1\xfb-B%\x9cX`x\x8a\x01Z\xff\xb8B\fkd\x00\x00\xe0\x94\xfb\x12o\x0e\xc7i\xf4\x9d\xce\xfc\xa2\xf2\x00(dQX0\x84\xb8\x8a\x01\x0f\xcb\xc25\x03\x96\xbf\x00\x00\xe0\x94\xfb\x13^\xb1Z\x8b\xacr\xb6\x99\x154*`\xbb\xc0k~\a|\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xfb\"<\x1e\"\xea\xc1&\x9b2\xee\x15jS\x85\x92.\xd3o\xb8\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb7\xcfkO\x81\xa9\xe2\"\xfb\xa2.\x9b\xd2KP\x98\xb73\u03c9\x02\x1auJm\xc5(\x00\x00\u07d4\xfb8`\xf4\x12\x1cC.\xbd\xc8\xecj\x031\xb1\xb7\ty.\x90\x89 \x8c9J\xf1\u0208\x00\x00\u07d4\xfb9\x18\x9a\xf8v\xe7b\xc7\x1dl>t\x18\x93\xdf\"l\xed\u0589\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfb:\v\rkjq\x8fo\xc0)*\x82]\xc9$z\x90\xa5\u0409\n\xd6\xdd\x19\x9e\x97[\x00\x00\xe0\x94\xfb?\xa1\xac\b\xab\xa9\xcc;\xf0\xfe\x9dH8 h\x8fe\xb4\x10\x8a\x06ZM\xa2]0\x16\xc0\x00\x00\u07d4\xfb?\xe0\x9b\xb86\x86\x15)\xd7Q\x8d\xa2v5\xf58PV\x15\x89K\xe3\x92\x16\xfd\xa0p\x00\x00\xe0\x94\xfbQ%\xbf\x0f^\xb0\xb6\xf0 \xe5k\xfc/\xdf=@,\t~\x8a\x01@a\xb9\xd7z^\x98\x00\x00\u07d4\xfbU\x18qL\xef\xc3m\x04\x86]\xe5\x91^\xf0\xffG\xdf\xe7C\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb_\xfa\xa0\xf7aW&5x\x91GX\x18\x93\x9d 7\u03d6\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfbh\\\x15\xe49\x96^\xf6&\xbf\r\x83L\u0468\x9f+V\x95\x89\u0556{\xe4\xfc?\x10\x00\x00\u07d4\xfbtK\x95\x1d\tK1\x02b\xc8\xf9\x86\xc8`\u07da\xb1\xdee\x89\x02\xd1\xc5\x15\xf1\xcbJ\x80\x00\u07d4\xfby\xab\u06d2\\U\xb9\xf9\x8e\xfe\xefd\xcf\xc9\xeba\xf5\x1b\xb1\x89a@\xc0V\xfb\n\xc8\x00\x00\u07d4\xfb\x81\x13\xf9M\x91s\xee\xfdZ0s\xf5\x16\x80:\x10\xb2\x86\xae\x89\x04V9\x18$O@\x00\x00\u07d4\xfb\x84,\xa2\xc5\xef\x139\x17\xa26\xa0\u052c@i\x01\x10\xb08\x89\x10\x96\x9ab\xbe\x15\x88\x00\x00\u07d4\xfb\x91\xfb\x1aiUS\xf0\u018e!'m\xec\xf0\xb89\t\xb8m\x89\x05l\x006\x17\xafx\x00\x00\u07d4\xfb\x94s\xcfw\x125\n\x1f\xa09Rs\xfc\x80V\aR\xe4\xfb\x89\x06\xaf!\x98\xba\x85\xaa\x00\x00\xe0\x94\xfb\x94\x9cd\u007f\xdc\xfd%\x14\xc7\u054e1\xf2\x8aS-\x8cX3\x8a\x04<3\xc1\x93ud\x80\x00\x00\u07d4\xfb\xa5HmS\xc6\xe2@IBA\xab\xf8~C\xc7`\rA:\x89k\xbfaIIH4\x00\x00\u07d4\xfb\xb1a\xfe\x87_\t)\nK&+\xc6\x01\x10\x84\x8f\r\"&\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfb\xbb\xeb\u03fe#^W\xdd#\x06\xad\x1a\x9e\u0141\xc7\xf9\xf4\x8f\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xfb\xc0\x1d\xb5NG\xcd\xc3\xc48iJ\xb7\x17\xa8V\xc2?\xe6\xe9\x8a\x01\xcaqP\xab\x17OG\x00\x00\xe0\x94\xfb\xcf\xccJ{\x0f&\xcf&\xe9\xf33!2\xe2\xfcj#\af\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfb\xe7\x16\"\xbc\xbd1\xc1\xa3iv\xe7\xe5\xf6p\xc0\u007f\xfe\x16\u0789\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfb\xed\xe3,4\x9f3\x00\xefL\xd3;M\xe7\xdc\x18\xe4C\xd3&\x89\xabM\xcf9\x9a:`\x00\x00\u07d4\xfb\xf2\x04\xc8\x13\xf86\xd89b\u01c7\fx\b\xca4\u007f\xd3>\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xfb\xf7Y3\xe0\x1bu\xb1T\xef\x06i\ak\xe8\u007fb\xdf\xfa\xe1\x8a\x10\x84cr\xf2I\xd4\xc0\x00\x00\u07d4\xfc\x00\x96\xb2\x1e\x95\xac\xb8\xd6\x19\xd1v\xa4\xa1\xd8\xd5)\xba\xdb\xef\x89\x14\xd9i;\xcb\xec\x02\x80\x00\xe0\x94\xfc\x00\xa4 \xa3a\a\xdf\xd5\xf4\x95\x12\x8a_\u5af2\xdb\x0f4\x8a\x01C\x17\x9d\x86\x91\x10 \x00\x00\xe0\x94\xfc\x01\x8ai\n\xd6tm\xbe:\u03d7\x12\xdd\xcaR\xb6%\x009\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\u07d4\xfc\x02s@3\xe5\u007fpQ~\n\xfc~\xe6$a\xf0o\xad\x8e\x89\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xfc\x0e\xe6\xf7\u00b3qJ\xe9\x91lEVf\x05\xb6V\xf3$A\x89_h\xe8\x13\x1e\u03c0\x00\x00\u07d4\xfc\x10\xb7\xa6{2h\xd53\x1b\xfbj\x14\xde\xf5\xeaJ\x16,\xa3\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfc\x15\u02d9\xa8\xd1\x03\v\x12w\n\xdd\x03:y\xee\r\f\x90\x8c\x89\x12\xfa\x00\xbdR\xe6$\x00\x00\u07d4\xfc)R\xb4\u011f\xed\u043c\x05(\xa3\bI^mj\x1cq\u0589lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xfc,\x1f\x88\x96\x1d\x01\x9c>\x9e\xa30\t\x15.\x06\x93\xfb\xf8\x8a\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\xe0\x94\xfc6\x11\x05\u0750\xf9\xed\xe5fI\x9di\xe9\x13\x03\x95\xf1*\u020aS\xa4\xfe/ N\x80\xe0\x00\x00\u07d4\xfc7/\xf6\x92|\xb3\x96\xd9\xcf)\x805\x00\x11\r\xa62\xbcR\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc9\xbeA\tK\x19\x97\xd2\x16\x9e\x82d\xc2\u00fa\xa6\u025b\u0109lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc=\"k\xb3jX\xf5&V\x88W\xb0\xbb\x12\xd1\t\xec\x93\x01\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfcC\x82\x9a\u01c7\xff\x88\xaa\xf1\x83\xba5*\xad\xbfZ\x15\xb1\x93\x89\u05ac\n+\x05R\xe0\x00\x00\u07d4\xfcI\xc1C\x9aA\u05b3\xcf&\xbbg\xe06R$\xe5\xe3\x8f_\x8966\u05ef^\u024e\x00\x00\u07d4\xfcU\x00\x82Q\x05\xcfq*1\x8a^\x9c;\xfci\u021d\f\x12\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\xe0\x94\xfcf\xfa\xba'\u007fK]\xe6J\xd4^\xb1\x9c1\xe0\f\xed>\u054a\x011\xbe\xb9%\xff\xd3 \x00\x00\xe0\x94\xfc~\"\xa5\x03\xecZ\xbe\x9b\b\xc5\v\xd1I\x99\xf5 \xfaH\x84\x8a\x01ZG}\xfb\xe1\xea\x14\x80\x00\u07d4\xfc\x82\x15\xa0\xa6\x99\x13\xf6*C\xbf\x1c\x85\x90\xb9\xdd\xcd\r\x8d\u06c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xfc\x98\x9c\xb4\x87\xbf\x1a}\x17\xe4\xc1\xb7\u0137\xaa\xfd\xdak\n\x8d\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\xe0\x94\xfc\x9b4td\xb2\xf9\x92\x9d\x80~\x03\x9d\xaeH\xd3\u064d\xe3y\x8a\x02\xf6\xf1\a\x80\xd2,\xc0\x00\x00\u07d4\xfc\xa4;\xbc#\xa0\xd3!\xba\x9eF\xb9)s\\\xe7\xd8\xef\f\x18\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfc\xa7>\xff\x87q\xc0\x10;\xa3\xcc\x1a\x9c%\x94H\xc7*\xbf\v\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfc\xad\xa3\x00(?k\xcc\x13J\x91Eg`\xb0\xd7}\xe4\x10\xe0\x89lk\x93[\x8b\xbd@\x00\x00\xe0\x94\xfc\xbc\\q\xac\xe7\x97AE\v\x01,\xf6\xb8\xd3\xf1}\xb6\x8ap\x8a\x02\x05\xb4\u07e1\xeetx\x00\x00\u07d4\xfc\xbd\x85\xfe\xeajuO\xcf4ID\x9e7\xff\x97\x84\xf7w<\x89\xa7J\xdai\xab\xd7x\x00\x00\xe0\x94\xfc\xc9\u0524&.z\x02z\xb7Q\x91\x10\xd8\x02\u0115\xce\xea9\x8a\x01YQ\x82\"K&H\x00\x00\xe0\x94\xfc\xcd\r\x1e\xce\xe2z\xdd\xea\x95\xf6\x85z\xee\xc8\u01e0K(\xee\x8a\x02\x1e\x19\xe0\u027a\xb2@\x00\x00\xe0\x94\xfc\u0434\x82|\xd2\b\xff\xbf^u\x9d\xba\x8c<\xc6\x1d\x8c,<\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfc\xe0\x89c\\\xe9z\xba\xc0kD\x81\x9b\xe5\xbb\n>.\v7\x89\x05\x03\x92\nv0\xa7\x80\x00\u07d4\xfc\xf1\x99\xf8\xb8T\"/\x18.N\x1d\t\x9dN2>*\xae\x01\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfc\xfc:P\x04\xd6xa?\v6\xa6B&\x9a\u007f7\x1c?j\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfd\x19\x1a5\x15}x\x13s\xfbA\x1b\xf9\xf2R\x90\x04|^\xef\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfd\x1f\xaa4{\x0f\u0300L-\xa8l6\xd5\xf1\u044bp\x87\xbb\x89\x02\xd6\xeb$z\x96\xf6\x00\x00\u07d4\xfd\x1f\xb5\xa8\x9a\x89\xa7!\xb8yph\xfb\xc4\u007f>\x9dR\xe1I\x89\f\u0435\x83\u007f\xc6X\x00\x00\u07d4\xfd OOJ\xba%%\xbar\x8a\xfd\xf7\x87\x92\xcb\u07b75\xae\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd'W\xcc5Q\xa0\x95\x87\x8d\x97\x87V\x15\xfe\fj2\xaa\x8a\x89 m\xb1R\x99\xbe\xac\x00\x00\u07d4\xfd(r\u045eW\x85<\xfa\x16\xef\xfe\x93\u0431\xd4{O\x93\xfb\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfd))'\x1e\x9d \x95\xa2dv~{\r\xf5.\xa0\xd1\xd4\x00\x89\xa2\xa1\xeb%\x1bZ\xe4\x00\x00\u07d4\xfd7z8Rr\x90\f\xb46\xa3\xbbyb\xcd\xff\xe9?]\xad\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd@$+\xb3Jp\x85^\xf0\xfd\x90\xf3\x80-\xec!6\xb3'\x89h\xa8u\a>)$\x00\x00\xe0\x94\xfdE,9i\xec\xe3\x80\x1cT \xf1\xcd\u02a1\xc7\x1e\xd2=\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\u07d4\xfdKU\x1fo\xdb\u0366\xc5\x11\xb5\xbb7\"P\xa6\xb7\x83\xe54\x89\x01\x1d\xe1\xe6\xdbE\f\x00\x00\u07d4\xfdK\x98\x95X\xae\x11\xbe\f;6\xe2\xd6\xf2\xa5J\x93C\xca.\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfdM\xe8\xe3t\x8a(\x9c\xf7\xd0`Q}\x9d88\x8d\xb0\x1f\xb8\x89\r\x8drkqw\xa8\x00\x00\u07d4\xfdZc\x15\u007f\x91O\u04d8\uac5c\x13}\xd9U\v\xb7q\\\x89\x05k\xc7^-c\x10\x00\x00\u07d4\xfd`\u04b5\xaf=5\xf7\xaa\xf0\u00d3\x05.y\xc4\xd8#\u0645\x89\x03\x0e\xb5\r.\x14\b\x00\x00\u07d4\xfdhm\xe5?\xa9\u007f\x99c\x9e%hT\x97 \xbcX\x8c\x9e\xfc\x89j\xc5\xc6-\x94\x86\a\x00\x00\u07d4\xfd~\u078fR@\xa0eA\xebi\x9dx,/\x9a\xfb!p\xf6\x89Hz\x9a0E9D\x00\x00\u07d4\xfd\x81+\u019f\xb1p\xefW\xe22~\x80\xaf\xfd\x14\xf8\xe4\xb6\u0489lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\x88\xd1\x14\"\x0f\b\x1c\xb3\xd5\xe1[\xe8\x15*\xb0sfWj\x89\x10CV\x1a\x88)0\x00\x00\u07d4\xfd\x91\x856\xa8\xef\xa6\xf6\xce\xfe\x1f\xa1\x159\x95\xfe\xf5\xe3=;\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xfd\x92\x0fr&\x82\xaf\xb5\xafE\x1b\x05D\xd4\xf4\x1b;\x9dWB\x89~R\x05j\x12?<\x00\x00\u07d4\xfd\x95y\xf1\x19\xbb\xc8\x19\xa0+a\u3348\x03\xc9B\xf2M2\x89\x05\xb9~\x90\x81\xd9@\x00\x00\u07d4\xfd\xa0\xce\x153\a\a\xf1\v\xce2\x01\x17- \x18\xb9\xdd\xeat\x89\x02\xd0A\xd7\x05\xa2\xc6\x00\x00\xe0\x94\xfd\xa3\x04(\x19\xaf>f)\x00\xe1\xb9+CX\xed\xa6\xe9%\x90\x8a\x19\a\xa2\x84\u054fc\xe0\x00\x00\u07d4\xfd\xa6\x81\x0e\xa5\xac\x98]o\xfb\xf1\xc5\x11\xf1\xc1B\xed\xcf\xdd\xf7\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfd\xb39D\xf26\x06\x15\xe5\xbe#\x95w\u0221\x9b\xa5-\x98\x87\x89 \x9d\x92/RY\xc5\x00\x00\u07d4\xfd\xbaSY\xf7\xec;\xc7p\xacI\x97]\x84N\xc9qbV\xf1\x8965\u026d\xc5\u07a0\x00\x00\xe0\x94\xfd\xc4\xd4vZ\x94/[\xf9i1\xa9\xe8\xccz\xb8\xb7W\xffL\x8a\x12lG\x8a\x0e>\xa8`\x00\x00\xe0\x94\xfd\xcd]\x80\xb1\x05\x89zW\xab\xc4xev\x8b)\x00RB\x95\x8a\x01Z\xf1\u05cbX\xc4\x00\x00\x00\u0794\xfd\xd1\x19_y}O5q}\x15\xe6\xf9\x81\n\x9a?\xf5T`\x88\xfc\x93c\x92\x80\x1c\x00\x00\u07d4\xfd\xd5\x02\xa7N\x81;\u03e3U\xce\xda<\x17ojhq\xaf\u007f\x89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfd\u357c\vm\\\xbbL\x1d\x8f\xea>\vK\xffc^\x9d\xb7\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\xea\xac*\xcf\x1d\x13\x8e\x19\xf2\xfc?\x9f\xb7E\x92\xe3\ud04a\x89$=M\x18\"\x9c\xa2\x00\x00\u07d4\xfd\xec\xc8-\xdf\xc5a\x92\xe2oV<=h\xcbTJ\x96\xbf\xed\x89\x17\xda:\x04\u01f3\xe0\x00\x00\u07d4\xfd\xf4#C\x01\x9b\v\fk\xf2`\xb1s\xaf\xab~E\xb9\xd6!\x89lj\xccg\u05f1\xd4\x00\x00\u07d4\xfd\xf4I\xf1\b\xc6\xfbOZ+\b\x1e\xed~E\u645eM%\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfd\xfda4\xc0J\x8a\xb7\xeb\x16\xf0\x06C\xf8\xfe\xd7\u06aa\ucc89\x15\xaf\x1dx\xb5\x8c@\x00\x00\u07d4\xfe\x00\xbfC\x99\x11\xa5S\x98-\xb68\x03\x92E\xbc\xf02\xdb\u0709\x15[\xd90\u007f\x9f\xe8\x00\x00\u07d4\xfe\x01n\xc1~\xc5\xf1\x0e;\xb9\x8f\xf4\xa1\xed\xa0E\x15v\x82\xab\x89\x14_T\x02\xe7\xb2\xe6\x00\x00\u07d4\xfe\x0e0\xe2\x14)\rt=\xd3\x0e\xb0\x82\xf1\xf0\xa5\"Z\xdea\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfe!\v\x8f\x04\xdcmOv!j\xcf\xcb\u055b\xa8;\xe9\xb60\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfe\"\xa0\xb3\x88f\x8d\x1a\xe2d>w\x1d\xac\xf3\x8aCB#\u0309\xd8\xdb^\xbd{&8\x00\x00\u07d4\xfe6&\x88\x84_\xa2D\u0300~K\x110\xeb7A\xa8\x05\x1e\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfe8'\xd5v0\u03c7a\xd5\x12y{\v\x85\x8eG\x8b\xbd\x12\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfeA\x8bB\x1a\x9cm76\x02y\x04u\xd20>\x11\xa7Y0\x897\b\xba\xed=h\x90\x00\x00\u07d4\xfeBI\x12yP\xe2\xf8\x96\xec\x0e~.=\x05Z\xab\x10U\x0f\x89$=M\x18\"\x9c\xa2\x00\x00\xe0\x94\xfeM\x84\x03!o\xd5qW+\xf1\xbd\xb0\x1d\x00W\x89x\u0588\x8a\x02\x15\xf85\xbcv\x9d\xa8\x00\x00\u07d4\xfeS\xb9I\x89\u0619d\xda aS\x95&\xbb\xe9y\xdd.\xa9\x89h\xa8u\a>)$\x00\x00\u07d4\xfeT\x9b\xbf\xe6G@\x18\x98\x92\x93%8\u06afF\u04b6\x1dO\x89\x02+\x1c\x8c\x12'\xa0\x00\x00\xe0\x94\xfea]\x97\\\b\x87\xe0\xc9\x11>\xc7)\x84 \xa7\x93\xaf\x8b\x96\x8a\x01\xb1\xaeMn.\xf5\x00\x00\x00\u07d4\xfee\xc4\x18\x8dy\"Wi\td D\xfd\xc5#\x95V\x01e\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfei\u007f\xf2,\xa5G\xbf\xc9^3\xd9`\xda`\\gc\xf3[\x89G\xd4\x11\x9f\xd9`\x94\x00\x00\u07d4\xfej\x89[y\\\xb4\xbf\x85\x90=<\xe0\x9cZ\xa49S\u04ff\x89\xb8Pz\x82\a( \x00\x00\u07d4\xfeo_B\xb6\x19;\x1a\xd1b\x06\u4bf5#\x9dM}\xb4^\x89]\u0212\xaa\x111\xc8\x00\x00\u07d4\xfep\x11\xb6\x98\xbf3q\x13-tE\xb1\x9e\xb5\xb0\x945j\xee\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x80\xe9#-\xea\xff\x19\xba\xf9\x98i\x88:K\xdf\x00\x04\xe5<\x89.b\xf2\ni\xbe@\x00\x00\u07d4\xfe\x8en6eW\r\xffz\x1b\xdaiz\xa5\x89\xc0\xb4\xe9\x02J\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x8f\x1f\u072b\u007f\xbe\u0266\xa3\xfc\xc5\aa\x96\x00P\\6\xa3\x89\x01\x11du\x9f\xfb2\x00\x00\u07d4\xfe\x91\xec\xcf+\xd5f\xaf\xa1\x16\x96\xc5\x04\x9f\xa8Lic\nR\x89i*\xe8\x89p\x81\xd0\x00\x00\u07d4\xfe\x96\xc4\xcd8\x15b@\x1a\xa3*\x86\xe6[\x9dR\xfa\x8a\xee'\x89\x8f\x1d\\\x1c\xae7@\x00\x00\u07d4\xfe\x98\xc6d\xc3\xe4G\xa9^i\xbdX!q\xb7\x17n\xa2\xa6\x85\x89\xd8\xd7&\xb7\x17z\x80\x00\x00\u07d4\xfe\x9a\xd1.\xf0]m\x90&\x1f\x96\xc84\n\x03\x81\x97M\xf4w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\x9c\x0f\xff\xef\xb8\x03\b\x12V\xc0\xcfMfY\xe6\xd3>\xb4\xfb\x89R\xd5B\x80O\x1c\xe0\x00\x00\u07d4\xfe\x9c\xfc;\xb2\x93\u0772\x85\xe6%\xf3X/t\xa6\xb0\xa5\xa6\u0349j\xcb=\xf2~\x1f\x88\x00\x00\xe0\x94\xfe\x9e\x11\x97\u05d7JvH\xdc\u01e01\x12\xa8\x8e\xdb\xc9\x04]\x8a\x01\n\xfc\x1a\xde;N\xd4\x00\x00\xe0\x94\xfe\xac\xa2\xactbK\xf3H\xda\u0258QC\xcf\xd6R\xa4\xbeU\x8a\x05\x89\u007f\u02f0)\x14\b\x80\x00\u07d4\xfe\xad\x18\x03\xe5\xe77\xa6\x8e\x18G-\x9a\xc7\x15\xf0\x99L\u00be\x89\x1b\x1a\xe4\xd6\xe2\xefP\x00\x00\u07d4\xfe\xb8\xb8\xe2\xafqj\xe4\x1f\xc7\xc0K\xcf)T\x01VF\x1ek\x89TQt\xa5(\xa7z\x00\x00\u07d4\xfe\xb9-0\xbf\x01\xff\x9a\x19\x01flUsS+\xfa\a\xee\xec\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xfe\xbc1s\xbc\x90r\x13cT\x00+{O\xb3\xbf\xc5?\"\xf1\x89\x14\x0e\xc8\x0f\xa7\xee\x88\x00\x00\u07d4\xfe\xbdH\xd0\xff\xdb\xd5el\xd5\xe6\x866:a\x14R(\xf2y\x89\x97\xc9\xceL\xf6\xd5\xc0\x00\x00\u07d4\xfe\xbd\x9f\x81\xcfx\xbd_\xb6\u0139\xa2K\xd4\x14\xbb\x9b\xfaLN\x89k\xe1\x0f\xb8\xedn\x13\x80\x00\u07d4\xfe\xc0o\xe2{D\u01c4\xb29n\xc9/{\x92:\xd1~\x90w\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xfe\xc1NT\x85\xde+>\xef^t\xc4aF\u06ceEN\x035\x89\t\xb4\x1f\xbf\x9e\n\xec\x00\x00\u07d4\xfe\xd8Gm\x10\u0544\xb3\x8b\xfag7`\x0e\xf1\x9d5\xc4\x1e\u0609b\xa9\x92\xe5:\n\xf0\x00\x00\u07d4\xfe\xef;n\xab\xc9J\xff\xd31\f\x1cM\x0ee7^\x13\x11\x19\x89\x01\x15\x8eF\t\x13\xd0\x00\x00\u07d4\xfe\xf0\x9dp$?9\xed\x8c\xd8\x00\xbf\x96QG\x9e\x8fJ\xca<\x89\n\u05ce\xbcZ\xc6 \x00\x00\u07d4\xfe\xf3\xb3\u07ad\x1ai&\u051a\xa3+\x12\xc2*\xf5M\x9f\xf9\x85\x8965\u026d\xc5\u07a0\x00\x00\u07d4\xff\v|\xb7\x1d\xa9\xd4\xc1\xean\xcc(\xeb\xdaPLc\xf8/\u04498\x8a\x88]\xf2\xfcl\x00\x00\u07d4\xff\f\xc6\u73c9lk\x93[\x8b\xbd@\x00\x00\u07d4\xff'&)AH\xb8lx\xa97$\x97\xe4Y\x89\x8e\xd3\xfe\xe3\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xff=\xedz@\u04ef\xf0\u05e8\xc4_\xa6\x13j\xa0C=\xb4W\x89lh\xcc\u041b\x02,\x00\x00\u07d4\xff>\xeeW\xc3Mm\xae\x97\r\x8b1\x11\x17\xc55\x86\xcd5\x02\x89\\(=A\x03\x94\x10\x00\x00\u07d4\xff>\xf6\xba\x15\x1c!\xb5\x99\x86\xaed\xf6\xe8\"\x8b\u0262\xc73\x89lk\x93[\x8b\xbd@\x00\x00\u07d4\xffA\xd9\xe1\xb4\xef\xfe\x18\u0630\xd1\xf6?\xc4%_\xb4\xe0l=\x89Hz\x9a0E9D\x00\x00\u07d4\xffE\xcb4\xc9(6M\x9c\xc9\u063b\x0074ta\x8f\x06\xf3\x89\x05k\xc7^-c\x10\x00\x00\xe0\x94\xffI\xa7u\x81N\xc0\x00Q\xa7\x95\xa8u\xde$Y.\xa4\x00\u050a*Z\x05\x8f\u0095\xed\x00\x00\x00\u07d4\xffJ@\x8fP\xe9\xe7!F\xa2\x8c\xe4\xfc\x8d\x90'\x1f\x11n\x84\x89j\xcb=\xf2~\x1f\x88\x00\x00\u07d4\xffM\x9c\x84\x84\xc4\x10T\x89H\xa4\x80\xc2?\x80\xc2@\x80\xc2A\x80\xc2B\x80\xc2C\x80\xc2D\x80\xc2E\x80\xc2F\x80\xc2G\x80\xc2H\x80\xc2I\x80\xc2J\x80\xc2K\x80\xc2L\x80\xc2M\x80\xc2N\x80\xc2O\x80\xc2P\x80\xc2Q\x80\xc2R\x80\xc2S\x80\xc2T\x80\xc2U\x80\xc2V\x80\xc2W\x80\xc2X\x80\xc2Y\x80\xc2Z\x80\xc2[\x80\xc2\\\x80\xc2]\x80\xc2^\x80\xc2_\x80\xc2`\x80\xc2a\x80\xc2b\x80\xc2c\x80\xc2d\x80\xc2e\x80\xc2f\x80\xc2g\x80\xc2h\x80\xc2i\x80\xc2j\x80\xc2k\x80\xc2l\x80\xc2m\x80\xc2n\x80\xc2o\x80\xc2p\x80\xc2q\x80\xc2r\x80\xc2s\x80\xc2t\x80\xc2u\x80\xc2v\x80\xc2w\x80\xc2x\x80\xc2y\x80\xc2z\x80\xc2{\x80\xc2|\x80\xc2}\x80\xc2~\x80\xc2\u007f\x80\u00c1\x80\x80\u00c1\x81\x80\u00c1\x82\x80\u00c1\x83\x80\u00c1\x84\x80\u00c1\x85\x80\u00c1\x86\x80\u00c1\x87\x80\u00c1\x88\x80\u00c1\x89\x80\u00c1\x8a\x80\u00c1\x8b\x80\u00c1\x8c\x80\u00c1\x8d\x80\u00c1\x8e\x80\u00c1\x8f\x80\u00c1\x90\x80\u00c1\x91\x80\u00c1\x92\x80\u00c1\x93\x80\u00c1\x94\x80\u00c1\x95\x80\u00c1\x96\x80\u00c1\x97\x80\u00c1\x98\x80\u00c1\x99\x80\u00c1\x9a\x80\u00c1\x9b\x80\u00c1\x9c\x80\u00c1\x9d\x80\u00c1\x9e\x80\u00c1\x9f\x80\u00c1\xa0\x80\u00c1\xa1\x80\u00c1\xa2\x80\u00c1\xa3\x80\u00c1\xa4\x80\u00c1\xa5\x80\u00c1\xa6\x80\u00c1\xa7\x80\u00c1\xa8\x80\u00c1\xa9\x80\u00c1\xaa\x80\u00c1\xab\x80\u00c1\xac\x80\u00c1\xad\x80\u00c1\xae\x80\u00c1\xaf\x80\u00c1\xb0\x80\u00c1\xb1\x80\u00c1\xb2\x80\u00c1\xb3\x80\u00c1\xb4\x80\u00c1\xb5\x80\u00c1\xb6\x80\u00c1\xb7\x80\u00c1\xb8\x80\u00c1\xb9\x80\u00c1\xba\x80\u00c1\xbb\x80\u00c1\xbc\x80\u00c1\xbd\x80\u00c1\xbe\x80\u00c1\xbf\x80\u00c1\xc0\x80\u00c1\xc1\x80\u00c1\u0080\u00c1\u00c0\u00c1\u0100\u00c1\u0140\u00c1\u0180\u00c1\u01c0\u00c1\u0200\u00c1\u0240\u00c1\u0280\u00c1\u02c0\u00c1\u0300\u00c1\u0340\u00c1\u0380\u00c1\u03c0\u00c1\u0400\u00c1\u0440\u00c1\u0480\u00c1\u04c0\u00c1\u0500\u00c1\u0540\u00c1\u0580\u00c1\u05c0\u00c1\u0600\u00c1\u0640\u00c1\u0680\u00c1\u06c0\u00c1\u0700\u00c1\u0740\u00c1\u0780\u00c1\u07c0\u00c1\xe0\x80\u00c1\xe1\x80\u00c1\xe2\x80\u00c1\xe3\x80\u00c1\xe4\x80\u00c1\xe5\x80\u00c1\xe6\x80\u00c1\xe7\x80\u00c1\xe8\x80\u00c1\xe9\x80\u00c1\xea\x80\u00c1\xeb\x80\u00c1\xec\x80\u00c1\xed\x80\u00c1\xee\x80\u00c1\xef\x80\u00c1\xf0\x80\u00c1\xf1\x80\u00c1\xf2\x80\u00c1\xf3\x80\u00c1\xf4\x80\u00c1\xf5\x80\u00c1\xf6\x80\u00c1\xf7\x80\u00c1\xf8\x80\u00c1\xf9\x80\u00c1\xfa\x80\u00c1\xfb\x80\u00c1\xfc\x80\u00c1\xfd\x80\u00c1\xfe\x80\u00c1\xff\x80\u3507KT\xa8\xbd\x15)f\xd6?pk\xae\x1f\xfe\xb0A\x19!\xe5\x8d\f\x9f,\x9c\xd0Ft\xed\xea@\x00\x00\x00" const rinkebyAllocData = "\xf9\x03\xb7\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xf6\x941\xb9\x8d\x14\x00{\xde\xe67)\x80\x86\x98\x8a\v\xbd1\x18E#\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" const goerliAllocData = "\xf9\x04\x06\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xe0\x94L*\xe4\x82Y5\x05\xf0\x16<\xde\xfc\a>\x81\xc6<\xdaA\a\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xa8\xe8\xf1G2e\x8eKQ\xe8q\x191\x05:\x8ai\xba\xf2\xb1\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe1\x94\u0665\x17\x9f\t\x1d\x85\x05\x1d<\x98'\x85\xef\xd1E\\\uc199\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\u08bdBX\xd2v\x887\xba\xa2j(\xfeq\xdc\a\x9f\x84\u01cbJG\xe3\xc1$H\xf4\xad\x00\x00\x00" const sepoliaAllocData = "\xf9\x01\xee\u0791i\x16\xa8{\x823?BE\x04f#\xb27\x94\xc6\\\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\x10\xf5\xd4XT\xe08\a\x14\x85\xac\x9e@#\b\u03c0\xd2\xd2\xfe\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\u0794y\x9d2\x9e_X4\x19\x16|\xd7\"\x96$\x85\x92n3\x8fJ\x88\r\u0db3\xa7d\x00\x00\xe0\x94|\xf5\xb7\x9b\xfe)\x1ag\xab\x02\xb3\x93\xe4V\xcc\xc4\xc2f\xf7S\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x8b\u007f\tw\xbbO\x0f\xbepv\xfa\"\xbc$\xac\xa0CX?^\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa2\xa6\xd949\x14O\xfeM'\xc9\xe0\x88\xdc\u0637\x83\x94bc\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xaa\xec\x869DA\xf9\x15\xbc\xe3\xe6\xab9\x99w\xe9\x90o;i\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u1532\x1c3\xde\x1f\xab?\xa1T\x99\xc6+Y\xfe\f\xc3%\x00 \u044bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xbc\x11)Y6\xaay\u0554\x13\x9d\xe1\xb2\xe1&)AO;\u06ca\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xbe\xef2\xca[\x9a\x19\x8d'\xb4\xe0/LpC\x9f\xe6\x03V\u03ca\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\xd7\xd7lX\xb3\xa5\x19\xe9\xfal\xc4\xd2-\xc0\x17%\x9b\u011f\x1e\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xd7\xed\xdbx\xed)[<\x96)$\x0e\x89$\xfb\x8d\x88t\xdd\u060a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\u0665\x17\x9f\t\x1d\x85\x05\x1d<\x98'\x85\xef\xd1E\\\uc199\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xe2\xe2e\x90(\x147\x84\xd5W\xbc\xeco\xf3\xa0r\x10H\x88\n\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xf4|\xae\x1c\xf7\x9c\xa6u\x8b\xfcx}\xbd!\u6f7eq\x12\xb8\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00" diff --git a/core/genesis_test.go b/core/genesis_test.go index d7030a201ec4..0e966bab0334 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -95,14 +95,14 @@ func TestSetupGenesis(t *testing.T) { wantConfig: customg.Config, }, { - name: "custom block in DB, genesis == ropsten", + name: "custom block in DB, genesis == goerli", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { customg.MustCommit(db) - return SetupGenesisBlock(db, trie.NewDatabase(db), DefaultRopstenGenesisBlock()) + return SetupGenesisBlock(db, trie.NewDatabase(db), DefaultGoerliGenesisBlock()) }, - wantErr: &GenesisMismatchError{Stored: customghash, New: params.RopstenGenesisHash}, - wantHash: params.RopstenGenesisHash, - wantConfig: params.RopstenChainConfig, + wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash}, + wantHash: params.GoerliGenesisHash, + wantConfig: params.GoerliChainConfig, }, { name: "compatible config in DB", @@ -172,7 +172,6 @@ func TestGenesisHashes(t *testing.T) { }{ {DefaultGenesisBlock(), params.MainnetGenesisHash}, {DefaultGoerliGenesisBlock(), params.GoerliGenesisHash}, - {DefaultRopstenGenesisBlock(), params.RopstenGenesisHash}, {DefaultRinkebyGenesisBlock(), params.RinkebyGenesisHash}, {DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash}, } { diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 60654b803051..ae4ec9142e8b 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -127,7 +127,7 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2 // NodeInfo represents a short summary of the `eth` sub-protocol metadata // known about the host peer. type NodeInfo struct { - Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Ropsten=3, Rinkeby=4, Goerli=5) + Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Rinkeby=4, Goerli=5) Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules diff --git a/les/commons.go b/les/commons.go index e83319543d36..860175c8ca4d 100644 --- a/les/commons.go +++ b/les/commons.go @@ -63,7 +63,7 @@ type lesCommons struct { // NodeInfo represents a short summary of the Ethereum sub-protocol metadata // known about the host peer. type NodeInfo struct { - Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Ropsten=3, Rinkeby=4, Goerli=5) + Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Rinkeby=4, Goerli=5) Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules diff --git a/miner/stress/1559/main.go b/miner/stress/1559/main.go index b4ce2a14f287..abc24f4a369b 100644 --- a/miner/stress/1559/main.go +++ b/miner/stress/1559/main.go @@ -59,7 +59,7 @@ func main() { // Pre-generate the ethash mining DAG so we don't race ethash.MakeDataset(1, ethconfig.Defaults.Ethash.DatasetDir) - // Create an Ethash network based off of the Ropsten config + // Create an Ethash network genesis := makeGenesis(faucets) // Handle interrupts. @@ -194,7 +194,7 @@ func makeTransaction(nonce uint64, privKey *ecdsa.PrivateKey, signer types.Signe // makeGenesis creates a custom Ethash genesis block based on some pre-defined // faucet accounts. func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { - genesis := core.DefaultRopstenGenesisBlock() + genesis := core.DefaultGenesisBlock() genesis.Config = params.AllEthashProtocolChanges genesis.Config.LondonBlock = londonBlock diff --git a/miner/stress/beacon/main.go b/miner/stress/beacon/main.go index 9b6d5e6d9357..516862c9cb52 100644 --- a/miner/stress/beacon/main.go +++ b/miner/stress/beacon/main.go @@ -392,7 +392,7 @@ func main() { // Pre-generate the ethash mining DAG so we don't race ethash.MakeDataset(1, filepath.Join(os.Getenv("HOME"), ".ethash")) - // Create an Ethash network based off of the Ropsten config + // Create an Ethash network genesis := makeGenesis(faucets) manager := newNodeManager(genesis) defer manager.shutdown() @@ -440,7 +440,7 @@ func main() { // makeGenesis creates a custom Ethash genesis block based on some pre-defined // faucet accounts. func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { - genesis := core.DefaultRopstenGenesisBlock() + genesis := core.DefaultGenesisBlock() genesis.Difficulty = params.MinimumDifficulty genesis.GasLimit = 25000000 diff --git a/miner/stress/ethash/main.go b/miner/stress/ethash/main.go index 4fe5429e6d7e..6b6e7059d33b 100644 --- a/miner/stress/ethash/main.go +++ b/miner/stress/ethash/main.go @@ -55,7 +55,7 @@ func main() { // Pre-generate the ethash mining DAG so we don't race ethash.MakeDataset(1, ethconfig.Defaults.Ethash.DatasetDir) - // Create an Ethash network based off of the Ropsten config + // Create an Ethash network genesis := makeGenesis(faucets) // Handle interrupts. @@ -134,7 +134,7 @@ func main() { // makeGenesis creates a custom Ethash genesis block based on some pre-defined // faucet accounts. func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { - genesis := core.DefaultRopstenGenesisBlock() + genesis := core.DefaultGenesisBlock() genesis.Difficulty = params.MinimumDifficulty genesis.GasLimit = 25000000 diff --git a/params/bootnodes.go b/params/bootnodes.go index 409e1d19e6c7..0a995bc3c404 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -32,13 +32,6 @@ var MainnetBootnodes = []string{ "enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", // bootnode-hetzner-fsn } -// RopstenBootnodes are the enode URLs of the P2P bootstrap nodes running on the -// Ropsten test network. -var RopstenBootnodes = []string{ - "enode://6332792c4a00e3e4ee0926ed89e0d27ef985424d97b6a45bf0f23e51f0dcb5e66b875777506458aea7af6f9e4ffb69f43f3778ee73c81ed9d34c51c4b16b0b0f@52.232.243.152:30303", // Parity - "enode://94c15d1b9e2fe7ce56e458b9a3b672ef11894ddedd0c6f247e0f1d3487f52b66208fb4aeb8179fce6e3a749ea93ed147c37976d67af557508d199d9594c35f09@192.81.208.223:30303", // @gpip -} - // SepoliaBootnodes are the enode URLs of the P2P bootstrap nodes running on the // Sepolia test network. var SepoliaBootnodes = []string{ @@ -100,8 +93,6 @@ func KnownDNSNetwork(genesis common.Hash, protocol string) string { switch genesis { case MainnetGenesisHash: net = "mainnet" - case RopstenGenesisHash: - net = "ropsten" case RinkebyGenesisHash: net = "rinkeby" case GoerliGenesisHash: diff --git a/params/config.go b/params/config.go index 3196a31de0ce..5d217ef70ecd 100644 --- a/params/config.go +++ b/params/config.go @@ -28,7 +28,6 @@ import ( // Genesis hashes to enforce below configs on. var ( MainnetGenesisHash = common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") - RopstenGenesisHash = common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d") SepoliaGenesisHash = common.HexToHash("0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9") RinkebyGenesisHash = common.HexToHash("0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177") GoerliGenesisHash = common.HexToHash("0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a") @@ -38,7 +37,6 @@ var ( // the chain it belongs to. var TrustedCheckpoints = map[common.Hash]*TrustedCheckpoint{ MainnetGenesisHash: MainnetTrustedCheckpoint, - RopstenGenesisHash: RopstenTrustedCheckpoint, SepoliaGenesisHash: SepoliaTrustedCheckpoint, RinkebyGenesisHash: RinkebyTrustedCheckpoint, GoerliGenesisHash: GoerliTrustedCheckpoint, @@ -48,7 +46,6 @@ var TrustedCheckpoints = map[common.Hash]*TrustedCheckpoint{ // the chain it belongs to. var CheckpointOracles = map[common.Hash]*CheckpointOracleConfig{ MainnetGenesisHash: MainnetCheckpointOracle, - RopstenGenesisHash: RopstenCheckpointOracle, RinkebyGenesisHash: RinkebyCheckpointOracle, GoerliGenesisHash: GoerliCheckpointOracle, } @@ -101,49 +98,6 @@ var ( Threshold: 2, } - // RopstenChainConfig contains the chain parameters to run a node on the Ropsten test network. - RopstenChainConfig = &ChainConfig{ - ChainID: big.NewInt(3), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), - EIP155Block: big.NewInt(10), - EIP158Block: big.NewInt(10), - ByzantiumBlock: big.NewInt(1_700_000), - ConstantinopleBlock: big.NewInt(4_230_000), - PetersburgBlock: big.NewInt(4_939_394), - IstanbulBlock: big.NewInt(6_485_846), - MuirGlacierBlock: big.NewInt(7_117_117), - BerlinBlock: big.NewInt(9_812_189), - LondonBlock: big.NewInt(10_499_401), - TerminalTotalDifficulty: new(big.Int).SetUint64(50_000_000_000_000_000), - TerminalTotalDifficultyPassed: true, - Ethash: new(EthashConfig), - } - - // RopstenTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network. - RopstenTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 393, - SectionHead: common.HexToHash("0x04479087c89428c6ed0d4ff25642776f0c35747d8ecef90547fa3ce4ebec8606"), - CHTRoot: common.HexToHash("0xaa100968cebe48dba3a8f196f044db04113d5a938ff083838ce6f2c588d416ad"), - BloomRoot: common.HexToHash("0xb9108d510c4b50b60793feead27620781bc1c2164e072d8022201c4eb7c36ba0"), - } - - // RopstenCheckpointOracle contains a set of configs for the Ropsten test network oracle. - RopstenCheckpointOracle = &CheckpointOracleConfig{ - Address: common.HexToAddress("0xEF79475013f154E6A65b54cB2742867791bf0B84"), - Signers: []common.Address{ - common.HexToAddress("0x32162F3581E88a5f62e8A61892B42C46E2c18f7b"), // Peter - common.HexToAddress("0x78d1aD571A1A09D60D9BBf25894b44e4C8859595"), // Martin - common.HexToAddress("0x286834935f4A8Cfb4FF4C77D5770C2775aE2b0E7"), // Zsolt - common.HexToAddress("0xb86e2B0Ab5A4B1373e40c51A7C712c70Ba2f9f8E"), // Gary - common.HexToAddress("0x0DF8fa387C602AE62559cC4aFa4972A7045d6707"), // Guillaume - }, - Threshold: 2, - } - // SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network. SepoliaChainConfig = &ChainConfig{ ChainID: big.NewInt(11155111), @@ -389,7 +343,6 @@ var ( // NetworkNames are user friendly names to use in the chain spec banner. var NetworkNames = map[string]string{ MainnetChainConfig.ChainID.String(): "mainnet", - RopstenChainConfig.ChainID.String(): "ropsten", RinkebyChainConfig.ChainID.String(): "rinkeby", GoerliChainConfig.ChainID.String(): "goerli", SepoliaChainConfig.ChainID.String(): "sepolia", diff --git a/tests/difficulty_test.go b/tests/difficulty_test.go index af9b0f86bd9a..a8273303e31f 100644 --- a/tests/difficulty_test.go +++ b/tests/difficulty_test.go @@ -36,6 +36,26 @@ var ( EIP158Block: big.NewInt(2675000), ByzantiumBlock: big.NewInt(4370000), } + + ropstenChainConfig = params.ChainConfig{ + ChainID: big.NewInt(3), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), + EIP155Block: big.NewInt(10), + EIP158Block: big.NewInt(10), + ByzantiumBlock: big.NewInt(1_700_000), + ConstantinopleBlock: big.NewInt(4_230_000), + PetersburgBlock: big.NewInt(4_939_394), + IstanbulBlock: big.NewInt(6_485_846), + MuirGlacierBlock: big.NewInt(7_117_117), + BerlinBlock: big.NewInt(9_812_189), + LondonBlock: big.NewInt(10_499_401), + TerminalTotalDifficulty: new(big.Int).SetUint64(50_000_000_000_000_000), + TerminalTotalDifficultyPassed: true, + } ) func TestDifficulty(t *testing.T) { @@ -53,7 +73,7 @@ func TestDifficulty(t *testing.T) { // files are 2 years old, contains strange values dt.skipLoad("difficultyCustomHomestead\\.json") - dt.config("Ropsten", *params.RopstenChainConfig) + dt.config("Ropsten", ropstenChainConfig) dt.config("Frontier", params.ChainConfig{}) dt.config("Homestead", params.ChainConfig{ @@ -64,7 +84,7 @@ func TestDifficulty(t *testing.T) { ByzantiumBlock: big.NewInt(0), }) - dt.config("Frontier", *params.RopstenChainConfig) + dt.config("Frontier", ropstenChainConfig) dt.config("MainNetwork", mainnetChainConfig) dt.config("CustomMainNetwork", mainnetChainConfig) dt.config("Constantinople", params.ChainConfig{ From ed51b8c5d3de45246ffa3e2caa90e8d25ee6242a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 9 Feb 2023 03:48:34 -0500 Subject: [PATCH 530/715] ethdb: pebble backend (64bit platforms only) (#26517) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ethdb: use pebble Co-authored-by: Gary Rong foo update * apply suggested changes * flags: go format node: fix ddir lookup mistake accounts/abi/bind: fix go.mod replacement for generated binding deps: update pebble + with fix 32-bit build * ethdb/pebble: respect max memtable size * core/rawdb, ethdb: enable pebble on non-32bit platforms only * core/rawdb: fix build tags, fix some review concerns * core/rawdb: refactor methods for database opening * core/rawdb: remove erroneous build tag * cmd/geth: fix the flag default handling + testcase * cmd/geth: improve testing regarding custom backends * ethdb/pebble, deps: update pebble dependency * core/rawdb: replace method with Open * ethdb/pebble: several updates for pebble (#49) * ethdb/pebble: fix size count in batch * ethdb/pebble: disable seek compaction * ethdb/pebble: more fixes * ethdb, core, cmd: polish and fixes (#50) * cmd/utils, core/rawdb, ethdb/pebble: address some review concerns * Update flags.go * ethdb/pebble: minor refactors * ethdb/pebble: avoid copy on batch replay * ethdb: fix compilation flaw * cmd: fix test fail due to mismatching error message * cmd/geth, node: rename backingdb to db.engine --------- Co-authored-by: Jared Wasinger Co-authored-by: rjl493456442 Co-authored-by: Péter Szilágyi --- cmd/geth/genesis_test.go | 101 ++++++ cmd/utils/flags.go | 20 ++ core/blockchain_repair_test.go | 22 +- core/blockchain_sethead_test.go | 5 +- core/blockchain_snapshot_test.go | 11 +- core/rawdb/database.go | 80 ++++- core/rawdb/databases_64bit.go | 37 ++ core/rawdb/databases_non64bit.go | 34 ++ ethdb/leveldb/leveldb.go | 26 +- ethdb/pebble/pebble.go | 570 +++++++++++++++++++++++++++++++ ethdb/pebble/pebble_test.go | 44 +++ go.mod | 30 +- go.sum | 355 ++++++++++++++++++- node/config.go | 2 + node/defaults.go | 1 + node/node.go | 20 +- 16 files changed, 1312 insertions(+), 46 deletions(-) create mode 100644 core/rawdb/databases_64bit.go create mode 100644 core/rawdb/databases_non64bit.go create mode 100644 ethdb/pebble/pebble.go create mode 100644 ethdb/pebble/pebble_test.go diff --git a/cmd/geth/genesis_test.go b/cmd/geth/genesis_test.go index 7667a8581158..8e379b867a7e 100644 --- a/cmd/geth/genesis_test.go +++ b/cmd/geth/genesis_test.go @@ -17,8 +17,10 @@ package main import ( + "fmt" "os" "path/filepath" + "strconv" "testing" ) @@ -70,6 +72,7 @@ var customGenesisTests = []struct { // Tests that initializing Geth with a custom genesis block and chain definitions // work properly. func TestCustomGenesis(t *testing.T) { + t.Parallel() for i, tt := range customGenesisTests { // Create a temporary data directory to use and inspect later datadir := t.TempDir() @@ -90,3 +93,101 @@ func TestCustomGenesis(t *testing.T) { geth.ExpectExit() } } + +// TestCustomBackend that the backend selection and detection (leveldb vs pebble) works properly. +func TestCustomBackend(t *testing.T) { + t.Parallel() + // Test pebble, but only on 64-bit platforms + if strconv.IntSize != 64 { + t.Skip("Custom backends are only available on 64-bit platform") + } + genesis := `{ + "alloc" : {}, + "coinbase" : "0x0000000000000000000000000000000000000000", + "difficulty" : "0x20000", + "extraData" : "", + "gasLimit" : "0x2fefd8", + "nonce" : "0x0000000000001338", + "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp" : "0x00", + "config" : {} + }` + type backendTest struct { + initArgs []string + initExpect string + execArgs []string + execExpect string + } + testfunc := func(t *testing.T, tt backendTest) error { + // Create a temporary data directory to use and inspect later + datadir := t.TempDir() + + // Initialize the data directory with the custom genesis block + json := filepath.Join(datadir, "genesis.json") + if err := os.WriteFile(json, []byte(genesis), 0600); err != nil { + return fmt.Errorf("failed to write genesis file: %v", err) + } + { // Init + args := append(tt.initArgs, "--datadir", datadir, "init", json) + geth := runGeth(t, args...) + geth.ExpectRegexp(tt.initExpect) + geth.ExpectExit() + } + { // Exec + query + args := append(tt.execArgs, "--networkid", "1337", "--syncmode=full", "--cache", "16", + "--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0", + "--nodiscover", "--nat", "none", "--ipcdisable", + "--exec", "eth.getBlock(0).nonce", "console") + geth := runGeth(t, args...) + geth.ExpectRegexp(tt.execExpect) + geth.ExpectExit() + } + return nil + } + for i, tt := range []backendTest{ + { // When not specified, it should default to leveldb + execArgs: []string{"--db.engine", "leveldb"}, + execExpect: "0x0000000000001338", + }, + { // Explicit leveldb + initArgs: []string{"--db.engine", "leveldb"}, + execArgs: []string{"--db.engine", "leveldb"}, + execExpect: "0x0000000000001338", + }, + { // Explicit leveldb first, then autodiscover + initArgs: []string{"--db.engine", "leveldb"}, + execExpect: "0x0000000000001338", + }, + { // Explicit pebble + initArgs: []string{"--db.engine", "pebble"}, + execArgs: []string{"--db.engine", "pebble"}, + execExpect: "0x0000000000001338", + }, + { // Explicit pebble, then auto-discover + initArgs: []string{"--db.engine", "pebble"}, + execExpect: "0x0000000000001338", + }, + { // Can't start pebble on top of leveldb + initArgs: []string{"--db.engine", "leveldb"}, + execArgs: []string{"--db.engine", "pebble"}, + execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was pebble but found pre-existing leveldb database in specified data directory`, + }, + { // Can't start leveldb on top of pebble + initArgs: []string{"--db.engine", "pebble"}, + execArgs: []string{"--db.engine", "leveldb"}, + execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was leveldb but found pre-existing pebble database in specified data directory`, + }, + { // Reject invalid backend choice + initArgs: []string{"--db.engine", "mssql"}, + initExpect: `Fatal: Invalid choice for db.engine 'mssql', allowed 'leveldb' or 'pebble'`, + // Since the init fails, this will return the (default) mainnet genesis + // block nonce + execExpect: `0x0000000000000042`, + }, + } { + if err := testfunc(t, tt); err != nil { + t.Fatalf("test %d-leveldb: %v", i, err) + } + } +} diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index d69be1a42a2b..08de71ee831b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -99,6 +99,12 @@ var ( Usage: "URL for remote database", Category: flags.LoggingCategory, } + DBEngineFlag = &cli.StringFlag{ + Name: "db.engine", + Usage: "Backing database implementation to use ('leveldb' or 'pebble')", + Value: "leveldb", + Category: flags.EthCategory, + } AncientFlag = &flags.DirectoryFlag{ Name: "datadir.ancient", Usage: "Root directory for ancient data (default = inside chaindata)", @@ -1009,6 +1015,12 @@ var ( } ) +func init() { + if rawdb.PebbleEnabled { + DatabasePathFlags = append(DatabasePathFlags, DBEngineFlag) + } +} + // MakeDataDir retrieves the currently requested data directory, terminating // if none (or the empty string) is specified. If the node is starting a testnet, // then a subdirectory of the specified datadir will be used. @@ -1484,6 +1496,14 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { if ctx.IsSet(InsecureUnlockAllowedFlag.Name) { cfg.InsecureUnlockAllowed = ctx.Bool(InsecureUnlockAllowedFlag.Name) } + if ctx.IsSet(DBEngineFlag.Name) { + dbEngine := ctx.String(DBEngineFlag.Name) + if dbEngine != "leveldb" && dbEngine != "pebble" { + Fatalf("Invalid choice for db.engine '%s', allowed 'leveldb' or 'pebble'", dbEngine) + } + log.Info(fmt.Sprintf("Using %s as db engine", dbEngine)) + cfg.DBEngine = dbEngine + } } func setSmartCard(ctx *cli.Context, cfg *node.Config) { diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 0fdd5ae27999..5db0fb5703d3 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1756,7 +1756,10 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { // Create a temporary persistent database datadir := t.TempDir() - db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) + db, err := rawdb.Open(rawdb.OpenOptions{ + Directory: datadir, + AncientsDirectory: datadir, + }) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } @@ -1829,7 +1832,11 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us - db, err = rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) + db, err = rawdb.Open(rawdb.OpenOptions{ + Directory: datadir, + AncientsDirectory: datadir, + }) + if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } @@ -1884,7 +1891,11 @@ func TestIssue23496(t *testing.T) { // Create a temporary persistent database datadir := t.TempDir() - db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) + db, err := rawdb.Open(rawdb.OpenOptions{ + Directory: datadir, + AncientsDirectory: datadir, + }) + if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } @@ -1944,7 +1955,10 @@ func TestIssue23496(t *testing.T) { chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us - db, err = rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) + db, err = rawdb.Open(rawdb.OpenOptions{ + Directory: datadir, + AncientsDirectory: datadir, + }) if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index fa55c6252d15..825a0e16b430 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -1956,7 +1956,10 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { // Create a temporary persistent database datadir := t.TempDir() - db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) + db, err := rawdb.Open(rawdb.OpenOptions{ + Directory: datadir, + AncientsDirectory: datadir, + }) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index 110d2d1e3c77..b34ea573c1ae 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -61,7 +61,10 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo // Create a temporary persistent database datadir := t.TempDir() - db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) + db, err := rawdb.Open(rawdb.OpenOptions{ + Directory: datadir, + AncientsDirectory: datadir, + }) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } @@ -250,7 +253,11 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us - newdb, err := rawdb.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "", false) + newdb, err := rawdb.Open(rawdb.OpenOptions{ + Directory: snaptest.datadir, + AncientsDirectory: snaptest.datadir, + }) + if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index cc4799792cfa..ef80c251a457 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -22,6 +22,7 @@ import ( "fmt" "os" "path" + "path/filepath" "strings" "sync/atomic" "time" @@ -302,19 +303,84 @@ func NewLevelDBDatabase(file string, cache int, handles int, namespace string, r if err != nil { return nil, err } + log.Info("Using LevelDB as the backing database") return NewDatabase(db), nil } -// NewLevelDBDatabaseWithFreezer creates a persistent key-value database with a -// freezer moving immutable chain segments into cold storage. The passed ancient -// indicates the path of root ancient directory where the chain freezer can be -// opened. -func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, ancient string, namespace string, readonly bool) (ethdb.Database, error) { - kvdb, err := leveldb.New(file, cache, handles, namespace, readonly) +const ( + dbPebble = "pebble" + dbLeveldb = "leveldb" +) + +// hasPreexistingDb checks the given data directory whether a database is already +// instantiated at that location, and if so, returns the type of database (or the +// empty string). +func hasPreexistingDb(path string) string { + if _, err := os.Stat(filepath.Join(path, "CURRENT")); err != nil { + return "" // No pre-existing db + } + if matches, err := filepath.Glob(filepath.Join(path, "OPTIONS*")); len(matches) > 0 || err != nil { + if err != nil { + panic(err) // only possible if the pattern is malformed + } + return dbPebble + } + return dbLeveldb +} + +// OpenOptions contains the options to apply when opening a database. +// OBS: If AncientsDirectory is empty, it indicates that no freezer is to be used. +type OpenOptions struct { + Type string // "leveldb" | "pebble" + Directory string // the datadir + AncientsDirectory string // the ancients-dir + Namespace string // the namespace for database relevant metrics + Cache int // the capacity(in megabytes) of the data caching + Handles int // number of files to be open simultaneously + ReadOnly bool +} + +// openKeyValueDatabase opens a disk-based key-value database, e.g. leveldb or pebble. +// +// type == null type != null +// +---------------------------------------- +// db is non-existent | leveldb default | specified type +// db is existent | from db | specified type (if compatible) +func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) { + existingDb := hasPreexistingDb(o.Directory) + if len(existingDb) != 0 && len(o.Type) != 0 && o.Type != existingDb { + return nil, fmt.Errorf("db.engine choice was %v but found pre-existing %v database in specified data directory", o.Type, existingDb) + } + if o.Type == dbPebble || existingDb == dbPebble { + if PebbleEnabled { + log.Info("Using pebble as the backing database") + return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) + } else { + return nil, errors.New("db.engine 'pebble' not supported on this platform") + } + } + if len(o.Type) != 0 && o.Type != dbLeveldb { + return nil, fmt.Errorf("unknown db.engine %v", o.Type) + } + log.Info("Using leveldb as the backing database") + // Use leveldb, either as default (no explicit choice), or pre-existing, or chosen explicitly + return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) +} + +// Open opens both a disk-based key-value database such as leveldb or pebble, but also +// integrates it with a freezer database -- if the AncientDir option has been +// set on the provided OpenOptions. +// The passed o.AncientDir indicates the path of root ancient directory where +// the chain freezer can be opened. +func Open(o OpenOptions) (ethdb.Database, error) { + kvdb, err := openKeyValueDatabase(o) if err != nil { return nil, err } - frdb, err := NewDatabaseWithFreezer(kvdb, ancient, namespace, readonly) + if len(o.AncientsDirectory) == 0 { + return kvdb, nil + } + frdb, err := NewDatabaseWithFreezer(kvdb, o.AncientsDirectory, o.Namespace, o.ReadOnly) if err != nil { kvdb.Close() return nil, err diff --git a/core/rawdb/databases_64bit.go b/core/rawdb/databases_64bit.go new file mode 100644 index 000000000000..139ce7d34777 --- /dev/null +++ b/core/rawdb/databases_64bit.go @@ -0,0 +1,37 @@ +// Copyright 2023 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 arm64 || amd64 + +package rawdb + +import ( + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/pebble" +) + +// Pebble is unsuported on 32bit architecture +const PebbleEnabled = true + +// NewPebbleDBDatabase creates a persistent key-value database without a freezer +// moving immutable chain segments into cold storage. +func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) { + db, err := pebble.New(file, cache, handles, namespace, readonly) + if err != nil { + return nil, err + } + return NewDatabase(db), nil +} diff --git a/core/rawdb/databases_non64bit.go b/core/rawdb/databases_non64bit.go new file mode 100644 index 000000000000..b8ab2ecada2f --- /dev/null +++ b/core/rawdb/databases_non64bit.go @@ -0,0 +1,34 @@ +// Copyright 2023 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 !(arm64 || amd64) + +package rawdb + +import ( + "errors" + + "github.com/ethereum/go-ethereum/ethdb" +) + +// Pebble is unsuported on 32bit architecture +const PebbleEnabled = false + +// NewPebbleDBDatabase creates a persistent key-value database without a freezer +// moving immutable chain segments into cold storage. +func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) { + return nil, errors.New("pebble is not supported on this platform") +} diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 0467531721c2..ce13659d9d97 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -63,18 +63,19 @@ type Database struct { fn string // filename for reporting db *leveldb.DB // LevelDB instance - compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction - compReadMeter metrics.Meter // Meter for measuring the data read during compaction - compWriteMeter metrics.Meter // Meter for measuring the data written during compaction - writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction - writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction - diskSizeGauge metrics.Gauge // Gauge for tracking the size of all the levels in the database - diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read - diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written - memCompGauge metrics.Gauge // Gauge for tracking the number of memory compaction - level0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in level0 - nonlevel0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in non0 level - seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt + compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction + compReadMeter metrics.Meter // Meter for measuring the data read during compaction + compWriteMeter metrics.Meter // Meter for measuring the data written during compaction + writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction + writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction + diskSizeGauge metrics.Gauge // Gauge for tracking the size of all the levels in the database + diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read + diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written + memCompGauge metrics.Gauge // Gauge for tracking the number of memory compaction + level0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in level0 + nonlevel0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in non0 level + seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt + manualMemAllocGauge metrics.Gauge // Gauge to track the amount of memory that has been manually allocated (not a part of runtime/GC) quitLock sync.Mutex // Mutex protecting the quit channel access quitChan chan chan error // Quit channel to stop the metrics collection before closing the database @@ -143,6 +144,7 @@ func NewCustom(file string, namespace string, customize func(options *opt.Option ldb.level0CompGauge = metrics.NewRegisteredGauge(namespace+"compact/level0", nil) ldb.nonlevel0CompGauge = metrics.NewRegisteredGauge(namespace+"compact/nonlevel0", nil) ldb.seekCompGauge = metrics.NewRegisteredGauge(namespace+"compact/seek", nil) + ldb.manualMemAllocGauge = metrics.NewRegisteredGauge(namespace+"memory/manualalloc", nil) // Start up the metrics gathering and return go ldb.meter(metricsGatheringInterval) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go new file mode 100644 index 000000000000..c850dc5a1b2a --- /dev/null +++ b/ethdb/pebble/pebble.go @@ -0,0 +1,570 @@ +// Copyright 2023 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 arm64 || amd64 + +// Package pebble implements the key-value database layer based on pebble. +package pebble + +import ( + "fmt" + "runtime" + "sync" + "sync/atomic" + "time" + + "github.com/cockroachdb/pebble" + "github.com/cockroachdb/pebble/bloom" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" +) + +const ( + // minCache is the minimum amount of memory in megabytes to allocate to pebble + // read and write caching, split half and half. + minCache = 16 + + // minHandles is the minimum number of files handles to allocate to the open + // database files. + minHandles = 16 + + // metricsGatheringInterval specifies the interval to retrieve pebble database + // compaction, io and pause stats to report to the user. + metricsGatheringInterval = 3 * time.Second +) + +// Database is a persistent key-value store based on the pebble storage engine. +// Apart from basic data storage functionality it also supports batch writes and +// iterating over the keyspace in binary-alphabetical order. +type Database struct { + fn string // filename for reporting + db *pebble.DB // Underlying pebble storage engine + + compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction + compReadMeter metrics.Meter // Meter for measuring the data read during compaction + compWriteMeter metrics.Meter // Meter for measuring the data written during compaction + writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction + writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction + diskSizeGauge metrics.Gauge // Gauge for tracking the size of all the levels in the database + diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read + diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written + memCompGauge metrics.Gauge // Gauge for tracking the number of memory compaction + level0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in level0 + nonlevel0CompGauge metrics.Gauge // Gauge for tracking the number of table compaction in non0 level + seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt + manualMemAllocGauge metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated + + quitLock sync.Mutex // Mutex protecting the quit channel access + quitChan chan chan error // Quit channel to stop the metrics collection before closing the database + + log log.Logger // Contextual logger tracking the database path + + activeComp int // Current number of active compactions + compStartTime time.Time // The start time of the earliest currently-active compaction + compTime int64 // Total time spent in compaction in ns + level0Comp uint32 // Total number of level-zero compactions + nonLevel0Comp uint32 // Total number of non level-zero compactions + writeDelayStartTime time.Time // The start time of the latest write stall + writeDelayCount int64 // Total number of write stall counts + writeDelayTime int64 // Total time spent in write stalls +} + +func (d *Database) onCompactionBegin(info pebble.CompactionInfo) { + if d.activeComp == 0 { + d.compStartTime = time.Now() + } + l0 := info.Input[0] + if l0.Level == 0 { + atomic.AddUint32(&d.level0Comp, 1) + } else { + atomic.AddUint32(&d.nonLevel0Comp, 1) + } + d.activeComp++ +} + +func (d *Database) onCompactionEnd(info pebble.CompactionInfo) { + if d.activeComp == 1 { + atomic.AddInt64(&d.compTime, int64(time.Since(d.compStartTime))) + } else if d.activeComp == 0 { + panic("should not happen") + } + d.activeComp-- +} + +func (d *Database) onWriteStallBegin(b pebble.WriteStallBeginInfo) { + d.writeDelayStartTime = time.Now() +} + +func (d *Database) onWriteStallEnd() { + atomic.AddInt64(&d.writeDelayTime, int64(time.Since(d.writeDelayStartTime))) +} + +// New returns a wrapped pebble DB object. The namespace is the prefix that the +// metrics reporting should use for surfacing internal stats. +func New(file string, cache int, handles int, namespace string, readonly bool) (*Database, error) { + var db *Database + // Ensure we have some minimal caching and file guarantees + if cache < minCache { + cache = minCache + } + if handles < minHandles { + handles = minHandles + } + logger := log.New("database", file) + logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024), "handles", handles) + + // The max memtable size is limited by the uint32 offsets stored in + // internal/arenaskl.node, DeferredBatchOp, and flushableBatchEntry. + // Taken from https://github.com/cockroachdb/pebble/blob/master/open.go#L38 + maxMemTableSize := 4 << 30 // 4 GB + + // Two memory tables is configured which is identical to leveldb, + // including a frozen memory table and another live one. + memTableLimit := 2 + memTableSize := cache * 1024 * 1024 / 2 / memTableLimit + if memTableSize > maxMemTableSize { + memTableSize = maxMemTableSize + } + opt := &pebble.Options{ + // Pebble has a single combined cache area and the write + // buffers are taken from this too. Assign all available + // memory allowance for cache. + Cache: pebble.NewCache(int64(cache * 1024 * 1024)), + MaxOpenFiles: handles, + + // The size of memory table(as well as the write buffer). + // Note, there may have more than two memory tables in the system. + MemTableSize: memTableSize, + + // MemTableStopWritesThreshold places a hard limit on the size + // of the existent MemTables(including the frozen one). + MemTableStopWritesThreshold: memTableLimit * memTableSize, + + // The default compaction concurrency(1 thread), + // Here use all available CPUs for faster compaction. + MaxConcurrentCompactions: func() int { return runtime.NumCPU() }, + + // Per-level options. Options for at least one level must be specified. The + // options for the last level are used for all subsequent levels. + Levels: []pebble.LevelOptions{ + {TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, + {TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, + {TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, + {TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, + {TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, + {TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, + {TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)}, + }, + ReadOnly: readonly, + EventListener: &pebble.EventListener{ + CompactionBegin: db.onCompactionBegin, + CompactionEnd: db.onCompactionEnd, + WriteStallBegin: db.onWriteStallBegin, + WriteStallEnd: db.onWriteStallEnd, + }, + } + // Disable seek compaction explicitly. Check https://github.com/ethereum/go-ethereum/pull/20130 + // for more details. + opt.Experimental.ReadSamplingMultiplier = -1 + + // Open the db and recover any potential corruptions + innerDB, err := pebble.Open(file, opt) + if err != nil { + return nil, err + } + // Assemble the wrapper with all the registered metrics + db = &Database{ + fn: file, + db: innerDB, + log: logger, + quitChan: make(chan chan error), + } + db.compTimeMeter = metrics.NewRegisteredMeter(namespace+"compact/time", nil) + db.compReadMeter = metrics.NewRegisteredMeter(namespace+"compact/input", nil) + db.compWriteMeter = metrics.NewRegisteredMeter(namespace+"compact/output", nil) + db.diskSizeGauge = metrics.NewRegisteredGauge(namespace+"disk/size", nil) + db.diskReadMeter = metrics.NewRegisteredMeter(namespace+"disk/read", nil) + db.diskWriteMeter = metrics.NewRegisteredMeter(namespace+"disk/write", nil) + db.writeDelayMeter = metrics.NewRegisteredMeter(namespace+"compact/writedelay/duration", nil) + db.writeDelayNMeter = metrics.NewRegisteredMeter(namespace+"compact/writedelay/counter", nil) + db.memCompGauge = metrics.NewRegisteredGauge(namespace+"compact/memory", nil) + db.level0CompGauge = metrics.NewRegisteredGauge(namespace+"compact/level0", nil) + db.nonlevel0CompGauge = metrics.NewRegisteredGauge(namespace+"compact/nonlevel0", nil) + db.seekCompGauge = metrics.NewRegisteredGauge(namespace+"compact/seek", nil) + db.manualMemAllocGauge = metrics.NewRegisteredGauge(namespace+"memory/manualalloc", nil) + + // Start up the metrics gathering and return + go db.meter(metricsGatheringInterval) + return db, nil +} + +// Close stops the metrics collection, flushes any pending data to disk and closes +// all io accesses to the underlying key-value store. +func (d *Database) Close() error { + d.quitLock.Lock() + defer d.quitLock.Unlock() + + if d.quitChan != nil { + errc := make(chan error) + d.quitChan <- errc + if err := <-errc; err != nil { + d.log.Error("Metrics collection failed", "err", err) + } + d.quitChan = nil + } + return d.db.Close() +} + +// Has retrieves if a key is present in the key-value store. +func (d *Database) Has(key []byte) (bool, error) { + _, closer, err := d.db.Get(key) + if err == pebble.ErrNotFound { + return false, nil + } else if err != nil { + return false, err + } + closer.Close() + return true, nil +} + +// Get retrieves the given key if it's present in the key-value store. +func (d *Database) Get(key []byte) ([]byte, error) { + dat, closer, err := d.db.Get(key) + if err != nil { + return nil, err + } + ret := make([]byte, len(dat)) + copy(ret, dat) + closer.Close() + return ret, nil +} + +// Put inserts the given value into the key-value store. +func (d *Database) Put(key []byte, value []byte) error { + return d.db.Set(key, value, pebble.NoSync) +} + +// Delete removes the key from the key-value store. +func (d *Database) Delete(key []byte) error { + return d.db.Delete(key, nil) +} + +// NewBatch creates a write-only key-value store that buffers changes to its host +// database until a final write is called. +func (d *Database) NewBatch() ethdb.Batch { + return &batch{ + b: d.db.NewBatch(), + } +} + +// NewBatchWithSize creates a write-only database batch with pre-allocated buffer. +// TODO can't do this with pebble. Batches are allocated in a pool so maybe this doesn't matter? +func (d *Database) NewBatchWithSize(_ int) ethdb.Batch { + return &batch{ + b: d.db.NewBatch(), + } +} + +// snapshot wraps a pebble snapshot for implementing the Snapshot interface. +type snapshot struct { + db *pebble.Snapshot +} + +// NewSnapshot creates a database snapshot based on the current state. +// The created snapshot will not be affected by all following mutations +// happened on the database. +// Note don't forget to release the snapshot once it's used up, otherwise +// the stale data will never be cleaned up by the underlying compactor. +func (d *Database) NewSnapshot() (ethdb.Snapshot, error) { + snap := d.db.NewSnapshot() + return &snapshot{db: snap}, nil +} + +// Has retrieves if a key is present in the snapshot backing by a key-value +// data store. +func (snap *snapshot) Has(key []byte) (bool, error) { + _, closer, err := snap.db.Get(key) + if err != nil { + if err != pebble.ErrNotFound { + return false, err + } else { + return false, nil + } + } + closer.Close() + return true, nil +} + +// Get retrieves the given key if it's present in the snapshot backing by +// key-value data store. +func (snap *snapshot) Get(key []byte) ([]byte, error) { + dat, closer, err := snap.db.Get(key) + if err != nil { + return nil, err + } + ret := make([]byte, len(dat)) + copy(ret, dat) + closer.Close() + return ret, nil +} + +// Release releases associated resources. Release should always succeed and can +// be called multiple times without causing error. +func (snap *snapshot) Release() { + snap.db.Close() +} + +// upperBound returns the upper bound for the given prefix +func upperBound(prefix []byte) (limit []byte) { + for i := len(prefix) - 1; i >= 0; i-- { + c := prefix[i] + if c == 0xff { + continue + } + limit = make([]byte, i+1) + copy(limit, prefix) + limit[i] = c + 1 + break + } + return limit +} + +// Stat returns a particular internal stat of the database. +func (d *Database) Stat(property string) (string, error) { + return "", nil +} + +// Compact flattens the underlying data store for the given key range. In essence, +// deleted and overwritten versions are discarded, and the data is rearranged to +// reduce the cost of operations needed to access them. +// +// A nil start is treated as a key before all keys in the data store; a nil limit +// is treated as a key after all keys in the data store. If both is nil then it +// will compact entire data store. +func (d *Database) Compact(start []byte, limit []byte) error { + return d.db.Compact(start, limit, true) // Parallelization is preferred +} + +// Path returns the path to the database directory. +func (d *Database) Path() string { + return d.fn +} + +// meter periodically retrieves internal pebble counters and reports them to +// the metrics subsystem. +func (d *Database) meter(refresh time.Duration) { + var errc chan error + timer := time.NewTimer(refresh) + defer timer.Stop() + + // Create storage and warning log tracer for write delay. + var ( + compTimes [2]int64 + writeDelayTimes [2]int64 + writeDelayCounts [2]int64 + compWrites [2]int64 + compReads [2]int64 + + nWrites [2]int64 + ) + + // Iterate ad infinitum and collect the stats + for i := 1; errc == nil; i++ { + var ( + compWrite int64 + compRead int64 + nWrite int64 + + metrics = d.db.Metrics() + compTime = atomic.LoadInt64(&d.compTime) + writeDelayCount = atomic.LoadInt64(&d.writeDelayCount) + writeDelayTime = atomic.LoadInt64(&d.writeDelayTime) + nonLevel0CompCount = int64(atomic.LoadUint32(&d.nonLevel0Comp)) + level0CompCount = int64(atomic.LoadUint32(&d.level0Comp)) + ) + writeDelayTimes[i%2] = writeDelayTime + writeDelayCounts[i%2] = writeDelayCount + compTimes[i%2] = compTime + + for _, levelMetrics := range metrics.Levels { + nWrite += int64(levelMetrics.BytesCompacted) + nWrite += int64(levelMetrics.BytesFlushed) + compWrite += int64(levelMetrics.BytesCompacted) + compRead += int64(levelMetrics.BytesRead) + } + + nWrite += int64(metrics.WAL.BytesWritten) + + compWrites[i%2] = compWrite + compReads[i%2] = compRead + nWrites[i%2] = nWrite + + if d.writeDelayNMeter != nil { + d.writeDelayNMeter.Mark(writeDelayCounts[i%2] - writeDelayCounts[(i-1)%2]) + } + if d.writeDelayMeter != nil { + d.writeDelayMeter.Mark(writeDelayTimes[i%2] - writeDelayTimes[(i-1)%2]) + } + if d.compTimeMeter != nil { + d.compTimeMeter.Mark(compTimes[i%2] - compTimes[(i-1)%2]) + } + if d.compReadMeter != nil { + d.compReadMeter.Mark(compReads[i%2] - compReads[(i-1)%2]) + } + if d.compWriteMeter != nil { + d.compWriteMeter.Mark(compWrites[i%2] - compWrites[(i-1)%2]) + } + if d.diskSizeGauge != nil { + d.diskSizeGauge.Update(int64(metrics.DiskSpaceUsage())) + } + if d.diskReadMeter != nil { + d.diskReadMeter.Mark(0) // pebble doesn't track non-compaction reads + } + if d.diskWriteMeter != nil { + d.diskWriteMeter.Mark(nWrites[i%2] - nWrites[(i-1)%2]) + } + // See https://github.com/cockroachdb/pebble/pull/1628#pullrequestreview-1026664054 + manuallyAllocated := metrics.BlockCache.Size + int64(metrics.MemTable.Size) + int64(metrics.MemTable.ZombieSize) + d.manualMemAllocGauge.Update(manuallyAllocated) + d.memCompGauge.Update(metrics.Flush.Count) + d.nonlevel0CompGauge.Update(nonLevel0CompCount) + d.level0CompGauge.Update(level0CompCount) + d.seekCompGauge.Update(metrics.Compact.ReadCount) + + // Sleep a bit, then repeat the stats collection + select { + case errc = <-d.quitChan: + // Quit requesting, stop hammering the database + case <-timer.C: + timer.Reset(refresh) + // Timeout, gather a new set of stats + } + } + errc <- nil +} + +// batch is a write-only batch that commits changes to its host database +// when Write is called. A batch cannot be used concurrently. +type batch struct { + b *pebble.Batch + size int +} + +// Put inserts the given value into the batch for later committing. +func (b *batch) Put(key, value []byte) error { + b.b.Set(key, value, nil) + b.size += len(key) + len(value) + return nil +} + +// Delete inserts the a key removal into the batch for later committing. +func (b *batch) Delete(key []byte) error { + b.b.Delete(key, nil) + b.size += len(key) + return nil +} + +// ValueSize retrieves the amount of data queued up for writing. +func (b *batch) ValueSize() int { + return b.size +} + +// Write flushes any accumulated data to disk. +func (b *batch) Write() error { + return b.b.Commit(pebble.NoSync) +} + +// Reset resets the batch for reuse. +func (b *batch) Reset() { + b.b.Reset() + b.size = 0 +} + +// Replay replays the batch contents. +func (b *batch) Replay(w ethdb.KeyValueWriter) error { + reader := b.b.Reader() + for { + kind, k, v, ok := reader.Next() + if !ok { + break + } + // The (k,v) slices might be overwritten if the batch is reset/reused, + // and the receiver should copy them if they are to be retained long-term. + if kind == pebble.InternalKeyKindSet { + w.Put(k, v) + } else if kind == pebble.InternalKeyKindDelete { + w.Delete(k) + } else { + return fmt.Errorf("unhandled operation, keytype: %v", kind) + } + } + return nil +} + +// pebbleIterator is a wrapper of underlying iterator in storage engine. +// The purpose of this structure is to implement the missing APIs. +type pebbleIterator struct { + iter *pebble.Iterator + moved bool +} + +// NewIterator creates a binary-alphabetical iterator over a subset +// of database content with a particular key prefix, starting at a particular +// initial key (or after, if it does not exist). +func (d *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator { + iter := d.db.NewIter(&pebble.IterOptions{ + LowerBound: append(prefix, start...), + UpperBound: upperBound(prefix), + }) + iter.First() + return &pebbleIterator{iter: iter, moved: true} +} + +// Next moves the iterator to the next key/value pair. It returns whether the +// iterator is exhausted. +func (iter *pebbleIterator) Next() bool { + if iter.moved { + iter.moved = false + return iter.iter.Valid() + } + return iter.iter.Next() +} + +// Error returns any accumulated error. Exhausting all the key/value pairs +// is not considered to be an error. +func (iter *pebbleIterator) Error() error { + return iter.iter.Error() +} + +// Key returns the key of the current key/value pair, or nil if done. The caller +// should not modify the contents of the returned slice, and its contents may +// change on the next call to Next. +func (iter *pebbleIterator) Key() []byte { + return iter.iter.Key() +} + +// Value returns the value of the current key/value pair, or nil if done. The +// caller should not modify the contents of the returned slice, and its contents +// may change on the next call to Next. +func (iter *pebbleIterator) Value() []byte { + return iter.iter.Value() +} + +// Release releases associated resources. Release should always succeed and can +// be called multiple times without causing error. +func (iter *pebbleIterator) Release() { iter.iter.Close() } diff --git a/ethdb/pebble/pebble_test.go b/ethdb/pebble/pebble_test.go new file mode 100644 index 000000000000..18b800e8aba9 --- /dev/null +++ b/ethdb/pebble/pebble_test.go @@ -0,0 +1,44 @@ +// Copyright 2023 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 arm64 || amd64 + +package pebble + +import ( + "testing" + + "github.com/cockroachdb/pebble" + "github.com/cockroachdb/pebble/vfs" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethdb/dbtest" +) + +func TestPebbleDB(t *testing.T) { + t.Run("DatabaseSuite", func(t *testing.T) { + dbtest.TestDatabaseSuite(t, func() ethdb.KeyValueStore { + db, err := pebble.Open("", &pebble.Options{ + FS: vfs.NewMem(), + }) + if err != nil { + t.Fatal(err) + } + return &Database{ + db: db, + } + }) + }) +} diff --git a/go.mod b/go.mod index 8860447f089a..5f185e628ec5 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.2.0 github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.14.0 + github.com/cockroachdb/pebble v0.0.0-20230203182935-f2e58dc4a0e1 github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 @@ -41,10 +42,10 @@ require ( github.com/influxdata/influxdb-client-go/v2 v2.4.0 github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e - github.com/julienschmidt/httprouter v1.2.0 + github.com/julienschmidt/httprouter v1.3.0 github.com/karalabe/usb v0.0.2 - github.com/mattn/go-colorable v0.1.8 - github.com/mattn/go-isatty v0.0.12 + github.com/mattn/go-colorable v0.1.11 + github.com/mattn/go-isatty v0.0.14 github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 @@ -59,7 +60,7 @@ require ( github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa golang.org/x/crypto v0.1.0 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 - golang.org/x/sys v0.2.0 + golang.org/x/sys v0.3.0 golang.org/x/text v0.4.0 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/tools v0.1.12 @@ -69,13 +70,19 @@ require ( require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect + github.com/DataDog/zstd v1.4.5 // indirect github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect github.com/aws/smithy-go v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cockroachdb/errors v1.8.1 // indirect + github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect + github.com/cockroachdb/redact v1.0.8 // indirect + github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 // indirect @@ -85,9 +92,14 @@ require ( github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect + github.com/klauspost/compress v1.15.15 // indirect + github.com/kr/pretty v0.3.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect @@ -95,14 +107,20 @@ require ( github.com/opentracing/opentracing-go v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.12.0 // indirect + github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/rogpeppe/go-internal v1.6.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.1.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect - google.golang.org/protobuf v1.26.0 // indirect + google.golang.org/protobuf v1.27.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index 400bcce8c9d1..b96fec448705 100644 --- a/go.sum +++ b/go.sum @@ -8,16 +8,34 @@ cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTj cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 h1:qoVeMsc9/fh/yhxVaA0obYjVH/oI/ihrOoMwsLS9KSA= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 h1:E+m3SkZCN0Bf5q7YdTs5lSm2CYY3CK4spn5OmUIiQtk= @@ -26,19 +44,31 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go-v2 v1.2.0 h1:BS+UYpbsElC82gB+2E2jiCBg36i8HlubTB/dO/moQ9c= github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= github.com/aws/aws-sdk-go-v2/config v1.1.1 h1:ZAoq32boMzcaTW9bcUacBswAmHTbvlvDJICgHFZuECo= @@ -57,8 +87,11 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 h1:TJoIfnIFubCX0ACVeJ0w46HEH5Mwj github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0 h1:D6CSsM3gdxaGaqXnPgOBCeL6Mophqzu7KJOu7zW78sU= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= @@ -69,18 +102,39 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= +github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= +github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= +github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/cockroachdb/pebble v0.0.0-20230203182935-f2e58dc4a0e1 h1:g6MDPQ7X2UK1K4cHB5uBguGwudRBoFJ2aeK5DBP0Y8k= +github.com/cockroachdb/pebble v0.0.0-20230203182935-f2e58dc4a0e1/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= +github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= +github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c h1:llSLg4o9EgH3SrXky+Q5BqEYqV76NGKo07K5Ps2pIKo= github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -101,8 +155,10 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeC github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= @@ -117,17 +173,25 @@ github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 h1:kgvzE5wLsLa7XKfV85V github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -135,6 +199,7 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgxrzK5E1fW7RQGeDwE8F/ZZnUYc= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 h1:AB7YjNrzlVHsYz06zCULVV2zYCEft82P86dSmtwxKL0= @@ -142,16 +207,26 @@ github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732/go.mod h1:o/XfIX github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -162,9 +237,17 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= @@ -172,18 +255,28 @@ github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgR github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +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= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -192,6 +285,7 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= @@ -200,15 +294,24 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= @@ -217,14 +320,17 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw= github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= @@ -235,7 +341,9 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= github.com/influxdata/influxdb v1.8.3 h1:WEypI1BQFTT4teLM+1qkEcvUi0dAvopAI/ir0vAiBg8= @@ -251,31 +359,54 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= +github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e h1:UvSe12bq+Uj2hWd8aOlwPmoZ+CITRFrdit+sDGfAg8U= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= +github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= +github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -287,30 +418,43 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= +github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= @@ -318,15 +462,23 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -334,6 +486,7 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -344,11 +497,14 @@ github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mo github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -358,14 +514,29 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= +github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y= +github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= @@ -374,22 +545,32 @@ github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBO github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -415,26 +596,47 @@ github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefld github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -452,6 +654,11 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 h1:rxKZ2gOnYxjfmakvUUqh9Gyb6KXfrj7JWTxORTYqb0E= +golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -463,34 +670,57 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= @@ -500,12 +730,17 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -514,27 +749,45 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -543,12 +796,17 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -561,18 +819,21 @@ golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -585,10 +846,32 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -610,11 +893,22 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -629,27 +923,61 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -658,6 +986,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -671,7 +1000,11 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/node/config.go b/node/config.go index 43ac824a0767..37a7d5837fa2 100644 --- a/node/config.go +++ b/node/config.go @@ -202,6 +202,8 @@ type Config struct { // EnablePersonal enables the deprecated personal namespace. EnablePersonal bool `toml:"-"` + + DBEngine string `toml:",omitempty"` } // IPCEndpoint resolves an IPC endpoint based on a configured value, taking into diff --git a/node/defaults.go b/node/defaults.go index fd0277e29dc9..96ebed81c536 100644 --- a/node/defaults.go +++ b/node/defaults.go @@ -64,6 +64,7 @@ var DefaultConfig = Config{ MaxPeers: 50, NAT: nat.Any(), }, + DBEngine: "", } // DefaultDataDir is the default data directory to use for the databases and other diff --git a/node/node.go b/node/node.go index 760e34d33597..112a771ab090 100644 --- a/node/node.go +++ b/node/node.go @@ -709,7 +709,14 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r if n.config.DataDir == "" { db = rawdb.NewMemoryDatabase() } else { - db, err = rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace, readonly) + db, err = rawdb.Open(rawdb.OpenOptions{ + Type: n.config.DBEngine, + Directory: n.ResolvePath(name), + Namespace: namespace, + Cache: cache, + Handles: handles, + ReadOnly: readonly, + }) } if err == nil { @@ -729,13 +736,20 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient if n.state == closedState { return nil, ErrNodeStopped } - var db ethdb.Database var err error if n.config.DataDir == "" { db = rawdb.NewMemoryDatabase() } else { - db, err = rawdb.NewLevelDBDatabaseWithFreezer(n.ResolvePath(name), cache, handles, n.ResolveAncient(name, ancient), namespace, readonly) + db, err = rawdb.Open(rawdb.OpenOptions{ + Type: n.config.DBEngine, + Directory: n.ResolvePath(name), + AncientsDirectory: n.ResolveAncient(name, ancient), + Namespace: namespace, + Cache: cache, + Handles: handles, + ReadOnly: readonly, + }) } if err == nil { From 6a148dd5c349c57431a3a6efd48842a41b9d0821 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 9 Feb 2023 09:53:22 +0100 Subject: [PATCH 531/715] eth/catalyst: disallow forkchoiceupdate v1 post-shanghai (#26645) --- eth/catalyst/api.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 15b53985a9da..01a29fc447dc 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -169,8 +169,13 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI { // If there are payloadAttributes: we try to assemble a block with the payloadAttributes // and return its payloadID. func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { - if payloadAttributes != nil && payloadAttributes.Withdrawals != nil { - return engine.STATUS_INVALID, engine.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1")) + if payloadAttributes != nil { + if payloadAttributes.Withdrawals != nil { + return engine.STATUS_INVALID, engine.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1")) + } + if api.eth.BlockChain().Config().IsShanghai(payloadAttributes.Timestamp) { + return engine.STATUS_INVALID, engine.InvalidParams.With(fmt.Errorf("forkChoiceUpdateV1 called post-shanghai")) + } } return api.forkchoiceUpdated(update, payloadAttributes) } From bf1798e04ee52eda35a908b9a67d52f881d71401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 9 Feb 2023 13:03:54 +0200 Subject: [PATCH 532/715] common/prque: generic priority queue (#26290) * common, core, eth, les, trie: make prque generic * les/vflux/server: fixed issues in priorityPool * common, core, eth, les, trie: make priority also generic in prque * les/flowcontrol: add test case for priority accumulator overflow * les/flowcontrol: avoid priority value overflow * common/prque: use int priority in some tests No need to convert to int64 when we can just change the type used by the queue. * common/prque: remove comment about int64 range --------- Co-authored-by: Zsolt Felfoldi Co-authored-by: Felix Lange --- common/prque/lazyqueue.go | 78 +++++++++++++-------------- common/prque/prque.go | 44 +++++++-------- common/prque/prque_test.go | 27 +++++----- common/prque/sstack.go | 65 ++++++++++------------ common/prque/sstack_test.go | 30 +++++------ core/blockchain.go | 22 ++++---- core/rawdb/chain_iterator.go | 8 +-- core/txpool/txpool.go | 6 +-- eth/downloader/fetchers_concurrent.go | 8 ++- eth/downloader/queue.go | 48 +++++++++-------- eth/fetcher/block_fetcher.go | 10 ++-- go.mod | 6 +-- go.sum | 14 ++--- les/downloader/queue.go | 46 ++++++++-------- les/fetcher/block_fetcher.go | 10 ++-- les/flowcontrol/manager.go | 25 +++++++-- les/flowcontrol/manager_test.go | 22 +++++--- les/servingqueue.go | 16 +++--- les/vflux/server/prioritypool.go | 52 +++++++++--------- trie/sync.go | 4 +- 20 files changed, 277 insertions(+), 264 deletions(-) diff --git a/common/prque/lazyqueue.go b/common/prque/lazyqueue.go index 13ef3ed2cdbf..59bda72fa7e7 100644 --- a/common/prque/lazyqueue.go +++ b/common/prque/lazyqueue.go @@ -21,6 +21,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common/mclock" + "golang.org/x/exp/constraints" ) // LazyQueue is a priority queue data structure where priorities can change over @@ -32,31 +33,31 @@ import ( // // If the upper estimate is exceeded then Update should be called for that item. // A global Refresh function should also be called periodically. -type LazyQueue struct { +type LazyQueue[P constraints.Ordered, V any] struct { clock mclock.Clock // Items are stored in one of two internal queues ordered by estimated max // priority until the next and the next-after-next refresh. Update and Refresh // always places items in queue[1]. - queue [2]*sstack - popQueue *sstack + queue [2]*sstack[P, V] + popQueue *sstack[P, V] period time.Duration maxUntil mclock.AbsTime indexOffset int - setIndex SetIndexCallback - priority PriorityCallback - maxPriority MaxPriorityCallback + setIndex SetIndexCallback[V] + priority PriorityCallback[P, V] + maxPriority MaxPriorityCallback[P, V] lastRefresh1, lastRefresh2 mclock.AbsTime } type ( - PriorityCallback func(data interface{}) int64 // actual priority callback - MaxPriorityCallback func(data interface{}, until mclock.AbsTime) int64 // estimated maximum priority callback + PriorityCallback[P constraints.Ordered, V any] func(data V) P // actual priority callback + MaxPriorityCallback[P constraints.Ordered, V any] func(data V, until mclock.AbsTime) P // estimated maximum priority callback ) // NewLazyQueue creates a new lazy queue -func NewLazyQueue(setIndex SetIndexCallback, priority PriorityCallback, maxPriority MaxPriorityCallback, clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue { - q := &LazyQueue{ - popQueue: newSstack(nil, false), +func NewLazyQueue[P constraints.Ordered, V any](setIndex SetIndexCallback[V], priority PriorityCallback[P, V], maxPriority MaxPriorityCallback[P, V], clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue[P, V] { + q := &LazyQueue[P, V]{ + popQueue: newSstack[P, V](nil), setIndex: setIndex, priority: priority, maxPriority: maxPriority, @@ -71,13 +72,13 @@ func NewLazyQueue(setIndex SetIndexCallback, priority PriorityCallback, maxPrior } // Reset clears the contents of the queue -func (q *LazyQueue) Reset() { - q.queue[0] = newSstack(q.setIndex0, false) - q.queue[1] = newSstack(q.setIndex1, false) +func (q *LazyQueue[P, V]) Reset() { + q.queue[0] = newSstack[P, V](q.setIndex0) + q.queue[1] = newSstack[P, V](q.setIndex1) } // Refresh performs queue re-evaluation if necessary -func (q *LazyQueue) Refresh() { +func (q *LazyQueue[P, V]) Refresh() { now := q.clock.Now() for time.Duration(now-q.lastRefresh2) >= q.period*2 { q.refresh(now) @@ -87,10 +88,10 @@ func (q *LazyQueue) Refresh() { } // refresh re-evaluates items in the older queue and swaps the two queues -func (q *LazyQueue) refresh(now mclock.AbsTime) { +func (q *LazyQueue[P, V]) refresh(now mclock.AbsTime) { q.maxUntil = now.Add(q.period) for q.queue[0].Len() != 0 { - q.Push(heap.Pop(q.queue[0]).(*item).value) + q.Push(heap.Pop(q.queue[0]).(*item[P, V]).value) } q.queue[0], q.queue[1] = q.queue[1], q.queue[0] q.indexOffset = 1 - q.indexOffset @@ -98,22 +99,22 @@ func (q *LazyQueue) refresh(now mclock.AbsTime) { } // Push adds an item to the queue -func (q *LazyQueue) Push(data interface{}) { - heap.Push(q.queue[1], &item{data, q.maxPriority(data, q.maxUntil)}) +func (q *LazyQueue[P, V]) Push(data V) { + heap.Push(q.queue[1], &item[P, V]{data, q.maxPriority(data, q.maxUntil)}) } // Update updates the upper priority estimate for the item with the given queue index -func (q *LazyQueue) Update(index int) { +func (q *LazyQueue[P, V]) Update(index int) { q.Push(q.Remove(index)) } // Pop removes and returns the item with the greatest actual priority -func (q *LazyQueue) Pop() (interface{}, int64) { +func (q *LazyQueue[P, V]) Pop() (V, P) { var ( - resData interface{} - resPri int64 + resData V + resPri P ) - q.MultiPop(func(data interface{}, priority int64) bool { + q.MultiPop(func(data V, priority P) bool { resData = data resPri = priority return false @@ -123,7 +124,7 @@ func (q *LazyQueue) Pop() (interface{}, int64) { // peekIndex returns the index of the internal queue where the item with the // highest estimated priority is or -1 if both are empty -func (q *LazyQueue) peekIndex() int { +func (q *LazyQueue[P, V]) peekIndex() int { if q.queue[0].Len() != 0 { if q.queue[1].Len() != 0 && q.queue[1].blocks[0][0].priority > q.queue[0].blocks[0][0].priority { return 1 @@ -139,17 +140,17 @@ func (q *LazyQueue) peekIndex() int { // MultiPop pops multiple items from the queue and is more efficient than calling // Pop multiple times. Popped items are passed to the callback. MultiPop returns // when the callback returns false or there are no more items to pop. -func (q *LazyQueue) MultiPop(callback func(data interface{}, priority int64) bool) { +func (q *LazyQueue[P, V]) MultiPop(callback func(data V, priority P) bool) { nextIndex := q.peekIndex() for nextIndex != -1 { - data := heap.Pop(q.queue[nextIndex]).(*item).value - heap.Push(q.popQueue, &item{data, q.priority(data)}) + data := heap.Pop(q.queue[nextIndex]).(*item[P, V]).value + heap.Push(q.popQueue, &item[P, V]{data, q.priority(data)}) nextIndex = q.peekIndex() for q.popQueue.Len() != 0 && (nextIndex == -1 || q.queue[nextIndex].blocks[0][0].priority < q.popQueue.blocks[0][0].priority) { - i := heap.Pop(q.popQueue).(*item) + i := heap.Pop(q.popQueue).(*item[P, V]) if !callback(i.value, i.priority) { for q.popQueue.Len() != 0 { - q.Push(heap.Pop(q.popQueue).(*item).value) + q.Push(heap.Pop(q.popQueue).(*item[P, V]).value) } return } @@ -159,31 +160,28 @@ func (q *LazyQueue) MultiPop(callback func(data interface{}, priority int64) boo } // PopItem pops the item from the queue only, dropping the associated priority value. -func (q *LazyQueue) PopItem() interface{} { +func (q *LazyQueue[P, V]) PopItem() V { i, _ := q.Pop() return i } // Remove removes the item with the given index. -func (q *LazyQueue) Remove(index int) interface{} { - if index < 0 { - return nil - } - return heap.Remove(q.queue[index&1^q.indexOffset], index>>1).(*item).value +func (q *LazyQueue[P, V]) Remove(index int) V { + return heap.Remove(q.queue[index&1^q.indexOffset], index>>1).(*item[P, V]).value } // Empty checks whether the priority queue is empty. -func (q *LazyQueue) Empty() bool { +func (q *LazyQueue[P, V]) Empty() bool { return q.queue[0].Len() == 0 && q.queue[1].Len() == 0 } // Size returns the number of items in the priority queue. -func (q *LazyQueue) Size() int { +func (q *LazyQueue[P, V]) Size() int { return q.queue[0].Len() + q.queue[1].Len() } // setIndex0 translates internal queue item index to the virtual index space of LazyQueue -func (q *LazyQueue) setIndex0(data interface{}, index int) { +func (q *LazyQueue[P, V]) setIndex0(data V, index int) { if index == -1 { q.setIndex(data, -1) } else { @@ -192,6 +190,6 @@ func (q *LazyQueue) setIndex0(data interface{}, index int) { } // setIndex1 translates internal queue item index to the virtual index space of LazyQueue -func (q *LazyQueue) setIndex1(data interface{}, index int) { +func (q *LazyQueue[P, V]) setIndex1(data V, index int) { q.setIndex(data, index+index+1) } diff --git a/common/prque/prque.go b/common/prque/prque.go index fb02e3418c28..0e8c9f897fad 100755 --- a/common/prque/prque.go +++ b/common/prque/prque.go @@ -19,65 +19,59 @@ package prque import ( "container/heap" + + "golang.org/x/exp/constraints" ) // Priority queue data structure. -type Prque struct { - cont *sstack +type Prque[P constraints.Ordered, V any] struct { + cont *sstack[P, V] } // New creates a new priority queue. -func New(setIndex SetIndexCallback) *Prque { - return &Prque{newSstack(setIndex, false)} -} - -// NewWrapAround creates a new priority queue with wrap-around priority handling. -func NewWrapAround(setIndex SetIndexCallback) *Prque { - return &Prque{newSstack(setIndex, true)} +func New[P constraints.Ordered, V any](setIndex SetIndexCallback[V]) *Prque[P, V] { + return &Prque[P, V]{newSstack[P, V](setIndex)} } // Pushes a value with a given priority into the queue, expanding if necessary. -func (p *Prque) Push(data interface{}, priority int64) { - heap.Push(p.cont, &item{data, priority}) +func (p *Prque[P, V]) Push(data V, priority P) { + heap.Push(p.cont, &item[P, V]{data, priority}) } // Peek returns the value with the greatest priority but does not pop it off. -func (p *Prque) Peek() (interface{}, int64) { +func (p *Prque[P, V]) Peek() (V, P) { item := p.cont.blocks[0][0] return item.value, item.priority } // Pops the value with the greatest priority off the stack and returns it. // Currently no shrinking is done. -func (p *Prque) Pop() (interface{}, int64) { - item := heap.Pop(p.cont).(*item) +func (p *Prque[P, V]) Pop() (V, P) { + item := heap.Pop(p.cont).(*item[P, V]) return item.value, item.priority } // Pops only the item from the queue, dropping the associated priority value. -func (p *Prque) PopItem() interface{} { - return heap.Pop(p.cont).(*item).value +func (p *Prque[P, V]) PopItem() V { + return heap.Pop(p.cont).(*item[P, V]).value } // Remove removes the element with the given index. -func (p *Prque) Remove(i int) interface{} { - if i < 0 { - return nil - } - return heap.Remove(p.cont, i) +func (p *Prque[P, V]) Remove(i int) V { + return heap.Remove(p.cont, i).(*item[P, V]).value } // Checks whether the priority queue is empty. -func (p *Prque) Empty() bool { +func (p *Prque[P, V]) Empty() bool { return p.cont.Len() == 0 } // Returns the number of element in the priority queue. -func (p *Prque) Size() int { +func (p *Prque[P, V]) Size() int { return p.cont.Len() } // Clears the contents of the priority queue. -func (p *Prque) Reset() { - *p = *New(p.cont.setIndex) +func (p *Prque[P, V]) Reset() { + *p = *New[P, V](p.cont.setIndex) } diff --git a/common/prque/prque_test.go b/common/prque/prque_test.go index 1cffcebad437..c4910f205a00 100644 --- a/common/prque/prque_test.go +++ b/common/prque/prque_test.go @@ -21,22 +21,24 @@ func TestPrque(t *testing.T) { for i := 0; i < size; i++ { data[i] = rand.Int() } - queue := New(nil) + queue := New[int, int](nil) + for rep := 0; rep < 2; rep++ { // Fill a priority queue with the above data for i := 0; i < size; i++ { - queue.Push(data[i], int64(prio[i])) + queue.Push(data[i], prio[i]) if queue.Size() != i+1 { t.Errorf("queue size mismatch: have %v, want %v.", queue.Size(), i+1) } } // Create a map the values to the priorities for easier verification - dict := make(map[int64]int) + dict := make(map[int]int) for i := 0; i < size; i++ { - dict[int64(prio[i])] = data[i] + dict[prio[i]] = data[i] } + // Pop out the elements in priority order and verify them - prevPrio := int64(size + 1) + prevPrio := size + 1 for !queue.Empty() { val, prio := queue.Pop() if prio > prevPrio { @@ -59,22 +61,23 @@ func TestReset(t *testing.T) { for i := 0; i < size; i++ { data[i] = rand.Int() } - queue := New(nil) + queue := New[int, int](nil) + for rep := 0; rep < 2; rep++ { // Fill a priority queue with the above data for i := 0; i < size; i++ { - queue.Push(data[i], int64(prio[i])) + queue.Push(data[i], prio[i]) if queue.Size() != i+1 { t.Errorf("queue size mismatch: have %v, want %v.", queue.Size(), i+1) } } // Create a map the values to the priorities for easier verification - dict := make(map[int64]int) + dict := make(map[int]int) for i := 0; i < size; i++ { - dict[int64(prio[i])] = data[i] + dict[prio[i]] = data[i] } // Pop out half the elements in priority order and verify them - prevPrio := int64(size + 1) + prevPrio := size + 1 for i := 0; i < size/2; i++ { val, prio := queue.Pop() if prio > prevPrio { @@ -104,7 +107,7 @@ func BenchmarkPush(b *testing.B) { } // Execute the benchmark b.ResetTimer() - queue := New(nil) + queue := New[int64, int](nil) for i := 0; i < len(data); i++ { queue.Push(data[i], prio[i]) } @@ -118,7 +121,7 @@ func BenchmarkPop(b *testing.B) { data[i] = rand.Int() prio[i] = rand.Int63() } - queue := New(nil) + queue := New[int64, int](nil) for i := 0; i < len(data); i++ { queue.Push(data[i], prio[i]) } diff --git a/common/prque/sstack.go b/common/prque/sstack.go index b06a95413df0..5dcd1d9dd0c4 100755 --- a/common/prque/sstack.go +++ b/common/prque/sstack.go @@ -10,53 +10,50 @@ package prque +import "golang.org/x/exp/constraints" + // The size of a block of data const blockSize = 4096 // A prioritized item in the sorted stack. -// -// Note: priorities can "wrap around" the int64 range, a comes before b if (a.priority - b.priority) > 0. -// The difference between the lowest and highest priorities in the queue at any point should be less than 2^63. -type item struct { - value interface{} - priority int64 +type item[P constraints.Ordered, V any] struct { + value V + priority P } // SetIndexCallback is called when the element is moved to a new index. // Providing SetIndexCallback is optional, it is needed only if the application needs // to delete elements other than the top one. -type SetIndexCallback func(data interface{}, index int) +type SetIndexCallback[V any] func(data V, index int) // Internal sortable stack data structure. Implements the Push and Pop ops for // the stack (heap) functionality and the Len, Less and Swap methods for the // sortability requirements of the heaps. -type sstack struct { - setIndex SetIndexCallback - size int - capacity int - offset int - wrapAround bool +type sstack[P constraints.Ordered, V any] struct { + setIndex SetIndexCallback[V] + size int + capacity int + offset int - blocks [][]*item - active []*item + blocks [][]*item[P, V] + active []*item[P, V] } // Creates a new, empty stack. -func newSstack(setIndex SetIndexCallback, wrapAround bool) *sstack { - result := new(sstack) +func newSstack[P constraints.Ordered, V any](setIndex SetIndexCallback[V]) *sstack[P, V] { + result := new(sstack[P, V]) result.setIndex = setIndex - result.active = make([]*item, blockSize) - result.blocks = [][]*item{result.active} + result.active = make([]*item[P, V], blockSize) + result.blocks = [][]*item[P, V]{result.active} result.capacity = blockSize - result.wrapAround = wrapAround return result } // Pushes a value onto the stack, expanding it if necessary. Required by // heap.Interface. -func (s *sstack) Push(data interface{}) { +func (s *sstack[P, V]) Push(data any) { if s.size == s.capacity { - s.active = make([]*item, blockSize) + s.active = make([]*item[P, V], blockSize) s.blocks = append(s.blocks, s.active) s.capacity += blockSize s.offset = 0 @@ -65,16 +62,16 @@ func (s *sstack) Push(data interface{}) { s.offset = 0 } if s.setIndex != nil { - s.setIndex(data.(*item).value, s.size) + s.setIndex(data.(*item[P, V]).value, s.size) } - s.active[s.offset] = data.(*item) + s.active[s.offset] = data.(*item[P, V]) s.offset++ s.size++ } // Pops a value off the stack and returns it. Currently no shrinking is done. // Required by heap.Interface. -func (s *sstack) Pop() (res interface{}) { +func (s *sstack[P, V]) Pop() (res any) { s.size-- s.offset-- if s.offset < 0 { @@ -83,28 +80,24 @@ func (s *sstack) Pop() (res interface{}) { } res, s.active[s.offset] = s.active[s.offset], nil if s.setIndex != nil { - s.setIndex(res.(*item).value, -1) + s.setIndex(res.(*item[P, V]).value, -1) } return } // Returns the length of the stack. Required by sort.Interface. -func (s *sstack) Len() int { +func (s *sstack[P, V]) Len() int { return s.size } // Compares the priority of two elements of the stack (higher is first). // Required by sort.Interface. -func (s *sstack) Less(i, j int) bool { - a, b := s.blocks[i/blockSize][i%blockSize].priority, s.blocks[j/blockSize][j%blockSize].priority - if s.wrapAround { - return a-b > 0 - } - return a > b +func (s *sstack[P, V]) Less(i, j int) bool { + return s.blocks[i/blockSize][i%blockSize].priority > s.blocks[j/blockSize][j%blockSize].priority } // Swaps two elements in the stack. Required by sort.Interface. -func (s *sstack) Swap(i, j int) { +func (s *sstack[P, V]) Swap(i, j int) { ib, io, jb, jo := i/blockSize, i%blockSize, j/blockSize, j%blockSize a, b := s.blocks[jb][jo], s.blocks[ib][io] if s.setIndex != nil { @@ -115,6 +108,6 @@ func (s *sstack) Swap(i, j int) { } // Resets the stack, effectively clearing its contents. -func (s *sstack) Reset() { - *s = *newSstack(s.setIndex, false) +func (s *sstack[P, V]) Reset() { + *s = *newSstack[P, V](s.setIndex) } diff --git a/common/prque/sstack_test.go b/common/prque/sstack_test.go index bc6298979cbc..edc99955e837 100644 --- a/common/prque/sstack_test.go +++ b/common/prque/sstack_test.go @@ -17,23 +17,23 @@ import ( func TestSstack(t *testing.T) { // Create some initial data size := 16 * blockSize - data := make([]*item, size) + data := make([]*item[int64, int], size) for i := 0; i < size; i++ { - data[i] = &item{rand.Int(), rand.Int63()} + data[i] = &item[int64, int]{rand.Int(), rand.Int63()} } - stack := newSstack(nil, false) + stack := newSstack[int64, int](nil) for rep := 0; rep < 2; rep++ { // Push all the data into the stack, pop out every second - secs := []*item{} + secs := []*item[int64, int]{} for i := 0; i < size; i++ { stack.Push(data[i]) if i%2 == 0 { - secs = append(secs, stack.Pop().(*item)) + secs = append(secs, stack.Pop().(*item[int64, int])) } } - rest := []*item{} + rest := []*item[int64, int]{} for stack.Len() > 0 { - rest = append(rest, stack.Pop().(*item)) + rest = append(rest, stack.Pop().(*item[int64, int])) } // Make sure the contents of the resulting slices are ok for i := 0; i < size; i++ { @@ -50,12 +50,12 @@ func TestSstack(t *testing.T) { func TestSstackSort(t *testing.T) { // Create some initial data size := 16 * blockSize - data := make([]*item, size) + data := make([]*item[int64, int], size) for i := 0; i < size; i++ { - data[i] = &item{rand.Int(), int64(i)} + data[i] = &item[int64, int]{rand.Int(), int64(i)} } // Push all the data into the stack - stack := newSstack(nil, false) + stack := newSstack[int64, int](nil) for _, val := range data { stack.Push(val) } @@ -72,18 +72,18 @@ func TestSstackSort(t *testing.T) { func TestSstackReset(t *testing.T) { // Create some initial data size := 16 * blockSize - data := make([]*item, size) + data := make([]*item[int64, int], size) for i := 0; i < size; i++ { - data[i] = &item{rand.Int(), rand.Int63()} + data[i] = &item[int64, int]{rand.Int(), rand.Int63()} } - stack := newSstack(nil, false) + stack := newSstack[int64, int](nil) for rep := 0; rep < 2; rep++ { // Push all the data into the stack, pop out every second - secs := []*item{} + secs := []*item[int64, int]{} for i := 0; i < size; i++ { stack.Push(data[i]) if i%2 == 0 { - secs = append(secs, stack.Pop().(*item)) + secs = append(secs, stack.Pop().(*item[int64, int])) } } // Reset and verify both pulled and stack contents diff --git a/core/blockchain.go b/core/blockchain.go index c049f8955a15..98d2e7a774ad 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -169,14 +169,14 @@ type BlockChain struct { chainConfig *params.ChainConfig // Chain & network configuration cacheConfig *CacheConfig // Cache configuration for pruning - db ethdb.Database // Low level persistent database to store final content in - snaps *snapshot.Tree // Snapshot tree for fast trie leaf access - triegc *prque.Prque // Priority queue mapping block numbers to tries to gc - gcproc time.Duration // Accumulates canonical block processing for trie dumping - lastWrite uint64 // Last block when the state was flushed - flushInterval int64 // Time interval (processing time) after which to flush a state - triedb *trie.Database // The database handler for maintaining trie nodes. - stateCache state.Database // State database to reuse between imports (contains state cache) + db ethdb.Database // Low level persistent database to store final content in + snaps *snapshot.Tree // Snapshot tree for fast trie leaf access + triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc + gcproc time.Duration // Accumulates canonical block processing for trie dumping + lastWrite uint64 // Last block when the state was flushed + flushInterval int64 // Time interval (processing time) after which to flush a state + triedb *trie.Database // The database handler for maintaining trie nodes. + stateCache state.Database // State database to reuse between imports (contains state cache) // txLookupLimit is the maximum number of blocks from head whose tx indices // are reserved: @@ -261,7 +261,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis db: db, triedb: triedb, flushInterval: int64(cacheConfig.TrieTimeLimit), - triegc: prque.New(nil), + triegc: prque.New[int64, common.Hash](nil), quit: make(chan struct{}), chainmu: syncx.NewClosableMutex(), bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit), @@ -957,7 +957,7 @@ func (bc *BlockChain) Stop() { } } for !bc.triegc.Empty() { - triedb.Dereference(bc.triegc.PopItem().(common.Hash)) + triedb.Dereference(bc.triegc.PopItem()) } if size, _ := triedb.Size(); size != 0 { log.Error("Dangling trie nodes after full cleanup") @@ -1391,7 +1391,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. bc.triegc.Push(root, number) break } - bc.triedb.Dereference(root.(common.Hash)) + bc.triedb.Dereference(root) } return nil } diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 121f6d39dda3..85ad88e29172 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -191,7 +191,7 @@ func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan // in to be [to-1]. Therefore, setting lastNum to means that the // prqueue gap-evaluation will work correctly lastNum = to - queue = prque.New(nil) + queue = prque.New[int64, *blockTxHashes](nil) // for stats reporting blocks, txs = 0, 0 ) @@ -210,7 +210,7 @@ func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan break } // Next block available, pop it off and index it - delivery := queue.PopItem().(*blockTxHashes) + delivery := queue.PopItem() lastNum = delivery.number WriteTxLookupEntries(batch, delivery.number, delivery.hashes) blocks++ @@ -282,7 +282,7 @@ func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt ch // we expect the first number to come in to be [from]. Therefore, setting // nextNum to from means that the prqueue gap-evaluation will work correctly nextNum = from - queue = prque.New(nil) + queue = prque.New[int64, *blockTxHashes](nil) // for stats reporting blocks, txs = 0, 0 ) @@ -299,7 +299,7 @@ func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt ch if hook != nil && !hook(nextNum) { break } - delivery := queue.PopItem().(*blockTxHashes) + delivery := queue.PopItem() nextNum = delivery.number + 1 DeleteTxLookupEntries(batch, delivery.hashes) txs += len(delivery.hashes) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 6b878ed58613..c80520186627 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -1395,7 +1395,7 @@ func (pool *TxPool) truncatePending() { pendingBeforeCap := pending // Assemble a spam order to penalize large transactors first - spammers := prque.New(nil) + spammers := prque.New[int64, common.Address](nil) for addr, list := range pool.pending { // Only evict transactions from high rollers if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots { @@ -1407,12 +1407,12 @@ func (pool *TxPool) truncatePending() { for pending > pool.config.GlobalSlots && !spammers.Empty() { // Retrieve the next offender if not local address offender, _ := spammers.Pop() - offenders = append(offenders, offender.(common.Address)) + offenders = append(offenders, offender) // Equalize balances until all the same or below threshold if len(offenders) > 1 { // Calculate the equalization threshold for all current offenders - threshold := pool.pending[offender.(common.Address)].Len() + threshold := pool.pending[offender].Len() // Iteratively reduce all offenders until below limit or threshold reached for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold { diff --git a/eth/downloader/fetchers_concurrent.go b/eth/downloader/fetchers_concurrent.go index 44e6aa8f8d88..ceec06de4fd5 100644 --- a/eth/downloader/fetchers_concurrent.go +++ b/eth/downloader/fetchers_concurrent.go @@ -91,8 +91,8 @@ func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { } }() ordering := make(map[*eth.Request]int) - timeouts := prque.New(func(data interface{}, index int) { - ordering[data.(*eth.Request)] = index + timeouts := prque.New[int64, *eth.Request](func(data *eth.Request, index int) { + ordering[data] = index }) timeout := time.NewTimer(0) @@ -268,14 +268,12 @@ func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { // below is purely for to catch programming errors, given the correct // code, there's no possible order of events that should result in a // timeout firing for a non-existent event. - item, exp := timeouts.Peek() + req, exp := timeouts.Peek() if now, at := time.Now(), time.Unix(0, -exp); now.Before(at) { log.Error("Timeout triggered but not reached", "left", at.Sub(now)) timeout.Reset(at.Sub(now)) continue } - req := item.(*eth.Request) - // Stop tracking the timed out request from a timing perspective, // cancel it, so it's not considered in-flight anymore, but keep // the peer marked busy to prevent assigning a second request and diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index c71b36466d41..13b3021b247d 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -115,7 +115,7 @@ type queue struct { // Headers are "special", they download in batches, supported by a skeleton chain headerHead common.Hash // Hash of the last queued header to verify order headerTaskPool map[uint64]*types.Header // Pending header retrieval tasks, mapping starting indexes to skeleton headers - headerTaskQueue *prque.Prque // Priority queue of the skeleton indexes to fetch the filling headers for + headerTaskQueue *prque.Prque[int64, uint64] // Priority queue of the skeleton indexes to fetch the filling headers for headerPeerMiss map[string]map[uint64]struct{} // Set of per-peer header batches known to be unavailable headerPendPool map[string]*fetchRequest // Currently pending header retrieval operations headerResults []*types.Header // Result cache accumulating the completed headers @@ -125,15 +125,15 @@ type queue struct { headerContCh chan bool // Channel to notify when header download finishes // All data retrievals below are based on an already assembles header chain - blockTaskPool map[common.Hash]*types.Header // Pending block (body) retrieval tasks, mapping hashes to headers - blockTaskQueue *prque.Prque // Priority queue of the headers to fetch the blocks (bodies) for - blockPendPool map[string]*fetchRequest // Currently pending block (body) retrieval operations - blockWakeCh chan bool // Channel to notify the block fetcher of new tasks + blockTaskPool map[common.Hash]*types.Header // Pending block (body) retrieval tasks, mapping hashes to headers + blockTaskQueue *prque.Prque[int64, *types.Header] // Priority queue of the headers to fetch the blocks (bodies) for + blockPendPool map[string]*fetchRequest // Currently pending block (body) retrieval operations + blockWakeCh chan bool // Channel to notify the block fetcher of new tasks - receiptTaskPool map[common.Hash]*types.Header // Pending receipt retrieval tasks, mapping hashes to headers - receiptTaskQueue *prque.Prque // Priority queue of the headers to fetch the receipts for - receiptPendPool map[string]*fetchRequest // Currently pending receipt retrieval operations - receiptWakeCh chan bool // Channel to notify when receipt fetcher of new tasks + receiptTaskPool map[common.Hash]*types.Header // Pending receipt retrieval tasks, mapping hashes to headers + receiptTaskQueue *prque.Prque[int64, *types.Header] // Priority queue of the headers to fetch the receipts for + receiptPendPool map[string]*fetchRequest // Currently pending receipt retrieval operations + receiptWakeCh chan bool // Channel to notify when receipt fetcher of new tasks resultCache *resultStore // Downloaded but not yet delivered fetch results resultSize common.StorageSize // Approximate size of a block (exponential moving average) @@ -150,9 +150,9 @@ func newQueue(blockCacheLimit int, thresholdInitialSize int) *queue { lock := new(sync.RWMutex) q := &queue{ headerContCh: make(chan bool, 1), - blockTaskQueue: prque.New(nil), + blockTaskQueue: prque.New[int64, *types.Header](nil), blockWakeCh: make(chan bool, 1), - receiptTaskQueue: prque.New(nil), + receiptTaskQueue: prque.New[int64, *types.Header](nil), receiptWakeCh: make(chan bool, 1), active: sync.NewCond(lock), lock: lock, @@ -258,7 +258,7 @@ func (q *queue) ScheduleSkeleton(from uint64, skeleton []*types.Header) { } // Schedule all the header retrieval tasks for the skeleton assembly q.headerTaskPool = make(map[uint64]*types.Header) - q.headerTaskQueue = prque.New(nil) + q.headerTaskQueue = prque.New[int64, uint64](nil) q.headerPeerMiss = make(map[string]map[uint64]struct{}) // Reset availability to correct invalid chains q.headerResults = make([]*types.Header, len(skeleton)*MaxHeaderFetch) q.headerHashes = make([]common.Hash, len(skeleton)*MaxHeaderFetch) @@ -428,12 +428,12 @@ func (q *queue) ReserveHeaders(p *peerConnection, count int) *fetchRequest { for send == 0 && !q.headerTaskQueue.Empty() { from, _ := q.headerTaskQueue.Pop() if q.headerPeerMiss[p.id] != nil { - if _, ok := q.headerPeerMiss[p.id][from.(uint64)]; ok { - skip = append(skip, from.(uint64)) + if _, ok := q.headerPeerMiss[p.id][from]; ok { + skip = append(skip, from) continue } } - send = from.(uint64) + send = from } // Merge all the skipped batches back for _, from := range skip { @@ -485,7 +485,7 @@ func (q *queue) ReserveReceipts(p *peerConnection, count int) (*fetchRequest, bo // item - the fetchRequest // progress - whether any progress was made // throttle - if the caller should throttle for a while -func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque, +func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque[int64, *types.Header], pendPool map[string]*fetchRequest, kind uint) (*fetchRequest, bool, bool) { // Short circuit if the pool has been depleted, or if the peer's already // downloading something (sanity check not to corrupt state) @@ -503,8 +503,8 @@ func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common for proc := 0; len(send) < count && !taskQueue.Empty(); proc++ { // the task queue will pop items in order, so the highest prio block // is also the lowest block number. - h, _ := taskQueue.Peek() - header := h.(*types.Header) + header, _ := taskQueue.Peek() + // we can ask the resultcache if this header is within the // "prioritized" segment of blocks. If it is not, we need to throttle @@ -627,12 +627,14 @@ func (q *queue) ExpireReceipts(peer string) int { } // expire is the generic check that moves a specific expired task from a pending -// pool back into a task pool. +// pool back into a task pool. The syntax on the passed taskQueue is a bit weird +// as we would need a generic expire method to handle both types, but that is not +// supported at the moment at least (Go 1.19). // // Note, this method expects the queue lock to be already held. The reason the // lock is not obtained in here is that the parameters already need to access // the queue, so they already need a lock anyway. -func (q *queue) expire(peer string, pendPool map[string]*fetchRequest, taskQueue *prque.Prque) int { +func (q *queue) expire(peer string, pendPool map[string]*fetchRequest, taskQueue interface{}) int { // Retrieve the request being expired and log an error if it's non-existent, // as there's no order of events that should lead to such expirations. req := pendPool[peer] @@ -644,10 +646,10 @@ func (q *queue) expire(peer string, pendPool map[string]*fetchRequest, taskQueue // Return any non-satisfied requests to the pool if req.From > 0 { - taskQueue.Push(req.From, -int64(req.From)) + taskQueue.(*prque.Prque[int64, uint64]).Push(req.From, -int64(req.From)) } for _, header := range req.Headers { - taskQueue.Push(header, -int64(header.Number.Uint64())) + taskQueue.(*prque.Prque[int64, *types.Header]).Push(header, -int64(header.Number.Uint64())) } return len(req.Headers) } @@ -824,7 +826,7 @@ func (q *queue) DeliverReceipts(id string, receiptList [][]*types.Receipt, recei // reason this lock is not obtained in here is because the parameters already need // to access the queue, so they already need a lock anyway. func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, - taskQueue *prque.Prque, pendPool map[string]*fetchRequest, + taskQueue *prque.Prque[int64, *types.Header], pendPool map[string]*fetchRequest, reqTimer metrics.Timer, resInMeter metrics.Meter, resDropMeter metrics.Meter, results int, validate func(index int, header *types.Header) error, reconstruct func(index int, result *fetchResult)) (int, error) { diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index 156d07e9131f..50081d2e542c 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -175,9 +175,9 @@ type BlockFetcher struct { completing map[common.Hash]*blockAnnounce // Blocks with headers, currently body-completing // Block cache - queue *prque.Prque // Queue containing the import operations (block number sorted) - queues map[string]int // Per peer block counts to prevent memory exhaustion - queued map[common.Hash]*blockOrHeaderInject // Set of already queued blocks (to dedup imports) + queue *prque.Prque[int64, *blockOrHeaderInject] // Queue containing the import operations (block number sorted) + queues map[string]int // Per peer block counts to prevent memory exhaustion + queued map[common.Hash]*blockOrHeaderInject // Set of already queued blocks (to dedup imports) // Callbacks getHeader HeaderRetrievalFn // Retrieves a header from the local chain @@ -212,7 +212,7 @@ func NewBlockFetcher(light bool, getHeader HeaderRetrievalFn, getBlock blockRetr fetching: make(map[common.Hash]*blockAnnounce), fetched: make(map[common.Hash][]*blockAnnounce), completing: make(map[common.Hash]*blockAnnounce), - queue: prque.New(nil), + queue: prque.New[int64, *blockOrHeaderInject](nil), queues: make(map[string]int), queued: make(map[common.Hash]*blockOrHeaderInject), getHeader: getHeader, @@ -351,7 +351,7 @@ func (f *BlockFetcher) loop() { // Import any queued blocks that could potentially fit height := f.chainHeight() for !f.queue.Empty() { - op := f.queue.PopItem().(*blockOrHeaderInject) + op := f.queue.PopItem() hash := op.hash() if f.queueChangeHook != nil { f.queueChangeHook(hash, false) diff --git a/go.mod b/go.mod index 5f185e628ec5..2945dcbda9d1 100644 --- a/go.mod +++ b/go.mod @@ -59,11 +59,12 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa golang.org/x/crypto v0.1.0 + golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 golang.org/x/sys v0.3.0 golang.org/x/text v0.4.0 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba - golang.org/x/tools v0.1.12 + golang.org/x/tools v0.2.0 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce ) @@ -116,8 +117,7 @@ require ( github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/mod v0.6.0 // indirect golang.org/x/net v0.1.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/protobuf v1.27.1 // indirect diff --git a/go.sum b/go.sum index b96fec448705..23b798cc36ee 100644 --- a/go.sum +++ b/go.sum @@ -298,7 +298,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= @@ -657,8 +657,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 h1:rxKZ2gOnYxjfmakvUUqh9Gyb6KXfrj7JWTxORTYqb0E= -golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 h1:yZNXmy+j/JpX19vZkVktWqAo7Gny4PBWYYK3zskGpx4= +golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -680,8 +680,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -872,8 +872,8 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/les/downloader/queue.go b/les/downloader/queue.go index 5b7054cf35cb..6896b09b388a 100644 --- a/les/downloader/queue.go +++ b/les/downloader/queue.go @@ -115,7 +115,7 @@ type queue struct { // Headers are "special", they download in batches, supported by a skeleton chain headerHead common.Hash // Hash of the last queued header to verify order headerTaskPool map[uint64]*types.Header // Pending header retrieval tasks, mapping starting indexes to skeleton headers - headerTaskQueue *prque.Prque // Priority queue of the skeleton indexes to fetch the filling headers for + headerTaskQueue *prque.Prque[int64, uint64] // Priority queue of the skeleton indexes to fetch the filling headers for headerPeerMiss map[string]map[uint64]struct{} // Set of per-peer header batches known to be unavailable headerPendPool map[string]*fetchRequest // Currently pending header retrieval operations headerResults []*types.Header // Result cache accumulating the completed headers @@ -124,13 +124,13 @@ type queue struct { headerContCh chan bool // Channel to notify when header download finishes // All data retrievals below are based on an already assembles header chain - blockTaskPool map[common.Hash]*types.Header // Pending block (body) retrieval tasks, mapping hashes to headers - blockTaskQueue *prque.Prque // Priority queue of the headers to fetch the blocks (bodies) for - blockPendPool map[string]*fetchRequest // Currently pending block (body) retrieval operations + blockTaskPool map[common.Hash]*types.Header // Pending block (body) retrieval tasks, mapping hashes to headers + blockTaskQueue *prque.Prque[int64, *types.Header] // Priority queue of the headers to fetch the blocks (bodies) for + blockPendPool map[string]*fetchRequest // Currently pending block (body) retrieval operations - receiptTaskPool map[common.Hash]*types.Header // Pending receipt retrieval tasks, mapping hashes to headers - receiptTaskQueue *prque.Prque // Priority queue of the headers to fetch the receipts for - receiptPendPool map[string]*fetchRequest // Currently pending receipt retrieval operations + receiptTaskPool map[common.Hash]*types.Header // Pending receipt retrieval tasks, mapping hashes to headers + receiptTaskQueue *prque.Prque[int64, *types.Header] // Priority queue of the headers to fetch the receipts for + receiptPendPool map[string]*fetchRequest // Currently pending receipt retrieval operations resultCache *resultStore // Downloaded but not yet delivered fetch results resultSize common.StorageSize // Approximate size of a block (exponential moving average) @@ -147,8 +147,8 @@ func newQueue(blockCacheLimit int, thresholdInitialSize int) *queue { lock := new(sync.RWMutex) q := &queue{ headerContCh: make(chan bool), - blockTaskQueue: prque.New(nil), - receiptTaskQueue: prque.New(nil), + blockTaskQueue: prque.New[int64, *types.Header](nil), + receiptTaskQueue: prque.New[int64, *types.Header](nil), active: sync.NewCond(lock), lock: lock, } @@ -262,7 +262,7 @@ func (q *queue) ScheduleSkeleton(from uint64, skeleton []*types.Header) { } // Schedule all the header retrieval tasks for the skeleton assembly q.headerTaskPool = make(map[uint64]*types.Header) - q.headerTaskQueue = prque.New(nil) + q.headerTaskQueue = prque.New[int64, uint64](nil) q.headerPeerMiss = make(map[string]map[uint64]struct{}) // Reset availability to correct invalid chains q.headerResults = make([]*types.Header, len(skeleton)*MaxHeaderFetch) q.headerProced = 0 @@ -424,12 +424,12 @@ func (q *queue) ReserveHeaders(p *peerConnection, count int) *fetchRequest { for send == 0 && !q.headerTaskQueue.Empty() { from, _ := q.headerTaskQueue.Pop() if q.headerPeerMiss[p.id] != nil { - if _, ok := q.headerPeerMiss[p.id][from.(uint64)]; ok { - skip = append(skip, from.(uint64)) + if _, ok := q.headerPeerMiss[p.id][from]; ok { + skip = append(skip, from) continue } } - send = from.(uint64) + send = from } // Merge all the skipped batches back for _, from := range skip { @@ -481,7 +481,7 @@ func (q *queue) ReserveReceipts(p *peerConnection, count int) (*fetchRequest, bo // item - the fetchRequest // progress - whether any progress was made // throttle - if the caller should throttle for a while -func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque, +func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque[int64, *types.Header], pendPool map[string]*fetchRequest, kind uint) (*fetchRequest, bool, bool) { // Short circuit if the pool has been depleted, or if the peer's already // downloading something (sanity check not to corrupt state) @@ -499,8 +499,8 @@ func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common for proc := 0; len(send) < count && !taskQueue.Empty(); proc++ { // the task queue will pop items in order, so the highest prio block // is also the lowest block number. - h, _ := taskQueue.Peek() - header := h.(*types.Header) + header, _ := taskQueue.Peek() + // we can ask the resultcache if this header is within the // "prioritized" segment of blocks. If it is not, we need to throttle @@ -591,12 +591,12 @@ func (q *queue) CancelReceipts(request *fetchRequest) { } // Cancel aborts a fetch request, returning all pending hashes to the task queue. -func (q *queue) cancel(request *fetchRequest, taskQueue *prque.Prque, pendPool map[string]*fetchRequest) { +func (q *queue) cancel(request *fetchRequest, taskQueue interface{}, pendPool map[string]*fetchRequest) { if request.From > 0 { - taskQueue.Push(request.From, -int64(request.From)) + taskQueue.(*prque.Prque[int64, uint64]).Push(request.From, -int64(request.From)) } for _, header := range request.Headers { - taskQueue.Push(header, -int64(header.Number.Uint64())) + taskQueue.(*prque.Prque[int64, *types.Header]).Push(header, -int64(header.Number.Uint64())) } delete(pendPool, request.Peer.id) } @@ -655,7 +655,7 @@ func (q *queue) ExpireReceipts(timeout time.Duration) map[string]int { // Note, this method expects the queue lock to be already held. The // reason the lock is not obtained in here is because the parameters already need // to access the queue, so they already need a lock anyway. -func (q *queue) expire(timeout time.Duration, pendPool map[string]*fetchRequest, taskQueue *prque.Prque, timeoutMeter metrics.Meter) map[string]int { +func (q *queue) expire(timeout time.Duration, pendPool map[string]*fetchRequest, taskQueue interface{}, timeoutMeter metrics.Meter) map[string]int { // Iterate over the expired requests and return each to the queue expiries := make(map[string]int) for id, request := range pendPool { @@ -665,10 +665,10 @@ func (q *queue) expire(timeout time.Duration, pendPool map[string]*fetchRequest, // Return any non satisfied requests to the pool if request.From > 0 { - taskQueue.Push(request.From, -int64(request.From)) + taskQueue.(*prque.Prque[int64, uint64]).Push(request.From, -int64(request.From)) } for _, header := range request.Headers { - taskQueue.Push(header, -int64(header.Number.Uint64())) + taskQueue.(*prque.Prque[int64, *types.Header]).Push(header, -int64(header.Number.Uint64())) } // Add the peer to the expiry report along the number of failed requests expiries[id] = len(request.Headers) @@ -831,7 +831,7 @@ func (q *queue) DeliverReceipts(id string, receiptList [][]*types.Receipt) (int, // reason this lock is not obtained in here is because the parameters already need // to access the queue, so they already need a lock anyway. func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, - taskQueue *prque.Prque, pendPool map[string]*fetchRequest, reqTimer metrics.Timer, + taskQueue *prque.Prque[int64, *types.Header], pendPool map[string]*fetchRequest, reqTimer metrics.Timer, results int, validate func(index int, header *types.Header) error, reconstruct func(index int, result *fetchResult)) (int, error) { // Short circuit if the data was never requested diff --git a/les/fetcher/block_fetcher.go b/les/fetcher/block_fetcher.go index 42cf9500a2ae..c76f20ced313 100644 --- a/les/fetcher/block_fetcher.go +++ b/les/fetcher/block_fetcher.go @@ -177,9 +177,9 @@ type BlockFetcher struct { completing map[common.Hash]*blockAnnounce // Blocks with headers, currently body-completing // Block cache - queue *prque.Prque // Queue containing the import operations (block number sorted) - queues map[string]int // Per peer block counts to prevent memory exhaustion - queued map[common.Hash]*blockOrHeaderInject // Set of already queued blocks (to dedup imports) + queue *prque.Prque[int64, *blockOrHeaderInject] // Queue containing the import operations (block number sorted) + queues map[string]int // Per peer block counts to prevent memory exhaustion + queued map[common.Hash]*blockOrHeaderInject // Set of already queued blocks (to dedup imports) // Callbacks getHeader HeaderRetrievalFn // Retrieves a header from the local chain @@ -214,7 +214,7 @@ func NewBlockFetcher(light bool, getHeader HeaderRetrievalFn, getBlock blockRetr fetching: make(map[common.Hash]*blockAnnounce), fetched: make(map[common.Hash][]*blockAnnounce), completing: make(map[common.Hash]*blockAnnounce), - queue: prque.New(nil), + queue: prque.New[int64, *blockOrHeaderInject](nil), queues: make(map[string]int), queued: make(map[common.Hash]*blockOrHeaderInject), getHeader: getHeader, @@ -353,7 +353,7 @@ func (f *BlockFetcher) loop() { // Import any queued blocks that could potentially fit height := f.chainHeight() for !f.queue.Empty() { - op := f.queue.PopItem().(*blockOrHeaderInject) + op := f.queue.PopItem() hash := op.hash() if f.queueChangeHook != nil { f.queueChangeHook(hash, false) diff --git a/les/flowcontrol/manager.go b/les/flowcontrol/manager.go index 497f91eeda79..b7cc9bd9030b 100644 --- a/les/flowcontrol/manager.go +++ b/les/flowcontrol/manager.go @@ -75,10 +75,11 @@ type ClientManager struct { // (totalRecharge / sumRecharge)*FixedPointMultiplier or 0 if sumRecharge==0 rcLastUpdate mclock.AbsTime // last time the recharge integrator was updated rcLastIntValue int64 // last updated value of the recharge integrator + priorityOffset int64 // offset for prque priority values ensures that all priorities stay in the int64 range // recharge queue is a priority queue with currently recharging client nodes // as elements. The priority value is rcFullIntValue which allows to quickly // determine which client will first finish recharge. - rcQueue *prque.Prque + rcQueue *prque.Prque[int64, *ClientNode] } // NewClientManager returns a new client manager. @@ -107,7 +108,7 @@ type ClientManager struct { func NewClientManager(curve PieceWiseLinear, clock mclock.Clock) *ClientManager { cm := &ClientManager{ clock: clock, - rcQueue: prque.NewWrapAround(func(a interface{}, i int) { a.(*ClientNode).queueIndex = i }), + rcQueue: prque.New[int64, *ClientNode](func(a *ClientNode, i int) { a.queueIndex = i }), capLastUpdate: clock.Now(), stop: make(chan chan struct{}), } @@ -288,13 +289,13 @@ func (cm *ClientManager) updateRecharge(now mclock.AbsTime) { } dt := now - lastUpdate // fetch the client that finishes first - rcqNode := cm.rcQueue.PopItem().(*ClientNode) // if sumRecharge > 0 then the queue cannot be empty + rcqNode := cm.rcQueue.PopItem() // if sumRecharge > 0 then the queue cannot be empty // check whether it has already finished dtNext := mclock.AbsTime(float64(rcqNode.rcFullIntValue-cm.rcLastIntValue) / bonusRatio) if dt < dtNext { // not finished yet, put it back, update integrator according // to current bonusRatio and return - cm.rcQueue.Push(rcqNode, -rcqNode.rcFullIntValue) + cm.addToQueue(rcqNode) cm.rcLastIntValue += int64(bonusRatio * float64(dt)) return } @@ -308,6 +309,20 @@ func (cm *ClientManager) updateRecharge(now mclock.AbsTime) { } } +func (cm *ClientManager) addToQueue(node *ClientNode) { + if cm.priorityOffset-node.rcFullIntValue < -0x4000000000000000 { + cm.priorityOffset += 0x4000000000000000 + // recreate priority queue with new offset to avoid overflow; should happen very rarely + newRcQueue := prque.New[int64, *ClientNode](func(a *ClientNode, i int) { a.queueIndex = i }) + for cm.rcQueue.Size() > 0 { + n := cm.rcQueue.PopItem() + newRcQueue.Push(n, cm.priorityOffset-n.rcFullIntValue) + } + cm.rcQueue = newRcQueue + } + cm.rcQueue.Push(node, cm.priorityOffset-node.rcFullIntValue) +} + // updateNodeRc updates a node's corrBufValue and adds an external correction value. // It also adds or removes the rcQueue entry and updates ServerParams and sumRecharge if necessary. func (cm *ClientManager) updateNodeRc(node *ClientNode, bvc int64, params *ServerParams, now mclock.AbsTime) { @@ -344,7 +359,7 @@ func (cm *ClientManager) updateNodeRc(node *ClientNode, bvc int64, params *Serve } node.rcLastIntValue = cm.rcLastIntValue node.rcFullIntValue = cm.rcLastIntValue + (int64(node.params.BufLimit)-node.corrBufValue)*FixedPointMultiplier/int64(node.params.MinRecharge) - cm.rcQueue.Push(node, -node.rcFullIntValue) + cm.addToQueue(node) } } diff --git a/les/flowcontrol/manager_test.go b/les/flowcontrol/manager_test.go index 564d813f15a3..3afc31272f54 100644 --- a/les/flowcontrol/manager_test.go +++ b/les/flowcontrol/manager_test.go @@ -17,6 +17,7 @@ package flowcontrol import ( + "math" "math/rand" "testing" "time" @@ -44,16 +45,17 @@ const ( // maximum permitted rate. The max capacity nodes are changed multiple times during // a single test. func TestConstantTotalCapacity(t *testing.T) { - testConstantTotalCapacity(t, 10, 1, 0) - testConstantTotalCapacity(t, 10, 1, 1) - testConstantTotalCapacity(t, 30, 1, 0) - testConstantTotalCapacity(t, 30, 2, 3) - testConstantTotalCapacity(t, 100, 1, 0) - testConstantTotalCapacity(t, 100, 3, 5) - testConstantTotalCapacity(t, 100, 5, 10) + testConstantTotalCapacity(t, 10, 1, 0, false) + testConstantTotalCapacity(t, 10, 1, 1, false) + testConstantTotalCapacity(t, 30, 1, 0, false) + testConstantTotalCapacity(t, 30, 2, 3, false) + testConstantTotalCapacity(t, 100, 1, 0, false) + testConstantTotalCapacity(t, 100, 3, 5, false) + testConstantTotalCapacity(t, 100, 5, 10, false) + testConstantTotalCapacity(t, 100, 3, 5, true) } -func testConstantTotalCapacity(t *testing.T, nodeCount, maxCapacityNodes, randomSend int) { +func testConstantTotalCapacity(t *testing.T, nodeCount, maxCapacityNodes, randomSend int, priorityOverflow bool) { clock := &mclock.Simulated{} nodes := make([]*testNode, nodeCount) var totalCapacity uint64 @@ -62,6 +64,10 @@ func testConstantTotalCapacity(t *testing.T, nodeCount, maxCapacityNodes, random totalCapacity += nodes[i].capacity } m := NewClientManager(PieceWiseLinear{{0, totalCapacity}}, clock) + if priorityOverflow { + // provoke a situation where rcLastUpdate overflow needs to be handled + m.rcLastIntValue = math.MaxInt64 - 10000000000 + } for _, n := range nodes { n.bufLimit = n.capacity * 6000 n.node = NewClientNode(m, ServerParams{BufLimit: n.bufLimit, MinRecharge: n.capacity}) diff --git a/les/servingqueue.go b/les/servingqueue.go index 10c7e6f48cba..b4b53d8df548 100644 --- a/les/servingqueue.go +++ b/les/servingqueue.go @@ -38,10 +38,10 @@ type servingQueue struct { setThreadsCh chan int wg sync.WaitGroup - threadCount int // number of currently running threads - queue *prque.Prque // priority queue for waiting or suspended tasks - best *servingTask // the highest priority task (not included in the queue) - suspendBias int64 // priority bias against suspending an already running task + threadCount int // number of currently running threads + queue *prque.Prque[int64, *servingTask] // priority queue for waiting or suspended tasks + best *servingTask // the highest priority task (not included in the queue) + suspendBias int64 // priority bias against suspending an already running task } // servingTask represents a request serving task. Tasks can be implemented to @@ -123,7 +123,7 @@ func (t *servingTask) waitOrStop() bool { // newServingQueue returns a new servingQueue func newServingQueue(suspendBias int64, utilTarget float64) *servingQueue { sq := &servingQueue{ - queue: prque.NewWrapAround(nil), + queue: prque.New[int64, *servingTask](nil), suspendBias: suspendBias, queueAddCh: make(chan *servingTask, 100), queueBestCh: make(chan *servingTask), @@ -214,7 +214,7 @@ func (sq *servingQueue) freezePeers() { } sq.best = nil for sq.queue.Size() > 0 { - task := sq.queue.PopItem().(*servingTask) + task := sq.queue.PopItem() tasks := peerMap[task.peer] if tasks == nil { bufValue, bufLimit := task.peer.fcClient.BufferStatus() @@ -251,7 +251,7 @@ func (sq *servingQueue) freezePeers() { } } if sq.queue.Size() > 0 { - sq.best = sq.queue.PopItem().(*servingTask) + sq.best = sq.queue.PopItem() } } @@ -310,7 +310,7 @@ func (sq *servingQueue) queueLoop() { if sq.queue.Size() == 0 { sq.best = nil } else { - sq.best, _ = sq.queue.PopItem().(*servingTask) + sq.best = sq.queue.PopItem() } case <-sq.quit: return diff --git a/les/vflux/server/prioritypool.go b/les/vflux/server/prioritypool.go index 059dac0d46d5..766026a80832 100644 --- a/les/vflux/server/prioritypool.go +++ b/les/vflux/server/prioritypool.go @@ -77,8 +77,8 @@ type priorityPool struct { // temporary state if tempState is not empty tempState []*ppNodeInfo activeCount, activeCap uint64 - activeQueue *prque.LazyQueue - inactiveQueue *prque.Prque + activeQueue *prque.LazyQueue[int64, *ppNodeInfo] + inactiveQueue *prque.Prque[int64, *ppNodeInfo] } // ppNodeInfo is the internal node descriptor of priorityPool @@ -104,7 +104,7 @@ func newPriorityPool(ns *nodestate.NodeStateMachine, setup *serverSetup, clock m setup: setup, ns: ns, clock: clock, - inactiveQueue: prque.New(inactiveSetIndex), + inactiveQueue: prque.New[int64, *ppNodeInfo](inactiveSetIndex), minCap: minCap, activeBias: activeBias, capacityStepDiv: capacityStepDiv, @@ -183,8 +183,7 @@ func (pp *priorityPool) requestCapacity(node *enode.Node, minTarget, maxTarget u } pp.setTempCapacity(c, maxTarget) c.minTarget = minTarget - pp.activeQueue.Remove(c.activeIndex) - pp.inactiveQueue.Remove(c.inactiveIndex) + pp.removeFromQueues(c) pp.activeQueue.Push(c) pp.enforceLimits() updates := pp.finalizeChanges(c.tempCapacity >= minTarget && c.tempCapacity <= maxTarget && c.tempCapacity != c.capacity) @@ -250,13 +249,13 @@ func (pp *priorityPool) Limits() (uint64, uint64) { } // inactiveSetIndex callback updates ppNodeInfo item index in inactiveQueue -func inactiveSetIndex(a interface{}, index int) { - a.(*ppNodeInfo).inactiveIndex = index +func inactiveSetIndex(a *ppNodeInfo, index int) { + a.inactiveIndex = index } // activeSetIndex callback updates ppNodeInfo item index in activeQueue -func activeSetIndex(a interface{}, index int) { - a.(*ppNodeInfo).activeIndex = index +func activeSetIndex(a *ppNodeInfo, index int) { + a.activeIndex = index } // invertPriority inverts a priority value. The active queue uses inverted priorities @@ -269,8 +268,7 @@ func invertPriority(p int64) int64 { } // activePriority callback returns actual priority of ppNodeInfo item in activeQueue -func activePriority(a interface{}) int64 { - c := a.(*ppNodeInfo) +func activePriority(c *ppNodeInfo) int64 { if c.bias == 0 { return invertPriority(c.nodePriority.priority(c.tempCapacity)) } else { @@ -279,8 +277,7 @@ func activePriority(a interface{}) int64 { } // activeMaxPriority callback returns estimated maximum priority of ppNodeInfo item in activeQueue -func (pp *priorityPool) activeMaxPriority(a interface{}, until mclock.AbsTime) int64 { - c := a.(*ppNodeInfo) +func (pp *priorityPool) activeMaxPriority(c *ppNodeInfo, until mclock.AbsTime) int64 { future := time.Duration(until - pp.clock.Now()) if future < 0 { future = 0 @@ -293,6 +290,16 @@ func (pp *priorityPool) inactivePriority(p *ppNodeInfo) int64 { return p.nodePriority.priority(pp.minCap) } +// removeFromQueues removes the node from the active/inactive queues +func (pp *priorityPool) removeFromQueues(c *ppNodeInfo) { + if c.activeIndex >= 0 { + pp.activeQueue.Remove(c.activeIndex) + } + if c.inactiveIndex >= 0 { + pp.inactiveQueue.Remove(c.inactiveIndex) + } +} + // connectNode is called when a new node has been added to the pool (inactiveFlag set) // Note: this function should run inside a NodeStateMachine operation func (pp *priorityPool) connectNode(c *ppNodeInfo) { @@ -320,8 +327,7 @@ func (pp *priorityPool) disconnectNode(c *ppNodeInfo) { return } c.connected = false - pp.activeQueue.Remove(c.activeIndex) - pp.inactiveQueue.Remove(c.inactiveIndex) + pp.removeFromQueues(c) var updates []capUpdate if c.capacity != 0 { @@ -411,11 +417,11 @@ func (pp *priorityPool) enforceLimits() (*ppNodeInfo, int64) { return nil, math.MinInt64 } var ( - c *ppNodeInfo + lastNode *ppNodeInfo maxActivePriority int64 ) - pp.activeQueue.MultiPop(func(data interface{}, priority int64) bool { - c = data.(*ppNodeInfo) + pp.activeQueue.MultiPop(func(c *ppNodeInfo, priority int64) bool { + lastNode = c pp.setTempState(c) maxActivePriority = priority if c.tempCapacity == c.minTarget || pp.activeCount > pp.maxCount { @@ -433,7 +439,7 @@ func (pp *priorityPool) enforceLimits() (*ppNodeInfo, int64) { } return pp.activeCap > pp.maxCap || pp.activeCount > pp.maxCount }) - return c, invertPriority(maxActivePriority) + return lastNode, invertPriority(maxActivePriority) } // finalizeChanges either commits or reverts temporary changes. The necessary capacity @@ -442,8 +448,7 @@ func (pp *priorityPool) enforceLimits() (*ppNodeInfo, int64) { func (pp *priorityPool) finalizeChanges(commit bool) (updates []capUpdate) { for _, c := range pp.tempState { // always remove and push back in order to update biased priority - pp.activeQueue.Remove(c.activeIndex) - pp.inactiveQueue.Remove(c.inactiveIndex) + pp.removeFromQueues(c) oldCapacity := c.capacity if commit { c.capacity = c.tempCapacity @@ -496,7 +501,7 @@ func (pp *priorityPool) updateFlags(updates []capUpdate) { // tryActivate tries to activate inactive nodes if possible func (pp *priorityPool) tryActivate(commit bool) []capUpdate { for pp.inactiveQueue.Size() > 0 { - c := pp.inactiveQueue.PopItem().(*ppNodeInfo) + c := pp.inactiveQueue.PopItem() pp.setTempState(c) pp.setTempBias(c, pp.activeBias) pp.setTempCapacity(c, pp.minCap) @@ -524,8 +529,7 @@ func (pp *priorityPool) updatePriority(node *enode.Node) { pp.lock.Unlock() return } - pp.activeQueue.Remove(c.activeIndex) - pp.inactiveQueue.Remove(c.inactiveIndex) + pp.removeFromQueues(c) if c.capacity != 0 { pp.activeQueue.Push(c) } else { diff --git a/trie/sync.go b/trie/sync.go index 46478b033a63..4bf735c02f2f 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -160,7 +160,7 @@ type Sync struct { membatch *syncMemBatch // Memory buffer to avoid frequent database writes nodeReqs map[string]*nodeRequest // Pending requests pertaining to a trie node path codeReqs map[common.Hash]*codeRequest // Pending requests pertaining to a code hash - queue *prque.Prque // Priority queue with the pending requests + queue *prque.Prque[int64, any] // Priority queue with the pending requests fetches map[int]int // Number of active fetches per trie node depth } @@ -172,7 +172,7 @@ func NewSync(root common.Hash, database ethdb.KeyValueReader, callback LeafCallb membatch: newSyncMemBatch(), nodeReqs: make(map[string]*nodeRequest), codeReqs: make(map[common.Hash]*codeRequest), - queue: prque.New(nil), + queue: prque.New[int64, any](nil), // Ugh, can contain both string and hash, whyyy fetches: make(map[int]int), } ts.AddSubTrie(root, nil, common.Hash{}, nil, callback) From da3c974c36cc6467d909264885f2d4f14b842d43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 9 Feb 2023 13:31:42 +0200 Subject: [PATCH 533/715] ethdb/pebble: fix nil callbacks (#26650) --- ethdb/pebble/pebble.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index c850dc5a1b2a..5ba7e03c25dd 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -117,7 +117,6 @@ func (d *Database) onWriteStallEnd() { // New returns a wrapped pebble DB object. The namespace is the prefix that the // metrics reporting should use for surfacing internal stats. func New(file string, cache int, handles int, namespace string, readonly bool) (*Database, error) { - var db *Database // Ensure we have some minimal caching and file guarantees if cache < minCache { cache = minCache @@ -140,6 +139,11 @@ func New(file string, cache int, handles int, namespace string, readonly bool) ( if memTableSize > maxMemTableSize { memTableSize = maxMemTableSize } + db := &Database{ + fn: file, + log: logger, + quitChan: make(chan chan error), + } opt := &pebble.Options{ // Pebble has a single combined cache area and the write // buffers are taken from this too. Assign all available @@ -187,13 +191,8 @@ func New(file string, cache int, handles int, namespace string, readonly bool) ( if err != nil { return nil, err } - // Assemble the wrapper with all the registered metrics - db = &Database{ - fn: file, - db: innerDB, - log: logger, - quitChan: make(chan chan error), - } + db.db = innerDB + db.compTimeMeter = metrics.NewRegisteredMeter(namespace+"compact/time", nil) db.compReadMeter = metrics.NewRegisteredMeter(namespace+"compact/input", nil) db.compWriteMeter = metrics.NewRegisteredMeter(namespace+"compact/output", nil) From 3086c256c932dc6da26822a5ec130c2fba7e222e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 9 Feb 2023 14:56:15 +0200 Subject: [PATCH 534/715] eth/downloader: fix timeout resurrection panic (#26652) * common/prque, eth/downloader: fix timeout resurrection panic * common/prque: revert -1 hack for les, temporaryly! --- eth/downloader/fetchers_concurrent.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/eth/downloader/fetchers_concurrent.go b/eth/downloader/fetchers_concurrent.go index ceec06de4fd5..649aa2761596 100644 --- a/eth/downloader/fetchers_concurrent.go +++ b/eth/downloader/fetchers_concurrent.go @@ -280,13 +280,14 @@ func (d *Downloader) concurrentFetch(queue typedQueue, beaconMode bool) error { // overloading it further. delete(pending, req.Peer) stales[req.Peer] = req - delete(ordering, req) - timeouts.Pop() + timeouts.Pop() // Popping an item will reorder indices in `ordering`, delete after, otherwise will resurrect! if timeouts.Size() > 0 { _, exp := timeouts.Peek() timeout.Reset(time.Until(time.Unix(0, -exp))) } + delete(ordering, req) + // New timeout potentially set if there are more requests pending, // reschedule the failed one to a free peer fails := queue.unreserve(req.Peer) From 22c3ad1d1270321c79c7798a5b44333b5ad46ad8 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 9 Feb 2023 08:56:59 -0500 Subject: [PATCH 535/715] core/state, trie: remove unused error-return from trie Commit operation (#26641) --- core/state/database.go | 2 +- core/state/snapshot/generate.go | 4 +-- core/state/snapshot/generate_test.go | 4 +-- core/state/state_object.go | 6 ++-- core/state/statedb.go | 5 +-- eth/protocols/snap/sync_test.go | 12 +++---- light/postprocess.go | 12 +++---- light/trie.go | 4 +-- tests/fuzzers/stacktrie/trie_fuzzer.go | 9 ++---- tests/fuzzers/trie/trie-fuzzer.go | 5 +-- trie/committer.go | 43 ++++++++++---------------- trie/iterator_test.go | 21 ++++++------- trie/secure_trie.go | 2 +- trie/secure_trie_test.go | 5 +-- trie/sync_test.go | 5 +-- trie/trie.go | 13 +++----- trie/trie_test.go | 37 +++++++--------------- trie/util_test.go | 14 +++------ 18 files changed, 72 insertions(+), 131 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index 7a719f0d9a7d..d3c36c10ac5d 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -109,7 +109,7 @@ type Trie interface { // 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 - Commit(collectLeaf bool) (common.Hash, *trie.NodeSet, error) + Commit(collectLeaf bool) (common.Hash, *trie.NodeSet) // NodeIterator returns an iterator that returns nodes of the trie. Iteration // starts at the key after the given start key. diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index a2be1c24b2a0..46f41cdbeedd 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -367,8 +367,8 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi for i, key := range result.keys { snapTrie.Update(key, result.vals[i]) } - root, nodes, err := snapTrie.Commit(false) - if err == nil && nodes != nil { + root, nodes := snapTrie.Commit(false) + if nodes != nil { tdb.Update(trie.NewWithNodeSet(nodes)) tdb.Commit(root, false) } diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index e79c919c174b..1bc3421e99b6 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -190,7 +190,7 @@ func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string if !commit { return stTrie.Hash().Bytes() } - root, nodes, _ := stTrie.Commit(false) + root, nodes := stTrie.Commit(false) if nodes != nil { t.nodes.Merge(nodes) } @@ -198,7 +198,7 @@ func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string } func (t *testHelper) Commit() common.Hash { - root, nodes, _ := t.accTrie.Commit(true) + root, nodes := t.accTrie.Commit(true) if nodes != nil { t.nodes.Merge(nodes) } diff --git a/core/state/state_object.go b/core/state/state_object.go index 6bd6f18322e3..1550926d3a62 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -385,10 +385,8 @@ func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) { if metrics.EnabledExpensive { defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) } - root, nodes, err := tr.Commit(false) - if err == nil { - s.data.Root = root - } + root, nodes := tr.Commit(false) + s.data.Root = root return nodes, err } diff --git a/core/state/statedb.go b/core/state/statedb.go index ebbf64a01866..3f4bec2392dc 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1019,10 +1019,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if metrics.EnabledExpensive { start = time.Now() } - root, set, err := s.trie.Commit(true) - if err != nil { - return common.Hash{}, err - } + root, set := s.trie.Commit(true) // Merge the dirty nodes of account trie into global set if set != nil { if err := nodes.Merge(set); err != nil { diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 4cdfb9be6ed5..971605d8c29d 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1388,7 +1388,7 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) { // Commit the state changes into db and re-create the trie // for accessing later. - root, nodes, _ := accTrie.Commit(false) + root, nodes := accTrie.Commit(false) db.Update(trie.NewWithNodeSet(nodes)) accTrie, _ = trie.New(trie.StateTrieID(root), db) @@ -1450,7 +1450,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { // Commit the state changes into db and re-create the trie // for accessing later. - root, nodes, _ := accTrie.Commit(false) + root, nodes := accTrie.Commit(false) db.Update(trie.NewWithNodeSet(nodes)) accTrie, _ = trie.New(trie.StateTrieID(root), db) @@ -1496,7 +1496,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) sort.Sort(entries) // Commit account trie - root, set, _ := accTrie.Commit(true) + root, set := accTrie.Commit(true) nodes.Merge(set) // Commit gathered dirty nodes into database @@ -1561,7 +1561,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin sort.Sort(entries) // Commit account trie - root, set, _ := accTrie.Commit(true) + root, set := accTrie.Commit(true) nodes.Merge(set) // Commit gathered dirty nodes into database @@ -1603,7 +1603,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas entries = append(entries, elem) } sort.Sort(entries) - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) return root, nodes, entries } @@ -1654,7 +1654,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo entries = append(entries, elem) } sort.Sort(entries) - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) return root, nodes, entries } diff --git a/light/postprocess.go b/light/postprocess.go index 61eec3609bfd..e800a1f0f7f0 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -212,10 +212,7 @@ func (c *ChtIndexerBackend) Process(ctx context.Context, header *types.Header) e // Commit implements core.ChainIndexerBackend func (c *ChtIndexerBackend) Commit() error { - root, nodes, err := c.trie.Commit(false) - if err != nil { - return err - } + root, nodes := c.trie.Commit(false) // Commit trie changes into trie database in case it's not nil. if nodes != nil { if err := c.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { @@ -226,6 +223,7 @@ func (c *ChtIndexerBackend) Commit() error { } } // Re-create trie with newly generated root and updated database. + var err error c.trie, err = trie.New(trie.TrieID(root), c.triedb) if err != nil { return err @@ -458,10 +456,7 @@ func (b *BloomTrieIndexerBackend) Commit() error { b.trie.Delete(encKey[:]) } } - root, nodes, err := b.trie.Commit(false) - if err != nil { - return err - } + root, nodes := b.trie.Commit(false) // Commit trie changes into trie database in case it's not nil. if nodes != nil { if err := b.triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { @@ -472,6 +467,7 @@ func (b *BloomTrieIndexerBackend) Commit() error { } } // Re-create trie with newly generated root and updated database. + var err error b.trie, err = trie.New(trie.TrieID(root), b.triedb) if err != nil { return err diff --git a/light/trie.go b/light/trie.go index c7c08331cb50..0ccab1588d3d 100644 --- a/light/trie.go +++ b/light/trie.go @@ -164,9 +164,9 @@ func (t *odrTrie) TryDeleteAccount(address common.Address) error { }) } -func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trie.NodeSet, error) { +func (t *odrTrie) Commit(collectLeaf bool) (common.Hash, *trie.NodeSet) { if t.trie == nil { - return t.id.Root, nil, nil + return t.id.Root, nil } return t.trie.Commit(collectLeaf) } diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 1d200e9e47a8..435aa3a47cf8 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -182,10 +182,7 @@ func (f *fuzzer) fuzz() int { return 0 } // Flush trie -> database - rootA, nodes, err := trieA.Commit(false) - if err != nil { - panic(err) - } + rootA, nodes := trieA.Commit(false) if nodes != nil { dbA.Update(trie.NewWithNodeSet(nodes)) } @@ -201,9 +198,7 @@ func (f *fuzzer) fuzz() int { trieB.Update(kv.k, kv.v) } rootB := trieB.Hash() - if _, err := trieB.Commit(); err != nil { - panic(err) - } + trieB.Commit() if rootA != rootB { panic(fmt.Sprintf("roots differ: (trie) %x != %x (stacktrie)", rootA, rootB)) } diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index 85a73c675589..40dec76b8f84 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -161,10 +161,7 @@ func runRandTest(rt randTest) error { case opHash: tr.Hash() case opCommit: - hash, nodes, err := tr.Commit(false) - if err != nil { - return err - } + hash, nodes := tr.Commit(false) if nodes != nil { if err := triedb.Update(trie.NewWithNodeSet(nodes)); err != nil { return err diff --git a/trie/committer.go b/trie/committer.go index 13c54d96980a..c4957f3490ea 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -48,25 +48,22 @@ func newCommitter(owner common.Hash, tracer *tracer, collectLeaf bool) *committe // Commit collapses a node down into a hash node and returns it along with // the modified nodeset. -func (c *committer) Commit(n node) (hashNode, *NodeSet, error) { - h, err := c.commit(nil, n) - if err != nil { - return nil, nil, err - } +func (c *committer) Commit(n node) (hashNode, *NodeSet) { + h := c.commit(nil, n) // Some nodes can be deleted from trie which can't be captured // by committer itself. Iterate all deleted nodes tracked by // tracer and marked them as deleted only if they are present // in database previously. c.tracer.markDeletions(c.nodes) - return h.(hashNode), c.nodes, nil + return h.(hashNode), c.nodes } // commit collapses a node down into a hash node and returns it. -func (c *committer) commit(path []byte, n node) (node, error) { +func (c *committer) commit(path []byte, n node) node { // if this path is clean, use available cached data hash, dirty := n.cache() if hash != nil && !dirty { - return hash, nil + return hash } // Commit children, then parent, and remove the dirty flag. switch cn := n.(type) { @@ -77,10 +74,8 @@ func (c *committer) commit(path []byte, n node) (node, error) { // If the child is fullNode, recursively commit, // otherwise it can only be hashNode or valueNode. if _, ok := cn.Val.(*fullNode); ok { - childV, err := c.commit(append(path, cn.Key...), cn.Val) - if err != nil { - return nil, err - } + childV := c.commit(append(path, cn.Key...), cn.Val) + collapsed.Val = childV } // The key needs to be copied, since we're adding it to the @@ -88,7 +83,7 @@ func (c *committer) commit(path []byte, n node) (node, error) { collapsed.Key = hexToCompact(cn.Key) hashedNode := c.store(path, collapsed) if hn, ok := hashedNode.(hashNode); ok { - return hn, nil + return hn } // The short node now is embedded in its parent. Mark the node as // deleted if it's present in database previously. It's equivalent @@ -96,18 +91,15 @@ func (c *committer) commit(path []byte, n node) (node, error) { if prev := c.tracer.getPrev(path); len(prev) != 0 { c.nodes.markDeleted(path, prev) } - return collapsed, nil + return collapsed case *fullNode: - hashedKids, err := c.commitChildren(path, cn) - if err != nil { - return nil, err - } + hashedKids := c.commitChildren(path, cn) collapsed := cn.copy() collapsed.Children = hashedKids hashedNode := c.store(path, collapsed) if hn, ok := hashedNode.(hashNode); ok { - return hn, nil + return hn } // The full node now is embedded in its parent. Mark the node as // deleted if it's present in database previously. It's equivalent @@ -115,9 +107,9 @@ func (c *committer) commit(path []byte, n node) (node, error) { if prev := c.tracer.getPrev(path); len(prev) != 0 { c.nodes.markDeleted(path, prev) } - return collapsed, nil + return collapsed case hashNode: - return cn, nil + return cn default: // nil, valuenode shouldn't be committed panic(fmt.Sprintf("%T: invalid node: %v", n, n)) @@ -125,7 +117,7 @@ func (c *committer) commit(path []byte, n node) (node, error) { } // commitChildren commits the children of the given fullnode -func (c *committer) commitChildren(path []byte, n *fullNode) ([17]node, error) { +func (c *committer) commitChildren(path []byte, n *fullNode) [17]node { var children [17]node for i := 0; i < 16; i++ { child := n.Children[i] @@ -142,17 +134,14 @@ func (c *committer) commitChildren(path []byte, n *fullNode) ([17]node, error) { // Commit the child recursively and store the "hashed" value. // Note the returned node can be some embedded nodes, so it's // possible the type is not hashNode. - hashed, err := c.commit(append(path, byte(i)), child) - if err != nil { - return children, err - } + hashed := c.commit(append(path, byte(i)), child) children[i] = hashed } // For the 17th child, it's possible the type is valuenode. if n.Children[16] != nil { children[16] = n.Children[16] } - return children, nil + return children } // store hashes the node n and adds it to the modified nodeset. If leaf collection diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 1fb6a97ea901..ac2a3d2a4c40 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -60,10 +60,7 @@ func TestIterator(t *testing.T) { all[val.k] = val.v trie.Update([]byte(val.k), []byte(val.v)) } - root, nodes, err := trie.Commit(false) - if err != nil { - t.Fatalf("Failed to commit trie %v", err) - } + root, nodes := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -225,7 +222,7 @@ func TestDifferenceIterator(t *testing.T) { for _, val := range testdata1 { triea.Update([]byte(val.k), []byte(val.v)) } - rootA, nodesA, _ := triea.Commit(false) + rootA, nodesA := triea.Commit(false) dba.Update(NewWithNodeSet(nodesA)) triea, _ = New(TrieID(rootA), dba) @@ -234,7 +231,7 @@ func TestDifferenceIterator(t *testing.T) { for _, val := range testdata2 { trieb.Update([]byte(val.k), []byte(val.v)) } - rootB, nodesB, _ := trieb.Commit(false) + rootB, nodesB := trieb.Commit(false) dbb.Update(NewWithNodeSet(nodesB)) trieb, _ = New(TrieID(rootB), dbb) @@ -267,7 +264,7 @@ func TestUnionIterator(t *testing.T) { for _, val := range testdata1 { triea.Update([]byte(val.k), []byte(val.v)) } - rootA, nodesA, _ := triea.Commit(false) + rootA, nodesA := triea.Commit(false) dba.Update(NewWithNodeSet(nodesA)) triea, _ = New(TrieID(rootA), dba) @@ -276,7 +273,7 @@ func TestUnionIterator(t *testing.T) { for _, val := range testdata2 { trieb.Update([]byte(val.k), []byte(val.v)) } - rootB, nodesB, _ := trieb.Commit(false) + rootB, nodesB := trieb.Commit(false) dbb.Update(NewWithNodeSet(nodesB)) trieb, _ = New(TrieID(rootB), dbb) @@ -334,7 +331,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { for _, val := range testdata1 { tr.Update([]byte(val.k), []byte(val.v)) } - _, nodes, _ := tr.Commit(false) + _, nodes := tr.Commit(false) triedb.Update(NewWithNodeSet(nodes)) if !memonly { triedb.Commit(tr.Hash(), false) @@ -426,7 +423,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { for _, val := range testdata1 { ctr.Update([]byte(val.k), []byte(val.v)) } - root, nodes, _ := ctr.Commit(false) + root, nodes := ctr.Commit(false) triedb.Update(NewWithNodeSet(nodes)) if !memonly { triedb.Commit(root, false) @@ -545,7 +542,7 @@ func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) { val = crypto.Keccak256(val) trie.Update(key, val) } - _, nodes, _ := trie.Commit(false) + _, nodes := trie.Commit(false) triedb.Update(NewWithNodeSet(nodes)) // Return the generated trie return triedb, trie, logDb @@ -585,7 +582,7 @@ func TestIteratorNodeBlob(t *testing.T) { all[val.k] = val.v trie.Update([]byte(val.k), []byte(val.v)) } - _, nodes, _ := trie.Commit(false) + _, nodes := trie.Commit(false) triedb.Update(NewWithNodeSet(nodes)) triedb.Cap(0) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 158a69cc2982..83b92cebd245 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -211,7 +211,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { // All cached preimages will be also flushed if preimages recording is enabled. // 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 *StateTrie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { +func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { // Write all the pre-images to the actual disk database if len(t.getSecKeyCache()) > 0 { if t.preimages != nil { diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index 24b8c5f095e0..d3e6c670690e 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -58,10 +58,7 @@ func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) { trie.Update(key, val) } } - root, nodes, err := trie.Commit(false) - if err != nil { - panic(fmt.Errorf("failed to commit trie %v", err)) - } + root, nodes := trie.Commit(false) if err := triedb.Update(NewWithNodeSet(nodes)); err != nil { panic(fmt.Errorf("failed to commit db %v", err)) } diff --git a/trie/sync_test.go b/trie/sync_test.go index 821f7cdf4dc4..709f22949f1b 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -52,10 +52,7 @@ func makeTestTrie() (*Database, *StateTrie, map[string][]byte) { trie.Update(key, val) } } - root, nodes, err := trie.Commit(false) - if err != nil { - panic(fmt.Errorf("failed to commit trie %v", err)) - } + root, nodes := trie.Commit(false) if err := triedb.Update(NewWithNodeSet(nodes)); err != nil { panic(fmt.Errorf("failed to commit db %v", err)) } diff --git a/trie/trie.go b/trie/trie.go index 1a456b8cfd56..c467ac476622 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -566,7 +566,7 @@ func (t *Trie) Hash() common.Hash { // 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 *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { +func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { defer t.tracer.reset() // Trie is empty and can be classified into two types of situations: @@ -576,7 +576,7 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { // Wrap tracked deletions as the return set := NewNodeSet(t.owner) t.tracer.markDeletions(set) - return emptyRoot, set, nil + return emptyRoot, set } // Derive the hash for all dirty nodes first. We hold the assumption // in the following procedure that all nodes are hashed. @@ -588,15 +588,12 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet, error) { // Replace the root node with the origin hash in order to // ensure all resolved nodes are dropped after the commit. t.root = hashedNode - return rootHash, nil, nil + return rootHash, nil } h := newCommitter(t.owner, t.tracer, collectLeaf) - newRoot, nodes, err := h.Commit(t.root) - if err != nil { - return common.Hash{}, nil, err - } + newRoot, nodes := h.Commit(t.root) t.root = newRoot - return rootHash, nodes, nil + return rootHash, nodes } // hashRoot calculates the root hash of the given trie diff --git a/trie/trie_test.go b/trie/trie_test.go index aa9db5063540..ece19fdff108 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -83,7 +83,7 @@ func testMissingNode(t *testing.T, memonly bool) { trie := NewEmpty(triedb) updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) triedb.Update(NewWithNodeSet(nodes)) if !memonly { triedb.Commit(root, false) @@ -166,10 +166,7 @@ func TestInsert(t *testing.T) { updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") - root, _, err := trie.Commit(false) - if err != nil { - t.Fatalf("commit error: %v", err) - } + root, _ = trie.Commit(false) if root != exp { t.Errorf("case 2: exp %x got %x", exp, root) } @@ -194,7 +191,7 @@ func TestGet(t *testing.T) { if i == 1 { return } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) } @@ -266,10 +263,7 @@ func TestReplication(t *testing.T) { for _, val := range vals { updateString(trie, val.k, val.v) } - exp, nodes, err := trie.Commit(false) - if err != nil { - t.Fatalf("commit error: %v", err) - } + exp, nodes := trie.Commit(false) triedb.Update(NewWithNodeSet(nodes)) // create a new trie on top of the database and check that lookups work. @@ -282,10 +276,7 @@ func TestReplication(t *testing.T) { t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) } } - hash, nodes, err := trie2.Commit(false) - if err != nil { - t.Fatalf("commit error: %v", err) - } + hash, nodes := trie2.Commit(false) if hash != exp { t.Errorf("root failure. expected %x got %x", exp, hash) } @@ -454,11 +445,7 @@ func runRandTest(rt randTest) bool { case opHash: tr.Hash() case opCommit: - root, nodes, err := tr.Commit(true) - if err != nil { - rt[i].err = err - return false - } + root, nodes := tr.Commit(true) // Validity the returned nodeset if nodes != nil { for path, node := range nodes.updates.nodes { @@ -710,7 +697,7 @@ func TestCommitAfterHash(t *testing.T) { if exp != root { t.Errorf("got %x, exp %x", root, exp) } - root, _, _ = trie.Commit(false) + root, _ = trie.Commit(false) if exp != root { t.Errorf("got %x, exp %x", root, exp) } @@ -813,7 +800,7 @@ func TestCommitSequence(t *testing.T) { trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) db.Commit(root, false) @@ -854,7 +841,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { trie.Update(key, val) } // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) db.Commit(root, false) @@ -893,7 +880,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { stTrie.TryUpdate(key, val) } // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) // Flush memdb -> disk (sponge) db.Update(NewWithNodeSet(nodes)) db.Commit(root, false) @@ -941,7 +928,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) { trie.TryUpdate(key, []byte{0x1}) stTrie.TryUpdate(key, []byte{0x1}) // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) // Flush memdb -> disk (sponge) db.Update(NewWithNodeSet(nodes)) db.Commit(root, false) @@ -1114,7 +1101,7 @@ func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [] trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) } h := trie.Hash() - _, nodes, _ := trie.Commit(false) + _, nodes := trie.Commit(false) triedb.Update(NewWithNodeSet(nodes)) b.StartTimer() triedb.Dereference(h) diff --git a/trie/util_test.go b/trie/util_test.go index d0f8f94f377c..01a46553aa68 100644 --- a/trie/util_test.go +++ b/trie/util_test.go @@ -69,7 +69,7 @@ func TestTrieTracer(t *testing.T) { } // Commit the changes and re-create with new root - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) if err := db.Update(NewWithNodeSet(nodes)); err != nil { t.Fatal(err) } @@ -154,7 +154,7 @@ func TestTrieTracePrevValue(t *testing.T) { } // Commit the changes and re-create with new root - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) if err := db.Update(NewWithNodeSet(nodes)); err != nil { t.Fatal(err) } @@ -261,10 +261,7 @@ func TestDeleteAll(t *testing.T) { for _, val := range vals { trie.Update([]byte(val.k), []byte(val.v)) } - root, set, err := trie.Commit(false) - if err != nil { - t.Fatal(err) - } + root, set := trie.Commit(false) if err := db.Update(NewWithNodeSet(set)); err != nil { t.Fatal(err) } @@ -288,10 +285,7 @@ func TestDeleteAll(t *testing.T) { for _, val := range vals { trie.Delete([]byte(val.k)) } - root, set, err = trie.Commit(false) - if err != nil { - t.Fatalf("Failed to delete trie %v", err) - } + root, set = trie.Commit(false) if root != emptyRoot { t.Fatalf("Invalid trie root %v", root) } From 77380b9629e4f679778ce9de037ffdaf9c925238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 9 Feb 2023 19:01:31 +0200 Subject: [PATCH 536/715] go.mod: update pebble to latest master (#26654) --- go.mod | 46 ++++---- go.sum | 332 ++++++++++++++++++--------------------------------------- 2 files changed, 126 insertions(+), 252 deletions(-) diff --git a/go.mod b/go.mod index 2945dcbda9d1..fbac3e4d67ad 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.2.0 github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.14.0 - github.com/cockroachdb/pebble v0.0.0-20230203182935-f2e58dc4a0e1 + github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 @@ -30,7 +30,7 @@ require ( github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.4 github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa - github.com/google/uuid v1.2.0 + github.com/google/uuid v1.3.0 github.com/gorilla/websocket v1.4.2 github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 @@ -44,8 +44,8 @@ require ( github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/julienschmidt/httprouter v1.3.0 github.com/karalabe/usb v0.0.2 - github.com/mattn/go-colorable v0.1.11 - github.com/mattn/go-isatty v0.0.14 + github.com/mattn/go-colorable v0.1.13 + github.com/mattn/go-isatty v0.0.16 github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 @@ -59,11 +59,11 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa golang.org/x/crypto v0.1.0 - golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 - golang.org/x/sys v0.3.0 - golang.org/x/text v0.4.0 - golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba + golang.org/x/exp v0.0.0-20230206171751-46f607a40771 + golang.org/x/sync v0.1.0 + golang.org/x/sys v0.5.0 + golang.org/x/text v0.7.0 + golang.org/x/time v0.0.0-20220922220347-f3bd1da661af golang.org/x/tools v0.2.0 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce ) @@ -71,7 +71,7 @@ require ( require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect - github.com/DataDog/zstd v1.4.5 // indirect + github.com/DataDog/zstd v1.5.2 // indirect github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2 // indirect @@ -80,10 +80,9 @@ require ( github.com/aws/smithy-go v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cockroachdb/errors v1.8.1 // indirect - github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f // indirect - github.com/cockroachdb/redact v1.0.8 // indirect - github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 // indirect + github.com/cockroachdb/errors v1.9.1 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.3 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 // indirect @@ -91,16 +90,17 @@ require ( github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect + github.com/getsentry/sentry-go v0.18.0 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect github.com/klauspost/compress v1.15.15 // indirect - github.com/kr/pretty v0.3.0 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect @@ -108,19 +108,19 @@ require ( github.com/opentracing/opentracing-go v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.12.0 // indirect - github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect - github.com/rogpeppe/go-internal v1.6.1 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.39.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/mod v0.6.0 // indirect - golang.org/x/net v0.1.0 // indirect + golang.org/x/net v0.4.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index 23b798cc36ee..bf28cd2e24e5 100644 --- a/go.sum +++ b/go.sum @@ -8,31 +8,14 @@ cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTj cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= @@ -44,13 +27,12 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= -github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= +github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= @@ -60,10 +42,7 @@ github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNu github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= @@ -103,7 +82,6 @@ github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -112,20 +90,18 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= -github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= -github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y= -github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/cockroachdb/pebble v0.0.0-20230203182935-f2e58dc4a0e1 h1:g6MDPQ7X2UK1K4cHB5uBguGwudRBoFJ2aeK5DBP0Y8k= -github.com/cockroachdb/pebble v0.0.0-20230203182935-f2e58dc4a0e1/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= -github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw= -github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= +github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= +github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= +github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= +github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= +github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= @@ -180,7 +156,7 @@ github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaB github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= @@ -191,7 +167,6 @@ github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -206,6 +181,9 @@ github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 h1:AB7YjNrzlVHsY github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732/go.mod h1:o/XfIXWi4/GqbQirfRm5uTbXMG5NpqxkxblnbZ+QM9I= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= +github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= @@ -213,19 +191,15 @@ github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= @@ -242,12 +216,14 @@ github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= @@ -255,19 +231,12 @@ github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgR github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 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= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -276,7 +245,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -295,32 +263,27 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= @@ -341,7 +304,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= +github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -361,7 +324,8 @@ github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mq github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= -github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= +github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= @@ -369,18 +333,12 @@ github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e h1:UvSe12bq+U github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -389,16 +347,17 @@ github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= -github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= -github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= -github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= +github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= +github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= +github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= +github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= +github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= @@ -406,20 +365,20 @@ github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= +github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= @@ -432,15 +391,17 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -448,10 +409,9 @@ github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= -github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -466,18 +426,17 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= -github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -485,8 +444,8 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -505,6 +464,7 @@ github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -514,35 +474,30 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y= -github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= +github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -550,17 +505,14 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -597,7 +549,9 @@ github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZF github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= @@ -619,15 +573,12 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmv github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -639,9 +590,12 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -654,11 +608,8 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 h1:yZNXmy+j/JpX19vZkVktWqAo7Gny4PBWYYK3zskGpx4= -golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= +golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -670,16 +621,15 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -697,53 +647,39 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -754,7 +690,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -763,31 +698,16 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -795,18 +715,22 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -815,14 +739,14 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -848,30 +772,13 @@ golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -893,21 +800,11 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -923,23 +820,8 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -948,11 +830,7 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -961,12 +839,11 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -977,6 +854,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= @@ -986,11 +864,11 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -1000,11 +878,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= From b0cd8c4a5c4f0f25011ed64235a3ea1280f03c51 Mon Sep 17 00:00:00 2001 From: Chris Ziogas Date: Fri, 10 Feb 2023 11:26:43 +0200 Subject: [PATCH 537/715] core/vm: set tracer-observable `value` of a delegatecall to match parent `value` (#26632) This is a breaking change in the tracing hooks API as well as semantics of the callTracer: - CaptureEnter hook provided a nil value argument in case of DELEGATECALL. However to stay consistent with how delegate calls behave in EVM this hook is changed to pass in the value of the parent call. - callTracer will return parent call's value for DELEGATECALL frames. --------- Co-authored-by: Sina Mahmoodi --- core/vm/evm.go | 6 ++++- .../testdata/call_tracer/delegatecall.json | 3 ++- .../call_tracer_withLog/delegatecall.json | 24 ++++++++++++------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index bc7b0ab964fa..d78ea0792664 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -315,7 +315,11 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Debug { - evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, nil) + // NOTE: caller must, at all times be a contract. It should never happen + // that caller is something other than a Contract. + parent := caller.(*Contract) + // DELEGATECALL inherits value from parent call + evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value) defer func(startGas uint64) { evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) }(gas) diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json index 3e7b5f436528..5fd946f73467 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json @@ -72,7 +72,8 @@ "input": "0x7d65837a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a529806c67cc6486d4d62024471772f47f6fd672", "output": "0x0000000000000000000000000000000000000000000000000000000000000001", "to": "0x42b02b5deeb78f34cd5ac896473b63e6c99a71a2", - "type": "DELEGATECALL" + "type": "DELEGATECALL", + "value": "0x0" } ], "from": "0x269296dddce321a6bcbaa2f0181127593d732cba", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json index d5d0d072f2a1..2c82138022ec 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json @@ -165,7 +165,8 @@ "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", "input": "0x24d4e90a0000000000000000000000000000000000000000000000020000000000000000", "output": "0x000000000000000000000000000000000000000000000000b17217f7d1cf79ab", - "type": "DELEGATECALL" + "type": "DELEGATECALL", + "value": "0x0" }, { "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", @@ -174,7 +175,8 @@ "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", "input": "0x872fb2b5000000000000000000000000000000000000000000000000c330b3f7006420b8", "output": "0x00000000000000000000000000000000000000000000000224bf7df2c80f0878", - "type": "DELEGATECALL" + "type": "DELEGATECALL", + "value": "0x0" }, { "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", @@ -183,7 +185,8 @@ "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", "input": "0x872fb2b50000000000000000000000000000000000000000000000000000000000000000", "output": "0x00000000000000000000000000000000000000000000000100000016aee6e8ef", - "type": "DELEGATECALL" + "type": "DELEGATECALL", + "value": "0x0" }, { "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", @@ -192,7 +195,8 @@ "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", "input": "0x24d4e90a00000000000000000000000000000000000000000000000324bf7e0976f5f167", "output": "0x0000000000000000000000000000000000000000000000012535c5e5f87ee0d2", - "type": "DELEGATECALL" + "type": "DELEGATECALL", + "value": "0x0" }, { "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", @@ -201,7 +205,8 @@ "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", "input": "0x872fb2b5000000000000000000000000000000000000000000000000c330b3f7006420b8", "output": "0x00000000000000000000000000000000000000000000000224bf7df2c80f0878", - "type": "DELEGATECALL" + "type": "DELEGATECALL", + "value": "0x0" }, { "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", @@ -210,7 +215,8 @@ "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", "input": "0x872fb2b500000000000000000000000000000000000000000000000237d37fe5d297a500", "output": "0x0000000000000000000000000000000000000000000000093088c407fcbbce38", - "type": "DELEGATECALL" + "type": "DELEGATECALL", + "value": "0x0" }, { "from": "0x8695e5e79dab06fbbb05f445316fa4edb0da30f0", @@ -219,7 +225,8 @@ "to": "0xef3487d24a0702703e04a26cef479e313c8fc7ae", "input": "0x24d4e90a00000000000000000000000000000000000000000000000b554841fac4cad6b0", "output": "0x0000000000000000000000000000000000000000000000026d7fc130d6a74cbe", - "type": "DELEGATECALL" + "type": "DELEGATECALL", + "value": "0x0" } ], "value": "0x0", @@ -387,7 +394,8 @@ "data": "0x000000000000000000000000000000000000000000000000de0b6b3a76400000" } ], - "type": "DELEGATECALL" + "type": "DELEGATECALL", + "value": "0x0" } ], "value": "0x0", From 0ea65d4020dd1fd2b19cbad5c90ea1bb0dd9ddc4 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 10 Feb 2023 17:35:00 +0800 Subject: [PATCH 538/715] ethdb: add benchmark test suite (#26659) --- ethdb/dbtest/testsuite.go | 118 ++++++++++++++++++++++++++++++++++ ethdb/leveldb/leveldb_test.go | 12 ++++ ethdb/pebble/pebble.go | 4 +- ethdb/pebble/pebble_test.go | 14 ++++ 4 files changed, 147 insertions(+), 1 deletion(-) diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 6b206af48d5e..06a2d330db55 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -18,6 +18,7 @@ package dbtest import ( "bytes" + "math/rand" "reflect" "sort" "testing" @@ -377,6 +378,101 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { }) } +// BenchDatabaseSuite runs a suite of benchmarks against a KeyValueStore database +// implementation. +func BenchDatabaseSuite(b *testing.B, New func() ethdb.KeyValueStore) { + var ( + keys, vals = makeDataset(1_000_000, 32, 32, false) + sKeys, sVals = makeDataset(1_000_000, 32, 32, true) + ) + // Run benchmarks sequentially + b.Run("Write", func(b *testing.B) { + benchWrite := func(b *testing.B, keys, vals [][]byte) { + b.ResetTimer() + b.ReportAllocs() + + db := New() + defer db.Close() + + for i := 0; i < len(keys); i++ { + db.Put(keys[i], vals[i]) + } + } + b.Run("WriteSorted", func(b *testing.B) { + benchWrite(b, sKeys, sVals) + }) + b.Run("WriteRandom", func(b *testing.B) { + benchWrite(b, keys, vals) + }) + }) + b.Run("Read", func(b *testing.B) { + benchRead := func(b *testing.B, keys, vals [][]byte) { + db := New() + defer db.Close() + + for i := 0; i < len(keys); i++ { + db.Put(keys[i], vals[i]) + } + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < len(keys); i++ { + db.Get(keys[i]) + } + } + b.Run("ReadSorted", func(b *testing.B) { + benchRead(b, sKeys, sVals) + }) + b.Run("ReadRandom", func(b *testing.B) { + benchRead(b, keys, vals) + }) + }) + b.Run("Iteration", func(b *testing.B) { + benchIteration := func(b *testing.B, keys, vals [][]byte) { + db := New() + defer db.Close() + + for i := 0; i < len(keys); i++ { + db.Put(keys[i], vals[i]) + } + b.ResetTimer() + b.ReportAllocs() + + it := db.NewIterator(nil, nil) + for it.Next() { + } + it.Release() + } + b.Run("IterationSorted", func(b *testing.B) { + benchIteration(b, sKeys, sVals) + }) + b.Run("IterationRandom", func(b *testing.B) { + benchIteration(b, keys, vals) + }) + }) + b.Run("BatchWrite", func(b *testing.B) { + benchBatchWrite := func(b *testing.B, keys, vals [][]byte) { + b.ResetTimer() + b.ReportAllocs() + + db := New() + defer db.Close() + + batch := db.NewBatch() + for i := 0; i < len(keys); i++ { + batch.Put(keys[i], vals[i]) + } + batch.Write() + } + b.Run("BenchWriteSorted", func(b *testing.B) { + benchBatchWrite(b, sKeys, sVals) + }) + b.Run("BenchWriteRandom", func(b *testing.B) { + benchBatchWrite(b, keys, vals) + }) + }) +} + func iterateKeys(it ethdb.Iterator) []string { keys := []string{} for it.Next() { @@ -386,3 +482,25 @@ func iterateKeys(it ethdb.Iterator) []string { it.Release() return keys } + +// randomHash generates a random blob of data and returns it as a hash. +func randBytes(len int) []byte { + buf := make([]byte, len) + if n, err := rand.Read(buf); n != len || err != nil { + panic(err) + } + return buf +} + +func makeDataset(size, ksize, vsize int, order bool) ([][]byte, [][]byte) { + var keys [][]byte + var vals [][]byte + for i := 0; i < size; i += 1 { + keys = append(keys, randBytes(ksize)) + vals = append(vals, randBytes(vsize)) + } + if order { + sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i], keys[j]) < 0 }) + } + return keys, vals +} diff --git a/ethdb/leveldb/leveldb_test.go b/ethdb/leveldb/leveldb_test.go index 421d9b4693f4..d8c63860161f 100644 --- a/ethdb/leveldb/leveldb_test.go +++ b/ethdb/leveldb/leveldb_test.go @@ -38,3 +38,15 @@ func TestLevelDB(t *testing.T) { }) }) } + +func BenchmarkLevelDB(b *testing.B) { + dbtest.BenchDatabaseSuite(b, func() ethdb.KeyValueStore { + db, err := leveldb.Open(storage.NewMemStorage(), nil) + if err != nil { + b.Fatal(err) + } + return &Database{ + db: db, + } + }) +} diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 5ba7e03c25dd..fa27efd96347 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -272,7 +272,9 @@ func (d *Database) NewBatch() ethdb.Batch { } // NewBatchWithSize creates a write-only database batch with pre-allocated buffer. -// TODO can't do this with pebble. Batches are allocated in a pool so maybe this doesn't matter? +// It's not supported by pebble, but pebble has better memory allocation strategy +// which turns out a lot faster than leveldb. It's performant enough to construct +// batch object without any pre-allocated space. func (d *Database) NewBatchWithSize(_ int) ethdb.Batch { return &batch{ b: d.db.NewBatch(), diff --git a/ethdb/pebble/pebble_test.go b/ethdb/pebble/pebble_test.go index 18b800e8aba9..c773967dc66f 100644 --- a/ethdb/pebble/pebble_test.go +++ b/ethdb/pebble/pebble_test.go @@ -42,3 +42,17 @@ func TestPebbleDB(t *testing.T) { }) }) } + +func BenchmarkPebbleDB(b *testing.B) { + dbtest.BenchDatabaseSuite(b, func() ethdb.KeyValueStore { + db, err := pebble.Open("", &pebble.Options{ + FS: vfs.NewMem(), + }) + if err != nil { + b.Fatal(err) + } + return &Database{ + db: db, + } + }) +} From 241cf62b5c8b70b1a4206587fa42606ad5de024a Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 10 Feb 2023 12:34:45 +0100 Subject: [PATCH 539/715] params: schedule shanghai fork on sepolia (#26662) * params: schedule shanghai fork on sepolia * params: u64 -> newUint64 --- core/forkid/forkid_test.go | 8 +++++--- params/config.go | 3 +++ params/config_test.go | 16 +++++++--------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index e0bd1dd38944..08a1da706d57 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -122,9 +122,11 @@ func TestCreation(t *testing.T) { params.SepoliaChainConfig, params.SepoliaGenesisHash, []testcase{ - {0, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin and first London block - {1735370, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Last London block - {1735371, 0, ID{Hash: checksumToBytes(0xb96cbd13), Next: 0}}, // First MergeNetsplit block + {0, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin and first London block + {1735370, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}}, // Last London block + {1735371, 0, ID{Hash: checksumToBytes(0xb96cbd13), Next: 1677557088}}, // First MergeNetsplit block + {1735372, 1677557087, ID{Hash: checksumToBytes(0xb96cbd13), Next: 1677557088}}, // Last MergeNetsplit block + {1735372, 1677557088, ID{Hash: checksumToBytes(0xf7f9bc08), Next: 0}}, // First Shanghai block }, }, // Temporary timestamped test cases diff --git a/params/config.go b/params/config.go index 5d217ef70ecd..701a7269f959 100644 --- a/params/config.go +++ b/params/config.go @@ -50,6 +50,8 @@ var CheckpointOracles = map[common.Hash]*CheckpointOracleConfig{ GoerliGenesisHash: GoerliCheckpointOracle, } +func newUint64(val uint64) *uint64 { return &val } + var ( MainnetTerminalTotalDifficulty, _ = new(big.Int).SetString("58_750_000_000_000_000_000_000", 0) @@ -117,6 +119,7 @@ var ( TerminalTotalDifficulty: big.NewInt(17_000_000_000_000_000), TerminalTotalDifficultyPassed: true, MergeNetsplitBlock: big.NewInt(1735371), + ShanghaiTime: newUint64(1677557088), Ethash: new(EthashConfig), } diff --git a/params/config_test.go b/params/config_test.go index f3911f433f3c..5634569e29f0 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -25,8 +25,6 @@ import ( "github.com/ethereum/go-ethereum/common/math" ) -func u64(val uint64) *uint64 { return &val } - func TestCheckCompatible(t *testing.T) { type test struct { stored, new *ChainConfig @@ -95,19 +93,19 @@ func TestCheckCompatible(t *testing.T) { }, }, { - stored: &ChainConfig{ShanghaiTime: u64(10)}, - new: &ChainConfig{ShanghaiTime: u64(20)}, + stored: &ChainConfig{ShanghaiTime: newUint64(10)}, + new: &ChainConfig{ShanghaiTime: newUint64(20)}, headTimestamp: 9, wantErr: nil, }, { - stored: &ChainConfig{ShanghaiTime: u64(10)}, - new: &ChainConfig{ShanghaiTime: u64(20)}, + stored: &ChainConfig{ShanghaiTime: newUint64(10)}, + new: &ChainConfig{ShanghaiTime: newUint64(20)}, headTimestamp: 25, wantErr: &ConfigCompatError{ What: "Shanghai fork timestamp", - StoredTime: u64(10), - NewTime: u64(20), + StoredTime: newUint64(10), + NewTime: newUint64(20), RewindToTime: 9, }, }, @@ -123,7 +121,7 @@ func TestCheckCompatible(t *testing.T) { func TestConfigRules(t *testing.T) { c := &ChainConfig{ - ShanghaiTime: u64(500), + ShanghaiTime: newUint64(500), } var stamp uint64 if r := c.Rules(big.NewInt(0), true, stamp); r.IsShanghai { From 2def62b99b2f9715f455b84cb4df2f14f4af93f2 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 13 Feb 2023 10:59:27 +0100 Subject: [PATCH 540/715] eth/filters: avoid block body retrieval when no matching logs (#25199) Logs stored on disk have minimal information. Contextual information such as block number, index of log in block, index of transaction in block are filled in upon request. We can fill in all these fields only having the block header and list of receipts. But determining the transaction hash of a log requires the block body. The goal of this PR is postponing this retrieval until we are sure we the transaction hash. It happens often that the header bloom filter signals there might be matches in a block, but after actually checking them reveals the logs do not match. We want to avoid fetching the body in this case. Note that this changes the semantics of Backend.GetLogs. Downstream callers of GetLogs now assume log context fields have not been derived, and need to call DeriveFields on the logs if necessary. --- accounts/abi/bind/backends/simulated.go | 7 ++ core/rawdb/accessors_chain.go | 15 +-- core/rawdb/accessors_chain_test.go | 4 - eth/api_backend.go | 11 ++ eth/filters/filter.go | 68 +++++------ eth/filters/filter_system.go | 117 +++++++++++------- eth/filters/filter_system_test.go | 145 +++++++++++++++++++++++ internal/ethapi/backend.go | 1 + internal/ethapi/transaction_args_test.go | 3 + les/api_backend.go | 4 + light/odr_util.go | 5 +- 11 files changed, 283 insertions(+), 97 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 0224488ddd0d..008c71feaa7a 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -872,6 +872,13 @@ func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*t return fb.bc.GetHeaderByHash(hash), nil } +func (fb *filterBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { + if body := fb.bc.GetBody(hash); body != nil { + return body, nil + } + return nil, errors.New("block body not found") +} + func (fb *filterBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { return fb.backend.pendingBlock, fb.backend.pendingReceipts } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 4df580e8c4ab..9b90d8f20cc4 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -714,9 +714,9 @@ func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, t return nil } -// ReadLogs retrieves the logs for all transactions in a block. The log fields -// are populated with metadata. In case the receipts or the block body -// are not found, a nil is returned. +// ReadLogs retrieves the logs for all transactions in a block. In case +// receipts is not found, a nil is returned. +// Note: ReadLogs does not derive unstored log fields. func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.ChainConfig) [][]*types.Log { // Retrieve the flattened receipt slice data := ReadReceiptsRLP(db, hash, number) @@ -729,15 +729,6 @@ func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.C return nil } - body := ReadBody(db, hash, number) - if body == nil { - log.Error("Missing body but have receipt", "hash", hash, "number", number) - return nil - } - if err := deriveLogFields(receipts, hash, number, body.Transactions); err != nil { - log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err) - return nil - } logs := make([][]*types.Log, len(receipts)) for i, receipt := range receipts { logs[i] = receipt.Logs diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 21d23e1f0c8b..f7f8d0b086d7 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -750,10 +750,6 @@ func TestReadLogs(t *testing.T) { t.Fatalf("unexpected number of logs[1] returned, have %d want %d", have, want) } - // Fill in log fields so we can compare their rlp encoding - if err := types.Receipts(receipts).DeriveFields(params.TestChainConfig, hash, 0, body.Transactions); err != nil { - t.Fatal(err) - } for i, pr := range receipts { for j, pl := range pr.Logs { rlpHave, err := rlp.EncodeToBytes(newFullLogRLP(logs[i][j])) diff --git a/eth/api_backend.go b/eth/api_backend.go index 3055bae75efa..8fd3e43300d3 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -135,6 +135,17 @@ func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*typ return b.eth.blockchain.GetBlockByHash(hash), nil } +// GetBody returns body of a block. It does not resolve special block numbers. +func (b *EthAPIBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { + if number < 0 || hash == (common.Hash{}) { + return nil, errors.New("invalid arguments; expect hash and no special block numbers") + } + if body := b.eth.blockchain.GetBody(hash); body != nil { + return body, nil + } + return nil, errors.New("block body not found") +} + func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { if blockNr, ok := blockNrOrHash.Number(); ok { return b.BlockByNumber(ctx, blockNr) diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 611fc8630144..8ba482817e0c 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -104,7 +104,7 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { if header == nil { return nil, errors.New("unknown block") } - return f.blockLogs(ctx, header, false) + return f.blockLogs(ctx, header) } // Short-cut if all we care about is pending logs if f.begin == rpc.PendingBlockNumber.Int64() { @@ -216,7 +216,7 @@ func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, err if header == nil || err != nil { return logs, err } - found, err := f.blockLogs(ctx, header, true) + found, err := f.checkMatches(ctx, header) if err != nil { return logs, err } @@ -241,7 +241,7 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e if header == nil || err != nil { return logs, err } - found, err := f.blockLogs(ctx, header, false) + found, err := f.blockLogs(ctx, header) if err != nil { return logs, err } @@ -251,15 +251,8 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e } // blockLogs returns the logs matching the filter criteria within a single block. -func (f *Filter) blockLogs(ctx context.Context, header *types.Header, skipBloom bool) ([]*types.Log, error) { - // Fast track: no filtering criteria - if len(f.addresses) == 0 && len(f.topics) == 0 { - list, err := f.sys.cachedGetLogs(ctx, header.Hash(), header.Number.Uint64()) - if err != nil { - return nil, err - } - return flatten(list), nil - } else if skipBloom || bloomFilter(header.Bloom, f.addresses, f.topics) { +func (f *Filter) blockLogs(ctx context.Context, header *types.Header) ([]*types.Log, error) { + if bloomFilter(header.Bloom, f.addresses, f.topics) { return f.checkMatches(ctx, header) } return nil, nil @@ -267,30 +260,37 @@ func (f *Filter) blockLogs(ctx context.Context, header *types.Header, skipBloom // checkMatches checks if the receipts belonging to the given header contain any log events that // match the filter criteria. This function is called when the bloom filter signals a potential match. +// skipFilter signals all logs of the given block are requested. func (f *Filter) checkMatches(ctx context.Context, header *types.Header) ([]*types.Log, error) { - logsList, err := f.sys.cachedGetLogs(ctx, header.Hash(), header.Number.Uint64()) + hash := header.Hash() + // Logs in cache are partially filled with context data + // such as tx index, block hash, etc. + // Notably tx hash is NOT filled in because it needs + // access to block body data. + cached, err := f.sys.cachedLogElem(ctx, hash, header.Number.Uint64()) if err != nil { return nil, err } - - unfiltered := flatten(logsList) - logs := filterLogs(unfiltered, nil, nil, f.addresses, f.topics) - if len(logs) > 0 { - // We have matching logs, check if we need to resolve full logs via the light client - if logs[0].TxHash == (common.Hash{}) { - receipts, err := f.sys.backend.GetReceipts(ctx, header.Hash()) - if err != nil { - return nil, err - } - unfiltered = unfiltered[:0] - for _, receipt := range receipts { - unfiltered = append(unfiltered, receipt.Logs...) - } - logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics) - } + logs := filterLogs(cached.logs, nil, nil, f.addresses, f.topics) + if len(logs) == 0 { + return nil, nil + } + // Most backends will deliver un-derived logs, but check nevertheless. + if len(logs) > 0 && logs[0].TxHash != (common.Hash{}) { return logs, nil } - return nil, nil + + body, err := f.sys.cachedGetBody(ctx, cached, hash, header.Number.Uint64()) + if err != nil { + return nil, err + } + for i, log := range logs { + // Copy log not to modify cache elements + logcopy := *log + logcopy.TxHash = body.Transactions[logcopy.TxIndex].Hash() + logs[i] = &logcopy + } + return logs, nil } // pendingLogs returns the logs matching the filter criteria within the pending block. @@ -380,11 +380,3 @@ func bloomFilter(bloom types.Bloom, addresses []common.Address, topics [][]commo } return true } - -func flatten(list [][]*types.Log) []*types.Log { - var flat []*types.Log - for _, logs := range list { - flat = append(flat, logs...) - } - return flat -} diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index c424dd2946e7..42ea17d5056b 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -22,6 +22,7 @@ import ( "context" "fmt" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum" @@ -58,6 +59,7 @@ type Backend interface { ChainDb() ethdb.Database HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) + GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) PendingBlockAndReceipts() (*types.Block, types.Receipts) @@ -77,7 +79,7 @@ type Backend interface { // FilterSystem holds resources shared by all filters. type FilterSystem struct { backend Backend - logsCache *lru.Cache[common.Hash, [][]*types.Log] + logsCache *lru.Cache[common.Hash, *logCacheElem] cfg *Config } @@ -86,13 +88,18 @@ func NewFilterSystem(backend Backend, config Config) *FilterSystem { config = config.withDefaults() return &FilterSystem{ backend: backend, - logsCache: lru.NewCache[common.Hash, [][]*types.Log](config.LogCacheSize), + logsCache: lru.NewCache[common.Hash, *logCacheElem](config.LogCacheSize), cfg: &config, } } -// cachedGetLogs loads block logs from the backend and caches the result. -func (sys *FilterSystem) cachedGetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { +type logCacheElem struct { + logs []*types.Log + body atomic.Pointer[types.Body] +} + +// cachedLogElem loads block logs from the backend and caches the result. +func (sys *FilterSystem) cachedLogElem(ctx context.Context, blockHash common.Hash, number uint64) (*logCacheElem, error) { cached, ok := sys.logsCache.Get(blockHash) if ok { return cached, nil @@ -105,8 +112,35 @@ func (sys *FilterSystem) cachedGetLogs(ctx context.Context, blockHash common.Has if logs == nil { return nil, fmt.Errorf("failed to get logs for block #%d (0x%s)", number, blockHash.TerminalString()) } - sys.logsCache.Add(blockHash, logs) - return logs, nil + // Database logs are un-derived. + // Fill in whatever we can (txHash is inaccessible at this point). + flattened := make([]*types.Log, 0) + var logIdx uint + for i, txLogs := range logs { + for _, log := range txLogs { + log.BlockHash = blockHash + log.BlockNumber = number + log.TxIndex = uint(i) + log.Index = logIdx + logIdx++ + flattened = append(flattened, log) + } + } + elem := &logCacheElem{logs: flattened} + sys.logsCache.Add(blockHash, elem) + return elem, nil +} + +func (sys *FilterSystem) cachedGetBody(ctx context.Context, elem *logCacheElem, hash common.Hash, number uint64) (*types.Body, error) { + if body := elem.body.Load(); body != nil { + return body, nil + } + body, err := sys.backend.GetBody(ctx, hash, rpc.BlockNumber(number)) + if err != nil { + return nil, err + } + elem.body.Store(body) + return body, nil } // Type determines the kind of filter and is used to put the filter in to @@ -431,6 +465,12 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) if es.lightMode && len(filters[LogsSubscription]) > 0 { es.lightFilterNewHead(ev.Block.Header(), func(header *types.Header, remove bool) { for _, f := range filters[LogsSubscription] { + if f.logsCrit.FromBlock != nil && header.Number.Cmp(f.logsCrit.FromBlock) < 0 { + continue + } + if f.logsCrit.ToBlock != nil && header.Number.Cmp(f.logsCrit.ToBlock) > 0 { + continue + } if matchedLogs := es.lightFilterLogs(header, f.logsCrit.Addresses, f.logsCrit.Topics, remove); len(matchedLogs) > 0 { f.logs <- matchedLogs } @@ -474,42 +514,39 @@ func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func // filter logs of a single header in light client mode func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.Address, topics [][]common.Hash, remove bool) []*types.Log { - if bloomFilter(header.Bloom, addresses, topics) { - // Get the logs of the block - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - logsList, err := es.sys.cachedGetLogs(ctx, header.Hash(), header.Number.Uint64()) - if err != nil { - return nil - } - var unfiltered []*types.Log - for _, logs := range logsList { - for _, log := range logs { - logcopy := *log - logcopy.Removed = remove - unfiltered = append(unfiltered, &logcopy) - } - } - logs := filterLogs(unfiltered, nil, nil, addresses, topics) - if len(logs) > 0 && logs[0].TxHash == (common.Hash{}) { - // We have matching but non-derived logs - receipts, err := es.backend.GetReceipts(ctx, header.Hash()) - if err != nil { - return nil - } - unfiltered = unfiltered[:0] - for _, receipt := range receipts { - for _, log := range receipt.Logs { - logcopy := *log - logcopy.Removed = remove - unfiltered = append(unfiltered, &logcopy) - } - } - logs = filterLogs(unfiltered, nil, nil, addresses, topics) - } + if !bloomFilter(header.Bloom, addresses, topics) { + return nil + } + // Get the logs of the block + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + cached, err := es.sys.cachedLogElem(ctx, header.Hash(), header.Number.Uint64()) + if err != nil { + return nil + } + unfiltered := append([]*types.Log{}, cached.logs...) + for i, log := range unfiltered { + // Don't modify in-cache elements + logcopy := *log + logcopy.Removed = remove + // Swap copy in-place + unfiltered[i] = &logcopy + } + logs := filterLogs(unfiltered, nil, nil, addresses, topics) + // Txhash is already resolved + if len(logs) > 0 && logs[0].TxHash != (common.Hash{}) { return logs } - return nil + // Resolve txhash + body, err := es.sys.cachedGetBody(ctx, cached, header.Hash(), header.Number.Uint64()) + if err != nil { + return nil + } + for _, log := range logs { + // logs are already copied, safe to modify + log.TxHash = body.Transactions[log.TxIndex].Hash() + } + return logs } // eventLoop (un)installs filters and processes mux events. diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 0609acc42861..974483b68fd4 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" @@ -99,6 +100,13 @@ func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*type return rawdb.ReadHeader(b.db, hash, *number), nil } +func (b *testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { + if body := rawdb.ReadBody(b.db, hash, uint64(number)); body != nil { + return body, nil + } + return nil, errors.New("block body not found") +} + func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil { return rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig), nil @@ -675,6 +683,143 @@ func TestPendingLogsSubscription(t *testing.T) { } } +func TestLightFilterLogs(t *testing.T) { + t.Parallel() + + var ( + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(t, db, Config{}) + api = NewFilterAPI(sys, true) + signer = types.HomesteadSigner{} + + firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") + secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") + thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") + notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") + firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") + secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") + + // posted twice, once as regular logs and once as pending logs. + allLogs = []*types.Log{ + // Block 1 + {Address: firstAddr, Topics: []common.Hash{}, Data: []byte{}, BlockNumber: 2, Index: 0}, + // Block 2 + {Address: firstAddr, Topics: []common.Hash{firstTopic}, Data: []byte{}, BlockNumber: 3, Index: 0}, + {Address: secondAddr, Topics: []common.Hash{firstTopic}, Data: []byte{}, BlockNumber: 3, Index: 1}, + {Address: thirdAddress, Topics: []common.Hash{secondTopic}, Data: []byte{}, BlockNumber: 3, Index: 2}, + // Block 3 + {Address: thirdAddress, Topics: []common.Hash{secondTopic}, Data: []byte{}, BlockNumber: 4, Index: 0}, + } + + testCases = []struct { + crit FilterCriteria + expected []*types.Log + id rpc.ID + }{ + // match all + 0: {FilterCriteria{}, allLogs, ""}, + // match none due to no matching addresses + 1: {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}}, []*types.Log{}, ""}, + // match logs based on addresses, ignore topics + 2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""}, + // match logs based on addresses and topics + 3: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""}, + // all logs with block num >= 3 + 4: {FilterCriteria{FromBlock: big.NewInt(3), ToBlock: big.NewInt(5)}, allLogs[1:], ""}, + // all logs + 5: {FilterCriteria{FromBlock: big.NewInt(0), ToBlock: big.NewInt(5)}, allLogs, ""}, + // all logs with 1>= block num <=2 and topic secondTopic + 6: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(3), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""}, + } + + key, _ = crypto.GenerateKey() + addr = crypto.PubkeyToAddress(key.PublicKey) + genesis = &core.Genesis{Config: params.TestChainConfig, + Alloc: core.GenesisAlloc{ + addr: {Balance: big.NewInt(params.Ether)}, + }, + } + receipts = []*types.Receipt{{ + Logs: []*types.Log{allLogs[0]}, + }, { + Logs: []*types.Log{allLogs[1], allLogs[2], allLogs[3]}, + }, { + Logs: []*types.Log{allLogs[4]}, + }} + ) + + _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 4, func(i int, b *core.BlockGen) { + if i == 0 { + return + } + receipts[i-1].Bloom = types.CreateBloom(types.Receipts{receipts[i-1]}) + b.AddUncheckedReceipt(receipts[i-1]) + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i - 1), To: &common.Address{}, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, key) + b.AddTx(tx) + }) + for i, block := range blocks { + rawdb.WriteBlock(db, block) + rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) + rawdb.WriteHeadBlockHash(db, block.Hash()) + if i > 0 { + rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), []*types.Receipt{receipts[i-1]}) + } + } + // create all filters + for i := range testCases { + id, err := api.NewFilter(testCases[i].crit) + if err != nil { + t.Fatal(err) + } + testCases[i].id = id + } + + // raise events + time.Sleep(1 * time.Second) + for _, block := range blocks { + backend.chainFeed.Send(core.ChainEvent{Block: block, Hash: common.Hash{}, Logs: allLogs}) + } + + for i, tt := range testCases { + var fetched []*types.Log + timeout := time.Now().Add(1 * time.Second) + for { // fetch all expected logs + results, err := api.GetFilterChanges(tt.id) + if err != nil { + t.Fatalf("Unable to fetch logs: %v", err) + } + fetched = append(fetched, results.([]*types.Log)...) + if len(fetched) >= len(tt.expected) { + break + } + // check timeout + if time.Now().After(timeout) { + break + } + + time.Sleep(100 * time.Millisecond) + } + + if len(fetched) != len(tt.expected) { + t.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) + return + } + + for l := range fetched { + if fetched[l].Removed { + t.Errorf("expected log not to be removed for log %d in case %d", l, i) + } + expected := *tt.expected[l] + blockNum := expected.BlockNumber - 1 + expected.BlockHash = blocks[blockNum].Hash() + expected.TxHash = blocks[blockNum].Transactions()[0].Hash() + if !reflect.DeepEqual(fetched[l], &expected) { + t.Errorf("invalid log on index %d for case %d", l, i) + } + } + } +} + // TestPendingTxFilterDeadlock tests if the event loop hangs when pending // txes arrive at the same time that one of multiple filters is timing out. // Please refer to #22131 for more details. diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 3bc7819a7d51..0c1763472f2d 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -90,6 +90,7 @@ type Backend interface { // This is copied from filters.Backend // eth/filters needs to be initialized from this backend type, so methods needed by // it must also be included here. + GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 28dc561c36e4..a8f2d5214889 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -288,6 +288,9 @@ func (b *backendMock) BlockByHash(ctx context.Context, hash common.Hash) (*types func (b *backendMock) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { return nil, nil } +func (b *backendMock) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { + return nil, nil +} func (b *backendMock) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { return nil, nil, nil } diff --git a/les/api_backend.go b/les/api_backend.go index 71cfbbed1e55..422ac74b8668 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -130,6 +130,10 @@ func (b *LesApiBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash r return nil, errors.New("invalid arguments; neither block nor hash specified") } +func (b *LesApiBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { + return light.GetBody(ctx, b.eth.odr, hash, uint64(number)) +} + func (b *LesApiBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { return nil, nil } diff --git a/light/odr_util.go b/light/odr_util.go index ea941ec32133..c49af3a1fb7a 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -148,7 +148,7 @@ func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint } // GetBlockReceipts retrieves the receipts generated by the transactions included -// in a block given by its hash. +// in a block given by its hash. Receipts will be filled in with context data. func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) { // Assume receipts are already stored locally and attempt to retrieve. receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number) @@ -184,9 +184,8 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num } // GetBlockLogs retrieves the logs generated by the transactions included in a -// block given by its hash. +// block given by its hash. Logs will be filled in with context data. func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) { - // Retrieve the potentially incomplete receipts from disk or network receipts, err := GetBlockReceipts(ctx, odr, hash, number) if err != nil { return nil, err From 7d29fff415c9ad08ebb34e5052a89585ce60eee2 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Mon, 13 Feb 2023 02:01:35 -0800 Subject: [PATCH 541/715] eth/tracers: more fork overrides in traceBlockToFile (#26655) This change allows all post-Berlin forks to be specified as overrides for futureForkBlock in the config parameter for traceBlockToFile. --- eth/tracers/api.go | 57 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 5a34d9d4a6ab..55c56b40c9f1 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -772,17 +772,9 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // actual specified block, not any preceding blocks that we have to go through // in order to obtain the state. // Therefore, it's perfectly valid to specify `"futureForkBlock": 0`, to enable `futureFork` - if config != nil && config.Overrides != nil { - // Copy the config, to not screw up the main config - // Note: the Clique-part is _not_ deep copied - chainConfigCopy := new(params.ChainConfig) - *chainConfigCopy = *chainConfig - chainConfig = chainConfigCopy - if berlin := config.Config.Overrides.BerlinBlock; berlin != nil { - chainConfig.BerlinBlock = berlin - canon = false - } + // Note: This copies the config, to not screw up the main config + chainConfig, canon = overrideConfig(chainConfig, config.Overrides) } for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution @@ -1006,3 +998,48 @@ func APIs(backend Backend) []rpc.API { }, } } + +// overrideConfig returns a copy of original with forks enabled by override enabled, +// along with a boolean that indicates whether the copy is canonical (equivalent to the original). +// Note: the Clique-part is _not_ deep copied +func overrideConfig(original *params.ChainConfig, override *params.ChainConfig) (*params.ChainConfig, bool) { + copy := new(params.ChainConfig) + *copy = *original + canon := true + + // Apply forks (after Berlin) to the copy. + if block := override.BerlinBlock; block != nil { + copy.BerlinBlock = block + canon = false + } + if block := override.LondonBlock; block != nil { + copy.LondonBlock = block + canon = false + } + if block := override.ArrowGlacierBlock; block != nil { + copy.ArrowGlacierBlock = block + canon = false + } + if block := override.GrayGlacierBlock; block != nil { + copy.GrayGlacierBlock = block + canon = false + } + if block := override.MergeNetsplitBlock; block != nil { + copy.MergeNetsplitBlock = block + canon = false + } + if timestamp := override.ShanghaiTime; timestamp != nil { + copy.ShanghaiTime = timestamp + canon = false + } + if timestamp := override.CancunTime; timestamp != nil { + copy.CancunTime = timestamp + canon = false + } + if timestamp := override.PragueTime; timestamp != nil { + copy.PragueTime = timestamp + canon = false + } + + return copy, canon +} From 03585ed7a932a6002569c382ab1d3b8d62819b07 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 13 Feb 2023 08:14:34 -0500 Subject: [PATCH 542/715] tests/fuzzers: supply gnark multiexp config, fixes #26669 (#26670) This change fixes a fuzzer which broke when we updated the gnark dependency earlier. --- tests/fuzzers/bls12381/bls12381_fuzz.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/fuzzers/bls12381/bls12381_fuzz.go b/tests/fuzzers/bls12381/bls12381_fuzz.go index a5b4b9e79856..ced87dd41a8e 100644 --- a/tests/fuzzers/bls12381/bls12381_fuzz.go +++ b/tests/fuzzers/bls12381/bls12381_fuzz.go @@ -26,6 +26,7 @@ import ( "io" "math/big" + "github.com/consensys/gnark-crypto/ecc" gnark "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" @@ -198,7 +199,7 @@ func FuzzCrossG1MultiExp(data []byte) int { } gethScalars = append(gethScalars, s) var gnarkScalar = &fr.Element{} - gnarkScalar = gnarkScalar.SetBigInt(s).FromMont() + gnarkScalar = gnarkScalar.SetBigInt(s) gnarkScalars = append(gnarkScalars, *gnarkScalar) gethPoints = append(gethPoints, new(bls12381.PointG1).Set(kp1)) @@ -217,7 +218,7 @@ func FuzzCrossG1MultiExp(data []byte) int { // gnark multi exp cp := new(gnark.G1Affine) - cp.MultiExp(gnarkPoints, gnarkScalars) + cp.MultiExp(gnarkPoints, gnarkScalars, ecc.MultiExpConfig{}) // compare result if !(bytes.Equal(cp.Marshal(), g1.ToBytes(&kp))) { From 1c5fa40a7892efa2876f8741446e9afeb92bb705 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 14 Feb 2023 03:08:06 -0500 Subject: [PATCH 543/715] cmd/devp2p: reduce output of node crawler (#26674) Our discovery crawler spits out a huge amount of logs, most of which is pretty non-interesting. This change moves the very verbose output to Debug, and adds a 8-second status log message giving the general idea about what's going on. --- cmd/devp2p/crawl.go | 53 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/cmd/devp2p/crawl.go b/cmd/devp2p/crawl.go index 9259b4894c9a..0d8127684e66 100644 --- a/cmd/devp2p/crawl.go +++ b/cmd/devp2p/crawl.go @@ -36,6 +36,14 @@ type crawler struct { revalidateInterval time.Duration } +const ( + nodeRemoved = iota + nodeSkipRecent + nodeSkipIncompat + nodeAdded + nodeUpdated +) + type resolver interface { RequestENR(*enode.Node) (*enode.Node, error) } @@ -63,19 +71,39 @@ func (c *crawler) run(timeout time.Duration) nodeSet { var ( timeoutTimer = time.NewTimer(timeout) timeoutCh <-chan time.Time + statusTicker = time.NewTicker(time.Second * 8) doneCh = make(chan enode.Iterator, len(c.iters)) liveIters = len(c.iters) ) defer timeoutTimer.Stop() + defer statusTicker.Stop() for _, it := range c.iters { go c.runIterator(doneCh, it) } + var ( + added int + updated int + skipped int + recent int + removed int + ) loop: for { select { case n := <-c.ch: - c.updateNode(n) + switch c.updateNode(n) { + case nodeSkipIncompat: + skipped++ + case nodeSkipRecent: + recent++ + case nodeRemoved: + removed++ + case nodeAdded: + added++ + default: + updated++ + } case it := <-doneCh: if it == c.inputIter { // Enable timeout when we're done revalidating the input nodes. @@ -89,6 +117,10 @@ loop: } case <-timeoutCh: break loop + case <-statusTicker.C: + log.Info("Crawling in progress", + "added", added, "updated", updated, "removed", removed, + "ignored(recent)", recent, "ignored(incompatible)", skipped) } } @@ -113,22 +145,25 @@ func (c *crawler) runIterator(done chan<- enode.Iterator, it enode.Iterator) { } } -func (c *crawler) updateNode(n *enode.Node) { +// updateNode updates the info about the given node, and returns a status +// about what changed +func (c *crawler) updateNode(n *enode.Node) int { node, ok := c.output[n.ID()] // Skip validation of recently-seen nodes. if ok && time.Since(node.LastCheck) < c.revalidateInterval { - return + return nodeSkipRecent } // Request the node record. nn, err := c.disc.RequestENR(n) node.LastCheck = truncNow() + status := nodeUpdated if err != nil { if node.Score == 0 { // Node doesn't implement EIP-868. log.Debug("Skipping node", "id", n.ID()) - return + return nodeSkipIncompat } node.Score /= 2 } else { @@ -137,18 +172,20 @@ func (c *crawler) updateNode(n *enode.Node) { node.Score++ if node.FirstResponse.IsZero() { node.FirstResponse = node.LastCheck + status = nodeAdded } node.LastResponse = node.LastCheck } // Store/update node in output set. if node.Score <= 0 { - log.Info("Removing node", "id", n.ID()) + log.Debug("Removing node", "id", n.ID()) delete(c.output, n.ID()) - } else { - log.Info("Updating node", "id", n.ID(), "seq", n.Seq(), "score", node.Score) - c.output[n.ID()] = node + return nodeRemoved } + log.Debug("Updating node", "id", n.ID(), "seq", n.Seq(), "score", node.Score) + c.output[n.ID()] = node + return status } func truncNow() time.Time { From f44ebc4838b690ef95cf10c6a278d3f33675c0b5 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 14 Feb 2023 04:12:34 -0500 Subject: [PATCH 544/715] params: update mainnet + rinkeby CHT (#26677) This change updates the CHT entries for mainnet and rinkeby --- params/config.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/params/config.go b/params/config.go index 701a7269f959..816577a54795 100644 --- a/params/config.go +++ b/params/config.go @@ -81,10 +81,10 @@ var ( // MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network. MainnetTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 471, - SectionHead: common.HexToHash("0xa03d6354f5ca8d33203bb646ac26a964f240ee54728dcb7483faff0204ec4c9b"), - CHTRoot: common.HexToHash("0x29efeeea3540b7f499b4214d5262bd1fcd87253de10a878f92e6497d848b186f"), - BloomRoot: common.HexToHash("0x2ff6a93ff5e78e823bfc80c6ec856bfe9b20c4ffd0af3cef644a916eabcd3c84"), + SectionIndex: 506, + SectionHead: common.HexToHash("0x3d1a139a6fc7764211236ef7c64d9e8c1fe55b358d7414e25277bac1144486cd"), + CHTRoot: common.HexToHash("0xef7fc3321a239a54238593bdf68d82933d903cb533b0d03228a8d958cd35ea77"), + BloomRoot: common.HexToHash("0x51d7bfe7c6397b1caa8b1cb046de4aeaf7e7fbd3fb6c726b60bf750de78809e8"), } // MainnetCheckpointOracle contains a set of configs for the main network oracle. @@ -157,10 +157,10 @@ var ( // RinkebyTrustedCheckpoint contains the light client trusted checkpoint for the Rinkeby test network. RinkebyTrustedCheckpoint = &TrustedCheckpoint{ - SectionIndex: 344, - SectionHead: common.HexToHash("0x06bb973aecce633df8cda532ff75b9d0b38c16de2545f52eaf745f858d0fe616"), - CHTRoot: common.HexToHash("0xf1c80b9270ef9fb7907362bca006f8349f0c38d45b83167b57638f54211c6aca"), - BloomRoot: common.HexToHash("0xd72187253f49bce9d471f5e0ddf2b5008ba695d7a1be1192d52fb4d8b01970c6"), + SectionIndex: 373, + SectionHead: common.HexToHash("0x09f6d8f0d08d61025ccf4578dc214220b78013841470d445ed86faab4a5a885a"), + CHTRoot: common.HexToHash("0xef72902b944a111e9fdfee5fb69a5e46f68bf11a1f0bd430321f92d6b66987df"), + BloomRoot: common.HexToHash("0xd0120268729c51dd6fa2714f7f88527adfecbdb08592c671233ad2e0ad7cd835"), } // RinkebyCheckpointOracle contains a set of configs for the Rinkeby test network oracle. From ff38c9ee2ebe64abaef115af70005128d90ae405 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 14 Feb 2023 16:48:22 +0300 Subject: [PATCH 545/715] eth/filters: replace atomic pointer with value (#26689) * eth/filters: replace atomic.Pointer * fix * improve Co-authored-by: Martin Holst Swende --------- Co-authored-by: Martin Holst Swende --- eth/filters/filter_system.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 42ea17d5056b..9fc20f335b1a 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -95,7 +95,7 @@ func NewFilterSystem(backend Backend, config Config) *FilterSystem { type logCacheElem struct { logs []*types.Log - body atomic.Pointer[types.Body] + body atomic.Value } // cachedLogElem loads block logs from the backend and caches the result. @@ -133,7 +133,7 @@ func (sys *FilterSystem) cachedLogElem(ctx context.Context, blockHash common.Has func (sys *FilterSystem) cachedGetBody(ctx context.Context, elem *logCacheElem, hash common.Hash, number uint64) (*types.Body, error) { if body := elem.body.Load(); body != nil { - return body, nil + return body.(*types.Body), nil } body, err := sys.backend.GetBody(ctx, hash, rpc.BlockNumber(number)) if err != nil { From 101587b3f400320f266eaa613c0217953a754676 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 14 Feb 2023 14:58:43 +0100 Subject: [PATCH 546/715] p2p/dnsdisc: fix tests with Go 1.20 (#26690) --- p2p/dnsdisc/client_test.go | 105 ++++++++++++++++++++++--------------- p2p/dnsdisc/tree_test.go | 17 ++++-- 2 files changed, 74 insertions(+), 48 deletions(-) diff --git a/p2p/dnsdisc/client_test.go b/p2p/dnsdisc/client_test.go index 93380fdcd3eb..6de7fead2208 100644 --- a/p2p/dnsdisc/client_test.go +++ b/p2p/dnsdisc/client_test.go @@ -20,12 +20,12 @@ import ( "context" "crypto/ecdsa" "errors" - "math/rand" "reflect" "testing" "time" "github.com/davecgh/go-spew/spew" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/testlog" @@ -34,23 +34,25 @@ import ( "github.com/ethereum/go-ethereum/p2p/enr" ) -const ( - signingKeySeed = 0x111111 - nodesSeed1 = 0x2945237 - nodesSeed2 = 0x4567299 -) +var signingKeyForTesting, _ = crypto.ToECDSA(hexutil.MustDecode("0xdc599867fc513f8f5e2c2c9c489cde5e71362d1d9ec6e693e0de063236ed1240")) func TestClientSyncTree(t *testing.T) { + nodes := []string{ + "enr:-HW4QOFzoVLaFJnNhbgMoDXPnOvcdVuj7pDpqRvh6BRDO68aVi5ZcjB3vzQRZH2IcLBGHzo8uUN3snqmgTiE56CH3AMBgmlkgnY0iXNlY3AyNTZrMaECC2_24YYkYHEgdzxlSNKQEnHhuNAbNlMlWJxrJxbAFvA", + "enr:-HW4QAggRauloj2SDLtIHN1XBkvhFZ1vtf1raYQp9TBW2RD5EEawDzbtSmlXUfnaHcvwOizhVYLtr7e6vw7NAf6mTuoCgmlkgnY0iXNlY3AyNTZrMaECjrXI8TLNXU0f8cthpAMxEshUyQlK-AM0PW2wfrnacNI", + "enr:-HW4QLAYqmrwllBEnzWWs7I5Ev2IAs7x_dZlbYdRdMUx5EyKHDXp7AV5CkuPGUPdvbv1_Ms1CPfhcGCvSElSosZmyoqAgmlkgnY0iXNlY3AyNTZrMaECriawHKWdDRk2xeZkrOXBQ0dfMFLHY4eENZwdufn1S1o", + } + r := mapResolver{ "n": "enrtree-root:v1 e=JWXYDBPXYWG6FX3GMDIBFA6CJ4 l=C7HRFPF3BLGF3YR4DY5KX3SMBE seq=1 sig=o908WmNp7LibOfPsr4btQwatZJ5URBr2ZAuxvK4UWHlsB9sUOTJQaGAlLPVAhM__XJesCHxLISo94z5Z2a463gA", "C7HRFPF3BLGF3YR4DY5KX3SMBE.n": "enrtree://AM5FCQLWIZX2QFPNJAP7VUERCCRNGRHWZG3YYHIUV7BVDQ5FDPRT2@morenodes.example.org", "JWXYDBPXYWG6FX3GMDIBFA6CJ4.n": "enrtree-branch:2XS2367YHAXJFGLZHVAWLQD4ZY,H4FHT4B454P6UXFD7JCYQ5PWDY,MHTDO6TMUBRIA2XWG5LUDACK24", - "2XS2367YHAXJFGLZHVAWLQD4ZY.n": "enr:-HW4QOFzoVLaFJnNhbgMoDXPnOvcdVuj7pDpqRvh6BRDO68aVi5ZcjB3vzQRZH2IcLBGHzo8uUN3snqmgTiE56CH3AMBgmlkgnY0iXNlY3AyNTZrMaECC2_24YYkYHEgdzxlSNKQEnHhuNAbNlMlWJxrJxbAFvA", - "H4FHT4B454P6UXFD7JCYQ5PWDY.n": "enr:-HW4QAggRauloj2SDLtIHN1XBkvhFZ1vtf1raYQp9TBW2RD5EEawDzbtSmlXUfnaHcvwOizhVYLtr7e6vw7NAf6mTuoCgmlkgnY0iXNlY3AyNTZrMaECjrXI8TLNXU0f8cthpAMxEshUyQlK-AM0PW2wfrnacNI", - "MHTDO6TMUBRIA2XWG5LUDACK24.n": "enr:-HW4QLAYqmrwllBEnzWWs7I5Ev2IAs7x_dZlbYdRdMUx5EyKHDXp7AV5CkuPGUPdvbv1_Ms1CPfhcGCvSElSosZmyoqAgmlkgnY0iXNlY3AyNTZrMaECriawHKWdDRk2xeZkrOXBQ0dfMFLHY4eENZwdufn1S1o", + "2XS2367YHAXJFGLZHVAWLQD4ZY.n": nodes[0], + "H4FHT4B454P6UXFD7JCYQ5PWDY.n": nodes[1], + "MHTDO6TMUBRIA2XWG5LUDACK24.n": nodes[2], } var ( - wantNodes = testNodes(0x29452, 3) + wantNodes = sortByID(parseNodes(nodes)) wantLinks = []string{"enrtree://AM5FCQLWIZX2QFPNJAP7VUERCCRNGRHWZG3YYHIUV7BVDQ5FDPRT2@morenodes.example.org"} wantSeq = uint(1) ) @@ -60,7 +62,7 @@ func TestClientSyncTree(t *testing.T) { if err != nil { t.Fatal("sync error:", err) } - if !reflect.DeepEqual(sortByID(stree.Nodes()), sortByID(wantNodes)) { + if !reflect.DeepEqual(sortByID(stree.Nodes()), wantNodes) { t.Errorf("wrong nodes in synced tree:\nhave %v\nwant %v", spew.Sdump(stree.Nodes()), spew.Sdump(wantNodes)) } if !reflect.DeepEqual(stree.Links(), wantLinks) { @@ -80,7 +82,7 @@ func TestClientSyncTreeBadNode(t *testing.T) { // tree, _ := MakeTree(3, nil, []string{"enrtree://AM5FCQLWIZX2QFPNJAP7VUERCCRNGRHWZG3YYHIUV7BVDQ5FDPRT2@morenodes.example.org"}) // tree.entries[badHash] = &b // tree.root.eroot = badHash - // url, _ := tree.Sign(testKey(signingKeySeed), "n") + // url, _ := tree.Sign(signingKeyForTesting, "n") // fmt.Println(url) // fmt.Printf("%#v\n", tree.ToTXT("n")) @@ -99,9 +101,13 @@ func TestClientSyncTreeBadNode(t *testing.T) { // This test checks that randomIterator finds all entries. func TestIterator(t *testing.T) { - nodes := testNodes(nodesSeed1, 30) - tree, url := makeTestTree("n", nodes, nil) - r := mapResolver(tree.ToTXT("n")) + var ( + keys = testKeys(30) + nodes = testNodes(keys) + tree, url = makeTestTree("n", nodes, nil) + r = mapResolver(tree.ToTXT("n")) + ) + c := NewClient(Config{ Resolver: r, Logger: testlog.Logger(t, log.LvlTrace), @@ -132,8 +138,12 @@ func TestIteratorCloseWithoutNext(t *testing.T) { // This test checks if closing randomIterator races. func TestIteratorClose(t *testing.T) { - nodes := testNodes(nodesSeed1, 500) - tree1, url1 := makeTestTree("t1", nodes, nil) + var ( + keys = testKeys(500) + nodes = testNodes(keys) + tree1, url1 = makeTestTree("t1", nodes, nil) + ) + c := NewClient(Config{Resolver: newMapResolver(tree1.ToTXT("t1"))}) it, err := c.NewIterator(url1) if err != nil { @@ -155,9 +165,13 @@ func TestIteratorClose(t *testing.T) { // This test checks that randomIterator traverses linked trees as well as explicitly added trees. func TestIteratorLinks(t *testing.T) { - nodes := testNodes(nodesSeed1, 40) - tree1, url1 := makeTestTree("t1", nodes[:10], nil) - tree2, url2 := makeTestTree("t2", nodes[10:], []string{url1}) + var ( + keys = testKeys(40) + nodes = testNodes(keys) + tree1, url1 = makeTestTree("t1", nodes[:10], nil) + tree2, url2 = makeTestTree("t2", nodes[10:], []string{url1}) + ) + c := NewClient(Config{ Resolver: newMapResolver(tree1.ToTXT("t1"), tree2.ToTXT("t2")), Logger: testlog.Logger(t, log.LvlTrace), @@ -176,7 +190,8 @@ func TestIteratorLinks(t *testing.T) { func TestIteratorNodeUpdates(t *testing.T) { var ( clock = new(mclock.Simulated) - nodes = testNodes(nodesSeed1, 30) + keys = testKeys(30) + nodes = testNodes(keys) resolver = newMapResolver() c = NewClient(Config{ Resolver: resolver, @@ -197,7 +212,7 @@ func TestIteratorNodeUpdates(t *testing.T) { checkIterator(t, it, nodes[:25]) // Ensure RandomNode returns the new nodes after the tree is updated. - updateSomeNodes(nodesSeed1, nodes) + updateSomeNodes(keys, nodes) tree2, _ := makeTestTree("n", nodes, nil) resolver.clear() resolver.add(tree2.ToTXT("n")) @@ -213,7 +228,8 @@ func TestIteratorNodeUpdates(t *testing.T) { func TestIteratorRootRecheckOnFail(t *testing.T) { var ( clock = new(mclock.Simulated) - nodes = testNodes(nodesSeed1, 30) + keys = testKeys(30) + nodes = testNodes(keys) resolver = newMapResolver() c = NewClient(Config{ Resolver: resolver, @@ -237,7 +253,7 @@ func TestIteratorRootRecheckOnFail(t *testing.T) { checkIterator(t, it, nodes[:25]) // Ensure RandomNode returns the new nodes after the tree is updated. - updateSomeNodes(nodesSeed1, nodes) + updateSomeNodes(keys, nodes) tree2, _ := makeTestTree("n", nodes, nil) resolver.clear() resolver.add(tree2.ToTXT("n")) @@ -250,7 +266,8 @@ func TestIteratorRootRecheckOnFail(t *testing.T) { func TestIteratorEmptyTree(t *testing.T) { var ( clock = new(mclock.Simulated) - nodes = testNodes(nodesSeed1, 1) + keys = testKeys(1) + nodes = testNodes(keys) resolver = newMapResolver() c = NewClient(Config{ Resolver: resolver, @@ -294,8 +311,7 @@ func TestIteratorEmptyTree(t *testing.T) { } // updateSomeNodes applies ENR updates to some of the given nodes. -func updateSomeNodes(keySeed int64, nodes []*enode.Node) { - keys := testKeys(nodesSeed1, len(nodes)) +func updateSomeNodes(keys []*ecdsa.PrivateKey, nodes []*enode.Node) { for i, n := range nodes[:len(nodes)/2] { r := n.Record() r.Set(enr.IP{127, 0, 0, 1}) @@ -311,7 +327,8 @@ func updateSomeNodes(keySeed int64, nodes []*enode.Node) { func TestIteratorLinkUpdates(t *testing.T) { var ( clock = new(mclock.Simulated) - nodes = testNodes(nodesSeed1, 30) + keys = testKeys(30) + nodes = testNodes(keys) resolver = newMapResolver() c = NewClient(Config{ Resolver: resolver, @@ -384,7 +401,7 @@ func makeTestTree(domain string, nodes []*enode.Node, links []string) (*Tree, st if err != nil { panic(err) } - url, err := tree.Sign(testKey(signingKeySeed), domain) + url, err := tree.Sign(signingKeyForTesting, domain) if err != nil { panic(err) } @@ -392,11 +409,10 @@ func makeTestTree(domain string, nodes []*enode.Node, links []string) (*Tree, st } // testKeys creates deterministic private keys for testing. -func testKeys(seed int64, n int) []*ecdsa.PrivateKey { - rand := rand.New(rand.NewSource(seed)) +func testKeys(n int) []*ecdsa.PrivateKey { keys := make([]*ecdsa.PrivateKey, n) for i := 0; i < n; i++ { - key, err := ecdsa.GenerateKey(crypto.S256(), rand) + key, err := crypto.GenerateKey() if err != nil { panic("can't generate key: " + err.Error()) } @@ -405,13 +421,8 @@ func testKeys(seed int64, n int) []*ecdsa.PrivateKey { return keys } -func testKey(seed int64) *ecdsa.PrivateKey { - return testKeys(seed, 1)[0] -} - -func testNodes(seed int64, n int) []*enode.Node { - keys := testKeys(seed, n) - nodes := make([]*enode.Node, n) +func testNodes(keys []*ecdsa.PrivateKey) []*enode.Node { + nodes := make([]*enode.Node, len(keys)) for i, key := range keys { record := new(enr.Record) record.SetSeq(uint64(i)) @@ -425,10 +436,6 @@ func testNodes(seed int64, n int) []*enode.Node { return nodes } -func testNode(seed int64) *enode.Node { - return testNodes(seed, 1)[0] -} - type mapResolver map[string]string func newMapResolver(maps ...map[string]string) mapResolver { @@ -457,3 +464,15 @@ func (mr mapResolver) LookupTXT(ctx context.Context, name string) ([]string, err } return nil, errors.New("not found") } + +func parseNodes(rec []string) []*enode.Node { + var ns []*enode.Node + for _, r := range rec { + var n enode.Node + if err := n.UnmarshalText([]byte(r)); err != nil { + panic(err) + } + ns = append(ns, &n) + } + return ns +} diff --git a/p2p/dnsdisc/tree_test.go b/p2p/dnsdisc/tree_test.go index 461b9ec4fd43..9ed17aa4b3e6 100644 --- a/p2p/dnsdisc/tree_test.go +++ b/p2p/dnsdisc/tree_test.go @@ -61,7 +61,9 @@ func TestParseRoot(t *testing.T) { } func TestParseEntry(t *testing.T) { - testkey := testKey(signingKeySeed) + testENRs := []string{"enr:-HW4QES8QIeXTYlDzbfr1WEzE-XKY4f8gJFJzjJL-9D7TC9lJb4Z3JPRRz1lP4pL_N_QpT6rGQjAU9Apnc-C1iMP36OAgmlkgnY0iXNlY3AyNTZrMaED5IdwfMxdmR8W37HqSFdQLjDkIwBd4Q_MjxgZifgKSdM"} + testNodes := parseNodes(testENRs) + tests := []struct { input string e entry @@ -91,7 +93,11 @@ func TestParseEntry(t *testing.T) { // Links { input: "enrtree://AKPYQIUQIL7PSIACI32J7FGZW56E5FKHEFCCOFHILBIMW3M6LWXS2@nodes.example.org", - e: &linkEntry{"AKPYQIUQIL7PSIACI32J7FGZW56E5FKHEFCCOFHILBIMW3M6LWXS2@nodes.example.org", "nodes.example.org", &testkey.PublicKey}, + e: &linkEntry{ + str: "AKPYQIUQIL7PSIACI32J7FGZW56E5FKHEFCCOFHILBIMW3M6LWXS2@nodes.example.org", + domain: "nodes.example.org", + pubkey: &signingKeyForTesting.PublicKey, + }, }, { input: "enrtree://nodes.example.org", @@ -107,8 +113,8 @@ func TestParseEntry(t *testing.T) { }, // ENRs { - input: "enr:-HW4QES8QIeXTYlDzbfr1WEzE-XKY4f8gJFJzjJL-9D7TC9lJb4Z3JPRRz1lP4pL_N_QpT6rGQjAU9Apnc-C1iMP36OAgmlkgnY0iXNlY3AyNTZrMaED5IdwfMxdmR8W37HqSFdQLjDkIwBd4Q_MjxgZifgKSdM", - e: &enrEntry{node: testNode(nodesSeed1)}, + input: testENRs[0], + e: &enrEntry{node: testNodes[0]}, }, { input: "enr:-HW4QLZHjM4vZXkbp-5xJoHsKSbE7W39FPC8283X-y8oHcHPTnDDlIlzL5ArvDUlHZVDPgmFASrh7cWgLOLxj4wprRkHgmlkgnY0iXNlY3AyNTZrMaEC3t2jLMhDpCDX5mbSEwDn4L3iUfyXzoO8G28XvjGRkrAg=", @@ -132,7 +138,8 @@ func TestParseEntry(t *testing.T) { } func TestMakeTree(t *testing.T) { - nodes := testNodes(nodesSeed2, 50) + keys := testKeys(50) + nodes := testNodes(keys) tree, err := MakeTree(2, nodes, nil) if err != nil { t.Fatal(err) From dbd6c1324dda8bb93c7a8297446fce7998cab4e1 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 14 Feb 2023 19:39:00 +0100 Subject: [PATCH 547/715] eth/catalyst: return error if withdrawals are nil post-shanghai (#26691) Spec: https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#request --- eth/catalyst/api.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 01a29fc447dc..00c4772185b1 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -410,13 +410,20 @@ func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID) (*engine.Executi // NewPayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.PayloadStatusV1, error) { if params.Withdrawals != nil { - return engine.PayloadStatusV1{Status: engine.INVALID}, fmt.Errorf("withdrawals not supported in V1") + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(fmt.Errorf("withdrawals not supported in V1")) } return api.newPayload(params) } // NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain. func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.PayloadStatusV1, error) { + if api.eth.BlockChain().Config().IsShanghai(params.Timestamp) { + if params.Withdrawals == nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(fmt.Errorf("nil withdrawals post-shanghai")) + } + } else if params.Withdrawals != nil { + return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(fmt.Errorf("non-nil withdrawals pre-shanghai")) + } return api.newPayload(params) } From 5967a2290a1805669bceba0dbc872aa456ed3a95 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Wed, 15 Feb 2023 00:27:52 -0800 Subject: [PATCH 548/715] ethdb/pebble: Fix `MemTableStopWritesThreshold` (#26692) MemTableStopWritesThreshold was set to the max size of all memtables before blocking writing but should be set to the max number of memtables. This is documented [here](https://github.com/cockroachdb/pebble/blob/master/options.go#L738-L742). --- ethdb/pebble/pebble.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index fa27efd96347..fdad13b392ea 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -157,7 +157,10 @@ func New(file string, cache int, handles int, namespace string, readonly bool) ( // MemTableStopWritesThreshold places a hard limit on the size // of the existent MemTables(including the frozen one). - MemTableStopWritesThreshold: memTableLimit * memTableSize, + // Note, this must be the number of tables not the size of all memtables + // according to https://github.com/cockroachdb/pebble/blob/master/options.go#L738-L742 + // and to https://github.com/cockroachdb/pebble/blob/master/db.go#L1892-L1903. + MemTableStopWritesThreshold: memTableLimit, // The default compaction concurrency(1 thread), // Here use all available CPUs for faster compaction. From 7fb42e6db2dd91c0a82096e6f44733ff73f6a87c Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 15 Feb 2023 13:23:07 +0100 Subject: [PATCH 549/715] eth/downloader: handle missing withdrawals if empty list is expected (#26675) This PR relaxes the block body ingress handling a bit: if block body withdrawals are missing (but expected to be empty), the body withdrawals are set to 'empty list' before being passed to upper layers. This fixes an issue where a block passed from EthereumJS to geth was deemed invalid. --- core/genesis.go | 4 +++- eth/downloader/queue.go | 4 ++++ eth/protocols/eth/handler_test.go | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index 1b9ec20ed99d..1120be015f7a 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -465,10 +465,12 @@ func (g *Genesis) ToBlock() *types.Block { head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee) } } + var withdrawals []*types.Withdrawal if g.Config != nil && g.Config.IsShanghai(g.Timestamp) { head.WithdrawalsHash = &types.EmptyRootHash + withdrawals = make([]*types.Withdrawal, 0) } - return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)) + return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)).WithWithdrawals(withdrawals) } // Commit writes the block and state of a genesis specification to the database. diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 13b3021b247d..b90f417ea44b 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -783,6 +783,10 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH if header.WithdrawalsHash == nil { // discard any withdrawals if we don't have a withdrawal hash set withdrawalLists[index] = nil + } else if *header.WithdrawalsHash == types.EmptyRootHash && withdrawalLists[index] == nil { + // if the withdrawal hash is the emptyRootHash, + // we expect withdrawals to be [] instead of nil + withdrawalLists[index] = make([]*types.Withdrawal, 0) } else if withdrawalListHashes[index] != *header.WithdrawalsHash { return errInvalidBody } diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 51850c60eae2..76505ab8d32b 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -424,7 +424,7 @@ func testGetBlockBodies(t *testing.T, protocol uint) { RequestId: 123, BlockBodiesPacket: bodies, }); err != nil { - t.Errorf("test %d: bodies mismatch: %v", i, err) + t.Fatalf("test %d: bodies mismatch: %v", i, err) } } } From 18b641b0643fc56d1fe5b90d3c7a5ecbf981add4 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 15 Feb 2023 19:14:20 +0100 Subject: [PATCH 550/715] params: go-ethereum v1.11.0 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 317241539325..fc8448f79db7 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 0 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 194b5c9152e4da400f0dc1f5f0869baac37dc773 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 15 Feb 2023 19:15:31 +0100 Subject: [PATCH 551/715] params: begin v1.11.1 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index fc8448f79db7..2a55ad122a37 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 1 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 5ccc99b258461457955fc523839fd373b33186af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 16 Feb 2023 09:00:45 +0200 Subject: [PATCH 552/715] travis, build: update Go to 1.20.1 (#26653) travis, build: update Go to 1.20 --- .travis.yml | 36 ++++++++++++++++++++++++------------ Dockerfile | 2 +- Dockerfile.alltools | 2 +- build/checksums.txt | 28 ++++++++++++++-------------- build/ci.go | 2 +- 5 files changed, 41 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9209f1cba704..f3c7a6783216 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,15 +8,13 @@ jobs: go: 1.17.x env: - azure-osx - - azure-ios - - cocoapods-ios include: # This builder only tests code linters on latest version of Go - stage: lint os: linux dist: bionic - go: 1.19.x + go: 1.20.x env: - lint git: @@ -31,7 +29,7 @@ jobs: os: linux arch: amd64 dist: bionic - go: 1.19.x + go: 1.20.x env: - docker services: @@ -48,7 +46,7 @@ jobs: os: linux arch: arm64 dist: bionic - go: 1.19.x + go: 1.20.x env: - docker services: @@ -65,7 +63,7 @@ jobs: if: type = push os: linux dist: bionic - go: 1.19.x + go: 1.20.x env: - ubuntu-ppa - GO111MODULE=on @@ -90,7 +88,7 @@ jobs: os: linux dist: bionic sudo: required - go: 1.19.x + go: 1.20.x env: - azure-linux - GO111MODULE=on @@ -120,12 +118,26 @@ jobs: - go run build/ci.go install -dlgo -arch arm64 -cc aarch64-linux-gnu-gcc - go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds + # This builder does the OSX Azure uploads + - stage: build + if: type = push + os: osx + go: 1.20.x + env: + - azure-osx + - GO111MODULE=on + git: + submodules: false # avoid cloning ethereum/tests + script: + - go run build/ci.go install -dlgo + - go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds + # These builders run the tests - stage: build os: linux arch: amd64 dist: bionic - go: 1.19.x + go: 1.20.x env: - GO111MODULE=on script: @@ -136,7 +148,7 @@ jobs: os: linux arch: arm64 dist: bionic - go: 1.18.x + go: 1.19.x env: - GO111MODULE=on script: @@ -145,7 +157,7 @@ jobs: - stage: build os: linux dist: bionic - go: 1.18.x + go: 1.19.x env: - GO111MODULE=on script: @@ -156,7 +168,7 @@ jobs: if: type = cron os: linux dist: bionic - go: 1.19.x + go: 1.20.x env: - azure-purge - GO111MODULE=on @@ -170,7 +182,7 @@ jobs: if: type = cron os: linux dist: bionic - go: 1.19.x + go: 1.20.x env: - GO111MODULE=on script: diff --git a/Dockerfile b/Dockerfile index c16b0ba87bfb..1951fed8ef87 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.19-alpine as builder +FROM golang:1.20-alpine as builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/Dockerfile.alltools b/Dockerfile.alltools index 044a9a689505..70ccc39825e9 100644 --- a/Dockerfile.alltools +++ b/Dockerfile.alltools @@ -4,7 +4,7 @@ ARG VERSION="" ARG BUILDNUM="" # Build Geth in a stock Go builder container -FROM golang:1.19-alpine as builder +FROM golang:1.20-alpine as builder RUN apk add --no-cache gcc musl-dev linux-headers git diff --git a/build/checksums.txt b/build/checksums.txt index ca6bd4f6de74..d00d9bf965da 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,19 +1,19 @@ # This file contains sha256 checksums of optional build dependencies. -8e486e8e85a281fc5ce3f0bedc5b9d2dbf6276d7db0b25d3ec034f313da0375f go1.19.5.src.tar.gz -23d22bb6571bbd60197bee8aaa10e702f9802786c2e2ddce5c84527e86b66aa0 go1.19.5.darwin-amd64.tar.gz -4a67f2bf0601afe2177eb58f825adf83509511d77ab79174db0712dc9efa16c8 go1.19.5.darwin-arm64.tar.gz -b18a5e1e60130003896e1d1c8a9e142c7cccf6f5063d52c55dd42006434419c1 go1.19.5.freebsd-386.tar.gz -317996f7427691ff3a7ffd1b6aa089b9c66cd76f32e9107443f2f6aad1bb568a go1.19.5.freebsd-amd64.tar.gz -f68331aa7458a3598060595f5601d5731fd452bb2c62ff23095ddad68854e510 go1.19.5.linux-386.tar.gz -36519702ae2fd573c9869461990ae550c8c0d955cd28d2827a6b159fda81ff95 go1.19.5.linux-amd64.tar.gz -fc0aa29c933cec8d76f5435d859aaf42249aa08c74eb2d154689ae44c08d23b3 go1.19.5.linux-arm64.tar.gz -ec14f04bdaf4a62bdcf8b55b9b6434cc27c2df7d214d0bb7076a7597283b026a go1.19.5.linux-armv6l.tar.gz -e4032e7c52ebc48bad5c58ba8de0759b6091d9b1e59581a8a521c8c9d88dbe93 go1.19.5.linux-ppc64le.tar.gz -764871cbca841a99a24e239b63c68a4aaff4104658e3165e9ca450cac1fcbea3 go1.19.5.linux-s390x.tar.gz -8873f5871d996106b701febd979c5af022e6ea58bdbbb3817a28ab948b22c286 go1.19.5.windows-386.zip -167db91a2e40aeb453d3e59d213ecab06f62e1c4a84d13a06ccda1d999961caa go1.19.5.windows-amd64.zip -85a75555e82d8aa6f486d8d29491c593389682acce9f0c270090d5938eee30ef go1.19.5.windows-arm64.zip +b5c1a3af52c385a6d1c76aed5361cf26459023980d0320de7658bae3915831a2 go1.20.1.src.tar.gz +a300a45e801ab459f3008aae5bb9efbe9a6de9bcd12388f5ca9bbd14f70236de go1.20.1.darwin-amd64.tar.gz +f1a8e06c7f1ba1c008313577f3f58132eb166a41ceb95ce6e9af30bc5a3efca4 go1.20.1.darwin-arm64.tar.gz +57d80349dc4fbf692f8cd85a5971f97841aedafcf211e367e59d3ae812292660 go1.20.1.freebsd-386.tar.gz +6e124d54d5850a15fdb15754f782986f06af23c5ddb6690849417b9c74f05f98 go1.20.1.freebsd-amd64.tar.gz +3a7345036ebd92455b653e4b4f6aaf4f7e1f91f4ced33b23d7059159cec5f4d7 go1.20.1.linux-386.tar.gz +000a5b1fca4f75895f78befeb2eecf10bfff3c428597f3f1e69133b63b911b02 go1.20.1.linux-amd64.tar.gz +5e5e2926733595e6f3c5b5ad1089afac11c1490351855e87849d0e7702b1ec2e go1.20.1.linux-arm64.tar.gz +e4edc05558ab3657ba3dddb909209463cee38df9c1996893dd08cde274915003 go1.20.1.linux-armv6l.tar.gz +85cfd4b89b48c94030783b6e9e619e35557862358b846064636361421d0b0c52 go1.20.1.linux-ppc64le.tar.gz +ba3a14381ed4538216dec3ea72b35731750597edd851cece1eb120edf7d60149 go1.20.1.linux-s390x.tar.gz +61259b5a346193e30b7b3c3f8d108062db25bbb80cf290ee251eeb855965f6ee go1.20.1.windows-386.zip +3b493969196a6de8d9762d09f5bc5ae7a3e5814b0cfbf9cc26838c2bc1314f9c go1.20.1.windows-amd64.zip +62d14ddb44bcda27c9b1f5ad9ffd4463013374ed325d762417e2adefd59a802f go1.20.1.windows-arm64.zip fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz 75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz diff --git a/build/ci.go b/build/ci.go index 094ae0a77bce..173dc7cc0308 100644 --- a/build/ci.go +++ b/build/ci.go @@ -139,7 +139,7 @@ var ( // This is the version of go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.19.5" + dlgoVersion = "1.20.1" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) From 08bf8a60c3b1dec73c67a187093cd066021d0453 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 16 Feb 2023 18:09:41 +0800 Subject: [PATCH 553/715] core: check genesis state presence by disk read (#26703) --- core/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index 1120be015f7a..5a6c409e0169 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -317,7 +317,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen // We have the genesis block in database(perhaps in ancient database) // but the corresponding state is missing. header := rawdb.ReadHeader(db, stored, 0) - if _, err := state.New(header.Root, state.NewDatabaseWithNodeDB(db, triedb), nil); err != nil { + if header.Root != types.EmptyRootHash && !rawdb.HasLegacyTrieNode(db, header.Root) { if genesis == nil { genesis = DefaultGenesisBlock() } From 645e3e86c45bfb726b507e661f788baa85d0249f Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 16 Feb 2023 05:10:16 -0500 Subject: [PATCH 554/715] core, eth/downloader: make body validation more strict (#26704) --- core/block_validator.go | 3 +++ eth/downloader/queue.go | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index 3704158c11b3..db7ea3568723 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -76,6 +76,9 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash { return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash) } + } else if block.Withdrawals() != nil { + // Withdrawals are not allowed prior to shanghai fork + return fmt.Errorf("withdrawals present in block body") } if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index b90f417ea44b..dfb7c3e48203 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -781,14 +781,17 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH return errInvalidBody } if header.WithdrawalsHash == nil { - // discard any withdrawals if we don't have a withdrawal hash set - withdrawalLists[index] = nil - } else if *header.WithdrawalsHash == types.EmptyRootHash && withdrawalLists[index] == nil { - // if the withdrawal hash is the emptyRootHash, - // we expect withdrawals to be [] instead of nil - withdrawalLists[index] = make([]*types.Withdrawal, 0) - } else if withdrawalListHashes[index] != *header.WithdrawalsHash { - return errInvalidBody + // nil hash means there withdrawals should not be present in body + if withdrawalLists[index] != nil { + return errInvalidBody + } + } else { // non-nil hash: body must have withdrawals + if withdrawalLists[index] == nil { + return errInvalidBody + } + if withdrawalListHashes[index] != *header.WithdrawalsHash { + return errInvalidBody + } } return nil } From 13d7de77f40b2c2bdcece96a06f6b7f89c0026cf Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 16 Feb 2023 05:28:01 -0500 Subject: [PATCH 555/715] eth/downloader: fix empty-body case in queue fetchresult (#26707) --- eth/downloader/queue.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index dfb7c3e48203..421d9d427024 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -76,6 +76,8 @@ func newFetchResult(header *types.Header, fastSync bool) *fetchResult { } if !header.EmptyBody() { item.pending |= (1 << bodyType) + } else if header.WithdrawalsHash != nil { + item.Withdrawals = make(types.Withdrawals, 0) } if fastSync && !header.EmptyReceipts() { item.pending |= (1 << receiptType) From e9d42499bbf46b13a7f1afef505f92e8d70f816a Mon Sep 17 00:00:00 2001 From: ucwong Date: Thu, 16 Feb 2023 11:40:16 -0600 Subject: [PATCH 556/715] eth/downloader: fix typo (#26716) --- eth/downloader/queue.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 421d9d427024..1f676e655031 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -783,7 +783,7 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH return errInvalidBody } if header.WithdrawalsHash == nil { - // nil hash means there withdrawals should not be present in body + // nil hash means that withdrawals should not be present in body if withdrawalLists[index] != nil { return errInvalidBody } From 4d3525610e9f2342ed5fcded04658cb8daa1a745 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 16 Feb 2023 14:36:58 -0500 Subject: [PATCH 557/715] all: remove deprecated uses of math.rand (#26710) This PR is a (superior) alternative to https://github.com/ethereum/go-ethereum/pull/26708, it handles deprecation, primarily two specific cases. `rand.Seed` is typically used in two ways - `rand.Seed(time.Now().UnixNano())` -- we seed it, just to be sure to get some random, and not always get the same thing on every run. This is not needed, with global seeding, so those are just removed. - `rand.Seed(1)` this is typically done to ensure we have a stable test. If we rely on this, we need to fix up the tests to use a deterministic prng-source. A few occurrences like this has been replaced with a proper custom source. `rand.Read` has been replaced by `crypto/rand`.`Read` in this PR. --- accounts/keystore/account_cache_test.go | 2 -- common/lru/basiclru_test.go | 5 +++-- common/prque/lazyqueue_test.go | 1 - consensus/ethash/consensus_test.go | 6 ++--- core/bloombits/generator_test.go | 3 ++- core/rawdb/freezer_table_test.go | 5 ----- core/state/snapshot/difflayer_test.go | 9 ++++---- core/state/snapshot/iterator_test.go | 5 +++-- core/state/snapshot/snapshot_test.go | 3 ++- core/txpool/txpool_test.go | 3 ++- crypto/signify/signify_test.go | 11 +--------- ethdb/dbtest/testsuite.go | 2 +- event/event_test.go | 1 - les/api_test.go | 3 ++- les/benchmark.go | 9 ++++---- les/utils/limiter_test.go | 2 +- les/vflux/client/fillset_test.go | 2 +- les/vflux/server/clientpool_test.go | 1 - metrics/sample.go | 29 +++++++++++++++++++++++-- metrics/sample_test.go | 17 ++++----------- miner/stress/1559/main.go | 5 +++-- miner/worker_test.go | 4 +--- p2p/discover/v4_udp_test.go | 1 - p2p/enode/localnode_test.go | 2 +- p2p/netutil/iptrack_test.go | 6 ++--- trie/encoding_test.go | 3 ++- trie/proof_test.go | 5 ----- trie/trie_test.go | 5 +++-- 28 files changed, 75 insertions(+), 75 deletions(-) diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index 01db587d1599..aa71c1201821 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -113,7 +113,6 @@ func TestWatchNewFile(t *testing.T) { func TestWatchNoDir(t *testing.T) { t.Parallel() // Create ks but not the directory that it watches. - rand.Seed(time.Now().UnixNano()) dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int())) ks := NewKeyStore(dir, LightScryptN, LightScryptP) list := ks.Accounts() @@ -322,7 +321,6 @@ func TestUpdatedKeyfileContents(t *testing.T) { t.Parallel() // Create a temporary keystore to test with - rand.Seed(time.Now().UnixNano()) dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-updatedkeyfilecontents-test-%d-%d", os.Getpid(), rand.Int())) ks := NewKeyStore(dir, LightScryptN, LightScryptP) diff --git a/common/lru/basiclru_test.go b/common/lru/basiclru_test.go index 68e13bfc92ec..e2d3559f55d3 100644 --- a/common/lru/basiclru_test.go +++ b/common/lru/basiclru_test.go @@ -17,6 +17,7 @@ package lru import ( + crand "crypto/rand" "fmt" "io" "math/rand" @@ -181,9 +182,9 @@ func BenchmarkLRU(b *testing.B) { } for i := range keys { b := make([]byte, 32) - rand.Read(b) + crand.Read(b) keys[i] = string(b) - rand.Read(b) + crand.Read(b) values[i] = b } diff --git a/common/prque/lazyqueue_test.go b/common/prque/lazyqueue_test.go index 9a831d628b6c..ffb7e5e9e387 100644 --- a/common/prque/lazyqueue_test.go +++ b/common/prque/lazyqueue_test.go @@ -56,7 +56,6 @@ func testSetIndex(a interface{}, i int) { } func TestLazyQueue(t *testing.T) { - rand.Seed(time.Now().UnixNano()) clock := &mclock.Simulated{} q := NewLazyQueue(testSetIndex, testPriority, testMaxPriority, clock, testQueueRefresh) diff --git a/consensus/ethash/consensus_test.go b/consensus/ethash/consensus_test.go index db997d737e62..e3793cd1b01f 100644 --- a/consensus/ethash/consensus_test.go +++ b/consensus/ethash/consensus_test.go @@ -17,6 +17,7 @@ package ethash import ( + crand "crypto/rand" "encoding/binary" "encoding/json" "math/big" @@ -90,16 +91,15 @@ func TestCalcDifficulty(t *testing.T) { func randSlice(min, max uint32) []byte { var b = make([]byte, 4) - rand.Read(b) + crand.Read(b) a := binary.LittleEndian.Uint32(b) size := min + a%(max-min) out := make([]byte, size) - rand.Read(out) + crand.Read(out) return out } func TestDifficultyCalculators(t *testing.T) { - rand.Seed(2) for i := 0; i < 5000; i++ { // 1 to 300 seconds diff var timeDelta = uint64(1 + rand.Uint32()%3000) diff --git a/core/bloombits/generator_test.go b/core/bloombits/generator_test.go index 883948d12bba..ac1aee0b2524 100644 --- a/core/bloombits/generator_test.go +++ b/core/bloombits/generator_test.go @@ -18,6 +18,7 @@ package bloombits import ( "bytes" + crand "crypto/rand" "math/rand" "testing" @@ -78,7 +79,7 @@ func BenchmarkGenerator(b *testing.B) { } }) for i := 0; i < types.BloomBitLength; i++ { - rand.Read(input[i][:]) + crand.Read(input[i][:]) } b.Run("random", func(b *testing.B) { b.ReportAllocs() diff --git a/core/rawdb/freezer_table_test.go b/core/rawdb/freezer_table_test.go index ea28e71756de..6181d4d72cac 100644 --- a/core/rawdb/freezer_table_test.go +++ b/core/rawdb/freezer_table_test.go @@ -27,17 +27,12 @@ import ( "sync/atomic" "testing" "testing/quick" - "time" "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/metrics" "github.com/stretchr/testify/require" ) -func init() { - rand.Seed(time.Now().Unix()) -} - // TestFreezerBasics test initializing a freezertable from scratch, writing to the table, // and reading it back. func TestFreezerBasics(t *testing.T) { diff --git a/core/state/snapshot/difflayer_test.go b/core/state/snapshot/difflayer_test.go index 59db920481b0..674a031b1608 100644 --- a/core/state/snapshot/difflayer_test.go +++ b/core/state/snapshot/difflayer_test.go @@ -18,6 +18,7 @@ package snapshot import ( "bytes" + crand "crypto/rand" "math/rand" "testing" @@ -73,7 +74,7 @@ func TestMergeBasics(t *testing.T) { if rand.Intn(2) == 0 { accStorage := make(map[common.Hash][]byte) value := make([]byte, 32) - rand.Read(value) + crand.Read(value) accStorage[randomHash()] = value storage[h] = accStorage } @@ -294,7 +295,7 @@ func BenchmarkSearchSlot(b *testing.B) { accStorage := make(map[common.Hash][]byte) for i := 0; i < 5; i++ { value := make([]byte, 32) - rand.Read(value) + crand.Read(value) accStorage[randomHash()] = value storage[accountKey] = accStorage } @@ -330,7 +331,7 @@ func BenchmarkFlatten(b *testing.B) { accStorage := make(map[common.Hash][]byte) for i := 0; i < 20; i++ { value := make([]byte, 32) - rand.Read(value) + crand.Read(value) accStorage[randomHash()] = value } storage[accountKey] = accStorage @@ -379,7 +380,7 @@ func BenchmarkJournal(b *testing.B) { accStorage := make(map[common.Hash][]byte) for i := 0; i < 200; i++ { value := make([]byte, 32) - rand.Read(value) + crand.Read(value) accStorage[randomHash()] = value } storage[accountKey] = accStorage diff --git a/core/state/snapshot/iterator_test.go b/core/state/snapshot/iterator_test.go index 7420a2dc22ed..54614427a5cf 100644 --- a/core/state/snapshot/iterator_test.go +++ b/core/state/snapshot/iterator_test.go @@ -18,6 +18,7 @@ package snapshot import ( "bytes" + crand "crypto/rand" "encoding/binary" "fmt" "math/rand" @@ -47,7 +48,7 @@ func TestAccountIteratorBasics(t *testing.T) { if rand.Intn(2) == 0 { accStorage := make(map[common.Hash][]byte) value := make([]byte, 32) - rand.Read(value) + crand.Read(value) accStorage[randomHash()] = value storage[h] = accStorage } @@ -79,7 +80,7 @@ func TestStorageIteratorBasics(t *testing.T) { var nilstorage int for i := 0; i < 100; i++ { - rand.Read(value) + crand.Read(value) if rand.Intn(2) == 0 { accStorage[randomHash()] = common.CopyBytes(value) } else { diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index bbb2650aafc2..82833873cb1c 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -17,6 +17,7 @@ package snapshot import ( + crand "crypto/rand" "encoding/binary" "fmt" "math/big" @@ -33,7 +34,7 @@ import ( // randomHash generates a random blob of data and returns it as a hash. func randomHash() common.Hash { var hash common.Hash - if n, err := rand.Read(hash[:]); n != common.HashLength || err != nil { + if n, err := crand.Read(hash[:]); n != common.HashLength || err != nil { panic(err) } return hash diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index 7aa016ab4192..bd82622f8de6 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -18,6 +18,7 @@ package txpool import ( "crypto/ecdsa" + crand "crypto/rand" "errors" "fmt" "math/big" @@ -92,7 +93,7 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec func pricedDataTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey, bytes uint64) *types.Transaction { data := make([]byte, bytes) - rand.Read(data) + crand.Read(data) tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gaslimit, gasprice, data), types.HomesteadSigner{}, key) return tx diff --git a/crypto/signify/signify_test.go b/crypto/signify/signify_test.go index ba85d2fc4339..9bac2c825f2c 100644 --- a/crypto/signify/signify_test.go +++ b/crypto/signify/signify_test.go @@ -20,10 +20,9 @@ package signify import ( - "math/rand" + "crypto/rand" "os" "testing" - "time" "github.com/jedisct1/go-minisign" ) @@ -41,8 +40,6 @@ func TestSignify(t *testing.T) { defer os.Remove(tmpFile.Name()) defer tmpFile.Close() - rand.Seed(time.Now().UnixNano()) - data := make([]byte, 1024) rand.Read(data) tmpFile.Write(data) @@ -85,8 +82,6 @@ func TestSignifyTrustedCommentTooManyLines(t *testing.T) { defer os.Remove(tmpFile.Name()) defer tmpFile.Close() - rand.Seed(time.Now().UnixNano()) - data := make([]byte, 1024) rand.Read(data) tmpFile.Write(data) @@ -110,8 +105,6 @@ func TestSignifyTrustedCommentTooManyLinesLF(t *testing.T) { defer os.Remove(tmpFile.Name()) defer tmpFile.Close() - rand.Seed(time.Now().UnixNano()) - data := make([]byte, 1024) rand.Read(data) tmpFile.Write(data) @@ -135,8 +128,6 @@ func TestSignifyTrustedCommentEmpty(t *testing.T) { defer os.Remove(tmpFile.Name()) defer tmpFile.Close() - rand.Seed(time.Now().UnixNano()) - data := make([]byte, 1024) rand.Read(data) tmpFile.Write(data) diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 06a2d330db55..e455215cb0af 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -18,7 +18,7 @@ package dbtest import ( "bytes" - "math/rand" + "crypto/rand" "reflect" "sort" "testing" diff --git a/event/event_test.go b/event/event_test.go index bdad11f13d6c..84b37eca3ba9 100644 --- a/event/event_test.go +++ b/event/event_test.go @@ -100,7 +100,6 @@ func TestSubscribeDuplicateType(t *testing.T) { } func TestMuxConcurrent(t *testing.T) { - rand.Seed(time.Now().Unix()) mux := new(TypeMux) defer mux.Stop() diff --git a/les/api_test.go b/les/api_test.go index 3db1c5fd5ec9..db680da0bff7 100644 --- a/les/api_test.go +++ b/les/api_test.go @@ -18,6 +18,7 @@ package les import ( "context" + crand "crypto/rand" "errors" "flag" "math/rand" @@ -326,7 +327,7 @@ func getHead(ctx context.Context, t *testing.T, client *rpc.Client) (uint64, com func testRequest(ctx context.Context, t *testing.T, client *rpc.Client) bool { var res string var addr common.Address - rand.Read(addr[:]) + crand.Read(addr[:]) c, cancel := context.WithTimeout(ctx, time.Second*12) defer cancel() err := client.CallContext(c, &res, "eth_getBalance", addr, "latest") diff --git a/les/benchmark.go b/les/benchmark.go index 757822a6b31a..95563a21aaf0 100644 --- a/les/benchmark.go +++ b/les/benchmark.go @@ -17,6 +17,7 @@ package les import ( + crand "crypto/rand" "encoding/binary" "fmt" "math/big" @@ -114,7 +115,7 @@ func (b *benchmarkProofsOrCode) init(h *serverHandler, count int) error { func (b *benchmarkProofsOrCode) request(peer *serverPeer, index int) error { key := make([]byte, 32) - rand.Read(key) + crand.Read(key) if b.code { return peer.requestCode(0, []CodeReq{{BHash: b.headHash, AccKey: key}}) } @@ -176,7 +177,7 @@ func (b *benchmarkTxSend) init(h *serverHandler, count int) error { for i := range b.txs { data := make([]byte, txSizeCostLimit) - rand.Read(data) + crand.Read(data) tx, err := types.SignTx(types.NewTransaction(0, addr, new(big.Int), 0, new(big.Int), data), signer, key) if err != nil { panic(err) @@ -200,7 +201,7 @@ func (b *benchmarkTxStatus) init(h *serverHandler, count int) error { func (b *benchmarkTxStatus) request(peer *serverPeer, index int) error { var hash common.Hash - rand.Read(hash[:]) + crand.Read(hash[:]) return peer.requestTxStatus(0, []common.Hash{hash}) } @@ -278,7 +279,7 @@ func (h *serverHandler) measure(setup *benchmarkSetup, count int) error { clientMeteredPipe := &meteredPipe{rw: clientPipe} serverMeteredPipe := &meteredPipe{rw: serverPipe} var id enode.ID - rand.Read(id[:]) + crand.Read(id[:]) peer1 := newServerPeer(lpv2, NetworkId, false, p2p.NewPeer(id, "client", nil), clientMeteredPipe) peer2 := newClientPeer(lpv2, NetworkId, p2p.NewPeer(id, "server", nil), serverMeteredPipe) diff --git a/les/utils/limiter_test.go b/les/utils/limiter_test.go index 3fbdc60d7c55..c031b21de58b 100644 --- a/les/utils/limiter_test.go +++ b/les/utils/limiter_test.go @@ -17,7 +17,7 @@ package utils import ( - "math/rand" + "crypto/rand" "testing" "github.com/ethereum/go-ethereum/p2p/enode" diff --git a/les/vflux/client/fillset_test.go b/les/vflux/client/fillset_test.go index ddb12a82f9b3..652dcf9f62be 100644 --- a/les/vflux/client/fillset_test.go +++ b/les/vflux/client/fillset_test.go @@ -17,7 +17,7 @@ package client import ( - "math/rand" + "crypto/rand" "testing" "time" diff --git a/les/vflux/server/clientpool_test.go b/les/vflux/server/clientpool_test.go index 790ec5136078..f75c70afcaba 100644 --- a/les/vflux/server/clientpool_test.go +++ b/les/vflux/server/clientpool_test.go @@ -135,7 +135,6 @@ func alwaysTrueFn() bool { } func testClientPool(t *testing.T, activeLimit, clientCount, paidCount int, randomDisconnect bool) { - rand.Seed(time.Now().UnixNano()) var ( clock mclock.Simulated db = rawdb.NewMemoryDatabase() diff --git a/metrics/sample.go b/metrics/sample.go index fa2bfb274e39..afcaa2118426 100644 --- a/metrics/sample.go +++ b/metrics/sample.go @@ -41,6 +41,7 @@ type ExpDecaySample struct { reservoirSize int t0, t1 time.Time values *expDecaySampleHeap + rand *rand.Rand } // NewExpDecaySample constructs a new exponentially-decaying sample with the @@ -59,6 +60,12 @@ func NewExpDecaySample(reservoirSize int, alpha float64) Sample { return s } +// SetRand sets the random source (useful in tests) +func (s *ExpDecaySample) SetRand(prng *rand.Rand) Sample { + s.rand = prng + return s +} + // Clear clears all samples. func (s *ExpDecaySample) Clear() { s.mutex.Lock() @@ -168,8 +175,14 @@ func (s *ExpDecaySample) update(t time.Time, v int64) { if s.values.Size() == s.reservoirSize { s.values.Pop() } + var f64 float64 + if s.rand != nil { + f64 = s.rand.Float64() + } else { + f64 = rand.Float64() + } s.values.Push(expDecaySample{ - k: math.Exp(t.Sub(s.t0).Seconds()*s.alpha) / rand.Float64(), + k: math.Exp(t.Sub(s.t0).Seconds()*s.alpha) / f64, v: v, }) if t.After(s.t1) { @@ -402,6 +415,7 @@ type UniformSample struct { mutex sync.Mutex reservoirSize int values []int64 + rand *rand.Rand } // NewUniformSample constructs a new uniform sample with the given reservoir @@ -416,6 +430,12 @@ func NewUniformSample(reservoirSize int) Sample { } } +// SetRand sets the random source (useful in tests) +func (s *UniformSample) SetRand(prng *rand.Rand) Sample { + s.rand = prng + return s +} + // Clear clears all samples. func (s *UniformSample) Clear() { s.mutex.Lock() @@ -511,7 +531,12 @@ func (s *UniformSample) Update(v int64) { if len(s.values) < s.reservoirSize { s.values = append(s.values, v) } else { - r := rand.Int63n(s.count) + var r int64 + if s.rand != nil { + r = s.rand.Int63n(s.count) + } else { + r = rand.Int63n(s.count) + } if r < int64(len(s.values)) { s.values[int(r)] = v } diff --git a/metrics/sample_test.go b/metrics/sample_test.go index c9168d3e8203..3ae128d56f67 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -80,7 +80,6 @@ func BenchmarkUniformSample1028(b *testing.B) { } func TestExpDecaySample10(t *testing.T) { - rand.Seed(1) s := NewExpDecaySample(100, 0.99) for i := 0; i < 10; i++ { s.Update(int64(i)) @@ -102,7 +101,6 @@ func TestExpDecaySample10(t *testing.T) { } func TestExpDecaySample100(t *testing.T) { - rand.Seed(1) s := NewExpDecaySample(1000, 0.01) for i := 0; i < 100; i++ { s.Update(int64(i)) @@ -124,7 +122,6 @@ func TestExpDecaySample100(t *testing.T) { } func TestExpDecaySample1000(t *testing.T) { - rand.Seed(1) s := NewExpDecaySample(100, 0.99) for i := 0; i < 1000; i++ { s.Update(int64(i)) @@ -150,7 +147,6 @@ func TestExpDecaySample1000(t *testing.T) { // The priority becomes +Inf quickly after starting if this is done, // effectively freezing the set of samples until a rescale step happens. func TestExpDecaySampleNanosecondRegression(t *testing.T) { - rand.Seed(1) s := NewExpDecaySample(100, 0.99) for i := 0; i < 100; i++ { s.Update(10) @@ -183,8 +179,7 @@ func TestExpDecaySampleRescale(t *testing.T) { func TestExpDecaySampleSnapshot(t *testing.T) { now := time.Now() - rand.Seed(1) - s := NewExpDecaySample(100, 0.99) + s := NewExpDecaySample(100, 0.99).(*ExpDecaySample).SetRand(rand.New(rand.NewSource(1))) for i := 1; i <= 10000; i++ { s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i)) } @@ -195,8 +190,7 @@ func TestExpDecaySampleSnapshot(t *testing.T) { func TestExpDecaySampleStatistics(t *testing.T) { now := time.Now() - rand.Seed(1) - s := NewExpDecaySample(100, 0.99) + s := NewExpDecaySample(100, 0.99).(*ExpDecaySample).SetRand(rand.New(rand.NewSource(1))) for i := 1; i <= 10000; i++ { s.(*ExpDecaySample).update(now.Add(time.Duration(i)), int64(i)) } @@ -204,7 +198,6 @@ func TestExpDecaySampleStatistics(t *testing.T) { } func TestUniformSample(t *testing.T) { - rand.Seed(1) s := NewUniformSample(100) for i := 0; i < 1000; i++ { s.Update(int64(i)) @@ -226,7 +219,6 @@ func TestUniformSample(t *testing.T) { } func TestUniformSampleIncludesTail(t *testing.T) { - rand.Seed(1) s := NewUniformSample(100) max := 100 for i := 0; i < max; i++ { @@ -244,7 +236,7 @@ func TestUniformSampleIncludesTail(t *testing.T) { } func TestUniformSampleSnapshot(t *testing.T) { - s := NewUniformSample(100) + s := NewUniformSample(100).(*UniformSample).SetRand(rand.New(rand.NewSource(1))) for i := 1; i <= 10000; i++ { s.Update(int64(i)) } @@ -254,8 +246,7 @@ func TestUniformSampleSnapshot(t *testing.T) { } func TestUniformSampleStatistics(t *testing.T) { - rand.Seed(1) - s := NewUniformSample(100) + s := NewUniformSample(100).(*UniformSample).SetRand(rand.New(rand.NewSource(1))) for i := 1; i <= 10000; i++ { s.Update(int64(i)) } diff --git a/miner/stress/1559/main.go b/miner/stress/1559/main.go index abc24f4a369b..c27875000d85 100644 --- a/miner/stress/1559/main.go +++ b/miner/stress/1559/main.go @@ -19,6 +19,7 @@ package main import ( "crypto/ecdsa" + crand "crypto/rand" "math/big" "math/rand" "os" @@ -162,7 +163,7 @@ func makeTransaction(nonce uint64, privKey *ecdsa.PrivateKey, signer types.Signe // Feecap and feetip are limited to 32 bytes. Offer a sightly // larger buffer for creating both valid and invalid transactions. var buf = make([]byte, 32+5) - rand.Read(buf) + crand.Read(buf) gasTipCap := new(big.Int).SetBytes(buf) // If the given base fee is nil(the 1559 is still not available), @@ -173,7 +174,7 @@ func makeTransaction(nonce uint64, privKey *ecdsa.PrivateKey, signer types.Signe // Generate the feecap, 75% valid feecap and 25% unguaranteed. var gasFeeCap *big.Int if rand.Intn(4) == 0 { - rand.Read(buf) + crand.Read(buf) gasFeeCap = new(big.Int).SetBytes(buf) } else { gasFeeCap = new(big.Int).Add(baseFee, gasTipCap) diff --git a/miner/worker_test.go b/miner/worker_test.go index a3f46db17cc9..ba929d293d8a 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -17,9 +17,9 @@ package miner import ( + "crypto/rand" "errors" "math/big" - "math/rand" "sync/atomic" "testing" "time" @@ -105,8 +105,6 @@ func init() { GasPrice: big.NewInt(params.InitialBaseFee), }) newTxs = append(newTxs, tx2) - - rand.Seed(time.Now().UnixNano()) } // testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index f4fd9b246fd3..21f0d75172c0 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -165,7 +165,6 @@ func TestUDPv4_responseTimeouts(t *testing.T) { test := newUDPTest(t) defer test.close() - rand.Seed(time.Now().UnixNano()) randomDuration := func(max time.Duration) time.Duration { return time.Duration(rand.Int63n(int64(max))) } diff --git a/p2p/enode/localnode_test.go b/p2p/enode/localnode_test.go index 312df813bba4..7f97ad392f27 100644 --- a/p2p/enode/localnode_test.go +++ b/p2p/enode/localnode_test.go @@ -17,7 +17,7 @@ package enode import ( - "math/rand" + "crypto/rand" "net" "testing" diff --git a/p2p/netutil/iptrack_test.go b/p2p/netutil/iptrack_test.go index a9a2998a6528..ee3bba861e25 100644 --- a/p2p/netutil/iptrack_test.go +++ b/p2p/netutil/iptrack_test.go @@ -17,8 +17,8 @@ package netutil import ( + crand "crypto/rand" "fmt" - mrand "math/rand" "testing" "time" @@ -123,8 +123,8 @@ func TestIPTrackerForceGC(t *testing.T) { for i := 0; i < 5*max; i++ { e1 := make([]byte, 4) e2 := make([]byte, 4) - mrand.Read(e1) - mrand.Read(e2) + crand.Read(e1) + crand.Read(e2) it.AddStatement(string(e1), string(e2)) it.AddContact(string(e1)) clock.Run(rate) diff --git a/trie/encoding_test.go b/trie/encoding_test.go index e8fe4f3c6bb4..d16d25c359c7 100644 --- a/trie/encoding_test.go +++ b/trie/encoding_test.go @@ -18,6 +18,7 @@ package trie import ( "bytes" + crand "crypto/rand" "encoding/hex" "math/rand" "testing" @@ -97,7 +98,7 @@ func TestHexToCompactInPlaceRandom(t *testing.T) { for i := 0; i < 10000; i++ { l := rand.Intn(128) key := make([]byte, l) - rand.Read(key) + crand.Read(key) hexBytes := keybytesToHex(key) hexOrig := []byte(string(hexBytes)) exp := hexToCompact(hexBytes) diff --git a/trie/proof_test.go b/trie/proof_test.go index 61667b20ab13..5796a308930e 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -23,7 +23,6 @@ import ( mrand "math/rand" "sort" "testing" - "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -31,10 +30,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb/memorydb" ) -func init() { - mrand.Seed(time.Now().Unix()) -} - // makeProvers creates Merkle trie provers based on different implementations to // test all variations. func makeProvers(trie *Trie) []func(key []byte) *memorydb.Database { diff --git a/trie/trie_test.go b/trie/trie_test.go index ece19fdff108..2fb97eebbf49 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -18,6 +18,7 @@ package trie import ( "bytes" + crand "crypto/rand" "encoding/binary" "errors" "fmt" @@ -1127,8 +1128,8 @@ func TestDecodeNode(t *testing.T) { elems = make([]byte, 20) ) for i := 0; i < 5000000; i++ { - rand.Read(hash) - rand.Read(elems) + crand.Read(hash) + crand.Read(elems) decodeNode(hash, elems) } } From 769610667db1e2540c548344fc5fd090416445a4 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 16 Feb 2023 20:51:51 +0100 Subject: [PATCH 558/715] params: go-ethereum v1.11.1 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 2a55ad122a37..2a62c17b59bb 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 1 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 1 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From b40c10916c13660472d3071f7e5c1fcdee9aceec Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 16 Feb 2023 20:53:16 +0100 Subject: [PATCH 559/715] params: begin v1.11.2 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 2a62c17b59bb..9be8a26a5dd7 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 1 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 2 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 6428663faf50f8368cedf0297063154483cce72b Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 17 Feb 2023 11:25:09 +0100 Subject: [PATCH 560/715] eth/catalyst: send INVALID instead of INVALID_BLOCK_HASH (#26696) This change will break one hive test, but pass another and it will be the better way going forward --- beacon/engine/errors.go | 2 -- eth/catalyst/api.go | 2 +- eth/catalyst/api_test.go | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/beacon/engine/errors.go b/beacon/engine/errors.go index b2f31139256f..fe1137e0041d 100644 --- a/beacon/engine/errors.go +++ b/beacon/engine/errors.go @@ -74,8 +74,6 @@ var ( // - newPayloadV1: if the payload was accepted, but not processed (side chain) ACCEPTED = "ACCEPTED" - INVALIDBLOCKHASH = "INVALID_BLOCK_HASH" - GenericServerError = &EngineAPIError{code: -32000, msg: "Server error"} UnknownPayload = &EngineAPIError{code: -38001, msg: "Unknown payload"} InvalidForkChoiceState = &EngineAPIError{code: -38002, msg: "Invalid forkchoice state"} diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 00c4772185b1..cee9b2c508cc 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -448,7 +448,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData) (engine.Payloa block, err := engine.ExecutableDataToBlock(params) if err != nil { log.Debug("Invalid NewPayload params", "params", params, "error", err) - return engine.PayloadStatusV1{Status: engine.INVALIDBLOCKHASH}, nil + return engine.PayloadStatusV1{Status: engine.INVALID}, nil } // Stash away the last update to warn the user if the beacon client goes offline api.lastNewPayloadLock.Lock() diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index f7881415a434..7155fb54d038 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -864,8 +864,8 @@ func TestInvalidBloom(t *testing.T) { if err != nil { t.Fatal(err) } - if status.Status != engine.INVALIDBLOCKHASH { - t.Errorf("invalid status: expected VALID got: %v", status.Status) + if status.Status != engine.INVALID { + t.Errorf("invalid status: expected INVALID got: %v", status.Status) } } From a0d63bc69a659009a3884f50c563a0e58483cdd0 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 17 Feb 2023 15:34:30 +0100 Subject: [PATCH 561/715] ci: disable coverage reporting in appveyor and travis --- .travis.yml | 8 ++++---- appveyor.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index f3c7a6783216..176cc83996a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -141,7 +141,7 @@ jobs: env: - GO111MODULE=on script: - - go run build/ci.go test -coverage $TEST_PACKAGES + - go run build/ci.go test $TEST_PACKAGES - stage: build if: type = pull_request @@ -152,7 +152,7 @@ jobs: env: - GO111MODULE=on script: - - go run build/ci.go test -coverage $TEST_PACKAGES + - go run build/ci.go test $TEST_PACKAGES - stage: build os: linux @@ -161,7 +161,7 @@ jobs: env: - GO111MODULE=on script: - - go run build/ci.go test -coverage $TEST_PACKAGES + - go run build/ci.go test $TEST_PACKAGES # This builder does the Azure archive purges to avoid accumulating junk - stage: build @@ -186,5 +186,5 @@ jobs: env: - GO111MODULE=on script: - - go run build/ci.go test -race -coverage $TEST_PACKAGES + - go run build/ci.go test -race $TEST_PACKAGES diff --git a/appveyor.yml b/appveyor.yml index d477e6db9f56..114aec644b27 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,7 +26,7 @@ for: - go run build/ci.go lint - go run build/ci.go install -dlgo test_script: - - go run build/ci.go test -dlgo -coverage + - go run build/ci.go test -dlgo # linux/386 is disabled. - matrix: @@ -54,4 +54,4 @@ for: - go run build/ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds - go run build/ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload gethstore/builds test_script: - - go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% -coverage + - go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% From 15e5e6176bb384514271c24e53c0b9e2f862b2a4 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Fri, 17 Feb 2023 20:30:38 +0200 Subject: [PATCH 562/715] eth/catalyst: request too large error (#26722) The method `GetPayloadBodiesByRangeV1` now returns "-38004: Too large request" error if the requested range is too large, according to spec Co-authored-by: Martin Holst Swende --- beacon/engine/errors.go | 1 + eth/catalyst/api.go | 5 ++++- eth/catalyst/api_test.go | 16 +++++++++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/beacon/engine/errors.go b/beacon/engine/errors.go index fe1137e0041d..769001b9e3d7 100644 --- a/beacon/engine/errors.go +++ b/beacon/engine/errors.go @@ -78,6 +78,7 @@ var ( UnknownPayload = &EngineAPIError{code: -38001, msg: "Unknown payload"} InvalidForkChoiceState = &EngineAPIError{code: -38002, msg: "Invalid forkchoice state"} InvalidPayloadAttributes = &EngineAPIError{code: -38003, msg: "Invalid payload attributes"} + TooLargeRequest = &EngineAPIError{code: -38004, msg: "Too large request"} InvalidParams = &EngineAPIError{code: -32602, msg: "Invalid parameters"} STATUS_INVALID = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: INVALID}, PayloadID: nil} diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index cee9b2c508cc..95eed408f031 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -785,9 +785,12 @@ func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engin // GetPayloadBodiesByRangeV1 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range // of block bodies by the engine api. func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBodyV1, error) { - if start == 0 || count == 0 || count > 1024 { + if start == 0 || count == 0 { return nil, engine.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count)) } + if count > 1024 { + return nil, engine.TooLargeRequest.With(fmt.Errorf("requested count too large: %v", count)) + } // limit count up until current current := api.eth.BlockChain().CurrentBlock().NumberU64() last := uint64(start) + uint64(count) - 1 diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 7155fb54d038..4dc0c0ea7ea9 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -1383,37 +1383,43 @@ func TestGetBlockBodiesByRangeInvalidParams(t *testing.T) { node, eth, _ := setupBodies(t) api := NewConsensusAPI(eth) defer node.Close() - tests := []struct { start hexutil.Uint64 count hexutil.Uint64 + want *engine.EngineAPIError }{ // Genesis { start: 0, count: 1, + want: engine.InvalidParams, }, // No block requested { start: 1, count: 0, + want: engine.InvalidParams, }, // Genesis & no block { start: 0, count: 0, + want: engine.InvalidParams, }, // More than 1024 blocks { start: 1, count: 1025, + want: engine.TooLargeRequest, }, } - - for _, test := range tests { - result, err := api.GetPayloadBodiesByRangeV1(test.start, test.count) + for i, tc := range tests { + result, err := api.GetPayloadBodiesByRangeV1(tc.start, tc.count) if err == nil { - t.Fatalf("expected error, got %v", result) + t.Fatalf("test %d: expected error, got %v", i, result) + } + if have, want := err.Error(), tc.want.Error(); have != want { + t.Fatalf("test %d: have %s, want %s", i, have, want) } } } From 7c749c947a9d5181f5f2c1b3fdb5ea6b0e401e8e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 19 Feb 2023 14:10:19 -0500 Subject: [PATCH 563/715] core/trie: remove trie tracer (#26665) This PR contains a small portion of the full pbss PR, namely Remove the tracer from trie (and comitter), and instead using an accessList. Related changes to the Nodeset. --------- Co-authored-by: Gary Rong --- core/state/metrics.go | 14 +- core/state/statedb.go | 29 ++-- trie/committer.go | 29 +--- trie/database.go | 9 +- trie/nodeset.go | 120 +++++++++-------- trie/trie.go | 71 ++++------ trie/trie_test.go | 66 +-------- trie/util_test.go | 304 ------------------------------------------ trie/utils.go | 199 --------------------------- 9 files changed, 116 insertions(+), 725 deletions(-) delete mode 100644 trie/util_test.go delete mode 100644 trie/utils.go diff --git a/core/state/metrics.go b/core/state/metrics.go index e702ef3a81a6..086666b7dbfc 100644 --- a/core/state/metrics.go +++ b/core/state/metrics.go @@ -19,12 +19,10 @@ package state import "github.com/ethereum/go-ethereum/metrics" var ( - accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) - storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) - accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) - storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil) - accountTrieUpdatedMeter = metrics.NewRegisteredMeter("state/update/accountnodes", nil) - storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil) - accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil) - storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil) + accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) + storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) + accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) + storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil) + accountTrieNodesMeter = metrics.NewRegisteredMeter("state/trie/account", nil) + storageTriesNodesMeter = metrics.NewRegisteredMeter("state/trie/storage", nil) ) diff --git a/core/state/statedb.go b/core/state/statedb.go index 3f4bec2392dc..4385c197692b 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -970,13 +970,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { // Commit objects to the trie, measuring the elapsed time var ( - accountTrieNodesUpdated int - accountTrieNodesDeleted int - storageTrieNodesUpdated int - storageTrieNodesDeleted int - nodes = trie.NewMergedNodeSet() + accountTrieNodes int + storageTrieNodes int + nodes = trie.NewMergedNodeSet() + codeWriter = s.db.DiskDB().NewBatch() ) - codeWriter := s.db.DiskDB().NewBatch() for addr := range s.stateObjectsDirty { if obj := s.stateObjects[addr]; !obj.deleted { // Write any contract code associated with the state object @@ -994,17 +992,9 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if err := nodes.Merge(set); err != nil { return common.Hash{}, err } - updates, deleted := set.Size() - storageTrieNodesUpdated += updates - storageTrieNodesDeleted += deleted + storageTrieNodes += set.Size() } } - // If the contract is destructed, the storage is still left in the - // database as dangling data. Theoretically it's should be wiped from - // database as well, but in hash-based-scheme it's extremely hard to - // determine that if the trie nodes are also referenced by other storage, - // and in path-based-scheme some technical challenges are still unsolved. - // Although it won't affect the correctness but please fix it TODO(rjl493456442). } if len(s.stateObjectsDirty) > 0 { s.stateObjectsDirty = make(map[common.Address]struct{}) @@ -1025,7 +1015,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if err := nodes.Merge(set); err != nil { return common.Hash{}, err } - accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size() + accountTrieNodes = set.Size() } if metrics.EnabledExpensive { s.AccountCommits += time.Since(start) @@ -1034,10 +1024,9 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { storageUpdatedMeter.Mark(int64(s.StorageUpdated)) accountDeletedMeter.Mark(int64(s.AccountDeleted)) storageDeletedMeter.Mark(int64(s.StorageDeleted)) - accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated)) - accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted)) - storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated)) - storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted)) + accountTrieNodesMeter.Mark(int64(accountTrieNodes)) + storageTriesNodesMeter.Mark(int64(storageTrieNodes)) + s.AccountUpdated, s.AccountDeleted = 0, 0 s.StorageUpdated, s.StorageDeleted = 0, 0 } diff --git a/trie/committer.go b/trie/committer.go index c4957f3490ea..745cb7683998 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -33,29 +33,22 @@ type leaf struct { // insertion order. type committer struct { nodes *NodeSet - tracer *tracer collectLeaf bool } // newCommitter creates a new committer or picks one from the pool. -func newCommitter(owner common.Hash, tracer *tracer, collectLeaf bool) *committer { +func newCommitter(nodes *NodeSet, collectLeaf bool) *committer { return &committer{ - nodes: NewNodeSet(owner), - tracer: tracer, + nodes: nodes, collectLeaf: collectLeaf, } } // Commit collapses a node down into a hash node and returns it along with // the modified nodeset. -func (c *committer) Commit(n node) (hashNode, *NodeSet) { +func (c *committer) Commit(n node) hashNode { h := c.commit(nil, n) - // Some nodes can be deleted from trie which can't be captured - // by committer itself. Iterate all deleted nodes tracked by - // tracer and marked them as deleted only if they are present - // in database previously. - c.tracer.markDeletions(c.nodes) - return h.(hashNode), c.nodes + return h.(hashNode) } // commit collapses a node down into a hash node and returns it. @@ -85,12 +78,6 @@ func (c *committer) commit(path []byte, n node) node { if hn, ok := hashedNode.(hashNode); ok { return hn } - // The short node now is embedded in its parent. Mark the node as - // deleted if it's present in database previously. It's equivalent - // as deletion from database's perspective. - if prev := c.tracer.getPrev(path); len(prev) != 0 { - c.nodes.markDeleted(path, prev) - } return collapsed case *fullNode: hashedKids := c.commitChildren(path, cn) @@ -101,12 +88,6 @@ func (c *committer) commit(path []byte, n node) node { if hn, ok := hashedNode.(hashNode); ok { return hn } - // The full node now is embedded in its parent. Mark the node as - // deleted if it's present in database previously. It's equivalent - // as deletion from database's perspective. - if prev := c.tracer.getPrev(path); len(prev) != 0 { - c.nodes.markDeleted(path, prev) - } return collapsed case hashNode: return cn @@ -169,7 +150,7 @@ func (c *committer) store(path []byte, n node) node { } ) // Collect the dirty node to nodeset for return. - c.nodes.markUpdated(path, mnode, c.tracer.getPrev(path)) + c.nodes.markUpdated(path, mnode) // 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/database.go b/trie/database.go index 74247d59c4f8..5d47475e0f04 100644 --- a/trie/database.go +++ b/trie/database.go @@ -792,13 +792,12 @@ func (db *Database) Update(nodes *MergedNodeSet) error { } for _, owner := range order { subset := nodes.sets[owner] - for _, path := range subset.updates.order { - n, ok := subset.updates.nodes[path] - if !ok { - return fmt.Errorf("missing node %x %v", owner, path) + subset.forEachWithOrder(false, func(path string, n *memoryNode) { + if n.isDeleted() { + return // ignore deletion } db.insert(n.hash, int(n.size), n.node) - } + }) } // Link up the account trie and storage trie if the node points // to an account trie leaf. diff --git a/trie/nodeset.go b/trie/nodeset.go index 928172350171..4251eccaf680 100644 --- a/trie/nodeset.go +++ b/trie/nodeset.go @@ -19,6 +19,7 @@ package trie import ( "fmt" "reflect" + "sort" "strings" "github.com/ethereum/go-ethereum/common" @@ -40,8 +41,8 @@ var memoryNodeSize = int(reflect.TypeOf(memoryNode{}).Size()) // memorySize returns the total memory size used by this node. // nolint:unused -func (n *memoryNode) memorySize(key int) int { - return int(n.size) + memoryNodeSize + key +func (n *memoryNode) memorySize(pathlen int) int { + return int(n.size) + memoryNodeSize + pathlen } // rlp returns the raw rlp encoded blob of the cached trie node, either directly @@ -64,14 +65,20 @@ func (n *memoryNode) obj() node { return expandNode(n.hash[:], n.node) } +// isDeleted returns the indicator if the node is marked as deleted. +func (n *memoryNode) isDeleted() bool { + return n.hash == (common.Hash{}) +} + // nodeWithPrev wraps the memoryNode with the previous node value. +// nolint: unused type nodeWithPrev struct { *memoryNode prev []byte // RLP-encoded previous value, nil means it's non-existent } // unwrap returns the internal memoryNode object. -// nolint:unused +// nolint: unused func (n *nodeWithPrev) unwrap() *memoryNode { return n.memoryNode } @@ -79,64 +86,69 @@ func (n *nodeWithPrev) unwrap() *memoryNode { // memorySize returns the total memory size used by this node. It overloads // the function in memoryNode by counting the size of previous value as well. // nolint: unused -func (n *nodeWithPrev) memorySize(key int) int { - return n.memoryNode.memorySize(key) + len(n.prev) -} - -// nodesWithOrder represents a collection of dirty nodes which includes -// newly-inserted and updated nodes. The modification order of all nodes -// is represented by order list. -type nodesWithOrder struct { - order []string // the path list of dirty nodes, sort by insertion order - nodes map[string]*nodeWithPrev // the map of dirty nodes, keyed by node path +func (n *nodeWithPrev) memorySize(pathlen int) int { + return n.memoryNode.memorySize(pathlen) + len(n.prev) } // NodeSet contains all dirty nodes collected during the commit operation. // Each node is keyed by path. It's not thread-safe to use. type NodeSet struct { - owner common.Hash // the identifier of the trie - updates *nodesWithOrder // the set of updated nodes(newly inserted, updated) - deletes map[string][]byte // the map of deleted nodes, keyed by node - leaves []*leaf // the list of dirty leaves + owner common.Hash // the identifier of the trie + nodes map[string]*memoryNode // the set of dirty nodes(inserted, updated, deleted) + leaves []*leaf // the list of dirty leaves + accessList map[string][]byte // The list of accessed nodes, which records the original node value } // NewNodeSet initializes an empty node set to be used for tracking dirty nodes -// from a specific account or storage trie. The owner is zero for the account -// trie and the owning account address hash for storage tries. -func NewNodeSet(owner common.Hash) *NodeSet { +// for a specific account or storage trie. The owner is zero for the account trie +// and the owning account address hash for storage tries. The provided accessList +// represents the original value of accessed nodes, it can be optional but would +// be beneficial for speeding up the construction of trie history. +func NewNodeSet(owner common.Hash, accessList map[string][]byte) *NodeSet { + // Don't panic for lazy users + if accessList == nil { + accessList = make(map[string][]byte) + } return &NodeSet{ - owner: owner, - updates: &nodesWithOrder{ - nodes: make(map[string]*nodeWithPrev), - }, - deletes: make(map[string][]byte), + owner: owner, + nodes: make(map[string]*memoryNode), + accessList: accessList, } } -/* -// NewNodeSetWithDeletion initializes the nodeset with provided deletion set. -func NewNodeSetWithDeletion(owner common.Hash, paths [][]byte, prev [][]byte) *NodeSet { - set := NewNodeSet(owner) - for i, path := range paths { - set.markDeleted(path, prev[i]) +// forEachWithOrder iterates the dirty nodes with the specified order. +// If topToBottom is true: +// +// then the order of iteration is top to bottom, left to right. +// +// If topToBottom is false: +// +// then the order of iteration is bottom to top, right to left. +func (set *NodeSet) forEachWithOrder(topToBottom bool, callback func(path string, n *memoryNode)) { + var paths sort.StringSlice + for path := range set.nodes { + paths = append(paths, path) + } + if topToBottom { + paths.Sort() + } else { + sort.Sort(sort.Reverse(paths)) + } + for _, path := range paths { + callback(path, set.nodes[path]) } - return set } -*/ // markUpdated marks the node as dirty(newly-inserted or updated) with provided // node path, node object along with its previous value. -func (set *NodeSet) markUpdated(path []byte, node *memoryNode, prev []byte) { - set.updates.order = append(set.updates.order, string(path)) - set.updates.nodes[string(path)] = &nodeWithPrev{ - memoryNode: node, - prev: prev, - } +func (set *NodeSet) markUpdated(path []byte, node *memoryNode) { + set.nodes[string(path)] = node } // markDeleted marks the node as deleted with provided path and previous value. -func (set *NodeSet) markDeleted(path []byte, prev []byte) { - set.deletes[string(path)] = prev +// nolint: unused +func (set *NodeSet) markDeleted(path []byte) { + set.nodes[string(path)] = &memoryNode{} } // addLeaf collects the provided leaf node into set. @@ -144,16 +156,16 @@ func (set *NodeSet) addLeaf(node *leaf) { set.leaves = append(set.leaves, node) } -// Size returns the number of updated and deleted nodes contained in the set. -func (set *NodeSet) Size() (int, int) { - return len(set.updates.order), len(set.deletes) +// Size returns the number of dirty nodes contained in the set. +func (set *NodeSet) Size() int { + return len(set.nodes) } // Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can // we get rid of it? func (set *NodeSet) Hashes() []common.Hash { var ret []common.Hash - for _, node := range set.updates.nodes { + for _, node := range set.nodes { ret = append(ret, node.hash) } return ret @@ -163,19 +175,17 @@ func (set *NodeSet) Hashes() []common.Hash { func (set *NodeSet) Summary() string { var out = new(strings.Builder) fmt.Fprintf(out, "nodeset owner: %v\n", set.owner) - if set.updates != nil { - for _, key := range set.updates.order { - updated := set.updates.nodes[key] - if updated.prev != nil { - fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", key, updated.hash, updated.prev) - } else { - fmt.Fprintf(out, " [+]: %x -> %v\n", key, updated.hash) + if set.nodes != nil { + for path, n := range set.nodes { + // Deletion + if n.isDeleted() { + fmt.Fprintf(out, " [-]: %x\n", path) + continue } + // Update + fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.hash) } } - for k, n := range set.deletes { - fmt.Fprintf(out, " [-]: %x -> %x\n", k, n) - } for _, n := range set.leaves { fmt.Fprintf(out, "[leaf]: %v\n", n) } diff --git a/trie/trie.go b/trie/trie.go index c467ac476622..65f89d91f8b4 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -51,12 +51,11 @@ type Trie struct { // actually unhashed nodes. unhashed int + // accessList tracks the loaded nodes from database. + accessList map[string][]byte + // reader is the handler trie can retrieve nodes from. reader *trieReader - - // tracer is the tool to track the trie changes. - // It will be reset after each commit operation. - tracer *tracer } // newFlag returns the cache flag value for a newly created node. @@ -66,12 +65,16 @@ func (t *Trie) newFlag() nodeFlag { // Copy returns a copy of Trie. func (t *Trie) Copy() *Trie { + accessList := make(map[string][]byte) + for path, blob := range t.accessList { + accessList[path] = common.CopyBytes(blob) + } return &Trie{ - root: t.root, - owner: t.owner, - unhashed: t.unhashed, - reader: t.reader, - tracer: t.tracer.copy(), + root: t.root, + owner: t.owner, + unhashed: t.unhashed, + reader: t.reader, + accessList: accessList, } } @@ -87,9 +90,9 @@ func New(id *ID, db NodeReader) (*Trie, error) { return nil, err } trie := &Trie{ - owner: id.Owner, - reader: reader, - //tracer: newTracer(), + owner: id.Owner, + reader: reader, + accessList: make(map[string][]byte), } if id.Root != (common.Hash{}) && id.Root != emptyRoot { rootnode, err := trie.resolveAndTrack(id.Root[:], nil) @@ -326,11 +329,6 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error if matchlen == 0 { return true, branch, nil } - // 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]...)) - // Replace it with a short node leading up to the branch. return true, &shortNode{key[:matchlen], branch, t.newFlag()}, nil @@ -345,11 +343,6 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error return true, n, nil case nil: - // 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) - return true, &shortNode{key, value, t.newFlag()}, nil case hashNode: @@ -402,11 +395,6 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { return false, n, nil // don't replace n on mismatch } if matchlen == len(key) { - // 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) - return true, nil, nil // remove n entirely for whole matches } // The key is longer than n.Key. Remove the remaining suffix @@ -419,10 +407,6 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { } switch child := child.(type) { case *shortNode: - // The child shortNode is merged into its parent, track - // is deleted as well. - t.tracer.onDelete(append(prefix, n.Key...)) - // Deleting from the subtrie reduced it to another // short node. Merge the nodes to avoid creating a // shortNode{..., shortNode{...}}. Use concat (which @@ -484,11 +468,6 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { return false, nil, err } if cnode, ok := cnode.(*shortNode); ok { - // 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))) - k := append([]byte{byte(pos)}, cnode.Key...) return true, &shortNode{k, cnode.Val, t.newFlag()}, nil } @@ -548,7 +527,7 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { if err != nil { return nil, err } - t.tracer.onRead(prefix, blob) + t.accessList[string(prefix)] = blob return mustDecodeNode(n, blob), nil } @@ -567,16 +546,15 @@ func (t *Trie) Hash() common.Hash { // 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 *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { - defer t.tracer.reset() - + // Reset accessList at the end of commit + defer func() { + t.accessList = make(map[string][]byte) + }() // Trie is empty and can be classified into two types of situations: // - The trie was empty and no update happens // - The trie was non-empty and all nodes are dropped if t.root == nil { - // Wrap tracked deletions as the return - set := NewNodeSet(t.owner) - t.tracer.markDeletions(set) - return emptyRoot, set + return emptyRoot, nil } // Derive the hash for all dirty nodes first. We hold the assumption // in the following procedure that all nodes are hashed. @@ -590,8 +568,9 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { t.root = hashedNode return rootHash, nil } - h := newCommitter(t.owner, t.tracer, collectLeaf) - newRoot, nodes := h.Commit(t.root) + nodes := NewNodeSet(t.owner, t.accessList) + h := newCommitter(nodes, collectLeaf) + newRoot := h.Commit(t.root) t.root = newRoot return rootHash, nodes } @@ -614,5 +593,5 @@ func (t *Trie) Reset() { t.root = nil t.owner = common.Hash{} t.unhashed = 0 - t.tracer.reset() + t.accessList = make(map[string][]byte) } diff --git a/trie/trie_test.go b/trie/trie_test.go index 2fb97eebbf49..b87b7d3cd6c9 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -410,7 +410,6 @@ func runRandTest(rt randTest) bool { values = make(map[string]string) // tracks content of the trie origTrie = NewEmpty(triedb) ) - tr.tracer = newTracer() for i, step := range rt { // fmt.Printf("{op: %d, key: common.Hex2Bytes(\"%x\"), value: common.Hex2Bytes(\"%x\")}, // step %d\n", @@ -449,21 +448,14 @@ func runRandTest(rt randTest) bool { root, nodes := tr.Commit(true) // Validity the returned nodeset if nodes != nil { - for path, node := range nodes.updates.nodes { + for path := range nodes.nodes { blob, _, _ := origTrie.TryGetNode(hexToCompact([]byte(path))) - got := node.prev + got := nodes.accessList[path] if !bytes.Equal(blob, got) { rt[i].err = fmt.Errorf("prevalue mismatch for 0x%x, got 0x%x want 0x%x", path, got, blob) panic(rt[i].err) } } - for path, prev := range nodes.deletes { - blob, _, _ := origTrie.TryGetNode(hexToCompact([]byte(path))) - if !bytes.Equal(blob, prev) { - rt[i].err = fmt.Errorf("prevalue mismatch for 0x%x, got 0x%x want 0x%x", path, prev, blob) - return false - } - } } if nodes != nil { triedb.Update(NewWithNodeSet(nodes)) @@ -477,7 +469,6 @@ func runRandTest(rt randTest) bool { // Enable node tracing. Resolve the root node again explicitly // since it's not captured at the beginning. - tr.tracer = newTracer() tr.resolveAndTrack(root.Bytes(), nil) origTrie = tr.Copy() @@ -490,59 +481,6 @@ func runRandTest(rt randTest) bool { if tr.Hash() != checktr.Hash() { rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") } - case opNodeDiff: - var ( - inserted = tr.tracer.insertList() - deleted = tr.tracer.deleteList() - origIter = origTrie.NodeIterator(nil) - curIter = tr.NodeIterator(nil) - origSeen = make(map[string]struct{}) - curSeen = make(map[string]struct{}) - ) - for origIter.Next(true) { - if origIter.Leaf() { - continue - } - origSeen[string(origIter.Path())] = struct{}{} - } - for curIter.Next(true) { - if curIter.Leaf() { - continue - } - curSeen[string(curIter.Path())] = struct{}{} - } - var ( - insertExp = make(map[string]struct{}) - deleteExp = make(map[string]struct{}) - ) - for path := range curSeen { - _, present := origSeen[path] - if !present { - insertExp[path] = struct{}{} - } - } - for path := range origSeen { - _, present := curSeen[path] - if !present { - deleteExp[path] = struct{}{} - } - } - if len(insertExp) != len(inserted) { - rt[i].err = fmt.Errorf("insert set mismatch") - } - if len(deleteExp) != len(deleted) { - rt[i].err = fmt.Errorf("delete set mismatch") - } - for _, insert := range inserted { - if _, present := insertExp[string(insert)]; !present { - rt[i].err = fmt.Errorf("missing inserted node") - } - } - for _, del := range deleted { - if _, present := deleteExp[string(del)]; !present { - rt[i].err = fmt.Errorf("missing deleted node") - } - } } // Abort the test on error. if rt[i].err != nil { diff --git a/trie/util_test.go b/trie/util_test.go deleted file mode 100644 index 01a46553aa68..000000000000 --- a/trie/util_test.go +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package trie - -import ( - "bytes" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" -) - -// Tests if the trie diffs are tracked correctly. -func TestTrieTracer(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - trie := NewEmpty(db) - trie.tracer = newTracer() - - // Insert a batch of entries, all the nodes should be marked as inserted - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) - } - trie.Hash() - - seen := make(map[string]struct{}) - it := trie.NodeIterator(nil) - for it.Next(true) { - if it.Leaf() { - continue - } - seen[string(it.Path())] = struct{}{} - } - inserted := trie.tracer.insertList() - if len(inserted) != len(seen) { - t.Fatalf("Unexpected inserted node tracked want %d got %d", len(seen), len(inserted)) - } - for _, k := range inserted { - _, ok := seen[string(k)] - if !ok { - t.Fatalf("Unexpected inserted node") - } - } - deleted := trie.tracer.deleteList() - if len(deleted) != 0 { - t.Fatalf("Unexpected deleted node tracked %d", len(deleted)) - } - - // Commit the changes and re-create with new root - root, nodes := trie.Commit(false) - if err := db.Update(NewWithNodeSet(nodes)); err != nil { - t.Fatal(err) - } - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - - // Delete all the elements, check deletion set - for _, val := range vals { - trie.Delete([]byte(val.k)) - } - trie.Hash() - - inserted = trie.tracer.insertList() - if len(inserted) != 0 { - t.Fatalf("Unexpected inserted node tracked %d", len(inserted)) - } - deleted = trie.tracer.deleteList() - if len(deleted) != len(seen) { - t.Fatalf("Unexpected deleted node tracked want %d got %d", len(seen), len(deleted)) - } - for _, k := range deleted { - _, ok := seen[string(k)] - if !ok { - t.Fatalf("Unexpected inserted node") - } - } -} - -func TestTrieTracerNoop(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) - trie.tracer = newTracer() - - // Insert a batch of entries, all the nodes should be marked as inserted - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) - } - for _, val := range vals { - trie.Delete([]byte(val.k)) - } - if len(trie.tracer.insertList()) != 0 { - t.Fatalf("Unexpected inserted node tracked %d", len(trie.tracer.insertList())) - } - if len(trie.tracer.deleteList()) != 0 { - t.Fatalf("Unexpected deleted node tracked %d", len(trie.tracer.deleteList())) - } -} - -func TestTrieTracePrevValue(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - trie := NewEmpty(db) - trie.tracer = newTracer() - - paths, blobs := trie.tracer.prevList() - if len(paths) != 0 || len(blobs) != 0 { - t.Fatalf("Nothing should be tracked") - } - // Insert a batch of entries, all the nodes should be marked as inserted - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) - } - paths, blobs = trie.tracer.prevList() - if len(paths) != 0 || len(blobs) != 0 { - t.Fatalf("Nothing should be tracked") - } - - // Commit the changes and re-create with new root - root, nodes := trie.Commit(false) - if err := db.Update(NewWithNodeSet(nodes)); err != nil { - t.Fatal(err) - } - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - trie.resolveAndTrack(root.Bytes(), nil) - - // Load all nodes in trie - for _, val := range vals { - trie.TryGet([]byte(val.k)) - } - - // Ensure all nodes are tracked by tracer with correct prev-values - iter := trie.NodeIterator(nil) - seen := make(map[string][]byte) - for iter.Next(true) { - // Embedded nodes are ignored since they are not present in - // database. - if iter.Hash() == (common.Hash{}) { - continue - } - seen[string(iter.Path())] = common.CopyBytes(iter.NodeBlob()) - } - - paths, blobs = trie.tracer.prevList() - if len(paths) != len(seen) || len(blobs) != len(seen) { - t.Fatalf("Unexpected tracked values") - } - for i, path := range paths { - blob := blobs[i] - prev, ok := seen[string(path)] - if !ok { - t.Fatalf("Missing node %v", path) - } - if !bytes.Equal(blob, prev) { - t.Fatalf("Unexpected value path: %v, want: %v, got: %v", path, prev, blob) - } - } - - // Re-open the trie and iterate the trie, ensure nothing will be tracked. - // Iterator will not link any loaded nodes to trie. - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - - iter = trie.NodeIterator(nil) - for iter.Next(true) { - } - paths, blobs = trie.tracer.prevList() - if len(paths) != 0 || len(blobs) != 0 { - t.Fatalf("Nothing should be tracked") - } - - // Re-open the trie and generate proof for entries, ensure nothing will - // be tracked. Prover will not link any loaded nodes to trie. - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - for _, val := range vals { - trie.Prove([]byte(val.k), 0, rawdb.NewMemoryDatabase()) - } - paths, blobs = trie.tracer.prevList() - if len(paths) != 0 || len(blobs) != 0 { - t.Fatalf("Nothing should be tracked") - } - - // Delete entries from trie, ensure all previous values are correct. - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - trie.resolveAndTrack(root.Bytes(), nil) - - for _, val := range vals { - trie.TryDelete([]byte(val.k)) - } - paths, blobs = trie.tracer.prevList() - if len(paths) != len(seen) || len(blobs) != len(seen) { - t.Fatalf("Unexpected tracked values") - } - for i, path := range paths { - blob := blobs[i] - prev, ok := seen[string(path)] - if !ok { - t.Fatalf("Missing node %v", path) - } - if !bytes.Equal(blob, prev) { - t.Fatalf("Unexpected value path: %v, want: %v, got: %v", path, prev, blob) - } - } -} - -func TestDeleteAll(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - trie := NewEmpty(db) - trie.tracer = newTracer() - - // Insert a batch of entries, all the nodes should be marked as inserted - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) - } - root, set := trie.Commit(false) - if err := db.Update(NewWithNodeSet(set)); err != nil { - t.Fatal(err) - } - // Delete entries from trie, ensure all values are detected - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - trie.resolveAndTrack(root.Bytes(), nil) - - // Iterate all existent nodes - var ( - it = trie.NodeIterator(nil) - nodes = make(map[string][]byte) - ) - for it.Next(true) { - if it.Hash() != (common.Hash{}) { - nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) - } - } - - // Perform deletion to purge the entire trie - for _, val := range vals { - trie.Delete([]byte(val.k)) - } - root, set = trie.Commit(false) - if root != emptyRoot { - t.Fatalf("Invalid trie root %v", root) - } - for path, blob := range set.deletes { - prev, ok := nodes[path] - if !ok { - t.Fatalf("Extra node deleted %v", []byte(path)) - } - if !bytes.Equal(prev, blob) { - t.Fatalf("Unexpected previous value %v", []byte(path)) - } - } - if len(set.deletes) != len(nodes) { - t.Fatalf("Unexpected deletion set") - } -} diff --git a/trie/utils.go b/trie/utils.go deleted file mode 100644 index 5dce65cd2971..000000000000 --- a/trie/utils.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package trie - -// tracer 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 -// used to track all insert and delete operations of trie and capture all -// deleted nodes eventually. -// -// The changed nodes can be mainly divided into two categories: the leaf -// node and intermediate node. The former is inserted/deleted by callers -// while the latter is inserted/deleted in order to follow the rule of trie. -// 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 reverse-diffs in the future. -// -// Note tracer is not thread-safe, callers should be responsible for handling -// the concurrency issues by themselves. -type tracer struct { - insert map[string]struct{} - delete map[string]struct{} - origin map[string][]byte -} - -// newTracer initializes the tracer for capturing trie changes. -func newTracer() *tracer { - return &tracer{ - insert: make(map[string]struct{}), - delete: make(map[string]struct{}), - origin: make(map[string][]byte), - } -} - -// 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) { - // Tracer isn't used right now, remove this check later. - if t == nil { - return - } - t.origin[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 the "untouched". -func (t *tracer) onInsert(path []byte) { - // Tracer isn't used right now, remove this check later. - if t == nil { - return - } - if _, present := t.delete[string(path)]; present { - delete(t.delete, string(path)) - return - } - t.insert[string(path)] = struct{}{} -} - -// 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) { - // Tracer isn't used right now, remove this check later. - if t == nil { - return - } - if _, present := t.insert[string(path)]; present { - delete(t.insert, string(path)) - return - } - t.delete[string(path)] = struct{}{} -} - -// insertList returns the tracked inserted trie nodes in list format. -func (t *tracer) insertList() [][]byte { - // Tracer isn't used right now, remove this check later. - if t == nil { - return nil - } - var ret [][]byte - for path := range t.insert { - ret = append(ret, []byte(path)) - } - return ret -} - -// deleteList returns the tracked deleted trie nodes in list format. -func (t *tracer) deleteList() [][]byte { - // Tracer isn't used right now, remove this check later. - if t == nil { - return nil - } - var ret [][]byte - for path := range t.delete { - ret = append(ret, []byte(path)) - } - return ret -} - -// prevList returns the tracked node blobs in list format. -func (t *tracer) prevList() ([][]byte, [][]byte) { - // Tracer isn't used right now, remove this check later. - if t == nil { - return nil, nil - } - var ( - paths [][]byte - blobs [][]byte - ) - for path, blob := range t.origin { - paths = append(paths, []byte(path)) - blobs = append(blobs, blob) - } - return paths, blobs -} - -// getPrev returns the cached original value of the specified node. -func (t *tracer) getPrev(path []byte) []byte { - // Tracer isn't used right now, remove this check later. - if t == nil { - return nil - } - return t.origin[string(path)] -} - -// reset clears the content tracked by tracer. -func (t *tracer) reset() { - // Tracer isn't used right now, remove this check later. - if t == nil { - return - } - t.insert = make(map[string]struct{}) - t.delete = make(map[string]struct{}) - t.origin = make(map[string][]byte) -} - -// copy returns a deep copied tracer instance. -func (t *tracer) copy() *tracer { - // Tracer isn't used right now, remove this check later. - if t == nil { - return nil - } - var ( - insert = make(map[string]struct{}) - delete = make(map[string]struct{}) - origin = make(map[string][]byte) - ) - for key := range t.insert { - insert[key] = struct{}{} - } - for key := range t.delete { - delete[key] = struct{}{} - } - for key, val := range t.origin { - origin[key] = val - } - return &tracer{ - insert: insert, - delete: delete, - origin: origin, - } -} - -// markDeletions puts all tracked deletions into the provided nodeset. -func (t *tracer) markDeletions(set *NodeSet) { - // Tracer isn't used right now, remove this check later. - if t == nil { - return - } - for _, path := range t.deleteList() { - // There are a few possibilities for this scenario(the node is deleted - // but not present in database previously), for example the node was - // embedded in the parent and now deleted from the trie. In this case - // it's noop from database's perspective. - val := t.getPrev(path) - if len(val) == 0 { - continue - } - set.markDeleted(path, val) - } -} From 1db978ca6b28b28d5eda9cf04b519ee301b05345 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Sun, 19 Feb 2023 20:23:18 +0100 Subject: [PATCH 564/715] rpc: fix unmarshaling of null result in CallContext (#26723) The change fixes unmarshaling of JSON null results into json.RawMessage. --------- Co-authored-by: Jason Yuan Co-authored-by: Jason Yuan --- rpc/client.go | 5 ++++- rpc/client_test.go | 20 ++++++++++++++++++++ rpc/server_test.go | 2 +- rpc/testservice_test.go | 4 ++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/rpc/client.go b/rpc/client.go index a509cb2e0fa0..69ff4851e317 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -345,7 +345,10 @@ func (c *Client) CallContext(ctx context.Context, result interface{}, method str case len(resp.Result) == 0: return ErrNoResult default: - return json.Unmarshal(resp.Result, &result) + if result == nil { + return nil + } + return json.Unmarshal(resp.Result, result) } } diff --git a/rpc/client_test.go b/rpc/client_test.go index 0a88ce40b2a8..a94a54929b31 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -69,6 +69,26 @@ func TestClientResponseType(t *testing.T) { } } +// This test checks calling a method that returns 'null'. +func TestClientNullResponse(t *testing.T) { + server := newTestServer() + defer server.Stop() + + client := DialInProc(server) + defer client.Close() + + var result json.RawMessage + if err := client.Call(&result, "test_null"); err != nil { + t.Fatal(err) + } + if result == nil { + t.Fatal("Expected non-nil result") + } + if !reflect.DeepEqual(result, json.RawMessage("null")) { + t.Errorf("Expected null, got %s", result) + } +} + // This test checks that server-returned errors with code and data come out of Client.Call. func TestClientErrorData(t *testing.T) { server := newTestServer() diff --git a/rpc/server_test.go b/rpc/server_test.go index c9abe53e5210..f1a9b3d5cd4a 100644 --- a/rpc/server_test.go +++ b/rpc/server_test.go @@ -45,7 +45,7 @@ func TestServerRegisterName(t *testing.T) { t.Fatalf("Expected service calc to be registered") } - wantCallbacks := 12 + wantCallbacks := 13 if len(svc.callbacks) != wantCallbacks { t.Errorf("Expected %d callbacks for service 'service', got %d", wantCallbacks, len(svc.callbacks)) } diff --git a/rpc/testservice_test.go b/rpc/testservice_test.go index 8454a4019222..eab67f1dd5d8 100644 --- a/rpc/testservice_test.go +++ b/rpc/testservice_test.go @@ -78,6 +78,10 @@ func (o *MarshalErrObj) MarshalText() ([]byte, error) { func (s *testService) NoArgsRets() {} +func (s *testService) Null() any { + return nil +} + func (s *testService) Echo(str string, i int, args *echoArgs) echoResult { return echoResult{str, i, args} } From 2166c86041800c91b64c2b72c5b33512e529ec77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 20 Feb 2023 08:53:15 +0200 Subject: [PATCH 565/715] build: ship bootstrapper Go along with builder for PPA (#26731) --- build/checksums.txt | 3 +++ build/ci.go | 45 +++++++++++++++++++++++++++++------- build/deb/ethereum/deb.rules | 5 ++++ 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index d00d9bf965da..0cbf700c9296 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -41,3 +41,6 @@ c4f58b7e227b9fd41f0e9310dc83f4a4e7d026598e2f6e95b78761081a6d9bd2 golangci-lint- eb57f9bcb56646f2e3d6ccaf02ec227815fb05077b2e0b1bf9e755805acdc2b9 golangci-lint-1.51.1-windows-arm64.zip bce02f7232723cb727755ee11f168a700a00896a25d37f87c4b173bce55596b4 golangci-lint-1.51.1-windows-armv6.zip cf6403f84707ce8c98664736772271bc8874f2e760c2fd0f00cf3e85963507e9 golangci-lint-1.51.1-windows-armv7.zip + +# This is the builder on PPA that will build Go itself (inception-y), don't modify! +9419cc70dc5a2523f29a77053cafff658ed21ef3561d9b6b020280ebceab28b9 go1.19.src.tar.gz diff --git a/build/ci.go b/build/ci.go index 173dc7cc0308..0a6eb2b499a0 100644 --- a/build/ci.go +++ b/build/ci.go @@ -136,10 +136,18 @@ var ( "golang-go": "/usr/lib/go", } - // This is the version of go that will be downloaded by + // This is the version of Go that will be downloaded by // // go run ci.go install -dlgo dlgoVersion = "1.20.1" + + // This is the version of Go that will be used to bootstrap the PPA builder. + // + // This version is fine to be old and full of security holes, we just use it + // to build the latest Go. Don't change it. If it ever becomes infufficient, + // we need to switch over to a recursive builder to jumpt across supported + // versions. + gobootVersion = "1.19" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) @@ -655,10 +663,11 @@ func doDebianSource(cmdline []string) { gpg.Stdin = bytes.NewReader(key) build.MustRun(gpg) } - - // Download and verify the Go source package. - gobundle := downloadGoSources(*cachedir) - + // Download and verify the Go source packages. + var ( + gobootbundle = downloadGoBootstrapSources(*cachedir) + gobundle = downloadGoSources(*cachedir) + ) // Download all the dependencies needed to build the sources and run the ci script srcdepfetch := tc.Go("mod", "download") srcdepfetch.Env = append(srcdepfetch.Env, "GOPATH="+filepath.Join(*workdir, "modgopath")) @@ -675,12 +684,19 @@ func doDebianSource(cmdline []string) { meta := newDebMetadata(distro, goboot, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables) pkgdir := stageDebianSource(*workdir, meta) - // Add Go source code + // Add bootstrapper Go source code + if err := build.ExtractArchive(gobootbundle, pkgdir); err != nil { + log.Fatalf("Failed to extract bootstrapper Go sources: %v", err) + } + if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, ".goboot")); err != nil { + log.Fatalf("Failed to rename bootstrapper Go source folder: %v", err) + } + // Add builder Go source code if err := build.ExtractArchive(gobundle, pkgdir); err != nil { - log.Fatalf("Failed to extract Go sources: %v", err) + log.Fatalf("Failed to extract builder Go sources: %v", err) } if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, ".go")); err != nil { - log.Fatalf("Failed to rename Go source folder: %v", err) + log.Fatalf("Failed to rename builder Go source folder: %v", err) } // Add all dependency modules in compressed form os.MkdirAll(filepath.Join(pkgdir, ".mod", "cache"), 0755) @@ -709,6 +725,19 @@ func doDebianSource(cmdline []string) { } } +// downloadGoBootstrapSources downloads the Go source tarball that will be used +// to bootstrap the builder Go. +func downloadGoBootstrapSources(cachedir string) string { + csdb := build.MustLoadChecksums("build/checksums.txt") + file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion) + url := "https://dl.google.com/go/" + file + dst := filepath.Join(cachedir, file) + if err := csdb.DownloadFile(url, dst); err != nil { + log.Fatal(err) + } + return dst +} + // downloadGoSources downloads the Go source tarball. func downloadGoSources(cachedir string) string { csdb := build.MustLoadChecksums("build/checksums.txt") diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules index 0677ef91e404..882b45d148b1 100644 --- a/build/deb/ethereum/deb.rules +++ b/build/deb/ethereum/deb.rules @@ -16,6 +16,11 @@ override_dh_auto_build: # We can't download a fresh Go within Launchpad, so we're shipping and building # one on the fly. However, we can't build it inside the go-ethereum folder as # bootstrapping clashes with go modules, so build in a sibling folder. + # + # We're also shipping the bootstrapper as of Go 1.20 as it had minimum version + # requirements opposed to older versions of Go. + (mv .goboot ../ && cd ../.goboot/src && ./make.bash) + (cd ../.goboot/bin && export GOROOT_BOOTSTRAP=`pwd`) (mv .go ../ && cd ../.go/src && ./make.bash) # We can't download external go modules within Launchpad, so we're shipping the From e1e2781105130b8cce6d34b33df7ea90838c1061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 20 Feb 2023 09:56:03 +0200 Subject: [PATCH 566/715] build: fix setting env var, temp early exit --- build/ci.go | 1 + build/deb/ethereum/deb.rules | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build/ci.go b/build/ci.go index 0a6eb2b499a0..9230945e94b8 100644 --- a/build/ci.go +++ b/build/ci.go @@ -721,6 +721,7 @@ func doDebianSource(cmdline []string) { if *upload != "" { ppaUpload(*workdir, *upload, *sshUser, []string{source, dsc, changes, buildinfo}) } + return } } } diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules index 882b45d148b1..885444a7e642 100644 --- a/build/deb/ethereum/deb.rules +++ b/build/deb/ethereum/deb.rules @@ -20,7 +20,7 @@ override_dh_auto_build: # We're also shipping the bootstrapper as of Go 1.20 as it had minimum version # requirements opposed to older versions of Go. (mv .goboot ../ && cd ../.goboot/src && ./make.bash) - (cd ../.goboot/bin && export GOROOT_BOOTSTRAP=`pwd`) + export GOROOT_BOOTSTRAP=`pwd`/../.goboot/bin (mv .go ../ && cd ../.go/src && ./make.bash) # We can't download external go modules within Launchpad, so we're shipping the From 4ec4235fc41b8bfcb5d959f2893cce79ff8cbb16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 20 Feb 2023 10:09:00 +0200 Subject: [PATCH 567/715] build: fix gobootstrap path for the PPA --- build/deb/ethereum/deb.rules | 2 +- internal/build/util.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules index 885444a7e642..6dfe0f8e0793 100644 --- a/build/deb/ethereum/deb.rules +++ b/build/deb/ethereum/deb.rules @@ -20,7 +20,7 @@ override_dh_auto_build: # We're also shipping the bootstrapper as of Go 1.20 as it had minimum version # requirements opposed to older versions of Go. (mv .goboot ../ && cd ../.goboot/src && ./make.bash) - export GOROOT_BOOTSTRAP=`pwd`/../.goboot/bin + export GOROOT_BOOTSTRAP=`pwd`/../.goboot (mv .go ../ && cd ../.go/src && ./make.bash) # We can't download external go modules within Launchpad, so we're shipping the diff --git a/internal/build/util.go b/internal/build/util.go index 9a721e9b83b1..ec25e1dac8ee 100644 --- a/internal/build/util.go +++ b/internal/build/util.go @@ -176,6 +176,7 @@ func UploadSFTP(identityFile, host, dir string, files []string) error { time.Sleep(500 * time.Millisecond) aborted = true sftp.Process.Kill() + return } } }() From a43efceaf2f8a661ad8f4d3f07aa321a82749f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 20 Feb 2023 10:31:35 +0200 Subject: [PATCH 568/715] build: add some PPA debug logs, sigh --- build/deb/ethereum/deb.rules | 1 + internal/build/util.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules index 6dfe0f8e0793..5797da538370 100644 --- a/build/deb/ethereum/deb.rules +++ b/build/deb/ethereum/deb.rules @@ -21,6 +21,7 @@ override_dh_auto_build: # requirements opposed to older versions of Go. (mv .goboot ../ && cd ../.goboot/src && ./make.bash) export GOROOT_BOOTSTRAP=`pwd`/../.goboot + echo $GOROOT_BOOTSTRAP (mv .go ../ && cd ../.go/src && ./make.bash) # We can't download external go modules within Launchpad, so we're shipping the diff --git a/internal/build/util.go b/internal/build/util.go index ec25e1dac8ee..91b5d71a67d9 100644 --- a/internal/build/util.go +++ b/internal/build/util.go @@ -130,7 +130,7 @@ func render(tpl *template.Template, outputFile string, outputPerm os.FileMode, x // The destination host may be specified either as [user@]host[: or as a URI in // the form sftp://[user@]host[:port]. func UploadSFTP(identityFile, host, dir string, files []string) error { - sftp := exec.Command("sftp") + sftp := exec.Command("sftp", "-B", "262144") sftp.Stderr = os.Stderr if identityFile != "" { sftp.Args = append(sftp.Args, "-i", identityFile) From 165268430c773376139931d1bde1e3d07d96f203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 20 Feb 2023 10:43:55 +0200 Subject: [PATCH 569/715] internal/build: revert raising the chunk size for PPA --- internal/build/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/build/util.go b/internal/build/util.go index 91b5d71a67d9..ec25e1dac8ee 100644 --- a/internal/build/util.go +++ b/internal/build/util.go @@ -130,7 +130,7 @@ func render(tpl *template.Template, outputFile string, outputPerm os.FileMode, x // The destination host may be specified either as [user@]host[: or as a URI in // the form sftp://[user@]host[:port]. func UploadSFTP(identityFile, host, dir string, files []string) error { - sftp := exec.Command("sftp", "-B", "262144") + sftp := exec.Command("sftp") sftp.Stderr = os.Stderr if identityFile != "" { sftp.Args = append(sftp.Args, "-i", identityFile) From c02334be1e97b138a4abb478f8c86d67104a9087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 20 Feb 2023 11:07:33 +0200 Subject: [PATCH 570/715] build: yet another weird PPA fix --- build/deb/ethereum/deb.rules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules index 5797da538370..b12011ef7a80 100644 --- a/build/deb/ethereum/deb.rules +++ b/build/deb/ethereum/deb.rules @@ -21,8 +21,8 @@ override_dh_auto_build: # requirements opposed to older versions of Go. (mv .goboot ../ && cd ../.goboot/src && ./make.bash) export GOROOT_BOOTSTRAP=`pwd`/../.goboot - echo $GOROOT_BOOTSTRAP - (mv .go ../ && cd ../.go/src && ./make.bash) + echo $(GOROOT_BOOTSTRAP) + (mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot ./make.bash) # We can't download external go modules within Launchpad, so we're shipping the # entire dependency source cache with go-ethereum. From 45190548160f97408ce3a13c73dc62d0acd76ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 20 Feb 2023 11:31:19 +0200 Subject: [PATCH 571/715] build: fix (finaly?) the PPA env vars for Go bootstrapping --- build/ci.go | 1 - build/deb/ethereum/deb.rules | 2 -- 2 files changed, 3 deletions(-) diff --git a/build/ci.go b/build/ci.go index 9230945e94b8..0a6eb2b499a0 100644 --- a/build/ci.go +++ b/build/ci.go @@ -721,7 +721,6 @@ func doDebianSource(cmdline []string) { if *upload != "" { ppaUpload(*workdir, *upload, *sshUser, []string{source, dsc, changes, buildinfo}) } - return } } } diff --git a/build/deb/ethereum/deb.rules b/build/deb/ethereum/deb.rules index b12011ef7a80..475e628b2f5e 100644 --- a/build/deb/ethereum/deb.rules +++ b/build/deb/ethereum/deb.rules @@ -20,8 +20,6 @@ override_dh_auto_build: # We're also shipping the bootstrapper as of Go 1.20 as it had minimum version # requirements opposed to older versions of Go. (mv .goboot ../ && cd ../.goboot/src && ./make.bash) - export GOROOT_BOOTSTRAP=`pwd`/../.goboot - echo $(GOROOT_BOOTSTRAP) (mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot ./make.bash) # We can't download external go modules within Launchpad, so we're shipping the From 41dee2623eccfe5bc54a4d9281aa7da71a4ed200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 20 Feb 2023 12:36:46 +0200 Subject: [PATCH 572/715] build: fix Go 1.19.0 bootstrapper issues on 386 PPA --- build/checksums.txt | 2 +- build/ci.go | 2 +- internal/build/util.go | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 0cbf700c9296..1fb85d62667b 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -43,4 +43,4 @@ bce02f7232723cb727755ee11f168a700a00896a25d37f87c4b173bce55596b4 golangci-lint- cf6403f84707ce8c98664736772271bc8874f2e760c2fd0f00cf3e85963507e9 golangci-lint-1.51.1-windows-armv7.zip # This is the builder on PPA that will build Go itself (inception-y), don't modify! -9419cc70dc5a2523f29a77053cafff658ed21ef3561d9b6b020280ebceab28b9 go1.19.src.tar.gz +d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz diff --git a/build/ci.go b/build/ci.go index 0a6eb2b499a0..73ec227b33ac 100644 --- a/build/ci.go +++ b/build/ci.go @@ -147,7 +147,7 @@ var ( // to build the latest Go. Don't change it. If it ever becomes infufficient, // we need to switch over to a recursive builder to jumpt across supported // versions. - gobootVersion = "1.19" + gobootVersion = "1.19.6" ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) diff --git a/internal/build/util.go b/internal/build/util.go index ec25e1dac8ee..9a721e9b83b1 100644 --- a/internal/build/util.go +++ b/internal/build/util.go @@ -176,7 +176,6 @@ func UploadSFTP(identityFile, host, dir string, files []string) error { time.Sleep(500 * time.Millisecond) aborted = true sftp.Process.Kill() - return } } }() From ba4267fcacdb45fe4480773011d7647316f6cd97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 20 Feb 2023 13:26:37 +0200 Subject: [PATCH 573/715] build: enable Lunar Lobster PPA builds --- build/ci.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ci.go b/build/ci.go index 73ec227b33ac..2aad2ac52b33 100644 --- a/build/ci.go +++ b/build/ci.go @@ -128,7 +128,7 @@ var ( "focal": "golang-go", // EOL: 04/2030 "jammy": "golang-go", // EOL: 04/2032 "kinetic": "golang-go", // EOL: 07/2023 - //"lunar": "golang-go", // EOL: 01/2024 + "lunar": "golang-go", // EOL: 01/2024 } debGoBootPaths = map[string]string{ @@ -144,7 +144,7 @@ var ( // This is the version of Go that will be used to bootstrap the PPA builder. // // This version is fine to be old and full of security holes, we just use it - // to build the latest Go. Don't change it. If it ever becomes infufficient, + // to build the latest Go. Don't change it. If it ever becomes insufficient, // we need to switch over to a recursive builder to jumpt across supported // versions. gobootVersion = "1.19.6" From 13ef21d4672742e805316df9f319d51e749a129d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 20 Feb 2023 22:54:52 +0800 Subject: [PATCH 574/715] Revert "core/trie: remove trie tracer (#26665)" (#26732) This reverts commit 7c749c947a9d5181f5f2c1b3fdb5ea6b0e401e8e. --- core/state/metrics.go | 14 +- core/state/statedb.go | 29 ++-- trie/committer.go | 29 +++- trie/database.go | 9 +- trie/nodeset.go | 120 ++++++++--------- trie/trie.go | 71 ++++++---- trie/trie_test.go | 66 ++++++++- trie/util_test.go | 304 ++++++++++++++++++++++++++++++++++++++++++ trie/utils.go | 199 +++++++++++++++++++++++++++ 9 files changed, 725 insertions(+), 116 deletions(-) create mode 100644 trie/util_test.go create mode 100644 trie/utils.go diff --git a/core/state/metrics.go b/core/state/metrics.go index 086666b7dbfc..e702ef3a81a6 100644 --- a/core/state/metrics.go +++ b/core/state/metrics.go @@ -19,10 +19,12 @@ package state import "github.com/ethereum/go-ethereum/metrics" var ( - accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) - storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) - accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) - storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil) - accountTrieNodesMeter = metrics.NewRegisteredMeter("state/trie/account", nil) - storageTriesNodesMeter = metrics.NewRegisteredMeter("state/trie/storage", nil) + accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) + storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) + accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) + storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil) + accountTrieUpdatedMeter = metrics.NewRegisteredMeter("state/update/accountnodes", nil) + storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil) + accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil) + storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil) ) diff --git a/core/state/statedb.go b/core/state/statedb.go index 4385c197692b..3f4bec2392dc 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -970,11 +970,13 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { // Commit objects to the trie, measuring the elapsed time var ( - accountTrieNodes int - storageTrieNodes int - nodes = trie.NewMergedNodeSet() - codeWriter = s.db.DiskDB().NewBatch() + accountTrieNodesUpdated int + accountTrieNodesDeleted int + storageTrieNodesUpdated int + storageTrieNodesDeleted int + nodes = trie.NewMergedNodeSet() ) + codeWriter := s.db.DiskDB().NewBatch() for addr := range s.stateObjectsDirty { if obj := s.stateObjects[addr]; !obj.deleted { // Write any contract code associated with the state object @@ -992,9 +994,17 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if err := nodes.Merge(set); err != nil { return common.Hash{}, err } - storageTrieNodes += set.Size() + updates, deleted := set.Size() + storageTrieNodesUpdated += updates + storageTrieNodesDeleted += deleted } } + // If the contract is destructed, the storage is still left in the + // database as dangling data. Theoretically it's should be wiped from + // database as well, but in hash-based-scheme it's extremely hard to + // determine that if the trie nodes are also referenced by other storage, + // and in path-based-scheme some technical challenges are still unsolved. + // Although it won't affect the correctness but please fix it TODO(rjl493456442). } if len(s.stateObjectsDirty) > 0 { s.stateObjectsDirty = make(map[common.Address]struct{}) @@ -1015,7 +1025,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { if err := nodes.Merge(set); err != nil { return common.Hash{}, err } - accountTrieNodes = set.Size() + accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size() } if metrics.EnabledExpensive { s.AccountCommits += time.Since(start) @@ -1024,9 +1034,10 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { storageUpdatedMeter.Mark(int64(s.StorageUpdated)) accountDeletedMeter.Mark(int64(s.AccountDeleted)) storageDeletedMeter.Mark(int64(s.StorageDeleted)) - accountTrieNodesMeter.Mark(int64(accountTrieNodes)) - storageTriesNodesMeter.Mark(int64(storageTrieNodes)) - + accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated)) + accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted)) + storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated)) + storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted)) s.AccountUpdated, s.AccountDeleted = 0, 0 s.StorageUpdated, s.StorageDeleted = 0, 0 } diff --git a/trie/committer.go b/trie/committer.go index 745cb7683998..c4957f3490ea 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -33,22 +33,29 @@ type leaf struct { // insertion order. type committer struct { nodes *NodeSet + tracer *tracer collectLeaf bool } // newCommitter creates a new committer or picks one from the pool. -func newCommitter(nodes *NodeSet, collectLeaf bool) *committer { +func newCommitter(owner common.Hash, tracer *tracer, collectLeaf bool) *committer { return &committer{ - nodes: nodes, + nodes: NewNodeSet(owner), + tracer: tracer, collectLeaf: collectLeaf, } } // Commit collapses a node down into a hash node and returns it along with // the modified nodeset. -func (c *committer) Commit(n node) hashNode { +func (c *committer) Commit(n node) (hashNode, *NodeSet) { h := c.commit(nil, n) - return h.(hashNode) + // Some nodes can be deleted from trie which can't be captured + // by committer itself. Iterate all deleted nodes tracked by + // tracer and marked them as deleted only if they are present + // in database previously. + c.tracer.markDeletions(c.nodes) + return h.(hashNode), c.nodes } // commit collapses a node down into a hash node and returns it. @@ -78,6 +85,12 @@ func (c *committer) commit(path []byte, n node) node { if hn, ok := hashedNode.(hashNode); ok { return hn } + // The short node now is embedded in its parent. Mark the node as + // deleted if it's present in database previously. It's equivalent + // as deletion from database's perspective. + if prev := c.tracer.getPrev(path); len(prev) != 0 { + c.nodes.markDeleted(path, prev) + } return collapsed case *fullNode: hashedKids := c.commitChildren(path, cn) @@ -88,6 +101,12 @@ func (c *committer) commit(path []byte, n node) node { if hn, ok := hashedNode.(hashNode); ok { return hn } + // The full node now is embedded in its parent. Mark the node as + // deleted if it's present in database previously. It's equivalent + // as deletion from database's perspective. + if prev := c.tracer.getPrev(path); len(prev) != 0 { + c.nodes.markDeleted(path, prev) + } return collapsed case hashNode: return cn @@ -150,7 +169,7 @@ func (c *committer) store(path []byte, n node) node { } ) // Collect the dirty node to nodeset for return. - c.nodes.markUpdated(path, mnode) + c.nodes.markUpdated(path, mnode, c.tracer.getPrev(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/database.go b/trie/database.go index 5d47475e0f04..74247d59c4f8 100644 --- a/trie/database.go +++ b/trie/database.go @@ -792,12 +792,13 @@ func (db *Database) Update(nodes *MergedNodeSet) error { } for _, owner := range order { subset := nodes.sets[owner] - subset.forEachWithOrder(false, func(path string, n *memoryNode) { - if n.isDeleted() { - return // ignore deletion + for _, path := range subset.updates.order { + n, ok := subset.updates.nodes[path] + if !ok { + return fmt.Errorf("missing node %x %v", owner, path) } db.insert(n.hash, int(n.size), n.node) - }) + } } // Link up the account trie and storage trie if the node points // to an account trie leaf. diff --git a/trie/nodeset.go b/trie/nodeset.go index 4251eccaf680..928172350171 100644 --- a/trie/nodeset.go +++ b/trie/nodeset.go @@ -19,7 +19,6 @@ package trie import ( "fmt" "reflect" - "sort" "strings" "github.com/ethereum/go-ethereum/common" @@ -41,8 +40,8 @@ var memoryNodeSize = int(reflect.TypeOf(memoryNode{}).Size()) // memorySize returns the total memory size used by this node. // nolint:unused -func (n *memoryNode) memorySize(pathlen int) int { - return int(n.size) + memoryNodeSize + pathlen +func (n *memoryNode) memorySize(key int) int { + return int(n.size) + memoryNodeSize + key } // rlp returns the raw rlp encoded blob of the cached trie node, either directly @@ -65,20 +64,14 @@ func (n *memoryNode) obj() node { return expandNode(n.hash[:], n.node) } -// isDeleted returns the indicator if the node is marked as deleted. -func (n *memoryNode) isDeleted() bool { - return n.hash == (common.Hash{}) -} - // nodeWithPrev wraps the memoryNode with the previous node value. -// nolint: unused type nodeWithPrev struct { *memoryNode prev []byte // RLP-encoded previous value, nil means it's non-existent } // unwrap returns the internal memoryNode object. -// nolint: unused +// nolint:unused func (n *nodeWithPrev) unwrap() *memoryNode { return n.memoryNode } @@ -86,69 +79,64 @@ func (n *nodeWithPrev) unwrap() *memoryNode { // memorySize returns the total memory size used by this node. It overloads // the function in memoryNode by counting the size of previous value as well. // nolint: unused -func (n *nodeWithPrev) memorySize(pathlen int) int { - return n.memoryNode.memorySize(pathlen) + len(n.prev) +func (n *nodeWithPrev) memorySize(key int) int { + return n.memoryNode.memorySize(key) + len(n.prev) +} + +// nodesWithOrder represents a collection of dirty nodes which includes +// newly-inserted and updated nodes. The modification order of all nodes +// is represented by order list. +type nodesWithOrder struct { + order []string // the path list of dirty nodes, sort by insertion order + nodes map[string]*nodeWithPrev // the map of dirty nodes, keyed by node path } // NodeSet contains all dirty nodes collected during the commit operation. // Each node is keyed by path. It's not thread-safe to use. type NodeSet struct { - owner common.Hash // the identifier of the trie - nodes map[string]*memoryNode // the set of dirty nodes(inserted, updated, deleted) - leaves []*leaf // the list of dirty leaves - accessList map[string][]byte // The list of accessed nodes, which records the original node value + owner common.Hash // the identifier of the trie + updates *nodesWithOrder // the set of updated nodes(newly inserted, updated) + deletes map[string][]byte // the map of deleted nodes, keyed by node + leaves []*leaf // the list of dirty leaves } // NewNodeSet initializes an empty node set to be used for tracking dirty nodes -// for a specific account or storage trie. The owner is zero for the account trie -// and the owning account address hash for storage tries. The provided accessList -// represents the original value of accessed nodes, it can be optional but would -// be beneficial for speeding up the construction of trie history. -func NewNodeSet(owner common.Hash, accessList map[string][]byte) *NodeSet { - // Don't panic for lazy users - if accessList == nil { - accessList = make(map[string][]byte) - } +// from a specific account or storage trie. The owner is zero for the account +// trie and the owning account address hash for storage tries. +func NewNodeSet(owner common.Hash) *NodeSet { return &NodeSet{ - owner: owner, - nodes: make(map[string]*memoryNode), - accessList: accessList, + owner: owner, + updates: &nodesWithOrder{ + nodes: make(map[string]*nodeWithPrev), + }, + deletes: make(map[string][]byte), } } -// forEachWithOrder iterates the dirty nodes with the specified order. -// If topToBottom is true: -// -// then the order of iteration is top to bottom, left to right. -// -// If topToBottom is false: -// -// then the order of iteration is bottom to top, right to left. -func (set *NodeSet) forEachWithOrder(topToBottom bool, callback func(path string, n *memoryNode)) { - var paths sort.StringSlice - for path := range set.nodes { - paths = append(paths, path) - } - if topToBottom { - paths.Sort() - } else { - sort.Sort(sort.Reverse(paths)) - } - for _, path := range paths { - callback(path, set.nodes[path]) +/* +// NewNodeSetWithDeletion initializes the nodeset with provided deletion set. +func NewNodeSetWithDeletion(owner common.Hash, paths [][]byte, prev [][]byte) *NodeSet { + set := NewNodeSet(owner) + for i, path := range paths { + set.markDeleted(path, prev[i]) } + return set } +*/ // markUpdated marks the node as dirty(newly-inserted or updated) with provided // node path, node object along with its previous value. -func (set *NodeSet) markUpdated(path []byte, node *memoryNode) { - set.nodes[string(path)] = node +func (set *NodeSet) markUpdated(path []byte, node *memoryNode, prev []byte) { + set.updates.order = append(set.updates.order, string(path)) + set.updates.nodes[string(path)] = &nodeWithPrev{ + memoryNode: node, + prev: prev, + } } // markDeleted marks the node as deleted with provided path and previous value. -// nolint: unused -func (set *NodeSet) markDeleted(path []byte) { - set.nodes[string(path)] = &memoryNode{} +func (set *NodeSet) markDeleted(path []byte, prev []byte) { + set.deletes[string(path)] = prev } // addLeaf collects the provided leaf node into set. @@ -156,16 +144,16 @@ func (set *NodeSet) addLeaf(node *leaf) { set.leaves = append(set.leaves, node) } -// Size returns the number of dirty nodes contained in the set. -func (set *NodeSet) Size() int { - return len(set.nodes) +// Size returns the number of updated and deleted nodes contained in the set. +func (set *NodeSet) Size() (int, int) { + return len(set.updates.order), len(set.deletes) } // Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can // we get rid of it? func (set *NodeSet) Hashes() []common.Hash { var ret []common.Hash - for _, node := range set.nodes { + for _, node := range set.updates.nodes { ret = append(ret, node.hash) } return ret @@ -175,17 +163,19 @@ func (set *NodeSet) Hashes() []common.Hash { func (set *NodeSet) Summary() string { var out = new(strings.Builder) fmt.Fprintf(out, "nodeset owner: %v\n", set.owner) - if set.nodes != nil { - for path, n := range set.nodes { - // Deletion - if n.isDeleted() { - fmt.Fprintf(out, " [-]: %x\n", path) - continue + if set.updates != nil { + for _, key := range set.updates.order { + updated := set.updates.nodes[key] + if updated.prev != nil { + fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", key, updated.hash, updated.prev) + } else { + fmt.Fprintf(out, " [+]: %x -> %v\n", key, updated.hash) } - // Update - fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.hash) } } + for k, n := range set.deletes { + fmt.Fprintf(out, " [-]: %x -> %x\n", k, n) + } for _, n := range set.leaves { fmt.Fprintf(out, "[leaf]: %v\n", n) } diff --git a/trie/trie.go b/trie/trie.go index 65f89d91f8b4..c467ac476622 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -51,11 +51,12 @@ type Trie struct { // actually unhashed nodes. unhashed int - // accessList tracks the loaded nodes from database. - accessList map[string][]byte - // reader is the handler trie can retrieve nodes from. reader *trieReader + + // tracer is the tool to track the trie changes. + // It will be reset after each commit operation. + tracer *tracer } // newFlag returns the cache flag value for a newly created node. @@ -65,16 +66,12 @@ func (t *Trie) newFlag() nodeFlag { // Copy returns a copy of Trie. func (t *Trie) Copy() *Trie { - accessList := make(map[string][]byte) - for path, blob := range t.accessList { - accessList[path] = common.CopyBytes(blob) - } return &Trie{ - root: t.root, - owner: t.owner, - unhashed: t.unhashed, - reader: t.reader, - accessList: accessList, + root: t.root, + owner: t.owner, + unhashed: t.unhashed, + reader: t.reader, + tracer: t.tracer.copy(), } } @@ -90,9 +87,9 @@ func New(id *ID, db NodeReader) (*Trie, error) { return nil, err } trie := &Trie{ - owner: id.Owner, - reader: reader, - accessList: make(map[string][]byte), + owner: id.Owner, + reader: reader, + //tracer: newTracer(), } if id.Root != (common.Hash{}) && id.Root != emptyRoot { rootnode, err := trie.resolveAndTrack(id.Root[:], nil) @@ -329,6 +326,11 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error if matchlen == 0 { return true, branch, nil } + // 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]...)) + // Replace it with a short node leading up to the branch. return true, &shortNode{key[:matchlen], branch, t.newFlag()}, nil @@ -343,6 +345,11 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error return true, n, nil case nil: + // 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) + return true, &shortNode{key, value, t.newFlag()}, nil case hashNode: @@ -395,6 +402,11 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { return false, n, nil // don't replace n on mismatch } if matchlen == len(key) { + // 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) + return true, nil, nil // remove n entirely for whole matches } // The key is longer than n.Key. Remove the remaining suffix @@ -407,6 +419,10 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { } switch child := child.(type) { case *shortNode: + // The child shortNode is merged into its parent, track + // is deleted as well. + t.tracer.onDelete(append(prefix, n.Key...)) + // Deleting from the subtrie reduced it to another // short node. Merge the nodes to avoid creating a // shortNode{..., shortNode{...}}. Use concat (which @@ -468,6 +484,11 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { return false, nil, err } if cnode, ok := cnode.(*shortNode); ok { + // 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))) + k := append([]byte{byte(pos)}, cnode.Key...) return true, &shortNode{k, cnode.Val, t.newFlag()}, nil } @@ -527,7 +548,7 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { if err != nil { return nil, err } - t.accessList[string(prefix)] = blob + t.tracer.onRead(prefix, blob) return mustDecodeNode(n, blob), nil } @@ -546,15 +567,16 @@ func (t *Trie) Hash() common.Hash { // 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 *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { - // Reset accessList at the end of commit - defer func() { - t.accessList = make(map[string][]byte) - }() + defer t.tracer.reset() + // Trie is empty and can be classified into two types of situations: // - The trie was empty and no update happens // - The trie was non-empty and all nodes are dropped if t.root == nil { - return emptyRoot, nil + // Wrap tracked deletions as the return + set := NewNodeSet(t.owner) + t.tracer.markDeletions(set) + return emptyRoot, set } // Derive the hash for all dirty nodes first. We hold the assumption // in the following procedure that all nodes are hashed. @@ -568,9 +590,8 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { t.root = hashedNode return rootHash, nil } - nodes := NewNodeSet(t.owner, t.accessList) - h := newCommitter(nodes, collectLeaf) - newRoot := h.Commit(t.root) + h := newCommitter(t.owner, t.tracer, collectLeaf) + newRoot, nodes := h.Commit(t.root) t.root = newRoot return rootHash, nodes } @@ -593,5 +614,5 @@ func (t *Trie) Reset() { t.root = nil t.owner = common.Hash{} t.unhashed = 0 - t.accessList = make(map[string][]byte) + t.tracer.reset() } diff --git a/trie/trie_test.go b/trie/trie_test.go index b87b7d3cd6c9..2fb97eebbf49 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -410,6 +410,7 @@ func runRandTest(rt randTest) bool { values = make(map[string]string) // tracks content of the trie origTrie = NewEmpty(triedb) ) + tr.tracer = newTracer() for i, step := range rt { // fmt.Printf("{op: %d, key: common.Hex2Bytes(\"%x\"), value: common.Hex2Bytes(\"%x\")}, // step %d\n", @@ -448,14 +449,21 @@ func runRandTest(rt randTest) bool { root, nodes := tr.Commit(true) // Validity the returned nodeset if nodes != nil { - for path := range nodes.nodes { + for path, node := range nodes.updates.nodes { blob, _, _ := origTrie.TryGetNode(hexToCompact([]byte(path))) - got := nodes.accessList[path] + got := node.prev if !bytes.Equal(blob, got) { rt[i].err = fmt.Errorf("prevalue mismatch for 0x%x, got 0x%x want 0x%x", path, got, blob) panic(rt[i].err) } } + for path, prev := range nodes.deletes { + blob, _, _ := origTrie.TryGetNode(hexToCompact([]byte(path))) + if !bytes.Equal(blob, prev) { + rt[i].err = fmt.Errorf("prevalue mismatch for 0x%x, got 0x%x want 0x%x", path, prev, blob) + return false + } + } } if nodes != nil { triedb.Update(NewWithNodeSet(nodes)) @@ -469,6 +477,7 @@ func runRandTest(rt randTest) bool { // Enable node tracing. Resolve the root node again explicitly // since it's not captured at the beginning. + tr.tracer = newTracer() tr.resolveAndTrack(root.Bytes(), nil) origTrie = tr.Copy() @@ -481,6 +490,59 @@ func runRandTest(rt randTest) bool { if tr.Hash() != checktr.Hash() { rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") } + case opNodeDiff: + var ( + inserted = tr.tracer.insertList() + deleted = tr.tracer.deleteList() + origIter = origTrie.NodeIterator(nil) + curIter = tr.NodeIterator(nil) + origSeen = make(map[string]struct{}) + curSeen = make(map[string]struct{}) + ) + for origIter.Next(true) { + if origIter.Leaf() { + continue + } + origSeen[string(origIter.Path())] = struct{}{} + } + for curIter.Next(true) { + if curIter.Leaf() { + continue + } + curSeen[string(curIter.Path())] = struct{}{} + } + var ( + insertExp = make(map[string]struct{}) + deleteExp = make(map[string]struct{}) + ) + for path := range curSeen { + _, present := origSeen[path] + if !present { + insertExp[path] = struct{}{} + } + } + for path := range origSeen { + _, present := curSeen[path] + if !present { + deleteExp[path] = struct{}{} + } + } + if len(insertExp) != len(inserted) { + rt[i].err = fmt.Errorf("insert set mismatch") + } + if len(deleteExp) != len(deleted) { + rt[i].err = fmt.Errorf("delete set mismatch") + } + for _, insert := range inserted { + if _, present := insertExp[string(insert)]; !present { + rt[i].err = fmt.Errorf("missing inserted node") + } + } + for _, del := range deleted { + if _, present := deleteExp[string(del)]; !present { + rt[i].err = fmt.Errorf("missing deleted node") + } + } } // Abort the test on error. if rt[i].err != nil { diff --git a/trie/util_test.go b/trie/util_test.go new file mode 100644 index 000000000000..01a46553aa68 --- /dev/null +++ b/trie/util_test.go @@ -0,0 +1,304 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package trie + +import ( + "bytes" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" +) + +// Tests if the trie diffs are tracked correctly. +func TestTrieTracer(t *testing.T) { + db := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(db) + trie.tracer = newTracer() + + // Insert a batch of entries, all the nodes should be marked as inserted + vals := []struct{ k, v string }{ + {"do", "verb"}, + {"ether", "wookiedoo"}, + {"horse", "stallion"}, + {"shaman", "horse"}, + {"doge", "coin"}, + {"dog", "puppy"}, + {"somethingveryoddindeedthis is", "myothernodedata"}, + } + for _, val := range vals { + trie.Update([]byte(val.k), []byte(val.v)) + } + trie.Hash() + + seen := make(map[string]struct{}) + it := trie.NodeIterator(nil) + for it.Next(true) { + if it.Leaf() { + continue + } + seen[string(it.Path())] = struct{}{} + } + inserted := trie.tracer.insertList() + if len(inserted) != len(seen) { + t.Fatalf("Unexpected inserted node tracked want %d got %d", len(seen), len(inserted)) + } + for _, k := range inserted { + _, ok := seen[string(k)] + if !ok { + t.Fatalf("Unexpected inserted node") + } + } + deleted := trie.tracer.deleteList() + if len(deleted) != 0 { + t.Fatalf("Unexpected deleted node tracked %d", len(deleted)) + } + + // Commit the changes and re-create with new root + root, nodes := trie.Commit(false) + if err := db.Update(NewWithNodeSet(nodes)); err != nil { + t.Fatal(err) + } + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + + // Delete all the elements, check deletion set + for _, val := range vals { + trie.Delete([]byte(val.k)) + } + trie.Hash() + + inserted = trie.tracer.insertList() + if len(inserted) != 0 { + t.Fatalf("Unexpected inserted node tracked %d", len(inserted)) + } + deleted = trie.tracer.deleteList() + if len(deleted) != len(seen) { + t.Fatalf("Unexpected deleted node tracked want %d got %d", len(seen), len(deleted)) + } + for _, k := range deleted { + _, ok := seen[string(k)] + if !ok { + t.Fatalf("Unexpected inserted node") + } + } +} + +func TestTrieTracerNoop(t *testing.T) { + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) + trie.tracer = newTracer() + + // Insert a batch of entries, all the nodes should be marked as inserted + vals := []struct{ k, v string }{ + {"do", "verb"}, + {"ether", "wookiedoo"}, + {"horse", "stallion"}, + {"shaman", "horse"}, + {"doge", "coin"}, + {"dog", "puppy"}, + {"somethingveryoddindeedthis is", "myothernodedata"}, + } + for _, val := range vals { + trie.Update([]byte(val.k), []byte(val.v)) + } + for _, val := range vals { + trie.Delete([]byte(val.k)) + } + if len(trie.tracer.insertList()) != 0 { + t.Fatalf("Unexpected inserted node tracked %d", len(trie.tracer.insertList())) + } + if len(trie.tracer.deleteList()) != 0 { + t.Fatalf("Unexpected deleted node tracked %d", len(trie.tracer.deleteList())) + } +} + +func TestTrieTracePrevValue(t *testing.T) { + db := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(db) + trie.tracer = newTracer() + + paths, blobs := trie.tracer.prevList() + if len(paths) != 0 || len(blobs) != 0 { + t.Fatalf("Nothing should be tracked") + } + // Insert a batch of entries, all the nodes should be marked as inserted + vals := []struct{ k, v string }{ + {"do", "verb"}, + {"ether", "wookiedoo"}, + {"horse", "stallion"}, + {"shaman", "horse"}, + {"doge", "coin"}, + {"dog", "puppy"}, + {"somethingveryoddindeedthis is", "myothernodedata"}, + } + for _, val := range vals { + trie.Update([]byte(val.k), []byte(val.v)) + } + paths, blobs = trie.tracer.prevList() + if len(paths) != 0 || len(blobs) != 0 { + t.Fatalf("Nothing should be tracked") + } + + // Commit the changes and re-create with new root + root, nodes := trie.Commit(false) + if err := db.Update(NewWithNodeSet(nodes)); err != nil { + t.Fatal(err) + } + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + trie.resolveAndTrack(root.Bytes(), nil) + + // Load all nodes in trie + for _, val := range vals { + trie.TryGet([]byte(val.k)) + } + + // Ensure all nodes are tracked by tracer with correct prev-values + iter := trie.NodeIterator(nil) + seen := make(map[string][]byte) + for iter.Next(true) { + // Embedded nodes are ignored since they are not present in + // database. + if iter.Hash() == (common.Hash{}) { + continue + } + seen[string(iter.Path())] = common.CopyBytes(iter.NodeBlob()) + } + + paths, blobs = trie.tracer.prevList() + if len(paths) != len(seen) || len(blobs) != len(seen) { + t.Fatalf("Unexpected tracked values") + } + for i, path := range paths { + blob := blobs[i] + prev, ok := seen[string(path)] + if !ok { + t.Fatalf("Missing node %v", path) + } + if !bytes.Equal(blob, prev) { + t.Fatalf("Unexpected value path: %v, want: %v, got: %v", path, prev, blob) + } + } + + // Re-open the trie and iterate the trie, ensure nothing will be tracked. + // Iterator will not link any loaded nodes to trie. + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + + iter = trie.NodeIterator(nil) + for iter.Next(true) { + } + paths, blobs = trie.tracer.prevList() + if len(paths) != 0 || len(blobs) != 0 { + t.Fatalf("Nothing should be tracked") + } + + // Re-open the trie and generate proof for entries, ensure nothing will + // be tracked. Prover will not link any loaded nodes to trie. + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + for _, val := range vals { + trie.Prove([]byte(val.k), 0, rawdb.NewMemoryDatabase()) + } + paths, blobs = trie.tracer.prevList() + if len(paths) != 0 || len(blobs) != 0 { + t.Fatalf("Nothing should be tracked") + } + + // Delete entries from trie, ensure all previous values are correct. + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + trie.resolveAndTrack(root.Bytes(), nil) + + for _, val := range vals { + trie.TryDelete([]byte(val.k)) + } + paths, blobs = trie.tracer.prevList() + if len(paths) != len(seen) || len(blobs) != len(seen) { + t.Fatalf("Unexpected tracked values") + } + for i, path := range paths { + blob := blobs[i] + prev, ok := seen[string(path)] + if !ok { + t.Fatalf("Missing node %v", path) + } + if !bytes.Equal(blob, prev) { + t.Fatalf("Unexpected value path: %v, want: %v, got: %v", path, prev, blob) + } + } +} + +func TestDeleteAll(t *testing.T) { + db := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(db) + trie.tracer = newTracer() + + // Insert a batch of entries, all the nodes should be marked as inserted + vals := []struct{ k, v string }{ + {"do", "verb"}, + {"ether", "wookiedoo"}, + {"horse", "stallion"}, + {"shaman", "horse"}, + {"doge", "coin"}, + {"dog", "puppy"}, + {"somethingveryoddindeedthis is", "myothernodedata"}, + } + for _, val := range vals { + trie.Update([]byte(val.k), []byte(val.v)) + } + root, set := trie.Commit(false) + if err := db.Update(NewWithNodeSet(set)); err != nil { + t.Fatal(err) + } + // Delete entries from trie, ensure all values are detected + trie, _ = New(TrieID(root), db) + trie.tracer = newTracer() + trie.resolveAndTrack(root.Bytes(), nil) + + // Iterate all existent nodes + var ( + it = trie.NodeIterator(nil) + nodes = make(map[string][]byte) + ) + for it.Next(true) { + if it.Hash() != (common.Hash{}) { + nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) + } + } + + // Perform deletion to purge the entire trie + for _, val := range vals { + trie.Delete([]byte(val.k)) + } + root, set = trie.Commit(false) + if root != emptyRoot { + t.Fatalf("Invalid trie root %v", root) + } + for path, blob := range set.deletes { + prev, ok := nodes[path] + if !ok { + t.Fatalf("Extra node deleted %v", []byte(path)) + } + if !bytes.Equal(prev, blob) { + t.Fatalf("Unexpected previous value %v", []byte(path)) + } + } + if len(set.deletes) != len(nodes) { + t.Fatalf("Unexpected deletion set") + } +} diff --git a/trie/utils.go b/trie/utils.go new file mode 100644 index 000000000000..5dce65cd2971 --- /dev/null +++ b/trie/utils.go @@ -0,0 +1,199 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package trie + +// tracer 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 +// used to track all insert and delete operations of trie and capture all +// deleted nodes eventually. +// +// The changed nodes can be mainly divided into two categories: the leaf +// node and intermediate node. The former is inserted/deleted by callers +// while the latter is inserted/deleted in order to follow the rule of trie. +// 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 reverse-diffs in the future. +// +// Note tracer is not thread-safe, callers should be responsible for handling +// the concurrency issues by themselves. +type tracer struct { + insert map[string]struct{} + delete map[string]struct{} + origin map[string][]byte +} + +// newTracer initializes the tracer for capturing trie changes. +func newTracer() *tracer { + return &tracer{ + insert: make(map[string]struct{}), + delete: make(map[string]struct{}), + origin: make(map[string][]byte), + } +} + +// 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) { + // Tracer isn't used right now, remove this check later. + if t == nil { + return + } + t.origin[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 the "untouched". +func (t *tracer) onInsert(path []byte) { + // Tracer isn't used right now, remove this check later. + if t == nil { + return + } + if _, present := t.delete[string(path)]; present { + delete(t.delete, string(path)) + return + } + t.insert[string(path)] = struct{}{} +} + +// 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) { + // Tracer isn't used right now, remove this check later. + if t == nil { + return + } + if _, present := t.insert[string(path)]; present { + delete(t.insert, string(path)) + return + } + t.delete[string(path)] = struct{}{} +} + +// insertList returns the tracked inserted trie nodes in list format. +func (t *tracer) insertList() [][]byte { + // Tracer isn't used right now, remove this check later. + if t == nil { + return nil + } + var ret [][]byte + for path := range t.insert { + ret = append(ret, []byte(path)) + } + return ret +} + +// deleteList returns the tracked deleted trie nodes in list format. +func (t *tracer) deleteList() [][]byte { + // Tracer isn't used right now, remove this check later. + if t == nil { + return nil + } + var ret [][]byte + for path := range t.delete { + ret = append(ret, []byte(path)) + } + return ret +} + +// prevList returns the tracked node blobs in list format. +func (t *tracer) prevList() ([][]byte, [][]byte) { + // Tracer isn't used right now, remove this check later. + if t == nil { + return nil, nil + } + var ( + paths [][]byte + blobs [][]byte + ) + for path, blob := range t.origin { + paths = append(paths, []byte(path)) + blobs = append(blobs, blob) + } + return paths, blobs +} + +// getPrev returns the cached original value of the specified node. +func (t *tracer) getPrev(path []byte) []byte { + // Tracer isn't used right now, remove this check later. + if t == nil { + return nil + } + return t.origin[string(path)] +} + +// reset clears the content tracked by tracer. +func (t *tracer) reset() { + // Tracer isn't used right now, remove this check later. + if t == nil { + return + } + t.insert = make(map[string]struct{}) + t.delete = make(map[string]struct{}) + t.origin = make(map[string][]byte) +} + +// copy returns a deep copied tracer instance. +func (t *tracer) copy() *tracer { + // Tracer isn't used right now, remove this check later. + if t == nil { + return nil + } + var ( + insert = make(map[string]struct{}) + delete = make(map[string]struct{}) + origin = make(map[string][]byte) + ) + for key := range t.insert { + insert[key] = struct{}{} + } + for key := range t.delete { + delete[key] = struct{}{} + } + for key, val := range t.origin { + origin[key] = val + } + return &tracer{ + insert: insert, + delete: delete, + origin: origin, + } +} + +// markDeletions puts all tracked deletions into the provided nodeset. +func (t *tracer) markDeletions(set *NodeSet) { + // Tracer isn't used right now, remove this check later. + if t == nil { + return + } + for _, path := range t.deleteList() { + // There are a few possibilities for this scenario(the node is deleted + // but not present in database previously), for example the node was + // embedded in the parent and now deleted from the trie. In this case + // it's noop from database's perspective. + val := t.getPrev(path) + if len(val) == 0 { + continue + } + set.markDeleted(path, val) + } +} From 7d4db6960724b9a3b8fea7144a7ccfd5493285c6 Mon Sep 17 00:00:00 2001 From: Sungwoo Kim Date: Tue, 21 Feb 2023 02:35:04 -0500 Subject: [PATCH 575/715] cmd/geth: clarify dumpconfig options (#26729) Clarifies the documentation around dumpconfi Signed-off-by: Sungwoo Kim --- cmd/geth/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 61b7ed5ec1e3..0b856d1c1b7a 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -47,10 +47,10 @@ var ( dumpConfigCommand = &cli.Command{ Action: dumpConfig, Name: "dumpconfig", - Usage: "Show configuration values", - ArgsUsage: "", + Usage: "Export configuration values in a TOML format", + ArgsUsage: "", Flags: flags.Merge(nodeFlags, rpcFlags), - Description: `The dumpconfig command shows configuration values.`, + Description: `Export configuration values in TOML format (to stdout by default).`, } configFileFlag = &cli.StringFlag{ From 90d25514af32f4e489d71fddf43c7f66c7de517b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 21 Feb 2023 12:17:34 +0200 Subject: [PATCH 576/715] core, eth: merge snap-sync chain download progress logs (#26676) --- core/blockchain.go | 2 +- core/headerchain.go | 2 +- core/rawdb/accessors_chain.go | 26 +++++++------- core/rawdb/ancient_scheme.go | 30 ++++++++-------- core/rawdb/chain_freezer.go | 10 +++--- core/rawdb/chain_iterator.go | 2 +- core/rawdb/database.go | 2 +- eth/downloader/downloader.go | 65 ++++++++++++++++++++++++++++++++++- eth/downloader/queue.go | 9 ++--- 9 files changed, 106 insertions(+), 42 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 98d2e7a774ad..38a129d4eec5 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1278,7 +1278,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ if stats.ignored > 0 { context = append(context, []interface{}{"ignored", stats.ignored}...) } - log.Info("Imported new block receipts", context...) + log.Debug("Imported new block receipts", context...) return 0, nil } diff --git a/core/headerchain.go b/core/headerchain.go index d40d26f72bf7..aed3c720c633 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -389,7 +389,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, start time.Time, if res.ignored > 0 { context = append(context, []interface{}{"ignored", res.ignored}...) } - log.Info("Imported new block headers", context...) + log.Debug("Imported new block headers", context...) return res.status, err } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 9b90d8f20cc4..e4dac3407fc5 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -37,7 +37,7 @@ import ( func ReadCanonicalHash(db ethdb.Reader, number uint64) common.Hash { var data []byte db.ReadAncients(func(reader ethdb.AncientReaderOp) error { - data, _ = reader.Ancient(chainFreezerHashTable, number) + data, _ = reader.Ancient(ChainFreezerHashTable, number) if len(data) == 0 { // Get it by hash from leveldb data, _ = db.Get(headerHashKey(number)) @@ -334,7 +334,7 @@ func ReadHeaderRange(db ethdb.Reader, number uint64, count uint64) []rlp.RawValu } // read remaining from ancients max := count * 700 - data, err := db.AncientRange(chainFreezerHeaderTable, i+1-count, count, max) + data, err := db.AncientRange(ChainFreezerHeaderTable, i+1-count, count, max) if err == nil && uint64(len(data)) == count { // the data is on the order [h, h+1, .., n] -- reordering needed for i := range data { @@ -351,7 +351,7 @@ func ReadHeaderRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValu // First try to look up the data in ancient database. Extra hash // comparison is necessary since ancient database only maintains // the canonical data. - data, _ = reader.Ancient(chainFreezerHeaderTable, number) + data, _ = reader.Ancient(ChainFreezerHeaderTable, number) if len(data) > 0 && crypto.Keccak256Hash(data) == hash { return nil } @@ -427,7 +427,7 @@ func deleteHeaderWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number // isCanon is an internal utility method, to check whether the given number/hash // is part of the ancient (canon) set. func isCanon(reader ethdb.AncientReaderOp, number uint64, hash common.Hash) bool { - h, err := reader.Ancient(chainFreezerHashTable, number) + h, err := reader.Ancient(ChainFreezerHashTable, number) if err != nil { return false } @@ -443,7 +443,7 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue db.ReadAncients(func(reader ethdb.AncientReaderOp) error { // Check if the data is in ancients if isCanon(reader, number, hash) { - data, _ = reader.Ancient(chainFreezerBodiesTable, number) + data, _ = reader.Ancient(ChainFreezerBodiesTable, number) return nil } // If not, try reading from leveldb @@ -458,7 +458,7 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue func ReadCanonicalBodyRLP(db ethdb.Reader, number uint64) rlp.RawValue { var data []byte db.ReadAncients(func(reader ethdb.AncientReaderOp) error { - data, _ = reader.Ancient(chainFreezerBodiesTable, number) + data, _ = reader.Ancient(ChainFreezerBodiesTable, number) if len(data) > 0 { return nil } @@ -526,7 +526,7 @@ func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { db.ReadAncients(func(reader ethdb.AncientReaderOp) error { // Check if the data is in ancients if isCanon(reader, number, hash) { - data, _ = reader.Ancient(chainFreezerDifficultyTable, number) + data, _ = reader.Ancient(ChainFreezerDifficultyTable, number) return nil } // If not, try reading from leveldb @@ -586,7 +586,7 @@ func ReadReceiptsRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawVa db.ReadAncients(func(reader ethdb.AncientReaderOp) error { // Check if the data is in ancients if isCanon(reader, number, hash) { - data, _ = reader.Ancient(chainFreezerReceiptTable, number) + data, _ = reader.Ancient(ChainFreezerReceiptTable, number) return nil } // If not, try reading from leveldb @@ -787,19 +787,19 @@ func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *types.Header, receipts []*types.ReceiptForStorage, td *big.Int) error { num := block.NumberU64() - if err := op.AppendRaw(chainFreezerHashTable, num, block.Hash().Bytes()); err != nil { + if err := op.AppendRaw(ChainFreezerHashTable, num, block.Hash().Bytes()); err != nil { return fmt.Errorf("can't add block %d hash: %v", num, err) } - if err := op.Append(chainFreezerHeaderTable, num, header); err != nil { + if err := op.Append(ChainFreezerHeaderTable, num, header); err != nil { return fmt.Errorf("can't append block header %d: %v", num, err) } - if err := op.Append(chainFreezerBodiesTable, num, block.Body()); err != nil { + if err := op.Append(ChainFreezerBodiesTable, num, block.Body()); err != nil { return fmt.Errorf("can't append block body %d: %v", num, err) } - if err := op.Append(chainFreezerReceiptTable, num, receipts); err != nil { + if err := op.Append(ChainFreezerReceiptTable, num, receipts); err != nil { return fmt.Errorf("can't append block %d receipts: %v", num, err) } - if err := op.Append(chainFreezerDifficultyTable, num, td); err != nil { + if err := op.Append(ChainFreezerDifficultyTable, num, td); err != nil { return fmt.Errorf("can't append block %d total difficulty: %v", num, err) } return nil diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index 047b504a24bc..b0428c5f5bd9 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -18,30 +18,30 @@ package rawdb // The list of table names of chain freezer. const ( - // chainFreezerHeaderTable indicates the name of the freezer header table. - chainFreezerHeaderTable = "headers" + // ChainFreezerHeaderTable indicates the name of the freezer header table. + ChainFreezerHeaderTable = "headers" - // chainFreezerHashTable indicates the name of the freezer canonical hash table. - chainFreezerHashTable = "hashes" + // ChainFreezerHashTable indicates the name of the freezer canonical hash table. + ChainFreezerHashTable = "hashes" - // chainFreezerBodiesTable indicates the name of the freezer block body table. - chainFreezerBodiesTable = "bodies" + // ChainFreezerBodiesTable indicates the name of the freezer block body table. + ChainFreezerBodiesTable = "bodies" - // chainFreezerReceiptTable indicates the name of the freezer receipts table. - chainFreezerReceiptTable = "receipts" + // ChainFreezerReceiptTable indicates the name of the freezer receipts table. + ChainFreezerReceiptTable = "receipts" - // chainFreezerDifficultyTable indicates the name of the freezer total difficulty table. - chainFreezerDifficultyTable = "diffs" + // ChainFreezerDifficultyTable indicates the name of the freezer total difficulty table. + ChainFreezerDifficultyTable = "diffs" ) // chainFreezerNoSnappy configures whether compression is disabled for the ancient-tables. // Hashes and difficulties don't compress well. var chainFreezerNoSnappy = map[string]bool{ - chainFreezerHeaderTable: false, - chainFreezerHashTable: true, - chainFreezerBodiesTable: false, - chainFreezerReceiptTable: false, - chainFreezerDifficultyTable: true, + ChainFreezerHeaderTable: false, + ChainFreezerHashTable: true, + ChainFreezerBodiesTable: false, + ChainFreezerReceiptTable: false, + ChainFreezerDifficultyTable: true, } // The list of identifiers of ancient stores. diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 738295cfb702..920a0ab59661 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -280,19 +280,19 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash } // Write to the batch. - if err := op.AppendRaw(chainFreezerHashTable, number, hash[:]); err != nil { + if err := op.AppendRaw(ChainFreezerHashTable, number, hash[:]); err != nil { return fmt.Errorf("can't write hash to Freezer: %v", err) } - if err := op.AppendRaw(chainFreezerHeaderTable, number, header); err != nil { + if err := op.AppendRaw(ChainFreezerHeaderTable, number, header); err != nil { return fmt.Errorf("can't write header to Freezer: %v", err) } - if err := op.AppendRaw(chainFreezerBodiesTable, number, body); err != nil { + if err := op.AppendRaw(ChainFreezerBodiesTable, number, body); err != nil { return fmt.Errorf("can't write body to Freezer: %v", err) } - if err := op.AppendRaw(chainFreezerReceiptTable, number, receipts); err != nil { + if err := op.AppendRaw(ChainFreezerReceiptTable, number, receipts); err != nil { return fmt.Errorf("can't write receipts to Freezer: %v", err) } - if err := op.AppendRaw(chainFreezerDifficultyTable, number, td); err != nil { + if err := op.AppendRaw(ChainFreezerDifficultyTable, number, td); err != nil { return fmt.Errorf("can't write td to Freezer: %v", err) } diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 85ad88e29172..102943516eff 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -50,7 +50,7 @@ func InitDatabaseFromFreezer(db ethdb.Database) { if i+count > frozen { count = frozen - i } - data, err := db.AncientRange(chainFreezerHashTable, i, count, 32*count) + data, err := db.AncientRange(ChainFreezerHashTable, i, count, 32*count) if err != nil { log.Crit("Failed to init database from freezer", "err", err) } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index ef80c251a457..a27b45e4d7af 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -231,7 +231,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st // If the freezer already contains something, ensure that the genesis blocks // match, otherwise we might mix up freezers across chains and destroy both // the freezer and the key-value store. - frgenesis, err := frdb.Ancient(chainFreezerHashTable, 0) + frgenesis, err := frdb.Ancient(ChainFreezerHashTable, 0) if err != nil { return nil, fmt.Errorf("failed to retrieve genesis from ancient %v", err) } else if !bytes.Equal(kvgenesis, frgenesis) { diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index f7790b2d80f0..bb74efe754e7 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -154,6 +154,11 @@ type Downloader struct { bodyFetchHook func([]*types.Header) // Method to call upon starting a block body fetch receiptFetchHook func([]*types.Header) // Method to call upon starting a receipt fetch chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations) + + // Progress reporting metrics + syncStartBlock uint64 // Head snap block when Geth was started + syncStartTime time.Time // Time instance when chain sync started + syncLogTime time.Time // Time instance when status was last reported } // LightChain encapsulates functions required to synchronise a light chain. @@ -231,7 +236,9 @@ func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain Bl quitCh: make(chan struct{}), SnapSyncer: snap.NewSyncer(stateDb, chain.TrieDB().Scheme()), stateSyncStart: make(chan *stateSync), + syncStartBlock: chain.CurrentFastBlock().NumberU64(), } + // Create the post-merge skeleton syncer and start the process dl.skeleton = newSkeleton(stateDb, dl.peers, dropPeer, newBeaconBackfiller(dl, success)) go dl.stateFetcher() @@ -1614,6 +1621,7 @@ func (d *Downloader) processSnapSyncContent() error { if len(results) == 0 { // If pivot sync is done, stop if oldPivot == nil { + d.reportSnapSyncProgress(true) return sync.Cancel() } // If sync failed, stop @@ -1627,6 +1635,8 @@ func (d *Downloader) processSnapSyncContent() error { if d.chainInsertHook != nil { d.chainInsertHook(results) } + d.reportSnapSyncProgress(false) + // If we haven't downloaded the pivot block yet, check pivot staleness // notifications from the header downloader d.pivotLock.RLock() @@ -1739,7 +1749,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state } default: } - // Retrieve the a batch of results to import + // Retrieve the batch of results to import first, last := results[0].Header, results[len(results)-1].Header log.Debug("Inserting snap-sync blocks", "items", len(results), "firstnum", first.Number, "firsthash", first.Hash(), @@ -1820,3 +1830,56 @@ func (d *Downloader) readHeaderRange(last *types.Header, count int) []*types.Hea } return headers } + +// reportSnapSyncProgress calculates various status reports and provides it to the user. +func (d *Downloader) reportSnapSyncProgress(force bool) { + // Initialize the sync start time if it's the first time we're reporting + if d.syncStartTime.IsZero() { + d.syncStartTime = time.Now().Add(-time.Millisecond) // -1ms offset to avoid division by zero + } + // Don't report all the events, just occasionally + if !force && time.Since(d.syncLogTime) < 8*time.Second { + return + } + // Don't report anything until we have a meaningful progress + var ( + headerBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerHeaderTable) + bodyBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerBodiesTable) + receiptBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerReceiptTable) + ) + syncedBytes := common.StorageSize(headerBytes + bodyBytes + receiptBytes) + if syncedBytes == 0 { + return + } + var ( + header = d.blockchain.CurrentHeader() + block = d.blockchain.CurrentFastBlock() + ) + syncedBlocks := block.NumberU64() - d.syncStartBlock + if syncedBlocks == 0 { + return + } + // Retrieve the current chain head and calculate the ETA + latest, _, err := d.skeleton.Bounds() + if err != nil { + // We're going to cheat for non-merged networks, but that's fine + latest = d.pivotHeader + } + if latest == nil { + // This should really never happen, but add some defensive code for now. + // TODO(karalabe): Remove it eventually if we don't see it blow. + log.Error("Nil latest block in sync progress report") + return + } + var ( + left = latest.Number.Uint64() - block.NumberU64() + eta = time.Since(d.syncStartTime) / time.Duration(syncedBlocks) * time.Duration(left) + + progress = fmt.Sprintf("%.2f%%", float64(block.NumberU64())*100/float64(latest.Number.Uint64())) + headers = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(header.Number.Uint64()), common.StorageSize(headerBytes).TerminalString()) + bodies = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(block.NumberU64()), common.StorageSize(bodyBytes).TerminalString()) + receipts = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(block.NumberU64()), common.StorageSize(receiptBytes).TerminalString()) + ) + log.Info("Syncing: chain download in progress", "synced", progress, "chain", syncedBytes, "headers", headers, "bodies", bodies, "receipts", receipts, "eta", common.PrettyDuration(eta)) + d.syncLogTime = time.Now() +} diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 1f676e655031..5af5068c98cf 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -144,7 +144,7 @@ type queue struct { active *sync.Cond closed bool - lastStatLog time.Time + logTime time.Time // Time instance when status was last reported } // newQueue creates a new download queue for scheduling block retrieval. @@ -390,11 +390,12 @@ func (q *queue) Results(block bool) []*fetchResult { } } // Log some info at certain times - if time.Since(q.lastStatLog) > 60*time.Second { - q.lastStatLog = time.Now() + if time.Since(q.logTime) >= 60*time.Second { + q.logTime = time.Now() + info := q.Stats() info = append(info, "throttle", throttleThreshold) - log.Info("Downloader queue stats", info...) + log.Debug("Downloader queue stats", info...) } return results } From 6d2d12610093774828e2964661767321e1c9c254 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 21 Feb 2023 05:18:33 -0500 Subject: [PATCH 577/715] core: fix accessor mismatch for genesis state (#26747) --- core/genesis.go | 14 +++++++------- core/rawdb/accessors_metadata.go | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index 5a6c409e0169..8b4e336ed07f 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -138,7 +138,7 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) { // flush is very similar with deriveHash, but the main difference is // all the generated states will be persisted into the given database. // Also, the genesis state specification will be flushed as well. -func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database) error { +func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error { statedb, err := state.New(common.Hash{}, state.NewDatabaseWithNodeDB(db, triedb), nil) if err != nil { return err @@ -166,15 +166,15 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database) error { if err != nil { return err } - rawdb.WriteGenesisStateSpec(db, root, blob) + rawdb.WriteGenesisStateSpec(db, blockhash, blob) return nil } // CommitGenesisState loads the stored genesis state with the given block // hash and commits it into the provided trie database. -func CommitGenesisState(db ethdb.Database, triedb *trie.Database, hash common.Hash) error { +func CommitGenesisState(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error { var alloc GenesisAlloc - blob := rawdb.ReadGenesisStateSpec(db, hash) + blob := rawdb.ReadGenesisStateSpec(db, blockhash) if len(blob) != 0 { if err := alloc.UnmarshalJSON(blob); err != nil { return err @@ -186,7 +186,7 @@ func CommitGenesisState(db ethdb.Database, triedb *trie.Database, hash common.Ha // - supported networks(mainnet, testnets), recover with defined allocations // - private network, can't recover var genesis *Genesis - switch hash { + switch blockhash { case params.MainnetGenesisHash: genesis = DefaultGenesisBlock() case params.RinkebyGenesisHash: @@ -202,7 +202,7 @@ func CommitGenesisState(db ethdb.Database, triedb *trie.Database, hash common.Ha return errors.New("not found") } } - return alloc.flush(db, triedb) + return alloc.flush(db, triedb, blockhash) } // GenesisAccount is an account in the state of the genesis block. @@ -493,7 +493,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block // All the checks has passed, flush the states derived from the genesis // specification as well as the specification itself into the provided // database. - if err := g.Alloc.flush(db, triedb); err != nil { + if err := g.Alloc.flush(db, triedb, block.Hash()); err != nil { return nil, err } rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go index 7a9e6442f011..2ff29d1add93 100644 --- a/core/rawdb/accessors_metadata.go +++ b/core/rawdb/accessors_metadata.go @@ -82,15 +82,15 @@ func WriteChainConfig(db ethdb.KeyValueWriter, hash common.Hash, cfg *params.Cha } // ReadGenesisStateSpec retrieves the genesis state specification based on the -// given genesis hash. -func ReadGenesisStateSpec(db ethdb.KeyValueReader, hash common.Hash) []byte { - data, _ := db.Get(genesisStateSpecKey(hash)) +// given genesis (block-)hash. +func ReadGenesisStateSpec(db ethdb.KeyValueReader, blockhash common.Hash) []byte { + data, _ := db.Get(genesisStateSpecKey(blockhash)) return data } // WriteGenesisStateSpec writes the genesis state specification into the disk. -func WriteGenesisStateSpec(db ethdb.KeyValueWriter, hash common.Hash, data []byte) { - if err := db.Put(genesisStateSpecKey(hash), data); err != nil { +func WriteGenesisStateSpec(db ethdb.KeyValueWriter, blockhash common.Hash, data []byte) { + if err := db.Put(genesisStateSpecKey(blockhash), data); err != nil { log.Crit("Failed to store genesis state", "err", err) } } From 2f20fd31ee2e7c7c544120e4a5eca8600fe8eebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 21 Feb 2023 13:10:01 +0200 Subject: [PATCH 578/715] core/rawdb: expose chain freezer constructor without internals (#26748) --- core/rawdb/chain_freezer.go | 4 ++-- core/rawdb/database.go | 2 +- core/rawdb/freezer.go | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 920a0ab59661..167afc38894c 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -55,8 +55,8 @@ type chainFreezer struct { } // newChainFreezer initializes the freezer for ancient chain data. -func newChainFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]bool) (*chainFreezer, error) { - freezer, err := NewFreezer(datadir, namespace, readonly, maxTableSize, tables) +func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFreezer, error) { + freezer, err := NewChainFreezer(datadir, namespace, readonly) if err != nil { return nil, err } diff --git a/core/rawdb/database.go b/core/rawdb/database.go index a27b45e4d7af..5b7299f38f86 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -200,7 +200,7 @@ func resolveChainFreezerDir(ancient string) string { // where the chain freezer can be opened. func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace string, readonly bool) (ethdb.Database, error) { // Create the idle freezer instance - frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly, freezerTableSize, chainFreezerNoSnappy) + frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly) if err != nil { return nil, err } diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 7bae0a2ea0d1..04c326c4f9e4 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -79,6 +79,12 @@ type Freezer struct { closeOnce sync.Once } +// NewChainFreezer is a small utility method around NewFreezer that sets the +// default parameters for the chain storage. +func NewChainFreezer(datadir string, namespace string, readonly bool) (*Freezer, error) { + return NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy) +} + // NewFreezer creates a freezer instance for maintaining immutable ordered // data according to the given parameters. // From fe01a2f63b8591d8226742726d8d6aaad4cd981e Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 21 Feb 2023 19:12:27 +0800 Subject: [PATCH 579/715] all: use unified emptyRootHash and emptyCodeHash (#26718) The EmptyRootHash and EmptyCodeHash are defined everywhere in the codebase, this PR replaces all of them with unified one defined in core/types package, and also defines constants for TxRoot, WithdrawalsRoot and UncleRoot --- cmd/devp2p/internal/ethtest/snap.go | 16 ++-- cmd/evm/internal/t8ntool/block.go | 4 +- cmd/geth/snapshot.go | 18 ++--- consensus/ethash/algorithm_test.go | 6 +- core/bench_test.go | 4 +- core/genesis.go | 2 +- core/rawdb/accessors_chain_test.go | 28 +++---- core/state/iterator.go | 2 +- core/state/pruner/pruner.go | 13 +--- core/state/snapshot/account.go | 9 ++- core/state/snapshot/conversion.go | 3 +- core/state/snapshot/generate.go | 14 +--- core/state/snapshot/generate_test.go | 108 +++++++++++++-------------- core/state/snapshot/snapshot_test.go | 3 +- core/state/state_object.go | 16 ++-- core/state/statedb.go | 13 +--- core/state/sync_test.go | 5 +- core/state_processor_test.go | 2 +- core/types/block.go | 17 ++--- core/types/hashes.go | 42 +++++++++++ eth/fetcher/block_fetcher.go | 2 +- eth/protocols/snap/handler.go | 3 +- eth/protocols/snap/sync.go | 12 +-- eth/protocols/snap/sync_test.go | 14 ++-- ethclient/ethclient.go | 4 +- les/fetcher/block_fetcher.go | 2 +- les/server_requests.go | 2 +- light/lightchain_test.go | 4 +- trie/database.go | 2 +- trie/iterator.go | 5 +- trie/stacktrie.go | 3 +- trie/sync.go | 5 +- trie/sync_test.go | 3 +- trie/trie.go | 16 +--- trie/trie_test.go | 6 +- trie/util_test.go | 3 +- 36 files changed, 202 insertions(+), 209 deletions(-) create mode 100644 core/types/hashes.go diff --git a/cmd/devp2p/internal/ethtest/snap.go b/cmd/devp2p/internal/ethtest/snap.go index 754d7850d530..f947e4bc9bae 100644 --- a/cmd/devp2p/internal/ethtest/snap.go +++ b/cmd/devp2p/internal/ethtest/snap.go @@ -23,6 +23,7 @@ import ( "math/rand" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/internal/utesting" @@ -210,13 +211,6 @@ type byteCodesTest struct { expHashes int } -var ( - // emptyRoot is the known root hash of an empty trie. - emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - // emptyCode is the known hash of the empty EVM bytecode. - emptyCode = common.HexToHash("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") -) - // TestSnapGetByteCodes various forms of GetByteCodes requests. func (s *Suite) TestSnapGetByteCodes(t *utesting.T) { // The halfchain import should yield these bytecodes @@ -263,15 +257,15 @@ func (s *Suite) TestSnapGetByteCodes(t *utesting.T) { }, // Empties { - nBytes: 10000, hashes: []common.Hash{emptyRoot}, + nBytes: 10000, hashes: []common.Hash{types.EmptyRootHash}, expHashes: 0, }, { - nBytes: 10000, hashes: []common.Hash{emptyCode}, + nBytes: 10000, hashes: []common.Hash{types.EmptyCodeHash}, expHashes: 1, }, { - nBytes: 10000, hashes: []common.Hash{emptyCode, emptyCode, emptyCode}, + nBytes: 10000, hashes: []common.Hash{types.EmptyCodeHash, types.EmptyCodeHash, types.EmptyCodeHash}, expHashes: 3, }, // The existing bytecodes @@ -363,7 +357,7 @@ func (s *Suite) TestSnapTrieNodes(t *utesting.T) { for i := 1; i <= 65; i++ { accPaths = append(accPaths, pathTo(i)) } - empty := emptyCode + empty := types.EmptyCodeHash for i, tc := range []trieNodesTest{ { root: s.chain.RootAt(999), diff --git a/cmd/evm/internal/t8ntool/block.go b/cmd/evm/internal/t8ntool/block.go index 1140daa2c27f..7a9c4b61011c 100644 --- a/cmd/evm/internal/t8ntool/block.go +++ b/cmd/evm/internal/t8ntool/block.go @@ -120,8 +120,8 @@ func (i *bbInput) ToBlock() *types.Block { UncleHash: types.EmptyUncleHash, Coinbase: common.Address{}, Root: i.Header.Root, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, Bloom: i.Header.Bloom, Difficulty: common.Big0, Number: i.Header.Number, diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 7175bb953dee..0759341fd966 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -38,14 +38,6 @@ import ( cli "github.com/urfave/cli/v2" ) -var ( - // emptyRoot is the known root hash of an empty trie. - emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - - // emptyCode is the known hash of the empty EVM bytecode. - emptyCode = crypto.Keccak256(nil) -) - var ( snapshotCommand = &cli.Command{ Name: "snapshot", @@ -308,7 +300,7 @@ func traverseState(ctx *cli.Context) error { log.Error("Invalid account encountered during traversal", "err", err) return err } - if acc.Root != emptyRoot { + if acc.Root != types.EmptyRootHash { id := trie.StorageTrieID(root, common.BytesToHash(accIter.Key), acc.Root) storageTrie, err := trie.NewStateTrie(id, triedb) if err != nil { @@ -324,7 +316,7 @@ func traverseState(ctx *cli.Context) error { return storageIter.Err } } - if !bytes.Equal(acc.CodeHash, emptyCode) { + if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) { if !rawdb.HasCode(chaindb, common.BytesToHash(acc.CodeHash)) { log.Error("Code is missing", "hash", common.BytesToHash(acc.CodeHash)) return errors.New("missing code") @@ -423,7 +415,7 @@ func traverseRawState(ctx *cli.Context) error { log.Error("Invalid account encountered during traversal", "err", err) return errors.New("invalid account") } - if acc.Root != emptyRoot { + if acc.Root != types.EmptyRootHash { id := trie.StorageTrieID(root, common.BytesToHash(accIter.LeafKey()), acc.Root) storageTrie, err := trie.NewStateTrie(id, triedb) if err != nil { @@ -461,7 +453,7 @@ func traverseRawState(ctx *cli.Context) error { return storageIter.Error() } } - if !bytes.Equal(acc.CodeHash, emptyCode) { + if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) { if !rawdb.HasCode(chaindb, common.BytesToHash(acc.CodeHash)) { log.Error("Code is missing", "account", common.BytesToHash(accIter.LeafKey())) return errors.New("missing code") @@ -536,7 +528,7 @@ func dumpState(ctx *cli.Context) error { CodeHash: account.CodeHash, SecureKey: accIt.Hash().Bytes(), } - if !conf.SkipCode && !bytes.Equal(account.CodeHash, emptyCode) { + if !conf.SkipCode && !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash)) } if !conf.SkipStorage { diff --git a/consensus/ethash/algorithm_test.go b/consensus/ethash/algorithm_test.go index 88769d277c09..3ecd7306819b 100644 --- a/consensus/ethash/algorithm_test.go +++ b/consensus/ethash/algorithm_test.go @@ -709,11 +709,11 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) { block := types.NewBlockWithHeader(&types.Header{ Number: big.NewInt(3311058), ParentHash: common.HexToHash("0xd783efa4d392943503f28438ad5830b2d5964696ffc285f338585e9fe0a37a05"), - UncleHash: common.HexToHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), + UncleHash: types.EmptyUncleHash, Coinbase: common.HexToAddress("0xc0ea08a2d404d3172d2add29a45be56da40e2949"), Root: common.HexToHash("0x77d14e10470b5850332524f8cd6f69ad21f070ce92dca33ab2858300242ef2f1"), - TxHash: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), - ReceiptHash: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, Difficulty: big.NewInt(167925187834220), GasLimit: 4015682, GasUsed: 0, diff --git a/core/bench_test.go b/core/bench_test.go index 7fc8a760f703..494998437c36 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -252,8 +252,8 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) { ParentHash: hash, Difficulty: big.NewInt(1), UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, } hash = header.Hash() diff --git a/core/genesis.go b/core/genesis.go index 8b4e336ed07f..269c1486d31d 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -467,7 +467,7 @@ func (g *Genesis) ToBlock() *types.Block { } var withdrawals []*types.Withdrawal if g.Config != nil && g.Config.IsShanghai(g.Timestamp) { - head.WithdrawalsHash = &types.EmptyRootHash + head.WithdrawalsHash = &types.EmptyWithdrawalsHash withdrawals = make([]*types.Withdrawal, 0) } return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)).WithWithdrawals(withdrawals) diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index f7f8d0b086d7..84eae1d90d25 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -113,8 +113,8 @@ func TestBlockStorage(t *testing.T) { block := types.NewBlockWithHeader(&types.Header{ Extra: []byte("test block"), UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, }) if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil { t.Fatalf("Non existent block returned: %v", entry) @@ -161,8 +161,8 @@ func TestPartialBlockStorage(t *testing.T) { block := types.NewBlockWithHeader(&types.Header{ Extra: []byte("test block"), UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, }) // Store a header and check that it's not recognized as a block WriteHeader(db, block.Header()) @@ -198,8 +198,8 @@ func TestBadBlockStorage(t *testing.T) { Number: big.NewInt(1), Extra: []byte("bad block"), UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, }) if entry := ReadBadBlock(db, block.Hash()); entry != nil { t.Fatalf("Non existent block returned: %v", entry) @@ -216,8 +216,8 @@ func TestBadBlockStorage(t *testing.T) { Number: big.NewInt(2), Extra: []byte("bad block two"), UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, }) WriteBadBlock(db, blockTwo) @@ -235,8 +235,8 @@ func TestBadBlockStorage(t *testing.T) { Number: big.NewInt(int64(n)), Extra: []byte("bad block"), UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, }) WriteBadBlock(db, block) } @@ -446,8 +446,8 @@ func TestAncientStorage(t *testing.T) { Number: big.NewInt(0), Extra: []byte("test block"), UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, }) // Ensure nothing non-existent will be read hash, number := block.Hash(), block.NumberU64() @@ -889,8 +889,8 @@ func TestHeadersRLPStorage(t *testing.T) { Number: big.NewInt(int64(i)), Extra: []byte("test block"), UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, ParentHash: pHash, }) chain = append(chain, block) diff --git a/core/state/iterator.go b/core/state/iterator.go index ba7efd4653b3..29c4abfc217f 100644 --- a/core/state/iterator.go +++ b/core/state/iterator.go @@ -117,7 +117,7 @@ func (it *NodeIterator) step() error { if !it.dataIt.Next(true) { it.dataIt = nil } - if !bytes.Equal(account.CodeHash, emptyCodeHash) { + if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { it.codeHash = common.BytesToHash(account.CodeHash) addrHash := common.BytesToHash(it.stateIt.LeafKey()) it.code, err = it.state.db.ContractCode(addrHash, common.BytesToHash(account.CodeHash)) diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index d1ffc4f9448f..2bd5658e0a45 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" @@ -55,14 +54,6 @@ const ( rangeCompactionThreshold = 100000 ) -var ( - // emptyRoot is the known root hash of an empty trie. - emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - - // emptyCode is the known hash of the empty EVM bytecode. - emptyCode = crypto.Keccak256(nil) -) - // Config includes all the configurations for pruning. type Config struct { Datadir string // The directory of the state database @@ -446,7 +437,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil { return err } - if acc.Root != emptyRoot { + if acc.Root != types.EmptyRootHash { id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root) storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db)) if err != nil { @@ -463,7 +454,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { return storageIter.Error() } } - if !bytes.Equal(acc.CodeHash, emptyCode) { + if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) { stateBloom.Put(acc.CodeHash, nil) } } diff --git a/core/state/snapshot/account.go b/core/state/snapshot/account.go index b92e94295014..b5634972ad62 100644 --- a/core/state/snapshot/account.go +++ b/core/state/snapshot/account.go @@ -21,6 +21,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) @@ -41,10 +42,10 @@ func SlimAccount(nonce uint64, balance *big.Int, root common.Hash, codehash []by Nonce: nonce, Balance: balance, } - if root != emptyRoot { + if root != types.EmptyRootHash { slim.Root = root[:] } - if !bytes.Equal(codehash, emptyCode[:]) { + if !bytes.Equal(codehash, types.EmptyCodeHash[:]) { slim.CodeHash = codehash } return slim @@ -68,10 +69,10 @@ func FullAccount(data []byte) (Account, error) { return Account{}, err } if len(account.Root) == 0 { - account.Root = emptyRoot[:] + account.Root = types.EmptyRootHash[:] } if len(account.CodeHash) == 0 { - account.CodeHash = emptyCode[:] + account.CodeHash = types.EmptyCodeHash[:] } return account, nil } diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index ebad28fc7365..ed7cb963ad0f 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" @@ -74,7 +75,7 @@ func GenerateTrie(snaptree *Tree, root common.Hash, src ethdb.Database, dst ethd scheme := snaptree.triedb.Scheme() got, err := generateTrieRoot(dst, scheme, acctIt, common.Hash{}, stackTrieGenerate, func(dst ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { // Migrate the code first, commit the contract code into the tmp db. - if codeHash != emptyCode { + if codeHash != types.EmptyCodeHash { code := rawdb.ReadCode(src, codeHash) if len(code) == 0 { return common.Hash{}, errors.New("failed to read contract code") diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 46f41cdbeedd..d46705d31e3f 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -27,7 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" @@ -35,12 +35,6 @@ import ( ) var ( - // emptyRoot is the known root hash of an empty trie. - emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - - // emptyCode is the known hash of the empty EVM bytecode. - emptyCode = crypto.Keccak256Hash(nil) - // accountCheckRange is the upper limit of the number of accounts involved in // each range check. This is a value estimated based on experience. If this // range is too large, the failure rate of range proof will increase. Otherwise, @@ -591,10 +585,10 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er if accMarker == nil || !bytes.Equal(account[:], accMarker) { dataLen := len(val) // Approximate size, saves us a round of RLP-encoding if !write { - if bytes.Equal(acc.CodeHash, emptyCode[:]) { + if bytes.Equal(acc.CodeHash, types.EmptyCodeHash[:]) { dataLen -= 32 } - if acc.Root == emptyRoot { + if acc.Root == types.EmptyRootHash { dataLen -= 32 } snapRecoveredAccountMeter.Mark(1) @@ -621,7 +615,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er // If the iterated account is the contract, create a further loop to // verify or regenerate the contract storage. - if acc.Root == emptyRoot { + if acc.Root == types.EmptyRootHash { ctx.removeStorageAt(account) } else { var storeMarker []byte diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 1bc3421e99b6..1bac4fd5604c 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" @@ -49,9 +50,9 @@ func TestGeneration(t *testing.T) { var helper = newHelper() stRoot := helper.makeStorageTrie(common.Hash{}, common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false) - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) @@ -83,16 +84,16 @@ func TestGenerateExistentState(t *testing.T) { var helper = newHelper() stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) - helper.addSnapAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addSnapAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) - helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) - helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) root, snap := helper.CommitAndGenerate() @@ -235,28 +236,28 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { helper := newHelper() // Account one, empty root but non-empty database - helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) // Account two, non empty root but empty database stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Miss slots { // Account three, non empty root but misses slots in the beginning helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"}) // Account four, non empty root but misses slots in the middle helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"}) // Account five, non empty root but misses slots in the end helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-5")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-5", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-5", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"}) } @@ -264,22 +265,22 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { { // Account six, non empty root but wrong slots in the beginning helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"}) // Account seven, non empty root but wrong slots in the middle helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-7")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-7", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-7", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"}) // Account eight, non empty root but wrong slots in the end helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-8")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-8", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-8", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"}) // Account 9, non empty root but rotated slots helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-9")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-9", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-9", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"}) } @@ -287,17 +288,17 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) { { // Account 10, non empty root but extra slots in the beginning helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-10")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-10", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-10", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"}) // Account 11, non empty root but extra slots in the middle helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-11")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-11", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-11", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"}) // Account 12, non empty root but extra slots in the end helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-12")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-12", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-12", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"}) } @@ -337,25 +338,25 @@ func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { // Missing accounts, only in the trie { - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // Beginning - helper.addTrieAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // Middle - helper.addTrieAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // End + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Beginning + helper.addTrieAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Middle + helper.addTrieAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // End } // Wrong accounts { - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: common.Hex2Bytes("0x1234")}) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) - helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) } // Extra accounts, only in the snap { - helper.addSnapAccount("acc-0", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyRoot.Bytes()}) // before the beginning - helper.addSnapAccount("acc-5", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: common.Hex2Bytes("0x1234")}) // Middle - helper.addSnapAccount("acc-7", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyRoot.Bytes()}) // after the end + helper.addSnapAccount("acc-0", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // before the beginning + helper.addSnapAccount("acc-5", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: common.Hex2Bytes("0x1234")}) // Middle + helper.addSnapAccount("acc-7", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // after the end } root, snap := helper.CommitAndGenerate() @@ -384,9 +385,9 @@ func TestGenerateCorruptAccountTrie(t *testing.T) { // without any storage slots to keep the test smaller. helper := newHelper() - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4 root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 @@ -419,10 +420,10 @@ func TestGenerateMissingStorageTrie(t *testing.T) { helper := newHelper() stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 root := helper.Commit() @@ -453,10 +454,10 @@ func TestGenerateCorruptStorageTrie(t *testing.T) { helper := newHelper() stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2 root := helper.Commit() @@ -488,7 +489,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) { []string{"val-1", "val-2", "val-3", "val-4", "val-5"}, true, ) - acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()} + acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e @@ -508,7 +509,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) { []string{"val-1", "val-2", "val-3", "val-4", "val-5"}, true, ) - acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()} + acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) key := hashData([]byte("acc-2")) rawdb.WriteAccountSnapshot(helper.diskdb, key, val) @@ -559,7 +560,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) { []string{"val-1", "val-2", "val-3"}, true, ) - acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()} + acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e @@ -573,8 +574,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) { { // 100 accounts exist only in snapshot for i := 0; i < 1000; i++ { - //acc := &Account{Balance: big.NewInt(int64(i)), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()} - acc := &Account{Balance: big.NewInt(int64(i)), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} + acc := &Account{Balance: big.NewInt(int64(i)), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) key := hashData([]byte(fmt.Sprintf("acc-%d", i))) rawdb.WriteAccountSnapshot(helper.diskdb, key, val) @@ -611,7 +611,7 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) { } helper := newHelper() { - acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} + acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val) helper.accTrie.Update(common.HexToHash("0x07").Bytes(), val) @@ -648,7 +648,7 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) { } helper := newHelper() { - acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()} + acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val) @@ -687,7 +687,7 @@ func TestGenerateFromEmptySnap(t *testing.T) { for i := 0; i < 400; i++ { stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte(fmt.Sprintf("acc-%d", i))), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount(fmt.Sprintf("acc-%d", i), - &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) } root, snap := helper.CommitAndGenerate() t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4 @@ -724,7 +724,7 @@ func TestGenerateWithIncompleteStorage(t *testing.T) { for i := 0; i < 8; i++ { accKey := fmt.Sprintf("acc-%d", i) stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte(accKey)), stKeys, stVals, true) - helper.addAccount(accKey, &Account{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount(accKey, &Account{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) var moddedKeys []string var moddedVals []string for ii := 0; ii < 8; ii++ { @@ -816,11 +816,11 @@ func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { var helper = newHelper() stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) - helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}) @@ -851,11 +851,11 @@ func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) { var helper = newHelper() stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) - helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) + helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) + helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) - helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) + helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) populateDangling(helper.diskdb) diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index 82833873cb1c..6893f6001e33 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -28,6 +28,7 @@ import ( "github.com/VictoriaMetrics/fastcache" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) @@ -47,7 +48,7 @@ func randomAccount() []byte { Balance: big.NewInt(rand.Int63()), Nonce: rand.Uint64(), Root: root[:], - CodeHash: emptyCode[:], + CodeHash: types.EmptyCodeHash[:], } data, _ := rlp.EncodeToBytes(a) return data diff --git a/core/state/state_object.go b/core/state/state_object.go index 1550926d3a62..5dfd3c1b648a 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -31,8 +31,6 @@ import ( "github.com/ethereum/go-ethereum/trie" ) -var emptyCodeHash = crypto.Keccak256(nil) - type Code []byte func (c Code) String() string { @@ -95,7 +93,7 @@ type stateObject struct { // empty returns whether the account is considered empty. func (s *stateObject) empty() bool { - return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash) + return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, types.EmptyCodeHash.Bytes()) } // newObject creates a state object. @@ -104,10 +102,10 @@ func newObject(db *StateDB, address common.Address, data types.StateAccount) *st data.Balance = new(big.Int) } if data.CodeHash == nil { - data.CodeHash = emptyCodeHash + data.CodeHash = types.EmptyCodeHash.Bytes() } if data.Root == (common.Hash{}) { - data.Root = emptyRoot + data.Root = types.EmptyRootHash } return &stateObject{ db: db, @@ -154,7 +152,7 @@ func (s *stateObject) getTrie(db Database) (Trie, error) { if s.trie == nil { // Try fetching from prefetcher first // We don't prefetch empty tries - if s.data.Root != emptyRoot && s.db.prefetcher != nil { + if s.data.Root != types.EmptyRootHash && s.db.prefetcher != nil { // When the miner is creating the pending state, there is no // prefetcher s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root) @@ -270,7 +268,7 @@ func (s *stateObject) finalise(prefetch bool) { slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure } } - if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != emptyRoot { + if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { s.db.prefetcher.prefetch(s.addrHash, s.data.Root, slotsToPrefetch) } if len(s.dirtyStorage) > 0 { @@ -454,7 +452,7 @@ func (s *stateObject) Code(db Database) []byte { if s.code != nil { return s.code } - if bytes.Equal(s.CodeHash(), emptyCodeHash) { + if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return nil } code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash())) @@ -472,7 +470,7 @@ func (s *stateObject) CodeSize(db Database) int { if s.code != nil { return len(s.code) } - if bytes.Equal(s.CodeHash(), emptyCodeHash) { + if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return 0 } size, err := db.ContractCodeSize(s.addrHash, common.BytesToHash(s.CodeHash())) diff --git a/core/state/statedb.go b/core/state/statedb.go index 3f4bec2392dc..3d8fd15bbd25 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -41,11 +41,6 @@ type revision struct { journalIndex int } -var ( - // emptyRoot is the known root hash of an empty trie. - emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") -) - type proofList [][]byte func (n *proofList) Put(key []byte, value []byte) error { @@ -580,10 +575,10 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { Root: common.BytesToHash(acc.Root), } if len(data.CodeHash) == 0 { - data.CodeHash = emptyCodeHash + data.CodeHash = types.EmptyCodeHash.Bytes() } if data.Root == (common.Hash{}) { - data.Root = emptyRoot + data.Root = types.EmptyRootHash } } } @@ -1066,11 +1061,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { s.stateObjectsDestruct = make(map[common.Address]struct{}) } if root == (common.Hash{}) { - root = emptyRoot + root = types.EmptyRootHash } origin := s.originalRoot if origin == (common.Hash{}) { - origin = emptyRoot + origin = types.EmptyRootHash } if root != origin { start := time.Now() diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 84b7bf84e02f..aff91268aafd 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -134,8 +134,7 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error { // Tests that an empty state is not scheduled for syncing. func TestEmptyStateSync(t *testing.T) { db := trie.NewDatabase(rawdb.NewMemoryDatabase()) - empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - sync := NewStateSync(empty, rawdb.NewMemoryDatabase(), nil, db.Scheme()) + sync := NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, db.Scheme()) if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes) } @@ -555,7 +554,7 @@ func TestIncompleteStateSync(t *testing.T) { isCode[crypto.Keccak256Hash(acc.code)] = struct{}{} } } - isCode[common.BytesToHash(emptyCodeHash)] = struct{}{} + isCode[types.EmptyCodeHash] = struct{}{} checkTrieConsistency(db, srcRoot) // Create a destination state and sync with the scheduler diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 821b85e9bcd5..59391fa86199 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -404,7 +404,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr header.BaseFee = misc.CalcBaseFee(config, parent.Header()) } if config.IsShanghai(header.Time) { - header.WithdrawalsHash = &types.EmptyRootHash + header.WithdrawalsHash = &types.EmptyWithdrawalsHash } var receipts []*types.Receipt // The post-state result doesn't need to be correct (this is a bad block), but we do need something there diff --git a/core/types/block.go b/core/types/block.go index ac8c031acf18..82ad3ce99cb7 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -31,11 +31,6 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -var ( - EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - EmptyUncleHash = rlpHash([]*Header(nil)) -) - // A BlockNonce is a 64-bit hash which proves (combined with the // mix-hash) that a sufficient amount of computation has been carried // out on a block. @@ -155,14 +150,14 @@ func (h *Header) SanityCheck() error { // that is: no transactions, no uncles and no withdrawals. func (h *Header) EmptyBody() bool { if h.WithdrawalsHash == nil { - return h.TxHash == EmptyRootHash && h.UncleHash == EmptyUncleHash + return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash } - return h.TxHash == EmptyRootHash && h.UncleHash == EmptyUncleHash && *h.WithdrawalsHash == EmptyRootHash + return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash && *h.WithdrawalsHash == EmptyWithdrawalsHash } // EmptyReceipts returns true if there are no receipts for this header/block. func (h *Header) EmptyReceipts() bool { - return h.ReceiptHash == EmptyRootHash + return h.ReceiptHash == EmptyReceiptsHash } // Body is a simple (mutable, non-safe) data container for storing and moving @@ -210,7 +205,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* // TODO: panic if len(txs) != len(receipts) if len(txs) == 0 { - b.header.TxHash = EmptyRootHash + b.header.TxHash = EmptyTxsHash } else { b.header.TxHash = DeriveSha(Transactions(txs), hasher) b.transactions = make(Transactions, len(txs)) @@ -218,7 +213,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* } if len(receipts) == 0 { - b.header.ReceiptHash = EmptyRootHash + b.header.ReceiptHash = EmptyReceiptsHash } else { b.header.ReceiptHash = DeriveSha(Receipts(receipts), hasher) b.header.Bloom = CreateBloom(receipts) @@ -250,7 +245,7 @@ func NewBlockWithWithdrawals(header *Header, txs []*Transaction, uncles []*Heade if withdrawals == nil { b.header.WithdrawalsHash = nil } else if len(withdrawals) == 0 { - b.header.WithdrawalsHash = &EmptyRootHash + b.header.WithdrawalsHash = &EmptyWithdrawalsHash } else { h := DeriveSha(Withdrawals(withdrawals), hasher) b.header.WithdrawalsHash = &h diff --git a/core/types/hashes.go b/core/types/hashes.go new file mode 100644 index 000000000000..3bad430be571 --- /dev/null +++ b/core/types/hashes.go @@ -0,0 +1,42 @@ +// Copyright 2023 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 types + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + // EmptyRootHash is the known root hash of an empty trie. + EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + + // EmptyUncleHash is the known hash of the empty uncle set. + EmptyUncleHash = rlpHash([]*Header(nil)) // 1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 + + // EmptyCodeHash is the known hash of the empty EVM bytecode. + EmptyCodeHash = crypto.Keccak256Hash(nil) // c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 + + // EmptyTxsHash is the known hash of the empty transaction set. + EmptyTxsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + + // EmptyReceiptsHash is the known hash of the empty receipt set. + EmptyReceiptsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + + // EmptyWithdrawalsHash is the known hash of the empty withdrawal set. + EmptyWithdrawalsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") +) diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index 50081d2e542c..35608031d979 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -599,7 +599,7 @@ func (f *BlockFetcher) loop() { announce.time = task.time // If the block is empty (header only), short circuit into the final import queue - if header.TxHash == types.EmptyRootHash && header.UncleHash == types.EmptyUncleHash { + if header.TxHash == types.EmptyTxsHash && header.UncleHash == types.EmptyUncleHash { log.Trace("Block empty, skipping body retrieval", "peer", announce.origin, "number", header.Number, "hash", header.Hash()) block := types.NewBlockWithHeader(header) diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 6941d522aa2e..d7c940044010 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -464,7 +465,7 @@ func ServiceGetByteCodesQuery(chain *core.BlockChain, req *GetByteCodesPacket) [ bytes uint64 ) for _, hash := range req.Hashes { - if hash == emptyCode { + if hash == types.EmptyCodeHash { // Peers should not request the empty code, but if they do, at // least sent them back a correct response without db lookups codes = append(codes, []byte{}) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 052d8eaca72f..13279fd96c43 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -46,14 +46,6 @@ import ( "golang.org/x/crypto/sha3" ) -var ( - // emptyRoot is the known root hash of an empty trie. - emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - - // emptyCode is the known hash of the empty EVM bytecode. - emptyCode = crypto.Keccak256Hash(nil) -) - const ( // minRequestSize is the minimum number of bytes to request from a remote peer. // This number is used as the low cap for account and storage range requests. @@ -1833,7 +1825,7 @@ func (s *Syncer) processAccountResponse(res *accountResponse) { res.task.pend = 0 for i, account := range res.accounts { // Check if the account is a contract with an unknown code - if !bytes.Equal(account.CodeHash, emptyCode[:]) { + if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { if !rawdb.HasCodeWithPrefix(s.db, common.BytesToHash(account.CodeHash)) { res.task.codeTasks[common.BytesToHash(account.CodeHash)] = struct{}{} res.task.needCode[i] = true @@ -1841,7 +1833,7 @@ func (s *Syncer) processAccountResponse(res *accountResponse) { } } // Check if the account is a contract with an unknown storage trie - if account.Root != emptyRoot { + if account.Root != types.EmptyRootHash { if !rawdb.HasTrieNode(s.db, res.hashes[i], nil, account.Root, s.scheme) { // If there was a previous large state retrieval in progress, // don't restart it from scratch. This happens if a sync cycle diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 971605d8c29d..0a6117972953 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1354,7 +1354,7 @@ func getCodeHash(i uint64) []byte { // getCodeByHash convenience function to lookup the code from the code hash func getCodeByHash(hash common.Hash) []byte { - if hash == emptyCode { + if hash == types.EmptyCodeHash { return nil } for i, h := range codehashes { @@ -1376,7 +1376,7 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) { value, _ := rlp.EncodeToBytes(&types.StateAccount{ Nonce: i, Balance: big.NewInt(int64(i)), - Root: emptyRoot, + Root: types.EmptyRootHash, CodeHash: getCodeHash(i), }) key := key32(i) @@ -1427,7 +1427,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { value, _ := rlp.EncodeToBytes(&types.StateAccount{ Nonce: uint64(0), Balance: big.NewInt(int64(i)), - Root: emptyRoot, + Root: types.EmptyRootHash, CodeHash: getCodeHash(uint64(i)), }) elem := &kv{boundaries[i].Bytes(), value} @@ -1439,7 +1439,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { value, _ := rlp.EncodeToBytes(&types.StateAccount{ Nonce: i, Balance: big.NewInt(int64(i)), - Root: emptyRoot, + Root: types.EmptyRootHash, CodeHash: getCodeHash(i), }) elem := &kv{key32(i), value} @@ -1472,7 +1472,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) // Create n accounts in the trie for i := uint64(1); i <= uint64(accounts); i++ { key := key32(i) - codehash := emptyCode[:] + codehash := types.EmptyCodeHash.Bytes() if code { codehash = getCodeHash(i) } @@ -1527,7 +1527,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin // Create n accounts in the trie for i := uint64(1); i <= uint64(accounts); i++ { key := key32(i) - codehash := emptyCode[:] + codehash := types.EmptyCodeHash.Bytes() if code { codehash = getCodeHash(i) } @@ -1678,7 +1678,7 @@ func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { log.Crit("Invalid account encountered during snapshot creation", "err", err) } accounts++ - if acc.Root != emptyRoot { + if acc.Root != types.EmptyRootHash { id := trie.StorageTrieID(root, common.BytesToHash(accIt.Key), acc.Root) storeTrie, err := trie.NewStateTrie(id, triedb) if err != nil { diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 1d2df5466ede..460035f36a6d 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -131,10 +131,10 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 { return nil, fmt.Errorf("server returned empty uncle list but block header indicates uncles") } - if head.TxHash == types.EmptyRootHash && len(body.Transactions) > 0 { + if head.TxHash == types.EmptyTxsHash && len(body.Transactions) > 0 { return nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions") } - if head.TxHash != types.EmptyRootHash && len(body.Transactions) == 0 { + if head.TxHash != types.EmptyTxsHash && len(body.Transactions) == 0 { return nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions") } // Load uncles because they are not included in the block response. diff --git a/les/fetcher/block_fetcher.go b/les/fetcher/block_fetcher.go index c76f20ced313..085ecb2d665b 100644 --- a/les/fetcher/block_fetcher.go +++ b/les/fetcher/block_fetcher.go @@ -548,7 +548,7 @@ func (f *BlockFetcher) loop() { announce.time = task.time // If the block is empty (header only), short circuit into the final import queue - if header.TxHash == types.EmptyRootHash && header.UncleHash == types.EmptyUncleHash { + if header.TxHash == types.EmptyTxsHash && header.UncleHash == types.EmptyUncleHash { log.Trace("Block empty, skipping body retrieval", "peer", announce.origin, "number", header.Number, "hash", header.Hash()) block := types.NewBlockWithHeader(header) diff --git a/les/server_requests.go b/les/server_requests.go index 3563bf93c63a..033b11d79370 100644 --- a/les/server_requests.go +++ b/les/server_requests.go @@ -348,7 +348,7 @@ func handleGetReceipts(msg Decoder) (serveRequestFn, uint64, uint64, error) { // Retrieve the requested block's receipts, skipping if unknown to us results := bc.GetReceiptsByHash(hash) if results == nil { - if header := bc.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { + if header := bc.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyReceiptsHash { p.bumpInvalid() continue } diff --git a/light/lightchain_test.go b/light/lightchain_test.go index 8600e56345f6..d19713dc2f8d 100644 --- a/light/lightchain_test.go +++ b/light/lightchain_test.go @@ -253,8 +253,8 @@ func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types. Number: big.NewInt(int64(i + 1)), Difficulty: big.NewInt(int64(difficulty)), UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, + TxHash: types.EmptyTxsHash, + ReceiptHash: types.EmptyReceiptsHash, } if i == 0 { header.ParentHash = genesis.Hash() diff --git a/trie/database.go b/trie/database.go index 74247d59c4f8..895ffdf89d88 100644 --- a/trie/database.go +++ b/trie/database.go @@ -808,7 +808,7 @@ func (db *Database) Update(nodes *MergedNodeSet) error { if err := rlp.DecodeBytes(n.blob, &account); err != nil { return err } - if account.Root != emptyRoot { + if account.Root != types.EmptyRootHash { db.reference(account.Root, n.parent) } } diff --git a/trie/iterator.go b/trie/iterator.go index aa621cd54a22..f42beec4abe8 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -22,6 +22,7 @@ import ( "errors" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" ) // NodeResolver is used for looking up trie nodes before reaching into the real @@ -160,7 +161,7 @@ func (e seekError) Error() string { } func newNodeIterator(trie *Trie, start []byte) NodeIterator { - if trie.Hash() == emptyRoot { + if trie.Hash() == types.EmptyRootHash { return &nodeIterator{ trie: trie, err: errIteratorEnd, @@ -302,7 +303,7 @@ func (it *nodeIterator) seek(prefix []byte) error { func (it *nodeIterator) init() (*nodeIteratorState, error) { root := it.trie.Hash() state := &nodeIteratorState{node: it.trie.root, index: -1} - if root != emptyRoot { + if root != types.EmptyRootHash { state.hash = root } return state, state.resolve(it, nil) diff --git a/trie/stacktrie.go b/trie/stacktrie.go index fb8cc0d763e6..e7b3171af6e8 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -25,6 +25,7 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" ) @@ -407,7 +408,7 @@ func (st *StackTrie) hashRec(hasher *hasher, path []byte) { return case emptyNode: - st.val = emptyRoot.Bytes() + st.val = types.EmptyRootHash.Bytes() st.key = st.key[:0] st.nodeType = hashedNode return diff --git a/trie/sync.go b/trie/sync.go index 4bf735c02f2f..4f5584599179 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) @@ -184,7 +185,7 @@ func NewSync(root common.Hash, database ethdb.KeyValueReader, callback LeafCallb // hex format and contain all the parent path if it's layered trie node. func (s *Sync) AddSubTrie(root common.Hash, path []byte, parent common.Hash, parentPath []byte, callback LeafCallback) { // Short circuit if the trie is empty or already known - if root == emptyRoot { + if root == types.EmptyRootHash { return } if s.membatch.hasNode(path) { @@ -217,7 +218,7 @@ func (s *Sync) AddSubTrie(root common.Hash, path []byte, parent common.Hash, par // as is. func (s *Sync) AddCodeEntry(hash common.Hash, path []byte, parent common.Hash, parentPath []byte) { // Short circuit if the entry is empty or already known - if hash == emptyState { + if hash == types.EmptyCodeHash { return } if s.membatch.hasCode(hash) { diff --git a/trie/sync_test.go b/trie/sync_test.go index 709f22949f1b..fc871a22c80a 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb/memorydb" ) @@ -104,7 +105,7 @@ func TestEmptySync(t *testing.T) { dbA := NewDatabase(rawdb.NewMemoryDatabase()) dbB := NewDatabase(rawdb.NewMemoryDatabase()) emptyA, _ := New(TrieID(common.Hash{}), dbA) - emptyB, _ := New(TrieID(emptyRoot), dbB) + emptyB, _ := New(TrieID(types.EmptyRootHash), dbB) for i, trie := range []*Trie{emptyA, emptyB} { sync := NewSync(trie.Hash(), memorydb.New(), nil, []*Database{dbA, dbB}[i].Scheme()) diff --git a/trie/trie.go b/trie/trie.go index c467ac476622..cf9108f1077b 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -23,18 +23,10 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" ) -var ( - // emptyRoot is the known root hash of an empty trie. - emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - - // emptyState is the known hash of an empty state trie entry. - emptyState = crypto.Keccak256Hash(nil) -) - // Trie is a Merkle Patricia Trie. Use New to create a trie that sits on // top of a database. Whenever trie performs a commit operation, the generated // nodes will be gathered and returned in a set. Once the trie is committed, @@ -91,7 +83,7 @@ func New(id *ID, db NodeReader) (*Trie, error) { reader: reader, //tracer: newTracer(), } - if id.Root != (common.Hash{}) && id.Root != emptyRoot { + if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash { rootnode, err := trie.resolveAndTrack(id.Root[:], nil) if err != nil { return nil, err @@ -576,7 +568,7 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { // Wrap tracked deletions as the return set := NewNodeSet(t.owner) t.tracer.markDeletions(set) - return emptyRoot, set + return types.EmptyRootHash, set } // Derive the hash for all dirty nodes first. We hold the assumption // in the following procedure that all nodes are hashed. @@ -599,7 +591,7 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { // hashRoot calculates the root hash of the given trie func (t *Trie) hashRoot() (node, node, error) { if t.root == nil { - return hashNode(emptyRoot.Bytes()), nil, nil + return hashNode(types.EmptyRootHash.Bytes()), nil, nil } // If the number of changes is below 100, we let one thread handle it h := newHasher(t.unhashed >= 100) diff --git a/trie/trie_test.go b/trie/trie_test.go index 2fb97eebbf49..2f56c89cde37 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -47,7 +47,7 @@ func init() { func TestEmptyTrie(t *testing.T) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) res := trie.Hash() - exp := emptyRoot + exp := types.EmptyRootHash if res != exp { t.Errorf("expected %x got %x", exp, res) } @@ -431,7 +431,7 @@ func runRandTest(rt randTest) bool { } case opProve: hash := tr.Hash() - if hash == emptyRoot { + if hash == types.EmptyRootHash { continue } proofDb := rawdb.NewMemoryDatabase() @@ -718,7 +718,7 @@ func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) { for i := 0; i < len(accounts); i++ { var ( nonce = uint64(random.Int63()) - root = emptyRoot + root = types.EmptyRootHash code = crypto.Keccak256(nil) ) // The big.Rand function is not deterministic with regards to 64 vs 32 bit systems, diff --git a/trie/util_test.go b/trie/util_test.go index 01a46553aa68..8d925a16aabb 100644 --- a/trie/util_test.go +++ b/trie/util_test.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" ) // Tests if the trie diffs are tracked correctly. @@ -286,7 +287,7 @@ func TestDeleteAll(t *testing.T) { trie.Delete([]byte(val.k)) } root, set = trie.Commit(false) - if root != emptyRoot { + if root != types.EmptyRootHash { t.Fatalf("Invalid trie root %v", root) } for path, blob := range set.deletes { From 4034c675be4cf95e1c51baec5f1babe809e45a3c Mon Sep 17 00:00:00 2001 From: Yier <90763233+yierx@users.noreply.github.com> Date: Wed, 22 Feb 2023 19:06:43 +0800 Subject: [PATCH 580/715] eth/filters: fix a breaking change and return rpctransaction (#26757) * eth/filters: fix a breaking change and return rpctransaction * eth/filters: fix test cases --------- Co-authored-by: Catror --- eth/filters/api.go | 26 ++++++++-- eth/filters/filter_system_test.go | 79 +++++++++++++++++++++++++++---- 2 files changed, 90 insertions(+), 15 deletions(-) diff --git a/eth/filters/api.go b/eth/filters/api.go index a30eb28befd2..f9ae70eba796 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -39,6 +39,7 @@ type filter struct { typ Type deadline *time.Timer // filter is inactive when deadline triggers hashes []common.Hash + fullTx bool txs []*types.Transaction crit FilterCriteria logs []*types.Log @@ -103,14 +104,14 @@ func (api *FilterAPI) timeoutLoop(timeout time.Duration) { // // It is part of the filter package because this filter can be used through the // `eth_getFilterChanges` polling method that is also used for log filters. -func (api *FilterAPI) NewPendingTransactionFilter() rpc.ID { +func (api *FilterAPI) NewPendingTransactionFilter(fullTx *bool) rpc.ID { var ( pendingTxs = make(chan []*types.Transaction) pendingTxSub = api.events.SubscribePendingTxs(pendingTxs) ) api.filtersMu.Lock() - api.filters[pendingTxSub.ID] = &filter{typ: PendingTransactionsSubscription, deadline: time.NewTimer(api.timeout), txs: make([]*types.Transaction, 0), s: pendingTxSub} + api.filters[pendingTxSub.ID] = &filter{typ: PendingTransactionsSubscription, fullTx: fullTx != nil && *fullTx, deadline: time.NewTimer(api.timeout), txs: make([]*types.Transaction, 0), s: pendingTxSub} api.filtersMu.Unlock() go func() { @@ -412,6 +413,9 @@ func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { api.filtersMu.Lock() defer api.filtersMu.Unlock() + chainConfig := api.sys.backend.ChainConfig() + latest := api.sys.backend.CurrentHeader() + if f, found := api.filters[id]; found { if !f.deadline.Stop() { // timer expired but filter is not yet removed in timeout loop @@ -426,9 +430,21 @@ func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { f.hashes = nil return returnHashes(hashes), nil case PendingTransactionsSubscription: - txs := f.txs - f.txs = nil - return txs, nil + if f.fullTx { + txs := make([]*ethapi.RPCTransaction, 0, len(f.txs)) + for _, tx := range f.txs { + txs = append(txs, ethapi.NewRPCPendingTransaction(tx, latest, chainConfig)) + } + f.txs = nil + return txs, nil + } else { + hashes := make([]common.Hash, 0, len(f.txs)) + for _, tx := range f.txs { + hashes = append(hashes, tx.Hash()) + } + f.txs = nil + return hashes, nil + } case LogsSubscription, MinedAndPendingLogsSubscription: logs := f.logs f.logs = nil diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 974483b68fd4..b70b0158ad00 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -52,11 +53,12 @@ type testBackend struct { } func (b *testBackend) ChainConfig() *params.ChainConfig { - panic("implement me") + return params.TestChainConfig } func (b *testBackend) CurrentHeader() *types.Header { - panic("implement me") + hdr, _ := b.HeaderByNumber(context.TODO(), rpc.LatestBlockNumber) + return hdr } func (b *testBackend) ChainDb() ethdb.Database { @@ -256,10 +258,10 @@ func TestPendingTxFilter(t *testing.T) { types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), } - txs []*types.Transaction + hashes []common.Hash ) - fid0 := api.NewPendingTransactionFilter() + fid0 := api.NewPendingTransactionFilter(nil) time.Sleep(1 * time.Second) backend.txFeed.Send(core.NewTxsEvent{Txs: transactions}) @@ -271,7 +273,64 @@ func TestPendingTxFilter(t *testing.T) { t.Fatalf("Unable to retrieve logs: %v", err) } - tx := results.([]*types.Transaction) + h := results.([]common.Hash) + hashes = append(hashes, h...) + if len(hashes) >= len(transactions) { + break + } + // check timeout + if time.Now().After(timeout) { + break + } + + time.Sleep(100 * time.Millisecond) + } + + if len(hashes) != len(transactions) { + t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(hashes)) + return + } + for i := range hashes { + if hashes[i] != transactions[i].Hash() { + t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), hashes[i]) + } + } +} + +// TestPendingTxFilterFullTx tests whether pending tx filters retrieve all pending transactions that are posted to the event mux. +func TestPendingTxFilterFullTx(t *testing.T) { + t.Parallel() + + var ( + db = rawdb.NewMemoryDatabase() + backend, sys = newTestFilterSystem(t, db, Config{}) + api = NewFilterAPI(sys, false) + + transactions = []*types.Transaction{ + types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), + types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), + types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), + types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), + types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), + } + + txs []*ethapi.RPCTransaction + ) + + fullTx := true + fid0 := api.NewPendingTransactionFilter(&fullTx) + + time.Sleep(1 * time.Second) + backend.txFeed.Send(core.NewTxsEvent{Txs: transactions}) + + timeout := time.Now().Add(1 * time.Second) + for { + results, err := api.GetFilterChanges(fid0) + if err != nil { + t.Fatalf("Unable to retrieve logs: %v", err) + } + + tx := results.([]*ethapi.RPCTransaction) txs = append(txs, tx...) if len(txs) >= len(transactions) { break @@ -289,8 +348,8 @@ func TestPendingTxFilter(t *testing.T) { return } for i := range txs { - if txs[i].Hash() != transactions[i].Hash() { - t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), txs[i].Hash()) + if txs[i].Hash != transactions[i].Hash() { + t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), txs[i].Hash) } } } @@ -854,15 +913,15 @@ func TestPendingTxFilterDeadlock(t *testing.T) { // timeout either in 100ms or 200ms fids := make([]rpc.ID, 20) for i := 0; i < len(fids); i++ { - fid := api.NewPendingTransactionFilter() + fid := api.NewPendingTransactionFilter(nil) fids[i] = fid // Wait for at least one tx to arrive in filter for { - txs, err := api.GetFilterChanges(fid) + hashes, err := api.GetFilterChanges(fid) if err != nil { t.Fatalf("Filter should exist: %v\n", err) } - if len(txs.([]*types.Transaction)) > 0 { + if len(hashes.([]common.Hash)) > 0 { break } runtime.Gosched() From f86f04864603d4d1398e134fae319531453b67e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 22 Feb 2023 13:55:09 +0200 Subject: [PATCH 581/715] common/math: allow HexOrDecimal to accept unquoted decimals too (#26758) --- common/math/big.go | 11 +++++++++++ common/math/integer.go | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/common/math/big.go b/common/math/big.go index 48427810e1ce..1c2afa749abd 100644 --- a/common/math/big.go +++ b/common/math/big.go @@ -49,6 +49,17 @@ func NewHexOrDecimal256(x int64) *HexOrDecimal256 { return &h } +// UnmarshalJSON implements json.Unmarshaler. +// +// It is similar to UnmarshalText, but allows parsing real decimals too, not just +// quoted decimal strings. +func (i *HexOrDecimal256) UnmarshalJSON(input []byte) error { + if len(input) > 0 && input[0] == '"' { + input = input[1 : len(input)-1] + } + return i.UnmarshalText(input) +} + // UnmarshalText implements encoding.TextUnmarshaler. func (i *HexOrDecimal256) UnmarshalText(input []byte) error { bigint, ok := ParseBig256(string(input)) diff --git a/common/math/integer.go b/common/math/integer.go index 50d3eba1f579..da01c0a08e00 100644 --- a/common/math/integer.go +++ b/common/math/integer.go @@ -41,6 +41,17 @@ const ( // HexOrDecimal64 marshals uint64 as hex or decimal. type HexOrDecimal64 uint64 +// UnmarshalJSON implements json.Unmarshaler. +// +// It is similar to UnmarshalText, but allows parsing real decimals too, not just +// quoted decimal strings. +func (i *HexOrDecimal64) UnmarshalJSON(input []byte) error { + if len(input) > 0 && input[0] == '"' { + input = input[1 : len(input)-1] + } + return i.UnmarshalText(input) +} + // UnmarshalText implements encoding.TextUnmarshaler. func (i *HexOrDecimal64) UnmarshalText(input []byte) error { int, ok := ParseUint64(string(input)) From 73b01f40ceb6bcb6f9f44c2a3d6f963b40452b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 22 Feb 2023 14:23:51 +0200 Subject: [PATCH 582/715] params: release Geth v1.11.2 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 9be8a26a5dd7..8bbf0b99be53 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 2 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 2 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From f6a7cc68d539731bcd04fc26ce68309a1e1f8673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 22 Feb 2023 14:25:19 +0200 Subject: [PATCH 583/715] params: begin v.1.11.3 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 8bbf0b99be53..27a2df12aef2 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 2 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 3 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From a36c68f12cdc45f52184b563dab475f340e00dd7 Mon Sep 17 00:00:00 2001 From: Nate Armstrong Date: Wed, 22 Feb 2023 04:39:41 -0800 Subject: [PATCH 584/715] log: improve documentation (#26753) Add usage examples --- log/logger.go | 48 +++++++++++++++++++++++++++++++++++++++++++++++- log/root.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/log/logger.go b/log/logger.go index 1549e3285481..4e471a22da9a 100644 --- a/log/logger.go +++ b/log/logger.go @@ -116,12 +116,58 @@ type Logger interface { // SetHandler updates the logger to write records to the specified handler. SetHandler(h Handler) - // Log a message at the given level with context key/value pairs + // Log a message at the trace level with context key/value pairs + // + // # Usage + // + // log.Trace("msg") + // log.Trace("msg", "key1", val1) + // log.Trace("msg", "key1", val1, "key2", val2) Trace(msg string, ctx ...interface{}) + + // Log a message at the debug level with context key/value pairs + // + // # Usage Examples + // + // log.Debug("msg") + // log.Debug("msg", "key1", val1) + // log.Debug("msg", "key1", val1, "key2", val2) Debug(msg string, ctx ...interface{}) + + // Log a message at the info level with context key/value pairs + // + // # Usage Examples + // + // log.Info("msg") + // log.Info("msg", "key1", val1) + // log.Info("msg", "key1", val1, "key2", val2) Info(msg string, ctx ...interface{}) + + // Log a message at the warn level with context key/value pairs + // + // # Usage Examples + // + // log.Warn("msg") + // log.Warn("msg", "key1", val1) + // log.Warn("msg", "key1", val1, "key2", val2) Warn(msg string, ctx ...interface{}) + + // Log a message at the error level with context key/value pairs + // + // # Usage Examples + // + // log.Error("msg") + // log.Error("msg", "key1", val1) + // log.Error("msg", "key1", val1, "key2", val2) Error(msg string, ctx ...interface{}) + + // Log a message at the crit level with context key/value pairs, and then exit. + // + // # Usage Examples + // + // log.Crit("msg") + // log.Crit("msg", "key1", val1) + // log.Crit("msg", "key1", val1, "key2", val2) Crit(msg string, ctx ...interface{}) } diff --git a/log/root.go b/log/root.go index 9fb4c5ae0b1c..5a41723c3eeb 100644 --- a/log/root.go +++ b/log/root.go @@ -30,31 +30,79 @@ func Root() Logger { // runtime.Caller(2) always refers to the call site in client code. // Trace is a convenient alias for Root().Trace +// +// Log a message at the trace level with context key/value pairs +// +// # Usage +// +// log.Trace("msg") +// log.Trace("msg", "key1", val1) +// log.Trace("msg", "key1", val1, "key2", val2) func Trace(msg string, ctx ...interface{}) { root.write(msg, LvlTrace, ctx, skipLevel) } // Debug is a convenient alias for Root().Debug +// +// Log a message at the debug level with context key/value pairs +// +// # Usage Examples +// +// log.Debug("msg") +// log.Debug("msg", "key1", val1) +// log.Debug("msg", "key1", val1, "key2", val2) func Debug(msg string, ctx ...interface{}) { root.write(msg, LvlDebug, ctx, skipLevel) } // Info is a convenient alias for Root().Info +// +// Log a message at the info level with context key/value pairs +// +// # Usage Examples +// +// log.Info("msg") +// log.Info("msg", "key1", val1) +// log.Info("msg", "key1", val1, "key2", val2) func Info(msg string, ctx ...interface{}) { root.write(msg, LvlInfo, ctx, skipLevel) } // Warn is a convenient alias for Root().Warn +// +// Log a message at the warn level with context key/value pairs +// +// # Usage Examples +// +// log.Warn("msg") +// log.Warn("msg", "key1", val1) +// log.Warn("msg", "key1", val1, "key2", val2) func Warn(msg string, ctx ...interface{}) { root.write(msg, LvlWarn, ctx, skipLevel) } // Error is a convenient alias for Root().Error +// +// Log a message at the error level with context key/value pairs +// +// # Usage Examples +// +// log.Error("msg") +// log.Error("msg", "key1", val1) +// log.Error("msg", "key1", val1, "key2", val2) func Error(msg string, ctx ...interface{}) { root.write(msg, LvlError, ctx, skipLevel) } // Crit is a convenient alias for Root().Crit +// +// Log a message at the crit level with context key/value pairs, and then exit. +// +// # Usage Examples +// +// log.Crit("msg") +// log.Crit("msg", "key1", val1) +// log.Crit("msg", "key1", val1, "key2", val2) func Crit(msg string, ctx ...interface{}) { root.write(msg, LvlCrit, ctx, skipLevel) os.Exit(1) From 09a9ccdbce88053fb8060d0f4fc82b24a88e3c3a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 23 Feb 2023 02:11:50 -0500 Subject: [PATCH 585/715] core/rawdb, node: use standalone flock dependency (#26633) --- core/rawdb/freezer.go | 22 ++++++++++++++-------- go.mod | 2 +- go.sum | 10 ++-------- node/node.go | 32 ++++++++++++++++---------------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 04c326c4f9e4..60e2c56e0ff7 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -30,7 +30,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" - "github.com/prometheus/tsdb/fileutil" + "github.com/gofrs/flock" ) var ( @@ -75,7 +75,7 @@ type Freezer struct { readonly bool tables map[string]*freezerTable // Data tables for storing everything - instanceLock fileutil.Releaser // File-system lock to prevent double opens + instanceLock *flock.Flock // File-system lock to prevent double opens closeOnce sync.Once } @@ -104,11 +104,17 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui return nil, errSymlinkDatadir } } + flockFile := filepath.Join(datadir, "FLOCK") + if err := os.MkdirAll(filepath.Dir(flockFile), 0755); err != nil { + return nil, err + } // Leveldb uses LOCK as the filelock filename. To prevent the // name collision, we use FLOCK as the lock name. - lock, _, err := fileutil.Flock(filepath.Join(datadir, "FLOCK")) - if err != nil { + lock := flock.New(flockFile) + if locked, err := lock.TryLock(); err != nil { return nil, err + } else if !locked { + return nil, errors.New("locking failed") } // Open all the supported data tables freezer := &Freezer{ @@ -124,12 +130,12 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui for _, table := range freezer.tables { table.Close() } - lock.Release() + lock.Unlock() return nil, err } freezer.tables[name] = table } - + var err error if freezer.readonly { // In readonly mode only validate, don't truncate. // validate also sets `freezer.frozen`. @@ -142,7 +148,7 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui for _, table := range freezer.tables { table.Close() } - lock.Release() + lock.Unlock() return nil, err } @@ -165,7 +171,7 @@ func (f *Freezer) Close() error { errs = append(errs, err) } } - if err := f.instanceLock.Release(); err != nil { + if err := f.instanceLock.Unlock(); err != nil { errs = append(errs, err) } }) diff --git a/go.mod b/go.mod index fbac3e4d67ad..d917dad2113a 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 github.com/go-stack/stack v1.8.1 + github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.4 @@ -49,7 +50,6 @@ require ( github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 - github.com/prometheus/tsdb v0.7.1 github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 diff --git a/go.sum b/go.sum index bf28cd2e24e5..18c7e271ecb1 100644 --- a/go.sum +++ b/go.sum @@ -135,7 +135,6 @@ github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6ps github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= @@ -195,11 +194,9 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= @@ -214,6 +211,8 @@ github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= @@ -440,7 +439,6 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -481,7 +479,6 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= @@ -490,8 +487,6 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -683,7 +678,6 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/node/node.go b/node/node.go index 112a771ab090..2f89bc1ad274 100644 --- a/node/node.go +++ b/node/node.go @@ -37,7 +37,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" - "github.com/prometheus/tsdb/fileutil" + "github.com/gofrs/flock" ) // Node is a container on which services can be registered. @@ -46,13 +46,13 @@ type Node struct { config *Config accman *accounts.Manager log log.Logger - keyDir string // key store directory - keyDirTemp bool // If true, key directory will be removed by Stop - dirLock fileutil.Releaser // prevents concurrent use of instance directory - stop chan struct{} // Channel to wait for termination notifications - server *p2p.Server // Currently running P2P networking layer - startStopLock sync.Mutex // Start/Stop are protected by an additional lock - state int // Tracks state of node lifecycle + keyDir string // key store directory + keyDirTemp bool // If true, key directory will be removed by Stop + dirLock *flock.Flock // prevents concurrent use of instance directory + stop chan struct{} // Channel to wait for termination notifications + server *p2p.Server // Currently running P2P networking layer + startStopLock sync.Mutex // Start/Stop are protected by an additional lock + state int // Tracks state of node lifecycle lock sync.Mutex lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle @@ -320,20 +320,20 @@ func (n *Node) openDataDir() error { } // Lock the instance directory to prevent concurrent use by another instance as well as // accidental use of the instance directory as a database. - release, _, err := fileutil.Flock(filepath.Join(instdir, "LOCK")) - if err != nil { - return convertFileLockError(err) + n.dirLock = flock.New(filepath.Join(instdir, "LOCK")) + + if locked, err := n.dirLock.TryLock(); err != nil { + return err + } else if !locked { + return ErrDatadirUsed } - n.dirLock = release return nil } func (n *Node) closeDataDir() { // Release instance directory lock. - if n.dirLock != nil { - if err := n.dirLock.Release(); err != nil { - n.log.Error("Can't release datadir lock", "err", err) - } + if n.dirLock != nil && n.dirLock.Locked() { + n.dirLock.Unlock() n.dirLock = nil } } From b3ae07348894ce52b5c32ad35ae943d23d7f9921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 23 Feb 2023 13:22:41 +0200 Subject: [PATCH 586/715] eth: use the last announced finalized block as the sync ancient limit (#26685) --- eth/catalyst/api.go | 16 +++++++-- eth/catalyst/queue.go | 9 +++-- eth/catalyst/tester.go | 2 +- eth/downloader/beaconsync.go | 16 ++++----- eth/downloader/downloader.go | 59 +++++++++++++++++++------------ eth/downloader/downloader_test.go | 2 +- eth/downloader/skeleton.go | 45 ++++++++++++++++------- eth/downloader/skeleton_test.go | 10 +++--- 8 files changed, 104 insertions(+), 55 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 95eed408f031..2c7494c7de30 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -237,6 +237,10 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl log.Warn("Forkchoice requested unknown head", "hash", update.HeadBlockHash) return engine.STATUS_SYNCING, nil } + // If the finalized hash is known, we can direct the downloader to move + // potentially more data to the freezer from the get go. + finalized := api.remoteBlocks.get(update.FinalizedBlockHash) + // Header advertised via a past newPayload request. Start syncing to it. // Before we do however, make sure any legacy sync in switched off so we // don't accidentally have 2 cycles running. @@ -244,8 +248,16 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl merger.ReachTTD() api.eth.Downloader().Cancel() } - log.Info("Forkchoice requested sync to new head", "number", header.Number, "hash", header.Hash()) - if err := api.eth.Downloader().BeaconSync(api.eth.SyncMode(), header); err != nil { + context := []interface{}{"number", header.Number, "hash", header.Hash()} + if update.FinalizedBlockHash != (common.Hash{}) { + if finalized == nil { + context = append(context, []interface{}{"finalized", "unknown"}...) + } else { + context = append(context, []interface{}{"finalized", finalized.Number}...) + } + } + log.Info("Forkchoice requested sync to new head", context...) + if err := api.eth.Downloader().BeaconSync(api.eth.SyncMode(), header, finalized); err != nil { return engine.STATUS_SYNCING, err } return engine.STATUS_SYNCING, nil diff --git a/eth/catalyst/queue.go b/eth/catalyst/queue.go index b7213dd591aa..e8037aacad83 100644 --- a/eth/catalyst/queue.go +++ b/eth/catalyst/queue.go @@ -31,9 +31,12 @@ import ( const maxTrackedPayloads = 10 // maxTrackedHeaders is the maximum number of executed payloads the execution -// engine tracks before evicting old ones. Ideally we should only ever track the -// latest one; but have a slight wiggle room for non-ideal conditions. -const maxTrackedHeaders = 10 +// engine tracks before evicting old ones. These are tracked outside the chain +// during initial sync to allow ForkchoiceUpdate to reference past blocks via +// hashes only. For the sync target it would be enough to track only the latest +// header, but snap sync also needs the latest finalized height for the ancient +// limit. +const maxTrackedHeaders = 96 // payloadQueueItem represents an id->payload tuple to store until it's retrieved // or evicted. diff --git a/eth/catalyst/tester.go b/eth/catalyst/tester.go index 05511eaf7a2f..c4eafd30d918 100644 --- a/eth/catalyst/tester.go +++ b/eth/catalyst/tester.go @@ -75,7 +75,7 @@ func (tester *FullSyncTester) Start() error { } // Trigger beacon sync with the provided block header as // trusted chain head. - err := tester.api.eth.Downloader().BeaconSync(downloader.FullSync, tester.block.Header()) + err := tester.api.eth.Downloader().BeaconSync(downloader.FullSync, tester.block.Header(), nil) if err != nil { log.Info("Failed to beacon sync", "err", err) } diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 65d9225f8b51..c539474c64dd 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -151,8 +151,8 @@ func (d *Downloader) SetBadBlockCallback(onBadBlock badBlockFn) { // // Internally backfilling and state sync is done the same way, but the header // retrieval and scheduling is replaced. -func (d *Downloader) BeaconSync(mode SyncMode, head *types.Header) error { - return d.beaconSync(mode, head, true) +func (d *Downloader) BeaconSync(mode SyncMode, head *types.Header, final *types.Header) error { + return d.beaconSync(mode, head, final, true) } // BeaconExtend is an optimistic version of BeaconSync, where an attempt is made @@ -162,7 +162,7 @@ func (d *Downloader) BeaconSync(mode SyncMode, head *types.Header) error { // This is useful if a beacon client is feeding us large chunks of payloads to run, // but is not setting the head after each. func (d *Downloader) BeaconExtend(mode SyncMode, head *types.Header) error { - return d.beaconSync(mode, head, false) + return d.beaconSync(mode, head, nil, false) } // beaconSync is the post-merge version of the chain synchronization, where the @@ -171,7 +171,7 @@ func (d *Downloader) BeaconExtend(mode SyncMode, head *types.Header) error { // // Internally backfilling and state sync is done the same way, but the header // retrieval and scheduling is replaced. -func (d *Downloader) beaconSync(mode SyncMode, head *types.Header, force bool) error { +func (d *Downloader) beaconSync(mode SyncMode, head *types.Header, final *types.Header, force bool) error { // When the downloader starts a sync cycle, it needs to be aware of the sync // mode to use (full, snap). To keep the skeleton chain oblivious, inject the // mode into the backfiller directly. @@ -181,7 +181,7 @@ func (d *Downloader) beaconSync(mode SyncMode, head *types.Header, force bool) e d.skeleton.filler.(*beaconBackfiller).setMode(mode) // Signal the skeleton sync to switch to a new head, however it wants - if err := d.skeleton.Sync(head, force); err != nil { + if err := d.skeleton.Sync(head, final, force); err != nil { return err } return nil @@ -207,7 +207,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { number := chainHead.Number.Uint64() // Retrieve the skeleton bounds and ensure they are linked to the local chain - beaconHead, beaconTail, err := d.skeleton.Bounds() + beaconHead, beaconTail, _, err := d.skeleton.Bounds() if err != nil { // This is a programming error. The chain backfiller was called with an // invalid beacon sync state. Ideally we would panic here, but erroring @@ -272,7 +272,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { // until sync errors or is finished. func (d *Downloader) fetchBeaconHeaders(from uint64) error { var head *types.Header - _, tail, err := d.skeleton.Bounds() + _, tail, _, err := d.skeleton.Bounds() if err != nil { return err } @@ -292,7 +292,7 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error { for { // Some beacon headers might have appeared since the last cycle, make // sure we're always syncing to all available ones - head, _, err = d.skeleton.Bounds() + head, _, _, err = d.skeleton.Bounds() if err != nil { return err } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index bb74efe754e7..ec9cce2eb621 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -480,7 +480,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * }(time.Now()) // Look up the sync boundaries: the common ancestor and the target block - var latest, pivot *types.Header + var latest, pivot, final *types.Header if !beaconMode { // In legacy mode, use the master peer to retrieve the headers from latest, pivot, err = d.fetchHead(p) @@ -489,7 +489,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * } } else { // In beacon mode, use the skeleton chain to retrieve the headers from - latest, _, err = d.skeleton.Bounds() + latest, _, final, err = d.skeleton.Bounds() if err != nil { return err } @@ -499,7 +499,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * // Retrieve the pivot header from the skeleton chain segment but // fallback to local chain if it's not found in skeleton space. if pivot = d.skeleton.Header(number); pivot == nil { - _, oldest, _ := d.skeleton.Bounds() // error is already checked + _, oldest, _, _ := d.skeleton.Bounds() // error is already checked if number < oldest.Number.Uint64() { count := int(oldest.Number.Uint64() - number) // it's capped by fsMinFullBlocks headers := d.readHeaderRange(oldest, count) @@ -567,26 +567,41 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * d.committed = 0 } if mode == SnapSync { - // Set the ancient data limitation. - // If we are running snap sync, all block data older than ancientLimit will be - // written to the ancient store. More recent data will be written to the active - // database and will wait for the freezer to migrate. + // Set the ancient data limitation. If we are running snap sync, all block + // data older than ancientLimit will be written to the ancient store. More + // recent data will be written to the active database and will wait for the + // freezer to migrate. // - // If there is a checkpoint available, then calculate the ancientLimit through - // that. Otherwise calculate the ancient limit through the advertised height - // of the remote peer. + // If the network is post-merge, use either the last announced finalized + // block as the ancient limit, or if we haven't yet received one, the head- + // a max fork ancestry limit. One quirky case if we've already passed the + // finalized block, in which case the skeleton.Bounds will return nil and + // we'll revert to head - 90K. That's fine, we're finishing sync anyway. // - // The reason for picking checkpoint first is that a malicious peer can give us - // a fake (very high) height, forcing the ancient limit to also be very high. - // The peer would start to feed us valid blocks until head, resulting in all of - // the blocks might be written into the ancient store. A following mini-reorg - // could cause issues. - if d.checkpoint != 0 && d.checkpoint > fullMaxForkAncestry+1 { - d.ancientLimit = d.checkpoint - } else if height > fullMaxForkAncestry+1 { - d.ancientLimit = height - fullMaxForkAncestry - 1 + // For non-merged networks, if there is a checkpoint available, then calculate + // the ancientLimit through that. Otherwise calculate the ancient limit through + // the advertised height of the remote peer. This most is mostly a fallback for + // legacy networks, but should eventually be droppped. TODO(karalabe). + if beaconMode { + // Beacon sync, use the latest finalized block as the ancient limit + // or a reasonable height if no finalized block is yet announced. + if final != nil { + d.ancientLimit = final.Number.Uint64() + } else if height > fullMaxForkAncestry+1 { + d.ancientLimit = height - fullMaxForkAncestry - 1 + } else { + d.ancientLimit = 0 + } } else { - d.ancientLimit = 0 + // Legacy sync, use any hardcoded checkpoints or the best announcement + // we have from the remote peer. TODO(karalabe): Drop this pathway. + if d.checkpoint != 0 && d.checkpoint > fullMaxForkAncestry+1 { + d.ancientLimit = d.checkpoint + } else if height > fullMaxForkAncestry+1 { + d.ancientLimit = height - fullMaxForkAncestry - 1 + } else { + d.ancientLimit = 0 + } } frozen, _ := d.stateDB.Ancients() // Ignore the error here since light client can also hit here. @@ -1566,7 +1581,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error { // In post-merge, notify the engine API of encountered bad chains if d.badBlock != nil { - head, _, err := d.skeleton.Bounds() + head, _, _, err := d.skeleton.Bounds() if err != nil { log.Error("Failed to retrieve beacon bounds for bad block reporting", "err", err) } else { @@ -1860,7 +1875,7 @@ func (d *Downloader) reportSnapSyncProgress(force bool) { return } // Retrieve the current chain head and calculate the ETA - latest, _, err := d.skeleton.Bounds() + latest, _, _, err := d.skeleton.Bounds() if err != nil { // We're going to cheat for non-merged networks, but that's fine latest = d.pivotHeader diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 2f0c4acf7887..ababb9deb140 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -1478,7 +1478,7 @@ func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) { if c.local > 0 { tester.chain.InsertChain(chain.blocks[1 : c.local+1]) } - if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)-1].Header()); err != nil { + if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)-1].Header(), nil); err != nil { t.Fatalf("Failed to beacon sync chain %v %v", c.name, err) } select { diff --git a/eth/downloader/skeleton.go b/eth/downloader/skeleton.go index 142e9e5e6bcb..12eb5700f8d3 100644 --- a/eth/downloader/skeleton.go +++ b/eth/downloader/skeleton.go @@ -102,6 +102,7 @@ type subchain struct { // suspended skeleton sync without prior knowledge of all prior suspension points. type skeletonProgress struct { Subchains []*subchain // Disjoint subchains downloaded until now + Finalized *uint64 // Last known finalized block number } // headUpdate is a notification that the beacon sync should switch to a new target. @@ -109,6 +110,7 @@ type skeletonProgress struct { // extend it and fail if it's not possible. type headUpdate struct { header *types.Header // Header to update the sync target to + final *types.Header // Finalized header to use as thresholds force bool // Whether to force the update or only extend if possible errc chan error // Channel to signal acceptance of the new head } @@ -321,12 +323,12 @@ func (s *skeleton) Terminate() error { // // This method does not block, rather it just waits until the syncer receives the // fed header. What the syncer does with it is the syncer's problem. -func (s *skeleton) Sync(head *types.Header, force bool) error { +func (s *skeleton) Sync(head *types.Header, final *types.Header, force bool) error { log.Trace("New skeleton head announced", "number", head.Number, "hash", head.Hash(), "force", force) errc := make(chan error) select { - case s.headEvents <- &headUpdate{header: head, force: force, errc: errc}: + case s.headEvents <- &headUpdate{header: head, final: final, force: force, errc: errc}: return <-errc case <-s.terminated: return errTerminated @@ -437,7 +439,7 @@ func (s *skeleton) sync(head *types.Header) (*types.Header, error) { // we don't seamlessly integrate reorgs to keep things simple. If the // network starts doing many mini reorgs, it might be worthwhile handling // a limited depth without an error. - if reorged := s.processNewHead(event.header, event.force); reorged { + if reorged := s.processNewHead(event.header, event.final, event.force); reorged { // If a reorg is needed, and we're forcing the new head, signal // the syncer to tear down and start over. Otherwise, drop the // non-force reorg. @@ -590,7 +592,17 @@ func (s *skeleton) saveSyncStatus(db ethdb.KeyValueWriter) { // accepts and integrates it into the skeleton or requests a reorg. Upon reorg, // the syncer will tear itself down and restart with a fresh head. It is simpler // to reconstruct the sync state than to mutate it and hope for the best. -func (s *skeleton) processNewHead(head *types.Header, force bool) bool { +func (s *skeleton) processNewHead(head *types.Header, final *types.Header, force bool) bool { + // If a new finalized block was announced, update the sync process independent + // of what happens with the sync head below + if final != nil { + if number := final.Number.Uint64(); s.progress.Finalized == nil || *s.progress.Finalized != number { + s.progress.Finalized = new(uint64) + *s.progress.Finalized = final.Number.Uint64() + + s.saveSyncStatus(s.db) + } + } // If the header cannot be inserted without interruption, return an error for // the outer loop to tear down the skeleton sync and restart it number := head.Number.Uint64() @@ -1150,9 +1162,10 @@ func (s *skeleton) cleanStales(filled *types.Header) error { return nil } -// Bounds retrieves the current head and tail tracked by the skeleton syncer. -// This method is used by the backfiller, whose life cycle is controlled by the -// skeleton syncer. +// Bounds retrieves the current head and tail tracked by the skeleton syncer +// and optionally the last known finalized header if any was announced and if +// it is still in the sync range. This method is used by the backfiller, whose +// life cycle is controlled by the skeleton syncer. // // Note, the method will not use the internal state of the skeleton, but will // rather blindly pull stuff from the database. This is fine, because the back- @@ -1160,28 +1173,34 @@ func (s *skeleton) cleanStales(filled *types.Header) error { // There might be new heads appended, but those are atomic from the perspective // of this method. Any head reorg will first tear down the backfiller and only // then make the modification. -func (s *skeleton) Bounds() (head *types.Header, tail *types.Header, err error) { +func (s *skeleton) Bounds() (head *types.Header, tail *types.Header, final *types.Header, err error) { // Read the current sync progress from disk and figure out the current head. // Although there's a lot of error handling here, these are mostly as sanity // checks to avoid crashing if a programming error happens. These should not // happen in live code. status := rawdb.ReadSkeletonSyncStatus(s.db) if len(status) == 0 { - return nil, nil, errors.New("beacon sync not yet started") + return nil, nil, nil, errors.New("beacon sync not yet started") } progress := new(skeletonProgress) if err := json.Unmarshal(status, progress); err != nil { - return nil, nil, err + return nil, nil, nil, err } head = rawdb.ReadSkeletonHeader(s.db, progress.Subchains[0].Head) if head == nil { - return nil, nil, fmt.Errorf("head skeleton header %d is missing", progress.Subchains[0].Head) + return nil, nil, nil, fmt.Errorf("head skeleton header %d is missing", progress.Subchains[0].Head) } tail = rawdb.ReadSkeletonHeader(s.db, progress.Subchains[0].Tail) if tail == nil { - return nil, nil, fmt.Errorf("tail skeleton header %d is missing", progress.Subchains[0].Tail) + return nil, nil, nil, fmt.Errorf("tail skeleton header %d is missing", progress.Subchains[0].Tail) + } + if progress.Finalized != nil && tail.Number.Uint64() <= *progress.Finalized && *progress.Finalized <= head.Number.Uint64() { + final = rawdb.ReadSkeletonHeader(s.db, *progress.Finalized) + if final == nil { + return nil, nil, nil, fmt.Errorf("finalized skeleton header %d is missing", *progress.Finalized) + } } - return head, tail, nil + return head, tail, final, nil } // Header retrieves a specific header tracked by the skeleton syncer. This method diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index 3b8e627cba89..b19494a7b069 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -370,7 +370,7 @@ func TestSkeletonSyncInit(t *testing.T) { skeleton := newSkeleton(db, newPeerSet(), nil, newHookedBackfiller()) skeleton.syncStarting = func() { close(wait) } - skeleton.Sync(tt.head, true) + skeleton.Sync(tt.head, nil, true) <-wait skeleton.Terminate() @@ -484,10 +484,10 @@ func TestSkeletonSyncExtend(t *testing.T) { skeleton := newSkeleton(db, newPeerSet(), nil, newHookedBackfiller()) skeleton.syncStarting = func() { close(wait) } - skeleton.Sync(tt.head, true) + skeleton.Sync(tt.head, nil, true) <-wait - if err := skeleton.Sync(tt.extend, false); err != tt.err { + if err := skeleton.Sync(tt.extend, nil, false); err != tt.err { t.Errorf("test %d: extension failure mismatch: have %v, want %v", i, err, tt.err) } skeleton.Terminate() @@ -859,7 +859,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) { } // Create a skeleton sync and run a cycle skeleton := newSkeleton(db, peerset, drop, filler) - skeleton.Sync(tt.head, true) + skeleton.Sync(tt.head, nil, true) var progress skeletonProgress // Wait a bit (bleah) for the initial sync loop to go to idle. This might @@ -910,7 +910,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) { } // Apply the post-init events if there's any if tt.newHead != nil { - skeleton.Sync(tt.newHead, true) + skeleton.Sync(tt.newHead, nil, true) } if tt.newPeer != nil { if err := peerset.Register(newPeerConnection(tt.newPeer.id, eth.ETH66, tt.newPeer, log.New("id", tt.newPeer.id))); err != nil { From c155c8e179519888fce575b276091923af19ffbe Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 27 Feb 2023 05:36:26 -0500 Subject: [PATCH 587/715] cmd/devp2p: faster crawling + less verbose dns updates (#26697) This improves the speed of DHT crawling by using concurrent requests. It also removes logging of individual DNS updates. --- cmd/devp2p/crawl.go | 77 ++++++++++++++++++++++++------------ cmd/devp2p/discv4cmd.go | 11 ++++-- cmd/devp2p/discv5cmd.go | 2 +- cmd/devp2p/dns_cloudflare.go | 19 +++++++-- cmd/devp2p/dns_route53.go | 5 ++- 5 files changed, 78 insertions(+), 36 deletions(-) diff --git a/cmd/devp2p/crawl.go b/cmd/devp2p/crawl.go index 0d8127684e66..8c9755ac1cd4 100644 --- a/cmd/devp2p/crawl.go +++ b/cmd/devp2p/crawl.go @@ -17,6 +17,8 @@ package main import ( + "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/log" @@ -34,6 +36,7 @@ type crawler struct { // settings revalidateInterval time.Duration + mu sync.RWMutex } const ( @@ -67,7 +70,7 @@ func newCrawler(input nodeSet, disc resolver, iters ...enode.Iterator) *crawler return c } -func (c *crawler) run(timeout time.Duration) nodeSet { +func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet { var ( timeoutTimer = time.NewTimer(timeout) timeoutCh <-chan time.Time @@ -75,35 +78,51 @@ func (c *crawler) run(timeout time.Duration) nodeSet { doneCh = make(chan enode.Iterator, len(c.iters)) liveIters = len(c.iters) ) + if nthreads < 1 { + nthreads = 1 + } defer timeoutTimer.Stop() defer statusTicker.Stop() for _, it := range c.iters { go c.runIterator(doneCh, it) } - var ( - added int - updated int - skipped int - recent int - removed int + added uint64 + updated uint64 + skipped uint64 + recent uint64 + removed uint64 + wg sync.WaitGroup ) + wg.Add(nthreads) + for i := 0; i < nthreads; i++ { + go func() { + defer wg.Done() + for { + select { + case n := <-c.ch: + switch c.updateNode(n) { + case nodeSkipIncompat: + atomic.AddUint64(&skipped, 1) + case nodeSkipRecent: + atomic.AddUint64(&recent, 1) + case nodeRemoved: + atomic.AddUint64(&removed, 1) + case nodeAdded: + atomic.AddUint64(&added, 1) + default: + atomic.AddUint64(&updated, 1) + } + case <-c.closed: + return + } + } + }() + } + loop: for { select { - case n := <-c.ch: - switch c.updateNode(n) { - case nodeSkipIncompat: - skipped++ - case nodeSkipRecent: - recent++ - case nodeRemoved: - removed++ - case nodeAdded: - added++ - default: - updated++ - } case it := <-doneCh: if it == c.inputIter { // Enable timeout when we're done revalidating the input nodes. @@ -119,8 +138,11 @@ loop: break loop case <-statusTicker.C: log.Info("Crawling in progress", - "added", added, "updated", updated, "removed", removed, - "ignored(recent)", recent, "ignored(incompatible)", skipped) + "added", atomic.LoadUint64(&added), + "updated", atomic.LoadUint64(&updated), + "removed", atomic.LoadUint64(&removed), + "ignored(recent)", atomic.LoadUint64(&removed), + "ignored(incompatible)", atomic.LoadUint64(&skipped)) } } @@ -131,6 +153,7 @@ loop: for ; liveIters > 0; liveIters-- { <-doneCh } + wg.Wait() return c.output } @@ -148,7 +171,9 @@ func (c *crawler) runIterator(done chan<- enode.Iterator, it enode.Iterator) { // updateNode updates the info about the given node, and returns a status // about what changed func (c *crawler) updateNode(n *enode.Node) int { + c.mu.RLock() node, ok := c.output[n.ID()] + c.mu.RUnlock() // Skip validation of recently-seen nodes. if ok && time.Since(node.LastCheck) < c.revalidateInterval { @@ -156,10 +181,9 @@ func (c *crawler) updateNode(n *enode.Node) int { } // Request the node record. - nn, err := c.disc.RequestENR(n) - node.LastCheck = truncNow() status := nodeUpdated - if err != nil { + node.LastCheck = truncNow() + if nn, err := c.disc.RequestENR(n); err != nil { if node.Score == 0 { // Node doesn't implement EIP-868. log.Debug("Skipping node", "id", n.ID()) @@ -176,8 +200,9 @@ func (c *crawler) updateNode(n *enode.Node) int { } node.LastResponse = node.LastCheck } - // Store/update node in output set. + c.mu.Lock() + defer c.mu.Unlock() if node.Score <= 0 { log.Debug("Removing node", "id", n.ID()) delete(c.output, n.ID()) diff --git a/cmd/devp2p/discv4cmd.go b/cmd/devp2p/discv4cmd.go index 94e61c36f325..63122634780d 100644 --- a/cmd/devp2p/discv4cmd.go +++ b/cmd/devp2p/discv4cmd.go @@ -78,7 +78,7 @@ var ( Name: "crawl", Usage: "Updates a nodes.json file with random nodes found in the DHT", Action: discv4Crawl, - Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{crawlTimeoutFlag}), + Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{crawlTimeoutFlag, crawlParallelismFlag}), } discv4TestCommand = &cli.Command{ Name: "test", @@ -120,6 +120,11 @@ var ( Usage: "Time limit for the crawl.", Value: 30 * time.Minute, } + crawlParallelismFlag = &cli.IntFlag{ + Name: "parallel", + Usage: "How many parallel discoveries to attempt.", + Value: 16, + } remoteEnodeFlag = &cli.StringFlag{ Name: "remote", Usage: "Enode of the remote node under test", @@ -195,7 +200,7 @@ func discv4ResolveJSON(ctx *cli.Context) error { defer disc.Close() c := newCrawler(inputSet, disc, enode.IterNodes(nodeargs)) c.revalidateInterval = 0 - output := c.run(0) + output := c.run(0, 1) writeNodesJSON(nodesFile, output) return nil } @@ -214,7 +219,7 @@ func discv4Crawl(ctx *cli.Context) error { defer disc.Close() c := newCrawler(inputSet, disc, disc.RandomNodes()) c.revalidateInterval = 10 * time.Minute - output := c.run(ctx.Duration(crawlTimeoutFlag.Name)) + output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name)) writeNodesJSON(nodesFile, output) return nil } diff --git a/cmd/devp2p/discv5cmd.go b/cmd/devp2p/discv5cmd.go index 343e2a0d5d42..832a4bc1f426 100644 --- a/cmd/devp2p/discv5cmd.go +++ b/cmd/devp2p/discv5cmd.go @@ -110,7 +110,7 @@ func discv5Crawl(ctx *cli.Context) error { defer disc.Close() c := newCrawler(inputSet, disc, disc.RandomNodes()) c.revalidateInterval = 10 * time.Minute - output := c.run(ctx.Duration(crawlTimeoutFlag.Name)) + output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name)) writeNodesJSON(nodesFile, output) return nil } diff --git a/cmd/devp2p/dns_cloudflare.go b/cmd/devp2p/dns_cloudflare.go index 92c6faf272ec..bfe92257ee5a 100644 --- a/cmd/devp2p/dns_cloudflare.go +++ b/cmd/devp2p/dns_cloudflare.go @@ -126,11 +126,16 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string) } // Iterate over the new records and inject anything missing. + log.Info("Updating DNS entries") + created := 0 + updated := 0 + skipped := 0 for path, val := range records { old, exists := existing[path] if !exists { // Entry is unknown, push a new one to Cloudflare. - log.Info(fmt.Sprintf("Creating %s = %q", path, val)) + log.Debug(fmt.Sprintf("Creating %s = %q", path, val)) + created++ ttl := rootTTL if path != name { ttl = treeNodeTTLCloudflare // Max TTL permitted by Cloudflare @@ -139,27 +144,33 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string) _, err = c.CreateDNSRecord(context.Background(), c.zoneID, record) } else if old.Content != val { // Entry already exists, only change its content. - log.Info(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val)) + log.Debug(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val)) + updated++ old.Content = val err = c.UpdateDNSRecord(context.Background(), c.zoneID, old.ID, old) } else { + skipped++ log.Debug(fmt.Sprintf("Skipping %s = %q", path, val)) } if err != nil { return fmt.Errorf("failed to publish %s: %v", path, err) } } - + log.Info("Updated DNS entries", "new", created, "updated", updated, "untouched", skipped) // Iterate over the old records and delete anything stale. + deleted := 0 + log.Info("Deleting stale DNS entries") for path, entry := range existing { if _, ok := records[path]; ok { continue } // Stale entry, nuke it. - log.Info(fmt.Sprintf("Deleting %s = %q", path, entry.Content)) + log.Debug(fmt.Sprintf("Deleting %s = %q", path, entry.Content)) + deleted++ if err := c.DeleteDNSRecord(context.Background(), c.zoneID, entry.ID); err != nil { return fmt.Errorf("failed to delete %s: %v", path, err) } } + log.Info("Deleted stale DNS entries", "count", deleted) return nil } diff --git a/cmd/devp2p/dns_route53.go b/cmd/devp2p/dns_route53.go index 4aab0856ff90..81734eb2ad87 100644 --- a/cmd/devp2p/dns_route53.go +++ b/cmd/devp2p/dns_route53.go @@ -329,8 +329,9 @@ func (c *route53Client) collectRecords(name string) (map[string]recordSet, error var req route53.ListResourceRecordSetsInput req.HostedZoneId = &c.zoneID existing := make(map[string]recordSet) + log.Info("Loading existing TXT records", "name", name, "zone", c.zoneID) for page := 0; ; page++ { - log.Info("Loading existing TXT records", "name", name, "zone", c.zoneID, "page", page) + log.Debug("Loading existing TXT records", "name", name, "zone", c.zoneID, "page", page) resp, err := c.api.ListResourceRecordSets(context.TODO(), &req) if err != nil { return existing, err @@ -360,7 +361,7 @@ func (c *route53Client) collectRecords(name string) (map[string]recordSet, error req.StartRecordName = resp.NextRecordName req.StartRecordType = resp.NextRecordType } - + log.Info("Loaded existing TXT records", "name", name, "zone", c.zoneID, "records", len(existing)) return existing, nil } From 2ad150d986dab085965be047c94af6b2952a9e24 Mon Sep 17 00:00:00 2001 From: Chris Ziogas Date: Tue, 28 Feb 2023 12:24:37 +0200 Subject: [PATCH 588/715] eth/tracers: add native flatCallTracer (aka parity style tracer) (#26377) Adds support for a native call tracer with the Parity format, which outputs call frames in a flat array. This tracer accepts the following options: - `convertParityErrors: true` will convert error messages to match those of Parity - `includePrecompiles: true` will report all calls to precompiles. The default matches Parity's behavior where CALL and STATICCALLs to precompiles are excluded Incompatibilities with Parity include: - Parity removes the result object in case of failure. This behavior is maintained with the exception of reverts. Revert output usually contains useful information, i.e. Solidity revert reason. - The `gasUsed` field accounts for intrinsic gas (e.g. 21000 for simple transfers) and refunds unlike Parity - Block rewards are not reported Co-authored-by: Sina Mahmoodi --- eth/tracers/api.go | 28 +- .../internal/tracetest/flat_calltrace_test.go | 213 +++++ .../testdata/call_tracer_flat/big_slow.json | 64 ++ .../callcode_precompiled_fail_hide.json | 74 ++ .../callcode_precompiled_oog.json | 94 ++ .../callcode_precompiled_throw.json | 90 ++ .../testdata/call_tracer_flat/create.json | 67 ++ .../testdata/call_tracer_flat/deep_calls.json | 635 +++++++++++++ .../call_tracer_flat/delegatecall.json | 120 +++ .../delegatecall_parent_value.json | 103 +++ .../testdata/call_tracer_flat/gas.json | 95 ++ .../call_tracer_flat/include_precompiled.json | 832 ++++++++++++++++++ .../inner_create_oog_outer_throw.json | 88 ++ .../call_tracer_flat/inner_instafail.json | 72 ++ .../inner_precompiled_wrong_gas.json | 219 +++++ .../inner_throw_outer_revert.json | 95 ++ .../call_tracer_flat/nested_create.json | 94 ++ .../nested_create2_action_gas.json | 94 ++ .../nested_create_action_gas.json | 90 ++ .../nested_create_inerror.json | 81 ++ .../nested_pointer_issue.json | 189 ++++ .../testdata/call_tracer_flat/oog.json | 68 ++ .../option_convert_parity_errors.json | 71 ++ .../call_tracer_flat/result_output.json | 111 +++ .../testdata/call_tracer_flat/revert.json | 68 ++ .../call_tracer_flat/revert_reason.json | 74 ++ .../call_tracer_flat/selfdestruct.json | 91 ++ .../testdata/call_tracer_flat/simple.json | 97 ++ .../skip_no_balance_error.json | 70 ++ .../staticcall_precompiled.json | 83 ++ .../testdata/call_tracer_flat/suicide.json | 92 ++ .../testdata/call_tracer_flat/throw.json | 70 ++ eth/tracers/native/call.go | 1 + eth/tracers/native/call_flat.go | 379 ++++++++ eth/tracers/native/gen_flatcallaction_json.go | 110 +++ eth/tracers/native/gen_flatcallresult_json.go | 55 ++ eth/tracers/tracers.go | 8 +- 37 files changed, 4870 insertions(+), 15 deletions(-) create mode 100644 eth/tracers/internal/tracetest/flat_calltrace_test.go create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json create mode 100644 eth/tracers/native/call_flat.go create mode 100644 eth/tracers/native/gen_flatcallaction_json.go create mode 100644 eth/tracers/native/gen_flatcallresult_json.go diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 55c56b40c9f1..d4cda67c90d3 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -295,9 +295,10 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed for i, tx := range task.block.Transactions() { msg, _ := tx.AsMessage(signer, task.block.BaseFee()) txctx := &Context{ - BlockHash: task.block.Hash(), - TxIndex: i, - TxHash: tx.Hash(), + BlockHash: task.block.Hash(), + BlockNumber: task.block.Number(), + TxIndex: i, + TxHash: tx.Hash(), } res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) if err != nil { @@ -629,9 +630,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac // Generate the next state snapshot fast without tracing msg, _ := tx.AsMessage(signer, block.BaseFee()) txctx := &Context{ - BlockHash: blockHash, - TxIndex: i, - TxHash: tx.Hash(), + BlockHash: blockHash, + BlockNumber: block.Number(), + TxIndex: i, + TxHash: tx.Hash(), } res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config) if err != nil { @@ -671,9 +673,10 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat for task := range jobs { msg, _ := txs[task.index].AsMessage(signer, block.BaseFee()) txctx := &Context{ - BlockHash: blockHash, - TxIndex: task.index, - TxHash: txs[task.index].Hash(), + BlockHash: blockHash, + BlockNumber: block.Number(), + TxIndex: task.index, + TxHash: txs[task.index].Hash(), } res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config) if err != nil { @@ -874,9 +877,10 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * defer release() txctx := &Context{ - BlockHash: blockHash, - TxIndex: int(index), - TxHash: hash, + BlockHash: blockHash, + BlockNumber: block.Number(), + TxIndex: int(index), + TxHash: hash, } return api.traceTx(ctx, msg, txctx, vmctx, statedb, config) } diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go new file mode 100644 index 000000000000..d8ded7015dbd --- /dev/null +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -0,0 +1,213 @@ +package tracetest + +import ( + "encoding/json" + "fmt" + "math/big" + "os" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/tests" + + // Force-load the native, to trigger registration + "github.com/ethereum/go-ethereum/eth/tracers" +) + +// flatCallTrace is the result of a callTracerParity run. +type flatCallTrace struct { + Action flatCallTraceAction `json:"action"` + BlockHash common.Hash `json:"-"` + BlockNumber uint64 `json:"-"` + Error string `json:"error,omitempty"` + Result flatCallTraceResult `json:"result,omitempty"` + Subtraces int `json:"subtraces"` + TraceAddress []int `json:"traceAddress"` + TransactionHash common.Hash `json:"-"` + TransactionPosition uint64 `json:"-"` + Type string `json:"type"` + Time string `json:"-"` +} + +type flatCallTraceAction struct { + Author common.Address `json:"author,omitempty"` + RewardType string `json:"rewardType,omitempty"` + SelfDestructed common.Address `json:"address,omitempty"` + Balance hexutil.Big `json:"balance,omitempty"` + CallType string `json:"callType,omitempty"` + CreationMethod string `json:"creationMethod,omitempty"` + From common.Address `json:"from,omitempty"` + Gas hexutil.Uint64 `json:"gas,omitempty"` + Init hexutil.Bytes `json:"init,omitempty"` + Input hexutil.Bytes `json:"input,omitempty"` + RefundAddress common.Address `json:"refundAddress,omitempty"` + To common.Address `json:"to,omitempty"` + Value hexutil.Big `json:"value,omitempty"` +} + +type flatCallTraceResult struct { + Address common.Address `json:"address,omitempty"` + Code hexutil.Bytes `json:"code,omitempty"` + GasUsed hexutil.Uint64 `json:"gasUsed,omitempty"` + Output hexutil.Bytes `json:"output,omitempty"` +} + +// flatCallTracerTest defines a single test to check the call tracer against. +type flatCallTracerTest struct { + Genesis core.Genesis `json:"genesis"` + Context callContext `json:"context"` + Input string `json:"input"` + TracerConfig json.RawMessage `json:"tracerConfig"` + Result []flatCallTrace `json:"result"` +} + +func flatCallTracerTestRunner(tracerName string, filename string, dirPath string, t testing.TB) error { + // Call tracer test found, read if from disk + blob, err := os.ReadFile(filepath.Join("testdata", dirPath, filename)) + if err != nil { + return fmt.Errorf("failed to read testcase: %v", err) + } + test := new(flatCallTracerTest) + if err := json.Unmarshal(blob, test); err != nil { + return fmt.Errorf("failed to parse testcase: %v", err) + } + // Configure a blockchain with the given prestate + tx := new(types.Transaction) + if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { + return fmt.Errorf("failed to parse testcase input: %v", err) + } + signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) + origin, _ := signer.Sender(tx) + txContext := vm.TxContext{ + Origin: origin, + GasPrice: tx.GasPrice(), + } + context := vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + Coinbase: test.Context.Miner, + BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), + Time: uint64(test.Context.Time), + Difficulty: (*big.Int)(test.Context.Difficulty), + GasLimit: uint64(test.Context.GasLimit), + } + _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) + + // Create the tracer, the EVM environment and run it + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) + if err != nil { + return fmt.Errorf("failed to create call tracer: %v", err) + } + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + + msg, err := tx.AsMessage(signer, nil) + if err != nil { + return fmt.Errorf("failed to prepare transaction for tracing: %v", err) + } + st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + + if _, err = st.TransitionDb(); err != nil { + return fmt.Errorf("failed to execute transaction: %v", err) + } + + // Retrieve the trace result and compare against the etalon + res, err := tracer.GetResult() + if err != nil { + return fmt.Errorf("failed to retrieve trace result: %v", err) + } + ret := new([]flatCallTrace) + if err := json.Unmarshal(res, ret); err != nil { + return fmt.Errorf("failed to unmarshal trace result: %v", err) + } + if !jsonEqualFlat(ret, test.Result) { + t.Logf("tracer name: %s", tracerName) + + // uncomment this for easier debugging + // have, _ := json.MarshalIndent(ret, "", " ") + // want, _ := json.MarshalIndent(test.Result, "", " ") + // t.Logf("trace mismatch: \nhave %+v\nwant %+v", string(have), string(want)) + + // uncomment this for harder debugging <3 meowsbits + // lines := deep.Equal(ret, test.Result) + // for _, l := range lines { + // t.Logf("%s", l) + // t.FailNow() + // } + + t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result) + } + return nil +} + +// Iterates over all the input-output datasets in the tracer parity test harness and +// runs the Native tracer against them. +func TestFlatCallTracerNative(t *testing.T) { + testFlatCallTracer("flatCallTracer", "call_tracer_flat", t) +} + +func testFlatCallTracer(tracerName string, dirPath string, t *testing.T) { + files, err := os.ReadDir(filepath.Join("testdata", dirPath)) + if err != nil { + t.Fatalf("failed to retrieve tracer test suite: %v", err) + } + for _, file := range files { + if !strings.HasSuffix(file.Name(), ".json") { + continue + } + file := file // capture range variable + t.Run(camel(strings.TrimSuffix(file.Name(), ".json")), func(t *testing.T) { + t.Parallel() + + err := flatCallTracerTestRunner(tracerName, file.Name(), dirPath, t) + if err != nil { + t.Fatal(err) + } + }) + } +} + +// jsonEqual is similar to reflect.DeepEqual, but does a 'bounce' via json prior to +// comparison +func jsonEqualFlat(x, y interface{}) bool { + xTrace := new([]flatCallTrace) + yTrace := new([]flatCallTrace) + if xj, err := json.Marshal(x); err == nil { + json.Unmarshal(xj, xTrace) + } else { + return false + } + if yj, err := json.Marshal(y); err == nil { + json.Unmarshal(yj, yTrace) + } else { + return false + } + return reflect.DeepEqual(xTrace, yTrace) +} + +func BenchmarkFlatCallTracer(b *testing.B) { + files, err := filepath.Glob("testdata/call_tracer_flat/*.json") + if err != nil { + b.Fatalf("failed to read testdata: %v", err) + } + + for _, file := range files { + filename := strings.TrimPrefix(file, "testdata/call_tracer_flat/") + b.Run(camel(strings.TrimSuffix(filename, ".json")), func(b *testing.B) { + for n := 0; n < b.N; n++ { + err := flatCallTracerTestRunner("flatCallTracer", filename, "call_tracer_flat", b) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json new file mode 100644 index 000000000000..e54ede92b02a --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json @@ -0,0 +1,64 @@ +{ + "genesis": { + "difficulty": "50486697699375", + "extraData": "0xd783010406844765746887676f312e362e32856c696e7578", + "gasLimit": "4788482", + "hash": "0xf6bbc5bbe34d5c93fd5b4712cd498d1026b8b0f586efefe7fe30231ed6b8a1a5", + "miner": "0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1", + "mixHash": "0xabca93555584c0463ee5c212251dd002bb3a93a157e06614276f93de53d4fdb8", + "nonce": "0xa64136fcb9c2d4ca", + "number": "1719576", + "stateRoot": "0xab5eec2177a92d633e282936af66c46e24cfa8f2fdc2b8155f33885f483d06f3", + "timestamp": "1466150166", + "totalDifficulty": "28295412423546970038", + "alloc": { + "0xf8bda96b67036ee48107f2a0695ea673479dda56": { + "balance": "0x1529e844f9ecdeec", + "nonce": "33", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 1, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 3000000, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 1150000, + "byzantiumBlock": 8772000, + "constantinopleBlock": 9573000, + "petersburgBlock": 10500839, + "istanbulBlock": 10500839 + } + }, + "context": { + "number": "1719577", + "difficulty": "50486697732143", + "timestamp": "1466150178", + "gasLimit": "4788484", + "miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226" + }, + "input": "0xf874218504a817c800832318608080a35b620186a05a131560135760016020526000565b600080601f600039601f565b6000f31ba0575fa000a1f06659a7b6d3c7877601519a4997f04293f0dfa0eee6d8cd840c77a04c52ce50719ee2ff7a0c5753f4ee69c0340666f582dbb5148845a354ca726e4a", + "result": [ + { + "action": { + "from": "0xf8bda96b67036ee48107f2a0695ea673479dda56", + "gas": "0x22410c", + "init": "0x5b620186a05a131560135760016020526000565b600080601f600039601f565b6000f3", + "value": "0x0" + }, + "blockNumber": 1719577, + "result": { + "address": "0xb2e6a2546c45889427757171ab05b8b438525b42", + "code": "0x", + "gasUsed": "0x219202" + }, + "subtraces": 0, + "traceAddress": [], + "type": "create" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json new file mode 100644 index 000000000000..be198885cbc3 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json @@ -0,0 +1,74 @@ +{ + "genesis": { + "difficulty": "4671584", + "extraData": "0xd683010b05846765746886676f312e3133856c696e7578", + "gasLimit": "9435026", + "hash": "0x755bd54de4b2f5a7a589a10d69888b4ead48a6311d5d69f2f69ca85ec35fbe0b", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "mixHash": "0x3a44525624571c31344ba57780f7664098fe7cbeafe532bcdee76a23fc474ba0", + "nonce": "0x6dca647c00c72bbf", + "number": "1555278", + "stateRoot": "0x5f56d8323ee384b0c8d1de49d63e150e17283eea813483698362bc0ec9e0242a", + "timestamp": "1590795319", + "totalDifficulty": "2242614315030", + "alloc": { + "0x0000000000000000000000000000000000000004": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x62436e941792f02a5fb1", + "nonce": "265356", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "1555279", + "difficulty": "4669303", + "timestamp": "1590795340", + "gasLimit": "9444238", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf86f83040c8c843b9aca0083019f7880809b60206000600060006013600462030d40f26002556000516000550081a2a086ad228c89ad9664287b12a5602a635a803506904f4ce39795990ac4f945cd57a025b30ea8042d773f6c5b13d7cc1b3979f9f10ee674410b6a2112ce840d0302dc", + "result": [ + { + "type": "create", + "action": { + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "value": "0x0", + "gas": "0xcf08", + "init": "0x60206000600060006013600462030d40f260025560005160005500" + }, + "result": { + "gasUsed": "0xf3bc", + "code": "0x", + "address": "0x5f8a7e007172ba80afbff1b15f800eb0b260f224" + }, + "traceAddress": [], + "subtraces": 0, + "transactionPosition": 74, + "transactionHash": "0x5ef60b27ac971c22a7d484e546e50093ca62300c8986d165154e47773764b6a4", + "blockNumber": 1555279, + "blockHash": "0xd6c98d1b87dfa92a210d99bad2873adaf0c9e51fe43addc63fd9cca03a5c6f46", + "time": "209.346µs" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json new file mode 100644 index 000000000000..94b864ff497d --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json @@ -0,0 +1,94 @@ +{ + "genesis": { + "difficulty": "4671584", + "extraData": "0xd883010b05846765746888676f312e31342e33856c696e7578", + "gasLimit": "9425823", + "hash": "0x27dd7d052dbc8a29cc5b9487e1e41d842e7a643fcaea4964caa22b834964acaf", + "miner": "0x73f26d124436b0791169d63a3af29c2ae47765a3", + "mixHash": "0xb4a050624f5d147fdf02857cbfd55da3ddc1451743acc5c163861584589c3034", + "nonce": "0x3c255875b17e0573", + "number": "1555277", + "stateRoot": "0x6290d79215a2eebc25d5e456b35876c6d78ffc1ea47bdd70e375ebb3cf325620", + "timestamp": "1590795308", + "totalDifficulty": "2242609643446", + "alloc": { + "0x0000000000000000000000000000000000000001": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x624329308610ab365fb1", + "nonce": "265194", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "1555278", + "difficulty": "4671584", + "timestamp": "1590795319", + "gasLimit": "9435026", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf8ee83040bea843b9aca008301a7588080b8997f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb7f260025560a060020a6080510660005560005432146001550081a1a05b9a162d84bfe84faa7c176e21c26c0083645d4dd0d566547b7be2c2da0b4259a05b37ff12a4c27634cb0da6008d9b69726d415ff4694f9bc38c7806eb1fb60ae9", + "result": [ + { + "type": "create", + "action": { + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "value": "0x0", + "gas": "0xcf08", + "init": "0x7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb7f260025560a060020a60805106600055600054321460015500" + }, + "result": { + "gasUsed": "0xf3e9", + "code": "0x", + "address": "0x568c19ecb14b87e4aec29b4d2d700a3ad3fd0613" + }, + "traceAddress": [], + "subtraces": 1, + "transactionPosition": 141, + "transactionHash": "0x1592cbda0d928b8d18eed98857942b91ade32d088e55b8bf63418917cb0231f1", + "blockNumber": 1555278, + "blockHash": "0x755bd54de4b2f5a7a589a10d69888b4ead48a6311d5d69f2f69ca85ec35fbe0b", + "time": "300.9µs" + }, + { + "type": "call", + "action": { + "from": "0x568c19ecb14b87e4aec29b4d2d700a3ad3fd0613", + "to": "0x0000000000000000000000000000000000000001", + "value": "0x0", + "gas": "0xbb7", + "input": "0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549", + "callType": "callcode" + }, + "error": "out of gas", + "traceAddress": [ + 0 + ], + "subtraces": 0, + "transactionPosition": 141, + "transactionHash": "0x1592cbda0d928b8d18eed98857942b91ade32d088e55b8bf63418917cb0231f1", + "blockNumber": 1555278, + "blockHash": "0x755bd54de4b2f5a7a589a10d69888b4ead48a6311d5d69f2f69ca85ec35fbe0b" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json new file mode 100644 index 000000000000..506dc5ff68ec --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json @@ -0,0 +1,90 @@ +{ + "genesis": { + "difficulty": "4683014", + "extraData": "0x537465762d63676574682d76312e31312e34", + "gasLimit": "9435044", + "hash": "0x3452ca5005cb73cd60dfa488a7b124251168e564491f80eb66765e79d78cfd95", + "miner": "0x415aa6292d1db797a467b22139704956c030e62f", + "mixHash": "0x6037612618507ae70c74a72bc2580253662971db959cfbc06d3f8527d4d01575", + "nonce": "0x314fc90dee5e39a2", + "number": "1555274", + "stateRoot": "0x795751f3f96a5de1fd3944ddd78cbfe4ef10491e1086be47609869a30929d0e5", + "timestamp": "1590795228", + "totalDifficulty": "2242595605834", + "alloc": { + "0x0000000000000000000000000000000000000009": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x6242e3ccf48e66425fb1", + "nonce": "264981", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "1555275", + "difficulty": "4683014", + "timestamp": "1590795244", + "gasLimit": "9444256", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf87a83040b15843b9aca008301a0348080a636600060003760406103e8366000600060095af26001556103e851600255610408516003550081a1a0dd883fbbb489b640dadc8c1bf151767155228d0a1321f687f070f35f14374b05a02dd0ccb16a8de39bc8ee61381bbbbb54f0ab18422afd7b03c6163da1f5023934", + "result": [ + { + "type": "create", + "action": { + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "value": "0x0", + "gas": "0xcf08", + "init": "0x36600060003760406103e8366000600060095af26001556103e8516002556104085160035500" + }, + "error": "out of gas", + "traceAddress": [], + "subtraces": 1, + "transactionPosition": 117, + "transactionHash": "0x7fe4dec901e1a62c1a1d96b8267bb9ff9dc1f75def43aa45b998743455eff8f9", + "blockNumber": 1555275, + "blockHash": "0x80945caaff2fc67253cbb0217d2e5a307afde943929e97d8b36e58b88cbb02fd", + "time": "332.877µs" + }, + { + "type": "call", + "action": { + "from": "0x8832ef498070145c3a5b30f47fbca71fd7b1de9f", + "to": "0x0000000000000000000000000000000000000009", + "value": "0x0", + "gas": "0xc897", + "input": "0x", + "callType": "callcode" + }, + "error": "invalid input length", + "traceAddress": [ + 0 + ], + "subtraces": 0, + "transactionPosition": 117, + "transactionHash": "0x7fe4dec901e1a62c1a1d96b8267bb9ff9dc1f75def43aa45b998743455eff8f9", + "blockNumber": 1555275, + "blockHash": "0x80945caaff2fc67253cbb0217d2e5a307afde943929e97d8b36e58b88cbb02fd" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json new file mode 100644 index 000000000000..b83236690c26 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json @@ -0,0 +1,67 @@ +{ + "context": { + "difficulty": "3755480783", + "gasLimit": "5401723", + "miner": "0xd049bfd667cb46aa3ef5df0da3e57db3be39e511", + "number": "2294702", + "timestamp": "1513676146" + }, + "genesis": { + "alloc": { + "0x13e4acefe6a6700604929946e70e6443e4e73447": { + "balance": "0xcf3e0938579f000", + "code": "0x", + "nonce": "9", + "storage": {} + }, + "0x7dc9c9730689ff0b0fd506c67db815f12d90a448": { + "balance": "0x0", + "code": "0x", + "nonce": "0", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3757315409", + "extraData": "0x566961425443", + "gasLimit": "5406414", + "hash": "0xae107f592eebdd9ff8d6ba00363676096e6afb0e1007a7d3d0af88173077378d", + "miner": "0xd049bfd667cb46aa3ef5df0da3e57db3be39e511", + "mixHash": "0xc927aa05a38bc3de864e95c33b3ae559d3f39c4ccd51cef6f113f9c50ba0caf1", + "nonce": "0x93363bbd2c95f410", + "number": "2294701", + "stateRoot": "0x6b6737d5bde8058990483e915866bd1578014baeff57bd5e4ed228a2bfad635c", + "timestamp": "1513676127", + "totalDifficulty": "7160808139332585" + }, + "input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f", + "result": [ + { + "action": { + "from": "0x13e4acefe6a6700604929946e70e6443e4e73447", + "gas": "0x5e106", + "init": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", + "value": "0x0" + }, + "blockNumber": 2294702, + "result": { + "address": "0x7dc9c9730689ff0b0fd506c67db815f12d90a448", + "code": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029", + "gasUsed": "0x897be" + }, + "subtraces": 0, + "traceAddress": [], + "type": "create" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json new file mode 100644 index 000000000000..5931b4080922 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json @@ -0,0 +1,635 @@ +{ + "context": { + "difficulty": "117066904", + "gasLimit": "4712384", + "miner": "0x1977c248e1014cc103929dd7f154199c916e39ec", + "number": "25001", + "timestamp": "1479891545" + }, + "genesis": { + "alloc": { + "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38": { + "balance": "0x0", + "code": "0x606060405236156100825760e060020a600035046302d05d3f811461008a5780630accce061461009c5780631ab9075a146100c757806331ed274614610102578063645a3b7214610133578063772fdae314610155578063a7f4377914610180578063ae5f80801461019e578063c9bded21146101ea578063f905c15a14610231575b61023a610002565b61023c600054600160a060020a031681565b61023a600435602435604435606435608435600254600160a060020a03166000141561024657610002565b61023a600435600254600160a060020a03166000148015906100f8575060025433600160a060020a03908116911614155b156102f457610002565b61023a60043560243560443560643560843560a43560c435600254600160a060020a03166000141561031657610002565b61023a600435602435600254600160a060020a0316600014156103d057610002565b61023a600435602435604435606435608435600254600160a060020a03166000141561046157610002565b61023a60025433600160a060020a0390811691161461051657610002565b61023a6004356024356044356060828152600160a060020a0382169060ff8516907fa6c2f0913db6f79ff0a4365762c61718973b3413d6e40382e704782a9a5099f690602090a3505050565b61023a600435602435600160a060020a038116606090815260ff8316907fee6348a7ec70f74e3d6cba55a53e9f9110d180d7698e9117fc466ae29a43e34790602090a25050565b61023c60035481565b005b6060908152602090f35b60025460e060020a6313bc6d4b02606090815233600160a060020a0390811660645291909116906313bc6d4b906084906020906024816000876161da5a03f115610002575050604051511515905061029d57610002565b60408051858152602081018390528151600160a060020a03858116939087169260ff8a16927f5a690ecd0cb15c1c1fd6b6f8a32df0d4f56cb41a54fea7e94020f013595de796929181900390910190a45050505050565b6002805473ffffffffffffffffffffffffffffffffffffffff19168217905550565b60025460e060020a6313bc6d4b02606090815233600160a060020a0390811660645291909116906313bc6d4b906084906020906024816000876161da5a03f115610002575050604051511515905061036d57610002565b6040805186815260208101869052808201859052606081018490529051600160a060020a03831691889160ff8b16917fd65d9ddafbad8824e2bbd6f56cc9f4ac27ba60737035c10a321ea2f681c94d47919081900360800190a450505050505050565b60025460e060020a6313bc6d4b02606090815233600160a060020a0390811660645291909116906313bc6d4b906084906020906024816000876161da5a03f115610002575050604051511515905061042757610002565b60408051828152905183917fa9c6cbc4bd352a6940479f6d802a1001550581858b310d7f68f7bea51218cda6919081900360200190a25050565b60025460e060020a6313bc6d4b02606090815233600160a060020a0390811660645291909116906313bc6d4b906084906020906024816000876161da5a03f11561000257505060405151151590506104b857610002565b80600160a060020a031684600160a060020a03168660ff167f69bdaf789251e1d3a0151259c0c715315496a7404bce9fd0b714674685c2cab78686604051808381526020018281526020019250505060405180910390a45050505050565b600254600160a060020a0316ff", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000002cccf5e0538493c235d1c5ef6580f77d99e91396" + } + }, + "0x2cccf5e0538493c235d1c5ef6580f77d99e91396": { + "balance": "0x0", + "code": "0x606060405236156100775760e060020a600035046302d05d3f811461007f57806313bc6d4b146100915780633688a877146100b95780635188f9961461012f5780637eadc976146101545780638ad79680146101d3578063a43e04d814610238578063a7f437791461025e578063e16c7d981461027c575b61029f610002565b6102a1600054600160a060020a031681565b6102be600435600160a060020a03811660009081526002602052604090205460ff165b919050565b6102d26004356040805160208181018352600080835284815260038252835190849020805460026001821615610100026000190190911604601f8101849004840283018401909552848252929390929183018282801561037d5780601f106103525761010080835404028352916020019161037d565b61029f6004356024356000805433600160a060020a039081169116146104a957610002565b61034060043560008181526001602090815260408083205481517ff905c15a0000000000000000000000000000000000000000000000000000000081529151600160a060020a03909116928392839263f905c15a92600483810193919291829003018189876161da5a03f1156100025750506040515195945050505050565b60408051602060248035600481810135601f810185900485028601850190965285855261029f9581359591946044949293909201918190840183828082843750949650505050505050600054600160a060020a0390811633909116146104f657610002565b61029f6004355b600080548190600160a060020a0390811633909116146105a457610002565b61029f60005433600160a060020a0390811691161461072957610002565b6102a1600435600081815260016020526040902054600160a060020a03166100b4565b005b60408051600160a060020a03929092168252519081900360200190f35b604080519115158252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156103325780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051918252519081900360200190f35b820191906000526020600020905b81548152906001019060200180831161036057829003601f168201915b505050505090506100b4565b506000828152600160208181526040808420805473ffffffffffffffffffffffffffffffffffffffff191686179055600160a060020a038581168086526002909352818520805460ff191690941790935580517f1ab9075a0000000000000000000000000000000000000000000000000000000081523090931660048401525184939192631ab9075a926024828101939192829003018183876161da5a03f11561000257505060408051602081018690528082019290925243606083015260808083526003908301527f414444000000000000000000000000000000000000000000000000000000000060a0830152517f8ac68d4e97d65912f220b4c5f87978b8186320a5e378c1369850b5b5f90323d39181900360c00190a15b505050565b600083815260016020526040902054600160a060020a03838116911614156104d0576104a4565b600083815260016020526040812054600160a060020a031614610389576103898361023f565b600082815260036020908152604082208054845182855293839020919360026001831615610100026000190190921691909104601f90810184900483019391929186019083901061056a57805160ff19168380011785555b5061059a9291505b808211156105a05760008155600101610556565b8280016001018555821561054e579182015b8281111561054e57825182600050559160200191906001019061057c565b50505050565b5090565b600083815260016020526040812054600160a060020a031614156105c757610002565b50506000818152600160205260408082205481517fa7f437790000000000000000000000000000000000000000000000000000000081529151600160a060020a0391909116928392839263a7f4377992600483810193919291829003018183876161da5a03f11561000257505050600160005060008460001916815260200190815260200160002060006101000a815490600160a060020a0302191690556002600050600083600160a060020a0316815260200190815260200160002060006101000a81549060ff02191690557f8ac68d4e97d65912f220b4c5f87978b8186320a5e378c1369850b5b5f90323d383834360405180806020018560001916815260200184600160a060020a03168152602001838152602001828103825260038152602001807f44454c000000000000000000000000000000000000000000000000000000000081526020015060200194505050505060405180910390a1505050565b600054600160a060020a0316ff", + "nonce": "1", + "storage": { + "0x0684ac65a9fa32414dda56996f4183597d695987fdb82b145d722743891a6fe8": "0x0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690", + "0x1cd76f78169a420d99346e3501dd3e541622c38a226f9b63e01cfebc69879dc7": "0x000000000000000000000000b4fe7aa695b326c9d219158d2ca50db77b39f99f", + "0x8e54a4494fe5da016bfc01363f4f6cdc91013bb5434bd2a4a3359f13a23afa2f": "0x000000000000000000000000cf00ffd997ad14939736f026006498e3f099baaf", + "0x94edf7f600ba56655fd65fca1f1424334ce369326c1dc3e53151dcd1ad06bc13": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xbbee47108b275f55f98482c6800f6372165e88b0330d3f5dae6419df4734366c": "0x0000000000000000000000002a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "0xd38c0c4e84de118cfdcc775130155d83b8bbaaf23dc7f3c83a626b10473213bd": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xfb3aa5c655c2ec9d40609401f88d505d1da61afaa550e36ef5da0509ada257ba": "0x0000000000000000000000007986bad81f4cbd9317f5a46861437dae58d69113" + } + }, + "0x3e9286eafa2db8101246c2131c09b49080d00690": { + "balance": "0x0", + "code": "0x606060405236156100cf5760e060020a600035046302d05d3f81146100d7578063056d4470146100e957806316c66cc61461010c5780631ab9075a146101935780633ae1005c146101ce57806358541662146101fe5780635ed61af014610231578063644e3b791461025457806384dbac3b146102db578063949ae479146102fd5780639859387b14610321578063a7f4377914610340578063ab03fc261461035e578063e8161b7814610385578063e964d4e114610395578063f905c15a146103a5578063f92eb774146103ae575b6103be610002565b6103c0600054600160a060020a031681565b6103be6004356002546000908190600160a060020a031681141561040357610002565b6103dd60043560006108365b6040805160025460e360020a631c2d8fb30282527f636f6e747261637464620000000000000000000000000000000000000000000060048301529151600092600160a060020a03169163e16c7d98916024828101926020929190829003018187876161da5a03f1156100025750506040515191506104e29050565b6103be600435600254600160a060020a03166000148015906101c4575060025433600160a060020a03908116911614155b1561088d57610002565b6103be600435602435604435606435600254600090819081908190600160a060020a03168114156108af57610002565b6103c0600435602435604435606435608435600254600090819081908190600160a060020a03168114156110e857610002565b6103be6004356002546000908190600160a060020a03168114156115ec57610002565b6103c06004356000611b635b6040805160025460e360020a631c2d8fb30282527f6d61726b6574646200000000000000000000000000000000000000000000000060048301529151600092600160a060020a03169163e16c7d98916024828101926020929190829003018187876161da5a03f1156100025750506040515191506104e29050565b6103be600435602435600254600160a060020a031660001415611bb557610002565b6103be600435602435600254600090600160a060020a0316811415611d2e57610002565b6103be600435600254600160a060020a031660001415611fc657610002565b6103be60025433600160a060020a0390811691161461207e57610002565b6103be600435602435604435600254600090600160a060020a031681141561208c57610002565b6103dd60043560006124b8610260565b6103c0600435600061250a610118565b6103f160035481565b6103f16004356000612561610260565b005b60408051600160a060020a03929092168252519081900360200190f35b604080519115158252519081900360200190f35b60408051918252519081900360200190f35b6040805160025460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f115610002575050604051511515905061046557610002565b8291506104e55b6040805160025460e360020a631c2d8fb30282527f63706f6f6c00000000000000000000000000000000000000000000000000000060048301529151600092600160a060020a03169163e16c7d98916024828101926020929190829003018187876161da5a03f115610002575050604051519150505b90565b600160a060020a031663b2206e6d83600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fb2206e6d0000000000000000000000000000000000000000000000000000000082526004820152600160a060020a038816602482015290516044808301935060209282900301816000876161da5a03f11561000257505060405151915061059b90506106ba565b600160a060020a031663d5b205ce83600160a060020a03166336da44686040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a636ad902e7028252600160a060020a0390811660048301526024820187905288166044820152905160648281019350600092829003018183876161da5a03f115610002575050506107355b6040805160025460e360020a631c2d8fb30282527f6c6f676d6772000000000000000000000000000000000000000000000000000060048301529151600092600160a060020a03169163e16c7d98916024828101926020929190829003018187876161da5a03f1156100025750506040515191506104e29050565b50826120ee5b6040805160025460e360020a631c2d8fb30282527f6163636f756e7463746c0000000000000000000000000000000000000000000060048301529151600092600160a060020a03169163e16c7d98916024828101926020929190829003018187876161da5a03f1156100025750506040515191506104e29050565b600160a060020a0316630accce06600684600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e360020a6306db488d02825291519192899290916336da446891600482810192602092919082900301816000876161da5a03f1156100025750505060405180519060200150866040518660e060020a028152600401808681526020018560001916815260200184600160a060020a0316815260200183600160a060020a03168152602001828152602001955050505050506000604051808303816000876161da5a03f11561000257505050505050565b600160a060020a03166316c66cc6836040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f115610002575050604051519150505b919050565b6002805473ffffffffffffffffffffffffffffffffffffffff19168217905550565b6040805160025460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f115610002575050604051511515905061091157610002565b87935061091c610260565b600160a060020a031663bdbdb08685600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fbdbdb0860000000000000000000000000000000000000000000000000000000082526004820152602481018a905290516044808301935060209282900301816000876161da5a03f1156100025750506040515193506109ca90506106ba565b600160a060020a03166381982a7a8885876040518460e060020a0281526004018084600160a060020a0316815260200183815260200182600160a060020a0316815260200193505050506000604051808303816000876161da5a03f11561000257505050610a3661046c565b600160a060020a03166308636bdb85600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517f08636bdb000000000000000000000000000000000000000000000000000000008252600482015260248101889052604481019290925251606482810192602092919082900301816000876161da5a03f11561000257505060408051805160e160020a630a5d50db028252600482018190529151919450600160a060020a03871692506314baa1b6916024828101926000929190829003018183876161da5a03f11561000257505050610b3561046c565b600160a060020a0316630a3b6ede85600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a63051db76f0282526004820152600160a060020a038d16602482015290516044808301935060209282900301816000876161da5a03f115610002575050604051519150610bd590506106ba565b600160a060020a031663d5b205ce87838b6040518460e060020a0281526004018084600160a060020a0316815260200183815260200182600160a060020a0316815260200193505050506000604051808303816000876161da5a03f11561000257505050610c41610118565b600160a060020a031663988db79c888a6040518360e060020a0281526004018083600160a060020a0316815260200182600160a060020a03168152602001925050506000604051808303816000876161da5a03f11561000257505050610ca5610260565b600160a060020a031663f4f2821b896040518260e060020a0281526004018082600160a060020a031681526020019150506000604051808303816000876161da5a03f11561000257505050610d6f5b6040805160025460e360020a631c2d8fb30282527f747261646564620000000000000000000000000000000000000000000000000060048301529151600092600160a060020a03169163e16c7d98916024828101926020929190829003018187876161da5a03f1156100025750506040515191506104e29050565b600160a060020a0316635f539d69896040518260e060020a0281526004018082600160a060020a031681526020019150506000604051808303816000876161da5a03f11561000257505050610dc2610639565b600160a060020a0316630accce06600386600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e360020a6315b1ea01028252915191928e928e9263ad8f500891600482810192602092919082900301816000876161da5a03f11561000257505050604051805190602001506040518660e060020a028152600401808681526020018560001916815260200184600160a060020a0316815260200183600160a060020a03168152602001828152602001955050505050506000604051808303816000876161da5a03f11561000257505050610ec5610639565b600160a060020a0316630accce06600386600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e360020a6315b1ea01028252915191928e928d9263ad8f500891600482810192602092919082900301816000876161da5a03f11561000257505050604051805190602001506040518660e060020a028152600401808681526020018560001916815260200184600160a060020a0316815260200183600160a060020a03168152602001828152602001955050505050506000604051808303816000876161da5a03f11561000257505050610fc8610639565b600160a060020a031663645a3b7285600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151905061101e610260565b600160a060020a031663f92eb77488600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e260020a633e4baddd028252600482015290516024828101935060209282900301816000876161da5a03f11561000257505060408051805160e060020a86028252600482019490945260248101939093525160448381019360009350829003018183876161da5a03f115610002575050505050505050505050565b6040805160025460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f115610002575050604051511515905061114a57610002565b604051600254600160a060020a0316908a908a908a908a908a90611579806125b38339018087600160a060020a0316815260200186600160a060020a03168152602001856000191681526020018481526020018381526020018281526020019650505050505050604051809103906000f092506111c5610118565b600160a060020a031663b9858a288a856040518360e060020a0281526004018083600160a060020a0316815260200182600160a060020a03168152602001925050506000604051808303816000876161da5a03f11561000257505050611229610260565b600160a060020a0316635188f99689856040518360e060020a028152600401808360001916815260200182600160a060020a03168152602001925050506000604051808303816000876161da5a03f11561000257505050611288610260565b600160a060020a031663bdbdb08689896040518360e060020a0281526004018083600019168152602001828152602001925050506020604051808303816000876161da5a03f1156100025750506040515192506112e590506106ba565b600160a060020a03166346d88e7d8a858a6040518460e060020a0281526004018084600160a060020a0316815260200183600160a060020a0316815260200182815260200193505050506000604051808303816000876161da5a03f115610002575050506113516106ba565b600160a060020a03166381982a7a8a84866040518460e060020a0281526004018084600160a060020a0316815260200183815260200182600160a060020a0316815260200193505050506000604051808303816000876161da5a03f115610002575050506113bd61046c565b600160a060020a0316632b58469689856040518360e060020a028152600401808360001916815260200182600160a060020a03168152602001925050506000604051808303816000876161da5a03f1156100025750505061141c61046c565b600160a060020a03166308636bdb8984866040518460e060020a028152600401808460001916815260200183815260200182600160a060020a0316815260200193505050506020604051808303816000876161da5a03f11561000257505060408051805160e160020a630a5d50db028252600482018190529151919350600160a060020a03861692506314baa1b6916024828101926000929190829003018183876161da5a03f115610002575050506114d3610639565b6040805160e160020a630566670302815260016004820152602481018b9052600160a060020a0386811660448301528c811660648301526000608483018190529251931692630accce069260a480840193919291829003018183876161da5a03f11561000257505050611544610639565b600160a060020a031663645a3b728961155b610260565b600160a060020a031663f92eb7748c6040518260e060020a02815260040180826000191681526020019150506020604051808303816000876161da5a03f11561000257505060408051805160e060020a86028252600482019490945260248101939093525160448084019360009350829003018183876161da5a03f1156100025750939a9950505050505050505050565b6040805160025460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f115610002575050604051511515905061164e57610002565b82915061165961046c565b600160a060020a0316630a3b6ede83600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a63051db76f0282526004820152600160a060020a038816602482015290516044808301935060209282900301816000876161da5a03f1156100025750506040515191506116f990506106ba565b600160a060020a031663d5b205ce83600160a060020a03166336da44686040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a636ad902e7028252600160a060020a0390811660048301526024820187905288166044820152905160648281019350600092829003018183876161da5a03f1156100025750505061179b6106ba565b600160a060020a031663d653078983600160a060020a03166336da44686040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517ff1ff78a0000000000000000000000000000000000000000000000000000000008252915191929163f1ff78a09160048181019260209290919082900301816000876161da5a03f1156100025750505060405180519060200150866040518460e060020a0281526004018084600160a060020a0316815260200183815260200182600160a060020a0316815260200193505050506000604051808303816000876161da5a03f1156100025750505061189f610260565b600160a060020a031663f4f2821b846040518260e060020a0281526004018082600160a060020a031681526020019150506000604051808303816000876161da5a03f115610002575050506118f2610118565b600160a060020a031663f4f2821b846040518260e060020a0281526004018082600160a060020a031681526020019150506000604051808303816000876161da5a03f11561000257505050611945610639565b600160a060020a0316630accce06600484600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e360020a6306db488d02825291519192899290916336da44689181870191602091908190038801816000876161da5a03f115610002575050506040518051906020015060006040518660e060020a028152600401808681526020018560001916815260200184600160a060020a0316815260200183600160a060020a03168152602001828152602001955050505050506000604051808303816000876161da5a03f11561000257505050611a48610639565b600160a060020a031663645a3b7283600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051519050611a9e610260565b600160a060020a031663f92eb77486600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e260020a633e4baddd028252600482015290516024828101935060209282900301816000876161da5a03f11561000257505060408051805160e060020a86028252600482019490945260248101939093525160448381019360009350829003018183876161da5a03f11561000257505050505050565b600160a060020a03166381738c59836040518260e060020a02815260040180826000191681526020019150506020604051808303816000876161da5a03f1156100025750506040515191506108889050565b6040805160025460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f1156100025750506040515115159050611c1757610002565b611c1f610260565b600160a060020a03166338a699a4836040518260e060020a02815260040180826000191681526020019150506020604051808303816000876161da5a03f11561000257505060405151159050611c7457610002565b611c7c610260565b600160a060020a0316632243118a836040518260e060020a02815260040180826000191681526020019150506000604051808303816000876161da5a03f11561000257505050611cca610639565b600160a060020a031663ae5f8080600184846040518460e060020a028152600401808481526020018360001916815260200182600160a060020a0316815260200193505050506000604051808303816000876161da5a03f115610002575050505050565b6040805160025460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f1156100025750506040515115159050611d9057610002565b5081611d9a610260565b600160a060020a031663581d5d6084846040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506000604051808303816000876161da5a03f11561000257505050611df5610639565b600160a060020a0316630accce06600283600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a630566670302825260048201949094526024810193909352600160a060020a038816604484015260006064840181905260848401819052905160a4808501949293509091829003018183876161da5a03f11561000257505050611eab610639565b600160a060020a031663645a3b7282600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051519050611f01610260565b600160a060020a031663f92eb77485600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e260020a633e4baddd028252600482015290516024828101935060209282900301816000876161da5a03f11561000257505060408051805160e060020a86028252600482019490945260248101939093525160448381019360009350829003018183876161da5a03f11561000257505050505050565b6040805160025460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f115610002575050604051511515905061202857610002565b612030610118565b600160a060020a0316639859387b826040518260e060020a0281526004018082600160a060020a031681526020019150506000604051808303816000876161da5a03f1156100025750505050565b600254600160a060020a0316ff5b6040805160025460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f11561000257505060405151151590506106b457610002565b600160a060020a031663d65307898383600160a060020a031663f1ff78a06040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fd6530789000000000000000000000000000000000000000000000000000000008252600160a060020a039485166004830152602482015292891660448401525160648381019360009350829003018183876161da5a03f115610002575050506121a5610118565b600160a060020a031663f4f2821b856040518260e060020a0281526004018082600160a060020a031681526020019150506000604051808303816000876161da5a03f115610002575050506121f8610cf4565b600160a060020a031663f4f2821b856040518260e060020a0281526004018082600160a060020a031681526020019150506000604051808303816000876161da5a03f1156100025750505061224b610639565b600160a060020a0316630accce06600583600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e360020a6306db488d028252915191928a9290916336da446891600482810192602092919082900301816000876161da5a03f1156100025750505060405180519060200150886040518660e060020a028152600401808681526020018560001916815260200184600160a060020a0316815260200183600160a060020a03168152602001828152602001955050505050506000604051808303816000876161da5a03f1156100025750505080600160a060020a031663ea71b02d6040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151600160a060020a031660001490506124b25761239f610639565b600160a060020a0316630accce06600583600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040805180517fea71b02d000000000000000000000000000000000000000000000000000000008252915191928a92909163ea71b02d91600482810192602092919082900301816000876161da5a03f1156100025750505060405180519060200150886040518660e060020a028152600401808681526020018560001916815260200184600160a060020a0316815260200183600160a060020a03168152602001828152602001955050505050506000604051808303816000876161da5a03f115610002575050505b50505050565b600160a060020a03166338a699a4836040518260e060020a02815260040180826000191681526020019150506020604051808303816000876161da5a03f1156100025750506040515191506108889050565b600160a060020a031663213fe2b7836040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515191506108889050565b600160a060020a031663f92eb774836040518260e060020a02815260040180826000191681526020019150506020604051808303816000876161da5a03f115610002575050604051519150610888905056606060405260405160c08061157983396101206040819052825160805160a051935160e0516101005160008054600160a060020a03199081163317909155600180546005805484168817905560048a90556006869055600b8590556008849055909116861760a060020a60ff02191690554360038190556002558686526101408390526101608190529396929594919390929091600160a060020a033016917f76885d242fb71c6f74a7e717416e42eff4d96faf54f6de75c6a0a6bbd8890c6b91a230600160a060020a03167fa609f6bd4ad0b4f419ddad4ac9f0d02c2b9295c5e6891469055cf73c2b568fff600b600050546040518082815260200191505060405180910390a250505050505061145e8061011b6000396000f3606060405236156101745760e060020a600035046302d05d3f811461017c57806304a7fdbc1461018e5780630e90f957146101fb5780630fb5a6b41461021257806314baa1b61461021b57806317fc45e21461023a5780632b096926146102435780632e94420f1461025b578063325a19f11461026457806336da44681461026d5780633f81a2c01461027f5780633fc306821461029757806345ecd3d7146102d45780634665096d146102dd5780634e71d92d146102e657806351a34eb8146103085780636111bb951461032d5780636f265b93146103445780637e9014e11461034d57806390ba009114610360578063927df5e014610393578063a7f437791461046c578063ad8f50081461046e578063bc6d909414610477578063bdec3ad114610557578063c19d93fb1461059a578063c9503fe2146105ad578063e0a73a93146105b6578063ea71b02d146105bf578063ea8a1af0146105d1578063ee4a96f9146105f3578063f1ff78a01461065c575b61046c610002565b610665600054600160a060020a031681565b6040805160c081810190925261046c9160049160c4918390600690839083908082843760408051808301909152929750909561018495509193509091908390839080828437509095505050505050600554600090600160a060020a0390811633909116146106a857610002565b61068260015460a060020a900460ff166000145b90565b61069660085481565b61046c600435600154600160a060020a03166000141561072157610002565b610696600d5481565b610696600435600f8160068110156100025750015481565b61069660045481565b61069660035481565b610665600554600160a060020a031681565b61069660043560158160068110156100025750015481565b6106966004355b600b54600f5460009160028202808203928083039290810191018386101561078357601054840186900394505b50505050919050565b61069660025481565b61069660095481565b61046c600554600090600160a060020a03908116339091161461085857610002565b61046c600435600554600090600160a060020a03908116339091161461092e57610002565b6106826001805460a060020a900460ff161461020f565b610696600b5481565b61068260075460a060020a900460ff1681565b6106966004355b600b54601554600091600282028082039280830392908101910183861015610a6c5760165494506102cb565b61046c6004356024356044356040805160015460e360020a631c2d8fb302825260b260020a691858d8dbdd5b9d18dd1b02600483015291516000928392600160a060020a03919091169163e16c7d9891602481810192602092909190829003018187876161da5a03f1156100025750505060405180519060200150905080600160a060020a031663c4b0c96a336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610b4657610002565b005b610696600a5481565b61046c60006000600060006000600160009054906101000a9004600160a060020a0316600160a060020a031663e16c7d986040518160e060020a028152600401808060b260020a691858d8dbdd5b9d18dd1b0281526020015060200190506020604051808303816000876161da5a03f1156100025750505060405180519060200150905080600160a060020a031663c4b0c96a336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610f1757610002565b61046c5b60015b60058160ff16101561071e57600f6001820160ff166006811015610002578101549060ff83166006811015610002570154101561129057610002565b61069660015460a060020a900460ff1681565b61069660065481565b610696600c5481565b610665600754600160a060020a031681565b61046c600554600090600160a060020a0390811633909116146112c857610002565b6040805160c081810190925261046c9160049160c4918390600690839083908082843760408051808301909152929750909561018495509193509091908390839080828437509095505050505050600154600090600160a060020a03168114156113fb57610002565b610696600e5481565b60408051600160a060020a03929092168252519081900360200190f35b604080519115158252519081900360200190f35b60408051918252519081900360200190f35b5060005b60068160ff16101561070857828160ff166006811015610002576020020151600f60ff831660068110156100025701558160ff82166006811015610002576020020151601560ff831660068110156100025701556001016106ac565b61071061055b565b505050565b600e8054820190555b50565b6040805160015460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f115610002575050604051511515905061071557610002565b83861015801561079257508286105b156107b457600f546010546011548689039082030291909104900394506102cb565b8286101580156107c55750600b5486105b156107e757600f546011546012548589039082030291909104900394506102cb565b600b5486108015906107f857508186105b1561081d57600b54600f546012546013549289039281039290920204900394506102cb565b81861015801561082c57508086105b1561084e57600f546013546014548489039082030291909104900394506102cb565b60145494506102cb565b60015460a060020a900460ff1660001461087157610002565b600254600a01431161088257610002565b6040805160015460e360020a631c2d8fb302825260a860020a6a636f6e74726163746170690260048301529151600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750505060405180519060200150905080600160a060020a031663771d50e16040518160e060020a0281526004018090506000604051808303816000876161da5a03f1156100025750505050565b60015460a060020a900460ff1660001461094757610002565b600254600a01431161095857610002565b6040805160015460e360020a631c2d8fb302825260a860020a6a636f6e74726163746170690260048301529151600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750506040805180517f51a34eb8000000000000000000000000000000000000000000000000000000008252600482018690529151919350600160a060020a03841692506351a34eb8916024808301926000929190829003018183876161da5a03f11561000257505050600b8290554360025560408051838152905130600160a060020a0316917fa609f6bd4ad0b4f419ddad4ac9f0d02c2b9295c5e6891469055cf73c2b568fff919081900360200190a25050565b838610158015610a7b57508286105b15610a9d576015546016546017548689039082900302919091040194506102cb565b828610158015610aae5750600b5486105b15610ad0576015546017546018548589039082900302919091040194506102cb565b600b548610801590610ae157508186105b15610b0657600b546015546018546019549289039281900392909202040194506102cb565b818610158015610b1557508086105b15610b3757601554601954601a548489039082900302919091040194506102cb565b601a54860181900394506102cb565b60015460a060020a900460ff16600014610b5f57610002565b6001805460a060020a60ff02191660a060020a17908190556040805160e360020a631c2d8fb302815260a860020a6a636f6e74726163746170690260048201529051600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750506040805180516004805460e260020a633e4baddd028452908301529151919450600160a060020a038516925063f92eb77491602482810192602092919082900301816000876161da5a03f115610002575050604080518051600a556005547ffebf661200000000000000000000000000000000000000000000000000000000825233600160a060020a03908116600484015216602482015260448101879052905163febf661291606480820192600092909190829003018183876161da5a03f115610002575050508215610cc7576007805473ffffffffffffffffffffffffffffffffffffffff191633179055610dbb565b6040805160055460065460e060020a63599efa6b028352600160a060020a039182166004840152602483015291519184169163599efa6b91604481810192600092909190829003018183876161da5a03f115610002575050604080516006547f56ccb6f000000000000000000000000000000000000000000000000000000000825233600160a060020a03166004830152602482015290516356ccb6f091604480820192600092909190829003018183876161da5a03f115610002575050600580546007805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a038416179091551633179055505b6007805460a060020a60ff02191660a060020a87810291909117918290556008544301600955900460ff1615610df757600a54610e039061029e565b600a54610e0b90610367565b600c55610e0f565b600c555b600c54670de0b6b3a7640000850204600d55600754600554604080517f759297bb000000000000000000000000000000000000000000000000000000008152600160a060020a039384166004820152918316602483015260448201879052519184169163759297bb91606481810192600092909190829003018183876161da5a03f11561000257505060408051600754600a54600d54600554600c5460a060020a850460ff161515865260208601929092528486019290925260608401529251600160a060020a0391821694509281169230909116917f3b3d1986083d191be01d28623dc19604728e29ae28bdb9ba52757fdee1a18de2919081900360800190a45050505050565b600954431015610f2657610002565b6001805460a060020a900460ff1614610f3e57610002565b6001805460a060020a60ff0219167402000000000000000000000000000000000000000017908190556040805160e360020a631c2d8fb302815260a860020a6a636f6e74726163746170690260048201529051600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750506040805180516004805460e260020a633e4baddd028452908301529151919750600160a060020a038816925063f92eb77491602482810192602092919082900301816000876161da5a03f115610002575050604051516007549095506000945060a060020a900460ff1615905061105c57600a5484111561105757600a54600d54670de0b6b3a7640000918603020492505b61107e565b600a5484101561107e57600a54600d54670de0b6b3a764000091869003020492505b60065483111561108e5760065492505b6006548390039150600083111561111857604080516005546007547f5928d37f000000000000000000000000000000000000000000000000000000008352600160a060020a0391821660048401528116602483015260448201869052915191871691635928d37f91606481810192600092909190829003018183876161da5a03f115610002575050505b600082111561117a576040805160055460e060020a63599efa6b028252600160a060020a0390811660048301526024820185905291519187169163599efa6b91604481810192600092909190829003018183876161da5a03f115610002575050505b6040805185815260208101849052808201859052905130600160a060020a0316917f89e690b1d5aaae14f3e85f108dc92d9ab3763a58d45aed8b59daedbbae8fe794919081900360600190a260008311156112285784600160a060020a0316634cc927d785336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506000604051808303816000876161da5a03f11561000257505050611282565b84600160a060020a0316634cc927d7600a60005054336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506000604051808303816000876161da5a03f115610002575050505b600054600160a060020a0316ff5b60156001820160ff166006811015610002578101549060ff8316600681101561000257015411156112c057610002565b60010161055e565b60015460a060020a900460ff166000146112e157610002565b600254600a0143116112f257610002565b6001546040805160e360020a631c2d8fb302815260a860020a6a636f6e74726163746170690260048201529051600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f11561000257505060408051805160055460065460e060020a63599efa6b028452600160a060020a03918216600485015260248401529251909450918416925063599efa6b916044808301926000929190829003018183876161da5a03f1156100025750505080600160a060020a0316632b68bb2d6040518160e060020a0281526004018090506000604051808303816000876161da5a03f115610002575050600054600160a060020a03169050ff5b6001546040805160e060020a6313bc6d4b02815233600160a060020a039081166004830152915191909216916313bc6d4b91602480830192602092919082900301816000876161da5a03f11561000257505060405151151590506106a85761000256", + "nonce": "16", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000002cccf5e0538493c235d1c5ef6580f77d99e91396" + } + }, + "0x70c9217d814985faef62b124420f8dfbddd96433": { + "balance": "0x4ef436dcbda6cd4a", + "code": "0x", + "nonce": "1634", + "storage": {} + }, + "0x7986bad81f4cbd9317f5a46861437dae58d69113": { + "balance": "0x0", + "code": "0x6060604052361561008d5760e060020a600035046302d05d3f811461009557806316c66cc6146100a75780631ab9075a146100d7578063213fe2b7146101125780639859387b1461013f578063988db79c1461015e578063a7f4377914610180578063b9858a281461019e578063c8e40fbf146101c0578063f4f2821b146101e8578063f905c15a14610209575b610212610002565b610214600054600160a060020a031681565b600160a060020a0360043581811660009081526005602052604081205461023193168114610257575060016101e3565b610212600435600254600160a060020a0316600014801590610108575060025433600160a060020a03908116911614155b1561025f57610002565b610214600435600160a060020a03811660009081526004602052604081205460ff16151561027557610002565b610212600435600254600160a060020a03166000141561029b57610002565b610212600435602435600254600160a060020a03166000141561050457610002565b61021260025433600160a060020a0390811691161461056757610002565b610212600435602435600254600160a060020a03166000141561057557610002565b610231600435600160a060020a03811660009081526004602052604090205460ff165b919050565b610212600435600254600090600160a060020a031681141561072057610002565b61024560035481565b005b60408051600160a060020a03929092168252519081900360200190f35b604080519115158252519081900360200190f35b60408051918252519081900360200190f35b5060006101e3565b60028054600160a060020a031916821790555b50565b50600160a060020a038181166000908152600460205260409020546101009004166101e3565b6002546040805160e060020a6313bc6d4b02815233600160a060020a039081166004830152915191909216916313bc6d4b91602482810192602092919082900301816000876161da5a03f11561000257505060405151151590506102fe57610002565b600160a060020a03811660009081526004602052604090205460ff161515610272576040516104028061092e833901809050604051809103906000f06004600050600083600160a060020a0316815260200190815260200160002060005060000160016101000a815481600160a060020a030219169083021790555060016004600050600083600160a060020a0316815260200190815260200160002060005060000160006101000a81548160ff0219169083021790555050565b600160a060020a03821660009081526004602052604090205460ff1615156104725760405161040280610d30833901809050604051809103906000f06004600050600084600160a060020a0316815260200190815260200160002060005060000160016101000a815481600160a060020a030219169083021790555060016004600050600084600160a060020a0316815260200190815260200160002060005060000160006101000a81548160ff021916908302179055505b600160a060020a03828116600090815260046020819052604080518184205460e060020a630a3b0a4f02825286861693820193909352905161010090920490931692630a3b0a4f926024828101939192829003018183876161da5a03f11561000257505050600160a060020a03811660009081526006602052604090208054600160a060020a031916831790555b5050565b6002546040805160e060020a6313bc6d4b02815233600160a060020a039081166004830152915191909216916313bc6d4b91602482810192602092919082900301816000876161da5a03f11561000257505060405151151590506103b957610002565b600254600160a060020a0316ff5b6002546040805160e060020a6313bc6d4b02815233600160a060020a039081166004830152915191909216916313bc6d4b91602482810192602092919082900301816000876161da5a03f11561000257505060405151151590506105d857610002565b600160a060020a03821660009081526004602052604090205460ff1615156106915760405161040280611132833901809050604051809103906000f06004600050600084600160a060020a0316815260200190815260200160002060005060000160016101000a815481600160a060020a030219169083021790555060016004600050600084600160a060020a0316815260200190815260200160002060005060000160006101000a81548160ff021916908302179055505b600160a060020a03828116600090815260046020819052604080518184205460e060020a630a3b0a4f02825286861693820193909352905161010090920490931692630a3b0a4f926024828101939192829003018183876161da5a03f11561000257505050600160a060020a031660009081526005602052604090208054600160a060020a0319169091179055565b6002546040805160e060020a6313bc6d4b02815233600160a060020a039081166004830152915191909216916313bc6d4b91602482810192602092919082900301816000876161da5a03f115610002575050604051511515905061078357610002565b50600160a060020a0381811660009081526005602090815260408083205490931680835260049091529190205460ff161561080f576040600081812054825160e260020a632e72bafd028152600160a060020a03868116600483015293516101009092049093169263b9caebf4926024828101939192829003018183876161da5a03f115610002575050505b600160a060020a03828116600090815260056020526040812054909116146108545760406000908120600160a060020a0384169091528054600160a060020a03191690555b50600160a060020a0381811660009081526006602090815260408083205490931680835260049091529190205460ff16156108e657600160a060020a038181166000908152604080518183205460e260020a632e72bafd028252868516600483015291516101009092049093169263b9caebf4926024828101939192829003018183876161da5a03f115610002575050505b600160a060020a03828116600090815260066020526040812054909116146105005760406000908120600160a060020a0384169091528054600160a060020a0319169055505056606060405260008054600160a060020a031916331790556103de806100246000396000f3606060405236156100615760e060020a600035046302d05d3f81146100695780630a3b0a4f1461007b5780630d327fa7146100f6578063524d81d314610109578063a7f4377914610114578063b9caebf414610132578063bbec3bae14610296575b6102ce610002565b6102d0600054600160a060020a031681565b6102ce600435600254600090600160a060020a03168114156102ed5760028054600160a060020a03199081168417808355600160a060020a03808616855260036020526040852060018101805493831694909316939093179091559154815461010060a860020a031916921661010002919091179055610372565b6102d0600254600160a060020a03165b90565b6102e3600154610106565b6102ce60005433600160a060020a039081169116146103c657610002565b6102ce600435600160a060020a038116600090815260036020526040812054819060ff16801561016457506001548190115b1561029157506040808220600180820154915461010090819004600160a060020a039081168087528587209093018054600160a060020a031916948216948517905583865293909420805461010060a860020a03191694820294909417909355600254909190811690841614156101e85760028054600160a060020a031916821790555b600254600160a060020a0390811690841614156102105760028054600160a060020a03191690555b6003600050600084600160a060020a0316815260200190815260200160002060006000820160006101000a81549060ff02191690556000820160016101000a815490600160a060020a0302191690556001820160006101000a815490600160a060020a03021916905550506001600081815054809291906001900391905055505b505050565b600160a060020a036004358181166000908152600360205260408120600101546002546102d09491821691168114156103d4576103d8565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60028054600160a060020a03908116835260036020526040808420805461010060a860020a0319808216610100808a029190911790935590829004841680875283872060019081018054600160a060020a03199081168b179091559654868a168952949097209687018054949095169390951692909217909255835416908202179091555b60016003600050600084600160a060020a0316815260200190815260200160002060005060000160006101000a81548160ff0219169083021790555060016000818150548092919060010191905055505050565b600054600160a060020a0316ff5b8091505b5091905056606060405260008054600160a060020a031916331790556103de806100246000396000f3606060405236156100615760e060020a600035046302d05d3f81146100695780630a3b0a4f1461007b5780630d327fa7146100f6578063524d81d314610109578063a7f4377914610114578063b9caebf414610132578063bbec3bae14610296575b6102ce610002565b6102d0600054600160a060020a031681565b6102ce600435600254600090600160a060020a03168114156102ed5760028054600160a060020a03199081168417808355600160a060020a03808616855260036020526040852060018101805493831694909316939093179091559154815461010060a860020a031916921661010002919091179055610372565b6102d0600254600160a060020a03165b90565b6102e3600154610106565b6102ce60005433600160a060020a039081169116146103c657610002565b6102ce600435600160a060020a038116600090815260036020526040812054819060ff16801561016457506001548190115b1561029157506040808220600180820154915461010090819004600160a060020a039081168087528587209093018054600160a060020a031916948216948517905583865293909420805461010060a860020a03191694820294909417909355600254909190811690841614156101e85760028054600160a060020a031916821790555b600254600160a060020a0390811690841614156102105760028054600160a060020a03191690555b6003600050600084600160a060020a0316815260200190815260200160002060006000820160006101000a81549060ff02191690556000820160016101000a815490600160a060020a0302191690556001820160006101000a815490600160a060020a03021916905550506001600081815054809291906001900391905055505b505050565b600160a060020a036004358181166000908152600360205260408120600101546002546102d09491821691168114156103d4576103d8565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60028054600160a060020a03908116835260036020526040808420805461010060a860020a0319808216610100808a029190911790935590829004841680875283872060019081018054600160a060020a03199081168b179091559654868a168952949097209687018054949095169390951692909217909255835416908202179091555b60016003600050600084600160a060020a0316815260200190815260200160002060005060000160006101000a81548160ff0219169083021790555060016000818150548092919060010191905055505050565b600054600160a060020a0316ff5b8091505b5091905056606060405260008054600160a060020a031916331790556103de806100246000396000f3606060405236156100615760e060020a600035046302d05d3f81146100695780630a3b0a4f1461007b5780630d327fa7146100f6578063524d81d314610109578063a7f4377914610114578063b9caebf414610132578063bbec3bae14610296575b6102ce610002565b6102d0600054600160a060020a031681565b6102ce600435600254600090600160a060020a03168114156102ed5760028054600160a060020a03199081168417808355600160a060020a03808616855260036020526040852060018101805493831694909316939093179091559154815461010060a860020a031916921661010002919091179055610372565b6102d0600254600160a060020a03165b90565b6102e3600154610106565b6102ce60005433600160a060020a039081169116146103c657610002565b6102ce600435600160a060020a038116600090815260036020526040812054819060ff16801561016457506001548190115b1561029157506040808220600180820154915461010090819004600160a060020a039081168087528587209093018054600160a060020a031916948216948517905583865293909420805461010060a860020a03191694820294909417909355600254909190811690841614156101e85760028054600160a060020a031916821790555b600254600160a060020a0390811690841614156102105760028054600160a060020a03191690555b6003600050600084600160a060020a0316815260200190815260200160002060006000820160006101000a81549060ff02191690556000820160016101000a815490600160a060020a0302191690556001820160006101000a815490600160a060020a03021916905550506001600081815054809291906001900391905055505b505050565b600160a060020a036004358181166000908152600360205260408120600101546002546102d09491821691168114156103d4576103d8565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60028054600160a060020a03908116835260036020526040808420805461010060a860020a0319808216610100808a029190911790935590829004841680875283872060019081018054600160a060020a03199081168b179091559654868a168952949097209687018054949095169390951692909217909255835416908202179091555b60016003600050600084600160a060020a0316815260200190815260200160002060005060000160006101000a81548160ff0219169083021790555060016000818150548092919060010191905055505050565b600054600160a060020a0316ff5b8091505b5091905056", + "nonce": "7", + "storage": { + "0xffc4df2d4f3d2cffad590bed6296406ab7926ca9e74784f74a95191fa069a174": "0x00000000000000000000000070c9217d814985faef62b124420f8dfbddd96433" + } + }, + "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f": { + "balance": "0x0", + "code": "0x606060405236156100ae5760e060020a600035046302d05d3f81146100b65780631ab9075a146100c85780632b68bb2d146101035780634cc927d7146101c557806351a34eb81461028e57806356ccb6f0146103545780635928d37f1461041d578063599efa6b146104e9578063759297bb146105b2578063771d50e11461067e578063a7f4377914610740578063f905c15a1461075e578063f92eb77414610767578063febf661214610836575b610902610002565b610904600054600160a060020a031681565b610902600435600254600160a060020a03166000148015906100f9575060025433600160a060020a03908116911614155b1561092057610002565b60025460e360020a631c2d8fb302606090815260aa60020a6a18dbdb9d1c9858dd18dd1b02606452610902916000918291600160a060020a03169063e16c7d989060849060209060248187876161da5a03f1156100025750505060405180519060200150905080600160a060020a03166316c66cc6336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f115610002575050604051511515905061094257610002565b61090260043560243560025460e360020a631c2d8fb302606090815260aa60020a6a18dbdb9d1c9858dd18dd1b026064526000918291600160a060020a039091169063e16c7d989060849060209060248187876161da5a03f1156100025750505060405180519060200150905080600160a060020a03166316c66cc6336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610a0d57610002565b61090260043560025460e360020a631c2d8fb302606090815260aa60020a6a18dbdb9d1c9858dd18dd1b026064526000918291600160a060020a039091169063e16c7d989060849060209060248187876161da5a03f1156100025750505060405180519060200150905080600160a060020a03166316c66cc6336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610ae957610002565b61090260043560243560025460e360020a631c2d8fb302606090815260aa60020a6a18dbdb9d1c9858dd18dd1b026064526000918291600160a060020a039091169063e16c7d989060849060209060248187876161da5a03f1156100025750505060405180519060200150905080600160a060020a03166316c66cc6336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610bbc57610002565b61090260043560243560443560025460e360020a631c2d8fb302606090815260aa60020a6a18dbdb9d1c9858dd18dd1b026064526000918291600160a060020a039091169063e16c7d989060849060209060248187876161da5a03f1156100025750505060405180519060200150905080600160a060020a03166316c66cc6336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610c9657610002565b61090260043560243560025460e360020a631c2d8fb302606090815260aa60020a6a18dbdb9d1c9858dd18dd1b026064526000918291600160a060020a039091169063e16c7d989060849060209060248187876161da5a03f1156100025750505060405180519060200150905080600160a060020a03166316c66cc6336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610de057610002565b61090260043560243560443560025460e360020a631c2d8fb302606090815260aa60020a6a18dbdb9d1c9858dd18dd1b026064526000918291600160a060020a039091169063e16c7d989060849060209060248187876161da5a03f1156100025750505060405180519060200150905080600160a060020a03166316c66cc6336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610ebb57610002565b60025460e360020a631c2d8fb302606090815260aa60020a6a18dbdb9d1c9858dd18dd1b02606452610902916000918291600160a060020a03169063e16c7d989060849060209060248187876161da5a03f1156100025750505060405180519060200150905080600160a060020a03166316c66cc6336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610f9e57610002565b61090260025433600160a060020a0390811691161461106957610002565b61090e60035481565b61090e60043560025460e360020a631c2d8fb302606090815260aa60020a6a18dbdb9d1c9858dd18dd1b026064526000918291600160a060020a039091169063e16c7d989060849060209060248187876161da5a03f1156100025750506040805180517ff92eb774000000000000000000000000000000000000000000000000000000008252600482018790529151919350600160a060020a038416925063f92eb774916024828101926020929190829003018188876161da5a03f11561000257505060405151949350505050565b61090260043560243560443560025460e360020a631c2d8fb302606090815260aa60020a6a18dbdb9d1c9858dd18dd1b026064526000918291600160a060020a039091169063e16c7d989060849060209060248187876161da5a03f1156100025750505060405180519060200150905080600160a060020a03166316c66cc6336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f115610002575050604051511515905061107757610002565b005b6060908152602090f35b60408051918252519081900360200190f35b6002805473ffffffffffffffffffffffffffffffffffffffff19168217905550565b6040805160025460e360020a631c2d8fb302825260aa60020a6a18dbdb9d1c9858dd18dd1b0260048301529151600160a060020a03929092169163e16c7d9891602481810192602092909190829003018188876161da5a03f1156100025750506040805180517f5ed61af000000000000000000000000000000000000000000000000000000000825233600160a060020a039081166004840152925190959286169350635ed61af092602483810193919291829003018183876161da5a03f115610002575050505050565b6040805160025460e360020a631c2d8fb302825260aa60020a6a18dbdb9d1c9858dd18dd1b0260048301529151600160a060020a03929092169163e16c7d9891602481810192602092909190829003018188876161da5a03f1156100025750506040805180517fab03fc2600000000000000000000000000000000000000000000000000000000825233600160a060020a03908116600484015260248301899052808816604484015292519095928616935063ab03fc2692606483810193919291829003018183876161da5a03f1156100025750505050505050565b6040805160025460e360020a631c2d8fb302825260aa60020a6a18dbdb9d1c9858dd18dd1b0260048301529151600160a060020a03929092169163e16c7d9891602481810192602092909190829003018188876161da5a03f1156100025750506040805180517f949ae47900000000000000000000000000000000000000000000000000000000825233600160a060020a0390811660048401526024830188905292519095928616935063949ae47992604483810193919291829003018183876161da5a03f11561000257505050505050565b6040805160025460e360020a631c2d8fb302825260b260020a691858d8dbdd5b9d18dd1b0260048301529151600160a060020a03929092169163e16c7d9891602481810192602092909190829003018188876161da5a03f1156100025750506040805180517f46d88e7d000000000000000000000000000000000000000000000000000000008252600160a060020a0380891660048401523381166024840152604483018890529251909592861693506346d88e7d92606483810193919291829003018183876161da5a03f1156100025750505050505050565b6040805160025460e360020a631c2d8fb302825260b260020a691858d8dbdd5b9d18dd1b0260048301529151600160a060020a03929092169163e16c7d9891602481810192602092909190829003018188876161da5a03f1156100025750506040805180517f5315cdde00000000000000000000000000000000000000000000000000000000825233600160a060020a039081166004840152808a16602484015260448301889052925190959286169350635315cdde92606483810193919291829003018183876161da5a03f115610002575050604080517f5928d37f00000000000000000000000000000000000000000000000000000000815233600160a060020a03908116600483015287166024820152604481018690529051635928d37f91606481810192600092909190829003018183876161da5a03f115610002575050505050505050565b6040805160025460e360020a631c2d8fb302825260b260020a691858d8dbdd5b9d18dd1b0260048301529151600160a060020a03929092169163e16c7d9891602481810192602092909190829003018188876161da5a03f1156100025750506040805180517fe68e401c00000000000000000000000000000000000000000000000000000000825233600160a060020a03908116600484015280891660248401526044830188905292519095928616935063e68e401c92606483810193919291829003018183876161da5a03f1156100025750505050505050565b6040805160025460e360020a631c2d8fb302825260b260020a691858d8dbdd5b9d18dd1b0260048301529151600160a060020a03929092169163e16c7d9891602481810192602092909190829003018188876161da5a03f1156100025750506040805180517f5152f381000000000000000000000000000000000000000000000000000000008252600160a060020a03808a1660048401528089166024840152604483018890523381166064840152925190959286169350635152f38192608483810193919291829003018183876161da5a03f115610002575050505050505050565b6040805160025460e360020a631c2d8fb302825260aa60020a6a18dbdb9d1c9858dd18dd1b0260048301529151600160a060020a03929092169163e16c7d9891602481810192602092909190829003018188876161da5a03f1156100025750506040805180517f056d447000000000000000000000000000000000000000000000000000000000825233600160a060020a03908116600484015292519095928616935063056d447092602483810193919291829003018183876161da5a03f115610002575050505050565b600254600160a060020a0316ff5b6040805160025460e360020a631c2d8fb302825260aa60020a6a18dbdb9d1c9858dd18dd1b0260048301529151600160a060020a03929092169163e16c7d9891602481810192602092909190829003018188876161da5a03f1156100025750506040805180517f3ae1005c00000000000000000000000000000000000000000000000000000000825233600160a060020a039081166004840152808a166024840152808916604484015260648301889052925190959286169350633ae1005c92608483810193919291829003018183876161da5a03f11561000257505050505050505056", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000002cccf5e0538493c235d1c5ef6580f77d99e91396" + } + }, + "0xc212e03b9e060e36facad5fd8f4435412ca22e6b": { + "balance": "0x0", + "code": "0x606060405236156101745760e060020a600035046302d05d3f811461017c57806304a7fdbc1461018e5780630e90f957146101fb5780630fb5a6b41461021257806314baa1b61461021b57806317fc45e21461023a5780632b096926146102435780632e94420f1461025b578063325a19f11461026457806336da44681461026d5780633f81a2c01461027f5780633fc306821461029757806345ecd3d7146102d45780634665096d146102dd5780634e71d92d146102e657806351a34eb8146103085780636111bb951461032d5780636f265b93146103445780637e9014e11461034d57806390ba009114610360578063927df5e014610393578063a7f437791461046c578063ad8f50081461046e578063bc6d909414610477578063bdec3ad114610557578063c19d93fb1461059a578063c9503fe2146105ad578063e0a73a93146105b6578063ea71b02d146105bf578063ea8a1af0146105d1578063ee4a96f9146105f3578063f1ff78a01461065c575b61046c610002565b610665600054600160a060020a031681565b6040805160c081810190925261046c9160049160c4918390600690839083908082843760408051808301909152929750909561018495509193509091908390839080828437509095505050505050600554600090600160a060020a0390811633909116146106a857610002565b61068260015460a060020a900460ff166000145b90565b61069660085481565b61046c600435600154600160a060020a03166000141561072157610002565b610696600d5481565b610696600435600f8160068110156100025750015481565b61069660045481565b61069660035481565b610665600554600160a060020a031681565b61069660043560158160068110156100025750015481565b6106966004355b600b54600f5460009160028202808203928083039290810191018386101561078357601054840186900394505b50505050919050565b61069660025481565b61069660095481565b61046c600554600090600160a060020a03908116339091161461085857610002565b61046c600435600554600090600160a060020a03908116339091161461092e57610002565b6106826001805460a060020a900460ff161461020f565b610696600b5481565b61068260075460a060020a900460ff1681565b6106966004355b600b54601554600091600282028082039280830392908101910183861015610a6c5760165494506102cb565b61046c6004356024356044356040805160015460e360020a631c2d8fb302825260b260020a691858d8dbdd5b9d18dd1b02600483015291516000928392600160a060020a03919091169163e16c7d9891602481810192602092909190829003018187876161da5a03f1156100025750505060405180519060200150905080600160a060020a031663c4b0c96a336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610b4657610002565b005b610696600a5481565b61046c60006000600060006000600160009054906101000a9004600160a060020a0316600160a060020a031663e16c7d986040518160e060020a028152600401808060b260020a691858d8dbdd5b9d18dd1b0281526020015060200190506020604051808303816000876161da5a03f1156100025750505060405180519060200150905080600160a060020a031663c4b0c96a336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610f1757610002565b61046c5b60015b60058160ff16101561071e57600f6001820160ff166006811015610002578101549060ff83166006811015610002570154101561129057610002565b61069660015460a060020a900460ff1681565b61069660065481565b610696600c5481565b610665600754600160a060020a031681565b61046c600554600090600160a060020a0390811633909116146112c857610002565b6040805160c081810190925261046c9160049160c4918390600690839083908082843760408051808301909152929750909561018495509193509091908390839080828437509095505050505050600154600090600160a060020a03168114156113fb57610002565b610696600e5481565b60408051600160a060020a03929092168252519081900360200190f35b604080519115158252519081900360200190f35b60408051918252519081900360200190f35b5060005b60068160ff16101561070857828160ff166006811015610002576020020151600f60ff831660068110156100025701558160ff82166006811015610002576020020151601560ff831660068110156100025701556001016106ac565b61071061055b565b505050565b600e8054820190555b50565b6040805160015460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f115610002575050604051511515905061071557610002565b83861015801561079257508286105b156107b457600f546010546011548689039082030291909104900394506102cb565b8286101580156107c55750600b5486105b156107e757600f546011546012548589039082030291909104900394506102cb565b600b5486108015906107f857508186105b1561081d57600b54600f546012546013549289039281039290920204900394506102cb565b81861015801561082c57508086105b1561084e57600f546013546014548489039082030291909104900394506102cb565b60145494506102cb565b60015460a060020a900460ff1660001461087157610002565b600254600a01431161088257610002565b6040805160015460e360020a631c2d8fb302825260a860020a6a636f6e74726163746170690260048301529151600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750505060405180519060200150905080600160a060020a031663771d50e16040518160e060020a0281526004018090506000604051808303816000876161da5a03f1156100025750505050565b60015460a060020a900460ff1660001461094757610002565b600254600a01431161095857610002565b6040805160015460e360020a631c2d8fb302825260a860020a6a636f6e74726163746170690260048301529151600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750506040805180517f51a34eb8000000000000000000000000000000000000000000000000000000008252600482018690529151919350600160a060020a03841692506351a34eb8916024808301926000929190829003018183876161da5a03f11561000257505050600b8290554360025560408051838152905130600160a060020a0316917fa609f6bd4ad0b4f419ddad4ac9f0d02c2b9295c5e6891469055cf73c2b568fff919081900360200190a25050565b838610158015610a7b57508286105b15610a9d576015546016546017548689039082900302919091040194506102cb565b828610158015610aae5750600b5486105b15610ad0576015546017546018548589039082900302919091040194506102cb565b600b548610801590610ae157508186105b15610b0657600b546015546018546019549289039281900392909202040194506102cb565b818610158015610b1557508086105b15610b3757601554601954601a548489039082900302919091040194506102cb565b601a54860181900394506102cb565b60015460a060020a900460ff16600014610b5f57610002565b6001805460a060020a60ff02191660a060020a17908190556040805160e360020a631c2d8fb302815260a860020a6a636f6e74726163746170690260048201529051600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750506040805180516004805460e260020a633e4baddd028452908301529151919450600160a060020a038516925063f92eb77491602482810192602092919082900301816000876161da5a03f115610002575050604080518051600a556005547ffebf661200000000000000000000000000000000000000000000000000000000825233600160a060020a03908116600484015216602482015260448101879052905163febf661291606480820192600092909190829003018183876161da5a03f115610002575050508215610cc7576007805473ffffffffffffffffffffffffffffffffffffffff191633179055610dbb565b6040805160055460065460e060020a63599efa6b028352600160a060020a039182166004840152602483015291519184169163599efa6b91604481810192600092909190829003018183876161da5a03f115610002575050604080516006547f56ccb6f000000000000000000000000000000000000000000000000000000000825233600160a060020a03166004830152602482015290516356ccb6f091604480820192600092909190829003018183876161da5a03f115610002575050600580546007805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a038416179091551633179055505b6007805460a060020a60ff02191660a060020a87810291909117918290556008544301600955900460ff1615610df757600a54610e039061029e565b600a54610e0b90610367565b600c55610e0f565b600c555b600c54670de0b6b3a7640000850204600d55600754600554604080517f759297bb000000000000000000000000000000000000000000000000000000008152600160a060020a039384166004820152918316602483015260448201879052519184169163759297bb91606481810192600092909190829003018183876161da5a03f11561000257505060408051600754600a54600d54600554600c5460a060020a850460ff161515865260208601929092528486019290925260608401529251600160a060020a0391821694509281169230909116917f3b3d1986083d191be01d28623dc19604728e29ae28bdb9ba52757fdee1a18de2919081900360800190a45050505050565b600954431015610f2657610002565b6001805460a060020a900460ff1614610f3e57610002565b6001805460a060020a60ff0219167402000000000000000000000000000000000000000017908190556040805160e360020a631c2d8fb302815260a860020a6a636f6e74726163746170690260048201529051600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750506040805180516004805460e260020a633e4baddd028452908301529151919750600160a060020a038816925063f92eb77491602482810192602092919082900301816000876161da5a03f115610002575050604051516007549095506000945060a060020a900460ff1615905061105c57600a5484111561105757600a54600d54670de0b6b3a7640000918603020492505b61107e565b600a5484101561107e57600a54600d54670de0b6b3a764000091869003020492505b60065483111561108e5760065492505b6006548390039150600083111561111857604080516005546007547f5928d37f000000000000000000000000000000000000000000000000000000008352600160a060020a0391821660048401528116602483015260448201869052915191871691635928d37f91606481810192600092909190829003018183876161da5a03f115610002575050505b600082111561117a576040805160055460e060020a63599efa6b028252600160a060020a0390811660048301526024820185905291519187169163599efa6b91604481810192600092909190829003018183876161da5a03f115610002575050505b6040805185815260208101849052808201859052905130600160a060020a0316917f89e690b1d5aaae14f3e85f108dc92d9ab3763a58d45aed8b59daedbbae8fe794919081900360600190a260008311156112285784600160a060020a0316634cc927d785336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506000604051808303816000876161da5a03f11561000257505050611282565b84600160a060020a0316634cc927d7600a60005054336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506000604051808303816000876161da5a03f115610002575050505b600054600160a060020a0316ff5b60156001820160ff166006811015610002578101549060ff8316600681101561000257015411156112c057610002565b60010161055e565b60015460a060020a900460ff166000146112e157610002565b600254600a0143116112f257610002565b6001546040805160e360020a631c2d8fb302815260a860020a6a636f6e74726163746170690260048201529051600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f11561000257505060408051805160055460065460e060020a63599efa6b028452600160a060020a03918216600485015260248401529251909450918416925063599efa6b916044808301926000929190829003018183876161da5a03f1156100025750505080600160a060020a0316632b68bb2d6040518160e060020a0281526004018090506000604051808303816000876161da5a03f115610002575050600054600160a060020a03169050ff5b6001546040805160e060020a6313bc6d4b02815233600160a060020a039081166004830152915191909216916313bc6d4b91602480830192602092919082900301816000876161da5a03f11561000257505060405151151590506106a85761000256", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000002cccf5e0538493c235d1c5ef6580f77d99e91396", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000006195", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x5842545553440000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x00000000000000000000000070c9217d814985faef62b124420f8dfbddd96433", + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000000000000000000008ac7230489e80000", + "0x000000000000000000000000000000000000000000000000000000000000000b": "0x0000000000000000000000000000000000000000000000283c7b9181eca20000" + } + }, + "0xcf00ffd997ad14939736f026006498e3f099baaf": { + "balance": "0x0", + "code": "0x606060405236156100cf5760e060020a600035046302d05d3f81146100d7578063031e7f5d146100e95780631ab9075a1461010b5780632243118a1461014657806327aad68a1461016557806338a699a4146101da5780635188f996146101f8578063581d5d601461021e57806381738c5914610246578063977da54014610269578063a07421ce14610288578063a7f43779146102be578063bdbdb086146102dc578063e1c7111914610303578063f4f2821b14610325578063f905c15a1461034a578063f92eb77414610353575b610387610002565b610389600054600160a060020a031681565b610387600435602435600254600160a060020a0316600014156103a857610002565b610387600435600254600160a060020a031660001480159061013c575060025433600160a060020a03908116911614155b1561042957610002565b610387600435600254600160a060020a03166000141561044b57610002565b6102ac60043560008181526004602081815260408320547f524d81d3000000000000000000000000000000000000000000000000000000006060908152610100909104600160a060020a031692839263524d81d3926064928188876161da5a03f1156100025750506040515192506103819050565b61039c60043560008181526004602052604090205460ff165b919050565b6103876004356024356002546000908190600160a060020a031681141561079457610002565b61038760043560243560025460009081908190600160a060020a031681141561080457610002565b61038960043560008181526004602052604081205460ff1615156109e357610002565b610387600435600254600160a060020a0316600014156109fb57610002565b600435600090815260096020526040902054670de0b6b3a764000090810360243502045b60408051918252519081900360200190f35b61038760025433600160a060020a03908116911614610a9257610002565b600435600090815260086020526040902054670de0b6b3a7640000602435909102046102ac565b610387600435602435600254600160a060020a031660001415610aa057610002565b61038760043560025460009081908190600160a060020a0316811415610b3657610002565b6102ac60035481565b6102ac600435600081815260076020908152604080832054600690925290912054670de0b6b3a76400000204805b50919050565b005b600160a060020a03166060908152602090f35b15156060908152602090f35b60025460e060020a6313bc6d4b02606090815233600160a060020a03908116606452909116906313bc6d4b906084906020906024816000876161da5a03f11561000257505060405151151590506103fe57610002565b60008281526004602052604090205460ff16151561041b57610002565b600860205260406000205550565b6002805473ffffffffffffffffffffffffffffffffffffffff19168217905550565b60025460e060020a6313bc6d4b02606090815233600160a060020a03908116606452909116906313bc6d4b906084906020906024816000876161da5a03f11561000257505060405151151590506104a157610002565b604080516000838152600460205291909120805460ff1916600117905561040280610de2833901809050604051809103906000f0600460005060008360001916815260200190815260200160002060005060000160016101000a815481600160a060020a030219169083021790555066470de4df8200006008600050600083600019168152602001908152602001600020600050819055506703782dace9d9000060096000506000836000191681526020019081526020016000206000508190555050565b600460005060008560001916815260200190815260200160002060005060000160019054906101000a9004600160a060020a0316915081600160a060020a031663524d81d36040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151821415905061060057838152600660209081526040808320839055600790915281208190555b81600160a060020a0316630a3b0a4f846040518260e060020a0281526004018082600160a060020a031681526020019150506000604051808303816000876161da5a03f11561000257505050600160a060020a038316808252600560209081526040808420879055805160e160020a6364a81ff102815290518694670de0b6b3a7640000949363c9503fe29360048181019492939183900301908290876161da5a03f11561000257505060408051805160e060020a636f265b930282529151919291636f265b939160048181019260209290919082900301816000876161da5a03f11561000257505050604051805190602001500204600660005060008660001916815260200190815260200160002060008282825054019250508190555080600160a060020a031663c9503fe26040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050506040518051906020015060076000506000866000191681526020019081526020016000206000828282505401925050819055505b50505050565b60025460e060020a6313bc6d4b02606090815233600160a060020a03908116606452909116906313bc6d4b9060849060209060248187876161da5a03f11561000257505060405151151590506107e957610002565b8381526004602052604081205460ff16151561056657610002565b60025460e060020a6313bc6d4b02606090815233600160a060020a03908116606452909116906313bc6d4b9060849060209060248187876161da5a03f115610002575050604051511515905061085957610002565b849250670de0b6b3a764000083600160a060020a031663c9503fe26040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575060408051805160e160020a6364a81ff102825291519189028590049650600481810192602092909190829003018188876161da5a03f11561000257505060408051805160e060020a636f265b930282529151919291636f265b9391600481810192602092909190829003018189876161da5a03f115610002575050506040518051906020015002049050806006600050600085600160a060020a0316632e94420f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750604080518051855260208681528286208054989098039097557f2e94420f00000000000000000000000000000000000000000000000000000000815290518896600483810193919291829003018187876161da5a03f115610002575050604080515183526020939093525020805490910190555050505050565b60409020546101009004600160a060020a03166101f3565b60025460e060020a6313bc6d4b02606090815233600160a060020a03908116606452909116906313bc6d4b906084906020906024816000876161da5a03f1156100025750506040515115159050610a5157610002565b60008181526004602052604090205460ff161515610a6e57610002565b6040600020805474ffffffffffffffffffffffffffffffffffffffffff1916905550565b600254600160a060020a0316ff5b60025460e060020a6313bc6d4b02606090815233600160a060020a03908116606452909116906313bc6d4b906084906020906024816000876161da5a03f1156100025750506040515115159050610af657610002565b60008281526004602052604090205460ff161515610b1357610002565b670de0b6b3a7640000811115610b2857610002565b600960205260406000205550565b60025460e060020a6313bc6d4b02606090815233600160a060020a03908116606452909116906313bc6d4b9060849060209060248187876161da5a03f1156100025750506040515115159050610b8b57610002565b600160a060020a038416815260056020908152604080832054808452600490925282205490935060ff161515610bc057610002565b600460005060008460001916815260200190815260200160002060005060000160019054906101000a9004600160a060020a0316915081600160a060020a031663b9caebf4856040518260e060020a0281526004018082600160a060020a031681526020019150506000604051808303816000876161da5a03f115610002575050506005600050600085600160a060020a0316815260200190815260200160002060005060009055839050600082600160a060020a031663524d81d36040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051519190911115905061078e57670de0b6b3a764000081600160a060020a031663c9503fe26040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e060020a636f265b930282529151919291636f265b939160048181019260209290919082900301816000876161da5a03f11561000257505050604051805190602001500204600660005060008560001916815260200190815260200160002060008282825054039250508190555080600160a060020a031663c9503fe26040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050506040518051906020015060076000506000856000191681526020019081526020016000206000828282505403925050819055505050505056606060405260008054600160a060020a031916331790556103de806100246000396000f3606060405236156100615760e060020a600035046302d05d3f81146100695780630a3b0a4f1461007b5780630d327fa7146100f6578063524d81d314610109578063a7f4377914610114578063b9caebf414610132578063bbec3bae14610296575b6102ce610002565b6102d0600054600160a060020a031681565b6102ce600435600254600090600160a060020a03168114156102ed5760028054600160a060020a03199081168417808355600160a060020a03808616855260036020526040852060018101805493831694909316939093179091559154815461010060a860020a031916921661010002919091179055610372565b6102d0600254600160a060020a03165b90565b6102e3600154610106565b6102ce60005433600160a060020a039081169116146103c657610002565b6102ce600435600160a060020a038116600090815260036020526040812054819060ff16801561016457506001548190115b1561029157506040808220600180820154915461010090819004600160a060020a039081168087528587209093018054600160a060020a031916948216948517905583865293909420805461010060a860020a03191694820294909417909355600254909190811690841614156101e85760028054600160a060020a031916821790555b600254600160a060020a0390811690841614156102105760028054600160a060020a03191690555b6003600050600084600160a060020a0316815260200190815260200160002060006000820160006101000a81549060ff02191690556000820160016101000a815490600160a060020a0302191690556001820160006101000a815490600160a060020a03021916905550506001600081815054809291906001900391905055505b505050565b600160a060020a036004358181166000908152600360205260408120600101546002546102d09491821691168114156103d4576103d8565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60028054600160a060020a03908116835260036020526040808420805461010060a860020a0319808216610100808a029190911790935590829004841680875283872060019081018054600160a060020a03199081168b179091559654868a168952949097209687018054949095169390951692909217909255835416908202179091555b60016003600050600084600160a060020a0316815260200190815260200160002060005060000160006101000a81548160ff0219169083021790555060016000818150548092919060010191905055505050565b600054600160a060020a0316ff5b8091505b5091905056", + "nonce": "3", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000002cccf5e0538493c235d1c5ef6580f77d99e91396", + "0x3571d73f14f31a1463bd0a2f92f7fde1653d4e1ead7aedf4b0a5df02f16092ab": "0x0000000000000000000000000000000000000000000007d634e4c55188be0000", + "0x4e64fe2d1b72d95a0a31945cc6e4f4e524ac5ad56d6bd44a85ec7bc9cc0462c0": "0x000000000000000000000000000000000000000000000002b5e3af16b1880000" + } + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "117124093", + "extraData": "0xd5830105008650617269747986312e31322e31826d61", + "gasLimit": "4707788", + "hash": "0xad325e4c49145fb7a4058a68ac741cc8607a71114e23fc88083c7e881dd653e7", + "miner": "0x00714b9ac97fd6bd9325a059a70c9b9fa94ce050", + "mixHash": "0x0af918f65cb4af04b608fc1f14a849707696986a0e7049e97ef3981808bcc65f", + "nonce": "0x38dee147326a8d40", + "number": "25000", + "stateRoot": "0xc5d6bbcd46236fcdcc80b332ffaaa5476b980b01608f9708408cfef01b58bd5b", + "timestamp": "1479891517", + "totalDifficulty": "1895410389427" + }, + "input": "0xf88b8206628504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb80000000000000000000000000000000000000000000000280faf689c35ac00002aa0a7ee5b7877811bf671d121b40569462e722657044808dc1d6c4f1e4233ec145ba0417e7543d52b65738d9df419cbe40a708424f4d54b0fc145c0a64545a2bb1065", + "result": [ + { + "action": { + "callType": "call", + "from": "0x70c9217d814985faef62b124420f8dfbddd96433", + "gas": "0x37b38", + "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "value": "0x0" + }, + "blockNumber": 25001, + "result": { + "gasUsed": "0x1810b", + "output": "0x" + }, + "subtraces": 2, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "gas": "0x31217", + "input": "0xe16c7d98636f6e7472616374617069000000000000000000000000000000000000000000", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x334", + "output": "0x000000000000000000000000b4fe7aa695b326c9d219158d2ca50db77b39f99f" + }, + "subtraces": 0, + "traceAddress": [0], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "gas": "0x30b4a", + "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", + "to": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0xedb7", + "output": "0x" + }, + "subtraces": 4, + "traceAddress": [1], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", + "gas": "0x2a68d", + "input": "0xe16c7d98636f6e747261637463746c000000000000000000000000000000000000000000", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x334", + "output": "0x0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690" + }, + "subtraces": 0, + "traceAddress": [1, 0], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", + "gas": "0x29f35", + "input": "0x16c66cc6000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b", + "to": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0xf8d", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 2, + "traceAddress": [1, 1], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x23ac9", + "input": "0xe16c7d98636f6e7472616374646200000000000000000000000000000000000000000000", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x334", + "output": "0x0000000000000000000000007986bad81f4cbd9317f5a46861437dae58d69113" + }, + "subtraces": 0, + "traceAddress": [1, 1, 0], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x23366", + "input": "0x16c66cc6000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b", + "to": "0x7986bad81f4cbd9317f5a46861437dae58d69113", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x273", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 0, + "traceAddress": [1, 1, 1], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", + "gas": "0x28a9e", + "input": "0xe16c7d98636f6e747261637463746c000000000000000000000000000000000000000000", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x334", + "output": "0x0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690" + }, + "subtraces": 0, + "traceAddress": [1, 2], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xb4fe7aa695b326c9d219158d2ca50db77b39f99f", + "gas": "0x283b9", + "input": "0x949ae479000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b0000000000000000000000000000000000000000000000280faf689c35ac0000", + "to": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0xc51c", + "output": "0x" + }, + "subtraces": 12, + "traceAddress": [1, 3], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x21d79", + "input": "0x13bc6d4b000000000000000000000000b4fe7aa695b326c9d219158d2ca50db77b39f99f", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x24d", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 0, + "traceAddress": [1, 3, 0], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x2165b", + "input": "0xe16c7d986d61726b65746462000000000000000000000000000000000000000000000000", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x334", + "output": "0x000000000000000000000000cf00ffd997ad14939736f026006498e3f099baaf" + }, + "subtraces": 0, + "traceAddress": [1, 3, 1], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x20ee1", + "input": "0x581d5d60000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b0000000000000000000000000000000000000000000000280faf689c35ac0000", + "to": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x5374", + "output": "0x" + }, + "subtraces": 6, + "traceAddress": [1, 3, 2], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x1a8e8", + "input": "0x13bc6d4b0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x24d", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 0, + "traceAddress": [1, 3, 2, 0], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x1a2c6", + "input": "0xc9503fe2", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x3cb", + "output": "0x0000000000000000000000000000000000000000000000008ac7230489e80000" + }, + "subtraces": 0, + "traceAddress": [1, 3, 2, 1], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x19b72", + "input": "0xc9503fe2", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x3cb", + "output": "0x0000000000000000000000000000000000000000000000008ac7230489e80000" + }, + "subtraces": 0, + "traceAddress": [1, 3, 2, 2], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x19428", + "input": "0x6f265b93", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x305", + "output": "0x0000000000000000000000000000000000000000000000283c7b9181eca20000" + }, + "subtraces": 0, + "traceAddress": [1, 3, 2, 3], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x18d45", + "input": "0x2e94420f", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x229", + "output": "0x5842545553440000000000000000000000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [1, 3, 2, 4], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "gas": "0x1734e", + "input": "0x2e94420f", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x229", + "output": "0x5842545553440000000000000000000000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [1, 3, 2, 5], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x1b6c1", + "input": "0xe16c7d986c6f676d67720000000000000000000000000000000000000000000000000000", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x334", + "output": "0x0000000000000000000000002a98c5f40bfa3dee83431103c535f6fae9a8ad38" + }, + "subtraces": 0, + "traceAddress": [1, 3, 3], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x1af69", + "input": "0x2e94420f", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x229", + "output": "0x5842545553440000000000000000000000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [1, 3, 4], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x1a91d", + "input": "0x0accce0600000000000000000000000000000000000000000000000000000000000000025842545553440000000000000000000000000000000000000000000000000000000000000000000000000000c212e03b9e060e36facad5fd8f4435412ca22e6b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "to": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x12fa", + "output": "0x" + }, + "subtraces": 1, + "traceAddress": [1, 3, 5], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "gas": "0x143a5", + "input": "0x13bc6d4b0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x24d", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 0, + "traceAddress": [1, 3, 5, 0], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x19177", + "input": "0xe16c7d986c6f676d67720000000000000000000000000000000000000000000000000000", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x334", + "output": "0x0000000000000000000000002a98c5f40bfa3dee83431103c535f6fae9a8ad38" + }, + "subtraces": 0, + "traceAddress": [1, 3, 6], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x18a22", + "input": "0x2e94420f", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x229", + "output": "0x5842545553440000000000000000000000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [1, 3, 7], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x18341", + "input": "0xe16c7d986d61726b65746462000000000000000000000000000000000000000000000000", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x334", + "output": "0x000000000000000000000000cf00ffd997ad14939736f026006498e3f099baaf" + }, + "subtraces": 0, + "traceAddress": [1, 3, 8], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x17bec", + "input": "0x2e94420f", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x229", + "output": "0x5842545553440000000000000000000000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [1, 3, 9], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x1764e", + "input": "0xf92eb7745842545553440000000000000000000000000000000000000000000000000000", + "to": "0xcf00ffd997ad14939736f026006498e3f099baaf", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x45c", + "output": "0x00000000000000000000000000000000000000000000002816d180e30c390000" + }, + "subtraces": 0, + "traceAddress": [1, 3, 10], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3e9286eafa2db8101246c2131c09b49080d00690", + "gas": "0x16e62", + "input": "0x645a3b72584254555344000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002816d180e30c390000", + "to": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0xebb", + "output": "0x" + }, + "subtraces": 1, + "traceAddress": [1, 3, 11], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x2a98c5f40bfa3dee83431103c535f6fae9a8ad38", + "gas": "0x108ba", + "input": "0x13bc6d4b0000000000000000000000003e9286eafa2db8101246c2131c09b49080d00690", + "to": "0x2cccf5e0538493c235d1c5ef6580f77d99e91396", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x24d", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 0, + "traceAddress": [1, 3, 11, 0], + "type": "call" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json new file mode 100644 index 000000000000..3a03ffc0fa96 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json @@ -0,0 +1,120 @@ +{ + "context": { + "difficulty": "31927752", + "gasLimit": "4707788", + "miner": "0x5659922ce141eedbc2733678f9806c77b4eebee8", + "number": "11495", + "timestamp": "1479735917" + }, + "genesis": { + "alloc": { + "0x13204f5d64c28326fd7bd05fd4ea855302d7f2ff": { + "balance": "0x0", + "code": "0x606060405236156100825760e060020a60003504630a0313a981146100875780630a3b0a4f146101095780630cd40fea1461021257806329092d0e1461021f5780634cd06a5f146103295780635dbe47e8146103395780637a9e5410146103d9578063825db5f7146103e6578063a820b44d146103f3578063efa52fb31461047a575b610002565b34610002576104fc600435600060006000507342b02b5deeb78f34cd5ac896473b63e6c99a71a26333556e849091846000604051602001526040518360e060020a028152600401808381526020018281526020019250505060206040518083038186803b156100025760325a03f415610002575050604051519150505b919050565b346100025761051060043560006000507342b02b5deeb78f34cd5ac896473b63e6c99a71a2637d65837a9091336000604051602001526040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038186803b156100025760325a03f4156100025750506040515115905061008257604080517f21ce24d4000000000000000000000000000000000000000000000000000000008152600060048201819052600160a060020a038416602483015291517342b02b5deeb78f34cd5ac896473b63e6c99a71a2926321ce24d49260448082019391829003018186803b156100025760325a03f415610002575050505b50565b3461000257610512600181565b346100025761051060043560006000507342b02b5deeb78f34cd5ac896473b63e6c99a71a2637d65837a9091336000604051602001526040518360e060020a0281526004018083815260200182600160a060020a031681526020019250505060206040518083038186803b156100025760325a03f4156100025750506040515115905061008257604080517f89489a87000000000000000000000000000000000000000000000000000000008152600060048201819052600160a060020a038416602483015291517342b02b5deeb78f34cd5ac896473b63e6c99a71a2926389489a879260448082019391829003018186803b156100025760325a03f4156100025750505061020f565b3461000257610528600435610403565b34610002576104fc600435604080516000602091820181905282517f7d65837a00000000000000000000000000000000000000000000000000000000815260048101829052600160a060020a0385166024820152925190927342b02b5deeb78f34cd5ac896473b63e6c99a71a292637d65837a92604480840193829003018186803b156100025760325a03f4156100025750506040515191506101049050565b3461000257610512600c81565b3461000257610512600081565b3461000257610528600061055660005b600060006000507342b02b5deeb78f34cd5ac896473b63e6c99a71a263685a1f3c9091846000604051602001526040518360e060020a028152600401808381526020018281526020019250505060206040518083038186803b156100025760325a03f4156100025750506040515191506101049050565b346100025761053a600435600060006000507342b02b5deeb78f34cd5ac896473b63e6c99a71a263f775b6b59091846000604051602001526040518360e060020a028152600401808381526020018281526020019250505060206040518083038186803b156100025760325a03f4156100025750506040515191506101049050565b604080519115158252519081900360200190f35b005b6040805160ff9092168252519081900360200190f35b60408051918252519081900360200190f35b60408051600160a060020a039092168252519081900360200190f35b90509056", + "nonce": "1", + "storage": { + "0x4d140b25abf3c71052885c66f73ce07cff141c1afabffdaf5cba04d625b7ebcc": "0x0000000000000000000000000000000000000000000000000000000000000001" + } + }, + "0x269296dddce321a6bcbaa2f0181127593d732cba": { + "balance": "0x0", + "code": "0x606060405236156101275760e060020a60003504630cd40fea811461012c578063173825d9146101395780631849cb5a146101c7578063285791371461030f5780632a58b3301461033f5780632cb0d48a146103565780632f54bf6e1461036a578063332b9f061461039d5780633ca8b002146103c55780633df4ddf4146103d557806341c0e1b5146103f457806347799da81461040557806362a51eee1461042457806366907d13146104575780637065cb48146104825780637a9e541014610496578063825db5f7146104a3578063949d225d146104b0578063a51687df146104c7578063b4da4e37146104e6578063b4e6850b146104ff578063bd7474ca14610541578063e75623d814610541578063e9938e1114610555578063f5d241d314610643575b610002565b3461000257610682600181565b34610002576106986004356106ff335b60006001600a9054906101000a9004600160a060020a0316600160a060020a0316635dbe47e8836000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100025760325a03f1156100025750506040515191506103989050565b3461000257604080516101008082018352600080835260208084018290528385018290526060808501839052608080860184905260a080870185905260c080880186905260e09788018690526001605060020a0360043581168752600586529589902089519788018a528054808816808a52605060020a91829004600160a060020a0316978a01889052600183015463ffffffff8082169d8c018e905264010000000082048116988c01899052604060020a90910416958a018690526002830154948a01859052600390920154808916938a01849052049096169690970186905293969495949293604080516001605060020a03998a16815297891660208901529590971686860152600160a060020a03909316606086015263ffffffff9182166080860152811660a08501521660c083015260e08201929092529051908190036101000190f35b346100025761069a60043560018054600091829160ff60f060020a909104161515141561063d5761072833610376565b34610002576106ae6004546001605060020a031681565b34610002576106986004356108b333610149565b346100025761069a6004355b600160a060020a03811660009081526002602052604090205460ff1615156001145b919050565b34610002576106986001805460ff60f060020a9091041615151415610913576108ed33610376565b346100025761069a600435610149565b34610002576106ae6003546001605060020a03605060020a9091041681565b346100025761069861091533610149565b34610002576106ae6003546001605060020a0360a060020a9091041681565b346100025761069a60043560243560018054600091829160ff60f060020a909104161515141561095e5761092633610376565b34610002576106986004356001805460ff60f060020a909104161515141561072557610a8b33610376565b3461000257610698600435610aa533610149565b3461000257610682600c81565b3461000257610682600081565b34610002576106ae6003546001605060020a031681565b34610002576106ca600154600160a060020a03605060020a9091041681565b346100025761069a60015460ff60f060020a9091041681565b346100025761069a60043560243560443560643560843560a43560c43560018054600091829160ff60f060020a9091041615151415610b5857610ad233610376565b3461000257610698600435610bd633610149565b34610002576106e6600435604080516101008181018352600080835260208084018290528385018290526060808501839052608080860184905260a080870185905260c080880186905260e09788018690526001605060020a03808b168752600586529589902089519788018a5280548088168952600160a060020a03605060020a918290041696890196909652600181015463ffffffff8082169b8a019b909b5264010000000081048b1695890195909552604060020a90940490981691860182905260028301549086015260039091015480841696850196909652940416918101919091525b50919050565b346100025761069a60043560243560443560643560843560a43560018054600091829160ff60f060020a9091041615151415610c8e57610bfb33610376565b6040805160ff9092168252519081900360200190f35b005b604080519115158252519081900360200190f35b604080516001605060020a039092168252519081900360200190f35b60408051600160a060020a039092168252519081900360200190f35b6040805163ffffffff9092168252519081900360200190f35b1561012757600160a060020a0381166000908152600260205260409020805460ff191690555b50565b1561063d57506001605060020a0380831660009081526005602052604090208054909116151561075b576000915061063d565b604080516101008101825282546001605060020a038082168352600160a060020a03605060020a92839004166020840152600185015463ffffffff80821695850195909552640100000000810485166060850152604060020a90049093166080830152600284015460a0830152600384015480841660c08401520490911660e0820152610817905b8051600354600090819060016001605060020a0390911611610c995760038054605060020a60f060020a0319169055610ddf565b600380546001605060020a031981166000196001605060020a03928316011782558416600090815260056020526040812080547fffff000000000000000000000000000000000000000000000000000000000000168155600181810180546bffffffffffffffffffffffff191690556002820192909255909101805473ffffffffffffffffffffffffffffffffffffffff19169055915061063d565b1561012757600180547fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660f060020a8302179055610725565b1561091357600480546001605060020a031981166001605060020a039091166001011790555b565b156101275733600160a060020a0316ff5b1561095e57506001605060020a03808416600090815260056020526040902080549091161515610965576000915061095e565b600191505b5092915050565b60038101546001605060020a0384811691161415610986576001915061095e565b604080516101008101825282546001605060020a038082168352600160a060020a03605060020a92839004166020840152600185015463ffffffff80821695850195909552640100000000810485166060850152604060020a90049093166080830152600284015460a0830152600384015480841660c08401520490911660e0820152610a12906107e3565b61095983825b80546003546001605060020a0391821691600091161515610de55760038054605060020a60a060020a031916605060020a84021760a060020a69ffffffffffffffffffff02191660a060020a84021781558301805473ffffffffffffffffffffffffffffffffffffffff19169055610ddf565b1561072557600480546001605060020a0319168217905550565b1561012757600160a060020a0381166000908152600260205260409020805460ff19166001179055610725565b15610b5857506001605060020a038088166000908152600560205260409020805490911615610b645760009150610b58565b6004546001605060020a0390811690891610610b3057600480546001605060020a03191660018a011790555b6003805460016001605060020a03821681016001605060020a03199092169190911790915591505b50979650505050505050565b80546001605060020a0319168817605060020a60f060020a031916605060020a880217815560018101805463ffffffff1916871767ffffffff0000000019166401000000008702176bffffffff00000000000000001916604060020a860217905560028101839055610b048982610a18565b156101275760018054605060020a60f060020a031916605060020a8302179055610725565b15610c8e57506001605060020a03808816600090815260056020526040902080549091161515610c2e5760009150610c8e565b8054605060020a60f060020a031916605060020a88021781556001808201805463ffffffff1916881767ffffffff0000000019166401000000008802176bffffffff00000000000000001916604060020a87021790556002820184905591505b509695505050505050565b6003546001605060020a03848116605060020a909204161415610d095760e084015160038054605060020a928302605060020a60a060020a031990911617808255919091046001605060020a031660009081526005602052604090200180546001605060020a0319169055610ddf565b6003546001605060020a0384811660a060020a909204161415610d825760c08401516003805460a060020a92830260a060020a69ffffffffffffffffffff021990911617808255919091046001605060020a03166000908152600560205260409020018054605060020a60a060020a0319169055610ddf565b505060c082015160e08301516001605060020a0380831660009081526005602052604080822060039081018054605060020a60a060020a031916605060020a8702179055928416825290200180546001605060020a031916831790555b50505050565b6001605060020a0384161515610e6457600380546001605060020a03605060020a9182900481166000908152600560205260409020830180546001605060020a0319908116871790915583548785018054918590049093168402605060020a60a060020a03199182161790911690915582549185029116179055610ddf565b506001605060020a038381166000908152600560205260409020600390810180549185018054605060020a60a060020a0319908116605060020a94859004909516808502959095176001605060020a0319168817909155815416918402919091179055801515610ef4576003805460a060020a69ffffffffffffffffffff02191660a060020a8402179055610ddf565b6003808401546001605060020a03605060020a9091041660009081526005602052604090200180546001605060020a031916831790555050505056", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x000113204f5d64c28326fd7bd05fd4ea855302d7f2ff00000000000000000000" + } + }, + "0x42b02b5deeb78f34cd5ac896473b63e6c99a71a2": { + "balance": "0x0", + "code": "0x6504032353da7150606060405236156100695760e060020a60003504631bf7509d811461006e57806321ce24d41461008157806333556e84146100ec578063685a1f3c146101035780637d65837a1461011757806389489a8714610140578063f775b6b5146101fc575b610007565b61023460043560006100fd82600061010d565b610246600435602435600160a060020a03811660009081526020839052604081205415156102cb57826001016000508054806001018281815481835581811511610278576000838152602090206102789181019083015b808211156102d057600081556001016100d8565b610248600435602435600182015481105b92915050565b6102346004356024355b60018101906100fd565b610248600435602435600160a060020a03811660009081526020839052604090205415156100fd565b61024660043560243580600160a060020a031632600160a060020a03161415156101f857600160a060020a038116600090815260208390526040902054156101f857600160a060020a038116600090815260208390526040902054600183018054909160001901908110156100075760009182526020808320909101805473ffffffffffffffffffffffffffffffffffffffff19169055600160a060020a038316825283905260408120556002820180546000190190555b5050565b61025c60043560243560008260010160005082815481101561000757600091825260209091200154600160a060020a03169392505050565b60408051918252519081900360200190f35b005b604080519115158252519081900360200190f35b60408051600160a060020a039092168252519081900360200190f35b50505060009283526020808420909201805473ffffffffffffffffffffffffffffffffffffffff191686179055600160a060020a0385168352908590526040909120819055600284018054600101905590505b505050565b509056", + "nonce": "1", + "storage": {} + }, + "0xa529806c67cc6486d4d62024471772f47f6fd672": { + "balance": "0x67820e39ac8fe9800", + "code": "0x", + "nonce": "68", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "31912170", + "extraData": "0xd783010502846765746887676f312e372e33856c696e7578", + "gasLimit": "4712388", + "hash": "0x0855914bdc581bccdc62591fd438498386ffb59ea4d5361ed5c3702e26e2c72f", + "miner": "0x334391aa808257952a462d1475562ee2106a6c90", + "mixHash": "0x64bb70b8ca883cadb8fbbda2c70a861612407864089ed87b98e5de20acceada6", + "nonce": "0x684129f283aaef18", + "number": "11494", + "stateRoot": "0x7057f31fe3dab1d620771adad35224aae43eb70e94861208bc84c557ff5b9d10", + "timestamp": "1479735912", + "totalDifficulty": "90744064339" + }, + "input": "0xf889448504a817c800832dc6c094269296dddce321a6bcbaa2f0181127593d732cba80a47065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e29a080ed81e4c5e9971a730efab4885566e2c868cd80bd4166d0ed8c287fdf181650a069d7c49215e3d4416ad239cd09dbb71b9f04c16b33b385d14f40b618a7a65115", + "result": [ + { + "action": { + "callType": "call", + "from": "0xa529806c67cc6486d4d62024471772f47f6fd672", + "gas": "0x2d6e28", + "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", + "to": "0x269296dddce321a6bcbaa2f0181127593d732cba", + "value": "0x0" + }, + "blockNumber": 11495, + "result": { + "gasUsed": "0xbd55", + "output": "0x" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x269296dddce321a6bcbaa2f0181127593d732cba", + "gas": "0x2cae73", + "input": "0x5dbe47e8000000000000000000000000a529806c67cc6486d4d62024471772f47f6fd672", + "to": "0x13204f5d64c28326fd7bd05fd4ea855302d7f2ff", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0xa9d", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 1, + "traceAddress": [0], + "type": "call" + }, + { + "action": { + "callType": "delegatecall", + "from": "0x13204f5d64c28326fd7bd05fd4ea855302d7f2ff", + "gas": "0x2bf459", + "input": "0x7d65837a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a529806c67cc6486d4d62024471772f47f6fd672", + "to": "0x42b02b5deeb78f34cd5ac896473b63e6c99a71a2", + "value": "0x0" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x2aa", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 0, + "traceAddress": [0, 0], + "type": "call" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json new file mode 100644 index 000000000000..800a6a4288de --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json @@ -0,0 +1,103 @@ +{ + "genesis": { + "number": "566098", + "hash": "0xba134562590a59291892395a29c5088899c2c64d720135dad88f7f076cf55f5f", + "nonce": "0x4b281be9594e3eb3", + "mixHash": "0xdb4ec386166d9c0dc9ba147755ecbb87af9f0a22563cbda02c799efa4e29db6e", + "stateRoot": "0xfc01993ad96a8fb8790a093cea4f505f8db1b0e1143c5f57bb1d173db0baa9e3", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "difficulty": "1926740", + "totalDifficulty": "482216286599", + "extraData": "0xd883010906846765746888676f312e31332e35856c696e7578", + "gasLimit": "19388354", + "timestamp": "1577558314", + "alloc": { + "0x6ab9dd83108698b9ca8d03af3c7eb91c0e54c3fc": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0xcbd5b9b25d1c38c2aad", + "nonce": "134969", + "code": "0x", + "storage": {} + }, + "0x91765918420bcb5ad22ee0997abed04056705798": { + "balance": "0x0", + "nonce": "1", + "code": "0x366000803760206000366000736ab9dd83108698b9ca8d03af3c7eb91c0e54c3fc60325a03f41560015760206000f3", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "566099", + "difficulty": "1927680", + "timestamp": "1577558317", + "gasLimit": "19369422", + "miner": "0x774c398d763161f55b66a646f17edda4addad2ca" + }, + "input": "0xf87983020f3985746a52880083015f909491765918420bcb5ad22ee0997abed04056705798888ac7230489e80000884e45375a4741394181a1a04b7260723fd02830754916b3bdf1537b6a851a7ae27c7e9296cfe1fc8275ec08a049d32158988eb717d61b4503b27c7583037c067daba1eb56f4bdfafc1b0045f6", + "result": [ + { + "action": { + "callType": "call", + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "gas": "0x10b68", + "input": "0x4e45375a47413941", + "to": "0x91765918420bcb5ad22ee0997abed04056705798", + "value": "0x8ac7230489e80000" + }, + "blockHash": "0xb05cc5c8f11df2b5d53ced342ee79e2805785f04c2f40add4539f27bd349f74e", + "blockNumber": 566099, + "result": { + "gasUsed": "0x5721", + "output": "0x4e45375a47413941000000000000000000000000000000000000000000000000" + }, + "subtraces": 1, + "traceAddress": [], + "transactionHash": "0x6e26dffe2f66186f03a2c36a16a4cd9724d07622c83746f1e35f988515713d4b", + "transactionPosition": 10, + "type": "call" + }, + { + "action": { + "callType": "delegatecall", + "from": "0x91765918420bcb5ad22ee0997abed04056705798", + "gas": "0x10463", + "input": "0x4e45375a47413941", + "to": "0x6ab9dd83108698b9ca8d03af3c7eb91c0e54c3fc", + "value": "0x8ac7230489e80000" + }, + "blockHash": "0xb05cc5c8f11df2b5d53ced342ee79e2805785f04c2f40add4539f27bd349f74e", + "blockNumber": 566099, + "result": { + "gasUsed": "0x0", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [ + 0 + ], + "transactionHash": "0x6e26dffe2f66186f03a2c36a16a4cd9724d07622c83746f1e35f988515713d4b", + "transactionPosition": 10, + "type": "call" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json new file mode 100644 index 000000000000..3b44a5e2cd99 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json @@ -0,0 +1,95 @@ +{ + "genesis": { + "difficulty": "4683014", + "extraData": "0x537465762d63676574682d76312e31312e34", + "gasLimit": "9435044", + "hash": "0x3452ca5005cb73cd60dfa488a7b124251168e564491f80eb66765e79d78cfd95", + "miner": "0x415aa6292d1db797a467b22139704956c030e62f", + "mixHash": "0x6037612618507ae70c74a72bc2580253662971db959cfbc06d3f8527d4d01575", + "nonce": "0x314fc90dee5e39a2", + "number": "1555274", + "stateRoot": "0x795751f3f96a5de1fd3944ddd78cbfe4ef10491e1086be47609869a30929d0e5", + "timestamp": "1590795228", + "totalDifficulty": "2242595605834", + "alloc": { + "0x0000000000000000000000000000000000000001": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x6242e3ccf48e66425fb1", + "nonce": "264882", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "1555275", + "difficulty": "4683014", + "timestamp": "1590795244", + "gasLimit": "9444256", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf9011583040ab2843b9aca008301a9c88080b8c0601b565b6000555b005b630badf00d6003565b63c001f00d6003565b7319e7e376e7c213b7e7e7e46cc70a5dd086daff2a7f22ae6da6b482f9b1b19b0b897c3fd43884180a1c5ee361e1107a1bc635649dda600052601b603f537f16433dce375ce6dc8151d3f0a22728bc4a1d9fd6ed39dfd18b4609331937367f6040527f306964c0cf5d74f04129fdc60b54d35b596dde1bf89ad92cb4123318f4c0e40060605260206080607f60006000600161fffff2156007576080511460125760095681a1a07682fc43dbe1fb13c6474f5e70e121c826dd996168d8bb1d8ca7a63470127b46a00a25b308ba417b7770899e8f98a3f0c14aa9bf7db0edacfe4e78d00dbbd3c31e", + "result": [ + { + "type": "create", + "action": { + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "value": "0x0", + "gas": "0xcf08", + "init": "0x601b565b6000555b005b630badf00d6003565b63c001f00d6003565b7319e7e376e7c213b7e7e7e46cc70a5dd086daff2a7f22ae6da6b482f9b1b19b0b897c3fd43884180a1c5ee361e1107a1bc635649dda600052601b603f537f16433dce375ce6dc8151d3f0a22728bc4a1d9fd6ed39dfd18b4609331937367f6040527f306964c0cf5d74f04129fdc60b54d35b596dde1bf89ad92cb4123318f4c0e40060605260206080607f60006000600161fffff21560075760805114601257600956" + }, + "result": { + "gasUsed": "0x137e5", + "code": "0x", + "address": "0x1a05d76017ca02010533a470e05e8925a0380d8f" + }, + "traceAddress": [], + "subtraces": 1, + "transactionPosition": 18, + "transactionHash": "0xc1c42a325856d513523aec464811923b2e2926f54015c7ba37877064cf889803", + "blockNumber": 1555275, + "blockHash": "0x80945caaff2fc67253cbb0217d2e5a307afde943929e97d8b36e58b88cbb02fd", + "time": "453.925µs" + }, + { + "type": "call", + "action": { + "from": "0x1a05d76017ca02010533a470e05e8925a0380d8f", + "to": "0x0000000000000000000000000000000000000001", + "value": "0x0", + "gas": "0xc8c6", + "input": "0x22ae6da6b482f9b1b19b0b897c3fd43884180a1c5ee361e1107a1bc635649dda000000000000000000000000000000000000000000000000000000000000001b16433dce375ce6dc8151d3f0a22728bc4a1d9fd6ed39dfd18b4609331937367f306964c0cf5d74f04129fdc60b54d35b596dde1bf89ad92cb4123318f4c0e4", + "callType": "callcode" + }, + "result": { + "gasUsed": "0xbb8", + "output": "0x00000000000000000000000019e7e376e7c213b7e7e7e46cc70a5dd086daff2a" + }, + "traceAddress": [0], + "subtraces": 0, + "transactionPosition": 18, + "transactionHash": "0xc1c42a325856d513523aec464811923b2e2926f54015c7ba37877064cf889803", + "blockNumber": 1555275, + "blockHash": "0x80945caaff2fc67253cbb0217d2e5a307afde943929e97d8b36e58b88cbb02fd" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json new file mode 100644 index 000000000000..d33375bfd220 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json @@ -0,0 +1,832 @@ +{ + "genesis": { + "number": "559197", + "hash": "0x0742a2bfab0452e2c634f3685b7e49ceb065c7000609b2b73f086e01fd1dfb58", + "nonce": "0x3060ad521440e1c2", + "mixHash": "0x59e7d4ae6cc3c38d23dac3f869b21984c7ba8f38070f4116a4941d9c403b6299", + "stateRoot": "0x68418fb5cf4afa9b807dc079e8cdde0e148ac2c8afb378e675465b5bed1fbd02", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "difficulty": "1813945", + "totalDifficulty": "469107641961", + "extraData": "0xd883010906846765746888676f312e31332e35856c696e7578", + "gasLimit": "6321166", + "timestamp": "1577471202", + "alloc": { + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0xc5e6fdae52af83f7e28", + "nonce": "77947", + "code": "0x", + "storage": {} + }, + "0x774c398d763161f55b66a646f17edda4addad2ca": { + "balance": "0xf09ef316eff819ee488", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc": { + "balance": "0x0", + "nonce": "1", + "code": "0x60006121df537c01000000000000000000000000000000000000000000000000000000006000350463b041b2858114156100d257600435604052780100000000000000000000000000000000000000000000000060606060599059016000905260038152604051816020015260008160400152809050205404606052606051151561008f57600060a052602060a0f35b604051601c604459905901600090520163e0e9a17b601c82035260605160048201526020610100602483600030602d5a03f1506101005190501460c052602060c0f35b632cce81aa81141561019957600435610120526001610120511280156100f85780610143565b78010000000000000000000000000000000000000000000000006060606059905901600090526003815266040000000000025481602001526000816040015280905020540461012051135b905015610157576000610180526020610180f35b601c604459905901600090520163e0e9a17b601c82035261012051600482015260206101c0602483600030602d5a03f1506101c05190506101a05260206101a0f35b63e0e9a17b8114156102e957600435610120526604000000000002546101e0526007610200525b610120517801000000000000000000000000000000000000000000000000606060605990590160009052600381526101e05181602001526000816040015280905020540413156102da575b6102005160050a610120517801000000000000000000000000000000000000000000000000606060605990590160009052600381526101e051816020015260008160400152809050205404031215610269576000610200511361026c565b60005b1561028157600161020051036102005261020b565b7c01000000000000000000000000000000000000000000000000000000006102005160200260020a606060605990590160009052600381526101e05181602001526001816040015280905020540204546101e0526101c0565b6101e051610280526020610280f35b63cef887b08114156103e757365990590160009052366004823760043560208201016102c0526024356102e052506060601c61014c5990590160009052016390fa337d601c8203526102c0516020601f602083035101046020026020018360048401526020820360648401528060c8840152808401935050506102e051602482015233604482015281600401599059016000905260648160648460006004601cf161039057fe5b60648101925060c882015180808582606487015160006004600a8705601201f16103b657fe5b5080840193505080830360206103a08284600030602d5a03f1506103a0519050905090509050610300526020610300f35b6390fa337d81141561065f57365990590160009052366004823760043560208201016102c0526024356102e0526044356103e052505a610400526020601c608c599059016000905201632b861629601c8203526102c0516020601f6020830351010460200260200183600484015260208203602484015280604884015280840193505050816004015990590160009052602481602484600060046015f161048a57fe5b602481019250604882015180808582602487015160006004600a8705601201f16104b057fe5b5080840193505080830360206104408284600030602d5a03f15061044051905090509050905061042052610420511561065e576102c05160208103516020599059016000905260208183856000600287604801f150805190509050905061046052602059905901600090526020816020610460600060026068f1508051905060005b6020811215610552578181601f031a816105400153600181019050610532565b5050610540516101e0526102e0516c010000000000000000000000006103e0510217606060605990590160009052600381526101e05181602001526003816040015280905020555a61058052700100000000000000000000000000000000660400000000000154046105a0526104006105a0516103ff02056105c0526104006105a05161040102056105e0526105c0513a12156105f6576105c05161060052610615565b6105e0513a131561060e576105e05161060052610614565b3a610600525b5b6105805161040051036106005160020202610620526106205170010000000000000000000000000000000061060051021766040000000000015561042051610640526020610640f35b5b63d467ae0381141561073257600435604052602435610660526106605134121515610725576000341315610718576c01000000000000000000000000606060605990590160009052600381526040518160200152600381604001528090502054046103e0526000600060006000346103e051611388f115156106dd57fe5b601c60405990590160009052013481526103e0517f15e746bf513b8a58e4265cc1162d7fc445da5c9b1928d7cfcde2582735d4677f602083a2505b60016106a05260206106a0f35b60006106c05260206106c0f35b63ea4971ee811415610851576004356101e0526024356102e0526044356103e052601c606459905901600090520163d467ae03601c8203526101e05160048201526604000000000001546fffffffffffffffffffffffffffffffff16602482015260206106e060448334306123555a03f1506106e051905015156107bd576000610700526020610700f35b606060605990590160009052600381526101e05181602001526003816040015280905020546bffffffffffffffffffffffff166102e0511215610844576102e0516c010000000000000000000000006103e0510217606060605990590160009052600381526101e05181602001526003816040015280905020556001610760526020610760f35b6000610780526020610780f35b6387def0818114156108a3576004356101e0526c01000000000000000000000000606060605990590160009052600381526101e0518160200152600381604001528090502054046107a05260206107a0f35b630aece23c8114156108f4576004356101e052606060605990590160009052600381526101e05181602001526003816040015280905020546bffffffffffffffffffffffff166107e05260206107e0f35b63fa14df6b811415610926576604000000000001546fffffffffffffffffffffffffffffffff16610820526020610820f35b63b8c48f8c811415610b1b576004356101e0526024356108405260443561086052600066040000000000035414151561096a576000610880526020610880f3610976565b60016604000000000003555b6101e051660400000000000255606060605990590160009052600381526101e05181602001526000816040015280905020546108a0526108a0610840518060181a82538060191a600183015380601a1a600283015380601b1a600383015380601c1a600483015380601d1a600583015380601e1a600683015380601f1a600783015350506108a051606060605990590160009052600381526101e0518160200152600081604001528090502055606060605990590160009052600381526101e051816020015260008160400152809050205461094052601061094001610860518060101a82538060111a60018301538060121a60028301538060131a60038301538060141a60048301538060151a60058301538060161a60068301538060171a60078301538060181a60088301538060191a600983015380601a1a600a83015380601b1a600b83015380601c1a600c83015380601d1a600d83015380601e1a600e83015380601f1a600f830153505061094051606060605990590160009052600381526101e051816020015260008160400152809050205560016109e05260206109e0f35b632b86162981141561179457365990590160009052366004823760043560208201016102c0525060483560005b6020811215610b68578181601f031a81610a600153600181019050610b48565b5050610a6051610a00526102c05160208103516020599059016000905260208183856000600287604801f1508051905090509050610a8052602059905901600090526020816020610a80600060026068f1508051905060005b6020811215610be1578181601f031a81610b600153600181019050610bc1565b5050610b60516101e05270010000000000000000000000000000000070010000000000000000000000000000000060606060599059016000905260038152610a005181602001526000816040015280905020540204610b8052610b80511515610c8b57601c602059905901600090520161272e6101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a3506000610bc0526020610bc0f35b700100000000000000000000000000000000700100000000000000000000000000000000606060605990590160009052600381526101e05181602001526000816040015280905020540204610be0526000610be051141515610d2e57601c60205990590160009052016127386101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a3506000610c20526020610c20f35b608c35610c40526301000000610c405160031a0262010000610c405160021a02610100610c405160011a02610c405160001a010101610c60526301000000610c605104610ca05262ffffff610c605116610cc0526003610ca051036101000a610cc05102610c805260006101e0511315610db057610c80516101e05112610db3565b60005b1561174d57780100000000000000000000000000000000000000000000000060606060599059016000905260038152610a00518160200152600081604001528090502054046001016101205260806080599059016000905260038152610a005181602001526002816040015260008160600152809050206002810154610d405250610d405160081a610d405160091a61010002610d4051600a1a6201000002610d4051600b1a630100000002010101610d005260006107e0610120510614158015610e7e5780610e8b565b6001660400000000000054145b905015610f0257610d0051610c6051141515610eae576000610d00511415610eb1565b60005b15610efd57601c602059905901600090520161271a6101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a3506000610da0526020610da0f35b6111b4565b6301000000610d005104610de05262ffffff610d005116610e00526003610de051036101000a610e005102610dc05260806080599059016000905260038152610a005181602001526002816040015260008160600152809050206002810154610e605250610e605160041a610e605160051a61010002610e605160061a6201000002610e605160071a630100000002010101610e2052601c604459905901600090520163e0e9a17b601c8203526107e0610120510360048201526020610ec0602483600030602d5a03f150610ec0519050610ea05260806080599059016000905260038152610ea05181602001526002816040015260008160600152809050206002810154610f205250610f205160041a610f205160051a61010002610f205160061a6201000002610f205160071a630100000002010101610ee052610ee051610e20510362049d408112156110595762049d4090505b6249d40081131561106b576249d40090505b62127500610dc0518202047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8113156110ba577bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90505b600860076000835b80156110d9576002810490506001820191506110c2565b5080905001046000600382131515611103578160030360080260020a62ffffff841602905061111a565b6003820360080260020a8304905062ffffff811690505b6280000081161561113357610100810490506001820191505b6301000000820281179050905090509050610f6052610f6051610c6051141515611164576000610f60511415611167565b60005b156111b357601c60205990590160009052016127246101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a3506000611040526020611040f35b5b6101e0516101e0516101e05166040000000000005455606060605990590160009052600381526101e0518160200152600081604001528090502054611060526008611060016604000000000000548060181a82538060191a600183015380601a1a600283015380601b1a600383015380601c1a600483015380601d1a600583015380601e1a600683015380601f1a6007830153505061106051606060605990590160009052600381526101e0518160200152600081604001528090502055600166040000000000005401660400000000000055606060605990590160009052600381526101e0518160200152600081604001528090502054611100526111006001780100000000000000000000000000000000000000000000000060606060599059016000905260038152610a0051816020015260008160400152809050205404018060181a82538060191a600183015380601a1a600283015380601b1a600383015380601c1a600483015380601d1a600583015380601e1a600683015380601f1a6007830153505061110051606060605990590160009052600381526101e051816020015260008160400152809050205560006111c05278010000000000000000000000000000000000000000000000006801000000000000000060606060599059016000905260038152610a0051816020015260008160400152809050205402046111e0526111c06111e05180601c1a825380601d1a600183015380601e1a600283015380601f1a600383015350506001611260525b6008611260511215611515576112605160050a611280526001611280517801000000000000000000000000000000000000000000000000606060605990590160009052600381526101e05181602001526000816040015280905020540407141561148757611260516004026111c0016111e05180601c1a825380601d1a600183015380601e1a600283015380601f1a60038301535050611505565b611260516004026111c0017c01000000000000000000000000000000000000000000000000000000006112605160200260020a60606060599059016000905260038152610a00518160200152600181604001528090502054020480601c1a825380601d1a600183015380601e1a600283015380601f1a600383015350505b60016112605101611260526113ec565b6111c051606060605990590160009052600381526101e05181602001526001816040015280905020555050608060805990590160009052600381526101e051816020015260028160400152600081606001528090502060005b600281121561159057806020026102c05101518282015560018101905061156e565b700100000000000000000000000000000000600003816020026102c051015116828201555050610c80517bffff0000000000000000000000000000000000000000000000000000056113e0526113e051610b805101610be052606060605990590160009052600381526101e051816020015260008160400152809050205461140052601061140001610be0518060101a82538060111a60018301538060121a60028301538060131a60038301538060141a60048301538060151a60058301538060161a60068301538060171a60078301538060181a60088301538060191a600983015380601a1a600a83015380601b1a600b83015380601c1a600c83015380601d1a600d83015380601e1a600e83015380601f1a600f830153505061140051606060605990590160009052600381526101e0518160200152600081604001528090502055660400000000000354610be051121515611703576101e051660400000000000255610be0516604000000000003555b601c6020599059016000905201610120516101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a350610120516114a05260206114a0f35b601c602059905901600090520161276a6101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a35060006114c05260206114c0f35b630f5995ce8114156119a157365990590160009052366004823760043560208201016114e05260243561150052604435602082010161152052606435604052506114e05160208103516020599059016000905260208183856000600287604801f150805190509050905061156052602059905901600090526020816020611560600060026068f1508051905060005b6020811215611843578181601f031a816116400153600181019050611823565b50506116405161154052604060206114e051035114156118a457601c6020599059016000905201614e52611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a3506000611660526020611660f35b6080601c6101ac59905901600090520163bd136cb3601c8203526115405160048201526115005160248201526115205160208103516020026020018360448401526020820360c48401528061014884015280840193505050604051606482015281600401599059016000905260848160848460006004601ff161192357fe5b6084810192506101488201518080858260c487015160006004600a8705601201f161194a57fe5b508084019350508083036020611680828434306123555a03f15061168051905090509050905061042052600161042051141561199357611540516116a05260206116a0f36119a0565b60006116c05260206116c0f35b5b63bd136cb3811415611d8c573659905901600090523660048237600435611540526024356115005260443560208201016115205260643560405250601c606459905901600090520163d467ae03601c82035260405160048201526060606059905901600090526003815260405181602001526003816040015280905020546bffffffffffffffffffffffff166024820152602061170060448334306123555a03f1506117005190501515611a9757601c6020599059016000905201614e2a611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a350614e2a611720526020611720f35b601c6044599059016000905201633d73b705601c82035260405160048201526020611740602483600030602d5a03f15061174051905015611b1a57601c6020599059016000905201614e34611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a350614e34611760526020611760f35b601c604459905901600090520163b041b285601c82035260405160048201526020611780602483600030602d5a03f1506117805190501515611b9e57601c6020599059016000905201614e3e611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a350614e3e6117a05260206117a0f35b6060601c61014c59905901600090520163b7129afb601c8203526115405160048201526115005160248201526115205160208103516020026020018360448401526020820360a4840152806101088401528084019350505081600401599059016000905260648160648460006004601cf1611c1557fe5b6064810192506101088201518080858260a487015160006004600a8705601201f1611c3c57fe5b5080840193505080830360206117e08284600030602d5a03f1506117e05190509050905090506117c0526080608059905901600090526003815260405181602001526002816040015260008160600152809050207c01000000000000000000000000000000000000000000000000000000006002820154046401000000006001830154020160005b6020811215611ce4578181601f031a816118a00153600181019050611cc4565b50506118a051905061180052611800516117c0511415611d4457601c60205990590160009052016001611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a35060016118c05260206118c0f35b601c6020599059016000905201614e48611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a350614e486118e05260206118e0f35b63318a3fee81141561205657365990590160009052366004823760043560208201016114e0526024356115005260443560208201016115205260643560405260843561190052506080601c6101ac599059016000905201630f5995ce601c8203526114e0516020601f6020830351010460200260200183600484015260208203608484015280610108840152808401935050506115005160248201526115205160208103516020026020018360448401526020820360c48401528061014884015280840193505050604051606482015281600401599059016000905260848160848460006004601ff1611e7b57fe5b60848101925061010882015180808582608487015160006004600a8705601201f1611ea257fe5b508084019350506101488201518080858260c487015160006004600a8705601201f1611eca57fe5b508084019350508083036020611920828434306123555a03f15061192051905090509050905061154052600061154051141515612010576040601c60ec599059016000905201631c0b6367601c8203526114e0516020601f6020830351010460200260200183600484015260208203604484015280608884015280840193505050611540516024820152816004015990590160009052604481604484600060046018f1611f7357fe5b604481019250608882015180808582604487015160006004600a8705601201f1611f9957fe5b5080840193505080830360206119608284600061190051602d5a03f15061196051905090509050905061194052601c602059905901600090520161194051611540517f2d0d11d0f27e21fab56a8712078721096066b7faaa8540a3ea566e70b97de2d4600084a35061194051611980526020611980f35b601c602059905901600090520161753a60007f2d0d11d0f27e21fab56a8712078721096066b7faaa8540a3ea566e70b97de2d4600084a35061753a6119a05260206119a0f35b6309dd0e81811415612076576604000000000002546119c05260206119c0f35b63023948728114156120d2577801000000000000000000000000000000000000000000000000606060605990590160009052600381526604000000000002548160200152600081604001528090502054046119e05260206119e0f35b632c181929811415612139577001000000000000000000000000000000007001000000000000000000000000000000006060606059905901600090526003815266040000000000025481602001526000816040015280905020540204611a20526020611a20f35b637ca823d58114156122af576604000000000002546101e052700100000000000000000000000000000000700100000000000000000000000000000000606060605990590160009052600381526101e05181602001526000816040015280905020540204611a60526000611260525b600a61126051121561224c57608060805990590160009052600381526101e05181602001526002816040015260008160600152809050207c01000000000000000000000000000000000000000000000000000000006001820154046401000000008254020160005b6020811215612230578181601f031a81611b200153600181019050612210565b5050611b205190506101e05260016112605101611260526121a8565b700100000000000000000000000000000000700100000000000000000000000000000000606060605990590160009052600381526101e05181602001526000816040015280905020540204611b4052611b4051611a605103611b80526020611b80f35b63b7129afb81141561246a57365990590160009052366004823760043561154052602435611500526044356020820101611520525061154051611ba0526020611520510351611bc0526000611260525b611bc05161126051121561245b5761126051602002611520510151611be05260026115005107611c00526001611c0051141561234a57611be051611c2052611ba051611c4052612368565b6000611c0051141561236757611ba051611c2052611be051611c40525b5b60405990590160009052611c205160005b6020811215612399578181601f031a81611ca00153600181019050612379565b5050611ca0518152611c405160005b60208112156123c8578181601f031a81611d2001536001810190506123a8565b5050611d2051602082015260205990590160009052602081604084600060026088f15080519050611d4052602059905901600090526020816020611d40600060026068f1508051905060005b6020811215612434578181601f031a81611de00153600181019050612414565b5050611de0519050611ba052600261150051056115005260016112605101611260526122ff565b611ba051611e00526020611e00f35b633d73b70581141561255b576004356040526604000000000002546101e0526000611260525b600661126051121561254e576101e05160405114156124b6576001611e20526020611e20f35b608060805990590160009052600381526101e05181602001526002816040015260008160600152809050207c01000000000000000000000000000000000000000000000000000000006001820154046401000000008254020160005b6020811215612532578181601f031a81611ec00153600181019050612512565b5050611ec05190506101e0526001611260510161126052612490565b6000611ee0526020611ee0f35b631f794436811415612737576004356101e052601c606459905901600090520163d467ae03601c8203526101e0516004820152606060605990590160009052600381526101e05181602001526003816040015280905020546bffffffffffffffffffffffff1660248201526020611f2060448334306123555a03f150611f20519050151561265657601c602059905901600090520160006101e0517f60ab231f060fa320acea170017564b7ee77f477e6465a8c964380cffb270aaf4600084a350602159905901600090526001815260006020820152602081019050602060408203526020601f6020830351604001010460200260408203f3505b601c602059905901600090520160016101e0517f60ab231f060fa320acea170017564b7ee77f477e6465a8c964380cffb270aaf4600084a350608060805990590160009052600381526101e0518160200152600281604001526000816060015280905020607059905901600090526050815260208101905060005b60028112156126f05780830154816020028301526001810190506126d1565b70010000000000000000000000000000000060000381840154168160200283015281905090509050602060408203526020601f6020830351604001010460200260408203f3505b6313f955e18114156128ca573659905901600090523660048237600435602082010161204052602435612060525060506120805260006120a052612080516120c0526000611260525b612060516112605112156128bb576120a051806120c051038080602001599059016000905281815260208101905090508180828286612040510160006004600a8705601201f16127cc57fe5b50809050905090506120e0526020601c608c599059016000905201632b861629601c8203526120e0516020601f6020830351010460200260200183600484015260208203602484015280604884015280840193505050816004015990590160009052602481602484600060046015f161284157fe5b602481019250604882015180808582602487015160006004600a8705601201f161286757fe5b5080840193505080830360206121a08284600030602d5a03f1506121a051905090509050905061042052612080516120a051016120a052612080516120c051016120c0526001611260510161126052612780565b610420516121c05260206121c0f35b50", + "storage": { + "0x292b7a8d467a95cffd303c7edd99875892cdb3eaee87e5ca29057dc88a09ffbd": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x4d2fcf8ac901ad7dcf5b1c3979801430d9979c87157230ae066a0276984c6ac7": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xdf951a5d1d9283b06d4f1de58542f1e1e310d8d17aada46586ddb9598bc42894": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x9c8d09d387f3ba5dd4733e24c63e4d549864a7cd57a1bdf1fdd831a2a0184815": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x4ab3b783bb170e11b0932a5ce8f5f343f67058b3925da271001a75ae498bd655": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x0000000000000000000000000000000000000004": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x0000000000000000000000000000000000000002": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "559198", + "difficulty": "1814830", + "timestamp": "1577471205", + "gasLimit": "6327338", + "miner": "0x774c398d763161f55b66a646f17edda4addad2ca" + }, + "tracerConfig": { + "includePrecompiles": true + }, + "input": "0xf9026f8301307b85746a52880083124f80946cc68eb482a757c690dd151d2bd5e774ada38bdc80b9020413f955e100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000019004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae704000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30304000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e00000000000000000000000000000000081a1a01c9e9d742c8e69daba2a026ccafdde618f2e44c96db281c2209c22f183ad03a2a049a61d267d22226896d4c065525819c238784c439dc2afa7d17fce76595730d1", + "result": [ + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "gas": "0x119d28", + "input": "0x13f955e100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000019004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae704000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30304000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e000000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x1c6ff", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 20, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x1a", + "input": "0x04000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x18", + "output": "0x04000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67" + }, + "subtraces": 0, + "traceAddress": [ + 0 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x15", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x15", + "output": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020" + }, + "subtraces": 0, + "traceAddress": [ + 1 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x1e", + "input": "0x000000000000000000000000000000000000000000000000000000000000005004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a6700000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x1b", + "output": "0x000000000000000000000000000000000000000000000000000000000000005004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a6700000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 2 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x114243", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a6700000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x27c3", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 2, + "traceAddress": [ + 3 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x98", + "input": "0x04000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000002", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x60", + "output": "0xb099ea4048830027371dc31039920ae4fd19a641a7cbe57c198edd19d60f158a" + }, + "subtraces": 0, + "traceAddress": [ + 3, + 0 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x68", + "input": "0xb099ea4048830027371dc31039920ae4fd19a641a7cbe57c198edd19d60f158a", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000002", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x48", + "output": "0x5b53875b0f1381589859adcf938980f4a8fb0af4c88450070000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 3, + 1 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x1a", + "input": "0x040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae7", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x18", + "output": "0x040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae7" + }, + "subtraces": 0, + "traceAddress": [ + 4 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x15", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x15", + "output": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020" + }, + "subtraces": 0, + "traceAddress": [ + 5 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x1e", + "input": "0x0000000000000000000000000000000000000000000000000000000000000050040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae700000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x1b", + "output": "0x0000000000000000000000000000000000000000000000000000000000000050040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae700000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 6 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x110d3b", + "input": "0x2b86162900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae700000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x27c3", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 2, + "traceAddress": [ + 7 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x98", + "input": "0x040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae7", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000002", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x60", + "output": "0xa0c6939b58a99b0d940f4435ab7db7d54d6b7786e68e00d9ff3890d69f95565d" + }, + "subtraces": 0, + "traceAddress": [ + 7, + 0 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x68", + "input": "0xa0c6939b58a99b0d940f4435ab7db7d54d6b7786e68e00d9ff3890d69f95565d", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000002", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x48", + "output": "0xabbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 7, + 1 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x1a", + "input": "0x04000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc303", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x18", + "output": "0x04000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc303" + }, + "subtraces": 0, + "traceAddress": [ + 8 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x15", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x15", + "output": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020" + }, + "subtraces": 0, + "traceAddress": [ + 9 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x1e", + "input": "0x000000000000000000000000000000000000000000000000000000000000005004000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30300000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x1b", + "output": "0x000000000000000000000000000000000000000000000000000000000000005004000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30300000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 10 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x10d833", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005004000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30300000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x27c3", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 2, + "traceAddress": [ + 11 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x98", + "input": "0x04000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc303", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000002", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x60", + "output": "0x6defff59ba277fa4511f8675ca98ca7d9c237c7433684490cf1ce09a9249e32f" + }, + "subtraces": 0, + "traceAddress": [ + 11, + 0 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x68", + "input": "0x6defff59ba277fa4511f8675ca98ca7d9c237c7433684490cf1ce09a9249e32f", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000002", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x48", + "output": "0xe93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 11, + 1 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x1a", + "input": "0x04000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x18", + "output": "0x04000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de" + }, + "subtraces": 0, + "traceAddress": [ + 12 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x15", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x15", + "output": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020" + }, + "subtraces": 0, + "traceAddress": [ + 13 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x1e", + "input": "0x000000000000000000000000000000000000000000000000000000000000005004000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de00000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x1b", + "output": "0x000000000000000000000000000000000000000000000000000000000000005004000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de00000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 14 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x10a328", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005004000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de00000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x27c3", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 2, + "traceAddress": [ + 15 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x98", + "input": "0x04000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000002", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x60", + "output": "0x996652142ffecd9cc272f376ca0e8228871a903772996289f847a6dbe2ce2698" + }, + "subtraces": 0, + "traceAddress": [ + 15, + 0 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x68", + "input": "0x996652142ffecd9cc272f376ca0e8228871a903772996289f847a6dbe2ce2698", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000002", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x48", + "output": "0xf2e372a0b5b837116eee8f968840393d85975a15313468070000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 15, + 1 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x1a", + "input": "0x04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e0", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x18", + "output": "0x04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e0" + }, + "subtraces": 0, + "traceAddress": [ + 16 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x15", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x15", + "output": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020" + }, + "subtraces": 0, + "traceAddress": [ + 17 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x1e", + "input": "0x000000000000000000000000000000000000000000000000000000000000005004000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e000000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000004", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x1b", + "output": "0x000000000000000000000000000000000000000000000000000000000000005004000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 18 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x106e1d", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005004000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e000000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x27c3", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 2, + "traceAddress": [ + 19 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x98", + "input": "0x04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e0", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000002", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x60", + "output": "0xe57cf1c1d6132b9cfd9e90f54f907c038b47941b2a7f3800783af26e852ec116" + }, + "subtraces": 0, + "traceAddress": [ + 19, + 0 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x68", + "input": "0xe57cf1c1d6132b9cfd9e90f54f907c038b47941b2a7f3800783af26e852ec116", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x0000000000000000000000000000000000000002", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x48", + "output": "0x8d5b6fafc6216500f9ef1ab16b30a59df9122d7de0f4910a0000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 19, + 1 + ], + "type": "call" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json new file mode 100644 index 000000000000..170948e15669 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json @@ -0,0 +1,88 @@ +{ + "context": { + "difficulty": "3451177886", + "gasLimit": "4709286", + "miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724", + "number": "2290744", + "timestamp": "1513616439" + }, + "genesis": { + "alloc": { + "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a": { + "balance": "0x0", + "code": "0x606060405263ffffffff60e060020a6000350416633b91f50681146100505780635bb47808146100715780635f51fca01461008c578063bc7647a9146100ad578063f1bd0d7a146100c8575b610000565b346100005761006f600160a060020a03600435811690602435166100e9565b005b346100005761006f600160a060020a0360043516610152565b005b346100005761006f600160a060020a036004358116906024351661019c565b005b346100005761006f600160a060020a03600435166101fa565b005b346100005761006f600160a060020a0360043581169060243516610db8565b005b600160a060020a038083166000908152602081905260408120549091908116903316811461011657610000565b839150600160a060020a038316151561012d573392505b6101378284610e2e565b6101418284610db8565b61014a826101fa565b5b5b50505050565b600154600160a060020a03908116903316811461016e57610000565b6002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0384161790555b5b5050565b600254600160a060020a0390811690331681146101b857610000565b600160a060020a038381166000908152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff19169184169190911790555b5b505050565b6040805160e260020a631a481fc102815260016024820181905260026044830152606482015262093a8060848201819052600060a4830181905260c06004840152601e60c48401527f736574456e7469747953746174757328616464726573732c75696e743829000060e484015292519091600160a060020a038516916369207f049161010480820192879290919082900301818387803b156100005760325a03f1156100005750506040805160e260020a63379938570281526000602482018190526001604483015260606004830152602360648301527f626567696e506f6c6c28616464726573732c75696e7436342c626f6f6c2c626f60848301527f6f6c29000000000000000000000000000000000000000000000000000000000060a48301529151600160a060020a038716935063de64e15c9260c48084019391929182900301818387803b156100005760325a03f1156100005750506040805160e260020a631a481fc102815260016024820181905260026044830152606482015267ffffffffffffffff8416608482015260ff851660a482015260c06004820152601960c48201527f61646453746f636b28616464726573732c75696e74323536290000000000000060e48201529051600160a060020a03861692506369207f04916101048082019260009290919082900301818387803b156100005760325a03f1156100005750506040805160e260020a631a481fc102815260016024820181905260026044830152606482015267ffffffffffffffff8416608482015260ff851660a482015260c06004820152601960c48201527f697373756553746f636b2875696e74382c75696e74323536290000000000000060e48201529051600160a060020a03861692506369207f04916101048082019260009290919082900301818387803b156100005760325a03f1156100005750506040805160e260020a63379938570281526002602482015260006044820181905260606004830152602160648301527f6772616e7453746f636b2875696e74382c75696e743235362c61646472657373608483015260f860020a60290260a48301529151600160a060020a038716935063de64e15c9260c48084019391929182900301818387803b156100005760325a03f115610000575050604080517f010555b8000000000000000000000000000000000000000000000000000000008152600160a060020a03338116602483015260006044830181905260606004840152603c60648401527f6772616e7456657374656453746f636b2875696e74382c75696e743235362c6160848401527f6464726573732c75696e7436342c75696e7436342c75696e743634290000000060a48401529251908716935063010555b89260c48084019391929182900301818387803b156100005760325a03f1156100005750506040805160e260020a631a481fc102815260016024820181905260026044830152606482015267ffffffffffffffff8416608482015260ff851660a482015260c06004820152601260c48201527f626567696e53616c65286164647265737329000000000000000000000000000060e48201529051600160a060020a03861692506369207f04916101048082019260009290919082900301818387803b156100005760325a03f1156100005750506040805160e260020a63379938570281526002602482015260006044820181905260606004830152601a60648301527f7472616e7366657253616c6546756e64732875696e743235362900000000000060848301529151600160a060020a038716935063de64e15c9260a48084019391929182900301818387803b156100005760325a03f1156100005750506040805160e260020a631a481fc102815260016024820181905260026044830152606482015267ffffffffffffffff8416608482015260ff851660a482015260c06004820152602d60c48201527f7365744163636f756e74696e6753657474696e67732875696e743235362c756960e48201527f6e7436342c75696e7432353629000000000000000000000000000000000000006101048201529051600160a060020a03861692506369207f04916101248082019260009290919082900301818387803b156100005760325a03f1156100005750506040805160e260020a63379938570281526002602482015260006044820181905260606004830152603460648301527f637265617465526563757272696e6752657761726428616464726573732c756960848301527f6e743235362c75696e7436342c737472696e672900000000000000000000000060a48301529151600160a060020a038716935063de64e15c9260c48084019391929182900301818387803b156100005760325a03f1156100005750506040805160e260020a63379938570281526002602482015260006044820181905260606004830152601b60648301527f72656d6f7665526563757272696e675265776172642875696e7429000000000060848301529151600160a060020a038716935063de64e15c9260a48084019391929182900301818387803b156100005760325a03f1156100005750506040805160e260020a63379938570281526002602482015260006044820181905260606004830152602360648301527f697373756552657761726428616464726573732c75696e743235362c7374726960848301527f6e6729000000000000000000000000000000000000000000000000000000000060a48301529151600160a060020a038716935063de64e15c9260c48084019391929182900301818387803b156100005760325a03f1156100005750506040805160e260020a6337993857028152600160248201819052604482015260606004820152602260648201527f61737369676e53746f636b2875696e74382c616464726573732c75696e743235608482015260f060020a6136290260a48201529051600160a060020a038616925063de64e15c9160c48082019260009290919082900301818387803b156100005760325a03f1156100005750506040805160e260020a6337993857028152600160248201819052604482015260606004820152602260648201527f72656d6f766553746f636b2875696e74382c616464726573732c75696e743235608482015260f060020a6136290260a48201529051600160a060020a038616925063de64e15c9160c48082019260009290919082900301818387803b156100005760325a03f1156100005750506040805160e260020a631a481fc102815260026024808301919091526003604483015260006064830181905267ffffffffffffffff8616608484015260ff871660a484015260c0600484015260c48301919091527f7365744164647265737342796c617728737472696e672c616464726573732c6260e48301527f6f6f6c29000000000000000000000000000000000000000000000000000000006101048301529151600160a060020a03871693506369207f04926101248084019391929182900301818387803b156100005760325a03f1156100005750506040805160e260020a631a481fc1028152600260248201526003604482015260006064820181905267ffffffffffffffff8516608483015260ff861660a483015260c06004830152602160c48301527f73657453746174757342796c617728737472696e672c75696e74382c626f6f6c60e483015260f860020a6029026101048301529151600160a060020a03871693506369207f04926101248084019391929182900301818387803b156100005760325a03f1156100005750506040805160e260020a631a481fc1028152600260248201526003604482015260006064820181905267ffffffffffffffff8516608483015260ff861660a483015260c06004830152603860c48301527f736574566f74696e6742796c617728737472696e672c75696e743235362c756960e48301527f6e743235362c626f6f6c2c75696e7436342c75696e74382900000000000000006101048301529151600160a060020a03871693506369207f04926101248084019391929182900301818387803b156100005760325a03f115610000575050505b505050565b604080517f225553a4000000000000000000000000000000000000000000000000000000008152600160a060020a0383811660048301526002602483015291519184169163225553a49160448082019260009290919082900301818387803b156100005760325a03f115610000575050505b5050565b600082604051611fd280610f488339600160a060020a03909216910190815260405190819003602001906000f0801561000057905082600160a060020a03166308b027418260016040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b156100005760325a03f115610000575050604080517fa14e3ee300000000000000000000000000000000000000000000000000000000815260006004820181905260016024830152600160a060020a0386811660448401529251928716935063a14e3ee39260648084019382900301818387803b156100005760325a03f115610000575050505b5050505600606060405234620000005760405160208062001fd283398101604052515b805b600a8054600160a060020a031916600160a060020a0383161790555b506001600d819055600e81905560408051808201909152600c8082527f566f74696e672053746f636b00000000000000000000000000000000000000006020928301908152600b805460008290528251601860ff1990911617825590947f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9600291831615610100026000190190921604601f0193909304830192906200010c565b828001600101855582156200010c579182015b828111156200010c578251825591602001919060010190620000ef565b5b50620001309291505b808211156200012c576000815560010162000116565b5090565b50506040805180820190915260038082527f43565300000000000000000000000000000000000000000000000000000000006020928301908152600c805460008290528251600660ff1990911617825590937fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c760026001841615610100026000190190931692909204601f010481019291620001f7565b82800160010185558215620001f7579182015b82811115620001f7578251825591602001919060010190620001da565b5b506200021b9291505b808211156200012c576000815560010162000116565b5090565b50505b505b611da280620002306000396000f3006060604052361561019a5763ffffffff60e060020a600035041662e1986d811461019f57806302a72a4c146101d657806306eb4e421461020157806306fdde0314610220578063095ea7b3146102ad578063158ccb99146102dd57806318160ddd146102f85780631cf65a781461031757806323b872dd146103365780632c71e60a1461036c57806333148fd6146103ca578063435ebc2c146103f55780635eeb6e451461041e578063600e85b71461043c5780636103d70b146104a157806362c1e46a146104b05780636c182e99146104ba578063706dc87c146104f057806370a082311461052557806377174f851461055057806395d89b411461056f578063a7771ee3146105fc578063a9059cbb14610629578063ab377daa14610659578063b25dbb5e14610685578063b89a73cb14610699578063ca5eb5e1146106c6578063cbcf2e5a146106e1578063d21f05ba1461070e578063d347c2051461072d578063d96831e114610765578063dd62ed3e14610777578063df3c211b146107a8578063e2982c21146107d6578063eb944e4c14610801575b610000565b34610000576101d4600160a060020a036004351660243567ffffffffffffffff6044358116906064358116906084351661081f565b005b34610000576101ef600160a060020a0360043516610a30565b60408051918252519081900360200190f35b34610000576101ef610a4f565b60408051918252519081900360200190f35b346100005761022d610a55565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516602435610ae3565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516610b4e565b005b34610000576101ef610b89565b60408051918252519081900360200190f35b34610000576101ef610b8f565b60408051918252519081900360200190f35b34610000576102c9600160a060020a0360043581169060243516604435610b95565b604080519115158252519081900360200190f35b3461000057610388600160a060020a0360043516602435610bb7565b60408051600160a060020a039096168652602086019490945267ffffffffffffffff928316858501529082166060850152166080830152519081900360a00190f35b34610000576101ef600160a060020a0360043516610c21565b60408051918252519081900360200190f35b3461000057610402610c40565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d4600160a060020a0360043516602435610c4f565b005b3461000057610458600160a060020a0360043516602435610cc9565b60408051600160a060020a03909716875260208701959095528585019390935267ffffffffffffffff9182166060860152811660808501521660a0830152519081900360c00190f35b34610000576101d4610d9e565b005b6101d4610e1e565b005b34610000576104d3600160a060020a0360043516610e21565b6040805167ffffffffffffffff9092168252519081900360200190f35b3461000057610402600160a060020a0360043516610ead565b60408051600160a060020a039092168252519081900360200190f35b34610000576101ef600160a060020a0360043516610ef9565b60408051918252519081900360200190f35b34610000576101ef610f18565b60408051918252519081900360200190f35b346100005761022d610f1e565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516610fac565b604080519115158252519081900360200190f35b34610000576102c9600160a060020a0360043516602435610fc2565b604080519115158252519081900360200190f35b3461000057610402600435610fe2565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d46004351515610ffd565b005b34610000576102c9600160a060020a036004351661104c565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516611062565b005b34610000576102c9600160a060020a0360043516611070565b604080519115158252519081900360200190f35b34610000576101ef6110f4565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351667ffffffffffffffff602435166110fa565b60408051918252519081900360200190f35b34610000576101d4600435611121565b005b34610000576101ef600160a060020a03600435811690602435166111c6565b60408051918252519081900360200190f35b34610000576101ef6004356024356044356064356084356111f3565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351661128c565b60408051918252519081900360200190f35b34610000576101d4600160a060020a036004351660243561129e565b005b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff848116908416101561086457610000565b8367ffffffffffffffff168267ffffffffffffffff16101561088557610000565b8267ffffffffffffffff168267ffffffffffffffff1610156108a657610000565b506040805160a081018252600160a060020a033381168252602080830188905267ffffffffffffffff80871684860152858116606085015287166080840152908816600090815260039091529190912080546001810180835582818380158290116109615760030281600302836000526020600020918201910161096191905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050916000526020600020906003020160005b5082518154600160a060020a031916600160a060020a03909116178155602083015160018201556040830151600290910180546060850151608086015167ffffffffffffffff1990921667ffffffffffffffff948516176fffffffffffffffff00000000000000001916604060020a918516919091021777ffffffffffffffff000000000000000000000000000000001916608060020a939091169290920291909117905550610a268686610fc2565b505b505050505050565b600160a060020a0381166000908152600360205260409020545b919050565b60055481565b600b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b600a5433600160a060020a03908116911614610b6957610000565b600a8054600160a060020a031916600160a060020a0383161790555b5b50565b60005481565b60005b90565b6000610ba2848484611600565b610bad8484846116e2565b90505b9392505050565b600360205281600052604060002081815481101561000057906000526020600020906003020160005b5080546001820154600290920154600160a060020a03909116935090915067ffffffffffffffff80821691604060020a8104821691608060020a9091041685565b600160a060020a0381166000908152600860205260409020545b919050565b600a54600160a060020a031681565b600a5433600160a060020a03908116911614610c6a57610000565b610c7660005482611714565b6000908155600160a060020a038316815260016020526040902054610c9b9082611714565b600160a060020a038316600090815260016020526040812091909155610cc390839083611600565b5b5b5050565b6000600060006000600060006000600360008a600160a060020a0316600160a060020a0316815260200190815260200160002088815481101561000057906000526020600020906003020160005b508054600182015460028301546040805160a081018252600160a060020a039094168085526020850184905267ffffffffffffffff808416928601839052604060020a8404811660608701819052608060020a9094041660808601819052909c50929a509197509095509350909150610d90904261172d565b94505b509295509295509295565b33600160a060020a038116600090815260066020526040902054801515610dc457610000565b8030600160a060020a0316311015610ddb57610000565b600160a060020a0382166000818152600660205260408082208290555183156108fc0291849190818181858888f193505050501515610cc357610000565b5b5050565b5b565b600160a060020a03811660009081526003602052604081205442915b81811015610ea557600160a060020a03841660009081526003602052604090208054610e9a9190839081101561000057906000526020600020906003020160005b5060020154604060020a900467ffffffffffffffff168461177d565b92505b600101610e3d565b5b5050919050565b600160a060020a0380821660009081526007602052604081205490911615610eef57600160a060020a0380831660009081526007602052604090205416610ef1565b815b90505b919050565b600160a060020a0381166000908152600160205260409020545b919050565b600d5481565b600c805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b60006000610fb983610c21565b1190505b919050565b6000610fcf338484611600565b610fd983836117ac565b90505b92915050565b600460205260009081526040902054600160a060020a031681565b8015801561101a575061100f33610ef9565b61101833610c21565b115b1561102457610000565b33600160a060020a03166000908152600960205260409020805460ff19168215151790555b50565b60006000610fb983610ef9565b1190505b919050565b610b8533826117dc565b5b50565b600a54604080516000602091820181905282517fcbcf2e5a000000000000000000000000000000000000000000000000000000008152600160a060020a03868116600483015293519194939093169263cbcf2e5a92602480830193919282900301818787803b156100005760325a03f115610000575050604051519150505b919050565b600e5481565b6000610fd961110984846118b2565b61111385856119b6565b611a05565b90505b92915050565b600a5433600160a060020a0390811691161461113c57610000565b61114860005482611a1f565b600055600554600190101561116c57600a5461116c90600160a060020a0316611a47565b5b600a54600160a060020a03166000908152600160205260409020546111929082611a1f565b600a8054600160a060020a039081166000908152600160205260408120939093559054610b8592911683611600565b5b5b50565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b92915050565b6000600060008487101561120a5760009250611281565b8387111561121a57879250611281565b61123f6112308961122b888a611714565b611a90565b61123a8689611714565b611abc565b915081925061124e8883611714565b905061127e8361127961126a8461122b8c8b611714565b611a90565b61123a888b611714565b611abc565b611a1f565b92505b505095945050505050565b60066020526000908152604090205481565b600160a060020a03821660009081526003602052604081208054829190849081101561000057906000526020600020906003020160005b50805490925033600160a060020a039081169116146112f357610000565b6040805160a0810182528354600160a060020a0316815260018401546020820152600284015467ffffffffffffffff80821693830193909352604060020a810483166060830152608060020a900490911660808201526113539042611af9565b600160a060020a0385166000908152600360205260409020805491925090849081101561000057906000526020600020906003020160005b508054600160a060020a031916815560006001820181905560029091018054600160c060020a0319169055600160a060020a0385168152600360205260409020805460001981019081101561000057906000526020600020906003020160005b50600160a060020a03851660009081526003602052604090208054859081101561000057906000526020600020906003020160005b5081548154600160a060020a031916600160a060020a03918216178255600180840154908301556002928301805493909201805467ffffffffffffffff191667ffffffffffffffff948516178082558354604060020a908190048616026fffffffffffffffff000000000000000019909116178082559254608060020a9081900490941690930277ffffffffffffffff00000000000000000000000000000000199092169190911790915584166000908152600360205260409020805460001981018083559190829080158290116115485760030281600302836000526020600020918201910161154891905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050600160a060020a033316600090815260016020526040902054611570915082611a1f565b600160a060020a03338116600090815260016020526040808220939093559086168152205461159f9082611714565b600160a060020a038086166000818152600160209081526040918290209490945580518581529051339093169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35b50505050565b600160a060020a0383161561166e576116466008600061161f86610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611714565b6008600061165386610ead565b600160a060020a031681526020810191909152604001600020555b600160a060020a038216156116dc576116b46008600061168d85610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611a1f565b600860006116c185610ead565b600160a060020a031681526020810191909152604001600020555b5b505050565b600083826116f082426110fa565b8111156116fc57610000565b611707868686611b1b565b92505b5b50509392505050565b600061172283831115611b4d565b508082035b92915050565b6000610fd983602001518367ffffffffffffffff16856080015167ffffffffffffffff16866040015167ffffffffffffffff16876060015167ffffffffffffffff166111f3565b90505b92915050565b60008167ffffffffffffffff168367ffffffffffffffff1610156117a15781610fd9565b825b90505b92915050565b600033826117ba82426110fa565b8111156117c657610000565b6117d08585611b5d565b92505b5b505092915050565b6117e582610ef9565b6117ee83610c21565b11156117f957610000565b600160a060020a03811660009081526009602052604090205460ff16158015611834575081600160a060020a031681600160a060020a031614155b1561183e57610000565b61184782611070565b1561185157610000565b611864828261185f85610ef9565b611600565b600160a060020a0382811660009081526007602052604090208054600160a060020a031916918316918217905561189a82610ead565b600160a060020a031614610cc357610000565b5b5050565b600160a060020a038216600090815260036020526040812054815b818110156119885761197d836112796003600089600160a060020a0316600160a060020a0316815260200190815260200160002084815481101561000057906000526020600020906003020160005b506040805160a0810182528254600160a060020a031681526001830154602082015260029092015467ffffffffffffffff80821692840192909252604060020a810482166060840152608060020a900416608082015287611af9565b611a1f565b92505b6001016118cd565b600160a060020a0385166000908152600160205260409020546117d09084611714565b92505b505092915050565b600060006119c384611070565b80156119d157506000600d54115b90506119fb816119e9576119e485610ef9565b6119ec565b60005b6111138686611b7b565b611a05565b91505b5092915050565b60008183106117a15781610fd9565b825b90505b92915050565b6000828201611a3c848210801590611a375750838210155b611b4d565b8091505b5092915050565b611a508161104c565b15611a5a57610b85565b6005805460009081526004602052604090208054600160a060020a031916600160a060020a038416179055805460010190555b50565b6000828202611a3c841580611a37575083858381156100005704145b611b4d565b8091505b5092915050565b60006000611acc60008411611b4d565b8284811561000057049050611a3c838581156100005706828502018514611b4d565b8091505b5092915050565b6000610fd98360200151611b0d858561172d565b611714565b90505b92915050565b60008382611b2982426110fa565b811115611b3557610000565b611707868686611b8f565b92505b5b50509392505050565b801515610b8557610000565b5b50565b6000611b6883611a47565b610fd98383611c92565b90505b92915050565b6000610fd983610ef9565b90505b92915050565b600160a060020a038084166000908152600260209081526040808320338516845282528083205493861683526001909152812054909190611bd09084611a1f565b600160a060020a038086166000908152600160205260408082209390935590871681522054611bff9084611714565b600160a060020a038616600090815260016020526040902055611c228184611714565b600160a060020a038087166000818152600260209081526040808320338616845282529182902094909455805187815290519288169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600191505b509392505050565b60003382611ca082426110fa565b811115611cac57610000565b6117d08585611cc2565b92505b5b505092915050565b600160a060020a033316600090815260016020526040812054611ce59083611714565b600160a060020a033381166000908152600160205260408082209390935590851681522054611d149083611a1f565b600160a060020a038085166000818152600160209081526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b929150505600a165627a7a72305820bfa5ddd3fecf3f43aed25385ec7ec3ef79638c2e58d99f85d9a3cc494183bf160029a165627a7a723058200e78a5f7e0f91739035d0fbf5eca02f79377210b722f63431f29a22e2880b3bd0029", + "nonce": "789", + "storage": { + "0xfe9ec0542a1c009be8b1f3acf43af97100ffff42eb736850fb038fa1151ad4d9": "0x000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8" + } + }, + "0x5cb4a6b902fcb21588c86c3517e797b07cdaadb9": { + "balance": "0x0", + "code": "0x", + "nonce": "0", + "storage": {} + }, + "0xe4a13bc304682a903e9472f469c33801dd18d9e8": { + "balance": "0x33c763c929f62c4f", + "code": "0x", + "nonce": "14", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3451177886", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "4713874", + "hash": "0x5d52a672417cd1269bf4f7095e25dcbf837747bba908cd5ef809dc1bd06144b5", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0x01a12845ed546b94a038a7a03e8df8d7952024ed41ccb3db7a7ade4abc290ce1", + "nonce": "0x28c446f1cb9748c1", + "number": "2290743", + "stateRoot": "0x4898aceede76739daef76448a367d10015a2c022c9e7909b99a10fbf6fb16708", + "timestamp": "1513616414", + "totalDifficulty": "7146523769022564" + }, + "input": "0xf8aa0e8509502f9000830493e0941d3ddf7caf024f253487e18bc4a15b1a360c170a80b8443b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e829a0524564944fa419f5c189b5074044f89210c6d6b2d77ee8f7f12a927d59b636dfa0015b28986807a424b18b186ee6642d76739df36cad802d20e8c00e79a61d7281", + "result": [ + { + "action": { + "callType": "call", + "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", + "gas": "0x435c8", + "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", + "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", + "value": "0x0" + }, + "blockNumber": 2290744, + "error": "invalid jump destination", + "result": {}, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "from": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", + "gas": "0x39ff0", + "init": "0x606060405234620000005760405160208062001fd283398101604052515b805b600a8054600160a060020a031916600160a060020a0383161790555b506001600d819055600e81905560408051808201909152600c8082527f566f74696e672053746f636b00000000000000000000000000000000000000006020928301908152600b805460008290528251601860ff1990911617825590947f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9600291831615610100026000190190921604601f0193909304830192906200010c565b828001600101855582156200010c579182015b828111156200010c578251825591602001919060010190620000ef565b5b50620001309291505b808211156200012c576000815560010162000116565b5090565b50506040805180820190915260038082527f43565300000000000000000000000000000000000000000000000000000000006020928301908152600c805460008290528251600660ff1990911617825590937fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c760026001841615610100026000190190931692909204601f010481019291620001f7565b82800160010185558215620001f7579182015b82811115620001f7578251825591602001919060010190620001da565b5b506200021b9291505b808211156200012c576000815560010162000116565b5090565b50505b505b611da280620002306000396000f3006060604052361561019a5763ffffffff60e060020a600035041662e1986d811461019f57806302a72a4c146101d657806306eb4e421461020157806306fdde0314610220578063095ea7b3146102ad578063158ccb99146102dd57806318160ddd146102f85780631cf65a781461031757806323b872dd146103365780632c71e60a1461036c57806333148fd6146103ca578063435ebc2c146103f55780635eeb6e451461041e578063600e85b71461043c5780636103d70b146104a157806362c1e46a146104b05780636c182e99146104ba578063706dc87c146104f057806370a082311461052557806377174f851461055057806395d89b411461056f578063a7771ee3146105fc578063a9059cbb14610629578063ab377daa14610659578063b25dbb5e14610685578063b89a73cb14610699578063ca5eb5e1146106c6578063cbcf2e5a146106e1578063d21f05ba1461070e578063d347c2051461072d578063d96831e114610765578063dd62ed3e14610777578063df3c211b146107a8578063e2982c21146107d6578063eb944e4c14610801575b610000565b34610000576101d4600160a060020a036004351660243567ffffffffffffffff6044358116906064358116906084351661081f565b005b34610000576101ef600160a060020a0360043516610a30565b60408051918252519081900360200190f35b34610000576101ef610a4f565b60408051918252519081900360200190f35b346100005761022d610a55565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516602435610ae3565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516610b4e565b005b34610000576101ef610b89565b60408051918252519081900360200190f35b34610000576101ef610b8f565b60408051918252519081900360200190f35b34610000576102c9600160a060020a0360043581169060243516604435610b95565b604080519115158252519081900360200190f35b3461000057610388600160a060020a0360043516602435610bb7565b60408051600160a060020a039096168652602086019490945267ffffffffffffffff928316858501529082166060850152166080830152519081900360a00190f35b34610000576101ef600160a060020a0360043516610c21565b60408051918252519081900360200190f35b3461000057610402610c40565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d4600160a060020a0360043516602435610c4f565b005b3461000057610458600160a060020a0360043516602435610cc9565b60408051600160a060020a03909716875260208701959095528585019390935267ffffffffffffffff9182166060860152811660808501521660a0830152519081900360c00190f35b34610000576101d4610d9e565b005b6101d4610e1e565b005b34610000576104d3600160a060020a0360043516610e21565b6040805167ffffffffffffffff9092168252519081900360200190f35b3461000057610402600160a060020a0360043516610ead565b60408051600160a060020a039092168252519081900360200190f35b34610000576101ef600160a060020a0360043516610ef9565b60408051918252519081900360200190f35b34610000576101ef610f18565b60408051918252519081900360200190f35b346100005761022d610f1e565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516610fac565b604080519115158252519081900360200190f35b34610000576102c9600160a060020a0360043516602435610fc2565b604080519115158252519081900360200190f35b3461000057610402600435610fe2565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d46004351515610ffd565b005b34610000576102c9600160a060020a036004351661104c565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516611062565b005b34610000576102c9600160a060020a0360043516611070565b604080519115158252519081900360200190f35b34610000576101ef6110f4565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351667ffffffffffffffff602435166110fa565b60408051918252519081900360200190f35b34610000576101d4600435611121565b005b34610000576101ef600160a060020a03600435811690602435166111c6565b60408051918252519081900360200190f35b34610000576101ef6004356024356044356064356084356111f3565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351661128c565b60408051918252519081900360200190f35b34610000576101d4600160a060020a036004351660243561129e565b005b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff848116908416101561086457610000565b8367ffffffffffffffff168267ffffffffffffffff16101561088557610000565b8267ffffffffffffffff168267ffffffffffffffff1610156108a657610000565b506040805160a081018252600160a060020a033381168252602080830188905267ffffffffffffffff80871684860152858116606085015287166080840152908816600090815260039091529190912080546001810180835582818380158290116109615760030281600302836000526020600020918201910161096191905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050916000526020600020906003020160005b5082518154600160a060020a031916600160a060020a03909116178155602083015160018201556040830151600290910180546060850151608086015167ffffffffffffffff1990921667ffffffffffffffff948516176fffffffffffffffff00000000000000001916604060020a918516919091021777ffffffffffffffff000000000000000000000000000000001916608060020a939091169290920291909117905550610a268686610fc2565b505b505050505050565b600160a060020a0381166000908152600360205260409020545b919050565b60055481565b600b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b600a5433600160a060020a03908116911614610b6957610000565b600a8054600160a060020a031916600160a060020a0383161790555b5b50565b60005481565b60005b90565b6000610ba2848484611600565b610bad8484846116e2565b90505b9392505050565b600360205281600052604060002081815481101561000057906000526020600020906003020160005b5080546001820154600290920154600160a060020a03909116935090915067ffffffffffffffff80821691604060020a8104821691608060020a9091041685565b600160a060020a0381166000908152600860205260409020545b919050565b600a54600160a060020a031681565b600a5433600160a060020a03908116911614610c6a57610000565b610c7660005482611714565b6000908155600160a060020a038316815260016020526040902054610c9b9082611714565b600160a060020a038316600090815260016020526040812091909155610cc390839083611600565b5b5b5050565b6000600060006000600060006000600360008a600160a060020a0316600160a060020a0316815260200190815260200160002088815481101561000057906000526020600020906003020160005b508054600182015460028301546040805160a081018252600160a060020a039094168085526020850184905267ffffffffffffffff808416928601839052604060020a8404811660608701819052608060020a9094041660808601819052909c50929a509197509095509350909150610d90904261172d565b94505b509295509295509295565b33600160a060020a038116600090815260066020526040902054801515610dc457610000565b8030600160a060020a0316311015610ddb57610000565b600160a060020a0382166000818152600660205260408082208290555183156108fc0291849190818181858888f193505050501515610cc357610000565b5b5050565b5b565b600160a060020a03811660009081526003602052604081205442915b81811015610ea557600160a060020a03841660009081526003602052604090208054610e9a9190839081101561000057906000526020600020906003020160005b5060020154604060020a900467ffffffffffffffff168461177d565b92505b600101610e3d565b5b5050919050565b600160a060020a0380821660009081526007602052604081205490911615610eef57600160a060020a0380831660009081526007602052604090205416610ef1565b815b90505b919050565b600160a060020a0381166000908152600160205260409020545b919050565b600d5481565b600c805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b60006000610fb983610c21565b1190505b919050565b6000610fcf338484611600565b610fd983836117ac565b90505b92915050565b600460205260009081526040902054600160a060020a031681565b8015801561101a575061100f33610ef9565b61101833610c21565b115b1561102457610000565b33600160a060020a03166000908152600960205260409020805460ff19168215151790555b50565b60006000610fb983610ef9565b1190505b919050565b610b8533826117dc565b5b50565b600a54604080516000602091820181905282517fcbcf2e5a000000000000000000000000000000000000000000000000000000008152600160a060020a03868116600483015293519194939093169263cbcf2e5a92602480830193919282900301818787803b156100005760325a03f115610000575050604051519150505b919050565b600e5481565b6000610fd961110984846118b2565b61111385856119b6565b611a05565b90505b92915050565b600a5433600160a060020a0390811691161461113c57610000565b61114860005482611a1f565b600055600554600190101561116c57600a5461116c90600160a060020a0316611a47565b5b600a54600160a060020a03166000908152600160205260409020546111929082611a1f565b600a8054600160a060020a039081166000908152600160205260408120939093559054610b8592911683611600565b5b5b50565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b92915050565b6000600060008487101561120a5760009250611281565b8387111561121a57879250611281565b61123f6112308961122b888a611714565b611a90565b61123a8689611714565b611abc565b915081925061124e8883611714565b905061127e8361127961126a8461122b8c8b611714565b611a90565b61123a888b611714565b611abc565b611a1f565b92505b505095945050505050565b60066020526000908152604090205481565b600160a060020a03821660009081526003602052604081208054829190849081101561000057906000526020600020906003020160005b50805490925033600160a060020a039081169116146112f357610000565b6040805160a0810182528354600160a060020a0316815260018401546020820152600284015467ffffffffffffffff80821693830193909352604060020a810483166060830152608060020a900490911660808201526113539042611af9565b600160a060020a0385166000908152600360205260409020805491925090849081101561000057906000526020600020906003020160005b508054600160a060020a031916815560006001820181905560029091018054600160c060020a0319169055600160a060020a0385168152600360205260409020805460001981019081101561000057906000526020600020906003020160005b50600160a060020a03851660009081526003602052604090208054859081101561000057906000526020600020906003020160005b5081548154600160a060020a031916600160a060020a03918216178255600180840154908301556002928301805493909201805467ffffffffffffffff191667ffffffffffffffff948516178082558354604060020a908190048616026fffffffffffffffff000000000000000019909116178082559254608060020a9081900490941690930277ffffffffffffffff00000000000000000000000000000000199092169190911790915584166000908152600360205260409020805460001981018083559190829080158290116115485760030281600302836000526020600020918201910161154891905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050600160a060020a033316600090815260016020526040902054611570915082611a1f565b600160a060020a03338116600090815260016020526040808220939093559086168152205461159f9082611714565b600160a060020a038086166000818152600160209081526040918290209490945580518581529051339093169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35b50505050565b600160a060020a0383161561166e576116466008600061161f86610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611714565b6008600061165386610ead565b600160a060020a031681526020810191909152604001600020555b600160a060020a038216156116dc576116b46008600061168d85610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611a1f565b600860006116c185610ead565b600160a060020a031681526020810191909152604001600020555b5b505050565b600083826116f082426110fa565b8111156116fc57610000565b611707868686611b1b565b92505b5b50509392505050565b600061172283831115611b4d565b508082035b92915050565b6000610fd983602001518367ffffffffffffffff16856080015167ffffffffffffffff16866040015167ffffffffffffffff16876060015167ffffffffffffffff166111f3565b90505b92915050565b60008167ffffffffffffffff168367ffffffffffffffff1610156117a15781610fd9565b825b90505b92915050565b600033826117ba82426110fa565b8111156117c657610000565b6117d08585611b5d565b92505b5b505092915050565b6117e582610ef9565b6117ee83610c21565b11156117f957610000565b600160a060020a03811660009081526009602052604090205460ff16158015611834575081600160a060020a031681600160a060020a031614155b1561183e57610000565b61184782611070565b1561185157610000565b611864828261185f85610ef9565b611600565b600160a060020a0382811660009081526007602052604090208054600160a060020a031916918316918217905561189a82610ead565b600160a060020a031614610cc357610000565b5b5050565b600160a060020a038216600090815260036020526040812054815b818110156119885761197d836112796003600089600160a060020a0316600160a060020a0316815260200190815260200160002084815481101561000057906000526020600020906003020160005b506040805160a0810182528254600160a060020a031681526001830154602082015260029092015467ffffffffffffffff80821692840192909252604060020a810482166060840152608060020a900416608082015287611af9565b611a1f565b92505b6001016118cd565b600160a060020a0385166000908152600160205260409020546117d09084611714565b92505b505092915050565b600060006119c384611070565b80156119d157506000600d54115b90506119fb816119e9576119e485610ef9565b6119ec565b60005b6111138686611b7b565b611a05565b91505b5092915050565b60008183106117a15781610fd9565b825b90505b92915050565b6000828201611a3c848210801590611a375750838210155b611b4d565b8091505b5092915050565b611a508161104c565b15611a5a57610b85565b6005805460009081526004602052604090208054600160a060020a031916600160a060020a038416179055805460010190555b50565b6000828202611a3c841580611a37575083858381156100005704145b611b4d565b8091505b5092915050565b60006000611acc60008411611b4d565b8284811561000057049050611a3c838581156100005706828502018514611b4d565b8091505b5092915050565b6000610fd98360200151611b0d858561172d565b611714565b90505b92915050565b60008382611b2982426110fa565b811115611b3557610000565b611707868686611b8f565b92505b5b50509392505050565b801515610b8557610000565b5b50565b6000611b6883611a47565b610fd98383611c92565b90505b92915050565b6000610fd983610ef9565b90505b92915050565b600160a060020a038084166000908152600260209081526040808320338516845282528083205493861683526001909152812054909190611bd09084611a1f565b600160a060020a038086166000908152600160205260408082209390935590871681522054611bff9084611714565b600160a060020a038616600090815260016020526040902055611c228184611714565b600160a060020a038087166000818152600260209081526040808320338616845282529182902094909455805187815290519288169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600191505b509392505050565b60003382611ca082426110fa565b811115611cac57610000565b6117d08585611cc2565b92505b5b505092915050565b600160a060020a033316600090815260016020526040812054611ce59083611714565b600160a060020a033381166000908152600160205260408082209390935590851681522054611d149083611a1f565b600160a060020a038085166000818152600160209081526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b929150505600a165627a7a72305820bfa5ddd3fecf3f43aed25385ec7ec3ef79638c2e58d99f85d9a3cc494183bf160029000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182", + "value": "0x0" + }, + "blockNumber": 0, + "error": "contract creation code storage out of gas", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "create" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json new file mode 100644 index 000000000000..328b743270db --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json @@ -0,0 +1,72 @@ +{ + "genesis": { + "difficulty": "117067574", + "extraData": "0xd783010502846765746887676f312e372e33856c696e7578", + "gasLimit": "4712380", + "hash": "0xe05db05eeb3f288041ecb10a787df121c0ed69499355716e17c307de313a4486", + "miner": "0x0c062b329265c965deef1eede55183b3acb8f611", + "mixHash": "0xb669ae39118a53d2c65fd3b1e1d3850dd3f8c6842030698ed846a2762d68b61d", + "nonce": "0x2b469722b8e28c45", + "number": "24973", + "stateRoot": "0x532a5c3f75453a696428db078e32ae283c85cb97e4d8560dbdf022adac6df369", + "timestamp": "1479891145", + "totalDifficulty": "1892250259406", + "alloc": { + "0x6c06b16512b332e6cd8293a2974872674716ce18": { + "balance": "0x0", + "nonce": "1", + "code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900480632e1a7d4d146036575b6000565b34600057604e60048080359060200190919050506050565b005b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051809050600060405180830381858888f19350505050505b5056", + "storage": {} + }, + "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31": { + "balance": "0x229ebbb36c3e0f20", + "nonce": "3", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 3, + "homesteadBlock": 0, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "byzantiumBlock": 1700000, + "constantinopleBlock": 4230000, + "petersburgBlock": 4939394, + "istanbulBlock": 6485846, + "muirGlacierBlock": 7117117, + "ethash": {} + } + }, + "context": { + "number": "24974", + "difficulty": "117067574", + "timestamp": "1479891162", + "gasLimit": "4712388", + "miner": "0xc822ef32e6d26e170b70cf761e204c1806265914" + }, + "input": "0xf889038504a81557008301f97e946c06b16512b332e6cd8293a2974872674716ce1880a42e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b1600002aa0e2a6558040c5d72bc59f2fb62a38993a314c849cd22fb393018d2c5af3112095a01bdb6d7ba32263ccc2ecc880d38c49d9f0c5a72d8b7908e3122b31356d349745", + "result": [ + { + "action": { + "callType": "call", + "from": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", + "gas": "0x1a466", + "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", + "to": "0x6c06b16512b332e6cd8293a2974872674716ce18", + "value": "0x0" + }, + "blockNumber": 24974, + "result": { + "gasUsed": "0x72de", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json new file mode 100644 index 000000000000..6b5738101c24 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json @@ -0,0 +1,219 @@ +{ + "genesis": { + "number": "559197", + "hash": "0x0742a2bfab0452e2c634f3685b7e49ceb065c7000609b2b73f086e01fd1dfb58", + "nonce": "0x3060ad521440e1c2", + "mixHash": "0x59e7d4ae6cc3c38d23dac3f869b21984c7ba8f38070f4116a4941d9c403b6299", + "stateRoot": "0x68418fb5cf4afa9b807dc079e8cdde0e148ac2c8afb378e675465b5bed1fbd02", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "difficulty": "1813945", + "totalDifficulty": "469107641961", + "extraData": "0xd883010906846765746888676f312e31332e35856c696e7578", + "gasLimit": "6321166", + "timestamp": "1577471202", + "alloc": { + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0xc5e6fdae52af83f7e28", + "nonce": "77947", + "code": "0x", + "storage": {} + }, + "0x774c398d763161f55b66a646f17edda4addad2ca": { + "balance": "0xf09ef316eff819ee488", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc": { + "balance": "0x0", + "nonce": "1", + "code": "0x60006121df537c01000000000000000000000000000000000000000000000000000000006000350463b041b2858114156100d257600435604052780100000000000000000000000000000000000000000000000060606060599059016000905260038152604051816020015260008160400152809050205404606052606051151561008f57600060a052602060a0f35b604051601c604459905901600090520163e0e9a17b601c82035260605160048201526020610100602483600030602d5a03f1506101005190501460c052602060c0f35b632cce81aa81141561019957600435610120526001610120511280156100f85780610143565b78010000000000000000000000000000000000000000000000006060606059905901600090526003815266040000000000025481602001526000816040015280905020540461012051135b905015610157576000610180526020610180f35b601c604459905901600090520163e0e9a17b601c82035261012051600482015260206101c0602483600030602d5a03f1506101c05190506101a05260206101a0f35b63e0e9a17b8114156102e957600435610120526604000000000002546101e0526007610200525b610120517801000000000000000000000000000000000000000000000000606060605990590160009052600381526101e05181602001526000816040015280905020540413156102da575b6102005160050a610120517801000000000000000000000000000000000000000000000000606060605990590160009052600381526101e051816020015260008160400152809050205404031215610269576000610200511361026c565b60005b1561028157600161020051036102005261020b565b7c01000000000000000000000000000000000000000000000000000000006102005160200260020a606060605990590160009052600381526101e05181602001526001816040015280905020540204546101e0526101c0565b6101e051610280526020610280f35b63cef887b08114156103e757365990590160009052366004823760043560208201016102c0526024356102e052506060601c61014c5990590160009052016390fa337d601c8203526102c0516020601f602083035101046020026020018360048401526020820360648401528060c8840152808401935050506102e051602482015233604482015281600401599059016000905260648160648460006004601cf161039057fe5b60648101925060c882015180808582606487015160006004600a8705601201f16103b657fe5b5080840193505080830360206103a08284600030602d5a03f1506103a0519050905090509050610300526020610300f35b6390fa337d81141561065f57365990590160009052366004823760043560208201016102c0526024356102e0526044356103e052505a610400526020601c608c599059016000905201632b861629601c8203526102c0516020601f6020830351010460200260200183600484015260208203602484015280604884015280840193505050816004015990590160009052602481602484600060046015f161048a57fe5b602481019250604882015180808582602487015160006004600a8705601201f16104b057fe5b5080840193505080830360206104408284600030602d5a03f15061044051905090509050905061042052610420511561065e576102c05160208103516020599059016000905260208183856000600287604801f150805190509050905061046052602059905901600090526020816020610460600060026068f1508051905060005b6020811215610552578181601f031a816105400153600181019050610532565b5050610540516101e0526102e0516c010000000000000000000000006103e0510217606060605990590160009052600381526101e05181602001526003816040015280905020555a61058052700100000000000000000000000000000000660400000000000154046105a0526104006105a0516103ff02056105c0526104006105a05161040102056105e0526105c0513a12156105f6576105c05161060052610615565b6105e0513a131561060e576105e05161060052610614565b3a610600525b5b6105805161040051036106005160020202610620526106205170010000000000000000000000000000000061060051021766040000000000015561042051610640526020610640f35b5b63d467ae0381141561073257600435604052602435610660526106605134121515610725576000341315610718576c01000000000000000000000000606060605990590160009052600381526040518160200152600381604001528090502054046103e0526000600060006000346103e051611388f115156106dd57fe5b601c60405990590160009052013481526103e0517f15e746bf513b8a58e4265cc1162d7fc445da5c9b1928d7cfcde2582735d4677f602083a2505b60016106a05260206106a0f35b60006106c05260206106c0f35b63ea4971ee811415610851576004356101e0526024356102e0526044356103e052601c606459905901600090520163d467ae03601c8203526101e05160048201526604000000000001546fffffffffffffffffffffffffffffffff16602482015260206106e060448334306123555a03f1506106e051905015156107bd576000610700526020610700f35b606060605990590160009052600381526101e05181602001526003816040015280905020546bffffffffffffffffffffffff166102e0511215610844576102e0516c010000000000000000000000006103e0510217606060605990590160009052600381526101e05181602001526003816040015280905020556001610760526020610760f35b6000610780526020610780f35b6387def0818114156108a3576004356101e0526c01000000000000000000000000606060605990590160009052600381526101e0518160200152600381604001528090502054046107a05260206107a0f35b630aece23c8114156108f4576004356101e052606060605990590160009052600381526101e05181602001526003816040015280905020546bffffffffffffffffffffffff166107e05260206107e0f35b63fa14df6b811415610926576604000000000001546fffffffffffffffffffffffffffffffff16610820526020610820f35b63b8c48f8c811415610b1b576004356101e0526024356108405260443561086052600066040000000000035414151561096a576000610880526020610880f3610976565b60016604000000000003555b6101e051660400000000000255606060605990590160009052600381526101e05181602001526000816040015280905020546108a0526108a0610840518060181a82538060191a600183015380601a1a600283015380601b1a600383015380601c1a600483015380601d1a600583015380601e1a600683015380601f1a600783015350506108a051606060605990590160009052600381526101e0518160200152600081604001528090502055606060605990590160009052600381526101e051816020015260008160400152809050205461094052601061094001610860518060101a82538060111a60018301538060121a60028301538060131a60038301538060141a60048301538060151a60058301538060161a60068301538060171a60078301538060181a60088301538060191a600983015380601a1a600a83015380601b1a600b83015380601c1a600c83015380601d1a600d83015380601e1a600e83015380601f1a600f830153505061094051606060605990590160009052600381526101e051816020015260008160400152809050205560016109e05260206109e0f35b632b86162981141561179457365990590160009052366004823760043560208201016102c0525060483560005b6020811215610b68578181601f031a81610a600153600181019050610b48565b5050610a6051610a00526102c05160208103516020599059016000905260208183856000600287604801f1508051905090509050610a8052602059905901600090526020816020610a80600060026068f1508051905060005b6020811215610be1578181601f031a81610b600153600181019050610bc1565b5050610b60516101e05270010000000000000000000000000000000070010000000000000000000000000000000060606060599059016000905260038152610a005181602001526000816040015280905020540204610b8052610b80511515610c8b57601c602059905901600090520161272e6101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a3506000610bc0526020610bc0f35b700100000000000000000000000000000000700100000000000000000000000000000000606060605990590160009052600381526101e05181602001526000816040015280905020540204610be0526000610be051141515610d2e57601c60205990590160009052016127386101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a3506000610c20526020610c20f35b608c35610c40526301000000610c405160031a0262010000610c405160021a02610100610c405160011a02610c405160001a010101610c60526301000000610c605104610ca05262ffffff610c605116610cc0526003610ca051036101000a610cc05102610c805260006101e0511315610db057610c80516101e05112610db3565b60005b1561174d57780100000000000000000000000000000000000000000000000060606060599059016000905260038152610a00518160200152600081604001528090502054046001016101205260806080599059016000905260038152610a005181602001526002816040015260008160600152809050206002810154610d405250610d405160081a610d405160091a61010002610d4051600a1a6201000002610d4051600b1a630100000002010101610d005260006107e0610120510614158015610e7e5780610e8b565b6001660400000000000054145b905015610f0257610d0051610c6051141515610eae576000610d00511415610eb1565b60005b15610efd57601c602059905901600090520161271a6101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a3506000610da0526020610da0f35b6111b4565b6301000000610d005104610de05262ffffff610d005116610e00526003610de051036101000a610e005102610dc05260806080599059016000905260038152610a005181602001526002816040015260008160600152809050206002810154610e605250610e605160041a610e605160051a61010002610e605160061a6201000002610e605160071a630100000002010101610e2052601c604459905901600090520163e0e9a17b601c8203526107e0610120510360048201526020610ec0602483600030602d5a03f150610ec0519050610ea05260806080599059016000905260038152610ea05181602001526002816040015260008160600152809050206002810154610f205250610f205160041a610f205160051a61010002610f205160061a6201000002610f205160071a630100000002010101610ee052610ee051610e20510362049d408112156110595762049d4090505b6249d40081131561106b576249d40090505b62127500610dc0518202047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8113156110ba577bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90505b600860076000835b80156110d9576002810490506001820191506110c2565b5080905001046000600382131515611103578160030360080260020a62ffffff841602905061111a565b6003820360080260020a8304905062ffffff811690505b6280000081161561113357610100810490506001820191505b6301000000820281179050905090509050610f6052610f6051610c6051141515611164576000610f60511415611167565b60005b156111b357601c60205990590160009052016127246101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a3506000611040526020611040f35b5b6101e0516101e0516101e05166040000000000005455606060605990590160009052600381526101e0518160200152600081604001528090502054611060526008611060016604000000000000548060181a82538060191a600183015380601a1a600283015380601b1a600383015380601c1a600483015380601d1a600583015380601e1a600683015380601f1a6007830153505061106051606060605990590160009052600381526101e0518160200152600081604001528090502055600166040000000000005401660400000000000055606060605990590160009052600381526101e0518160200152600081604001528090502054611100526111006001780100000000000000000000000000000000000000000000000060606060599059016000905260038152610a0051816020015260008160400152809050205404018060181a82538060191a600183015380601a1a600283015380601b1a600383015380601c1a600483015380601d1a600583015380601e1a600683015380601f1a6007830153505061110051606060605990590160009052600381526101e051816020015260008160400152809050205560006111c05278010000000000000000000000000000000000000000000000006801000000000000000060606060599059016000905260038152610a0051816020015260008160400152809050205402046111e0526111c06111e05180601c1a825380601d1a600183015380601e1a600283015380601f1a600383015350506001611260525b6008611260511215611515576112605160050a611280526001611280517801000000000000000000000000000000000000000000000000606060605990590160009052600381526101e05181602001526000816040015280905020540407141561148757611260516004026111c0016111e05180601c1a825380601d1a600183015380601e1a600283015380601f1a60038301535050611505565b611260516004026111c0017c01000000000000000000000000000000000000000000000000000000006112605160200260020a60606060599059016000905260038152610a00518160200152600181604001528090502054020480601c1a825380601d1a600183015380601e1a600283015380601f1a600383015350505b60016112605101611260526113ec565b6111c051606060605990590160009052600381526101e05181602001526001816040015280905020555050608060805990590160009052600381526101e051816020015260028160400152600081606001528090502060005b600281121561159057806020026102c05101518282015560018101905061156e565b700100000000000000000000000000000000600003816020026102c051015116828201555050610c80517bffff0000000000000000000000000000000000000000000000000000056113e0526113e051610b805101610be052606060605990590160009052600381526101e051816020015260008160400152809050205461140052601061140001610be0518060101a82538060111a60018301538060121a60028301538060131a60038301538060141a60048301538060151a60058301538060161a60068301538060171a60078301538060181a60088301538060191a600983015380601a1a600a83015380601b1a600b83015380601c1a600c83015380601d1a600d83015380601e1a600e83015380601f1a600f830153505061140051606060605990590160009052600381526101e0518160200152600081604001528090502055660400000000000354610be051121515611703576101e051660400000000000255610be0516604000000000003555b601c6020599059016000905201610120516101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a350610120516114a05260206114a0f35b601c602059905901600090520161276a6101e0517f055e4f8dd3a534789b3feb8e0681afa2aee8713fdd6472f25b2c30dc7bf4e0f4600084a35060006114c05260206114c0f35b630f5995ce8114156119a157365990590160009052366004823760043560208201016114e05260243561150052604435602082010161152052606435604052506114e05160208103516020599059016000905260208183856000600287604801f150805190509050905061156052602059905901600090526020816020611560600060026068f1508051905060005b6020811215611843578181601f031a816116400153600181019050611823565b50506116405161154052604060206114e051035114156118a457601c6020599059016000905201614e52611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a3506000611660526020611660f35b6080601c6101ac59905901600090520163bd136cb3601c8203526115405160048201526115005160248201526115205160208103516020026020018360448401526020820360c48401528061014884015280840193505050604051606482015281600401599059016000905260848160848460006004601ff161192357fe5b6084810192506101488201518080858260c487015160006004600a8705601201f161194a57fe5b508084019350508083036020611680828434306123555a03f15061168051905090509050905061042052600161042051141561199357611540516116a05260206116a0f36119a0565b60006116c05260206116c0f35b5b63bd136cb3811415611d8c573659905901600090523660048237600435611540526024356115005260443560208201016115205260643560405250601c606459905901600090520163d467ae03601c82035260405160048201526060606059905901600090526003815260405181602001526003816040015280905020546bffffffffffffffffffffffff166024820152602061170060448334306123555a03f1506117005190501515611a9757601c6020599059016000905201614e2a611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a350614e2a611720526020611720f35b601c6044599059016000905201633d73b705601c82035260405160048201526020611740602483600030602d5a03f15061174051905015611b1a57601c6020599059016000905201614e34611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a350614e34611760526020611760f35b601c604459905901600090520163b041b285601c82035260405160048201526020611780602483600030602d5a03f1506117805190501515611b9e57601c6020599059016000905201614e3e611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a350614e3e6117a05260206117a0f35b6060601c61014c59905901600090520163b7129afb601c8203526115405160048201526115005160248201526115205160208103516020026020018360448401526020820360a4840152806101088401528084019350505081600401599059016000905260648160648460006004601cf1611c1557fe5b6064810192506101088201518080858260a487015160006004600a8705601201f1611c3c57fe5b5080840193505080830360206117e08284600030602d5a03f1506117e05190509050905090506117c0526080608059905901600090526003815260405181602001526002816040015260008160600152809050207c01000000000000000000000000000000000000000000000000000000006002820154046401000000006001830154020160005b6020811215611ce4578181601f031a816118a00153600181019050611cc4565b50506118a051905061180052611800516117c0511415611d4457601c60205990590160009052016001611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a35060016118c05260206118c0f35b601c6020599059016000905201614e48611540517fd008620948a1ed10f4fed82dc43cf79acad36dc6b7c2c924e27c9813193b83ad600084a350614e486118e05260206118e0f35b63318a3fee81141561205657365990590160009052366004823760043560208201016114e0526024356115005260443560208201016115205260643560405260843561190052506080601c6101ac599059016000905201630f5995ce601c8203526114e0516020601f6020830351010460200260200183600484015260208203608484015280610108840152808401935050506115005160248201526115205160208103516020026020018360448401526020820360c48401528061014884015280840193505050604051606482015281600401599059016000905260848160848460006004601ff1611e7b57fe5b60848101925061010882015180808582608487015160006004600a8705601201f1611ea257fe5b508084019350506101488201518080858260c487015160006004600a8705601201f1611eca57fe5b508084019350508083036020611920828434306123555a03f15061192051905090509050905061154052600061154051141515612010576040601c60ec599059016000905201631c0b6367601c8203526114e0516020601f6020830351010460200260200183600484015260208203604484015280608884015280840193505050611540516024820152816004015990590160009052604481604484600060046018f1611f7357fe5b604481019250608882015180808582604487015160006004600a8705601201f1611f9957fe5b5080840193505080830360206119608284600061190051602d5a03f15061196051905090509050905061194052601c602059905901600090520161194051611540517f2d0d11d0f27e21fab56a8712078721096066b7faaa8540a3ea566e70b97de2d4600084a35061194051611980526020611980f35b601c602059905901600090520161753a60007f2d0d11d0f27e21fab56a8712078721096066b7faaa8540a3ea566e70b97de2d4600084a35061753a6119a05260206119a0f35b6309dd0e81811415612076576604000000000002546119c05260206119c0f35b63023948728114156120d2577801000000000000000000000000000000000000000000000000606060605990590160009052600381526604000000000002548160200152600081604001528090502054046119e05260206119e0f35b632c181929811415612139577001000000000000000000000000000000007001000000000000000000000000000000006060606059905901600090526003815266040000000000025481602001526000816040015280905020540204611a20526020611a20f35b637ca823d58114156122af576604000000000002546101e052700100000000000000000000000000000000700100000000000000000000000000000000606060605990590160009052600381526101e05181602001526000816040015280905020540204611a60526000611260525b600a61126051121561224c57608060805990590160009052600381526101e05181602001526002816040015260008160600152809050207c01000000000000000000000000000000000000000000000000000000006001820154046401000000008254020160005b6020811215612230578181601f031a81611b200153600181019050612210565b5050611b205190506101e05260016112605101611260526121a8565b700100000000000000000000000000000000700100000000000000000000000000000000606060605990590160009052600381526101e05181602001526000816040015280905020540204611b4052611b4051611a605103611b80526020611b80f35b63b7129afb81141561246a57365990590160009052366004823760043561154052602435611500526044356020820101611520525061154051611ba0526020611520510351611bc0526000611260525b611bc05161126051121561245b5761126051602002611520510151611be05260026115005107611c00526001611c0051141561234a57611be051611c2052611ba051611c4052612368565b6000611c0051141561236757611ba051611c2052611be051611c40525b5b60405990590160009052611c205160005b6020811215612399578181601f031a81611ca00153600181019050612379565b5050611ca0518152611c405160005b60208112156123c8578181601f031a81611d2001536001810190506123a8565b5050611d2051602082015260205990590160009052602081604084600060026088f15080519050611d4052602059905901600090526020816020611d40600060026068f1508051905060005b6020811215612434578181601f031a81611de00153600181019050612414565b5050611de0519050611ba052600261150051056115005260016112605101611260526122ff565b611ba051611e00526020611e00f35b633d73b70581141561255b576004356040526604000000000002546101e0526000611260525b600661126051121561254e576101e05160405114156124b6576001611e20526020611e20f35b608060805990590160009052600381526101e05181602001526002816040015260008160600152809050207c01000000000000000000000000000000000000000000000000000000006001820154046401000000008254020160005b6020811215612532578181601f031a81611ec00153600181019050612512565b5050611ec05190506101e0526001611260510161126052612490565b6000611ee0526020611ee0f35b631f794436811415612737576004356101e052601c606459905901600090520163d467ae03601c8203526101e0516004820152606060605990590160009052600381526101e05181602001526003816040015280905020546bffffffffffffffffffffffff1660248201526020611f2060448334306123555a03f150611f20519050151561265657601c602059905901600090520160006101e0517f60ab231f060fa320acea170017564b7ee77f477e6465a8c964380cffb270aaf4600084a350602159905901600090526001815260006020820152602081019050602060408203526020601f6020830351604001010460200260408203f3505b601c602059905901600090520160016101e0517f60ab231f060fa320acea170017564b7ee77f477e6465a8c964380cffb270aaf4600084a350608060805990590160009052600381526101e0518160200152600281604001526000816060015280905020607059905901600090526050815260208101905060005b60028112156126f05780830154816020028301526001810190506126d1565b70010000000000000000000000000000000060000381840154168160200283015281905090509050602060408203526020601f6020830351604001010460200260408203f3505b6313f955e18114156128ca573659905901600090523660048237600435602082010161204052602435612060525060506120805260006120a052612080516120c0526000611260525b612060516112605112156128bb576120a051806120c051038080602001599059016000905281815260208101905090508180828286612040510160006004600a8705601201f16127cc57fe5b50809050905090506120e0526020601c608c599059016000905201632b861629601c8203526120e0516020601f6020830351010460200260200183600484015260208203602484015280604884015280840193505050816004015990590160009052602481602484600060046015f161284157fe5b602481019250604882015180808582602487015160006004600a8705601201f161286757fe5b5080840193505080830360206121a08284600030602d5a03f1506121a051905090509050905061042052612080516120a051016120a052612080516120c051016120c0526001611260510161126052612780565b610420516121c05260206121c0f35b50", + "storage": { + "0x292b7a8d467a95cffd303c7edd99875892cdb3eaee87e5ca29057dc88a09ffbd": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x4d2fcf8ac901ad7dcf5b1c3979801430d9979c87157230ae066a0276984c6ac7": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xdf951a5d1d9283b06d4f1de58542f1e1e310d8d17aada46586ddb9598bc42894": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x9c8d09d387f3ba5dd4733e24c63e4d549864a7cd57a1bdf1fdd831a2a0184815": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x4ab3b783bb170e11b0932a5ce8f5f343f67058b3925da271001a75ae498bd655": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x0000000000000000000000000000000000000004": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x0000000000000000000000000000000000000002": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "559198", + "difficulty": "1814830", + "timestamp": "1577471205", + "gasLimit": "6327338", + "miner": "0x774c398d763161f55b66a646f17edda4addad2ca" + }, + "input": "0xf9026f8301307b85746a52880083124f80946cc68eb482a757c690dd151d2bd5e774ada38bdc80b9020413f955e100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000019004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae704000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30304000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e00000000000000000000000000000000081a1a01c9e9d742c8e69daba2a026ccafdde618f2e44c96db281c2209c22f183ad03a2a049a61d267d22226896d4c065525819c238784c439dc2afa7d17fce76595730d1", + "result": [ + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "gas": "0x119d28", + "input": "0x13f955e100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000019004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae704000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30304000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e000000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x1c6ff", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 5, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x114243", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a6700000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x27c3", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 0 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x110d3b", + "input": "0x2b86162900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae700000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x27c3", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 1 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x10d833", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005004000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30300000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x27c3", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 2 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x10a328", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005004000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de00000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x27c3", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 3 + ], + "type": "call" + }, + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "gas": "0x106e1d", + "input": "0x2b8616290000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005004000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e000000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", + "value": "0x0" + }, + "result": { + "address": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x27c3", + "output": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "subtraces": 0, + "traceAddress": [ + 4 + ], + "type": "call" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json new file mode 100644 index 000000000000..b11b8e040dd3 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json @@ -0,0 +1,95 @@ +{ + "context": { + "difficulty": "3956606365", + "gasLimit": "5413248", + "miner": "0x00d8ae40d9a06d0e7a2877b62e32eb959afbe16d", + "number": "2295104", + "timestamp": "1513681256" + }, + "genesis": { + "alloc": { + "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76": { + "balance": "0x0", + "code": "0x60606040526004361061015e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680625b4487146101a257806311df9995146101cb578063278ecde11461022057806330adce0e146102435780633197cbb61461026c5780634bb278f3146102955780636103d70b146102aa57806363a599a4146102bf5780636a2d1cb8146102d457806375f12b21146102fd57806378e979251461032a578063801db9cc1461035357806386d1a69f1461037c5780638da5cb5b146103915780638ef26a71146103e65780639890220b1461040f5780639b39caef14610424578063b85dfb801461044d578063be9a6555146104a1578063ccb07cef146104b6578063d06c91e4146104e3578063d669e1d414610538578063df40503c14610561578063e2982c2114610576578063f02e030d146105c3578063f2fde38b146105d8578063f3283fba14610611575b600060149054906101000a900460ff1615151561017a57600080fd5b60075442108061018b575060085442115b15151561019757600080fd5b6101a03361064a565b005b34156101ad57600080fd5b6101b5610925565b6040518082815260200191505060405180910390f35b34156101d657600080fd5b6101de61092b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561022b57600080fd5b6102416004808035906020019091905050610951565b005b341561024e57600080fd5b610256610c48565b6040518082815260200191505060405180910390f35b341561027757600080fd5b61027f610c4e565b6040518082815260200191505060405180910390f35b34156102a057600080fd5b6102a8610c54565b005b34156102b557600080fd5b6102bd610f3e565b005b34156102ca57600080fd5b6102d261105d565b005b34156102df57600080fd5b6102e76110d5565b6040518082815260200191505060405180910390f35b341561030857600080fd5b6103106110e1565b604051808215151515815260200191505060405180910390f35b341561033557600080fd5b61033d6110f4565b6040518082815260200191505060405180910390f35b341561035e57600080fd5b6103666110fa565b6040518082815260200191505060405180910390f35b341561038757600080fd5b61038f611104565b005b341561039c57600080fd5b6103a4611196565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156103f157600080fd5b6103f96111bb565b6040518082815260200191505060405180910390f35b341561041a57600080fd5b6104226111c1565b005b341561042f57600080fd5b610437611296565b6040518082815260200191505060405180910390f35b341561045857600080fd5b610484600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061129c565b604051808381526020018281526020019250505060405180910390f35b34156104ac57600080fd5b6104b46112c0565b005b34156104c157600080fd5b6104c9611341565b604051808215151515815260200191505060405180910390f35b34156104ee57600080fd5b6104f6611354565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561054357600080fd5b61054b61137a565b6040518082815260200191505060405180910390f35b341561056c57600080fd5b610574611385565b005b341561058157600080fd5b6105ad600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506116c3565b6040518082815260200191505060405180910390f35b34156105ce57600080fd5b6105d66116db565b005b34156105e357600080fd5b61060f600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611829565b005b341561061c57600080fd5b610648600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506118fe565b005b600080670de0b6b3a7640000341015151561066457600080fd5b61069b610696670de0b6b3a7640000610688610258346119d990919063ffffffff16565b611a0c90919063ffffffff16565b611a27565b9150660221b262dd80006106ba60065484611a7e90919063ffffffff16565b111515156106c757600080fd5b600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84846000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15156107d557600080fd5b6102c65a03f115156107e657600080fd5b5050506040518051905050610808828260010154611a7e90919063ffffffff16565b8160010181905550610827348260000154611a7e90919063ffffffff16565b816000018190555061084434600554611a7e90919063ffffffff16565b60058190555061085f82600654611a7e90919063ffffffff16565b6006819055503373ffffffffffffffffffffffffffffffffffffffff167ff3c1c7c0eb1328ddc834c4c9e579c06d35f443bf1102b034653624a239c7a40c836040518082815260200191505060405180910390a27fd1dc370699ae69fb860ed754789a4327413ec1cd379b93f2cbedf449a26b0e8583600554604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a1505050565b60025481565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060085442108061096b5750651b48eb57e00060065410155b15151561097757600080fd5b600a60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010154821415156109c757600080fd5b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856000604051602001526040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1515610ac857600080fd5b6102c65a03f11515610ad957600080fd5b5050506040518051905050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166342966c68836000604051602001526040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b1515610b7d57600080fd5b6102c65a03f11515610b8e57600080fd5b505050604051805190501515610ba357600080fd5b600a60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000015490506000600a60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001819055506000811115610c4457610c433382611a9c565b5b5050565b60055481565b60085481565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610cb157600080fd5b600854421015610cd357660221b262dd8000600654141515610cd257600080fd5b5b651b48eb57e000600654108015610cf057506213c6806008540142105b151515610cfc57600080fd5b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f193505050501515610d7557600080fd5b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306000604051602001526040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1515610e3a57600080fd5b6102c65a03f11515610e4b57600080fd5b5050506040518051905090506000811115610f2057600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166342966c68826000604051602001526040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b1515610ef957600080fd5b6102c65a03f11515610f0a57600080fd5b505050604051805190501515610f1f57600080fd5b5b6001600960006101000a81548160ff02191690831515021790555050565b600080339150600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060008114151515610f9657600080fd5b803073ffffffffffffffffffffffffffffffffffffffff163110151515610fbc57600080fd5b610fd181600254611b5090919063ffffffff16565b6002819055506000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561105957fe5b5050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156110b857600080fd5b6001600060146101000a81548160ff021916908315150217905550565b670de0b6b3a764000081565b600060149054906101000a900460ff1681565b60075481565b651b48eb57e00081565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561115f57600080fd5b600060149054906101000a900460ff16151561117a57600080fd5b60008060146101000a81548160ff021916908315150217905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60065481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561121c57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050151561129457600080fd5b565b61025881565b600a6020528060005260406000206000915090508060000154908060010154905082565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561131b57600080fd5b600060075414151561132c57600080fd5b4260078190555062278d004201600881905550565b600960009054906101000a900460ff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b660221b262dd800081565b60008060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156113e557600080fd5b600654660221b262dd800003925061142b670de0b6b3a764000061141c610258670de0b6b3a76400006119d990919063ffffffff16565b81151561142557fe5b04611a27565b915081831115151561143c57600080fd5b600a60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16856000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b151561158c57600080fd5b6102c65a03f1151561159d57600080fd5b50505060405180519050506115bf838260010154611a7e90919063ffffffff16565b81600101819055506115dc83600654611a7e90919063ffffffff16565b6006819055503073ffffffffffffffffffffffffffffffffffffffff167ff3c1c7c0eb1328ddc834c4c9e579c06d35f443bf1102b034653624a239c7a40c846040518082815260200191505060405180910390a27fd1dc370699ae69fb860ed754789a4327413ec1cd379b93f2cbedf449a26b0e856000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600554604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a1505050565b60016020528060005260406000206000915090505481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561173657600080fd5b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f2fde38b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b151561181357600080fd5b6102c65a03f1151561182457600080fd5b505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561188457600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415156118fb57806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561195957600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561199557600080fd5b80600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600080828402905060008414806119fa57508284828115156119f757fe5b04145b1515611a0257fe5b8091505092915050565b6000808284811515611a1a57fe5b0490508091505092915050565b6000611a416202a300600754611a7e90919063ffffffff16565b421015611a7557611a6e611a5f600584611a0c90919063ffffffff16565b83611a7e90919063ffffffff16565b9050611a79565b8190505b919050565b6000808284019050838110151515611a9257fe5b8091505092915050565b611aee81600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611a7e90919063ffffffff16565b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611b4681600254611a7e90919063ffffffff16565b6002819055505050565b6000828211151515611b5e57fe5b8183039050929150505600a165627a7a72305820ec0d82a406896ccf20989b3d6e650abe4dc104e400837f1f58e67ef499493ae90029", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000008d69d00910d0b2afb2a99ed6c16c8129fa8e1751", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000e819f024b41358d2c08e3a868a5c5dd0566078d4", + "0x0000000000000000000000000000000000000000000000000000000000000007": "0x000000000000000000000000000000000000000000000000000000005a388981", + "0x0000000000000000000000000000000000000000000000000000000000000008": "0x000000000000000000000000000000000000000000000000000000005a3b38e6" + } + }, + "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826": { + "balance": "0x2a2dd979a35cf000", + "code": "0x", + "nonce": "0", + "storage": {} + }, + "0xe819f024b41358d2c08e3a868a5c5dd0566078d4": { + "balance": "0x0", + "code": "0x6060604052600436106100ba576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100bf578063095ea7b31461014d57806318160ddd146101a757806323b872dd146101d0578063313ce5671461024957806342966c681461027257806370a08231146102ad5780638da5cb5b146102fa57806395d89b411461034f578063a9059cbb146103dd578063dd62ed3e14610437578063f2fde38b146104a3575b600080fd5b34156100ca57600080fd5b6100d26104dc565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101125780820151818401526020810190506100f7565b50505050905090810190601f16801561013f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015857600080fd5b61018d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610515565b604051808215151515815260200191505060405180910390f35b34156101b257600080fd5b6101ba61069c565b6040518082815260200191505060405180910390f35b34156101db57600080fd5b61022f600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506106a2565b604051808215151515815260200191505060405180910390f35b341561025457600080fd5b61025c610952565b6040518082815260200191505060405180910390f35b341561027d57600080fd5b6102936004808035906020019091905050610957565b604051808215151515815260200191505060405180910390f35b34156102b857600080fd5b6102e4600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610abe565b6040518082815260200191505060405180910390f35b341561030557600080fd5b61030d610b07565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561035a57600080fd5b610362610b2d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103a2578082015181840152602081019050610387565b50505050905090810190601f1680156103cf5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156103e857600080fd5b61041d600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610b66565b604051808215151515815260200191505060405180910390f35b341561044257600080fd5b61048d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610d01565b6040518082815260200191505060405180910390f35b34156104ae57600080fd5b6104da600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610d88565b005b6040805190810160405280600b81526020017f416c6c436f6465436f696e00000000000000000000000000000000000000000081525081565b6000808214806105a157506000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054145b15156105ac57600080fd5b81600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60005481565b600080600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905061077683600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e5f90919063ffffffff16565b600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061080b83600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e7d90919063ffffffff16565b600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506108618382610e7d90919063ffffffff16565b600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a360019150509392505050565b600681565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156109b557600080fd5b610a0782600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e7d90919063ffffffff16565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610a5f82600054610e7d90919063ffffffff16565b60008190555060003373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050919050565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040805190810160405280600481526020017f414c4c430000000000000000000000000000000000000000000000000000000081525081565b6000610bba82600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e7d90919063ffffffff16565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610c4f82600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e5f90919063ffffffff16565b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610de457600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515610e5c5780600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50565b6000808284019050838110151515610e7357fe5b8091505092915050565b6000828211151515610e8b57fe5b8183039050929150505600a165627a7a7230582059f3ea3df0b054e9ab711f37969684ba83fe38f255ffe2c8d850d951121c51100029", + "nonce": "1", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3956606365", + "extraData": "0x566961425443", + "gasLimit": "5418523", + "hash": "0x6f37eb930a25da673ea1bb80fd9e32ddac19cdf7cd4bb2eac62cc13598624077", + "miner": "0xd049bfd667cb46aa3ef5df0da3e57db3be39e511", + "mixHash": "0x10971cde68c587c750c23b8589ae868ce82c2c646636b97e7d9856470c5297c7", + "nonce": "0x810f923ff4b450a1", + "number": "2295103", + "stateRoot": "0xff403612573d76dfdaf4fea2429b77dbe9764021ae0e38dc8ac79a3cf551179e", + "timestamp": "1513681246", + "totalDifficulty": "7162347056825919" + }, + "input": "0xf86d808504e3b292008307dfa69433056b5dcac09a9b4becad0e1dcf92c19bd0af76880e92596fd62900008029a0e5f27bb66431f7081bb7f1f242003056d7f3f35414c352cd3d1848b52716dac2a07d0be78980edb0bd2a0678fc53aa90ea9558ce346b0d947967216918ac74ccea", + "result": [ + { + "action": { + "callType": "call", + "from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826", + "gas": "0x78d9e", + "input": "0x", + "to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", + "value": "0xe92596fd6290000" + }, + "blockNumber": 2295104, + "error": "execution reverted", + "result": { + "gasUsed": "0x7c1c8" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", + "gas": "0x75fe3", + "input": "0xa9059cbb000000000000000000000000d4fcab9f0a6dc0493af47c864f6f17a8a5e2e82600000000000000000000000000000000000000000000000000000000000002f4", + "to": "0xe819f024b41358d2c08e3a868a5c5dd0566078d4", + "value": "0x0" + }, + "blockNumber": 0, + "error": "invalid opcode: INVALID", + "result": {}, + "subtraces": 0, + "traceAddress": [0], + "type": "call" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json new file mode 100644 index 000000000000..64425dbaddac --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json @@ -0,0 +1,94 @@ +{ + "genesis": { + "difficulty": "1808543", + "extraData": "0xd883010906846765746888676f312e31332e35856c696e7578", + "gasLimit": "4875092", + "hash": "0x3851fdc18bd5f2314cf0c90439356f9a1fe157d7fb06c20e20b77954da903671", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "mixHash": "0x3d4e702d6058acf94c9547560f05536d45d515bd4f9014564ec41b5b4ff9578b", + "nonce": "0x1695153e7b16c1e7", + "number": "555461", + "stateRoot": "0xba8272acd0dfeb5f04376328e8bfc5b276b177697000c204a060f6f7b629ae32", + "timestamp": "1577423350", + "totalDifficulty": "462222992438", + "alloc": { + "0xcf5b3467dfa45cdc8e5358a7a1ba4deb02e5faed": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x16c102a3b09c02abdace", + "nonce": "19049", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "555462", + "difficulty": "1808543", + "timestamp": "1577423360", + "gasLimit": "4873701", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf90451824a6985746a52880083053e908080b903fb60606040525b60405161015b806102a0833901809050604051809103906000f0600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b610247806100596000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900480632ef9db1314610044578063e37678761461007157610042565b005b61005b6004803590602001803590602001506100ad565b6040518082815260200191505060405180910390f35b61008860048035906020018035906020015061008a565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000600060008484604051808381526020018281526020019250505060405180910390209150610120600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff167f6164640000000000000000000000000000000000000000000000000000000000846101e3565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681868660405180807f616464000000000000000000000000000000000000000000000000000000000081526020015060200184815260200183815260200182815260200193505050506000604051808303816000866161da5a03f191505050600060005060008281526020019081526020016000206000505492506101db565b505092915050565b60004340848484604051808581526020018473ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140183815260200182815260200194505050505060405180910390209050610240565b9392505050566060604052610148806100136000396000f30060606040526000357c010000000000000000000000000000000000000000000000000000000090048063471407e614610044578063e37678761461007757610042565b005b6100616004803590602001803590602001803590602001506100b3565b6040518082815260200191505060405180910390f35b61008e600480359060200180359060200150610090565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000818301905080506100c684826100d5565b8090506100ce565b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff16828260405180807f7265676973746572496e74000000000000000000000000000000000000000000815260200150602001838152602001828152602001925050506000604051808303816000866161da5a03f1915050505b50505681a1a0b9a85df655d3b6aa081e52d8c3db52c50c2bf97d9d993a980113b2262649c125a00d51e63880ca8ef4705914a71e7ff906834a9cdcff0cbd063ff4e43a5905890d", + "result": [ + { + "type": "create", + "action": { + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "value": "0x0", + "gas": "0x3951c", + "init": "0x60606040525b60405161015b806102a0833901809050604051809103906000f0600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b610247806100596000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900480632ef9db1314610044578063e37678761461007157610042565b005b61005b6004803590602001803590602001506100ad565b6040518082815260200191505060405180910390f35b61008860048035906020018035906020015061008a565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000600060008484604051808381526020018281526020019250505060405180910390209150610120600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff167f6164640000000000000000000000000000000000000000000000000000000000846101e3565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681868660405180807f616464000000000000000000000000000000000000000000000000000000000081526020015060200184815260200183815260200182815260200193505050506000604051808303816000866161da5a03f191505050600060005060008281526020019081526020016000206000505492506101db565b505092915050565b60004340848484604051808581526020018473ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140183815260200182815260200194505050505060405180910390209050610240565b9392505050566060604052610148806100136000396000f30060606040526000357c010000000000000000000000000000000000000000000000000000000090048063471407e614610044578063e37678761461007757610042565b005b6100616004803590602001803590602001803590602001506100b3565b6040518082815260200191505060405180910390f35b61008e600480359060200180359060200150610090565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000818301905080506100c684826100d5565b8090506100ce565b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff16828260405180807f7265676973746572496e74000000000000000000000000000000000000000000815260200150602001838152602001828152602001925050506000604051808303816000866161da5a03f1915050505b505056" + }, + "result": { + "gasUsed": "0x53e90", + "code": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900480632ef9db1314610044578063e37678761461007157610042565b005b61005b6004803590602001803590602001506100ad565b6040518082815260200191505060405180910390f35b61008860048035906020018035906020015061008a565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000600060008484604051808381526020018281526020019250505060405180910390209150610120600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff167f6164640000000000000000000000000000000000000000000000000000000000846101e3565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681868660405180807f616464000000000000000000000000000000000000000000000000000000000081526020015060200184815260200183815260200182815260200193505050506000604051808303816000866161da5a03f191505050600060005060008281526020019081526020016000206000505492506101db565b505092915050565b60004340848484604051808581526020018473ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140183815260200182815260200194505050505060405180910390209050610240565b939250505056", + "address": "0x9db7a1baf185a865ffee3824946ccd8958191e5e" + }, + "traceAddress": [], + "subtraces": 1, + "transactionPosition": 23, + "transactionHash": "0xe267552ce8437a5bc7081385c99f912de5723ad34b958db215dbc41abd5f6c03", + "blockNumber": 555462, + "blockHash": "0x38bba9e3965b57205097ea5ec53fc403cf3941bec2e4c933faae244de5ca4ba1", + "time": "1.147715ms" + }, + { + "type": "create", + "action": { + "from": "0x9db7a1baf185a865ffee3824946ccd8958191e5e", + "value": "0x0", + "gas": "0x30b34", + "init": "0x6060604052610148806100136000396000f30060606040526000357c010000000000000000000000000000000000000000000000000000000090048063471407e614610044578063e37678761461007757610042565b005b6100616004803590602001803590602001803590602001506100b3565b6040518082815260200191505060405180910390f35b61008e600480359060200180359060200150610090565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000818301905080506100c684826100d5565b8090506100ce565b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff16828260405180807f7265676973746572496e74000000000000000000000000000000000000000000815260200150602001838152602001828152602001925050506000604051808303816000866161da5a03f1915050505b505056" + }, + "result": { + "gasUsed": "0x1009d", + "code": "0x60606040526000357c010000000000000000000000000000000000000000000000000000000090048063471407e614610044578063e37678761461007757610042565b005b6100616004803590602001803590602001803590602001506100b3565b6040518082815260200191505060405180910390f35b61008e600480359060200180359060200150610090565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000818301905080506100c684826100d5565b8090506100ce565b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff16828260405180807f7265676973746572496e74000000000000000000000000000000000000000000815260200150602001838152602001828152602001925050506000604051808303816000866161da5a03f1915050505b505056", + "address": "0xcf5b3467dfa45cdc8e5358a7a1ba4deb02e5faed" + }, + "traceAddress": [0], + "subtraces": 0, + "transactionPosition": 23, + "transactionHash": "0xe267552ce8437a5bc7081385c99f912de5723ad34b958db215dbc41abd5f6c03", + "blockNumber": 555462, + "blockHash": "0x38bba9e3965b57205097ea5ec53fc403cf3941bec2e4c933faae244de5ca4ba1" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json new file mode 100644 index 000000000000..bbd9904d9c7e --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json @@ -0,0 +1,94 @@ +{ + "genesis": { + "difficulty": "4635413", + "extraData": "0xd683010b05846765746886676f312e3133856c696e7578", + "gasLimit": "9289294", + "hash": "0x359775cf1a2ae2400e26ec68bf33bcfe38b7979c76b7e616f42c4ca7e7605e39", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "mixHash": "0x4b2a0ef121a9c7d732fa0fbd4166a0e1041d2da2b8cb677c61edabf8b7183b64", + "nonce": "0x2a8a64ad9757be55", + "number": "1555160", + "stateRoot": "0x95067c12148e2362fcd4a89df286ff0b1739ef097a40ca42ae7f698af9a9d913", + "timestamp": "1590793999", + "totalDifficulty": "2242063623471", + "alloc": { + "0x8785e369f0ef0a4e5c5a5f929680427dc75273a5": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x623145b285b3f551fa3f", + "nonce": "260617", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "1555161", + "difficulty": "4633150", + "timestamp": "1590794020", + "gasLimit": "9298364", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf85e8303fa09843b9aca0083019ed880808a6000600060006000f50081a2a0485ea410e210740eef8e6f6de11c530f46f8da80eecb02afbb6c5f61749ac015a068d72f1b0f1d3cb4e214d5def79b49a73e6ee91db2df83499a54c656c144600f", + "result": [ + { + "type": "create", + "action": { + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "value": "0x0", + "gas": "0xcf6c", + "init": "0x6000600060006000f500" + }, + "result": { + "gasUsed": "0x14c78", + "code": "0x", + "address": "0x2e8eded627eead210cb6143eb39ef7a3e44e4f00" + }, + "traceAddress": [], + "subtraces": 1, + "transactionPosition": 31, + "transactionHash": "0x1257b698c5833c54ce786734087002b097275abc3877af082b5c2a538e894a41", + "blockNumber": 1555161, + "blockHash": "0xb0793dd508dd106a19794b8ce1dfc0ff8d98c76aab61bf32a11799854149a171", + "time": "889.048µs" + }, + { + "type": "create", + "action": { + "from": "0x2e8eded627eead210cb6143eb39ef7a3e44e4f00", + "value": "0x0", + "gas": "0x5117", + "init": "0x" + }, + "result": { + "gasUsed": "0x0", + "code": "0x", + "address": "0x8785e369f0ef0a4e5c5a5f929680427dc75273a5" + }, + "traceAddress": [0], + "subtraces": 0, + "transactionPosition": 31, + "transactionHash": "0x1257b698c5833c54ce786734087002b097275abc3877af082b5c2a538e894a41", + "blockNumber": 1555161, + "blockHash": "0xb0793dd508dd106a19794b8ce1dfc0ff8d98c76aab61bf32a11799854149a171" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json new file mode 100644 index 000000000000..19ae5fc5d3f0 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json @@ -0,0 +1,90 @@ +{ + "genesis": { + "difficulty": "4639933", + "extraData": "0xd883010b05846765746888676f312e31342e33856c696e7578", + "gasLimit": "9280188", + "hash": "0x9a5f3a98eb1c60f6e3f450658a9cea190157e7021d04f927b752ad6482cf9194", + "miner": "0x73f26d124436b0791169d63a3af29c2ae47765a3", + "mixHash": "0x6b6f8fcaa54b8565c4c1ae7cf0a020e938a53007f4561e758b17bc05c9044d78", + "nonce": "0x773aba50dc51b462", + "number": "1555169", + "stateRoot": "0xc4b9703de3e59ff795baae2c3afa010cf039c37244a7a6af7f3f491a10601348", + "timestamp": "1590794111", + "totalDifficulty": "2242105342155", + "alloc": { + "0x5ac5599fc9df172c89ee7ec55ad9104ccbfed40d": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x62325b40cbbd0915c4b9", + "nonce": "260875", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "1555170", + "difficulty": "4642198", + "timestamp": "1590794112", + "gasLimit": "9289249", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf8658303fb0b843b9aca0083019ee48080915a600055600060006000f0505a6001550081a2a01a7deb3a16d967b766459ef486b00656c6581e5ad58968184a33701e27e0eb8aa07162ccdfe2018d64360a605310a62c399dd586c7282dd42a88c54f02f51d451f", + "result": [ + { + "type": "create", + "action": { + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "value": "0x0", + "gas": "0xcf08", + "init": "0x5a600055600060006000f0505a60015500" + }, + "error": "out of gas", + "traceAddress": [], + "subtraces": 1, + "transactionPosition": 63, + "transactionHash": "0x60e881fae3884657b5430925c5d0053535b45cce0b8188f2a6be1feee8bcc650", + "blockNumber": 1555170, + "blockHash": "0xea46fbf941d51bf1e4180fbf26d22fda3896f49c7f371d109c226de95dd7b02e", + "time": "952.736µs" + }, + { + "type": "create", + "action": { + "from": "0x9c5cfe45b15eaff4ad617af4250189e26024a4f8", + "value": "0x0", + "gas": "0x3cb", + "init": "0x" + }, + "result": { + "gasUsed": "0x0", + "code": "0x", + "address": "0x5ac5599fc9df172c89ee7ec55ad9104ccbfed40d" + }, + "traceAddress": [0], + "subtraces": 0, + "transactionPosition": 63, + "transactionHash": "0x60e881fae3884657b5430925c5d0053535b45cce0b8188f2a6be1feee8bcc650", + "blockNumber": 1555170, + "blockHash": "0xea46fbf941d51bf1e4180fbf26d22fda3896f49c7f371d109c226de95dd7b02e" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json new file mode 100644 index 000000000000..a62d4bb64525 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json @@ -0,0 +1,81 @@ +{ + "genesis": { + "difficulty": "3244991", + "extraData": "0x", + "gasLimit": "7968787", + "hash": "0x62bbf18c203068a8793af8d8360d054f95a63bc62b87ade550861ed490af3f15", + "miner": "0x9f2659ffe7b3b467e46dcec3623392cf51635079", + "mixHash": "0xc8dec711fd1e03972b6a279a09dc0cd29c5171b60f42c4ce37c7c51ff445f776", + "nonce": "0x40b1bbcc25ddb804", + "number": "839246", + "stateRoot": "0x4bb3b02ec70b837651233957fb61a6ea3fc6a4244c1f55df7a713c154829ec0a", + "timestamp": "1581179375", + "totalDifficulty": "1023985623933", + "alloc": { + "0x76554b33410b6d90b7dc889bfed0451ad195f27e": { + "balance": "0x0", + "nonce": "1", + "code": "0x6080604052348015600f57600080fd5b506004361060505760003560e01c8063391521f414605557806355313dea14605d5780636d3d14161460655780638da5cb5b14606d578063b9d1e5aa1460b5575b600080fd5b605b60bd565b005b606360c8565b005b606b60ca565b005b607360cf565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60bb60f4565b005b6020610123600af050565b005b600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565bfefea165627a7a723058202094d5aa5dbbd493e9a2c64c50b62eba4b109b2a12d2bb73a5d0d54982651fc80029", + "storage": {} + }, + "0xed69ab7145a9bae7152406d062c077c6ecc6ae18": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0xa3b31cbd5168d3c99756660d4b7625d679e12573": { + "balance": "0x569bc6535d3083fce", + "nonce": "26", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "839247", + "difficulty": "3213311", + "timestamp": "1581179571", + "gasLimit": "7961006", + "miner": "0x9f2659ffe7b3b467e46dcec3623392cf51635079" + }, + "input": "0xf86a1a8509502f9000830334509476554b33410b6d90b7dc889bfed0451ad195f27e8084391521f481a2a02e4ff0d171a860c8c7de2283978e2f225f9ba3ed4dec446b773c6b2d73ef22dea02a6a517528b491cb71b204f534db11a1c8059035f54d5bae347d1cab536bde2c", + "result": [ + { + "type": "call", + "action": { + "from": "0xa3b31cbd5168d3c99756660d4b7625d679e12573", + "to": "0x76554b33410b6d90b7dc889bfed0451ad195f27e", + "value": "0x0", + "gas": "0x2e138", + "input": "0x391521f4", + "callType": "call" + }, + "result": { + "gasUsed": "0xd0b5", + "output": "0x" + }, + "traceAddress": [], + "subtraces": 0, + "transactionPosition": 26, + "transactionHash": "0xcb1090fa85d2a3da8326b75333e92b3dca89963c895d9c981bfdaa64643135e4", + "blockNumber": 839247, + "blockHash": "0xce7ff7d84ca97f0f89d6065e2c12409a795c9f607cdb14aef0713cad5d7e311c", + "time": "182.267µs" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json new file mode 100644 index 000000000000..792845538f98 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json @@ -0,0 +1,189 @@ +{ + "genesis": { + "number": "13535", + "hash": "0x6f706fe8026edb51577b57685574dc152dba4e2ebfc8a50bb63a8c95a4f8818d", + "nonce": "0x0000000000000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "stateRoot": "0x7f54db248a004ca182fe87fdfa6efda97163908b4f0cc84b36a6d60699d5d1be", + "miner": "0x0000000000000000000000000000000000000000", + "difficulty": "1", + "totalDifficulty": "24766", + "extraData": "0xf09f928e20407072796c616273206e6f64652d3020f09f928e000000000000001d32ac3baf238e163e18ed6d77b67b0b54b08ad9781dc4ffd93c5ede1ca12c5f21b36ac39c7ebb88dff65da91f5b9461f19873a02602230b931ba388a809119f00", + "gasLimit": "8000000", + "timestamp": "1549153003", + "alloc": { + "0x0b1ba0af832d7c05fd64161e0db78e85978e8082": { + "balance": "0x0", + "nonce": "1", + "code": "0x6080604052600436106100ae5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100b8578063095ea7b31461014257806318160ddd1461018757806323b872dd146101ae5780632e1a7d4d146101e5578063313ce567146101fd57806370a082311461022857806395d89b4114610256578063a9059cbb1461026b578063d0e30db0146100ae578063dd62ed3e1461029c575b6100b66102d0565b005b3480156100c457600080fd5b506100cd61031f565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101075781810151838201526020016100ef565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561014e57600080fd5b5061017373ffffffffffffffffffffffffffffffffffffffff600435166024356103cb565b604080519115158252519081900360200190f35b34801561019357600080fd5b5061019c61043e565b60408051918252519081900360200190f35b3480156101ba57600080fd5b5061017373ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610443565b3480156101f157600080fd5b506100b66004356105e3565b34801561020957600080fd5b50610212610678565b6040805160ff9092168252519081900360200190f35b34801561023457600080fd5b5061019c73ffffffffffffffffffffffffffffffffffffffff60043516610681565b34801561026257600080fd5b506100cd610693565b34801561027757600080fd5b5061017373ffffffffffffffffffffffffffffffffffffffff6004351660243561070b565b3480156102a857600080fd5b5061019c73ffffffffffffffffffffffffffffffffffffffff6004358116906024351661071f565b33600081815260036020908152604091829020805434908101909155825190815291517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9281900390910190a2565b6000805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f810184900484028201840190925281815292918301828280156103c35780601f10610398576101008083540402835291602001916103c3565b820191906000526020600020905b8154815290600101906020018083116103a657829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b303190565b73ffffffffffffffffffffffffffffffffffffffff831660009081526003602052604081205482111561047557600080fd5b73ffffffffffffffffffffffffffffffffffffffff841633148015906104eb575073ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14155b156105655773ffffffffffffffffffffffffffffffffffffffff8416600090815260046020908152604080832033845290915290205482111561052d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020805483900390555b73ffffffffffffffffffffffffffffffffffffffff808516600081815260036020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060019392505050565b336000908152600360205260409020548111156105ff57600080fd5b33600081815260036020526040808220805485900390555183156108fc0291849190818181858888f1935050505015801561063e573d6000803e3d6000fd5b5060408051828152905133917f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65919081900360200190a250565b60025460ff1681565b60036020526000908152604090205481565b60018054604080516020600284861615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f810184900484028201840190925281815292918301828280156103c35780601f10610398576101008083540402835291602001916103c3565b6000610718338484610443565b9392505050565b6004602090815260009283526040808420909152908252902054815600a165627a7a72305820228981f11f47ad9630080069b0a81423fcfba5aa8e0f478a579c4bc080ba7e820029", + "storage": { + "0xbe8a6e3827dad84a671edac41a02b0f5b47b9d0339adb1e9411b9ba4e2118738": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x48bacb9266a570d521063ef5dd96e61686dbe788": { + "balance": "0x0", + "nonce": "1", + "code": "0x6080604052600436106101b65763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663288cdc9181146101bb578063297bb70b146101f15780632ac126221461021e5780633683ef8e1461024b5780633c28d8611461026d5780633e228bae1461029a5780633fd3c997146102ba5780634ac14782146102e75780634d0ae546146103075780634f9559b11461032757806350dde190146103475780636070410814610367578063642f2eaf1461039457806364a3bc15146103b457806377fcce68146103d45780637b8e3514146103f45780637e1d9808146104145780637e9d74dc1461043457806382c174d0146104615780638da5cb5b146104815780639363470214610496578063a3e20380146104b6578063b4be83d5146104d6578063bfc8bfce146104f6578063c585bb9314610516578063c75e0a8114610536578063d46b02c314610563578063d9bfa73e14610583578063db123b1a146105a3578063dd1c7d18146105c5578063e306f779146105e5578063e5fa431b146105fa578063eea086ba1461061a578063f2fde38b1461062f578063ffa1ad741461064f575b600080fd5b3480156101c757600080fd5b506101db6101d63660046148ee565b610664565b6040516101e89190615513565b60405180910390f35b3480156101fd57600080fd5b5061021161020c366004614811565b610676565b6040516101e891906157ed565b34801561022a57600080fd5b5061023e6102393660046148ee565b6107a1565b6040516101e89190615505565b34801561025757600080fd5b5061026b61026636600461492b565b6107b6565b005b34801561027957600080fd5b5061028d610288366004614a5f565b6108a3565b6040516101e891906157fb565b3480156102a657600080fd5b506102116102b5366004614b1f565b610a3a565b3480156102c657600080fd5b506102da6102d53660046149ee565b610a90565b6040516101e891906155cf565b3480156102f357600080fd5b5061026b6103023660046147dc565b610ab8565b34801561031357600080fd5b50610211610322366004614811565b610b85565b34801561033357600080fd5b5061026b6103423660046148ee565b610c75565b34801561035357600080fd5b50610211610362366004614811565b610e2a565b34801561037357600080fd5b506103876103823660046149ee565b610ebe565b6040516101e89190615425565b3480156103a057600080fd5b5061023e6103af3660046148ee565b610f0c565b3480156103c057600080fd5b506102116103cf366004614b1f565b610f21565b3480156103e057600080fd5b5061026b6103ef3660046147ac565b610fcc565b34801561040057600080fd5b5061023e61040f366004614772565b611106565b34801561042057600080fd5b5061021161042f3660046148a5565b611126565b34801561044057600080fd5b5061045461044f3660046147dc565b61128a565b6040516101e891906154f4565b34801561046d57600080fd5b5061023e61047c36600461490c565b61131f565b34801561048d57600080fd5b5061038761133f565b3480156104a257600080fd5b5061023e6104b1366004614993565b61135b565b3480156104c257600080fd5b506102116104d13660046148a5565b6118de565b3480156104e257600080fd5b506102116104f1366004614b1f565b6119f1565b34801561050257600080fd5b5061026b610511366004614b68565b611a6c565b34801561052257600080fd5b5061026b610531366004614754565b611d05565b34801561054257600080fd5b50610556610551366004614a2a565b611f30565b6040516101e8919061580a565b34801561056f57600080fd5b5061026b61057e366004614a2a565b61202a565b34801561058f57600080fd5b506101db61059e366004614772565b6120c6565b3480156105af57600080fd5b506105b86120e3565b6040516101e891906155be565b3480156105d157600080fd5b506102116105e03660046148a5565b61218e565b3480156105f157600080fd5b506101db612263565b34801561060657600080fd5b506102116106153660046148a5565b612269565b34801561062657600080fd5b506103876123db565b34801561063b57600080fd5b5061026b61064a366004614754565b6123f7565b34801561065b57600080fd5b506105b86124a8565b60046020526000908152604090205481565b61067e614386565b600080610689614386565b60005460ff16156106cf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781558751935091505b81831461076f57610758878381518110151561071957fe5b90602001906020020151878481518110151561073157fe5b90602001906020020151878581518110151561074957fe5b906020019060200201516124df565b9050610764848261257d565b600190910190610701565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055509392505050565b60056020526000908152604090205460ff1681565b73ffffffffffffffffffffffffffffffffffffffff831633146108465761080e848484848080601f0160208091040260200160405190810160405280939291908181526020018383808284375061135b945050505050565b1515610846576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061569d565b5050600091825260076020908152604080842073ffffffffffffffffffffffffffffffffffffffff9093168452919052902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6108ab6143af565b6108b36143de565b6108bb6143de565b6000805460ff16156108f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561016080890151610140808a01919091528901519088015261094588611f30565b925061095087611f30565b915061095a6125df565b905061096888848389612611565b61097487838388612611565b61097e88886127a9565b610992888885604001518560400151612809565b8051602081015190519195506109ad918a9186918190612990565b6020808501519081015190516109c99189918591908190612990565b6109e28882856020015186604001518860000151612aa9565b6109fb8782846020015185604001518860200151612aa9565b610a0788888387612b55565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905550949350505050565b610a42614386565b6060610a4f858585612d2d565b9050608081825160208401305af48015610a8657815183526020820151602084015260408201516040840152606082015160608401525b505b509392505050565b600b6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60008054819060ff1615610af8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781558151905b808214610b5857610b508382815181101515610b4157fe5b90602001906020020151612eff565b600101610b29565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905550565b610b8d614386565b600080610b98614386565b60005460ff1615610bd5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781558751935091505b81831461076f57610c5e8783815181101515610c1f57fe5b906020019060200201518784815181101515610c3757fe5b906020019060200201518785815181101515610c4f57fe5b90602001906020020151612f2a565b9050610c6a848261257d565b600190910190610c07565b6000805481908190819060ff1615610cb9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610cec6125df565b935073ffffffffffffffffffffffffffffffffffffffff84163314610d115733610d14565b60005b73ffffffffffffffffffffffffffffffffffffffff8086166000908152600660209081526040808320938516835292905220549093506001860192509050808211610d8b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061572d565b73ffffffffffffffffffffffffffffffffffffffff80851660008181526006602090815260408083209488168084529490915290819020859055517f82af639571738f4ebd4268fb0363d8957ebe1bbb9e78dba5ebd69eed39b154f090610df3908690615513565b60405180910390a35050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055505050565b610e32614386565b600080610e3d614386565b86519250600091505b818314610eb457610e9d8783815181101515610e5e57fe5b906020019060200201518784815181101515610e7657fe5b906020019060200201518785815181101515610e8e57fe5b90602001906020020151610a3a565b9050610ea9848261257d565b600190910190610e46565b5050509392505050565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152600b602052604090205473ffffffffffffffffffffffffffffffffffffffff165b919050565b60096020526000908152604090205460ff1681565b610f29614386565b60005460ff1615610f66576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610f9c848484612f2a565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055949350505050565b6000805460ff161561100a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561103d6125df565b73ffffffffffffffffffffffffffffffffffffffff8181166000818152600860209081526040808320948916808452949091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168715151790555192935090917fa8656e308026eeabce8f0bc18048433252318ab80ac79da0b3d3d8697dfba891906110d1908690615505565b60405180910390a35050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905550565b600860209081526000928352604080842090915290825290205460ff1681565b61112e614386565b6060600080600061113d614386565b60005460ff161561117a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117815589518a919081106111b257fe5b906020019060200201516101600151945088519350600092505b828414611255578489848151811015156111e257fe5b906020019060200201516101600181905250611202888760200151612f7d565b915061122e898481518110151561121557fe5b9060200190602002015183898681518110151561074957fe5b905061123a868261257d565b6020860151881161124a57611255565b6001909201916111cc565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055509195945050505050565b606060006060600084519250826040519080825280602002602001820160405280156112d057816020015b6112bd6143de565b8152602001906001900390816112b55790505b509150600090505b808314610a88576112ff85828151811015156112f057fe5b90602001906020020151611f30565b828281518110151561130d57fe5b602090810290910101526001016112d8565b600760209081526000928352604080842090915290825290205460ff1681565b60035473ffffffffffffffffffffffffffffffffffffffff1681565b600080600080600080600080600089511115156113a4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061571d565b6113ad89612fc4565b7f010000000000000000000000000000000000000000000000000000000000000090049650600760ff88161061140f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061563d565b8660ff16600781111561141e57fe5b9550600086600781111561142e57fe5b1415611466576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061570d565b600186600781111561147457fe5b14156114bc578851156114b3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906157dd565b600097506118d0565b60028660078111156114ca57fe5b141561160557885160411461150b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906155dd565b88600081518110151561151a57fe5b01602001517f010000000000000000000000000000000000000000000000000000000000000090819004810204945061155a89600163ffffffff61308816565b935061156d89602163ffffffff61308816565b925060018b86868660405160008152602001604052604051611592949392919061556e565b60206040516020810390808403906000865af11580156115b6573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015173ffffffffffffffffffffffffffffffffffffffff8c811690821614995092506118d09050565b600386600781111561161357fe5b14156117b9578851604114611654576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906155dd565b88600081518110151561166357fe5b01602001517f01000000000000000000000000000000000000000000000000000000000000009081900481020494506116a389600163ffffffff61308816565b93506116b689602163ffffffff61308816565b925060018b60405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b6020831061175757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161171a565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040805192909401829003822060008352910192839052611592945092508991899150889061556e565b60048660078111156117c757fe5b14156117df576117d88b8b8b6130d3565b97506118d0565b60058660078111156117ed57fe5b1415611850576117fc89613228565b73ffffffffffffffffffffffffffffffffffffffff808c1660009081526008602090815260408083209385168352929052205490915060ff16151561184457600097506118d0565b6117d8818c8c8c6132a1565b600686600781111561185e57fe5b141561189e5760008b815260076020908152604080832073ffffffffffffffffffffffffffffffffffffffff8e16845290915290205460ff1697506118d0565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061563d565b505050505050509392505050565b6118e6614386565b60606000806000806118f6614386565b89600081518110151561190557fe5b906020019060200201516101400151955089519450600093505b8385146119e457858a8581518110151561193557fe5b6020908102909101015161014001528651611951908a90612f7d565b92506119948a8581518110151561196457fe5b9060200190602002015160a001518b8681518110151561198057fe5b9060200190602002015160800151856133fd565b91506119c08a858151811015156119a757fe5b90602001906020020151838a87815181101515610e8e57fe5b90506119cc878261257d565b865189116119d9576119e4565b60019093019261191f565b5050505050509392505050565b6119f9614386565b60005460ff1615611a36576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610f9c8484846124df565b600a5460009073ffffffffffffffffffffffffffffffffffffffff1615611abf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b611b02611afd888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843750613453945050505050565b613694565b60008181526009602052604090205490915060ff1615611b4e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061568d565b73ffffffffffffffffffffffffffffffffffffffff86163314611c1f57611ba6818785858080601f0160208091040260200160405190810160405280939291908181526020018383808284375061135b945050505050565b1515611bde576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906157cd565b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88161790555b6000818152600960205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555130908690869080838380828437820191505092505050600060405180830381855af49150501515611cb6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906156bd565b73ffffffffffffffffffffffffffffffffffffffff86163314611cfc57600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b50505050505050565b6003546000908190819073ffffffffffffffffffffffffffffffffffffffff163314611d5d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061577d565b8392508273ffffffffffffffffffffffffffffffffffffffff1663ae25532e6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015611dc457600080fd5b505af1158015611dd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611dfc9190810190614a0c565b7fffffffff0000000000000000000000000000000000000000000000000000000081166000908152600b602052604090205490925073ffffffffffffffffffffffffffffffffffffffff1690508015611e81576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061561d565b7fffffffff0000000000000000000000000000000000000000000000000000000082166000908152600b60205260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8616179055517fd2c6b762299c609bdb96520b58a49bfb80186934d4f71a86a367571a15c0319490611f2290849087906155a3565b60405180910390a150505050565b611f386143de565b611f41826136d1565b6020808301829052600091825260049052604090819020549082015260808201511515611f755760015b60ff168152610f07565b60a08201511515611f87576002611f6b565b60a0820151604082015110611f9d576005611f6b565b6101008201514210611fb0576004611f6b565b60208082015160009081526005909152604090205460ff1615611fd4576006611f6b565b610120820151825173ffffffffffffffffffffffffffffffffffffffff90811660009081526006602090815260408083206060880151909416835292905220541115612021576006611f6b565b60038152919050565b60005460ff1615612067576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561209b81612eff565b50600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b600660209081526000928352604080842090915290825290205481565b60018054604080516020600284861615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f810184900484028201840190925281815292918301828280156121865780601f1061215b57610100808354040283529160200191612186565b820191906000526020600020905b81548152906001019060200180831161216957829003601f168201915b505050505081565b612196614386565b606060008060006121a5614386565b8860008151811015156121b457fe5b906020019060200201516101600151945088519350600092505b828414612257578489848151811015156121e457fe5b906020019060200201516101600181905250612204888760200151612f7d565b9150612230898481518110151561221757fe5b90602001906020020151838986815181101515610e8e57fe5b905061223c868261257d565b6020860151881161224c57612257565b6001909201916121ce565b50505050509392505050565b60025481565b612271614386565b6060600080600080612281614386565b60005460ff16156122be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061576d565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781558a518b919081106122f657fe5b906020019060200201516101400151955089519450600093505b8385146123a557858a8581518110151561232657fe5b6020908102909101015161014001528651612342908a90612f7d565b92506123558a8581518110151561196457fe5b91506123818a8581518110151561236857fe5b90602001906020020151838a8781518110151561074957fe5b905061238d878261257d565b8651891161239a576123a5565b600190930192612310565b5050600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905550929695505050505050565b600a5473ffffffffffffffffffffffffffffffffffffffff1681565b60035473ffffffffffffffffffffffffffffffffffffffff163314612448576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061577d565b73ffffffffffffffffffffffffffffffffffffffff8116156124a557600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b60408051808201909152600581527f322e302e30000000000000000000000000000000000000000000000000000000602082015281565b6124e7614386565b6124ef6143de565b60008060006124fd88611f30565b93506125076125df565b925061251588858589612611565b6125278860a001518560400151612f7d565b915061253387836136df565b9050612546888589848960000151612990565b61255088826136f5565b945061256788848660200151876040015189612aa9565b612572888487613756565b505050509392505050565b8151815161258b9190613864565b8252602080830151908201516125a19190613864565b6020830152604080830151908201516125ba9190613864565b6040830152606080830151908201516125d39190613864565b60609092019190915250565b600a5460009073ffffffffffffffffffffffffffffffffffffffff16818115612608578161260a565b335b9392505050565b825160ff1660031461264f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061579d565b606084015173ffffffffffffffffffffffffffffffffffffffff16156126c257606084015173ffffffffffffffffffffffffffffffffffffffff1633146126c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906157ad565b602084015173ffffffffffffffffffffffffffffffffffffffff161561274d578173ffffffffffffffffffffffffffffffffffffffff16846020015173ffffffffffffffffffffffffffffffffffffffff1614151561274d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906155ed565b604083015115156127a35761276b836020015185600001518361135b565b15156127a3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061565d565b50505050565b6127bb8260a001518260a001516138ae565b6127cd836080015183608001516138ae565b1015612805576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906157bd565b5050565b6128116143af565b6000806000806128258960a0015188612f7d565b935061283a89608001518a60a0015186613909565b925061284a8860a0015187612f7d565b915061285f88608001518960a0015184613909565b90508084106128a25760208086018051839052805182018490525151865182015260808a015160a08b015187519092015161289a9290613909565b8551526128df565b845183905284516020908101859052855181015190860180519190915260a089015160808a01519151516128d69290613986565b60208087015101525b84515160208087015101516128f49190612f7d565b604086015284515160808a015160c08b0151612911929190613909565b85516040015284516020015160a08a015160e08b0151612932929190613909565b855160600152602085015151608089015160c08a0151612953929190613909565b8560200151604001818152505061297b8560200151602001518960a001518a60e00151613909565b60208601516060015250505050949350505050565b8215156129c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906156dd565b82821115612a03576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906156cd565b8460a00151612a16856040015184613864565b1115612a4e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906155fd565b612a5c8560800151836138ae565b612a6a828760a001516138ae565b1115612aa2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061575d565b5050505050565b612ab7828260200151613864565b600084815260046020908152604091829020929092558681015187518451938501518584015160608701516101408c01516101608d015196518b9873ffffffffffffffffffffffffffffffffffffffff9788169897909616967f0bcc4c97732e47d9946f229edb95f5b6323f601300e4690de719993f3c37112996612b46968f96339692959194909390615433565b60405180910390a45050505050565b60018054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101008789161502019095169490940493840181900481028201810190925282815260609390929091830182828015612bfe5780601f10612bd357610100808354040283529160200191612bfe565b820191906000526020600020905b815481529060010190602001808311612be157829003601f168201915b50505050509050612c2685610140015186600001518660000151856020015160200151613a23565b61014084015184518651845160200151612c4293929190613a23565b612c5b8561014001518660000151858560400151613a23565b612c778186600001518760400151856000015160400151613a23565b612c938185600001518660400151856020015160400151613a23565b836040015173ffffffffffffffffffffffffffffffffffffffff16856040015173ffffffffffffffffffffffffffffffffffffffff161415612cfd57612cf881848760400151612cf3866000015160600151876020015160600151613864565b613a23565b612aa2565b612d1581848760400151856000015160600151613a23565b612aa281848660400151856020015160600151613a23565b604080517fb4be83d5000000000000000000000000000000000000000000000000000000006020808301919091526060602483018181528751608485019081528884015160a48601529488015160c48501529087015160e4840152608087015161010484015260a087015161012484015260c087015161014484015260e08701516101648401526101008701516101848401526101208701516101a4840152610140870180516101c485019081526101608901516101e4860152610180905251805161020485018190529394919384936044870192849261022489019291820191601f82010460005b81811015612e34578351855260209485019490930192600101612e16565b50505050818103610160808401919091528a0151805180835260209283019291820191601f82010460005b81811015612e7d578351855260209485019490930192600101612e5f565b50505089845250848103602093840190815288518083529093918201918981019190601f82010460005b81811015612ec5578351855260209485019490930192600101612ea7565b5050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08883030188525060405250505050509392505050565b612f076143de565b612f1082611f30565b9050612f1c8282613bed565b612805828260200151613d04565b612f32614386565b612f3d8484846124df565b6020810151909150831461260a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061574d565b600082821115612fb9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061560d565b508082035b92915050565b6000808251111515613002576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906156fd565b815182907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810190811061303257fe5b016020015182517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01909252507f0100000000000000000000000000000000000000000000000000000000000000908190040290565b6000816020018351101515156130ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061562d565b50016020015190565b6040516000906060907f1626ba7e000000000000000000000000000000000000000000000000000000009061310e908790869060240161554e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093178352815191935090829081885afa8080156131ab576001811461321c57612572565b7f08c379a0000000000000000000000000000000000000000000000000000000006000527c20000000000000000000000000000000000000000000000000000000006020527c0c57414c4c45545f4552524f5200000000000000000000000000000000604052600060605260646000fd5b50505195945050505050565b60006014825110151515613268576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061578d565b613276826014845103613dab565b82517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec019092525090565b6040516000906060907f9363470200000000000000000000000000000000000000000000000000000000906132de90879087908790602401615521565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931783528151919350908290818a5afa80801561337b57600181146133ec576133f1565b7f08c379a0000000000000000000000000000000000000000000000000000000006000527c20000000000000000000000000000000000000000000000000000000006020527c0f56414c494441544f525f4552524f5200000000000000000000000000604052600060605260646000fd5b825194505b50505050949350505050565b6000808311613438576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061564d565b61344b61344585846138ae565b84613e0c565b949350505050565b604080517f5a65726f45785472616e73616374696f6e2800000000000000000000000000006020808301919091527f75696e743235362073616c742c0000000000000000000000000000000000000060328301527f61646472657373207369676e6572416464726573732c00000000000000000000603f8301527f627974657320646174610000000000000000000000000000000000000000000060558301527f2900000000000000000000000000000000000000000000000000000000000000605f830152825180830384018152606090920192839052815160009384938493909282918401908083835b6020831061357c57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161353f565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018019909216911617905260405191909301819003812089519097508995509093508392850191508083835b6020831061361257805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016135d5565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040805192909401829003822097825281019a909a525073ffffffffffffffffffffffffffffffffffffffff97909716968801969096525050606085015250506080909120919050565b600280546040517f190100000000000000000000000000000000000000000000000000000000000081529182015260228101919091526042902090565b6000612fbe611afd83613e23565b60008183106136ee578161260a565b5090919050565b6136fd614386565b6020810182905260a08301516080840151613719918491613909565b808252608084015160c0850151613731929190613909565b604082015260a083015160e084015161374b918491613909565b606082015292915050565b60018054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61010087891615020190951694909404938401819004810282018101909252828152606093909290918301828280156137ff5780601f106137d4576101008083540402835291602001916137ff565b820191906000526020600020905b8154815290600101906020018083116137e257829003601f168201915b5050505050905061381f8461014001518560000151858560000151613a23565b6138388461016001518486600001518560200151613a23565b61385081856000015186604001518560400151613a23565b6127a3818486604001518560600151613a23565b6000828201838110156138a3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061567d565b8091505b5092915050565b6000808315156138c157600091506138a7565b508282028284828115156138d157fe5b04146138a3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061567d565b6000808311613944576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061564d565b61394f84848461427c565b15613438576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906156ad565b60008083116139c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061564d565b6139cc848484614301565b15613a03576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906156ad565b61344b613445613a1386856138ae565b613a1e866001612f7d565b613864565b600080600083118015613a6257508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b15613be5578551600310613aa2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061573d565b50506020848101517fffffffff00000000000000000000000000000000000000000000000000000000166000818152600b90925260409091205473ffffffffffffffffffffffffffffffffffffffff16801515613b2b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906156ed565b604051660fffffffffffe0603f885101168060840182017fa85e59e40000000000000000000000000000000000000000000000000000000083526080600484015273ffffffffffffffffffffffffffffffffffffffff8816602484015273ffffffffffffffffffffffffffffffffffffffff87166044840152856064840152608483015b81811015613bc757895181526020998a019901613baf565b61020084858403866000895af1801515613bdf573d85fd5b50505050505b505050505050565b805160009060ff16600314613c2e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061579d565b606083015173ffffffffffffffffffffffffffffffffffffffff1615613ca157606083015173ffffffffffffffffffffffffffffffffffffffff163314613ca1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c6906157ad565b613ca96125df565b835190915073ffffffffffffffffffffffffffffffffffffffff808316911614613cff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061566d565b505050565b6000818152600560205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558281015183516101408501516101608601519351859473ffffffffffffffffffffffffffffffffffffffff9485169493909316927fdc47b3613d9fe400085f6dbdc99453462279057e6207385042827ed6b1a62cf792613d9f923392906154b7565b60405180910390a45050565b600081601401835110151515613ded576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061578d565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b6000808284811515613e1a57fe5b04949350505050565b604080517f4f726465722800000000000000000000000000000000000000000000000000006020808301919091527f61646472657373206d616b6572416464726573732c000000000000000000000060268301527f616464726573732074616b6572416464726573732c0000000000000000000000603b8301527f6164647265737320666565526563697069656e74416464726573732c0000000060508301527f616464726573732073656e646572416464726573732c00000000000000000000606c8301527f75696e74323536206d616b65724173736574416d6f756e742c0000000000000060828301527f75696e743235362074616b65724173736574416d6f756e742c00000000000000609b8301527f75696e74323536206d616b65724665652c00000000000000000000000000000060b48301527f75696e743235362074616b65724665652c00000000000000000000000000000060c58301527f75696e743235362065787069726174696f6e54696d655365636f6e64732c000060d68301527f75696e743235362073616c742c0000000000000000000000000000000000000060f48301527f6279746573206d616b65724173736574446174612c00000000000000000000006101018301527f62797465732074616b65724173736574446174610000000000000000000000006101168301527f290000000000000000000000000000000000000000000000000000000000000061012a830152825161010b81840301815261012b90920192839052815160009384938493849391929182918401908083835b602083106140ab57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161406e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930181900381206101408b0151805191995095509093508392850191508083835b6020831061414657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614109565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930181900381206101608b0151805191985095509093508392850191508083835b602083106141e157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016141a4565b5181516020939093036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018019909116921691909117905260405192018290039091207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0890180516101408b018051610160909c0180519a84529881529288526101a0822091529890525050509190525090919050565b6000808084116142b8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061564d565b8215806142c3575084155b156142d15760009150610a88565b838015156142db57fe5b85840990506142ea85846138ae565b6142f66103e8836138ae565b101595945050505050565b60008080841161433d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c69061564d565b821580614348575084155b156143565760009150610a88565b8380151561436057fe5b8584099050836143708583612f7d565b81151561437957fe5b0690506142ea85846138ae565b608060405190810160405280600081526020016000815260200160008152602001600081525090565b610120604051908101604052806143c4614386565b81526020016143d1614386565b8152602001600081525090565b604080516060810182526000808252602082018190529181019190915290565b600061260a82356158b0565b6000601f8201831361441b57600080fd5b813561442e6144298261583f565b615818565b81815260209384019390925082018360005b8381101561446c578135860161445688826145bc565b8452506020928301929190910190600101614440565b5050505092915050565b6000601f8201831361448757600080fd5b81356144956144298261583f565b81815260209384019390925082018360005b8381101561446c57813586016144bd888261460b565b84525060209283019291909101906001016144a7565b6000601f820183136144e457600080fd5b81356144f26144298261583f565b9150818183526020840193506020810190508385602084028201111561451757600080fd5b60005b8381101561446c578161452d888261454f565b845250602092830192919091019060010161451a565b600061260a82356158c9565b600061260a82356158ce565b600061260a82356158d1565b600061260a82516158d1565b600080601f8301841361458557600080fd5b50813567ffffffffffffffff81111561459d57600080fd5b6020830191508360018202830111156145b557600080fd5b9250929050565b6000601f820183136145cd57600080fd5b81356145db61442982615860565b915080825260208301602083018583830111156145f757600080fd5b614602838284615907565b50505092915050565b6000610180828403121561461e57600080fd5b614629610180615818565b9050600061463784846143fe565b8252506020614648848483016143fe565b602083015250604061465c848285016143fe565b6040830152506060614670848285016143fe565b60608301525060806146848482850161454f565b60808301525060a06146988482850161454f565b60a08301525060c06146ac8482850161454f565b60c08301525060e06146c08482850161454f565b60e0830152506101006146d58482850161454f565b610100830152506101206146eb8482850161454f565b6101208301525061014082013567ffffffffffffffff81111561470d57600080fd5b614719848285016145bc565b6101408301525061016082013567ffffffffffffffff81111561473b57600080fd5b614747848285016145bc565b6101608301525092915050565b60006020828403121561476657600080fd5b600061344b84846143fe565b6000806040838503121561478557600080fd5b600061479185856143fe565b92505060206147a2858286016143fe565b9150509250929050565b600080604083850312156147bf57600080fd5b60006147cb85856143fe565b92505060206147a285828601614543565b6000602082840312156147ee57600080fd5b813567ffffffffffffffff81111561480557600080fd5b61344b84828501614476565b60008060006060848603121561482657600080fd5b833567ffffffffffffffff81111561483d57600080fd5b61484986828701614476565b935050602084013567ffffffffffffffff81111561486657600080fd5b614872868287016144d3565b925050604084013567ffffffffffffffff81111561488f57600080fd5b61489b8682870161440a565b9150509250925092565b6000806000606084860312156148ba57600080fd5b833567ffffffffffffffff8111156148d157600080fd5b6148dd86828701614476565b93505060206148728682870161454f565b60006020828403121561490057600080fd5b600061344b848461454f565b6000806040838503121561491f57600080fd5b6000614791858561454f565b6000806000806060858703121561494157600080fd5b600061494d878761454f565b945050602061495e878288016143fe565b935050604085013567ffffffffffffffff81111561497b57600080fd5b61498787828801614573565b95989497509550505050565b6000806000606084860312156149a857600080fd5b60006149b4868661454f565b93505060206149c5868287016143fe565b925050604084013567ffffffffffffffff8111156149e257600080fd5b61489b868287016145bc565b600060208284031215614a0057600080fd5b600061344b848461455b565b600060208284031215614a1e57600080fd5b600061344b8484614567565b600060208284031215614a3c57600080fd5b813567ffffffffffffffff811115614a5357600080fd5b61344b8482850161460b565b60008060008060808587031215614a7557600080fd5b843567ffffffffffffffff811115614a8c57600080fd5b614a988782880161460b565b945050602085013567ffffffffffffffff811115614ab557600080fd5b614ac18782880161460b565b935050604085013567ffffffffffffffff811115614ade57600080fd5b614aea878288016145bc565b925050606085013567ffffffffffffffff811115614b0757600080fd5b614b13878288016145bc565b91505092959194509250565b600080600060608486031215614b3457600080fd5b833567ffffffffffffffff811115614b4b57600080fd5b614b578682870161460b565b93505060206149c58682870161454f565b60008060008060008060808789031215614b8157600080fd5b6000614b8d898961454f565b9650506020614b9e89828a016143fe565b955050604087013567ffffffffffffffff811115614bbb57600080fd5b614bc789828a01614573565b9450945050606087013567ffffffffffffffff811115614be657600080fd5b614bf289828a01614573565b92509250509295509295509295565b614c0a816158b0565b82525050565b6000614c1b826158ac565b808452602084019350614c2d836158a6565b60005b82811015614c5d57614c438683516153e5565b614c4c826158a6565b606096909601959150600101614c30565b5093949350505050565b614c0a816158c9565b614c0a816158ce565b614c0a816158d1565b6000614c8d826158ac565b808452614ca1816020860160208601615913565b614caa8161593f565b9093016020019392505050565b614c0a816158fc565b601281527f4c454e4754485f36355f52455155495245440000000000000000000000000000602082015260400190565b600d81527f494e56414c49445f54414b455200000000000000000000000000000000000000602082015260400190565b600e81527f4f524445525f4f56455246494c4c000000000000000000000000000000000000602082015260400190565b601181527f55494e543235365f554e444552464c4f57000000000000000000000000000000602082015260400190565b601a81527f41535345545f50524f58595f414c52454144595f455849535453000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601581527f5349474e41545552455f554e535550504f525445440000000000000000000000602082015260400190565b601081527f4449564953494f4e5f42595f5a45524f00000000000000000000000000000000602082015260400190565b601781527f494e56414c49445f4f524445525f5349474e4154555245000000000000000000602082015260400190565b600d81527f494e56414c49445f4d414b455200000000000000000000000000000000000000602082015260400190565b601081527f55494e543235365f4f564552464c4f5700000000000000000000000000000000602082015260400190565b600f81527f494e56414c49445f54585f484153480000000000000000000000000000000000602082015260400190565b601181527f494e56414c49445f5349474e4154555245000000000000000000000000000000602082015260400190565b600e81527f524f554e44494e475f4552524f52000000000000000000000000000000000000602082015260400190565b601081527f4641494c45445f455845435554494f4e00000000000000000000000000000000602082015260400190565b600d81527f54414b45525f4f56455250415900000000000000000000000000000000000000602082015260400190565b601481527f494e56414c49445f54414b45525f414d4f554e54000000000000000000000000602082015260400190565b601a81527f41535345545f50524f58595f444f45535f4e4f545f4558495354000000000000602082015260400190565b602181527f475245415445525f5448414e5f5a45524f5f4c454e4754485f5245515549524560208201527f4400000000000000000000000000000000000000000000000000000000000000604082015260600190565b601181527f5349474e41545552455f494c4c4547414c000000000000000000000000000000602082015260400190565b601e81527f4c454e4754485f475245415445525f5448414e5f305f52455155495245440000602082015260400190565b601781527f494e56414c49445f4e45575f4f524445525f45504f4348000000000000000000602082015260400190565b601e81527f4c454e4754485f475245415445525f5448414e5f335f52455155495245440000602082015260400190565b601481527f434f4d504c4554455f46494c4c5f4641494c4544000000000000000000000000602082015260400190565b601281527f494e56414c49445f46494c4c5f50524943450000000000000000000000000000602082015260400190565b601281527f5245454e5452414e43595f494c4c4547414c0000000000000000000000000000602082015260400190565b601381527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601081527f4f524445525f554e46494c4c41424c4500000000000000000000000000000000602082015260400190565b600e81527f494e56414c49445f53454e444552000000000000000000000000000000000000602082015260400190565b601881527f4e454741544956455f5350524541445f52455155495245440000000000000000602082015260400190565b601481527f494e56414c49445f54585f5349474e4154555245000000000000000000000000602082015260400190565b601181527f4c454e4754485f305f5245515549524544000000000000000000000000000000602082015260400190565b805160808301906153738482614c70565b5060208201516153866020850182614c70565b5060408201516153996040850182614c70565b5060608201516127a36060850182614c70565b80516101208301906153be8482615362565b5060208201516153d16080850182615362565b5060408201516127a3610100850182614c70565b805160608301906153f6848261541c565b5060208201516154096020850182614c70565b5060408201516127a36040850182614c70565b614c0a816158f6565b60208101612fbe8284614c01565b6101008101615442828b614c01565b61544f602083018a614c01565b61545c6040830189614c70565b6154696060830188614c70565b6154766080830187614c70565b61548360a0830186614c70565b81810360c08301526154958185614c82565b905081810360e08301526154a98184614c82565b9a9950505050505050505050565b606081016154c58286614c01565b81810360208301526154d78185614c82565b905081810360408301526154eb8184614c82565b95945050505050565b6020808252810161260a8184614c10565b60208101612fbe8284614c67565b60208101612fbe8284614c70565b6060810161552f8286614c70565b61553c6020830185614c01565b81810360408301526154eb8184614c82565b6040810161555c8285614c70565b818103602083015261344b8184614c82565b6080810161557c8287614c70565b615589602083018661541c565b6155966040830185614c70565b6154eb6060830184614c70565b604081016155b18285614c79565b61260a6020830184614c01565b6020808252810161260a8184614c82565b60208101612fbe8284614cb7565b60208082528101612fbe81614cc0565b60208082528101612fbe81614cf0565b60208082528101612fbe81614d20565b60208082528101612fbe81614d50565b60208082528101612fbe81614d80565b60208082528101612fbe81614db0565b60208082528101612fbe81614e06565b60208082528101612fbe81614e36565b60208082528101612fbe81614e66565b60208082528101612fbe81614e96565b60208082528101612fbe81614ec6565b60208082528101612fbe81614ef6565b60208082528101612fbe81614f26565b60208082528101612fbe81614f56565b60208082528101612fbe81614f86565b60208082528101612fbe81614fb6565b60208082528101612fbe81614fe6565b60208082528101612fbe81615016565b60208082528101612fbe81615046565b60208082528101612fbe8161509c565b60208082528101612fbe816150cc565b60208082528101612fbe816150fc565b60208082528101612fbe8161512c565b60208082528101612fbe8161515c565b60208082528101612fbe8161518c565b60208082528101612fbe816151bc565b60208082528101612fbe816151ec565b60208082528101612fbe8161521c565b60208082528101612fbe81615272565b60208082528101612fbe816152a2565b60208082528101612fbe816152d2565b60208082528101612fbe81615302565b60208082528101612fbe81615332565b60808101612fbe8284615362565b6101208101612fbe82846153ac565b60608101612fbe82846153e5565b60405181810167ffffffffffffffff8111828210171561583757600080fd5b604052919050565b600067ffffffffffffffff82111561585657600080fd5b5060209081020190565b600067ffffffffffffffff82111561587757600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b60200190565b5190565b73ffffffffffffffffffffffffffffffffffffffff1690565b151590565b90565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b60ff1690565b6000612fbe826158b0565b82818337506000910152565b60005b8381101561592e578181015183820152602001615916565b838111156127a35750506000910152565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016905600a265627a7a72305820d41ee66f45c4d1637cb6e5f109447c6d5d7fef3204a685dc442151c0f029b7da6c6578706572696d656e74616cf50037", + "storage": { + "0x1458d05345aa0372fb580f207529f32cbb6e9242890d36a93225785d4496083e": "0x0000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48" + } + }, + "0x5409ed021d9299bf6814279a6a1411a7e866a631": { + "balance": "0xac6bd1cc338c2000", + "nonce": "22", + "code": "0x", + "storage": {} + }, + "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c": { + "balance": "0x0", + "nonce": "1", + "code": "0x606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a723058201b5b70cf82a73dec658c2e60ab9a0f8e2ba01a74b66a6f5b0402f56d2ea0ffcf0029", + "storage": { + "0xd37b858806ebf992fe75c1dd1a61cc7625ea52328d19005ba6b8b62506ae5306": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + } + }, + "config": { + "chainId": 5, + "supportedProtocolVersions": [ + 67, + 66 + ], + "homesteadBlock": 0, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 1561651, + "berlinBlock": 4460644, + "londonBlock": 5062605, + "terminalTotalDifficulty": 10790000, + "terminalTotalDifficultyPassed": true, + "clique": { + "period": 15, + "epoch": 30000 + }, + "trustedCheckpoint": { + "sectionIndex": 210, + "sectionHead": "0xbb11eaf551a6c06f74a6c7bbfe1699cbf64b8f248b64691da916dd443176db2f", + "chtRoot": "0x9934ae326d00d9c7de2e074c0e51689efb7fa7fcba18929ff4279c27259c45e6", + "bloomRoot": "0x7fe3bd4fd45194aa8a5cfe5ac590edff1f870d3d98d3c310494e7f67613a87ff" + }, + "trustedCheckpointOracle": { + "address": "0x18ca0e045f0d772a851bc7e48357bcaab0a0795d", + "signers": [ + "0x4769bcad07e3b938b7f43eb7d278bc7cb9effb38", + "0x78d1ad571a1a09d60d9bbf25894b44e4c8859595", + "0x286834935f4a8cfb4ff4c77d5770c2775ae2b0e7", + "0xb86e2b0ab5a4b1373e40c51a7c712c70ba2f9f8e", + "0x0df8fa387c602ae62559cc4afa4972a7045d6707" + ], + "threshold": 2 + } + } + }, + "context": { + "number": "13536", + "difficulty": "1", + "timestamp": "1549153018", + "gasLimit": "8000000", + "miner": "0x0000000000000000000000000000000000000000", + "transactionHash": "0x6974f745a004f030bebb1c01d4595edbda2fafcf01c0bfbd5d335711e2a7b04e" + }, + "input": "0xf92e9e1684ee6b2800832c8c7f8080b92e4c60806040523480156200001157600080fd5b5060405162002d2c38038062002d2c83398101806040526200003791908101906200051d565b6000805433600160a060020a031991821617825560018054909116600160a060020a0386161790558251849084908490849081906200007e906004906020870190620003d0565b50825162000094906005906020860190620003d0565b50620000b0836010640100000000620019476200036f82021704565b9150620000cd846010640100000000620019476200036f82021704565b60028054600160a060020a03948516600160a060020a031991821617909155600380549285169290911691909117905550600154604080517f4552433230546f6b656e28616464726573732900000000000000000000000000815290519081900360130181207f6070410800000000000000000000000000000000000000000000000000000000825291909216945063607041089350620001739250906004016200068e565b602060405180830381600087803b1580156200018e57600080fd5b505af1158015620001a3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620001c99190810190620004f4565b9050600160a060020a038116151562000219576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200021090620006b0565b60405180910390fd5b6002546040517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a039091169063095ea7b39062000268908490600019906004016200066f565b602060405180830381600087803b1580156200028357600080fd5b505af115801562000298573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002be9190810190620005a1565b506003546040517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a039091169063095ea7b3906200030e908490600019906004016200066f565b602060405180830381600087803b1580156200032957600080fd5b505af11580156200033e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620003649190810190620005a1565b50505050506200077a565b600081601401835110151515620003b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000210906200069e565b506014818301810151910190600160a060020a03165b92915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200041357805160ff191683800117855562000443565b8280016001018555821562000443579182015b828111156200044357825182559160200191906001019062000426565b506200045192915062000455565b5090565b6200047291905b808211156200045157600081556001016200045c565b90565b600062000483825162000711565b9392505050565b600062000483825162000742565b6000601f82018313620004aa57600080fd5b8151620004c1620004bb82620006e9565b620006c2565b91508082526020830160208301858383011115620004de57600080fd5b620004eb83828462000747565b50505092915050565b6000602082840312156200050757600080fd5b600062000515848462000475565b949350505050565b6000806000606084860312156200053357600080fd5b600062000541868662000475565b93505060208401516001604060020a038111156200055e57600080fd5b6200056c8682870162000498565b92505060408401516001604060020a038111156200058957600080fd5b620005978682870162000498565b9150509250925092565b600060208284031215620005b457600080fd5b60006200051584846200048a565b620005cd8162000711565b82525050565b620005cd816200071d565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601881527f554e524547495354455245445f41535345545f50524f58590000000000000000602082015260400190565b620005cd8162000472565b604081016200067f8285620005c2565b62000483602083018462000664565b60208101620003ca8284620005d3565b60208082528101620003ca81620005de565b60208082528101620003ca8162000634565b6040518181016001604060020a0381118282101715620006e157600080fd5b604052919050565b60006001604060020a038211156200070057600080fd5b506020601f91909101601f19160190565b600160a060020a031690565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b151590565b60005b83811015620007645781810151838201526020016200074a565b8381111562000774576000848401525b50505050565b6125a2806200078a6000396000f30060806040526004361061006c5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166318978e8281146100c8578063630f1e6c146100f25780638da5cb5b146101125780639395525c14610134578063f2fde38b14610147575b60025473ffffffffffffffffffffffffffffffffffffffff1633146100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612388565b60405180910390fd5b005b6100db6100d6366004611df1565b610167565b6040516100e9929190612488565b60405180910390f35b3480156100fe57600080fd5b506100c661010d366004611eec565b6102f7565b34801561011e57600080fd5b50610127610388565b6040516100e99190612337565b6100db610142366004611d0b565b6103a4565b34801561015357600080fd5b506100c6610162366004611ce5565b61050a565b61016f6119fa565b6101776119fa565b6000806101826105bb565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100600188161502019095169490940493840181900481028201810190925282815261025c939092909183018282801561022d5780601f106102025761010080835404028352916020019161022d565b820191906000526020600020905b81548152906001019060200180831161021057829003601f168201915b50505050508c600081518110151561024157fe5b6020908102909101015161014001519063ffffffff61069616565b156102875761026c8b8b8b6107c3565b935061028084600001518560600151610ac1565b90506102ae565b6102928b8b8b610b03565b9350836060015191506102a68883896107c3565b845190935090505b6102c2846020015184602001518888610d15565b6102e98b60008151811015156102d457fe5b90602001906020020151610140015182610f29565b505097509795505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610348576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612438565b61038383838080601f01602080910402602001604051908101604052809392919081815260200183838082843750879450610f299350505050565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b6103ac6119fa565b6103b46119fa565b60008060006103c16105bb565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152610441939092909183018282801561022d5780601f106102025761010080835404028352916020019161022d565b156104925761046a670de0b6b3a7640000610464670de0b6b3a76400008a611045565b3461108f565b92506104778b848c6110e7565b945061048b85600001518660600151610ac1565b90506104d6565b6104ad670d2f13f7789f0000670de0b6b3a76400003461108f565b92506104ba8b848c6110e7565b9450846060015191506104ce89838a6107c3565b855190945090505b6104ea856020015185602001518989610d15565b6104fc8b60008151811015156102d457fe5b505050965096945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461055b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612438565b73ffffffffffffffffffffffffffffffffffffffff8116156105b857600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b600034116105f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612398565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004016000604051808303818588803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b5050505050565b6000815183511480156107ba5750816040518082805190602001908083835b602083106106f257805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016106b5565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0180199092169116179052604051919093018190038120885190955088945090928392508401908083835b6020831061078757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161074a565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916145b90505b92915050565b6107cb6119fa565b60608060008060008060006107de6119fa565b8a15156107ea57610ab2565b6004805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561088e5780601f106108635761010080835404028352916020019161088e565b820191906000526020600020905b81548152906001019060200180831161087157829003601f168201915b505060058054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152969e509194509250840190508282801561093d5780601f106109125761010080835404028352916020019161093d565b820191906000526020600020905b81548152906001019060200180831161092057829003601f168201915b50505050509650600095508b519450600093505b838514610a7857878c8581518110151561096757fe5b6020908102909101015161014001528b5187908d908690811061098657fe5b60209081029091010151610160015261099f8b87610ac1565b9250610a068c858151811015156109b257fe5b9060200190602002015160a00151610a008e878151811015156109d157fe5b90602001906020020151608001518f888151811015156109ed57fe5b9060200190602002015160e00151610ac1565b8561128b565b9150610a418c85815181101515610a1957fe5b90602001906020020151838c87815181101515610a3257fe5b906020019060200201516112e6565b9050610a4d898261135e565b610a5f89600001518a60600151610ac1565b95508a8610610a6d57610a78565b600190930192610951565b8a861015610ab2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612418565b50505050505050509392505050565b600082821115610afd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123b8565b50900390565b610b0b6119fa565b606080600080600080610b1c6119fa565b60008b6000815181101515610b2d57fe5b6020908102919091018101516101400151600580546040805160026001841615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190931692909204601f8101869004860283018601909152808252929b5092909190830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505096508b519550600094505b848614610cdb57878c86815181101515610c0b57fe5b6020908102909101015161014001528b5187908d9087908110610c2a57fe5b6020908102909101015161016001528851610c46908c90610ac1565b9350610c898c86815181101515610c5957fe5b9060200190602002015160a001518d87815181101515610c7557fe5b90602001906020020151608001518661128b565b9250610cb58c86815181101515610c9c57fe5b90602001906020020151848c88815181101515610a3257fe5b9150610cc1898361135e565b5087518a8110610cd057610cdb565b600190940193610bf5565b8a811015610ab2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612418565b600080808066b1a2bc2ec50000861115610d5b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612448565b610d658888611045565b935034841115610da1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123a8565b610dab3485610ac1565b9250610dc086670de0b6b3a76400008a61108f565b915082821115610dfc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612428565b6000831115610f1f576002546040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d90610e5b9086906004016124a4565b600060405180830381600087803b158015610e7557600080fd5b505af1158015610e89573d6000803e3d6000fd5b505050506000821115610edb5760405173ffffffffffffffffffffffffffffffffffffffff86169083156108fc029084906000818181858888f19350505050158015610ed9573d6000803e3d6000fd5b505b610ee58383610ac1565b90506000811115610f1f57604051339082156108fc029083906000818181858888f19350505050158015610f1d573d6000803e3d6000fd5b505b5050505050505050565b6000610f3b838263ffffffff6113c016565b604080517f4552433230546f6b656e28616464726573732900000000000000000000000000815290519081900360130190209091507fffffffff0000000000000000000000000000000000000000000000000000000080831691161415610fab57610fa6838361142d565b610383565b604080517f455243373231546f6b656e28616464726573732c75696e7432353629000000008152905190819003601c0190207fffffffff000000000000000000000000000000000000000000000000000000008281169116141561101357610fa6838361161b565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123f8565b600082820183811015611084576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123e8565b8091505b5092915050565b60008083116110ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123d8565b6110dd6110d78584611703565b8461175e565b90505b9392505050565b6110ef6119fa565b60608060008060006110ff6119fa565b89600081518110151561110e57fe5b6020908102919091018101516101400151600580546040805160026001841615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190931692909204601f8101869004860283018601909152808252929950929091908301828280156111c65780601f1061119b576101008083540402835291602001916111c6565b820191906000526020600020905b8154815290600101906020018083116111a957829003601f168201915b5050505050945089519350600092505b82841461127e57858a848151811015156111ec57fe5b602090810290910101516101400152895185908b908590811061120b57fe5b90602001906020020151610160018190525061122b898860200151610ac1565b91506112578a8481518110151561123e57fe5b90602001906020020151838a86815181101515610a3257fe5b9050611263878261135e565b602087015189116112735761127e565b6001909201916111d6565b5050505050509392505050565b60008083116112c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123d8565b6110dd6110d76112d68685611703565b6112e1866001610ac1565b611045565b6112ee6119fa565b606060006112fd868686611775565b600154815191935073ffffffffffffffffffffffffffffffffffffffff1691506080908390602082016000855af1801561135457825184526020830151602085015260408301516040850152606083015160608501525b5050509392505050565b8151815161136c9190611045565b8252602080830151908201516113829190611045565b60208301526040808301519082015161139b9190611045565b6040830152606080830151908201516113b49190611045565b60609092019190915250565b600081600401835110151515611402576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612468565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b60008061144184601063ffffffff61194716565b604080517f7472616e7366657228616464726573732c75696e7432353629000000000000008152905190819003601901812091935073ffffffffffffffffffffffffffffffffffffffff8416919061149f903390879060240161236d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931783525181519192909182919080838360005b8381101561154357818101518382015260200161152b565b50505050905090810190601f1680156115705780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1925050508015156115bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612408565b3d156115dc575060003d602014156115dc5760206000803e506000515b801515611615576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612408565b50505050565b60008060018314611658576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612478565b61166984601063ffffffff61194716565b915061167c84602463ffffffff6119a816565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8316906323b872dd906116d590309033908690600401612345565b600060405180830381600087803b1580156116ef57600080fd5b505af1158015610f1f573d6000803e3d6000fd5b6000808315156117165760009150611088565b5082820282848281151561172657fe5b0414611084576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123e8565b600080828481151561176c57fe5b04949350505050565b604080517fb4be83d5000000000000000000000000000000000000000000000000000000006020808301919091526060602483018181528751608485019081528884015160a48601529488015160c48501529087015160e4840152608087015161010484015260a087015161012484015260c087015161014484015260e08701516101648401526101008701516101848401526101208701516101a4840152610140870180516101c485019081526101608901516101e4860152610180905251805161020485018190529394919384936044870192849261022489019291820191601f82010460005b8181101561187c57835185526020948501949093019260010161185e565b50505050818103610160808401919091528a0151805180835260209283019291820191601f82010460005b818110156118c55783518552602094850194909301926001016118a7565b50505089845250848103602093840190815288518083529093918201918981019190601f82010460005b8181101561190d5783518552602094850194909301926001016118ef565b5050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08883030188525060405250505050509392505050565b600081601401835110151515611989576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612458565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b60006107ba83836000816020018351101515156119f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123c8565b50016020015190565b608060405190810160405280600081526020016000815260200160008152602001600081525090565b60006107ba8235612540565b6000601f82018313611a4057600080fd5b8135611a53611a4e826124d9565b6124b2565b81815260209384019390925082018360005b83811015611a915781358601611a7b8882611b41565b8452506020928301929190910190600101611a65565b5050505092915050565b6000601f82018313611aac57600080fd5b8135611aba611a4e826124d9565b81815260209384019390925082018360005b83811015611a915781358601611ae28882611b90565b8452506020928301929190910190600101611acc565b600080601f83018413611b0a57600080fd5b50813567ffffffffffffffff811115611b2257600080fd5b602083019150836001820283011115611b3a57600080fd5b9250929050565b6000601f82018313611b5257600080fd5b8135611b60611a4e826124fa565b91508082526020830160208301858383011115611b7c57600080fd5b611b8783828461255c565b50505092915050565b60006101808284031215611ba357600080fd5b611bae6101806124b2565b90506000611bbc8484611a23565b8252506020611bcd84848301611a23565b6020830152506040611be184828501611a23565b6040830152506060611bf584828501611a23565b6060830152506080611c0984828501611cd9565b60808301525060a0611c1d84828501611cd9565b60a08301525060c0611c3184828501611cd9565b60c08301525060e0611c4584828501611cd9565b60e083015250610100611c5a84828501611cd9565b61010083015250610120611c7084828501611cd9565b6101208301525061014082013567ffffffffffffffff811115611c9257600080fd5b611c9e84828501611b41565b6101408301525061016082013567ffffffffffffffff811115611cc057600080fd5b611ccc84828501611b41565b6101608301525092915050565b60006107ba8235612559565b600060208284031215611cf757600080fd5b6000611d038484611a23565b949350505050565b60008060008060008060c08789031215611d2457600080fd5b863567ffffffffffffffff811115611d3b57600080fd5b611d4789828a01611a9b565b965050602087013567ffffffffffffffff811115611d6457600080fd5b611d7089828a01611a2f565b955050604087013567ffffffffffffffff811115611d8d57600080fd5b611d9989828a01611a9b565b945050606087013567ffffffffffffffff811115611db657600080fd5b611dc289828a01611a2f565b9350506080611dd389828a01611cd9565b92505060a0611de489828a01611a23565b9150509295509295509295565b600080600080600080600060e0888a031215611e0c57600080fd5b873567ffffffffffffffff811115611e2357600080fd5b611e2f8a828b01611a9b565b9750506020611e408a828b01611cd9565b965050604088013567ffffffffffffffff811115611e5d57600080fd5b611e698a828b01611a2f565b955050606088013567ffffffffffffffff811115611e8657600080fd5b611e928a828b01611a9b565b945050608088013567ffffffffffffffff811115611eaf57600080fd5b611ebb8a828b01611a2f565b93505060a0611ecc8a828b01611cd9565b92505060c0611edd8a828b01611a23565b91505092959891949750929550565b600080600060408486031215611f0157600080fd5b833567ffffffffffffffff811115611f1857600080fd5b611f2486828701611af8565b93509350506020611f3786828701611cd9565b9150509250925092565b611f4a81612540565b82525050565b602381527f44454641554c545f46554e4354494f4e5f574554485f434f4e54524143545f4f60208201527f4e4c590000000000000000000000000000000000000000000000000000000000604082015260600190565b601181527f494e56414c49445f4d53475f56414c5545000000000000000000000000000000602082015260400190565b600d81527f4f564552534f4c445f5745544800000000000000000000000000000000000000602082015260400190565b601181527f55494e543235365f554e444552464c4f57000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601081527f4449564953494f4e5f42595f5a45524f00000000000000000000000000000000602082015260400190565b601081527f55494e543235365f4f564552464c4f5700000000000000000000000000000000602082015260400190565b601781527f554e535550504f525445445f41535345545f50524f5859000000000000000000602082015260400190565b600f81527f5452414e534645525f4641494c45440000000000000000000000000000000000602082015260400190565b601481527f434f4d504c4554455f46494c4c5f4641494c4544000000000000000000000000602082015260400190565b601a81527f494e53554646494349454e545f4554485f52454d41494e494e47000000000000602082015260400190565b601381527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000602082015260400190565b601881527f4645455f50455243454e544147455f544f4f5f4c415247450000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b602581527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160208201527f5549524544000000000000000000000000000000000000000000000000000000604082015260600190565b600e81527f494e56414c49445f414d4f554e54000000000000000000000000000000000000602082015260400190565b805160808301906122f9848261232e565b50602082015161230c602085018261232e565b50604082015161231f604085018261232e565b50606082015161161560608501825b611f4a81612559565b602081016107bd8284611f41565b606081016123538286611f41565b6123606020830185611f41565b611d03604083018461232e565b6040810161237b8285611f41565b6110e0602083018461232e565b602080825281016107bd81611f50565b602080825281016107bd81611fa6565b602080825281016107bd81611fd6565b602080825281016107bd81612006565b602080825281016107bd81612036565b602080825281016107bd8161208c565b602080825281016107bd816120bc565b602080825281016107bd816120ec565b602080825281016107bd8161211c565b602080825281016107bd8161214c565b602080825281016107bd8161217c565b602080825281016107bd816121ac565b602080825281016107bd816121dc565b602080825281016107bd8161220c565b602080825281016107bd81612262565b602080825281016107bd816122b8565b610100810161249782856122e8565b6110e060808301846122e8565b602081016107bd828461232e565b60405181810167ffffffffffffffff811182821017156124d157600080fd5b604052919050565b600067ffffffffffffffff8211156124f057600080fd5b5060209081020190565b600067ffffffffffffffff82111561251157600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b73ffffffffffffffffffffffffffffffffffffffff1690565b90565b828183375060009101525600a265627a7a72305820d9f418f11e0f91f06f6f9d22924be0add925495eeb76a6388b5417adb505eeb36c6578706572696d656e74616cf5003700000000000000000000000048bacb9266a570d521063ef5dd96e61686dbe788000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082000000000000000000000000000000000000000000000000000000001ba0a7c6b0c9a5cb47eb4a8449556851a943353640d4fe93a64eb89eff56245c27f1a00e0d13877bfb8842dc394fd206d041b1f76be95a371eff128c8c34812a1b24c8", + "result": [ + { + "action": { + "from": "0x5409ed021d9299bf6814279a6a1411a7e866a631", + "gas": "0x215c47", + "init": "0x60806040523480156200001157600080fd5b5060405162002d2c38038062002d2c83398101806040526200003791908101906200051d565b6000805433600160a060020a031991821617825560018054909116600160a060020a0386161790558251849084908490849081906200007e906004906020870190620003d0565b50825162000094906005906020860190620003d0565b50620000b0836010640100000000620019476200036f82021704565b9150620000cd846010640100000000620019476200036f82021704565b60028054600160a060020a03948516600160a060020a031991821617909155600380549285169290911691909117905550600154604080517f4552433230546f6b656e28616464726573732900000000000000000000000000815290519081900360130181207f6070410800000000000000000000000000000000000000000000000000000000825291909216945063607041089350620001739250906004016200068e565b602060405180830381600087803b1580156200018e57600080fd5b505af1158015620001a3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620001c99190810190620004f4565b9050600160a060020a038116151562000219576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200021090620006b0565b60405180910390fd5b6002546040517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a039091169063095ea7b39062000268908490600019906004016200066f565b602060405180830381600087803b1580156200028357600080fd5b505af115801562000298573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002be9190810190620005a1565b506003546040517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a039091169063095ea7b3906200030e908490600019906004016200066f565b602060405180830381600087803b1580156200032957600080fd5b505af11580156200033e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620003649190810190620005a1565b50505050506200077a565b600081601401835110151515620003b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000210906200069e565b506014818301810151910190600160a060020a03165b92915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200041357805160ff191683800117855562000443565b8280016001018555821562000443579182015b828111156200044357825182559160200191906001019062000426565b506200045192915062000455565b5090565b6200047291905b808211156200045157600081556001016200045c565b90565b600062000483825162000711565b9392505050565b600062000483825162000742565b6000601f82018313620004aa57600080fd5b8151620004c1620004bb82620006e9565b620006c2565b91508082526020830160208301858383011115620004de57600080fd5b620004eb83828462000747565b50505092915050565b6000602082840312156200050757600080fd5b600062000515848462000475565b949350505050565b6000806000606084860312156200053357600080fd5b600062000541868662000475565b93505060208401516001604060020a038111156200055e57600080fd5b6200056c8682870162000498565b92505060408401516001604060020a038111156200058957600080fd5b620005978682870162000498565b9150509250925092565b600060208284031215620005b457600080fd5b60006200051584846200048a565b620005cd8162000711565b82525050565b620005cd816200071d565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601881527f554e524547495354455245445f41535345545f50524f58590000000000000000602082015260400190565b620005cd8162000472565b604081016200067f8285620005c2565b62000483602083018462000664565b60208101620003ca8284620005d3565b60208082528101620003ca81620005de565b60208082528101620003ca8162000634565b6040518181016001604060020a0381118282101715620006e157600080fd5b604052919050565b60006001604060020a038211156200070057600080fd5b506020601f91909101601f19160190565b600160a060020a031690565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b151590565b60005b83811015620007645781810151838201526020016200074a565b8381111562000774576000848401525b50505050565b6125a2806200078a6000396000f30060806040526004361061006c5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166318978e8281146100c8578063630f1e6c146100f25780638da5cb5b146101125780639395525c14610134578063f2fde38b14610147575b60025473ffffffffffffffffffffffffffffffffffffffff1633146100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612388565b60405180910390fd5b005b6100db6100d6366004611df1565b610167565b6040516100e9929190612488565b60405180910390f35b3480156100fe57600080fd5b506100c661010d366004611eec565b6102f7565b34801561011e57600080fd5b50610127610388565b6040516100e99190612337565b6100db610142366004611d0b565b6103a4565b34801561015357600080fd5b506100c6610162366004611ce5565b61050a565b61016f6119fa565b6101776119fa565b6000806101826105bb565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100600188161502019095169490940493840181900481028201810190925282815261025c939092909183018282801561022d5780601f106102025761010080835404028352916020019161022d565b820191906000526020600020905b81548152906001019060200180831161021057829003601f168201915b50505050508c600081518110151561024157fe5b6020908102909101015161014001519063ffffffff61069616565b156102875761026c8b8b8b6107c3565b935061028084600001518560600151610ac1565b90506102ae565b6102928b8b8b610b03565b9350836060015191506102a68883896107c3565b845190935090505b6102c2846020015184602001518888610d15565b6102e98b60008151811015156102d457fe5b90602001906020020151610140015182610f29565b505097509795505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610348576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612438565b61038383838080601f01602080910402602001604051908101604052809392919081815260200183838082843750879450610f299350505050565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b6103ac6119fa565b6103b46119fa565b60008060006103c16105bb565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152610441939092909183018282801561022d5780601f106102025761010080835404028352916020019161022d565b156104925761046a670de0b6b3a7640000610464670de0b6b3a76400008a611045565b3461108f565b92506104778b848c6110e7565b945061048b85600001518660600151610ac1565b90506104d6565b6104ad670d2f13f7789f0000670de0b6b3a76400003461108f565b92506104ba8b848c6110e7565b9450846060015191506104ce89838a6107c3565b855190945090505b6104ea856020015185602001518989610d15565b6104fc8b60008151811015156102d457fe5b505050965096945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461055b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612438565b73ffffffffffffffffffffffffffffffffffffffff8116156105b857600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b600034116105f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612398565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004016000604051808303818588803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b5050505050565b6000815183511480156107ba5750816040518082805190602001908083835b602083106106f257805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016106b5565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0180199092169116179052604051919093018190038120885190955088945090928392508401908083835b6020831061078757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161074a565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916145b90505b92915050565b6107cb6119fa565b60608060008060008060006107de6119fa565b8a15156107ea57610ab2565b6004805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561088e5780601f106108635761010080835404028352916020019161088e565b820191906000526020600020905b81548152906001019060200180831161087157829003601f168201915b505060058054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152969e509194509250840190508282801561093d5780601f106109125761010080835404028352916020019161093d565b820191906000526020600020905b81548152906001019060200180831161092057829003601f168201915b50505050509650600095508b519450600093505b838514610a7857878c8581518110151561096757fe5b6020908102909101015161014001528b5187908d908690811061098657fe5b60209081029091010151610160015261099f8b87610ac1565b9250610a068c858151811015156109b257fe5b9060200190602002015160a00151610a008e878151811015156109d157fe5b90602001906020020151608001518f888151811015156109ed57fe5b9060200190602002015160e00151610ac1565b8561128b565b9150610a418c85815181101515610a1957fe5b90602001906020020151838c87815181101515610a3257fe5b906020019060200201516112e6565b9050610a4d898261135e565b610a5f89600001518a60600151610ac1565b95508a8610610a6d57610a78565b600190930192610951565b8a861015610ab2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612418565b50505050505050509392505050565b600082821115610afd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123b8565b50900390565b610b0b6119fa565b606080600080600080610b1c6119fa565b60008b6000815181101515610b2d57fe5b6020908102919091018101516101400151600580546040805160026001841615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190931692909204601f8101869004860283018601909152808252929b5092909190830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505096508b519550600094505b848614610cdb57878c86815181101515610c0b57fe5b6020908102909101015161014001528b5187908d9087908110610c2a57fe5b6020908102909101015161016001528851610c46908c90610ac1565b9350610c898c86815181101515610c5957fe5b9060200190602002015160a001518d87815181101515610c7557fe5b90602001906020020151608001518661128b565b9250610cb58c86815181101515610c9c57fe5b90602001906020020151848c88815181101515610a3257fe5b9150610cc1898361135e565b5087518a8110610cd057610cdb565b600190940193610bf5565b8a811015610ab2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612418565b600080808066b1a2bc2ec50000861115610d5b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612448565b610d658888611045565b935034841115610da1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123a8565b610dab3485610ac1565b9250610dc086670de0b6b3a76400008a61108f565b915082821115610dfc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612428565b6000831115610f1f576002546040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d90610e5b9086906004016124a4565b600060405180830381600087803b158015610e7557600080fd5b505af1158015610e89573d6000803e3d6000fd5b505050506000821115610edb5760405173ffffffffffffffffffffffffffffffffffffffff86169083156108fc029084906000818181858888f19350505050158015610ed9573d6000803e3d6000fd5b505b610ee58383610ac1565b90506000811115610f1f57604051339082156108fc029083906000818181858888f19350505050158015610f1d573d6000803e3d6000fd5b505b5050505050505050565b6000610f3b838263ffffffff6113c016565b604080517f4552433230546f6b656e28616464726573732900000000000000000000000000815290519081900360130190209091507fffffffff0000000000000000000000000000000000000000000000000000000080831691161415610fab57610fa6838361142d565b610383565b604080517f455243373231546f6b656e28616464726573732c75696e7432353629000000008152905190819003601c0190207fffffffff000000000000000000000000000000000000000000000000000000008281169116141561101357610fa6838361161b565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123f8565b600082820183811015611084576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123e8565b8091505b5092915050565b60008083116110ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123d8565b6110dd6110d78584611703565b8461175e565b90505b9392505050565b6110ef6119fa565b60608060008060006110ff6119fa565b89600081518110151561110e57fe5b6020908102919091018101516101400151600580546040805160026001841615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190931692909204601f8101869004860283018601909152808252929950929091908301828280156111c65780601f1061119b576101008083540402835291602001916111c6565b820191906000526020600020905b8154815290600101906020018083116111a957829003601f168201915b5050505050945089519350600092505b82841461127e57858a848151811015156111ec57fe5b602090810290910101516101400152895185908b908590811061120b57fe5b90602001906020020151610160018190525061122b898860200151610ac1565b91506112578a8481518110151561123e57fe5b90602001906020020151838a86815181101515610a3257fe5b9050611263878261135e565b602087015189116112735761127e565b6001909201916111d6565b5050505050509392505050565b60008083116112c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123d8565b6110dd6110d76112d68685611703565b6112e1866001610ac1565b611045565b6112ee6119fa565b606060006112fd868686611775565b600154815191935073ffffffffffffffffffffffffffffffffffffffff1691506080908390602082016000855af1801561135457825184526020830151602085015260408301516040850152606083015160608501525b5050509392505050565b8151815161136c9190611045565b8252602080830151908201516113829190611045565b60208301526040808301519082015161139b9190611045565b6040830152606080830151908201516113b49190611045565b60609092019190915250565b600081600401835110151515611402576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612468565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b60008061144184601063ffffffff61194716565b604080517f7472616e7366657228616464726573732c75696e7432353629000000000000008152905190819003601901812091935073ffffffffffffffffffffffffffffffffffffffff8416919061149f903390879060240161236d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931783525181519192909182919080838360005b8381101561154357818101518382015260200161152b565b50505050905090810190601f1680156115705780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1925050508015156115bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612408565b3d156115dc575060003d602014156115dc5760206000803e506000515b801515611615576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612408565b50505050565b60008060018314611658576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612478565b61166984601063ffffffff61194716565b915061167c84602463ffffffff6119a816565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8316906323b872dd906116d590309033908690600401612345565b600060405180830381600087803b1580156116ef57600080fd5b505af1158015610f1f573d6000803e3d6000fd5b6000808315156117165760009150611088565b5082820282848281151561172657fe5b0414611084576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123e8565b600080828481151561176c57fe5b04949350505050565b604080517fb4be83d5000000000000000000000000000000000000000000000000000000006020808301919091526060602483018181528751608485019081528884015160a48601529488015160c48501529087015160e4840152608087015161010484015260a087015161012484015260c087015161014484015260e08701516101648401526101008701516101848401526101208701516101a4840152610140870180516101c485019081526101608901516101e4860152610180905251805161020485018190529394919384936044870192849261022489019291820191601f82010460005b8181101561187c57835185526020948501949093019260010161185e565b50505050818103610160808401919091528a0151805180835260209283019291820191601f82010460005b818110156118c55783518552602094850194909301926001016118a7565b50505089845250848103602093840190815288518083529093918201918981019190601f82010460005b8181101561190d5783518552602094850194909301926001016118ef565b5050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08883030188525060405250505050509392505050565b600081601401835110151515611989576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612458565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b60006107ba83836000816020018351101515156119f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123c8565b50016020015190565b608060405190810160405280600081526020016000815260200160008152602001600081525090565b60006107ba8235612540565b6000601f82018313611a4057600080fd5b8135611a53611a4e826124d9565b6124b2565b81815260209384019390925082018360005b83811015611a915781358601611a7b8882611b41565b8452506020928301929190910190600101611a65565b5050505092915050565b6000601f82018313611aac57600080fd5b8135611aba611a4e826124d9565b81815260209384019390925082018360005b83811015611a915781358601611ae28882611b90565b8452506020928301929190910190600101611acc565b600080601f83018413611b0a57600080fd5b50813567ffffffffffffffff811115611b2257600080fd5b602083019150836001820283011115611b3a57600080fd5b9250929050565b6000601f82018313611b5257600080fd5b8135611b60611a4e826124fa565b91508082526020830160208301858383011115611b7c57600080fd5b611b8783828461255c565b50505092915050565b60006101808284031215611ba357600080fd5b611bae6101806124b2565b90506000611bbc8484611a23565b8252506020611bcd84848301611a23565b6020830152506040611be184828501611a23565b6040830152506060611bf584828501611a23565b6060830152506080611c0984828501611cd9565b60808301525060a0611c1d84828501611cd9565b60a08301525060c0611c3184828501611cd9565b60c08301525060e0611c4584828501611cd9565b60e083015250610100611c5a84828501611cd9565b61010083015250610120611c7084828501611cd9565b6101208301525061014082013567ffffffffffffffff811115611c9257600080fd5b611c9e84828501611b41565b6101408301525061016082013567ffffffffffffffff811115611cc057600080fd5b611ccc84828501611b41565b6101608301525092915050565b60006107ba8235612559565b600060208284031215611cf757600080fd5b6000611d038484611a23565b949350505050565b60008060008060008060c08789031215611d2457600080fd5b863567ffffffffffffffff811115611d3b57600080fd5b611d4789828a01611a9b565b965050602087013567ffffffffffffffff811115611d6457600080fd5b611d7089828a01611a2f565b955050604087013567ffffffffffffffff811115611d8d57600080fd5b611d9989828a01611a9b565b945050606087013567ffffffffffffffff811115611db657600080fd5b611dc289828a01611a2f565b9350506080611dd389828a01611cd9565b92505060a0611de489828a01611a23565b9150509295509295509295565b600080600080600080600060e0888a031215611e0c57600080fd5b873567ffffffffffffffff811115611e2357600080fd5b611e2f8a828b01611a9b565b9750506020611e408a828b01611cd9565b965050604088013567ffffffffffffffff811115611e5d57600080fd5b611e698a828b01611a2f565b955050606088013567ffffffffffffffff811115611e8657600080fd5b611e928a828b01611a9b565b945050608088013567ffffffffffffffff811115611eaf57600080fd5b611ebb8a828b01611a2f565b93505060a0611ecc8a828b01611cd9565b92505060c0611edd8a828b01611a23565b91505092959891949750929550565b600080600060408486031215611f0157600080fd5b833567ffffffffffffffff811115611f1857600080fd5b611f2486828701611af8565b93509350506020611f3786828701611cd9565b9150509250925092565b611f4a81612540565b82525050565b602381527f44454641554c545f46554e4354494f4e5f574554485f434f4e54524143545f4f60208201527f4e4c590000000000000000000000000000000000000000000000000000000000604082015260600190565b601181527f494e56414c49445f4d53475f56414c5545000000000000000000000000000000602082015260400190565b600d81527f4f564552534f4c445f5745544800000000000000000000000000000000000000602082015260400190565b601181527f55494e543235365f554e444552464c4f57000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601081527f4449564953494f4e5f42595f5a45524f00000000000000000000000000000000602082015260400190565b601081527f55494e543235365f4f564552464c4f5700000000000000000000000000000000602082015260400190565b601781527f554e535550504f525445445f41535345545f50524f5859000000000000000000602082015260400190565b600f81527f5452414e534645525f4641494c45440000000000000000000000000000000000602082015260400190565b601481527f434f4d504c4554455f46494c4c5f4641494c4544000000000000000000000000602082015260400190565b601a81527f494e53554646494349454e545f4554485f52454d41494e494e47000000000000602082015260400190565b601381527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000602082015260400190565b601881527f4645455f50455243454e544147455f544f4f5f4c415247450000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b602581527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160208201527f5549524544000000000000000000000000000000000000000000000000000000604082015260600190565b600e81527f494e56414c49445f414d4f554e54000000000000000000000000000000000000602082015260400190565b805160808301906122f9848261232e565b50602082015161230c602085018261232e565b50604082015161231f604085018261232e565b50606082015161161560608501825b611f4a81612559565b602081016107bd8284611f41565b606081016123538286611f41565b6123606020830185611f41565b611d03604083018461232e565b6040810161237b8285611f41565b6110e0602083018461232e565b602080825281016107bd81611f50565b602080825281016107bd81611fa6565b602080825281016107bd81611fd6565b602080825281016107bd81612006565b602080825281016107bd81612036565b602080825281016107bd8161208c565b602080825281016107bd816120bc565b602080825281016107bd816120ec565b602080825281016107bd8161211c565b602080825281016107bd8161214c565b602080825281016107bd8161217c565b602080825281016107bd816121ac565b602080825281016107bd816121dc565b602080825281016107bd8161220c565b602080825281016107bd81612262565b602080825281016107bd816122b8565b610100810161249782856122e8565b6110e060808301846122e8565b602081016107bd828461232e565b60405181810167ffffffffffffffff811182821017156124d157600080fd5b604052919050565b600067ffffffffffffffff8211156124f057600080fd5b5060209081020190565b600067ffffffffffffffff82111561251157600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b73ffffffffffffffffffffffffffffffffffffffff1690565b90565b828183375060009101525600a265627a7a72305820d9f418f11e0f91f06f6f9d22924be0add925495eeb76a6388b5417adb505eeb36c6578706572696d656e74616cf5003700000000000000000000000048bacb9266a570d521063ef5dd96e61686dbe788000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e808200000000000000000000000000000000000000000000000000000000", + "value": "0x0" + }, + "blockHash": "0x6456fbd35a3a69a1709c324fad114d68507d2c8ab391e9adb128f9734c8e4ae8", + "blockNumber": 13536, + "result": { + "address": "0x6000eca38b8b5bba64986182fe2a69c57f6b5414", + "code": "0x60806040526004361061006c5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166318978e8281146100c8578063630f1e6c146100f25780638da5cb5b146101125780639395525c14610134578063f2fde38b14610147575b60025473ffffffffffffffffffffffffffffffffffffffff1633146100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612388565b60405180910390fd5b005b6100db6100d6366004611df1565b610167565b6040516100e9929190612488565b60405180910390f35b3480156100fe57600080fd5b506100c661010d366004611eec565b6102f7565b34801561011e57600080fd5b50610127610388565b6040516100e99190612337565b6100db610142366004611d0b565b6103a4565b34801561015357600080fd5b506100c6610162366004611ce5565b61050a565b61016f6119fa565b6101776119fa565b6000806101826105bb565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100600188161502019095169490940493840181900481028201810190925282815261025c939092909183018282801561022d5780601f106102025761010080835404028352916020019161022d565b820191906000526020600020905b81548152906001019060200180831161021057829003601f168201915b50505050508c600081518110151561024157fe5b6020908102909101015161014001519063ffffffff61069616565b156102875761026c8b8b8b6107c3565b935061028084600001518560600151610ac1565b90506102ae565b6102928b8b8b610b03565b9350836060015191506102a68883896107c3565b845190935090505b6102c2846020015184602001518888610d15565b6102e98b60008151811015156102d457fe5b90602001906020020151610140015182610f29565b505097509795505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610348576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612438565b61038383838080601f01602080910402602001604051908101604052809392919081815260200183838082843750879450610f299350505050565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b6103ac6119fa565b6103b46119fa565b60008060006103c16105bb565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152610441939092909183018282801561022d5780601f106102025761010080835404028352916020019161022d565b156104925761046a670de0b6b3a7640000610464670de0b6b3a76400008a611045565b3461108f565b92506104778b848c6110e7565b945061048b85600001518660600151610ac1565b90506104d6565b6104ad670d2f13f7789f0000670de0b6b3a76400003461108f565b92506104ba8b848c6110e7565b9450846060015191506104ce89838a6107c3565b855190945090505b6104ea856020015185602001518989610d15565b6104fc8b60008151811015156102d457fe5b505050965096945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461055b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612438565b73ffffffffffffffffffffffffffffffffffffffff8116156105b857600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b600034116105f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612398565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004016000604051808303818588803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b5050505050565b6000815183511480156107ba5750816040518082805190602001908083835b602083106106f257805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016106b5565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0180199092169116179052604051919093018190038120885190955088945090928392508401908083835b6020831061078757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161074a565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916145b90505b92915050565b6107cb6119fa565b60608060008060008060006107de6119fa565b8a15156107ea57610ab2565b6004805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561088e5780601f106108635761010080835404028352916020019161088e565b820191906000526020600020905b81548152906001019060200180831161087157829003601f168201915b505060058054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152969e509194509250840190508282801561093d5780601f106109125761010080835404028352916020019161093d565b820191906000526020600020905b81548152906001019060200180831161092057829003601f168201915b50505050509650600095508b519450600093505b838514610a7857878c8581518110151561096757fe5b6020908102909101015161014001528b5187908d908690811061098657fe5b60209081029091010151610160015261099f8b87610ac1565b9250610a068c858151811015156109b257fe5b9060200190602002015160a00151610a008e878151811015156109d157fe5b90602001906020020151608001518f888151811015156109ed57fe5b9060200190602002015160e00151610ac1565b8561128b565b9150610a418c85815181101515610a1957fe5b90602001906020020151838c87815181101515610a3257fe5b906020019060200201516112e6565b9050610a4d898261135e565b610a5f89600001518a60600151610ac1565b95508a8610610a6d57610a78565b600190930192610951565b8a861015610ab2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612418565b50505050505050509392505050565b600082821115610afd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123b8565b50900390565b610b0b6119fa565b606080600080600080610b1c6119fa565b60008b6000815181101515610b2d57fe5b6020908102919091018101516101400151600580546040805160026001841615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190931692909204601f8101869004860283018601909152808252929b5092909190830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505096508b519550600094505b848614610cdb57878c86815181101515610c0b57fe5b6020908102909101015161014001528b5187908d9087908110610c2a57fe5b6020908102909101015161016001528851610c46908c90610ac1565b9350610c898c86815181101515610c5957fe5b9060200190602002015160a001518d87815181101515610c7557fe5b90602001906020020151608001518661128b565b9250610cb58c86815181101515610c9c57fe5b90602001906020020151848c88815181101515610a3257fe5b9150610cc1898361135e565b5087518a8110610cd057610cdb565b600190940193610bf5565b8a811015610ab2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612418565b600080808066b1a2bc2ec50000861115610d5b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612448565b610d658888611045565b935034841115610da1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123a8565b610dab3485610ac1565b9250610dc086670de0b6b3a76400008a61108f565b915082821115610dfc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612428565b6000831115610f1f576002546040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d90610e5b9086906004016124a4565b600060405180830381600087803b158015610e7557600080fd5b505af1158015610e89573d6000803e3d6000fd5b505050506000821115610edb5760405173ffffffffffffffffffffffffffffffffffffffff86169083156108fc029084906000818181858888f19350505050158015610ed9573d6000803e3d6000fd5b505b610ee58383610ac1565b90506000811115610f1f57604051339082156108fc029083906000818181858888f19350505050158015610f1d573d6000803e3d6000fd5b505b5050505050505050565b6000610f3b838263ffffffff6113c016565b604080517f4552433230546f6b656e28616464726573732900000000000000000000000000815290519081900360130190209091507fffffffff0000000000000000000000000000000000000000000000000000000080831691161415610fab57610fa6838361142d565b610383565b604080517f455243373231546f6b656e28616464726573732c75696e7432353629000000008152905190819003601c0190207fffffffff000000000000000000000000000000000000000000000000000000008281169116141561101357610fa6838361161b565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123f8565b600082820183811015611084576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123e8565b8091505b5092915050565b60008083116110ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123d8565b6110dd6110d78584611703565b8461175e565b90505b9392505050565b6110ef6119fa565b60608060008060006110ff6119fa565b89600081518110151561110e57fe5b6020908102919091018101516101400151600580546040805160026001841615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190931692909204601f8101869004860283018601909152808252929950929091908301828280156111c65780601f1061119b576101008083540402835291602001916111c6565b820191906000526020600020905b8154815290600101906020018083116111a957829003601f168201915b5050505050945089519350600092505b82841461127e57858a848151811015156111ec57fe5b602090810290910101516101400152895185908b908590811061120b57fe5b90602001906020020151610160018190525061122b898860200151610ac1565b91506112578a8481518110151561123e57fe5b90602001906020020151838a86815181101515610a3257fe5b9050611263878261135e565b602087015189116112735761127e565b6001909201916111d6565b5050505050509392505050565b60008083116112c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123d8565b6110dd6110d76112d68685611703565b6112e1866001610ac1565b611045565b6112ee6119fa565b606060006112fd868686611775565b600154815191935073ffffffffffffffffffffffffffffffffffffffff1691506080908390602082016000855af1801561135457825184526020830151602085015260408301516040850152606083015160608501525b5050509392505050565b8151815161136c9190611045565b8252602080830151908201516113829190611045565b60208301526040808301519082015161139b9190611045565b6040830152606080830151908201516113b49190611045565b60609092019190915250565b600081600401835110151515611402576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612468565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b60008061144184601063ffffffff61194716565b604080517f7472616e7366657228616464726573732c75696e7432353629000000000000008152905190819003601901812091935073ffffffffffffffffffffffffffffffffffffffff8416919061149f903390879060240161236d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931783525181519192909182919080838360005b8381101561154357818101518382015260200161152b565b50505050905090810190601f1680156115705780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1925050508015156115bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612408565b3d156115dc575060003d602014156115dc5760206000803e506000515b801515611615576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612408565b50505050565b60008060018314611658576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612478565b61166984601063ffffffff61194716565b915061167c84602463ffffffff6119a816565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8316906323b872dd906116d590309033908690600401612345565b600060405180830381600087803b1580156116ef57600080fd5b505af1158015610f1f573d6000803e3d6000fd5b6000808315156117165760009150611088565b5082820282848281151561172657fe5b0414611084576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123e8565b600080828481151561176c57fe5b04949350505050565b604080517fb4be83d5000000000000000000000000000000000000000000000000000000006020808301919091526060602483018181528751608485019081528884015160a48601529488015160c48501529087015160e4840152608087015161010484015260a087015161012484015260c087015161014484015260e08701516101648401526101008701516101848401526101208701516101a4840152610140870180516101c485019081526101608901516101e4860152610180905251805161020485018190529394919384936044870192849261022489019291820191601f82010460005b8181101561187c57835185526020948501949093019260010161185e565b50505050818103610160808401919091528a0151805180835260209283019291820191601f82010460005b818110156118c55783518552602094850194909301926001016118a7565b50505089845250848103602093840190815288518083529093918201918981019190601f82010460005b8181101561190d5783518552602094850194909301926001016118ef565b5050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08883030188525060405250505050509392505050565b600081601401835110151515611989576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612458565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b60006107ba83836000816020018351101515156119f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123c8565b50016020015190565b608060405190810160405280600081526020016000815260200160008152602001600081525090565b60006107ba8235612540565b6000601f82018313611a4057600080fd5b8135611a53611a4e826124d9565b6124b2565b81815260209384019390925082018360005b83811015611a915781358601611a7b8882611b41565b8452506020928301929190910190600101611a65565b5050505092915050565b6000601f82018313611aac57600080fd5b8135611aba611a4e826124d9565b81815260209384019390925082018360005b83811015611a915781358601611ae28882611b90565b8452506020928301929190910190600101611acc565b600080601f83018413611b0a57600080fd5b50813567ffffffffffffffff811115611b2257600080fd5b602083019150836001820283011115611b3a57600080fd5b9250929050565b6000601f82018313611b5257600080fd5b8135611b60611a4e826124fa565b91508082526020830160208301858383011115611b7c57600080fd5b611b8783828461255c565b50505092915050565b60006101808284031215611ba357600080fd5b611bae6101806124b2565b90506000611bbc8484611a23565b8252506020611bcd84848301611a23565b6020830152506040611be184828501611a23565b6040830152506060611bf584828501611a23565b6060830152506080611c0984828501611cd9565b60808301525060a0611c1d84828501611cd9565b60a08301525060c0611c3184828501611cd9565b60c08301525060e0611c4584828501611cd9565b60e083015250610100611c5a84828501611cd9565b61010083015250610120611c7084828501611cd9565b6101208301525061014082013567ffffffffffffffff811115611c9257600080fd5b611c9e84828501611b41565b6101408301525061016082013567ffffffffffffffff811115611cc057600080fd5b611ccc84828501611b41565b6101608301525092915050565b60006107ba8235612559565b600060208284031215611cf757600080fd5b6000611d038484611a23565b949350505050565b60008060008060008060c08789031215611d2457600080fd5b863567ffffffffffffffff811115611d3b57600080fd5b611d4789828a01611a9b565b965050602087013567ffffffffffffffff811115611d6457600080fd5b611d7089828a01611a2f565b955050604087013567ffffffffffffffff811115611d8d57600080fd5b611d9989828a01611a9b565b945050606087013567ffffffffffffffff811115611db657600080fd5b611dc289828a01611a2f565b9350506080611dd389828a01611cd9565b92505060a0611de489828a01611a23565b9150509295509295509295565b600080600080600080600060e0888a031215611e0c57600080fd5b873567ffffffffffffffff811115611e2357600080fd5b611e2f8a828b01611a9b565b9750506020611e408a828b01611cd9565b965050604088013567ffffffffffffffff811115611e5d57600080fd5b611e698a828b01611a2f565b955050606088013567ffffffffffffffff811115611e8657600080fd5b611e928a828b01611a9b565b945050608088013567ffffffffffffffff811115611eaf57600080fd5b611ebb8a828b01611a2f565b93505060a0611ecc8a828b01611cd9565b92505060c0611edd8a828b01611a23565b91505092959891949750929550565b600080600060408486031215611f0157600080fd5b833567ffffffffffffffff811115611f1857600080fd5b611f2486828701611af8565b93509350506020611f3786828701611cd9565b9150509250925092565b611f4a81612540565b82525050565b602381527f44454641554c545f46554e4354494f4e5f574554485f434f4e54524143545f4f60208201527f4e4c590000000000000000000000000000000000000000000000000000000000604082015260600190565b601181527f494e56414c49445f4d53475f56414c5545000000000000000000000000000000602082015260400190565b600d81527f4f564552534f4c445f5745544800000000000000000000000000000000000000602082015260400190565b601181527f55494e543235365f554e444552464c4f57000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601081527f4449564953494f4e5f42595f5a45524f00000000000000000000000000000000602082015260400190565b601081527f55494e543235365f4f564552464c4f5700000000000000000000000000000000602082015260400190565b601781527f554e535550504f525445445f41535345545f50524f5859000000000000000000602082015260400190565b600f81527f5452414e534645525f4641494c45440000000000000000000000000000000000602082015260400190565b601481527f434f4d504c4554455f46494c4c5f4641494c4544000000000000000000000000602082015260400190565b601a81527f494e53554646494349454e545f4554485f52454d41494e494e47000000000000602082015260400190565b601381527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000602082015260400190565b601881527f4645455f50455243454e544147455f544f4f5f4c415247450000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b602581527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160208201527f5549524544000000000000000000000000000000000000000000000000000000604082015260600190565b600e81527f494e56414c49445f414d4f554e54000000000000000000000000000000000000602082015260400190565b805160808301906122f9848261232e565b50602082015161230c602085018261232e565b50604082015161231f604085018261232e565b50606082015161161560608501825b611f4a81612559565b602081016107bd8284611f41565b606081016123538286611f41565b6123606020830185611f41565b611d03604083018461232e565b6040810161237b8285611f41565b6110e0602083018461232e565b602080825281016107bd81611f50565b602080825281016107bd81611fa6565b602080825281016107bd81611fd6565b602080825281016107bd81612006565b602080825281016107bd81612036565b602080825281016107bd8161208c565b602080825281016107bd816120bc565b602080825281016107bd816120ec565b602080825281016107bd8161211c565b602080825281016107bd8161214c565b602080825281016107bd8161217c565b602080825281016107bd816121ac565b602080825281016107bd816121dc565b602080825281016107bd8161220c565b602080825281016107bd81612262565b602080825281016107bd816122b8565b610100810161249782856122e8565b6110e060808301846122e8565b602081016107bd828461232e565b60405181810167ffffffffffffffff811182821017156124d157600080fd5b604052919050565b600067ffffffffffffffff8211156124f057600080fd5b5060209081020190565b600067ffffffffffffffff82111561251157600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b73ffffffffffffffffffffffffffffffffffffffff1690565b90565b828183375060009101525600a265627a7a72305820d9f418f11e0f91f06f6f9d22924be0add925495eeb76a6388b5417adb505eeb36c6578706572696d656e74616cf50037", + "gasUsed": "0x2c8c7f" + }, + "subtraces": 3, + "traceAddress": [], + "transactionHash": "0x6974f745a004f030bebb1c01d4595edbda2fafcf01c0bfbd5d335711e2a7b04e", + "transactionPosition": 0, + "type": "create" + }, + { + "action": { + "callType": "call", + "from": "0x6000eca38b8b5bba64986182fe2a69c57f6b5414", + "gas": "0x1dba84", + "input": "0x60704108f47261b000000000000000000000000000000000000000000000000000000000", + "to": "0x48bacb9266a570d521063ef5dd96e61686dbe788", + "value": "0x0" + }, + "blockHash": "0x6456fbd35a3a69a1709c324fad114d68507d2c8ab391e9adb128f9734c8e4ae8", + "blockNumber": 13536, + "result": { + "gasUsed": "0x3d9", + "output": "0x0000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48" + }, + "subtraces": 0, + "traceAddress": [ + 0 + ], + "transactionHash": "0x6974f745a004f030bebb1c01d4595edbda2fafcf01c0bfbd5d335711e2a7b04e", + "transactionPosition": 0, + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x6000eca38b8b5bba64986182fe2a69c57f6b5414", + "gas": "0x1dad2e", + "input": "0x095ea7b30000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "to": "0x0b1ba0af832d7c05fd64161e0db78e85978e8082", + "value": "0x0" + }, + "blockHash": "0x6456fbd35a3a69a1709c324fad114d68507d2c8ab391e9adb128f9734c8e4ae8", + "blockNumber": 13536, + "result": { + "gasUsed": "0x56c8", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 0, + "traceAddress": [ + 1 + ], + "transactionHash": "0x6974f745a004f030bebb1c01d4595edbda2fafcf01c0bfbd5d335711e2a7b04e", + "transactionPosition": 0, + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x6000eca38b8b5bba64986182fe2a69c57f6b5414", + "gas": "0x1d4ee1", + "input": "0x095ea7b30000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "to": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c", + "value": "0x0" + }, + "blockHash": "0x6456fbd35a3a69a1709c324fad114d68507d2c8ab391e9adb128f9734c8e4ae8", + "blockNumber": 13536, + "result": { + "gasUsed": "0x56ca", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 0, + "traceAddress": [ + 2 + ], + "transactionHash": "0x6974f745a004f030bebb1c01d4595edbda2fafcf01c0bfbd5d335711e2a7b04e", + "transactionPosition": 0, + "type": "call" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json new file mode 100644 index 000000000000..26ae2f0604b5 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json @@ -0,0 +1,68 @@ +{ + "context": { + "difficulty": "3699098917", + "gasLimit": "5258985", + "miner": "0xd049bfd667cb46aa3ef5df0da3e57db3be39e511", + "number": "2294631", + "timestamp": "1513675366" + }, + "genesis": { + "alloc": { + "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62": { + "balance": "0x0", + "code": "0x6060604052600436106100ba576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100bf578063095ea7b31461014d57806318160ddd146101a757806323b872dd146101d0578063313ce5671461024957806342966c68146102785780635a3b7e42146102b357806370a082311461034157806379cc67901461038e57806395d89b41146103e8578063a9059cbb14610476578063dd62ed3e146104b8575b600080fd5b34156100ca57600080fd5b6100d2610524565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101125780820151818401526020810190506100f7565b50505050905090810190601f16801561013f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015857600080fd5b61018d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061055d565b604051808215151515815260200191505060405180910390f35b34156101b257600080fd5b6101ba6105ea565b6040518082815260200191505060405180910390f35b34156101db57600080fd5b61022f600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506105f0565b604051808215151515815260200191505060405180910390f35b341561025457600080fd5b61025c610910565b604051808260ff1660ff16815260200191505060405180910390f35b341561028357600080fd5b6102996004808035906020019091905050610915565b604051808215151515815260200191505060405180910390f35b34156102be57600080fd5b6102c6610a18565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103065780820151818401526020810190506102eb565b50505050905090810190601f1680156103335780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561034c57600080fd5b610378600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a51565b6040518082815260200191505060405180910390f35b341561039957600080fd5b6103ce600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a69565b604051808215151515815260200191505060405180910390f35b34156103f357600080fd5b6103fb610bf8565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561043b578082015181840152602081019050610420565b50505050905090810190601f1680156104685780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561048157600080fd5b6104b6600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610c31565b005b34156104c357600080fd5b61050e600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610e34565b6040518082815260200191505060405180910390f35b6040805190810160405280600881526020017f446f70616d696e6500000000000000000000000000000000000000000000000081525081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001905092915050565b60005481565b6000808373ffffffffffffffffffffffffffffffffffffffff161415151561061757600080fd5b81600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561066557600080fd5b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401101515156106f157fe5b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115151561077c57600080fd5b81600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b601281565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561096557600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040518082815260200191505060405180910390a260019050919050565b6040805190810160405280600981526020017f446f706d6e20302e32000000000000000000000000000000000000000000000081525081565b60016020528060005260406000206000915090505481565b600081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610ab957600080fd5b600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548211151515610b4457600080fd5b81600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508160008082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040518082815260200191505060405180910390a26001905092915050565b6040805190810160405280600581526020017f444f504d4e00000000000000000000000000000000000000000000000000000081525081565b60008273ffffffffffffffffffffffffffffffffffffffff1614151515610c5757600080fd5b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610ca557600080fd5b600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540110151515610d3157fe5b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555080600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b60026020528160005260406000206020528060005260406000206000915091505054815600a165627a7a723058206d93424f4e7b11929b8276a269038402c10c0ddf21800e999916ddd9dff4a7630029", + "nonce": "1", + "storage": { + "0x296b66049cc4f9c8bf3d4f14752add261d1a980b39bdd194a7897baf39ac7579": "0x0000000000000000000000000000000000000000033b2e3c9fc9653f9e72b1e0" + } + }, + "0x94194bc2aaf494501d7880b61274a169f6502a54": { + "balance": "0xea8c39a876d19888d", + "code": "0x", + "nonce": "265", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3699098917", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "5263953", + "hash": "0x03a0f62a8106793dafcfae7b75fd2654322062d585a19cea568314d7205790dc", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0x15482cc64b7c00a947f5bf015dfc010db1a6a668c74df61974d6a7848c174408", + "nonce": "0xd1bdb150f6fd170e", + "number": "2294630", + "stateRoot": "0x1ab1a534e84cc787cda1db21e0d5920ab06017948075b759166cfea7274657a1", + "timestamp": "1513675347", + "totalDifficulty": "7160543502214733" + }, + "input": "0xf8ab820109855d21dba00082ca1d9443064693d3d38ad6a7cb579e0d6d9718c8aa6b6280b844a9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f90001ba0ce3ad83f5530136467b7c2bb225f406bd170f4ad59c254e5103c34eeabb5bd69a0455154527224a42ab405cacf0fe92918a75641ce4152f8db292019a5527aa956", + "result": [ + { + "action": { + "callType": "call", + "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", + "gas": "0x7045", + "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", + "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", + "value": "0x0" + }, + "blockNumber": 2294631, + "error": "out of gas", + "result": {}, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json new file mode 100644 index 000000000000..0216c318b55a --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json @@ -0,0 +1,71 @@ +{ + "context": { + "difficulty": "3699098917", + "gasLimit": "5258985", + "miner": "0xd049bfd667cb46aa3ef5df0da3e57db3be39e511", + "number": "2294631", + "timestamp": "1513675366" + }, + "genesis": { + "alloc": { + "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62": { + "balance": "0x0", + "code": "0x6060604052600436106100ba576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100bf578063095ea7b31461014d57806318160ddd146101a757806323b872dd146101d0578063313ce5671461024957806342966c68146102785780635a3b7e42146102b357806370a082311461034157806379cc67901461038e57806395d89b41146103e8578063a9059cbb14610476578063dd62ed3e146104b8575b600080fd5b34156100ca57600080fd5b6100d2610524565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101125780820151818401526020810190506100f7565b50505050905090810190601f16801561013f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015857600080fd5b61018d600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061055d565b604051808215151515815260200191505060405180910390f35b34156101b257600080fd5b6101ba6105ea565b6040518082815260200191505060405180910390f35b34156101db57600080fd5b61022f600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506105f0565b604051808215151515815260200191505060405180910390f35b341561025457600080fd5b61025c610910565b604051808260ff1660ff16815260200191505060405180910390f35b341561028357600080fd5b6102996004808035906020019091905050610915565b604051808215151515815260200191505060405180910390f35b34156102be57600080fd5b6102c6610a18565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103065780820151818401526020810190506102eb565b50505050905090810190601f1680156103335780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561034c57600080fd5b610378600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610a51565b6040518082815260200191505060405180910390f35b341561039957600080fd5b6103ce600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610a69565b604051808215151515815260200191505060405180910390f35b34156103f357600080fd5b6103fb610bf8565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561043b578082015181840152602081019050610420565b50505050905090810190601f1680156104685780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561048157600080fd5b6104b6600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610c31565b005b34156104c357600080fd5b61050e600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610e34565b6040518082815260200191505060405180910390f35b6040805190810160405280600881526020017f446f70616d696e6500000000000000000000000000000000000000000000000081525081565b600081600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001905092915050565b60005481565b6000808373ffffffffffffffffffffffffffffffffffffffff161415151561061757600080fd5b81600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561066557600080fd5b600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401101515156106f157fe5b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115151561077c57600080fd5b81600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b601281565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561096557600080fd5b81600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040518082815260200191505060405180910390a260019050919050565b6040805190810160405280600981526020017f446f706d6e20302e32000000000000000000000000000000000000000000000081525081565b60016020528060005260406000206000915090505481565b600081600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610ab957600080fd5b600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548211151515610b4457600080fd5b81600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508160008082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040518082815260200191505060405180910390a26001905092915050565b6040805190810160405280600581526020017f444f504d4e00000000000000000000000000000000000000000000000000000081525081565b60008273ffffffffffffffffffffffffffffffffffffffff1614151515610c5757600080fd5b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610ca557600080fd5b600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205481600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540110151515610d3157fe5b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555080600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b60026020528160005260406000206020528060005260406000206000915091505054815600a165627a7a723058206d93424f4e7b11929b8276a269038402c10c0ddf21800e999916ddd9dff4a7630029", + "nonce": "1", + "storage": { + "0x296b66049cc4f9c8bf3d4f14752add261d1a980b39bdd194a7897baf39ac7579": "0x0000000000000000000000000000000000000000033b2e3c9fc9653f9e72b1e0" + } + }, + "0x94194bc2aaf494501d7880b61274a169f6502a54": { + "balance": "0xea8c39a876d19888d", + "code": "0x", + "nonce": "265", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3699098917", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "5263953", + "hash": "0x03a0f62a8106793dafcfae7b75fd2654322062d585a19cea568314d7205790dc", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0x15482cc64b7c00a947f5bf015dfc010db1a6a668c74df61974d6a7848c174408", + "nonce": "0xd1bdb150f6fd170e", + "number": "2294630", + "stateRoot": "0x1ab1a534e84cc787cda1db21e0d5920ab06017948075b759166cfea7274657a1", + "timestamp": "1513675347", + "totalDifficulty": "7160543502214733" + }, + "tracerConfig": { + "convertParityErrors": true + }, + "input": "0xf8ab820109855d21dba00082ca1d9443064693d3d38ad6a7cb579e0d6d9718c8aa6b6280b844a9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f90001ba0ce3ad83f5530136467b7c2bb225f406bd170f4ad59c254e5103c34eeabb5bd69a0455154527224a42ab405cacf0fe92918a75641ce4152f8db292019a5527aa956", + "result": [ + { + "action": { + "callType": "call", + "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", + "gas": "0x7045", + "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", + "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", + "value": "0x0" + }, + "blockNumber": 2294631, + "error": "Out of gas", + "result": {}, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json new file mode 100644 index 000000000000..f58d20cd2b04 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json @@ -0,0 +1,111 @@ +{ + "genesis": { + "difficulty": "1911202", + "extraData": "0xd883010906846765746888676f312e31332e35856c696e7578", + "gasLimit": "7842876", + "hash": "0x4d7bc82e0d56307094378e1a8fbfa6260986f621de95b5fe68a95248b3ba8efe", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "mixHash": "0xc102ad52677c391edab82cc895ca7a7e9fff3eed4fa966ecf7fb61ec1e84bb6b", + "nonce": "0x39f5b074e3437f3f", + "number": "553415", + "stateRoot": "0x8f89e79109c19fa00e72b400502448540dc4773ad92dddd341dbba20c710a3b5", + "timestamp": "1577396195", + "totalDifficulty": "458361299240", + "alloc": { + "0x531f76bad925f6a925474996c7d738c1008045f6": { + "balance": "0x0", + "nonce": "1", + "code": "0x6060604052361561008a576000357c01000000000000000000000000000000000000000000000000000000009004806301cb3b20146102bf57806329dcb0cf146102cc57806338af3eed146102ed5780636e66f6e9146103245780637a3a0e841461035b5780637b3e5e7b1461037c578063a035b1fe1461039d578063dc0d3dff146103be5761008a565b6102bd5b60003490506040604051908101604052803381526020018281526020015060066000506006600050805480919060010190908154818355818115116101365760020281600202836000526020600020918201910161013591906100ec565b808211156101315760006000820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001820160005060009055506001016100ec565b5090565b5b505050815481101561000257906000526020600020906002020160005060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff0219169083021790555060208201518160010160005055905050806002600082828250540192505081905550600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166390b98a11336004600050548404604051837c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506020604051808303816000876161da5a03f1156100025750505060405151507fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf633826001604051808473ffffffffffffffffffffffffffffffffffffffff168152602001838152602001828152602001935050505060405180910390a15b50565b005b6102ca6004506104c8565b005b6102d760045061043a565b6040518082815260200191505060405180910390f35b6102f8600450610402565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61032f60045061044c565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610366600450610428565b6040518082815260200191505060405180910390f35b610387600450610431565b6040518082815260200191505060405180910390f35b6103a8600450610443565b6040518082815260200191505060405180910390f35b6103cf600480359060200150610472565b604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60016000505481565b60026000505481565b60036000505481565b60046000505481565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60066000508181548110156100025790600052602060002090600202016000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160005054905082565b6000600360005054421015156107d8576001600050546002600050541015156105cf57600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166000600260005054604051809050600060405180830381858888f19350505050507fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166002600050546000604051808473ffffffffffffffffffffffffffffffffffffffff168152602001838152602001828152602001935050505060405180910390a161079d565b7fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf66000600b600060405180848152602001838152602001828152602001935050505060405180910390a1600090505b60066000505481101561079c57600660005081815481101561000257906000526020600020906002020160005060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166000600660005083815481101561000257906000526020600020906002020160005060010160005054604051809050600060405180830381858888f19350505050507fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6600660005082815481101561000257906000526020600020906002020160005060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166006600050838154811015610002579060005260206000209060020201600050600101600050546000604051808473ffffffffffffffffffffffffffffffffffffffff168152602001838152602001828152602001935050505060405180910390a15b806001019050805061061e565b5b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b5056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x000000000000000000000000b49180d443dc4ca6028de0031ac09337891fd8ce", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" + } + }, + "0xb49180d443dc4ca6028de0031ac09337891fd8ce": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x193e9986e2e3f0c58988", + "nonce": "2585", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "553416", + "difficulty": "1909336", + "timestamp": "1577396224", + "gasLimit": "7835218", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf870820a1985e8d4a5100083040b2894531f76bad925f6a925474996c7d738c1008045f6880de0b6b3a76400008081a2a08693170f040d9501b831b404d9e40fba040c5aef4b8974aedc20b3844aea7c32a0476861058ff9b8030c58bcba8be320acc855e4694a633c493fb50fbdb9455489", + "result": [ + { + "type": "call", + "action": { + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "to": "0x531f76bad925f6a925474996c7d738c1008045f6", + "value": "0xde0b6b3a7640000", + "gas": "0x3b920", + "input": "0x", + "callType": "call" + }, + "result": { + "gasUsed": "0x19c3e", + "output": "0x" + }, + "traceAddress": [], + "subtraces": 1, + "transactionPosition": 5, + "transactionHash": "0x04d2029a5cbbed30969cdc0a2ca9e9fc6b719e323af0802b52466f07ee0ecada", + "blockNumber": 553416, + "blockHash": "0x8df024322173d225a09681d35edeaa528aca60743a11a70f854c158862bf5282", + "time": "617.42µs" + }, + { + "type": "call", + "action": { + "from": "0x531f76bad925f6a925474996c7d738c1008045f6", + "to": "0xb49180d443dc4ca6028de0031ac09337891fd8ce", + "value": "0x0", + "gas": "0x2164e", + "input": "0x90b98a11000000000000000000000000877bd459c9b7d8576b44e59e09d076c25946f4430000000000000000000000000000000000000000000000000000000000000001", + "callType": "call" + }, + "result": { + "gasUsed": "0x0", + "output": "0x" + }, + "traceAddress": [ + 0 + ], + "subtraces": 0, + "transactionPosition": 5, + "transactionHash": "0x04d2029a5cbbed30969cdc0a2ca9e9fc6b719e323af0802b52466f07ee0ecada", + "blockNumber": 553416, + "blockHash": "0x8df024322173d225a09681d35edeaa528aca60743a11a70f854c158862bf5282" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json new file mode 100644 index 000000000000..897aebb0e05b --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json @@ -0,0 +1,68 @@ +{ + "context": { + "difficulty": "3665057456", + "gasLimit": "5232723", + "miner": "0xf4d8e706cfb25c0decbbdd4d2e2cc10c66376a3f", + "number": "2294501", + "timestamp": "1513673601" + }, + "genesis": { + "alloc": { + "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9": { + "balance": "0x2a3fc32bcc019283", + "code": "0x", + "nonce": "10", + "storage": {} + }, + "0xabbcd5b340c80b5f1c0545c04c987b87310296ae": { + "balance": "0x0", + "code": "0x606060405236156100755763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416632d0335ab811461007a578063548db174146100ab5780637f649783146100fc578063b092145e1461014d578063c3f44c0a14610186578063c47cf5de14610203575b600080fd5b341561008557600080fd5b610099600160a060020a0360043516610270565b60405190815260200160405180910390f35b34156100b657600080fd5b6100fa600460248135818101908301358060208181020160405190810160405280939291908181526020018383602002808284375094965061028f95505050505050565b005b341561010757600080fd5b6100fa600460248135818101908301358060208181020160405190810160405280939291908181526020018383602002808284375094965061029e95505050505050565b005b341561015857600080fd5b610172600160a060020a03600435811690602435166102ad565b604051901515815260200160405180910390f35b341561019157600080fd5b6100fa6004803560ff1690602480359160443591606435600160a060020a0316919060a49060843590810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965050509235600160a060020a031692506102cd915050565b005b341561020e57600080fd5b61025460046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061056a95505050505050565b604051600160a060020a03909116815260200160405180910390f35b600160a060020a0381166000908152602081905260409020545b919050565b61029a816000610594565b5b50565b61029a816001610594565b5b50565b600160209081526000928352604080842090915290825290205460ff1681565b60008080600160a060020a038416158061030d5750600160a060020a038085166000908152600160209081526040808320339094168352929052205460ff165b151561031857600080fd5b6103218561056a565b600160a060020a038116600090815260208190526040808220549295507f19000000000000000000000000000000000000000000000000000000000000009230918891908b908b90517fff000000000000000000000000000000000000000000000000000000000000008089168252871660018201526c01000000000000000000000000600160a060020a038088168202600284015286811682026016840152602a8301869052841602604a820152605e810182805190602001908083835b6020831061040057805182525b601f1990920191602091820191016103e0565b6001836020036101000a0380198251168184511617909252505050919091019850604097505050505050505051809103902091506001828a8a8a6040516000815260200160405260006040516020015260405193845260ff90921660208085019190915260408085019290925260608401929092526080909201915160208103908084039060008661646e5a03f1151561049957600080fd5b5050602060405103519050600160a060020a03838116908216146104bc57600080fd5b600160a060020a0380841660009081526020819052604090819020805460010190559087169086905180828051906020019080838360005b8381101561050d5780820151818401525b6020016104f4565b50505050905090810190601f16801561053a5780820380516001836020036101000a031916815260200191505b5091505060006040518083038160008661646e5a03f1915050151561055e57600080fd5b5b505050505050505050565b600060248251101561057e5750600061028a565b600160a060020a0360248301511690505b919050565b60005b825181101561060157600160a060020a033316600090815260016020526040812083918584815181106105c657fe5b90602001906020020151600160a060020a031681526020810191909152604001600020805460ff19169115159190911790555b600101610597565b5b5050505600a165627a7a723058200027e8b695e9d2dea9f3629519022a69f3a1d23055ce86406e686ea54f31ee9c0029", + "nonce": "1", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3672229776", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "5227619", + "hash": "0xa07b3d6c6bf63f5f981016db9f2d1d93033833f2c17e8bf7209e85f1faf08076", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0x806e151ce2817be922e93e8d5921fa0f0d0fd213d6b2b9a3fa17458e74a163d0", + "nonce": "0xbc5d43adc2c30c7d", + "number": "2294500", + "stateRoot": "0xca645b335888352ef9d8b1ef083e9019648180b259026572e3139717270de97d", + "timestamp": "1513673552", + "totalDifficulty": "7160066586979149" + }, + "input": "0xf9018b0a8505d21dba00832dc6c094abbcd5b340c80b5f1c0545c04c987b87310296ae80b9012473b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988000000000000000000000000000000000000000000000000000000000000000000000000000000001ba0fd659d76a4edbd2a823e324c93f78ad6803b30ff4a9c8bce71ba82798975c70ca06571eecc0b765688ec6c78942c5ee8b585e00988c0141b518287e9be919bc48a", + "result": [ + { + "action": { + "callType": "call", + "from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9", + "gas": "0x2d55e8", + "input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000", + "to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae", + "value": "0x0" + }, + "blockNumber": 2294501, + "error": "execution reverted", + "result": { + "gasUsed": "0x719b" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json new file mode 100644 index 000000000000..62dbaf20dc94 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json @@ -0,0 +1,74 @@ +{ + "context": { + "difficulty": "2", + "gasLimit": "8000000", + "miner": "0x0000000000000000000000000000000000000000", + "number": "3212651", + "timestamp": "1597246515" + }, + "genesis": { + "alloc": { + "0xf58833cf0c791881b494eb79d461e08a1f043f52": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063609ff1bd11610078578063609ff1bd146101af5780639e7b8d61146101cd578063a3ec138d14610211578063e2ba53f0146102ae576100a5565b80630121b93f146100aa578063013cf08b146100d85780632e4176cf146101215780635c19a95c1461016b575b600080fd5b6100d6600480360360208110156100c057600080fd5b81019080803590602001909291905050506102cc565b005b610104600480360360208110156100ee57600080fd5b8101908080359060200190929190505050610469565b604051808381526020018281526020019250505060405180910390f35b61012961049a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101ad6004803603602081101561018157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506104bf565b005b6101b76108db565b6040518082815260200191505060405180910390f35b61020f600480360360208110156101e357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610952565b005b6102536004803603602081101561022757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610b53565b60405180858152602001841515151581526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200194505050505060405180910390f35b6102b6610bb0565b6040518082815260200191505060405180910390f35b6000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008160000154141561038a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f486173206e6f20726967687420746f20766f746500000000000000000000000081525060200191505060405180910390fd5b8060010160009054906101000a900460ff161561040f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f416c726561647920766f7465642e00000000000000000000000000000000000081525060200191505060405180910390fd5b60018160010160006101000a81548160ff02191690831515021790555081816002018190555080600001546002838154811061044757fe5b9060005260206000209060020201600101600082825401925050819055505050565b6002818154811061047657fe5b90600052602060002090600202016000915090508060000154908060010154905082565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010160009054906101000a900460ff1615610587576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f596f7520616c726561647920766f7465642e000000000000000000000000000081525060200191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610629576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f53656c662d64656c65676174696f6e20697320646973616c6c6f7765642e000081525060200191505060405180910390fd5b5b600073ffffffffffffffffffffffffffffffffffffffff16600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146107cc57600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691503373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156107c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f466f756e64206c6f6f7020696e2064656c65676174696f6e2e0000000000000081525060200191505060405180910390fd5b61062a565b60018160010160006101000a81548160ff021916908315150217905550818160010160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060010160009054906101000a900460ff16156108bf578160000154600282600201548154811061089c57fe5b9060005260206000209060020201600101600082825401925050819055506108d6565b816000015481600001600082825401925050819055505b505050565b6000806000905060008090505b60028054905081101561094d57816002828154811061090357fe5b9060005260206000209060020201600101541115610940576002818154811061092857fe5b90600052602060002090600202016001015491508092505b80806001019150506108e8565b505090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109f7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180610bde6028913960400191505060405180910390fd5b600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160009054906101000a900460ff1615610aba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f54686520766f74657220616c726561647920766f7465642e000000000000000081525060200191505060405180910390fd5b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000015414610b0957600080fd5b60018060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018190555050565b60016020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16908060010160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154905084565b60006002610bbc6108db565b81548110610bc657fe5b90600052602060002090600202016000015490509056fe4f6e6c79206368616972706572736f6e2063616e206769766520726967687420746f20766f74652ea26469706673582212201d282819f8f06fed792100d60a8b08809b081a34a1ecd225e83a4b41122165ed64736f6c63430006060033", + "nonce": "1", + "storage": { + "0x6200beec95762de01ce05f2a0e58ce3299dbb53c68c9f3254a242121223cdf58": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1": { + "balance": "0x57af9d6b3df812900", + "code": "0x", + "nonce": "6", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "IstanbulBlock": 1561651, + "chainId": 5, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3509749784", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "4727564", + "hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada", + "nonce": "0x4eb12e19c16d43da", + "number": "2289805", + "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", + "timestamp": "1513601261", + "totalDifficulty": "7143276353481064" + }, + "input": "0xf888068449504f80832dc6c094f58833cf0c791881b494eb79d461e08a1f043f5280a45c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf12da0264664db3e71fae1dbdaf2f53954be149ad3b7ba8a5054b4d89c70febfacc8b1a0212e8398757963f419681839ae8c5a54b411e252473c82d93dda68405ca63294", + "result": [ + { + "action": { + "callType": "call", + "from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", + "gas": "0x2d7308", + "input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", + "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", + "value": "0x0" + }, + "blockNumber": 3212651, + "error": "execution reverted", + "result": { + "gasUsed": "0x5940", + "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e53656c662d64656c65676174696f6e20697320646973616c6c6f7765642e0000" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json new file mode 100644 index 000000000000..cd34d0b6d063 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json @@ -0,0 +1,91 @@ +{ + "genesis": { + "difficulty": "4628640", + "extraData": "0xd883010b05846765746888676f312e31342e33856c696e7578", + "gasLimit": "9244120", + "hash": "0x5a1f551897cc91265225b0453136ad8c7eef1c1c8b06139da4f2e6e710c1f4df", + "miner": "0x73f26d124436b0791169d63a3af29c2ae47765a3", + "mixHash": "0xd6735e63f8937fe0c5491e0d5836ec28467363be7ada5a2f979f9d107e2c831e", + "nonce": "0x7c35e34d2e328d7d", + "number": "1555145", + "stateRoot": "0x565873b05f71b98595133e37a52d79c3476ce820c05ebedaddd35541b0e894a3", + "timestamp": "1590793819", + "totalDifficulty": "2241994078605", + "alloc": { + "0x119f569a45e9d0089d51d7f9529f5ea9bf5785e2": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x622e8fced69d43eb8d97", + "nonce": "260140", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "1555146", + "difficulty": "4630900", + "timestamp": "1590793820", + "gasLimit": "9253146", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf8628303f82c843b9aca0083019ecc80808e605a600053600160006001f0ff0081a2a077f539ae2a58746bbfa6370fc423f946870efa32753d697d3729d361a428623aa0384ef9a5650d6630f5c1ddef616bffa5fc72a95a9314361d0918de066aa4475a", + "result": [ + { + "type": "create", + "action": { + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "value": "0x0", + "gas": "0xcf08", + "init": "0x605a600053600160006001f0ff00" + }, + "result": { + "gasUsed": "0x102a1", + "code": "0x", + "address": "0x1d99a1a3efa9181f540f9e24fa6e4e08eb7844ca" + }, + "traceAddress": [], + "subtraces": 1, + "transactionPosition": 14, + "transactionHash": "0xdd76f02407e2f8329303ba688e111cae4f7008ad0d14d6e42c5698424ea36d79", + "blockNumber": 1555146, + "blockHash": "0xafb4f1dd27b9054c805acb81a88ed04384788cb31d84164c21874935c81e5c7e", + "time": "187.145µs" + }, + { + "type": "suicide", + "action": { + "address": "0x1d99a1a3efa9181f540f9e24fa6e4e08eb7844ca", + "refundAddress": "0x0000000000000000000000000000000000000000", + "balance": "0x0" + }, + "result": null, + "traceAddress": [ + 0 + ], + "subtraces": 0, + "transactionPosition": 14, + "transactionHash": "0xdd76f02407e2f8329303ba688e111cae4f7008ad0d14d6e42c5698424ea36d79", + "blockNumber": 1555146, + "blockHash": "0xafb4f1dd27b9054c805acb81a88ed04384788cb31d84164c21874935c81e5c7e" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json new file mode 100644 index 000000000000..6d084410a366 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json @@ -0,0 +1,97 @@ +{ + "context": { + "difficulty": "3502894804", + "gasLimit": "4722976", + "miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724", + "number": "2289806", + "timestamp": "1513601314" + }, + "genesis": { + "alloc": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "code": "0x", + "nonce": "22", + "storage": {} + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "code": "0x", + "nonce": "29072", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3509749784", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "4727564", + "hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada", + "nonce": "0x4eb12e19c16d43da", + "number": "2289805", + "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", + "timestamp": "1513601261", + "totalDifficulty": "7143276353481064" + }, + "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", + "result": [ + { + "action": { + "callType": "call", + "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", + "gas": "0x10738", + "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "value": "0x0" + }, + "blockNumber": 2289806, + "result": { + "gasUsed": "0x9751", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "gas": "0x6d05", + "input": "0x", + "to": "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "value": "0x6f05b59d3b20000" + }, + "blockNumber": 0, + "result": { + "gasUsed": "0x0", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [0], + "type": "call" + } + ] +} diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json new file mode 100644 index 000000000000..d530fe908b2a --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json @@ -0,0 +1,70 @@ +{ + "genesis": { + "difficulty": "4673862", + "extraData": "0xd683010b05846765746886676f312e3133856c696e7578", + "gasLimit": "9471919", + "hash": "0x7f072150c5905c214966e3432d418910badcdbe510aceaac295b1d7059cc0ffc", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "mixHash": "0x113ced8fedb939fdc862008da7bdddde726f997c0e6dfba0e55613994757b489", + "nonce": "0x0f411a2e5552c5b7", + "number": "1555284", + "stateRoot": "0x9fe125b361b72d5479b24ad9be9964b74228c73a2dfb0065060a79b4a6dfaa1e", + "timestamp": "1590795374", + "totalDifficulty": "2242642335405", + "alloc": { + "0xe85df1413eebe1b191c26260e19783a274a6b041": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x6244c985ef1e48e84531", + "nonce": "265775", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "1555285", + "difficulty": "4676144", + "timestamp": "1590795378", + "gasLimit": "9481167", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf9014083040e2f843b9aca008301aab08080b8eb7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b5547f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000000000000000000000000000000000000000c3507f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000037f05581a2a09db45e7846f193471f6d897fb6ff58b7ec41a9c6f63d10aca47d821c365981cba052ec320875625e16141a1a9e8b7993de863698fb699f93ae2cab26149bbb144f", + "result": [ + { + "type": "create", + "action": { + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "value": "0x0", + "gas": "0xd550", + "init": "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b5547f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000000000000000000000000000000000000000c3507f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000037f055" + }, + "error": "out of gas", + "traceAddress": [], + "subtraces": 0, + "transactionPosition": 16, + "transactionHash": "0x384487e5ae8d2997aece8e28403d393cb9752425e6de358891bed981c5af1c05", + "blockNumber": 1555285, + "blockHash": "0x93231d8e9662adb4c5c703583a92c7b3112cd5448f43ab4fa1f0f00a0183ed3f", + "time": "665.278µs" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json new file mode 100644 index 000000000000..9291149bdb69 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json @@ -0,0 +1,83 @@ +{ + "genesis": { + "difficulty": "2028219", + "extraData": "0xd883010906846765746888676f312e31332e35856c696e7578", + "gasLimit": "23481547", + "hash": "0x3c06114e88c26b52decfe4e5f6d4d51cfaaea0317b646017fac32fadbe7df9f5", + "miner": "0x2a1442b4fbabf7b5507c13ccf076a547abfaeb1b", + "mixHash": "0x46108f74220c5ab23651f93912b14fea37ed1380d22e10639a1f5651c98cb949", + "nonce": "0x426a5267e0b636fe", + "number": "567687", + "stateRoot": "0x7b4b193fe73ef87101c7c325954681861cc240c299d03459784b2b11c9c522ae", + "timestamp": "1577578008", + "totalDifficulty": "485254950048", + "alloc": { + "0x8521f13dd5e4bc3dab3cf0f01a195a5af899e851": { + "balance": "0x0", + "nonce": "1", + "code": "0x608060405260043610610251576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806301ffc9a7146102565780630519ce79146102c857806306fdde031461031f578063095ea7b3146103af5780630a0f81681461040a5780631155dfe51461046157806318160ddd1461048c5780631b57cd44146104b7578063200b1e641461050657806327d7874c146105cb5780632ba73c151461061c5780633108e4d71461066d578063317676bf146106bc5780633f4ba83a1461071557806342842e0e1461072c57806346cb96fa146107a75780634e0a3379146107f65780635501d42d146108475780635c975abb146108a05780635fd8c710146108cf5780636352211e146108e65780636af04a571461096157806370a08231146109b85780637158798814610a1d5780637866928014610a6e5780638456cb5914610ae95780638462151c14610b0057806385ac788214610ba657806395787d2614610c2c57806395d89b4114610c6e57806396b5d99214610cfe578063990581b614610d795780639db797f014610e2d578063ab8f933a14610e80578063ad84202814610eab578063b047fb5014610ed6578063b355752214610f2d578063b9db15b414610f7c578063bc4006f514610fd2578063ca083be214611029578063cdd22c9314611082578063cec21acb146110d1578063e078d8b114611136578063e17b25af14611182578063e52ab74b146111d3578063f010432314611222578063fac9c51f1461129d578063fdb33429146112ec578063fffb147914611367575b600080fd5b34801561026257600080fd5b506102ae6004803603602081101561027957600080fd5b8101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690602001909291905050506113e2565b604051808215151515815260200191505060405180910390f35b3480156102d457600080fd5b506102dd6116cb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561032b57600080fd5b506103346116f1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610374578082015181840152602081019050610359565b50505050905090810190601f1680156103a15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103bb57600080fd5b50610408600480360360408110156103d257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061172a565b005b34801561041657600080fd5b5061041f6117c4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561046d57600080fd5b506104766117e9565b6040518082815260200191505060405180910390f35b34801561049857600080fd5b506104a16117f6565b6040518082815260200191505060405180910390f35b3480156104c357600080fd5b506104f0600480360360208110156104da57600080fd5b8101908080359060200190929190505050611806565b6040518082815260200191505060405180910390f35b34801561051257600080fd5b506105b5600480360360a081101561052957600080fd5b81019080803590602001909291908035906020019064010000000081111561055057600080fd5b82018360208201111561056257600080fd5b8035906020019184600183028401116401000000008311171561058457600080fd5b9091929391929390803560ff169060200190929190803590602001909291908035906020019092919050505061181e565b6040518082815260200191505060405180910390f35b3480156105d757600080fd5b5061061a600480360360208110156105ee57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611cac565b005b34801561062857600080fd5b5061066b6004803603602081101561063f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611d86565b005b34801561067957600080fd5b506106a66004803603602081101561069057600080fd5b8101908080359060200190929190505050611e61565b6040518082815260200191505060405180910390f35b3480156106c857600080fd5b506106ff600480360360408110156106df57600080fd5b810190808035906020019092919080359060200190929190505050611e79565b6040518082815260200191505060405180910390f35b34801561072157600080fd5b5061072a611ea9565b005b34801561073857600080fd5b506107a56004803603606081101561074f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611f86565b005b3480156107b357600080fd5b506107e0600480360360208110156107ca57600080fd5b8101908080359060200190929190505050612053565b6040518082815260200191505060405180910390f35b34801561080257600080fd5b506108456004803603602081101561081957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061206b565b005b34801561085357600080fd5b5061088a6004803603604081101561086a57600080fd5b810190808035906020019092919080359060200190929190505050612146565b6040518082815260200191505060405180910390f35b3480156108ac57600080fd5b506108b5612176565b604051808215151515815260200191505060405180910390f35b3480156108db57600080fd5b506108e4612189565b005b3480156108f257600080fd5b5061091f6004803603602081101561090957600080fd5b810190808035906020019092919050505061226d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561096d57600080fd5b506109766122e6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156109c457600080fd5b50610a07600480360360208110156109db57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061230c565b6040518082815260200191505060405180910390f35b348015610a2957600080fd5b50610a6c60048036036020811015610a4057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612355565b005b348015610a7a57600080fd5b50610aa760048036036020811015610a9157600080fd5b8101908080359060200190929190505050612472565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610af557600080fd5b50610afe6124a5565b005b348015610b0c57600080fd5b50610b4f60048036036020811015610b2357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506125e9565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610b92578082015181840152602081019050610b77565b505050509050019250505060405180910390f35b348015610bb257600080fd5b50610c16600480360360c0811015610bc957600080fd5b810190808035906020019092919080359060200190929190803515159060200190929190803560ff1690602001909291908035906020019092919080359060200190929190505050612737565b6040518082815260200191505060405180910390f35b610c5860048036036020811015610c4257600080fd5b8101908080359060200190929190505050612c0c565b6040518082815260200191505060405180910390f35b348015610c7a57600080fd5b50610c8361304b565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610cc3578082015181840152602081019050610ca8565b50505050905090810190601f168015610cf05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610d0a57600080fd5b50610d3760048036036020811015610d2157600080fd5b8101908080359060200190929190505050613084565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610d8557600080fd5b50610db260048036036020811015610d9c57600080fd5b81019080803590602001909291905050506130b7565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610df2578082015181840152602081019050610dd7565b50505050905090810190601f168015610e1f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b348015610e3957600080fd5b50610e6660048036036020811015610e5057600080fd5b810190808035906020019092919050505061317b565b604051808215151515815260200191505060405180910390f35b348015610e8c57600080fd5b50610e956131b3565b6040518082815260200191505060405180910390f35b348015610eb757600080fd5b50610ec06131b9565b6040518082815260200191505060405180910390f35b348015610ee257600080fd5b50610eeb6131bf565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610f3957600080fd5b50610f6660048036036020811015610f5057600080fd5b81019080803590602001909291905050506131e5565b6040518082815260200191505060405180910390f35b348015610f8857600080fd5b50610fb560048036036020811015610f9f57600080fd5b81019080803590602001909291905050506131fd565b604051808381526020018281526020019250505060405180910390f35b348015610fde57600080fd5b50610fe7613235565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561103557600080fd5b5061106c6004803603604081101561104c57600080fd5b81019080803590602001909291908035906020019092919050505061325b565b6040518082815260200191505060405180910390f35b34801561108e57600080fd5b506110bb600480360360208110156110a557600080fd5b810190808035906020019092919050505061328b565b6040518082815260200191505060405180910390f35b3480156110dd57600080fd5b50611120600480360360208110156110f457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506132ab565b6040518082815260200191505060405180910390f35b61116c6004803603604081101561114c57600080fd5b8101908080359060200190929190803590602001909291905050506132c3565b6040518082815260200191505060405180910390f35b34801561118e57600080fd5b506111d1600480360360208110156111a557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506134ee565b005b3480156111df57600080fd5b5061120c600480360360208110156111f657600080fd5b810190808035906020019092919050505061358d565b6040518082815260200191505060405180910390f35b34801561122e57600080fd5b5061125b6004803603602081101561124557600080fd5b81019080803590602001909291905050506135ad565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156112a957600080fd5b506112d6600480360360208110156112c057600080fd5b81019080803590602001909291905050506135e0565b6040518082815260200191505060405180910390f35b3480156112f857600080fd5b506113256004803603602081101561130f57600080fd5b81019080803590602001909291905050506135f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561137357600080fd5b506113a06004803603602081101561138a57600080fd5b810190808035906020019092919050505061362b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600060405180807f737570706f727473496e74657266616365286279746573342900000000000000815250601901905060405180910390207bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611610575060405180807f746f6b656e734f664f776e6572286164647265737329000000000000000000008152506016019050604051809103902060405180807f736166655472616e7366657246726f6d28616464726573732c6164647265737381526020017f2c75696e743235362900000000000000000000000000000000000000000000008152506029019050604051809103902060405180807f617070726f766528616464726573732c75696e743235362900000000000000008152506018019050604051809103902060405180807f6f776e65724f662875696e7432353629000000000000000000000000000000008152506010019050604051809103902060405180807f62616c616e63654f6628616464726573732900000000000000000000000000008152506012019050604051809103902060405180807f746f74616c537570706c79282900000000000000000000000000000000000000815250600d019050604051809103902018181818187bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806116c4575060405180807f73796d626f6c28290000000000000000000000000000000000000000000000008152506008019050604051809103902060405180807f6e616d652829000000000000000000000000000000000000000000000000000081525060060190506040518091039020187bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040805190810160405280600781526020017f426974766965770000000000000000000000000000000000000000000000000081525081565b600260149054906101000a900460ff1615151561174657600080fd5b611750338261365e565b151561175b57600080fd5b61176581836136ca565b808273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600480549050905090565b6000600160048054905003905090565b60166020528060005260406000206000915090505481565b600085858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506101006000825111801561187a575080825111155b151561188557600080fd5b33896005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141515156118f557600080fd5b6000878760405160200180838152602001828152602001925050506040516020818303038152906040528051906020012090506000600e6000838152602001908152602001600020541415156119b3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f5369676e617475726520416c726561647920557365640000000000000000000081525060200191505060405180910390fd5b600560008d815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660018d60405160200180828152602001915050604051602081830303815290604052805190602001208b8b8b60405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015611a80573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff16141515611aac57600080fd5b611ab4613a21565b6020604051908101604052808d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050815250905060006001600a839080600181540180825580915050906001820390600052602060002001600090919290919091506000820151816000019080519060200190611b54929190613a35565b5050500390508063ffffffff1681141515611b6e57600080fd5b7fe819187a0cf517f3c23c7bd6e6b11a3aec56ec3f2784dc69ac56ebac668748ee3382604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a133600b600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508d600c600083815260200190815260200160002081905550600860008f81526020019081526020016000208190806001815401808255809150509060018203906000526020600020016000909192909190915055508d600e600085815260200190815260200160002081905550809750505050505050509695505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611d0757600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515611d4357600080fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611de157600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515611e1d57600080fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60116020528060005260406000206000915090505481565b600860205281600052604060002081815481101515611e9457fe5b90600052602060002001600091509150505481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611f0457600080fd5b600260149054906101000a900460ff161515611f1f57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16601860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141515611f7c57600080fd5b611f84613720565b565b600260149054906101000a900460ff16151515611fa257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515611fde57600080fd5b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561201957600080fd5b61202333826137b3565b151561202e57600080fd5b612038838261365e565b151561204357600080fd5b61204e83838361381f565b505050565b600e6020528060005260406000206000915090505481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156120c657600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415151561210257600080fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600d6020528160005260406000208181548110151561216157fe5b90600052602060002001600091509150505481565b600260149054906101000a900460ff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156121e557600080fd5b60003073ffffffffffffffffffffffffffffffffffffffff16319050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015612269573d6000803e3d6000fd5b5050565b60006005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156122e157600080fd5b919050565b601860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156123b057600080fd5b600260149054906101000a900460ff1615156123cb57600080fd5b80601860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f450db8da6efbe9c22f2347f7c2021231df1fc58d3ae9a2fa75d39fa44619930581604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b600b6020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061254d57506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b806125a55750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156125b057600080fd5b600260149054906101000a900460ff161515156125cc57600080fd5b6001600260146101000a81548160ff021916908315150217905550565b606060006125f68361230c565b9050600081141561263a5760006040519080825280602002602001820160405280156126315781602001602082028038833980820191505090505b50915050612732565b60608160405190808252806020026020018201604052801561266b5781602001602082028038833980820191505090505b50905060006126786117f6565b905060008090506000600190505b8281111515612729578673ffffffffffffffffffffffffffffffffffffffff166005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561271c5780848381518110151561270557fe5b906020019060200201818152505081806001019250505b8080600101915050612686565b83955050505050505b919050565b600033876005600082815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141515156127a957600080fd5b60008585604051602001808381526020018281526020019250505060405160208183030381529060405280519060200120905060008911156128715788601260008381526020019081526020016000205414151515612870576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260168152602001807f5369676e617475726520416c726561647920557365640000000000000000000081525060200191505060405180910390fd5b5b600560008b815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660018b604051602001808281526020019150506040516020818303038152906040528051906020012089898960405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561293e573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff1614151561296a57600080fd5b6000339050600073ffffffffffffffffffffffffffffffffffffffff16600b60008c815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141515156129de57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff16600b60008c815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151515612a4c57600080fd5b612a54613ab5565b6020604051908101604052808b1515815250905060006001600f8390806001815401808255809150509060018203906000526020600020016000909192909190915060008201518160000160006101000a81548160ff02191690831515021790555050500390508063ffffffff1681141515612acf57600080fd5b7fa10f25ef783c24056e27eb55eb6c0ac1c4863cd5eab7e657cd067926b3dce0648382604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a1826010600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600d60008d81526020019081526020016000208190806001815401808255809150509060018203906000526020600020016000909192909190915055508b60116000838152602001908152602001600020819055508b60126000868152602001908152602001600020819055508096505050505050509695505050505050565b600034601354808210151515612c2157600080fd5b60003390506000600b600087815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515612c9a57600080fd5b8173ffffffffffffffffffffffffffffffffffffffff16600b600088815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151515612d0857600080fd5b612d10613acb565b602060405190810160405280348152509050600060016014839080600181540180825580915050906001820390600052602060002001600090919290919091506000820151816000015550500390508063ffffffff1681141515612d7357600080fd5b836015600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508760166000838152602001908152602001600020819055506000606434604602811515612dee57fe5b0490506000600d60008b815260200190815260200160002080549050823403811515612e1657fe5b049050600b60008b815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015612e92573d6000803e3d6000fd5b5060008090505b600d60008c815260200190815260200160002080549050811015612fcf5760106000600d60008e815260200190815260200160002083815481101515612edb57fe5b9060005260206000200154815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015612f5a573d6000803e3d6000fd5b5060176000858152602001908152602001600020600d60008d815260200190815260200160002082815481101515612f8e57fe5b906000526020600020015490806001815401808255809150509060018203906000526020600020016000909192909190915055508080600101915050612e99565b507f6ea1e5e03071ff9bad53b614eafcc00d29db646e9c351fcc00d45a4118d7c51a8684604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a18298505050505050505050919050565b6040805190810160405280600281526020017f425600000000000000000000000000000000000000000000000000000000000081525081565b60056020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60606000600a838154811015156130ca57fe5b906000526020600020019050806000018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561316e5780601f106131435761010080835404028352916020019161316e565b820191906000526020600020905b81548152906001019060200180831161315157829003601f168201915b5050505050915050919050565b600080600f8381548110151561318d57fe5b9060005260206000200190508060000160009054906101000a900460ff16915050919050565b60035481565b60135481565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60126020528060005260406000206000915090505481565b600080600060048481548110151561321157fe5b90600052602060002090600202019050806000015492508060010154915050915091565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60176020528160005260406000208181548110151561327657fe5b90600052602060002001600091509150505481565b600060086000838152602001908152602001600020805490509050919050565b60066020528060005260406000206000915090505481565b6000346003548082101515156132d857600080fd5b8460007f01000000000000000000000000000000000000000000000000000000000000000281600060208110151561330c57fe5b1a7f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415151561335e57600080fd5b8460007f01000000000000000000000000000000000000000000000000000000000000000281600060208110151561339257fe5b1a7f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141515156133e457600080fd5b60003390506133f1613adf565b60408051908101604052808a81526020018981525090506000600160048390806001815401808255809150509060018203906000526020600020906002020160009091929091909150600082015181600001556020820151816001015550500390508063ffffffff168114151561346757600080fd5b7f982bb66d9aa60573bc0a2066122e1466ecbc4c179a5e7c1c5b589345008ce69a8382604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a16134de6000848361381f565b8097505050505050505092915050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561354957600080fd5b80600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600d6000838152602001908152602001600020805490509050919050565b60156020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600c6020528060005260406000206000915090505481565b60076020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60106020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008273ffffffffffffffffffffffffffffffffffffffff166005600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905092915050565b806007600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561377b57600080fd5b600260149054906101000a900460ff16151561379657600080fd5b6000600260146101000a81548160ff021916908315150217905550565b60008273ffffffffffffffffffffffffffffffffffffffff166007600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905092915050565b600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906001019190505550816005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151561397d57600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906001900391905055506007600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555b7f70a295484349ac4c2073cdca8ba026869fff31e0d35e268f820e44c9d25f4a2e838383604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a1505050565b602060405190810160405280606081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613a7657805160ff1916838001178555613aa4565b82800160010185558215613aa4579182015b82811115613aa3578251825591602001919060010190613a88565b5b509050613ab19190613aff565b5090565b6020604051908101604052806000151581525090565b602060405190810160405280600081525090565b604080519081016040528060008019168152602001600080191681525090565b613b2191905b80821115613b1d576000816000905550600101613b05565b5090565b9056fea165627a7a72305820b73bf81476c95567782e45ebae5220573d46c55a9004c11243c470bc91f2d26d0029", + "storage": { + "0x05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0xa54c2b4154b4f221d71d6d5bc0ec905c931a021bb6fb138fc0495bb0373e2276": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "0x0000000000000000000000000000000000000001": { + "balance": "0x0", + "nonce": "0", + "code": "0x", + "storage": {} + }, + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0xcec3d4daf44926cc41e", + "nonce": "147795", + "code": "0x", + "storage": {} + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "567688", + "difficulty": "2028219", + "timestamp": "1577578023", + "gasLimit": "23504477", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf9018f8302415385746a52880083048196948521f13dd5e4bc3dab3cf0f01a195a5af899e85180b90124200b1e64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001b9af799918107e9a339eba0584b8b60b35aae6f087c74f6bfc00c9301849b204d094ed65e09c76c2597f5516f9440aad2921e50dde096e7caaa65a536d4d9265e00000000000000000000000000000000000000000000000000000000000000504269747669657720697320616e20616d617a696e6720776562736974652e20596f752073686f756c6420646566696e6974656c792061646420796f75722070726f6475637420746f2069742e20e282bf0000000000000000000000000000000081a2a0686e4a69e1fa6cac6b4f751a3935ca5a371d720c34d3a7136988aa017a528ed5a07d993e607b665c24557d0eae166c21fe744e618ed3430902ac6206c63a331dc0", + "result": [ + { + "action": { + "author": "0x0000000000000000000000000000000000000000", + "address": "0x0000000000000000000000000000000000000000", + "balance": "0x0", + "callType": "call", + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "gas": "0x4053e", + "input": "0x200b1e64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001b9af799918107e9a339eba0584b8b60b35aae6f087c74f6bfc00c9301849b204d094ed65e09c76c2597f5516f9440aad2921e50dde096e7caaa65a536d4d9265e00000000000000000000000000000000000000000000000000000000000000504269747669657720697320616e20616d617a696e6720776562736974652e20596f752073686f756c6420646566696e6974656c792061646420796f75722070726f6475637420746f2069742e20e282bf00000000000000000000000000000000", + "refundAddress": "0x0000000000000000000000000000000000000000", + "to": "0x8521f13dd5e4bc3dab3cf0f01a195a5af899e851", + "value": "0x0" + }, + "error": "execution reverted", + "result": { + "gasUsed": "0x947c" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json new file mode 100644 index 000000000000..bd9e057c0229 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json @@ -0,0 +1,92 @@ +{ + "genesis": { + "number": "553153", + "hash": "0x88bde20840880a1f3fba92121912a3cc0d3b26d76e4d914fbd85fc2e43da3b3f", + "nonce": "0x7be554ffe4b82fc2", + "mixHash": "0xf73d2ff3c16599c3b8a24b9ebde6c09583b5ee3f747d3cd37845d564f4c8d87a", + "stateRoot": "0x40b5f53d610108947688a04fb68838ff9c0aa0dd6e54156b682537192171ff5c", + "miner": "0x774c398d763161f55b66a646f17edda4addad2ca", + "difficulty": "1928226", + "totalDifficulty": "457857582215", + "extraData": "0xd983010907846765746888676f312e31332e358664617277696e", + "gasLimit": "7999473", + "timestamp": "1577392669", + "alloc": { + "0x877bd459c9b7d8576b44e59e09d076c25946f443": { + "balance": "0x19bb4ac611ca7a1fc881", + "nonce": "701", + "code": "0x", + "storage": {} + }, + "0x8ee79c5b3f6e1d214d2c4fcf7ea4092a32e26e91": { + "balance": "0x0", + "nonce": "1", + "code": "0x60606040526000357c01000000000000000000000000000000000000000000000000000000009004806341c0e1b514610044578063cfae32171461005157610042565b005b61004f6004506100ca565b005b61005c60045061015e565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156100bc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561015b57600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5b565b60206040519081016040528060008152602001506001600050805480601f016020809104026020016040519081016040528092919081815260200182805480156101cd57820191906000526020600020905b8154815290600101906020018083116101b057829003601f168201915b505050505090506101d9565b9056", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000877bd459c9b7d8576b44e59e09d076c25946f443" + } + } + }, + "config": { + "chainId": 63, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 0, + "eip158Block": 0, + "ethash": {}, + "homesteadBlock": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 301243, + "petersburgBlock": 999983, + "istanbulBlock": 999983 + } + }, + "context": { + "number": "553154", + "difficulty": "1929167", + "timestamp": "1577392670", + "gasLimit": "8000000", + "miner": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "input": "0xf86c8202bd850ee6b280008344aa20948ee79c5b3f6e1d214d2c4fcf7ea4092a32e26e91808441c0e1b581a2a03f95ca5cdf7fd727630341c4c6aa1b64ccd9949bd9ecc72cfdd7ce17a2013a69a06d34795ef7fb0108a6dbee4ae0a1bdc48dcd2a4ee53bb6a33d45515af07bb9a8", + "result": [ + { + "action": { + "callType": "call", + "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", + "gas": "0x445708", + "input": "0x41c0e1b5", + "to": "0x8ee79c5b3f6e1d214d2c4fcf7ea4092a32e26e91", + "value": "0x0" + }, + "blockHash": "0xf641c3b0f82b07cd3a528adb9927dd83eeb4f1682e2bd523ed36888e0d82c9a9", + "blockNumber": 553154, + "result": { + "gasUsed": "0x347a", + "output": "0x" + }, + "subtraces": 1, + "traceAddress": [], + "transactionHash": "0x6af0a5c3188ffacae4d340d4a17e14fdb5a54187683a80ef241bde248189882b", + "transactionPosition": 15, + "type": "call" + }, + { + "action": { + "address": "0x8ee79c5b3f6e1d214d2c4fcf7ea4092a32e26e91", + "balance": "0x0", + "refundAddress": "0x877bd459c9b7d8576b44e59e09d076c25946f443" + }, + "blockHash": "0xf641c3b0f82b07cd3a528adb9927dd83eeb4f1682e2bd523ed36888e0d82c9a9", + "blockNumber": 553154, + "subtraces": 0, + "traceAddress": [ + 0 + ], + "transactionHash": "0x6af0a5c3188ffacae4d340d4a17e14fdb5a54187683a80ef241bde248189882b", + "transactionPosition": 15, + "type": "suicide" + } + ] +} \ No newline at end of file diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json new file mode 100644 index 000000000000..b119bed5289a --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json @@ -0,0 +1,70 @@ +{ + "context": { + "difficulty": "117009631", + "gasLimit": "4712388", + "miner": "0x294e5d6c39a36ce38af1dca70c1060f78dee8070", + "number": "25009", + "timestamp": "1479891666" + }, + "genesis": { + "alloc": { + "0x70c9217d814985faef62b124420f8dfbddd96433": { + "balance": "0x4ecd70668f5d854a", + "code": "0x", + "nonce": "1638", + "storage": {} + }, + "0xc212e03b9e060e36facad5fd8f4435412ca22e6b": { + "balance": "0x0", + "code": "0x606060405236156101745760e060020a600035046302d05d3f811461017c57806304a7fdbc1461018e5780630e90f957146101fb5780630fb5a6b41461021257806314baa1b61461021b57806317fc45e21461023a5780632b096926146102435780632e94420f1461025b578063325a19f11461026457806336da44681461026d5780633f81a2c01461027f5780633fc306821461029757806345ecd3d7146102d45780634665096d146102dd5780634e71d92d146102e657806351a34eb8146103085780636111bb951461032d5780636f265b93146103445780637e9014e11461034d57806390ba009114610360578063927df5e014610393578063a7f437791461046c578063ad8f50081461046e578063bc6d909414610477578063bdec3ad114610557578063c19d93fb1461059a578063c9503fe2146105ad578063e0a73a93146105b6578063ea71b02d146105bf578063ea8a1af0146105d1578063ee4a96f9146105f3578063f1ff78a01461065c575b61046c610002565b610665600054600160a060020a031681565b6040805160c081810190925261046c9160049160c4918390600690839083908082843760408051808301909152929750909561018495509193509091908390839080828437509095505050505050600554600090600160a060020a0390811633909116146106a857610002565b61068260015460a060020a900460ff166000145b90565b61069660085481565b61046c600435600154600160a060020a03166000141561072157610002565b610696600d5481565b610696600435600f8160068110156100025750015481565b61069660045481565b61069660035481565b610665600554600160a060020a031681565b61069660043560158160068110156100025750015481565b6106966004355b600b54600f5460009160028202808203928083039290810191018386101561078357601054840186900394505b50505050919050565b61069660025481565b61069660095481565b61046c600554600090600160a060020a03908116339091161461085857610002565b61046c600435600554600090600160a060020a03908116339091161461092e57610002565b6106826001805460a060020a900460ff161461020f565b610696600b5481565b61068260075460a060020a900460ff1681565b6106966004355b600b54601554600091600282028082039280830392908101910183861015610a6c5760165494506102cb565b61046c6004356024356044356040805160015460e360020a631c2d8fb302825260b260020a691858d8dbdd5b9d18dd1b02600483015291516000928392600160a060020a03919091169163e16c7d9891602481810192602092909190829003018187876161da5a03f1156100025750505060405180519060200150905080600160a060020a031663c4b0c96a336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610b4657610002565b005b610696600a5481565b61046c60006000600060006000600160009054906101000a9004600160a060020a0316600160a060020a031663e16c7d986040518160e060020a028152600401808060b260020a691858d8dbdd5b9d18dd1b0281526020015060200190506020604051808303816000876161da5a03f1156100025750505060405180519060200150905080600160a060020a031663c4b0c96a336040518260e060020a0281526004018082600160a060020a031681526020019150506020604051808303816000876161da5a03f1156100025750506040515115159050610f1757610002565b61046c5b60015b60058160ff16101561071e57600f6001820160ff166006811015610002578101549060ff83166006811015610002570154101561129057610002565b61069660015460a060020a900460ff1681565b61069660065481565b610696600c5481565b610665600754600160a060020a031681565b61046c600554600090600160a060020a0390811633909116146112c857610002565b6040805160c081810190925261046c9160049160c4918390600690839083908082843760408051808301909152929750909561018495509193509091908390839080828437509095505050505050600154600090600160a060020a03168114156113fb57610002565b610696600e5481565b60408051600160a060020a03929092168252519081900360200190f35b604080519115158252519081900360200190f35b60408051918252519081900360200190f35b5060005b60068160ff16101561070857828160ff166006811015610002576020020151600f60ff831660068110156100025701558160ff82166006811015610002576020020151601560ff831660068110156100025701556001016106ac565b61071061055b565b505050565b600e8054820190555b50565b6040805160015460e060020a6313bc6d4b02825233600160a060020a03908116600484015292519216916313bc6d4b9160248181019260209290919082900301816000876161da5a03f115610002575050604051511515905061071557610002565b83861015801561079257508286105b156107b457600f546010546011548689039082030291909104900394506102cb565b8286101580156107c55750600b5486105b156107e757600f546011546012548589039082030291909104900394506102cb565b600b5486108015906107f857508186105b1561081d57600b54600f546012546013549289039281039290920204900394506102cb565b81861015801561082c57508086105b1561084e57600f546013546014548489039082030291909104900394506102cb565b60145494506102cb565b60015460a060020a900460ff1660001461087157610002565b600254600a01431161088257610002565b6040805160015460e360020a631c2d8fb302825260a860020a6a636f6e74726163746170690260048301529151600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750505060405180519060200150905080600160a060020a031663771d50e16040518160e060020a0281526004018090506000604051808303816000876161da5a03f1156100025750505050565b60015460a060020a900460ff1660001461094757610002565b600254600a01431161095857610002565b6040805160015460e360020a631c2d8fb302825260a860020a6a636f6e74726163746170690260048301529151600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750506040805180517f51a34eb8000000000000000000000000000000000000000000000000000000008252600482018690529151919350600160a060020a03841692506351a34eb8916024808301926000929190829003018183876161da5a03f11561000257505050600b8290554360025560408051838152905130600160a060020a0316917fa609f6bd4ad0b4f419ddad4ac9f0d02c2b9295c5e6891469055cf73c2b568fff919081900360200190a25050565b838610158015610a7b57508286105b15610a9d576015546016546017548689039082900302919091040194506102cb565b828610158015610aae5750600b5486105b15610ad0576015546017546018548589039082900302919091040194506102cb565b600b548610801590610ae157508186105b15610b0657600b546015546018546019549289039281900392909202040194506102cb565b818610158015610b1557508086105b15610b3757601554601954601a548489039082900302919091040194506102cb565b601a54860181900394506102cb565b60015460a060020a900460ff16600014610b5f57610002565b6001805460a060020a60ff02191660a060020a17908190556040805160e360020a631c2d8fb302815260a860020a6a636f6e74726163746170690260048201529051600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750506040805180516004805460e260020a633e4baddd028452908301529151919450600160a060020a038516925063f92eb77491602482810192602092919082900301816000876161da5a03f115610002575050604080518051600a556005547ffebf661200000000000000000000000000000000000000000000000000000000825233600160a060020a03908116600484015216602482015260448101879052905163febf661291606480820192600092909190829003018183876161da5a03f115610002575050508215610cc7576007805473ffffffffffffffffffffffffffffffffffffffff191633179055610dbb565b6040805160055460065460e060020a63599efa6b028352600160a060020a039182166004840152602483015291519184169163599efa6b91604481810192600092909190829003018183876161da5a03f115610002575050604080516006547f56ccb6f000000000000000000000000000000000000000000000000000000000825233600160a060020a03166004830152602482015290516356ccb6f091604480820192600092909190829003018183876161da5a03f115610002575050600580546007805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a038416179091551633179055505b6007805460a060020a60ff02191660a060020a87810291909117918290556008544301600955900460ff1615610df757600a54610e039061029e565b600a54610e0b90610367565b600c55610e0f565b600c555b600c54670de0b6b3a7640000850204600d55600754600554604080517f759297bb000000000000000000000000000000000000000000000000000000008152600160a060020a039384166004820152918316602483015260448201879052519184169163759297bb91606481810192600092909190829003018183876161da5a03f11561000257505060408051600754600a54600d54600554600c5460a060020a850460ff161515865260208601929092528486019290925260608401529251600160a060020a0391821694509281169230909116917f3b3d1986083d191be01d28623dc19604728e29ae28bdb9ba52757fdee1a18de2919081900360800190a45050505050565b600954431015610f2657610002565b6001805460a060020a900460ff1614610f3e57610002565b6001805460a060020a60ff0219167402000000000000000000000000000000000000000017908190556040805160e360020a631c2d8fb302815260a860020a6a636f6e74726163746170690260048201529051600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f1156100025750506040805180516004805460e260020a633e4baddd028452908301529151919750600160a060020a038816925063f92eb77491602482810192602092919082900301816000876161da5a03f115610002575050604051516007549095506000945060a060020a900460ff1615905061105c57600a5484111561105757600a54600d54670de0b6b3a7640000918603020492505b61107e565b600a5484101561107e57600a54600d54670de0b6b3a764000091869003020492505b60065483111561108e5760065492505b6006548390039150600083111561111857604080516005546007547f5928d37f000000000000000000000000000000000000000000000000000000008352600160a060020a0391821660048401528116602483015260448201869052915191871691635928d37f91606481810192600092909190829003018183876161da5a03f115610002575050505b600082111561117a576040805160055460e060020a63599efa6b028252600160a060020a0390811660048301526024820185905291519187169163599efa6b91604481810192600092909190829003018183876161da5a03f115610002575050505b6040805185815260208101849052808201859052905130600160a060020a0316917f89e690b1d5aaae14f3e85f108dc92d9ab3763a58d45aed8b59daedbbae8fe794919081900360600190a260008311156112285784600160a060020a0316634cc927d785336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506000604051808303816000876161da5a03f11561000257505050611282565b84600160a060020a0316634cc927d7600a60005054336040518360e060020a0281526004018083815260200182600160a060020a03168152602001925050506000604051808303816000876161da5a03f115610002575050505b600054600160a060020a0316ff5b60156001820160ff166006811015610002578101549060ff8316600681101561000257015411156112c057610002565b60010161055e565b60015460a060020a900460ff166000146112e157610002565b600254600a0143116112f257610002565b6001546040805160e360020a631c2d8fb302815260a860020a6a636f6e74726163746170690260048201529051600160a060020a03929092169163e16c7d989160248181019260209290919082900301816000876161da5a03f11561000257505060408051805160055460065460e060020a63599efa6b028452600160a060020a03918216600485015260248401529251909450918416925063599efa6b916044808301926000929190829003018183876161da5a03f1156100025750505080600160a060020a0316632b68bb2d6040518160e060020a0281526004018090506000604051808303816000876161da5a03f115610002575050600054600160a060020a03169050ff5b6001546040805160e060020a6313bc6d4b02815233600160a060020a039081166004830152915191909216916313bc6d4b91602480830192602092919082900301816000876161da5a03f11561000257505060405151151590506106a85761000256", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000002cccf5e0538493c235d1c5ef6580f77d99e91396", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000000000000061a9", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x00000000000000000000000070c9217d814985faef62b124420f8dfbddd96433" + } + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "117066792", + "extraData": "0xd783010502846765746887676f312e372e33856c696e7578", + "gasLimit": "4712388", + "hash": "0xe23e8d4562a1045b70cbc99fefb20c101a8f0fc8559a80d65fea8896e2f1d46e", + "miner": "0x71842f946b98800fe6feb49f0ae4e253259031c9", + "mixHash": "0x0aada9d6e93dd4db0d09c0488dc0a048fca2ccdc1f3fc7b83ba2a8d393a3a4ff", + "nonce": "0x70849d5838dee2e9", + "number": "25008", + "stateRoot": "0x1e01d2161794768c5b917069e73d86e8dca80cd7f3168c0597de420ab93a3b7b", + "timestamp": "1479891641", + "totalDifficulty": "1896347038589" + }, + "input": "0xf88b8206668504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb8000000000000000000000000000000000000000000000027fad02094277c000029a0692a3b4e7b2842f8dd7832e712c21e09f451f416c8976d5b8d02e8c0c2b4bea9a07645e90fc421b63dd755767fd93d3c03b4ec0c4d8fafa059558d08cf11d59750", + "result": [ + { + "action": { + "callType": "call", + "from": "0x70c9217d814985faef62b124420f8dfbddd96433", + "gas": "0x37b38", + "input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000", + "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", + "value": "0x0" + }, + "blockNumber": 25009, + "error": "invalid jump destination", + "result": {}, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ] +} diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 75103f64cc87..7b631a88f620 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -240,6 +240,7 @@ func (t *callTracer) GetResult() (json.RawMessage, error) { if len(t.callstack) != 1 { return nil, errors.New("incorrect number of top-level calls") } + res, err := json.Marshal(t.callstack[0]) if err != nil { return nil, err diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go new file mode 100644 index 000000000000..75aa8a583fe4 --- /dev/null +++ b/eth/tracers/native/call_flat.go @@ -0,0 +1,379 @@ +// Copyright 2022 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 native + +import ( + "encoding/json" + "errors" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" +) + +//go:generate go run github.com/fjl/gencodec -type flatCallAction -field-override flatCallActionMarshaling -out gen_flatcallaction_json.go +//go:generate go run github.com/fjl/gencodec -type flatCallResult -field-override flatCallResultMarshaling -out gen_flatcallresult_json.go + +func init() { + tracers.DefaultDirectory.Register("flatCallTracer", newFlatCallTracer, false) +} + +var parityErrorMapping = map[string]string{ + "contract creation code storage out of gas": "Out of gas", + "out of gas": "Out of gas", + "gas uint64 overflow": "Out of gas", + "max code size exceeded": "Out of gas", + "invalid jump destination": "Bad jump destination", + "execution reverted": "Reverted", + "return data out of bounds": "Out of bounds", + "stack limit reached 1024 (1023)": "Out of stack", + "precompiled failed": "Built-in failed", + "invalid input length": "Built-in failed", +} + +var parityErrorMappingStartingWith = map[string]string{ + "invalid opcode:": "Bad instruction", + "stack underflow": "Stack underflow", +} + +// flatCallFrame is a standalone callframe. +type flatCallFrame struct { + Action flatCallAction `json:"action"` + BlockHash *common.Hash `json:"blockHash"` + BlockNumber uint64 `json:"blockNumber"` + Error string `json:"error,omitempty"` + Result *flatCallResult `json:"result,omitempty"` + Subtraces int `json:"subtraces"` + TraceAddress []int `json:"traceAddress"` + TransactionHash *common.Hash `json:"transactionHash"` + TransactionPosition uint64 `json:"transactionPosition"` + Type string `json:"type"` +} + +type flatCallAction struct { + Author *common.Address `json:"author,omitempty"` + RewardType string `json:"rewardType,omitempty"` + SelfDestructed *common.Address `json:"address,omitempty"` + Balance *big.Int `json:"balance,omitempty"` + CallType string `json:"callType,omitempty"` + CreationMethod string `json:"creationMethod,omitempty"` + From *common.Address `json:"from,omitempty"` + Gas *uint64 `json:"gas,omitempty"` + Init *[]byte `json:"init,omitempty"` + Input *[]byte `json:"input,omitempty"` + RefundAddress *common.Address `json:"refundAddress,omitempty"` + To *common.Address `json:"to,omitempty"` + Value *big.Int `json:"value,omitempty"` +} + +type flatCallActionMarshaling struct { + Balance *hexutil.Big + Gas *hexutil.Uint64 + Init *hexutil.Bytes + Input *hexutil.Bytes + Value *hexutil.Big +} + +type flatCallResult struct { + Address *common.Address `json:"address,omitempty"` + Code *[]byte `json:"code,omitempty"` + GasUsed *uint64 `json:"gasUsed,omitempty"` + Output *[]byte `json:"output,omitempty"` +} + +type flatCallResultMarshaling struct { + Code *hexutil.Bytes + GasUsed *hexutil.Uint64 + Output *hexutil.Bytes +} + +// flatCallTracer reports call frame information of a tx in a flat format, i.e. +// as opposed to the nested format of `callTracer`. +type flatCallTracer struct { + tracer *callTracer + config flatCallTracerConfig + ctx *tracers.Context // Holds tracer context data + reason error // Textual reason for the interruption + activePrecompiles []common.Address // Updated on CaptureStart based on given rules +} + +type flatCallTracerConfig struct { + ConvertParityErrors bool `json:"convertParityErrors"` // If true, call tracer converts errors to parity format + IncludePrecompiles bool `json:"includePrecompiles"` // If true, call tracer includes calls to precompiled contracts +} + +// newFlatCallTracer returns a new flatCallTracer. +func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { + var config flatCallTracerConfig + if cfg != nil { + if err := json.Unmarshal(cfg, &config); err != nil { + return nil, err + } + } + + tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, cfg) + if err != nil { + return nil, err + } + t, ok := tracer.(*callTracer) + if !ok { + return nil, errors.New("internal error: embedded tracer has wrong type") + } + + return &flatCallTracer{tracer: t, ctx: ctx, config: config}, nil +} + +// CaptureStart implements the EVMLogger interface to initialize the tracing operation. +func (t *flatCallTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { + t.tracer.CaptureStart(env, from, to, create, input, gas, value) + // Update list of precompiles based on current block + rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) + t.activePrecompiles = vm.ActivePrecompiles(rules) +} + +// CaptureEnd is called after the call finishes to finalize the tracing. +func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { + t.tracer.CaptureEnd(output, gasUsed, err) +} + +// CaptureState implements the EVMLogger interface to trace a single step of VM execution. +func (t *flatCallTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + t.tracer.CaptureState(pc, op, gas, cost, scope, rData, depth, err) +} + +// CaptureFault implements the EVMLogger interface to trace an execution fault. +func (t *flatCallTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { + t.tracer.CaptureFault(pc, op, gas, cost, scope, depth, err) +} + +// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *flatCallTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + t.tracer.CaptureEnter(typ, from, to, input, gas, value) + + // Child calls must have a value, even if it's zero. + // Practically speaking, only STATICCALL has nil value. Set it to zero. + if t.tracer.callstack[len(t.tracer.callstack)-1].Value == nil && value == nil { + t.tracer.callstack[len(t.tracer.callstack)-1].Value = big.NewInt(0) + } +} + +// CaptureExit is called when EVM exits a scope, even if the scope didn't +// execute any code. +func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) { + t.tracer.CaptureExit(output, gasUsed, err) + + // Parity traces don't include CALL/STATICCALLs to precompiles. + // By default we remove them from the callstack. + if t.config.IncludePrecompiles { + return + } + var ( + // call has been nested in parent + parent = t.tracer.callstack[len(t.tracer.callstack)-1] + call = parent.Calls[len(parent.Calls)-1] + typ = call.Type + to = call.To + ) + if typ == vm.CALL || typ == vm.STATICCALL { + if t.isPrecompiled(to) { + t.tracer.callstack[len(t.tracer.callstack)-1].Calls = parent.Calls[:len(parent.Calls)-1] + } + } +} + +func (t *flatCallTracer) CaptureTxStart(gasLimit uint64) { + t.tracer.CaptureTxStart(gasLimit) +} + +func (t *flatCallTracer) CaptureTxEnd(restGas uint64) { + t.tracer.CaptureTxEnd(restGas) +} + +// GetResult returns an empty json object. +func (t *flatCallTracer) GetResult() (json.RawMessage, error) { + if len(t.tracer.callstack) < 1 { + return nil, errors.New("invalid number of calls") + } + + flat, err := flatFromNested(&t.tracer.callstack[0], []int{}, t.config.ConvertParityErrors, t.ctx) + if err != nil { + return nil, err + } + + res, err := json.Marshal(flat) + if err != nil { + return nil, err + } + return res, t.reason +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (t *flatCallTracer) Stop(err error) { + t.tracer.Stop(err) +} + +// isPrecompiled returns whether the addr is a precompile. +func (t *flatCallTracer) isPrecompiled(addr common.Address) bool { + for _, p := range t.activePrecompiles { + if p == addr { + return true + } + } + return false +} + +func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx *tracers.Context) (output []flatCallFrame, err error) { + var frame *flatCallFrame + switch input.Type { + case vm.CREATE, vm.CREATE2: + frame = newFlatCreate(input) + case vm.SELFDESTRUCT: + frame = newFlatSuicide(input) + case vm.CALL, vm.STATICCALL, vm.CALLCODE, vm.DELEGATECALL: + frame = newFlatCall(input) + default: + return nil, fmt.Errorf("unrecognized call frame type: %s", input.Type) + } + + frame.TraceAddress = traceAddress + frame.Error = input.Error + frame.Subtraces = len(input.Calls) + fillCallFrameFromContext(frame, ctx) + if convertErrs { + convertErrorToParity(frame) + } + + // Revert output contains useful information (revert reason). + // Otherwise discard result. + if input.Error != "" && input.Error != vm.ErrExecutionReverted.Error() { + frame.Result = nil + } + + output = append(output, *frame) + if len(input.Calls) > 0 { + for i, childCall := range input.Calls { + childAddr := childTraceAddress(traceAddress, i) + childCallCopy := childCall + flat, err := flatFromNested(&childCallCopy, childAddr, convertErrs, ctx) + if err != nil { + return nil, err + } + output = append(output, flat...) + } + } + + return output, nil +} + +func newFlatCreate(input *callFrame) *flatCallFrame { + var ( + actionInit = input.Input[:] + resultCode = input.Output[:] + ) + + return &flatCallFrame{ + Type: strings.ToLower(vm.CREATE.String()), + Action: flatCallAction{ + From: &input.From, + Gas: &input.Gas, + Value: input.Value, + Init: &actionInit, + }, + Result: &flatCallResult{ + GasUsed: &input.GasUsed, + Address: &input.To, + Code: &resultCode, + }, + } +} + +func newFlatCall(input *callFrame) *flatCallFrame { + var ( + actionInput = input.Input[:] + resultOutput = input.Output[:] + ) + + return &flatCallFrame{ + Type: strings.ToLower(vm.CALL.String()), + Action: flatCallAction{ + From: &input.From, + To: &input.To, + Gas: &input.Gas, + Value: input.Value, + CallType: strings.ToLower(input.Type.String()), + Input: &actionInput, + }, + Result: &flatCallResult{ + GasUsed: &input.GasUsed, + Output: &resultOutput, + }, + } +} + +func newFlatSuicide(input *callFrame) *flatCallFrame { + return &flatCallFrame{ + Type: "suicide", + Action: flatCallAction{ + SelfDestructed: &input.From, + Balance: input.Value, + RefundAddress: &input.To, + }, + } +} + +func fillCallFrameFromContext(callFrame *flatCallFrame, ctx *tracers.Context) { + if ctx == nil { + return + } + if ctx.BlockHash != (common.Hash{}) { + callFrame.BlockHash = &ctx.BlockHash + } + if ctx.BlockNumber != nil { + callFrame.BlockNumber = ctx.BlockNumber.Uint64() + } + if ctx.TxHash != (common.Hash{}) { + callFrame.TransactionHash = &ctx.TxHash + } + callFrame.TransactionPosition = uint64(ctx.TxIndex) +} + +func convertErrorToParity(call *flatCallFrame) { + if call.Error == "" { + return + } + + if parityError, ok := parityErrorMapping[call.Error]; ok { + call.Error = parityError + } else { + for gethError, parityError := range parityErrorMappingStartingWith { + if strings.HasPrefix(call.Error, gethError) { + call.Error = parityError + } + } + } +} + +func childTraceAddress(a []int, i int) []int { + child := make([]int, 0, len(a)+1) + child = append(child, a...) + child = append(child, i) + return child +} diff --git a/eth/tracers/native/gen_flatcallaction_json.go b/eth/tracers/native/gen_flatcallaction_json.go new file mode 100644 index 000000000000..c0756069835b --- /dev/null +++ b/eth/tracers/native/gen_flatcallaction_json.go @@ -0,0 +1,110 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package native + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*flatCallActionMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (f flatCallAction) MarshalJSON() ([]byte, error) { + type flatCallAction struct { + Author *common.Address `json:"author,omitempty"` + RewardType string `json:"rewardType,omitempty"` + SelfDestructed *common.Address `json:"address,omitempty"` + Balance *hexutil.Big `json:"balance,omitempty"` + CallType string `json:"callType,omitempty"` + CreationMethod string `json:"creationMethod,omitempty"` + From *common.Address `json:"from,omitempty"` + Gas *hexutil.Uint64 `json:"gas,omitempty"` + Init *hexutil.Bytes `json:"init,omitempty"` + Input *hexutil.Bytes `json:"input,omitempty"` + RefundAddress *common.Address `json:"refundAddress,omitempty"` + To *common.Address `json:"to,omitempty"` + Value *hexutil.Big `json:"value,omitempty"` + } + var enc flatCallAction + enc.Author = f.Author + enc.RewardType = f.RewardType + enc.SelfDestructed = f.SelfDestructed + enc.Balance = (*hexutil.Big)(f.Balance) + enc.CallType = f.CallType + enc.CreationMethod = f.CreationMethod + enc.From = f.From + enc.Gas = (*hexutil.Uint64)(f.Gas) + enc.Init = (*hexutil.Bytes)(f.Init) + enc.Input = (*hexutil.Bytes)(f.Input) + enc.RefundAddress = f.RefundAddress + enc.To = f.To + enc.Value = (*hexutil.Big)(f.Value) + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (f *flatCallAction) UnmarshalJSON(input []byte) error { + type flatCallAction struct { + Author *common.Address `json:"author,omitempty"` + RewardType *string `json:"rewardType,omitempty"` + SelfDestructed *common.Address `json:"address,omitempty"` + Balance *hexutil.Big `json:"balance,omitempty"` + CallType *string `json:"callType,omitempty"` + CreationMethod *string `json:"creationMethod,omitempty"` + From *common.Address `json:"from,omitempty"` + Gas *hexutil.Uint64 `json:"gas,omitempty"` + Init *hexutil.Bytes `json:"init,omitempty"` + Input *hexutil.Bytes `json:"input,omitempty"` + RefundAddress *common.Address `json:"refundAddress,omitempty"` + To *common.Address `json:"to,omitempty"` + Value *hexutil.Big `json:"value,omitempty"` + } + var dec flatCallAction + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Author != nil { + f.Author = dec.Author + } + if dec.RewardType != nil { + f.RewardType = *dec.RewardType + } + if dec.SelfDestructed != nil { + f.SelfDestructed = dec.SelfDestructed + } + if dec.Balance != nil { + f.Balance = (*big.Int)(dec.Balance) + } + if dec.CallType != nil { + f.CallType = *dec.CallType + } + if dec.CreationMethod != nil { + f.CreationMethod = *dec.CreationMethod + } + if dec.From != nil { + f.From = dec.From + } + if dec.Gas != nil { + f.Gas = (*uint64)(dec.Gas) + } + if dec.Init != nil { + f.Init = (*[]byte)(dec.Init) + } + if dec.Input != nil { + f.Input = (*[]byte)(dec.Input) + } + if dec.RefundAddress != nil { + f.RefundAddress = dec.RefundAddress + } + if dec.To != nil { + f.To = dec.To + } + if dec.Value != nil { + f.Value = (*big.Int)(dec.Value) + } + return nil +} diff --git a/eth/tracers/native/gen_flatcallresult_json.go b/eth/tracers/native/gen_flatcallresult_json.go new file mode 100644 index 000000000000..e9fa5e44da8b --- /dev/null +++ b/eth/tracers/native/gen_flatcallresult_json.go @@ -0,0 +1,55 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package native + +import ( + "encoding/json" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*flatCallResultMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (f flatCallResult) MarshalJSON() ([]byte, error) { + type flatCallResult struct { + Address *common.Address `json:"address,omitempty"` + Code *hexutil.Bytes `json:"code,omitempty"` + GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"` + Output *hexutil.Bytes `json:"output,omitempty"` + } + var enc flatCallResult + enc.Address = f.Address + enc.Code = (*hexutil.Bytes)(f.Code) + enc.GasUsed = (*hexutil.Uint64)(f.GasUsed) + enc.Output = (*hexutil.Bytes)(f.Output) + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (f *flatCallResult) UnmarshalJSON(input []byte) error { + type flatCallResult struct { + Address *common.Address `json:"address,omitempty"` + Code *hexutil.Bytes `json:"code,omitempty"` + GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"` + Output *hexutil.Bytes `json:"output,omitempty"` + } + var dec flatCallResult + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Address != nil { + f.Address = dec.Address + } + if dec.Code != nil { + f.Code = (*[]byte)(dec.Code) + } + if dec.GasUsed != nil { + f.GasUsed = (*uint64)(dec.GasUsed) + } + if dec.Output != nil { + f.Output = (*[]byte)(dec.Output) + } + return nil +} diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index b93f7db6f570..856f52a10de3 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -19,6 +19,7 @@ package tracers import ( "encoding/json" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" @@ -27,9 +28,10 @@ import ( // Context contains some contextual infos for a transaction execution that is not // available from within the EVM object. type Context struct { - BlockHash common.Hash // Hash of the block the tx is contained within (zero if dangling tx or call) - TxIndex int // Index of the transaction within a block (zero if dangling tx or call) - TxHash common.Hash // Hash of the transaction being traced (zero if dangling call) + BlockHash common.Hash // Hash of the block the tx is contained within (zero if dangling tx or call) + BlockNumber *big.Int // Number of the block the tx is contained within (zero if dangling tx or call) + TxIndex int // Index of the transaction within a block (zero if dangling tx or call) + TxHash common.Hash // Hash of the transaction being traced (zero if dangling call) } // Tracer interface extends vm.EVMLogger and additionally From 2ea48f8a224e0e286285d63cf13d42bdedcc66b8 Mon Sep 17 00:00:00 2001 From: Dan Cline <6798349+Rjected@users.noreply.github.com> Date: Tue, 28 Feb 2023 05:46:32 -0500 Subject: [PATCH 589/715] core: improve withdrawal index assignment in GenerateChain (#26756) This fixes an issue where the withdrawal index was not calculated correctly for multiple withdrawals in a single block. Co-authored-by: Gary Rong Co-authored-by: Felix Lange --- core/chain_makers.go | 26 +++++---- core/chain_makers_test.go | 109 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 9 deletions(-) diff --git a/core/chain_makers.go b/core/chain_makers.go index 3518929f8e71..052d6efae2f7 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -207,23 +207,31 @@ func (b *BlockGen) AddUncle(h *types.Header) { } // AddWithdrawal adds a withdrawal to the generated block. -func (b *BlockGen) AddWithdrawal(w *types.Withdrawal) { - // The withdrawal will be assigned the next valid index. - var idx uint64 +// It returns the withdrawal index. +func (b *BlockGen) AddWithdrawal(w *types.Withdrawal) uint64 { + cpy := *w + cpy.Index = b.nextWithdrawalIndex() + b.withdrawals = append(b.withdrawals, &cpy) + return cpy.Index +} + +// nextWithdrawalIndex computes the index of the next withdrawal. +func (b *BlockGen) nextWithdrawalIndex() uint64 { + if len(b.withdrawals) != 0 { + return b.withdrawals[len(b.withdrawals)-1].Index + 1 + } for i := b.i - 1; i >= 0; i-- { if wd := b.chain[i].Withdrawals(); len(wd) != 0 { - idx = wd[len(wd)-1].Index + 1 - break + return wd[len(wd)-1].Index + 1 } if i == 0 { - // Correctly set the index if no parent had withdrawals + // Correctly set the index if no parent had withdrawals. if wd := b.parent.Withdrawals(); len(wd) != 0 { - idx = wd[len(wd)-1].Index + 1 + return wd[len(wd)-1].Index + 1 } } } - w.Index = idx - b.withdrawals = append(b.withdrawals, w) + return 0 } // PrevBlock returns a previously generated block by number. It panics if diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 166ac3f227fc..7e895a8d2057 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -19,7 +19,10 @@ package core import ( "fmt" "math/big" + "testing" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" @@ -28,6 +31,112 @@ import ( "github.com/ethereum/go-ethereum/params" ) +func TestGenerateWithdrawalChain(t *testing.T) { + var ( + keyHex = "9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c" + key, _ = crypto.HexToECDSA(keyHex) + address = crypto.PubkeyToAddress(key.PublicKey) // 658bdf435d810c91414ec09147daa6db62406379 + aa = common.Address{0xaa} + bb = common.Address{0xbb} + funds = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether)) + config = *params.AllEthashProtocolChanges + gspec = &Genesis{ + Config: &config, + Alloc: GenesisAlloc{address: {Balance: funds}}, + BaseFee: big.NewInt(params.InitialBaseFee), + Difficulty: common.Big1, + GasLimit: 5_000_000, + } + gendb = rawdb.NewMemoryDatabase() + signer = types.LatestSigner(gspec.Config) + db = rawdb.NewMemoryDatabase() + ) + + config.TerminalTotalDifficultyPassed = true + config.TerminalTotalDifficulty = common.Big0 + config.ShanghaiTime = u64(0) + + // init 0xaa with some storage elements + storage := make(map[common.Hash]common.Hash) + storage[common.Hash{0x00}] = common.Hash{0x00} + storage[common.Hash{0x01}] = common.Hash{0x01} + storage[common.Hash{0x02}] = common.Hash{0x02} + storage[common.Hash{0x03}] = common.HexToHash("0303") + gspec.Alloc[aa] = GenesisAccount{ + Balance: common.Big1, + Nonce: 1, + Storage: storage, + Code: common.Hex2Bytes("6042"), + } + gspec.Alloc[bb] = GenesisAccount{ + Balance: common.Big2, + Nonce: 1, + Storage: storage, + Code: common.Hex2Bytes("600154600354"), + } + + genesis := gspec.MustCommit(gendb) + + chain, _ := GenerateChain(gspec.Config, genesis, beacon.NewFaker(), gendb, 4, func(i int, gen *BlockGen) { + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(address), address, big.NewInt(1000), params.TxGas, new(big.Int).Add(gen.BaseFee(), common.Big1), nil), signer, key) + gen.AddTx(tx) + if i == 1 { + gen.AddWithdrawal(&types.Withdrawal{ + Validator: 42, + Address: common.Address{0xee}, + Amount: 1337, + }) + gen.AddWithdrawal(&types.Withdrawal{ + Validator: 13, + Address: common.Address{0xee}, + Amount: 1, + }) + } + if i == 3 { + gen.AddWithdrawal(&types.Withdrawal{ + Validator: 42, + Address: common.Address{0xee}, + Amount: 1337, + }) + gen.AddWithdrawal(&types.Withdrawal{ + Validator: 13, + Address: common.Address{0xee}, + Amount: 1, + }) + } + }) + + // Import the chain. This runs all block validation rules. + blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil, nil) + defer blockchain.Stop() + + if i, err := blockchain.InsertChain(chain); err != nil { + fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err) + return + } + + // enforce that withdrawal indexes are monotonically increasing from 0 + var ( + withdrawalIndex uint64 + head = blockchain.CurrentBlock().NumberU64() + ) + for i := 0; i < int(head); i++ { + block := blockchain.GetBlockByNumber(uint64(i)) + if block == nil { + t.Fatalf("block %d not found", i) + } + if len(block.Withdrawals()) == 0 { + continue + } + for j := 0; j < len(block.Withdrawals()); j++ { + if block.Withdrawals()[j].Index != withdrawalIndex { + t.Fatalf("withdrawal index %d does not equal expected index %d", block.Withdrawals()[j].Index, withdrawalIndex) + } + withdrawalIndex += 1 + } + } +} + func ExampleGenerateChain() { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") From 98b0ea62b5869388e14728e119baae7008aed218 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 28 Feb 2023 21:32:51 +0800 Subject: [PATCH 590/715] ethdb/pebble: fix range compaction (#26771) * ethdb/pebble: fix range compaction * ethdb/pebble: add comment --- ethdb/pebble/pebble.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index fdad13b392ea..6a7573bdc691 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -20,6 +20,7 @@ package pebble import ( + "bytes" "fmt" "runtime" "sync" @@ -361,6 +362,17 @@ func (d *Database) Stat(property string) (string, error) { // is treated as a key after all keys in the data store. If both is nil then it // will compact entire data store. func (d *Database) Compact(start []byte, limit []byte) error { + // There is no special flag to represent the end of key range + // in pebble(nil in leveldb). Use an ugly hack to construct a + // large key to represent it. + // Note any prefixed database entry will be smaller than this + // flag, as for trie nodes we need the 32 byte 0xff because + // there might be a shared prefix starting with a number of + // 0xff-s, so 32 ensures than only a hash collision could touch it. + // https://github.com/cockroachdb/pebble/issues/2359#issuecomment-1443995833 + if limit == nil { + limit = bytes.Repeat([]byte{0xff}, 32) + } return d.db.Compact(start, limit, true) // Parallelization is preferred } From 2bb622ce40c4ff017304b4f06486852b2002b3b9 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 28 Feb 2023 21:34:12 +0800 Subject: [PATCH 591/715] ethdb/pebble: fix max memorytable size (#26776) --- ethdb/pebble/pebble.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 6a7573bdc691..1f331fa33995 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -131,7 +131,7 @@ func New(file string, cache int, handles int, namespace string, readonly bool) ( // The max memtable size is limited by the uint32 offsets stored in // internal/arenaskl.node, DeferredBatchOp, and flushableBatchEntry. // Taken from https://github.com/cockroachdb/pebble/blob/master/open.go#L38 - maxMemTableSize := 4 << 30 // 4 GB + maxMemTableSize := 4<<30 - 1 // Capped by 4 GB // Two memory tables is configured which is identical to leveldb, // including a frozen memory table and another live one. From e1b98f49a5075694c5022f5ec74425e40da415dd Mon Sep 17 00:00:00 2001 From: "Peter (bitfly)" <1674920+peterbitfly@users.noreply.github.com> Date: Tue, 28 Feb 2023 14:40:24 +0100 Subject: [PATCH 592/715] ethclient: include withdrawals in ethclient block responses (#26778) * include withdrawals in ethclient responses * omit empty withdrawals array in json serialization --- ethclient/ethclient.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 460035f36a6d..6f309030bab9 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -102,9 +102,10 @@ func (ec *Client) PeerCount(ctx context.Context) (uint64, error) { } type rpcBlock struct { - Hash common.Hash `json:"hash"` - Transactions []rpcTransaction `json:"transactions"` - UncleHashes []common.Hash `json:"uncles"` + Hash common.Hash `json:"hash"` + Transactions []rpcTransaction `json:"transactions"` + UncleHashes []common.Hash `json:"uncles"` + Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` } func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { @@ -169,7 +170,7 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface } txs[i] = tx.tx } - return types.NewBlockWithHeader(head).WithBody(txs, uncles), nil + return types.NewBlockWithHeader(head).WithBody(txs, uncles).WithWithdrawals(body.Withdrawals), nil } // HeaderByHash returns the block header with the given hash. From cd31f2dee2843776e485769ce85e0524716199bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 2 Mar 2023 08:29:15 +0200 Subject: [PATCH 593/715] all: change chain head markers from block to header (#26777) --- accounts/abi/bind/backends/simulated.go | 34 +-- accounts/abi/bind/backends/simulated_test.go | 6 +- cmd/geth/chaincmd.go | 4 +- cmd/utils/cmd.go | 2 +- consensus/clique/clique_test.go | 4 +- core/blockchain.go | 220 ++++++++++--------- core/blockchain_reader.go | 24 +- core/blockchain_repair_test.go | 24 +- core/blockchain_sethead_test.go | 8 +- core/blockchain_snapshot_test.go | 8 +- core/blockchain_test.go | 85 +++---- core/chain_makers_test.go | 2 +- core/dao_test.go | 20 +- core/txpool/txpool.go | 10 +- core/txpool/txpool_test.go | 9 +- eth/api.go | 38 ++-- eth/api_backend.go | 19 +- eth/catalyst/api.go | 8 +- eth/catalyst/api_test.go | 68 +++--- eth/downloader/beaconsync.go | 8 +- eth/downloader/downloader.go | 44 ++-- eth/downloader/downloader_test.go | 20 +- eth/gasprice/gasprice_test.go | 12 +- eth/handler.go | 16 +- eth/handler_eth_test.go | 18 +- eth/protocols/eth/handler.go | 6 +- eth/protocols/eth/handler_test.go | 28 +-- eth/protocols/eth/handshake_test.go | 2 +- eth/sync.go | 22 +- eth/tracers/api_test.go | 2 +- graphql/graphql.go | 2 +- internal/ethapi/api.go | 2 +- internal/ethapi/backend.go | 2 +- internal/ethapi/transaction_args_test.go | 2 +- les/api_backend.go | 4 +- les/handler_test.go | 26 +-- les/odr_test.go | 2 +- miner/miner_test.go | 10 +- miner/worker.go | 35 +-- miner/worker_test.go | 12 +- tests/block_test_util.go | 6 +- 41 files changed, 462 insertions(+), 412 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 008c71feaa7a..dc7405ed1905 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -95,7 +95,10 @@ func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.Genesis backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{}) backend.events = filters.NewEventSystem(backend.filterSystem, false) - backend.rollback(blockchain.CurrentBlock()) + header := backend.blockchain.CurrentBlock() + block := backend.blockchain.GetBlock(header.Hash(), header.Number.Uint64()) + + backend.rollback(block) return backend } @@ -135,7 +138,10 @@ func (b *SimulatedBackend) Rollback() { b.mu.Lock() defer b.mu.Unlock() - b.rollback(b.blockchain.CurrentBlock()) + header := b.blockchain.CurrentBlock() + block := b.blockchain.GetBlock(header.Hash(), header.Number.Uint64()) + + b.rollback(block) } func (b *SimulatedBackend) rollback(parent *types.Block) { @@ -174,7 +180,7 @@ func (b *SimulatedBackend) Fork(ctx context.Context, parent common.Hash) error { // stateByBlockNumber retrieves a state by a given blocknumber. func (b *SimulatedBackend) stateByBlockNumber(ctx context.Context, blockNumber *big.Int) (*state.StateDB, error) { - if blockNumber == nil || blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) == 0 { + if blockNumber == nil || blockNumber.Cmp(b.blockchain.CurrentBlock().Number) == 0 { return b.blockchain.State() } block, err := b.blockByNumber(ctx, blockNumber) @@ -303,7 +309,7 @@ func (b *SimulatedBackend) BlockByNumber(ctx context.Context, number *big.Int) ( // (associated with its hash) if found without Lock. func (b *SimulatedBackend) blockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { if number == nil || number.Cmp(b.pendingBlock.Number()) == 0 { - return b.blockchain.CurrentBlock(), nil + return b.blockByHash(ctx, b.blockchain.CurrentBlock().Hash()) } block := b.blockchain.GetBlockByNumber(uint64(number.Int64())) @@ -431,7 +437,7 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM b.mu.Lock() defer b.mu.Unlock() - if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { + if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number) != 0 { return nil, errBlockNumberUnsupported } stateDB, err := b.blockchain.State() @@ -455,7 +461,7 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereu defer b.mu.Unlock() defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot()) - res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) + res, err := b.callContract(ctx, call, b.pendingBlock.Header(), b.pendingState) if err != nil { return nil, err } @@ -549,7 +555,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs call.Gas = gas snapshot := b.pendingState.Snapshot() - res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) + res, err := b.callContract(ctx, call, b.pendingBlock.Header(), b.pendingState) b.pendingState.RevertToSnapshot(snapshot) if err != nil { @@ -599,7 +605,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs // callContract implements common code between normal and pending contract calls. // state is modified during execution, make sure to copy it if necessary. -func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, stateDB *state.StateDB) (*core.ExecutionResult, error) { +func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, header *types.Header, stateDB *state.StateDB) (*core.ExecutionResult, error) { // Gas prices post 1559 need to be initialized if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) { return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") @@ -645,7 +651,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM msg := callMsg{call} txContext := core.NewEVMTxContext(msg) - evmContext := core.NewEVMBlockContext(block.Header(), b.blockchain, nil) + evmContext := core.NewEVMBlockContext(header, b.blockchain, nil) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true}) @@ -854,15 +860,9 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNum case rpc.LatestBlockNumber: return fb.bc.CurrentHeader(), nil case rpc.FinalizedBlockNumber: - if block := fb.bc.CurrentFinalizedBlock(); block != nil { - return block.Header(), nil - } - return nil, errors.New("finalized block not found") + return fb.bc.CurrentFinalBlock(), nil case rpc.SafeBlockNumber: - if block := fb.bc.CurrentSafeBlock(); block != nil { - return block.Header(), nil - } - return nil, errors.New("safe block not found") + return fb.bc.CurrentSafeBlock(), nil default: return fb.bc.GetHeaderByNumber(uint64(number.Int64())), nil } diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index 40699e011636..698bfc576573 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -1189,7 +1189,7 @@ func TestFork(t *testing.T) { sim.Commit() } // 3. - if sim.blockchain.CurrentBlock().NumberU64() != uint64(n) { + if sim.blockchain.CurrentBlock().Number.Uint64() != uint64(n) { t.Error("wrong chain length") } // 4. @@ -1199,7 +1199,7 @@ func TestFork(t *testing.T) { sim.Commit() } // 6. - if sim.blockchain.CurrentBlock().NumberU64() != uint64(n+1) { + if sim.blockchain.CurrentBlock().Number.Uint64() != uint64(n+1) { t.Error("wrong chain length") } } @@ -1344,7 +1344,7 @@ func TestCommitReturnValue(t *testing.T) { sim := simTestBackend(testAddr) defer sim.Close() - startBlockHeight := sim.blockchain.CurrentBlock().NumberU64() + startBlockHeight := sim.blockchain.CurrentBlock().Number.Uint64() // Test if Commit returns the correct block hash h1 := sim.Commit() diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 10af6f32f49a..96999075a316 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -349,8 +349,8 @@ func exportChain(ctx *cli.Context) error { if first < 0 || last < 0 { utils.Fatalf("Export error: block number must be greater than 0\n") } - if head := chain.CurrentFastBlock(); uint64(last) > head.NumberU64() { - utils.Fatalf("Export error: block number %d larger than head block %d\n", uint64(last), head.NumberU64()) + if head := chain.CurrentSnapBlock(); uint64(last) > head.Number.Uint64() { + utils.Fatalf("Export error: block number %d larger than head block %d\n", uint64(last), head.Number.Uint64()) } err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last)) } diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index d1d900a6da9d..e1bafc53c319 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -222,7 +222,7 @@ func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block head := chain.CurrentBlock() for i, block := range blocks { // If we're behind the chain head, only check block, state is available at head - if head.NumberU64() > block.NumberU64() { + if head.Number.Uint64() > block.NumberU64() { if !chain.HasBlock(block.Hash(), block.NumberU64()) { return blocks[i:] } diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index f213bc8247d6..f2c6d740c08a 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -93,7 +93,7 @@ func TestReimportMirroredState(t *testing.T) { if _, err := chain.InsertChain(blocks[:2]); err != nil { t.Fatalf("failed to insert initial blocks: %v", err) } - if head := chain.CurrentBlock().NumberU64(); head != 2 { + if head := chain.CurrentBlock().Number.Uint64(); head != 2 { t.Fatalf("chain head mismatch: have %d, want %d", head, 2) } @@ -106,7 +106,7 @@ func TestReimportMirroredState(t *testing.T) { if _, err := chain.InsertChain(blocks[2:]); err != nil { t.Fatalf("failed to insert final block: %v", err) } - if head := chain.CurrentBlock().NumberU64(); head != 3 { + if head := chain.CurrentBlock().Number.Uint64(); head != 3 { t.Fatalf("chain head mismatch: have %d, want %d", head, 3) } } diff --git a/core/blockchain.go b/core/blockchain.go index 38a129d4eec5..f63ac845c1f2 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -199,10 +199,10 @@ type BlockChain struct { // Readers don't need to take it, they can just read the database. chainmu *syncx.ClosableMutex - currentBlock atomic.Value // Current head of the block chain - currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!) - currentFinalizedBlock atomic.Value // Current finalized head - currentSafeBlock atomic.Value // Current safe head + currentBlock atomic.Pointer[types.Header] // Current head of the chain + currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync + currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block + currentSafeBlock atomic.Pointer[types.Header] // Latest (consensus) safe block bodyCache *lru.Cache[common.Hash, *types.Body] bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] @@ -289,11 +289,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis return nil, ErrNoGenesis } - var nilBlock *types.Block - bc.currentBlock.Store(nilBlock) - bc.currentFastBlock.Store(nilBlock) - bc.currentFinalizedBlock.Store(nilBlock) - bc.currentSafeBlock.Store(nilBlock) + bc.currentBlock.Store(nil) + bc.currentSnapBlock.Store(nil) + bc.currentFinalBlock.Store(nil) + bc.currentSafeBlock.Store(nil) // If Geth is initialized with an external ancient store, re-initialize the // missing chain indexes and chain flags. This procedure can survive crash @@ -307,7 +306,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } // Make sure the state associated with the block is available head := bc.CurrentBlock() - if !bc.HasState(head.Root()) { + if !bc.HasState(head.Root) { // Head state is missing, before the state recovery, find out the // disk layer point of snapshot(if it's enabled). Make sure the // rewound point is lower than disk layer. @@ -316,9 +315,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis diskRoot = rawdb.ReadSnapshotRoot(bc.db) } if diskRoot != (common.Hash{}) { - log.Warn("Head state missing, repairing", "number", head.Number(), "hash", head.Hash(), "snaproot", diskRoot) + log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "snaproot", diskRoot) - snapDisk, err := bc.setHeadBeyondRoot(head.NumberU64(), 0, diskRoot, true) + snapDisk, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, diskRoot, true) if err != nil { return nil, err } @@ -327,13 +326,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis rawdb.WriteSnapshotRecoveryNumber(bc.db, snapDisk) } } else { - log.Warn("Head state missing, repairing", "number", head.Number(), "hash", head.Hash()) - if _, err := bc.setHeadBeyondRoot(head.NumberU64(), 0, common.Hash{}, true); err != nil { + log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash()) + if _, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, common.Hash{}, true); err != nil { return nil, err } } } - // Ensure that a previous crash in SetHead doesn't leave extra ancients if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 { var ( @@ -344,18 +342,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // blockchain repair. If the head full block is even lower than the ancient // chain, truncate the ancient store. fullBlock := bc.CurrentBlock() - if fullBlock != nil && fullBlock.Hash() != bc.genesisBlock.Hash() && fullBlock.NumberU64() < frozen-1 { + if fullBlock != nil && fullBlock.Hash() != bc.genesisBlock.Hash() && fullBlock.Number.Uint64() < frozen-1 { needRewind = true - low = fullBlock.NumberU64() + low = fullBlock.Number.Uint64() } // In fast sync, it may happen that ancient data has been written to the // ancient store, but the LastFastBlock has not been updated, truncate the // extra data here. - fastBlock := bc.CurrentFastBlock() - if fastBlock != nil && fastBlock.NumberU64() < frozen-1 { + snapBlock := bc.CurrentSnapBlock() + if snapBlock != nil && snapBlock.Number.Uint64() < frozen-1 { needRewind = true - if fastBlock.NumberU64() < low || low == 0 { - low = fastBlock.NumberU64() + if snapBlock.Number.Uint64() < low || low == 0 { + low = snapBlock.Number.Uint64() } } if needRewind { @@ -395,8 +393,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis var recover bool head := bc.CurrentBlock() - if layer := rawdb.ReadSnapshotRecoveryNumber(bc.db); layer != nil && *layer >= head.NumberU64() { - log.Warn("Enabling snapshot recovery", "chainhead", head.NumberU64(), "diskbase", *layer) + if layer := rawdb.ReadSnapshotRecoveryNumber(bc.db); layer != nil && *layer >= head.Number.Uint64() { + log.Warn("Enabling snapshot recovery", "chainhead", head.Number, "diskbase", *layer) recover = true } snapconfig := snapshot.Config{ @@ -405,7 +403,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis NoBuild: bc.cacheConfig.SnapshotNoBuild, AsyncBuild: !bc.cacheConfig.SnapshotWait, } - bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root()) + bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root) } // Start future block processor. @@ -469,32 +467,32 @@ func (bc *BlockChain) loadLastState() error { return bc.Reset() } // Make sure the entire head block is available - currentBlock := bc.GetBlockByHash(head) - if currentBlock == nil { + headBlock := bc.GetBlockByHash(head) + if headBlock == nil { // Corrupt or empty database, init from scratch log.Warn("Head block missing, resetting chain", "hash", head) return bc.Reset() } // Everything seems to be fine, set as the head block - bc.currentBlock.Store(currentBlock) - headBlockGauge.Update(int64(currentBlock.NumberU64())) + bc.currentBlock.Store(headBlock.Header()) + headBlockGauge.Update(int64(headBlock.NumberU64())) // Restore the last known head header - currentHeader := currentBlock.Header() + headHeader := headBlock.Header() if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) { if header := bc.GetHeaderByHash(head); header != nil { - currentHeader = header + headHeader = header } } - bc.hc.SetCurrentHeader(currentHeader) + bc.hc.SetCurrentHeader(headHeader) // Restore the last known head fast block - bc.currentFastBlock.Store(currentBlock) - headFastBlockGauge.Update(int64(currentBlock.NumberU64())) + bc.currentSnapBlock.Store(headBlock.Header()) + headFastBlockGauge.Update(int64(headBlock.NumberU64())) if head := rawdb.ReadHeadFastBlockHash(bc.db); head != (common.Hash{}) { if block := bc.GetBlockByHash(head); block != nil { - bc.currentFastBlock.Store(block) + bc.currentSnapBlock.Store(block.Header()) headFastBlockGauge.Update(int64(block.NumberU64())) } } @@ -504,27 +502,31 @@ func (bc *BlockChain) loadLastState() error { // known finalized block on startup if head := rawdb.ReadFinalizedBlockHash(bc.db); head != (common.Hash{}) { if block := bc.GetBlockByHash(head); block != nil { - bc.currentFinalizedBlock.Store(block) + bc.currentFinalBlock.Store(block.Header()) headFinalizedBlockGauge.Update(int64(block.NumberU64())) - bc.currentSafeBlock.Store(block) + bc.currentSafeBlock.Store(block.Header()) headSafeBlockGauge.Update(int64(block.NumberU64())) } } // Issue a status log for the user - currentFastBlock := bc.CurrentFastBlock() - currentFinalizedBlock := bc.CurrentFinalizedBlock() - - headerTd := bc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()) - blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) - fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64()) - - log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(currentHeader.Time), 0))) - log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(currentBlock.Time()), 0))) - log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd, "age", common.PrettyAge(time.Unix(int64(currentFastBlock.Time()), 0))) + var ( + currentSnapBlock = bc.CurrentSnapBlock() + currentFinalBlock = bc.CurrentFinalBlock() - if currentFinalizedBlock != nil { - finalTd := bc.GetTd(currentFinalizedBlock.Hash(), currentFinalizedBlock.NumberU64()) - log.Info("Loaded most recent local finalized block", "number", currentFinalizedBlock.Number(), "hash", currentFinalizedBlock.Hash(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalizedBlock.Time()), 0))) + headerTd = bc.GetTd(headHeader.Hash(), headHeader.Number.Uint64()) + blockTd = bc.GetTd(headBlock.Hash(), headBlock.NumberU64()) + ) + if headHeader.Hash() != headBlock.Hash() { + log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0))) + } + log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0))) + if headBlock.Hash() != currentSnapBlock.Hash() { + fastTd := bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64()) + log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "td", fastTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0))) + } + if currentFinalBlock != nil { + finalTd := bc.GetTd(currentFinalBlock.Hash(), currentFinalBlock.Number.Uint64()) + log.Info("Loaded most recent local finalized block", "number", currentFinalBlock.Number, "hash", currentFinalBlock.Hash(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalBlock.Time), 0))) } if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil { log.Info("Loaded last fast-sync pivot marker", "number", *pivot) @@ -540,7 +542,16 @@ func (bc *BlockChain) SetHead(head uint64) error { return err } // Send chain head event to update the transaction pool - bc.chainHeadFeed.Send(ChainHeadEvent{Block: bc.CurrentBlock()}) + header := bc.CurrentBlock() + block := bc.GetBlock(header.Hash(), header.Number.Uint64()) + if block == nil { + // This should never happen. In practice, previsouly currentBlock + // contained the entire block whereas now only a "marker", so there + // is an ever so slight chance for a race we should handle. + log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash()) + return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4]) + } + bc.chainHeadFeed.Send(ChainHeadEvent{Block: block}) return nil } @@ -553,16 +564,25 @@ func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error { return err } // Send chain head event to update the transaction pool - bc.chainHeadFeed.Send(ChainHeadEvent{Block: bc.CurrentBlock()}) + header := bc.CurrentBlock() + block := bc.GetBlock(header.Hash(), header.Number.Uint64()) + if block == nil { + // This should never happen. In practice, previsouly currentBlock + // contained the entire block whereas now only a "marker", so there + // is an ever so slight chance for a race we should handle. + log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash()) + return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4]) + } + bc.chainHeadFeed.Send(ChainHeadEvent{Block: block}) return nil } // SetFinalized sets the finalized block. -func (bc *BlockChain) SetFinalized(block *types.Block) { - bc.currentFinalizedBlock.Store(block) - if block != nil { - rawdb.WriteFinalizedBlockHash(bc.db, block.Hash()) - headFinalizedBlockGauge.Update(int64(block.NumberU64())) +func (bc *BlockChain) SetFinalized(header *types.Header) { + bc.currentFinalBlock.Store(header) + if header != nil { + rawdb.WriteFinalizedBlockHash(bc.db, header.Hash()) + headFinalizedBlockGauge.Update(int64(header.Number.Uint64())) } else { rawdb.WriteFinalizedBlockHash(bc.db, common.Hash{}) headFinalizedBlockGauge.Update(0) @@ -570,10 +590,10 @@ func (bc *BlockChain) SetFinalized(block *types.Block) { } // SetSafe sets the safe block. -func (bc *BlockChain) SetSafe(block *types.Block) { - bc.currentSafeBlock.Store(block) - if block != nil { - headSafeBlockGauge.Update(int64(block.NumberU64())) +func (bc *BlockChain) SetSafe(header *types.Header) { + bc.currentSafeBlock.Store(header) + if header != nil { + headSafeBlockGauge.Update(int64(header.Number.Uint64())) } else { headSafeBlockGauge.Update(0) } @@ -609,7 +629,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha // Rewind the blockchain, ensuring we don't end up with a stateless head // block. Note, depth equality is permitted to allow using SetHead as a // chain reparation mechanism without deleting any data! - if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.NumberU64() { + if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.Number.Uint64() { newHeadBlock := bc.GetBlock(header.Hash(), header.Number.Uint64()) if newHeadBlock == nil { log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash()) @@ -667,27 +687,27 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha // In theory we should update all in-memory markers in the // last step, however the direction of SetHead is from high // to low, so it's safe to update in-memory markers directly. - bc.currentBlock.Store(newHeadBlock) + bc.currentBlock.Store(newHeadBlock.Header()) headBlockGauge.Update(int64(newHeadBlock.NumberU64())) } // Rewind the fast block in a simpleton way to the target head - if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock != nil && header.Number.Uint64() < currentFastBlock.NumberU64() { - newHeadFastBlock := bc.GetBlock(header.Hash(), header.Number.Uint64()) + if currentSnapBlock := bc.CurrentSnapBlock(); currentSnapBlock != nil && header.Number.Uint64() < currentSnapBlock.Number.Uint64() { + newHeadSnapBlock := bc.GetBlock(header.Hash(), header.Number.Uint64()) // If either blocks reached nil, reset to the genesis state - if newHeadFastBlock == nil { - newHeadFastBlock = bc.genesisBlock + if newHeadSnapBlock == nil { + newHeadSnapBlock = bc.genesisBlock } - rawdb.WriteHeadFastBlockHash(db, newHeadFastBlock.Hash()) + rawdb.WriteHeadFastBlockHash(db, newHeadSnapBlock.Hash()) // Degrade the chain markers if they are explicitly reverted. // In theory we should update all in-memory markers in the // last step, however the direction of SetHead is from high // to low, so it's safe the update in-memory markers directly. - bc.currentFastBlock.Store(newHeadFastBlock) - headFastBlockGauge.Update(int64(newHeadFastBlock.NumberU64())) + bc.currentSnapBlock.Store(newHeadSnapBlock.Header()) + headFastBlockGauge.Update(int64(newHeadSnapBlock.NumberU64())) } var ( - headHeader = bc.CurrentBlock().Header() + headHeader = bc.CurrentBlock() headNumber = headHeader.Number.Uint64() ) // If setHead underflown the freezer threshold and the block processing @@ -723,7 +743,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha // If SetHead was only called as a chain reparation method, try to skip // touching the header chain altogether, unless the freezer is broken if repair { - if target, force := updateFn(bc.db, bc.CurrentBlock().Header()); force { + if target, force := updateFn(bc.db, bc.CurrentBlock()); force { bc.hc.SetHead(target.Number.Uint64(), updateFn, delFn) } } else { @@ -746,15 +766,14 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha bc.futureBlocks.Purge() // Clear safe block, finalized block if needed - if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.NumberU64() { + if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.Number.Uint64() { log.Warn("SetHead invalidated safe block") bc.SetSafe(nil) } - if finalized := bc.CurrentFinalizedBlock(); finalized != nil && head < finalized.NumberU64() { + if finalized := bc.CurrentFinalBlock(); finalized != nil && head < finalized.Number.Uint64() { log.Error("SetHead invalidated finalized block") bc.SetFinalized(nil) } - return rootNumber, bc.loadLastState() } @@ -774,7 +793,7 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error { if !bc.chainmu.TryLock() { return errChainStopped } - bc.currentBlock.Store(block) + bc.currentBlock.Store(block.Header()) headBlockGauge.Update(int64(block.NumberU64())) bc.chainmu.Unlock() @@ -815,18 +834,18 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error { // Last update all in-memory chain markers bc.genesisBlock = genesis - bc.currentBlock.Store(bc.genesisBlock) + bc.currentBlock.Store(bc.genesisBlock.Header()) headBlockGauge.Update(int64(bc.genesisBlock.NumberU64())) bc.hc.SetGenesis(bc.genesisBlock.Header()) bc.hc.SetCurrentHeader(bc.genesisBlock.Header()) - bc.currentFastBlock.Store(bc.genesisBlock) + bc.currentSnapBlock.Store(bc.genesisBlock.Header()) headFastBlockGauge.Update(int64(bc.genesisBlock.NumberU64())) return nil } // Export writes the active chain to the given writer. func (bc *BlockChain) Export(w io.Writer) error { - return bc.ExportN(w, uint64(0), bc.CurrentBlock().NumberU64()) + return bc.ExportN(w, uint64(0), bc.CurrentBlock().Number.Uint64()) } // ExportN writes a subset of the active chain to the given writer. @@ -883,10 +902,10 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) { // Update all in-memory chain markers in the last step bc.hc.SetCurrentHeader(block.Header()) - bc.currentFastBlock.Store(block) + bc.currentSnapBlock.Store(block.Header()) headFastBlockGauge.Update(int64(block.NumberU64())) - bc.currentBlock.Store(block) + bc.currentBlock.Store(block.Header()) headBlockGauge.Update(int64(block.NumberU64())) } @@ -927,7 +946,7 @@ func (bc *BlockChain) Stop() { var snapBase common.Hash if bc.snaps != nil { var err error - if snapBase, err = bc.snaps.Journal(bc.CurrentBlock().Root()); err != nil { + if snapBase, err = bc.snaps.Journal(bc.CurrentBlock().Root); err != nil { log.Error("Failed to journal state snapshot", "err", err) } } @@ -941,7 +960,7 @@ func (bc *BlockChain) Stop() { triedb := bc.triedb for _, offset := range []uint64{0, 1, TriesInMemory - 1} { - if number := bc.CurrentBlock().NumberU64(); number > offset { + if number := bc.CurrentBlock().Number.Uint64(); number > offset { recent := bc.GetBlockByNumber(number - offset) log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) @@ -1059,7 +1078,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ // Rewind may have occurred, skip in that case. if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 { - reorg, err := bc.forker.ReorgNeeded(bc.CurrentFastBlock().Header(), head.Header()) + reorg, err := bc.forker.ReorgNeeded(bc.CurrentSnapBlock(), head.Header()) if err != nil { log.Warn("Reorg failed", "err", err) return false @@ -1067,13 +1086,12 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ return false } rawdb.WriteHeadFastBlockHash(bc.db, head.Hash()) - bc.currentFastBlock.Store(head) + bc.currentSnapBlock.Store(head.Header()) headFastBlockGauge.Update(int64(head.NumberU64())) return true } return false } - // writeAncient writes blockchain and corresponding receipt chain into ancient store. // // this function only accepts canonical chain data. All side chain will be reverted @@ -1135,8 +1153,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ if batch.ValueSize() > ethdb.IdealBatchSize || i == len(blockChain)-1 { size += int64(batch.ValueSize()) if err = batch.Write(); err != nil { - fastBlock := bc.CurrentFastBlock().NumberU64() - if err := bc.db.TruncateHead(fastBlock + 1); err != nil { + snapBlock := bc.CurrentSnapBlock().Number.Uint64() + if err := bc.db.TruncateHead(snapBlock + 1); err != nil { log.Error("Can't truncate ancient store after failed insert", "err", err) } return 0, err @@ -1150,11 +1168,11 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ return 0, err } // Update the current fast block because all block data is now present in DB. - previousFastBlock := bc.CurrentFastBlock().NumberU64() + previousSnapBlock := bc.CurrentSnapBlock().Number.Uint64() if !updateHead(blockChain[len(blockChain)-1]) { // We end up here if the header chain has reorg'ed, and the blocks/receipts // don't match the canonical chain. - if err := bc.db.TruncateHead(previousFastBlock + 1); err != nil { + if err := bc.db.TruncateHead(previousSnapBlock + 1); err != nil { log.Error("Can't truncate ancient store after failed insert", "err", err) } return 0, errSideChainReceipts @@ -1414,7 +1432,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types return NonStatTy, err } currentBlock := bc.CurrentBlock() - reorg, err := bc.forker.ReorgNeeded(currentBlock.Header(), block.Header()) + reorg, err := bc.forker.ReorgNeeded(currentBlock, block.Header()) if err != nil { return NonStatTy, err } @@ -1562,7 +1580,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) current = bc.CurrentBlock() ) for block != nil && bc.skipBlock(err, it) { - reorg, err = bc.forker.ReorgNeeded(current.Header(), block.Header()) + reorg, err = bc.forker.ReorgNeeded(current, block.Header()) if err != nil { return it.index, err } @@ -1572,7 +1590,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // In eth2 the forker always returns true for reorg decision (blindly trusting // the external consensus engine), but in order to prevent the unnecessary // reorgs when importing known blocks, the special case is handled here. - if block.NumberU64() > current.NumberU64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() { + if block.NumberU64() > current.Number.Uint64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() { break } } @@ -1872,7 +1890,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i err := consensus.ErrPrunedAncestor for ; block != nil && errors.Is(err, consensus.ErrPrunedAncestor); block, err = it.next() { // Check the canonical state root for that number - if number := block.NumberU64(); current.NumberU64() >= number { + if number := block.NumberU64(); current.Number.Uint64() >= number { canonical := bc.GetBlockByNumber(number) if canonical != nil && canonical.Hash() == block.Hash() { // Not a sidechain block, this is a re-import of a canon block which has it's state pruned @@ -1922,12 +1940,12 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i // // If the externTd was larger than our local TD, we now need to reimport the previous // blocks to regenerate the required state - reorg, err := bc.forker.ReorgNeeded(current.Header(), lastBlock.Header()) + reorg, err := bc.forker.ReorgNeeded(current, lastBlock.Header()) if err != nil { return it.index, err } if !reorg { - localTd := bc.GetTd(current.Hash(), current.NumberU64()) + localTd := bc.GetTd(current.Hash(), current.Number.Uint64()) log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd) return it.index, err } @@ -2051,7 +2069,7 @@ func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { // potential missing transactions and post an event about them. // Note the new head block won't be processed here, callers need to handle it // externally. -func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { +func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { var ( newChain types.Blocks oldChain types.Blocks @@ -2060,6 +2078,12 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { deletedTxs []common.Hash addedTxs []common.Hash ) + oldBlock := bc.GetBlock(oldHead.Hash(), oldHead.Number.Uint64()) + if oldBlock == nil { + return errors.New("current head block missing") + } + newBlock := newHead + // Reduce the longer chain to the same number as the shorter one if oldBlock.NumberU64() > newBlock.NumberU64() { // Old chain is longer, gather all transactions and logs as deleted ones @@ -2076,10 +2100,10 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } } if oldBlock == nil { - return fmt.Errorf("invalid old chain") + return errors.New("invalid old chain") } if newBlock == nil { - return fmt.Errorf("invalid new chain") + return errors.New("invalid new chain") } // Both sides of the reorg are at the same number, reduce both until the common // ancestor is found diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index e8a5d952a240..21a9c6676bd5 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -40,26 +40,26 @@ func (bc *BlockChain) CurrentHeader() *types.Header { // CurrentBlock retrieves the current head block of the canonical chain. The // block is retrieved from the blockchain's internal cache. -func (bc *BlockChain) CurrentBlock() *types.Block { - return bc.currentBlock.Load().(*types.Block) +func (bc *BlockChain) CurrentBlock() *types.Header { + return bc.currentBlock.Load() } -// CurrentFastBlock retrieves the current fast-sync head block of the canonical +// CurrentSnapBlock retrieves the current snap-sync head block of the canonical // chain. The block is retrieved from the blockchain's internal cache. -func (bc *BlockChain) CurrentFastBlock() *types.Block { - return bc.currentFastBlock.Load().(*types.Block) +func (bc *BlockChain) CurrentSnapBlock() *types.Header { + return bc.currentSnapBlock.Load() } -// CurrentFinalizedBlock retrieves the current finalized block of the canonical +// CurrentFinalBlock retrieves the current finalized block of the canonical // chain. The block is retrieved from the blockchain's internal cache. -func (bc *BlockChain) CurrentFinalizedBlock() *types.Block { - return bc.currentFinalizedBlock.Load().(*types.Block) +func (bc *BlockChain) CurrentFinalBlock() *types.Header { + return bc.currentFinalBlock.Load() } // CurrentSafeBlock retrieves the current safe block of the canonical // chain. The block is retrieved from the blockchain's internal cache. -func (bc *BlockChain) CurrentSafeBlock() *types.Block { - return bc.currentSafeBlock.Load().(*types.Block) +func (bc *BlockChain) CurrentSafeBlock() *types.Header { + return bc.currentSafeBlock.Load() } // HasHeader checks if a block header is present in the database or not, caching @@ -315,7 +315,7 @@ func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) { // State returns a new mutable state based on the current HEAD block. func (bc *BlockChain) State() (*state.StateDB, error) { - return bc.StateAt(bc.CurrentBlock().Root()) + return bc.StateAt(bc.CurrentBlock().Root) } // StateAt returns a new mutable state based on a particular point in time. @@ -351,7 +351,7 @@ func (bc *BlockChain) StateCache() state.Database { // GasLimit returns the gas limit of the current HEAD block. func (bc *BlockChain) GasLimit() uint64 { - return bc.CurrentBlock().GasLimit() + return bc.CurrentBlock().GasLimit } // Genesis retrieves the chain's genesis block. diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 5db0fb5703d3..6a4a9c9d22bd 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -1857,11 +1857,11 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { if head := newChain.CurrentHeader(); head.Number.Uint64() != tt.expHeadHeader { t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader) } - if head := newChain.CurrentFastBlock(); head.NumberU64() != tt.expHeadFastBlock { - t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadFastBlock) + if head := newChain.CurrentSnapBlock(); head.Number.Uint64() != tt.expHeadFastBlock { + t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, tt.expHeadFastBlock) } - if head := newChain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock { - t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock) + if head := newChain.CurrentBlock(); head.Number.Uint64() != tt.expHeadBlock { + t.Errorf("Head block mismatch: have %d, want %d", head.Number, tt.expHeadBlock) } if frozen, err := db.(freezer).Ancients(); err != nil { t.Errorf("Failed to retrieve ancient count: %v\n", err) @@ -1973,11 +1973,11 @@ func TestIssue23496(t *testing.T) { if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) { t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4) } - if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) { - t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), uint64(4)) + if head := chain.CurrentSnapBlock(); head.Number.Uint64() != uint64(4) { + t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, uint64(4)) } - if head := chain.CurrentBlock(); head.NumberU64() != uint64(1) { - t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(1)) + if head := chain.CurrentBlock(); head.Number.Uint64() != uint64(1) { + t.Errorf("Head block mismatch: have %d, want %d", head.Number, uint64(1)) } // Reinsert B2-B4 @@ -1987,11 +1987,11 @@ func TestIssue23496(t *testing.T) { if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) { t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4) } - if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) { - t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), uint64(4)) + if head := chain.CurrentSnapBlock(); head.Number.Uint64() != uint64(4) { + t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, uint64(4)) } - if head := chain.CurrentBlock(); head.NumberU64() != uint64(4) { - t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(4)) + if head := chain.CurrentBlock(); head.Number.Uint64() != uint64(4) { + t.Errorf("Head block mismatch: have %d, want %d", head.Number, uint64(4)) } if layer := chain.Snapshots().Snapshot(blocks[2].Root()); layer == nil { t.Error("Failed to regenerate the snapshot of known state") diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index 825a0e16b430..9dc350db849e 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -2047,11 +2047,11 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { if head := chain.CurrentHeader(); head.Number.Uint64() != tt.expHeadHeader { t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader) } - if head := chain.CurrentFastBlock(); head.NumberU64() != tt.expHeadFastBlock { - t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadFastBlock) + if head := chain.CurrentSnapBlock(); head.Number.Uint64() != tt.expHeadFastBlock { + t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, tt.expHeadFastBlock) } - if head := chain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock { - t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock) + if head := chain.CurrentBlock(); head.Number.Uint64() != tt.expHeadBlock { + t.Errorf("Head block mismatch: have %d, want %d", head.Number, tt.expHeadBlock) } if frozen, err := db.(freezer).Ancients(); err != nil { t.Errorf("Failed to retrieve ancient count: %v\n", err) diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index b34ea573c1ae..3bd876a58ec7 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -136,11 +136,11 @@ func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks [ if head := chain.CurrentHeader(); head.Number.Uint64() != basic.expHeadHeader { t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader) } - if head := chain.CurrentFastBlock(); head.NumberU64() != basic.expHeadFastBlock { - t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadFastBlock) + if head := chain.CurrentSnapBlock(); head.Number.Uint64() != basic.expHeadFastBlock { + t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, basic.expHeadFastBlock) } - if head := chain.CurrentBlock(); head.NumberU64() != basic.expHeadBlock { - t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadBlock) + if head := chain.CurrentBlock(); head.Number.Uint64() != basic.expHeadBlock { + t.Errorf("Head block mismatch: have %d, want %d", head.Number, basic.expHeadBlock) } // Check the disk layer, ensure they are matched diff --git a/core/blockchain_test.go b/core/blockchain_test.go index ae77d0b7f669..0f9ef6a1921a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -109,7 +109,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara headerChainB []*types.Header ) if full { - blockChainB = makeBlockChain(blockchain2.chainConfig, blockchain2.CurrentBlock(), n, ethash.NewFaker(), genDb, forkSeed) + blockChainB = makeBlockChain(blockchain2.chainConfig, blockchain2.GetBlockByHash(blockchain2.CurrentBlock().Hash()), n, ethash.NewFaker(), genDb, forkSeed) if _, err := blockchain2.InsertChain(blockChainB); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } @@ -124,7 +124,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara if full { cur := blockchain.CurrentBlock() - tdPre = blockchain.GetTd(cur.Hash(), cur.NumberU64()) + tdPre = blockchain.GetTd(cur.Hash(), cur.Number.Uint64()) if err := testBlockChainImport(blockChainB, blockchain); err != nil { t.Fatalf("failed to import forked block chain: %v", err) } @@ -206,7 +206,7 @@ func TestLastBlock(t *testing.T) { } defer blockchain.Stop() - blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 1, ethash.NewFullFaker(), genDb, 0) + blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 1, ethash.NewFullFaker(), genDb, 0) if _, err := blockchain.InsertChain(blocks); err != nil { t.Fatalf("Failed to insert block: %v", err) } @@ -240,11 +240,11 @@ func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full b // Extend the newly created chain if full { - blockChainB := makeBlockChain(blockchain2.chainConfig, blockchain2.CurrentBlock(), n, ethash.NewFaker(), genDb, forkSeed) + blockChainB := makeBlockChain(blockchain2.chainConfig, blockchain2.GetBlockByHash(blockchain2.CurrentBlock().Hash()), n, ethash.NewFaker(), genDb, forkSeed) if _, err := blockchain2.InsertChain(blockChainB); err != nil { t.Fatalf("failed to insert forking chain: %v", err) } - if blockchain2.CurrentBlock().NumberU64() != blockChainB[len(blockChainB)-1].NumberU64() { + if blockchain2.CurrentBlock().Number.Uint64() != blockChainB[len(blockChainB)-1].NumberU64() { t.Fatalf("failed to reorg to the given chain") } if blockchain2.CurrentBlock().Hash() != blockChainB[len(blockChainB)-1].Hash() { @@ -477,7 +477,7 @@ func testBrokenChain(t *testing.T, full bool) { // Create a forked chain, and try to insert with a missing link if full { - chain := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 5, ethash.NewFaker(), genDb, forkSeed)[1:] + chain := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 5, ethash.NewFaker(), genDb, forkSeed)[1:] if err := testBlockChainImport(chain, blockchain); err == nil { t.Errorf("broken block chain not reported") } @@ -527,10 +527,10 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) { defer blockchain.Stop() // Insert an easy and a difficult chain afterwards - easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), genDb, len(first), func(i int, b *BlockGen) { + easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), ethash.NewFaker(), genDb, len(first), func(i int, b *BlockGen) { b.OffsetTime(first[i]) }) - diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), genDb, len(second), func(i int, b *BlockGen) { + diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), ethash.NewFaker(), genDb, len(second), func(i int, b *BlockGen) { b.OffsetTime(second[i]) }) if full { @@ -559,9 +559,9 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) { // Check that the chain is valid number and link wise if full { prev := blockchain.CurrentBlock() - for block := blockchain.GetBlockByNumber(blockchain.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, blockchain.GetBlockByNumber(block.NumberU64()-1) { - if prev.ParentHash() != block.Hash() { - t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash(), block.Hash()) + for block := blockchain.GetBlockByNumber(blockchain.CurrentBlock().Number.Uint64() - 1); block.NumberU64() != 0; prev, block = block.Header(), blockchain.GetBlockByNumber(block.NumberU64()-1) { + if prev.ParentHash != block.Hash() { + t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash, block.Hash()) } } } else { @@ -576,7 +576,7 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) { want := new(big.Int).Add(blockchain.genesisBlock.Difficulty(), big.NewInt(td)) if full { cur := blockchain.CurrentBlock() - if have := blockchain.GetTd(cur.Hash(), cur.NumberU64()); have.Cmp(want) != 0 { + if have := blockchain.GetTd(cur.Hash(), cur.Number.Uint64()); have.Cmp(want) != 0 { t.Errorf("total difficulty mismatch: have %v, want %v", have, want) } } else { @@ -601,7 +601,7 @@ func testBadHashes(t *testing.T, full bool) { // Create a chain, ban a hash and try to import if full { - blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 3, ethash.NewFaker(), genDb, 10) + blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 3, ethash.NewFaker(), genDb, 10) BadHashes[blocks[2].Header().Hash()] = true defer func() { delete(BadHashes, blocks[2].Header().Hash()) }() @@ -633,7 +633,7 @@ func testReorgBadHashes(t *testing.T, full bool) { } // Create a chain, import and ban afterwards headers := makeHeaderChain(blockchain.chainConfig, blockchain.CurrentHeader(), 4, ethash.NewFaker(), genDb, 10) - blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 4, ethash.NewFaker(), genDb, 10) + blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 4, ethash.NewFaker(), genDb, 10) if full { if _, err = blockchain.InsertChain(blocks); err != nil { @@ -696,7 +696,7 @@ func testInsertNonceError(t *testing.T, full bool) { failNum uint64 ) if full { - blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), i, ethash.NewFaker(), genDb, 0) + blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), i, ethash.NewFaker(), genDb, 0) failAt = rand.Int() % len(blocks) failNum = blocks[failAt].NumberU64() @@ -894,11 +894,11 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { assert := func(t *testing.T, kind string, chain *BlockChain, header uint64, fast uint64, block uint64) { t.Helper() - if num := chain.CurrentBlock().NumberU64(); num != block { + if num := chain.CurrentBlock().Number.Uint64(); num != block { t.Errorf("%s head block mismatch: have #%v, want #%v", kind, num, block) } - if num := chain.CurrentFastBlock().NumberU64(); num != fast { - t.Errorf("%s head fast-block mismatch: have #%v, want #%v", kind, num, fast) + if num := chain.CurrentSnapBlock().Number.Uint64(); num != fast { + t.Errorf("%s head snap-block mismatch: have #%v, want #%v", kind, num, fast) } if num := chain.CurrentHeader().Number.Uint64(); num != header { t.Errorf("%s head header mismatch: have #%v, want #%v", kind, num, header) @@ -1649,13 +1649,13 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { t.Fatalf("block %d: failed to insert into chain: %v", i, err) } if chain.CurrentBlock().Hash() != chain.CurrentHeader().Hash() { - t.Errorf("block %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number(), chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4]) + t.Errorf("block %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number, chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4]) } if _, err := chain.InsertChain(forks[i : i+1]); err != nil { t.Fatalf(" fork %d: failed to insert into chain: %v", i, err) } if chain.CurrentBlock().Hash() != chain.CurrentHeader().Hash() { - t.Errorf(" fork %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number(), chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4]) + t.Errorf(" fork %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number, chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4]) } } } @@ -1797,11 +1797,11 @@ func TestBlockchainRecovery(t *testing.T) { // Reopen broken blockchain again ancient, _ = NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() - if num := ancient.CurrentBlock().NumberU64(); num != 0 { + if num := ancient.CurrentBlock().Number.Uint64(); num != 0 { t.Errorf("head block mismatch: have #%v, want #%v", num, 0) } - if num := ancient.CurrentFastBlock().NumberU64(); num != midBlock.NumberU64() { - t.Errorf("head fast-block mismatch: have #%v, want #%v", num, midBlock.NumberU64()) + if num := ancient.CurrentSnapBlock().Number.Uint64(); num != midBlock.NumberU64() { + t.Errorf("head snap-block mismatch: have #%v, want #%v", num, midBlock.NumberU64()) } if num := ancient.CurrentHeader().Number.Uint64(); num != midBlock.NumberU64() { t.Errorf("head header mismatch: have #%v, want #%v", num, midBlock.NumberU64()) @@ -1820,7 +1820,7 @@ func TestInsertReceiptChainRollback(t *testing.T) { if _, err := tmpChain.InsertChain(sideblocks); err != nil { t.Fatal("processing side chain failed:", err) } - t.Log("sidechain head:", tmpChain.CurrentBlock().Number(), tmpChain.CurrentBlock().Hash()) + t.Log("sidechain head:", tmpChain.CurrentBlock().Number, tmpChain.CurrentBlock().Hash()) sidechainReceipts := make([]types.Receipts, len(sideblocks)) for i, block := range sideblocks { sidechainReceipts[i] = tmpChain.GetReceiptsByHash(block.Hash()) @@ -1829,7 +1829,7 @@ func TestInsertReceiptChainRollback(t *testing.T) { if _, err := tmpChain.InsertChain(canonblocks); err != nil { t.Fatal("processing canon chain failed:", err) } - t.Log("canon head:", tmpChain.CurrentBlock().Number(), tmpChain.CurrentBlock().Hash()) + t.Log("canon head:", tmpChain.CurrentBlock().Number, tmpChain.CurrentBlock().Hash()) canonReceipts := make([]types.Receipts, len(canonblocks)) for i, block := range canonblocks { canonReceipts[i] = tmpChain.GetReceiptsByHash(block.Hash()) @@ -1859,8 +1859,8 @@ func TestInsertReceiptChainRollback(t *testing.T) { if err == nil { t.Fatal("expected error from InsertReceiptChain.") } - if ancientChain.CurrentFastBlock().NumberU64() != 0 { - t.Fatalf("failed to rollback ancient data, want %d, have %d", 0, ancientChain.CurrentFastBlock().NumberU64()) + if ancientChain.CurrentSnapBlock().Number.Uint64() != 0 { + t.Fatalf("failed to rollback ancient data, want %d, have %d", 0, ancientChain.CurrentSnapBlock().Number) } if frozen, err := ancientChain.db.Ancients(); err != nil || frozen != 1 { t.Fatalf("failed to truncate ancient data, frozen index is %d", frozen) @@ -1871,7 +1871,7 @@ func TestInsertReceiptChainRollback(t *testing.T) { if err != nil { t.Fatalf("can't import canon chain receipts: %v", err) } - if ancientChain.CurrentFastBlock().NumberU64() != canonblocks[len(canonblocks)-1].NumberU64() { + if ancientChain.CurrentSnapBlock().Number.Uint64() != canonblocks[len(canonblocks)-1].NumberU64() { t.Fatalf("failed to insert ancient recept chain after rollback") } if frozen, _ := ancientChain.db.Ancients(); frozen != uint64(len(canonblocks))+1 { @@ -1926,7 +1926,7 @@ func TestLowDiffLongChain(t *testing.T) { } // Sanity check that all the canonical numbers are present header := chain.CurrentHeader() - for number := head.NumberU64(); number > 0; number-- { + for number := head.Number.Uint64(); number > 0; number-- { if hash := chain.GetHeaderByNumber(number).Hash(); hash != header.Hash() { t.Fatalf("header %d: canonical hash mismatch: have %x, want %x", number, hash, header.Hash()) } @@ -2150,8 +2150,8 @@ func testInsertKnownChainData(t *testing.T, typ string) { return err } asserter = func(t *testing.T, block *types.Block) { - if chain.CurrentFastBlock().Hash() != block.Hash() { - t.Fatalf("current head fast block mismatch, have %v, want %v", chain.CurrentFastBlock().Hash().Hex(), block.Hash().Hex()) + if chain.CurrentSnapBlock().Hash() != block.Hash() { + t.Fatalf("current head fast block mismatch, have %v, want %v", chain.CurrentSnapBlock().Hash().Hex(), block.Hash().Hex()) } } } else { @@ -2324,8 +2324,8 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i return err } asserter = func(t *testing.T, block *types.Block) { - if chain.CurrentFastBlock().Hash() != block.Hash() { - t.Fatalf("current head fast block mismatch, have %v, want %v", chain.CurrentFastBlock().Hash().Hex(), block.Hash().Hex()) + if chain.CurrentSnapBlock().Hash() != block.Hash() { + t.Fatalf("current head fast block mismatch, have %v, want %v", chain.CurrentSnapBlock().Hash().Hex(), block.Hash().Hex()) } } } else { @@ -2452,7 +2452,7 @@ func TestReorgToShorterRemovesCanonMapping(t *testing.T) { if n, err := chain.InsertChain(canonblocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } - canonNum := chain.CurrentBlock().NumberU64() + canonNum := chain.CurrentBlock().Number.Uint64() canonHash := chain.CurrentBlock().Hash() _, err = chain.InsertChain(sideblocks) if err != nil { @@ -2467,7 +2467,7 @@ func TestReorgToShorterRemovesCanonMapping(t *testing.T) { t.Errorf("expected block to be gone: %v", blockByNum.NumberU64()) } if headerByNum := chain.GetHeaderByNumber(canonNum); headerByNum != nil { - t.Errorf("expected header to be gone: %v", headerByNum.Number.Uint64()) + t.Errorf("expected header to be gone: %v", headerByNum.Number) } if blockByHash := chain.GetBlockByHash(canonHash); blockByHash == nil { t.Errorf("expected block to be present: %x", blockByHash.Hash()) @@ -2553,7 +2553,7 @@ func TestTransactionIndices(t *testing.T) { t.Fatalf("Oldest indexded block mismatch, want %d, have %d", *tail, *stored) } if tail != nil { - for i := *tail; i <= chain.CurrentBlock().NumberU64(); i++ { + for i := *tail; i <= chain.CurrentBlock().Number.Uint64(); i++ { block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i) if block.Transactions().Len() == 0 { continue @@ -2649,7 +2649,7 @@ func TestSkipStaleTxIndicesInSnapSync(t *testing.T) { t.Fatalf("Oldest indexded block mismatch, want %d, have %d", *tail, *stored) } if tail != nil { - for i := *tail; i <= chain.CurrentBlock().NumberU64(); i++ { + for i := *tail; i <= chain.CurrentBlock().Number.Uint64(); i++ { block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i) if block.Transactions().Len() == 0 { continue @@ -2752,7 +2752,8 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in b.Fatalf("failed to insert shared chain: %v", err) } b.StopTimer() - if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks { + block := chain.GetBlockByHash(chain.CurrentBlock().Hash()) + if got := block.Transactions().Len(); got != numTxs*numBlocks { b.Fatalf("Transactions were not included, expected %d, got %d", numTxs*numBlocks, got) } } @@ -3715,8 +3716,8 @@ func TestSetCanonical(t *testing.T) { if chain.CurrentBlock().Hash() != head.Hash() { t.Fatalf("Unexpected block hash, want %x, got %x", head.Hash(), chain.CurrentBlock().Hash()) } - if chain.CurrentFastBlock().Hash() != head.Hash() { - t.Fatalf("Unexpected fast block hash, want %x, got %x", head.Hash(), chain.CurrentFastBlock().Hash()) + if chain.CurrentSnapBlock().Hash() != head.Hash() { + t.Fatalf("Unexpected fast block hash, want %x, got %x", head.Hash(), chain.CurrentSnapBlock().Hash()) } if chain.CurrentHeader().Hash() != head.Hash() { t.Fatalf("Unexpected head header, want %x, got %x", head.Hash(), chain.CurrentHeader().Hash()) @@ -3799,8 +3800,8 @@ func TestCanonicalHashMarker(t *testing.T) { if chain.CurrentBlock().Hash() != head.Hash() { t.Fatalf("Unexpected block hash, want %x, got %x", head.Hash(), chain.CurrentBlock().Hash()) } - if chain.CurrentFastBlock().Hash() != head.Hash() { - t.Fatalf("Unexpected fast block hash, want %x, got %x", head.Hash(), chain.CurrentFastBlock().Hash()) + if chain.CurrentSnapBlock().Hash() != head.Hash() { + t.Fatalf("Unexpected fast block hash, want %x, got %x", head.Hash(), chain.CurrentSnapBlock().Hash()) } if chain.CurrentHeader().Hash() != head.Hash() { t.Fatalf("Unexpected head header, want %x, got %x", head.Hash(), chain.CurrentHeader().Hash()) diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 7e895a8d2057..6c4e0914362e 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -197,7 +197,7 @@ func ExampleGenerateChain() { } state, _ := blockchain.State() - fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number()) + fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number) fmt.Println("balance of addr1:", state.GetBalance(addr1)) fmt.Println("balance of addr2:", state.GetBalance(addr2)) fmt.Println("balance of addr3:", state.GetBalance(addr3)) diff --git a/core/dao_test.go b/core/dao_test.go index 4ae86b50ff1f..f2e8dfe8f9aa 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -76,7 +76,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a pro-fork block, and try to feed into the no-fork chain bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) + blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j] } @@ -87,19 +87,19 @@ func TestDAOForkRangeExtradata(t *testing.T) { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } bc.Stop() - blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&proConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err == nil { t.Fatalf("contra-fork chain accepted pro-fork block: %v", blocks[0]) } // Create a proper no-fork block for the contra-forker - blocks, _ = GenerateChain(&conConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&conConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err != nil { t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err) } // Create a no-fork block, and try to feed into the pro-fork chain bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) - blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) + blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j] } @@ -110,12 +110,12 @@ func TestDAOForkRangeExtradata(t *testing.T) { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } bc.Stop() - blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&conConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err == nil { t.Fatalf("pro-fork chain accepted contra-fork block: %v", blocks[0]) } // Create a proper pro-fork block for the pro-forker - blocks, _ = GenerateChain(&proConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&proConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err != nil { t.Fatalf("pro-fork chain didn't accepted pro-fork block: %v", err) } @@ -124,7 +124,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer bc.Stop() - blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) + blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j] } @@ -134,7 +134,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } - blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&proConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := conBc.InsertChain(blocks); err != nil { t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err) } @@ -142,7 +142,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer bc.Stop() - blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) + blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j] } @@ -152,7 +152,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } - blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) + blocks, _ = GenerateChain(&conConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) if _, err := proBc.InsertChain(blocks); err != nil { t.Fatalf("pro-fork chain didn't accept contra-fork block post-fork: %v", err) } diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index c80520186627..762210b7b74a 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -145,7 +145,7 @@ const ( // blockChain provides the state of blockchain and current gas limit to do // some pre checks in tx pool and event subscribers. type blockChain interface { - CurrentBlock() *types.Block + CurrentBlock() *types.Header GetBlock(hash common.Hash, number uint64) *types.Block StateAt(root common.Hash) (*state.StateDB, error) @@ -309,7 +309,7 @@ func NewTxPool(config Config, chainconfig *params.ChainConfig, chain blockChain) pool.locals.add(addr) } pool.priced = newPricedList(pool.all) - pool.reset(nil, chain.CurrentBlock().Header()) + pool.reset(nil, chain.CurrentBlock()) // Start the reorg loop early so it can handle requests generated during journal loading. pool.wg.Add(1) @@ -361,8 +361,8 @@ func (pool *TxPool) loop() { // Handle ChainHeadEvent case ev := <-pool.chainHeadCh: if ev.Block != nil { - pool.requestReset(head.Header(), ev.Block.Header()) - head = ev.Block + pool.requestReset(head, ev.Block.Header()) + head = ev.Block.Header() } // System shutdown. @@ -1291,7 +1291,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { } // Initialize the internal state to the current head if newHead == nil { - newHead = pool.chain.CurrentBlock().Header() // Special case during testing + newHead = pool.chain.CurrentBlock() // Special case during testing } statedb, err := pool.chain.StateAt(newHead.Root) if err != nil { diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index bd82622f8de6..237f97afe434 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -64,14 +64,15 @@ type testBlockChain struct { chainHeadFeed *event.Feed } -func (bc *testBlockChain) CurrentBlock() *types.Block { - return types.NewBlock(&types.Header{ +func (bc *testBlockChain) CurrentBlock() *types.Header { + return &types.Header{ + Number: new(big.Int), GasLimit: atomic.LoadUint64(&bc.gasLimit), - }, nil, nil, nil, trie.NewStackTrie(nil)) + } } func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { - return bc.CurrentBlock() + return types.NewBlock(bc.CurrentBlock(), nil, nil, nil, trie.NewStackTrie(nil)) } func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { diff --git a/eth/api.go b/eth/api.go index ceed85ef576b..cd6510ccf9a2 100644 --- a/eth/api.go +++ b/eth/api.go @@ -267,20 +267,24 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) { _, stateDb := api.eth.miner.Pending() return stateDb.RawDump(opts), nil } - var block *types.Block + var header *types.Header if blockNr == rpc.LatestBlockNumber { - block = api.eth.blockchain.CurrentBlock() + header = api.eth.blockchain.CurrentBlock() } else if blockNr == rpc.FinalizedBlockNumber { - block = api.eth.blockchain.CurrentFinalizedBlock() + header = api.eth.blockchain.CurrentFinalBlock() } else if blockNr == rpc.SafeBlockNumber { - block = api.eth.blockchain.CurrentSafeBlock() + header = api.eth.blockchain.CurrentSafeBlock() } else { - block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr)) + block := api.eth.blockchain.GetBlockByNumber(uint64(blockNr)) + if block == nil { + return state.Dump{}, fmt.Errorf("block #%d not found", blockNr) + } + header = block.Header() } - if block == nil { + if header == nil { return state.Dump{}, fmt.Errorf("block #%d not found", blockNr) } - stateDb, err := api.eth.BlockChain().StateAt(block.Root()) + stateDb, err := api.eth.BlockChain().StateAt(header.Root) if err != nil { return state.Dump{}, err } @@ -347,20 +351,24 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex // the miner and operate on those _, stateDb = api.eth.miner.Pending() } else { - var block *types.Block + var header *types.Header if number == rpc.LatestBlockNumber { - block = api.eth.blockchain.CurrentBlock() + header = api.eth.blockchain.CurrentBlock() } else if number == rpc.FinalizedBlockNumber { - block = api.eth.blockchain.CurrentFinalizedBlock() + header = api.eth.blockchain.CurrentFinalBlock() } else if number == rpc.SafeBlockNumber { - block = api.eth.blockchain.CurrentSafeBlock() + header = api.eth.blockchain.CurrentSafeBlock() } else { - block = api.eth.blockchain.GetBlockByNumber(uint64(number)) + block := api.eth.blockchain.GetBlockByNumber(uint64(number)) + if block == nil { + return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) + } + header = block.Header() } - if block == nil { + if header == nil { return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) } - stateDb, err = api.eth.BlockChain().StateAt(block.Root()) + stateDb, err = api.eth.BlockChain().StateAt(header.Root) if err != nil { return state.IteratorDump{}, err } @@ -552,7 +560,7 @@ func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error if block == nil { return 0, fmt.Errorf("current block missing") } - return block.NumberU64(), nil + return block.Number.Uint64(), nil } return uint64(num.Int64()), nil } diff --git a/eth/api_backend.go b/eth/api_backend.go index 8fd3e43300d3..e7daea2f6cdb 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -55,7 +55,7 @@ func (b *EthAPIBackend) ChainConfig() *params.ChainConfig { return b.eth.blockchain.Config() } -func (b *EthAPIBackend) CurrentBlock() *types.Block { +func (b *EthAPIBackend) CurrentBlock() *types.Header { return b.eth.blockchain.CurrentBlock() } @@ -72,19 +72,19 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb } // Otherwise resolve and return the block if number == rpc.LatestBlockNumber { - return b.eth.blockchain.CurrentBlock().Header(), nil + return b.eth.blockchain.CurrentBlock(), nil } if number == rpc.FinalizedBlockNumber { - block := b.eth.blockchain.CurrentFinalizedBlock() + block := b.eth.blockchain.CurrentFinalBlock() if block != nil { - return block.Header(), nil + return block, nil } return nil, errors.New("finalized block not found") } if number == rpc.SafeBlockNumber { block := b.eth.blockchain.CurrentSafeBlock() if block != nil { - return block.Header(), nil + return block, nil } return nil, errors.New("safe block not found") } @@ -120,13 +120,16 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe } // Otherwise resolve and return the block if number == rpc.LatestBlockNumber { - return b.eth.blockchain.CurrentBlock(), nil + header := b.eth.blockchain.CurrentBlock() + return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } if number == rpc.FinalizedBlockNumber { - return b.eth.blockchain.CurrentFinalizedBlock(), nil + header := b.eth.blockchain.CurrentFinalBlock() + return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } if number == rpc.SafeBlockNumber { - return b.eth.blockchain.CurrentSafeBlock(), nil + header := b.eth.blockchain.CurrentSafeBlock() + return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 2c7494c7de30..fc7529c8f5d7 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -301,7 +301,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl } else { // If the head block is already in our canonical chain, the beacon client is // probably resyncing. Ignore the update. - log.Info("Ignoring beacon update to old head", "number", block.NumberU64(), "hash", update.HeadBlockHash, "age", common.PrettyAge(time.Unix(int64(block.Time()), 0)), "have", api.eth.BlockChain().CurrentBlock().NumberU64()) + log.Info("Ignoring beacon update to old head", "number", block.NumberU64(), "hash", update.HeadBlockHash, "age", common.PrettyAge(time.Unix(int64(block.Time()), 0)), "have", api.eth.BlockChain().CurrentBlock().Number) return valid(nil), nil } api.eth.SetSynced() @@ -322,7 +322,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not in canonical chain")) } // Set the finalized block - api.eth.BlockChain().SetFinalized(finalBlock) + api.eth.BlockChain().SetFinalized(finalBlock.Header()) } // Check if the safe block hash is in our canonical tree, if not somethings wrong if update.SafeBlockHash != (common.Hash{}) { @@ -336,7 +336,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain")) } // Set the safe block - api.eth.BlockChain().SetSafe(safeBlock) + api.eth.BlockChain().SetSafe(safeBlock.Header()) } // If payload generation was requested, create a new block to be potentially // sealed by the beacon client. The payload will be requested later, and we @@ -804,7 +804,7 @@ func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) return nil, engine.TooLargeRequest.With(fmt.Errorf("requested count too large: %v", count)) } // limit count up until current - current := api.eth.BlockChain().CurrentBlock().NumberU64() + current := api.eth.BlockChain().CurrentBlock().Number.Uint64() last := uint64(start) + uint64(count) - 1 if last > current { last = current diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 4dc0c0ea7ea9..f1af087cf00a 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -248,8 +248,8 @@ func TestInvalidPayloadTimestamp(t *testing.T) { shouldErr bool }{ {0, true}, - {parent.Time(), true}, - {parent.Time() - 1, true}, + {parent.Time, true}, + {parent.Time - 1, true}, // TODO (MariusVanDerWijden) following tests are currently broken, // fixed in upcoming merge-kiln-v2 pr @@ -262,7 +262,7 @@ func TestInvalidPayloadTimestamp(t *testing.T) { params := engine.PayloadAttributes{ Timestamp: test.time, Random: crypto.Keccak256Hash([]byte{byte(123)}), - SuggestedFeeRecipient: parent.Coinbase(), + SuggestedFeeRecipient: parent.Coinbase, } fcState := engine.ForkchoiceStateV1{ HeadBlockHash: parent.Hash(), @@ -319,7 +319,7 @@ func TestEth2NewBlock(t *testing.T) { t.Fatalf("Failed to insert block: %v", err) case newResp.Status != "VALID": t.Fatalf("Failed to insert block: %v", newResp.Status) - case ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1: + case ethservice.BlockChain().CurrentBlock().Number.Uint64() != block.NumberU64()-1: t.Fatalf("Chain head shouldn't be updated") } checkLogEvents(t, newLogCh, rmLogsCh, 0, 0) @@ -331,7 +331,7 @@ func TestEth2NewBlock(t *testing.T) { if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { t.Fatalf("Failed to insert block: %v", err) } - if have, want := ethservice.BlockChain().CurrentBlock().NumberU64(), block.NumberU64(); have != want { + if have, want := ethservice.BlockChain().CurrentBlock().Number.Uint64(), block.NumberU64(); have != want { t.Fatalf("Chain head should be updated, have %d want %d", have, want) } checkLogEvents(t, newLogCh, rmLogsCh, 1, 0) @@ -341,7 +341,7 @@ func TestEth2NewBlock(t *testing.T) { // Introduce fork chain var ( - head = ethservice.BlockChain().CurrentBlock().NumberU64() + head = ethservice.BlockChain().CurrentBlock().Number.Uint64() ) parent = preMergeBlocks[len(preMergeBlocks)-1] for i := 0; i < 10; i++ { @@ -359,7 +359,7 @@ func TestEth2NewBlock(t *testing.T) { if err != nil || newResp.Status != "VALID" { t.Fatalf("Failed to insert block: %v", err) } - if ethservice.BlockChain().CurrentBlock().NumberU64() != head { + if ethservice.BlockChain().CurrentBlock().Number.Uint64() != head { t.Fatalf("Chain head shouldn't be updated") } @@ -371,7 +371,7 @@ func TestEth2NewBlock(t *testing.T) { if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { t.Fatalf("Failed to insert block: %v", err) } - if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() { + if ethservice.BlockChain().CurrentBlock().Number.Uint64() != block.NumberU64() { t.Fatalf("Chain head should be updated") } parent, head = block, block.NumberU64() @@ -389,7 +389,7 @@ func TestEth2DeepReorg(t *testing.T) { var ( api = NewConsensusAPI(ethservice, nil) parent = preMergeBlocks[len(preMergeBlocks)-core.TriesInMemory-1] - head = ethservice.BlockChain().CurrentBlock().NumberU64() + head = ethservice.BlockChain().CurrentBlock().Number.Uint64()() ) if ethservice.BlockChain().HasBlockAndState(parent.Hash(), parent.NumberU64()) { t.Errorf("Block %d not pruned", parent.NumberU64()) @@ -410,13 +410,13 @@ func TestEth2DeepReorg(t *testing.T) { if err != nil || newResp.Status != "VALID" { t.Fatalf("Failed to insert block: %v", err) } - if ethservice.BlockChain().CurrentBlock().NumberU64() != head { + if ethservice.BlockChain().CurrentBlock().Number.Uint64()() != head { t.Fatalf("Chain head shouldn't be updated") } if err := api.setHead(block.Hash()); err != nil { t.Fatalf("Failed to set head: %v", err) } - if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() { + if ethservice.BlockChain().CurrentBlock().Number.Uint64()() != block.NumberU64() { t.Fatalf("Chain head should be updated") } parent, head = block, block.NumberU64() @@ -466,8 +466,8 @@ func TestFullAPI(t *testing.T) { logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") ) - callback := func(parent *types.Block) { - statedb, _ := ethservice.BlockChain().StateAt(parent.Root()) + callback := func(parent *types.Header) { + statedb, _ := ethservice.BlockChain().StateAt(parent.Root) nonce := statedb.GetNonce(testAddr) tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) ethservice.TxPool().AddLocal(tx) @@ -476,9 +476,9 @@ func TestFullAPI(t *testing.T) { setupBlocks(t, ethservice, 10, parent, callback) } -func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Block, callback func(parent *types.Block)) []*types.Block { +func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header)) []*types.Header { api := NewConsensusAPI(ethservice) - var blocks []*types.Block + var blocks []*types.Header for i := 0; i < n; i++ { callback(parent) @@ -499,10 +499,10 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Bl if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { t.Fatalf("Failed to insert block: %v", err) } - if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number { + if ethservice.BlockChain().CurrentBlock().Number.Uint64() != payload.Number { t.Fatal("Chain head should be updated") } - if ethservice.BlockChain().CurrentFinalizedBlock().NumberU64() != payload.Number-1 { + if ethservice.BlockChain().CurrentFinalBlock().Number.Uint64() != payload.Number-1 { t.Fatal("Finalized block should be updated") } parent = ethservice.BlockChain().CurrentBlock() @@ -585,7 +585,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") ) for i := 0; i < 10; i++ { - statedb, _ := ethservice.BlockChain().StateAt(parent.Root()) + statedb, _ := ethservice.BlockChain().StateAt(parent.Root) tx := types.MustSignNewTx(testKey, signer, &types.LegacyTx{ Nonce: statedb.GetNonce(testAddr), Value: new(big.Int), @@ -596,9 +596,9 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { ethservice.TxPool().AddRemotesSync([]*types.Transaction{tx}) var ( params = engine.PayloadAttributes{ - Timestamp: parent.Time() + 1, + Timestamp: parent.Time + 1, Random: crypto.Keccak256Hash([]byte{byte(i)}), - SuggestedFeeRecipient: parent.Coinbase(), + SuggestedFeeRecipient: parent.Coinbase, } fcState = engine.ForkchoiceStateV1{ HeadBlockHash: parent.Hash(), @@ -645,7 +645,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) { if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { t.Fatalf("Failed to insert block: %v", err) } - if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number { + if ethservice.BlockChain().CurrentBlock().Number.Uint64() != payload.Number { t.Fatalf("Chain head should be updated") } parent = ethservice.BlockChain().CurrentBlock() @@ -676,7 +676,7 @@ func TestEmptyBlocks(t *testing.T) { api := NewConsensusAPI(ethservice) // Setup 10 blocks on the canonical chain - setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Block) {}) + setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}) // (1) check LatestValidHash by sending a normal payload (P1'') payload := getNewPayload(t, api, commonAncestor) @@ -727,11 +727,11 @@ func TestEmptyBlocks(t *testing.T) { } } -func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *engine.ExecutableData { +func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header) *engine.ExecutableData { params := engine.PayloadAttributes{ - Timestamp: parent.Time() + 1, + Timestamp: parent.Time + 1, Random: crypto.Keccak256Hash([]byte{byte(1)}), - SuggestedFeeRecipient: parent.Coinbase(), + SuggestedFeeRecipient: parent.Coinbase, } payload, err := assembleBlock(api, parent.Hash(), ¶ms) @@ -799,7 +799,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { commonAncestor := ethserviceA.BlockChain().CurrentBlock() // Setup 10 blocks on the canonical chain - setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Block) {}) + setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}) commonAncestor = ethserviceA.BlockChain().CurrentBlock() var invalidChain []*engine.ExecutableData @@ -855,7 +855,7 @@ func TestInvalidBloom(t *testing.T) { api := NewConsensusAPI(ethservice) // Setup 10 blocks on the canonical chain - setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Block) {}) + setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}) // (1) check LatestValidHash by sending a normal payload (P1'') payload := getNewPayload(t, api, commonAncestor) @@ -966,7 +966,7 @@ func TestSimultaneousNewBlock(t *testing.T) { if err != nil { t.Fatalf("Failed to convert executable data to block %v", err) } - if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1 { + if ethservice.BlockChain().CurrentBlock().Number.Uint64() != block.NumberU64()-1 { t.Fatalf("Chain head shouldn't be updated") } fcState := engine.ForkchoiceStateV1{ @@ -997,7 +997,7 @@ func TestSimultaneousNewBlock(t *testing.T) { t.Fatal(testErr) } } - if have, want := ethservice.BlockChain().CurrentBlock().NumberU64(), block.NumberU64(); have != want { + if have, want := ethservice.BlockChain().CurrentBlock().Number.Uint64(), block.NumberU64(); have != want { t.Fatalf("Chain head should be updated, have %d want %d", have, want) } parent = block @@ -1242,14 +1242,18 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") ) - callback := func(parent *types.Block) { - statedb, _ := ethservice.BlockChain().StateAt(parent.Root()) + callback := func(parent *types.Header) { + statedb, _ := ethservice.BlockChain().StateAt(parent.Root) nonce := statedb.GetNonce(testAddr) tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) ethservice.TxPool().AddLocal(tx) } - postMergeBlocks := setupBlocks(t, ethservice, 10, parent, callback) + postMergeHeaders := setupBlocks(t, ethservice, 10, parent, callback) + postMergeBlocks := make([]*types.Block, len(postMergeHeaders)) + for i, header := range postMergeHeaders { + postMergeBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64()) + } return n, ethservice, append(preMergeBlocks, postMergeBlocks...) } diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index c539474c64dd..ff985e6b035f 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -76,7 +76,7 @@ func (b *beaconBackfiller) suspend() *types.Header { // Sync cycle was just terminated, retrieve and return the last filled header. // Can't use `filled` as that contains a stale value from before cancellation. - return b.downloader.blockchain.CurrentFastBlock().Header() + return b.downloader.blockchain.CurrentSnapBlock() } // resume starts the downloader threads for backfilling state and chain data. @@ -101,7 +101,7 @@ func (b *beaconBackfiller) resume() { defer func() { b.lock.Lock() b.filling = false - b.filled = b.downloader.blockchain.CurrentFastBlock().Header() + b.filled = b.downloader.blockchain.CurrentSnapBlock() b.lock.Unlock() }() // If the downloader fails, report an error as in beacon chain mode there @@ -198,9 +198,9 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { switch d.getMode() { case FullSync: - chainHead = d.blockchain.CurrentBlock().Header() + chainHead = d.blockchain.CurrentBlock() case SnapSync: - chainHead = d.blockchain.CurrentFastBlock().Header() + chainHead = d.blockchain.CurrentSnapBlock() default: chainHead = d.lightchain.CurrentHeader() } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index ec9cce2eb621..fb9de79912e2 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -196,10 +196,10 @@ type BlockChain interface { GetBlockByHash(common.Hash) *types.Block // CurrentBlock retrieves the head block from the local chain. - CurrentBlock() *types.Block + CurrentBlock() *types.Header - // CurrentFastBlock retrieves the head snap block from the local chain. - CurrentFastBlock() *types.Block + // CurrentSnapBlock retrieves the head snap block from the local chain. + CurrentSnapBlock() *types.Header // SnapSyncCommitHead directly commits the head block to a certain entity. SnapSyncCommitHead(common.Hash) error @@ -236,7 +236,7 @@ func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain Bl quitCh: make(chan struct{}), SnapSyncer: snap.NewSyncer(stateDb, chain.TrieDB().Scheme()), stateSyncStart: make(chan *stateSync), - syncStartBlock: chain.CurrentFastBlock().NumberU64(), + syncStartBlock: chain.CurrentSnapBlock().Number.Uint64(), } // Create the post-merge skeleton syncer and start the process dl.skeleton = newSkeleton(stateDb, dl.peers, dropPeer, newBeaconBackfiller(dl, success)) @@ -261,9 +261,9 @@ func (d *Downloader) Progress() ethereum.SyncProgress { mode := d.getMode() switch { case d.blockchain != nil && mode == FullSync: - current = d.blockchain.CurrentBlock().NumberU64() + current = d.blockchain.CurrentBlock().Number.Uint64() case d.blockchain != nil && mode == SnapSync: - current = d.blockchain.CurrentFastBlock().NumberU64() + current = d.blockchain.CurrentSnapBlock().Number.Uint64() case d.lightchain != nil: current = d.lightchain.CurrentHeader().Number.Uint64() default: @@ -523,7 +523,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * // anyway, but still need a valid pivot block to avoid some code hitting // nil panics on access. if mode == SnapSync && pivot == nil { - pivot = d.blockchain.CurrentBlock().Header() + pivot = d.blockchain.CurrentBlock() } height := latest.Number.Uint64() @@ -834,9 +834,9 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) mode := d.getMode() switch mode { case FullSync: - localHeight = d.blockchain.CurrentBlock().NumberU64() + localHeight = d.blockchain.CurrentBlock().Number.Uint64() case SnapSync: - localHeight = d.blockchain.CurrentFastBlock().NumberU64() + localHeight = d.blockchain.CurrentSnapBlock().Number.Uint64() default: localHeight = d.lightchain.CurrentHeader().Number.Uint64() } @@ -1174,8 +1174,8 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, head uint64) e if mode == LightSync { head = d.lightchain.CurrentHeader().Number.Uint64() } else { - head = d.blockchain.CurrentFastBlock().NumberU64() - if full := d.blockchain.CurrentBlock().NumberU64(); head < full { + head = d.blockchain.CurrentSnapBlock().Number.Uint64() + if full := d.blockchain.CurrentBlock().Number.Uint64(); head < full { head = full } } @@ -1289,8 +1289,8 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode if rollback > 0 { lastHeader, lastFastBlock, lastBlock := d.lightchain.CurrentHeader().Number, common.Big0, common.Big0 if mode != LightSync { - lastFastBlock = d.blockchain.CurrentFastBlock().Number() - lastBlock = d.blockchain.CurrentBlock().Number() + lastFastBlock = d.blockchain.CurrentSnapBlock().Number + lastBlock = d.blockchain.CurrentBlock().Number } if err := d.lightchain.SetHead(rollback - 1); err != nil { // -1 to target the parent of the first uncertain block // We're already unwinding the stack, only print the error to make it more visible @@ -1298,8 +1298,8 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode } curFastBlock, curBlock := common.Big0, common.Big0 if mode != LightSync { - curFastBlock = d.blockchain.CurrentFastBlock().Number() - curBlock = d.blockchain.CurrentBlock().Number() + curFastBlock = d.blockchain.CurrentSnapBlock().Number + curBlock = d.blockchain.CurrentBlock().Number } log.Warn("Rolled back chain segment", "header", fmt.Sprintf("%d->%d", lastHeader, d.lightchain.CurrentHeader().Number), @@ -1344,7 +1344,7 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode // R: Nothing to give if mode != LightSync { head := d.blockchain.CurrentBlock() - if !gotHeaders && td.Cmp(d.blockchain.GetTd(head.Hash(), head.NumberU64())) > 0 { + if !gotHeaders && td.Cmp(d.blockchain.GetTd(head.Hash(), head.Number.Uint64())) > 0 { return errStallingPeer } } @@ -1868,9 +1868,9 @@ func (d *Downloader) reportSnapSyncProgress(force bool) { } var ( header = d.blockchain.CurrentHeader() - block = d.blockchain.CurrentFastBlock() + block = d.blockchain.CurrentSnapBlock() ) - syncedBlocks := block.NumberU64() - d.syncStartBlock + syncedBlocks := block.Number.Uint64() - d.syncStartBlock if syncedBlocks == 0 { return } @@ -1887,13 +1887,13 @@ func (d *Downloader) reportSnapSyncProgress(force bool) { return } var ( - left = latest.Number.Uint64() - block.NumberU64() + left = latest.Number.Uint64() - block.Number.Uint64() eta = time.Since(d.syncStartTime) / time.Duration(syncedBlocks) * time.Duration(left) - progress = fmt.Sprintf("%.2f%%", float64(block.NumberU64())*100/float64(latest.Number.Uint64())) + progress = fmt.Sprintf("%.2f%%", float64(block.Number.Uint64())*100/float64(latest.Number.Uint64())) headers = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(header.Number.Uint64()), common.StorageSize(headerBytes).TerminalString()) - bodies = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(block.NumberU64()), common.StorageSize(bodyBytes).TerminalString()) - receipts = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(block.NumberU64()), common.StorageSize(receiptBytes).TerminalString()) + bodies = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(block.Number.Uint64()), common.StorageSize(bodyBytes).TerminalString()) + receipts = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(block.Number.Uint64()), common.StorageSize(receiptBytes).TerminalString()) ) log.Info("Syncing: chain download in progress", "synced", progress, "chain", syncedBytes, "headers", headers, "bodies", bodies, "receipts", receipts, "eta", common.PrettyDuration(eta)) d.syncLogTime = time.Now() diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index ababb9deb140..a884c1e950b0 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -100,7 +100,7 @@ func (dl *downloadTester) sync(id string, td *big.Int, mode SyncMode) error { head := dl.peers[id].chain.CurrentBlock() if td == nil { // If no particular TD was requested, load from the peer's blockchain - td = dl.peers[id].chain.GetTd(head.Hash(), head.NumberU64()) + td = dl.peers[id].chain.GetTd(head.Hash(), head.Number.Uint64()) } // Synchronise with the chosen peer and ensure proper cleanup afterwards err := dl.downloader.synchronise(id, head.Hash(), td, nil, mode, false, nil) @@ -158,7 +158,7 @@ type downloadTesterPeer struct { // and total difficulty. func (dlp *downloadTesterPeer) Head() (common.Hash, *big.Int) { head := dlp.chain.CurrentBlock() - return head.Hash(), dlp.chain.GetTd(head.Hash(), head.NumberU64()) + return head.Hash(), dlp.chain.GetTd(head.Hash(), head.Number.Uint64()) } func unmarshalRlpHeaders(rlpdata []rlp.RawValue) []*types.Header { @@ -430,10 +430,10 @@ func assertOwnChain(t *testing.T, tester *downloadTester, length int) { if hs := int(tester.chain.CurrentHeader().Number.Uint64()) + 1; hs != headers { t.Fatalf("synchronised headers mismatch: have %v, want %v", hs, headers) } - if bs := int(tester.chain.CurrentBlock().NumberU64()) + 1; bs != blocks { + if bs := int(tester.chain.CurrentBlock().Number.Uint64()) + 1; bs != blocks { t.Fatalf("synchronised blocks mismatch: have %v, want %v", bs, blocks) } - if rs := int(tester.chain.CurrentFastBlock().NumberU64()) + 1; rs != receipts { + if rs := int(tester.chain.CurrentSnapBlock().Number.Uint64()) + 1; rs != receipts { t.Fatalf("synchronised receipts mismatch: have %v, want %v", rs, receipts) } } @@ -490,7 +490,7 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { for { // Check the retrieval count synchronously (! reason for this ugly block) tester.lock.RLock() - retrieved := int(tester.chain.CurrentFastBlock().Number().Uint64()) + 1 + retrieved := int(tester.chain.CurrentSnapBlock().Number.Uint64()) + 1 tester.lock.RUnlock() if retrieved >= targetBlocks+1 { break @@ -506,7 +506,7 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { { cached = tester.downloader.queue.resultCache.countCompleted() frozen = int(atomic.LoadUint32(&blocked)) - retrieved = int(tester.chain.CurrentFastBlock().Number().Uint64()) + 1 + retrieved = int(tester.chain.CurrentSnapBlock().Number.Uint64()) + 1 } tester.downloader.queue.resultCache.lock.Unlock() tester.downloader.queue.lock.Unlock() @@ -522,7 +522,7 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { // Make sure we filled up the cache, then exhaust it time.Sleep(25 * time.Millisecond) // give it a chance to screw up tester.lock.RLock() - retrieved = int(tester.chain.CurrentFastBlock().Number().Uint64()) + 1 + retrieved = int(tester.chain.CurrentSnapBlock().Number.Uint64()) + 1 tester.lock.RUnlock() if cached != blockCacheMaxItems && cached != blockCacheMaxItems-reorgProtHeaderDelay && retrieved+cached+frozen != targetBlocks+1 && retrieved+cached+frozen != targetBlocks+1-reorgProtHeaderDelay { t.Fatalf("block count mismatch: have %v, want %v (owned %v, blocked %v, target %v)", cached, blockCacheMaxItems, retrieved, frozen, targetBlocks+1) @@ -921,7 +921,7 @@ func testInvalidHeaderRollback(t *testing.T, protocol uint, mode SyncMode) { t.Errorf("rollback head mismatch: have %v, want at most %v", head, 2*fsHeaderSafetyNet+MaxHeaderFetch) } if mode == SnapSync { - if head := tester.chain.CurrentBlock().NumberU64(); head != 0 { + if head := tester.chain.CurrentBlock().Number.Uint64(); head != 0 { t.Errorf("fast sync pivot block #%d not rolled back", head) } } @@ -943,7 +943,7 @@ func testInvalidHeaderRollback(t *testing.T, protocol uint, mode SyncMode) { t.Errorf("rollback head mismatch: have %v, want at most %v", head, 2*fsHeaderSafetyNet+MaxHeaderFetch) } if mode == SnapSync { - if head := tester.chain.CurrentBlock().NumberU64(); head != 0 { + if head := tester.chain.CurrentBlock().Number.Uint64(); head != 0 { t.Errorf("fast sync pivot block #%d not rolled back", head) } } @@ -1484,7 +1484,7 @@ func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) { select { case <-success: // Ok, downloader fully cancelled after sync cycle - if bs := int(tester.chain.CurrentBlock().NumberU64()) + 1; bs != len(chain.blocks) { + if bs := int(tester.chain.CurrentBlock().Number.Uint64()) + 1; bs != len(chain.blocks) { t.Fatalf("synchronised blocks mismatch: have %v, want %v", bs, len(chain.blocks)) } case <-time.NewTimer(time.Second * 3).C: diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index a987d46458e4..4ee5a0d1b287 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -49,10 +49,10 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber number = 0 } if number == rpc.FinalizedBlockNumber { - return b.chain.CurrentFinalizedBlock().Header(), nil + return b.chain.CurrentFinalBlock(), nil } if number == rpc.SafeBlockNumber { - return b.chain.CurrentSafeBlock().Header(), nil + return b.chain.CurrentSafeBlock(), nil } if number == rpc.LatestBlockNumber { number = testHead @@ -75,10 +75,10 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) number = 0 } if number == rpc.FinalizedBlockNumber { - return b.chain.CurrentFinalizedBlock(), nil + number = rpc.BlockNumber(b.chain.CurrentFinalBlock().Number.Uint64()) } if number == rpc.SafeBlockNumber { - return b.chain.CurrentSafeBlock(), nil + number = rpc.BlockNumber(b.chain.CurrentSafeBlock().Number.Uint64()) } if number == rpc.LatestBlockNumber { number = testHead @@ -169,8 +169,8 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke t.Fatalf("Failed to create local chain, %v", err) } chain.InsertChain(blocks) - chain.SetFinalized(chain.GetBlockByNumber(25)) - chain.SetSafe(chain.GetBlockByNumber(25)) + chain.SetFinalized(chain.GetBlockByNumber(25).Header()) + chain.SetSafe(chain.GetBlockByNumber(25).Header()) return &testBackend{chain: chain, pending: pending} } diff --git a/eth/handler.go b/eth/handler.go index 078133f059f2..83df6ff2eb60 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -152,13 +152,13 @@ func newHandler(config *handlerConfig) (*handler, error) { // * the last snap sync is not finished while user specifies a full sync this // time. But we don't have any recent state for full sync. // In these cases however it's safe to reenable snap sync. - fullBlock, fastBlock := h.chain.CurrentBlock(), h.chain.CurrentFastBlock() - if fullBlock.NumberU64() == 0 && fastBlock.NumberU64() > 0 { + fullBlock, snapBlock := h.chain.CurrentBlock(), h.chain.CurrentSnapBlock() + if fullBlock.Number.Uint64() == 0 && snapBlock.Number.Uint64() > 0 { h.snapSync = uint32(1) log.Warn("Switch sync mode from full sync to snap sync") } } else { - if h.chain.CurrentBlock().NumberU64() > 0 { + if h.chain.CurrentBlock().Number.Uint64() > 0 { // Print warning log if database is not empty to run snap sync. log.Warn("Switch sync mode from snap sync to full sync") } else { @@ -183,10 +183,10 @@ func newHandler(config *handlerConfig) (*handler, error) { // If we've successfully finished a sync cycle and passed any required // checkpoint, enable accepting transactions from the network head := h.chain.CurrentBlock() - if head.NumberU64() >= h.checkpointNumber { + if head.Number.Uint64() >= h.checkpointNumber { // Checkpoint passed, sanity check the timestamp to have a fallback mechanism // for non-checkpointed (number = 0) private networks. - if head.Time() >= uint64(time.Now().AddDate(0, -1, 0).Unix()) { + if head.Time >= uint64(time.Now().AddDate(0, -1, 0).Unix()) { atomic.StoreUint32(&h.acceptTxs, 1) } } @@ -198,7 +198,7 @@ func newHandler(config *handlerConfig) (*handler, error) { log.Info("Chain post-merge, sync via beacon client") } else { head := h.chain.CurrentBlock() - if td := h.chain.GetTd(head.Hash(), head.NumberU64()); td.Cmp(ttd) >= 0 { + if td := h.chain.GetTd(head.Hash(), head.Number.Uint64()); td.Cmp(ttd) >= 0 { log.Info("Chain post-TTD, sync via beacon client") } else { log.Warn("Chain pre-merge, sync via PoW (ensure beacon client is ready)") @@ -227,7 +227,7 @@ func newHandler(config *handlerConfig) (*handler, error) { return h.chain.Engine().VerifyHeader(h.chain, header, true) } heighter := func() uint64 { - return h.chain.CurrentBlock().NumberU64() + return h.chain.CurrentBlock().Number.Uint64() } inserter := func(blocks types.Blocks) (int, error) { // All the block fetcher activities should be disabled @@ -250,7 +250,7 @@ func newHandler(config *handlerConfig) (*handler, error) { // the propagated block if the head is too old. Unfortunately there is a corner // case when starting new networks, where the genesis might be ancient (0 unix) // which would prevent full nodes from accepting it. - if h.chain.CurrentBlock().NumberU64() < h.checkpointNumber { + if h.chain.CurrentBlock().Number.Uint64() < h.checkpointNumber { log.Warn("Unsynced yet, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) return 0, nil } diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 502cc8e6a9f6..9f0dd8ec5de4 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -274,7 +274,7 @@ func testRecvTransactions(t *testing.T, protocol uint) { var ( genesis = handler.chain.Genesis() head = handler.chain.CurrentBlock() - td = handler.chain.GetTd(head.Hash(), head.NumberU64()) + td = handler.chain.GetTd(head.Hash(), head.Number.Uint64()) ) if err := src.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil { t.Fatalf("failed to run protocol handshake") @@ -337,7 +337,7 @@ func testSendTransactions(t *testing.T, protocol uint) { var ( genesis = handler.chain.Genesis() head = handler.chain.CurrentBlock() - td = handler.chain.GetTd(head.Hash(), head.NumberU64()) + td = handler.chain.GetTd(head.Hash(), head.Number.Uint64()) ) if err := sink.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil { t.Fatalf("failed to run protocol handshake") @@ -545,7 +545,7 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo var ( genesis = handler.chain.Genesis() head = handler.chain.CurrentBlock() - td = handler.chain.GetTd(head.Hash(), head.NumberU64()) + td = handler.chain.GetTd(head.Hash(), head.Number.Uint64()) ) if err := remote.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil { t.Fatalf("failed to run protocol handshake") @@ -661,7 +661,8 @@ func testBroadcastBlock(t *testing.T, peers, bcasts int) { } // Initiate a block propagation across the peers time.Sleep(100 * time.Millisecond) - source.handler.BroadcastBlock(source.chain.CurrentBlock(), true) + header := source.chain.CurrentBlock() + source.handler.BroadcastBlock(source.chain.GetBlock(header.Hash(), header.Number.Uint64()), true) // Iterate through all the sinks and ensure the correct number got the block done := make(chan struct{}, peers) @@ -734,18 +735,19 @@ func testBroadcastMalformedBlock(t *testing.T, protocol uint) { // Create various combinations of malformed blocks head := source.chain.CurrentBlock() + block := source.chain.GetBlock(head.Hash(), head.Number.Uint64()) - malformedUncles := head.Header() + malformedUncles := head malformedUncles.UncleHash[0]++ - malformedTransactions := head.Header() + malformedTransactions := head malformedTransactions.TxHash[0]++ - malformedEverything := head.Header() + malformedEverything := head malformedEverything.UncleHash[0]++ malformedEverything.TxHash[0]++ // Try to broadcast all malformations and ensure they all get discarded for _, header := range []*types.Header{malformedUncles, malformedTransactions, malformedEverything} { - block := types.NewBlockWithHeader(header).WithBody(head.Transactions(), head.Uncles()) + block := types.NewBlockWithHeader(header).WithBody(block.Transactions(), block.Uncles()) if err := src.SendNewBlock(block, big.NewInt(131136)); err != nil { t.Fatalf("failed to broadcast block: %v", err) } diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index ae4ec9142e8b..2f2dd1cf6ae3 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -137,12 +137,14 @@ type NodeInfo struct { // nodeInfo retrieves some `eth` protocol metadata about the running host node. func nodeInfo(chain *core.BlockChain, network uint64) *NodeInfo { head := chain.CurrentBlock() + hash := head.Hash() + return &NodeInfo{ Network: network, - Difficulty: chain.GetTd(head.Hash(), head.NumberU64()), + Difficulty: chain.GetTd(hash, head.Number.Uint64()), Genesis: chain.Genesis().Hash(), Config: chain.Config(), - Head: head.Hash(), + Head: hash, } } diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 76505ab8d32b..bbb9866bd3df 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -225,24 +225,24 @@ func testGetBlockHeaders(t *testing.T, protocol uint) { []common.Hash{backend.chain.GetBlockByNumber(0).Hash()}, }, { - &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().NumberU64()}, Amount: 1}, + &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().Number.Uint64()}, Amount: 1}, []common.Hash{backend.chain.CurrentBlock().Hash()}, }, { // If the peer requests a bit into the future, we deliver what we have - &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().NumberU64()}, Amount: 10}, + &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().Number.Uint64()}, Amount: 10}, []common.Hash{backend.chain.CurrentBlock().Hash()}, }, // Ensure protocol limits are honored { - &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true}, - getHashes(backend.chain.CurrentBlock().NumberU64(), limit), + &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().Number.Uint64() - 1}, Amount: limit + 10, Reverse: true}, + getHashes(backend.chain.CurrentBlock().Number.Uint64(), limit), }, // Check that requesting more than available is handled gracefully { - &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3}, + &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().Number.Uint64() - 4}, Skip: 3, Amount: 3}, []common.Hash{ - backend.chain.GetBlockByNumber(backend.chain.CurrentBlock().NumberU64() - 4).Hash(), - backend.chain.GetBlockByNumber(backend.chain.CurrentBlock().NumberU64()).Hash(), + backend.chain.GetBlockByNumber(backend.chain.CurrentBlock().Number.Uint64() - 4).Hash(), + backend.chain.GetBlockByNumber(backend.chain.CurrentBlock().Number.Uint64()).Hash(), }, }, { &GetBlockHeadersPacket{Origin: HashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true}, @@ -253,10 +253,10 @@ func testGetBlockHeaders(t *testing.T, protocol uint) { }, // Check that requesting more than available is handled gracefully, even if mid skip { - &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3}, + &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().Number.Uint64() - 4}, Skip: 2, Amount: 3}, []common.Hash{ - backend.chain.GetBlockByNumber(backend.chain.CurrentBlock().NumberU64() - 4).Hash(), - backend.chain.GetBlockByNumber(backend.chain.CurrentBlock().NumberU64() - 1).Hash(), + backend.chain.GetBlockByNumber(backend.chain.CurrentBlock().Number.Uint64() - 4).Hash(), + backend.chain.GetBlockByNumber(backend.chain.CurrentBlock().Number.Uint64() - 1).Hash(), }, }, { &GetBlockHeadersPacket{Origin: HashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true}, @@ -293,7 +293,7 @@ func testGetBlockHeaders(t *testing.T, protocol uint) { &GetBlockHeadersPacket{Origin: HashOrNumber{Hash: unknown}, Amount: 1}, []common.Hash{}, }, { - &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().NumberU64() + 1}, Amount: 1}, + &GetBlockHeadersPacket{Origin: HashOrNumber{Number: backend.chain.CurrentBlock().Number.Uint64() + 1}, Amount: 1}, []common.Hash{}, }, } @@ -394,7 +394,7 @@ func testGetBlockBodies(t *testing.T, protocol uint) { ) for j := 0; j < tt.random; j++ { for { - num := rand.Int63n(int64(backend.chain.CurrentBlock().NumberU64())) + num := rand.Int63n(int64(backend.chain.CurrentBlock().Number.Uint64())) if !seen[num] { seen[num] = true @@ -529,7 +529,7 @@ func testGetNodeData(t *testing.T, protocol uint, drop bool) { // Sanity check whether all state matches. accounts := []common.Address{testAddr, acc1Addr, acc2Addr} - for i := uint64(0); i <= backend.chain.CurrentBlock().NumberU64(); i++ { + for i := uint64(0); i <= backend.chain.CurrentBlock().Number.Uint64(); i++ { root := backend.chain.GetBlockByNumber(i).Root() reconstructed, _ := state.New(root, state.NewDatabase(reconstructDB), nil) for j, acc := range accounts { @@ -602,7 +602,7 @@ func testGetBlockReceipts(t *testing.T, protocol uint) { hashes []common.Hash receipts [][]*types.Receipt ) - for i := uint64(0); i <= backend.chain.CurrentBlock().NumberU64(); i++ { + for i := uint64(0); i <= backend.chain.CurrentBlock().Number.Uint64(); i++ { block := backend.chain.GetBlockByNumber(i) hashes = append(hashes, block.Hash()) diff --git a/eth/protocols/eth/handshake_test.go b/eth/protocols/eth/handshake_test.go index c768edaeac01..5c6727d91cc7 100644 --- a/eth/protocols/eth/handshake_test.go +++ b/eth/protocols/eth/handshake_test.go @@ -39,7 +39,7 @@ func testHandshake(t *testing.T, protocol uint) { var ( genesis = backend.chain.Genesis() head = backend.chain.CurrentBlock() - td = backend.chain.GetTd(head.Hash(), head.NumberU64()) + td = backend.chain.GetTd(head.Hash(), head.Number.Uint64()) forkID = forkid.NewID(backend.chain.Config(), backend.chain.Genesis().Hash(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time) ) tests := []struct { diff --git a/eth/sync.go b/eth/sync.go index 8fd86b578cf6..6d764ef4822b 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -206,22 +206,22 @@ func peerToSyncOp(mode downloader.SyncMode, p *eth.Peer) *chainSyncOp { func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) { // If we're in snap sync mode, return that directly if atomic.LoadUint32(&cs.handler.snapSync) == 1 { - block := cs.handler.chain.CurrentFastBlock() - td := cs.handler.chain.GetTd(block.Hash(), block.NumberU64()) + block := cs.handler.chain.CurrentSnapBlock() + td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64()) return downloader.SnapSync, td } // We are probably in full sync, but we might have rewound to before the // snap sync pivot, check if we should reenable if pivot := rawdb.ReadLastPivotNumber(cs.handler.database); pivot != nil { - if head := cs.handler.chain.CurrentBlock(); head.NumberU64() < *pivot { - block := cs.handler.chain.CurrentFastBlock() - td := cs.handler.chain.GetTd(block.Hash(), block.NumberU64()) + if head := cs.handler.chain.CurrentBlock(); head.Number.Uint64() < *pivot { + block := cs.handler.chain.CurrentSnapBlock() + td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64()) return downloader.SnapSync, td } } // Nope, we're really full syncing head := cs.handler.chain.CurrentBlock() - td := cs.handler.chain.GetTd(head.Hash(), head.NumberU64()) + td := cs.handler.chain.GetTd(head.Hash(), head.Number.Uint64()) return downloader.FullSync, td } @@ -263,21 +263,23 @@ func (h *handler) doSync(op *chainSyncOp) error { // If we've successfully finished a sync cycle and passed any required checkpoint, // enable accepting transactions from the network. head := h.chain.CurrentBlock() - if head.NumberU64() >= h.checkpointNumber { + if head.Number.Uint64() >= h.checkpointNumber { // Checkpoint passed, sanity check the timestamp to have a fallback mechanism // for non-checkpointed (number = 0) private networks. - if head.Time() >= uint64(time.Now().AddDate(0, -1, 0).Unix()) { + if head.Time >= uint64(time.Now().AddDate(0, -1, 0).Unix()) { atomic.StoreUint32(&h.acceptTxs, 1) } } - if head.NumberU64() > 0 { + if head.Number.Uint64() > 0 { // We've completed a sync cycle, notify all peers of new state. This path is // essential in star-topology networks where a gateway node needs to notify // all its out-of-date peers of the availability of a new block. This failure // scenario will most often crop up in private and hackathon networks with // degenerate connectivity, but it should be healthy for the mainnet too to // more reliably update peers or the local TD state. - h.BroadcastBlock(head, false) + if block := h.chain.GetBlock(head.Hash(), head.Number.Uint64()); block != nil { + h.BroadcastBlock(block, false) + } } return nil } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 29ec80868579..b0dae4ca3e0d 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -109,7 +109,7 @@ func (b *testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber { - return b.chain.CurrentBlock(), nil + return b.chain.GetBlockByNumber(b.chain.CurrentBlock().Number.Uint64()), nil } return b.chain.GetBlockByNumber(uint64(number)), nil } diff --git a/graphql/graphql.go b/graphql/graphql.go index 356ff669fb16..0c13cc80f555 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -1219,7 +1219,7 @@ func (r *Resolver) Blocks(ctx context.Context, args struct { if args.To != nil { to = rpc.BlockNumber(*args.To) } else { - to = rpc.BlockNumber(r.backend.CurrentBlock().Number().Int64()) + to = rpc.BlockNumber(r.backend.CurrentBlock().Number.Int64()) } if to < from { return []*Block{}, nil diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 58f65f86d794..a2a3366c9739 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1704,7 +1704,7 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c return common.Hash{}, err } // Print a log with full tx details for manual investigations and interventions - signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number()) + signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number) from, err := types.Sender(signer, tx) if err != nil { return common.Hash{}, err diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 0c1763472f2d..2405efa234e3 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -59,7 +59,7 @@ type Backend interface { HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) CurrentHeader() *types.Header - CurrentBlock() *types.Block + CurrentBlock() *types.Header BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index a8f2d5214889..3279b6a8e533 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -278,7 +278,7 @@ func (b *backendMock) HeaderByHash(ctx context.Context, hash common.Hash) (*type func (b *backendMock) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { return nil, nil } -func (b *backendMock) CurrentBlock() *types.Block { return nil } +func (b *backendMock) CurrentBlock() *types.Header { return nil } func (b *backendMock) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { return nil, nil } diff --git a/les/api_backend.go b/les/api_backend.go index 422ac74b8668..a724af04c5d3 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -52,8 +52,8 @@ func (b *LesApiBackend) ChainConfig() *params.ChainConfig { return b.eth.chainConfig } -func (b *LesApiBackend) CurrentBlock() *types.Block { - return types.NewBlockWithHeader(b.eth.BlockChain().CurrentHeader()) +func (b *LesApiBackend) CurrentBlock() *types.Header { + return b.eth.BlockChain().CurrentHeader() } func (b *LesApiBackend) SetHead(number uint64) { diff --git a/les/handler_test.go b/les/handler_test.go index b7be29b862ab..c39709259619 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -121,20 +121,20 @@ func testGetBlockHeaders(t *testing.T, protocol int) { &GetBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1}, []common.Hash{bc.GetBlockByNumber(0).Hash()}, }, { - &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64()}, Amount: 1}, + &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64()}, Amount: 1}, []common.Hash{bc.CurrentBlock().Hash()}, }, // Ensure protocol limits are honored //{ - // &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true}, + // &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64()() - 1}, Amount: limit + 10, Reverse: true}, // []common.Hash{}, //}, // Check that requesting more than available is handled gracefully { - &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3}, + &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64() - 4}, Skip: 3, Amount: 3}, []common.Hash{ - bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 4).Hash(), - bc.GetBlockByNumber(bc.CurrentBlock().NumberU64()).Hash(), + bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64() - 4).Hash(), + bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64()).Hash(), }, }, { &GetBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true}, @@ -145,10 +145,10 @@ func testGetBlockHeaders(t *testing.T, protocol int) { }, // Check that requesting more than available is handled gracefully, even if mid skip { - &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3}, + &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64() - 4}, Skip: 2, Amount: 3}, []common.Hash{ - bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 4).Hash(), - bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1).Hash(), + bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64() - 4).Hash(), + bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64() - 1).Hash(), }, }, { &GetBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true}, @@ -162,7 +162,7 @@ func testGetBlockHeaders(t *testing.T, protocol int) { &GetBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1}, []common.Hash{}, }, { - &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() + 1}, Amount: 1}, + &GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64() + 1}, Amount: 1}, []common.Hash{}, }, } @@ -240,7 +240,7 @@ func testGetBlockBodies(t *testing.T, protocol int) { for j := 0; j < tt.random; j++ { for { - num := rand.Int63n(int64(bc.CurrentBlock().NumberU64())) + num := rand.Int63n(int64(bc.CurrentBlock().Number.Uint64())) if !seen[num] { seen[num] = true @@ -292,7 +292,7 @@ func testGetCode(t *testing.T, protocol int) { var codereqs []*CodeReq var codes [][]byte - for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ { + for i := uint64(0); i <= bc.CurrentBlock().Number.Uint64(); i++ { header := bc.GetHeaderByNumber(i) req := &CodeReq{ BHash: header.Hash(), @@ -367,7 +367,7 @@ func testGetReceipt(t *testing.T, protocol int) { // Collect the hashes to request, and the response to expect var receipts []types.Receipts var hashes []common.Hash - for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ { + for i := uint64(0); i <= bc.CurrentBlock().Number.Uint64(); i++ { block := bc.GetBlockByNumber(i) hashes = append(hashes, block.Hash()) @@ -404,7 +404,7 @@ func testGetProofs(t *testing.T, protocol int) { proofsV2 := light.NewNodeSet() accounts := []common.Address{bankAddr, userAddr1, userAddr2, signerAddr, {}} - for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ { + for i := uint64(0); i <= bc.CurrentBlock().Number.Uint64(); i++ { header := bc.GetHeaderByNumber(i) trie, _ := trie.New(trie.StateTrieID(header.Root), trie.NewDatabase(server.db)) diff --git a/les/odr_test.go b/les/odr_test.go index e028d35e639c..bd0574768c27 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -281,7 +281,7 @@ func testGetTxStatusFromUnindexedPeers(t *testing.T, protocol int) { blockHashes = make(map[common.Hash]common.Hash) // Transaction hash to block hash mappings intraIndex = make(map[common.Hash]uint64) // Transaction intra-index in block ) - for number := uint64(1); number < server.backend.Blockchain().CurrentBlock().NumberU64(); number++ { + for number := uint64(1); number < server.backend.Blockchain().CurrentBlock().Number.Uint64(); number++ { block := server.backend.Blockchain().GetBlockByNumber(number) if block == nil { t.Fatalf("Failed to retrieve block %d", number) diff --git a/miner/miner_test.go b/miner/miner_test.go index 2e7682acd331..6bf3edae5dbb 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -19,6 +19,7 @@ package miner import ( "errors" + "math/big" "testing" "time" @@ -65,14 +66,15 @@ type testBlockChain struct { chainHeadFeed *event.Feed } -func (bc *testBlockChain) CurrentBlock() *types.Block { - return types.NewBlock(&types.Header{ +func (bc *testBlockChain) CurrentBlock() *types.Header { + return &types.Header{ + Number: new(big.Int), GasLimit: bc.gasLimit, - }, nil, nil, nil, trie.NewStackTrie(nil)) + } } func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { - return bc.CurrentBlock() + return types.NewBlock(bc.CurrentBlock(), nil, nil, nil, trie.NewStackTrie(nil)) } func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { diff --git a/miner/worker.go b/miner/worker.go index 49204f71a076..8940c5037b41 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -494,7 +494,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { for { select { case <-w.startCh: - clearPending(w.chain.CurrentBlock().NumberU64()) + clearPending(w.chain.CurrentBlock().Number.Uint64()) timestamp = time.Now().Unix() commit(false, commitInterruptNewHead) @@ -607,12 +607,12 @@ func (w *worker) mainLoop() { case <-cleanTicker.C: chainHead := w.chain.CurrentBlock() for hash, uncle := range w.localUncles { - if uncle.NumberU64()+staleThreshold <= chainHead.NumberU64() { + if uncle.NumberU64()+staleThreshold <= chainHead.Number.Uint64() { delete(w.localUncles, hash) } } for hash, uncle := range w.remoteUncles { - if uncle.NumberU64()+staleThreshold <= chainHead.NumberU64() { + if uncle.NumberU64()+staleThreshold <= chainHead.Number.Uint64() { delete(w.remoteUncles, hash) } } @@ -790,10 +790,10 @@ func (w *worker) resultLoop() { } // makeEnv creates a new environment for the sealing block. -func (w *worker) makeEnv(parent *types.Block, header *types.Header, coinbase common.Address) (*environment, error) { +func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address) (*environment, error) { // Retrieve the parent state to execute on top and start a prefetcher for // the miner to speed block sealing up a bit. - state, err := w.chain.StateAt(parent.Root()) + state, err := w.chain.StateAt(parent.Root) if err != nil { return nil, err } @@ -988,25 +988,26 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { // Find the parent block for sealing task parent := w.chain.CurrentBlock() if genParams.parentHash != (common.Hash{}) { - parent = w.chain.GetBlockByHash(genParams.parentHash) - } - if parent == nil { - return nil, fmt.Errorf("missing parent") + block := w.chain.GetBlockByHash(genParams.parentHash) + if block == nil { + return nil, fmt.Errorf("missing parent") + } + parent = block.Header() } // Sanity check the timestamp correctness, recap the timestamp // to parent+1 if the mutation is allowed. timestamp := genParams.timestamp - if parent.Time() >= timestamp { + if parent.Time >= timestamp { if genParams.forceTime { - return nil, fmt.Errorf("invalid timestamp, parent %d given %d", parent.Time(), timestamp) + return nil, fmt.Errorf("invalid timestamp, parent %d given %d", parent.Time, timestamp) } - timestamp = parent.Time() + 1 + timestamp = parent.Time + 1 } // Construct the sealing block header. header := &types.Header{ ParentHash: parent.Hash(), - Number: new(big.Int).Add(parent.Number(), common.Big1), - GasLimit: core.CalcGasLimit(parent.GasLimit(), w.config.GasCeil), + Number: new(big.Int).Add(parent.Number, common.Big1), + GasLimit: core.CalcGasLimit(parent.GasLimit, w.config.GasCeil), Time: timestamp, Coinbase: genParams.coinbase, } @@ -1020,9 +1021,9 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { } // Set baseFee and GasLimit if we are on an EIP-1559 chain if w.chainConfig.IsLondon(header.Number) { - header.BaseFee = misc.CalcBaseFee(w.chainConfig, parent.Header()) - if !w.chainConfig.IsLondon(parent.Number()) { - parentGasLimit := parent.GasLimit() * w.chainConfig.ElasticityMultiplier() + header.BaseFee = misc.CalcBaseFee(w.chainConfig, parent) + if !w.chainConfig.IsLondon(parent.Number) { + parentGasLimit := parent.GasLimit * w.chainConfig.ElasticityMultiplier() header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) } } diff --git a/miner/worker_test.go b/miner/worker_test.go index ba929d293d8a..e60de679326c 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -147,7 +147,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine if _, err := chain.InsertChain(blocks); err != nil { t.Fatalf("failed to insert origin chain: %v", err) } - parent := chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) + parent := chain.GetBlockByHash(chain.CurrentBlock().ParentHash) blocks, _ = core.GenerateChain(chainConfig, parent, engine, genDb, 1, func(i int, gen *core.BlockGen) { gen.SetCoinbase(testUserAddress) }) @@ -176,10 +176,10 @@ func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base func (b *testWorkerBackend) newRandomUncle() *types.Block { var parent *types.Block cur := b.chain.CurrentBlock() - if cur.NumberU64() == 0 { + if cur.Number.Uint64() == 0 { parent = b.chain.Genesis() } else { - parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash()) + parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash) } blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.db, 1, func(i int, gen *core.BlockGen) { var addr = make([]byte, common.AddressLength) @@ -607,21 +607,21 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co b.chain.CurrentBlock().Hash(), common.HexToAddress("0xdeadbeef"), common.HexToHash("0xcafebabe"), - b.chain.CurrentBlock().NumberU64() + 1, + b.chain.CurrentBlock().Number.Uint64() + 1, false, }, { b.chain.CurrentBlock().Hash(), common.Address{}, common.HexToHash("0xcafebabe"), - b.chain.CurrentBlock().NumberU64() + 1, + b.chain.CurrentBlock().Number.Uint64() + 1, false, }, { b.chain.CurrentBlock().Hash(), common.Address{}, common.Hash{}, - b.chain.CurrentBlock().NumberU64() + 1, + b.chain.CurrentBlock().Number.Uint64() + 1, false, }, { diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 8da95a640a10..b74653ea6acc 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -154,7 +154,7 @@ func (t *BlockTest) Run(snapshotter bool) error { } // Cross-check the snapshot-to-hash against the trie hash if snapshotter { - if err := chain.Snapshots().Verify(chain.CurrentBlock().Root()); err != nil { + if err := chain.Snapshots().Verify(chain.CurrentBlock().Root); err != nil { return err } } @@ -317,8 +317,8 @@ func (t *BlockTest) validateImportedHeaders(cm *core.BlockChain, validBlocks []b // block-by-block, so we can only validate imported headers after // all blocks have been processed by BlockChain, as they may not // be part of the longest chain until last block is imported. - for b := cm.CurrentBlock(); b != nil && b.NumberU64() != 0; b = cm.GetBlockByHash(b.Header().ParentHash) { - if err := validateHeader(bmap[b.Hash()].BlockHeader, b.Header()); err != nil { + for b := cm.CurrentBlock(); b != nil && b.Number.Uint64() != 0; b = cm.GetBlockByHash(b.ParentHash).Header() { + if err := validateHeader(bmap[b.Hash()].BlockHeader, b); err != nil { return fmt.Errorf("imported block header validation failed: %v", err) } } From 19f74fa3c0003115e5750c0dc2872d6b1dc97745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 3 Mar 2023 12:05:00 +0200 Subject: [PATCH 594/715] core/rawdb, ethdb/pebble: disable pebble on openbsd (#26801) --- core/rawdb/databases_64bit.go | 2 +- core/rawdb/databases_non64bit.go | 2 +- ethdb/pebble/pebble.go | 2 +- ethdb/pebble/pebble_test.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/rawdb/databases_64bit.go b/core/rawdb/databases_64bit.go index 139ce7d34777..73bfeb20838f 100644 --- a/core/rawdb/databases_64bit.go +++ b/core/rawdb/databases_64bit.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see -//go:build arm64 || amd64 +//go:build (arm64 || amd64) && !openbsd package rawdb diff --git a/core/rawdb/databases_non64bit.go b/core/rawdb/databases_non64bit.go index b8ab2ecada2f..1f10c2f52bd2 100644 --- a/core/rawdb/databases_non64bit.go +++ b/core/rawdb/databases_non64bit.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build !(arm64 || amd64) +//go:build !((arm64 || amd64) && !openbsd) package rawdb diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 1f331fa33995..4e374c9e2832 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build arm64 || amd64 +//go:build (arm64 || amd64) && !openbsd // Package pebble implements the key-value database layer based on pebble. package pebble diff --git a/ethdb/pebble/pebble_test.go b/ethdb/pebble/pebble_test.go index c773967dc66f..590d5bf0353d 100644 --- a/ethdb/pebble/pebble_test.go +++ b/ethdb/pebble/pebble_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build arm64 || amd64 +//go:build (arm64 || amd64) && !openbsd package pebble From 010189538e7eebfbf72753bcd1f300e445edefdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 3 Mar 2023 12:11:39 +0200 Subject: [PATCH 595/715] core: fix a merge fault (#26802) --- core/chain_makers_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 6c4e0914362e..4f7355527553 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -118,7 +118,7 @@ func TestGenerateWithdrawalChain(t *testing.T) { // enforce that withdrawal indexes are monotonically increasing from 0 var ( withdrawalIndex uint64 - head = blockchain.CurrentBlock().NumberU64() + head = blockchain.CurrentBlock().Number.Uint64() ) for i := 0; i < int(head); i++ { block := blockchain.GetBlockByNumber(uint64(i)) From 403cac71eb593591f7f31aaa30eb63677520408e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 3 Mar 2023 12:24:09 +0200 Subject: [PATCH 596/715] README, go.mod, event, internal/version: bump min Go to 1.19 (#26803) --- README.md | 2 +- event/feedof.go | 3 --- event/feedof_test.go | 3 --- go.mod | 2 +- internal/version/{vcs_go1.18.go => vcs.go} | 3 --- internal/version/vcs_fallback.go | 28 ---------------------- 6 files changed, 2 insertions(+), 39 deletions(-) rename internal/version/{vcs_go1.18.go => vcs.go} (97%) delete mode 100644 internal/version/vcs_fallback.go diff --git a/README.md b/README.md index 9835b0045895..325f796a3e3b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ archives are published at https://geth.ethereum.org/downloads/. For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth). -Building `geth` requires both a Go (version 1.18 or later) and a C compiler. You can install +Building `geth` requires both a Go (version 1.19 or later) and a C compiler. You can install them using your favourite package manager. Once the dependencies are installed, run ```shell diff --git a/event/feedof.go b/event/feedof.go index 598038a19e24..4a24e37f1256 100644 --- a/event/feedof.go +++ b/event/feedof.go @@ -14,9 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build go1.18 -// +build go1.18 - package event import ( diff --git a/event/feedof_test.go b/event/feedof_test.go index 8478eeffb1e5..846afc9ee19e 100644 --- a/event/feedof_test.go +++ b/event/feedof_test.go @@ -14,9 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build go1.18 -// +build go1.18 - package event import ( diff --git a/go.mod b/go.mod index d917dad2113a..1be13e163e3d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ethereum/go-ethereum -go 1.18 +go 1.19 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 diff --git a/internal/version/vcs_go1.18.go b/internal/version/vcs.go similarity index 97% rename from internal/version/vcs_go1.18.go rename to internal/version/vcs.go index 53cd41fb3097..21de8946e803 100644 --- a/internal/version/vcs_go1.18.go +++ b/internal/version/vcs.go @@ -14,9 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -//go:build go1.18 -// +build go1.18 - package version import ( diff --git a/internal/version/vcs_fallback.go b/internal/version/vcs_fallback.go deleted file mode 100644 index f792c68cdb4c..000000000000 --- a/internal/version/vcs_fallback.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 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 !go1.18 -// +build !go1.18 - -package version - -import "runtime/debug" - -// In Go versions before 1.18, VCS information is not available. - -func buildInfoVCS(info *debug.BuildInfo) (VCSInfo, bool) { - return VCSInfo{}, false -} From 27e59827d804b0112c4213465ff3b902e25cb6d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 3 Mar 2023 12:26:04 +0200 Subject: [PATCH 597/715] travi: remove strange leftover Go version --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 176cc83996a0..6bc7712797dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ jobs: allow_failures: - stage: build os: osx - go: 1.17.x env: - azure-osx From d865a5d6ae3734a03c86e63fbb385edd92c3cc8d Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 6 Mar 2023 08:26:43 +0100 Subject: [PATCH 598/715] core, params: schedule Shanghai on goerli (#26795) * core: params: schedule Shanghai on goerli * core/forkid: fix comment --- core/forkid/forkid_test.go | 18 ++++++++++-------- params/config.go | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index 08a1da706d57..15918791ad10 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -107,14 +107,16 @@ func TestCreation(t *testing.T) { params.GoerliChainConfig, params.GoerliGenesisHash, []testcase{ - {0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block - {1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block - {1561651, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block - {4460643, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block - {4460644, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block - {5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block - {5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 0}}, // First London block - {6000000, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 0}}, // Future London block + {0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block + {1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block + {1561651, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block + {4460643, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block + {4460644, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block + {5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block + {5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // First London block + {6000000, 1678832735, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // Last London block + {6000001, 1678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 0}}, // First Shanghai block + {6500000, 2678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 0}}, // Future Shanghai block }, }, // Sepolia test cases diff --git a/params/config.go b/params/config.go index 816577a54795..adb5f44f0952 100644 --- a/params/config.go +++ b/params/config.go @@ -194,6 +194,7 @@ var ( ArrowGlacierBlock: nil, TerminalTotalDifficulty: big.NewInt(10_790_000), TerminalTotalDifficultyPassed: true, + ShanghaiTime: newUint64(1678832736), Clique: &CliqueConfig{ Period: 15, Epoch: 30000, From 4c23fe97c5472f2c0a6c89fcf4e459316110fb0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 6 Mar 2023 09:27:46 +0200 Subject: [PATCH 599/715] eth: remove admin.peers[i].eth.head and difficulty (#26804) --- eth/peer.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/eth/peer.go b/eth/peer.go index 55e5f0046206..761877771660 100644 --- a/eth/peer.go +++ b/eth/peer.go @@ -17,8 +17,6 @@ package eth import ( - "math/big" - "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" ) @@ -26,9 +24,7 @@ import ( // ethPeerInfo represents a short summary of the `eth` sub-protocol metadata known // about a connected peer. type ethPeerInfo struct { - Version uint `json:"version"` // Ethereum protocol version negotiated - Difficulty *big.Int `json:"difficulty"` // Total difficulty of the peer's blockchain - Head string `json:"head"` // Hex hash of the peer's best owned block + Version uint `json:"version"` // Ethereum protocol version negotiated } // ethPeer is a wrapper around eth.Peer to maintain a few extra metadata. @@ -39,12 +35,8 @@ type ethPeer struct { // info gathers and returns some `eth` protocol metadata known about a peer. func (p *ethPeer) info() *ethPeerInfo { - hash, td := p.Head() - return ðPeerInfo{ - Version: p.Version(), - Difficulty: td, - Head: hash.Hex(), + Version: p.Version(), } } From 87186148e0c4e46f7825e01cdcc57e833d1d3be6 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 6 Mar 2023 17:19:41 +0100 Subject: [PATCH 600/715] core/types: add EffectiveGasPrice in Receipt (#26713) This change adds a struct field EffectiveGasPrice in types.Receipt. The field is present in RPC responses, but not in the Go struct, and thus can't easily be accessed via ethclient. Co-authored-by: PulsarAI --- core/blockchain.go | 2 +- core/rawdb/accessors_chain.go | 9 +- core/types/gen_receipt_json.go | 6 + core/types/receipt.go | 16 +- core/types/receipt_test.go | 261 ++++++++++++++++++++------------- core/types/transaction.go | 8 + core/types/tx_access_list.go | 4 + core/types/tx_dynamic_fee.go | 11 ++ core/types/tx_legacy.go | 4 + internal/ethapi/api.go | 15 +- light/odr_util.go | 2 +- 11 files changed, 214 insertions(+), 124 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index f63ac845c1f2..f22562ccfa94 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2049,7 +2049,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) // the processing of a block. These logs are later announced as deleted or reborn. func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64()) - receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Transactions()) + receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.BaseFee(), b.Transactions()) var logs []*types.Log for _, receipt := range receipts { diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index e4dac3407fc5..3d0f36ba7644 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -636,7 +636,14 @@ func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, config *para log.Error("Missing body but have receipt", "hash", hash, "number", number) return nil } - if err := receipts.DeriveFields(config, hash, number, body.Transactions); err != nil { + header := ReadHeader(db, hash, number) + var baseFee *big.Int + if header == nil { + baseFee = big.NewInt(0) + } else { + baseFee = header.BaseFee + } + if err := receipts.DeriveFields(config, hash, number, baseFee, body.Transactions); err != nil { log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err) return nil } diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index bb892f85bec8..8d85dd5b9c1a 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -25,6 +25,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) { TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice,omitempty"` BlockHash common.Hash `json:"blockHash,omitempty"` BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` TransactionIndex hexutil.Uint `json:"transactionIndex"` @@ -39,6 +40,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) { enc.TxHash = r.TxHash enc.ContractAddress = r.ContractAddress enc.GasUsed = hexutil.Uint64(r.GasUsed) + enc.EffectiveGasPrice = (*hexutil.Big)(r.EffectiveGasPrice) enc.BlockHash = r.BlockHash enc.BlockNumber = (*hexutil.Big)(r.BlockNumber) enc.TransactionIndex = hexutil.Uint(r.TransactionIndex) @@ -57,6 +59,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { TxHash *common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress *common.Address `json:"contractAddress"` GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice,omitempty"` BlockHash *common.Hash `json:"blockHash,omitempty"` BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` TransactionIndex *hexutil.Uint `json:"transactionIndex"` @@ -97,6 +100,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'gasUsed' for Receipt") } r.GasUsed = uint64(*dec.GasUsed) + if dec.EffectiveGasPrice != nil { + r.EffectiveGasPrice = (*big.Int)(dec.EffectiveGasPrice) + } if dec.BlockHash != nil { r.BlockHash = *dec.BlockHash } diff --git a/core/types/receipt.go b/core/types/receipt.go index 4404b278891f..61b3b3517806 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -59,10 +59,10 @@ type Receipt struct { Logs []*Log `json:"logs" gencodec:"required"` // Implementation fields: These fields are added by geth when processing a transaction. - // They are stored in the chain database. - TxHash common.Hash `json:"transactionHash" gencodec:"required"` - ContractAddress common.Address `json:"contractAddress"` - GasUsed uint64 `json:"gasUsed" gencodec:"required"` + TxHash common.Hash `json:"transactionHash" gencodec:"required"` + ContractAddress common.Address `json:"contractAddress"` + GasUsed uint64 `json:"gasUsed" gencodec:"required"` + EffectiveGasPrice *big.Int `json:"effectiveGasPrice"` // Inclusion information: These fields provide information about the inclusion of the // transaction corresponding to this receipt. @@ -313,7 +313,7 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) { // DeriveFields fills the receipts with their computed fields based on consensus // data and contextual infos like containing block and transactions. -func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs Transactions) error { +func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, baseFee *big.Int, txs []*Transaction) error { signer := MakeSigner(config, new(big.Int).SetUint64(number)) logIndex := uint(0) @@ -325,6 +325,8 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, nu rs[i].Type = txs[i].Type() rs[i].TxHash = txs[i].Hash() + rs[i].EffectiveGasPrice = txs[i].inner.effectiveGasPrice(new(big.Int), baseFee) + // block location fields rs[i].BlockHash = hash rs[i].BlockNumber = new(big.Int).SetUint64(number) @@ -335,13 +337,17 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, nu // Deriving the signer is expensive, only do if it's actually needed from, _ := Sender(signer, txs[i]) rs[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce()) + } else { + rs[i].ContractAddress = common.Address{} } + // The used gas can be calculated based on previous r if i == 0 { rs[i].GasUsed = rs[i].CumulativeGasUsed } else { rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed } + // The derived log fields can simply be set from the block and transaction for j := 0; j < len(rs[i].Logs); j++ { rs[i].Logs[j].BlockNumber = number diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index f44bb80b04b4..376177f976ef 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -18,15 +18,16 @@ package types import ( "bytes" + "encoding/json" "math" "math/big" "reflect" "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "github.com/kylelemons/godebug/diff" ) var ( @@ -96,122 +97,177 @@ func TestDeriveFields(t *testing.T) { // Create a few transactions to have receipts for to2 := common.HexToAddress("0x2") to3 := common.HexToAddress("0x3") + to4 := common.HexToAddress("0x4") + to5 := common.HexToAddress("0x5") txs := Transactions{ NewTx(&LegacyTx{ Nonce: 1, Value: big.NewInt(1), Gas: 1, - GasPrice: big.NewInt(1), + GasPrice: big.NewInt(11), }), NewTx(&LegacyTx{ To: &to2, Nonce: 2, Value: big.NewInt(2), Gas: 2, - GasPrice: big.NewInt(2), + GasPrice: big.NewInt(22), }), NewTx(&AccessListTx{ To: &to3, Nonce: 3, Value: big.NewInt(3), Gas: 3, - GasPrice: big.NewInt(3), + GasPrice: big.NewInt(33), + }), + // EIP-1559 transactions. + NewTx(&DynamicFeeTx{ + To: &to4, + Nonce: 4, + Value: big.NewInt(4), + Gas: 4, + GasTipCap: big.NewInt(44), + GasFeeCap: big.NewInt(1045), + }), + NewTx(&DynamicFeeTx{ + To: &to5, + Nonce: 5, + Value: big.NewInt(5), + Gas: 5, + GasTipCap: big.NewInt(56), + GasFeeCap: big.NewInt(1055), }), } + + blockNumber := big.NewInt(1) + blockHash := common.BytesToHash([]byte{0x03, 0x14}) + // Create the corresponding receipts receipts := Receipts{ &Receipt{ Status: ReceiptStatusFailed, CumulativeGasUsed: 1, Logs: []*Log{ - {Address: common.BytesToAddress([]byte{0x11})}, - {Address: common.BytesToAddress([]byte{0x01, 0x11})}, + { + Address: common.BytesToAddress([]byte{0x11}), + // derived fields: + BlockNumber: blockNumber.Uint64(), + TxHash: txs[0].Hash(), + TxIndex: 0, + BlockHash: blockHash, + Index: 0, + }, + { + Address: common.BytesToAddress([]byte{0x01, 0x11}), + // derived fields: + BlockNumber: blockNumber.Uint64(), + TxHash: txs[0].Hash(), + TxIndex: 0, + BlockHash: blockHash, + Index: 1, + }, }, - TxHash: txs[0].Hash(), - ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), - GasUsed: 1, + // derived fields: + TxHash: txs[0].Hash(), + ContractAddress: common.HexToAddress("0x5a443704dd4b594b382c22a083e2bd3090a6fef3"), + GasUsed: 1, + EffectiveGasPrice: big.NewInt(11), + BlockHash: blockHash, + BlockNumber: blockNumber, + TransactionIndex: 0, }, &Receipt{ PostState: common.Hash{2}.Bytes(), CumulativeGasUsed: 3, Logs: []*Log{ - {Address: common.BytesToAddress([]byte{0x22})}, - {Address: common.BytesToAddress([]byte{0x02, 0x22})}, + { + Address: common.BytesToAddress([]byte{0x22}), + // derived fields: + BlockNumber: blockNumber.Uint64(), + TxHash: txs[1].Hash(), + TxIndex: 1, + BlockHash: blockHash, + Index: 2, + }, + { + Address: common.BytesToAddress([]byte{0x02, 0x22}), + // derived fields: + BlockNumber: blockNumber.Uint64(), + TxHash: txs[1].Hash(), + TxIndex: 1, + BlockHash: blockHash, + Index: 3, + }, }, - TxHash: txs[1].Hash(), - ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), - GasUsed: 2, + // derived fields: + TxHash: txs[1].Hash(), + GasUsed: 2, + EffectiveGasPrice: big.NewInt(22), + BlockHash: blockHash, + BlockNumber: blockNumber, + TransactionIndex: 1, }, &Receipt{ Type: AccessListTxType, PostState: common.Hash{3}.Bytes(), CumulativeGasUsed: 6, - Logs: []*Log{ - {Address: common.BytesToAddress([]byte{0x33})}, - {Address: common.BytesToAddress([]byte{0x03, 0x33})}, - }, - TxHash: txs[2].Hash(), - ContractAddress: common.BytesToAddress([]byte{0x03, 0x33, 0x33}), - GasUsed: 3, + Logs: []*Log{}, + // derived fields: + TxHash: txs[2].Hash(), + GasUsed: 3, + EffectiveGasPrice: big.NewInt(33), + BlockHash: blockHash, + BlockNumber: blockNumber, + TransactionIndex: 2, + }, + &Receipt{ + Type: DynamicFeeTxType, + PostState: common.Hash{4}.Bytes(), + CumulativeGasUsed: 10, + Logs: []*Log{}, + // derived fields: + TxHash: txs[3].Hash(), + GasUsed: 4, + EffectiveGasPrice: big.NewInt(1044), + BlockHash: blockHash, + BlockNumber: blockNumber, + TransactionIndex: 3, + }, + &Receipt{ + Type: DynamicFeeTxType, + PostState: common.Hash{5}.Bytes(), + CumulativeGasUsed: 15, + Logs: []*Log{}, + // derived fields: + TxHash: txs[4].Hash(), + GasUsed: 5, + EffectiveGasPrice: big.NewInt(1055), + BlockHash: blockHash, + BlockNumber: blockNumber, + TransactionIndex: 4, }, } - // Clear all the computed fields and re-derive them - number := big.NewInt(1) - hash := common.BytesToHash([]byte{0x03, 0x14}) - clearComputedFieldsOnReceipts(t, receipts) - if err := receipts.DeriveFields(params.TestChainConfig, hash, number.Uint64(), txs); err != nil { + // Re-derive receipts. + basefee := big.NewInt(1000) + derivedReceipts := clearComputedFieldsOnReceipts(receipts) + err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), basefee, txs) + if err != nil { t.Fatalf("DeriveFields(...) = %v, want ", err) } - // Iterate over all the computed fields and check that they're correct - signer := MakeSigner(params.TestChainConfig, number) - logIndex := uint(0) - for i := range receipts { - if receipts[i].Type != txs[i].Type() { - t.Errorf("receipts[%d].Type = %d, want %d", i, receipts[i].Type, txs[i].Type()) - } - if receipts[i].TxHash != txs[i].Hash() { - t.Errorf("receipts[%d].TxHash = %s, want %s", i, receipts[i].TxHash.String(), txs[i].Hash().String()) - } - if receipts[i].BlockHash != hash { - t.Errorf("receipts[%d].BlockHash = %s, want %s", i, receipts[i].BlockHash.String(), hash.String()) - } - if receipts[i].BlockNumber.Cmp(number) != 0 { - t.Errorf("receipts[%c].BlockNumber = %s, want %s", i, receipts[i].BlockNumber.String(), number.String()) - } - if receipts[i].TransactionIndex != uint(i) { - t.Errorf("receipts[%d].TransactionIndex = %d, want %d", i, receipts[i].TransactionIndex, i) - } - if receipts[i].GasUsed != txs[i].Gas() { - t.Errorf("receipts[%d].GasUsed = %d, want %d", i, receipts[i].GasUsed, txs[i].Gas()) - } - if txs[i].To() != nil && receipts[i].ContractAddress != (common.Address{}) { - t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), (common.Address{}).String()) - } - from, _ := Sender(signer, txs[i]) - contractAddress := crypto.CreateAddress(from, txs[i].Nonce()) - if txs[i].To() == nil && receipts[i].ContractAddress != contractAddress { - t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), contractAddress.String()) - } - for j := range receipts[i].Logs { - if receipts[i].Logs[j].BlockNumber != number.Uint64() { - t.Errorf("receipts[%d].Logs[%d].BlockNumber = %d, want %d", i, j, receipts[i].Logs[j].BlockNumber, number.Uint64()) - } - if receipts[i].Logs[j].BlockHash != hash { - t.Errorf("receipts[%d].Logs[%d].BlockHash = %s, want %s", i, j, receipts[i].Logs[j].BlockHash.String(), hash.String()) - } - if receipts[i].Logs[j].TxHash != txs[i].Hash() { - t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String()) - } - if receipts[i].Logs[j].TxIndex != uint(i) { - t.Errorf("receipts[%d].Logs[%d].TransactionIndex = %d, want %d", i, j, receipts[i].Logs[j].TxIndex, i) - } - if receipts[i].Logs[j].Index != logIndex { - t.Errorf("receipts[%d].Logs[%d].Index = %d, want %d", i, j, receipts[i].Logs[j].Index, logIndex) - } - logIndex++ - } + // Check diff of receipts against derivedReceipts. + r1, err := json.MarshalIndent(receipts, "", " ") + if err != nil { + t.Fatal("error marshaling input receipts:", err) + } + r2, err := json.MarshalIndent(derivedReceipts, "", " ") + if err != nil { + t.Fatal("error marshaling derived receipts:", err) + } + d := diff.Diff(string(r1), string(r2)) + if d != "" { + t.Fatal("receipts differ:", d) } } @@ -342,41 +398,36 @@ func TestReceiptUnmarshalBinary(t *testing.T) { } } -func clearComputedFieldsOnReceipts(t *testing.T, receipts Receipts) { - t.Helper() - - for _, receipt := range receipts { - clearComputedFieldsOnReceipt(t, receipt) +func clearComputedFieldsOnReceipts(receipts []*Receipt) []*Receipt { + r := make([]*Receipt, len(receipts)) + for i, receipt := range receipts { + r[i] = clearComputedFieldsOnReceipt(receipt) } + return r } -func clearComputedFieldsOnReceipt(t *testing.T, receipt *Receipt) { - t.Helper() - - receipt.TxHash = common.Hash{} - receipt.BlockHash = common.Hash{} - receipt.BlockNumber = big.NewInt(math.MaxUint32) - receipt.TransactionIndex = math.MaxUint32 - receipt.ContractAddress = common.Address{} - receipt.GasUsed = 0 - - clearComputedFieldsOnLogs(t, receipt.Logs) +func clearComputedFieldsOnReceipt(receipt *Receipt) *Receipt { + cpy := *receipt + cpy.TxHash = common.Hash{0xff, 0xff, 0x11} + cpy.BlockHash = common.Hash{0xff, 0xff, 0x22} + cpy.BlockNumber = big.NewInt(math.MaxUint32) + cpy.TransactionIndex = math.MaxUint32 + cpy.ContractAddress = common.Address{0xff, 0xff, 0x33} + cpy.GasUsed = 0xffffffff + cpy.Logs = clearComputedFieldsOnLogs(receipt.Logs) + return &cpy } -func clearComputedFieldsOnLogs(t *testing.T, logs []*Log) { - t.Helper() - - for _, log := range logs { - clearComputedFieldsOnLog(t, log) +func clearComputedFieldsOnLogs(logs []*Log) []*Log { + l := make([]*Log, len(logs)) + for i, log := range logs { + cpy := *log + cpy.BlockNumber = math.MaxUint32 + cpy.BlockHash = common.Hash{} + cpy.TxHash = common.Hash{} + cpy.TxIndex = math.MaxUint32 + cpy.Index = math.MaxUint32 + l[i] = &cpy } -} - -func clearComputedFieldsOnLog(t *testing.T, log *Log) { - t.Helper() - - log.BlockNumber = math.MaxUint32 - log.BlockHash = common.Hash{} - log.TxHash = common.Hash{} - log.TxIndex = math.MaxUint32 - log.Index = math.MaxUint32 + return l } diff --git a/core/types/transaction.go b/core/types/transaction.go index 353e0e599c68..cd212edbe3b3 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -85,6 +85,14 @@ type TxData interface { rawSignatureValues() (v, r, s *big.Int) setSignatureValues(chainID, v, r, s *big.Int) + + // effectiveGasPrice computes the gas price paid by the transaction, given + // the inclusion block baseFee. + // + // Unlike other TxData methods, the returned *big.Int should be an independent + // copy of the computed value, i.e. callers are allowed to mutate the result. + // Method implementations can use 'dst' to store the result. + effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int } // EncodeRLP implements rlp.Encoder diff --git a/core/types/tx_access_list.go b/core/types/tx_access_list.go index 620848fe624a..692bba4ff2d9 100644 --- a/core/types/tx_access_list.go +++ b/core/types/tx_access_list.go @@ -106,6 +106,10 @@ func (tx *AccessListTx) value() *big.Int { return tx.Value } func (tx *AccessListTx) nonce() uint64 { return tx.Nonce } func (tx *AccessListTx) to() *common.Address { return tx.To } +func (tx *AccessListTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { + return dst.Set(tx.GasPrice) +} + func (tx *AccessListTx) rawSignatureValues() (v, r, s *big.Int) { return tx.V, tx.R, tx.S } diff --git a/core/types/tx_dynamic_fee.go b/core/types/tx_dynamic_fee.go index 53f246ea1fad..570810665817 100644 --- a/core/types/tx_dynamic_fee.go +++ b/core/types/tx_dynamic_fee.go @@ -94,6 +94,17 @@ func (tx *DynamicFeeTx) value() *big.Int { return tx.Value } func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce } func (tx *DynamicFeeTx) to() *common.Address { return tx.To } +func (tx *DynamicFeeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { + if baseFee == nil { + return dst.Set(tx.GasFeeCap) + } + tip := dst.Sub(tx.GasFeeCap, baseFee) + if tip.Cmp(tx.GasTipCap) > 0 { + tip.Set(tx.GasTipCap) + } + return tip.Add(tip, baseFee) +} + func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) { return tx.V, tx.R, tx.S } diff --git a/core/types/tx_legacy.go b/core/types/tx_legacy.go index 14d307829cc9..988de7db09aa 100644 --- a/core/types/tx_legacy.go +++ b/core/types/tx_legacy.go @@ -103,6 +103,10 @@ func (tx *LegacyTx) value() *big.Int { return tx.Value } func (tx *LegacyTx) nonce() uint64 { return tx.Nonce } func (tx *LegacyTx) to() *common.Address { return tx.To } +func (tx *LegacyTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { + return dst.Set(tx.GasPrice) +} + func (tx *LegacyTx) rawSignatureValues() (v, r, s *big.Int) { return tx.V, tx.R, tx.S } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a2a3366c9739..7091e4900155 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1621,6 +1621,7 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common. // as per specification. return nil, nil } + receipts, err := s.b.GetReceipts(ctx, blockHash) if err != nil { return nil, err @@ -1648,18 +1649,9 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common. "logs": receipt.Logs, "logsBloom": receipt.Bloom, "type": hexutil.Uint(tx.Type()), + "effectiveGasPrice": (*hexutil.Big)(receipt.EffectiveGasPrice), } - // Assign the effective gas price paid - if !s.b.ChainConfig().IsLondon(bigblock) { - fields["effectiveGasPrice"] = hexutil.Uint64(tx.GasPrice().Uint64()) - } else { - header, err := s.b.HeaderByHash(ctx, blockHash) - if err != nil { - return nil, err - } - gasPrice := new(big.Int).Add(header.BaseFee, tx.EffectiveGasTipValue(header.BaseFee)) - fields["effectiveGasPrice"] = hexutil.Uint64(gasPrice.Uint64()) - } + // Assign receipt status or post state. if len(receipt.PostState) > 0 { fields["root"] = hexutil.Bytes(receipt.PostState) @@ -1669,6 +1661,7 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common. if receipt.Logs == nil { fields["logs"] = []*types.Log{} } + // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation if receipt.ContractAddress != (common.Address{}) { fields["contractAddress"] = receipt.ContractAddress diff --git a/light/odr_util.go b/light/odr_util.go index c49af3a1fb7a..786b54132aa7 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -175,7 +175,7 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num genesis := rawdb.ReadCanonicalHash(odr.Database(), 0) config := rawdb.ReadChainConfig(odr.Database(), genesis) - if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Transactions()); err != nil { + if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.BaseFee(), block.Transactions()); err != nil { return nil, err } rawdb.WriteReceipts(odr.Database(), hash, number, receipts) From 5bc2ef984faedc815f75107c9120a6774f55ae8e Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 6 Mar 2023 23:32:27 +0100 Subject: [PATCH 601/715] core, eth/catalyst: fix race conditions in tests (#26790) Fixes a race in TestNewPayloadOnInvalidTerminalBlock where setting the TTD raced with the miner. Solution: set the TTD on the blockchain config not the genesis config. Also fixes a race in CopyHeader which resulted in race reports all over the place. --- core/types/block.go | 1 + eth/catalyst/api_test.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/types/block.go b/core/types/block.go index 82ad3ce99cb7..e2c71abebd70 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -279,6 +279,7 @@ func CopyHeader(h *Header) *Header { copy(cpy.Extra, h.Extra) } if h.WithdrawalsHash != nil { + cpy.WithdrawalsHash = new(common.Hash) *cpy.WithdrawalsHash = *h.WithdrawalsHash } return &cpy diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index f1af087cf00a..09972691729e 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -874,7 +874,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() - genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty()) + ethservice.BlockChain().Config().TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty()) var ( api = NewConsensusAPI(ethservice) From 544e4a700b185b226741e8e308ccbc1a241d26ae Mon Sep 17 00:00:00 2001 From: turboboost55 <7891737+turboboost55@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:29:48 -0800 Subject: [PATCH 602/715] metrics: improve accuracy of CPU gauges (#26793) This PR changes metrics collection to actually measure the time interval between collections, rather than assume 3 seconds. I did some ad hoc profiling, and on slower hardware (eg, my Raspberry Pi 4) I routinely saw intervals between 3.3 - 3.5 seconds, with some being as high as 4.5 seconds. This will generally cause the CPU gauge readings to be too high, and in some cases can cause impossibly large values for the CPU load metrics (eg. greater than 400 for a 4 core CPU). --------- Co-authored-by: Felix Lange --- metrics/cpu.go | 7 ++++--- metrics/cpu_enabled.go | 4 ++-- metrics/cputime_nop.go | 2 +- metrics/cputime_unix.go | 4 ++-- metrics/metrics.go | 21 +++++++++++++++------ 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/metrics/cpu.go b/metrics/cpu.go index 72ece16e0768..3a49cd42493a 100644 --- a/metrics/cpu.go +++ b/metrics/cpu.go @@ -17,8 +17,9 @@ package metrics // CPUStats is the system and process CPU stats. +// All values are in seconds. type CPUStats struct { - GlobalTime int64 // Time spent by the CPU working on all processes - GlobalWait int64 // Time spent by waiting on disk for all processes - LocalTime int64 // Time spent by the CPU working on this process + GlobalTime float64 // Time spent by the CPU working on all processes + GlobalWait float64 // Time spent by waiting on disk for all processes + LocalTime float64 // Time spent by the CPU working on this process } diff --git a/metrics/cpu_enabled.go b/metrics/cpu_enabled.go index 533d40b85a58..2359028a2120 100644 --- a/metrics/cpu_enabled.go +++ b/metrics/cpu_enabled.go @@ -38,7 +38,7 @@ func ReadCPUStats(stats *CPUStats) { } // requesting all cpu times will always return an array with only one time stats entry timeStat := timeStats[0] - stats.GlobalTime = int64((timeStat.User + timeStat.Nice + timeStat.System) * cpu.ClocksPerSec) - stats.GlobalWait = int64((timeStat.Iowait) * cpu.ClocksPerSec) + stats.GlobalTime = timeStat.User + timeStat.Nice + timeStat.System + stats.GlobalWait = timeStat.Iowait stats.LocalTime = getProcessCPUTime() } diff --git a/metrics/cputime_nop.go b/metrics/cputime_nop.go index 0188735a7833..465d88c4d232 100644 --- a/metrics/cputime_nop.go +++ b/metrics/cputime_nop.go @@ -21,6 +21,6 @@ package metrics // getProcessCPUTime returns 0 on Windows as there is no system call to resolve // the actual process' CPU time. -func getProcessCPUTime() int64 { +func getProcessCPUTime() float64 { return 0 } diff --git a/metrics/cputime_unix.go b/metrics/cputime_unix.go index 3c56a75d0077..ad4f812fd285 100644 --- a/metrics/cputime_unix.go +++ b/metrics/cputime_unix.go @@ -26,11 +26,11 @@ import ( ) // getProcessCPUTime retrieves the process' CPU time since program startup. -func getProcessCPUTime() int64 { +func getProcessCPUTime() float64 { var usage syscall.Rusage if err := syscall.Getrusage(syscall.RUSAGE_SELF, &usage); err != nil { log.Warn("Failed to retrieve CPU time", "err", err) return 0 } - return int64(usage.Utime.Sec+usage.Stime.Sec)*100 + int64(usage.Utime.Usec+usage.Stime.Usec)/10000 //nolint:unconvert + return float64(usage.Utime.Sec+usage.Stime.Sec) + float64(usage.Utime.Usec+usage.Stime.Usec)/1000000 //nolint:unconvert } diff --git a/metrics/metrics.go b/metrics/metrics.go index 2edf8e35f151..ff7196b56494 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -127,8 +127,6 @@ func CollectProcessMetrics(refresh time.Duration) { return } - refreshFreq := int64(refresh / time.Second) - // Create the various data collectors var ( cpustats = make([]CPUStats, 2) @@ -163,14 +161,25 @@ func CollectProcessMetrics(refresh time.Duration) { diskWriteBytesCounter = GetOrRegisterCounter("system/disk/writebytes", DefaultRegistry) ) + var lastCollectTime time.Time + // Iterate loading the different stats and updating the meters. now, prev := 0, 1 for ; ; now, prev = prev, now { - // CPU + // Gather CPU times. ReadCPUStats(&cpustats[now]) - cpuSysLoad.Update((cpustats[now].GlobalTime - cpustats[prev].GlobalTime) / refreshFreq) - cpuSysWait.Update((cpustats[now].GlobalWait - cpustats[prev].GlobalWait) / refreshFreq) - cpuProcLoad.Update((cpustats[now].LocalTime - cpustats[prev].LocalTime) / refreshFreq) + collectTime := time.Now() + secondsSinceLastCollect := collectTime.Sub(lastCollectTime).Seconds() + lastCollectTime = collectTime + if secondsSinceLastCollect > 0 { + sysLoad := (cpustats[now].GlobalTime - cpustats[prev].GlobalTime) / secondsSinceLastCollect + sysWait := (cpustats[now].GlobalWait - cpustats[prev].GlobalWait) / secondsSinceLastCollect + procLoad := (cpustats[now].LocalTime - cpustats[prev].LocalTime) / secondsSinceLastCollect + // Convert to integer percentage. + cpuSysLoad.Update(int64(sysLoad * 100)) + cpuSysWait.Update(int64(sysWait * 100)) + cpuProcLoad.Update(int64(procLoad * 100)) + } // Threads cpuThreads.Update(int64(threadCreateProfile.Count())) From 4688d3c8f45cab05329906d96d9c63ba9cd9f398 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 7 Mar 2023 11:21:23 +0100 Subject: [PATCH 603/715] ethclient: fix panic when requesting missing blocks (#26817) This fixes a regression introduced by #26723. Fixes #26816. --- ethclient/ethclient.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 6f309030bab9..c8353b25ae21 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -113,15 +113,19 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface err := ec.c.CallContext(ctx, &raw, method, args...) if err != nil { return nil, err - } else if len(raw) == 0 { - return nil, ethereum.NotFound } + // Decode header and transactions. var head *types.Header - var body rpcBlock if err := json.Unmarshal(raw, &head); err != nil { return nil, err } + // When the block is not found, the API returns JSON null. + if head == nil { + return nil, ethereum.NotFound + } + + var body rpcBlock if err := json.Unmarshal(raw, &body); err != nil { return nil, err } From 77e33e5a49be99130a02dc72d6a0e4739fdd44d6 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 7 Mar 2023 18:23:52 +0800 Subject: [PATCH 604/715] core, miner: revert block gas counter in case of invalid transaction (#26799) This change fixes a flaw where, in certain scenarios, the block sealer did not accurately reset the remaining gas after failing to include an invalid transaction. Fixes #26791 --- cmd/evm/internal/t8ntool/execution.go | 9 +++++++-- core/gaspool.go | 5 +++++ miner/worker.go | 7 +++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 2c68659945eb..b023dde932d0 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -176,8 +176,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, vmConfig.Tracer = tracer vmConfig.Debug = (tracer != nil) statedb.SetTxContext(tx.Hash(), txIndex) - txContext := core.NewEVMTxContext(msg) - snapshot := statedb.Snapshot() + + var ( + txContext = core.NewEVMTxContext(msg) + snapshot = statedb.Snapshot() + prevGas = gaspool.Gas() + ) evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) // (ret []byte, usedGas uint64, failed bool, err error) @@ -186,6 +190,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, statedb.RevertToSnapshot(snapshot) log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) + gaspool.SetGas(prevGas) continue } includedTxs = append(includedTxs, tx) diff --git a/core/gaspool.go b/core/gaspool.go index e3795c1ee9ef..767222674f77 100644 --- a/core/gaspool.go +++ b/core/gaspool.go @@ -49,6 +49,11 @@ func (gp *GasPool) Gas() uint64 { return uint64(*gp) } +// SetGas sets the amount of gas with the provided number. +func (gp *GasPool) SetGas(gas uint64) { + *(*uint64)(gp) = gas +} + func (gp *GasPool) String() string { return fmt.Sprintf("%d", *gp) } diff --git a/miner/worker.go b/miner/worker.go index 8940c5037b41..67a5842d23e0 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -861,11 +861,14 @@ func (w *worker) updateSnapshot(env *environment) { } func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]*types.Log, error) { - snap := env.state.Snapshot() - + var ( + snap = env.state.Snapshot() + gp = env.gasPool.Gas() + ) receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *w.chain.GetVMConfig()) if err != nil { env.state.RevertToSnapshot(snap) + env.gasPool.SetGas(gp) return nil, err } env.txs = append(env.txs, tx) From 39be753bf52b0c31c723423701a4c400743a9870 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Tue, 7 Mar 2023 20:26:19 +1000 Subject: [PATCH 605/715] internal/ethapi: add tests for transaction types JSON marshal/unmarshal (#26667) Checks that Transaction.MarshalJSON and newRPCTransaction JSON output can be parsed by Transaction.UnmarshalJSON --------- Co-authored-by: Martin Holst Swende --- internal/ethapi/api_test.go | 159 ++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 internal/ethapi/api_test.go diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go new file mode 100644 index 000000000000..762dc8337d30 --- /dev/null +++ b/internal/ethapi/api_test.go @@ -0,0 +1,159 @@ +// Copyright 2023 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 ethapi + +import ( + "encoding/json" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" +) + +func TestTransaction_RoundTripRpcJSON(t *testing.T) { + var ( + config = params.AllEthashProtocolChanges + signer = types.LatestSigner(config) + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + tests = allTransactionTypes(common.Address{0xde, 0xad}, config) + ) + t.Parallel() + for i, tt := range tests { + var tx2 types.Transaction + tx, err := types.SignNewTx(key, signer, tt) + if err != nil { + t.Fatalf("test %d: signing failed: %v", i, err) + } + // Regular transaction + if data, err := json.Marshal(tx); err != nil { + t.Fatalf("test %d: marshalling failed; %v", i, err) + } else if err = tx2.UnmarshalJSON(data); err != nil { + t.Fatalf("test %d: sunmarshal failed: %v", i, err) + } else if want, have := tx.Hash(), tx2.Hash(); want != have { + t.Fatalf("test %d: stx changed, want %x have %x", i, want, have) + } + + // rpcTransaction + rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, nil, config) + if data, err := json.Marshal(rpcTx); err != nil { + t.Fatalf("test %d: marshalling failed; %v", i, err) + } else if err = tx2.UnmarshalJSON(data); err != nil { + t.Fatalf("test %d: unmarshal failed: %v", i, err) + } else if want, have := tx.Hash(), tx2.Hash(); want != have { + t.Fatalf("test %d: tx changed, want %x have %x", i, want, have) + } + } +} + +func allTransactionTypes(addr common.Address, config *params.ChainConfig) []types.TxData { + return []types.TxData{ + &types.LegacyTx{ + Nonce: 5, + GasPrice: big.NewInt(6), + Gas: 7, + To: &addr, + Value: big.NewInt(8), + Data: []byte{0, 1, 2, 3, 4}, + V: big.NewInt(9), + R: big.NewInt(10), + S: big.NewInt(11), + }, + &types.LegacyTx{ + Nonce: 5, + GasPrice: big.NewInt(6), + Gas: 7, + To: nil, + Value: big.NewInt(8), + Data: []byte{0, 1, 2, 3, 4}, + V: big.NewInt(32), + R: big.NewInt(10), + S: big.NewInt(11), + }, + &types.AccessListTx{ + ChainID: config.ChainID, + Nonce: 5, + GasPrice: big.NewInt(6), + Gas: 7, + To: &addr, + Value: big.NewInt(8), + Data: []byte{0, 1, 2, 3, 4}, + AccessList: types.AccessList{ + types.AccessTuple{ + Address: common.Address{0x2}, + StorageKeys: []common.Hash{types.EmptyRootHash}, + }, + }, + V: big.NewInt(32), + R: big.NewInt(10), + S: big.NewInt(11), + }, + &types.AccessListTx{ + ChainID: config.ChainID, + Nonce: 5, + GasPrice: big.NewInt(6), + Gas: 7, + To: nil, + Value: big.NewInt(8), + Data: []byte{0, 1, 2, 3, 4}, + AccessList: types.AccessList{ + types.AccessTuple{ + Address: common.Address{0x2}, + StorageKeys: []common.Hash{types.EmptyRootHash}, + }, + }, + V: big.NewInt(32), + R: big.NewInt(10), + S: big.NewInt(11), + }, + &types.DynamicFeeTx{ + ChainID: config.ChainID, + Nonce: 5, + GasTipCap: big.NewInt(6), + GasFeeCap: big.NewInt(9), + Gas: 7, + To: &addr, + Value: big.NewInt(8), + Data: []byte{0, 1, 2, 3, 4}, + AccessList: types.AccessList{ + types.AccessTuple{ + Address: common.Address{0x2}, + StorageKeys: []common.Hash{types.EmptyRootHash}, + }, + }, + V: big.NewInt(32), + R: big.NewInt(10), + S: big.NewInt(11), + }, + &types.DynamicFeeTx{ + ChainID: config.ChainID, + Nonce: 5, + GasTipCap: big.NewInt(6), + GasFeeCap: big.NewInt(9), + Gas: 7, + To: nil, + Value: big.NewInt(8), + Data: []byte{0, 1, 2, 3, 4}, + AccessList: types.AccessList{}, + V: big.NewInt(32), + R: big.NewInt(10), + S: big.NewInt(11), + }, + } +} From cb1f6bdbc8eb5dbdce032c45ae8d05d9945f39ab Mon Sep 17 00:00:00 2001 From: Guruprasad Kamath <48196632+gurukamath@users.noreply.github.com> Date: Tue, 7 Mar 2023 11:32:52 +0100 Subject: [PATCH 606/715] cmd/evm: correct `alloc` for `t8n` testdata (#26822) Fixes a minor error in the testdata --- cmd/evm/testdata/9/env.json | 2 +- cmd/evm/testdata/9/readme.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/evm/testdata/9/env.json b/cmd/evm/testdata/9/env.json index ec5164b9952e..082bff778a3a 100644 --- a/cmd/evm/testdata/9/env.json +++ b/cmd/evm/testdata/9/env.json @@ -1,7 +1,7 @@ { "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentDifficulty": "0x20000", - "currentGasTarget": "0x1000000000", + "currentGasLimit": "0x1000000000", "currentBaseFee": "0x3B9ACA00", "currentNumber": "0x1000000", "currentTimestamp": "0x04" diff --git a/cmd/evm/testdata/9/readme.md b/cmd/evm/testdata/9/readme.md index 88f0f12aaaa5..f26225a342ee 100644 --- a/cmd/evm/testdata/9/readme.md +++ b/cmd/evm/testdata/9/readme.md @@ -44,10 +44,10 @@ $ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.jso "nonce": "0x1" }, "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { - "balance": "0xbfc02677a000" + "balance": "0x5bb10ddef6e0" }, "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0xff104fcfea7800", + "balance": "0xff745ee8832120", "nonce": "0x2" } } From 41af42e97c9d62d303a883cc3c143f560867fa34 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 7 Mar 2023 17:09:11 +0330 Subject: [PATCH 607/715] eth/tracers/native: set created address to nil in case of failure (#26779) Fixes #26073 --- .../internal/tracetest/calltrace_test.go | 2 +- .../inner_create_oog_outer_throw.json | 1 - .../call_tracer/inner_revert_reason.json | 1 - eth/tracers/native/call.go | 30 ++++++++++--------- eth/tracers/native/call_flat.go | 8 ++--- eth/tracers/native/gen_callframe_json.go | 28 ++++++++--------- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 808841ade111..2d9bdaed7138 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -58,7 +58,7 @@ type callTrace struct { From common.Address `json:"from"` Gas *hexutil.Uint64 `json:"gas"` GasUsed *hexutil.Uint64 `json:"gasUsed"` - To common.Address `json:"to,omitempty"` + To *common.Address `json:"to,omitempty"` Input hexutil.Bytes `json:"input"` Output hexutil.Bytes `json:"output,omitempty"` Error string `json:"error,omitempty"` diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json index 40d240e4b82b..95c5889269fc 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json @@ -58,7 +58,6 @@ { "error": "contract creation code storage out of gas", "from": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", - "to": "0x0000000000000000000000000000000000000000", "gas": "0x39ff0", "gasUsed": "0x39ff0", "input": "0x606060405234620000005760405160208062001fd283398101604052515b805b600a8054600160a060020a031916600160a060020a0383161790555b506001600d819055600e81905560408051808201909152600c8082527f566f74696e672053746f636b00000000000000000000000000000000000000006020928301908152600b805460008290528251601860ff1990911617825590947f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9600291831615610100026000190190921604601f0193909304830192906200010c565b828001600101855582156200010c579182015b828111156200010c578251825591602001919060010190620000ef565b5b50620001309291505b808211156200012c576000815560010162000116565b5090565b50506040805180820190915260038082527f43565300000000000000000000000000000000000000000000000000000000006020928301908152600c805460008290528251600660ff1990911617825590937fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c760026001841615610100026000190190931692909204601f010481019291620001f7565b82800160010185558215620001f7579182015b82811115620001f7578251825591602001919060010190620001da565b5b506200021b9291505b808211156200012c576000815560010162000116565b5090565b50505b505b611da280620002306000396000f3006060604052361561019a5763ffffffff60e060020a600035041662e1986d811461019f57806302a72a4c146101d657806306eb4e421461020157806306fdde0314610220578063095ea7b3146102ad578063158ccb99146102dd57806318160ddd146102f85780631cf65a781461031757806323b872dd146103365780632c71e60a1461036c57806333148fd6146103ca578063435ebc2c146103f55780635eeb6e451461041e578063600e85b71461043c5780636103d70b146104a157806362c1e46a146104b05780636c182e99146104ba578063706dc87c146104f057806370a082311461052557806377174f851461055057806395d89b411461056f578063a7771ee3146105fc578063a9059cbb14610629578063ab377daa14610659578063b25dbb5e14610685578063b89a73cb14610699578063ca5eb5e1146106c6578063cbcf2e5a146106e1578063d21f05ba1461070e578063d347c2051461072d578063d96831e114610765578063dd62ed3e14610777578063df3c211b146107a8578063e2982c21146107d6578063eb944e4c14610801575b610000565b34610000576101d4600160a060020a036004351660243567ffffffffffffffff6044358116906064358116906084351661081f565b005b34610000576101ef600160a060020a0360043516610a30565b60408051918252519081900360200190f35b34610000576101ef610a4f565b60408051918252519081900360200190f35b346100005761022d610a55565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516602435610ae3565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516610b4e565b005b34610000576101ef610b89565b60408051918252519081900360200190f35b34610000576101ef610b8f565b60408051918252519081900360200190f35b34610000576102c9600160a060020a0360043581169060243516604435610b95565b604080519115158252519081900360200190f35b3461000057610388600160a060020a0360043516602435610bb7565b60408051600160a060020a039096168652602086019490945267ffffffffffffffff928316858501529082166060850152166080830152519081900360a00190f35b34610000576101ef600160a060020a0360043516610c21565b60408051918252519081900360200190f35b3461000057610402610c40565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d4600160a060020a0360043516602435610c4f565b005b3461000057610458600160a060020a0360043516602435610cc9565b60408051600160a060020a03909716875260208701959095528585019390935267ffffffffffffffff9182166060860152811660808501521660a0830152519081900360c00190f35b34610000576101d4610d9e565b005b6101d4610e1e565b005b34610000576104d3600160a060020a0360043516610e21565b6040805167ffffffffffffffff9092168252519081900360200190f35b3461000057610402600160a060020a0360043516610ead565b60408051600160a060020a039092168252519081900360200190f35b34610000576101ef600160a060020a0360043516610ef9565b60408051918252519081900360200190f35b34610000576101ef610f18565b60408051918252519081900360200190f35b346100005761022d610f1e565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516610fac565b604080519115158252519081900360200190f35b34610000576102c9600160a060020a0360043516602435610fc2565b604080519115158252519081900360200190f35b3461000057610402600435610fe2565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d46004351515610ffd565b005b34610000576102c9600160a060020a036004351661104c565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516611062565b005b34610000576102c9600160a060020a0360043516611070565b604080519115158252519081900360200190f35b34610000576101ef6110f4565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351667ffffffffffffffff602435166110fa565b60408051918252519081900360200190f35b34610000576101d4600435611121565b005b34610000576101ef600160a060020a03600435811690602435166111c6565b60408051918252519081900360200190f35b34610000576101ef6004356024356044356064356084356111f3565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351661128c565b60408051918252519081900360200190f35b34610000576101d4600160a060020a036004351660243561129e565b005b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff848116908416101561086457610000565b8367ffffffffffffffff168267ffffffffffffffff16101561088557610000565b8267ffffffffffffffff168267ffffffffffffffff1610156108a657610000565b506040805160a081018252600160a060020a033381168252602080830188905267ffffffffffffffff80871684860152858116606085015287166080840152908816600090815260039091529190912080546001810180835582818380158290116109615760030281600302836000526020600020918201910161096191905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050916000526020600020906003020160005b5082518154600160a060020a031916600160a060020a03909116178155602083015160018201556040830151600290910180546060850151608086015167ffffffffffffffff1990921667ffffffffffffffff948516176fffffffffffffffff00000000000000001916604060020a918516919091021777ffffffffffffffff000000000000000000000000000000001916608060020a939091169290920291909117905550610a268686610fc2565b505b505050505050565b600160a060020a0381166000908152600360205260409020545b919050565b60055481565b600b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b600a5433600160a060020a03908116911614610b6957610000565b600a8054600160a060020a031916600160a060020a0383161790555b5b50565b60005481565b60005b90565b6000610ba2848484611600565b610bad8484846116e2565b90505b9392505050565b600360205281600052604060002081815481101561000057906000526020600020906003020160005b5080546001820154600290920154600160a060020a03909116935090915067ffffffffffffffff80821691604060020a8104821691608060020a9091041685565b600160a060020a0381166000908152600860205260409020545b919050565b600a54600160a060020a031681565b600a5433600160a060020a03908116911614610c6a57610000565b610c7660005482611714565b6000908155600160a060020a038316815260016020526040902054610c9b9082611714565b600160a060020a038316600090815260016020526040812091909155610cc390839083611600565b5b5b5050565b6000600060006000600060006000600360008a600160a060020a0316600160a060020a0316815260200190815260200160002088815481101561000057906000526020600020906003020160005b508054600182015460028301546040805160a081018252600160a060020a039094168085526020850184905267ffffffffffffffff808416928601839052604060020a8404811660608701819052608060020a9094041660808601819052909c50929a509197509095509350909150610d90904261172d565b94505b509295509295509295565b33600160a060020a038116600090815260066020526040902054801515610dc457610000565b8030600160a060020a0316311015610ddb57610000565b600160a060020a0382166000818152600660205260408082208290555183156108fc0291849190818181858888f193505050501515610cc357610000565b5b5050565b5b565b600160a060020a03811660009081526003602052604081205442915b81811015610ea557600160a060020a03841660009081526003602052604090208054610e9a9190839081101561000057906000526020600020906003020160005b5060020154604060020a900467ffffffffffffffff168461177d565b92505b600101610e3d565b5b5050919050565b600160a060020a0380821660009081526007602052604081205490911615610eef57600160a060020a0380831660009081526007602052604090205416610ef1565b815b90505b919050565b600160a060020a0381166000908152600160205260409020545b919050565b600d5481565b600c805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b60006000610fb983610c21565b1190505b919050565b6000610fcf338484611600565b610fd983836117ac565b90505b92915050565b600460205260009081526040902054600160a060020a031681565b8015801561101a575061100f33610ef9565b61101833610c21565b115b1561102457610000565b33600160a060020a03166000908152600960205260409020805460ff19168215151790555b50565b60006000610fb983610ef9565b1190505b919050565b610b8533826117dc565b5b50565b600a54604080516000602091820181905282517fcbcf2e5a000000000000000000000000000000000000000000000000000000008152600160a060020a03868116600483015293519194939093169263cbcf2e5a92602480830193919282900301818787803b156100005760325a03f115610000575050604051519150505b919050565b600e5481565b6000610fd961110984846118b2565b61111385856119b6565b611a05565b90505b92915050565b600a5433600160a060020a0390811691161461113c57610000565b61114860005482611a1f565b600055600554600190101561116c57600a5461116c90600160a060020a0316611a47565b5b600a54600160a060020a03166000908152600160205260409020546111929082611a1f565b600a8054600160a060020a039081166000908152600160205260408120939093559054610b8592911683611600565b5b5b50565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b92915050565b6000600060008487101561120a5760009250611281565b8387111561121a57879250611281565b61123f6112308961122b888a611714565b611a90565b61123a8689611714565b611abc565b915081925061124e8883611714565b905061127e8361127961126a8461122b8c8b611714565b611a90565b61123a888b611714565b611abc565b611a1f565b92505b505095945050505050565b60066020526000908152604090205481565b600160a060020a03821660009081526003602052604081208054829190849081101561000057906000526020600020906003020160005b50805490925033600160a060020a039081169116146112f357610000565b6040805160a0810182528354600160a060020a0316815260018401546020820152600284015467ffffffffffffffff80821693830193909352604060020a810483166060830152608060020a900490911660808201526113539042611af9565b600160a060020a0385166000908152600360205260409020805491925090849081101561000057906000526020600020906003020160005b508054600160a060020a031916815560006001820181905560029091018054600160c060020a0319169055600160a060020a0385168152600360205260409020805460001981019081101561000057906000526020600020906003020160005b50600160a060020a03851660009081526003602052604090208054859081101561000057906000526020600020906003020160005b5081548154600160a060020a031916600160a060020a03918216178255600180840154908301556002928301805493909201805467ffffffffffffffff191667ffffffffffffffff948516178082558354604060020a908190048616026fffffffffffffffff000000000000000019909116178082559254608060020a9081900490941690930277ffffffffffffffff00000000000000000000000000000000199092169190911790915584166000908152600360205260409020805460001981018083559190829080158290116115485760030281600302836000526020600020918201910161154891905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050600160a060020a033316600090815260016020526040902054611570915082611a1f565b600160a060020a03338116600090815260016020526040808220939093559086168152205461159f9082611714565b600160a060020a038086166000818152600160209081526040918290209490945580518581529051339093169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35b50505050565b600160a060020a0383161561166e576116466008600061161f86610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611714565b6008600061165386610ead565b600160a060020a031681526020810191909152604001600020555b600160a060020a038216156116dc576116b46008600061168d85610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611a1f565b600860006116c185610ead565b600160a060020a031681526020810191909152604001600020555b5b505050565b600083826116f082426110fa565b8111156116fc57610000565b611707868686611b1b565b92505b5b50509392505050565b600061172283831115611b4d565b508082035b92915050565b6000610fd983602001518367ffffffffffffffff16856080015167ffffffffffffffff16866040015167ffffffffffffffff16876060015167ffffffffffffffff166111f3565b90505b92915050565b60008167ffffffffffffffff168367ffffffffffffffff1610156117a15781610fd9565b825b90505b92915050565b600033826117ba82426110fa565b8111156117c657610000565b6117d08585611b5d565b92505b5b505092915050565b6117e582610ef9565b6117ee83610c21565b11156117f957610000565b600160a060020a03811660009081526009602052604090205460ff16158015611834575081600160a060020a031681600160a060020a031614155b1561183e57610000565b61184782611070565b1561185157610000565b611864828261185f85610ef9565b611600565b600160a060020a0382811660009081526007602052604090208054600160a060020a031916918316918217905561189a82610ead565b600160a060020a031614610cc357610000565b5b5050565b600160a060020a038216600090815260036020526040812054815b818110156119885761197d836112796003600089600160a060020a0316600160a060020a0316815260200190815260200160002084815481101561000057906000526020600020906003020160005b506040805160a0810182528254600160a060020a031681526001830154602082015260029092015467ffffffffffffffff80821692840192909252604060020a810482166060840152608060020a900416608082015287611af9565b611a1f565b92505b6001016118cd565b600160a060020a0385166000908152600160205260409020546117d09084611714565b92505b505092915050565b600060006119c384611070565b80156119d157506000600d54115b90506119fb816119e9576119e485610ef9565b6119ec565b60005b6111138686611b7b565b611a05565b91505b5092915050565b60008183106117a15781610fd9565b825b90505b92915050565b6000828201611a3c848210801590611a375750838210155b611b4d565b8091505b5092915050565b611a508161104c565b15611a5a57610b85565b6005805460009081526004602052604090208054600160a060020a031916600160a060020a038416179055805460010190555b50565b6000828202611a3c841580611a37575083858381156100005704145b611b4d565b8091505b5092915050565b60006000611acc60008411611b4d565b8284811561000057049050611a3c838581156100005706828502018514611b4d565b8091505b5092915050565b6000610fd98360200151611b0d858561172d565b611714565b90505b92915050565b60008382611b2982426110fa565b811115611b3557610000565b611707868686611b8f565b92505b5b50509392505050565b801515610b8557610000565b5b50565b6000611b6883611a47565b610fd98383611c92565b90505b92915050565b6000610fd983610ef9565b90505b92915050565b600160a060020a038084166000908152600260209081526040808320338516845282528083205493861683526001909152812054909190611bd09084611a1f565b600160a060020a038086166000908152600160205260408082209390935590871681522054611bff9084611714565b600160a060020a038616600090815260016020526040902055611c228184611714565b600160a060020a038087166000818152600260209081526040808320338616845282529182902094909455805187815290519288169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600191505b509392505050565b60003382611ca082426110fa565b811115611cac57610000565b6117d08585611cc2565b92505b5b505092915050565b600160a060020a033316600090815260016020526040812054611ce59083611714565b600160a060020a033381166000908152600160205260408082209390935590851681522054611d149083611a1f565b600160a060020a038085166000818152600160209081526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b929150505600a165627a7a72305820bfa5ddd3fecf3f43aed25385ec7ec3ef79638c2e58d99f85d9a3cc494183bf160029000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json index ec10902b284b..b5355f65fe94 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json @@ -50,7 +50,6 @@ "input": "0x02f9029d82053980849502f90085010c388d00832dc6c08080b90241608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033c001a07566181071cabaf58b70fc41557eb813bfc7a24f5c58554e7fed0bf7c031f169a0420af50b5fe791a4d839e181a676db5250b415dfb35cb85d544db7a1475ae2cc", "result": { "from": "0x3623191d4ccfbbdf09e8ebf6382a1f8257417bc1", - "to": "0x0000000000000000000000000000000000000000", "gas": "0x2cd774", "gasUsed": "0x25590", "input": "0x608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033", diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 7b631a88f620..02ee152a5aa1 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -42,17 +42,17 @@ type callLog struct { } type callFrame struct { - Type vm.OpCode `json:"-"` - From common.Address `json:"from"` - Gas uint64 `json:"gas"` - GasUsed uint64 `json:"gasUsed"` - To common.Address `json:"to,omitempty" rlp:"optional"` - Input []byte `json:"input" rlp:"optional"` - Output []byte `json:"output,omitempty" rlp:"optional"` - Error string `json:"error,omitempty" rlp:"optional"` - RevertReason string `json:"revertReason,omitempty"` - Calls []callFrame `json:"calls,omitempty" rlp:"optional"` - Logs []callLog `json:"logs,omitempty" rlp:"optional"` + Type vm.OpCode `json:"-"` + From common.Address `json:"from"` + Gas uint64 `json:"gas"` + GasUsed uint64 `json:"gasUsed"` + To *common.Address `json:"to,omitempty" rlp:"optional"` + Input []byte `json:"input" rlp:"optional"` + Output []byte `json:"output,omitempty" rlp:"optional"` + Error string `json:"error,omitempty" rlp:"optional"` + RevertReason string `json:"revertReason,omitempty"` + Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Logs []callLog `json:"logs,omitempty" rlp:"optional"` // Placed at end on purpose. The RLP will be decoded to 0 instead of // nil if there are non-empty elements after in the struct. Value *big.Int `json:"value,omitempty" rlp:"optional"` @@ -74,7 +74,7 @@ func (f *callFrame) processOutput(output []byte, err error) { } f.Error = err.Error() if f.Type == vm.CREATE || f.Type == vm.CREATE2 { - f.To = common.Address{} + f.To = nil } if !errors.Is(err, vm.ErrExecutionReverted) || len(output) == 0 { return @@ -127,10 +127,11 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, e // CaptureStart implements the EVMLogger interface to initialize the tracing operation. func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { + toCopy := to t.callstack[0] = callFrame{ Type: vm.CALL, From: from, - To: to, + To: &toCopy, Input: common.CopyBytes(input), Gas: gas, Value: value, @@ -191,10 +192,11 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. return } + toCopy := to call := callFrame{ Type: typ, From: from, - To: to, + To: &toCopy, Input: common.CopyBytes(input), Gas: gas, Value: value, diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 75aa8a583fe4..5da60405062f 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -193,7 +193,7 @@ func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) { to = call.To ) if typ == vm.CALL || typ == vm.STATICCALL { - if t.isPrecompiled(to) { + if t.isPrecompiled(*to) { t.tracer.callstack[len(t.tracer.callstack)-1].Calls = parent.Calls[:len(parent.Calls)-1] } } @@ -299,7 +299,7 @@ func newFlatCreate(input *callFrame) *flatCallFrame { }, Result: &flatCallResult{ GasUsed: &input.GasUsed, - Address: &input.To, + Address: input.To, Code: &resultCode, }, } @@ -315,7 +315,7 @@ func newFlatCall(input *callFrame) *flatCallFrame { Type: strings.ToLower(vm.CALL.String()), Action: flatCallAction{ From: &input.From, - To: &input.To, + To: input.To, Gas: &input.Gas, Value: input.Value, CallType: strings.ToLower(input.Type.String()), @@ -334,7 +334,7 @@ func newFlatSuicide(input *callFrame) *flatCallFrame { Action: flatCallAction{ SelfDestructed: &input.From, Balance: input.Value, - RefundAddress: &input.To, + RefundAddress: input.To, }, } } diff --git a/eth/tracers/native/gen_callframe_json.go b/eth/tracers/native/gen_callframe_json.go index 21fc9e2b31af..c44f38390df7 100644 --- a/eth/tracers/native/gen_callframe_json.go +++ b/eth/tracers/native/gen_callframe_json.go @@ -16,19 +16,19 @@ var _ = (*callFrameMarshaling)(nil) // MarshalJSON marshals as JSON. func (c callFrame) MarshalJSON() ([]byte, error) { type callFrame0 struct { - Type vm.OpCode `json:"-"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasUsed hexutil.Uint64 `json:"gasUsed"` - To common.Address `json:"to,omitempty" rlp:"optional"` - Input hexutil.Bytes `json:"input" rlp:"optional"` - Output hexutil.Bytes `json:"output,omitempty" rlp:"optional"` - Error string `json:"error,omitempty" rlp:"optional"` - RevertReason string `json:"revertReason,omitempty"` - Calls []callFrame `json:"calls,omitempty" rlp:"optional"` - Logs []callLog `json:"logs,omitempty" rlp:"optional"` - Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` - TypeString string `json:"type"` + Type vm.OpCode `json:"-"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasUsed hexutil.Uint64 `json:"gasUsed"` + To *common.Address `json:"to,omitempty" rlp:"optional"` + Input hexutil.Bytes `json:"input" rlp:"optional"` + Output hexutil.Bytes `json:"output,omitempty" rlp:"optional"` + Error string `json:"error,omitempty" rlp:"optional"` + RevertReason string `json:"revertReason,omitempty"` + Calls []callFrame `json:"calls,omitempty" rlp:"optional"` + Logs []callLog `json:"logs,omitempty" rlp:"optional"` + Value *hexutil.Big `json:"value,omitempty" rlp:"optional"` + TypeString string `json:"type"` } var enc callFrame0 enc.Type = c.Type @@ -80,7 +80,7 @@ func (c *callFrame) UnmarshalJSON(input []byte) error { c.GasUsed = uint64(*dec.GasUsed) } if dec.To != nil { - c.To = *dec.To + c.To = dec.To } if dec.Input != nil { c.Input = *dec.Input From 1e3177de220b1590704c96572fce820bfc87281e Mon Sep 17 00:00:00 2001 From: James Prestwich <10149425+prestwich@users.noreply.github.com> Date: Tue, 7 Mar 2023 06:20:04 -0800 Subject: [PATCH 608/715] accounts/usbwallet: mitigate ledger app chunking issue (#26773) This PR mitigates an issue with Ledger's on-device RLP deserialization, see https://github.com/LedgerHQ/app-ethereum/issues/409 Ledger's RLP deserialization code does not validate the length of the RLP list received, and it may prematurely enter the signing flow when a APDU chunk boundary falls immediately before the EIP-155 chain_id when deserializing a transaction. Since the chain_id is uninitialized, it is 0 during this signing flow. This may cause the user to accidentally sign the transaction with chain_id = 0. That signature would be returned from the device 1 packet earlier than expected by the communication loop. The device blocks the second-to-last packet waiting for the signer flow, and then errors on the successive packet (which contains the chain_id, zeroed r, and zeroed s) Since the signature's early arrival causes successive errors during the communication process, geth does not parse the improper signature produced by the device, and therefore no improperly-signed transaction can be created. User funds are not at risk. We mitigate by selecting the highest chunk size that leaves at least 4 bytes in the final chunk. --- accounts/usbwallet/ledger.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/accounts/usbwallet/ledger.go b/accounts/usbwallet/ledger.go index cda94280fdd2..723df0f2b352 100644 --- a/accounts/usbwallet/ledger.go +++ b/accounts/usbwallet/ledger.go @@ -59,6 +59,8 @@ const ( ledgerP1InitTransactionData ledgerParam1 = 0x00 // First transaction data block for signing ledgerP1ContTransactionData ledgerParam1 = 0x80 // Subsequent transaction data block for signing ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address + + ledgerEip155Size int = 3 // Size of the EIP-155 chain_id,r,s in unsigned transactions ) // errLedgerReplyInvalidHeader is the error message returned by a Ledger data exchange @@ -347,9 +349,15 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction op = ledgerP1InitTransactionData reply []byte ) + + // Chunk size selection to mitigate an underlying RLP deserialization issue on the ledger app. + // https://github.com/LedgerHQ/app-ethereum/issues/409 + chunk := 255 + for ; len(payload)%chunk <= ledgerEip155Size; chunk-- { + } + for len(payload) > 0 { // Calculate the size of the next data chunk - chunk := 255 if chunk > len(payload) { chunk = len(payload) } From 78429f7733812395ba8f704e728a5c1e8380c934 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 7 Mar 2023 16:30:04 +0100 Subject: [PATCH 609/715] beacon/engine: don't omit empty withdrawals in ExecutionPayloadBodies (#26698) This ensures the "withdrawals" field will always be present in responses to getPayloadBodiesByRangeV1 and getPayloadBodiesByHashV1. --------- Co-authored-by: Felix Lange --- beacon/engine/types.go | 2 +- eth/catalyst/api_test.go | 108 +++++++++++++++++++++++++++------------ 2 files changed, 77 insertions(+), 33 deletions(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 58f72631194f..07ebe544b438 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -233,5 +233,5 @@ func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadE // ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1 type ExecutionPayloadBodyV1 struct { TransactionData []hexutil.Bytes `json:"transactions"` - Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` + Withdrawals []*types.Withdrawal `json:"withdrawals"` } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 09972691729e..fb6e6935ee46 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -19,8 +19,11 @@ package catalyst import ( "bytes" "context" + crand "crypto/rand" "fmt" "math/big" + "math/rand" + "reflect" "sync" "testing" "time" @@ -41,7 +44,6 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" ) @@ -473,18 +475,21 @@ func TestFullAPI(t *testing.T) { ethservice.TxPool().AddLocal(tx) } - setupBlocks(t, ethservice, 10, parent, callback) + setupBlocks(t, ethservice, 10, parent, callback, nil) } -func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header)) []*types.Header { +func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header), withdrawals [][]*types.Withdrawal) []*types.Header { api := NewConsensusAPI(ethservice) var blocks []*types.Header for i := 0; i < n; i++ { callback(parent) + var w []*types.Withdrawal + if withdrawals != nil { + w = withdrawals[i] + } - payload := getNewPayload(t, api, parent) - - execResp, err := api.NewPayloadV1(*payload) + payload := getNewPayload(t, api, parent, w) + execResp, err := api.NewPayloadV2(*payload) if err != nil { t.Fatalf("can't execute payload: %v", err) } @@ -676,10 +681,10 @@ func TestEmptyBlocks(t *testing.T) { api := NewConsensusAPI(ethservice) // Setup 10 blocks on the canonical chain - setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}) + setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil) // (1) check LatestValidHash by sending a normal payload (P1'') - payload := getNewPayload(t, api, commonAncestor) + payload := getNewPayload(t, api, commonAncestor, nil) status, err := api.NewPayloadV1(*payload) if err != nil { @@ -693,7 +698,7 @@ func TestEmptyBlocks(t *testing.T) { } // (2) Now send P1' which is invalid - payload = getNewPayload(t, api, commonAncestor) + payload = getNewPayload(t, api, commonAncestor, nil) payload.GasUsed += 1 payload = setBlockhash(payload) // Now latestValidHash should be the common ancestor @@ -711,7 +716,7 @@ func TestEmptyBlocks(t *testing.T) { } // (3) Now send a payload with unknown parent - payload = getNewPayload(t, api, commonAncestor) + payload = getNewPayload(t, api, commonAncestor, nil) payload.ParentHash = common.Hash{1} payload = setBlockhash(payload) // Now latestValidHash should be the common ancestor @@ -727,11 +732,12 @@ func TestEmptyBlocks(t *testing.T) { } } -func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header) *engine.ExecutableData { +func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal) *engine.ExecutableData { params := engine.PayloadAttributes{ Timestamp: parent.Time + 1, Random: crypto.Keccak256Hash([]byte{byte(1)}), SuggestedFeeRecipient: parent.Coinbase, + Withdrawals: withdrawals, } payload, err := assembleBlock(api, parent.Hash(), ¶ms) @@ -799,7 +805,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { commonAncestor := ethserviceA.BlockChain().CurrentBlock() // Setup 10 blocks on the canonical chain - setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}) + setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}, nil) commonAncestor = ethserviceA.BlockChain().CurrentBlock() var invalidChain []*engine.ExecutableData @@ -808,7 +814,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { //invalidChain = append(invalidChain, payload1) // create an invalid payload2 (P2) - payload2 := getNewPayload(t, apiA, commonAncestor) + payload2 := getNewPayload(t, apiA, commonAncestor, nil) //payload2.ParentHash = payload1.BlockHash payload2.GasUsed += 1 payload2 = setBlockhash(payload2) @@ -817,7 +823,7 @@ func TestTrickRemoteBlockCache(t *testing.T) { head := payload2 // create some valid payloads on top for i := 0; i < 10; i++ { - payload := getNewPayload(t, apiA, commonAncestor) + payload := getNewPayload(t, apiA, commonAncestor, nil) payload.ParentHash = head.BlockHash payload = setBlockhash(payload) invalidChain = append(invalidChain, payload) @@ -855,10 +861,10 @@ func TestInvalidBloom(t *testing.T) { api := NewConsensusAPI(ethservice) // Setup 10 blocks on the canonical chain - setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}) + setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil) // (1) check LatestValidHash by sending a normal payload (P1'') - payload := getNewPayload(t, api, commonAncestor) + payload := getNewPayload(t, api, commonAncestor, nil) payload.LogsBloom = append(payload.LogsBloom, byte(1)) status, err := api.NewPayloadV1(*payload) if err != nil { @@ -1233,8 +1239,10 @@ func TestNilWithdrawals(t *testing.T) { } func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { - genesis, preMergeBlocks := generateMergeChain(10, false) - n, ethservice := startEthService(t, genesis, preMergeBlocks) + genesis, blocks := generateMergeChain(10, true) + n, ethservice := startEthService(t, genesis, blocks) + // enable shanghai on the last block + ethservice.BlockChain().Config().ShanghaiTime = &blocks[len(blocks)-1].Header().Time var ( parent = ethservice.BlockChain().CurrentBlock() @@ -1249,12 +1257,38 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { ethservice.TxPool().AddLocal(tx) } - postMergeHeaders := setupBlocks(t, ethservice, 10, parent, callback) - postMergeBlocks := make([]*types.Block, len(postMergeHeaders)) - for i, header := range postMergeHeaders { - postMergeBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64()) + withdrawals := make([][]*types.Withdrawal, 10) + withdrawals[0] = nil // should be filtered out by miner + withdrawals[1] = make([]*types.Withdrawal, 0) + for i := 2; i < len(withdrawals); i++ { + addr := make([]byte, 20) + crand.Read(addr) + withdrawals[i] = []*types.Withdrawal{ + {Index: rand.Uint64(), Validator: rand.Uint64(), Amount: rand.Uint64(), Address: common.BytesToAddress(addr)}, + } + } + + postShanghaiHeaders := setupBlocks(t, ethservice, 10, parent, callback, withdrawals) + postShanghaiBlocks := make([]*types.Block, len(postShanghaiHeaders)) + for i, header := range postShanghaiHeaders { + postShanghaiBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64()) } - return n, ethservice, append(preMergeBlocks, postMergeBlocks...) + return n, ethservice, append(blocks, postShanghaiBlocks...) +} + +func allHashes(blocks []*types.Block) []common.Hash { + var hashes []common.Hash + for _, b := range blocks { + hashes = append(hashes, b.Hash()) + } + return hashes +} +func allBodies(blocks []*types.Block) []*types.Body { + var bodies []*types.Body + for _, b := range blocks { + bodies = append(bodies, b.Body()) + } + return bodies } func TestGetBlockBodiesByHash(t *testing.T) { @@ -1296,6 +1330,11 @@ func TestGetBlockBodiesByHash(t *testing.T) { results: []*types.Body{blocks[0].Body(), nil, blocks[0].Body(), blocks[0].Body()}, hashes: []common.Hash{blocks[0].Hash(), {1, 2}, blocks[0].Hash(), blocks[0].Hash()}, }, + // all blocks + { + results: allBodies(blocks), + hashes: allHashes(blocks), + }, } for k, test := range tests { @@ -1364,6 +1403,12 @@ func TestGetBlockBodiesByRange(t *testing.T) { start: 22, count: 2, }, + // allBlocks + { + results: allBodies(blocks), + start: 1, + count: hexutil.Uint64(len(blocks)), + }, } for k, test := range tests { @@ -1434,15 +1479,14 @@ func equalBody(a *types.Body, b *engine.ExecutionPayloadBodyV1) bool { } else if a == nil || b == nil { return false } - var want []hexutil.Bytes - for _, tx := range a.Transactions { - data, _ := tx.MarshalBinary() - want = append(want, hexutil.Bytes(data)) - } - aBytes, errA := rlp.EncodeToBytes(want) - bBytes, errB := rlp.EncodeToBytes(b.TransactionData) - if errA != errB { + if len(a.Transactions) != len(b.TransactionData) { return false } - return bytes.Equal(aBytes, bBytes) + for i, tx := range a.Transactions { + data, _ := tx.MarshalBinary() + if !bytes.Equal(data, b.TransactionData[i]) { + return false + } + } + return reflect.DeepEqual(a.Withdrawals, b.Withdrawals) } From a54d91ac5adbd81b2bbc317b838189f912f6d987 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 7 Mar 2023 18:16:21 +0100 Subject: [PATCH 610/715] build: update to go 1.20.2 (#26824) --- build/checksums.txt | 28 ++++++++++++++-------------- build/ci.go | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 1fb85d62667b..e349d3eba03b 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,19 +1,19 @@ # This file contains sha256 checksums of optional build dependencies. -b5c1a3af52c385a6d1c76aed5361cf26459023980d0320de7658bae3915831a2 go1.20.1.src.tar.gz -a300a45e801ab459f3008aae5bb9efbe9a6de9bcd12388f5ca9bbd14f70236de go1.20.1.darwin-amd64.tar.gz -f1a8e06c7f1ba1c008313577f3f58132eb166a41ceb95ce6e9af30bc5a3efca4 go1.20.1.darwin-arm64.tar.gz -57d80349dc4fbf692f8cd85a5971f97841aedafcf211e367e59d3ae812292660 go1.20.1.freebsd-386.tar.gz -6e124d54d5850a15fdb15754f782986f06af23c5ddb6690849417b9c74f05f98 go1.20.1.freebsd-amd64.tar.gz -3a7345036ebd92455b653e4b4f6aaf4f7e1f91f4ced33b23d7059159cec5f4d7 go1.20.1.linux-386.tar.gz -000a5b1fca4f75895f78befeb2eecf10bfff3c428597f3f1e69133b63b911b02 go1.20.1.linux-amd64.tar.gz -5e5e2926733595e6f3c5b5ad1089afac11c1490351855e87849d0e7702b1ec2e go1.20.1.linux-arm64.tar.gz -e4edc05558ab3657ba3dddb909209463cee38df9c1996893dd08cde274915003 go1.20.1.linux-armv6l.tar.gz -85cfd4b89b48c94030783b6e9e619e35557862358b846064636361421d0b0c52 go1.20.1.linux-ppc64le.tar.gz -ba3a14381ed4538216dec3ea72b35731750597edd851cece1eb120edf7d60149 go1.20.1.linux-s390x.tar.gz -61259b5a346193e30b7b3c3f8d108062db25bbb80cf290ee251eeb855965f6ee go1.20.1.windows-386.zip -3b493969196a6de8d9762d09f5bc5ae7a3e5814b0cfbf9cc26838c2bc1314f9c go1.20.1.windows-amd64.zip -62d14ddb44bcda27c9b1f5ad9ffd4463013374ed325d762417e2adefd59a802f go1.20.1.windows-arm64.zip +4d0e2850d197b4ddad3bdb0196300179d095bb3aefd4dfbc3b36702c3728f8ab go1.20.2.src.tar.gz +c93b8ced9517d07e1cd4c362c6e2d5242cb139e29b417a328fbf19aded08764c go1.20.2.darwin-amd64.tar.gz +7343c87f19e79c0063532e82e1c4d6f42175a32d99f7a4d15e658e88bf97f885 go1.20.2.darwin-arm64.tar.gz +14f9be2004e042b3a64d0facb0c020756a9084a5c7333e33b0752b393b6016ea go1.20.2.freebsd-386.tar.gz +b41b67b4f1b56797a7cecf6ee7f47fcf4f93960b2788a3683c07dd009d30b2a4 go1.20.2.freebsd-amd64.tar.gz +ee240ed33ae57504c41f04c12236aeaa17fbeb6ea9fcd096cd9dc7a89d10d4db go1.20.2.linux-386.tar.gz +4eaea32f59cde4dc635fbc42161031d13e1c780b87097f4b4234cfce671f1768 go1.20.2.linux-amd64.tar.gz +78d632915bb75e9a6356a47a42625fd1a785c83a64a643fedd8f61e31b1b3bef go1.20.2.linux-arm64.tar.gz +d79d56bafd6b52b8d8cbe3f8e967caaac5383a23d7a4fa9ac0e89778cd16a076 go1.20.2.linux-armv6l.tar.gz +850564ddb760cb703db63bf20182dc4407abd2ff090a95fa66d6634d172fd095 go1.20.2.linux-ppc64le.tar.gz +8da24c5c4205fe8115f594237e5db7bcb1d23df67bc1fa9a999954b1976896e8 go1.20.2.linux-s390x.tar.gz +31838b291117495bbb93683603e98d5118bfabd2eb318b4d07540bfd524bab86 go1.20.2.windows-386.zip +fe439f0e438f7555a7f5f7194ddb6f4a07b0de1fa414385d19f2aeb26d9f43db go1.20.2.windows-amd64.zip +ac5010c8b8b22849228a8dea698d58b9c7be2195d30c6d778cce0f709858fa64 go1.20.2.windows-arm64.zip fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz 75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz diff --git a/build/ci.go b/build/ci.go index 2aad2ac52b33..49926621bda6 100644 --- a/build/ci.go +++ b/build/ci.go @@ -139,7 +139,7 @@ var ( // This is the version of Go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.20.1" + dlgoVersion = "1.20.2" // This is the version of Go that will be used to bootstrap the PPA builder. // From 5ed08c4735c9d034fface08e4c400f1bd1ba8318 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 7 Mar 2023 18:17:32 +0100 Subject: [PATCH 611/715] params: go-ethereum v1.11.3 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 27a2df12aef2..5ad83fa5c24c 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 3 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 3 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From bb4ac2d396de254898a5f44b1ea2086bfe5bd193 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 7 Mar 2023 18:18:59 +0100 Subject: [PATCH 612/715] params: begin v1.11.4 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 5ad83fa5c24c..35cf0d53c951 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 3 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 4 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From f7661a662a6e0743b440956e4e15bdae1ba3821e Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 8 Mar 2023 15:39:13 +0800 Subject: [PATCH 613/715] core/rawdb: find smallest block stored in key-value store when chain gapped (#26719) This change prints out more information about the problem, in the case where geth detects a gap between leveldb and ancients, so we can determine more exactly where the gap is (what the first missing is). Also prints out more metadata. --------- Co-authored-by: Martin Holst Swende --- cmd/geth/dbcmd.go | 28 +++----------------- core/rawdb/database.go | 58 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 4deb081ed8f6..b409b19260e0 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -694,41 +694,19 @@ func showMetaData(ctx *cli.Context) error { if err != nil { fmt.Fprintf(os.Stderr, "Error accessing ancients: %v", err) } - pp := func(val *uint64) string { - if val == nil { - return "" - } - return fmt.Sprintf("%d (%#x)", *val, *val) - } - data := [][]string{ - {"databaseVersion", pp(rawdb.ReadDatabaseVersion(db))}, - {"headBlockHash", fmt.Sprintf("%v", rawdb.ReadHeadBlockHash(db))}, - {"headFastBlockHash", fmt.Sprintf("%v", rawdb.ReadHeadFastBlockHash(db))}, - {"headHeaderHash", fmt.Sprintf("%v", rawdb.ReadHeadHeaderHash(db))}} + data := rawdb.ReadChainMetadata(db) + data = append(data, []string{"frozen", fmt.Sprintf("%d items", ancients)}) + data = append(data, []string{"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))}) if b := rawdb.ReadHeadBlock(db); b != nil { data = append(data, []string{"headBlock.Hash", fmt.Sprintf("%v", b.Hash())}) data = append(data, []string{"headBlock.Root", fmt.Sprintf("%v", b.Root())}) data = append(data, []string{"headBlock.Number", fmt.Sprintf("%d (%#x)", b.Number(), b.Number())}) } - if b := rawdb.ReadSkeletonSyncStatus(db); b != nil { - data = append(data, []string{"SkeletonSyncStatus", string(b)}) - } if h := rawdb.ReadHeadHeader(db); h != nil { data = append(data, []string{"headHeader.Hash", fmt.Sprintf("%v", h.Hash())}) data = append(data, []string{"headHeader.Root", fmt.Sprintf("%v", h.Root)}) data = append(data, []string{"headHeader.Number", fmt.Sprintf("%d (%#x)", h.Number, h.Number)}) } - data = append(data, [][]string{{"frozen", fmt.Sprintf("%d items", ancients)}, - {"lastPivotNumber", pp(rawdb.ReadLastPivotNumber(db))}, - {"len(snapshotSyncStatus)", fmt.Sprintf("%d bytes", len(rawdb.ReadSnapshotSyncStatus(db)))}, - {"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))}, - {"snapshotDisabled", fmt.Sprintf("%v", rawdb.ReadSnapshotDisabled(db))}, - {"snapshotJournal", fmt.Sprintf("%d bytes", len(rawdb.ReadSnapshotJournal(db)))}, - {"snapshotRecoveryNumber", pp(rawdb.ReadSnapshotRecoveryNumber(db))}, - {"snapshotRoot", fmt.Sprintf("%v", rawdb.ReadSnapshotRoot(db))}, - {"txIndexTail", pp(rawdb.ReadTxIndexTail(db))}, - {"fastTxLookupLimit", pp(rawdb.ReadFastTxLookupLimit(db))}, - }...) table := tablewriter.NewWriter(os.Stdout) table.SetHeader([]string{"Field", "Value"}) table.AppendBulk(data) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 5b7299f38f86..6c545032f969 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -202,6 +202,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st // Create the idle freezer instance frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly) if err != nil { + printChainMetadata(db) return nil, err } // Since the freezer can be stored separately from the user's key-value database, @@ -233,8 +234,10 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st // the freezer and the key-value store. frgenesis, err := frdb.Ancient(ChainFreezerHashTable, 0) if err != nil { + printChainMetadata(db) return nil, fmt.Errorf("failed to retrieve genesis from ancient %v", err) } else if !bytes.Equal(kvgenesis, frgenesis) { + printChainMetadata(db) return nil, fmt.Errorf("genesis mismatch: %#x (leveldb) != %#x (ancients)", kvgenesis, frgenesis) } // Key-value store and freezer belong to the same network. Ensure that they @@ -242,8 +245,19 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st if kvhash, _ := db.Get(headerHashKey(frozen)); len(kvhash) == 0 { // Subsequent header after the freezer limit is missing from the database. // Reject startup if the database has a more recent head. - if ldbNum := *ReadHeaderNumber(db, ReadHeadHeaderHash(db)); ldbNum > frozen-1 { - return nil, fmt.Errorf("gap in the chain between ancients (#%d) and leveldb (#%d) ", frozen, ldbNum) + if head := *ReadHeaderNumber(db, ReadHeadHeaderHash(db)); head > frozen-1 { + // Find the smallest block stored in the key-value store + // in range of [frozen, head] + var number uint64 + for number = frozen; number <= head; number++ { + if present, _ := db.Has(headerHashKey(number)); present { + break + } + } + // We are about to exit on error. Print database metdata beore exiting + printChainMetadata(db) + return nil, fmt.Errorf("gap in the chain between ancients [0 - #%d] and leveldb [#%d - #%d] ", + frozen-1, number, head) } // Database contains only older data than the freezer, this happens if the // state was wiped and reinited from an existing freezer. @@ -260,6 +274,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st // Key-value store contains more data than the genesis block, make sure we // didn't freeze anything yet. if kvblob, _ := db.Get(headerHashKey(1)); len(kvblob) == 0 { + printChainMetadata(db) return nil, errors.New("ancient chain segments already extracted, please set --datadir.ancient to the correct path") } // Block #1 is still in the database, we're allowed to init a new freezer @@ -581,3 +596,42 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { } return nil } + +// printChainMetadata prints out chain metadata to stderr. +func printChainMetadata(db ethdb.KeyValueStore) { + fmt.Fprintf(os.Stderr, "Chain metadata\n") + for _, v := range ReadChainMetadata(db) { + fmt.Fprintf(os.Stderr, " %s\n", strings.Join(v, ": ")) + } + fmt.Fprintf(os.Stderr, "\n\n") +} + +// ReadChainMetadata returns a set of key/value pairs that contains informatin +// about the database chain status. This can be used for diagnostic purposes +// when investigating the state of the node. +func ReadChainMetadata(db ethdb.KeyValueStore) [][]string { + pp := func(val *uint64) string { + if val == nil { + return "" + } + return fmt.Sprintf("%d (%#x)", *val, *val) + } + data := [][]string{ + {"databaseVersion", pp(ReadDatabaseVersion(db))}, + {"headBlockHash", fmt.Sprintf("%v", ReadHeadBlockHash(db))}, + {"headFastBlockHash", fmt.Sprintf("%v", ReadHeadFastBlockHash(db))}, + {"headHeaderHash", fmt.Sprintf("%v", ReadHeadHeaderHash(db))}, + {"lastPivotNumber", pp(ReadLastPivotNumber(db))}, + {"len(snapshotSyncStatus)", fmt.Sprintf("%d bytes", len(ReadSnapshotSyncStatus(db)))}, + {"snapshotDisabled", fmt.Sprintf("%v", ReadSnapshotDisabled(db))}, + {"snapshotJournal", fmt.Sprintf("%d bytes", len(ReadSnapshotJournal(db)))}, + {"snapshotRecoveryNumber", pp(ReadSnapshotRecoveryNumber(db))}, + {"snapshotRoot", fmt.Sprintf("%v", ReadSnapshotRoot(db))}, + {"txIndexTail", pp(ReadTxIndexTail(db))}, + {"fastTxLookupLimit", pp(ReadFastTxLookupLimit(db))}, + } + if b := ReadSkeletonSyncStatus(db); b != nil { + data = append(data, []string{"SkeletonSyncStatus", string(b)}) + } + return data +} From 02796f6bee7e014fd16ad39f0bcd3b665b51e0bb Mon Sep 17 00:00:00 2001 From: Daniel Fernandes <711733+daferna@users.noreply.github.com> Date: Tue, 7 Mar 2023 23:48:53 -0800 Subject: [PATCH 614/715] signer/core: accept all solidity primitive types for EIP-712 signing (#26770) Accept all primitive types in Solidity for EIP-712 from intN, uintN, intN[], uintN[] for N as 0 to 256 in multiples of 8 --------- Co-authored-by: Martin Holst Swende --- signer/core/apitypes/types.go | 122 +++++------------------------ signer/core/apitypes/types_test.go | 40 ++++++++++ 2 files changed, 60 insertions(+), 102 deletions(-) create mode 100644 signer/core/apitypes/types_test.go diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index c72cad5939cf..8218e754d36c 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -742,112 +742,30 @@ func isPrimitiveTypeValid(primitiveType string) bool { primitiveType == "bool" || primitiveType == "bool[]" || primitiveType == "string" || - primitiveType == "string[]" { - return true - } - if primitiveType == "bytes" || + primitiveType == "string[]" || + primitiveType == "bytes" || primitiveType == "bytes[]" || - primitiveType == "bytes1" || - primitiveType == "bytes1[]" || - primitiveType == "bytes2" || - primitiveType == "bytes2[]" || - primitiveType == "bytes3" || - primitiveType == "bytes3[]" || - primitiveType == "bytes4" || - primitiveType == "bytes4[]" || - primitiveType == "bytes5" || - primitiveType == "bytes5[]" || - primitiveType == "bytes6" || - primitiveType == "bytes6[]" || - primitiveType == "bytes7" || - primitiveType == "bytes7[]" || - primitiveType == "bytes8" || - primitiveType == "bytes8[]" || - primitiveType == "bytes9" || - primitiveType == "bytes9[]" || - primitiveType == "bytes10" || - primitiveType == "bytes10[]" || - primitiveType == "bytes11" || - primitiveType == "bytes11[]" || - primitiveType == "bytes12" || - primitiveType == "bytes12[]" || - primitiveType == "bytes13" || - primitiveType == "bytes13[]" || - primitiveType == "bytes14" || - primitiveType == "bytes14[]" || - primitiveType == "bytes15" || - primitiveType == "bytes15[]" || - primitiveType == "bytes16" || - primitiveType == "bytes16[]" || - primitiveType == "bytes17" || - primitiveType == "bytes17[]" || - primitiveType == "bytes18" || - primitiveType == "bytes18[]" || - primitiveType == "bytes19" || - primitiveType == "bytes19[]" || - primitiveType == "bytes20" || - primitiveType == "bytes20[]" || - primitiveType == "bytes21" || - primitiveType == "bytes21[]" || - primitiveType == "bytes22" || - primitiveType == "bytes22[]" || - primitiveType == "bytes23" || - primitiveType == "bytes23[]" || - primitiveType == "bytes24" || - primitiveType == "bytes24[]" || - primitiveType == "bytes25" || - primitiveType == "bytes25[]" || - primitiveType == "bytes26" || - primitiveType == "bytes26[]" || - primitiveType == "bytes27" || - primitiveType == "bytes27[]" || - primitiveType == "bytes28" || - primitiveType == "bytes28[]" || - primitiveType == "bytes29" || - primitiveType == "bytes29[]" || - primitiveType == "bytes30" || - primitiveType == "bytes30[]" || - primitiveType == "bytes31" || - primitiveType == "bytes31[]" || - primitiveType == "bytes32" || - primitiveType == "bytes32[]" { - return true - } - if primitiveType == "int" || + primitiveType == "int" || primitiveType == "int[]" || - primitiveType == "int8" || - primitiveType == "int8[]" || - primitiveType == "int16" || - primitiveType == "int16[]" || - primitiveType == "int32" || - primitiveType == "int32[]" || - primitiveType == "int64" || - primitiveType == "int64[]" || - primitiveType == "int96" || - primitiveType == "int96[]" || - primitiveType == "int128" || - primitiveType == "int128[]" || - primitiveType == "int256" || - primitiveType == "int256[]" { + primitiveType == "uint" || + primitiveType == "uint[]" { return true } - if primitiveType == "uint" || - primitiveType == "uint[]" || - primitiveType == "uint8" || - primitiveType == "uint8[]" || - primitiveType == "uint16" || - primitiveType == "uint16[]" || - primitiveType == "uint32" || - primitiveType == "uint32[]" || - primitiveType == "uint64" || - primitiveType == "uint64[]" || - primitiveType == "uint96" || - primitiveType == "uint96[]" || - primitiveType == "uint128" || - primitiveType == "uint128[]" || - primitiveType == "uint256" || - primitiveType == "uint256[]" { - return true + // For 'bytesN', 'bytesN[]', we allow N from 1 to 32 + for n := 1; n <= 32; n++ { + // e.g. 'bytes28' or 'bytes28[]' + if primitiveType == fmt.Sprintf("bytes%d", n) || primitiveType == fmt.Sprintf("bytes%d[]", n) { + return true + } + } + // For 'intN','intN[]' and 'uintN','uintN[]' we allow N in increments of 8, from 8 up to 256 + for n := 8; n <= 256; n += 8 { + if primitiveType == fmt.Sprintf("int%d", n) || primitiveType == fmt.Sprintf("int%d[]", n) { + return true + } + if primitiveType == fmt.Sprintf("uint%d", n) || primitiveType == fmt.Sprintf("uint%d[]", n) { + return true + } } return false } diff --git a/signer/core/apitypes/types_test.go b/signer/core/apitypes/types_test.go new file mode 100644 index 000000000000..eef3cae00cc4 --- /dev/null +++ b/signer/core/apitypes/types_test.go @@ -0,0 +1,40 @@ +// Copyright 2023 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 apitypes + +import "testing" + +func TestIsPrimitive(t *testing.T) { + // Expected positives + for i, tc := range []string{ + "int24", "int24[]", "uint88", "uint88[]", "uint", "uint[]", "int256", "int256[]", + "uint96", "uint96[]", "int96", "int96[]", "bytes17[]", "bytes17", + } { + if !isPrimitiveTypeValid(tc) { + t.Errorf("test %d: expected '%v' to be a valid primitive", i, tc) + } + } + // Expected negatives + for i, tc := range []string{ + "int257", "int257[]", "uint88 ", "uint88 []", "uint257", "uint-1[]", + "uint0", "uint0[]", "int95", "int95[]", "uint1", "uint1[]", "bytes33[]", "bytess", + } { + if isPrimitiveTypeValid(tc) { + t.Errorf("test %d: expected '%v' to not be a valid primitive", i, tc) + } + } +} From e14043db71c5d2d91520fab217302fcecf7aa939 Mon Sep 17 00:00:00 2001 From: Rafael Matias Date: Wed, 8 Mar 2023 10:13:56 +0000 Subject: [PATCH 615/715] params: remove EF azure bootnodes (#26828) --- params/bootnodes.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/params/bootnodes.go b/params/bootnodes.go index 0a995bc3c404..45e27c441a78 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -22,14 +22,10 @@ import "github.com/ethereum/go-ethereum/common" // the main Ethereum network. var MainnetBootnodes = []string{ // Ethereum Foundation Go Bootnodes - "enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303", // bootnode-aws-ap-southeast-1-001 - "enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303", // bootnode-aws-us-east-1-001 - "enode://8499da03c47d637b20eee24eec3c356c9a2e6148d6fe25ca195c7949ab8ec2c03e3556126b0d7ed644675e78c4318b08691b7b57de10e5f0d40d05b09238fa0a@52.187.207.27:30303", // bootnode-azure-australiaeast-001 - "enode://103858bdb88756c71f15e9b5e09b56dc1be52f0a5021d46301dbbfb7e130029cc9d0d6f73f693bc29b665770fff7da4d34f3c6379fe12721b5d7a0bcb5ca1fc1@191.234.162.198:30303", // bootnode-azure-brazilsouth-001 - "enode://715171f50508aba88aecd1250af392a45a330af91d7b90701c436b618c86aaa1589c9184561907bebbb56439b8f8787bc01f49a7c77276c58c1b09822d75e8e8@52.231.165.108:30303", // bootnode-azure-koreasouth-001 - "enode://5d6d7cd20d6da4bb83a1d28cadb5d409b64edf314c0335df658c1a54e32c7c4a7ab7823d57c39b6a757556e68ff1df17c748b698544a55cb488b52479a92b60f@104.42.217.25:30303", // bootnode-azure-westus-001 - "enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303", // bootnode-hetzner-hel - "enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", // bootnode-hetzner-fsn + "enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303", // bootnode-aws-ap-southeast-1-001 + "enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303", // bootnode-aws-us-east-1-001 + "enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303", // bootnode-hetzner-hel + "enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", // bootnode-hetzner-fsn } // SepoliaBootnodes are the enode URLs of the P2P bootstrap nodes running on the From b80f05bde2c4e93ae64bb3813b6d67266b5fc0e6 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 8 Mar 2023 13:12:53 -0500 Subject: [PATCH 616/715] core/vm: use golang native big.Int (#26834) reverts #26021, to use the upstream bigint instead. --- common/math/modexp_test.go | 53 ---------------- core/vm/contracts.go | 7 +-- go.mod | 3 +- go.sum | 2 - oss-fuzz.sh | 2 - tests/fuzzers/modexp/debug/main.go | 40 ------------ tests/fuzzers/modexp/modexp-fuzzer.go | 90 --------------------------- 7 files changed, 4 insertions(+), 193 deletions(-) delete mode 100644 common/math/modexp_test.go delete mode 100644 tests/fuzzers/modexp/debug/main.go delete mode 100644 tests/fuzzers/modexp/modexp-fuzzer.go diff --git a/common/math/modexp_test.go b/common/math/modexp_test.go deleted file mode 100644 index bd90076f84f6..000000000000 --- a/common/math/modexp_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2022 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 math - -import ( - "math/big" - "testing" - - big2 "github.com/holiman/big" -) - -// TestFastModexp tests some cases found during fuzzing. -func TestFastModexp(t *testing.T) { - for i, tc := range []struct { - base string - exp string - mod string - }{ - {"0xeffffff900002f00", "0x40000000000000", "0x200"}, - {"0xf000", "0x4f900b400080000", "0x400000d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9ffffff005aeffd310000000000000000000000000000000000009f9f9f9f0000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000befffa5a5a5fff900002f000040000000000000000000000000000000029d9d9d000000000000009f9f9f00000000000000009f9f9f000000f3a080ab00000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f0000000000002900009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000cf000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000befffff0000c0800000000800000000000000000000000000000002000000000000009f9f9f0000000000000000008000ff000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000befffa5a5a5fff900002f000040000000000000000000000000000000029d9d9d000000000000009f9f9f00000000000000009f9f9f000000f3a080ab00000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f0000000000002900009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f000000000000000000000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000beffffff900002f0000400000c100000000000000000000000000000000000000006160600000000000000000008000ff0000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f00000000000000009f9f0000"}, - {"5", "1435700818", "72"}, - {"0xffff", "0x300030003000300030003000300030003000302a3000300030003000300030003000300030003000300030003000300030003030623066307f3030783062303430383064303630343036", "0x300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, - {"0x3133", "0x667f00000000000000000000000000ff002a000000000000000000000000000000000000000000000000000000000000667fff30783362773057ee756a6c266134643831646230313630", "0x3030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, - } { - var ( - base, _ = new(big.Int).SetString(tc.base, 0) - exp, _ = new(big.Int).SetString(tc.exp, 0) - mod, _ = new(big.Int).SetString(tc.mod, 0) - base2, _ = new(big2.Int).SetString(tc.base, 0) - exp2, _ = new(big2.Int).SetString(tc.exp, 0) - mod2, _ = new(big2.Int).SetString(tc.mod, 0) - ) - var a = new(big2.Int).Exp(base2, exp2, mod2).String() - var b = new(big.Int).Exp(base, exp, mod).String() - if a != b { - t.Errorf("test %d: %#x ^ %#x mod %#x \n have %x\n want %x", i, base, exp, mod, a, b) - } - } -} diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 9a52616657bb..aa4a3f13df5e 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/crypto/bls12381" "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/params" - big2 "github.com/holiman/big" "golang.org/x/crypto/ripemd160" ) @@ -378,9 +377,9 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) { } // Retrieve the operands and execute the exponentiation var ( - base = new(big2.Int).SetBytes(getData(input, 0, baseLen)) - exp = new(big2.Int).SetBytes(getData(input, baseLen, expLen)) - mod = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + base = new(big.Int).SetBytes(getData(input, 0, baseLen)) + exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) + mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) v []byte ) switch { diff --git a/go.mod b/go.mod index 1be13e163e3d..21325d5669e1 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,6 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 - github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e github.com/holiman/bloomfilter/v2 v2.0.3 github.com/holiman/uint256 v1.2.0 github.com/huin/goupnp v1.0.3 @@ -45,6 +44,7 @@ require ( github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/julienschmidt/httprouter v1.3.0 github.com/karalabe/usb v0.0.2 + github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.16 github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 @@ -98,7 +98,6 @@ require ( github.com/klauspost/compress v1.15.15 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect diff --git a/go.sum b/go.sum index 18c7e271ecb1..51beb15cd24a 100644 --- a/go.sum +++ b/go.sum @@ -293,8 +293,6 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw= -github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= diff --git a/oss-fuzz.sh b/oss-fuzz.sh index 7f454ff307b4..745a5ba7c7c0 100644 --- a/oss-fuzz.sh +++ b/oss-fuzz.sh @@ -125,7 +125,5 @@ compile_fuzzer tests/fuzzers/snap FuzzSRange fuzz_storage_range compile_fuzzer tests/fuzzers/snap FuzzByteCodes fuzz_byte_codes compile_fuzzer tests/fuzzers/snap FuzzTrieNodes fuzz_trie_nodes -compile_fuzzer tests/fuzzers/modexp Fuzz fuzzModexp - #TODO: move this to tests/fuzzers, if possible compile_fuzzer crypto/blake2b Fuzz fuzzBlake2b diff --git a/tests/fuzzers/modexp/debug/main.go b/tests/fuzzers/modexp/debug/main.go deleted file mode 100644 index 22002bd3f807..000000000000 --- a/tests/fuzzers/modexp/debug/main.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2020 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 main - -import ( - "fmt" - "os" - - "github.com/ethereum/go-ethereum/tests/fuzzers/modexp" -) - -func main() { - if len(os.Args) != 2 { - fmt.Fprintf(os.Stderr, "Usage: debug \n") - fmt.Fprintf(os.Stderr, "Example\n") - fmt.Fprintf(os.Stderr, " $ debug ../crashers/4bbef6857c733a87ecf6fd8b9e7238f65eb9862a\n") - os.Exit(1) - } - crasher := os.Args[1] - data, err := os.ReadFile(crasher) - if err != nil { - fmt.Fprintf(os.Stderr, "error loading crasher %v: %v", crasher, err) - os.Exit(1) - } - modexp.Fuzz(data) -} diff --git a/tests/fuzzers/modexp/modexp-fuzzer.go b/tests/fuzzers/modexp/modexp-fuzzer.go deleted file mode 100644 index 086d9e115310..000000000000 --- a/tests/fuzzers/modexp/modexp-fuzzer.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2022 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 modexp - -import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - big2 "github.com/holiman/big" -) - -// Fuzz is the fuzzing entry-point. -// The function must return -// -// - 1 if the fuzzer should increase priority of the -// given input during subsequent fuzzing (for example, the input is lexically -// correct and was parsed successfully); -// - -1 if the input must not be added to corpus even if gives new coverage; and -// - 0 otherwise -// -// other values are reserved for future use. -func Fuzz(input []byte) int { - if len(input) <= 96 { - return -1 - } - // Abort on too expensive inputs - precomp := vm.PrecompiledContractsBerlin[common.BytesToAddress([]byte{5})] - if gas := precomp.RequiredGas(input); gas > 40_000_000 { - return 0 - } - 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() - ) - // Handle a special case when both the base and mod length is zero - if baseLen == 0 && modLen == 0 { - return -1 - } - input = input[96:] - // Retrieve the operands and execute the exponentiation - var ( - base = new(big.Int).SetBytes(getData(input, 0, baseLen)) - exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) - mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) - base2 = new(big2.Int).SetBytes(getData(input, 0, baseLen)) - exp2 = new(big2.Int).SetBytes(getData(input, baseLen, expLen)) - mod2 = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen)) - ) - if mod.BitLen() == 0 { - // Modulo 0 is undefined, return zero - return -1 - } - var a = new(big2.Int).Exp(base2, exp2, mod2).String() - var b = new(big.Int).Exp(base, exp, mod).String() - if a != b { - panic(fmt.Sprintf("Inequality %#x ^ %#x mod %#x \n have %s\n want %s", base, exp, mod, a, b)) - } - return 1 -} - -// getData returns a slice from the data based on the start and size and pads -// up to size with zero's. This function is overflow safe. -func getData(data []byte, start uint64, size uint64) []byte { - length := uint64(len(data)) - if start > length { - start = length - } - end := start + size - if end > length { - end = length - } - return common.RightPadBytes(data[start:end], int(size)) -} From 1bf1168432223b69de97975bb457870889a85dd3 Mon Sep 17 00:00:00 2001 From: xiyang <90125263+JBossBC@users.noreply.github.com> Date: Thu, 9 Mar 2023 17:39:17 +0800 Subject: [PATCH 617/715] core/vm: fix typo in comment (#26838) fixes eip 220 -> 2200 --- core/vm/gas_table.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 65d46b3436d9..4f961ef4db3f 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -163,7 +163,7 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi return params.NetSstoreDirtyGas, nil } -// Here come the EIP220 rules: +// Here come the EIP2200 rules: // // (0.) If *gasleft* is less than or equal to 2300, fail the current call. // (1.) If current value equals new value (this is a no-op), SLOAD_GAS is deducted. From 5395362e0f2ca6f3c9a3a2aa7efd14bfae5a86da Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 9 Mar 2023 12:37:44 +0100 Subject: [PATCH 618/715] core/forkid: fix issue in validation test (#26544) This changes the test to match the comment description. Using timestampedConfig in this test case is incorrect, the comment says 'local is at Gray Glacier' and isn't aware of more forks. --- core/forkid/forkid_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index 15918791ad10..4dda280e7150 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -308,7 +308,7 @@ func TestValidation(t *testing.T) { // Local is mainnet Gray Glacier, and isn't aware of more forks. Remote announces Gray Glacier + // 0xffffffff. Local needs software update, reject. - {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(checksumUpdate(0xf0afd0e3, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, + {params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(checksumUpdate(0xf0afd0e3, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Gray Glacier, and is aware of Shanghai. Remote announces Shanghai + // 0xffffffff. Local needs software update, reject. From 08f6a2a89d89e4510ab98ad8fc4e6b1894d0da94 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 9 Mar 2023 07:06:47 -0500 Subject: [PATCH 619/715] cmd/evm: update readmes for the tests (#26841) --- cmd/evm/testdata/10/readme.md | 134 ++++++----- cmd/evm/testdata/12/readme.md | 45 ++-- cmd/evm/testdata/14/readme.md | 24 +- cmd/evm/testdata/19/readme.md | 16 ++ cmd/evm/testdata/7/readme.md | 370 ++++++++++++++++++++++++++++- cmd/evm/testdata/8/readme.md | 38 ++- cmd/evm/testdata/9/readme.md | 58 ++--- cmd/evm/testdata/9/txs_signed.json | 37 +++ 8 files changed, 578 insertions(+), 144 deletions(-) create mode 100644 cmd/evm/testdata/9/txs_signed.json diff --git a/cmd/evm/testdata/10/readme.md b/cmd/evm/testdata/10/readme.md index c34be80bb71c..afa378723814 100644 --- a/cmd/evm/testdata/10/readme.md +++ b/cmd/evm/testdata/10/readme.md @@ -9,71 +9,77 @@ INFO [05-09|22:11:59.436] rejected tx index=3 hash= Output: ```json { - "alloc": { - "0x1111111111111111111111111111111111111111": { - "code": "0xfe", - "balance": "0x10000000000", - "nonce": "0x1" + "alloc": { + "0x1111111111111111111111111111111111111111": { + "code": "0xfe", + "balance": "0x10000000000", + "nonce": "0x1" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x10000000000", + "nonce": "0x1" + }, + "0xd02d72e067e77158444ef2020ff2d325f929b363": { + "balance": "0xff5beffffc95", + "nonce": "0x4" + } }, - "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0x10000000000", - "nonce": "0x1" - }, - "0xd02d72e067e77158444ef2020ff2d325f929b363": { - "balance": "0xff5beffffc95", - "nonce": "0x4" - } - }, - "result": { - "stateRoot": "0xf91a7ec08e4bfea88719aab34deabb000c86902360532b52afa9599d41f2bb8b", - "txRoot": "0xda925f2306a52fa24c15d5cd212d736ee016415fd8dd0c45fd368de7917d64bb", - "receiptRoot": "0x439a25f7fc424c10fb1f89800e4aa1df74156b137239d9ac3eaa7c911c353cd5", - "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "receipts": [ - { - "type": "0x2", - "root": "0x", - "status": "0x0", - "cumulativeGasUsed": "0x10000001", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "logs": null, - "transactionHash": "0x88980f6efcc5358d9c359663e7b9414722d430497637340ea056b076bc206701", - "contractAddress": "0x0000000000000000000000000000000000000000", - "gasUsed": "0x10000001", - "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "transactionIndex": "0x0" - }, - { - "type": "0x2", - "root": "0x", - "status": "0x0", - "cumulativeGasUsed": "0x20000001", + "result": { + "stateRoot": "0xf91a7ec08e4bfea88719aab34deabb000c86902360532b52afa9599d41f2bb8b", + "txRoot": "0xda925f2306a52fa24c15d5cd212d736ee016415fd8dd0c45fd368de7917d64bb", + "receiptsRoot": "0x439a25f7fc424c10fb1f89800e4aa1df74156b137239d9ac3eaa7c911c353cd5", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "logs": null, - "transactionHash": "0xd7bf3886f4e2aef74d525ae072c680f3846f550254401b67cbfda4a233757582", - "contractAddress": "0x0000000000000000000000000000000000000000", - "gasUsed": "0x10000000", - "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "transactionIndex": "0x1" - }, - { - "type": "0x2", - "root": "0x", - "status": "0x0", - "cumulativeGasUsed": "0x30000001", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "logs": null, - "transactionHash": "0x50308296760f01f1eeec7500e9e73cad67469249b1f59e9a9f55e6625a4923db", - "contractAddress": "0x0000000000000000000000000000000000000000", - "gasUsed": "0x10000000", - "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "transactionIndex": "0x2" - } - ], - "rejected": [ - 3 - ] - } + "receipts": [ + { + "type": "0x2", + "root": "0x", + "status": "0x0", + "cumulativeGasUsed": "0x10000001", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x88980f6efcc5358d9c359663e7b9414722d430497637340ea056b076bc206701", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x10000001", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x0" + }, + { + "type": "0x2", + "root": "0x", + "status": "0x0", + "cumulativeGasUsed": "0x20000001", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0xd7bf3886f4e2aef74d525ae072c680f3846f550254401b67cbfda4a233757582", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x10000000", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x1" + }, + { + "type": "0x2", + "root": "0x", + "status": "0x0", + "cumulativeGasUsed": "0x30000001", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "logs": null, + "transactionHash": "0x50308296760f01f1eeec7500e9e73cad67469249b1f59e9a9f55e6625a4923db", + "contractAddress": "0x0000000000000000000000000000000000000000", + "gasUsed": "0x10000000", + "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionIndex": "0x2" + } + ], + "rejected": [ + { + "index": 3, + "error": "gas limit reached" + } + ], + "currentDifficulty": "0x20000", + "gasUsed": "0x30000001", + "currentBaseFee": "0x36b" + } } ``` diff --git a/cmd/evm/testdata/12/readme.md b/cmd/evm/testdata/12/readme.md index b0177ecc24b6..e3195be48ba5 100644 --- a/cmd/evm/testdata/12/readme.md +++ b/cmd/evm/testdata/12/readme.md @@ -11,29 +11,32 @@ dir=./testdata/12 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json With the fix applied, the result is: ``` dir=./testdata/12 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout --output.result=stdout -INFO [07-21|19:03:50.276] rejected tx index=0 hash=ccc996..d83435 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032" -INFO [07-21|19:03:50.276] Trie dumping started root=e05f81..6597a5 -INFO [07-21|19:03:50.276] Trie dumping complete accounts=1 elapsed="39.549µs" +INFO [03-09|10:43:12.649] rejected tx index=0 hash=ccc996..d83435 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032" +INFO [03-09|10:43:12.650] Trie dumping started root=e05f81..6597a5 +INFO [03-09|10:43:12.650] Trie dumping complete accounts=1 elapsed="46.393µs" { - "alloc": { - "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0x501bd00" + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x501bd00" + } + }, + "result": { + "stateRoot": "0xe05f81f8244a76503ceec6f88abfcd03047a612a1001217f37d30984536597a5", + "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [], + "rejected": [ + { + "index": 0, + "error": "insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032" + } + ], + "currentDifficulty": "0x20000", + "gasUsed": "0x0", + "currentBaseFee": "0x20" } - }, - "result": { - "stateRoot": "0xe05f81f8244a76503ceec6f88abfcd03047a612a1001217f37d30984536597a5", - "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "receipts": [], - "rejected": [ - { - "index": 0, - "error": "insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032" - } - ] - } } ``` diff --git a/cmd/evm/testdata/14/readme.md b/cmd/evm/testdata/14/readme.md index 9d0dc9569c67..40dd75486ee8 100644 --- a/cmd/evm/testdata/14/readme.md +++ b/cmd/evm/testdata/14/readme.md @@ -5,36 +5,40 @@ This test shows how the `evm t8n` can be used to calculate the (ethash) difficul Calculating it (with an empty set of txs) using `London` rules (and no provided unclehash for the parent block): ``` [user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.json --output.result=stdout --state.fork=London -INFO [08-30|20:43:09.352] Trie dumping started root=6f0588..7f4bdc -INFO [08-30|20:43:09.352] Trie dumping complete accounts=2 elapsed="82.533µs" -INFO [08-30|20:43:09.352] Wrote file file=alloc.json +INFO [03-09|10:43:57.070] Trie dumping started root=6f0588..7f4bdc +INFO [03-09|10:43:57.070] Trie dumping complete accounts=2 elapsed="214.663µs" +INFO [03-09|10:43:57.071] Wrote file file=alloc.json { "result": { "stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc", "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "receipts": [], - "currentDifficulty": "0x2000020000000" + "currentDifficulty": "0x2000020000000", + "gasUsed": "0x0", + "currentBaseFee": "0x500" } } ``` Same thing, but this time providing a non-empty (and non-`emptyKeccak`) unclehash, which leads to a slightly different result: ``` [user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.uncles.json --output.result=stdout --state.fork=London -INFO [08-30|20:44:33.102] Trie dumping started root=6f0588..7f4bdc -INFO [08-30|20:44:33.102] Trie dumping complete accounts=2 elapsed="72.91µs" -INFO [08-30|20:44:33.102] Wrote file file=alloc.json +INFO [03-09|10:44:20.511] Trie dumping started root=6f0588..7f4bdc +INFO [03-09|10:44:20.511] Trie dumping complete accounts=2 elapsed="184.319µs" +INFO [03-09|10:44:20.512] Wrote file file=alloc.json { "result": { "stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc", "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "receipts": [], - "currentDifficulty": "0x1ff8020000000" + "currentDifficulty": "0x1ff8020000000", + "gasUsed": "0x0", + "currentBaseFee": "0x500" } } ``` diff --git a/cmd/evm/testdata/19/readme.md b/cmd/evm/testdata/19/readme.md index 095d4525d4fe..9c7c4b3656b0 100644 --- a/cmd/evm/testdata/19/readme.md +++ b/cmd/evm/testdata/19/readme.md @@ -6,4 +6,20 @@ this time on `GrayGlacier` (Eip 5133). Calculating it (with an empty set of txs) using `GrayGlacier` rules (and no provided unclehash for the parent block): ``` [user@work evm]$ ./evm t8n --input.alloc=./testdata/19/alloc.json --input.txs=./testdata/19/txs.json --input.env=./testdata/19/env.json --output.result=stdout --state.fork=GrayGlacier +INFO [03-09|10:45:26.777] Trie dumping started root=6f0588..7f4bdc +INFO [03-09|10:45:26.777] Trie dumping complete accounts=2 elapsed="176.471µs" +INFO [03-09|10:45:26.777] Wrote file file=alloc.json +{ + "result": { + "stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc", + "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [], + "currentDifficulty": "0x2000000004000", + "gasUsed": "0x0", + "currentBaseFee": "0x500" + } +} ``` \ No newline at end of file diff --git a/cmd/evm/testdata/7/readme.md b/cmd/evm/testdata/7/readme.md index c9826e0ba67e..59e0dbef99b0 100644 --- a/cmd/evm/testdata/7/readme.md +++ b/cmd/evm/testdata/7/readme.md @@ -3,5 +3,373 @@ DAO-transition works Example: ``` -./statet8n --input.alloc=./testdata/7/alloc.json --input.txs=./testdata/7/txs.json --input.env=./testdata/7/env.json --output.alloc=stdout --state.fork=HomesteadToDaoAt5 + ./evm t8n --input.alloc=./testdata/7/alloc.json --input.txs=./testdata/7/txs.json --input.env=./testdata/7/env.json --output.alloc=stdout --state.fork=HomesteadToDaoAt5 +INFO [03-09|10:47:37.255] Trie dumping started root=157847..2891b7 +INFO [03-09|10:47:37.256] Trie dumping complete accounts=120 elapsed="715.635µs" +INFO [03-09|10:47:37.256] Wrote file file=result.json +{ + "alloc": { + "0x005f5cee7a43331d5a3d3eec71305925a62f34b6": { + "balance": "0x0" + }, + "0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9": { + "balance": "0x0" + }, + "0x057b56736d32b86616a10f619859c6cd6f59092a": { + "balance": "0x0" + }, + "0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936": { + "balance": "0x0" + }, + "0x0737a6b837f97f46ebade41b9bc3e1c509c85c53": { + "balance": "0x0" + }, + "0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a": { + "balance": "0x0" + }, + "0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d": { + "balance": "0x0" + }, + "0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00": { + "balance": "0x0" + }, + "0x12e626b0eebfe86a56d633b9864e389b45dcb260": { + "balance": "0x0" + }, + "0x1591fc0f688c81fbeb17f5426a162a7024d430c2": { + "balance": "0x0" + }, + "0x17802f43a0137c506ba92291391a8a8f207f487d": { + "balance": "0x0" + }, + "0x1975bd06d486162d5dc297798dfc41edd5d160a7": { + "balance": "0x0" + }, + "0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b": { + "balance": "0x0" + }, + "0x1cba23d343a983e9b5cfd19496b9a9701ada385f": { + "balance": "0x0" + }, + "0x200450f06520bdd6c527622a273333384d870efb": { + "balance": "0x0" + }, + "0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241": { + "balance": "0x0" + }, + "0x23b75c2f6791eef49c69684db4c6c1f93bf49a50": { + "balance": "0x0" + }, + "0x24c4d950dfd4dd1902bbed3508144a54542bba94": { + "balance": "0x0" + }, + "0x253488078a4edf4d6f42f113d1e62836a942cf1a": { + "balance": "0x0" + }, + "0x27b137a85656544b1ccb5a0f2e561a5703c6a68f": { + "balance": "0x0" + }, + "0x2a5ed960395e2a49b1c758cef4aa15213cfd874c": { + "balance": "0x0" + }, + "0x2b3455ec7fedf16e646268bf88846bd7a2319bb2": { + "balance": "0x0" + }, + "0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f": { + "balance": "0x0" + }, + "0x304a554a310c7e546dfe434669c62820b7d83490": { + "balance": "0x0" + }, + "0x319f70bab6845585f412ec7724b744fec6095c85": { + "balance": "0x0" + }, + "0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b": { + "balance": "0x0" + }, + "0x3ba4d81db016dc2890c81f3acec2454bff5aada5": { + "balance": "0x0" + }, + "0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5": { + "balance": "0x0" + }, + "0x40b803a9abce16f50f36a77ba41180eb90023925": { + "balance": "0x0" + }, + "0x440c59b325d2997a134c2c7c60a8c61611212bad": { + "balance": "0x0" + }, + "0x4486a3d68fac6967006d7a517b889fd3f98c102b": { + "balance": "0x0" + }, + "0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a": { + "balance": "0x0" + }, + "0x47e7aa56d6bdf3f36be34619660de61275420af8": { + "balance": "0x0" + }, + "0x4863226780fe7c0356454236d3b1c8792785748d": { + "balance": "0x0" + }, + "0x492ea3bb0f3315521c31f273e565b868fc090f17": { + "balance": "0x0" + }, + "0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c": { + "balance": "0x0" + }, + "0x4deb0033bb26bc534b197e61d19e0733e5679784": { + "balance": "0x0" + }, + "0x4fa802324e929786dbda3b8820dc7834e9134a2a": { + "balance": "0x0" + }, + "0x4fd6ace747f06ece9c49699c7cabc62d02211f75": { + "balance": "0x0" + }, + "0x51e0ddd9998364a2eb38588679f0d2c42653e4a6": { + "balance": "0x0" + }, + "0x52c5317c848ba20c7504cb2c8052abd1fde29d03": { + "balance": "0x0" + }, + "0x542a9515200d14b68e934e9830d91645a980dd7a": { + "balance": "0x0" + }, + "0x5524c55fb03cf21f549444ccbecb664d0acad706": { + "balance": "0x0" + }, + "0x579a80d909f346fbfb1189493f521d7f48d52238": { + "balance": "0x0" + }, + "0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb": { + "balance": "0x0" + }, + "0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5": { + "balance": "0x0" + }, + "0x5c8536898fbb74fc7445814902fd08422eac56d0": { + "balance": "0x0" + }, + "0x5d2b2e6fcbe3b11d26b525e085ff818dae332479": { + "balance": "0x0" + }, + "0x5dc28b15dffed94048d73806ce4b7a4612a1d48f": { + "balance": "0x0" + }, + "0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c": { + "balance": "0x0" + }, + "0x6131c42fa982e56929107413a9d526fd99405560": { + "balance": "0x0" + }, + "0x6231b6d0d5e77fe001c2a460bd9584fee60d409b": { + "balance": "0x0" + }, + "0x627a0a960c079c21c34f7612d5d230e01b4ad4c7": { + "balance": "0x0" + }, + "0x63ed5a272de2f6d968408b4acb9024f4cc208ebf": { + "balance": "0x0" + }, + "0x6966ab0d485353095148a2155858910e0965b6f9": { + "balance": "0x0" + }, + "0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb": { + "balance": "0x0" + }, + "0x6d87578288b6cb5549d5076a207456a1f6a63dc0": { + "balance": "0x0" + }, + "0x6f6704e5a10332af6672e50b3d9754dc460dfa4d": { + "balance": "0x0" + }, + "0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97": { + "balance": "0x0" + }, + "0x779543a0491a837ca36ce8c635d6154e3c4911a6": { + "balance": "0x0" + }, + "0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6": { + "balance": "0x0" + }, + "0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4": { + "balance": "0x0" + }, + "0x807640a13483f8ac783c557fcdf27be11ea4ac7a": { + "balance": "0x0" + }, + "0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd": { + "balance": "0x0" + }, + "0x84ef4b2357079cd7a7c69fd7a37cd0609a679106": { + "balance": "0x0" + }, + "0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915": { + "balance": "0x0" + }, + "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": { + "balance": "0xfeedbead" + }, + "0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6": { + "balance": "0x0" + }, + "0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79": { + "balance": "0x0" + }, + "0x97f43a37f595ab5dd318fb46e7a155eae057317a": { + "balance": "0x0" + }, + "0x9aa008f65de0b923a2a4f02012ad034a5e2e2192": { + "balance": "0x0" + }, + "0x9c15b54878ba618f494b38f0ae7443db6af648ba": { + "balance": "0x0" + }, + "0x9c50426be05db97f5d64fc54bf89eff947f0a321": { + "balance": "0x0" + }, + "0x9da397b9e80755301a3b32173283a91c0ef6c87e": { + "balance": "0x0" + }, + "0x9ea779f907f0b315b364b0cfc39a0fde5b02a416": { + "balance": "0x0" + }, + "0x9f27daea7aca0aa0446220b98d028715e3bc803d": { + "balance": "0x0" + }, + "0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339": { + "balance": "0x0" + }, + "0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7": { + "balance": "0x0" + }, + "0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6": { + "balance": "0x0" + }, + "0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90": { + "balance": "0x0" + }, + "0xa82f360a8d3455c5c41366975bde739c37bfeb8a": { + "balance": "0x0" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x5ffd4878be161d74", + "nonce": "0xac" + }, + "0xac1ecab32727358dba8962a0f3b261731aad9723": { + "balance": "0x0" + }, + "0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6": { + "balance": "0x0" + }, + "0xacd87e28b0c9d1254e868b81cba4cc20d9a32225": { + "balance": "0x0" + }, + "0xadf80daec7ba8dcf15392f1ac611fff65d94f880": { + "balance": "0x0" + }, + "0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c": { + "balance": "0x0" + }, + "0xb136707642a4ea12fb4bae820f03d2562ebff487": { + "balance": "0x0" + }, + "0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e": { + "balance": "0x0" + }, + "0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425": { + "balance": "0x0" + }, + "0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab": { + "balance": "0x0" + }, + "0xb9637156d330c0d605a791f1c31ba5890582fe1c": { + "balance": "0x0" + }, + "0xbb9bc244d798123fde783fcc1c72d3bb8c189413": { + "balance": "0x0" + }, + "0xbc07118b9ac290e4622f5e77a0853539789effbe": { + "balance": "0x0" + }, + "0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76": { + "balance": "0x0" + }, + "0xbe8539bfe837b67d1282b2b1d61c3f723966f049": { + "balance": "0x0" + }, + "0xbf4ed7b27f1d666546e30d74d50d173d20bca754": { + "balance": "0x0" + }, + "0xc4bbd073882dd2add2424cf47d35213405b01324": { + "balance": "0x0" + }, + "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x0" + }, + "0xca544e5c4687d109611d0f8f928b53a25af72448": { + "balance": "0x0" + }, + "0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7": { + "balance": "0x0" + }, + "0xcc34673c6c40e791051898567a1222daf90be287": { + "balance": "0x0" + }, + "0xceaeb481747ca6c540a000c1f3641f8cef161fa7": { + "balance": "0x0" + }, + "0xd131637d5275fd1a68a3200f4ad25c71a2a9522e": { + "balance": "0x0" + }, + "0xd164b088bd9108b60d0ca3751da4bceb207b0782": { + "balance": "0x0" + }, + "0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091": { + "balance": "0x0" + }, + "0xd343b217de44030afaa275f54d31a9317c7f441e": { + "balance": "0x0" + }, + "0xd4fe7bc31cedb7bfb8a345f31e668033056b2728": { + "balance": "0x0" + }, + "0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b": { + "balance": "0x0" + }, + "0xda2fef9e4a3230988ff17df2165440f37e8b1708": { + "balance": "0x0" + }, + "0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940": { + "balance": "0x0" + }, + "0xe308bd1ac5fda103967359b2712dd89deffb7973": { + "balance": "0x0" + }, + "0xe4ae1efdfc53b73893af49113d8694a057b9c0d1": { + "balance": "0x0" + }, + "0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5": { + "balance": "0x0" + }, + "0xecd135fa4f61a655311e86238c92adcd779555d2": { + "balance": "0x0" + }, + "0xf0b1aa0eb660754448a7937c022e30aa692fe0c5": { + "balance": "0x0" + }, + "0xf1385fb24aad0cd7432824085e42aff90886fef5": { + "balance": "0x0" + }, + "0xf14c14075d6c4ed84b86798af0956deef67365b5": { + "balance": "0x0" + }, + "0xf4c64518ea10f995918a454158c6b61407ea345c": { + "balance": "0x0" + }, + "0xfe24cdd8648121a43a7c86d289be4dd2951ed49f": { + "balance": "0x0" + } + } +} ``` \ No newline at end of file diff --git a/cmd/evm/testdata/8/readme.md b/cmd/evm/testdata/8/readme.md index e021cd7e2ee4..c991fb217799 100644 --- a/cmd/evm/testdata/8/readme.md +++ b/cmd/evm/testdata/8/readme.md @@ -23,41 +23,37 @@ There are three transactions, each invokes the contract above. Running it yields: ``` -dir=./testdata/8 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace && cat trace-* | grep SLOAD -{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} - +dir=./testdata/8 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace 2>/dev/null && cat trace-* | grep SLOAD +{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"} ``` Simlarly, we can provide the input transactions via `stdin` instead of as file: ``` -dir=./testdata/8 \ +$ dir=./testdata/8 \ && cat $dir/txs.json | jq "{txs: .}" \ | ./evm t8n --state.fork=Berlin \ --input.alloc=$dir/alloc.json \ --input.txs=stdin \ --input.env=$dir/env.json \ --trace \ + 2>/dev/null \ && cat trace-* | grep SLOAD - -{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} +{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"} ``` If we try to execute it on older rules: ``` -dir=./testdata/8 && ./evm t8n --state.fork=Istanbul --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json -INFO [01-21|23:21:51.265] rejected tx index=0 hash=d2818d..6ab3da error="tx type not supported" -INFO [01-21|23:21:51.265] rejected tx index=1 hash=26ea00..81c01b from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0" -INFO [01-21|23:21:51.265] rejected tx index=2 hash=698d01..369cee error="tx type not supported" +$ dir=./testdata/8 && ./evm t8n --state.fork=Istanbul --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json +ERROR(10): failed signing transactions: ERROR(10): tx 0: failed to sign tx: transaction type not supported ``` -Number `1` and `3` are not applicable, and therefore number `2` has wrong nonce. \ No newline at end of file diff --git a/cmd/evm/testdata/9/readme.md b/cmd/evm/testdata/9/readme.md index f26225a342ee..b14464465547 100644 --- a/cmd/evm/testdata/9/readme.md +++ b/cmd/evm/testdata/9/readme.md @@ -22,35 +22,37 @@ There are two transactions, each invokes the contract above. Running it yields: ``` -$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace && cat trace-* | grep SLOAD -{"pc":2,"op":84,"gas":"0x48c28","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x1"],"returnStack":null,"returnD -ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":3,"op":84,"gas":"0x483f4","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0","0x0"],"returnStack":null,"returnDa -ta":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":2,"op":84,"gas":"0x49cf4","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x1"],"returnStack":null,"returnD -ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} -{"pc":3,"op":84,"gas":"0x494c0","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x0"],"returnStack":null,"returnD -ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} +$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace 2>/dev/null && cat trace-* | grep SLOAD +{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":2,"op":84,"gas":"0x48c28","gasCost":"0x834","memSize":0,"stack":["0x0","0x1"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":3,"op":84,"gas":"0x483f4","gasCost":"0x64","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":2,"op":84,"gas":"0x49cf4","gasCost":"0x834","memSize":0,"stack":["0x0","0x1"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":3,"op":84,"gas":"0x494c0","gasCost":"0x834","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"} +{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"} ``` We can also get the post-alloc: ``` -$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout +$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout 2>/dev/null { - "alloc": { - "0x000000000000000000000000000000000000aaaa": { - "code": "0x58585454", - "balance": "0x3", - "nonce": "0x1" - }, - "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { - "balance": "0x5bb10ddef6e0" - }, - "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0xff745ee8832120", - "nonce": "0x2" + "alloc": { + "0x000000000000000000000000000000000000aaaa": { + "code": "0x58585454", + "balance": "0x3", + "nonce": "0x1" + }, + "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { + "balance": "0x5bb10ddef6e0" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0xff745ee8832120", + "nonce": "0x2" + } } - } } ``` @@ -65,10 +67,12 @@ by feeding it presigned transactions, located in `txs_signed.json`. ``` dir=./testdata/9 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs_signed.json --input.env=$dir/env.json -INFO [05-07|12:28:42.072] rejected tx index=0 hash=b4821e..536819 error="transaction type not supported" -INFO [05-07|12:28:42.072] rejected tx index=1 hash=a9c6c6..fa4036 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0" -INFO [05-07|12:28:42.073] Wrote file file=alloc.json -INFO [05-07|12:28:42.073] Wrote file file=result.json +WARN [03-09|11:06:22.065] rejected tx index=0 hash=334e09..f8dce5 error="transaction type not supported" +INFO [03-09|11:06:22.066] rejected tx index=1 hash=a9c6c6..fa4036 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0" +INFO [03-09|11:06:22.066] Trie dumping started root=6eebe9..a0fda5 +INFO [03-09|11:06:22.066] Trie dumping complete accounts=2 elapsed="55.844µs" +INFO [03-09|11:06:22.066] Wrote file file=alloc.json +INFO [03-09|11:06:22.066] Wrote file file=result.json ``` Number `0` is not applicable, and therefore number `1` has wrong nonce, and both are rejected. diff --git a/cmd/evm/testdata/9/txs_signed.json b/cmd/evm/testdata/9/txs_signed.json new file mode 100644 index 000000000000..dcddf011b449 --- /dev/null +++ b/cmd/evm/testdata/9/txs_signed.json @@ -0,0 +1,37 @@ +[ + { + "gas": "0x4ef00", + "maxFeePerGas": "0x2", + "maxPriorityFeePerGas": "0x12A05F200", + "chainId": "0x1", + "input": "0x", + "nonce": "0x0", + "to": "0x000000000000000000000000000000000000aaaa", + "value": "0x0", + "type" : "0x2", + "accessList": [ + {"address": "0x000000000000000000000000000000000000aaaa", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ] + } + ], + "v": "0x1", + "r": "0xd77c8ff989789b5d9d99254cbae2e2996dc7e6215cba4d55254c14e6d6b9f314", + "s": "0x5cc021481e7e6bb444bbb87ab32071e8fd0a8d1e125c7bb352d2879bd7ff5c0a", + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + }, + { + "gas": "0x4ef00", + "gasPrice": "0x12A05F200", + "chainId": "0x1", + "input": "0x", + "nonce": "0x1", + "to": "0x000000000000000000000000000000000000aaaa", + "value": "0x0", + "v": "0x25", + "r": "0xbee5ec9f6650020266bf3455a852eece2b073a2fa918c4d1836a1af69c2aa50c", + "s": "0x556c897a58dbc007a6b09814e1fba7502adb76effd2146da4365816926f387ce", + "secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" + } +] From 67ac5f0ae797fbafa1e57e982cab4c2d291244c3 Mon Sep 17 00:00:00 2001 From: Roberto Bayardo Date: Thu, 9 Mar 2023 05:19:12 -0800 Subject: [PATCH 620/715] core, core/types: plain Message struct (#25977) Here, the core.Message interface turns into a plain struct and types.Message gets removed. This is a breaking change to packages core and core/types. While we do not promise API stability for package core, we do for core/types. An exception can be made for types.Message, since it doesn't have any purpose apart from invoking the state transition in package core. types.Message was also marked deprecated by the same commit it got added in, 4dca5d4db7 (November 2016). The core.Message interface was added in December 2014, in commit db494170dc, for the purpose of 'testing' state transitions. It's the same change that made transaction struct fields private. Before that, the state transition used *types.Transaction directly. Over time, multiple implementations of the interface accrued across different packages, since constructing a Message is required whenever one wants to invoke the state transition. These implementations all looked very similar, a struct with private fields exposing the fields as accessor methods. By changing Message into a struct with public fields we can remove all these useless interface implementations. It will also hopefully simplify future changes to the type with less updates to apply across all of go-ethereum when a field is added to Message. --------- Co-authored-by: Felix Lange --- accounts/abi/bind/backends/simulated.go | 38 ++- cmd/evm/internal/t8ntool/execution.go | 6 +- core/evm.go | 6 +- core/state_prefetcher.go | 4 +- core/state_processor.go | 8 +- core/state_transition.go | 262 ++++++++++-------- core/types/transaction.go | 68 ----- eth/api_backend.go | 4 +- eth/state_accessor.go | 4 +- eth/tracers/api.go | 24 +- eth/tracers/api_test.go | 4 +- .../internal/tracetest/calltrace_test.go | 6 +- .../internal/tracetest/flat_calltrace_test.go | 2 +- .../internal/tracetest/prestate_test.go | 2 +- eth/tracers/tracers_test.go | 2 +- internal/ethapi/api.go | 4 +- internal/ethapi/backend.go | 2 +- internal/ethapi/transaction_args.go | 18 +- internal/ethapi/transaction_args_test.go | 2 +- les/api_backend.go | 4 +- les/odr_test.go | 30 +- les/state_accessor.go | 4 +- light/odr_test.go | 18 +- tests/state_test.go | 8 +- tests/state_test_util.go | 16 +- 25 files changed, 265 insertions(+), 281 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index dc7405ed1905..3d5259b894df 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -644,20 +644,33 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM if call.Value == nil { call.Value = new(big.Int) } + // Set infinite balance to the fake caller account. from := stateDB.GetOrNewStateObject(call.From) from.SetBalance(math.MaxBig256) + // Execute the call. - msg := callMsg{call} + msg := &core.Message{ + From: call.From, + To: call.To, + Value: call.Value, + GasLimit: call.Gas, + GasPrice: call.GasPrice, + GasFeeCap: call.GasFeeCap, + GasTipCap: call.GasTipCap, + Data: call.Data, + AccessList: call.AccessList, + SkipAccountChecks: true, + } - txContext := core.NewEVMTxContext(msg) - evmContext := core.NewEVMBlockContext(header, b.blockchain, nil) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. + txContext := core.NewEVMTxContext(msg) + evmContext := core.NewEVMBlockContext(header, b.blockchain, nil) vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true}) gasPool := new(core.GasPool).AddGas(math.MaxUint64) - return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb() + return core.ApplyMessage(vmEnv, msg, gasPool) } // SendTransaction updates the pending block to include the given transaction. @@ -821,23 +834,6 @@ func (b *SimulatedBackend) Blockchain() *core.BlockChain { return b.blockchain } -// callMsg implements core.Message to allow passing it as a transaction simulator. -type callMsg struct { - ethereum.CallMsg -} - -func (m callMsg) From() common.Address { return m.CallMsg.From } -func (m callMsg) Nonce() uint64 { return 0 } -func (m callMsg) IsFake() bool { return true } -func (m callMsg) To() *common.Address { return m.CallMsg.To } -func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } -func (m callMsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap } -func (m callMsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap } -func (m callMsg) Gas() uint64 { return m.CallMsg.Gas } -func (m callMsg) Value() *big.Int { return m.CallMsg.Value } -func (m callMsg) Data() []byte { return m.CallMsg.Data } -func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList } - // filterBackend implements filters.Backend to support filtering for logs without // taking bloom-bits acceleration structures into account. type filterBackend struct { diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index b023dde932d0..5f796c1d6639 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -163,7 +163,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } for i, tx := range txs { - msg, err := tx.AsMessage(signer, pre.Env.BaseFee) + msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee) if err != nil { log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) @@ -188,7 +188,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, msgResult, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { statedb.RevertToSnapshot(snapshot) - log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err) + log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) gaspool.SetGas(prevGas) continue @@ -220,7 +220,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, receipt.GasUsed = msgResult.UsedGas // If the transaction created a contract, store the creation address in the receipt. - if msg.To() == nil { + if msg.To == nil { receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) } diff --git a/core/evm.go b/core/evm.go index 35e12338ef05..bd4f2b0e55f1 100644 --- a/core/evm.go +++ b/core/evm.go @@ -70,10 +70,10 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common } // NewEVMTxContext creates a new transaction context for a single transaction. -func NewEVMTxContext(msg Message) vm.TxContext { +func NewEVMTxContext(msg *Message) vm.TxContext { return vm.TxContext{ - Origin: msg.From(), - GasPrice: new(big.Int).Set(msg.GasPrice()), + Origin: msg.From, + GasPrice: new(big.Int).Set(msg.GasPrice), } } diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 867b47db5319..c258eee4f4cc 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -63,7 +63,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c return } // Convert the transaction into an executable message and pre-cache its sender - msg, err := tx.AsMessage(signer, header.BaseFee) + msg, err := TransactionToMessage(tx, signer, header.BaseFee) if err != nil { return // Also invalid block, bail out } @@ -85,7 +85,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c // precacheTransaction attempts to apply a transaction to the given state database // and uses the input parameters for its environment. The goal is not to execute // the transaction successfully, rather to warm up touched data slots. -func precacheTransaction(msg types.Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error { +func precacheTransaction(msg *Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error { // Update the evm with the new transaction context. evm.Reset(NewEVMTxContext(msg), statedb) // Add addresses to access list if applicable diff --git a/core/state_processor.go b/core/state_processor.go index 163ea0a0200a..2fa9c41bcc01 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -74,7 +74,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) // Iterate over and process the individual transactions for i, tx := range block.Transactions() { - msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee) + msg, err := TransactionToMessage(tx, types.MakeSigner(p.config, header.Number), header.BaseFee) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -97,7 +97,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return receipts, allLogs, *usedGas, nil } -func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { +func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) evm.Reset(txContext, statedb) @@ -129,7 +129,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool receipt.GasUsed = result.UsedGas // If the transaction created a contract, store the creation address in the receipt. - if msg.To() == nil { + if msg.To == nil { receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) } @@ -147,7 +147,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { - msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), header.BaseFee) + msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number), header.BaseFee) if err != nil { return nil, err } diff --git a/core/state_transition.go b/core/state_transition.go index 653c6b183618..1802f1daf70a 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -25,65 +25,9 @@ import ( cmath "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" ) -var emptyCodeHash = crypto.Keccak256Hash(nil) - -// StateTransition represents a state transition. -// -// == The State Transitioning Model -// -// A state transition is a change made when a transaction is applied to the current world -// state. The state transitioning model does all the necessary work to work out a valid new -// state root. -// -// 1. Nonce handling -// 2. Pre pay gas -// 3. Create a new state object if the recipient is nil -// 4. Value transfer -// -// == If contract creation == -// -// 4a. Attempt to run transaction data -// 4b. If valid, use result as code for the new state object -// -// == end == -// -// 5. Run Script section -// 6. Derive new state root -type StateTransition struct { - gp *GasPool - msg Message - gas uint64 - gasPrice *big.Int - gasFeeCap *big.Int - gasTipCap *big.Int - initialGas uint64 - value *big.Int - data []byte - state vm.StateDB - evm *vm.EVM -} - -// Message represents a message sent to a contract. -type Message interface { - From() common.Address - To() *common.Address - - GasPrice() *big.Int - GasFeeCap() *big.Int - GasTipCap() *big.Int - Gas() uint64 - Value() *big.Int - - Nonce() uint64 - IsFake() bool - Data() []byte - AccessList() types.AccessList -} - // ExecutionResult includes all output after executing given evm // message no matter the execution itself is successful or not. type ExecutionResult struct { @@ -178,19 +122,47 @@ func toWordSize(size uint64) uint64 { return (size + 31) / 32 } -// NewStateTransition initialises and returns a new state transition object. -func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { - return &StateTransition{ - gp: gp, - evm: evm, - msg: msg, - gasPrice: msg.GasPrice(), - gasFeeCap: msg.GasFeeCap(), - gasTipCap: msg.GasTipCap(), - value: msg.Value(), - data: msg.Data(), - state: evm.StateDB, +// A Message contains the data derived from a single transaction that is relevant to state +// processing. +type Message struct { + To *common.Address + From common.Address + Nonce uint64 + Value *big.Int + GasLimit uint64 + GasPrice *big.Int + GasFeeCap *big.Int + GasTipCap *big.Int + Data []byte + AccessList types.AccessList + + // When SkipAccountCheckss is true, the message nonce is not checked against the + // account nonce in state. It also disables checking that the sender is an EOA. + // This field will be set to true for operations like RPC eth_call. + SkipAccountChecks bool +} + +// TransactionToMessage converts a transaction into a Message. +func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) { + msg := &Message{ + Nonce: tx.Nonce(), + GasLimit: tx.Gas(), + GasPrice: new(big.Int).Set(tx.GasPrice()), + GasFeeCap: new(big.Int).Set(tx.GasFeeCap()), + GasTipCap: new(big.Int).Set(tx.GasTipCap()), + To: tx.To(), + Value: tx.Value(), + Data: tx.Data(), + AccessList: tx.AccessList(), + SkipAccountChecks: false, } + // If baseFee provided, set gasPrice to effectiveGasPrice. + if baseFee != nil { + msg.GasPrice = cmath.BigMin(msg.GasPrice.Add(msg.GasTipCap, baseFee), msg.GasFeeCap) + } + var err error + msg.From, err = types.Sender(s, tx) + return msg, err } // ApplyMessage computes the new state by applying the given message @@ -200,82 +172,126 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition // the gas used (which includes gas refunds) and an error if it failed. An error always // indicates a core error meaning that the message would always fail for that particular // state and would never be accepted within a block. -func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) { +func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) { return NewStateTransition(evm, msg, gp).TransitionDb() } +// StateTransition represents a state transition. +// +// == The State Transitioning Model +// +// A state transition is a change made when a transaction is applied to the current world +// state. The state transitioning model does all the necessary work to work out a valid new +// state root. +// +// 1. Nonce handling +// 2. Pre pay gas +// 3. Create a new state object if the recipient is nil +// 4. Value transfer +// +// == If contract creation == +// +// 4a. Attempt to run transaction data +// 4b. If valid, use result as code for the new state object +// +// == end == +// +// 5. Run Script section +// 6. Derive new state root +type StateTransition struct { + gp *GasPool + msg *Message + gasRemaining uint64 + initialGas uint64 + state vm.StateDB + evm *vm.EVM +} + +// NewStateTransition initialises and returns a new state transition object. +func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition { + return &StateTransition{ + gp: gp, + evm: evm, + msg: msg, + state: evm.StateDB, + } +} + // to returns the recipient of the message. func (st *StateTransition) to() common.Address { - if st.msg == nil || st.msg.To() == nil /* contract creation */ { + if st.msg == nil || st.msg.To == nil /* contract creation */ { return common.Address{} } - return *st.msg.To() + return *st.msg.To } func (st *StateTransition) buyGas() error { - mgval := new(big.Int).SetUint64(st.msg.Gas()) - mgval = mgval.Mul(mgval, st.gasPrice) + mgval := new(big.Int).SetUint64(st.msg.GasLimit) + mgval = mgval.Mul(mgval, st.msg.GasPrice) balanceCheck := mgval - if st.gasFeeCap != nil { - balanceCheck = new(big.Int).SetUint64(st.msg.Gas()) - balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap) - balanceCheck.Add(balanceCheck, st.value) + if st.msg.GasFeeCap != nil { + balanceCheck = new(big.Int).SetUint64(st.msg.GasLimit) + balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap) + balanceCheck.Add(balanceCheck, st.msg.Value) } - if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 { - return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want) + if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 { + return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want) } - if err := st.gp.SubGas(st.msg.Gas()); err != nil { + if err := st.gp.SubGas(st.msg.GasLimit); err != nil { return err } - st.gas += st.msg.Gas() + st.gasRemaining += st.msg.GasLimit - st.initialGas = st.msg.Gas() - st.state.SubBalance(st.msg.From(), mgval) + st.initialGas = st.msg.GasLimit + st.state.SubBalance(st.msg.From, mgval) return nil } func (st *StateTransition) preCheck() error { // Only check transactions that are not fake - if !st.msg.IsFake() { + msg := st.msg + if !msg.SkipAccountChecks { // Make sure this transaction's nonce is correct. - stNonce := st.state.GetNonce(st.msg.From()) - if msgNonce := st.msg.Nonce(); stNonce < msgNonce { + stNonce := st.state.GetNonce(msg.From) + if msgNonce := msg.Nonce; stNonce < msgNonce { return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh, - st.msg.From().Hex(), msgNonce, stNonce) + msg.From.Hex(), msgNonce, stNonce) } else if stNonce > msgNonce { return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow, - st.msg.From().Hex(), msgNonce, stNonce) + msg.From.Hex(), msgNonce, stNonce) } else if stNonce+1 < stNonce { return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax, - st.msg.From().Hex(), stNonce) + msg.From.Hex(), stNonce) } // Make sure the sender is an EOA - if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) { + codeHash := st.state.GetCodeHash(msg.From) + if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash { return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA, - st.msg.From().Hex(), codeHash) + msg.From.Hex(), codeHash) } } + // Make sure that transaction gasFeeCap is greater than the baseFee (post london) if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) { // Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call) - if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 { - if l := st.gasFeeCap.BitLen(); l > 256 { + if !st.evm.Config.NoBaseFee || msg.GasFeeCap.BitLen() > 0 || msg.GasTipCap.BitLen() > 0 { + if l := msg.GasFeeCap.BitLen(); l > 256 { return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh, - st.msg.From().Hex(), l) + msg.From.Hex(), l) } - if l := st.gasTipCap.BitLen(); l > 256 { + if l := msg.GasTipCap.BitLen(); l > 256 { return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh, - st.msg.From().Hex(), l) + msg.From.Hex(), l) } - if st.gasFeeCap.Cmp(st.gasTipCap) < 0 { + if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 { return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap, - st.msg.From().Hex(), st.gasTipCap, st.gasFeeCap) + msg.From.Hex(), msg.GasTipCap, msg.GasFeeCap) } // This will panic if baseFee is nil, but basefee presence is verified // as part of header validation. - if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 { + if msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 { return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow, - st.msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee) + msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee) } } } @@ -311,52 +327,52 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { if st.evm.Config.Debug { st.evm.Config.Tracer.CaptureTxStart(st.initialGas) defer func() { - st.evm.Config.Tracer.CaptureTxEnd(st.gas) + st.evm.Config.Tracer.CaptureTxEnd(st.gasRemaining) }() } var ( msg = st.msg - sender = vm.AccountRef(msg.From()) + sender = vm.AccountRef(msg.From) rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time) - contractCreation = msg.To() == nil + contractCreation = msg.To == nil ) // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) + gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) if err != nil { return nil, err } - if st.gas < gas { - return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas) + if st.gasRemaining < gas { + return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas) } - st.gas -= gas + st.gasRemaining -= gas // Check clause 6 - if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) { - return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex()) + if msg.Value.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Value) { + return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex()) } // Check whether the init code size has been exceeded. - if rules.IsShanghai && contractCreation && len(st.data) > params.MaxInitCodeSize { - return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize) + if rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSize { + return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize) } // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - st.state.Prepare(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) + st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList) var ( ret []byte vmerr error // vm errors do not effect consensus and are therefore not assigned to err ) if contractCreation { - ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value) + ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, msg.Value) } else { // Increment the nonce for the next transaction - st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) - ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value) + st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1) + ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value) } if !rules.IsLondon { @@ -366,12 +382,12 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { // After EIP-3529: refunds are capped to gasUsed / 5 st.refundGas(params.RefundQuotientEIP3529) } - effectiveTip := st.gasPrice + effectiveTip := msg.GasPrice if rules.IsLondon { - effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)) + effectiveTip = cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee)) } - if st.evm.Config.NoBaseFee && st.gasFeeCap.Sign() == 0 && st.gasTipCap.Sign() == 0 { + if st.evm.Config.NoBaseFee && msg.GasFeeCap.Sign() == 0 && msg.GasTipCap.Sign() == 0 { // Skip fee payment when NoBaseFee is set and the fee fields // are 0. This avoids a negative effectiveTip being applied to // the coinbase when simulating calls. @@ -394,18 +410,18 @@ func (st *StateTransition) refundGas(refundQuotient uint64) { if refund > st.state.GetRefund() { refund = st.state.GetRefund() } - st.gas += refund + st.gasRemaining += refund // Return ETH for remaining gas, exchanged at the original rate. - remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) - st.state.AddBalance(st.msg.From(), remaining) + remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice) + st.state.AddBalance(st.msg.From, remaining) // Also return remaining gas to the block gas counter so it is // available for the next transaction. - st.gp.AddGas(st.gas) + st.gp.AddGas(st.gasRemaining) } // gasUsed returns the amount of gas used up by the state transition. func (st *StateTransition) gasUsed() uint64 { - return st.initialGas - st.gas + return st.initialGas - st.gasRemaining } diff --git a/core/types/transaction.go b/core/types/transaction.go index cd212edbe3b3..89192f049bd5 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -589,74 +589,6 @@ func (t *TransactionsByPriceAndNonce) Pop() { heap.Pop(&t.heads) } -// Message is a fully derived transaction and implements core.Message -// -// NOTE: In a future PR this will be removed. -type Message struct { - to *common.Address - from common.Address - nonce uint64 - amount *big.Int - gasLimit uint64 - gasPrice *big.Int - gasFeeCap *big.Int - gasTipCap *big.Int - data []byte - accessList AccessList - isFake bool -} - -func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, gasFeeCap, gasTipCap *big.Int, data []byte, accessList AccessList, isFake bool) Message { - return Message{ - from: from, - to: to, - nonce: nonce, - amount: amount, - gasLimit: gasLimit, - gasPrice: gasPrice, - gasFeeCap: gasFeeCap, - gasTipCap: gasTipCap, - data: data, - accessList: accessList, - isFake: isFake, - } -} - -// AsMessage returns the transaction as a core.Message. -func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) { - msg := Message{ - nonce: tx.Nonce(), - gasLimit: tx.Gas(), - gasPrice: new(big.Int).Set(tx.GasPrice()), - gasFeeCap: new(big.Int).Set(tx.GasFeeCap()), - gasTipCap: new(big.Int).Set(tx.GasTipCap()), - to: tx.To(), - amount: tx.Value(), - data: tx.Data(), - accessList: tx.AccessList(), - isFake: false, - } - // If baseFee provided, set gasPrice to effectiveGasPrice. - if baseFee != nil { - msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap) - } - var err error - msg.from, err = Sender(s, tx) - return msg, err -} - -func (m Message) From() common.Address { return m.from } -func (m Message) To() *common.Address { return m.to } -func (m Message) GasPrice() *big.Int { return m.gasPrice } -func (m Message) GasFeeCap() *big.Int { return m.gasFeeCap } -func (m Message) GasTipCap() *big.Int { return m.gasTipCap } -func (m Message) Value() *big.Int { return m.amount } -func (m Message) Gas() uint64 { return m.gasLimit } -func (m Message) Nonce() uint64 { return m.nonce } -func (m Message) Data() []byte { return m.data } -func (m Message) AccessList() AccessList { return m.accessList } -func (m Message) IsFake() bool { return m.isFake } - // copyAddressPtr copies an address. func copyAddressPtr(a *common.Address) *common.Address { if a == nil { diff --git a/eth/api_backend.go b/eth/api_backend.go index e7daea2f6cdb..78b9b08ecb32 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -228,7 +228,7 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { +func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { if vmConfig == nil { vmConfig = b.eth.blockchain.GetVMConfig() } @@ -382,6 +382,6 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk) } -func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 3bb1464952a0..59b471425542 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -189,7 +189,7 @@ func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexe } // stateAtTransaction returns the execution environment of a certain transaction. -func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { // Short circuit if it's genesis block. if block.NumberU64() == 0 { return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis") @@ -212,7 +212,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, signer := types.MakeSigner(eth.blockchain.Config(), block.Number()) for idx, tx := range block.Transactions() { // Assemble the transaction call message and return if the requested offset - msg, _ := tx.AsMessage(signer, block.BaseFee()) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) if idx == txIndex { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index d4cda67c90d3..58ad0c3c9ad7 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -87,7 +87,7 @@ type Backend interface { Engine() consensus.Engine ChainDb() ethdb.Database StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) - StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) + StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) } // API is the collection of tracing APIs exposed over the private debugging endpoint. @@ -293,7 +293,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed ) // Trace all the transactions contained within for i, tx := range task.block.Transactions() { - msg, _ := tx.AsMessage(signer, task.block.BaseFee()) + msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee()) txctx := &Context{ BlockHash: task.block.Hash(), BlockNumber: task.block.Number(), @@ -554,12 +554,12 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config return nil, err } var ( - msg, _ = tx.AsMessage(signer, block.BaseFee()) + msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) txContext = core.NewEVMTxContext(msg) vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{}) ) statedb.SetTxContext(tx.Hash(), i) - if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { + if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) // We intentionally don't return the error here: if we do, then the RPC server will not // return the roots. Most likely, the caller already knows that a certain transaction fails to @@ -628,7 +628,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac ) for i, tx := range txs { // Generate the next state snapshot fast without tracing - msg, _ := tx.AsMessage(signer, block.BaseFee()) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), @@ -671,7 +671,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat defer pend.Done() // Fetch and execute the next transaction trace tasks for task := range jobs { - msg, _ := txs[task.index].AsMessage(signer, block.BaseFee()) + msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee()) txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), @@ -702,10 +702,10 @@ txloop: } // Generate the next state snapshot fast without tracing - msg, _ := tx.AsMessage(signer, block.BaseFee()) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) statedb.SetTxContext(tx.Hash(), i) vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) - if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { + if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { failed = err break txloop } @@ -782,7 +782,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution var ( - msg, _ = tx.AsMessage(signer, block.BaseFee()) + msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) txContext = core.NewEVMTxContext(msg) vmConf vm.Config dump *os.File @@ -813,7 +813,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) statedb.SetTxContext(tx.Hash(), i) - _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) + _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) if writer != nil { writer.Flush() } @@ -947,7 +947,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc // traceTx configures a new tracer according to the provided configuration, and // executes the given message in the provided environment. The return value will // be tracer dependent. -func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { +func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { var ( tracer Tracer err error @@ -986,7 +986,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex // Call Prepare to clear out the statedb access list statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) - if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())); err != nil { + if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil { return nil, fmt.Errorf("tracing failed: %w", err) } return tracer.GetResult() diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index b0dae4ca3e0d..b1eaf60b16c4 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -156,7 +156,7 @@ func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reex return statedb, release, nil } -func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) { +func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) { parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { return nil, vm.BlockContext{}, nil, nil, errBlockNotFound @@ -171,7 +171,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block // Recompute transactions up to the target index. signer := types.MakeSigner(b.chainConfig, block.Number()) for idx, tx := range block.Transactions() { - msg, _ := tx.AsMessage(signer, block.BaseFee()) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), b.chain, nil) if idx == txIndex { diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 2d9bdaed7138..62182e3a82b4 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -145,7 +145,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to create call tracer: %v", err) } evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) - msg, err := tx.AsMessage(signer, nil) + msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } @@ -220,7 +220,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.Fatalf("failed to parse testcase input: %v", err) } signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) - msg, err := tx.AsMessage(signer, nil) + msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) } @@ -314,7 +314,7 @@ func TestZeroValueToNotExitCall(t *testing.T) { t.Fatalf("failed to create call tracer: %v", err) } evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) - msg, err := tx.AsMessage(signer, nil) + msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index d8ded7015dbd..8cd5a42bc0c0 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -109,7 +109,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string } evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) - msg, err := tx.AsMessage(signer, nil) + msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index 03f06311a3b9..f578e2f0f5fd 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -115,7 +115,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to create call tracer: %v", err) } evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) - msg, err := tx.AsMessage(signer, nil) + msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 6cd5a022b1a1..7c5ec65650ee 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -88,7 +88,7 @@ func BenchmarkTransactionTrace(b *testing.B) { //EnableReturnData: false, }) evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer}) - msg, err := tx.AsMessage(signer, nil) + msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 7091e4900155..93a2d1264d32 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1005,7 +1005,7 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout) } if err != nil { - return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.Gas()) + return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.GasLimit) } return result, nil } @@ -1478,7 +1478,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH if err != nil { return nil, 0, nil, err } - res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) + res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err) } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 2405efa234e3..98887afc803f 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -68,7 +68,7 @@ type Backend interface { PendingBlockAndReceipts() (*types.Block, types.Receipts) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetTd(ctx context.Context, hash common.Hash) *big.Int - GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) + GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index e07248db5d69..c74f540b761b 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" @@ -199,10 +200,10 @@ func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *typ // ToMessage converts the transaction arguments to the Message type used by the // core evm. This method is used in calls and traces that do not require a real // live transaction. -func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (types.Message, error) { +func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*core.Message, error) { // Reject invalid combinations of pre- and post-1559 fee styles if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { - return types.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") + return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") } // Set sender address or use zero address if none specified. addr := args.from() @@ -263,7 +264,18 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (t if args.AccessList != nil { accessList = *args.AccessList } - msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, true) + msg := &core.Message{ + From: addr, + To: args.To, + Value: value, + GasLimit: gas, + GasPrice: gasPrice, + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, + Data: data, + AccessList: accessList, + SkipAccountChecks: true, + } return msg, nil } diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 3279b6a8e533..1b533861d5d6 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -305,7 +305,7 @@ func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number return nil, nil } func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *backendMock) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { +func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { return nil, nil, nil } func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil } diff --git a/les/api_backend.go b/les/api_backend.go index a724af04c5d3..4b0369845a5a 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -184,7 +184,7 @@ func (b *LesApiBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { +func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { if vmConfig == nil { vmConfig = new(vm.Config) } @@ -330,6 +330,6 @@ func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, re return b.eth.stateAtBlock(ctx, block, reexec) } -func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { return b.eth.stateAtTransaction(ctx, block, txIndex, reexec) } diff --git a/les/odr_test.go b/les/odr_test.go index bd0574768c27..90b7cd08d7f5 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -116,12 +116,6 @@ func TestOdrContractCallLes2(t *testing.T) { testOdr(t, 2, 2, true, odrContractC func TestOdrContractCallLes3(t *testing.T) { testOdr(t, 3, 2, true, odrContractCall) } func TestOdrContractCallLes4(t *testing.T) { testOdr(t, 4, 2, true, odrContractCall) } -type callmsg struct { - types.Message -} - -func (callmsg) CheckNonce() bool { return false } - func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") @@ -136,7 +130,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai from := statedb.GetOrNewStateObject(bankAddr) from.SetBalance(math.MaxBig256) - msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)} + msg := &core.Message{ + From: from.Address(), + To: &testContractAddr, + Value: new(big.Int), + GasLimit: 100000, + GasPrice: big.NewInt(params.InitialBaseFee), + GasFeeCap: big.NewInt(params.InitialBaseFee), + GasTipCap: new(big.Int), + Data: data, + SkipAccountChecks: true, + } context := core.NewEVMBlockContext(header, bc, nil) txContext := core.NewEVMTxContext(msg) @@ -151,7 +155,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai header := lc.GetHeaderByHash(bhash) state := light.NewState(ctx, header, lc.Odr()) state.SetBalance(bankAddr, math.MaxBig256) - msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)} + msg := &core.Message{ + From: bankAddr, + To: &testContractAddr, + Value: new(big.Int), + GasLimit: 100000, + GasPrice: big.NewInt(params.InitialBaseFee), + GasFeeCap: big.NewInt(params.InitialBaseFee), + GasTipCap: new(big.Int), + Data: data, + SkipAccountChecks: true, + } context := core.NewEVMBlockContext(header, lc, nil) txContext := core.NewEVMTxContext(msg) vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true}) diff --git a/les/state_accessor.go b/les/state_accessor.go index 091ec8871eee..030d6b5a5004 100644 --- a/les/state_accessor.go +++ b/les/state_accessor.go @@ -39,7 +39,7 @@ func (leth *LightEthereum) stateAtBlock(ctx context.Context, block *types.Block, } // stateAtTransaction returns the execution environment of a certain transaction. -func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { +func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { // Short circuit if it's genesis block. if block.NumberU64() == 0 { return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis") @@ -60,7 +60,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types. signer := types.MakeSigner(leth.blockchain.Config(), block.Number()) for idx, tx := range block.Transactions() { // Assemble the transaction call message and return if the requested offset - msg, _ := tx.AsMessage(signer, block.BaseFee()) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil) statedb.SetTxContext(tx.Hash(), idx) diff --git a/light/odr_test.go b/light/odr_test.go index 903c7f6f90a6..173298bb77f2 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -174,12 +174,6 @@ func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc func TestOdrContractCallLes2(t *testing.T) { testChainOdr(t, 1, odrContractCall) } -type callmsg struct { - types.Message -} - -func (callmsg) CheckNonce() bool { return false } - func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") config := params.TestChainConfig @@ -205,7 +199,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain // Perform read-only call. st.SetBalance(testBankAddress, math.MaxBig256) - msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)} + msg := &core.Message{ + From: testBankAddress, + To: &testContractAddr, + Value: new(big.Int), + GasLimit: 1000000, + GasPrice: big.NewInt(params.InitialBaseFee), + GasFeeCap: big.NewInt(params.InitialBaseFee), + GasTipCap: new(big.Int), + Data: data, + SkipAccountChecks: true, + } txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(header, chain, nil) vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true}) diff --git a/tests/state_test.go b/tests/state_test.go index 7dd2f678c683..787427f01e45 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -228,7 +228,7 @@ func runBenchmark(b *testing.B, t *StateTest) { evm := vm.NewEVM(context, txContext, statedb, config, vmconfig) // Create "contract" for sender to cache code analysis. - sender := vm.NewContract(vm.AccountRef(msg.From()), vm.AccountRef(msg.From()), + sender := vm.NewContract(vm.AccountRef(msg.From), vm.AccountRef(msg.From), nil, 0) var ( @@ -239,12 +239,12 @@ func runBenchmark(b *testing.B, t *StateTest) { b.ResetTimer() for n := 0; n < b.N; n++ { snapshot := statedb.Snapshot() - statedb.Prepare(rules, msg.From(), context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) + statedb.Prepare(rules, msg.From, context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList) b.StartTimer() start := time.Now() // Execute the message. - _, leftOverGas, err := evm.Call(sender, *msg.To(), msg.Data(), msg.Gas(), msg.Value()) + _, leftOverGas, err := evm.Call(sender, *msg.To, msg.Data, msg.GasLimit, msg.Value) if err != nil { b.Error(err) return @@ -253,7 +253,7 @@ func runBenchmark(b *testing.B, t *StateTest) { b.StopTimer() elapsed += uint64(time.Since(start)) refund += statedb.GetRefund() - gasUsed += msg.Gas() - leftOverGas + gasUsed += msg.GasLimit - leftOverGas statedb.RevertToSnapshot(snapshot) } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index b2e87fb004b9..98acc468a1d8 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -329,7 +329,7 @@ func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis { return genesis } -func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Message, error) { +func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Message, error) { // Derive sender from private key if present. var from common.Address if len(tx.PrivateKey) > 0 { @@ -397,8 +397,18 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Messa return nil, fmt.Errorf("no gas price provided") } - msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, gasPrice, - tx.MaxFeePerGas, tx.MaxPriorityFeePerGas, data, accessList, false) + msg := &core.Message{ + From: from, + To: to, + Nonce: tx.Nonce, + Value: value, + GasLimit: gasLimit, + GasPrice: gasPrice, + GasFeeCap: tx.MaxFeePerGas, + GasTipCap: tx.MaxPriorityFeePerGas, + Data: data, + AccessList: accessList, + } return msg, nil } From df027995437d84ae8f0476a1be42a3dba64edae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 9 Mar 2023 16:44:54 +0200 Subject: [PATCH 621/715] travis: only build PPAs nightly, not on every push, too heavy (#26846) --- .travis.yml | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6bc7712797dd..db21bd5d96ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,30 +57,6 @@ jobs: script: - go run build/ci.go docker -image -manifest amd64,arm64 -upload ethereum/client-go - # This builder does the Ubuntu PPA upload - - stage: build - if: type = push - os: linux - dist: bionic - go: 1.20.x - env: - - ubuntu-ppa - - GO111MODULE=on - git: - submodules: false # avoid cloning ethereum/tests - addons: - apt: - packages: - - devscripts - - debhelper - - dput - - fakeroot - - python-bzrlib - - python-paramiko - script: - - echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts - - go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder " - # This builder does the Linux Azure uploads - stage: build if: type = push @@ -162,6 +138,30 @@ jobs: script: - go run build/ci.go test $TEST_PACKAGES + # This builder does the Ubuntu PPA nightly uploads + - stage: build + if: type = cron + os: linux + dist: bionic + go: 1.20.x + env: + - ubuntu-ppa + - GO111MODULE=on + git: + submodules: false # avoid cloning ethereum/tests + addons: + apt: + packages: + - devscripts + - debhelper + - dput + - fakeroot + - python-bzrlib + - python-paramiko + script: + - echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts + - go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder " + # This builder does the Azure archive purges to avoid accumulating junk - stage: build if: type = cron From 051493d9bf39dd55e152915082cc2eeeccd23096 Mon Sep 17 00:00:00 2001 From: panicalways <113693386+panicalways@users.noreply.github.com> Date: Fri, 10 Mar 2023 18:45:49 +0900 Subject: [PATCH 622/715] p2p: small comment typo (#26850) Update server.go --- p2p/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/server.go b/p2p/server.go index 19f7935ffcae..610b82d784f6 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -1057,7 +1057,7 @@ func (srv *Server) runPeer(p *Peer) { // Broadcast peer drop to external subscribers. This needs to be // after the send to delpeer so subscribers have a consistent view of // the peer set (i.e. Server.Peers() doesn't include the peer when the - // event is received. + // event is received). srv.peerFeed.Send(&PeerEvent{ Type: PeerEventTypeDrop, Peer: p.ID(), From 564db9a95f564f06566072d429761f7f2d4ee2da Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 10 Mar 2023 14:03:27 +0100 Subject: [PATCH 623/715] core: add Timestamp method in BlockGen (#26844) Since forks are now scheduled by block time, it can be necessary to check the timestamp of a block while generating transactions. --- core/chain_makers.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/chain_makers.go b/core/chain_makers.go index 052d6efae2f7..61d0098af3f6 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -156,6 +156,11 @@ func (b *BlockGen) Number() *big.Int { return new(big.Int).Set(b.header.Number) } +// Timestamp returns the timestamp of the block being generated. +func (b *BlockGen) Timestamp() uint64 { + return b.header.Time +} + // BaseFee returns the EIP-1559 base fee of the block being generated. func (b *BlockGen) BaseFee() *big.Int { return new(big.Int).Set(b.header.BaseFee) From 6cf2e921a79c2ac914f8b413f3c689919a60110f Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 10 Mar 2023 18:30:26 +0100 Subject: [PATCH 624/715] core/txpool: implement additional DoS defenses (#26648) This adds two new rules to the transaction pool: - A future transaction can not evict a pending transaction. - A transaction can not overspend available funds of a sender. --- Co-authored-by: dwn1998 <42262393+dwn1998@users.noreply.github.com> Co-authored-by: Martin Holst Swende --- core/txpool/list.go | 45 ++++++-- core/txpool/txpool.go | 82 ++++++++++++-- core/txpool/txpool2_test.go | 212 ++++++++++++++++++++++++++++++++++++ core/txpool/txpool_test.go | 27 +++-- 4 files changed, 341 insertions(+), 25 deletions(-) create mode 100644 core/txpool/txpool2_test.go diff --git a/core/txpool/list.go b/core/txpool/list.go index 062cbbf63e6a..724bb6caca99 100644 --- a/core/txpool/list.go +++ b/core/txpool/list.go @@ -254,17 +254,19 @@ type list struct { strict bool // Whether nonces are strictly continuous or not txs *sortedMap // Heap indexed sorted hash map of the transactions - costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance) - gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) + costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance) + gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) + totalcost *big.Int // Total cost of all transactions in the list } // newList create a new transaction list for maintaining nonce-indexable fast, // gapped, sortable transaction lists. func newList(strict bool) *list { return &list{ - strict: strict, - txs: newSortedMap(), - costcap: new(big.Int), + strict: strict, + txs: newSortedMap(), + costcap: new(big.Int), + totalcost: new(big.Int), } } @@ -302,7 +304,11 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa if tx.GasFeeCapIntCmp(thresholdFeeCap) < 0 || tx.GasTipCapIntCmp(thresholdTip) < 0 { return false, nil } + // Old is being replaced, subtract old cost + l.subTotalCost([]*types.Transaction{old}) } + // Add new tx cost to totalcost + l.totalcost.Add(l.totalcost, tx.Cost()) // Otherwise overwrite the old transaction with the current one l.txs.Put(tx) if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 { @@ -318,7 +324,9 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa // provided threshold. Every removed transaction is returned for any post-removal // maintenance. func (l *list) Forward(threshold uint64) types.Transactions { - return l.txs.Forward(threshold) + txs := l.txs.Forward(threshold) + l.subTotalCost(txs) + return txs } // Filter removes all transactions from the list with a cost or gas limit higher @@ -357,6 +365,9 @@ func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions, } invalids = l.txs.filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest }) } + // Reset total cost + l.subTotalCost(removed) + l.subTotalCost(invalids) l.txs.reheap() return removed, invalids } @@ -364,7 +375,9 @@ func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions, // Cap places a hard limit on the number of items, returning all transactions // exceeding that limit. func (l *list) Cap(threshold int) types.Transactions { - return l.txs.Cap(threshold) + txs := l.txs.Cap(threshold) + l.subTotalCost(txs) + return txs } // Remove deletes a transaction from the maintained list, returning whether the @@ -376,9 +389,12 @@ func (l *list) Remove(tx *types.Transaction) (bool, types.Transactions) { if removed := l.txs.Remove(nonce); !removed { return false, nil } + l.subTotalCost([]*types.Transaction{tx}) // In strict mode, filter out non-executable transactions if l.strict { - return true, l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce }) + txs := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce }) + l.subTotalCost(txs) + return true, txs } return true, nil } @@ -391,7 +407,9 @@ func (l *list) Remove(tx *types.Transaction) (bool, types.Transactions) { // prevent getting into and invalid state. This is not something that should ever // happen but better to be self correcting than failing! func (l *list) Ready(start uint64) types.Transactions { - return l.txs.Ready(start) + txs := l.txs.Ready(start) + l.subTotalCost(txs) + return txs } // Len returns the length of the transaction list. @@ -417,6 +435,14 @@ func (l *list) LastElement() *types.Transaction { return l.txs.LastElement() } +// subTotalCost subtracts the cost of the given transactions from the +// total cost of all transactions. +func (l *list) subTotalCost(txs []*types.Transaction) { + for _, tx := range txs { + l.totalcost.Sub(l.totalcost, tx.Cost()) + } +} + // priceHeap is a heap.Interface implementation over transactions for retrieving // price-sorted transactions to discard when the pool fills up. If baseFee is set // then the heap is sorted based on the effective tip based on the given base fee. @@ -561,6 +587,7 @@ func (l *pricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool { // Discard finds a number of most underpriced transactions, removes them from the // priced list and returns them for further removal from the entire pool. +// If noPending is set to true, we will only consider the floating list // // Note local transaction won't be considered for eviction. func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) { diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 762210b7b74a..4306d5aee6f5 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -17,6 +17,7 @@ package txpool import ( + "container/heap" "errors" "fmt" "math" @@ -87,6 +88,14 @@ var ( // than some meaningful limit a user might use. This is not a consensus error // making the transaction invalid, rather a DOS protection. ErrOversizedData = errors.New("oversized data") + + // ErrFutureReplacePending is returned if a future transaction replaces a pending + // transaction. Future transactions should only be able to replace other future transactions. + ErrFutureReplacePending = errors.New("future transaction tries to replace pending") + + // ErrOverdraft is returned if a transaction would cause the senders balance to go negative + // thus invalidating a potential large number of transactions. + ErrOverdraft = errors.New("transaction would cause overdraft") ) var ( @@ -639,9 +648,25 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { } // Transactor should have enough funds to cover the costs // cost == V + GP * GL - if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { + balance := pool.currentState.GetBalance(from) + if balance.Cmp(tx.Cost()) < 0 { return core.ErrInsufficientFunds } + + // Verify that replacing transactions will not result in overdraft + list := pool.pending[from] + if list != nil { // Sender already has pending txs + sum := new(big.Int).Add(tx.Cost(), list.totalcost) + if repl := list.txs.Get(tx.Nonce()); repl != nil { + // Deduct the cost of a transaction replaced by this + sum.Sub(sum, repl.Cost()) + } + if balance.Cmp(sum) < 0 { + log.Trace("Replacing transactions would overdraft", "sender", from, "balance", pool.currentState.GetBalance(from), "required", sum) + return ErrOverdraft + } + } + // Ensure the transaction has more gas than the basic tx fee. intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai) if err != nil { @@ -678,6 +703,10 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e invalidTxMeter.Mark(1) return false, err } + + // already validated by this point + from, _ := types.Sender(pool.signer, tx) + // If the transaction pool is full, discard underpriced transactions if uint64(pool.all.Slots()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue { // If the new transaction is underpriced, don't accept it @@ -686,6 +715,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e underpricedTxMeter.Mark(1) return false, ErrUnderpriced } + // We're about to replace a transaction. The reorg does a more thorough // analysis of what to remove and how, but it runs async. We don't want to // do too many replacements between reorg-runs, so we cap the number of @@ -706,17 +736,37 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e overflowedTxMeter.Mark(1) return false, ErrTxPoolOverflow } - // Bump the counter of rejections-since-reorg - pool.changesSinceReorg += len(drop) + + // If the new transaction is a future transaction it should never churn pending transactions + if pool.isFuture(from, tx) { + var replacesPending bool + for _, dropTx := range drop { + dropSender, _ := types.Sender(pool.signer, dropTx) + if list := pool.pending[dropSender]; list != nil && list.Overlaps(dropTx) { + replacesPending = true + break + } + } + // Add all transactions back to the priced queue + if replacesPending { + for _, dropTx := range drop { + heap.Push(&pool.priced.urgent, dropTx) + } + log.Trace("Discarding future transaction replacing pending tx", "hash", hash) + return false, ErrFutureReplacePending + } + } + // Kick out the underpriced remote transactions. for _, tx := range drop { log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap()) underpricedTxMeter.Mark(1) - pool.removeTx(tx.Hash(), false) + dropped := pool.removeTx(tx.Hash(), false) + pool.changesSinceReorg += dropped } } + // Try to replace an existing transaction in the pending pool - from, _ := types.Sender(pool.signer, tx) // already validated if list := pool.pending[from]; list != nil && list.Overlaps(tx) { // Nonce already pending, check if required price bump is met inserted, old := list.Add(tx, pool.config.PriceBump) @@ -760,6 +810,20 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e return replaced, nil } +// isFuture reports whether the given transaction is immediately executable. +func (pool *TxPool) isFuture(from common.Address, tx *types.Transaction) bool { + list := pool.pending[from] + if list == nil { + return pool.pendingNonces.get(from) != tx.Nonce() + } + // Sender has pending transactions. + if old := list.txs.Get(tx.Nonce()); old != nil { + return false // It replaces a pending transaction. + } + // Not replacing, check if parent nonce exists in pending. + return list.txs.Get(tx.Nonce()-1) == nil +} + // enqueueTx inserts a new transaction into the non-executable transaction queue. // // Note, this method assumes the pool lock is held! @@ -996,11 +1060,12 @@ func (pool *TxPool) Has(hash common.Hash) bool { // removeTx removes a single transaction from the queue, moving all subsequent // transactions back to the future queue. -func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) { +// Returns the number of transactions removed from the pending queue. +func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) int { // Fetch the transaction we wish to delete tx := pool.all.Get(hash) if tx == nil { - return + return 0 } addr, _ := types.Sender(pool.signer, tx) // already validated during insertion @@ -1028,7 +1093,7 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) { pool.pendingNonces.setIfLower(addr, tx.Nonce()) // Reduce the pending counter pendingGauge.Dec(int64(1 + len(invalids))) - return + return 1 + len(invalids) } } // Transaction is in the future queue @@ -1042,6 +1107,7 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) { delete(pool.beats, addr) } } + return 0 } // requestReset requests a pool reset to the new head block. diff --git a/core/txpool/txpool2_test.go b/core/txpool/txpool2_test.go new file mode 100644 index 000000000000..20d6dd713a95 --- /dev/null +++ b/core/txpool/txpool2_test.go @@ -0,0 +1,212 @@ +// Copyright 2023 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 txpool + +import ( + "crypto/ecdsa" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/event" +) + +func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction { + tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(value), gaslimit, gasprice, nil), types.HomesteadSigner{}, key) + return tx +} + +func count(t *testing.T, pool *TxPool) (pending int, queued int) { + t.Helper() + pending, queued = pool.stats() + if err := validatePoolInternals(pool); err != nil { + t.Fatalf("pool internal state corrupted: %v", err) + } + return pending, queued +} + +func fillPool(t *testing.T, pool *TxPool) { + t.Helper() + // Create a number of test accounts, fund them and make transactions + executableTxs := types.Transactions{} + nonExecutableTxs := types.Transactions{} + for i := 0; i < 384; i++ { + key, _ := crypto.GenerateKey() + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000)) + // Add executable ones + for j := 0; j < int(pool.config.AccountSlots); j++ { + executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key)) + } + } + // Import the batch and verify that limits have been enforced + pool.AddRemotesSync(executableTxs) + pool.AddRemotesSync(nonExecutableTxs) + pending, queued := pool.Stats() + slots := pool.all.Slots() + // sanity-check that the test prerequisites are ok (pending full) + if have, want := pending, slots; have != want { + t.Fatalf("have %d, want %d", have, want) + } + if have, want := queued, 0; have != want { + t.Fatalf("have %d, want %d", have, want) + } + + t.Logf("pool.config: GlobalSlots=%d, GlobalQueue=%d\n", pool.config.GlobalSlots, pool.config.GlobalQueue) + t.Logf("pending: %d queued: %d, all: %d\n", pending, queued, slots) +} + +// Tests that if a batch high-priced of non-executables arrive, they do not kick out +// executable transactions +func TestTransactionFutureAttack(t *testing.T) { + t.Parallel() + + // Create the pool to test the limit enforcement with + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + config := testTxPoolConfig + config.GlobalQueue = 100 + config.GlobalSlots = 100 + pool := NewTxPool(config, eip1559Config, blockchain) + defer pool.Stop() + fillPool(t, pool) + pending, _ := pool.Stats() + // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops + { + key, _ := crypto.GenerateKey() + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + futureTxs := types.Transactions{} + for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { + futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key)) + } + for i := 0; i < 5; i++ { + pool.AddRemotesSync(futureTxs) + newPending, newQueued := count(t, pool) + t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots()) + } + } + newPending, _ := pool.Stats() + // Pending should not have been touched + if have, want := newPending, pending; have < want { + t.Errorf("wrong pending-count, have %d, want %d (GlobalSlots: %d)", + have, want, pool.config.GlobalSlots) + } +} + +// Tests that if a batch high-priced of non-executables arrive, they do not kick out +// executable transactions +func TestTransactionFuture1559(t *testing.T) { + t.Parallel() + // Create the pool to test the pricing enforcement with + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) + defer pool.Stop() + + // Create a number of test accounts, fund them and make transactions + fillPool(t, pool) + pending, _ := pool.Stats() + + // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops + { + key, _ := crypto.GenerateKey() + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + futureTxs := types.Transactions{} + for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { + futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key)) + } + pool.AddRemotesSync(futureTxs) + } + newPending, _ := pool.Stats() + // Pending should not have been touched + if have, want := newPending, pending; have != want { + t.Errorf("Wrong pending-count, have %d, want %d (GlobalSlots: %d)", + have, want, pool.config.GlobalSlots) + } +} + +// Tests that if a batch of balance-overdraft txs arrive, they do not kick out +// executable transactions +func TestTransactionZAttack(t *testing.T) { + t.Parallel() + // Create the pool to test the pricing enforcement with + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) + defer pool.Stop() + // Create a number of test accounts, fund them and make transactions + fillPool(t, pool) + + countInvalidPending := func() int { + t.Helper() + var ivpendingNum int + pendingtxs, _ := pool.Content() + for account, txs := range pendingtxs { + cur_balance := new(big.Int).Set(pool.currentState.GetBalance(account)) + for _, tx := range txs { + if cur_balance.Cmp(tx.Value()) <= 0 { + ivpendingNum++ + } else { + cur_balance.Sub(cur_balance, tx.Value()) + } + } + } + if err := validatePoolInternals(pool); err != nil { + t.Fatalf("pool internal state corrupted: %v", err) + } + return ivpendingNum + } + ivPending := countInvalidPending() + t.Logf("invalid pending: %d\n", ivPending) + + // Now, DETER-Z attack starts, let's add a bunch of expensive non-executables (from N accounts) along with balance-overdraft txs (from one account), and see if the pending-count drops + for j := 0; j < int(pool.config.GlobalQueue); j++ { + futureTxs := types.Transactions{} + key, _ := crypto.GenerateKey() + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key)) + pool.AddRemotesSync(futureTxs) + } + + overDraftTxs := types.Transactions{} + { + key, _ := crypto.GenerateKey() + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + for j := 0; j < int(pool.config.GlobalSlots); j++ { + overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 60000000000, 21000, big.NewInt(500), key)) + } + } + pool.AddRemotesSync(overDraftTxs) + pool.AddRemotesSync(overDraftTxs) + pool.AddRemotesSync(overDraftTxs) + pool.AddRemotesSync(overDraftTxs) + pool.AddRemotesSync(overDraftTxs) + + newPending, newQueued := count(t, pool) + newIvPending := countInvalidPending() + t.Logf("pool.all.Slots(): %d\n", pool.all.Slots()) + t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots()) + t.Logf("invalid pending: %d\n", newIvPending) + + // Pending should not have been touched + if newIvPending != ivPending { + t.Errorf("Wrong invalid pending-count, have %d, want %d (GlobalSlots: %d, queued: %d)", + newIvPending, ivPending, pool.config.GlobalSlots, newQueued) + } +} diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index 237f97afe434..c4c62db2d6da 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -158,6 +158,9 @@ func validatePoolInternals(pool *TxPool) error { if nonce := pool.pendingNonces.get(addr); nonce != last+1 { return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1) } + if txs.totalcost.Cmp(common.Big0) < 0 { + return fmt.Errorf("totalcost went negative: %v", txs.totalcost) + } } return nil } @@ -1105,7 +1108,7 @@ func TestPendingLimiting(t *testing.T) { defer pool.Stop() account := crypto.PubkeyToAddress(key.PublicKey) - testAddBalance(pool, account, big.NewInt(1000000)) + testAddBalance(pool, account, big.NewInt(1000000000000)) // Keep track of transaction events to ensure all executables get announced events := make(chan core.NewTxsEvent, testTxPoolConfig.AccountQueue+5) @@ -1584,7 +1587,7 @@ func TestRepricingKeepsLocals(t *testing.T) { keys := make([]*ecdsa.PrivateKey, 3) for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() - testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000*1000000)) + testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(100000*1000000)) } // Create transaction (both pending and queued) with a linearly growing gasprice for i := uint64(0); i < 500; i++ { @@ -1663,7 +1666,7 @@ func TestUnderpricing(t *testing.T) { defer sub.Unsubscribe() // Create a number of test accounts and fund them - keys := make([]*ecdsa.PrivateKey, 4) + keys := make([]*ecdsa.PrivateKey, 5) for i := 0; i < len(keys); i++ { keys[i], _ = crypto.GenerateKey() testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000)) @@ -1699,6 +1702,10 @@ func TestUnderpricing(t *testing.T) { if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced { t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) } + // Replace a future transaction with a future transaction + if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[1])); err != nil { // +K1:1 => -K1:1 => Pend K0:0, K0:1, K2:0; Que K1:1 + t.Fatalf("failed to add well priced transaction: %v", err) + } // Ensure that adding high priced transactions drops cheap ones, but not own if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { // +K1:0 => -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que - t.Fatalf("failed to add well priced transaction: %v", err) @@ -1709,6 +1716,10 @@ func TestUnderpricing(t *testing.T) { if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3 t.Fatalf("failed to add well priced transaction: %v", err) } + // Ensure that replacing a pending transaction with a future transaction fails + if err := pool.AddRemote(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != ErrFutureReplacePending { + t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, ErrFutureReplacePending) + } pending, queued = pool.Stats() if pending != 2 { t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2) @@ -1716,7 +1727,7 @@ func TestUnderpricing(t *testing.T) { if queued != 2 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) } - if err := validateEvents(events, 1); err != nil { + if err := validateEvents(events, 2); err != nil { t.Fatalf("additional event firing failed: %v", err) } if err := validatePoolInternals(pool); err != nil { @@ -1878,11 +1889,11 @@ func TestUnderpricingDynamicFee(t *testing.T) { t.Fatalf("failed to add well priced transaction: %v", err) } - tx = pricedTransaction(2, 100000, big.NewInt(3), keys[1]) + tx = pricedTransaction(1, 100000, big.NewInt(3), keys[1]) if err := pool.AddRemote(tx); err != nil { // +K1:2, -K0:1 => Pend K0:0 K1:0, K2:0; Que K1:2 t.Fatalf("failed to add well priced transaction: %v", err) } - tx = dynamicFeeTx(3, 100000, big.NewInt(4), big.NewInt(1), keys[1]) + tx = dynamicFeeTx(2, 100000, big.NewInt(4), big.NewInt(1), keys[1]) if err := pool.AddRemote(tx); err != nil { // +K1:3, -K1:0 => Pend K0:0 K2:0; Que K1:2 K1:3 t.Fatalf("failed to add well priced transaction: %v", err) } @@ -1893,7 +1904,7 @@ func TestUnderpricingDynamicFee(t *testing.T) { if queued != 2 { t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2) } - if err := validateEvents(events, 1); err != nil { + if err := validateEvents(events, 2); err != nil { t.Fatalf("additional event firing failed: %v", err) } if err := validatePoolInternals(pool); err != nil { @@ -2487,7 +2498,7 @@ func benchmarkBatchInsert(b *testing.B, size int, local bool) { defer pool.Stop() account := crypto.PubkeyToAddress(key.PublicKey) - testAddBalance(pool, account, big.NewInt(1000000)) + testAddBalance(pool, account, big.NewInt(1000000000000000000)) batches := make([]types.Transactions, b.N) for i := 0; i < b.N; i++ { From 7e3b149be054053fd1177deaba3caf60d5f5d30b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 10 Mar 2023 19:53:52 +0100 Subject: [PATCH 625/715] params: go-ethereum v1.11.4 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 35cf0d53c951..74f27877ef23 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 4 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 4 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 4930614a097b70dd7bd2de0c680678bf980ed1a6 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 10 Mar 2023 20:00:23 +0100 Subject: [PATCH 626/715] params: begin v1.11.5 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 74f27877ef23..0cede57bbff4 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 4 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 5 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 789de23d16045190af3ace2276ea3957190e869b Mon Sep 17 00:00:00 2001 From: Guruprasad Kamath <48196632+gurukamath@users.noreply.github.com> Date: Fri, 10 Mar 2023 21:47:05 +0100 Subject: [PATCH 627/715] tests: define `MuirGlacier` fork (#26856) add muir glacier to t8n --- tests/init.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/init.go b/tests/init.go index db037e3e1a06..869f1bfcdd67 100644 --- a/tests/init.go +++ b/tests/init.go @@ -90,6 +90,19 @@ var Forks = map[string]*params.ChainConfig{ PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), }, + "MuirGlacier": { + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + DAOForkBlock: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + }, "FrontierToHomesteadAt5": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(5), From ca61048178bd25bdb42adb026c1e1639864bcffd Mon Sep 17 00:00:00 2001 From: xiyang <90125263+JBossBC@users.noreply.github.com> Date: Mon, 13 Mar 2023 15:30:32 +0800 Subject: [PATCH 628/715] code/vm: fix comment typo (#26865) it should be constantinople rather than contantinople --- core/vm/jump_table.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 91f1be669a40..a45287de80df 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -98,7 +98,7 @@ func newMergeInstructionSet() JumpTable { } // newLondonInstructionSet returns the frontier, homestead, byzantium, -// contantinople, istanbul, petersburg, berlin and london instructions. +// constantinople, istanbul, petersburg, berlin and london instructions. func newLondonInstructionSet() JumpTable { instructionSet := newBerlinInstructionSet() enable3529(&instructionSet) // EIP-3529: Reduction in refunds https://eips.ethereum.org/EIPS/eip-3529 @@ -107,7 +107,7 @@ func newLondonInstructionSet() JumpTable { } // newBerlinInstructionSet returns the frontier, homestead, byzantium, -// contantinople, istanbul, petersburg and berlin instructions. +// constantinople, istanbul, petersburg and berlin instructions. func newBerlinInstructionSet() JumpTable { instructionSet := newIstanbulInstructionSet() enable2929(&instructionSet) // Access lists for trie accesses https://eips.ethereum.org/EIPS/eip-2929 @@ -115,7 +115,7 @@ func newBerlinInstructionSet() JumpTable { } // newIstanbulInstructionSet returns the frontier, homestead, byzantium, -// contantinople, istanbul and petersburg instructions. +// constantinople, istanbul and petersburg instructions. func newIstanbulInstructionSet() JumpTable { instructionSet := newConstantinopleInstructionSet() @@ -127,7 +127,7 @@ func newIstanbulInstructionSet() JumpTable { } // newConstantinopleInstructionSet returns the frontier, homestead, -// byzantium and contantinople instructions. +// byzantium and constantinople instructions. func newConstantinopleInstructionSet() JumpTable { instructionSet := newByzantiumInstructionSet() instructionSet[SHL] = &operation{ From a20e38720c239a8e62797ec0ff8ffbcb813b2300 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Mon, 13 Mar 2023 16:02:50 +0800 Subject: [PATCH 629/715] core: minor code refactor (#26852) * core: refactor code * core: drop it from this anonymous goroutine func --- core/blockchain.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index f22562ccfa94..1fe7d73e0087 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1740,14 +1740,14 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) if followup, err := it.peek(); followup != nil && err == nil { throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps) - go func(start time.Time, followup *types.Block, throwaway *state.StateDB, interrupt *uint32) { + go func(start time.Time, followup *types.Block, throwaway *state.StateDB) { bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) blockPrefetchExecuteTimer.Update(time.Since(start)) - if atomic.LoadUint32(interrupt) == 1 { + if atomic.LoadUint32(&followupInterrupt) == 1 { blockPrefetchInterruptMeter.Mark(1) } - }(time.Now(), followup, throwaway, &followupInterrupt) + }(time.Now(), followup, throwaway) } } From d1c5f918a3d2e332d63725566a2ac54a616fa7e8 Mon Sep 17 00:00:00 2001 From: ucwong Date: Mon, 13 Mar 2023 02:45:25 -0600 Subject: [PATCH 630/715] core/txpool: use priceList.Put instead of heap.Push (#26863) Minor refactor to use the 'intended' accessor --- core/txpool/txpool.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 4306d5aee6f5..ad556f39fbb2 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -17,7 +17,6 @@ package txpool import ( - "container/heap" "errors" "fmt" "math" @@ -750,7 +749,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e // Add all transactions back to the priced queue if replacesPending { for _, dropTx := range drop { - heap.Push(&pool.priced.urgent, dropTx) + pool.priced.Put(dropTx, false) } log.Trace("Discarding future transaction replacing pending tx", "hash", hash) return false, ErrFutureReplacePending From 5f81db68c6cd0544ae5f3b9b4c7b1d56d02b23da Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 13 Mar 2023 04:51:23 -0600 Subject: [PATCH 631/715] eth: return error if 'safe' or 'finalized' tag used pre-merge (#26862) Co-authored-by: Martin Holst Swende Co-authored-by: Felix Lange --- eth/api_backend.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/eth/api_backend.go b/eth/api_backend.go index 78b9b08ecb32..643f6369df0e 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -75,6 +75,9 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb return b.eth.blockchain.CurrentBlock(), nil } if number == rpc.FinalizedBlockNumber { + if !b.eth.Merger().TDDReached() { + return nil, errors.New("'finalized' tag not supported on pre-merge network") + } block := b.eth.blockchain.CurrentFinalBlock() if block != nil { return block, nil @@ -82,6 +85,9 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb return nil, errors.New("finalized block not found") } if number == rpc.SafeBlockNumber { + if !b.eth.Merger().TDDReached() { + return nil, errors.New("'safe' tag not supported on pre-merge network") + } block := b.eth.blockchain.CurrentSafeBlock() if block != nil { return block, nil @@ -124,10 +130,16 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } if number == rpc.FinalizedBlockNumber { + if !b.eth.Merger().TDDReached() { + return nil, errors.New("'finalized' tag not supported on pre-merge network") + } header := b.eth.blockchain.CurrentFinalBlock() return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } if number == rpc.SafeBlockNumber { + if !b.eth.Merger().TDDReached() { + return nil, errors.New("'safe' tag not supported on pre-merge network") + } header := b.eth.blockchain.CurrentSafeBlock() return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } From 94ff7219114540263c76d1895618041959fae1f9 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 13 Mar 2023 14:10:19 +0100 Subject: [PATCH 632/715] .travis.yml: reenable PPA build on tag push (#26873) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index db21bd5d96ae..925e23b1a57f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -140,7 +140,7 @@ jobs: # This builder does the Ubuntu PPA nightly uploads - stage: build - if: type = cron + if: type = cron || (type = push && tag ~= /^v[0-9]/) os: linux dist: bionic go: 1.20.x From c8a6b7100c56255a9cde580be59136beb8d28b8e Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 14 Mar 2023 16:50:53 +0800 Subject: [PATCH 633/715] core/state, trie: port changes from PBSS (#26763) --- core/state/statedb.go | 2 +- trie/committer.go | 46 ++---- trie/database.go | 9 +- trie/nodeset.go | 115 ++++++------- trie/proof.go | 2 +- trie/tracer.go | 125 ++++++++++++++ trie/tracer_test.go | 368 ++++++++++++++++++++++++++++++++++++++++++ trie/trie.go | 28 ++-- trie/trie_test.go | 91 +++++++---- trie/util_test.go | 305 ---------------------------------- trie/utils.go | 199 ----------------------- 11 files changed, 645 insertions(+), 645 deletions(-) create mode 100644 trie/tracer.go create mode 100644 trie/tracer_test.go delete mode 100644 trie/util_test.go delete mode 100644 trie/utils.go diff --git a/core/state/statedb.go b/core/state/statedb.go index 3d8fd15bbd25..247aef8b239c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -970,8 +970,8 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { storageTrieNodesUpdated int storageTrieNodesDeleted int nodes = trie.NewMergedNodeSet() + codeWriter = s.db.DiskDB().NewBatch() ) - codeWriter := s.db.DiskDB().NewBatch() for addr := range s.stateObjectsDirty { if obj := s.stateObjects[addr]; !obj.deleted { // Write any contract code associated with the state object diff --git a/trie/committer.go b/trie/committer.go index c4957f3490ea..9f978873a8dd 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -33,29 +33,20 @@ type leaf struct { // insertion order. type committer struct { nodes *NodeSet - tracer *tracer collectLeaf bool } // newCommitter creates a new committer or picks one from the pool. -func newCommitter(owner common.Hash, tracer *tracer, collectLeaf bool) *committer { +func newCommitter(nodeset *NodeSet, collectLeaf bool) *committer { return &committer{ - nodes: NewNodeSet(owner), - tracer: tracer, + nodes: nodeset, collectLeaf: collectLeaf, } } -// Commit collapses a node down into a hash node and returns it along with -// the modified nodeset. -func (c *committer) Commit(n node) (hashNode, *NodeSet) { - h := c.commit(nil, n) - // Some nodes can be deleted from trie which can't be captured - // by committer itself. Iterate all deleted nodes tracked by - // tracer and marked them as deleted only if they are present - // in database previously. - c.tracer.markDeletions(c.nodes) - return h.(hashNode), c.nodes +// Commit collapses a node down into a hash node. +func (c *committer) Commit(n node) hashNode { + return c.commit(nil, n).(hashNode) } // commit collapses a node down into a hash node and returns it. @@ -74,9 +65,7 @@ func (c *committer) commit(path []byte, n node) node { // If the child is fullNode, recursively commit, // otherwise it can only be hashNode or valueNode. if _, ok := cn.Val.(*fullNode); ok { - childV := c.commit(append(path, cn.Key...), cn.Val) - - collapsed.Val = childV + collapsed.Val = c.commit(append(path, cn.Key...), cn.Val) } // The key needs to be copied, since we're adding it to the // modified nodeset. @@ -85,12 +74,6 @@ func (c *committer) commit(path []byte, n node) node { if hn, ok := hashedNode.(hashNode); ok { return hn } - // The short node now is embedded in its parent. Mark the node as - // deleted if it's present in database previously. It's equivalent - // as deletion from database's perspective. - if prev := c.tracer.getPrev(path); len(prev) != 0 { - c.nodes.markDeleted(path, prev) - } return collapsed case *fullNode: hashedKids := c.commitChildren(path, cn) @@ -101,12 +84,6 @@ func (c *committer) commit(path []byte, n node) node { if hn, ok := hashedNode.(hashNode); ok { return hn } - // The full node now is embedded in its parent. Mark the node as - // deleted if it's present in database previously. It's equivalent - // as deletion from database's perspective. - if prev := c.tracer.getPrev(path); len(prev) != 0 { - c.nodes.markDeleted(path, prev) - } return collapsed case hashNode: return cn @@ -134,8 +111,7 @@ func (c *committer) commitChildren(path []byte, n *fullNode) [17]node { // Commit the child recursively and store the "hashed" value. // Note the returned node can be some embedded nodes, so it's // possible the type is not hashNode. - hashed := c.commit(append(path, byte(i)), child) - children[i] = hashed + children[i] = c.commit(append(path, byte(i)), child) } // For the 17th child, it's possible the type is valuenode. if n.Children[16] != nil { @@ -155,6 +131,12 @@ func (c *committer) store(path []byte, n node) node { // usually is leaf node). But small value (less than 32bytes) is not // our target (leaves in account trie only). if hash == nil { + // 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. + if _, ok := c.nodes.accessList[string(path)]; ok { + c.nodes.markDeleted(path) + } return n } // We have the hash already, estimate the RLP encoding-size of the node. @@ -169,7 +151,7 @@ func (c *committer) store(path []byte, n node) node { } ) // Collect the dirty node to nodeset for return. - c.nodes.markUpdated(path, mnode, c.tracer.getPrev(path)) + c.nodes.markUpdated(path, mnode) // 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/database.go b/trie/database.go index 895ffdf89d88..200ed3674bf3 100644 --- a/trie/database.go +++ b/trie/database.go @@ -792,13 +792,12 @@ func (db *Database) Update(nodes *MergedNodeSet) error { } for _, owner := range order { subset := nodes.sets[owner] - for _, path := range subset.updates.order { - n, ok := subset.updates.nodes[path] - if !ok { - return fmt.Errorf("missing node %x %v", owner, path) + subset.forEachWithOrder(func(path string, n *memoryNode) { + if n.isDeleted() { + return // ignore deletion } db.insert(n.hash, int(n.size), n.node) - } + }) } // Link up the account trie and storage trie if the node points // to an account trie leaf. diff --git a/trie/nodeset.go b/trie/nodeset.go index 928172350171..99e4a80fa8ac 100644 --- a/trie/nodeset.go +++ b/trie/nodeset.go @@ -19,6 +19,7 @@ package trie import ( "fmt" "reflect" + "sort" "strings" "github.com/ethereum/go-ethereum/common" @@ -40,8 +41,8 @@ var memoryNodeSize = int(reflect.TypeOf(memoryNode{}).Size()) // memorySize returns the total memory size used by this node. // nolint:unused -func (n *memoryNode) memorySize(key int) int { - return int(n.size) + memoryNodeSize + key +func (n *memoryNode) memorySize(pathlen int) int { + return int(n.size) + memoryNodeSize + pathlen } // rlp returns the raw rlp encoded blob of the cached trie node, either directly @@ -64,7 +65,13 @@ func (n *memoryNode) obj() node { return expandNode(n.hash[:], n.node) } +// isDeleted returns the indicator if the node is marked as deleted. +func (n *memoryNode) isDeleted() bool { + return n.hash == (common.Hash{}) +} + // nodeWithPrev wraps the memoryNode with the previous node value. +// nolint: unused type nodeWithPrev struct { *memoryNode prev []byte // RLP-encoded previous value, nil means it's non-existent @@ -79,64 +86,60 @@ func (n *nodeWithPrev) unwrap() *memoryNode { // memorySize returns the total memory size used by this node. It overloads // the function in memoryNode by counting the size of previous value as well. // nolint: unused -func (n *nodeWithPrev) memorySize(key int) int { - return n.memoryNode.memorySize(key) + len(n.prev) -} - -// nodesWithOrder represents a collection of dirty nodes which includes -// newly-inserted and updated nodes. The modification order of all nodes -// is represented by order list. -type nodesWithOrder struct { - order []string // the path list of dirty nodes, sort by insertion order - nodes map[string]*nodeWithPrev // the map of dirty nodes, keyed by node path +func (n *nodeWithPrev) memorySize(pathlen int) int { + return n.memoryNode.memorySize(pathlen) + len(n.prev) } // NodeSet contains all dirty nodes collected during the commit operation. // Each node is keyed by path. It's not thread-safe to use. type NodeSet struct { - owner common.Hash // the identifier of the trie - updates *nodesWithOrder // the set of updated nodes(newly inserted, updated) - deletes map[string][]byte // the map of deleted nodes, keyed by node - leaves []*leaf // the list of dirty leaves + owner common.Hash // the identifier of the trie + nodes map[string]*memoryNode // the set of dirty nodes(inserted, updated, deleted) + leaves []*leaf // the list of dirty leaves + updates int // the count of updated and inserted nodes + deletes int // the count of deleted nodes + + // The list of accessed nodes, which records the original node value. + // The origin value is expected to be nil for newly inserted node + // and is expected to be non-nil for other types(updated, deleted). + accessList map[string][]byte } // NewNodeSet initializes an empty node set to be used for tracking dirty nodes // from a specific account or storage trie. The owner is zero for the account // trie and the owning account address hash for storage tries. -func NewNodeSet(owner common.Hash) *NodeSet { +func NewNodeSet(owner common.Hash, accessList map[string][]byte) *NodeSet { return &NodeSet{ - owner: owner, - updates: &nodesWithOrder{ - nodes: make(map[string]*nodeWithPrev), - }, - deletes: make(map[string][]byte), + owner: owner, + nodes: make(map[string]*memoryNode), + accessList: accessList, } } -/* -// NewNodeSetWithDeletion initializes the nodeset with provided deletion set. -func NewNodeSetWithDeletion(owner common.Hash, paths [][]byte, prev [][]byte) *NodeSet { - set := NewNodeSet(owner) - for i, path := range paths { - set.markDeleted(path, prev[i]) +// forEachWithOrder iterates the dirty nodes with the order from bottom to top, +// right to left, nodes with the longest path will be iterated first. +func (set *NodeSet) forEachWithOrder(callback func(path string, n *memoryNode)) { + var paths sort.StringSlice + for path := range set.nodes { + paths = append(paths, path) + } + // Bottom-up, longest path first + sort.Sort(sort.Reverse(paths)) + for _, path := range paths { + callback(path, set.nodes[path]) } - return set } -*/ -// markUpdated marks the node as dirty(newly-inserted or updated) with provided -// node path, node object along with its previous value. -func (set *NodeSet) markUpdated(path []byte, node *memoryNode, prev []byte) { - set.updates.order = append(set.updates.order, string(path)) - set.updates.nodes[string(path)] = &nodeWithPrev{ - memoryNode: node, - prev: prev, - } +// markUpdated marks the node as dirty(newly-inserted or updated). +func (set *NodeSet) markUpdated(path []byte, node *memoryNode) { + set.nodes[string(path)] = node + set.updates += 1 } -// markDeleted marks the node as deleted with provided path and previous value. -func (set *NodeSet) markDeleted(path []byte, prev []byte) { - set.deletes[string(path)] = prev +// markDeleted marks the node as deleted. +func (set *NodeSet) markDeleted(path []byte) { + set.nodes[string(path)] = &memoryNode{} + set.deletes += 1 } // addLeaf collects the provided leaf node into set. @@ -144,16 +147,16 @@ func (set *NodeSet) addLeaf(node *leaf) { set.leaves = append(set.leaves, node) } -// Size returns the number of updated and deleted nodes contained in the set. +// Size returns the number of dirty nodes in set. func (set *NodeSet) Size() (int, int) { - return len(set.updates.order), len(set.deletes) + return set.updates, set.deletes } // Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can // we get rid of it? func (set *NodeSet) Hashes() []common.Hash { var ret []common.Hash - for _, node := range set.updates.nodes { + for _, node := range set.nodes { ret = append(ret, node.hash) } return ret @@ -163,19 +166,23 @@ func (set *NodeSet) Hashes() []common.Hash { func (set *NodeSet) Summary() string { var out = new(strings.Builder) fmt.Fprintf(out, "nodeset owner: %v\n", set.owner) - if set.updates != nil { - for _, key := range set.updates.order { - updated := set.updates.nodes[key] - if updated.prev != nil { - fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", key, updated.hash, updated.prev) - } else { - fmt.Fprintf(out, " [+]: %x -> %v\n", key, updated.hash) + if set.nodes != nil { + for path, n := range set.nodes { + // Deletion + if n.isDeleted() { + fmt.Fprintf(out, " [-]: %x prev: %x\n", path, set.accessList[path]) + continue } + // Insertion + origin, ok := set.accessList[path] + if !ok { + fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.hash) + continue + } + // Update + fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", path, n.hash, origin) } } - for k, n := range set.deletes { - fmt.Fprintf(out, " [-]: %x -> %x\n", k, n) - } for _, n := range set.leaves { fmt.Fprintf(out, "[leaf]: %v\n", n) } diff --git a/trie/proof.go b/trie/proof.go index af49ce36b36c..f11dfc47afab 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -563,7 +563,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key } // Rebuild the trie with the leaf stream, the shape of trie // should be same with the original one. - tr := &Trie{root: root, reader: newEmptyReader()} + tr := &Trie{root: root, reader: newEmptyReader(), tracer: newTracer()} if empty { tr.root = nil } diff --git a/trie/tracer.go b/trie/tracer.go new file mode 100644 index 000000000000..a27e371c7acb --- /dev/null +++ b/trie/tracer.go @@ -0,0 +1,125 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package trie + +import "github.com/ethereum/go-ethereum/common" + +// tracer 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 +// used to track all insert and delete operations of trie and capture all +// deleted nodes eventually. +// +// The changed nodes can be mainly divided into two categories: the leaf +// node and intermediate node. The former is inserted/deleted by callers +// while the latter is inserted/deleted in order to follow the rule of trie. +// 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 +// the concurrency issues by themselves. +type tracer struct { + inserts map[string]struct{} + deletes map[string]struct{} + accessList map[string][]byte +} + +// 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), + } +} + +// 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) { + if _, present := t.deletes[string(path)]; present { + delete(t.deletes, string(path)) + return + } + t.inserts[string(path)] = struct{}{} +} + +// 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) { + if _, present := t.inserts[string(path)]; present { + delete(t.inserts, string(path)) + return + } + t.deletes[string(path)] = struct{}{} +} + +// 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) +} + +// copy returns a deep copied tracer instance. +func (t *tracer) copy() *tracer { + var ( + inserts = make(map[string]struct{}) + deletes = make(map[string]struct{}) + accessList = make(map[string][]byte) + ) + for path := range t.inserts { + inserts[path] = struct{}{} + } + for path := range t.deletes { + deletes[path] = struct{}{} + } + for path, blob := range t.accessList { + accessList[path] = common.CopyBytes(blob) + } + return &tracer{ + inserts: inserts, + deletes: deletes, + accessList: accessList, + } +} + +// markDeletions puts all tracked deletions into the provided nodeset. +func (t *tracer) markDeletions(set *NodeSet) { + 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. + if _, ok := set.accessList[path]; !ok { + continue + } + set.markDeleted([]byte(path)) + } +} diff --git a/trie/tracer_test.go b/trie/tracer_test.go new file mode 100644 index 000000000000..5e627c89c9be --- /dev/null +++ b/trie/tracer_test.go @@ -0,0 +1,368 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package trie + +import ( + "bytes" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" +) + +var ( + tiny = []struct{ k, v string }{ + {"k1", "v1"}, + {"k2", "v2"}, + {"k3", "v3"}, + } + nonAligned = []struct{ k, v string }{ + {"do", "verb"}, + {"ether", "wookiedoo"}, + {"horse", "stallion"}, + {"shaman", "horse"}, + {"doge", "coin"}, + {"dog", "puppy"}, + {"somethingveryoddindeedthis is", "myothernodedata"}, + } + standard = []struct{ k, v string }{ + {string(randBytes(32)), "verb"}, + {string(randBytes(32)), "wookiedoo"}, + {string(randBytes(32)), "stallion"}, + {string(randBytes(32)), "horse"}, + {string(randBytes(32)), "coin"}, + {string(randBytes(32)), "puppy"}, + {string(randBytes(32)), "myothernodedata"}, + } +) + +func TestTrieTracer(t *testing.T) { + testTrieTracer(t, tiny) + testTrieTracer(t, nonAligned) + testTrieTracer(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 }) { + db := NewDatabase(rawdb.NewMemoryDatabase()) + trie := NewEmpty(db) + + // Determine all new nodes are tracked + for _, val := range vals { + trie.Update([]byte(val.k), []byte(val.v)) + } + insertSet := copySet(trie.tracer.inserts) // copy before commit + deleteSet := copySet(trie.tracer.deletes) // copy before commit + root, nodes := trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) + + seen := setKeys(iterNodes(db, root)) + if !compareSet(insertSet, seen) { + t.Fatal("Unexpected insertion set") + } + if !compareSet(deleteSet, nil) { + t.Fatal("Unexpected deletion set") + } + + // Determine all deletions are tracked + trie, _ = New(TrieID(root), db) + for _, val := range vals { + trie.Delete([]byte(val.k)) + } + insertSet, deleteSet = copySet(trie.tracer.inserts), copySet(trie.tracer.deletes) + if !compareSet(insertSet, nil) { + t.Fatal("Unexpected insertion set") + } + if !compareSet(deleteSet, seen) { + t.Fatal("Unexpected deletion set") + } +} + +// 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 testTrieTracerNoop(t *testing.T, vals []struct{ k, v string }) { + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) + for _, val := range vals { + trie.Update([]byte(val.k), []byte(val.v)) + } + for _, val := range vals { + trie.Delete([]byte(val.k)) + } + if len(trie.tracer.inserts) != 0 { + t.Fatal("Unexpected insertion set") + } + if len(trie.tracer.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) +} + +func testAccessList(t *testing.T, vals []struct{ k, v string }) { + var ( + db = NewDatabase(rawdb.NewMemoryDatabase()) + trie = NewEmpty(db) + orig = trie.Copy() + ) + // Create trie from scratch + for _, val := range vals { + trie.Update([]byte(val.k), []byte(val.v)) + } + root, nodes := trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) + + trie, _ = New(TrieID(root), db) + if err := verifyAccessList(orig, trie, nodes); err != nil { + t.Fatalf("Invalid accessList %v", err) + } + + // Update trie + trie, _ = New(TrieID(root), db) + orig = trie.Copy() + for _, val := range vals { + trie.Update([]byte(val.k), randBytes(32)) + } + root, nodes = trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) + + trie, _ = New(TrieID(root), db) + if err := verifyAccessList(orig, trie, nodes); err != nil { + t.Fatalf("Invalid accessList %v", err) + } + + // Add more new nodes + trie, _ = New(TrieID(root), db) + orig = trie.Copy() + var keys []string + for i := 0; i < 30; i++ { + key := randBytes(32) + keys = append(keys, string(key)) + trie.Update(key, randBytes(32)) + } + root, nodes = trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) + + trie, _ = New(TrieID(root), db) + if err := verifyAccessList(orig, trie, nodes); err != nil { + t.Fatalf("Invalid accessList %v", err) + } + + // Partial deletions + trie, _ = New(TrieID(root), db) + orig = trie.Copy() + for _, key := range keys { + trie.Update([]byte(key), nil) + } + root, nodes = trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) + + trie, _ = New(TrieID(root), db) + if err := verifyAccessList(orig, trie, nodes); err != nil { + t.Fatalf("Invalid accessList %v", err) + } + + // Delete all + trie, _ = New(TrieID(root), db) + orig = trie.Copy() + for _, val := range vals { + trie.Update([]byte(val.k), nil) + } + root, nodes = trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) + + trie, _ = New(TrieID(root), db) + if err := verifyAccessList(orig, trie, nodes); err != nil { + t.Fatalf("Invalid accessList %v", err) + } +} + +// Tests origin values won't be tracked in Iterator or Prover +func TestAccessListLeak(t *testing.T) { + var ( + db = NewDatabase(rawdb.NewMemoryDatabase()) + trie = NewEmpty(db) + ) + // Create trie from scratch + for _, val := range standard { + trie.Update([]byte(val.k), []byte(val.v)) + } + root, nodes := trie.Commit(false) + db.Update(NewWithNodeSet(nodes)) + + var cases = []struct { + op func(tr *Trie) + }{ + { + func(tr *Trie) { + it := tr.NodeIterator(nil) + for it.Next(true) { + } + }, + }, + { + func(tr *Trie) { + it := NewIterator(tr.NodeIterator(nil)) + for it.Next() { + } + }, + }, + { + func(tr *Trie) { + for _, val := range standard { + tr.Prove([]byte(val.k), 0, rawdb.NewMemoryDatabase()) + } + }, + }, + } + for _, c := range cases { + trie, _ = New(TrieID(root), db) + n1 := len(trie.tracer.accessList) + c.op(trie) + n2 := len(trie.tracer.accessList) + + if n1 != n2 { + t.Fatalf("AccessList is leaked, prev %d after %d", n1, n2) + } + } +} + +// Tests whether the original tree node is correctly deleted after being embedded +// in its parent due to the smaller size of the original tree node. +func TestTinyTree(t *testing.T) { + var ( + db = NewDatabase(rawdb.NewMemoryDatabase()) + trie = NewEmpty(db) + ) + for _, val := range tiny { + trie.Update([]byte(val.k), randBytes(32)) + } + root, set := trie.Commit(false) + db.Update(NewWithNodeSet(set)) + + trie, _ = New(TrieID(root), db) + orig := trie.Copy() + for _, val := range tiny { + trie.Update([]byte(val.k), []byte(val.v)) + } + root, set = trie.Commit(false) + db.Update(NewWithNodeSet(set)) + + trie, _ = New(TrieID(root), db) + if err := verifyAccessList(orig, trie, set); err != nil { + t.Fatalf("Invalid accessList %v", err) + } +} + +func compareSet(setA, setB map[string]struct{}) bool { + if len(setA) != len(setB) { + return false + } + for key := range setA { + if _, ok := setB[key]; !ok { + return false + } + } + return true +} + +func forNodes(tr *Trie) map[string][]byte { + var ( + it = tr.NodeIterator(nil) + nodes = make(map[string][]byte) + ) + for it.Next(true) { + if it.Leaf() { + continue + } + nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) + } + return nodes +} + +func iterNodes(db *Database, root common.Hash) map[string][]byte { + tr, _ := New(TrieID(root), db) + return forNodes(tr) +} + +func forHashedNodes(tr *Trie) map[string][]byte { + var ( + it = tr.NodeIterator(nil) + nodes = make(map[string][]byte) + ) + for it.Next(true) { + if it.Hash() == (common.Hash{}) { + continue + } + nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) + } + return nodes +} + +func diffTries(trieA, trieB *Trie) (map[string][]byte, map[string][]byte, map[string][]byte) { + var ( + nodesA = forHashedNodes(trieA) + nodesB = forHashedNodes(trieB) + inA = make(map[string][]byte) // hashed nodes in trie a but not b + inB = make(map[string][]byte) // hashed nodes in trie b but not a + both = make(map[string][]byte) // hashed nodes in both tries but different value + ) + for path, blobA := range nodesA { + if blobB, ok := nodesB[path]; ok { + if bytes.Equal(blobA, blobB) { + continue + } + both[path] = blobA + continue + } + inA[path] = blobA + } + for path, blobB := range nodesB { + if _, ok := nodesA[path]; ok { + continue + } + inB[path] = blobB + } + return inA, inB, both +} + +func setKeys(set map[string][]byte) map[string]struct{} { + keys := make(map[string]struct{}) + for k := range set { + keys[k] = struct{}{} + } + return keys +} + +func copySet(set map[string]struct{}) map[string]struct{} { + copied := make(map[string]struct{}) + for k := range set { + copied[k] = struct{}{} + } + return copied +} diff --git a/trie/trie.go b/trie/trie.go index cf9108f1077b..17bacba00fdc 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -81,7 +81,7 @@ func New(id *ID, db NodeReader) (*Trie, error) { trie := &Trie{ owner: id.Owner, reader: reader, - //tracer: newTracer(), + tracer: newTracer(), } if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash { rootnode, err := trie.resolveAndTrack(id.Root[:], nil) @@ -547,7 +547,7 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { // Hash returns the root hash of the trie. It does not write to the // database and can be used even if the trie doesn't have one. func (t *Trie) Hash() common.Hash { - hash, cached, _ := t.hashRoot() + hash, cached := t.hashRoot() t.root = cached return common.BytesToHash(hash.(hashNode)) } @@ -561,14 +561,14 @@ func (t *Trie) Hash() common.Hash { func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { defer t.tracer.reset() + nodes := NewNodeSet(t.owner, t.tracer.accessList) + t.tracer.markDeletions(nodes) + // Trie is empty and can be classified into two types of situations: // - The trie was empty and no update happens // - The trie was non-empty and all nodes are dropped if t.root == nil { - // Wrap tracked deletions as the return - set := NewNodeSet(t.owner) - t.tracer.markDeletions(set) - return types.EmptyRootHash, set + return types.EmptyRootHash, nodes } // Derive the hash for all dirty nodes first. We hold the assumption // in the following procedure that all nodes are hashed. @@ -582,23 +582,23 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *NodeSet) { t.root = hashedNode return rootHash, nil } - h := newCommitter(t.owner, t.tracer, collectLeaf) - newRoot, nodes := h.Commit(t.root) - t.root = newRoot + t.root = newCommitter(nodes, collectLeaf).Commit(t.root) return rootHash, nodes } // hashRoot calculates the root hash of the given trie -func (t *Trie) hashRoot() (node, node, error) { +func (t *Trie) hashRoot() (node, node) { if t.root == nil { - return hashNode(types.EmptyRootHash.Bytes()), nil, nil + return hashNode(types.EmptyRootHash.Bytes()), nil } // If the number of changes is below 100, we let one thread handle it h := newHasher(t.unhashed >= 100) - defer returnHasherToPool(h) + defer func() { + returnHasherToPool(h) + t.unhashed = 0 + }() hashed, cached := h.hash(t.root, true) - t.unhashed = 0 - return hashed, cached, nil + return hashed, cached } // Reset drops the referenced root node and cleans all internal state. diff --git a/trie/trie_test.go b/trie/trie_test.go index 2f56c89cde37..e415937073ea 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -403,6 +403,51 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value { return reflect.ValueOf(steps) } +func verifyAccessList(old *Trie, new *Trie, set *NodeSet) error { + deletes, inserts, updates := diffTries(old, new) + + // Check insertion set + for path := range inserts { + n, ok := set.nodes[path] + if !ok || n.isDeleted() { + return errors.New("expect new node") + } + _, ok = set.accessList[path] + if ok { + return errors.New("unexpected origin value") + } + } + // Check deletion set + for path, blob := range deletes { + n, ok := set.nodes[path] + if !ok || !n.isDeleted() { + return errors.New("expect deleted node") + } + v, ok := set.accessList[path] + if !ok { + return errors.New("expect origin value") + } + if !bytes.Equal(v, blob) { + return errors.New("invalid origin value") + } + } + // Check update set + for path, blob := range updates { + n, ok := set.nodes[path] + if !ok || n.isDeleted() { + return errors.New("expect updated node") + } + v, ok := set.accessList[path] + if !ok { + return errors.New("expect origin value") + } + if !bytes.Equal(v, blob) { + return errors.New("invalid origin value") + } + } + return nil +} + func runRandTest(rt randTest) bool { var ( triedb = NewDatabase(rawdb.NewMemoryDatabase()) @@ -410,8 +455,6 @@ func runRandTest(rt randTest) bool { values = make(map[string]string) // tracks content of the trie origTrie = NewEmpty(triedb) ) - tr.tracer = newTracer() - for i, step := range rt { // fmt.Printf("{op: %d, key: common.Hex2Bytes(\"%x\"), value: common.Hex2Bytes(\"%x\")}, // step %d\n", // step.op, step.key, step.value, i) @@ -447,24 +490,6 @@ func runRandTest(rt randTest) bool { tr.Hash() case opCommit: root, nodes := tr.Commit(true) - // Validity the returned nodeset - if nodes != nil { - for path, node := range nodes.updates.nodes { - blob, _, _ := origTrie.TryGetNode(hexToCompact([]byte(path))) - got := node.prev - if !bytes.Equal(blob, got) { - rt[i].err = fmt.Errorf("prevalue mismatch for 0x%x, got 0x%x want 0x%x", path, got, blob) - panic(rt[i].err) - } - } - for path, prev := range nodes.deletes { - blob, _, _ := origTrie.TryGetNode(hexToCompact([]byte(path))) - if !bytes.Equal(blob, prev) { - rt[i].err = fmt.Errorf("prevalue mismatch for 0x%x, got 0x%x want 0x%x", path, prev, blob) - return false - } - } - } if nodes != nil { triedb.Update(NewWithNodeSet(nodes)) } @@ -473,13 +498,13 @@ func runRandTest(rt randTest) bool { rt[i].err = err return false } + if nodes != nil { + if err := verifyAccessList(origTrie, newtr, nodes); err != nil { + rt[i].err = err + return false + } + } tr = newtr - - // Enable node tracing. Resolve the root node again explicitly - // since it's not captured at the beginning. - tr.tracer = newTracer() - tr.resolveAndTrack(root.Bytes(), nil) - origTrie = tr.Copy() case opItercheckhash: checktr := NewEmpty(triedb) @@ -492,8 +517,6 @@ func runRandTest(rt randTest) bool { } case opNodeDiff: var ( - inserted = tr.tracer.insertList() - deleted = tr.tracer.deleteList() origIter = origTrie.NodeIterator(nil) curIter = tr.NodeIterator(nil) origSeen = make(map[string]struct{}) @@ -527,19 +550,19 @@ func runRandTest(rt randTest) bool { deleteExp[path] = struct{}{} } } - if len(insertExp) != len(inserted) { + if len(insertExp) != len(tr.tracer.inserts) { rt[i].err = fmt.Errorf("insert set mismatch") } - if len(deleteExp) != len(deleted) { + if len(deleteExp) != len(tr.tracer.deletes) { rt[i].err = fmt.Errorf("delete set mismatch") } - for _, insert := range inserted { - if _, present := insertExp[string(insert)]; !present { + for insert := range tr.tracer.inserts { + if _, present := insertExp[insert]; !present { rt[i].err = fmt.Errorf("missing inserted node") } } - for _, del := range deleted { - if _, present := deleteExp[string(del)]; !present { + for del := range tr.tracer.deletes { + if _, present := deleteExp[del]; !present { rt[i].err = fmt.Errorf("missing deleted node") } } diff --git a/trie/util_test.go b/trie/util_test.go deleted file mode 100644 index 8d925a16aabb..000000000000 --- a/trie/util_test.go +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package trie - -import ( - "bytes" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/types" -) - -// Tests if the trie diffs are tracked correctly. -func TestTrieTracer(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - trie := NewEmpty(db) - trie.tracer = newTracer() - - // Insert a batch of entries, all the nodes should be marked as inserted - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) - } - trie.Hash() - - seen := make(map[string]struct{}) - it := trie.NodeIterator(nil) - for it.Next(true) { - if it.Leaf() { - continue - } - seen[string(it.Path())] = struct{}{} - } - inserted := trie.tracer.insertList() - if len(inserted) != len(seen) { - t.Fatalf("Unexpected inserted node tracked want %d got %d", len(seen), len(inserted)) - } - for _, k := range inserted { - _, ok := seen[string(k)] - if !ok { - t.Fatalf("Unexpected inserted node") - } - } - deleted := trie.tracer.deleteList() - if len(deleted) != 0 { - t.Fatalf("Unexpected deleted node tracked %d", len(deleted)) - } - - // Commit the changes and re-create with new root - root, nodes := trie.Commit(false) - if err := db.Update(NewWithNodeSet(nodes)); err != nil { - t.Fatal(err) - } - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - - // Delete all the elements, check deletion set - for _, val := range vals { - trie.Delete([]byte(val.k)) - } - trie.Hash() - - inserted = trie.tracer.insertList() - if len(inserted) != 0 { - t.Fatalf("Unexpected inserted node tracked %d", len(inserted)) - } - deleted = trie.tracer.deleteList() - if len(deleted) != len(seen) { - t.Fatalf("Unexpected deleted node tracked want %d got %d", len(seen), len(deleted)) - } - for _, k := range deleted { - _, ok := seen[string(k)] - if !ok { - t.Fatalf("Unexpected inserted node") - } - } -} - -func TestTrieTracerNoop(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) - trie.tracer = newTracer() - - // Insert a batch of entries, all the nodes should be marked as inserted - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) - } - for _, val := range vals { - trie.Delete([]byte(val.k)) - } - if len(trie.tracer.insertList()) != 0 { - t.Fatalf("Unexpected inserted node tracked %d", len(trie.tracer.insertList())) - } - if len(trie.tracer.deleteList()) != 0 { - t.Fatalf("Unexpected deleted node tracked %d", len(trie.tracer.deleteList())) - } -} - -func TestTrieTracePrevValue(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - trie := NewEmpty(db) - trie.tracer = newTracer() - - paths, blobs := trie.tracer.prevList() - if len(paths) != 0 || len(blobs) != 0 { - t.Fatalf("Nothing should be tracked") - } - // Insert a batch of entries, all the nodes should be marked as inserted - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) - } - paths, blobs = trie.tracer.prevList() - if len(paths) != 0 || len(blobs) != 0 { - t.Fatalf("Nothing should be tracked") - } - - // Commit the changes and re-create with new root - root, nodes := trie.Commit(false) - if err := db.Update(NewWithNodeSet(nodes)); err != nil { - t.Fatal(err) - } - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - trie.resolveAndTrack(root.Bytes(), nil) - - // Load all nodes in trie - for _, val := range vals { - trie.TryGet([]byte(val.k)) - } - - // Ensure all nodes are tracked by tracer with correct prev-values - iter := trie.NodeIterator(nil) - seen := make(map[string][]byte) - for iter.Next(true) { - // Embedded nodes are ignored since they are not present in - // database. - if iter.Hash() == (common.Hash{}) { - continue - } - seen[string(iter.Path())] = common.CopyBytes(iter.NodeBlob()) - } - - paths, blobs = trie.tracer.prevList() - if len(paths) != len(seen) || len(blobs) != len(seen) { - t.Fatalf("Unexpected tracked values") - } - for i, path := range paths { - blob := blobs[i] - prev, ok := seen[string(path)] - if !ok { - t.Fatalf("Missing node %v", path) - } - if !bytes.Equal(blob, prev) { - t.Fatalf("Unexpected value path: %v, want: %v, got: %v", path, prev, blob) - } - } - - // Re-open the trie and iterate the trie, ensure nothing will be tracked. - // Iterator will not link any loaded nodes to trie. - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - - iter = trie.NodeIterator(nil) - for iter.Next(true) { - } - paths, blobs = trie.tracer.prevList() - if len(paths) != 0 || len(blobs) != 0 { - t.Fatalf("Nothing should be tracked") - } - - // Re-open the trie and generate proof for entries, ensure nothing will - // be tracked. Prover will not link any loaded nodes to trie. - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - for _, val := range vals { - trie.Prove([]byte(val.k), 0, rawdb.NewMemoryDatabase()) - } - paths, blobs = trie.tracer.prevList() - if len(paths) != 0 || len(blobs) != 0 { - t.Fatalf("Nothing should be tracked") - } - - // Delete entries from trie, ensure all previous values are correct. - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - trie.resolveAndTrack(root.Bytes(), nil) - - for _, val := range vals { - trie.TryDelete([]byte(val.k)) - } - paths, blobs = trie.tracer.prevList() - if len(paths) != len(seen) || len(blobs) != len(seen) { - t.Fatalf("Unexpected tracked values") - } - for i, path := range paths { - blob := blobs[i] - prev, ok := seen[string(path)] - if !ok { - t.Fatalf("Missing node %v", path) - } - if !bytes.Equal(blob, prev) { - t.Fatalf("Unexpected value path: %v, want: %v, got: %v", path, prev, blob) - } - } -} - -func TestDeleteAll(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - trie := NewEmpty(db) - trie.tracer = newTracer() - - // Insert a batch of entries, all the nodes should be marked as inserted - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) - } - root, set := trie.Commit(false) - if err := db.Update(NewWithNodeSet(set)); err != nil { - t.Fatal(err) - } - // Delete entries from trie, ensure all values are detected - trie, _ = New(TrieID(root), db) - trie.tracer = newTracer() - trie.resolveAndTrack(root.Bytes(), nil) - - // Iterate all existent nodes - var ( - it = trie.NodeIterator(nil) - nodes = make(map[string][]byte) - ) - for it.Next(true) { - if it.Hash() != (common.Hash{}) { - nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) - } - } - - // Perform deletion to purge the entire trie - for _, val := range vals { - trie.Delete([]byte(val.k)) - } - root, set = trie.Commit(false) - if root != types.EmptyRootHash { - t.Fatalf("Invalid trie root %v", root) - } - for path, blob := range set.deletes { - prev, ok := nodes[path] - if !ok { - t.Fatalf("Extra node deleted %v", []byte(path)) - } - if !bytes.Equal(prev, blob) { - t.Fatalf("Unexpected previous value %v", []byte(path)) - } - } - if len(set.deletes) != len(nodes) { - t.Fatalf("Unexpected deletion set") - } -} diff --git a/trie/utils.go b/trie/utils.go deleted file mode 100644 index 5dce65cd2971..000000000000 --- a/trie/utils.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package trie - -// tracer 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 -// used to track all insert and delete operations of trie and capture all -// deleted nodes eventually. -// -// The changed nodes can be mainly divided into two categories: the leaf -// node and intermediate node. The former is inserted/deleted by callers -// while the latter is inserted/deleted in order to follow the rule of trie. -// 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 reverse-diffs in the future. -// -// Note tracer is not thread-safe, callers should be responsible for handling -// the concurrency issues by themselves. -type tracer struct { - insert map[string]struct{} - delete map[string]struct{} - origin map[string][]byte -} - -// newTracer initializes the tracer for capturing trie changes. -func newTracer() *tracer { - return &tracer{ - insert: make(map[string]struct{}), - delete: make(map[string]struct{}), - origin: make(map[string][]byte), - } -} - -// 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) { - // Tracer isn't used right now, remove this check later. - if t == nil { - return - } - t.origin[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 the "untouched". -func (t *tracer) onInsert(path []byte) { - // Tracer isn't used right now, remove this check later. - if t == nil { - return - } - if _, present := t.delete[string(path)]; present { - delete(t.delete, string(path)) - return - } - t.insert[string(path)] = struct{}{} -} - -// 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) { - // Tracer isn't used right now, remove this check later. - if t == nil { - return - } - if _, present := t.insert[string(path)]; present { - delete(t.insert, string(path)) - return - } - t.delete[string(path)] = struct{}{} -} - -// insertList returns the tracked inserted trie nodes in list format. -func (t *tracer) insertList() [][]byte { - // Tracer isn't used right now, remove this check later. - if t == nil { - return nil - } - var ret [][]byte - for path := range t.insert { - ret = append(ret, []byte(path)) - } - return ret -} - -// deleteList returns the tracked deleted trie nodes in list format. -func (t *tracer) deleteList() [][]byte { - // Tracer isn't used right now, remove this check later. - if t == nil { - return nil - } - var ret [][]byte - for path := range t.delete { - ret = append(ret, []byte(path)) - } - return ret -} - -// prevList returns the tracked node blobs in list format. -func (t *tracer) prevList() ([][]byte, [][]byte) { - // Tracer isn't used right now, remove this check later. - if t == nil { - return nil, nil - } - var ( - paths [][]byte - blobs [][]byte - ) - for path, blob := range t.origin { - paths = append(paths, []byte(path)) - blobs = append(blobs, blob) - } - return paths, blobs -} - -// getPrev returns the cached original value of the specified node. -func (t *tracer) getPrev(path []byte) []byte { - // Tracer isn't used right now, remove this check later. - if t == nil { - return nil - } - return t.origin[string(path)] -} - -// reset clears the content tracked by tracer. -func (t *tracer) reset() { - // Tracer isn't used right now, remove this check later. - if t == nil { - return - } - t.insert = make(map[string]struct{}) - t.delete = make(map[string]struct{}) - t.origin = make(map[string][]byte) -} - -// copy returns a deep copied tracer instance. -func (t *tracer) copy() *tracer { - // Tracer isn't used right now, remove this check later. - if t == nil { - return nil - } - var ( - insert = make(map[string]struct{}) - delete = make(map[string]struct{}) - origin = make(map[string][]byte) - ) - for key := range t.insert { - insert[key] = struct{}{} - } - for key := range t.delete { - delete[key] = struct{}{} - } - for key, val := range t.origin { - origin[key] = val - } - return &tracer{ - insert: insert, - delete: delete, - origin: origin, - } -} - -// markDeletions puts all tracked deletions into the provided nodeset. -func (t *tracer) markDeletions(set *NodeSet) { - // Tracer isn't used right now, remove this check later. - if t == nil { - return - } - for _, path := range t.deleteList() { - // There are a few possibilities for this scenario(the node is deleted - // but not present in database previously), for example the node was - // embedded in the parent and now deleted from the trie. In this case - // it's noop from database's perspective. - val := t.getPrev(path) - if len(val) == 0 { - continue - } - set.markDeleted(path, val) - } -} From eca3d39c314c0eaa2b2b616619fde84d032a11b1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 14 Mar 2023 07:40:40 -0400 Subject: [PATCH 634/715] p2p/discover: pass invalid discv5 packets to Unhandled channel (#26699) This makes it possible to run another protocol alongside discv5, by reading unhandled packets from the channel. --- p2p/discover/v5_udp.go | 10 ++++++++++ p2p/discover/v5wire/encoding.go | 18 ++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 53a1c6f7670a..38f5b3b652cf 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -83,6 +83,7 @@ type UDPv5 struct { callCh chan *callV5 callDoneCh chan *callV5 respTimeoutCh chan *callTimeout + unhandled chan<- ReadPacket // state of dispatch codec codecV5 @@ -156,6 +157,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { callCh: make(chan *callV5), callDoneCh: make(chan *callV5), respTimeoutCh: make(chan *callTimeout), + unhandled: cfg.Unhandled, // state of dispatch codec: v5wire.NewCodec(ln, cfg.PrivateKey, cfg.Clock, cfg.V5ProtocolID), activeCallByNode: make(map[enode.ID]*callV5), @@ -657,6 +659,14 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { addr := fromAddr.String() fromID, fromNode, packet, err := t.codec.Decode(rawpacket, addr) if err != nil { + if t.unhandled != nil && v5wire.IsInvalidHeader(err) { + // The packet seems unrelated to discv5, send it to the next protocol. + // t.log.Trace("Unhandled discv5 packet", "id", fromID, "addr", addr, "err", err) + up := ReadPacket{Data: make([]byte, len(rawpacket)), Addr: fromAddr} + copy(up.Data, rawpacket) + t.unhandled <- up + return nil + } t.log.Debug("Bad discv5 packet", "id", fromID, "addr", addr, "err", err) return err } diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index d979ab0f9cd8..5108910620e0 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -94,6 +94,8 @@ const ( // Should reject packets smaller than minPacketSize. minPacketSize = 63 + maxPacketSize = 1280 + minMessageSize = 48 // this refers to data after static headers randomPacketMsgSize = 20 ) @@ -122,6 +124,13 @@ var ( ErrInvalidReqID = errors.New("request ID larger than 8 bytes") ) +// IsInvalidHeader reports whether 'err' is related to an invalid packet header. When it +// returns false, it is pretty certain that the packet causing the error does not belong +// to discv5. +func IsInvalidHeader(err error) bool { + return err == errTooShort || err == errInvalidHeader || err == errMsgTooShort +} + // Packet sizes. var ( sizeofStaticHeader = binary.Size(StaticHeader{}) @@ -147,6 +156,7 @@ type Codec struct { msgctbuf []byte // message data ciphertext // decoder buffer + decbuf []byte reader bytes.Reader } @@ -158,6 +168,7 @@ func NewCodec(ln *enode.LocalNode, key *ecdsa.PrivateKey, clock mclock.Clock, pr privkey: key, sc: NewSessionCache(1024, clock), protocolID: DefaultProtocolID, + decbuf: make([]byte, maxPacketSize), } if protocolID != nil { c.protocolID = *protocolID @@ -424,10 +435,13 @@ func (c *Codec) encryptMessage(s *session, p Packet, head *Header, headerData [] } // Decode decodes a discovery packet. -func (c *Codec) Decode(input []byte, addr string) (src enode.ID, n *enode.Node, p Packet, err error) { - if len(input) < minPacketSize { +func (c *Codec) Decode(inputData []byte, addr string) (src enode.ID, n *enode.Node, p Packet, err error) { + if len(inputData) < minPacketSize { return enode.ID{}, nil, nil, errTooShort } + // Copy the packet to a tmp buffer to avoid modifying it. + c.decbuf = append(c.decbuf[:0], inputData...) + input := c.decbuf // Unmask the static header. var head Header copy(head.IV[:], input[:sizeofMaskingIV]) From b5c9be3358f0eb0a6f217474678dfd609f1d2743 Mon Sep 17 00:00:00 2001 From: Stephen Flynn Date: Tue, 14 Mar 2023 10:23:49 -0400 Subject: [PATCH 635/715] all: update links in documentation (#26882) Co-authored-by: Stephen Flynn --- .github/CONTRIBUTING.md | 2 +- README.md | 12 ++++++------ cmd/checkpoint-admin/README.md | 2 +- cmd/geth/consolecmd.go | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a08542df2555..969b7f8f9fa1 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -35,6 +35,6 @@ and help. ## Configuration, dependencies, and tests -Please see the [Developers' Guide](https://geth.ethereum.org/docs/developers/devguide) +Please see the [Developers' Guide](https://geth.ethereum.org/docs/developers/geth-developer/dev-guide) for more details on configuring your environment, managing project dependencies and testing procedures. diff --git a/README.md b/README.md index 325f796a3e3b..34bd8b94c98d 100644 --- a/README.md +++ b/README.md @@ -36,10 +36,10 @@ directory. | Command | Description | | :--------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI page](https://geth.ethereum.org/docs/interface/command-line-options) for command line options. | +| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI page](https://geth.ethereum.org/docs/fundamentals/command-line-options) for command line options. | | `clef` | Stand-alone signing tool, which can be used as a backend signer for `geth`. | | `devp2p` | Utilities to interact with nodes on the networking layer, without running a full blockchain. | -| `abigen` | Source code generator to convert Ethereum contract definitions into easy-to-use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://docs.soliditylang.org/en/develop/abi-spec.html) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://geth.ethereum.org/docs/dapp/native-bindings) page for details. | +| `abigen` | Source code generator to convert Ethereum contract definitions into easy-to-use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://docs.soliditylang.org/en/develop/abi-spec.html) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://geth.ethereum.org/docs/developers/dapp-developer/native-bindings) page for details. | | `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. | | `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug run`). | | `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | @@ -47,7 +47,7 @@ directory. ## Running `geth` Going through all the possible command line flags is out of scope here (please consult our -[CLI Wiki page](https://geth.ethereum.org/docs/interface/command-line-options)), +[CLI Wiki page](https://geth.ethereum.org/docs/fundamentals/command-line-options)), but we've enumerated a few common parameter combos to get you up to speed quickly on how you can run your own `geth` instance. @@ -82,10 +82,10 @@ This command will: * Start `geth` in snap sync mode (default, can be changed with the `--syncmode` flag), causing it to download more data in exchange for avoiding processing the entire history of the Ethereum network, which is very CPU intensive. - * Start the built-in interactive [JavaScript console](https://geth.ethereum.org/docs/interface/javascript-console), + * Start the built-in interactive [JavaScript console](https://geth.ethereum.org/docs/interacting-with-geth/javascript-console), (via the trailing `console` subcommand) through which you can interact using [`web3` methods](https://github.com/ChainSafe/web3.js/blob/0.20.7/DOCUMENTATION.md) (note: the `web3` version bundled within `geth` is very old, and not up to date with official docs), - as well as `geth`'s own [management APIs](https://geth.ethereum.org/docs/rpc/server). + as well as `geth`'s own [management APIs](https://geth.ethereum.org/docs/interacting-with-geth/rpc). This tool is optional and if you leave it out you can always attach it to an already running `geth` instance with `geth attach`. @@ -175,7 +175,7 @@ accessible from the outside. As a developer, sooner rather than later you'll want to start interacting with `geth` and the Ethereum network via your own programs and not manually through the console. To aid this, `geth` has built-in support for a JSON-RPC based APIs ([standard APIs](https://ethereum.github.io/execution-apis/api-documentation/) -and [`geth` specific APIs](https://geth.ethereum.org/docs/rpc/server)). +and [`geth` specific APIs](https://geth.ethereum.org/docs/interacting-with-geth/rpc)). These can be exposed via HTTP, WebSockets and IPC (UNIX sockets on UNIX based platforms, and named pipes on Windows). diff --git a/cmd/checkpoint-admin/README.md b/cmd/checkpoint-admin/README.md index 7c0c657eb5cb..1067ead0564f 100644 --- a/cmd/checkpoint-admin/README.md +++ b/cmd/checkpoint-admin/README.md @@ -46,7 +46,7 @@ Deploy checkpoint oracle contract. `--signers` indicates the specified trusted s checkpoint-admin deploy --rpc --clef --signer --signers --threshold 1 ``` -It is worth noting that checkpoint-admin only supports clef as a signer for transactions and plain text(checkpoint). For more clef usage, please see the clef [tutorial](https://geth.ethereum.org/docs/clef/tutorial) . +It is worth noting that checkpoint-admin only supports clef as a signer for transactions and plain text(checkpoint). For more clef usage, please see the clef [tutorial](https://geth.ethereum.org/docs/tools/clef/tutorial) . #### Sign diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index 23f6fd277c61..aeee6f9c9e40 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -37,7 +37,7 @@ var ( Description: ` The Geth console is an interactive shell for the JavaScript runtime environment which exposes a node admin interface as well as the Ðapp JavaScript API. -See https://geth.ethereum.org/docs/interface/javascript-console.`, +See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console.`, } attachCommand = &cli.Command{ @@ -49,7 +49,7 @@ See https://geth.ethereum.org/docs/interface/javascript-console.`, Description: ` The Geth console is an interactive shell for the JavaScript runtime environment which exposes a node admin interface as well as the Ðapp JavaScript API. -See https://geth.ethereum.org/docs/interface/javascript-console. +See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console. This command allows to open a console on a running geth node.`, } @@ -61,7 +61,7 @@ This command allows to open a console on a running geth node.`, Flags: flags.Merge(nodeFlags, consoleFlags), Description: ` The JavaScript VM exposes a node admin interface as well as the Ðapp -JavaScript API. See https://geth.ethereum.org/docs/interface/javascript-console`, +JavaScript API. See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console`, } ) From 6bc68f8d94b359e08beefa2b6006e5ad003519f9 Mon Sep 17 00:00:00 2001 From: Jonathan Otto Date: Tue, 14 Mar 2023 13:41:28 -0400 Subject: [PATCH 636/715] Increase websocket frame size (from erigon rpc client) (#26883) This increases the maximum allowed message size to 32MB. Originally submitted at https://github.com/ledgerwatch/erigon/pull/2739 example block failure: https://etherscan.io/tx/0x1317d973a55cedf9b0f2df6ea48e8077dd176f5444a3423368a46d6e4db89982#internal --- rpc/websocket.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/websocket.go b/rpc/websocket.go index 0ac2a2792d5a..a6b95dd2acd3 100644 --- a/rpc/websocket.go +++ b/rpc/websocket.go @@ -38,7 +38,7 @@ const ( wsPingInterval = 30 * time.Second wsPingWriteTimeout = 5 * time.Second wsPongTimeout = 30 * time.Second - wsMessageSizeLimit = 15 * 1024 * 1024 + wsMessageSizeLimit = 32 * 1024 * 1024 ) var wsBufferPool = new(sync.Pool) From f86913bc3e9a4f2439b6c3cd4d00cb364495238c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 15 Mar 2023 14:34:36 +0100 Subject: [PATCH 637/715] cmd/devp2p, cmd/geth: add version in --help output (#26895) Not sure why this was removed, it's pretty useful to see the version also in --help. --- cmd/devp2p/main.go | 1 - cmd/geth/main.go | 1 - 2 files changed, 2 deletions(-) diff --git a/cmd/devp2p/main.go b/cmd/devp2p/main.go index 9e13d29ab72d..8461a8b9b5e2 100644 --- a/cmd/devp2p/main.go +++ b/cmd/devp2p/main.go @@ -29,7 +29,6 @@ import ( var app = flags.NewApp("go-ethereum devp2p tool") func init() { - app.HideVersion = true app.Flags = append(app.Flags, debug.Flags...) app.Before = func(ctx *cli.Context) error { flags.MigrateGlobalFlags(ctx) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 5ba070249897..a970e7652342 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -205,7 +205,6 @@ var app = flags.NewApp("the go-ethereum command line interface") func init() { // Initialize the CLI app and start Geth app.Action = geth - app.HideVersion = true // we have a command to print the version app.Copyright = "Copyright 2013-2023 The go-ethereum Authors" app.Commands = []*cli.Command{ // See chaincmd.go: From bba2a1bac5fb896e644ff6a5307419812e0f6819 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 16 Mar 2023 15:12:34 +0800 Subject: [PATCH 638/715] core: show db error-info in case of mismatched hash root (#26870) When a database failure occurs, bubble it up a into statedb, and report it in suitable places, such as during a 'bad block' report. --- core/block_validator.go | 2 +- core/state/state_object.go | 47 ++++++++------------------------------ core/state/statedb.go | 10 ++++---- core/vm/interface.go | 2 -- 4 files changed, 17 insertions(+), 44 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index db7ea3568723..2a8df7c965f8 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -113,7 +113,7 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD // Validate the state root against the received state root and throw // an error if they don't match. if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { - return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) + return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error()) } return nil } diff --git a/core/state/state_object.go b/core/state/state_object.go index 5dfd3c1b648a..7e34cba44a82 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -43,7 +43,6 @@ func (s Storage) String() (str string) { for key, value := range s { str += fmt.Sprintf("%X : %X\n", key, value) } - return } @@ -52,7 +51,6 @@ func (s Storage) Copy() Storage { for key, value := range s { cpy[key] = value } - return cpy } @@ -68,13 +66,6 @@ type stateObject struct { data types.StateAccount db *StateDB - // DB error. - // State objects are used by the consensus core and VM which are - // unable to deal with database-level errors. Any error that occurs - // during a database read is memoized here and will eventually be returned - // by StateDB.Commit. - dbErr error - // Write caches. trie Trie // storage trie, which becomes non-nil on first access code Code // contract bytecode, which gets set when code is loaded @@ -84,7 +75,7 @@ type stateObject struct { dirtyStorage Storage // Storage entries that have been modified in the current transaction execution // Cache flags. - // When an object is marked suicided it will be delete from the trie + // When an object is marked suicided it will be deleted from the trie // during the "update" phase of the state transition. dirtyCode bool // true if the code was updated suicided bool @@ -123,13 +114,6 @@ func (s *stateObject) EncodeRLP(w io.Writer) error { return rlp.Encode(w, &s.data) } -// setError remembers the first non-nil error it is called with. -func (s *stateObject) setError(err error) { - if s.dbErr == nil { - s.dbErr = err - } -} - func (s *stateObject) markSuicided() { s.suicided = true } @@ -214,7 +198,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has start := time.Now() tr, err := s.getTrie(db) if err != nil { - s.setError(err) + s.db.setError(err) return common.Hash{} } enc, err = tr.TryGet(key.Bytes()) @@ -222,7 +206,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has s.db.StorageReads += time.Since(start) } if err != nil { - s.setError(err) + s.db.setError(err) return common.Hash{} } } @@ -230,7 +214,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has if len(enc) > 0 { _, content, _, err := rlp.Split(enc) if err != nil { - s.setError(err) + s.db.setError(err) } value.SetBytes(content) } @@ -296,7 +280,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { ) tr, err := s.getTrie(db) if err != nil { - s.setError(err) + s.db.setError(err) return nil, err } // Insert all the pending updates into the trie @@ -311,7 +295,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { var v []byte if (value == common.Hash{}) { if err := tr.TryDelete(key[:]); err != nil { - s.setError(err) + s.db.setError(err) return nil, err } s.db.StorageDeleted += 1 @@ -319,7 +303,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { // Encoding []byte cannot fail, ok to ignore the error. v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) if err := tr.TryUpdate(key[:], v); err != nil { - s.setError(err) + s.db.setError(err) return nil, err } s.db.StorageUpdated += 1 @@ -351,7 +335,6 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { func (s *stateObject) updateRoot(db Database) { tr, err := s.updateTrie(db) if err != nil { - s.setError(fmt.Errorf("updateRoot (%x) error: %w", s.address, err)) return } // If nothing changed, don't bother with hashing anything @@ -372,9 +355,6 @@ func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) { if err != nil { return nil, err } - if s.dbErr != nil { - return nil, s.dbErr - } // If nothing changed, don't bother with committing anything if tr == nil { return nil, nil @@ -385,7 +365,7 @@ func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) { } root, nodes := tr.Commit(false) s.data.Root = root - return nodes, err + return nodes, nil } // AddBalance adds amount to s's balance. @@ -457,7 +437,7 @@ func (s *stateObject) Code(db Database) []byte { } code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash())) if err != nil { - s.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) + s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) } s.code = code return code @@ -475,7 +455,7 @@ func (s *stateObject) CodeSize(db Database) int { } size, err := db.ContractCodeSize(s.addrHash, common.BytesToHash(s.CodeHash())) if err != nil { - s.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err)) + s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err)) } return size } @@ -519,10 +499,3 @@ func (s *stateObject) Balance() *big.Int { func (s *stateObject) Nonce() uint64 { return s.data.Nonce } - -// Value is never called, but must be present to allow stateObject to be used -// as a vm.Account interface that also satisfies the vm.ContractRef -// interface. Interfaces are awesome. -func (s *stateObject) Value() *big.Int { - panic("Value on stateObject should never be called") -} diff --git a/core/state/statedb.go b/core/state/statedb.go index 247aef8b239c..54d5040451be 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -81,8 +81,10 @@ type StateDB struct { // DB error. // State objects are used by the consensus core and VM which are // unable to deal with database-level errors. Any error that occurs - // during a database read is memoized here and will eventually be returned - // by StateDB.Commit. + // during a database read is memoized here and will eventually be + // returned by StateDB.Commit. Notably, this error is also shared + // by all cached state objects in case the database failure occurs + // when accessing state of accounts. dbErr error // The refund counter, also used by state transitioning. @@ -187,6 +189,7 @@ func (s *StateDB) setError(err error) { } } +// Error returns the memorized database failure occurred earlier. func (s *StateDB) Error() error { return s.dbErr } @@ -478,13 +481,11 @@ func (s *StateDB) SetTransientState(addr common.Address, key, value common.Hash) if prev == value { return } - s.journal.append(transientStorageChange{ account: &addr, key: key, prevalue: prev, }) - s.setTransientState(addr, key, value) } @@ -957,6 +958,7 @@ func (s *StateDB) clearJournalAndRefund() { // Commit writes the state to the underlying in-memory trie database. func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { + // Short circuit in case any database failure occurred earlier. if s.dbErr != nil { return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) } diff --git a/core/vm/interface.go b/core/vm/interface.go index 0ee32b1dd510..b83f78307eb7 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -76,8 +76,6 @@ type StateDB interface { AddLog(*types.Log) AddPreimage(common.Hash, []byte) - - ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error } // CallContext provides a basic interface for the EVM calling conventions. The EVM From 48d1bf06780799304b96d8c0fea3cc61941da4df Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 17 Mar 2023 03:34:25 +0800 Subject: [PATCH 639/715] consensus: improve consensus engine definition (#26871) Makes clear the distinction between Finalize and FinalizedAndAssemble: - In Finalize function, a series of state operations are applied according to consensus rules. The statedb is mutated and the root hash can be checked and compared afterwards. This function should be used in block processing(receive afrom network and apply it locally) but not block generation. - In FinalizeAndAssemble function, after applying state mutations, the block is also to be assembled with the latest state root computed, updating the header. This function should be used in block generation only. --- consensus/beacon/consensus.go | 15 +++++----- consensus/clique/clique.go | 14 ++++----- consensus/consensus.go | 10 +++---- consensus/ethash/consensus.go | 11 ++++---- core/block_validator.go | 6 ++-- core/blockchain.go | 53 ++++++++++++++++++----------------- 6 files changed, 54 insertions(+), 55 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index eb5aa58ca887..b4da9b553a7b 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -326,10 +326,8 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H return nil } -// Finalize implements consensus.Engine, setting the final state on the header +// Finalize implements consensus.Engine and processes withdrawals on top. func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { - // Finalize is different with Prepare, it can be used in both block generation - // and verification. So determine the consensus rules by header type. if !beacon.IsPoSHeader(header) { beacon.ethone.Finalize(chain, header, state, txs, uncles, nil) return @@ -341,16 +339,12 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. amount = amount.Mul(amount, big.NewInt(params.GWei)) state.AddBalance(w.Address, amount) } - // The block reward is no longer handled here. It's done by the - // external consensus engine. - header.Root = state.IntermediateRoot(true) + // No block reward which is issued by consensus layer instead. } // FinalizeAndAssemble implements consensus.Engine, setting the final state and // assembling the block. func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { - // FinalizeAndAssemble is different with Prepare, it can be used in both block - // generation and verification. So determine the consensus rules by header type. if !beacon.IsPoSHeader(header) { return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts, nil) } @@ -367,6 +361,11 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea } // Finalize and assemble the block. beacon.Finalize(chain, header, state, txs, uncles, withdrawals) + + // Assign the final state root to header. + header.Root = state.IntermediateRoot(true) + + // Assemble and return the final block. return types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, trie.NewStackTrie(nil)), nil } diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 4706bbac1ca9..6c20803b2a11 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -565,12 +565,10 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header return nil } -// Finalize implements consensus.Engine, ensuring no uncles are set, nor block -// rewards given. +// Finalize implements consensus.Engine. There is no post-transaction +// consensus rules in clique, do nothing here. func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { - // No block rewards in PoA, so the state remains as is and uncles are dropped - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) - header.UncleHash = types.CalcUncleHash(nil) + // No block rewards in PoA, so the state remains as is } // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, @@ -579,11 +577,13 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * if len(withdrawals) > 0 { return nil, errors.New("clique does not support withdrawals") } - // Finalize block c.Finalize(chain, header, state, txs, uncles, nil) - // Assemble and return the final block for sealing + // Assign the final state root to header. + header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + + // Assemble and return the final block for sealing. return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil } diff --git a/consensus/consensus.go b/consensus/consensus.go index 190d5ae12c8a..a9fd8dd1cf9f 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -84,16 +84,16 @@ type Engine interface { // rules of a particular engine. The changes are executed inline. Prepare(chain ChainHeaderReader, header *types.Header) error - // Finalize runs any post-transaction state modifications (e.g. block rewards) - // but does not assemble the block. + // Finalize runs any post-transaction state modifications (e.g. block rewards + // or process withdrawals) but does not assemble the block. // - // Note: The block header and state database might be updated to reflect any - // consensus rules that happen at finalization (e.g. block rewards). + // Note: The state database might be updated to reflect any consensus rules + // that happen at finalization (e.g. block rewards). Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) // FinalizeAndAssemble runs any post-transaction state modifications (e.g. block - // rewards) and assembles the final block. + // rewards or process withdrawals) and assembles the final block. // // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index da29e16597b6..c3c06c541cab 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -598,12 +598,10 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H return nil } -// Finalize implements consensus.Engine, accumulating the block and uncle rewards, -// setting the final state on the header +// Finalize implements consensus.Engine, accumulating the block and uncle rewards. func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { - // Accumulate any block and uncle rewards and commit the final state root + // Accumulate any block and uncle rewards accumulateRewards(chain.Config(), state, header, uncles) - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) } // FinalizeAndAssemble implements consensus.Engine, accumulating the block and @@ -612,9 +610,12 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea if len(withdrawals) > 0 { return nil, errors.New("ethash does not support withdrawals") } - // Finalize block ethash.Finalize(chain, header, state, txs, uncles, nil) + + // Assign the final state root to header. + header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + // Header seems complete, assemble into a block and return return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil } diff --git a/core/block_validator.go b/core/block_validator.go index 2a8df7c965f8..bcb228830d4e 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -90,10 +90,8 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { return nil } -// ValidateState validates the various changes that happen after a state -// transition, such as amount of used gas, the receipt roots and the state root -// itself. ValidateState returns a database batch if the validation was a success -// otherwise nil and an error is returned. +// ValidateState validates the various changes that happen after a state transition, +// such as amount of used gas, the receipt roots and the state root itself. func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { header := block.Header() if block.GasUsed() != usedGas { diff --git a/core/blockchain.go b/core/blockchain.go index 1fe7d73e0087..8fc520e7760f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1752,44 +1752,45 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) } // Process block using the parent state as reference point - substart := time.Now() + pstart := time.Now() receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) atomic.StoreUint32(&followupInterrupt, 1) return it.index, err } + ptime := time.Since(pstart) - // Update the metrics touched during block processing - accountReadTimer.Update(statedb.AccountReads) // Account reads are complete, we can mark them - storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete, we can mark them - accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete, we can mark them - storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete, we can mark them - snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete, we can mark them - snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete, we can mark them - triehash := statedb.AccountHashes + statedb.StorageHashes // Save to not double count in validation - trieproc := statedb.SnapshotAccountReads + statedb.AccountReads + statedb.AccountUpdates - trieproc += statedb.SnapshotStorageReads + statedb.StorageReads + statedb.StorageUpdates - - blockExecutionTimer.Update(time.Since(substart) - trieproc - triehash) - - // Validate the state using the default validator - substart = time.Now() + vstart := time.Now() if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { bc.reportBlock(block, receipts, err) atomic.StoreUint32(&followupInterrupt, 1) return it.index, err } - proctime := time.Since(start) - - // Update the metrics touched during block validation - accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete, we can mark them - storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete, we can mark them - blockValidationTimer.Update(time.Since(substart) - (statedb.AccountHashes + statedb.StorageHashes - triehash)) + vtime := time.Since(vstart) + proctime := time.Since(start) // processing + validation + + // Update the metrics touched during block processing and validation + accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) + storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) + snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) + snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) + accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) + storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) + accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) + storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation) + triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing + trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update + trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read + trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read + blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing + blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation // Write the block to the chain and get the status. - substart = time.Now() - var status WriteStatus + var ( + wstart = time.Now() + status WriteStatus + ) if !setHead { // Don't set the head, only insert the block err = bc.writeBlockWithState(block, receipts, statedb) @@ -1804,9 +1805,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them - triedbCommitTimer.Update(statedb.TrieDBCommits) // Triedb commits are complete, we can mark them + triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them - blockWriteTimer.Update(time.Since(substart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) + blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) blockInsertTimer.UpdateSince(start) // Report the import stats before returning the various results From d8066dcde801baed8ebc1605bd3bfaefa781e8e3 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 16 Mar 2023 20:35:36 +0100 Subject: [PATCH 640/715] eth/catalyst: increase update consensus timeout (#26840) Increases the time between consensus updates that we give the CL before we start warning the user. --- eth/catalyst/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index fc7529c8f5d7..9077f20bffcc 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -72,7 +72,7 @@ const ( // beaconUpdateConsensusTimeout is the max time allowed for a beacon client // to send a consensus update before it's considered offline and the user is // warned. - beaconUpdateConsensusTimeout = 30 * time.Second + beaconUpdateConsensusTimeout = 2 * time.Minute // beaconUpdateWarnFrequency is the frequency at which to warn the user that // the beacon client is offline. From f73365738309d9b3249efca9c1492856bf6e7848 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Thu, 16 Mar 2023 15:53:39 -0700 Subject: [PATCH 641/715] internal/ethapi: avoid int overflow in GetTransactionReceipt (#26911) --- internal/ethapi/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 93a2d1264d32..0cf29e5fe642 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1626,7 +1626,7 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common. if err != nil { return nil, err } - if len(receipts) <= int(index) { + if uint64(len(receipts)) <= index { return nil, nil } receipt := receipts[index] From b7bfbc1e649cecc9fa11ad55b3943272a919c24b Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Fri, 17 Mar 2023 03:19:51 -0700 Subject: [PATCH 642/715] trie, accounts/abi: add error-checks (#26914) --- accounts/abi/abi.go | 5 ++++- trie/stacktrie.go | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 841d3c6cb676..62b860e18c77 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -246,7 +246,10 @@ func UnpackRevert(data []byte) (string, error) { if !bytes.Equal(data[:4], revertSelector) { return "", errors.New("invalid data for unpacking") } - typ, _ := NewType("string", "", nil) + typ, err := NewType("string", "", nil) + if err != nil { + return "", err + } unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:]) if err != nil { return "", err diff --git a/trie/stacktrie.go b/trie/stacktrie.go index e7b3171af6e8..83034e29a530 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -144,7 +144,9 @@ func (st *StackTrie) unmarshalBinary(r io.Reader) error { Val []byte Key []byte } - gob.NewDecoder(r).Decode(&dec) + if err := gob.NewDecoder(r).Decode(&dec); err != nil { + return err + } st.owner = dec.Owner st.nodeType = dec.NodeType st.val = dec.Val @@ -158,7 +160,9 @@ func (st *StackTrie) unmarshalBinary(r io.Reader) error { continue } var child StackTrie - child.unmarshalBinary(r) + if err := child.unmarshalBinary(r); err != nil { + return err + } st.children[i] = &child } return nil From 58d0f6440ba82a0cbf327ca77b7cd795c2d687c6 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 17 Mar 2023 06:51:55 -0400 Subject: [PATCH 643/715] rlp: support for uint256 (#26898) This adds built-in support in package rlp for encoding, decoding and generating code dealing with uint256.Int. --------- Co-authored-by: Felix Lange --- rlp/decode.go | 64 +++++++++++++++++++++++++++++ rlp/decode_test.go | 42 +++++++++++++++++++ rlp/encbuffer.go | 25 +++++++++++ rlp/encode.go | 21 ++++++++++ rlp/encode_test.go | 49 ++++++++++++++++++++++ rlp/rlpgen/gen.go | 51 ++++++++++++++++++++++- rlp/rlpgen/gen_test.go | 2 +- rlp/rlpgen/testdata/uint256.in.txt | 10 +++++ rlp/rlpgen/testdata/uint256.out.txt | 44 ++++++++++++++++++++ rlp/rlpgen/types.go | 10 +++++ 10 files changed, 316 insertions(+), 2 deletions(-) create mode 100644 rlp/rlpgen/testdata/uint256.in.txt create mode 100644 rlp/rlpgen/testdata/uint256.out.txt diff --git a/rlp/decode.go b/rlp/decode.go index c9b265241455..c9b50e8c1879 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -29,6 +29,7 @@ import ( "sync" "github.com/ethereum/go-ethereum/rlp/internal/rlpstruct" + "github.com/holiman/uint256" ) //lint:ignore ST1012 EOL is not an error. @@ -52,6 +53,7 @@ var ( errUintOverflow = errors.New("rlp: uint overflow") errNoPointer = errors.New("rlp: interface given to Decode must be a pointer") errDecodeIntoNil = errors.New("rlp: pointer given to Decode must not be nil") + errUint256Large = errors.New("rlp: value too large for uint256") streamPool = sync.Pool{ New: func() interface{} { return new(Stream) }, @@ -148,6 +150,7 @@ func addErrorContext(err error, ctx string) error { var ( decoderInterface = reflect.TypeOf(new(Decoder)).Elem() bigInt = reflect.TypeOf(big.Int{}) + u256Int = reflect.TypeOf(uint256.Int{}) ) func makeDecoder(typ reflect.Type, tags rlpstruct.Tags) (dec decoder, err error) { @@ -159,6 +162,10 @@ func makeDecoder(typ reflect.Type, tags rlpstruct.Tags) (dec decoder, err error) return decodeBigInt, nil case typ.AssignableTo(bigInt): return decodeBigIntNoPtr, nil + case typ == reflect.PtrTo(u256Int): + return decodeU256, nil + case typ == u256Int: + return decodeU256NoPtr, nil case kind == reflect.Ptr: return makePtrDecoder(typ, tags) case reflect.PtrTo(typ).Implements(decoderInterface): @@ -235,6 +242,24 @@ func decodeBigInt(s *Stream, val reflect.Value) error { return nil } +func decodeU256NoPtr(s *Stream, val reflect.Value) error { + return decodeU256(s, val.Addr()) +} + +func decodeU256(s *Stream, val reflect.Value) error { + i := val.Interface().(*uint256.Int) + if i == nil { + i = new(uint256.Int) + val.Set(reflect.ValueOf(i)) + } + + err := s.ReadUint256(i) + if err != nil { + return wrapStreamError(err, val.Type()) + } + return nil +} + func makeListDecoder(typ reflect.Type, tag rlpstruct.Tags) (decoder, error) { etype := typ.Elem() if etype.Kind() == reflect.Uint8 && !reflect.PtrTo(etype).Implements(decoderInterface) { @@ -863,6 +888,45 @@ func (s *Stream) decodeBigInt(dst *big.Int) error { return nil } +// ReadUint256 decodes the next value as a uint256. +func (s *Stream) ReadUint256(dst *uint256.Int) error { + var buffer []byte + kind, size, err := s.Kind() + switch { + case err != nil: + return err + case kind == List: + return ErrExpectedString + case kind == Byte: + buffer = s.uintbuf[:1] + buffer[0] = s.byteval + s.kind = -1 // re-arm Kind + case size == 0: + // Avoid zero-length read. + s.kind = -1 + case size <= uint64(len(s.uintbuf)): + // All possible uint256 values fit into s.uintbuf. + buffer = s.uintbuf[:size] + if err := s.readFull(buffer); err != nil { + return err + } + // Reject inputs where single byte encoding should have been used. + if size == 1 && buffer[0] < 128 { + return ErrCanonSize + } + default: + return errUint256Large + } + + // Reject leading zero bytes. + if len(buffer) > 0 && buffer[0] == 0 { + return ErrCanonInt + } + // Set the integer bytes. + dst.SetBytes(buffer) + return nil +} + // Decode decodes a value and stores the result in the value pointed // to by val. Please see the documentation for the Decode function // to learn about the decoding rules. diff --git a/rlp/decode_test.go b/rlp/decode_test.go index dbcfcffed1a1..07d9c579a6a4 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -28,6 +28,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common/math" + "github.com/holiman/uint256" ) func TestStreamKind(t *testing.T) { @@ -468,6 +469,10 @@ var ( veryVeryBigInt = new(big.Int).Exp(veryBigInt, big.NewInt(8), nil) ) +var ( + veryBigInt256, _ = uint256.FromBig(veryBigInt) +) + var decodeTests = []decodeTest{ // booleans {input: "01", ptr: new(bool), value: true}, @@ -541,11 +546,27 @@ var decodeTests = []decodeTest{ {input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*big.Int), value: veryBigInt}, {input: "B848FFFFFFFFFFFFFFFFF800000000000000001BFFFFFFFFFFFFFFFFC8000000000000000045FFFFFFFFFFFFFFFFC800000000000000001BFFFFFFFFFFFFFFFFF8000000000000000001", ptr: new(*big.Int), value: veryVeryBigInt}, {input: "10", ptr: new(big.Int), value: *big.NewInt(16)}, // non-pointer also works + + // big int errors {input: "C0", ptr: new(*big.Int), error: "rlp: expected input string or byte for *big.Int"}, {input: "00", ptr: new(*big.Int), error: "rlp: non-canonical integer (leading zero bytes) for *big.Int"}, {input: "820001", ptr: new(*big.Int), error: "rlp: non-canonical integer (leading zero bytes) for *big.Int"}, {input: "8105", ptr: new(*big.Int), error: "rlp: non-canonical size information for *big.Int"}, + // uint256 + {input: "80", ptr: new(*uint256.Int), value: uint256.NewInt(0)}, + {input: "01", ptr: new(*uint256.Int), value: uint256.NewInt(1)}, + {input: "88FFFFFFFFFFFFFFFF", ptr: new(*uint256.Int), value: uint256.NewInt(math.MaxUint64)}, + {input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*uint256.Int), value: veryBigInt256}, + {input: "10", ptr: new(uint256.Int), value: *uint256.NewInt(16)}, // non-pointer also works + + // uint256 errors + {input: "C0", ptr: new(*uint256.Int), error: "rlp: expected input string or byte for *uint256.Int"}, + {input: "00", ptr: new(*uint256.Int), error: "rlp: non-canonical integer (leading zero bytes) for *uint256.Int"}, + {input: "820001", ptr: new(*uint256.Int), error: "rlp: non-canonical integer (leading zero bytes) for *uint256.Int"}, + {input: "8105", ptr: new(*uint256.Int), error: "rlp: non-canonical size information for *uint256.Int"}, + {input: "A1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00", ptr: new(*uint256.Int), error: "rlp: value too large for uint256"}, + // structs { input: "C50583343434", @@ -1223,6 +1244,27 @@ func BenchmarkDecodeBigInts(b *testing.B) { } } +func BenchmarkDecodeU256Ints(b *testing.B) { + ints := make([]*uint256.Int, 200) + for i := range ints { + ints[i], _ = uint256.FromBig(math.BigPow(2, int64(i))) + } + enc, err := EncodeToBytes(ints) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(enc))) + b.ReportAllocs() + b.ResetTimer() + + var out []*uint256.Int + for i := 0; i < b.N; i++ { + if err := DecodeBytes(enc, &out); err != nil { + b.Fatal(err) + } + } +} + func encodeTestSlice(n uint) []byte { s := make([]uint, n) for i := uint(0); i < n; i++ { diff --git a/rlp/encbuffer.go b/rlp/encbuffer.go index d2c6d93bcaea..9ac4fcb2cabc 100644 --- a/rlp/encbuffer.go +++ b/rlp/encbuffer.go @@ -17,10 +17,13 @@ package rlp import ( + "encoding/binary" "io" "math/big" "reflect" "sync" + + "github.com/holiman/uint256" ) type encBuffer struct { @@ -169,6 +172,23 @@ func (w *encBuffer) writeBigInt(i *big.Int) { } } +// writeUint256 writes z as an integer. +func (w *encBuffer) writeUint256(z *uint256.Int) { + bitlen := z.BitLen() + if bitlen <= 64 { + w.writeUint64(z.Uint64()) + return + } + nBytes := byte((bitlen + 7) / 8) + var b [33]byte + binary.BigEndian.PutUint64(b[1:9], z[3]) + binary.BigEndian.PutUint64(b[9:17], z[2]) + binary.BigEndian.PutUint64(b[17:25], z[1]) + binary.BigEndian.PutUint64(b[25:33], z[0]) + b[32-nBytes] = 0x80 + nBytes + w.str = append(w.str, b[32-nBytes:]...) +} + // list adds a new list header to the header stack. It returns the index of the header. // Call listEnd with this index after encoding the content of the list. func (buf *encBuffer) list() int { @@ -376,6 +396,11 @@ func (w EncoderBuffer) WriteBigInt(i *big.Int) { w.buf.writeBigInt(i) } +// WriteUint256 encodes uint256.Int as an RLP string. +func (w EncoderBuffer) WriteUint256(i *uint256.Int) { + w.buf.writeUint256(i) +} + // WriteBytes encodes b as an RLP string. func (w EncoderBuffer) WriteBytes(b []byte) { w.buf.writeBytes(b) diff --git a/rlp/encode.go b/rlp/encode.go index a377a1ef4c99..3fac0bd2d3c2 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -24,6 +24,7 @@ import ( "reflect" "github.com/ethereum/go-ethereum/rlp/internal/rlpstruct" + "github.com/holiman/uint256" ) var ( @@ -144,6 +145,10 @@ func makeWriter(typ reflect.Type, ts rlpstruct.Tags) (writer, error) { return writeBigIntPtr, nil case typ.AssignableTo(bigInt): return writeBigIntNoPtr, nil + case typ == reflect.PtrTo(u256Int): + return writeU256IntPtr, nil + case typ == u256Int: + return writeU256IntNoPtr, nil case kind == reflect.Ptr: return makePtrWriter(typ, ts) case reflect.PtrTo(typ).Implements(encoderInterface): @@ -206,6 +211,22 @@ func writeBigIntNoPtr(val reflect.Value, w *encBuffer) error { return nil } +func writeU256IntPtr(val reflect.Value, w *encBuffer) error { + ptr := val.Interface().(*uint256.Int) + if ptr == nil { + w.str = append(w.str, 0x80) + return nil + } + w.writeUint256(ptr) + return nil +} + +func writeU256IntNoPtr(val reflect.Value, w *encBuffer) error { + i := val.Interface().(uint256.Int) + w.writeUint256(&i) + return nil +} + func writeBytes(val reflect.Value, w *encBuffer) error { w.writeBytes(val.Bytes()) return nil diff --git a/rlp/encode_test.go b/rlp/encode_test.go index 82c490a80275..02be47d0ef1b 100644 --- a/rlp/encode_test.go +++ b/rlp/encode_test.go @@ -27,6 +27,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common/math" + "github.com/holiman/uint256" ) type testEncoder struct { @@ -147,6 +148,30 @@ var encTests = []encTest{ {val: big.NewInt(-1), error: "rlp: cannot encode negative big.Int"}, {val: *big.NewInt(-1), error: "rlp: cannot encode negative big.Int"}, + // uint256 + {val: uint256.NewInt(0), output: "80"}, + {val: uint256.NewInt(1), output: "01"}, + {val: uint256.NewInt(127), output: "7F"}, + {val: uint256.NewInt(128), output: "8180"}, + {val: uint256.NewInt(256), output: "820100"}, + {val: uint256.NewInt(1024), output: "820400"}, + {val: uint256.NewInt(0xFFFFFF), output: "83FFFFFF"}, + {val: uint256.NewInt(0xFFFFFFFF), output: "84FFFFFFFF"}, + {val: uint256.NewInt(0xFFFFFFFFFF), output: "85FFFFFFFFFF"}, + {val: uint256.NewInt(0xFFFFFFFFFFFF), output: "86FFFFFFFFFFFF"}, + {val: uint256.NewInt(0xFFFFFFFFFFFFFF), output: "87FFFFFFFFFFFFFF"}, + { + val: new(uint256.Int).SetBytes(unhex("102030405060708090A0B0C0D0E0F2")), + output: "8F102030405060708090A0B0C0D0E0F2", + }, + { + val: new(uint256.Int).SetBytes(unhex("0100020003000400050006000700080009000A000B000C000D000E01")), + output: "9C0100020003000400050006000700080009000A000B000C000D000E01", + }, + // non-pointer uint256.Int + {val: *uint256.NewInt(0), output: "80"}, + {val: *uint256.NewInt(0xFFFFFF), output: "83FFFFFF"}, + // byte arrays {val: [0]byte{}, output: "80"}, {val: [1]byte{0}, output: "00"}, @@ -256,6 +281,12 @@ var encTests = []encTest{ output: "F90200CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376CF84617364668471776572847A786376", }, + // Non-byte arrays are encoded as lists. + // Note that it is important to test [4]uint64 specifically, + // because that's the underlying type of uint256.Int. + {val: [4]uint32{1, 2, 3, 4}, output: "C401020304"}, + {val: [4]uint64{1, 2, 3, 4}, output: "C401020304"}, + // RawValue {val: RawValue(unhex("01")), output: "01"}, {val: RawValue(unhex("82FFFF")), output: "82FFFF"}, @@ -301,6 +332,7 @@ var encTests = []encTest{ {val: (*[]byte)(nil), output: "80"}, {val: (*[10]byte)(nil), output: "80"}, {val: (*big.Int)(nil), output: "80"}, + {val: (*uint256.Int)(nil), output: "80"}, {val: (*[]string)(nil), output: "C0"}, {val: (*[10]string)(nil), output: "C0"}, {val: (*[]interface{})(nil), output: "C0"}, @@ -509,6 +541,23 @@ func BenchmarkEncodeBigInts(b *testing.B) { } } +func BenchmarkEncodeU256Ints(b *testing.B) { + ints := make([]*uint256.Int, 200) + for i := range ints { + ints[i], _ = uint256.FromBig(math.BigPow(2, int64(i))) + } + out := bytes.NewBuffer(make([]byte, 0, 4096)) + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + out.Reset() + if err := Encode(out, ints); err != nil { + b.Fatal(err) + } + } +} + func BenchmarkEncodeConcurrentInterface(b *testing.B) { type struct1 struct { A string diff --git a/rlp/rlpgen/gen.go b/rlp/rlpgen/gen.go index 1deb5a93c2a3..0c6586482698 100644 --- a/rlp/rlpgen/gen.go +++ b/rlp/rlpgen/gen.go @@ -283,7 +283,7 @@ func (op byteArrayOp) genDecode(ctx *genContext) (string, string) { return resultV, b.String() } -// bigIntNoPtrOp handles non-pointer big.Int. +// bigIntOp handles big.Int. // This exists because big.Int has it's own decoder operation on rlp.Stream, // but the decode method returns *big.Int, so it needs to be dereferenced. type bigIntOp struct { @@ -330,6 +330,49 @@ func (op bigIntOp) genDecode(ctx *genContext) (string, string) { return result, b.String() } +// uint256Op handles "github.com/holiman/uint256".Int +type uint256Op struct { + pointer bool +} + +func (op uint256Op) genWrite(ctx *genContext, v string) string { + var b bytes.Buffer + + dst := v + if !op.pointer { + dst = "&" + v + } + fmt.Fprintf(&b, "w.WriteUint256(%s)\n", dst) + + // Wrap with nil check. + if op.pointer { + code := b.String() + b.Reset() + fmt.Fprintf(&b, "if %s == nil {\n", v) + fmt.Fprintf(&b, " w.Write(rlp.EmptyString)") + fmt.Fprintf(&b, "} else {\n") + fmt.Fprint(&b, code) + fmt.Fprintf(&b, "}\n") + } + + return b.String() +} + +func (op uint256Op) genDecode(ctx *genContext) (string, string) { + ctx.addImport("github.com/holiman/uint256") + + var b bytes.Buffer + resultV := ctx.temp() + fmt.Fprintf(&b, "var %s uint256.Int\n", resultV) + fmt.Fprintf(&b, "if err := dec.ReadUint256(&%s); err != nil { return err }\n", resultV) + + result := resultV + if op.pointer { + result = "&" + resultV + } + return result, b.String() +} + // encoderDecoderOp handles rlp.Encoder and rlp.Decoder. // In order to be used with this, the type must implement both interfaces. // This restriction may be lifted in the future by creating separate ops for @@ -635,6 +678,9 @@ func (bctx *buildContext) makeOp(name *types.Named, typ types.Type, tags rlpstru if isBigInt(typ) { return bigIntOp{}, nil } + if isUint256(typ) { + return uint256Op{}, nil + } if typ == bctx.rawValueType { return bctx.makeRawValueOp(), nil } @@ -647,6 +693,9 @@ func (bctx *buildContext) makeOp(name *types.Named, typ types.Type, tags rlpstru if isBigInt(typ.Elem()) { return bigIntOp{pointer: true}, nil } + if isUint256(typ.Elem()) { + return uint256Op{pointer: true}, nil + } // Encoder/Decoder interfaces. if bctx.isEncoder(typ) { if bctx.isDecoder(typ) { diff --git a/rlp/rlpgen/gen_test.go b/rlp/rlpgen/gen_test.go index 241c34b6dfaa..ff3b8385ae16 100644 --- a/rlp/rlpgen/gen_test.go +++ b/rlp/rlpgen/gen_test.go @@ -47,7 +47,7 @@ func init() { } } -var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint"} +var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256"} func TestOutput(t *testing.T) { for _, test := range tests { diff --git a/rlp/rlpgen/testdata/uint256.in.txt b/rlp/rlpgen/testdata/uint256.in.txt new file mode 100644 index 000000000000..ed16e0a7882f --- /dev/null +++ b/rlp/rlpgen/testdata/uint256.in.txt @@ -0,0 +1,10 @@ +// -*- mode: go -*- + +package test + +import "github.com/holiman/uint256" + +type Test struct { + Int *uint256.Int + IntNoPtr uint256.Int +} diff --git a/rlp/rlpgen/testdata/uint256.out.txt b/rlp/rlpgen/testdata/uint256.out.txt new file mode 100644 index 000000000000..5e6d3ed992cd --- /dev/null +++ b/rlp/rlpgen/testdata/uint256.out.txt @@ -0,0 +1,44 @@ +package test + +import "github.com/ethereum/go-ethereum/rlp" +import "github.com/holiman/uint256" +import "io" + +func (obj *Test) EncodeRLP(_w io.Writer) error { + w := rlp.NewEncoderBuffer(_w) + _tmp0 := w.List() + if obj.Int == nil { + w.Write(rlp.EmptyString) + } else { + w.WriteUint256(obj.Int) + } + w.WriteUint256(&obj.IntNoPtr) + w.ListEnd(_tmp0) + return w.Flush() +} + +func (obj *Test) DecodeRLP(dec *rlp.Stream) error { + var _tmp0 Test + { + if _, err := dec.List(); err != nil { + return err + } + // Int: + var _tmp1 uint256.Int + if err := dec.ReadUint256(&_tmp1); err != nil { + return err + } + _tmp0.Int = &_tmp1 + // IntNoPtr: + var _tmp2 uint256.Int + if err := dec.ReadUint256(&_tmp2); err != nil { + return err + } + _tmp0.IntNoPtr = _tmp2 + if err := dec.ListEnd(); err != nil { + return err + } + } + *obj = _tmp0 + return nil +} diff --git a/rlp/rlpgen/types.go b/rlp/rlpgen/types.go index 19694262e54e..ea7dc96d8813 100644 --- a/rlp/rlpgen/types.go +++ b/rlp/rlpgen/types.go @@ -97,6 +97,16 @@ func isBigInt(typ types.Type) bool { return name.Pkg().Path() == "math/big" && name.Name() == "Int" } +// isUint256 checks whether 'typ' is "github.com/holiman/uint256".Int. +func isUint256(typ types.Type) bool { + named, ok := typ.(*types.Named) + if !ok { + return false + } + name := named.Obj() + return name.Pkg().Path() == "github.com/holiman/uint256" && name.Name() == "Int" +} + // isByte checks whether the underlying type of 'typ' is uint8. func isByte(typ types.Type) bool { basic, ok := resolveUnderlying(typ).(*types.Basic) From ee8e83fa5f6cb261dad2ed0a7bbcde4930c41e6c Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Fri, 17 Mar 2023 11:06:06 -0700 Subject: [PATCH 644/715] eth: fix output file permissions in admin_exportChain (#26912) * api: Use 0700 file permissions for ExportChain * change perm to 0644 * Update api.go --------- Co-authored-by: Felix Lange --- eth/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/api.go b/eth/api.go index cd6510ccf9a2..66df927ac641 100644 --- a/eth/api.go +++ b/eth/api.go @@ -161,7 +161,7 @@ func (api *AdminAPI) ExportChain(file string, first *uint64, last *uint64) (bool return false, errors.New("location would overwrite an existing file") } // Make sure we can create the file to export into - out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) + out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { return false, err } From 81b0aa0cc705e5583ba3f03ff7f3dba5965f7d49 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 20 Mar 2023 09:09:35 +0100 Subject: [PATCH 645/715] trie: reduce unit test time (#26918) --- trie/proof_test.go | 25 +++++++++++++++++++------ trie/sync_test.go | 1 + trie/trie_test.go | 6 +++--- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/trie/proof_test.go b/trie/proof_test.go index 5796a308930e..6b23bcdb27d8 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -20,6 +20,7 @@ import ( "bytes" crand "crypto/rand" "encoding/binary" + "fmt" mrand "math/rand" "sort" "testing" @@ -30,6 +31,24 @@ import ( "github.com/ethereum/go-ethereum/ethdb/memorydb" ) +// Prng is a pseudo random number generator seeded by strong randomness. +// The randomness is printed on startup in order to make failures reproducible. +var prng = initRnd() + +func initRnd() *mrand.Rand { + var seed [8]byte + crand.Read(seed[:]) + rnd := mrand.New(mrand.NewSource(int64(binary.LittleEndian.Uint64(seed[:])))) + fmt.Printf("Seed: %x\n", seed) + return rnd +} + +func randBytes(n int) []byte { + r := make([]byte, n) + prng.Read(r) + return r +} + // makeProvers creates Merkle trie provers based on different implementations to // test all variations. func makeProvers(trie *Trie) []func(key []byte) *memorydb.Database { @@ -1041,12 +1060,6 @@ func randomTrie(n int) (*Trie, map[string]*kv) { return trie, vals } -func randBytes(n int) []byte { - r := make([]byte, n) - crand.Read(r) - return r -} - func nonRandomTrie(n int) (*Trie, map[string]*kv) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := make(map[string]*kv) diff --git a/trie/sync_test.go b/trie/sync_test.go index fc871a22c80a..8fec378333da 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -434,6 +434,7 @@ func TestDuplicateAvoidanceSync(t *testing.T) { // Tests that at any point in time during a sync, only complete sub-tries are in // the database. func TestIncompleteSync(t *testing.T) { + t.Parallel() // Create a random trie to copy srcDb, srcTrie, _ := makeTestTrie() diff --git a/trie/trie_test.go b/trie/trie_test.go index e415937073ea..089bb44a9741 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -18,7 +18,6 @@ package trie import ( "bytes" - crand "crypto/rand" "encoding/binary" "errors" "fmt" @@ -1146,13 +1145,14 @@ func deleteString(trie *Trie, k string) { func TestDecodeNode(t *testing.T) { t.Parallel() + var ( hash = make([]byte, 20) elems = make([]byte, 20) ) for i := 0; i < 5000000; i++ { - crand.Read(hash) - crand.Read(elems) + prng.Read(hash) + prng.Read(elems) decodeNode(hash, elems) } } From 80ff0b4e6a1b3059195ad7949a2e5dbf12065592 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Mon, 20 Mar 2023 16:12:24 +0800 Subject: [PATCH 646/715] core/txpool: use atomic int added in go1.19 (#26913) Makes use of atomic.Uint64 instead of atomic by pointer --- core/txpool/list.go | 15 +++++------ core/txpool/txpool.go | 3 +-- core/txpool/txpool2_test.go | 6 ++--- core/txpool/txpool_test.go | 52 +++++++++++++++++++++---------------- 4 files changed, 39 insertions(+), 37 deletions(-) diff --git a/core/txpool/list.go b/core/txpool/list.go index 724bb6caca99..639d69bcbed4 100644 --- a/core/txpool/list.go +++ b/core/txpool/list.go @@ -508,10 +508,7 @@ func (h *priceHeap) Pop() interface{} { // the floating heap is better. When baseFee is decreasing they behave similarly. type pricedList struct { // Number of stale price points to (re-heap trigger). - // This field is accessed atomically, and must be the first field - // to ensure it has correct alignment for atomic.AddInt64. - // See https://golang.org/pkg/sync/atomic/#pkg-note-BUG. - stales int64 + stales atomic.Int64 all *lookup // Pointer to the map of all transactions urgent, floating priceHeap // Heaps of prices of all the stored **remote** transactions @@ -545,7 +542,7 @@ func (l *pricedList) Put(tx *types.Transaction, local bool) { // the heap if a large enough ratio of transactions go stale. func (l *pricedList) Removed(count int) { // Bump the stale counter, but exit if still too low (< 25%) - stales := atomic.AddInt64(&l.stales, int64(count)) + stales := l.stales.Add(int64(count)) if int(stales) <= (len(l.urgent.list)+len(l.floating.list))/4 { return } @@ -570,7 +567,7 @@ func (l *pricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool { for len(h.list) > 0 { head := h.list[0] if l.all.GetRemote(head.Hash()) == nil { // Removed or migrated - atomic.AddInt64(&l.stales, -1) + l.stales.Add(-1) heap.Pop(h) continue } @@ -597,7 +594,7 @@ func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) { // Discard stale transactions if found during cleanup tx := heap.Pop(&l.urgent).(*types.Transaction) if l.all.GetRemote(tx.Hash()) == nil { // Removed or migrated - atomic.AddInt64(&l.stales, -1) + l.stales.Add(-1) continue } // Non stale transaction found, move to floating heap @@ -610,7 +607,7 @@ func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) { // Discard stale transactions if found during cleanup tx := heap.Pop(&l.floating).(*types.Transaction) if l.all.GetRemote(tx.Hash()) == nil { // Removed or migrated - atomic.AddInt64(&l.stales, -1) + l.stales.Add(-1) continue } // Non stale transaction found, discard it @@ -633,7 +630,7 @@ func (l *pricedList) Reheap() { l.reheapMu.Lock() defer l.reheapMu.Unlock() start := time.Now() - atomic.StoreInt64(&l.stales, 0) + l.stales.Store(0) l.urgent.list = make([]*types.Transaction, 0, l.all.RemoteCount()) l.all.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool { l.urgent.list = append(l.urgent.list, tx) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index ad556f39fbb2..cc673ccc10eb 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -23,7 +23,6 @@ import ( "math/big" "sort" "sync" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -383,7 +382,7 @@ func (pool *TxPool) loop() { pool.mu.RLock() pending, queued := pool.stats() pool.mu.RUnlock() - stales := int(atomic.LoadInt64(&pool.priced.stales)) + stales := int(pool.priced.stales.Load()) if pending != prevPending || queued != prevQueued || stales != prevStales { log.Debug("Transaction pool status report", "executable", pending, "queued", queued, "stales", stales) diff --git a/core/txpool/txpool2_test.go b/core/txpool/txpool2_test.go index 20d6dd713a95..6d84975d83f9 100644 --- a/core/txpool/txpool2_test.go +++ b/core/txpool/txpool2_test.go @@ -79,7 +79,7 @@ func TestTransactionFutureAttack(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalQueue = 100 config.GlobalSlots = 100 @@ -115,7 +115,7 @@ func TestTransactionFuture1559(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) defer pool.Stop() @@ -147,7 +147,7 @@ func TestTransactionZAttack(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) defer pool.Stop() // Create a number of test accounts, fund them and make transactions diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index c4c62db2d6da..7771c5f7cda1 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -59,15 +59,21 @@ func init() { } type testBlockChain struct { - gasLimit uint64 // must be first field for 64 bit alignment (atomic access) + gasLimit atomic.Uint64 statedb *state.StateDB chainHeadFeed *event.Feed } +func newTestBlockChain(gasLimit uint64, statedb *state.StateDB, chainHeadFeed *event.Feed) *testBlockChain { + bc := testBlockChain{statedb: statedb, chainHeadFeed: new(event.Feed)} + bc.gasLimit.Store(gasLimit) + return &bc +} + func (bc *testBlockChain) CurrentBlock() *types.Header { return &types.Header{ Number: new(big.Int), - GasLimit: atomic.LoadUint64(&bc.gasLimit), + GasLimit: bc.gasLimit.Load(), } } @@ -121,7 +127,7 @@ func setupPool() (*TxPool, *ecdsa.PrivateKey) { func setupPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateKey) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{10000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(10000000, statedb, new(event.Feed)) key, _ := crypto.GenerateKey() pool := NewTxPool(testTxPoolConfig, config, blockchain) @@ -236,7 +242,7 @@ func TestStateChangeDuringReset(t *testing.T) { // setup pool with 2 transaction in it statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether)) - blockchain := &testChain{&testBlockChain{1000000000, statedb, new(event.Feed)}, address, &trigger} + blockchain := &testChain{newTestBlockChain(1000000000, statedb, new(event.Feed)), address, &trigger} tx0 := transaction(0, 100000, key) tx1 := transaction(1, 100000, key) @@ -430,7 +436,7 @@ func TestChainFork(t *testing.T) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.AddBalance(addr, big.NewInt(100000000000000)) - pool.chain = &testBlockChain{1000000, statedb, new(event.Feed)} + pool.chain = newTestBlockChain(1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) } resetState() @@ -459,7 +465,7 @@ func TestDoubleNonce(t *testing.T) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb.AddBalance(addr, big.NewInt(100000000000000)) - pool.chain = &testBlockChain{1000000, statedb, new(event.Feed)} + pool.chain = newTestBlockChain(1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) } resetState() @@ -629,7 +635,7 @@ func TestDropping(t *testing.T) { t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 4) } // Reduce the block gas limit, check that invalidated transactions are dropped - atomic.StoreUint64(&pool.chain.(*testBlockChain).gasLimit, 100) + pool.chain.(*testBlockChain).gasLimit.Store(100) <-pool.requestReset(nil, nil) if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { @@ -657,7 +663,7 @@ func TestPostponing(t *testing.T) { // Create the pool to test the postponing with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -869,7 +875,7 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) { // Create the pool to test the limit enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.NoLocals = nolocals @@ -961,7 +967,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { // Create the pool to test the non-expiration enforcement statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.Lifetime = time.Second @@ -1146,7 +1152,7 @@ func TestPendingGlobalLimiting(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalSlots = config.AccountSlots * 10 @@ -1248,7 +1254,7 @@ func TestCapClearsFromAll(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.AccountSlots = 2 @@ -1282,7 +1288,7 @@ func TestPendingMinimumAllowance(t *testing.T) { // Create the pool to test the limit enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalSlots = 1 @@ -1330,7 +1336,7 @@ func TestRepricing(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -1578,7 +1584,7 @@ func TestRepricingKeepsLocals(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain) defer pool.Stop() @@ -1651,7 +1657,7 @@ func TestUnderpricing(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalSlots = 2 @@ -1765,7 +1771,7 @@ func TestStableUnderpricing(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalSlots = 128 @@ -1997,7 +2003,7 @@ func TestDeduplication(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -2063,7 +2069,7 @@ func TestReplacement(t *testing.T) { // Create the pool to test the pricing enforcement with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -2268,7 +2274,7 @@ func testJournaling(t *testing.T, nolocals bool) { // Create the original pool to inject transaction into the journal statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.NoLocals = nolocals @@ -2310,7 +2316,7 @@ func testJournaling(t *testing.T, nolocals bool) { // Terminate the old pool, bump the local nonce, create a new pool and ensure relevant transaction survive pool.Stop() statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) - blockchain = &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain = newTestBlockChain(1000000, statedb, new(event.Feed)) pool = NewTxPool(config, params.TestChainConfig, blockchain) @@ -2337,7 +2343,7 @@ func testJournaling(t *testing.T, nolocals bool) { pool.Stop() statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) - blockchain = &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain = newTestBlockChain(1000000, statedb, new(event.Feed)) pool = NewTxPool(config, params.TestChainConfig, blockchain) pending, queued = pool.Stats() @@ -2366,7 +2372,7 @@ func TestStatusCheck(t *testing.T) { // Create the pool to test the status retrievals with statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{1000000, statedb, new(event.Feed)} + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() From 5d23d21fffa8d11e599d8e482323c321a88658f4 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 20 Mar 2023 12:38:34 +0100 Subject: [PATCH 647/715] params: schedule shanghai fork on mainnet (#26908) Schedules the shanghai hardfork on timestamp 1681338455 as discussed on ACDE 157: https://github.com/ethereum/execution-specs/pull/727 --- core/forkid/forkid_test.go | 185 +++++++++++++++---------------------- params/config.go | 1 + 2 files changed, 74 insertions(+), 112 deletions(-) diff --git a/core/forkid/forkid_test.go b/core/forkid/forkid_test.go index 4dda280e7150..ab59a454d8c9 100644 --- a/core/forkid/forkid_test.go +++ b/core/forkid/forkid_test.go @@ -26,15 +26,9 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) -func u64(val uint64) *uint64 { return &val } - // TestCreation tests that different genesis and fork rule combinations result in // the correct fork ID. func TestCreation(t *testing.T) { - // Temporary non-existent scenario TODO(karalabe): delete when Shanghai is enabled - timestampedConfig := *params.MainnetChainConfig - timestampedConfig.ShanghaiTime = u64(1668000000) - type testcase struct { head uint64 time uint64 @@ -50,32 +44,34 @@ func TestCreation(t *testing.T) { params.MainnetChainConfig, params.MainnetGenesisHash, []testcase{ - {0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced - {1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block - {1150000, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // First Homestead block - {1919999, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // Last Homestead block - {1920000, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // First DAO block - {2462999, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // Last DAO block - {2463000, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // First Tangerine block - {2674999, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // Last Tangerine block - {2675000, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // First Spurious block - {4369999, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // Last Spurious block - {4370000, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // First Byzantium block - {7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // Last Byzantium block - {7280000, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // First and last Constantinople, first Petersburg block - {9068999, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // Last Petersburg block - {9069000, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // First Istanbul and first Muir Glacier block - {9199999, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // Last Istanbul and first Muir Glacier block - {9200000, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // First Muir Glacier block - {12243999, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // Last Muir Glacier block - {12244000, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // First Berlin block - {12964999, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block - {12965000, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block - {13772999, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block - {13773000, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block - {15049999, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block - {15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}}, // First Gray Glacier block - {20000000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}}, // Future Gray Glacier block + {0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced + {1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block + {1150000, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // First Homestead block + {1919999, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // Last Homestead block + {1920000, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // First DAO block + {2462999, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // Last DAO block + {2463000, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // First Tangerine block + {2674999, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // Last Tangerine block + {2675000, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // First Spurious block + {4369999, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // Last Spurious block + {4370000, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // First Byzantium block + {7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // Last Byzantium block + {7280000, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // First and last Constantinople, first Petersburg block + {9068999, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // Last Petersburg block + {9069000, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // First Istanbul and first Muir Glacier block + {9199999, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // Last Istanbul and first Muir Glacier block + {9200000, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // First Muir Glacier block + {12243999, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // Last Muir Glacier block + {12244000, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // First Berlin block + {12964999, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block + {12965000, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block + {13772999, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block + {13773000, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block + {15049999, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block + {15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1681338455}}, // First Gray Glacier block + {20000000, 1681338454, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1681338455}}, // Last Gray Glacier block + {20000000, 1681338455, ID{Hash: checksumToBytes(0xdce96c2d), Next: 0}}, // First Shanghai block + {30000000, 2000000000, ID{Hash: checksumToBytes(0xdce96c2d), Next: 0}}, // Future Shanghai block }, }, // Rinkeby test cases @@ -131,41 +127,6 @@ func TestCreation(t *testing.T) { {1735372, 1677557088, ID{Hash: checksumToBytes(0xf7f9bc08), Next: 0}}, // First Shanghai block }, }, - // Temporary timestamped test cases - { - ×tampedConfig, - params.MainnetGenesisHash, - []testcase{ - {0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Unsynced - {1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}}, // Last Frontier block - {1150000, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // First Homestead block - {1919999, 0, ID{Hash: checksumToBytes(0x97c2c34c), Next: 1920000}}, // Last Homestead block - {1920000, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // First DAO block - {2462999, 0, ID{Hash: checksumToBytes(0x91d1f948), Next: 2463000}}, // Last DAO block - {2463000, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // First Tangerine block - {2674999, 0, ID{Hash: checksumToBytes(0x7a64da13), Next: 2675000}}, // Last Tangerine block - {2675000, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // First Spurious block - {4369999, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}}, // Last Spurious block - {4370000, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // First Byzantium block - {7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}}, // Last Byzantium block - {7280000, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // First and last Constantinople, first Petersburg block - {9068999, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 9069000}}, // Last Petersburg block - {9069000, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // First Istanbul and first Muir Glacier block - {9199999, 0, ID{Hash: checksumToBytes(0x879d6e30), Next: 9200000}}, // Last Istanbul and first Muir Glacier block - {9200000, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // First Muir Glacier block - {12243999, 0, ID{Hash: checksumToBytes(0xe029e991), Next: 12244000}}, // Last Muir Glacier block - {12244000, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // First Berlin block - {12964999, 0, ID{Hash: checksumToBytes(0x0eb440f6), Next: 12965000}}, // Last Berlin block - {12965000, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // First London block - {13772999, 0, ID{Hash: checksumToBytes(0xb715077d), Next: 13773000}}, // Last London block - {13773000, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // First Arrow Glacier block - {15049999, 0, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}}, // Last Arrow Glacier block - {15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1668000000}}, // First Gray Glacier block - {19999999, 1667999999, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1668000000}}, // Last Gray Glacier block - {20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}}, // First Shanghai block - {20000000, 2668000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}}, // Future Shanghai block - }, - }, } for i, tt := range tests { for j, ttt := range tt.cases { @@ -179,9 +140,9 @@ func TestCreation(t *testing.T) { // TestValidation tests that a local peer correctly validates and accepts a remote // fork ID. func TestValidation(t *testing.T) { - // Temporary non-existent scenario TODO(karalabe): delete when Shanghai is enabled - timestampedConfig := *params.MainnetChainConfig - timestampedConfig.ShanghaiTime = u64(1668000000) + // Config that has not timestamp enabled + legacyConfig := *params.MainnetChainConfig + legacyConfig.ShanghaiTime = nil tests := []struct { config *params.ChainConfig @@ -195,60 +156,60 @@ func TestValidation(t *testing.T) { //------------------ // Local is mainnet Gray Glacier, remote announces the same. No future fork is announced. - {params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, nil}, + {&legacyConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, nil}, // Local is mainnet Gray Glacier, remote announces the same. Remote also announces a next fork // at block 0xffffffff, but that is uncertain. - {params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: math.MaxUint64}, nil}, + {&legacyConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: math.MaxUint64}, nil}, // Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote announces // also Byzantium, but it's not yet aware of Petersburg (e.g. non updated node before the fork). // In this case we don't know if Petersburg passed yet or not. - {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, + {&legacyConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, // Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote announces // also Byzantium, and it's also aware of Petersburg (e.g. updated node before the fork). We // don't know if Petersburg passed yet (will pass) or not. - {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + {&legacyConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, // Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote announces // also Byzantium, and it's also aware of some random fork (e.g. misconfigured Petersburg). As // neither forks passed at neither nodes, they may mismatch, but we still connect for now. - {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: math.MaxUint64}, nil}, + {&legacyConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: math.MaxUint64}, nil}, // Local is mainnet exactly on Petersburg, remote announces Byzantium + knowledge about Petersburg. Remote // is simply out of sync, accept. - {params.MainnetChainConfig, 7280000, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + {&legacyConfig, 7280000, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, // Local is mainnet Petersburg, remote announces Byzantium + knowledge about Petersburg. Remote // is simply out of sync, accept. - {params.MainnetChainConfig, 7987396, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, + {&legacyConfig, 7987396, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7280000}, nil}, // Local is mainnet Petersburg, remote announces Spurious + knowledge about Byzantium. Remote // is definitely out of sync. It may or may not need the Petersburg update, we don't know yet. - {params.MainnetChainConfig, 7987396, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, + {&legacyConfig, 7987396, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, // Local is mainnet Byzantium, remote announces Petersburg. Local is out of sync, accept. - {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 0}, nil}, + {&legacyConfig, 7279999, 0, ID{Hash: checksumToBytes(0x668db0af), Next: 0}, nil}, // Local is mainnet Spurious, remote announces Byzantium, but is not aware of Petersburg. Local // out of sync. Local also knows about a future fork, but that is uncertain yet. - {params.MainnetChainConfig, 4369999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, + {&legacyConfig, 4369999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, nil}, // Local is mainnet Petersburg. remote announces Byzantium but is not aware of further forks. // Remote needs software update. - {params.MainnetChainConfig, 7987396, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, ErrRemoteStale}, + {&legacyConfig, 7987396, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 0}, ErrRemoteStale}, // Local is mainnet Petersburg, and isn't aware of more forks. Remote announces Petersburg + // 0xffffffff. Local needs software update, reject. - {params.MainnetChainConfig, 7987396, 0, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, + {&legacyConfig, 7987396, 0, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Byzantium, and is aware of Petersburg. Remote announces Petersburg + // 0xffffffff. Local needs software update, reject. - {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, + {&legacyConfig, 7279999, 0, ID{Hash: checksumToBytes(0x5cddc0e1), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Petersburg, remote is Rinkeby Petersburg. - {params.MainnetChainConfig, 7987396, 0, ID{Hash: checksumToBytes(0xafec6b27), Next: 0}, ErrLocalIncompatibleOrStale}, + {&legacyConfig, 7987396, 0, ID{Hash: checksumToBytes(0xafec6b27), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Gray Glacier, far in the future. Remote announces Gopherium (non existing fork) // at some future block 88888888, for itself, but past block for local. Local is incompatible. @@ -256,13 +217,13 @@ func TestValidation(t *testing.T) { // This case detects non-upgraded nodes with majority hash power (typical Ropsten mess). // // TODO(karalabe): This testcase will fail once mainnet gets timestamped forks, make legacy chain config - {params.MainnetChainConfig, 88888888, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 88888888}, ErrLocalIncompatibleOrStale}, + {&legacyConfig, 88888888, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 88888888}, ErrLocalIncompatibleOrStale}, // Local is mainnet Byzantium. Remote is also in Byzantium, but announces Gopherium (non existing // fork) at block 7279999, before Petersburg. Local is incompatible. // // TODO(karalabe): This testcase will fail once mainnet gets timestamped forks, make legacy chain config - {params.MainnetChainConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7279999}, ErrLocalIncompatibleOrStale}, + {&legacyConfig, 7279999, 0, ID{Hash: checksumToBytes(0xa00bc324), Next: 7279999}, ErrLocalIncompatibleOrStale}, //------------------------------------ // Block to timestamp transition tests @@ -271,40 +232,40 @@ func TestValidation(t *testing.T) { // Local is mainnet currently in Gray Glacier only (so it's aware of Shanghai), remote announces // also Gray Glacier, but it's not yet aware of Shanghai (e.g. non updated node before the fork). // In this case we don't know if Shanghai passed yet or not. - {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, nil}, + {params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, nil}, // Local is mainnet currently in Gray Glacier only (so it's aware of Shanghai), remote announces // also Gray Glacier, and it's also aware of Shanghai (e.g. updated node before the fork). We // don't know if Shanghai passed yet (will pass) or not. - {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1668000000}, nil}, + {params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1681338455}, nil}, // Local is mainnet currently in Gray Glacier only (so it's aware of Shanghai), remote announces // also Gray Glacier, and it's also aware of some random fork (e.g. misconfigured Shanghai). As // neither forks passed at neither nodes, they may mismatch, but we still connect for now. - {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: math.MaxUint64}, nil}, + {params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: math.MaxUint64}, nil}, // Local is mainnet exactly on Shanghai, remote announces Gray Glacier + knowledge about Shanghai. Remote // is simply out of sync, accept. - {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1668000000}, nil}, + {params.MainnetChainConfig, 20000000, 1681338455, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1681338455}, nil}, // Local is mainnet Shanghai, remote announces Gray Glacier + knowledge about Shanghai. Remote // is simply out of sync, accept. - {×tampedConfig, 20123456, 1668123456, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1668000000}, nil}, + {params.MainnetChainConfig, 20123456, 1681338456, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1681338455}, nil}, // Local is mainnet Shanghai, remote announces Arrow Glacier + knowledge about Gray Glacier. Remote // is definitely out of sync. It may or may not need the Shanghai update, we don't know yet. - {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}, nil}, + {params.MainnetChainConfig, 20000000, 1681338455, ID{Hash: checksumToBytes(0x20c327fc), Next: 15050000}, nil}, // Local is mainnet Gray Glacier, remote announces Shanghai. Local is out of sync, accept. - {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(0x71147644), Next: 0}, nil}, + {params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(0xdce96c2d), Next: 0}, nil}, // Local is mainnet Arrow Glacier, remote announces Gray Glacier, but is not aware of Shanghai. Local // out of sync. Local also knows about a future fork, but that is uncertain yet. - {×tampedConfig, 13773000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, nil}, + {params.MainnetChainConfig, 13773000, 0, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, nil}, // Local is mainnet Shanghai. remote announces Gray Glacier but is not aware of further forks. // Remote needs software update. - {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, ErrRemoteStale}, + {params.MainnetChainConfig, 20000000, 1681338455, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 0}, ErrRemoteStale}, // Local is mainnet Gray Glacier, and isn't aware of more forks. Remote announces Gray Glacier + // 0xffffffff. Local needs software update, reject. @@ -312,7 +273,7 @@ func TestValidation(t *testing.T) { // Local is mainnet Gray Glacier, and is aware of Shanghai. Remote announces Shanghai + // 0xffffffff. Local needs software update, reject. - {×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(checksumUpdate(0x71147644, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, + {params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(checksumUpdate(0xdce96c2d, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Gray Glacier, far in the future. Remote announces Gopherium (non existing fork) // at some future timestamp 8888888888, for itself, but past block for local. Local is incompatible. @@ -322,92 +283,92 @@ func TestValidation(t *testing.T) { // Local is mainnet Gray Glacier. Remote is also in Gray Glacier, but announces Gopherium (non existing // fork) at block 7279999, before Shanghai. Local is incompatible. - {×tampedConfig, 19999999, 1667999999, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1667999999}, ErrLocalIncompatibleOrStale}, + {params.MainnetChainConfig, 19999999, 1667999999, ID{Hash: checksumToBytes(0xf0afd0e3), Next: 1667999999}, ErrLocalIncompatibleOrStale}, //---------------------- // Timestamp based tests //---------------------- // Local is mainnet Shanghai, remote announces the same. No future fork is announced. - {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}, nil}, + {params.MainnetChainConfig, 20000000, 1681338455, ID{Hash: checksumToBytes(0xdce96c2d), Next: 0}, nil}, // Local is mainnet Shanghai, remote announces the same. Remote also announces a next fork // at time 0xffffffff, but that is uncertain. - {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: math.MaxUint64}, nil}, + {params.MainnetChainConfig, 20000000, 1681338455, ID{Hash: checksumToBytes(0xdce96c2d), Next: math.MaxUint64}, nil}, // Local is mainnet currently in Shanghai only (so it's aware of Cancun), remote announces // also Shanghai, but it's not yet aware of Cancun (e.g. non updated node before the fork). // In this case we don't know if Cancun passed yet or not. // // TODO(karalabe): Enable this when Cancun is specced - //{×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}, nil}, + //{params.MainnetChainConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}, nil}, // Local is mainnet currently in Shanghai only (so it's aware of Cancun), remote announces // also Shanghai, and it's also aware of Cancun (e.g. updated node before the fork). We // don't know if Cancun passed yet (will pass) or not. // // TODO(karalabe): Enable this when Cancun is specced and update next timestamp - //{×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, nil}, + //{params.MainnetChainConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, nil}, // Local is mainnet currently in Shanghai only (so it's aware of Cancun), remote announces // also Shanghai, and it's also aware of some random fork (e.g. misconfigured Cancun). As // neither forks passed at neither nodes, they may mismatch, but we still connect for now. // // TODO(karalabe): Enable this when Cancun is specced - //{×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: math.MaxUint64}, nil}, + //{params.MainnetChainConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x71147644), Next: math.MaxUint64}, nil}, // Local is mainnet exactly on Cancun, remote announces Shanghai + knowledge about Cancun. Remote // is simply out of sync, accept. // // TODO(karalabe): Enable this when Cancun is specced, update local head and time, next timestamp - // {×tampedConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, nil}, + // {params.MainnetChainConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, nil}, // Local is mainnet Cancun, remote announces Shanghai + knowledge about Cancun. Remote // is simply out of sync, accept. // TODO(karalabe): Enable this when Cancun is specced, update local head and time, next timestamp - //{×tampedConfig, 21123456, 1678123456, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, nil}, + //{params.MainnetChainConfig, 21123456, 1678123456, ID{Hash: checksumToBytes(0x71147644), Next: 1678000000}, nil}, // Local is mainnet Prague, remote announces Shanghai + knowledge about Cancun. Remote // is definitely out of sync. It may or may not need the Prague update, we don't know yet. // // TODO(karalabe): Enable this when Cancun **and** Prague is specced, update all the numbers - //{×tampedConfig, 0, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, + //{params.MainnetChainConfig, 0, 0, ID{Hash: checksumToBytes(0x3edd5b10), Next: 4370000}, nil}, // Local is mainnet Shanghai, remote announces Cancun. Local is out of sync, accept. // // TODO(karalabe): Enable this when Cancun is specced, update remote checksum - //{×tampedConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x00000000), Next: 0}, nil}, + //{params.MainnetChainConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x00000000), Next: 0}, nil}, // Local is mainnet Shanghai, remote announces Cancun, but is not aware of Prague. Local // out of sync. Local also knows about a future fork, but that is uncertain yet. // // TODO(karalabe): Enable this when Cancun **and** Prague is specced, update remote checksum - //{×tampedConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x00000000), Next: 0}, nil}, + //{params.MainnetChainConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x00000000), Next: 0}, nil}, // Local is mainnet Cancun. remote announces Shanghai but is not aware of further forks. // Remote needs software update. // // TODO(karalabe): Enable this when Cancun is specced, update local head and time - //{×tampedConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}, ErrRemoteStale}, + //{params.MainnetChainConfig, 21000000, 1678000000, ID{Hash: checksumToBytes(0x71147644), Next: 0}, ErrRemoteStale}, // Local is mainnet Shanghai, and isn't aware of more forks. Remote announces Shanghai + // 0xffffffff. Local needs software update, reject. - {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(checksumUpdate(0x71147644, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, + {params.MainnetChainConfig, 20000000, 1681338455, ID{Hash: checksumToBytes(checksumUpdate(0xdce96c2d, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Shanghai, and is aware of Cancun. Remote announces Cancun + // 0xffffffff. Local needs software update, reject. // // TODO(karalabe): Enable this when Cancun is specced, update remote checksum - //{×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(checksumUpdate(0x00000000, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, + //{params.MainnetChainConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(checksumUpdate(0x00000000, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Shanghai, remote is random Shanghai. - {×tampedConfig, 20000000, 1668000000, ID{Hash: checksumToBytes(0x12345678), Next: 0}, ErrLocalIncompatibleOrStale}, + {params.MainnetChainConfig, 20000000, 1681338455, ID{Hash: checksumToBytes(0x12345678), Next: 0}, ErrLocalIncompatibleOrStale}, // Local is mainnet Shanghai, far in the future. Remote announces Gopherium (non existing fork) // at some future timestamp 8888888888, for itself, but past block for local. Local is incompatible. // // This case detects non-upgraded nodes with majority hash power (typical Ropsten mess). - {×tampedConfig, 88888888, 8888888888, ID{Hash: checksumToBytes(0x71147644), Next: 8888888888}, ErrLocalIncompatibleOrStale}, + {params.MainnetChainConfig, 88888888, 8888888888, ID{Hash: checksumToBytes(0xdce96c2d), Next: 8888888888}, ErrLocalIncompatibleOrStale}, // Local is mainnet Shanghai. Remote is also in Shanghai, but announces Gopherium (non existing // fork) at timestamp 1668000000, before Cancun. Local is incompatible. diff --git a/params/config.go b/params/config.go index adb5f44f0952..e04b16673c6b 100644 --- a/params/config.go +++ b/params/config.go @@ -76,6 +76,7 @@ var ( GrayGlacierBlock: big.NewInt(15_050_000), TerminalTotalDifficulty: MainnetTerminalTotalDifficulty, // 58_750_000_000_000_000_000_000 TerminalTotalDifficultyPassed: true, + ShanghaiTime: newUint64(1681338455), Ethash: new(EthashConfig), } From e6b6a8b738069ad0579f6798ee59fde93ed13b43 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 20 Mar 2023 14:15:18 +0100 Subject: [PATCH 648/715] core/txpool: allow future local transactions (#26930) Local transactions should not be subject to the "future shouldn't churn pending txs" rule --- core/txpool/txpool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index cc673ccc10eb..ac4486c6cba8 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -736,7 +736,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e } // If the new transaction is a future transaction it should never churn pending transactions - if pool.isFuture(from, tx) { + if !isLocal && pool.isFuture(from, tx) { var replacesPending bool for _, dropTx := range drop { dropSender, _ := types.Sender(pool.signer, dropTx) From a38f4108571d1a144dc3cf3faf8990430d109bc4 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 21 Mar 2023 09:03:04 +0100 Subject: [PATCH 649/715] params: go-ethereum v1.11.5 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 0cede57bbff4..2ac4a554b1d5 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 5 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 5 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 7ecb5785641385ca24dc6ab71c792e16d23afd85 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 21 Mar 2023 09:04:26 +0100 Subject: [PATCH 650/715] params: begin v1.11.6 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 2ac4a554b1d5..7df3a82b3ddc 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 5 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 6 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 2ed8013f08757a914c04e3fe9ae7c5023609d07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 21 Mar 2023 11:52:29 +0200 Subject: [PATCH 651/715] build: allow building nightly archives via cron jobs (#26938) --- build/ci.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build/ci.go b/build/ci.go index 49926621bda6..3e145b20b079 100644 --- a/build/ci.go +++ b/build/ci.go @@ -465,10 +465,6 @@ func maybeSkipArchive(env build.Environment) { log.Printf("skipping archive creation because this is a PR build") os.Exit(0) } - if env.IsCronJob { - log.Printf("skipping archive creation because this is a cron job") - os.Exit(0) - } if env.Branch != "master" && !strings.HasPrefix(env.Tag, "v1.") { log.Printf("skipping archive creation because branch %q, tag %q is not on the inclusion list", env.Branch, env.Tag) os.Exit(0) From 8a9a73c99b292bfcb832342877be48856397ee2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 21 Mar 2023 12:01:43 +0200 Subject: [PATCH 652/715] log: add special casing of uint256 into the logger (#26936) --- go.mod | 2 +- go.sum | 4 ++++ log/format.go | 42 +++++++++++++++++++++++++++++++++++++++++- log/format_test.go | 20 ++++++++++++++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 21325d5669e1..26519b80480d 100644 --- a/go.mod +++ b/go.mod @@ -36,7 +36,7 @@ require ( github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 github.com/holiman/bloomfilter/v2 v2.0.3 - github.com/holiman/uint256 v1.2.0 + github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c github.com/huin/goupnp v1.0.3 github.com/influxdata/influxdb v1.8.3 github.com/influxdata/influxdb-client-go/v2 v2.4.0 diff --git a/go.sum b/go.sum index 51beb15cd24a..4491e0189179 100644 --- a/go.sum +++ b/go.sum @@ -297,6 +297,10 @@ github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o= +github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= +github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= diff --git a/log/format.go b/log/format.go index d7e2f820afe7..b10786efa04c 100644 --- a/log/format.go +++ b/log/format.go @@ -12,6 +12,8 @@ import ( "sync/atomic" "time" "unicode/utf8" + + "github.com/holiman/uint256" ) const ( @@ -339,12 +341,20 @@ func formatLogfmtValue(value interface{}, term bool) string { return v.Format(timeFormat) case *big.Int: - // Big ints get consumed by the Stringer clause so we need to handle + // Big ints get consumed by the Stringer clause, so we need to handle // them earlier on. if v == nil { return "" } return formatLogfmtBigInt(v) + + case *uint256.Int: + // Uint256s get consumed by the Stringer clause, so we need to handle + // them earlier on. + if v == nil { + return "" + } + return formatLogfmtUint256(v) } if term { if s, ok := value.(TerminalStringer); ok { @@ -469,6 +479,36 @@ func formatLogfmtBigInt(n *big.Int) string { return string(buf[i+1:]) } +// formatLogfmtUint256 formats n with thousand separators. +func formatLogfmtUint256(n *uint256.Int) string { + if n.IsUint64() { + return FormatLogfmtUint64(n.Uint64()) + } + var ( + text = n.Dec() + buf = make([]byte, len(text)+len(text)/3) + comma = 0 + i = len(buf) - 1 + ) + for j := len(text) - 1; j >= 0; j, i = j-1, i-1 { + c := text[j] + + switch { + case c == '-': + buf[i] = c + case comma == 3: + buf[i] = ',' + i-- + comma = 0 + fallthrough + default: + buf[i] = c + comma++ + } + } + return string(buf[i+1:]) +} + // escapeString checks if the provided string needs escaping/quoting, and // calls strconv.Quote if needed func escapeString(s string) string { diff --git a/log/format_test.go b/log/format_test.go index cfcfe85802a4..e08c1d1a4a9c 100644 --- a/log/format_test.go +++ b/log/format_test.go @@ -7,6 +7,8 @@ import ( "math/rand" "strings" "testing" + + "github.com/holiman/uint256" ) func TestPrettyInt64(t *testing.T) { @@ -80,6 +82,24 @@ func TestPrettyBigInt(t *testing.T) { } } +func TestPrettyUint256(t *testing.T) { + tests := []struct { + int string + s string + }{ + {"111222333444555678999", "111,222,333,444,555,678,999"}, + {"11122233344455567899900", "11,122,233,344,455,567,899,900"}, + } + + for _, tt := range tests { + v := new(uint256.Int) + v.SetFromDecimal(tt.int) + if have := formatLogfmtUint256(v); have != tt.s { + t.Errorf("invalid output %s, want %s", have, tt.s) + } + } +} + var sink string func BenchmarkPrettyInt64Logfmt(b *testing.B) { From 905a723fae3df9cc9280e539989db21c1b80d5b6 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 21 Mar 2023 19:10:23 +0800 Subject: [PATCH 653/715] core/rawdb: use atomic int added in go1.19 (#26935) --- core/rawdb/chain_freezer.go | 24 +++++++-------- core/rawdb/chain_iterator.go | 5 +-- core/rawdb/database.go | 7 ++--- core/rawdb/freezer.go | 53 +++++++++++++++----------------- core/rawdb/freezer_batch.go | 5 ++- core/rawdb/freezer_table.go | 53 +++++++++++++++----------------- core/rawdb/freezer_table_test.go | 39 ++++++++++++----------- core/rawdb/freezer_test.go | 4 +-- 8 files changed, 90 insertions(+), 100 deletions(-) diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 167afc38894c..22dbda4a2107 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -43,10 +43,7 @@ const ( // The background thread will keep moving ancient chain segments from key-value // database to flat files for saving space on live database. type chainFreezer struct { - // WARNING: The `threshold` field is accessed atomically. On 32 bit platforms, only - // 64-bit aligned fields can be atomic. The struct is guaranteed to be so aligned, - // so take advantage of that (https://golang.org/pkg/sync/atomic/#pkg-note-BUG). - threshold uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests) + threshold atomic.Uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests) *Freezer quit chan struct{} @@ -60,12 +57,13 @@ func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFre if err != nil { return nil, err } - return &chainFreezer{ - Freezer: freezer, - threshold: params.FullImmutabilityThreshold, - quit: make(chan struct{}), - trigger: make(chan chan struct{}), - }, nil + cf := chainFreezer{ + Freezer: freezer, + quit: make(chan struct{}), + trigger: make(chan chan struct{}), + } + cf.threshold.Store(params.FullImmutabilityThreshold) + return &cf, nil } // Close closes the chain freezer instance and terminates the background thread. @@ -124,8 +122,8 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { continue } number := ReadHeaderNumber(nfdb, hash) - threshold := atomic.LoadUint64(&f.threshold) - frozen := atomic.LoadUint64(&f.frozen) + threshold := f.threshold.Load() + frozen := f.frozen.Load() switch { case number == nil: log.Error("Current full block number unavailable", "hash", hash) @@ -186,7 +184,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) { // Wipe out side chains also and track dangling side chains var dangling []common.Hash - frozen = atomic.LoadUint64(&f.frozen) // Needs reload after during freezeRange + frozen = f.frozen.Load() // Needs reload after during freezeRange for number := first; number < frozen; number++ { // Always keep the genesis block in active database if number != 0 { diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 102943516eff..56bb15b718ad 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -132,11 +132,12 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool } } // process runs in parallel - nThreadsAlive := int32(threads) + var nThreadsAlive atomic.Int32 + nThreadsAlive.Store(int32(threads)) process := func() { defer func() { // Last processor closes the result channel - if atomic.AddInt32(&nThreadsAlive, -1) == 0 { + if nThreadsAlive.Add(-1) == 0 { close(hashesCh) } }() diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 6c545032f969..b8cc36a811e5 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -24,7 +24,6 @@ import ( "path" "path/filepath" "strings" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -72,9 +71,9 @@ func (frdb *freezerdb) Freeze(threshold uint64) error { } // Set the freezer threshold to a temporary value defer func(old uint64) { - atomic.StoreUint64(&frdb.AncientStore.(*chainFreezer).threshold, old) - }(atomic.LoadUint64(&frdb.AncientStore.(*chainFreezer).threshold)) - atomic.StoreUint64(&frdb.AncientStore.(*chainFreezer).threshold, threshold) + frdb.AncientStore.(*chainFreezer).threshold.Store(old) + }(frdb.AncientStore.(*chainFreezer).threshold.Load()) + frdb.AncientStore.(*chainFreezer).threshold.Store(threshold) // Trigger a freeze cycle and block until it's done trigger := make(chan struct{}, 1) diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 60e2c56e0ff7..323dc1ddb326 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -62,11 +62,8 @@ const freezerTableSize = 2 * 1000 * 1000 * 1000 // reserving it for go-ethereum. This would also reduce the memory requirements // of Geth, and thus also GC overhead. type Freezer struct { - // WARNING: The `frozen` and `tail` fields are accessed atomically. On 32 bit platforms, only - // 64-bit aligned fields can be atomic. The struct is guaranteed to be so aligned, - // so take advantage of that (https://golang.org/pkg/sync/atomic/#pkg-note-BUG). - frozen uint64 // Number of blocks already frozen - tail uint64 // Number of the first stored item in the freezer + frozen atomic.Uint64 // Number of blocks already frozen + tail atomic.Uint64 // Number of the first stored item in the freezer // This lock synchronizes writers and the truncate operation, as well as // the "atomic" (batched) read operations. @@ -212,12 +209,12 @@ func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][] // Ancients returns the length of the frozen items. func (f *Freezer) Ancients() (uint64, error) { - return atomic.LoadUint64(&f.frozen), nil + return f.frozen.Load(), nil } // Tail returns the number of first stored item in the freezer. func (f *Freezer) Tail() (uint64, error) { - return atomic.LoadUint64(&f.tail), nil + return f.tail.Load(), nil } // AncientSize returns the ancient size of the specified category. @@ -251,7 +248,7 @@ func (f *Freezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize defer f.writeLock.Unlock() // Roll back all tables to the starting position in case of error. - prevItem := atomic.LoadUint64(&f.frozen) + prevItem := f.frozen.Load() defer func() { if err != nil { // The write operation has failed. Go back to the previous item position. @@ -272,7 +269,7 @@ func (f *Freezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize if err != nil { return 0, err } - atomic.StoreUint64(&f.frozen, item) + f.frozen.Store(item) return writeSize, nil } @@ -284,7 +281,7 @@ func (f *Freezer) TruncateHead(items uint64) error { f.writeLock.Lock() defer f.writeLock.Unlock() - if atomic.LoadUint64(&f.frozen) <= items { + if f.frozen.Load() <= items { return nil } for _, table := range f.tables { @@ -292,7 +289,7 @@ func (f *Freezer) TruncateHead(items uint64) error { return err } } - atomic.StoreUint64(&f.frozen, items) + f.frozen.Store(items) return nil } @@ -304,7 +301,7 @@ func (f *Freezer) TruncateTail(tail uint64) error { f.writeLock.Lock() defer f.writeLock.Unlock() - if atomic.LoadUint64(&f.tail) >= tail { + if f.tail.Load() >= tail { return nil } for _, table := range f.tables { @@ -312,7 +309,7 @@ func (f *Freezer) TruncateTail(tail uint64) error { return err } } - atomic.StoreUint64(&f.tail, tail) + f.tail.Store(tail) return nil } @@ -343,22 +340,22 @@ func (f *Freezer) validate() error { ) // Hack to get boundary of any table for kind, table := range f.tables { - head = atomic.LoadUint64(&table.items) - tail = atomic.LoadUint64(&table.itemHidden) + head = table.items.Load() + tail = table.itemHidden.Load() name = kind break } // Now check every table against those boundaries. for kind, table := range f.tables { - if head != atomic.LoadUint64(&table.items) { - return fmt.Errorf("freezer tables %s and %s have differing head: %d != %d", kind, name, atomic.LoadUint64(&table.items), head) + if head != table.items.Load() { + return fmt.Errorf("freezer tables %s and %s have differing head: %d != %d", kind, name, table.items.Load(), head) } - if tail != atomic.LoadUint64(&table.itemHidden) { - return fmt.Errorf("freezer tables %s and %s have differing tail: %d != %d", kind, name, atomic.LoadUint64(&table.itemHidden), tail) + if tail != table.itemHidden.Load() { + return fmt.Errorf("freezer tables %s and %s have differing tail: %d != %d", kind, name, table.itemHidden.Load(), tail) } } - atomic.StoreUint64(&f.frozen, head) - atomic.StoreUint64(&f.tail, tail) + f.frozen.Store(head) + f.tail.Store(tail) return nil } @@ -369,11 +366,11 @@ func (f *Freezer) repair() error { tail = uint64(0) ) for _, table := range f.tables { - items := atomic.LoadUint64(&table.items) + items := table.items.Load() if head > items { head = items } - hidden := atomic.LoadUint64(&table.itemHidden) + hidden := table.itemHidden.Load() if hidden > tail { tail = hidden } @@ -386,8 +383,8 @@ func (f *Freezer) repair() error { return err } } - atomic.StoreUint64(&f.frozen, head) - atomic.StoreUint64(&f.tail, tail) + f.frozen.Store(head) + f.tail.Store(tail) return nil } @@ -413,7 +410,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error { // and that error will be returned. forEach := func(t *freezerTable, offset uint64, fn func(uint64, []byte) error) error { var ( - items = atomic.LoadUint64(&t.items) + items = t.items.Load() batchSize = uint64(1024) maxBytes = uint64(1024 * 1024) ) @@ -436,7 +433,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error { } // TODO(s1na): This is a sanity-check since as of now no process does tail-deletion. But the migration // process assumes no deletion at tail and needs to be modified to account for that. - if table.itemOffset > 0 || table.itemHidden > 0 { + if table.itemOffset.Load() > 0 || table.itemHidden.Load() > 0 { return fmt.Errorf("migration not supported for tail-deleted freezers") } ancientsPath := filepath.Dir(table.index.Name()) @@ -452,7 +449,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error { out []byte start = time.Now() logged = time.Now() - offset = newTable.items + offset = newTable.items.Load() ) if offset > 0 { log.Info("found previous migration attempt", "migrated", offset) diff --git a/core/rawdb/freezer_batch.go b/core/rawdb/freezer_batch.go index 54c98cee0807..3cc7d84f4ef4 100644 --- a/core/rawdb/freezer_batch.go +++ b/core/rawdb/freezer_batch.go @@ -18,7 +18,6 @@ package rawdb import ( "fmt" - "sync/atomic" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/rlp" @@ -107,7 +106,7 @@ func (t *freezerTable) newBatch() *freezerTableBatch { func (batch *freezerTableBatch) reset() { batch.dataBuffer = batch.dataBuffer[:0] batch.indexBuffer = batch.indexBuffer[:0] - batch.curItem = atomic.LoadUint64(&batch.t.items) + batch.curItem = batch.t.items.Load() batch.totalBytes = 0 } @@ -201,7 +200,7 @@ func (batch *freezerTableBatch) commit() error { // Update headBytes of table. batch.t.headBytes += dataSize - atomic.StoreUint64(&batch.t.items, batch.curItem) + batch.t.items.Store(batch.curItem) // Update metrics. batch.t.sizeGauge.Inc(dataSize + indexSize) diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index b111797d5297..10dfb90ea77d 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -88,18 +88,15 @@ func (i *indexEntry) bounds(end *indexEntry) (startOffset, endOffset, fileId uin // It consists of a data file (snappy encoded arbitrary data blobs) and an indexEntry // file (uncompressed 64 bit indices into the data file). type freezerTable struct { - // WARNING: The `items` field is accessed atomically. On 32 bit platforms, only - // 64-bit aligned fields can be atomic. The struct is guaranteed to be so aligned, - // so take advantage of that (https://golang.org/pkg/sync/atomic/#pkg-note-BUG). - items uint64 // Number of items stored in the table (including items removed from tail) - itemOffset uint64 // Number of items removed from the table + items atomic.Uint64 // Number of items stored in the table (including items removed from tail) + itemOffset atomic.Uint64 // Number of items removed from the table // itemHidden is the number of items marked as deleted. Tail deletion is // only supported at file level which means the actual deletion will be // delayed until the entire data file is marked as deleted. Before that // these items will be hidden to prevent being visited again. The value // should never be lower than itemOffset. - itemHidden uint64 + itemHidden atomic.Uint64 noCompression bool // if true, disables snappy compression. Note: does not work retroactively readonly bool @@ -241,14 +238,14 @@ func (t *freezerTable) repair() error { // which is not enough in theory but enough in practice. // TODO: use uint64 to represent total removed items. t.tailId = firstIndex.filenum - t.itemOffset = uint64(firstIndex.offset) + t.itemOffset.Store(uint64(firstIndex.offset)) // Load metadata from the file - meta, err := loadMetadata(t.meta, t.itemOffset) + meta, err := loadMetadata(t.meta, t.itemOffset.Load()) if err != nil { return err } - t.itemHidden = meta.VirtualTail + t.itemHidden.Store(meta.VirtualTail) // Read the last index, use the default value in case the freezer is empty if offsetsSize == indexEntrySize { @@ -331,7 +328,7 @@ func (t *freezerTable) repair() error { } } // Update the item and byte counters and return - t.items = t.itemOffset + uint64(offsetsSize/indexEntrySize-1) // last indexEntry points to the end of the data file + t.items.Store(t.itemOffset.Load() + uint64(offsetsSize/indexEntrySize-1)) // last indexEntry points to the end of the data file t.headBytes = contentSize t.headId = lastIndex.filenum @@ -346,9 +343,9 @@ func (t *freezerTable) repair() error { return err } if verbose { - t.logger.Info("Chain freezer table opened", "items", t.items, "size", t.headBytes) + t.logger.Info("Chain freezer table opened", "items", t.items.Load(), "size", t.headBytes) } else { - t.logger.Debug("Chain freezer table opened", "items", t.items, "size", common.StorageSize(t.headBytes)) + t.logger.Debug("Chain freezer table opened", "items", t.items.Load(), "size", common.StorageSize(t.headBytes)) } return nil } @@ -382,11 +379,11 @@ func (t *freezerTable) truncateHead(items uint64) error { defer t.lock.Unlock() // Ensure the given truncate target falls in the correct range - existing := atomic.LoadUint64(&t.items) + existing := t.items.Load() if existing <= items { return nil } - if items < atomic.LoadUint64(&t.itemHidden) { + if items < t.itemHidden.Load() { return errors.New("truncation below tail") } // We need to truncate, save the old size for metrics tracking @@ -403,7 +400,7 @@ func (t *freezerTable) truncateHead(items uint64) error { // Truncate the index file first, the tail position is also considered // when calculating the new freezer table length. - length := items - atomic.LoadUint64(&t.itemOffset) + length := items - t.itemOffset.Load() if err := truncateFreezerFile(t.index, int64(length+1)*indexEntrySize); err != nil { return err } @@ -438,7 +435,7 @@ func (t *freezerTable) truncateHead(items uint64) error { } // All data files truncated, set internal counters and return t.headBytes = int64(expected.offset) - atomic.StoreUint64(&t.items, items) + t.items.Store(items) // Retrieve the new size and update the total size counter newSize, err := t.sizeNolock() @@ -455,10 +452,10 @@ func (t *freezerTable) truncateTail(items uint64) error { defer t.lock.Unlock() // Ensure the given truncate target falls in the correct range - if atomic.LoadUint64(&t.itemHidden) >= items { + if t.itemHidden.Load() >= items { return nil } - if atomic.LoadUint64(&t.items) < items { + if t.items.Load() < items { return errors.New("truncation above head") } // Load the new tail index by the given new tail position @@ -466,10 +463,10 @@ func (t *freezerTable) truncateTail(items uint64) error { newTailId uint32 buffer = make([]byte, indexEntrySize) ) - if atomic.LoadUint64(&t.items) == items { + if t.items.Load() == items { newTailId = t.headId } else { - offset := items - atomic.LoadUint64(&t.itemOffset) + offset := items - t.itemOffset.Load() if _, err := t.index.ReadAt(buffer, int64((offset+1)*indexEntrySize)); err != nil { return err } @@ -478,7 +475,7 @@ func (t *freezerTable) truncateTail(items uint64) error { newTailId = newTail.filenum } // Update the virtual tail marker and hidden these entries in table. - atomic.StoreUint64(&t.itemHidden, items) + t.itemHidden.Store(items) if err := writeMetadata(t.meta, newMetadata(items)); err != nil { return err } @@ -501,7 +498,7 @@ func (t *freezerTable) truncateTail(items uint64) error { // Count how many items can be deleted from the file. var ( newDeleted = items - deleted = atomic.LoadUint64(&t.itemOffset) + deleted = t.itemOffset.Load() ) for current := items - 1; current >= deleted; current -= 1 { if _, err := t.index.ReadAt(buffer, int64((current-deleted+1)*indexEntrySize)); err != nil { @@ -541,7 +538,7 @@ func (t *freezerTable) truncateTail(items uint64) error { } // Release any files before the current tail t.tailId = newTailId - atomic.StoreUint64(&t.itemOffset, newDeleted) + t.itemOffset.Store(newDeleted) t.releaseFilesBefore(t.tailId, true) // Retrieve the new size and update the total size counter @@ -654,7 +651,7 @@ func (t *freezerTable) releaseFilesBefore(num uint32, remove bool) { // it will return error. func (t *freezerTable) getIndices(from, count uint64) ([]*indexEntry, error) { // Apply the table-offset - from = from - t.itemOffset + from = from - t.itemOffset.Load() // For reading N items, we need N+1 indices. buffer := make([]byte, (count+1)*indexEntrySize) if _, err := t.index.ReadAt(buffer, int64(from*indexEntrySize)); err != nil { @@ -744,8 +741,8 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i return nil, nil, errClosed } var ( - items = atomic.LoadUint64(&t.items) // the total items(head + 1) - hidden = atomic.LoadUint64(&t.itemHidden) // the number of hidden items + items = t.items.Load() // the total items(head + 1) + hidden = t.itemHidden.Load() // the number of hidden items ) // Ensure the start is written, not deleted from the tail, and that the // caller actually wants something @@ -832,7 +829,7 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i // has returns an indicator whether the specified number data is still accessible // in the freezer table. func (t *freezerTable) has(number uint64) bool { - return atomic.LoadUint64(&t.items) > number && atomic.LoadUint64(&t.itemHidden) <= number + return t.items.Load() > number && t.itemHidden.Load() <= number } // size returns the total data size in the freezer table. @@ -922,7 +919,7 @@ func (t *freezerTable) dumpIndex(w io.Writer, start, stop int64) { return } fmt.Fprintf(w, "Version %d count %d, deleted %d, hidden %d\n", meta.Version, - atomic.LoadUint64(&t.items), atomic.LoadUint64(&t.itemOffset), atomic.LoadUint64(&t.itemHidden)) + t.items.Load(), t.itemOffset.Load(), t.itemHidden.Load()) buf := make([]byte, indexEntrySize) diff --git a/core/rawdb/freezer_table_test.go b/core/rawdb/freezer_table_test.go index 6181d4d72cac..5c4cc40eddc7 100644 --- a/core/rawdb/freezer_table_test.go +++ b/core/rawdb/freezer_table_test.go @@ -24,7 +24,6 @@ import ( "os" "path/filepath" "reflect" - "sync/atomic" "testing" "testing/quick" @@ -191,7 +190,7 @@ func TestFreezerRepairDanglingHeadLarge(t *testing.T) { writeChunks(t, f, 255, 15) // The last item should be there - if _, err = f.Retrieve(f.items - 1); err != nil { + if _, err = f.Retrieve(f.items.Load() - 1); err != nil { t.Fatal(err) } f.Close() @@ -317,7 +316,7 @@ func TestFreezerRepairDanglingIndex(t *testing.T) { writeChunks(t, f, 9, 15) // The last item should be there - if _, err = f.Retrieve(f.items - 1); err != nil { + if _, err = f.Retrieve(f.items.Load() - 1); err != nil { f.Close() t.Fatal(err) } @@ -350,8 +349,8 @@ func TestFreezerRepairDanglingIndex(t *testing.T) { t.Fatal(err) } defer f.Close() - if f.items != 7 { - t.Fatalf("expected %d items, got %d", 7, f.items) + if f.items.Load() != 7 { + t.Fatalf("expected %d items, got %d", 7, f.items.Load()) } if err := assertFileSize(fileToCrop, 15); err != nil { t.Fatal(err) @@ -374,7 +373,7 @@ func TestFreezerTruncate(t *testing.T) { writeChunks(t, f, 30, 15) // The last item should be there - if _, err = f.Retrieve(f.items - 1); err != nil { + if _, err = f.Retrieve(f.items.Load() - 1); err != nil { t.Fatal(err) } f.Close() @@ -388,8 +387,8 @@ func TestFreezerTruncate(t *testing.T) { } defer f.Close() f.truncateHead(10) // 150 bytes - if f.items != 10 { - t.Fatalf("expected %d items, got %d", 10, f.items) + if f.items.Load() != 10 { + t.Fatalf("expected %d items, got %d", 10, f.items.Load()) } // 45, 45, 45, 15 -- bytes should be 15 if f.headBytes != 15 { @@ -444,9 +443,9 @@ func TestFreezerRepairFirstFile(t *testing.T) { if err != nil { t.Fatal(err) } - if f.items != 1 { + if f.items.Load() != 1 { f.Close() - t.Fatalf("expected %d items, got %d", 0, f.items) + t.Fatalf("expected %d items, got %d", 0, f.items.Load()) } // Write 40 bytes @@ -483,7 +482,7 @@ func TestFreezerReadAndTruncate(t *testing.T) { writeChunks(t, f, 30, 15) // The last item should be there - if _, err = f.Retrieve(f.items - 1); err != nil { + if _, err = f.Retrieve(f.items.Load() - 1); err != nil { t.Fatal(err) } f.Close() @@ -495,9 +494,9 @@ func TestFreezerReadAndTruncate(t *testing.T) { if err != nil { t.Fatal(err) } - if f.items != 30 { + if f.items.Load() != 30 { f.Close() - t.Fatalf("expected %d items, got %d", 0, f.items) + t.Fatalf("expected %d items, got %d", 0, f.items.Load()) } for y := byte(0); y < 30; y++ { f.Retrieve(uint64(y)) @@ -1210,13 +1209,13 @@ func runRandTest(rt randTest) bool { rt[i].err = fmt.Errorf("failed to reload table %v", err) } case opCheckAll: - tail := atomic.LoadUint64(&f.itemHidden) - head := atomic.LoadUint64(&f.items) + tail := f.itemHidden.Load() + head := f.items.Load() if tail == head { continue } - got, err := f.RetrieveItems(atomic.LoadUint64(&f.itemHidden), head-tail, 100000) + got, err := f.RetrieveItems(f.itemHidden.Load(), head-tail, 100000) if err != nil { rt[i].err = err } else { @@ -1238,7 +1237,7 @@ func runRandTest(rt randTest) bool { if len(step.items) == 0 { continue } - tail := atomic.LoadUint64(&f.itemHidden) + tail := f.itemHidden.Load() for i := 0; i < len(step.items); i++ { blobs = append(blobs, values[step.items[i]-tail]) } @@ -1254,7 +1253,7 @@ func runRandTest(rt randTest) bool { case opTruncateHead: f.truncateHead(step.target) - length := atomic.LoadUint64(&f.items) - atomic.LoadUint64(&f.itemHidden) + length := f.items.Load() - f.itemHidden.Load() values = values[:length] case opTruncateHeadAll: @@ -1262,10 +1261,10 @@ func runRandTest(rt randTest) bool { values = nil case opTruncateTail: - prev := atomic.LoadUint64(&f.itemHidden) + prev := f.itemHidden.Load() f.truncateTail(step.target) - truncated := atomic.LoadUint64(&f.itemHidden) - prev + truncated := f.itemHidden.Load() - prev values = values[truncated:] case opTruncateTailAll: diff --git a/core/rawdb/freezer_test.go b/core/rawdb/freezer_test.go index 5896e43ce232..630c9029b0f5 100644 --- a/core/rawdb/freezer_test.go +++ b/core/rawdb/freezer_test.go @@ -267,10 +267,10 @@ func TestFreezerReadonlyValidate(t *testing.T) { bBatch := f.tables["b"].newBatch() require.NoError(t, bBatch.AppendRaw(0, item)) require.NoError(t, bBatch.commit()) - if f.tables["a"].items != 3 { + if f.tables["a"].items.Load() != 3 { t.Fatalf("unexpected number of items in table") } - if f.tables["b"].items != 1 { + if f.tables["b"].items.Load() != 1 { t.Fatalf("unexpected number of items in table") } require.NoError(t, f.Close()) From b3f43c89b3b884d5d0b8e1a239847f54a291a19b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 21 Mar 2023 07:14:47 -0400 Subject: [PATCH 654/715] core/vm: expose jumptable constructors (#26880) When interacting with geth as a library to e.g. produce state tests, it is desirable to obtain the consensus-correct jumptable definition for a given fork. This changes adds accessors so the instructionset can be obtained and characteristics about opcodes can be inspected. --- core/vm/jump_table_export.go | 74 ++++++++++++++++++++++++++++++++++++ params/config.go | 6 +-- 2 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 core/vm/jump_table_export.go diff --git a/core/vm/jump_table_export.go b/core/vm/jump_table_export.go new file mode 100644 index 000000000000..0d61b00ede09 --- /dev/null +++ b/core/vm/jump_table_export.go @@ -0,0 +1,74 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package vm + +import ( + "errors" + + "github.com/ethereum/go-ethereum/params" +) + +// LookupInstructionSet returns the instructionset for the fork configured by +// the rules. +func LookupInstructionSet(rules params.Rules) (JumpTable, error) { + switch { + case rules.IsPrague: + return newShanghaiInstructionSet(), errors.New("prague-fork not defined yet") + case rules.IsCancun: + return newShanghaiInstructionSet(), errors.New("cancun-fork not defined yet") + case rules.IsShanghai: + return newShanghaiInstructionSet(), nil + case rules.IsMerge: + return newMergeInstructionSet(), nil + case rules.IsLondon: + return newLondonInstructionSet(), nil + case rules.IsBerlin: + return newBerlinInstructionSet(), nil + case rules.IsIstanbul: + return newIstanbulInstructionSet(), nil + case rules.IsConstantinople: + return newConstantinopleInstructionSet(), nil + case rules.IsByzantium: + return newByzantiumInstructionSet(), nil + case rules.IsEIP158: + return newSpuriousDragonInstructionSet(), nil + case rules.IsEIP150: + return newTangerineWhistleInstructionSet(), nil + case rules.IsHomestead: + return newHomesteadInstructionSet(), nil + } + return newFrontierInstructionSet(), nil +} + +// Stack returns the mininum and maximum stack requirements. +func (op *operation) Stack() (int, int) { + return op.minStack, op.maxStack +} + +// HasCost returns true if the opcode has a cost. Opcodes which do _not_ have +// a cost assigned are one of two things: +// - undefined, a.k.a invalid opcodes, +// - the STOP opcode. +// This method can thus be used to check if an opcode is "Invalid (or STOP)". +func (op *operation) HasCost() bool { + // Ideally, we'd check this: + // return op.execute == opUndefined + // However, go-lang does now allow that. So we'll just check some other + // 'indicators' that this is an invalid op. Alas, STOP is impossible to + // filter out + return op.dynamicGas != nil || op.constantGas != 0 +} diff --git a/params/config.go b/params/config.go index e04b16673c6b..190eb737c48b 100644 --- a/params/config.go +++ b/params/config.go @@ -956,7 +956,7 @@ type Rules struct { IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool - IsMerge, IsShanghai, isCancun, isPrague bool + IsMerge, IsShanghai, IsCancun, IsPrague bool } // Rules ensures c's ChainID is not nil. @@ -979,7 +979,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsLondon: c.IsLondon(num), IsMerge: isMerge, IsShanghai: c.IsShanghai(timestamp), - isCancun: c.IsCancun(timestamp), - isPrague: c.IsPrague(timestamp), + IsCancun: c.IsCancun(timestamp), + IsPrague: c.IsPrague(timestamp), } } From 20f8eb756bdbfa6dbd94374bbad15883e23ab150 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 22 Mar 2023 18:36:26 +0100 Subject: [PATCH 655/715] eth/catalyst: fix races (#26950) --- eth/catalyst/api_test.go | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index fb6e6935ee46..f38122200233 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -879,15 +879,10 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { genesis, preMergeBlocks := generateMergeChain(100, false) n, ethservice := startEthService(t, genesis, preMergeBlocks) defer n.Close() - - ethservice.BlockChain().Config().TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty()) - - var ( - api = NewConsensusAPI(ethservice) - parent = preMergeBlocks[len(preMergeBlocks)-1] - ) + api := NewConsensusAPI(ethservice) // Test parent already post TTD in FCU + parent := preMergeBlocks[len(preMergeBlocks)-2] fcState := engine.ForkchoiceStateV1{ HeadBlockHash: parent.Hash(), SafeBlockHash: common.Hash{}, @@ -913,6 +908,28 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { t.Fatalf("error preparing payload, err=%v", err) } data := *payload.Resolve().ExecutionPayload + // We need to recompute the blockhash, since the miner computes a wrong (correct) blockhash + txs, _ := decodeTransactions(data.Transactions) + header := &types.Header{ + ParentHash: data.ParentHash, + UncleHash: types.EmptyUncleHash, + Coinbase: data.FeeRecipient, + Root: data.StateRoot, + TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), + ReceiptHash: data.ReceiptsRoot, + Bloom: types.BytesToBloom(data.LogsBloom), + Difficulty: common.Big0, + Number: new(big.Int).SetUint64(data.Number), + GasLimit: data.GasLimit, + GasUsed: data.GasUsed, + Time: data.Timestamp, + BaseFee: data.BaseFeePerGas, + Extra: data.ExtraData, + MixDigest: data.Random, + } + block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */) + data.BlockHash = block.Hash() + // Send the new payload resp2, err := api.NewPayloadV1(data) if err != nil { t.Fatalf("error sending NewPayload, err=%v", err) @@ -1240,9 +1257,10 @@ func TestNilWithdrawals(t *testing.T) { func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { genesis, blocks := generateMergeChain(10, true) - n, ethservice := startEthService(t, genesis, blocks) // enable shanghai on the last block - ethservice.BlockChain().Config().ShanghaiTime = &blocks[len(blocks)-1].Header().Time + time := blocks[len(blocks)-1].Header().Time + 1 + genesis.Config.ShanghaiTime = &time + n, ethservice := startEthService(t, genesis, blocks) var ( parent = ethservice.BlockChain().CurrentBlock() From 7f3fc15a8bea47831c6058047967cabf17ce0fed Mon Sep 17 00:00:00 2001 From: Delweng Date: Thu, 23 Mar 2023 15:34:40 +0800 Subject: [PATCH 656/715] core/rawdb: update freezertable read meter (#26946) The meter for "for measuring the effective amount of data read" within the freezertable was never updated. This change remedies that. --------- Signed-off-by: jsvisa --- core/rawdb/freezer_table.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index 10dfb90ea77d..928b37d70b2d 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -823,6 +823,9 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i break } } + + // Update metrics. + t.readMeter.Mark(int64(totalSize)) return output[:outputSize], sizes, nil } From 37ecff0967bec978e0723f4861803943bd6d0e17 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 23 Mar 2023 03:15:40 -0600 Subject: [PATCH 657/715] cmd/evm, tests: record preimages if dump is expected (#26955) With #25287 we made it so that preimages were not recorded by default. This had the side effect that the evm command is no longer able to dump state since it does a preimage lookup to determine the address represented by a key. This change enables the recording of preimages when the dump command is given. --- cmd/evm/runner.go | 8 ++++++-- tests/state_test_util.go | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 3a010da9f2dc..d6ec8ae7527d 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -40,6 +40,7 @@ import ( "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" "github.com/urfave/cli/v2" ) @@ -125,6 +126,7 @@ func runCmd(ctx *cli.Context) error { sender = common.BytesToAddress([]byte("sender")) receiver = common.BytesToAddress([]byte("receiver")) genesisConfig *core.Genesis + preimages = ctx.Bool(DumpFlag.Name) ) if ctx.Bool(MachineFlag.Name) { tracer = logger.NewJSONLogger(logconfig, os.Stdout) @@ -139,10 +141,12 @@ func runCmd(ctx *cli.Context) error { genesisConfig = gen db := rawdb.NewMemoryDatabase() genesis := gen.MustCommit(db) - statedb, _ = state.New(genesis.Root(), state.NewDatabase(db), nil) + sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: preimages}) + statedb, _ = state.New(genesis.Root(), sdb, nil) chainConfig = gen.Config } else { - statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + sdb := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: preimages}) + statedb, _ = state.New(common.Hash{}, sdb, nil) genesisConfig = new(core.Genesis) } if ctx.String(SenderFlag.Name) != "" { diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 98acc468a1d8..14b6fe534169 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" "golang.org/x/crypto/sha3" ) @@ -284,7 +285,7 @@ func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { } func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool) (*snapshot.Tree, *state.StateDB) { - sdb := state.NewDatabase(db) + sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) statedb, _ := state.New(common.Hash{}, sdb, nil) for addr, a := range accounts { statedb.SetCode(addr, a.Code) From 8990c92aea01ca07801597b00c0d83d4e2d9b811 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 23 Mar 2023 11:52:22 +0100 Subject: [PATCH 658/715] core/state: add account address to Trie slot accessors (#26934) This changes the Trie interface to add the plain account address as a parameter to all storage-related methods. After the introduction of the TryAccount* functions, TryGet, TryUpdate and TryDelete are now only meant to read an account's storage. In their current form, they assume that an account storage is stored in a separate trie, and that the hashing of the slot is independent of its account's address. The proposed structure for a stateless storage breaks these two assumptions: the hashing of a slot key requires the address and all slots and accounts are stored in a single trie. This PR therefore adds an address parameter to the interface. It is ignored in the MPT version, so this change has no functional impact, however it will reduce the diff size when merging verkle trees. --- core/state/database.go | 20 ++++++++++---------- core/state/state_object.go | 8 ++++---- core/state/statedb.go | 2 +- core/state/trie_prefetcher.go | 24 +++++++++++++++--------- core/state/trie_prefetcher_test.go | 16 ++++++++-------- light/trie.go | 6 +++--- trie/secure_trie.go | 12 ++++++------ 7 files changed, 47 insertions(+), 41 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index d3c36c10ac5d..a67c414d9307 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -68,10 +68,10 @@ type Trie interface { // TODO(fjl): remove this when StateTrie is removed GetKey([]byte) []byte - // TryGet 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. - TryGet(key []byte) ([]byte, error) + // TryGetStorage 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. + TryGetStorage(addr common.Address, key []byte) ([]byte, error) // TryGetAccount abstracts an account read from the trie. It retrieves the // account blob from the trie with provided account address and decodes it @@ -81,20 +81,20 @@ type Trie interface { // be returned. TryGetAccount(address common.Address) (*types.StateAccount, error) - // TryUpdate 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 + // TryUpdateStorage 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. If a node was not found in the // database, a trie.MissingNodeError is returned. - TryUpdate(key, value []byte) error + TryUpdateStorage(addr common.Address, key, value []byte) error // TryUpdateAccount 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. TryUpdateAccount(address common.Address, account *types.StateAccount) error - // TryDelete removes any existing value for key from the trie. If a node was not - // found in the database, a trie.MissingNodeError is returned. - TryDelete(key []byte) error + // TryDeleteStorage removes any existing value for key from the trie. If a node + // was not found in the database, a trie.MissingNodeError is returned. + TryDeleteStorage(addr common.Address, key []byte) error // TryDeleteAccount abstracts an account deletion from the trie. TryDeleteAccount(address common.Address) error diff --git a/core/state/state_object.go b/core/state/state_object.go index 7e34cba44a82..936f6dae2f13 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -201,7 +201,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has s.db.setError(err) return common.Hash{} } - enc, err = tr.TryGet(key.Bytes()) + enc, err = tr.TryGetStorage(s.address, key.Bytes()) if metrics.EnabledExpensive { s.db.StorageReads += time.Since(start) } @@ -253,7 +253,7 @@ func (s *stateObject) finalise(prefetch bool) { } } if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { - s.db.prefetcher.prefetch(s.addrHash, s.data.Root, slotsToPrefetch) + s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch) } if len(s.dirtyStorage) > 0 { s.dirtyStorage = make(Storage) @@ -294,7 +294,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { var v []byte if (value == common.Hash{}) { - if err := tr.TryDelete(key[:]); err != nil { + if err := tr.TryDeleteStorage(s.address, key[:]); err != nil { s.db.setError(err) return nil, err } @@ -302,7 +302,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { } else { // Encoding []byte cannot fail, ok to ignore the error. v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) - if err := tr.TryUpdate(key[:], v); err != nil { + if err := tr.TryUpdateStorage(s.address, key[:], v); err != nil { s.db.setError(err) return nil, err } diff --git a/core/state/statedb.go b/core/state/statedb.go index 54d5040451be..38583f51db20 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -871,7 +871,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure } if s.prefetcher != nil && len(addressesToPrefetch) > 0 { - s.prefetcher.prefetch(common.Hash{}, s.originalRoot, addressesToPrefetch) + s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch) } // Invalidate journal because reverting across transactions is not allowed. s.clearJournalAndRefund() diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index f142c86bbfa0..edd370fbdbb6 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -141,7 +141,7 @@ func (p *triePrefetcher) copy() *triePrefetcher { } // prefetch schedules a batch of trie items to prefetch. -func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, keys [][]byte) { +func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) { // If the prefetcher is an inactive one, bail out if p.fetches != nil { return @@ -150,7 +150,7 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, keys [][] id := p.trieID(owner, root) fetcher := p.fetchers[id] if fetcher == nil { - fetcher = newSubfetcher(p.db, p.root, owner, root) + fetcher = newSubfetcher(p.db, p.root, owner, root, addr) p.fetchers[id] = fetcher } fetcher.schedule(keys) @@ -205,11 +205,12 @@ func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string { // main prefetcher is paused and either all requested items are processed or if // the trie being worked on is retrieved from the prefetcher. type subfetcher struct { - db Database // Database to load trie nodes through - state common.Hash // Root hash of the state to prefetch - owner common.Hash // Owner of the trie, usually account hash - root common.Hash // Root hash of the trie to prefetch - trie Trie // Trie being populated with nodes + db Database // Database to load trie nodes through + state common.Hash // Root hash of the state to prefetch + owner common.Hash // Owner of the trie, usually account hash + root common.Hash // Root hash of the trie to prefetch + addr common.Address // Address of the account that the trie belongs to + trie Trie // Trie being populated with nodes tasks [][]byte // Items queued up for retrieval lock sync.Mutex // Lock protecting the task queue @@ -226,12 +227,13 @@ type subfetcher struct { // newSubfetcher creates a goroutine to prefetch state items belonging to a // particular root hash. -func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash) *subfetcher { +func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher { sf := &subfetcher{ db: db, state: state, owner: owner, root: root, + addr: addr, wake: make(chan struct{}, 1), stop: make(chan struct{}), term: make(chan struct{}), @@ -336,7 +338,11 @@ func (sf *subfetcher) loop() { if _, ok := sf.seen[string(task)]; ok { sf.dups++ } else { - sf.trie.TryGet(task) + if len(task) == common.AddressLength { + sf.trie.TryGetAccount(common.BytesToAddress(task)) + } else { + sf.trie.TryGetStorage(sf.addr, task) + } sf.seen[string(task)] = struct{}{} } } diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index cb0b67d7ea79..501bb70840f0 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -47,19 +47,19 @@ func TestCopyAndClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) time.Sleep(1 * time.Second) a := prefetcher.trie(common.Hash{}, db.originalRoot) - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) b := prefetcher.trie(common.Hash{}, db.originalRoot) cpy := prefetcher.copy() - cpy.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) - cpy.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) + cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) c := cpy.trie(common.Hash{}, db.originalRoot) prefetcher.close() cpy2 := cpy.copy() - cpy2.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + cpy2.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) d := cpy2.trie(common.Hash{}, db.originalRoot) cpy.close() cpy2.close() @@ -72,7 +72,7 @@ func TestUseAfterClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) a := prefetcher.trie(common.Hash{}, db.originalRoot) prefetcher.close() b := prefetcher.trie(common.Hash{}, db.originalRoot) @@ -88,7 +88,7 @@ func TestCopyClose(t *testing.T) { db := filledStateDB() prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) + prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) cpy := prefetcher.copy() a := prefetcher.trie(common.Hash{}, db.originalRoot) b := cpy.trie(common.Hash{}, db.originalRoot) diff --git a/light/trie.go b/light/trie.go index 0ccab1588d3d..0f05a80004ab 100644 --- a/light/trie.go +++ b/light/trie.go @@ -105,7 +105,7 @@ type odrTrie struct { trie *trie.Trie } -func (t *odrTrie) TryGet(key []byte) ([]byte, error) { +func (t *odrTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { key = crypto.Keccak256(key) var res []byte err := t.do(key, func() (err error) { @@ -142,14 +142,14 @@ func (t *odrTrie) TryUpdateAccount(address common.Address, acc *types.StateAccou }) } -func (t *odrTrie) TryUpdate(key, value []byte) error { +func (t *odrTrie) TryUpdateStorage(_ common.Address, key, value []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryUpdate(key, value) }) } -func (t *odrTrie) TryDelete(key []byte) error { +func (t *odrTrie) TryDeleteStorage(_ common.Address, key []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryDelete(key) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 83b92cebd245..01e004d02ed5 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -75,7 +75,7 @@ func NewStateTrie(id *ID, db *Database) (*StateTrie, error) { // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. func (t *StateTrie) Get(key []byte) []byte { - res, err := t.TryGet(key) + res, err := t.TryGetStorage(common.Address{}, key) if err != nil { log.Error("Unhandled trie error in StateTrie.Get", "err", err) } @@ -86,7 +86,7 @@ func (t *StateTrie) Get(key []byte) []byte { // The value bytes must not be modified by the caller. // If the specified node 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) TryGet(key []byte) ([]byte, error) { +func (t *StateTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { return t.trie.TryGet(t.hashKey(key)) } @@ -131,7 +131,7 @@ func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { // The value bytes must not be modified by the caller while they are // stored in the trie. func (t *StateTrie) Update(key, value []byte) { - if err := t.TryUpdate(key, value); err != nil { + if err := t.TryUpdateStorage(common.Address{}, key, value); err != nil { log.Error("Unhandled trie error in StateTrie.Update", "err", err) } } @@ -144,7 +144,7 @@ func (t *StateTrie) Update(key, value []byte) { // stored in the trie. // // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryUpdate(key, value []byte) error { +func (t *StateTrie) TryUpdateStorage(_ common.Address, key, value []byte) error { hk := t.hashKey(key) err := t.trie.TryUpdate(hk, value) if err != nil { @@ -171,7 +171,7 @@ func (t *StateTrie) TryUpdateAccount(address common.Address, acc *types.StateAcc // Delete removes any existing value for key from the trie. func (t *StateTrie) Delete(key []byte) { - if err := t.TryDelete(key); err != nil { + if err := t.TryDeleteStorage(common.Address{}, key); err != nil { log.Error("Unhandled trie error in StateTrie.Delete", "err", err) } } @@ -179,7 +179,7 @@ func (t *StateTrie) Delete(key []byte) { // TryDelete removes any existing value for key from the trie. // If the specified trie node is not in the trie, nothing will be changed. // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryDelete(key []byte) error { +func (t *StateTrie) TryDeleteStorage(_ common.Address, key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) return t.trie.TryDelete(hk) From 7dc100714d5477296fbeef1f4f58b788d6bab738 Mon Sep 17 00:00:00 2001 From: turboboost55 <7891737+turboboost55@users.noreply.github.com> Date: Thu, 23 Mar 2023 06:13:50 -0700 Subject: [PATCH 659/715] metrics: add cpu counters (#26796) This PR adds counter metrics for the CPU system and the Geth process. Currently the only metrics available for these items are gauges. Gauges are fine when the consumer scrapes metrics data at the same interval as Geth produces new values (every 3 seconds), but it is likely that most consumers will not scrape that often. Intervals of 10, 15, or maybe even 30 seconds are probably more common. So the problem is, how does the consumer estimate what the CPU was doing in between scrapes. With a counter, it's easy ... you just subtract two successive values and divide by the time to get a nice, accurate average. But with a gauge, you can't do that. A gauge reading is an instantaneous picture of what was happening at that moment, but it gives you no idea about what was going on between scrapes. Taking an average of values is meaningless. --- metrics/counter_float64.go | 153 +++++++++++++++++++++++++++ metrics/counter_float_64_test.go | 77 ++++++++++++++ metrics/exp/exp.go | 7 ++ metrics/graphite.go | 2 + metrics/influxdb/influxdb.go | 10 ++ metrics/influxdb/influxdbv2.go | 17 +-- metrics/librato/librato.go | 11 ++ metrics/log.go | 3 + metrics/metrics.go | 19 ++-- metrics/metrics_test.go | 2 + metrics/opentsdb.go | 2 + metrics/prometheus/collector.go | 4 + metrics/prometheus/collector_test.go | 7 ++ metrics/prometheus/prometheus.go | 2 + metrics/registry.go | 4 +- metrics/syslog.go | 2 + metrics/writer.go | 3 + 17 files changed, 312 insertions(+), 13 deletions(-) create mode 100644 metrics/counter_float64.go create mode 100644 metrics/counter_float_64_test.go diff --git a/metrics/counter_float64.go b/metrics/counter_float64.go new file mode 100644 index 000000000000..f05f62fed632 --- /dev/null +++ b/metrics/counter_float64.go @@ -0,0 +1,153 @@ +package metrics + +import ( + "sync" +) + +// CounterFloat64 holds a float64 value that can be incremented and decremented. +type CounterFloat64 interface { + Clear() + Count() float64 + Dec(float64) + Inc(float64) + Snapshot() CounterFloat64 +} + +// GetOrRegisterCounterFloat64 returns an existing CounterFloat64 or constructs and registers +// a new StandardCounterFloat64. +func GetOrRegisterCounterFloat64(name string, r Registry) CounterFloat64 { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewCounterFloat64).(CounterFloat64) +} + +// GetOrRegisterCounterFloat64Forced returns an existing CounterFloat64 or constructs and registers a +// new CounterFloat64 no matter the global switch is enabled or not. +// Be sure to unregister the counter from the registry once it is of no use to +// allow for garbage collection. +func GetOrRegisterCounterFloat64Forced(name string, r Registry) CounterFloat64 { + if nil == r { + r = DefaultRegistry + } + return r.GetOrRegister(name, NewCounterFloat64Forced).(CounterFloat64) +} + +// NewCounterFloat64 constructs a new StandardCounterFloat64. +func NewCounterFloat64() CounterFloat64 { + if !Enabled { + return NilCounterFloat64{} + } + return &StandardCounterFloat64{count: 0.0} +} + +// NewCounterFloat64Forced constructs a new StandardCounterFloat64 and returns it no matter if +// the global switch is enabled or not. +func NewCounterFloat64Forced() CounterFloat64 { + return &StandardCounterFloat64{count: 0.0} +} + +// NewRegisteredCounterFloat64 constructs and registers a new StandardCounterFloat64. +func NewRegisteredCounterFloat64(name string, r Registry) CounterFloat64 { + c := NewCounterFloat64() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// NewRegisteredCounterFloat64Forced constructs and registers a new StandardCounterFloat64 +// and launches a goroutine no matter the global switch is enabled or not. +// Be sure to unregister the counter from the registry once it is of no use to +// allow for garbage collection. +func NewRegisteredCounterFloat64Forced(name string, r Registry) CounterFloat64 { + c := NewCounterFloat64Forced() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// CounterFloat64Snapshot is a read-only copy of another CounterFloat64. +type CounterFloat64Snapshot float64 + +// Clear panics. +func (CounterFloat64Snapshot) Clear() { + panic("Clear called on a CounterFloat64Snapshot") +} + +// Count returns the value at the time the snapshot was taken. +func (c CounterFloat64Snapshot) Count() float64 { return float64(c) } + +// Dec panics. +func (CounterFloat64Snapshot) Dec(float64) { + panic("Dec called on a CounterFloat64Snapshot") +} + +// Inc panics. +func (CounterFloat64Snapshot) Inc(float64) { + panic("Inc called on a CounterFloat64Snapshot") +} + +// Snapshot returns the snapshot. +func (c CounterFloat64Snapshot) Snapshot() CounterFloat64 { return c } + +// NilCounterFloat64 is a no-op CounterFloat64. +type NilCounterFloat64 struct{} + +// Clear is a no-op. +func (NilCounterFloat64) Clear() {} + +// Count is a no-op. +func (NilCounterFloat64) Count() float64 { return 0.0 } + +// Dec is a no-op. +func (NilCounterFloat64) Dec(i float64) {} + +// Inc is a no-op. +func (NilCounterFloat64) Inc(i float64) {} + +// Snapshot is a no-op. +func (NilCounterFloat64) Snapshot() CounterFloat64 { return NilCounterFloat64{} } + +// StandardCounterFloat64 is the standard implementation of a CounterFloat64 and uses the +// sync.Mutex package to manage a single float64 value. +type StandardCounterFloat64 struct { + mutex sync.Mutex + count float64 +} + +// Clear sets the counter to zero. +func (c *StandardCounterFloat64) Clear() { + c.mutex.Lock() + defer c.mutex.Unlock() + c.count = 0.0 +} + +// Count returns the current value. +func (c *StandardCounterFloat64) Count() float64 { + c.mutex.Lock() + defer c.mutex.Unlock() + return c.count +} + +// Dec decrements the counter by the given amount. +func (c *StandardCounterFloat64) Dec(v float64) { + c.mutex.Lock() + defer c.mutex.Unlock() + c.count -= v +} + +// Inc increments the counter by the given amount. +func (c *StandardCounterFloat64) Inc(v float64) { + c.mutex.Lock() + defer c.mutex.Unlock() + c.count += v +} + +// Snapshot returns a read-only copy of the counter. +func (c *StandardCounterFloat64) Snapshot() CounterFloat64 { + return CounterFloat64Snapshot(c.Count()) +} diff --git a/metrics/counter_float_64_test.go b/metrics/counter_float_64_test.go new file mode 100644 index 000000000000..44d9b4c20c85 --- /dev/null +++ b/metrics/counter_float_64_test.go @@ -0,0 +1,77 @@ +package metrics + +import "testing" + +func BenchmarkCounterFloat64(b *testing.B) { + c := NewCounterFloat64() + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Inc(1.0) + } +} + +func TestCounterFloat64Clear(t *testing.T) { + c := NewCounterFloat64() + c.Inc(1.0) + c.Clear() + if count := c.Count(); count != 0 { + t.Errorf("c.Count(): 0 != %v\n", count) + } +} + +func TestCounterFloat64Dec1(t *testing.T) { + c := NewCounterFloat64() + c.Dec(1.0) + if count := c.Count(); count != -1.0 { + t.Errorf("c.Count(): -1.0 != %v\n", count) + } +} + +func TestCounterFloat64Dec2(t *testing.T) { + c := NewCounterFloat64() + c.Dec(2.0) + if count := c.Count(); count != -2.0 { + t.Errorf("c.Count(): -2.0 != %v\n", count) + } +} + +func TestCounterFloat64Inc1(t *testing.T) { + c := NewCounterFloat64() + c.Inc(1.0) + if count := c.Count(); count != 1.0 { + t.Errorf("c.Count(): 1.0 != %v\n", count) + } +} + +func TestCounterFloat64Inc2(t *testing.T) { + c := NewCounterFloat64() + c.Inc(2.0) + if count := c.Count(); count != 2.0 { + t.Errorf("c.Count(): 2.0 != %v\n", count) + } +} + +func TestCounterFloat64Snapshot(t *testing.T) { + c := NewCounterFloat64() + c.Inc(1.0) + snapshot := c.Snapshot() + c.Inc(1.0) + if count := snapshot.Count(); count != 1.0 { + t.Errorf("c.Count(): 1.0 != %v\n", count) + } +} + +func TestCounterFloat64Zero(t *testing.T) { + c := NewCounterFloat64() + if count := c.Count(); count != 0 { + t.Errorf("c.Count(): 0 != %v\n", count) + } +} + +func TestGetOrRegisterCounterFloat64(t *testing.T) { + r := NewRegistry() + NewRegisteredCounterFloat64("foo", r).Inc(47.0) + if c := GetOrRegisterCounterFloat64("foo", r); c.Count() != 47.0 { + t.Fatal(c) + } +} diff --git a/metrics/exp/exp.go b/metrics/exp/exp.go index 3ebe8cc68aad..2b04eeab271f 100644 --- a/metrics/exp/exp.go +++ b/metrics/exp/exp.go @@ -100,6 +100,11 @@ func (exp *exp) publishCounter(name string, metric metrics.Counter) { v.Set(metric.Count()) } +func (exp *exp) publishCounterFloat64(name string, metric metrics.CounterFloat64) { + v := exp.getFloat(name) + v.Set(metric.Count()) +} + func (exp *exp) publishGauge(name string, metric metrics.Gauge) { v := exp.getInt(name) v.Set(metric.Value()) @@ -167,6 +172,8 @@ func (exp *exp) syncToExpvar() { switch i := i.(type) { case metrics.Counter: exp.publishCounter(name, i) + case metrics.CounterFloat64: + exp.publishCounterFloat64(name, i) case metrics.Gauge: exp.publishGauge(name, i) case metrics.GaugeFloat64: diff --git a/metrics/graphite.go b/metrics/graphite.go index 142eec86beb4..29f72b0c4181 100644 --- a/metrics/graphite.go +++ b/metrics/graphite.go @@ -67,6 +67,8 @@ func graphite(c *GraphiteConfig) error { switch metric := i.(type) { case Counter: fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, metric.Count(), now) + case CounterFloat64: + fmt.Fprintf(w, "%s.%s.count %f %d\n", c.Prefix, name, metric.Count(), now) case Gauge: fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Value(), now) case GaugeFloat64: diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go index 748c692e1310..ea6c3d9dff7f 100644 --- a/metrics/influxdb/influxdb.go +++ b/metrics/influxdb/influxdb.go @@ -141,6 +141,16 @@ func (r *reporter) send() error { }, Time: now, }) + case metrics.CounterFloat64: + count := metric.Count() + pts = append(pts, client.Point{ + Measurement: fmt.Sprintf("%s%s.count", namespace, name), + Tags: r.tags, + Fields: map[string]interface{}{ + "value": count, + }, + Time: now, + }) case metrics.Gauge: ms := metric.Snapshot() pts = append(pts, client.Point{ diff --git a/metrics/influxdb/influxdbv2.go b/metrics/influxdb/influxdbv2.go index bfb762196cb3..dc8a42cd5af6 100644 --- a/metrics/influxdb/influxdbv2.go +++ b/metrics/influxdb/influxdbv2.go @@ -24,8 +24,6 @@ type v2Reporter struct { client influxdb2.Client write api.WriteAPI - - cache map[string]int64 } // InfluxDBWithTags starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval with the specified tags @@ -39,7 +37,6 @@ func InfluxDBV2WithTags(r metrics.Registry, d time.Duration, endpoint string, to organization: organization, namespace: namespace, tags: tags, - cache: make(map[string]int64), } rep.client = influxdb2.NewClient(rep.endpoint, rep.token) @@ -86,17 +83,25 @@ func (r *v2Reporter) send() { switch metric := i.(type) { case metrics.Counter: v := metric.Count() - l := r.cache[name] measurement := fmt.Sprintf("%s%s.count", namespace, name) fields := map[string]interface{}{ - "value": v - l, + "value": v, } pt := influxdb2.NewPoint(measurement, r.tags, fields, now) r.write.WritePoint(pt) - r.cache[name] = v + case metrics.CounterFloat64: + v := metric.Count() + + measurement := fmt.Sprintf("%s%s.count", namespace, name) + fields := map[string]interface{}{ + "value": v, + } + + pt := influxdb2.NewPoint(measurement, r.tags, fields, now) + r.write.WritePoint(pt) case metrics.Gauge: ms := metric.Snapshot() diff --git a/metrics/librato/librato.go b/metrics/librato/librato.go index b16493413ee1..3d45f4c7be1b 100644 --- a/metrics/librato/librato.go +++ b/metrics/librato/librato.go @@ -107,6 +107,17 @@ func (rep *Reporter) BuildRequest(now time.Time, r metrics.Registry) (snapshot B } snapshot.Counters = append(snapshot.Counters, measurement) } + case metrics.CounterFloat64: + if m.Count() > 0 { + measurement[Name] = fmt.Sprintf("%s.%s", name, "count") + measurement[Value] = m.Count() + measurement[Attributes] = map[string]interface{}{ + DisplayUnitsLong: Operations, + DisplayUnitsShort: OperationsShort, + DisplayMin: "0", + } + snapshot.Counters = append(snapshot.Counters, measurement) + } case metrics.Gauge: measurement[Name] = name measurement[Value] = float64(m.Value()) diff --git a/metrics/log.go b/metrics/log.go index 0c8ea7c97123..d1ce627a8378 100644 --- a/metrics/log.go +++ b/metrics/log.go @@ -24,6 +24,9 @@ func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) { case Counter: l.Printf("counter %s\n", name) l.Printf(" count: %9d\n", metric.Count()) + case CounterFloat64: + l.Printf("counter %s\n", name) + l.Printf(" count: %f\n", metric.Count()) case Gauge: l.Printf("gauge %s\n", name) l.Printf(" value: %9d\n", metric.Value()) diff --git a/metrics/metrics.go b/metrics/metrics.go index ff7196b56494..c206f1692407 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -144,6 +144,9 @@ func CollectProcessMetrics(refresh time.Duration) { cpuSysLoad = GetOrRegisterGauge("system/cpu/sysload", DefaultRegistry) cpuSysWait = GetOrRegisterGauge("system/cpu/syswait", DefaultRegistry) cpuProcLoad = GetOrRegisterGauge("system/cpu/procload", DefaultRegistry) + cpuSysLoadTotal = GetOrRegisterCounterFloat64("system/cpu/sysload/total", DefaultRegistry) + cpuSysWaitTotal = GetOrRegisterCounterFloat64("system/cpu/syswait/total", DefaultRegistry) + cpuProcLoadTotal = GetOrRegisterCounterFloat64("system/cpu/procload/total", DefaultRegistry) cpuThreads = GetOrRegisterGauge("system/cpu/threads", DefaultRegistry) cpuGoroutines = GetOrRegisterGauge("system/cpu/goroutines", DefaultRegistry) cpuSchedLatency = getOrRegisterRuntimeHistogram("system/cpu/schedlatency", secondsToNs, nil) @@ -172,13 +175,17 @@ func CollectProcessMetrics(refresh time.Duration) { secondsSinceLastCollect := collectTime.Sub(lastCollectTime).Seconds() lastCollectTime = collectTime if secondsSinceLastCollect > 0 { - sysLoad := (cpustats[now].GlobalTime - cpustats[prev].GlobalTime) / secondsSinceLastCollect - sysWait := (cpustats[now].GlobalWait - cpustats[prev].GlobalWait) / secondsSinceLastCollect - procLoad := (cpustats[now].LocalTime - cpustats[prev].LocalTime) / secondsSinceLastCollect + sysLoad := cpustats[now].GlobalTime - cpustats[prev].GlobalTime + sysWait := cpustats[now].GlobalWait - cpustats[prev].GlobalWait + procLoad := cpustats[now].LocalTime - cpustats[prev].LocalTime // Convert to integer percentage. - cpuSysLoad.Update(int64(sysLoad * 100)) - cpuSysWait.Update(int64(sysWait * 100)) - cpuProcLoad.Update(int64(procLoad * 100)) + cpuSysLoad.Update(int64(sysLoad / secondsSinceLastCollect * 100)) + cpuSysWait.Update(int64(sysWait / secondsSinceLastCollect * 100)) + cpuProcLoad.Update(int64(procLoad / secondsSinceLastCollect * 100)) + // increment counters (ms) + cpuSysLoadTotal.Inc(sysLoad) + cpuSysWaitTotal.Inc(sysWait) + cpuProcLoadTotal.Inc(procLoad) } // Threads diff --git a/metrics/metrics_test.go b/metrics/metrics_test.go index e3fde1ea62ce..534c44139b36 100644 --- a/metrics/metrics_test.go +++ b/metrics/metrics_test.go @@ -18,6 +18,7 @@ func TestReadRuntimeValues(t *testing.T) { func BenchmarkMetrics(b *testing.B) { r := NewRegistry() c := NewRegisteredCounter("counter", r) + cf := NewRegisteredCounterFloat64("counterfloat64", r) g := NewRegisteredGauge("gauge", r) gf := NewRegisteredGaugeFloat64("gaugefloat64", r) h := NewRegisteredHistogram("histogram", r, NewUniformSample(100)) @@ -71,6 +72,7 @@ func BenchmarkMetrics(b *testing.B) { //log.Println("go", i) for i := 0; i < b.N; i++ { c.Inc(1) + cf.Inc(1.0) g.Update(int64(i)) gf.Update(float64(i)) h.Update(int64(i)) diff --git a/metrics/opentsdb.go b/metrics/opentsdb.go index 3fde55454ba9..c9fd2e75d5e5 100644 --- a/metrics/opentsdb.go +++ b/metrics/opentsdb.go @@ -71,6 +71,8 @@ func openTSDB(c *OpenTSDBConfig) error { switch metric := i.(type) { case Counter: fmt.Fprintf(w, "put %s.%s.count %d %d host=%s\n", c.Prefix, name, now, metric.Count(), shortHostname) + case CounterFloat64: + fmt.Fprintf(w, "put %s.%s.count %d %f host=%s\n", c.Prefix, name, now, metric.Count(), shortHostname) case Gauge: fmt.Fprintf(w, "put %s.%s.value %d %d host=%s\n", c.Prefix, name, now, metric.Value(), shortHostname) case GaugeFloat64: diff --git a/metrics/prometheus/collector.go b/metrics/prometheus/collector.go index e8d5e4f5d1ea..2bd9bf22ccae 100644 --- a/metrics/prometheus/collector.go +++ b/metrics/prometheus/collector.go @@ -50,6 +50,10 @@ func (c *collector) addCounter(name string, m metrics.Counter) { c.writeGaugeCounter(name, m.Count()) } +func (c *collector) addCounterFloat64(name string, m metrics.CounterFloat64) { + c.writeGaugeCounter(name, m.Count()) +} + func (c *collector) addGauge(name string, m metrics.Gauge) { c.writeGaugeCounter(name, m.Value()) } diff --git a/metrics/prometheus/collector_test.go b/metrics/prometheus/collector_test.go index 43f2f804d32e..ff87c8e765e1 100644 --- a/metrics/prometheus/collector_test.go +++ b/metrics/prometheus/collector_test.go @@ -20,6 +20,10 @@ func TestCollector(t *testing.T) { counter.Inc(12345) c.addCounter("test/counter", counter) + counterfloat64 := metrics.NewCounterFloat64() + counterfloat64.Inc(54321.98) + c.addCounterFloat64("test/counter_float64", counterfloat64) + gauge := metrics.NewGauge() gauge.Update(23456) c.addGauge("test/gauge", gauge) @@ -61,6 +65,9 @@ func TestCollector(t *testing.T) { const expectedOutput = `# TYPE test_counter gauge test_counter 12345 +# TYPE test_counter_float64 gauge +test_counter_float64 54321.98 + # TYPE test_gauge gauge test_gauge 23456 diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index c8408d8cab85..d966fa9a8666 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -45,6 +45,8 @@ func Handler(reg metrics.Registry) http.Handler { switch m := i.(type) { case metrics.Counter: c.addCounter(name, m.Snapshot()) + case metrics.CounterFloat64: + c.addCounterFloat64(name, m.Snapshot()) case metrics.Gauge: c.addGauge(name, m.Snapshot()) case metrics.GaugeFloat64: diff --git a/metrics/registry.go b/metrics/registry.go index c5435adf2402..4c62248351a7 100644 --- a/metrics/registry.go +++ b/metrics/registry.go @@ -120,6 +120,8 @@ func (r *StandardRegistry) GetAll() map[string]map[string]interface{} { switch metric := i.(type) { case Counter: values["count"] = metric.Count() + case CounterFloat64: + values["count"] = metric.Count() case Gauge: values["value"] = metric.Value() case GaugeFloat64: @@ -196,7 +198,7 @@ func (r *StandardRegistry) register(name string, i interface{}) error { return DuplicateMetric(name) } switch i.(type) { - case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer: + case Counter, CounterFloat64, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer: r.metrics[name] = i } return nil diff --git a/metrics/syslog.go b/metrics/syslog.go index 551a2bd0f072..f23b07e199f3 100644 --- a/metrics/syslog.go +++ b/metrics/syslog.go @@ -17,6 +17,8 @@ func Syslog(r Registry, d time.Duration, w *syslog.Writer) { switch metric := i.(type) { case Counter: w.Info(fmt.Sprintf("counter %s: count: %d", name, metric.Count())) + case CounterFloat64: + w.Info(fmt.Sprintf("counter %s: count: %f", name, metric.Count())) case Gauge: w.Info(fmt.Sprintf("gauge %s: value: %d", name, metric.Value())) case GaugeFloat64: diff --git a/metrics/writer.go b/metrics/writer.go index 88521a80d9d7..256fbd14c9b9 100644 --- a/metrics/writer.go +++ b/metrics/writer.go @@ -29,6 +29,9 @@ func WriteOnce(r Registry, w io.Writer) { case Counter: fmt.Fprintf(w, "counter %s\n", namedMetric.name) fmt.Fprintf(w, " count: %9d\n", metric.Count()) + case CounterFloat64: + fmt.Fprintf(w, "counter %s\n", namedMetric.name) + fmt.Fprintf(w, " count: %f\n", metric.Count()) case Gauge: fmt.Fprintf(w, "gauge %s\n", namedMetric.name) fmt.Fprintf(w, " value: %9d\n", metric.Value()) From f6c3a534a49f6ba0f8abc6b6a7de8d2d9a6ed555 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 23 Mar 2023 15:12:32 -0400 Subject: [PATCH 660/715] metrics/influxdb: use smaller dependency and reuse code between v1 and v2 reporters (#26963) This change switches to use the smaller influxdata/influxdb1-client package instead of depending on the whole infuxdb package. The new smaller client is very similar to the influxdb-v2 client, which made it possible to refactor the two reporters to reuse code a lot more. --- go.mod | 2 +- go.sum | 241 +--------------------- metrics/influxdb/influxdb.go | 360 +++++++++------------------------ metrics/influxdb/influxdbv1.go | 145 +++++++++++++ metrics/influxdb/influxdbv2.go | 142 +------------ 5 files changed, 254 insertions(+), 636 deletions(-) create mode 100644 metrics/influxdb/influxdbv1.go diff --git a/go.mod b/go.mod index 26519b80480d..29e8c22723f7 100644 --- a/go.mod +++ b/go.mod @@ -38,8 +38,8 @@ require ( github.com/holiman/bloomfilter/v2 v2.0.3 github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c github.com/huin/goupnp v1.0.3 - github.com/influxdata/influxdb v1.8.3 github.com/influxdata/influxdb-client-go/v2 v2.4.0 + github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/julienschmidt/httprouter v1.3.0 diff --git a/go.sum b/go.sum index 4491e0189179..229ecef206a0 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,4 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 h1:qoVeMsc9/fh/yhxVaA0obYjVH/oI/ihrOoMwsLS9KSA= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= @@ -26,27 +7,19 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= -github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go-v2 v1.2.0 h1:BS+UYpbsElC82gB+2E2jiCBg36i8HlubTB/dO/moQ9c= github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= @@ -67,26 +40,17 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxq github.com/aws/smithy-go v1.1.0 h1:D6CSsM3gdxaGaqXnPgOBCeL6Mophqzu7KJOu7zW78sU= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= @@ -118,7 +82,6 @@ github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 h1:6IrxszG5G+O github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= -github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -133,7 +96,6 @@ github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbz github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= @@ -149,7 +111,6 @@ github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOG github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= @@ -166,7 +127,6 @@ github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= @@ -186,17 +146,10 @@ github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnR github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= -github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= @@ -204,8 +157,6 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -213,26 +164,17 @@ github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -247,15 +189,11 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -269,17 +207,10 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -290,8 +221,6 @@ github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLt github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= @@ -306,23 +235,15 @@ github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= -github.com/influxdata/influxdb v1.8.3 h1:WEypI1BQFTT4teLM+1qkEcvUi0dAvopAI/ir0vAiBg8= -github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= -github.com/influxdata/influxql v1.1.1-0.20200828144457-65d3ef77d385/go.mod h1:gHp9y86a/pxhjJ+zMjNXiQAA197Xk9wLxaz+fGG+kWk= -github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsDSy7TDxedi9gyBkMvAirat/oRcL0lFdJBf6tdM= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= -github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= -github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= -github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -336,15 +257,9 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= @@ -353,20 +268,13 @@ github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYb github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= -github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= -github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -383,19 +291,16 @@ github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awS github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= @@ -406,10 +311,7 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= @@ -429,8 +331,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= @@ -451,46 +351,28 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= -github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= @@ -503,19 +385,14 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= -github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -523,9 +400,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -538,7 +413,6 @@ github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCA github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= @@ -558,11 +432,9 @@ github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBn github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= @@ -573,17 +445,8 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -595,34 +458,13 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -632,19 +474,13 @@ golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -663,10 +499,6 @@ golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -678,28 +510,17 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -728,7 +549,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -737,40 +557,20 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -783,48 +583,17 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -840,7 +609,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -870,11 +638,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go index ea6c3d9dff7f..5dfbbab3edeb 100644 --- a/metrics/influxdb/influxdb.go +++ b/metrics/influxdb/influxdb.go @@ -2,270 +2,112 @@ package influxdb import ( "fmt" - uurl "net/url" - "time" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" - "github.com/influxdata/influxdb/client" ) -type reporter struct { - reg metrics.Registry - interval time.Duration - - url uurl.URL - database string - username string - password string - namespace string - tags map[string]string - - client *client.Client - - cache map[string]int64 -} - -// InfluxDB starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval. -func InfluxDB(r metrics.Registry, d time.Duration, url, database, username, password, namespace string) { - InfluxDBWithTags(r, d, url, database, username, password, namespace, nil) -} - -// InfluxDBWithTags starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval with the specified tags -func InfluxDBWithTags(r metrics.Registry, d time.Duration, url, database, username, password, namespace string, tags map[string]string) { - u, err := uurl.Parse(url) - if err != nil { - log.Warn("Unable to parse InfluxDB", "url", url, "err", err) - return - } - - rep := &reporter{ - reg: r, - interval: d, - url: *u, - database: database, - username: username, - password: password, - namespace: namespace, - tags: tags, - cache: make(map[string]int64), - } - if err := rep.makeClient(); err != nil { - log.Warn("Unable to make InfluxDB client", "err", err) - return - } - - rep.run() -} - -// InfluxDBWithTagsOnce runs once an InfluxDB reporter and post the given metrics.Registry with the specified tags -func InfluxDBWithTagsOnce(r metrics.Registry, url, database, username, password, namespace string, tags map[string]string) error { - u, err := uurl.Parse(url) - if err != nil { - return fmt.Errorf("unable to parse InfluxDB. url: %s, err: %v", url, err) - } - - rep := &reporter{ - reg: r, - url: *u, - database: database, - username: username, - password: password, - namespace: namespace, - tags: tags, - cache: make(map[string]int64), - } - if err := rep.makeClient(); err != nil { - return fmt.Errorf("unable to make InfluxDB client. err: %v", err) - } - - if err := rep.send(); err != nil { - return fmt.Errorf("unable to send to InfluxDB. err: %v", err) - } - - return nil -} - -func (r *reporter) makeClient() (err error) { - r.client, err = client.NewClient(client.Config{ - URL: r.url, - Username: r.username, - Password: r.password, - Timeout: 10 * time.Second, - }) - - return -} - -func (r *reporter) run() { - intervalTicker := time.NewTicker(r.interval) - pingTicker := time.NewTicker(time.Second * 5) - - defer intervalTicker.Stop() - defer pingTicker.Stop() - - for { - select { - case <-intervalTicker.C: - if err := r.send(); err != nil { - log.Warn("Unable to send to InfluxDB", "err", err) - } - case <-pingTicker.C: - _, _, err := r.client.Ping() - if err != nil { - log.Warn("Got error while sending a ping to InfluxDB, trying to recreate client", "err", err) - - if err = r.makeClient(); err != nil { - log.Warn("Unable to make InfluxDB client", "err", err) - } - } +func readMeter(namespace, name string, i interface{}) (string, map[string]interface{}) { + switch metric := i.(type) { + case metrics.Counter: + measurement := fmt.Sprintf("%s%s.count", namespace, name) + fields := map[string]interface{}{ + "value": metric.Count(), } - } -} - -func (r *reporter) send() error { - var pts []client.Point - - r.reg.Each(func(name string, i interface{}) { - now := time.Now() - namespace := r.namespace - - switch metric := i.(type) { - case metrics.Counter: - count := metric.Count() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.count", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "value": count, - }, - Time: now, - }) - case metrics.CounterFloat64: - count := metric.Count() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.count", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "value": count, - }, - Time: now, - }) - case metrics.Gauge: - ms := metric.Snapshot() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.gauge", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "value": ms.Value(), - }, - Time: now, - }) - case metrics.GaugeFloat64: - ms := metric.Snapshot() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.gauge", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "value": ms.Value(), - }, - Time: now, - }) - case metrics.Histogram: - ms := metric.Snapshot() - if ms.Count() > 0 { - ps := ms.Percentiles([]float64{0.25, 0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) - fields := map[string]interface{}{ - "count": ms.Count(), - "max": ms.Max(), - "mean": ms.Mean(), - "min": ms.Min(), - "stddev": ms.StdDev(), - "variance": ms.Variance(), - "p25": ps[0], - "p50": ps[1], - "p75": ps[2], - "p95": ps[3], - "p99": ps[4], - "p999": ps[5], - "p9999": ps[6], - } - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.histogram", namespace, name), - Tags: r.tags, - Fields: fields, - Time: now, - }) - } - case metrics.Meter: - ms := metric.Snapshot() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.meter", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "count": ms.Count(), - "m1": ms.Rate1(), - "m5": ms.Rate5(), - "m15": ms.Rate15(), - "mean": ms.RateMean(), - }, - Time: now, - }) - case metrics.Timer: - ms := metric.Snapshot() - ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.timer", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "count": ms.Count(), - "max": ms.Max(), - "mean": ms.Mean(), - "min": ms.Min(), - "stddev": ms.StdDev(), - "variance": ms.Variance(), - "p50": ps[0], - "p75": ps[1], - "p95": ps[2], - "p99": ps[3], - "p999": ps[4], - "p9999": ps[5], - "m1": ms.Rate1(), - "m5": ms.Rate5(), - "m15": ms.Rate15(), - "meanrate": ms.RateMean(), - }, - Time: now, - }) - case metrics.ResettingTimer: - t := metric.Snapshot() - - if len(t.Values()) > 0 { - ps := t.Percentiles([]float64{50, 95, 99}) - val := t.Values() - pts = append(pts, client.Point{ - Measurement: fmt.Sprintf("%s%s.span", namespace, name), - Tags: r.tags, - Fields: map[string]interface{}{ - "count": len(val), - "max": val[len(val)-1], - "mean": t.Mean(), - "min": val[0], - "p50": ps[0], - "p95": ps[1], - "p99": ps[2], - }, - Time: now, - }) - } + return measurement, fields + case metrics.CounterFloat64: + measurement := fmt.Sprintf("%s%s.count", namespace, name) + fields := map[string]interface{}{ + "value": metric.Count(), } - }) - - bps := client.BatchPoints{ - Points: pts, - Database: r.database, + return measurement, fields + case metrics.Gauge: + measurement := fmt.Sprintf("%s%s.gauge", namespace, name) + fields := map[string]interface{}{ + "value": metric.Snapshot().Value(), + } + return measurement, fields + case metrics.GaugeFloat64: + measurement := fmt.Sprintf("%s%s.gauge", namespace, name) + fields := map[string]interface{}{ + "value": metric.Snapshot().Value(), + } + return measurement, fields + case metrics.Histogram: + ms := metric.Snapshot() + if ms.Count() <= 0 { + break + } + ps := ms.Percentiles([]float64{0.25, 0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) + measurement := fmt.Sprintf("%s%s.histogram", namespace, name) + fields := map[string]interface{}{ + "count": ms.Count(), + "max": ms.Max(), + "mean": ms.Mean(), + "min": ms.Min(), + "stddev": ms.StdDev(), + "variance": ms.Variance(), + "p25": ps[0], + "p50": ps[1], + "p75": ps[2], + "p95": ps[3], + "p99": ps[4], + "p999": ps[5], + "p9999": ps[6], + } + return measurement, fields + case metrics.Meter: + ms := metric.Snapshot() + measurement := fmt.Sprintf("%s%s.meter", namespace, name) + fields := map[string]interface{}{ + "count": ms.Count(), + "m1": ms.Rate1(), + "m5": ms.Rate5(), + "m15": ms.Rate15(), + "mean": ms.RateMean(), + } + return measurement, fields + case metrics.Timer: + ms := metric.Snapshot() + ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) + + measurement := fmt.Sprintf("%s%s.timer", namespace, name) + fields := map[string]interface{}{ + "count": ms.Count(), + "max": ms.Max(), + "mean": ms.Mean(), + "min": ms.Min(), + "stddev": ms.StdDev(), + "variance": ms.Variance(), + "p50": ps[0], + "p75": ps[1], + "p95": ps[2], + "p99": ps[3], + "p999": ps[4], + "p9999": ps[5], + "m1": ms.Rate1(), + "m5": ms.Rate5(), + "m15": ms.Rate15(), + "meanrate": ms.RateMean(), + } + return measurement, fields + case metrics.ResettingTimer: + t := metric.Snapshot() + if len(t.Values()) == 0 { + break + } + ps := t.Percentiles([]float64{50, 95, 99}) + val := t.Values() + measurement := fmt.Sprintf("%s%s.span", namespace, name) + fields := map[string]interface{}{ + "count": len(val), + "max": val[len(val)-1], + "mean": t.Mean(), + "min": val[0], + "p50": ps[0], + "p95": ps[1], + "p99": ps[2], + } + return measurement, fields } - - _, err := r.client.Write(bps) - return err + return "", nil } diff --git a/metrics/influxdb/influxdbv1.go b/metrics/influxdb/influxdbv1.go new file mode 100644 index 000000000000..f65d30ef9590 --- /dev/null +++ b/metrics/influxdb/influxdbv1.go @@ -0,0 +1,145 @@ +package influxdb + +import ( + "fmt" + uurl "net/url" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" + client "github.com/influxdata/influxdb1-client/v2" +) + +type reporter struct { + reg metrics.Registry + interval time.Duration + + url uurl.URL + database string + username string + password string + namespace string + tags map[string]string + + client client.Client + + cache map[string]int64 +} + +// InfluxDB starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval. +func InfluxDB(r metrics.Registry, d time.Duration, url, database, username, password, namespace string) { + InfluxDBWithTags(r, d, url, database, username, password, namespace, nil) +} + +// InfluxDBWithTags starts a InfluxDB reporter which will post the from the given metrics.Registry at each d interval with the specified tags +func InfluxDBWithTags(r metrics.Registry, d time.Duration, url, database, username, password, namespace string, tags map[string]string) { + u, err := uurl.Parse(url) + if err != nil { + log.Warn("Unable to parse InfluxDB", "url", url, "err", err) + return + } + + rep := &reporter{ + reg: r, + interval: d, + url: *u, + database: database, + username: username, + password: password, + namespace: namespace, + tags: tags, + cache: make(map[string]int64), + } + if err := rep.makeClient(); err != nil { + log.Warn("Unable to make InfluxDB client", "err", err) + return + } + + rep.run() +} + +// InfluxDBWithTagsOnce runs once an InfluxDB reporter and post the given metrics.Registry with the specified tags +func InfluxDBWithTagsOnce(r metrics.Registry, url, database, username, password, namespace string, tags map[string]string) error { + u, err := uurl.Parse(url) + if err != nil { + return fmt.Errorf("unable to parse InfluxDB. url: %s, err: %v", url, err) + } + + rep := &reporter{ + reg: r, + url: *u, + database: database, + username: username, + password: password, + namespace: namespace, + tags: tags, + cache: make(map[string]int64), + } + if err := rep.makeClient(); err != nil { + return fmt.Errorf("unable to make InfluxDB client. err: %v", err) + } + + if err := rep.send(); err != nil { + return fmt.Errorf("unable to send to InfluxDB. err: %v", err) + } + + return nil +} + +func (r *reporter) makeClient() (err error) { + r.client, err = client.NewHTTPClient(client.HTTPConfig{ + Addr: r.url.String(), + Username: r.username, + Password: r.password, + Timeout: 10 * time.Second, + }) + + return +} + +func (r *reporter) run() { + intervalTicker := time.NewTicker(r.interval) + pingTicker := time.NewTicker(time.Second * 5) + + defer intervalTicker.Stop() + defer pingTicker.Stop() + + for { + select { + case <-intervalTicker.C: + if err := r.send(); err != nil { + log.Warn("Unable to send to InfluxDB", "err", err) + } + case <-pingTicker.C: + _, _, err := r.client.Ping(0) + if err != nil { + log.Warn("Got error while sending a ping to InfluxDB, trying to recreate client", "err", err) + + if err = r.makeClient(); err != nil { + log.Warn("Unable to make InfluxDB client", "err", err) + } + } + } + } +} + +func (r *reporter) send() error { + bps, err := client.NewBatchPoints( + client.BatchPointsConfig{ + Database: r.database, + }) + if err != nil { + return err + } + r.reg.Each(func(name string, i interface{}) { + now := time.Now() + measurement, fields := readMeter(r.namespace, name, i) + if fields == nil { + return + } + if p, err := client.NewPoint(measurement, r.tags, fields, now); err == nil { + bps.AddPoint(p) + } + }) + return r.client.Write(bps) +} diff --git a/metrics/influxdb/influxdbv2.go b/metrics/influxdb/influxdbv2.go index dc8a42cd5af6..7984898f3259 100644 --- a/metrics/influxdb/influxdbv2.go +++ b/metrics/influxdb/influxdbv2.go @@ -2,7 +2,6 @@ package influxdb import ( "context" - "fmt" "time" "github.com/ethereum/go-ethereum/log" @@ -78,144 +77,13 @@ func (r *v2Reporter) run() { func (r *v2Reporter) send() { r.reg.Each(func(name string, i interface{}) { now := time.Now() - namespace := r.namespace - - switch metric := i.(type) { - case metrics.Counter: - v := metric.Count() - - measurement := fmt.Sprintf("%s%s.count", namespace, name) - fields := map[string]interface{}{ - "value": v, - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.CounterFloat64: - v := metric.Count() - - measurement := fmt.Sprintf("%s%s.count", namespace, name) - fields := map[string]interface{}{ - "value": v, - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.Gauge: - ms := metric.Snapshot() - - measurement := fmt.Sprintf("%s%s.gauge", namespace, name) - fields := map[string]interface{}{ - "value": ms.Value(), - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.GaugeFloat64: - ms := metric.Snapshot() - - measurement := fmt.Sprintf("%s%s.gauge", namespace, name) - fields := map[string]interface{}{ - "value": ms.Value(), - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.Histogram: - ms := metric.Snapshot() - - if ms.Count() > 0 { - ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) - measurement := fmt.Sprintf("%s%s.histogram", namespace, name) - fields := map[string]interface{}{ - "count": ms.Count(), - "max": ms.Max(), - "mean": ms.Mean(), - "min": ms.Min(), - "stddev": ms.StdDev(), - "variance": ms.Variance(), - "p50": ps[0], - "p75": ps[1], - "p95": ps[2], - "p99": ps[3], - "p999": ps[4], - "p9999": ps[5], - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - } - - case metrics.Meter: - ms := metric.Snapshot() - - measurement := fmt.Sprintf("%s%s.meter", namespace, name) - fields := map[string]interface{}{ - "count": ms.Count(), - "m1": ms.Rate1(), - "m5": ms.Rate5(), - "m15": ms.Rate15(), - "mean": ms.RateMean(), - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.Timer: - ms := metric.Snapshot() - ps := ms.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}) - - measurement := fmt.Sprintf("%s%s.timer", namespace, name) - fields := map[string]interface{}{ - "count": ms.Count(), - "max": ms.Max(), - "mean": ms.Mean(), - "min": ms.Min(), - "stddev": ms.StdDev(), - "variance": ms.Variance(), - "p50": ps[0], - "p75": ps[1], - "p95": ps[2], - "p99": ps[3], - "p999": ps[4], - "p9999": ps[5], - "m1": ms.Rate1(), - "m5": ms.Rate5(), - "m15": ms.Rate15(), - "meanrate": ms.RateMean(), - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - - case metrics.ResettingTimer: - t := metric.Snapshot() - - if len(t.Values()) > 0 { - ps := t.Percentiles([]float64{50, 95, 99}) - val := t.Values() - - measurement := fmt.Sprintf("%s%s.span", namespace, name) - fields := map[string]interface{}{ - "count": len(val), - "max": val[len(val)-1], - "mean": t.Mean(), - "min": val[0], - "p50": ps[0], - "p95": ps[1], - "p99": ps[2], - } - - pt := influxdb2.NewPoint(measurement, r.tags, fields, now) - r.write.WritePoint(pt) - } + measurement, fields := readMeter(r.namespace, name, i) + if fields == nil { + return } + pt := influxdb2.NewPoint(measurement, r.tags, fields, now) + r.write.WritePoint(pt) }) - // Force all unwritten data to be sent r.write.Flush() } From b1acaf47aa3cbd91241605850381bb4dadecfbea Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Thu, 23 Mar 2023 16:12:37 -0400 Subject: [PATCH 661/715] eth/gasprice: change feehistory input type from int to uint64 (#26922) Change input param type from int to uint64 --- eth/api_backend.go | 2 +- eth/gasprice/feehistory.go | 14 +++++++------- eth/gasprice/feehistory_test.go | 4 ++-- eth/gasprice/gasprice.go | 6 +++--- internal/ethapi/api.go | 2 +- internal/ethapi/backend.go | 2 +- internal/ethapi/transaction_args_test.go | 2 +- les/api_backend.go | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index 643f6369df0e..ac160b0736a1 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -327,7 +327,7 @@ func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) return b.gpo.SuggestTipCap(ctx) } -func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { +func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { return b.gpo.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles) } diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 47cc31999e01..82edf9a7fb05 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -142,7 +142,7 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { // also returned if requested and available. // Note: an error is only returned if retrieving the head header has failed. If there are no // retrievable blocks in the specified range then zero block count is returned with no error. -func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNumber, blocks int) (*types.Block, []*types.Receipt, uint64, int, error) { +func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNumber, blocks uint64) (*types.Block, []*types.Receipt, uint64, uint64, error) { var ( headBlock *types.Header pendingBlock *types.Block @@ -200,8 +200,8 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNum return nil, nil, 0, 0, nil } // Ensure not trying to retrieve before genesis. - if int(reqEnd+1) < blocks { - blocks = int(reqEnd + 1) + if uint64(reqEnd+1) < blocks { + blocks = uint64(reqEnd + 1) } return pendingBlock, pendingReceipts, uint64(reqEnd), blocks, nil } @@ -220,7 +220,7 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNum // // Note: baseFee includes the next block after the newest of the returned range, because this // value can be derived from the newest block. -func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { +func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedLastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { if blocks < 1 { return common.Big0, nil, nil, nil, nil // returning with no data and no error means there are no retrievable blocks } @@ -249,7 +249,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast if err != nil || blocks == 0 { return common.Big0, nil, nil, nil, err } - oldestBlock := lastBlock + 1 - uint64(blocks) + oldestBlock := lastBlock + 1 - blocks var ( next = oldestBlock @@ -259,7 +259,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast for i, p := range rewardPercentiles { binary.LittleEndian.PutUint64(percentileKey[i*8:(i+1)*8], math.Float64bits(p)) } - for i := 0; i < maxBlockFetchers && i < blocks; i++ { + for i := 0; i < maxBlockFetchers && i < int(blocks); i++ { go func() { for { // Retrieve the next block number to fetch with this goroutine @@ -314,7 +314,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast if fees.err != nil { return common.Big0, nil, nil, nil, fees.err } - i := int(fees.blockNumber - oldestBlock) + i := fees.blockNumber - oldestBlock if fees.results.baseFee != nil { reward[i], baseFee[i], baseFee[i+1], gasUsedRatio[i] = fees.results.reward, fees.results.baseFee, fees.results.nextBaseFee, fees.results.gasUsedRatio } else { diff --git a/eth/gasprice/feehistory_test.go b/eth/gasprice/feehistory_test.go index b54874d68847..1bcfb287a571 100644 --- a/eth/gasprice/feehistory_test.go +++ b/eth/gasprice/feehistory_test.go @@ -28,8 +28,8 @@ import ( func TestFeeHistory(t *testing.T) { var cases = []struct { pending bool - maxHeader, maxBlock int - count int + maxHeader, maxBlock uint64 + count uint64 last rpc.BlockNumber percent []float64 expFirst uint64 diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 604ad5e10432..8e98a3409bac 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -42,8 +42,8 @@ var ( type Config struct { Blocks int Percentile int - MaxHeaderHistory int - MaxBlockHistory int + MaxHeaderHistory uint64 + MaxBlockHistory uint64 Default *big.Int `toml:",omitempty"` MaxPrice *big.Int `toml:",omitempty"` IgnorePrice *big.Int `toml:",omitempty"` @@ -71,7 +71,7 @@ type Oracle struct { fetchLock sync.Mutex checkBlocks, percentile int - maxHeaderHistory, maxBlockHistory int + maxHeaderHistory, maxBlockHistory uint64 historyCache *lru.Cache[cacheKey, processedFees] } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 0cf29e5fe642..4e3985530996 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -89,7 +89,7 @@ type feeHistoryResult struct { // FeeHistory returns the fee market history. func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { - oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, int(blockCount), lastBlock, rewardPercentiles) + oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, uint64(blockCount), lastBlock, rewardPercentiles) if err != nil { return nil, err } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 98887afc803f..0249c8664d3c 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -44,7 +44,7 @@ type Backend interface { SyncProgress() ethereum.SyncProgress SuggestGasTipCap(ctx context.Context) (*big.Int, error) - FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) + FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) ChainDb() ethdb.Database AccountManager() *accounts.Manager ExtRPCEnabled() bool diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 1b533861d5d6..24c15b777560 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -258,7 +258,7 @@ func (b *backendMock) ChainConfig() *params.ChainConfig { return b.config } // Other methods needed to implement Backend interface. func (b *backendMock) SyncProgress() ethereum.SyncProgress { return ethereum.SyncProgress{} } -func (b *backendMock) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { +func (b *backendMock) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { return nil, nil, nil, nil, nil } func (b *backendMock) ChainDb() ethdb.Database { return nil } diff --git a/les/api_backend.go b/les/api_backend.go index 4b0369845a5a..2d1fccd9ad43 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -272,7 +272,7 @@ func (b *LesApiBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) return b.gpo.SuggestTipCap(ctx) } -func (b *LesApiBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { +func (b *LesApiBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { return b.gpo.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles) } From 0137bd69c55ca1edd42c533e543297493d3182ff Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 24 Mar 2023 07:39:20 -0400 Subject: [PATCH 662/715] go.mod: update golang.org/x/tools (#26960) --- go.mod | 10 +++++----- go.sum | 24 ++++++++++-------------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 29e8c22723f7..95c80c6fd8b1 100644 --- a/go.mod +++ b/go.mod @@ -61,10 +61,10 @@ require ( golang.org/x/crypto v0.1.0 golang.org/x/exp v0.0.0-20230206171751-46f607a40771 golang.org/x/sync v0.1.0 - golang.org/x/sys v0.5.0 - golang.org/x/text v0.7.0 + golang.org/x/sys v0.6.0 + golang.org/x/text v0.8.0 golang.org/x/time v0.0.0-20220922220347-f3bd1da661af - golang.org/x/tools v0.2.0 + golang.org/x/tools v0.7.0 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce ) @@ -116,8 +116,8 @@ require ( github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/mod v0.6.0 // indirect - golang.org/x/net v0.4.0 // indirect + golang.org/x/mod v0.9.0 // indirect + golang.org/x/net v0.8.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 229ecef206a0..4c134a277221 100644 --- a/go.sum +++ b/go.sum @@ -224,10 +224,6 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= -github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o= -github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -469,8 +465,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -496,8 +492,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -544,8 +540,8 @@ golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -555,8 +551,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= @@ -575,8 +571,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 792d893ed01cd70f3253fa3f6834e1fbf7bee13c Mon Sep 17 00:00:00 2001 From: ucwong Date: Fri, 24 Mar 2023 07:17:39 -0600 Subject: [PATCH 663/715] rlp/rlpgen: print want/expect output string if mismatch (#26932) Co-authored-by: Marius van der Wijden --- rlp/rlpgen/gen_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rlp/rlpgen/gen_test.go b/rlp/rlpgen/gen_test.go index ff3b8385ae16..3b4f5df28765 100644 --- a/rlp/rlpgen/gen_test.go +++ b/rlp/rlpgen/gen_test.go @@ -75,7 +75,7 @@ func TestOutput(t *testing.T) { t.Fatal("error loading expected test output:", err) } if !bytes.Equal(output, wantOutput) { - t.Fatal("output mismatch:\n", string(output)) + t.Fatalf("output mismatch, want: %v got %v", string(wantOutput), string(output)) } }) } From df383addee1df80d899b9dc32e3761ce68228606 Mon Sep 17 00:00:00 2001 From: norwnd <112318969+norwnd@users.noreply.github.com> Date: Sun, 26 Mar 2023 00:38:43 +0300 Subject: [PATCH 664/715] ethclient: ensure returned subscription is nil on error (#26976) --- ethclient/ethclient.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index c8353b25ae21..47beaf63cc0e 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -320,7 +320,14 @@ func (ec *Client) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, err // SubscribeNewHead subscribes to notifications about the current blockchain head // on the given channel. func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) { - return ec.c.EthSubscribe(ctx, ch, "newHeads") + sub, err := ec.c.EthSubscribe(ctx, ch, "newHeads") + if err != nil { + // Defensively prefer returning nil interface explicitly on error-path, instead + // of letting default golang behavior wrap it with non-nil interface that stores + // nil concrete type value. + return nil, err + } + return sub, nil } // State Access @@ -389,7 +396,14 @@ func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuer if err != nil { return nil, err } - return ec.c.EthSubscribe(ctx, ch, "logs", arg) + sub, err := ec.c.EthSubscribe(ctx, ch, "logs", arg) + if err != nil { + // Defensively prefer returning nil interface explicitly on error-path, instead + // of letting default golang behavior wrap it with non-nil interface that stores + // nil concrete type value. + return nil, err + } + return sub, nil } func toFilterArg(q ethereum.FilterQuery) (interface{}, error) { From 41f89ca94423fad523a4427c9af2c327fe344fe2 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:48:46 +0200 Subject: [PATCH 665/715] core/state, trie: remove Try prefix in Trie accessors (#26975) This change renames StateTrie methods to remove the Try* prefix. We added the Trie methods with prefix 'Try' a long time ago, working around the problem that most existing methods of Trie did not return the database error. This weird naming convention has persisted until now. Co-authored-by: Gary Rong --- core/state/database.go | 24 +++++++++--------- core/state/state_object.go | 6 ++--- core/state/statedb.go | 6 ++--- core/state/trie_prefetcher.go | 4 +-- eth/protocols/snap/handler.go | 8 +++--- light/trie.go | 12 ++++----- trie/secure_trie.go | 47 +++++++++++++++++------------------ trie/sync_test.go | 2 +- 8 files changed, 54 insertions(+), 55 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index a67c414d9307..82f620b46083 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -68,36 +68,36 @@ type Trie interface { // TODO(fjl): remove this when StateTrie is removed GetKey([]byte) []byte - // TryGetStorage returns the value for key stored in the trie. The value bytes + // 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. - TryGetStorage(addr common.Address, key []byte) ([]byte, error) + GetStorage(addr common.Address, key []byte) ([]byte, error) - // TryGetAccount abstracts an account read from the trie. It retrieves the + // GetAccount abstracts an account read from the trie. It retrieves the // account blob from the trie with provided account address and decodes it // with associated decoding algorithm. If the specified account is not in // the trie, nil will be returned. If the trie is corrupted(e.g. some nodes // are missing or the account blob is incorrect for decoding), an error will // be returned. - TryGetAccount(address common.Address) (*types.StateAccount, error) + GetAccount(address common.Address) (*types.StateAccount, error) - // TryUpdateStorage associates key with value in the trie. If value has length zero, + // 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. If a node was not found in the // database, a trie.MissingNodeError is returned. - TryUpdateStorage(addr common.Address, key, value []byte) error + UpdateStorage(addr common.Address, key, value []byte) error - // TryUpdateAccount abstracts an account write to the trie. It encodes the + // 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. - TryUpdateAccount(address common.Address, account *types.StateAccount) error + UpdateAccount(address common.Address, account *types.StateAccount) error - // TryDeleteStorage removes any existing value for key from the trie. If a node + // DeleteStorage removes any existing value for key from the trie. If a node // was not found in the database, a trie.MissingNodeError is returned. - TryDeleteStorage(addr common.Address, key []byte) error + DeleteStorage(addr common.Address, key []byte) error - // TryDeleteAccount abstracts an account deletion from the trie. - TryDeleteAccount(address common.Address) error + // DeleteAccount abstracts an account deletion from the trie. + DeleteAccount(address common.Address) error // Hash returns the root hash of the trie. It does not write to the database and // can be used even if the trie doesn't have one. diff --git a/core/state/state_object.go b/core/state/state_object.go index 936f6dae2f13..95fe6f52fa84 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -201,7 +201,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has s.db.setError(err) return common.Hash{} } - enc, err = tr.TryGetStorage(s.address, key.Bytes()) + enc, err = tr.GetStorage(s.address, key.Bytes()) if metrics.EnabledExpensive { s.db.StorageReads += time.Since(start) } @@ -294,7 +294,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { var v []byte if (value == common.Hash{}) { - if err := tr.TryDeleteStorage(s.address, key[:]); err != nil { + if err := tr.DeleteStorage(s.address, key[:]); err != nil { s.db.setError(err) return nil, err } @@ -302,7 +302,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) { } else { // Encoding []byte cannot fail, ok to ignore the error. v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) - if err := tr.TryUpdateStorage(s.address, key[:], v); err != nil { + if err := tr.UpdateStorage(s.address, key[:], v); err != nil { s.db.setError(err) return nil, err } diff --git a/core/state/statedb.go b/core/state/statedb.go index 38583f51db20..b89f4bfd8c32 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -512,7 +512,7 @@ func (s *StateDB) updateStateObject(obj *stateObject) { } // Encode the account and update the account trie addr := obj.Address() - if err := s.trie.TryUpdateAccount(addr, &obj.data); err != nil { + if err := s.trie.UpdateAccount(addr, &obj.data); err != nil { s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err)) } @@ -533,7 +533,7 @@ func (s *StateDB) deleteStateObject(obj *stateObject) { } // Delete the account from the trie addr := obj.Address() - if err := s.trie.TryDeleteAccount(addr); err != nil { + if err := s.trie.DeleteAccount(addr); err != nil { s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err)) } } @@ -587,7 +587,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { if data == nil { start := time.Now() var err error - data, err = s.trie.TryGetAccount(addr) + data, err = s.trie.GetAccount(addr) if metrics.EnabledExpensive { s.AccountReads += time.Since(start) } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index edd370fbdbb6..844f72fc106b 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -339,9 +339,9 @@ func (sf *subfetcher) loop() { sf.dups++ } else { if len(task) == common.AddressLength { - sf.trie.TryGetAccount(common.BytesToAddress(task)) + sf.trie.GetAccount(common.BytesToAddress(task)) } else { - sf.trie.TryGetStorage(sf.addr, task) + sf.trie.GetStorage(sf.addr, task) } sf.seen[string(task)] = struct{}{} } diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index d7c940044010..55781ac54b74 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -418,7 +418,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP if err != nil { return nil, nil } - acc, err := accTrie.TryGetAccountByHash(account) + acc, err := accTrie.GetAccountByHash(account) if err != nil || acc == nil { return nil, nil } @@ -510,7 +510,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s case 1: // If we're only retrieving an account trie node, fetch it directly - blob, resolved, err := accTrie.TryGetNode(pathset[0]) + blob, resolved, err := accTrie.GetNode(pathset[0]) loads += resolved // always account database reads, even for failures if err != nil { break @@ -524,7 +524,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s if snap == nil { // We don't have the requested state snapshotted yet (or it is stale), // but can look up the account via the trie instead. - account, err := accTrie.TryGetAccountByHash(common.BytesToHash(pathset[0])) + account, err := accTrie.GetAccountByHash(common.BytesToHash(pathset[0])) loads += 8 // We don't know the exact cost of lookup, this is an estimate if err != nil || account == nil { break @@ -545,7 +545,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s break } for _, path := range pathset[1:] { - blob, resolved, err := stTrie.TryGetNode(path) + blob, resolved, err := stTrie.GetNode(path) loads += resolved // always account database reads, even for failures if err != nil { break diff --git a/light/trie.go b/light/trie.go index 0f05a80004ab..2f8f71c61e9a 100644 --- a/light/trie.go +++ b/light/trie.go @@ -105,7 +105,7 @@ type odrTrie struct { trie *trie.Trie } -func (t *odrTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { +func (t *odrTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { key = crypto.Keccak256(key) var res []byte err := t.do(key, func() (err error) { @@ -115,7 +115,7 @@ func (t *odrTrie) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { return res, err } -func (t *odrTrie) TryGetAccount(address common.Address) (*types.StateAccount, error) { +func (t *odrTrie) GetAccount(address common.Address) (*types.StateAccount, error) { var res types.StateAccount key := crypto.Keccak256(address.Bytes()) err := t.do(key, func() (err error) { @@ -131,7 +131,7 @@ func (t *odrTrie) TryGetAccount(address common.Address) (*types.StateAccount, er return &res, err } -func (t *odrTrie) TryUpdateAccount(address common.Address, acc *types.StateAccount) error { +func (t *odrTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error { key := crypto.Keccak256(address.Bytes()) value, err := rlp.EncodeToBytes(acc) if err != nil { @@ -142,14 +142,14 @@ func (t *odrTrie) TryUpdateAccount(address common.Address, acc *types.StateAccou }) } -func (t *odrTrie) TryUpdateStorage(_ common.Address, key, value []byte) error { +func (t *odrTrie) UpdateStorage(_ common.Address, key, value []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryUpdate(key, value) }) } -func (t *odrTrie) TryDeleteStorage(_ common.Address, key []byte) error { +func (t *odrTrie) DeleteStorage(_ common.Address, key []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { return t.trie.TryDelete(key) @@ -157,7 +157,7 @@ func (t *odrTrie) TryDeleteStorage(_ common.Address, key []byte) error { } // TryDeleteAccount abstracts an account deletion from the trie. -func (t *odrTrie) TryDeleteAccount(address common.Address) error { +func (t *odrTrie) DeleteAccount(address common.Address) error { key := crypto.Keccak256(address.Bytes()) return t.do(key, func() error { return t.trie.TryDelete(key) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 01e004d02ed5..b25bf758c15d 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -75,25 +75,25 @@ func NewStateTrie(id *ID, db *Database) (*StateTrie, error) { // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. func (t *StateTrie) Get(key []byte) []byte { - res, err := t.TryGetStorage(common.Address{}, key) + res, err := t.GetStorage(common.Address{}, key) if err != nil { log.Error("Unhandled trie error in StateTrie.Get", "err", err) } return res } -// TryGet returns the value for key stored in the trie. -// The value bytes must not be modified by the caller. -// If the specified node is not in the trie, nil will be returned. +// 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) TryGetStorage(_ common.Address, key []byte) ([]byte, error) { +func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { return t.trie.TryGet(t.hashKey(key)) } -// TryGetAccount attempts to retrieve an account with provided account address. +// 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. -func (t *StateTrie) TryGetAccount(address common.Address) (*types.StateAccount, error) { +func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) { res, err := t.trie.TryGet(t.hashKey(address.Bytes())) if res == nil || err != nil { return nil, err @@ -103,10 +103,10 @@ func (t *StateTrie) TryGetAccount(address common.Address) (*types.StateAccount, return ret, err } -// TryGetAccountByHash does the same thing as TryGetAccount, however -// it expects an account hash that is the hash of address. This constitutes an -// abstraction leak, since the client code needs to know the key format. -func (t *StateTrie) TryGetAccountByHash(addrHash common.Hash) (*types.StateAccount, error) { +// GetAccountByHash does the same thing as GetAccount, however it expects an +// account hash that is the hash of address. This constitutes an abstraction +// leak, since the client code needs to know the key format. +func (t *StateTrie) GetAccountByHash(addrHash common.Hash) (*types.StateAccount, error) { res, err := t.trie.TryGet(addrHash.Bytes()) if res == nil || err != nil { return nil, err @@ -116,11 +116,11 @@ func (t *StateTrie) TryGetAccountByHash(addrHash common.Hash) (*types.StateAccou return ret, err } -// TryGetNode attempts to retrieve a trie node by compact-encoded path. It is not +// 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. // If a trie node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { +func (t *StateTrie) GetNode(path []byte) ([]byte, int, error) { return t.trie.TryGetNode(path) } @@ -131,12 +131,12 @@ func (t *StateTrie) TryGetNode(path []byte) ([]byte, int, error) { // The value bytes must not be modified by the caller while they are // stored in the trie. func (t *StateTrie) Update(key, value []byte) { - if err := t.TryUpdateStorage(common.Address{}, key, value); err != nil { + if err := t.UpdateStorage(common.Address{}, key, value); err != nil { log.Error("Unhandled trie error in StateTrie.Update", "err", err) } } -// TryUpdate associates key with value in the trie. Subsequent calls to +// UpdateStorage associates key with value in the trie. Subsequent calls to // Get will return value. If value has length zero, any existing value // is deleted from the trie and calls to Get will return nil. // @@ -144,7 +144,7 @@ func (t *StateTrie) Update(key, value []byte) { // stored in the trie. // // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryUpdateStorage(_ common.Address, key, value []byte) error { +func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error { hk := t.hashKey(key) err := t.trie.TryUpdate(hk, value) if err != nil { @@ -154,9 +154,8 @@ func (t *StateTrie) TryUpdateStorage(_ common.Address, key, value []byte) error return nil } -// TryUpdateAccount account will abstract the write of an account to the -// secure trie. -func (t *StateTrie) TryUpdateAccount(address common.Address, acc *types.StateAccount) error { +// UpdateAccount will abstract the write of an account to the secure trie. +func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error { hk := t.hashKey(address.Bytes()) data, err := rlp.EncodeToBytes(acc) if err != nil { @@ -171,22 +170,22 @@ func (t *StateTrie) TryUpdateAccount(address common.Address, acc *types.StateAcc // Delete removes any existing value for key from the trie. func (t *StateTrie) Delete(key []byte) { - if err := t.TryDeleteStorage(common.Address{}, key); err != nil { + if err := t.DeleteStorage(common.Address{}, key); err != nil { log.Error("Unhandled trie error in StateTrie.Delete", "err", err) } } -// TryDelete removes any existing value for key from the trie. +// DeleteStorage removes any existing storage slot from the trie. // If the specified trie node is not in the trie, nothing will be changed. // If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) TryDeleteStorage(_ common.Address, key []byte) error { +func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) return t.trie.TryDelete(hk) } -// TryDeleteAccount abstracts an account deletion from the trie. -func (t *StateTrie) TryDeleteAccount(address common.Address) error { +// DeleteAccount abstracts an account deletion from the trie. +func (t *StateTrie) DeleteAccount(address common.Address) error { hk := t.hashKey(address.Bytes()) delete(t.getSecKeyCache(), string(hk)) return t.trie.TryDelete(hk) diff --git a/trie/sync_test.go b/trie/sync_test.go index 8fec378333da..f404dc1cda80 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -154,7 +154,7 @@ func testIterativeSync(t *testing.T, count int, bypath bool) { } } else { for i, element := range elements { - data, _, err := srcTrie.TryGetNode(element.syncPath[len(element.syncPath)-1]) + data, _, err := srcTrie.GetNode(element.syncPath[len(element.syncPath)-1]) if err != nil { t.Fatalf("failed to retrieve node data for path %x: %v", element.path, err) } From 117530b0e6784be38e5f874d7ed88971fa49db9b Mon Sep 17 00:00:00 2001 From: Delweng Date: Mon, 27 Mar 2023 19:44:41 +0800 Subject: [PATCH 666/715] metrics/librato: ensure resp.body closed (#26969) This change ensures that we call Close on a http response body, in various places in the source code (mostly tests) --- graphql/graphql_test.go | 3 +++ metrics/librato/client.go | 4 +++- node/node_test.go | 1 + node/rpcstack_test.go | 1 + p2p/simulations/adapters/exec.go | 4 +++- p2p/simulations/mocker_test.go | 5 ++++- rpc/http_test.go | 1 + 7 files changed, 16 insertions(+), 3 deletions(-) diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 46acd1529342..30b4e7c3547b 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -156,6 +156,7 @@ func TestGraphQLBlockSerialization(t *testing.T) { t.Fatalf("could not post: %v", err) } bodyBytes, err := io.ReadAll(resp.Body) + resp.Body.Close() if err != nil { t.Fatalf("could not read from response body: %v", err) } @@ -239,6 +240,7 @@ func TestGraphQLBlockSerializationEIP2718(t *testing.T) { t.Fatalf("could not post: %v", err) } bodyBytes, err := io.ReadAll(resp.Body) + resp.Body.Close() if err != nil { t.Fatalf("could not read from response body: %v", err) } @@ -263,6 +265,7 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) { if err != nil { t.Fatalf("could not post: %v", err) } + resp.Body.Close() // make sure the request is not handled successfully assert.Equal(t, http.StatusNotFound, resp.StatusCode) } diff --git a/metrics/librato/client.go b/metrics/librato/client.go index 729c2da9a9bc..f1b9e1e91669 100644 --- a/metrics/librato/client.go +++ b/metrics/librato/client.go @@ -87,9 +87,11 @@ func (c *LibratoClient) PostMetrics(batch Batch) (err error) { req.Header.Set("Content-Type", "application/json") req.SetBasicAuth(c.Email, c.Token) - if resp, err = http.DefaultClient.Do(req); err != nil { + resp, err = http.DefaultClient.Do(req) + if err != nil { return } + defer resp.Body.Close() if resp.StatusCode != http.StatusOK { var body []byte diff --git a/node/node_test.go b/node/node_test.go index 560d487fa823..04810a815bf6 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -615,6 +615,7 @@ func doHTTPRequest(t *testing.T, req *http.Request) *http.Response { if err != nil { t.Fatalf("could not issue a GET request to the given endpoint: %v", err) } + t.Cleanup(func() { resp.Body.Close() }) return resp } diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index 4d10e61e2dec..0790dddec411 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -320,6 +320,7 @@ func baseRpcRequest(t *testing.T, url, bodyStr string, extraHeaders ...string) * if err != nil { t.Fatal(err) } + t.Cleanup(func() { resp.Body.Close() }) return resp } diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go index 7bfa8aab6d10..1d812514dee7 100644 --- a/p2p/simulations/adapters/exec.go +++ b/p2p/simulations/adapters/exec.go @@ -428,9 +428,11 @@ func execP2PNode() { // Send status to the host. statusJSON, _ := json.Marshal(status) - if _, err := http.Post(statusURL, "application/json", bytes.NewReader(statusJSON)); err != nil { + resp, err := http.Post(statusURL, "application/json", bytes.NewReader(statusJSON)) + if err != nil { log.Crit("Can't post startup info", "url", statusURL, "err", err) } + resp.Body.Close() if stackErr != nil { os.Exit(1) } diff --git a/p2p/simulations/mocker_test.go b/p2p/simulations/mocker_test.go index 56d81942bbd0..0112ee5cfd6e 100644 --- a/p2p/simulations/mocker_test.go +++ b/p2p/simulations/mocker_test.go @@ -124,6 +124,7 @@ func TestMocker(t *testing.T) { if err != nil { t.Fatalf("Could not start mocker: %s", err) } + resp.Body.Close() if resp.StatusCode != 200 { t.Fatalf("Invalid Status Code received for starting mocker, expected 200, got %d", resp.StatusCode) } @@ -145,15 +146,17 @@ func TestMocker(t *testing.T) { if err != nil { t.Fatalf("Could not stop mocker: %s", err) } + resp.Body.Close() if resp.StatusCode != 200 { t.Fatalf("Invalid Status Code received for stopping mocker, expected 200, got %d", resp.StatusCode) } //reset the network - _, err = http.Post(s.URL+"/reset", "", nil) + resp, err = http.Post(s.URL+"/reset", "", nil) if err != nil { t.Fatalf("Could not reset network: %s", err) } + resp.Body.Close() //now the number of nodes in the network should be zero nodesInfo, err = client.GetNodes() diff --git a/rpc/http_test.go b/rpc/http_test.go index 528e1bcfc5e7..584842a9aa8d 100644 --- a/rpc/http_test.go +++ b/rpc/http_test.go @@ -94,6 +94,7 @@ func confirmHTTPRequestYieldsStatusCode(t *testing.T, method, contentType, body if err != nil { t.Fatalf("request failed: %v", err) } + resp.Body.Close() confirmStatusCode(t, resp.StatusCode, expectedStatusCode) } From 881fed032c7183b2abeb357cc4123a8375c0c9f5 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Mon, 27 Mar 2023 21:40:20 +0800 Subject: [PATCH 667/715] core/vm: use atomic.Bool (#26951) Make use of new atomic types --------- Co-authored-by: Felix Lange Co-authored-by: Martin Holst Swende --- core/vm/evm.go | 7 +++---- core/vm/instructions.go | 6 ++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index d78ea0792664..0084e4ca51fc 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -114,8 +114,7 @@ type EVM struct { // used throughout the execution of the tx. interpreter *EVMInterpreter // abort is used to abort the EVM calling operations - // NOTE: must be set atomically - abort int32 + abort atomic.Bool // callGasTemp holds the gas available for the current call. This is needed because the // available gas is calculated in gasCall* according to the 63/64 rule and later // applied in opCall*. @@ -147,12 +146,12 @@ func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) { // Cancel cancels any running EVM operation. This may be called concurrently and // it's safe to be called multiple times. func (evm *EVM) Cancel() { - atomic.StoreInt32(&evm.abort, 1) + evm.abort.Store(true) } // Cancelled returns true if Cancel has been called func (evm *EVM) Cancelled() bool { - return atomic.LoadInt32(&evm.abort) == 1 + return evm.abort.Load() } // Interpreter returns the current interpreter diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 77b6e02bfcc7..21d8cc215ad9 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,8 +17,6 @@ package vm import ( - "sync/atomic" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -531,7 +529,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b } func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if atomic.LoadInt32(&interpreter.evm.abort) != 0 { + if interpreter.evm.abort.Load() { return nil, errStopToken } pos := scope.Stack.pop() @@ -543,7 +541,7 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt } func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { - if atomic.LoadInt32(&interpreter.evm.abort) != 0 { + if interpreter.evm.abort.Load() { return nil, errStopToken } pos, cond := scope.Stack.pop(), scope.Stack.pop() From 79532a25b1ecf81b281f7a22b251abbd35c784c2 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 28 Mar 2023 15:05:29 +0800 Subject: [PATCH 668/715] core/bloombits: use atomic type (#26993) --- core/bloombits/matcher.go | 6 +++--- core/bloombits/matcher_test.go | 12 ++++++------ core/bloombits/scheduler_test.go | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go index 0d2f6f950d86..d8f932041bc0 100644 --- a/core/bloombits/matcher.go +++ b/core/bloombits/matcher.go @@ -83,7 +83,7 @@ type Matcher struct { retrievals chan chan *Retrieval // Retriever processes waiting for task allocations deliveries chan *Retrieval // Retriever processes waiting for task response deliveries - running uint32 // Atomic flag whether a session is live or not + running atomic.Bool // Atomic flag whether a session is live or not } // NewMatcher creates a new pipeline for retrieving bloom bit streams and doing @@ -146,10 +146,10 @@ func (m *Matcher) addScheduler(idx uint) { // channel is closed. func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uint64) (*MatcherSession, error) { // Make sure we're not creating concurrent sessions - if atomic.SwapUint32(&m.running, 1) == 1 { + if m.running.Swap(true) { return nil, errors.New("matcher already running") } - defer atomic.StoreUint32(&m.running, 0) + defer m.running.Store(false) // Initiate a new matching round session := &MatcherSession{ diff --git a/core/bloombits/matcher_test.go b/core/bloombits/matcher_test.go index 93d4632b8587..36764c3f174b 100644 --- a/core/bloombits/matcher_test.go +++ b/core/bloombits/matcher_test.go @@ -160,7 +160,7 @@ func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, in } } // Track the number of retrieval requests made - var requested uint32 + var requested atomic.Uint32 // Start the matching session for the filter and the retriever goroutines quit := make(chan struct{}) @@ -208,15 +208,15 @@ func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, in session.Close() close(quit) - if retrievals != 0 && requested != retrievals { - t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, have #%v, want #%v", filter, blocks, intermittent, requested, retrievals) + if retrievals != 0 && requested.Load() != retrievals { + t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, have #%v, want #%v", filter, blocks, intermittent, requested.Load(), retrievals) } - return requested + return requested.Load() } // startRetrievers starts a batch of goroutines listening for section requests // and serving them. -func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *uint32, batch int) { +func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *atomic.Uint32, batch int) { requests := make(chan chan *Retrieval) for i := 0; i < 10; i++ { @@ -238,7 +238,7 @@ func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *ui for i, section := range task.Sections { if rand.Int()%4 != 0 { // Handle occasional missing deliveries task.Bitsets[i] = generateBitset(task.Bit, section) - atomic.AddUint32(retrievals, 1) + retrievals.Add(1) } } request <- task diff --git a/core/bloombits/scheduler_test.go b/core/bloombits/scheduler_test.go index 49e113c117ba..dcaaa915258a 100644 --- a/core/bloombits/scheduler_test.go +++ b/core/bloombits/scheduler_test.go @@ -45,13 +45,13 @@ func testScheduler(t *testing.T, clients int, fetchers int, requests int) { fetch := make(chan *request, 16) defer close(fetch) - var delivered uint32 + var delivered atomic.Uint32 for i := 0; i < fetchers; i++ { go func() { defer fetchPend.Done() for req := range fetch { - atomic.AddUint32(&delivered, 1) + delivered.Add(1) f.deliver([]uint64{ req.section + uint64(requests), // Non-requested data (ensure it doesn't go out of bounds) @@ -97,7 +97,7 @@ func testScheduler(t *testing.T, clients int, fetchers int, requests int) { } pend.Wait() - if have := atomic.LoadUint32(&delivered); int(have) != requests { + if have := delivered.Load(); int(have) != requests { t.Errorf("request count mismatch: have %v, want %v", have, requests) } } From fb8a3aaf1e084f6190c72f039571f3c7da565b4a Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 28 Mar 2023 15:06:50 +0800 Subject: [PATCH 669/715] core/state: use atomic.Bool (#26992) --- core/state/snapshot/difflayer.go | 6 +++--- core/state/snapshot/snapshot.go | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index f916a020e7bc..4701acccd399 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -103,7 +103,7 @@ type diffLayer struct { memory uint64 // Approximate guess as to how much memory we use root common.Hash // Root hash to which this snapshot diff belongs to - stale uint32 // Signals that the layer became stale (state progressed) + stale atomic.Bool // Signals that the layer became stale (state progressed) // destructSet is a very special helper marker. If an account is marked as // deleted, then it's recorded in this set. However it's allowed that an account @@ -267,7 +267,7 @@ func (dl *diffLayer) Parent() snapshot { // Stale return whether this layer has become stale (was flattened across) or if // it's still live. func (dl *diffLayer) Stale() bool { - return atomic.LoadUint32(&dl.stale) != 0 + return dl.stale.Load() } // Account directly retrieves the account associated with a particular hash in @@ -449,7 +449,7 @@ func (dl *diffLayer) flatten() snapshot { // Before actually writing all our data to the parent, first ensure that the // parent hasn't been 'corrupted' by someone else already flattening into it - if atomic.SwapUint32(&parent.stale, 1) != 0 { + if parent.stale.Swap(true) { panic("parent diff layer is stale") // we've flattened into the same parent from two children, boo } // Overwrite all the updated accounts blindly, merge the sorted list diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 0f3fa2c7a4f0..2e57a059dd7c 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -22,7 +22,6 @@ import ( "errors" "fmt" "sync" - "sync/atomic" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -272,7 +271,7 @@ func (t *Tree) Disable() { case *diffLayer: // If the layer is a simple diff, simply mark as stale layer.lock.Lock() - atomic.StoreUint32(&layer.stale, 1) + layer.stale.Store(true) layer.lock.Unlock() default: @@ -726,7 +725,7 @@ func (t *Tree) Rebuild(root common.Hash) { case *diffLayer: // If the layer is a simple diff, simply mark as stale layer.lock.Lock() - atomic.StoreUint32(&layer.stale, 1) + layer.stale.Store(true) layer.lock.Unlock() default: From a236e03d0094fd2703cecfb235d91e1e36d0b276 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 28 Mar 2023 09:08:10 +0200 Subject: [PATCH 670/715] graphql: fix data races (#26965) Fixes multiple data races caused by the fact that resolving fields are done concurrently by the graphql library. It also enforces caching at the stateobject level for account fields. --- graphql/graphql.go | 306 ++++++++++++++++++++-------------------- graphql/graphql_test.go | 76 +++++++--- 2 files changed, 211 insertions(+), 171 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 0c13cc80f555..3c637d2d2c03 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -24,6 +24,7 @@ import ( "math/big" "sort" "strconv" + "sync" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -80,12 +81,26 @@ type Account struct { r *Resolver address common.Address blockNrOrHash rpc.BlockNumberOrHash + state *state.StateDB + mu sync.Mutex } // getState fetches the StateDB object for an account. func (a *Account) getState(ctx context.Context) (*state.StateDB, error) { + a.mu.Lock() + defer a.mu.Unlock() + if a.state != nil { + return a.state, nil + } state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash) - return state, err + if err != nil { + return nil, err + } + a.state = state + // Cache the state object. This is done so that concurrent resolvers + // don't have to fetch the object from DB individually. + a.state.GetOrNewStateObject(a.address) + return a.state, nil } func (a *Account) Address(ctx context.Context) (common.Address, error) { @@ -184,32 +199,39 @@ func (at *AccessTuple) StorageKeys(ctx context.Context) []common.Hash { // Transaction represents an Ethereum transaction. // backend and hash are mandatory; all others will be fetched when required. type Transaction struct { - r *Resolver - hash common.Hash + r *Resolver + hash common.Hash // Must be present after initialization + mu sync.Mutex + // mu protects following resources tx *types.Transaction block *Block index uint64 } // resolve returns the internal transaction object, fetching it if needed. -func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, error) { - if t.tx == nil { - // Try to return an already finalized transaction - tx, blockHash, _, index, err := t.r.backend.GetTransaction(ctx, t.hash) - if err == nil && tx != nil { - t.tx = tx - blockNrOrHash := rpc.BlockNumberOrHashWithHash(blockHash, false) - t.block = &Block{ - r: t.r, - numberOrHash: &blockNrOrHash, - } - t.index = index - return t.tx, nil +// It also returns the block the tx blongs to, unless it is a pending tx. +func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, *Block, error) { + t.mu.Lock() + defer t.mu.Unlock() + if t.tx != nil { + return t.tx, t.block, nil + } + // Try to return an already finalized transaction + tx, blockHash, _, index, err := t.r.backend.GetTransaction(ctx, t.hash) + if err == nil && tx != nil { + t.tx = tx + blockNrOrHash := rpc.BlockNumberOrHashWithHash(blockHash, false) + t.block = &Block{ + r: t.r, + numberOrHash: &blockNrOrHash, + hash: blockHash, } - // No finalized transaction, try to retrieve it from the pool - t.tx = t.r.backend.GetPoolTransaction(t.hash) + t.index = index + return t.tx, t.block, nil } - return t.tx, nil + // No finalized transaction, try to retrieve it from the pool + t.tx = t.r.backend.GetPoolTransaction(t.hash) + return t.tx, nil, nil } func (t *Transaction) Hash(ctx context.Context) common.Hash { @@ -217,7 +239,7 @@ func (t *Transaction) Hash(ctx context.Context) common.Hash { } func (t *Transaction) InputData(ctx context.Context) (hexutil.Bytes, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Bytes{}, err } @@ -225,7 +247,7 @@ func (t *Transaction) InputData(ctx context.Context) (hexutil.Bytes, error) { } func (t *Transaction) Gas(ctx context.Context) (hexutil.Uint64, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return 0, err } @@ -233,7 +255,7 @@ func (t *Transaction) Gas(ctx context.Context) (hexutil.Uint64, error) { } func (t *Transaction) GasPrice(ctx context.Context) (hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, block, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Big{}, err } @@ -241,8 +263,8 @@ func (t *Transaction) GasPrice(ctx context.Context) (hexutil.Big, error) { case types.AccessListTxType: return hexutil.Big(*tx.GasPrice()), nil case types.DynamicFeeTxType: - if t.block != nil { - if baseFee, _ := t.block.BaseFeePerGas(ctx); baseFee != nil { + if block != nil { + if baseFee, _ := block.BaseFeePerGas(ctx); baseFee != nil { // price = min(tip, gasFeeCap - baseFee) + baseFee return (hexutil.Big)(*math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee.ToInt()), tx.GasFeeCap())), nil } @@ -254,15 +276,15 @@ func (t *Transaction) GasPrice(ctx context.Context) (hexutil.Big, error) { } func (t *Transaction) EffectiveGasPrice(ctx context.Context) (*hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, block, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } // Pending tx - if t.block == nil { + if block == nil { return nil, nil } - header, err := t.block.resolveHeader(ctx) + header, err := block.resolveHeader(ctx) if err != nil || header == nil { return nil, err } @@ -273,7 +295,7 @@ func (t *Transaction) EffectiveGasPrice(ctx context.Context) (*hexutil.Big, erro } func (t *Transaction) MaxFeePerGas(ctx context.Context) (*hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } @@ -288,7 +310,7 @@ func (t *Transaction) MaxFeePerGas(ctx context.Context) (*hexutil.Big, error) { } func (t *Transaction) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } @@ -303,15 +325,15 @@ func (t *Transaction) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, e } func (t *Transaction) EffectiveTip(ctx context.Context) (*hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, block, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } // Pending tx - if t.block == nil { + if block == nil { return nil, nil } - header, err := t.block.resolveHeader(ctx) + header, err := block.resolveHeader(ctx) if err != nil || header == nil { return nil, err } @@ -327,7 +349,7 @@ func (t *Transaction) EffectiveTip(ctx context.Context) (*hexutil.Big, error) { } func (t *Transaction) Value(ctx context.Context) (hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Big{}, err } @@ -338,7 +360,7 @@ func (t *Transaction) Value(ctx context.Context) (hexutil.Big, error) { } func (t *Transaction) Nonce(ctx context.Context) (hexutil.Uint64, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return 0, err } @@ -346,7 +368,7 @@ func (t *Transaction) Nonce(ctx context.Context) (hexutil.Uint64, error) { } func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) (*Account, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } @@ -362,7 +384,7 @@ func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) (*Account, e } func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } @@ -376,17 +398,20 @@ func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account, } func (t *Transaction) Block(ctx context.Context) (*Block, error) { - if _, err := t.resolve(ctx); err != nil { + _, block, err := t.resolve(ctx) + if err != nil { return nil, err } - return t.block, nil + return block, nil } func (t *Transaction) Index(ctx context.Context) (*int32, error) { - if _, err := t.resolve(ctx); err != nil { + _, block, err := t.resolve(ctx) + if err != nil { return nil, err } - if t.block == nil { + // Pending tx + if block == nil { return nil, nil } index := int32(t.index) @@ -395,13 +420,15 @@ func (t *Transaction) Index(ctx context.Context) (*int32, error) { // getReceipt returns the receipt associated with this transaction, if any. func (t *Transaction) getReceipt(ctx context.Context) (*types.Receipt, error) { - if _, err := t.resolve(ctx); err != nil { + _, block, err := t.resolve(ctx) + if err != nil { return nil, err } - if t.block == nil { + // Pending tx + if block == nil { return nil, nil } - receipts, err := t.block.resolveReceipts(ctx) + receipts, err := block.resolveReceipts(ctx) if err != nil { return nil, err } @@ -451,28 +478,25 @@ func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs) } func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) { - if _, err := t.resolve(ctx); err != nil { + _, block, err := t.resolve(ctx) + if err != nil { return nil, err } - if t.block == nil { + // Pending tx + if block == nil { return nil, nil } - if _, ok := t.block.numberOrHash.Hash(); !ok { - header, err := t.r.backend.HeaderByNumberOrHash(ctx, *t.block.numberOrHash) - if err != nil { - return nil, err - } - hash := header.Hash() - t.block.numberOrHash.BlockHash = &hash + h, err := block.Hash(ctx) + if err != nil { + return nil, err } - return t.getLogs(ctx) + return t.getLogs(ctx, h) } // getLogs returns log objects for the given tx. // Assumes block hash is resolved. -func (t *Transaction) getLogs(ctx context.Context) (*[]*Log, error) { +func (t *Transaction) getLogs(ctx context.Context, hash common.Hash) (*[]*Log, error) { var ( - hash, _ = t.block.numberOrHash.Hash() filter = t.r.filterSystem.NewBlockFilter(hash, nil, nil) logs, err = filter.Logs(ctx) ) @@ -494,7 +518,7 @@ func (t *Transaction) getLogs(ctx context.Context) (*[]*Log, error) { } func (t *Transaction) Type(ctx context.Context) (*int32, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil { return nil, err } @@ -503,7 +527,7 @@ func (t *Transaction) Type(ctx context.Context) (*int32, error) { } func (t *Transaction) AccessList(ctx context.Context) (*[]*AccessTuple, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return nil, err } @@ -519,7 +543,7 @@ func (t *Transaction) AccessList(ctx context.Context) (*[]*AccessTuple, error) { } func (t *Transaction) R(ctx context.Context) (hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Big{}, err } @@ -528,7 +552,7 @@ func (t *Transaction) R(ctx context.Context) (hexutil.Big, error) { } func (t *Transaction) S(ctx context.Context) (hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Big{}, err } @@ -537,7 +561,7 @@ func (t *Transaction) S(ctx context.Context) (hexutil.Big, error) { } func (t *Transaction) V(ctx context.Context) (hexutil.Big, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Big{}, err } @@ -546,7 +570,7 @@ func (t *Transaction) V(ctx context.Context) (hexutil.Big, error) { } func (t *Transaction) Raw(ctx context.Context) (hexutil.Bytes, error) { - tx, err := t.resolve(ctx) + tx, _, err := t.resolve(ctx) if err != nil || tx == nil { return hexutil.Bytes{}, err } @@ -568,16 +592,20 @@ type BlockType int // when required. type Block struct { r *Resolver - numberOrHash *rpc.BlockNumberOrHash - hash common.Hash - header *types.Header - block *types.Block - receipts []*types.Receipt + numberOrHash *rpc.BlockNumberOrHash // Field resolvers assume numberOrHash is always present + mu sync.Mutex + // mu protects following resources + hash common.Hash // Must be resolved during initialization + header *types.Header + block *types.Block + receipts []*types.Receipt } // resolve returns the internal Block object representing this block, fetching // it if necessary. func (b *Block) resolve(ctx context.Context) (*types.Block, error) { + b.mu.Lock() + defer b.mu.Unlock() if b.block != nil { return b.block, nil } @@ -587,10 +615,10 @@ func (b *Block) resolve(ctx context.Context) (*types.Block, error) { } var err error b.block, err = b.r.backend.BlockByNumberOrHash(ctx, *b.numberOrHash) - if b.block != nil && b.header == nil { - b.header = b.block.Header() - if hash, ok := b.numberOrHash.Hash(); ok { - b.hash = hash + if b.block != nil { + b.hash = b.block.Hash() + if b.header == nil { + b.header = b.block.Header() } } return b.block, err @@ -600,39 +628,39 @@ func (b *Block) resolve(ctx context.Context) (*types.Block, error) { // if necessary. Call this function instead of `resolve` unless you need the // additional data (transactions and uncles). func (b *Block) resolveHeader(ctx context.Context) (*types.Header, error) { + b.mu.Lock() + defer b.mu.Unlock() + if b.header != nil { + return b.header, nil + } if b.numberOrHash == nil && b.hash == (common.Hash{}) { return nil, errBlockInvariant } var err error - if b.header == nil { - if b.hash != (common.Hash{}) { - b.header, err = b.r.backend.HeaderByHash(ctx, b.hash) - } else { - b.header, err = b.r.backend.HeaderByNumberOrHash(ctx, *b.numberOrHash) - } + b.header, err = b.r.backend.HeaderByNumberOrHash(ctx, *b.numberOrHash) + if err != nil { + return nil, err + } + if b.hash == (common.Hash{}) { + b.hash = b.header.Hash() } - return b.header, err + return b.header, nil } // resolveReceipts returns the list of receipts for this block, fetching them // if necessary. func (b *Block) resolveReceipts(ctx context.Context) ([]*types.Receipt, error) { - if b.receipts == nil { - hash := b.hash - if hash == (common.Hash{}) { - header, err := b.resolveHeader(ctx) - if err != nil { - return nil, err - } - hash = header.Hash() - } - receipts, err := b.r.backend.GetReceipts(ctx, hash) - if err != nil { - return nil, err - } - b.receipts = receipts + b.mu.Lock() + defer b.mu.Unlock() + if b.receipts != nil { + return b.receipts, nil } - return b.receipts, nil + receipts, err := b.r.backend.GetReceipts(ctx, b.hash) + if err != nil { + return nil, err + } + b.receipts = receipts + return receipts, nil } func (b *Block) Number(ctx context.Context) (Long, error) { @@ -645,13 +673,8 @@ func (b *Block) Number(ctx context.Context) (Long, error) { } func (b *Block) Hash(ctx context.Context) (common.Hash, error) { - if b.hash == (common.Hash{}) { - header, err := b.resolveHeader(ctx) - if err != nil { - return common.Hash{}, err - } - b.hash = header.Hash() - } + b.mu.Lock() + defer b.mu.Unlock() return b.hash, nil } @@ -705,11 +728,18 @@ func (b *Block) Parent(ctx context.Context) (*Block, error) { if b.header == nil || b.header.Number.Uint64() < 1 { return nil, nil } - num := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(b.header.Number.Uint64() - 1)) + var ( + num = rpc.BlockNumber(b.header.Number.Uint64() - 1) + hash = b.header.ParentHash + numOrHash = rpc.BlockNumberOrHash{ + BlockNumber: &num, + BlockHash: &hash, + } + ) return &Block{ r: b.r, - numberOrHash: &num, - hash: b.header.ParentHash, + numberOrHash: &numOrHash, + hash: hash, }, nil } @@ -798,6 +828,7 @@ func (b *Block) Ommers(ctx context.Context) (*[]*Block, error) { r: b.r, numberOrHash: &blockNumberOrHash, header: uncle, + hash: uncle.Hash(), }) } return &ret, nil @@ -820,17 +851,13 @@ func (b *Block) LogsBloom(ctx context.Context) (hexutil.Bytes, error) { } func (b *Block) TotalDifficulty(ctx context.Context) (hexutil.Big, error) { - h := b.hash - if h == (common.Hash{}) { - header, err := b.resolveHeader(ctx) - if err != nil { - return hexutil.Big{}, err - } - h = header.Hash() + hash, err := b.Hash(ctx) + if err != nil { + return hexutil.Big{}, err } - td := b.r.backend.GetTd(ctx, h) + td := b.r.backend.GetTd(ctx, hash) if td == nil { - return hexutil.Big{}, fmt.Errorf("total difficulty not found %x", b.hash) + return hexutil.Big{}, fmt.Errorf("total difficulty not found %x", hash) } return hexutil.Big(*td), nil } @@ -948,6 +975,7 @@ func (b *Block) OmmerAt(ctx context.Context, args struct{ Index int32 }) (*Block r: b.r, numberOrHash: &blockNumberOrHash, header: uncle, + hash: uncle.Hash(), }, nil } @@ -997,15 +1025,11 @@ func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteri if args.Filter.Topics != nil { topics = *args.Filter.Topics } - hash := b.hash - if hash == (common.Hash{}) { - header, err := b.resolveHeader(ctx) - if err != nil { - return nil, err - } - hash = header.Hash() - } // Construct the range filter + hash, err := b.Hash(ctx) + if err != nil { + return nil, err + } filter := b.r.filterSystem.NewBlockFilter(hash, addresses, topics) // Run the filter and return all the logs @@ -1015,12 +1039,6 @@ func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteri func (b *Block) Account(ctx context.Context, args struct { Address common.Address }) (*Account, error) { - if b.numberOrHash == nil { - _, err := b.resolveHeader(ctx) - if err != nil { - return nil, err - } - } return &Account{ r: b.r, address: args.Address, @@ -1063,12 +1081,6 @@ func (c *CallResult) Status() Long { func (b *Block) Call(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (*CallResult, error) { - if b.numberOrHash == nil { - _, err := b.resolve(ctx) - if err != nil { - return nil, err - } - } result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap()) if err != nil { return nil, err @@ -1088,12 +1100,6 @@ func (b *Block) Call(ctx context.Context, args struct { func (b *Block) EstimateGas(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (Long, error) { - if b.numberOrHash == nil { - _, err := b.resolveHeader(ctx) - if err != nil { - return 0, err - } - } gas, err := ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, b.r.backend.RPCGasCap()) return Long(gas), err } @@ -1173,29 +1179,21 @@ func (r *Resolver) Block(ctx context.Context, args struct { Number *Long Hash *common.Hash }) (*Block, error) { - var block *Block + var numberOrHash rpc.BlockNumberOrHash if args.Number != nil { if *args.Number < 0 { return nil, nil } number := rpc.BlockNumber(*args.Number) - numberOrHash := rpc.BlockNumberOrHashWithNumber(number) - block = &Block{ - r: r, - numberOrHash: &numberOrHash, - } + numberOrHash = rpc.BlockNumberOrHashWithNumber(number) } else if args.Hash != nil { - numberOrHash := rpc.BlockNumberOrHashWithHash(*args.Hash, false) - block = &Block{ - r: r, - numberOrHash: &numberOrHash, - } + numberOrHash = rpc.BlockNumberOrHashWithHash(*args.Hash, false) } else { - numberOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) - block = &Block{ - r: r, - numberOrHash: &numberOrHash, - } + numberOrHash = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) + } + block := &Block{ + r: r, + numberOrHash: &numberOrHash, } // Resolve the header, return nil if it doesn't exist. // Note we don't resolve block directly here since it will require an @@ -1256,7 +1254,7 @@ func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Has hash: args.Hash, } // Resolve the transaction; if it doesn't exist, return nil. - t, err := tx.resolve(ctx) + t, _, err := tx.resolve(ctx) if err != nil { return nil, err } else if t == nil { diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go index 30b4e7c3547b..9354eac0f359 100644 --- a/graphql/graphql_test.go +++ b/graphql/graphql_test.go @@ -270,7 +270,7 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) { assert.Equal(t, http.StatusNotFound, resp.StatusCode) } -func TestGraphQLTransactionLogs(t *testing.T) { +func TestGraphQLConcurrentResolvers(t *testing.T) { var ( key, _ = crypto.GenerateKey() addr = crypto.PubkeyToAddress(key.PublicKey) @@ -295,8 +295,9 @@ func TestGraphQLTransactionLogs(t *testing.T) { ) defer stack.Close() - handler := newGQLService(t, stack, genesis, 1, func(i int, gen *core.BlockGen) { - tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) + var tx *types.Transaction + handler, chain := newGQLService(t, stack, genesis, 1, func(i int, gen *core.BlockGen) { + tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) gen.AddTx(tx) tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{To: &dad, Nonce: 1, Gas: 100000, GasPrice: big.NewInt(params.InitialBaseFee)}) gen.AddTx(tx) @@ -307,18 +308,59 @@ func TestGraphQLTransactionLogs(t *testing.T) { if err := stack.Start(); err != nil { t.Fatalf("could not start node: %v", err) } - query := `{block { transactions { logs { account { address } } } } }` - res := handler.Schema.Exec(context.Background(), query, "", map[string]interface{}{}) - if res.Errors != nil { - t.Fatalf("graphql query failed: %v", res.Errors) - } - have, err := json.Marshal(res.Data) - if err != nil { - t.Fatalf("failed to encode graphql response: %s", err) - } - want := fmt.Sprintf(`{"block":{"transactions":[{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]}]}}`, dadStr, dadStr, dadStr, dadStr, dadStr, dadStr) - if string(have) != want { - t.Errorf("response unmatch. expected %s, got %s", want, have) + + for i, tt := range []struct { + body string + want string + }{ + // Multiple txes race to get/set the block hash. + { + body: "{block { transactions { logs { account { address } } } } }", + want: fmt.Sprintf(`{"block":{"transactions":[{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]},{"logs":[{"account":{"address":"%s"}},{"account":{"address":"%s"}}]}]}}`, dadStr, dadStr, dadStr, dadStr, dadStr, dadStr), + }, + // Multiple fields of a tx race to resolve it. Happens in this case + // because resolving the tx body belonging to a log is delayed. + { + body: `{block { logs(filter: {}) { transaction { nonce value gasPrice }}}}`, + want: `{"block":{"logs":[{"transaction":{"nonce":"0x0","value":"0x0","gasPrice":"0x3b9aca00"}},{"transaction":{"nonce":"0x0","value":"0x0","gasPrice":"0x3b9aca00"}},{"transaction":{"nonce":"0x1","value":"0x0","gasPrice":"0x3b9aca00"}},{"transaction":{"nonce":"0x1","value":"0x0","gasPrice":"0x3b9aca00"}},{"transaction":{"nonce":"0x2","value":"0x0","gasPrice":"0x3b9aca00"}},{"transaction":{"nonce":"0x2","value":"0x0","gasPrice":"0x3b9aca00"}}]}}`, + }, + // Multiple txes of a block race to set/retrieve receipts of a block. + { + body: "{block { transactions { status gasUsed } } }", + want: `{"block":{"transactions":[{"status":1,"gasUsed":21768},{"status":1,"gasUsed":21768},{"status":1,"gasUsed":21768}]}}`, + }, + // Multiple fields of block race to resolve header and body. + { + body: "{ block { number hash gasLimit ommerCount transactionCount totalDifficulty } }", + want: fmt.Sprintf(`{"block":{"number":1,"hash":"%s","gasLimit":11500000,"ommerCount":0,"transactionCount":3,"totalDifficulty":"0x200000"}}`, chain[len(chain)-1].Hash()), + }, + // Multiple fields of a block race to resolve the header and body. + { + body: fmt.Sprintf(`{ transaction(hash: "%s") { block { number hash gasLimit ommerCount transactionCount } } }`, tx.Hash()), + want: fmt.Sprintf(`{"transaction":{"block":{"number":1,"hash":"%s","gasLimit":11500000,"ommerCount":0,"transactionCount":3}}}`, chain[len(chain)-1].Hash()), + }, + // Account fields race the resolve the state object. + { + body: fmt.Sprintf(`{ block { account(address: "%s") { balance transactionCount code } } }`, dadStr), + want: `{"block":{"account":{"balance":"0x0","transactionCount":"0x0","code":"0x60006000a060006000a060006000f3"}}}`, + }, + // Test values for a non-existent account. + { + body: fmt.Sprintf(`{ block { account(address: "%s") { balance transactionCount code } } }`, "0x1111111111111111111111111111111111111111"), + want: `{"block":{"account":{"balance":"0x0","transactionCount":"0x0","code":"0x"}}}`, + }, + } { + res := handler.Schema.Exec(context.Background(), tt.body, "", map[string]interface{}{}) + if res.Errors != nil { + t.Fatalf("failed to execute query for testcase #%d: %v", i, res.Errors) + } + have, err := json.Marshal(res.Data) + if err != nil { + t.Fatalf("failed to encode graphql response for testcase #%d: %s", i, err) + } + if string(have) != tt.want { + t.Errorf("response unmatch for testcase #%d.\nExpected:\n%s\nGot:\n%s\n", i, tt.want, have) + } } } @@ -336,7 +378,7 @@ func createNode(t *testing.T) *node.Node { return stack } -func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) *handler { +func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlocks int, genfunc func(i int, gen *core.BlockGen)) (*handler, []*types.Block) { ethConf := ðconfig.Config{ Genesis: gspec, Ethash: ethash.Config{ @@ -367,5 +409,5 @@ func newGQLService(t *testing.T, stack *node.Node, gspec *core.Genesis, genBlock if err != nil { t.Fatalf("could not create graphql service: %v", err) } - return handler + return handler, chain } From fd94b4fcfa244179c0500b70fb2944cb686b9ca4 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 28 Mar 2023 02:46:53 -0700 Subject: [PATCH 671/715] eth/tracers/native: prevent panic for LOG edge-cases (#26848) This PR fixes OOM panic in the callTracer as well as panicing on opcode validation errors (e.g. stack underflow) in callTracer and prestateTracer. Co-authored-by: Martin Holst Swende --- .../internal/tracetest/calltrace_test.go | 181 +++++++++++------- eth/tracers/js/goja.go | 21 +- eth/tracers/js/tracer_test.go | 4 +- eth/tracers/native/call.go | 11 +- eth/tracers/native/prestate.go | 3 + eth/tracers/tracers.go | 25 +++ eth/tracers/tracers_test.go | 38 ++++ 7 files changed, 194 insertions(+), 89 deletions(-) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 62182e3a82b4..c5405e245179 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" @@ -260,75 +259,121 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { } } -// TestZeroValueToNotExitCall tests the calltracer(s) on the following: -// Tx to A, A calls B with zero value. B does not already exist. -// Expected: that enter/exit is invoked and the inner call is shown in the result -func TestZeroValueToNotExitCall(t *testing.T) { - var to = common.HexToAddress("0x00000000000000000000000000000000deadbeef") - privkey, err := crypto.HexToECDSA("0000000000000000deadbeef00000000000000000000000000000000deadbeef") - if err != nil { - t.Fatalf("err %v", err) - } - signer := types.NewEIP155Signer(big.NewInt(1)) - tx, err := types.SignNewTx(privkey, signer, &types.LegacyTx{ - GasPrice: big.NewInt(0), - Gas: 50000, - To: &to, - }) - if err != nil { - t.Fatalf("err %v", err) - } - origin, _ := signer.Sender(tx) - txContext := vm.TxContext{ - Origin: origin, - GasPrice: big.NewInt(1), - } - context := vm.BlockContext{ - CanTransfer: core.CanTransfer, - Transfer: core.Transfer, - Coinbase: common.Address{}, - BlockNumber: new(big.Int).SetUint64(8000000), - Time: 5, - Difficulty: big.NewInt(0x30000), - GasLimit: uint64(6000000), - } - var code = []byte{ - byte(vm.PUSH1), 0x0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), // in and outs zero - byte(vm.DUP1), byte(vm.PUSH1), 0xff, byte(vm.GAS), // value=0,address=0xff, gas=GAS - byte(vm.CALL), +func TestInternals(t *testing.T) { + var ( + to = common.HexToAddress("0x00000000000000000000000000000000deadbeef") + origin = common.HexToAddress("0x00000000000000000000000000000000feed") + txContext = vm.TxContext{ + Origin: origin, + GasPrice: big.NewInt(1), + } + context = vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + Coinbase: common.Address{}, + BlockNumber: new(big.Int).SetUint64(8000000), + Time: 5, + Difficulty: big.NewInt(0x30000), + GasLimit: uint64(6000000), + } + ) + mkTracer := func(name string, cfg json.RawMessage) tracers.Tracer { + tr, err := tracers.DefaultDirectory.New(name, nil, cfg) + if err != nil { + t.Fatalf("failed to create call tracer: %v", err) + } + return tr } - var alloc = core.GenesisAlloc{ - to: core.GenesisAccount{ - Nonce: 1, - Code: code, + + for _, tc := range []struct { + name string + code []byte + tracer tracers.Tracer + want string + }{ + { + // TestZeroValueToNotExitCall tests the calltracer(s) on the following: + // Tx to A, A calls B with zero value. B does not already exist. + // Expected: that enter/exit is invoked and the inner call is shown in the result + name: "ZeroValueToNotExitCall", + code: []byte{ + byte(vm.PUSH1), 0x0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), // in and outs zero + byte(vm.DUP1), byte(vm.PUSH1), 0xff, byte(vm.GAS), // value=0,address=0xff, gas=GAS + byte(vm.CALL), + }, + tracer: mkTracer("callTracer", nil), + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, }, - origin: core.GenesisAccount{ - Nonce: 0, - Balance: big.NewInt(500000000000000), + { + name: "Stack depletion in LOG0", + code: []byte{byte(vm.LOG3)}, + tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, }, - } - _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false) - // Create the tracer, the EVM environment and run it - tracer, err := tracers.DefaultDirectory.New("callTracer", nil, nil) - if err != nil { - t.Fatalf("failed to create call tracer: %v", err) - } - evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) - msg, err := core.TransactionToMessage(tx, signer, nil) - if err != nil { - t.Fatalf("failed to prepare transaction for tracing: %v", err) - } - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - if _, err = st.TransitionDb(); err != nil { - t.Fatalf("failed to execute transaction: %v", err) - } - // Retrieve the trace result and compare against the etalon - res, err := tracer.GetResult() - if err != nil { - t.Fatalf("failed to retrieve trace result: %v", err) - } - wantStr := `{"from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","gas":"0x7148","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}` - if string(res) != wantStr { - t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), wantStr) + { + name: "Mem expansion in LOG0", + code: []byte{ + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x0, + byte(vm.MSTORE), + byte(vm.PUSH1), 0xff, + byte(vm.PUSH1), 0x0, + byte(vm.LOG0), + }, + tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, + }, + { + // Leads to OOM on the prestate tracer + name: "Prestate-tracer - mem expansion in CREATE2", + code: []byte{ + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x0, + byte(vm.MSTORE), + byte(vm.PUSH1), 0x1, + byte(vm.PUSH5), 0xff, 0xff, 0xff, 0xff, 0xff, + byte(vm.PUSH1), 0x1, + byte(vm.PUSH1), 0x0, + byte(vm.CREATE2), + byte(vm.PUSH1), 0xff, + byte(vm.PUSH1), 0x0, + byte(vm.LOG0), + }, + tracer: mkTracer("prestateTracer", json.RawMessage(`{ "withLog": true }`)), + want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52640350"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`, + }, + } { + _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), + core.GenesisAlloc{ + to: core.GenesisAccount{ + Code: tc.code, + }, + origin: core.GenesisAccount{ + Balance: big.NewInt(500000000000000), + }, + }, false) + evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tc.tracer}) + msg := &core.Message{ + To: &to, + From: origin, + Value: big.NewInt(0), + GasLimit: 50000, + GasPrice: big.NewInt(0), + GasFeeCap: big.NewInt(0), + GasTipCap: big.NewInt(0), + SkipAccountChecks: false, + } + st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) + if _, err := st.TransitionDb(); err != nil { + t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err) + } + // Retrieve the trace result and compare against the expected + res, err := tc.tracer.GetResult() + if err != nil { + t.Fatalf("test %v: failed to retrieve trace result: %v", tc.name, err) + } + if string(res) != tc.want { + t.Fatalf("test %v: trace mismatch\n have: %v\n want: %v\n", tc.name, string(res), tc.want) + } } } diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 8e52f5b21077..33298f3097fa 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -32,10 +32,6 @@ import ( jsassets "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers" ) -const ( - memoryPadLimit = 1024 * 1024 -) - var assetTracers = make(map[string]string) // init retrieves the JavaScript transaction tracers included in go-ethereum. @@ -571,14 +567,10 @@ func (mo *memoryObj) slice(begin, end int64) ([]byte, error) { if end < begin || begin < 0 { return nil, fmt.Errorf("tracer accessed out of bound memory: offset %d, end %d", begin, end) } - mlen := mo.memory.Len() - if end-int64(mlen) > memoryPadLimit { - return nil, fmt.Errorf("tracer reached limit for padding memory slice: end %d, memorySize %d", end, mlen) + slice, err := tracers.GetMemoryCopyPadded(mo.memory, begin, end-begin) + if err != nil { + return nil, err } - slice := make([]byte, end-begin) - end = min(end, int64(mo.memory.Len())) - ptr := mo.memory.GetPtr(begin, end-begin) - copy(slice[:], ptr[:]) return slice, nil } @@ -959,10 +951,3 @@ func (l *steplog) setupObject() *goja.Object { o.Set("contract", l.contract.setupObject()) return o } - -func min(a, b int64) int64 { - if a < b { - return a - } - return b -} diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 524d17474930..1f3753721116 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -150,12 +150,12 @@ func TestTracer(t *testing.T) { }, { code: "{res: [], step: function(log) { if (log.op.toString() === 'STOP') { this.res.push(log.memory.slice(5, 1025 * 1024)) } }, fault: function() {}, result: function() { return this.res }}", want: "", - fail: "tracer reached limit for padding memory slice: end 1049600, memorySize 32 at step (:1:83(20)) in server-side tracer function 'step'", + fail: "reached limit for padding memory slice: 1049568 at step (:1:83(20)) in server-side tracer function 'step'", contract: []byte{byte(vm.PUSH1), byte(0xff), byte(vm.PUSH1), byte(0x00), byte(vm.MSTORE8), byte(vm.STOP)}, }, } { if have, err := execTracer(tt.code, tt.contract); tt.want != string(have) || tt.fail != err { - t.Errorf("testcase %d: expected return value to be '%s' got '%s', error to be '%s' got '%s'\n\tcode: %v", i, tt.want, string(have), tt.fail, err, tt.code) + t.Errorf("testcase %d: expected return value to be \n'%s'\n\tgot\n'%s'\nerror to be\n'%s'\n\tgot\n'%s'\n\tcode: %v", i, tt.want, string(have), tt.fail, err, tt.code) } } } diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 02ee152a5aa1..88fc2be40c25 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -148,6 +148,10 @@ func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { // CaptureState implements the EVMLogger interface to trace a single step of VM execution. func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + // skip if the previous op caused an error + if err != nil { + return + } // Only logs need to be captured via opcode processing if !t.config.WithLog { return @@ -176,7 +180,12 @@ func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco topics[i] = common.Hash(topic.Bytes32()) } - data := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64())) + data, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(mStart.Uint64()), int64(mSize.Uint64())) + if err != nil { + // mSize was unrealistically large + return + } + log := callLog{Address: scope.Contract.Address(), Topics: topics, Data: hexutil.Bytes(data)} t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, log) } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 948d09ef767c..42ec4fe7828b 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -133,6 +133,9 @@ func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { // CaptureState implements the EVMLogger interface to trace a single step of VM execution. func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + if err != nil { + return + } stack := scope.Stack stackData := stack.Data() stackLen := len(stackData) diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index 856f52a10de3..023f73ef3708 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -19,6 +19,7 @@ package tracers import ( "encoding/json" + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -95,3 +96,27 @@ func (d *directory) IsJS(name string) bool { // JS eval will execute JS code return true } + +const ( + memoryPadLimit = 1024 * 1024 +) + +// GetMemoryCopyPadded returns offset + size as a new slice. +// It zero-pads the slice if it extends beyond memory bounds. +func GetMemoryCopyPadded(m *vm.Memory, offset, size int64) ([]byte, error) { + if offset < 0 || size < 0 { + return nil, fmt.Errorf("offset or size must not be negative") + } + if int(offset+size) < m.Len() { // slice fully inside memory + return m.GetCopy(offset, size), nil + } + paddingNeeded := int(offset+size) - m.Len() + if paddingNeeded > memoryPadLimit { + return nil, fmt.Errorf("reached limit for padding memory slice: %d", paddingNeeded) + } + cpy := make([]byte, size) + if overlap := int64(m.Len()) - offset; overlap > 0 { + copy(cpy, m.GetPtr(offset, overlap)) + } + return cpy, nil +} diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 7c5ec65650ee..46182db48b98 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -109,3 +109,41 @@ func BenchmarkTransactionTrace(b *testing.B) { tracer.Reset() } } + +func TestMemCopying(t *testing.T) { + for i, tc := range []struct { + memsize int64 + offset int64 + size int64 + wantErr string + wantSize int + }{ + {0, 0, 100, "", 100}, // Should pad up to 100 + {0, 100, 0, "", 0}, // No need to pad (0 size) + {100, 50, 100, "", 100}, // Should pad 100-150 + {100, 50, 5, "", 5}, // Wanted range fully within memory + {100, -50, 0, "offset or size must not be negative", 0}, // Errror + {0, 1, 1024*1024 + 1, "reached limit for padding memory slice: 1048578", 0}, // Errror + {10, 0, 1024*1024 + 100, "reached limit for padding memory slice: 1048666", 0}, // Errror + + } { + mem := vm.NewMemory() + mem.Resize(uint64(tc.memsize)) + cpy, err := GetMemoryCopyPadded(mem, tc.offset, tc.size) + if want := tc.wantErr; want != "" { + if err == nil { + t.Fatalf("test %d: want '%v' have no error", i, want) + } + if have := err.Error(); want != have { + t.Fatalf("test %d: want '%v' have '%v'", i, want, have) + } + continue + } + if err != nil { + t.Fatalf("test %d: unexpected error: %v", i, err) + } + if want, have := tc.wantSize, len(cpy); have != want { + t.Fatalf("test %d: want %v have %v", i, want, have) + } + } +} From 56c1f98f8acfcc79e4348ba3aeecd3ea2e0c9a84 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Tue, 28 Mar 2023 22:37:40 +1000 Subject: [PATCH 672/715] internal/debug: add log.logfmt flag to set logging to use logfmt (#26970) --- internal/debug/flags.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index e014a85d7fc8..0bae9883ec3b 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -54,6 +54,11 @@ var ( Usage: "Format logs with JSON", Category: flags.LoggingCategory, } + logfmtFlag = &cli.BoolFlag{ + Name: "log.logfmt", + Usage: "Format logs with logfmt", + Category: flags.LoggingCategory, + } logFileFlag = &cli.StringFlag{ Name: "log.file", Usage: "Write logs to a file", @@ -115,6 +120,7 @@ var Flags = []cli.Flag{ verbosityFlag, vmoduleFlag, logjsonFlag, + logfmtFlag, logFileFlag, backtraceAtFlag, debugFlag, @@ -147,6 +153,8 @@ func Setup(ctx *cli.Context) error { var logfmt log.Format if ctx.Bool(logjsonFlag.Name) { logfmt = log.JSONFormat() + } else if ctx.Bool(logfmtFlag.Name) { + logfmt = log.LogfmtFormat() } else { logfmt = log.TerminalFormat(useColor) } From 7ca4f60a1abd2a8c9df2ed9ae35a891b0ac9e464 Mon Sep 17 00:00:00 2001 From: David Murdoch <187813+davidmurdoch@users.noreply.github.com> Date: Tue, 28 Mar 2023 08:59:37 -0400 Subject: [PATCH 673/715] docs: update outdated DeriveSha docs comment (#26968) --- core/types/hashing.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/types/hashing.go b/core/types/hashing.go index 3df75432a4b4..71295c107cf8 100644 --- a/core/types/hashing.go +++ b/core/types/hashing.go @@ -83,7 +83,7 @@ func encodeForDerive(list DerivableList, i int, buf *bytes.Buffer) []byte { return common.CopyBytes(buf.Bytes()) } -// DeriveSha creates the tree hashes of transactions and receipts in a block header. +// DeriveSha creates the tree hashes of transactions, receipts, and withdrawals in a block header. func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash { hasher.Reset() From a03490c6b2ff0e1d9a1274afdbe087a695d533eb Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 30 Mar 2023 10:58:23 +0200 Subject: [PATCH 674/715] remove @gballet as a GraphQL codeowner (#27012) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 780f2a800ec1..faf922df0161 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,7 +10,7 @@ core/ @karalabe @holiman @rjl493456442 eth/ @karalabe @holiman @rjl493456442 eth/catalyst/ @gballet eth/tracers/ @s1na -graphql/ @gballet @s1na +graphql/ @s1na les/ @zsfelfoldi @rjl493456442 light/ @zsfelfoldi @rjl493456442 node/ @fjl From 949cee2fe343532a2fb9cd4a5edebfedae86a371 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Thu, 30 Mar 2023 18:53:32 +0800 Subject: [PATCH 675/715] core: use atomic type (#27011) --- core/blockchain.go | 28 ++++++++++++++-------------- core/chain_indexer.go | 6 +++--- core/state_prefetcher.go | 4 ++-- core/types.go | 4 +++- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 8fc520e7760f..d7094c516acd 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -174,7 +174,7 @@ type BlockChain struct { triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc gcproc time.Duration // Accumulates canonical block processing for trie dumping lastWrite uint64 // Last block when the state was flushed - flushInterval int64 // Time interval (processing time) after which to flush a state + flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state triedb *trie.Database // The database handler for maintaining trie nodes. stateCache state.Database // State database to reuse between imports (contains state cache) @@ -215,8 +215,8 @@ type BlockChain struct { wg sync.WaitGroup // quit chan struct{} // shutdown signal, closed in Stop. - running int32 // 0 if chain is running, 1 when stopped - procInterrupt int32 // interrupt signaler for block processing + stopping atomic.Bool // false if chain is running, true when stopped + procInterrupt atomic.Bool // interrupt signaler for block processing engine consensus.Engine validator Validator // Block and state validator interface @@ -260,7 +260,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis cacheConfig: cacheConfig, db: db, triedb: triedb, - flushInterval: int64(cacheConfig.TrieTimeLimit), triegc: prque.New[int64, common.Hash](nil), quit: make(chan struct{}), chainmu: syncx.NewClosableMutex(), @@ -273,6 +272,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis engine: engine, vmConfig: vmConfig, } + bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) bc.forker = NewForkChoice(bc, shouldPreserve) bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) bc.validator = NewBlockValidator(chainConfig, bc, engine) @@ -916,7 +916,7 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) { // This method has been exposed to allow tests to stop the blockchain while simulating // a crash. func (bc *BlockChain) stopWithoutSaving() { - if !atomic.CompareAndSwapInt32(&bc.running, 0, 1) { + if !bc.stopping.CompareAndSwap(false, true) { return } @@ -998,12 +998,12 @@ func (bc *BlockChain) Stop() { // errInsertionInterrupted as soon as possible. Insertion is permanently disabled after // calling this method. func (bc *BlockChain) StopInsert() { - atomic.StoreInt32(&bc.procInterrupt, 1) + bc.procInterrupt.Store(true) } // insertStopped returns true after StopInsert has been called. func (bc *BlockChain) insertStopped() bool { - return atomic.LoadInt32(&bc.procInterrupt) == 1 + return bc.procInterrupt.Load() } func (bc *BlockChain) procFutureBlocks() { @@ -1382,7 +1382,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } // Find the next state trie we need to commit chosen := current - TriesInMemory - flushInterval := time.Duration(atomic.LoadInt64(&bc.flushInterval)) + flushInterval := time.Duration(bc.flushInterval.Load()) // If we exceeded time allowance, flush an entire trie to disk if bc.gcproc > flushInterval { // If the header is missing (canonical chain behind), we're reorging a low @@ -1735,7 +1735,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // If we have a followup block, run that against the current state to pre-cache // transactions and probabilistically some of the account/storage trie nodes. - var followupInterrupt uint32 + var followupInterrupt atomic.Bool if !bc.cacheConfig.TrieCleanNoPrefetch { if followup, err := it.peek(); followup != nil && err == nil { throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps) @@ -1744,7 +1744,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) blockPrefetchExecuteTimer.Update(time.Since(start)) - if atomic.LoadUint32(&followupInterrupt) == 1 { + if followupInterrupt.Load() { blockPrefetchInterruptMeter.Mark(1) } }(time.Now(), followup, throwaway) @@ -1756,7 +1756,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) - atomic.StoreUint32(&followupInterrupt, 1) + followupInterrupt.Store(true) return it.index, err } ptime := time.Since(pstart) @@ -1764,7 +1764,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) vstart := time.Now() if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { bc.reportBlock(block, receipts, err) - atomic.StoreUint32(&followupInterrupt, 1) + followupInterrupt.Store(true) return it.index, err } vtime := time.Since(vstart) @@ -1797,7 +1797,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) } else { status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) } - atomic.StoreUint32(&followupInterrupt, 1) + followupInterrupt.Store(true) if err != nil { return it.index, err } @@ -2497,5 +2497,5 @@ func (bc *BlockChain) SetBlockValidatorAndProcessorForTesting(v Validator, p Pro // The interval is in terms of block processing time, not wall clock. // It is thread-safe and can be called repeatedly without side effects. func (bc *BlockChain) SetTrieFlushInterval(interval time.Duration) { - atomic.StoreInt64(&bc.flushInterval, int64(interval)) + bc.flushInterval.Store(int64(interval)) } diff --git a/core/chain_indexer.go b/core/chain_indexer.go index 95901a0eaa71..23ab23ef0fb9 100644 --- a/core/chain_indexer.go +++ b/core/chain_indexer.go @@ -75,7 +75,7 @@ type ChainIndexer struct { backend ChainIndexerBackend // Background processor generating the index data content children []*ChainIndexer // Child indexers to cascade chain updates to - active uint32 // Flag whether the event loop was started + active atomic.Bool // Flag whether the event loop was started update chan struct{} // Notification channel that headers should be processed quit chan chan error // Quit channel to tear down running goroutines ctx context.Context @@ -166,7 +166,7 @@ func (c *ChainIndexer) Close() error { errs = append(errs, err) } // If needed, tear down the secondary event loop - if atomic.LoadUint32(&c.active) != 0 { + if c.active.Load() { c.quit <- errc if err := <-errc; err != nil { errs = append(errs, err) @@ -196,7 +196,7 @@ func (c *ChainIndexer) Close() error { // queue. func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainHeadEvent, sub event.Subscription) { // Mark the chain indexer as active, requiring an additional teardown - atomic.StoreUint32(&c.active, 1) + c.active.Store(true) defer sub.Unsubscribe() diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index c258eee4f4cc..721f4056b2d2 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -47,7 +47,7 @@ func newStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine conse // Prefetch processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb, but any changes are discarded. The // only goal is to pre-cache transaction signatures and state trie nodes. -func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32) { +func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *atomic.Bool) { var ( header = block.Header() gaspool = new(GasPool).AddGas(block.GasLimit()) @@ -59,7 +59,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c byzantium := p.config.IsByzantium(block.Number()) for i, tx := range block.Transactions() { // If block precaching was interrupted, abort - if interrupt != nil && atomic.LoadUint32(interrupt) == 1 { + if interrupt != nil && interrupt.Load() { return } // Convert the transaction into an executable message and pre-cache its sender diff --git a/core/types.go b/core/types.go index 4c5b74a49865..36eb0d1dedbe 100644 --- a/core/types.go +++ b/core/types.go @@ -17,6 +17,8 @@ package core import ( + "sync/atomic" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -39,7 +41,7 @@ type Prefetcher interface { // Prefetch processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb, but any changes are discarded. The // only goal is to pre-cache transaction signatures and state trie nodes. - Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32) + Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *atomic.Bool) } // Processor is an interface for processing blocks using a given initial state. From 62fb7d3f851aa8dda0b5abc7d761dd2fc7c499c2 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Thu, 30 Mar 2023 12:57:49 +0200 Subject: [PATCH 676/715] graphql: revert storage access regression (#27007) --- graphql/graphql.go | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 3c637d2d2c03..45a1f7a2aa74 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -81,26 +81,12 @@ type Account struct { r *Resolver address common.Address blockNrOrHash rpc.BlockNumberOrHash - state *state.StateDB - mu sync.Mutex } // getState fetches the StateDB object for an account. func (a *Account) getState(ctx context.Context) (*state.StateDB, error) { - a.mu.Lock() - defer a.mu.Unlock() - if a.state != nil { - return a.state, nil - } state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash) - if err != nil { - return nil, err - } - a.state = state - // Cache the state object. This is done so that concurrent resolvers - // don't have to fetch the object from DB individually. - a.state.GetOrNewStateObject(a.address) - return a.state, nil + return state, err } func (a *Account) Address(ctx context.Context) (common.Address, error) { From 2d1492821d058a3488b4da2c1f62906eaf6d7c95 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Thu, 30 Mar 2023 23:24:48 +1000 Subject: [PATCH 677/715] cmd/geth: Add `--log.format` cli param (#27001) Removes the new --log.logfmt directive and hides --log.json, replacing both with log.format=(json|logfmt|terminal). The hidden log.json option is still respected if log.format is not specified for backwards compatibility. Co-authored-by: Martin Holst Swende --- internal/debug/flags.go | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 0bae9883ec3b..068817d532a9 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -52,11 +52,12 @@ var ( logjsonFlag = &cli.BoolFlag{ Name: "log.json", Usage: "Format logs with JSON", + Hidden: true, Category: flags.LoggingCategory, } - logfmtFlag = &cli.BoolFlag{ - Name: "log.logfmt", - Usage: "Format logs with logfmt", + logFormatFlag = &cli.StringFlag{ + Name: "log.format", + Usage: "Log format to use (json|logfmt|terminal)", Category: flags.LoggingCategory, } logFileFlag = &cli.StringFlag{ @@ -120,7 +121,7 @@ var Flags = []cli.Flag{ verbosityFlag, vmoduleFlag, logjsonFlag, - logfmtFlag, + logFormatFlag, logFileFlag, backtraceAtFlag, debugFlag, @@ -151,12 +152,24 @@ func Setup(ctx *cli.Context) error { useColor := logFile == "" && os.Getenv("TERM") != "dumb" && (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) var logfmt log.Format - if ctx.Bool(logjsonFlag.Name) { + switch ctx.String(logFormatFlag.Name) { + case "json": logfmt = log.JSONFormat() - } else if ctx.Bool(logfmtFlag.Name) { + case "logfmt": logfmt = log.LogfmtFormat() - } else { + case "terminal": logfmt = log.TerminalFormat(useColor) + case "": + // Retain backwards compatibility with `--log.json` flag if `--log.format` not set + if ctx.Bool(logjsonFlag.Name) { + defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead") + logfmt = log.JSONFormat() + } else { + logfmt = log.TerminalFormat(useColor) + } + default: + // Unknown log format specified + return fmt.Errorf("unknown log format: %v", ctx.String(logFormatFlag.Name)) } if logFile != "" { From 50317bdacec8fc61f434c5b07ac77afed95e0c4a Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Fri, 31 Mar 2023 03:02:14 +0800 Subject: [PATCH 678/715] ethdb/pebble: use atomic type (#27014) --- ethdb/pebble/pebble.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 4e374c9e2832..7c01b879b8e7 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -75,14 +75,14 @@ type Database struct { log log.Logger // Contextual logger tracking the database path - activeComp int // Current number of active compactions - compStartTime time.Time // The start time of the earliest currently-active compaction - compTime int64 // Total time spent in compaction in ns - level0Comp uint32 // Total number of level-zero compactions - nonLevel0Comp uint32 // Total number of non level-zero compactions - writeDelayStartTime time.Time // The start time of the latest write stall - writeDelayCount int64 // Total number of write stall counts - writeDelayTime int64 // Total time spent in write stalls + activeComp int // Current number of active compactions + compStartTime time.Time // The start time of the earliest currently-active compaction + compTime atomic.Int64 // Total time spent in compaction in ns + level0Comp atomic.Uint32 // Total number of level-zero compactions + nonLevel0Comp atomic.Uint32 // Total number of non level-zero compactions + writeDelayStartTime time.Time // The start time of the latest write stall + writeDelayCount atomic.Int64 // Total number of write stall counts + writeDelayTime atomic.Int64 // Total time spent in write stalls } func (d *Database) onCompactionBegin(info pebble.CompactionInfo) { @@ -91,16 +91,16 @@ func (d *Database) onCompactionBegin(info pebble.CompactionInfo) { } l0 := info.Input[0] if l0.Level == 0 { - atomic.AddUint32(&d.level0Comp, 1) + d.level0Comp.Add(1) } else { - atomic.AddUint32(&d.nonLevel0Comp, 1) + d.nonLevel0Comp.Add(1) } d.activeComp++ } func (d *Database) onCompactionEnd(info pebble.CompactionInfo) { if d.activeComp == 1 { - atomic.AddInt64(&d.compTime, int64(time.Since(d.compStartTime))) + d.compTime.Add(int64(time.Since(d.compStartTime))) } else if d.activeComp == 0 { panic("should not happen") } @@ -112,7 +112,7 @@ func (d *Database) onWriteStallBegin(b pebble.WriteStallBeginInfo) { } func (d *Database) onWriteStallEnd() { - atomic.AddInt64(&d.writeDelayTime, int64(time.Since(d.writeDelayStartTime))) + d.writeDelayTime.Add(int64(time.Since(d.writeDelayStartTime))) } // New returns a wrapped pebble DB object. The namespace is the prefix that the @@ -407,11 +407,11 @@ func (d *Database) meter(refresh time.Duration) { nWrite int64 metrics = d.db.Metrics() - compTime = atomic.LoadInt64(&d.compTime) - writeDelayCount = atomic.LoadInt64(&d.writeDelayCount) - writeDelayTime = atomic.LoadInt64(&d.writeDelayTime) - nonLevel0CompCount = int64(atomic.LoadUint32(&d.nonLevel0Comp)) - level0CompCount = int64(atomic.LoadUint32(&d.level0Comp)) + compTime = d.compTime.Load() + writeDelayCount = d.writeDelayCount.Load() + writeDelayTime = d.writeDelayTime.Load() + nonLevel0CompCount = int64(d.nonLevel0Comp.Load()) + level0CompCount = int64(d.level0Comp.Load()) ) writeDelayTimes[i%2] = writeDelayTime writeDelayCounts[i%2] = writeDelayCount From 9ce047452e35919b0c78ad9fc140f2644aab8a48 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 31 Mar 2023 03:04:28 +0800 Subject: [PATCH 679/715] common: fix json marshaller MixedcaseAddress (#26998) Fix the json marshaller of MixedcaseAddress --- common/types.go | 2 +- common/types_test.go | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/common/types.go b/common/types.go index 218ca0be4c44..0b68a19dd319 100644 --- a/common/types.go +++ b/common/types.go @@ -400,7 +400,7 @@ func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error { } // MarshalJSON marshals the original value -func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) { +func (ma MixedcaseAddress) MarshalJSON() ([]byte, error) { if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") { return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:])) } diff --git a/common/types_test.go b/common/types_test.go index 94492278d84a..88c642522d80 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -154,6 +154,31 @@ func BenchmarkAddressHex(b *testing.B) { } } +// Test checks if the customized json marshaller of MixedcaseAddress object +// is invoked correctly. In golang the struct pointer will inherit the +// non-pointer receiver methods, the reverse is not true. In the case of +// MixedcaseAddress, it must define the MarshalJSON method in the object +// but not the pointer level, so that this customized marshalled can be used +// for both MixedcaseAddress object and pointer. +func TestMixedcaseAddressMarshal(t *testing.T) { + var ( + output string + input = "0xae967917c465db8578ca9024c205720b1a3651A9" + ) + addr, err := NewMixedcaseAddressFromString(input) + if err != nil { + t.Fatal(err) + } + blob, err := json.Marshal(*addr) + if err != nil { + t.Fatal(err) + } + json.Unmarshal(blob, &output) + if output != input { + t.Fatal("Failed to marshal/unmarshal MixedcaseAddress object") + } +} + func TestMixedcaseAccount_Address(t *testing.T) { // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md // Note: 0X{checksum_addr} is not valid according to spec above @@ -177,7 +202,7 @@ func TestMixedcaseAccount_Address(t *testing.T) { } } - //These should throw exceptions: + // These should throw exceptions: var r2 []MixedcaseAddress for _, r := range []string{ `["0x11111111111111111111122222222222233333"]`, // Too short From d0fbb10658a85f0b2bd4466892747758bacddaf7 Mon Sep 17 00:00:00 2001 From: openex Date: Fri, 31 Mar 2023 03:09:35 +0800 Subject: [PATCH 680/715] eth/catalyst: improve consensus heartbeat (#26896) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit improve the heartbeat function that is no longer suitable in the current situation Co-authored-by: “openex27” <“openexkevin@gmail.com”> --- eth/catalyst/api.go | 85 +++++---------------------------------------- 1 file changed, 8 insertions(+), 77 deletions(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 9077f20bffcc..1fe98424723b 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -20,7 +20,6 @@ package catalyst import ( "errors" "fmt" - "math/big" "sync" "time" @@ -64,11 +63,6 @@ const ( // attached before starting to issue warnings. beaconUpdateStartupTimeout = 30 * time.Second - // beaconUpdateExchangeTimeout is the max time allowed for a beacon client to - // do a transition config exchange before it's considered offline and the user - // is warned. - beaconUpdateExchangeTimeout = 2 * time.Minute - // beaconUpdateConsensusTimeout is the max time allowed for a beacon client // to send a consensus update before it's considered offline and the user is // warned. @@ -667,14 +661,13 @@ func (api *ConsensusAPI) heartbeat() { // attached, so no need to print scary warnings to the user. time.Sleep(beaconUpdateStartupTimeout) - var ( - offlineLogged time.Time - ttd = api.eth.BlockChain().Config().TerminalTotalDifficulty - ) // If the network is not yet merged/merging, don't bother continuing. - if ttd == nil { + if api.eth.BlockChain().Config().TerminalTotalDifficulty == nil { return } + + var offlineLogged time.Time + for { // Sleep a bit and retrieve the last known consensus updates time.Sleep(5 * time.Second) @@ -698,20 +691,14 @@ func (api *ConsensusAPI) heartbeat() { offlineLogged = time.Time{} continue } - if time.Since(lastTransitionUpdate) > beaconUpdateExchangeTimeout { - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { + + if time.Since(offlineLogged) > beaconUpdateWarnFrequency { + if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { if lastTransitionUpdate.IsZero() { log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!") } else { - log.Warn("Previously seen beacon client is offline. Please ensure it is operational to follow the chain!") + log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") } - offlineLogged = time.Now() - } - continue - } - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { - log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") } else { log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!") } @@ -719,62 +706,6 @@ func (api *ConsensusAPI) heartbeat() { } continue } - if time.Since(lastTransitionUpdate) <= beaconUpdateExchangeTimeout { - offlineLogged = time.Time{} - continue - } - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - // Retrieve the last few blocks and make a rough estimate as - // to when the merge transition should happen - var ( - chain = api.eth.BlockChain() - head = chain.CurrentHeader() - htd = chain.GetTd(head.Hash(), head.Number.Uint64()) - ) - if htd.Cmp(ttd) >= 0 { - if lastTransitionUpdate.IsZero() { - log.Warn("Merge already reached, but no beacon client seen. Please launch one to follow the chain!") - } else { - log.Warn("Merge already reached, but previously seen beacon client is offline. Please ensure it is operational to follow the chain!") - } - offlineLogged = time.Now() - continue - } - var eta time.Duration - if head.Number.Uint64() > 0 { - // Accumulate the last 64 difficulties to estimate the growth - var ( - deltaDiff uint64 - deltaTime uint64 - current = head - ) - for i := 0; i < 64; i++ { - parent := chain.GetHeader(current.ParentHash, current.Number.Uint64()-1) - if parent == nil { - break - } - deltaDiff += current.Difficulty.Uint64() - deltaTime += current.Time - parent.Time - current = parent - } - // Estimate an ETA based on the block times and the difficulty growth - if deltaTime > 0 { - growth := deltaDiff / deltaTime - left := new(big.Int).Sub(ttd, htd) - eta = time.Duration(new(big.Int).Div(left, new(big.Int).SetUint64(growth+1)).Uint64()) * time.Second - } - } - message := "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transition arrives!" - if lastTransitionUpdate.IsZero() { - message = "Merge is configured, but no beacon client seen. Please ensure you have one available before the transition arrives!" - } - if eta < time.Second { - log.Warn(message) - } else { - log.Warn(message, "eta", common.PrettyAge(time.Now().Add(-eta))) // weird hack, but duration formatted doesn't handle days - } - offlineLogged = time.Now() - } } } From b92d0ea3bbb04cbe99b57dd0934ad4dfba932a16 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Fri, 31 Mar 2023 14:32:47 +0800 Subject: [PATCH 681/715] miner: use atomic type (#27013) Use the new typed atomics in the miner package --- miner/worker.go | 46 ++++++++++++++++++++++---------------------- miner/worker_test.go | 6 +++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 67a5842d23e0..9fbece865891 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -164,7 +164,7 @@ const ( // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. type newWorkReq struct { - interrupt *int32 + interrupt *atomic.Int32 noempty bool timestamp int64 } @@ -239,15 +239,15 @@ type worker struct { snapshotState *state.StateDB // atomic status counters - running int32 // The indicator whether the consensus engine is running or not. - newTxs int32 // New arrival transaction count since last sealing work submitting. + running atomic.Bool // The indicator whether the consensus engine is running or not. + newTxs atomic.Int32 // New arrival transaction count since last sealing work submitting. // noempty is the flag used to control whether the feature of pre-seal empty // block is enabled. The default value is false(pre-seal is enabled by default). // But in some special scenario the consensus engine will seal blocks instantaneously, // in this case this feature will add all empty blocks into canonical chain // non-stop and no real transaction will be included. - noempty uint32 + noempty atomic.Bool // newpayloadTimeout is the maximum timeout allowance for creating payload. // The default value is 2 seconds but node operator can set it to arbitrary @@ -372,12 +372,12 @@ func (w *worker) setRecommitInterval(interval time.Duration) { // disablePreseal disables pre-sealing feature func (w *worker) disablePreseal() { - atomic.StoreUint32(&w.noempty, 1) + w.noempty.Store(true) } // enablePreseal enables pre-sealing feature func (w *worker) enablePreseal() { - atomic.StoreUint32(&w.noempty, 0) + w.noempty.Store(false) } // pending returns the pending state and corresponding block. @@ -409,24 +409,24 @@ func (w *worker) pendingBlockAndReceipts() (*types.Block, types.Receipts) { // start sets the running status as 1 and triggers new work submitting. func (w *worker) start() { - atomic.StoreInt32(&w.running, 1) + w.running.Store(true) w.startCh <- struct{}{} } // stop sets the running status as 0. func (w *worker) stop() { - atomic.StoreInt32(&w.running, 0) + w.running.Store(false) } // isRunning returns an indicator whether worker is running or not. func (w *worker) isRunning() bool { - return atomic.LoadInt32(&w.running) == 1 + return w.running.Load() } // close terminates all background threads maintained by the worker. // Note the worker does not support being closed multiple times. func (w *worker) close() { - atomic.StoreInt32(&w.running, 0) + w.running.Store(false) close(w.exitCh) w.wg.Wait() } @@ -457,7 +457,7 @@ func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) t func (w *worker) newWorkLoop(recommit time.Duration) { defer w.wg.Done() var ( - interrupt *int32 + interrupt *atomic.Int32 minRecommit = recommit // minimal resubmit interval specified by user. timestamp int64 // timestamp for each round of sealing. ) @@ -469,16 +469,16 @@ func (w *worker) newWorkLoop(recommit time.Duration) { // commit aborts in-flight transaction execution with given signal and resubmits a new one. commit := func(noempty bool, s int32) { if interrupt != nil { - atomic.StoreInt32(interrupt, s) + interrupt.Store(s) } - interrupt = new(int32) + interrupt = new(atomic.Int32) select { case w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp}: case <-w.exitCh: return } timer.Reset(recommit) - atomic.StoreInt32(&w.newTxs, 0) + w.newTxs.Store(0) } // clearPending cleans the stale pending tasks. clearPending := func(number uint64) { @@ -508,7 +508,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { // higher priced transactions. Disable this overhead for pending blocks. if w.isRunning() && (w.chainConfig.Clique == nil || w.chainConfig.Clique.Period > 0) { // Short circuit if no new transaction arrives. - if atomic.LoadInt32(&w.newTxs) == 0 { + if w.newTxs.Load() == 0 { timer.Reset(recommit) continue } @@ -650,7 +650,7 @@ func (w *worker) mainLoop() { w.commitWork(nil, true, time.Now().Unix()) } } - atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) + w.newTxs.Add(int32(len(ev.Txs))) // System stopped case <-w.exitCh: @@ -877,7 +877,7 @@ func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]* return receipt.Logs, nil } -func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, interrupt *int32) error { +func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, interrupt *atomic.Int32) error { gasLimit := env.header.GasLimit if env.gasPool == nil { env.gasPool = new(core.GasPool).AddGas(gasLimit) @@ -887,7 +887,7 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP for { // Check interruption signal and abort building if it's fired. if interrupt != nil { - if signal := atomic.LoadInt32(interrupt); signal != commitInterruptNone { + if signal := interrupt.Load(); signal != commitInterruptNone { return signalToErr(signal) } } @@ -1067,7 +1067,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { // fillTransactions retrieves the pending transactions from the txpool and fills them // into the given sealing block. The transaction selection and ordering strategy can // be customized with the plugin in the future. -func (w *worker) fillTransactions(interrupt *int32, env *environment) error { +func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) error { // Split the pending transactions into locals and remotes // Fill the block with all available pending transactions. pending := w.eth.TxPool().Pending(true) @@ -1102,9 +1102,9 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, e defer work.discard() if !params.noTxs { - interrupt := new(int32) + interrupt := new(atomic.Int32) timer := time.AfterFunc(w.newpayloadTimeout, func() { - atomic.StoreInt32(interrupt, commitInterruptTimeout) + interrupt.Store(commitInterruptTimeout) }) defer timer.Stop() @@ -1122,7 +1122,7 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, e // commitWork generates several new sealing tasks based on the parent block // and submit them to the sealer. -func (w *worker) commitWork(interrupt *int32, noempty bool, timestamp int64) { +func (w *worker) commitWork(interrupt *atomic.Int32, noempty bool, timestamp int64) { start := time.Now() // Set the coinbase if the worker is running or it's required @@ -1143,7 +1143,7 @@ func (w *worker) commitWork(interrupt *int32, noempty bool, timestamp int64) { } // Create an empty block based on temporary copied state for // sealing in advance without waiting block execution finished. - if !noempty && atomic.LoadUint32(&w.noempty) == 0 { + if !noempty && !w.noempty.Load() { w.commit(work.copy(), nil, false, start) } // Fill pending transactions from the txpool into the block. diff --git a/miner/worker_test.go b/miner/worker_test.go index e60de679326c..9db64a240d36 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -454,11 +454,11 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co progress = make(chan struct{}, 10) result = make([]float64, 0, 10) index = 0 - start uint32 + start atomic.Bool ) w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { // Short circuit if interval checking hasn't started. - if atomic.LoadUint32(&start) == 0 { + if !start.Load() { return } var wantMinInterval, wantRecommitInterval time.Duration @@ -493,7 +493,7 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co w.start() time.Sleep(time.Second) // Ensure two tasks have been submitted due to start opt - atomic.StoreUint32(&start, 1) + start.Store(true) w.setRecommitInterval(3 * time.Second) select { From 00a73fbcce3250b87fc4160f3deddc44390848f4 Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Fri, 31 Mar 2023 02:35:29 -0400 Subject: [PATCH 682/715] accounts/abi/bind: handle UnpackLog with zero topics (#26920) Adds error handling for the case that UnpackLog or UnpackLogIntoMap is called with a log that has zero topics. --------- Co-authored-by: Sina Mahmoodi --- accounts/abi/bind/base.go | 17 +++++++++++++++-- accounts/abi/bind/base_test.go | 17 +++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index df3f52a403e7..b03f431f7717 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -34,6 +34,11 @@ import ( const basefeeWiggleMultiplier = 2 +var ( + errNoEventSignature = errors.New("no event signature") + errEventSignatureMismatch = errors.New("event signature mismatch") +) + // SignerFn is a signer function callback when a contract requires a method to // sign the transaction before submission. type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error) @@ -488,8 +493,12 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter // UnpackLog unpacks a retrieved log into the provided output structure. func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { + // Anonymous events are not supported. + if len(log.Topics) == 0 { + return errNoEventSignature + } if log.Topics[0] != c.abi.Events[event].ID { - return fmt.Errorf("event signature mismatch") + return errEventSignatureMismatch } if len(log.Data) > 0 { if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { @@ -507,8 +516,12 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) // UnpackLogIntoMap unpacks a retrieved log into the provided map. func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { + // Anonymous events are not supported. + if len(log.Topics) == 0 { + return errNoEventSignature + } if log.Topics[0] != c.abi.Events[event].ID { - return fmt.Errorf("event signature mismatch") + return errEventSignatureMismatch } if len(log.Data) > 0 { if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil { diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index 2307b9874b18..ca0128148ffa 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -186,6 +186,23 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { unpackAndCheck(t, bc, expectedReceivedMap, mockLog) } +func TestUnpackAnonymousLogIntoMap(t *testing.T) { + mockLog := newMockLog(nil, common.HexToHash("0x0")) + + abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` + parsedAbi, _ := abi.JSON(strings.NewReader(abiString)) + bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil) + + var received map[string]interface{} + err := bc.UnpackLogIntoMap(received, "received", mockLog) + if err == nil { + t.Error("unpacking anonymous event is not supported") + } + if err.Error() != "no event signature" { + t.Errorf("expected error 'no event signature', got '%s'", err) + } +} + func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"}) if err != nil { From bed07cd5906e6c26168512f0bf3047e1a948c0e1 Mon Sep 17 00:00:00 2001 From: Guruprasad Kamath <48196632+gurukamath@users.noreply.github.com> Date: Mon, 3 Apr 2023 09:33:17 +0200 Subject: [PATCH 683/715] cmd/evm: use correct parent number for t8n base fee calculation (#27032) Currently the t8n tool uses the same block number for the current block and its parent while calculating the base fee. This causes incorrect base fee calculation for the london fork block. This commit sets the parent block number to be one less than the current block number --- cmd/evm/internal/t8ntool/transition.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index cb7466d86cae..f63635687b9b 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -250,9 +250,9 @@ func Transition(ctx *cli.Context) error { if chainConfig.IsLondon(big.NewInt(int64(prestate.Env.Number))) { if prestate.Env.BaseFee != nil { // Already set, base fee has precedent over parent base fee. - } else if prestate.Env.ParentBaseFee != nil { + } else if prestate.Env.ParentBaseFee != nil && prestate.Env.Number != 0 { parent := &types.Header{ - Number: new(big.Int).SetUint64(prestate.Env.Number), + Number: new(big.Int).SetUint64(prestate.Env.Number - 1), BaseFee: prestate.Env.ParentBaseFee, GasUsed: prestate.Env.ParentGasUsed, GasLimit: prestate.Env.ParentGasLimit, From dc2f4b9304517fd17321c26c47fb5e9ef1ca544b Mon Sep 17 00:00:00 2001 From: ucwong Date: Mon, 3 Apr 2023 01:35:13 -0600 Subject: [PATCH 684/715] go.mod : update snappy (#27027) --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 95c80c6fd8b1..efde64a5fb8f 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/gofrs/flock v0.8.1 github.com/golang-jwt/jwt/v4 v4.3.0 github.com/golang/protobuf v1.5.2 - github.com/golang/snappy v0.0.4 + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa github.com/google/uuid v1.3.0 github.com/gorilla/websocket v1.4.2 diff --git a/go.sum b/go.sum index 4c134a277221..67baa0b2ac1e 100644 --- a/go.sum +++ b/go.sum @@ -190,8 +190,9 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= From 2c5798464eea24fb78089e51c09e5e1f98f9fd8a Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 3 Apr 2023 01:51:31 -0600 Subject: [PATCH 685/715] common: delete MakeName (#27023) common,p2p: remove unused function MakeName --- common/path.go | 9 --------- p2p/server.go | 1 - 2 files changed, 10 deletions(-) diff --git a/common/path.go b/common/path.go index 69820cfe5dec..c1e382fd29c4 100644 --- a/common/path.go +++ b/common/path.go @@ -17,19 +17,10 @@ package common import ( - "fmt" "os" "path/filepath" - "runtime" ) -// MakeName creates a node name that follows the ethereum convention -// for such names. It adds the operation system name and Go runtime version -// the name. -func MakeName(name, version string) string { - return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version()) -} - // FileExist checks if a file exists at filePath. func FileExist(filePath string) bool { _, err := os.Stat(filePath) diff --git a/p2p/server.go b/p2p/server.go index 610b82d784f6..b8a2f8fd211f 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -94,7 +94,6 @@ type Config struct { DiscoveryV5 bool `toml:",omitempty"` // Name sets the node name of this server. - // Use common.MakeName to create a name that follows existing conventions. Name string `toml:"-"` // BootstrapNodes are used to establish connectivity From 7076ae00aa36ae250608455de928557ce4e5549f Mon Sep 17 00:00:00 2001 From: sudeep Date: Mon, 3 Apr 2023 14:35:36 +0530 Subject: [PATCH 686/715] cmd/geth: enable log rotation (#26843) This change enables log rotation, which can be activated using the flag --log.rotate. Additional parameters that can be given are: - log.maxsize to set maximum size before files are rotated, - log.maxbackups to set how many files are retailed, - log.maxage to configure max age of rotated files, - log.compress whether to compress rotated files The way to configure location of the logfile(s) is left unchanged, via the `log.logfile` parameter. --------- Co-authored-by: Martin Holst Swende --- .gitignore | 1 + go.mod | 1 + go.sum | 3 + internal/debug/flags.go | 139 +++++++++++++++++++++++++++++++--------- 4 files changed, 114 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index 1ee8b83022ef..e24e1d167709 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ profile.cov /dashboard/assets/package-lock.json **/yarn-error.log +logs/ \ No newline at end of file diff --git a/go.mod b/go.mod index efde64a5fb8f..c3e4ee0b49e5 100644 --- a/go.mod +++ b/go.mod @@ -65,6 +65,7 @@ require ( golang.org/x/text v0.8.0 golang.org/x/time v0.0.0-20220922220347-f3bd1da661af golang.org/x/tools v0.7.0 + gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce ) diff --git a/go.sum b/go.sum index 67baa0b2ac1e..1022db1e43a9 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,7 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= @@ -617,6 +618,8 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 068817d532a9..3c8b569b4f38 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -20,8 +20,9 @@ import ( "fmt" "io" "net/http" - _ "net/http/pprof" // nolint: gosec + _ "net/http/pprof" "os" + "path/filepath" "runtime" "github.com/ethereum/go-ethereum/internal/flags" @@ -32,6 +33,7 @@ import ( "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "github.com/urfave/cli/v2" + "gopkg.in/natefinch/lumberjack.v2" ) var Memsize memsizeui.Handler @@ -76,6 +78,34 @@ var ( Usage: "Prepends log messages with call-site location (file and line number)", Category: flags.LoggingCategory, } + logRotateFlag = &cli.BoolFlag{ + Name: "log.rotate", + Usage: "Enables log file rotation", + } + logMaxSizeMBsFlag = &cli.IntFlag{ + Name: "log.maxsize", + Usage: "Maximum size in MBs of a single log file", + Value: 100, + Category: flags.LoggingCategory, + } + logMaxBackupsFlag = &cli.IntFlag{ + Name: "log.maxbackups", + Usage: "Maximum number of log files to retain", + Value: 10, + Category: flags.LoggingCategory, + } + logMaxAgeFlag = &cli.IntFlag{ + Name: "log.maxage", + Usage: "Maximum number of days to retain a log file", + Value: 30, + Category: flags.LoggingCategory, + } + logCompressFlag = &cli.BoolFlag{ + Name: "log.compress", + Usage: "Compress the log files", + Value: false, + Category: flags.LoggingCategory, + } pprofFlag = &cli.BoolFlag{ Name: "pprof", Usage: "Enable the pprof HTTP server", @@ -120,11 +150,16 @@ var ( var Flags = []cli.Flag{ verbosityFlag, vmoduleFlag, + backtraceAtFlag, + debugFlag, logjsonFlag, logFormatFlag, logFileFlag, - backtraceAtFlag, - debugFlag, + logRotateFlag, + logMaxSizeMBsFlag, + logMaxBackupsFlag, + logMaxAgeFlag, + logCompressFlag, pprofFlag, pprofAddrFlag, pprofPortFlag, @@ -148,44 +183,71 @@ func init() { // Setup initializes profiling and logging based on the CLI flags. // It should be called as early as possible in the program. func Setup(ctx *cli.Context) error { - logFile := ctx.String(logFileFlag.Name) - useColor := logFile == "" && os.Getenv("TERM") != "dumb" && (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) - - var logfmt log.Format - switch ctx.String(logFormatFlag.Name) { - case "json": + var ( + logfmt log.Format + output = io.Writer(os.Stderr) + logFmtFlag = ctx.String(logFormatFlag.Name) + ) + switch { + case ctx.Bool(logjsonFlag.Name): + // Retain backwards compatibility with `--log.json` flag if `--log.format` not set + defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead") logfmt = log.JSONFormat() - case "logfmt": + case logFmtFlag == "json": + logfmt = log.JSONFormat() + case logFmtFlag == "logfmt": logfmt = log.LogfmtFormat() - case "terminal": - logfmt = log.TerminalFormat(useColor) - case "": - // Retain backwards compatibility with `--log.json` flag if `--log.format` not set - if ctx.Bool(logjsonFlag.Name) { - defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead") - logfmt = log.JSONFormat() - } else { - logfmt = log.TerminalFormat(useColor) + case logFmtFlag == "", logFmtFlag == "terminal": + useColor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" + if useColor { + output = colorable.NewColorableStderr() } + logfmt = log.TerminalFormat(useColor) default: // Unknown log format specified return fmt.Errorf("unknown log format: %v", ctx.String(logFormatFlag.Name)) } - - if logFile != "" { - var err error - logOutputStream, err = log.FileHandler(logFile, logfmt) - if err != nil { - return err + var ( + stdHandler = log.StreamHandler(output, logfmt) + ostream = stdHandler + logFile = ctx.String(logFileFlag.Name) + rotation = ctx.Bool(logRotateFlag.Name) + ) + if len(logFile) > 0 { + if err := validateLogLocation(filepath.Dir(logFile)); err != nil { + return fmt.Errorf("failed to initiatilize file logger: %v", err) } + } + context := []interface{}{"rotate", rotation} + if len(logFmtFlag) > 0 { + context = append(context, "format", logFmtFlag) } else { - output := io.Writer(os.Stderr) - if useColor { - output = colorable.NewColorableStderr() + context = append(context, "format", "terminal") + } + if rotation { + // Lumberjack uses -lumberjack.log in is.TempDir() if empty. + // so typically /tmp/geth-lumberjack.log on linux + if len(logFile) > 0 { + context = append(context, "location", logFile) + } else { + context = append(context, "location", filepath.Join(os.TempDir(), "geth-lumberjack.log")) + } + ostream = log.MultiHandler(log.StreamHandler(&lumberjack.Logger{ + Filename: logFile, + MaxSize: ctx.Int(logMaxSizeMBsFlag.Name), + MaxBackups: ctx.Int(logMaxBackupsFlag.Name), + MaxAge: ctx.Int(logMaxAgeFlag.Name), + Compress: ctx.Bool(logCompressFlag.Name), + }, logfmt), stdHandler) + } else if logFile != "" { + if logOutputStream, err := log.FileHandler(logFile, logfmt); err != nil { + return err + } else { + ostream = log.MultiHandler(logOutputStream, stdHandler) + context = append(context, "location", logFile) } - logOutputStream = log.StreamHandler(output, logfmt) } - glogger.SetHandler(logOutputStream) + glogger.SetHandler(ostream) // logging verbosity := ctx.Int(verbosityFlag.Name) @@ -236,6 +298,9 @@ func Setup(ctx *cli.Context) error { // It cannot be imported because it will cause a cyclical dependency. StartPProf(address, !ctx.IsSet("metrics.addr")) } + if len(logFile) > 0 || rotation { + log.Info("Logging configured", context...) + } return nil } @@ -263,3 +328,17 @@ func Exit() { closer.Close() } } + +func validateLogLocation(path string) error { + if err := os.MkdirAll(path, os.ModePerm); err != nil { + return fmt.Errorf("error creating the directory: %w", err) + } + // Check if the path is writable by trying to create a temporary file + tmp := filepath.Join(path, "tmp") + if f, err := os.Create(tmp); err != nil { + return err + } else { + f.Close() + } + return os.Remove(tmp) +} From 94457cce072d1e45f47d13dce290e0473615ec5d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 3 Apr 2023 17:08:06 +0800 Subject: [PATCH 687/715] cmd, miner, signer: avoid panic if keystore is not available (#27039) * cmd, miner, singer: avoid panic if keystore is not available * cmd/geth: print warning instead of panic --- cmd/geth/accountcmd.go | 18 +++++++++++++++--- cmd/geth/main.go | 7 ++++++- miner/stress/beacon/main.go | 6 +++++- signer/core/uiapi.go | 6 +++++- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go index 5158b7606cde..a36da7d55f2c 100644 --- a/cmd/geth/accountcmd.go +++ b/cmd/geth/accountcmd.go @@ -301,7 +301,11 @@ func accountUpdate(ctx *cli.Context) error { utils.Fatalf("No accounts specified to update") } stack, _ := makeConfigNode(ctx) - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + backends := stack.AccountManager().Backends(keystore.KeyStoreType) + if len(backends) == 0 { + utils.Fatalf("Keystore is not available") + } + ks := backends[0].(*keystore.KeyStore) for _, addr := range ctx.Args().Slice() { account, oldPassword := unlockAccount(ks, addr, 0, nil) @@ -326,7 +330,11 @@ func importWallet(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) passphrase := utils.GetPassPhraseWithList("", false, 0, utils.MakePasswordList(ctx)) - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + backends := stack.AccountManager().Backends(keystore.KeyStoreType) + if len(backends) == 0 { + utils.Fatalf("Keystore is not available") + } + ks := backends[0].(*keystore.KeyStore) acct, err := ks.ImportPreSaleKey(keyJSON, passphrase) if err != nil { utils.Fatalf("%v", err) @@ -347,7 +355,11 @@ func accountImport(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) passphrase := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + backends := stack.AccountManager().Backends(keystore.KeyStoreType) + if len(backends) == 0 { + utils.Fatalf("Keystore is not available") + } + ks := backends[0].(*keystore.KeyStore) acct, err := ks.ImportECDSA(key, passphrase) if err != nil { utils.Fatalf("Could not create the account: %v", err) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index a970e7652342..f55adb1449da 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -464,7 +464,12 @@ func unlockAccounts(ctx *cli.Context, stack *node.Node) { if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() { utils.Fatalf("Account unlock with HTTP access is forbidden!") } - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + backends := stack.AccountManager().Backends(keystore.KeyStoreType) + if len(backends) == 0 { + log.Warn("Failed to unlock accounts, keystore is not available") + return + } + ks := backends[0].(*keystore.KeyStore) passwords := utils.MakePasswordList(ctx) for i, account := range unlocks { unlockAccount(ks, account, i, passwords) diff --git a/miner/stress/beacon/main.go b/miner/stress/beacon/main.go index 516862c9cb52..65318f1a0e4e 100644 --- a/miner/stress/beacon/main.go +++ b/miner/stress/beacon/main.go @@ -127,7 +127,11 @@ func newNode(typ nodetype, genesis *core.Genesis, enodes []*enode.Node) *ethNode // Inject the signer key and start sealing with it stack.AccountManager().AddBackend(keystore.NewPlaintextKeyStore("beacon-stress")) - store := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + ks := stack.AccountManager().Backends(keystore.KeyStoreType) + if len(ks) == 0 { + panic("Keystore is not available") + } + store := ks[0].(*keystore.KeyStore) if _, err := store.NewAccount(""); err != nil { panic(err) } diff --git a/signer/core/uiapi.go b/signer/core/uiapi.go index 59466d8fa030..924203a139a7 100644 --- a/signer/core/uiapi.go +++ b/signer/core/uiapi.go @@ -111,7 +111,11 @@ func (s *UIServerAPI) DeriveAccount(url string, path string, pin *bool) (account // fetchKeystore retrieves the encrypted keystore from the account manager. func fetchKeystore(am *accounts.Manager) *keystore.KeyStore { - return am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) + ks := am.Backends(keystore.KeyStoreType) + if len(ks) == 0 { + return nil + } + return ks[0].(*keystore.KeyStore) } // ImportRawKey stores the given hex encoded ECDSA key into the key directory, From a25dd8064ed7329dd5924bce18b2a04d0b2843e8 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 3 Apr 2023 05:42:34 -0400 Subject: [PATCH 688/715] test/fuzzers: fuzz rlp handling of big.Int and uint256.Int (#26917) test/fuzzers: fuzz rlp handling of big.Lnt and uint256.Int --- tests/fuzzers/rlp/rlp_fuzzer.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/fuzzers/rlp/rlp_fuzzer.go b/tests/fuzzers/rlp/rlp_fuzzer.go index ac02e1651d44..9fcdb5776930 100644 --- a/tests/fuzzers/rlp/rlp_fuzzer.go +++ b/tests/fuzzers/rlp/rlp_fuzzer.go @@ -19,9 +19,11 @@ package rlp import ( "bytes" "fmt" + "math/big" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" + "github.com/holiman/uint256" ) func decodeEncode(input []byte, val interface{}, i int) { @@ -126,5 +128,16 @@ func Fuzz(input []byte) int { var rs types.Receipts decodeEncode(input, &rs, i) } + { + i++ + var v struct { + AnIntPtr *big.Int + AnInt big.Int + AnU256Ptr *uint256.Int + AnU256 uint256.Int + NotAnU256 [4]uint64 + } + decodeEncode(input, &v, i) + } return 1 } From beda6c41adbc72d1e39215359cdfd75ae0d2f053 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 3 Apr 2023 07:16:57 -0400 Subject: [PATCH 689/715] core/txpool: move some validation to outside of mutex (#27006) Currently, most of transaction validation while holding the txpool mutex: one exception being an early-on signature check. This PR changes that, so that we do all non-stateful checks before we entering the mutex area. This means they can be performed in parallel, and to enable that, certain fields have been made atomic bools and uint64. --- core/txpool/txpool.go | 81 +++++++++++++++++++++----------------- core/txpool/txpool_test.go | 31 ++++++++------- 2 files changed, 61 insertions(+), 51 deletions(-) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index ac4486c6cba8..3a5ed695681c 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -23,6 +23,7 @@ import ( "math/big" "sort" "sync" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -250,14 +251,14 @@ type TxPool struct { signer types.Signer mu sync.RWMutex - istanbul bool // Fork indicator whether we are in the istanbul stage. - eip2718 bool // Fork indicator whether we are using EIP-2718 type transactions. - eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions. - shanghai bool // Fork indicator whether we are in the Shanghai stage. + istanbul atomic.Bool // Fork indicator whether we are in the istanbul stage. + eip2718 atomic.Bool // Fork indicator whether we are using EIP-2718 type transactions. + eip1559 atomic.Bool // Fork indicator whether we are using EIP-1559 type transactions. + shanghai atomic.Bool // Fork indicator whether we are in the Shanghai stage. currentState *state.StateDB // Current state in the blockchain head pendingNonces *noncer // Pending state tracking virtual nonces - currentMaxGas uint64 // Current gas limit for transaction caps + currentMaxGas atomic.Uint64 // Current gas limit for transaction caps locals *accountSet // Set of local transaction to exempt from eviction rules journal *journal // Journal of local transaction to back up to disk @@ -592,15 +593,17 @@ func (pool *TxPool) local() map[common.Address]types.Transactions { return txs } -// validateTx checks whether a transaction is valid according to the consensus -// rules and adheres to some heuristic limits of the local node (price and size). -func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { +// validateTxBasics checks whether a transaction is valid according to the consensus +// rules, but does not check state-dependent validation such as sufficient balance. +// This check is meant as an early check which only needs to be performed once, +// and does not require the pool mutex to be held. +func (pool *TxPool) validateTxBasics(tx *types.Transaction, local bool) error { // Accept only legacy transactions until EIP-2718/2930 activates. - if !pool.eip2718 && tx.Type() != types.LegacyTxType { + if !pool.eip2718.Load() && tx.Type() != types.LegacyTxType { return core.ErrTxTypeNotSupported } // Reject dynamic fee transactions until EIP-1559 activates. - if !pool.eip1559 && tx.Type() == types.DynamicFeeTxType { + if !pool.eip1559.Load() && tx.Type() == types.DynamicFeeTxType { return core.ErrTxTypeNotSupported } // Reject transactions over defined size to prevent DOS attacks @@ -608,7 +611,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrOversizedData } // Check whether the init code size has been exceeded. - if pool.shanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + if pool.shanghai.Load() && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { return fmt.Errorf("%w: code size %v limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) } // Transactions can't be negative. This may never happen using RLP decoded @@ -617,7 +620,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrNegativeValue } // Ensure the transaction doesn't exceed the current block limit gas. - if pool.currentMaxGas < tx.Gas() { + if pool.currentMaxGas.Load() < tx.Gas() { return ErrGasLimit } // Sanity check for extremely large numbers @@ -632,14 +635,29 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return core.ErrTipAboveFeeCap } // Make sure the transaction is signed properly. - from, err := types.Sender(pool.signer, tx) - if err != nil { + if _, err := types.Sender(pool.signer, tx); err != nil { return ErrInvalidSender } // Drop non-local transactions under our own minimal accepted gas price or tip if !local && tx.GasTipCapIntCmp(pool.gasPrice) < 0 { return ErrUnderpriced } + // Ensure the transaction has more gas than the basic tx fee. + intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul.Load(), pool.shanghai.Load()) + if err != nil { + return err + } + if tx.Gas() < intrGas { + return core.ErrIntrinsicGas + } + return nil +} + +// validateTx checks whether a transaction is valid according to the consensus +// rules and adheres to some heuristic limits of the local node (price and size). +func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { + // Signature has been checked already, this cannot error. + from, _ := types.Sender(pool.signer, tx) // Ensure the transaction adheres to nonce ordering if pool.currentState.GetNonce(from) > tx.Nonce() { return core.ErrNonceTooLow @@ -664,15 +682,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrOverdraft } } - - // Ensure the transaction has more gas than the basic tx fee. - intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai) - if err != nil { - return err - } - if tx.Gas() < intrGas { - return core.ErrIntrinsicGas - } return nil } @@ -969,12 +978,12 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error { knownTxMeter.Mark(1) continue } - // Exclude transactions with invalid signatures as soon as - // possible and cache senders in transactions before - // obtaining lock - _, err := types.Sender(pool.signer, tx) - if err != nil { - errs[i] = ErrInvalidSender + // Exclude transactions with basic errors, e.g invalid signatures and + // insufficient intrinsic gas as soon as possible and cache senders + // in transactions before obtaining lock + + if err := pool.validateTxBasics(tx, local); err != nil { + errs[i] = err invalidTxMeter.Mark(1) continue } @@ -1364,7 +1373,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { } pool.currentState = statedb pool.pendingNonces = newNoncer(statedb) - pool.currentMaxGas = newHead.GasLimit + pool.currentMaxGas.Store(newHead.GasLimit) // Inject any transactions discarded due to reorgs log.Debug("Reinjecting stale transactions", "count", len(reinject)) @@ -1373,10 +1382,10 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { // Update all fork indicator by next pending block number. next := new(big.Int).Add(newHead.Number, big.NewInt(1)) - pool.istanbul = pool.chainconfig.IsIstanbul(next) - pool.eip2718 = pool.chainconfig.IsBerlin(next) - pool.eip1559 = pool.chainconfig.IsLondon(next) - pool.shanghai = pool.chainconfig.IsShanghai(uint64(time.Now().Unix())) + pool.istanbul.Store(pool.chainconfig.IsIstanbul(next)) + pool.eip2718.Store(pool.chainconfig.IsBerlin(next)) + pool.eip1559.Store(pool.chainconfig.IsLondon(next)) + pool.shanghai.Store(pool.chainconfig.IsShanghai(uint64(time.Now().Unix()))) } // promoteExecutables moves transactions that have become processable from the @@ -1400,7 +1409,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans } log.Trace("Removed old queued transactions", "count", len(forwards)) // Drop all transactions that are too costly (low balance or out of gas) - drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) + drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas.Load()) for _, tx := range drops { hash := tx.Hash() pool.all.Remove(hash) @@ -1597,7 +1606,7 @@ func (pool *TxPool) demoteUnexecutables() { log.Trace("Removed old pending transaction", "hash", hash) } // Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later - drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) + drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas.Load()) for _, tx := range drops { hash := tx.Hash() log.Trace("Removed unpayable pending transaction", "hash", hash) diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go index 7771c5f7cda1..a4889fa62f59 100644 --- a/core/txpool/txpool_test.go +++ b/core/txpool/txpool_test.go @@ -293,28 +293,29 @@ func TestInvalidTransactions(t *testing.T) { tx := transaction(0, 100, key) from, _ := deriveSender(tx) + // Intrinsic gas too low testAddBalance(pool, from, big.NewInt(1)) - if err := pool.AddRemote(tx); !errors.Is(err, core.ErrInsufficientFunds) { - t.Error("expected", core.ErrInsufficientFunds) + if err, want := pool.AddRemote(tx), core.ErrIntrinsicGas; !errors.Is(err, want) { + t.Errorf("want %v have %v", want, err) } - balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())) - testAddBalance(pool, from, balance) - if err := pool.AddRemote(tx); !errors.Is(err, core.ErrIntrinsicGas) { - t.Error("expected", core.ErrIntrinsicGas, "got", err) + // Insufficient funds + tx = transaction(0, 100000, key) + if err, want := pool.AddRemote(tx), core.ErrInsufficientFunds; !errors.Is(err, want) { + t.Errorf("want %v have %v", want, err) } testSetNonce(pool, from, 1) testAddBalance(pool, from, big.NewInt(0xffffffffffffff)) tx = transaction(0, 100000, key) - if err := pool.AddRemote(tx); !errors.Is(err, core.ErrNonceTooLow) { - t.Error("expected", core.ErrNonceTooLow) + if err, want := pool.AddRemote(tx), core.ErrNonceTooLow; !errors.Is(err, want) { + t.Errorf("want %v have %v", want, err) } tx = transaction(1, 100000, key) pool.gasPrice = big.NewInt(1000) - if err := pool.AddRemote(tx); err != ErrUnderpriced { - t.Error("expected", ErrUnderpriced, "got", err) + if err, want := pool.AddRemote(tx), ErrUnderpriced; !errors.Is(err, want) { + t.Errorf("want %v have %v", want, err) } if err := pool.AddLocal(tx); err != nil { t.Error("expected", nil, "got", err) @@ -1217,22 +1218,22 @@ func TestAllowedTxSize(t *testing.T) { // All those fields are summed up to at most 213 bytes. baseSize := uint64(213) dataSize := txMaxSize - baseSize - + maxGas := pool.currentMaxGas.Load() // Try adding a transaction with maximal allowed size - tx := pricedDataTransaction(0, pool.currentMaxGas, big.NewInt(1), key, dataSize) + tx := pricedDataTransaction(0, maxGas, big.NewInt(1), key, dataSize) if err := pool.addRemoteSync(tx); err != nil { t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err) } // Try adding a transaction with random allowed size - if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentMaxGas, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil { + if err := pool.addRemoteSync(pricedDataTransaction(1, maxGas, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil { t.Fatalf("failed to add transaction of random allowed size: %v", err) } // Try adding a transaction of minimal not allowed size - if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentMaxGas, big.NewInt(1), key, txMaxSize)); err == nil { + if err := pool.addRemoteSync(pricedDataTransaction(2, maxGas, big.NewInt(1), key, txMaxSize)); err == nil { t.Fatalf("expected rejection on slightly oversize transaction") } // Try adding a transaction of random not allowed size - if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentMaxGas, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { + if err := pool.addRemoteSync(pricedDataTransaction(2, maxGas, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { t.Fatalf("expected rejection on oversize transaction") } // Run some sanity checks on the pool internals From db18293c32f6dc5d6886e5e68ab8bfd12e33cad6 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 4 Apr 2023 03:48:10 +0800 Subject: [PATCH 690/715] eth/downloader: use atomic types (#27030) * eth/downloader: use atomic type * Update eth/downloader/downloader_test.go Co-authored-by: Martin Holst Swende * Update eth/downloader/downloader_test.go Co-authored-by: Martin Holst Swende --------- Co-authored-by: Martin Holst Swende --- eth/downloader/beaconsync.go | 3 +-- eth/downloader/downloader.go | 30 +++++++++++++++--------------- eth/downloader/downloader_test.go | 25 +++++++++++++------------ eth/downloader/queue.go | 18 +++++++++--------- eth/downloader/resultstore.go | 8 ++++---- eth/downloader/skeleton_test.go | 24 ++++++++++++------------ 6 files changed, 54 insertions(+), 54 deletions(-) diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index ff985e6b035f..df8af68bc798 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -19,7 +19,6 @@ package downloader import ( "fmt" "sync" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -371,7 +370,7 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error { continue } // If the pivot block is committed, signal header sync termination - if atomic.LoadInt32(&d.committed) == 1 { + if d.committed.Load() { select { case d.headerProcCh <- nil: return nil diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index fb9de79912e2..a3d8a210600c 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -98,7 +98,7 @@ type headerTask struct { } type Downloader struct { - mode uint32 // Synchronisation mode defining the strategy used (per sync cycle), use d.getMode() to get the SyncMode + mode atomic.Uint32 // Synchronisation mode defining the strategy used (per sync cycle), use d.getMode() to get the SyncMode mux *event.TypeMux // Event multiplexer to announce sync operation events checkpoint uint64 // Checkpoint block number to enforce head against (e.g. snap sync) @@ -122,9 +122,9 @@ type Downloader struct { // Status synchroniseMock func(id string, hash common.Hash) error // Replacement for synchronise during testing - synchronising int32 - notified int32 - committed int32 + synchronising atomic.Bool + notified atomic.Bool + committed atomic.Bool ancientLimit uint64 // The maximum block number which can be regarded as ancient data. // Channels @@ -292,7 +292,7 @@ func (d *Downloader) Progress() ethereum.SyncProgress { // Synchronising returns whether the downloader is currently retrieving blocks. func (d *Downloader) Synchronising() bool { - return atomic.LoadInt32(&d.synchronising) > 0 + return d.synchronising.Load() } // RegisterPeer injects a new download peer into the set of block source to be @@ -392,13 +392,13 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, return d.synchroniseMock(id, hash) } // Make sure only one goroutine is ever allowed past this point at once - if !atomic.CompareAndSwapInt32(&d.synchronising, 0, 1) { + if !d.synchronising.CompareAndSwap(false, true) { return errBusy } - defer atomic.StoreInt32(&d.synchronising, 0) + defer d.synchronising.Store(false) // Post a user notification of the sync (only once per session) - if atomic.CompareAndSwapInt32(&d.notified, 0, 1) { + if d.notified.CompareAndSwap(false, true) { log.Info("Block synchronisation started") } if mode == SnapSync { @@ -435,7 +435,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, defer d.Cancel() // No matter what, we can't leave the cancel channel open // Atomically set the requested sync mode - atomic.StoreUint32(&d.mode, uint32(mode)) + d.mode.Store(uint32(mode)) // Retrieve the origin peer and initiate the downloading process var p *peerConnection @@ -452,7 +452,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, } func (d *Downloader) getMode() SyncMode { - return SyncMode(atomic.LoadUint32(&d.mode)) + return SyncMode(d.mode.Load()) } // syncWithPeer starts a block synchronization based on the hash chain from the @@ -562,9 +562,9 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd * rawdb.WriteLastPivotNumber(d.stateDB, pivotNumber) } } - d.committed = 1 + d.committed.Store(true) if mode == SnapSync && pivot.Number.Uint64() != 0 { - d.committed = 0 + d.committed.Store(false) } if mode == SnapSync { // Set the ancient data limitation. If we are running snap sync, all block @@ -1128,7 +1128,7 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, head uint64) e // If no more headers are inbound, notify the content fetchers and return if len(headers) == 0 { // Don't abort header fetches while the pivot is downloading - if atomic.LoadInt32(&d.committed) == 0 && pivot <= from { + if !d.committed.Load() && pivot <= from { p.log.Debug("No headers, waiting for pivot commit") select { case <-time.After(fsHeaderContCheck): @@ -1669,7 +1669,7 @@ func (d *Downloader) processSnapSyncContent() error { results = append(append([]*fetchResult{oldPivot}, oldTail...), results...) } // Split around the pivot block and process the two sides via snap/full sync - if atomic.LoadInt32(&d.committed) == 0 { + if !d.committed.Load() { latest := results[len(results)-1].Header // If the height is above the pivot block by 2 sets, it means the pivot // become stale in the network and it was garbage collected, move to a @@ -1794,7 +1794,7 @@ func (d *Downloader) commitPivotBlock(result *fetchResult) error { if err := d.blockchain.SnapSyncCommitHead(block.Hash()); err != nil { return err } - atomic.StoreInt32(&d.committed, 1) + d.committed.Store(true) return nil } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index a884c1e950b0..37f7a7670469 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -476,9 +476,10 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { tester.newPeer("peer", protocol, testChainBase.blocks[1:]) // Wrap the importer to allow stepping - blocked, proceed := uint32(0), make(chan struct{}) + var blocked atomic.Uint32 + proceed := make(chan struct{}) tester.downloader.chainInsertHook = func(results []*fetchResult) { - atomic.StoreUint32(&blocked, uint32(len(results))) + blocked.Store(uint32(len(results))) <-proceed } // Start a synchronisation concurrently @@ -505,7 +506,7 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { tester.downloader.queue.resultCache.lock.Lock() { cached = tester.downloader.queue.resultCache.countCompleted() - frozen = int(atomic.LoadUint32(&blocked)) + frozen = int(blocked.Load()) retrieved = int(tester.chain.CurrentSnapBlock().Number.Uint64()) + 1 } tester.downloader.queue.resultCache.lock.Unlock() @@ -528,8 +529,8 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { t.Fatalf("block count mismatch: have %v, want %v (owned %v, blocked %v, target %v)", cached, blockCacheMaxItems, retrieved, frozen, targetBlocks+1) } // Permit the blocked blocks to import - if atomic.LoadUint32(&blocked) > 0 { - atomic.StoreUint32(&blocked, uint32(0)) + if blocked.Load() > 0 { + blocked.Store(uint32(0)) proceed <- struct{}{} } } @@ -786,12 +787,12 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { tester.newPeer("peer", protocol, chain.blocks[1:]) // Instrument the downloader to signal body requests - bodiesHave, receiptsHave := int32(0), int32(0) + var bodiesHave, receiptsHave atomic.Int32 tester.downloader.bodyFetchHook = func(headers []*types.Header) { - atomic.AddInt32(&bodiesHave, int32(len(headers))) + bodiesHave.Add(int32(len(headers))) } tester.downloader.receiptFetchHook = func(headers []*types.Header) { - atomic.AddInt32(&receiptsHave, int32(len(headers))) + receiptsHave.Add(int32(len(headers))) } // Synchronise with the peer and make sure all blocks were retrieved if err := tester.sync("peer", nil, mode); err != nil { @@ -811,11 +812,11 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { receiptsNeeded++ } } - if int(bodiesHave) != bodiesNeeded { - t.Errorf("body retrieval count mismatch: have %v, want %v", bodiesHave, bodiesNeeded) + if int(bodiesHave.Load()) != bodiesNeeded { + t.Errorf("body retrieval count mismatch: have %v, want %v", bodiesHave.Load(), bodiesNeeded) } - if int(receiptsHave) != receiptsNeeded { - t.Errorf("receipt retrieval count mismatch: have %v, want %v", receiptsHave, receiptsNeeded) + if int(receiptsHave.Load()) != receiptsNeeded { + t.Errorf("receipt retrieval count mismatch: have %v, want %v", receiptsHave.Load(), receiptsNeeded) } } diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 5af5068c98cf..e9907297a0b9 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -61,7 +61,7 @@ type fetchRequest struct { // fetchResult is a struct collecting partial results from data fetchers until // all outstanding pieces complete and the result as a whole can be processed. type fetchResult struct { - pending int32 // Flag telling what deliveries are outstanding + pending atomic.Int32 // Flag telling what deliveries are outstanding Header *types.Header Uncles []*types.Header @@ -75,38 +75,38 @@ func newFetchResult(header *types.Header, fastSync bool) *fetchResult { Header: header, } if !header.EmptyBody() { - item.pending |= (1 << bodyType) + item.pending.Store(item.pending.Load() | (1 << bodyType)) } else if header.WithdrawalsHash != nil { item.Withdrawals = make(types.Withdrawals, 0) } if fastSync && !header.EmptyReceipts() { - item.pending |= (1 << receiptType) + item.pending.Store(item.pending.Load() | (1 << receiptType)) } return item } // SetBodyDone flags the body as finished. func (f *fetchResult) SetBodyDone() { - if v := atomic.LoadInt32(&f.pending); (v & (1 << bodyType)) != 0 { - atomic.AddInt32(&f.pending, -1) + if v := f.pending.Load(); (v & (1 << bodyType)) != 0 { + f.pending.Add(-1) } } // AllDone checks if item is done. func (f *fetchResult) AllDone() bool { - return atomic.LoadInt32(&f.pending) == 0 + return f.pending.Load() == 0 } // SetReceiptsDone flags the receipts as finished. func (f *fetchResult) SetReceiptsDone() { - if v := atomic.LoadInt32(&f.pending); (v & (1 << receiptType)) != 0 { - atomic.AddInt32(&f.pending, -2) + if v := f.pending.Load(); (v & (1 << receiptType)) != 0 { + f.pending.Add(-2) } } // Done checks if the given type is done already func (f *fetchResult) Done(kind uint) bool { - v := atomic.LoadInt32(&f.pending) + v := f.pending.Load() return v&(1<= int32(len(r.items)) { break @@ -156,7 +156,7 @@ func (r *resultStore) countCompleted() int { break } } - atomic.StoreInt32(&r.indexIncomplete, index) + r.indexIncomplete.Store(index) return int(index) } @@ -179,7 +179,7 @@ func (r *resultStore) GetCompleted(limit int) []*fetchResult { } // Advance the expected block number of the first cache entry r.resultOffset += uint64(limit) - atomic.AddInt32(&r.indexIncomplete, int32(-limit)) + r.indexIncomplete.Add(int32(-limit)) return results } diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index b19494a7b069..6a76d78ac817 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -82,8 +82,8 @@ type skeletonTestPeer struct { serve func(origin uint64) []*types.Header // Hook to allow custom responses - served uint64 // Number of headers served by this peer - dropped uint64 // Flag whether the peer was dropped (stop responding) + served atomic.Uint64 // Number of headers served by this peer + dropped atomic.Uint64 // Flag whether the peer was dropped (stop responding) } // newSkeletonTestPeer creates a new mock peer to test the skeleton sync with. @@ -113,7 +113,7 @@ func (p *skeletonTestPeer) RequestHeadersByNumber(origin uint64, amount int, ski // Since skeleton test peer are in-memory mocks, dropping the does not make // them inaccessible. As such, check a local `dropped` field to see if the // peer has been dropped and should not respond any more. - if atomic.LoadUint64(&p.dropped) != 0 { + if p.dropped.Load() != 0 { return nil, errors.New("peer already dropped") } // Skeleton sync retrieves batches of headers going backward without gaps. @@ -161,7 +161,7 @@ func (p *skeletonTestPeer) RequestHeadersByNumber(origin uint64, amount int, ski } } } - atomic.AddUint64(&p.served, uint64(len(headers))) + p.served.Add(uint64(len(headers))) hashes := make([]common.Hash, len(headers)) for i, header := range headers { @@ -182,7 +182,7 @@ func (p *skeletonTestPeer) RequestHeadersByNumber(origin uint64, amount int, ski sink <- res if err := <-res.Done; err != nil { log.Warn("Skeleton test peer response rejected", "err", err) - atomic.AddUint64(&p.dropped, 1) + p.dropped.Add(1) } }() return req, nil @@ -817,7 +817,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) { dropped := make(map[string]int) drop := func(peer string) { if p := peerset.Peer(peer); p != nil { - atomic.AddUint64(&p.peer.(*skeletonTestPeer).dropped, 1) + p.peer.(*skeletonTestPeer).dropped.Add(1) } peerset.Unregister(peer) dropped[peer]++ @@ -895,14 +895,14 @@ func TestSkeletonSyncRetrievals(t *testing.T) { if !tt.unpredictable { var served uint64 for _, peer := range tt.peers { - served += atomic.LoadUint64(&peer.served) + served += peer.served.Load() } if served != tt.midserve { t.Errorf("test %d, mid state: served headers mismatch: have %d, want %d", i, served, tt.midserve) } var drops uint64 for _, peer := range tt.peers { - drops += atomic.LoadUint64(&peer.dropped) + drops += peer.dropped.Load() } if drops != tt.middrop { t.Errorf("test %d, mid state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) @@ -950,20 +950,20 @@ func TestSkeletonSyncRetrievals(t *testing.T) { if !tt.unpredictable { served := uint64(0) for _, peer := range tt.peers { - served += atomic.LoadUint64(&peer.served) + served += peer.served.Load() } if tt.newPeer != nil { - served += atomic.LoadUint64(&tt.newPeer.served) + served += tt.newPeer.served.Load() } if served != tt.endserve { t.Errorf("test %d, end state: served headers mismatch: have %d, want %d", i, served, tt.endserve) } drops := uint64(0) for _, peer := range tt.peers { - drops += atomic.LoadUint64(&peer.dropped) + drops += peer.dropped.Load() } if tt.newPeer != nil { - drops += atomic.LoadUint64(&tt.newPeer.dropped) + drops += tt.newPeer.dropped.Load() } if drops != tt.enddrop { t.Errorf("test %d, end state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) From 9b1a82c6009385be860608fbc573d5842c8c187f Mon Sep 17 00:00:00 2001 From: joohhnnn <68833933+joohhnnn@users.noreply.github.com> Date: Tue, 4 Apr 2023 14:59:40 +0800 Subject: [PATCH 691/715] core/vm: clarify comment (#27045) --- core/vm/analysis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 4aa8cfe70f11..38af9084aca1 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -63,7 +63,7 @@ func (bits *bitvec) codeSegment(pos uint64) bool { // codeBitmap collects data locations in code. func codeBitmap(code []byte) bitvec { // The bitmap is 4 bytes longer than necessary, in case the code - // ends with a PUSH32, the algorithm will push zeroes onto the + // ends with a PUSH32, the algorithm will set bits on the // bitvector outside the bounds of the actual code. bits := make(bitvec, len(code)/8+1+4) return codeBitmapInternal(code, bits) From 91faf2c55958d182677f15dc30c0ad9847342395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 4 Apr 2023 10:02:50 +0300 Subject: [PATCH 692/715] consensus, core/typer: add 4844 excessDataGas to header, tie it to Cancun (#27046) --- consensus/beacon/consensus.go | 10 +++++++++- consensus/clique/clique.go | 3 +++ consensus/ethash/consensus.go | 3 +++ core/types/block.go | 3 +++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index b4da9b553a7b..1129ac06c8e4 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -263,11 +263,19 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa // Verify existence / non-existence of withdrawalsHash. shanghai := chain.Config().IsShanghai(header.Time) if shanghai && header.WithdrawalsHash == nil { - return fmt.Errorf("missing withdrawalsHash") + return errors.New("missing withdrawalsHash") } if !shanghai && header.WithdrawalsHash != nil { return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash) } + // Verify the existence / non-existence of excessDataGas + cancun := chain.Config().IsCancun(header.Time) + if cancun && header.ExcessDataGas == nil { + return errors.New("missing excessDataGas") + } + if !cancun && header.ExcessDataGas != nil { + return fmt.Errorf("invalid excessDataGas: have %d, expected nil", header.ExcessDataGas) + } return nil } diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 6c20803b2a11..1b9a1d923690 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -301,6 +301,9 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H if chain.Config().IsShanghai(header.Time) { return fmt.Errorf("clique does not support shanghai fork") } + if chain.Config().IsCancun(header.Time) { + return fmt.Errorf("clique does not support cancun fork") + } // If all checks passed, validate any special fields for hard forks if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { return err diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index c3c06c541cab..8f1b497cbdfb 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -313,6 +313,9 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa if chain.Config().IsShanghai(header.Time) { return fmt.Errorf("ethash does not support shanghai fork") } + if chain.Config().IsCancun(header.Time) { + return fmt.Errorf("ethash does not support cancun fork") + } // Verify the engine specific seal securing the block if seal { if err := ethash.verifySeal(chain, header, false); err != nil { diff --git a/core/types/block.go b/core/types/block.go index e2c71abebd70..a1a14f5b1657 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -85,6 +85,9 @@ type Header struct { // WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers. WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` + // ExcessDataGas was added by EIP-4844 and is ignored in legacy headers. + ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"` + /* TODO (MariusVanDerWijden) Add this field once needed // Random was added during the merge and contains the BeaconState randomness From d2cf49327f3d083e6e4eec0c747a8683f7c7b97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 4 Apr 2023 11:25:28 +0300 Subject: [PATCH 693/715] consensus/misc, params: add EIP-4844 blobfee conversions (#27041) * consensus/misc, params: add EIP-4844 blobfee conversions * consensus/misc: pull in fakeExponential test cases * consensus/misc: reuse bigints * consensus/misc: nit renames, additional larger testcase --------- Co-authored-by: Roberto Bayardo Co-authored-by: Martin Holst Swende --- consensus/misc/eip4844.go | 54 +++++++++++++++++++++ consensus/misc/eip4844_test.go | 85 ++++++++++++++++++++++++++++++++++ params/protocol_params.go | 3 ++ 3 files changed, 142 insertions(+) create mode 100644 consensus/misc/eip4844.go create mode 100644 consensus/misc/eip4844_test.go diff --git a/consensus/misc/eip4844.go b/consensus/misc/eip4844.go new file mode 100644 index 000000000000..66ca9bd26d86 --- /dev/null +++ b/consensus/misc/eip4844.go @@ -0,0 +1,54 @@ +// Copyright 2023 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 misc + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/params" +) + +var ( + minDataGasPrice = big.NewInt(params.BlobTxMinDataGasprice) + dataGaspriceUpdateFraction = big.NewInt(params.BlobTxDataGaspriceUpdateFraction) +) + +// CalcBlobFee calculates the blobfee from the header's excess data gas field. +func CalcBlobFee(excessDataGas *big.Int) *big.Int { + // If this block does not yet have EIP-4844 enabled, return the starting fee + if excessDataGas == nil { + return big.NewInt(params.BlobTxMinDataGasprice) + } + return fakeExponential(minDataGasPrice, excessDataGas, dataGaspriceUpdateFraction) +} + +// fakeExponential approximates factor * e ** (numerator / denominator) using +// Taylor expansion. +func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { + var ( + output = new(big.Int) + accum = new(big.Int).Mul(factor, denominator) + ) + for i := 1; accum.Sign() > 0; i++ { + output.Add(output, accum) + + accum.Mul(accum, numerator) + accum.Div(accum, denominator) + accum.Div(accum, big.NewInt(int64(i))) + } + return output.Div(output, denominator) +} diff --git a/consensus/misc/eip4844_test.go b/consensus/misc/eip4844_test.go new file mode 100644 index 000000000000..5838cab8e669 --- /dev/null +++ b/consensus/misc/eip4844_test.go @@ -0,0 +1,85 @@ +// Copyright 2023 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 misc + +import ( + "fmt" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/params" +) + +func TestCalcBlobFee(t *testing.T) { + tests := []struct { + excessDataGas int64 + blobfee int64 + }{ + {0, 1}, + {1542706, 1}, + {1542707, 2}, + {10 * 1024 * 1024, 111}, + } + have := CalcBlobFee(nil) + if have.Int64() != params.BlobTxMinDataGasprice { + t.Errorf("nil test: blobfee mismatch: have %v, want %v", have, params.BlobTxMinDataGasprice) + } + for i, tt := range tests { + have := CalcBlobFee(big.NewInt(tt.excessDataGas)) + if have.Int64() != 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 + numerator int64 + denominator int64 + want int64 + }{ + // When numerator == 0 the return value should always equal the value of factor + {1, 0, 1, 1}, + {38493, 0, 1000, 38493}, + {0, 1234, 2345, 0}, // should be 0 + {1, 2, 1, 6}, // approximate 7.389 + {1, 4, 2, 6}, + {1, 3, 1, 16}, // approximate 20.09 + {1, 6, 2, 18}, + {1, 4, 1, 49}, // approximate 54.60 + {1, 8, 2, 50}, + {10, 8, 2, 542}, // approximate 540.598 + {11, 8, 2, 596}, // approximate 600.58 + {1, 5, 1, 136}, // approximate 148.4 + {1, 5, 2, 11}, // approximate 12.18 + {2, 5, 2, 23}, // approximate 24.36 + {1, 50000000, 2225652, 5709098764}, + } + for i, tt := range tests { + f, n, d := big.NewInt(tt.factor), big.NewInt(tt.numerator), big.NewInt(tt.denominator) + original := fmt.Sprintf("%d %d %d", f, n, d) + have := fakeExponential(f, n, d) + if have.Int64() != tt.want { + t.Errorf("test %d: fake exponential mismatch: have %v want %v", i, have, tt.want) + } + later := fmt.Sprintf("%d %d %d", f, n, d) + if original != later { + t.Errorf("test %d: fake exponential modified arguments: have\n%v\nwant\n%v", i, later, original) + } + } +} diff --git a/params/protocol_params.go b/params/protocol_params.go index bb703d0b74dc..ab5ed13c0603 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -159,6 +159,9 @@ const ( // up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529 RefundQuotient uint64 = 2 RefundQuotientEIP3529 uint64 = 5 + + BlobTxMinDataGasprice = 1 // Minimum gas price for data blobs + BlobTxDataGaspriceUpdateFraction = 2225652 // Controls the maximum rate of change for data gas price ) // Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations From 0b76eb3708626fbd2eb9c1b58d7b4eac6a5eec15 Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 4 Apr 2023 18:34:23 +0800 Subject: [PATCH 694/715] eth/tracers: report correct gasLimit in call tracers (#27029) This includes a semantic change to the `callTracer` as well as `flatCallTracer`. The value of field `gas` in the **first** call frame will change as follows: - It previously contained gas available after initial deductions (i.e. tx costs) - It will now contain the full tx gasLimit value Signed-off-by: jsvisa --- eth/tracers/internal/tracetest/calltrace_test.go | 6 +++--- eth/tracers/internal/tracetest/flat_calltrace_test.go | 4 ++-- .../internal/tracetest/testdata/call_tracer/create.json | 2 +- .../internal/tracetest/testdata/call_tracer/deep_calls.json | 2 +- .../tracetest/testdata/call_tracer/delegatecall.json | 2 +- .../testdata/call_tracer/inner_create_oog_outer_throw.json | 2 +- .../tracetest/testdata/call_tracer/inner_instafail.json | 2 +- .../tracetest/testdata/call_tracer/inner_revert_reason.json | 2 +- .../testdata/call_tracer/inner_throw_outer_revert.json | 2 +- .../internal/tracetest/testdata/call_tracer/oog.json | 2 +- .../internal/tracetest/testdata/call_tracer/revert.json | 2 +- .../tracetest/testdata/call_tracer/revert_reason.json | 4 ++-- .../tracetest/testdata/call_tracer/selfdestruct.json | 2 +- .../internal/tracetest/testdata/call_tracer/simple.json | 2 +- .../tracetest/testdata/call_tracer/simple_onlytop.json | 2 +- .../internal/tracetest/testdata/call_tracer/throw.json | 2 +- .../tracetest/testdata/call_tracer_flat/big_slow.json | 2 +- .../call_tracer_flat/callcode_precompiled_fail_hide.json | 2 +- .../testdata/call_tracer_flat/callcode_precompiled_oog.json | 2 +- .../call_tracer_flat/callcode_precompiled_throw.json | 2 +- .../tracetest/testdata/call_tracer_flat/create.json | 2 +- .../tracetest/testdata/call_tracer_flat/deep_calls.json | 2 +- .../tracetest/testdata/call_tracer_flat/delegatecall.json | 2 +- .../call_tracer_flat/delegatecall_parent_value.json | 2 +- .../internal/tracetest/testdata/call_tracer_flat/gas.json | 2 +- .../testdata/call_tracer_flat/include_precompiled.json | 2 +- .../call_tracer_flat/inner_create_oog_outer_throw.json | 2 +- .../testdata/call_tracer_flat/inner_instafail.json | 2 +- .../call_tracer_flat/inner_precompiled_wrong_gas.json | 2 +- .../testdata/call_tracer_flat/inner_throw_outer_revert.json | 2 +- .../tracetest/testdata/call_tracer_flat/nested_create.json | 2 +- .../call_tracer_flat/nested_create2_action_gas.json | 2 +- .../testdata/call_tracer_flat/nested_create_action_gas.json | 2 +- .../testdata/call_tracer_flat/nested_create_inerror.json | 2 +- .../testdata/call_tracer_flat/nested_pointer_issue.json | 2 +- .../internal/tracetest/testdata/call_tracer_flat/oog.json | 2 +- .../call_tracer_flat/option_convert_parity_errors.json | 2 +- .../tracetest/testdata/call_tracer_flat/result_output.json | 2 +- .../tracetest/testdata/call_tracer_flat/revert.json | 2 +- .../tracetest/testdata/call_tracer_flat/revert_reason.json | 2 +- .../tracetest/testdata/call_tracer_flat/selfdestruct.json | 2 +- .../tracetest/testdata/call_tracer_flat/simple.json | 2 +- .../testdata/call_tracer_flat/skip_no_balance_error.json | 2 +- .../testdata/call_tracer_flat/staticcall_precompiled.json | 2 +- .../tracetest/testdata/call_tracer_flat/suicide.json | 2 +- .../internal/tracetest/testdata/call_tracer_flat/throw.json | 2 +- .../tracetest/testdata/call_tracer_legacy/create.json | 2 +- .../tracetest/testdata/call_tracer_legacy/deep_calls.json | 2 +- .../tracetest/testdata/call_tracer_legacy/delegatecall.json | 2 +- .../call_tracer_legacy/inner_create_oog_outer_throw.json | 2 +- .../testdata/call_tracer_legacy/inner_instafail.json | 4 ++-- .../call_tracer_legacy/inner_throw_outer_revert.json | 2 +- .../internal/tracetest/testdata/call_tracer_legacy/oog.json | 2 +- .../tracetest/testdata/call_tracer_legacy/revert.json | 2 +- .../testdata/call_tracer_legacy/revert_reason.json | 2 +- .../tracetest/testdata/call_tracer_legacy/selfdestruct.json | 2 +- .../tracetest/testdata/call_tracer_legacy/simple.json | 2 +- .../tracetest/testdata/call_tracer_legacy/throw.json | 2 +- .../tracetest/testdata/call_tracer_withLog/calldata.json | 2 +- .../testdata/call_tracer_withLog/delegatecall.json | 2 +- .../testdata/call_tracer_withLog/multi_contracts.json | 2 +- .../tracetest/testdata/call_tracer_withLog/multilogs.json | 2 +- .../tracetest/testdata/call_tracer_withLog/notopic.json | 2 +- .../tracetest/testdata/call_tracer_withLog/simple.json | 2 +- .../tracetest/testdata/call_tracer_withLog/tx_failed.json | 2 +- .../testdata/call_tracer_withLog/tx_partial_failed.json | 2 +- .../testdata/call_tracer_withLog/with_onlyTopCall.json | 2 +- eth/tracers/js/goja.go | 2 +- eth/tracers/native/call.go | 2 +- 69 files changed, 74 insertions(+), 74 deletions(-) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index c5405e245179..a70842d40c0a 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -302,13 +302,13 @@ func TestInternals(t *testing.T) { byte(vm.CALL), }, tracer: mkTracer("callTracer", nil), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, }, { name: "Stack depletion in LOG0", code: []byte{byte(vm.LOG3)}, tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, }, { name: "Mem expansion in LOG0", @@ -321,7 +321,7 @@ func TestInternals(t *testing.T) { byte(vm.LOG0), }, tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)), - want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x7148","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, + want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, }, { // Leads to OOM on the prestate tracer diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 8cd5a42bc0c0..9b51ba80ffa5 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -124,8 +124,8 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to retrieve trace result: %v", err) } - ret := new([]flatCallTrace) - if err := json.Unmarshal(res, ret); err != nil { + ret := make([]flatCallTrace, 0) + if err := json.Unmarshal(res, &ret); err != nil { return fmt.Errorf("failed to unmarshal trace result: %v", err) } if !jsonEqualFlat(ret, test.Result) { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer/create.json index 8557f8efd69b..df0b2872b48b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/create.json @@ -47,7 +47,7 @@ "input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f", "result": { "from": "0x13e4acefe6a6700604929946e70e6443e4e73447", - "gas": "0x5e106", + "gas": "0x897be", "gasUsed": "0x897be", "input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", "output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json index 174f23fc456c..975616064af9 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/deep_calls.json @@ -399,7 +399,7 @@ } ], "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "gasUsed": "0x1810b", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json index 5fd946f73467..6a2cda7dc989 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/delegatecall.json @@ -87,7 +87,7 @@ } ], "from": "0xa529806c67cc6486d4d62024471772f47f6fd672", - "gas": "0x2d6e28", + "gas": "0x2dc6c0", "gasUsed": "0xbd55", "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", "to": "0x269296dddce321a6bcbaa2f0181127593d732cba", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json index 95c5889269fc..bb16a4a4303a 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_create_oog_outer_throw.json @@ -67,7 +67,7 @@ ], "error": "invalid jump destination", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", - "gas": "0x435c8", + "gas": "0x493e0", "gasUsed": "0x493e0", "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json index 4d7305a15479..9b45b52fe9ad 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json @@ -54,7 +54,7 @@ "from": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", "to": "0x6c06b16512b332e6cd8293a2974872674716ce18", "value": "0x0", - "gas": "0x1a466", + "gas": "0x1f97e", "gasUsed": "0x72de", "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000" } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json index b5355f65fe94..ad0627ccd660 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_revert_reason.json @@ -50,7 +50,7 @@ "input": "0x02f9029d82053980849502f90085010c388d00832dc6c08080b90241608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033c001a07566181071cabaf58b70fc41557eb813bfc7a24f5c58554e7fed0bf7c031f169a0420af50b5fe791a4d839e181a676db5250b415dfb35cb85d544db7a1475ae2cc", "result": { "from": "0x3623191d4ccfbbdf09e8ebf6382a1f8257417bc1", - "gas": "0x2cd774", + "gas": "0x2dc6c0", "gasUsed": "0x25590", "input": "0x608060405234801561001057600080fd5b50600060405161001f906100a2565b604051809103906000f08015801561003b573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c04062266040518163ffffffff1660e01b815260040160006040518083038186803b15801561008457600080fd5b505afa158015610098573d6000803e3d6000fd5b50505050506100af565b610145806100fc83390190565b603f806100bd6000396000f3fe6080604052600080fdfea264697066735822122077f7dbd3450d6e817079cf3fe27107de5768bb3163a402b94e2206b468eb025664736f6c63430008070033608060405234801561001057600080fd5b50610125806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c040622614602d575b600080fd5b60336035565b005b60036002116076576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401606d906097565b60405180910390fd5b565b6000608360128360b5565b9150608c8260c6565b602082019050919050565b6000602082019050818103600083015260ae816078565b9050919050565b600082825260208201905092915050565b7f546869732063616c6c6564206661696c6564000000000000000000000000000060008201525056fea264697066735822122033f8d92e29d467e5ea08d0024eab0b36b86b8cdb3542c6e89dbaabeb8ffaa42064736f6c63430008070033", "output": "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012546869732063616c6c6564206661696c65640000000000000000000000000000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json index 2be2dee23f26..a023ed6d9bd7 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_throw_outer_revert.json @@ -71,7 +71,7 @@ ], "error": "execution reverted", "from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826", - "gas": "0x78d9e", + "gas": "0x7dfa6", "gasUsed": "0x7c1c8", "input": "0x", "to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json index 8022f53a992d..333bdd038cf5 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/oog.json @@ -50,7 +50,7 @@ "result": { "error": "out of gas", "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", - "gas": "0x7045", + "gas": "0xca1d", "gasUsed": "0xca1d", "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json index aee894d11fde..3207a298a98b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/revert.json @@ -48,7 +48,7 @@ "result": { "error": "execution reverted", "from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9", - "gas": "0x2d55e8", + "gas": "0x2dc6c0", "gasUsed": "0x719b", "input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000", "to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json index 8c8abd4d6d24..f02e5c686322 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/revert_reason.json @@ -27,7 +27,7 @@ "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, - "IstanbulBlock":1561651, + "IstanbulBlock": 1561651, "chainId": 5, "daoForkSupport": true, "eip150Block": 0, @@ -53,7 +53,7 @@ "result": { "error": "execution reverted", "from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", - "gas": "0x2d7308", + "gas": "0x2dc6c0", "gasUsed": "0x5940", "input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json index a89d4dc7456b..620df1d6149d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/selfdestruct.json @@ -64,7 +64,7 @@ } ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "gasUsed": "0x6fcb", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json index 0a6d66a5c4ca..6c7d01de1fc6 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple.json @@ -69,7 +69,7 @@ } ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "gasUsed": "0x9751", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x0000000000000000000000000000000000000000000000000000000000000001", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json index 5e25a01cef2d..affb4ab033ab 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json @@ -61,7 +61,7 @@ }, "result": { "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "gasUsed": "0x9751", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x0000000000000000000000000000000000000000000000000000000000000001", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json index 76fae3c392b3..499b449a6ece 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/throw.json @@ -52,7 +52,7 @@ "result": { "error": "invalid jump destination", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "gasUsed": "0x3d090", "input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json index e54ede92b02a..617f52a14e8a 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/big_slow.json @@ -46,7 +46,7 @@ { "action": { "from": "0xf8bda96b67036ee48107f2a0695ea673479dda56", - "gas": "0x22410c", + "gas": "0x231860", "init": "0x5b620186a05a131560135760016020526000565b600080601f600039601f565b6000f3", "value": "0x0" }, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json index be198885cbc3..c796804a4bcd 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x19f78", "init": "0x60206000600060006013600462030d40f260025560005160005500" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json index 94b864ff497d..fb29e49660d5 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_oog.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x1a758", "init": "0x7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb7f260025560a060020a60805106600055600054321460015500" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json index 506dc5ff68ec..3c1e370f91c7 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_throw.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x1a034", "init": "0x36600060003760406103e8366000600060095af26001556103e8516002556104085160035500" }, "error": "out of gas", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json index b83236690c26..11bc4eae022b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/create.json @@ -49,7 +49,7 @@ { "action": { "from": "0x13e4acefe6a6700604929946e70e6443e4e73447", - "gas": "0x5e106", + "gas": "0x897be", "init": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", "value": "0x0" }, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json index 5931b4080922..375a16361413 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/deep_calls.json @@ -113,7 +113,7 @@ "action": { "callType": "call", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json index 3a03ffc0fa96..e5a37cbfdd27 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json @@ -66,7 +66,7 @@ "action": { "callType": "call", "from": "0xa529806c67cc6486d4d62024471772f47f6fd672", - "gas": "0x2d6e28", + "gas": "0x2dc6c0", "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", "to": "0x269296dddce321a6bcbaa2f0181127593d732cba", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json index 800a6a4288de..177912420aae 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall_parent_value.json @@ -59,7 +59,7 @@ "action": { "callType": "call", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "gas": "0x10b68", + "gas": "0x15f90", "input": "0x4e45375a47413941", "to": "0x91765918420bcb5ad22ee0997abed04056705798", "value": "0x8ac7230489e80000" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json index 3b44a5e2cd99..d977dbe30d13 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/gas.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x1a9c8", "init": "0x601b565b6000555b005b630badf00d6003565b63c001f00d6003565b7319e7e376e7c213b7e7e7e46cc70a5dd086daff2a7f22ae6da6b482f9b1b19b0b897c3fd43884180a1c5ee361e1107a1bc635649dda600052601b603f537f16433dce375ce6dc8151d3f0a22728bc4a1d9fd6ed39dfd18b4609331937367f6040527f306964c0cf5d74f04129fdc60b54d35b596dde1bf89ad92cb4123318f4c0e40060605260206080607f60006000600161fffff21560075760805114601257600956" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json index d33375bfd220..0f28c07a9be2 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/include_precompiled.json @@ -83,7 +83,7 @@ "balance": "0x0", "callType": "call", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "gas": "0x119d28", + "gas": "0x124f80", "input": "0x13f955e100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000019004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae704000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30304000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e000000000000000000000000000000000", "refundAddress": "0x0000000000000000000000000000000000000000", "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json index 170948e15669..6c4ce18063ea 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_create_oog_outer_throw.json @@ -58,7 +58,7 @@ "action": { "callType": "call", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", - "gas": "0x435c8", + "gas": "0x493e0", "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json index 328b743270db..4de08f2ccaf1 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json @@ -54,7 +54,7 @@ "action": { "callType": "call", "from": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", - "gas": "0x1a466", + "gas": "0x1f97e", "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", "to": "0x6c06b16512b332e6cd8293a2974872674716ce18", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json index 6b5738101c24..70442fdb9ab7 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_precompiled_wrong_gas.json @@ -80,7 +80,7 @@ "balance": "0x0", "callType": "call", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "gas": "0x119d28", + "gas": "0x124f80", "input": "0x13f955e100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000019004000000afbe013b4a83b2f91f3d9b6627cf382394c4914fd2b7510700000000000000008621196eb526a0e02430b6dd5c72fd368e768977f3a8364861e5a471a8ae61a1028f745609c40b185f537a67040000005b53875b0f1381589859adcf938980f4a8fb0af4c8845007000000000000000075289d1c48c8f71deee521a76c8d92948cbe14343991998dfaea6b08596d97dcc891745609c40b18ae825ae704000000abbacd8711f647ab97c6c9b9658eb9bef081e2cedb630f010000000000000000549bcab22422baef6c34af382b227e4b1a27bec3312e04dbb62fc315203c67f30f9d745609c40b180fdfc30304000000e93433dde5128942e47e8722d37ec4dcc1c8a78cf9c4a4030000000000000000bf92c09e8e37b2c8ffbb4b9cadfccc563e474c4feae6997f52d56236fedafce20a9f745609c40b1840cc27de04000000f2e372a0b5b837116eee8f968840393d85975a1531346807000000000000000076bc91399edda1de98976ee0774e2ad3b21dd38ad9f5f34d2c816a832747fe7f4c9e745609c40b18e290e9e000000000000000000000000000000000", "refundAddress": "0x0000000000000000000000000000000000000000", "to": "0x6cc68eb482a757c690dd151d2bd5e774ada38bdc", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json index b11b8e040dd3..bc9470871801 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_throw_outer_revert.json @@ -61,7 +61,7 @@ "action": { "callType": "call", "from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826", - "gas": "0x78d9e", + "gas": "0x7dfa6", "input": "0x", "to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", "value": "0xe92596fd6290000" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json index 64425dbaddac..3fcc61fc806f 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0x3951c", + "gas": "0x53e90", "init": "0x60606040525b60405161015b806102a0833901809050604051809103906000f0600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b610247806100596000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900480632ef9db1314610044578063e37678761461007157610042565b005b61005b6004803590602001803590602001506100ad565b6040518082815260200191505060405180910390f35b61008860048035906020018035906020015061008a565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000600060008484604051808381526020018281526020019250505060405180910390209150610120600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff167f6164640000000000000000000000000000000000000000000000000000000000846101e3565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681868660405180807f616464000000000000000000000000000000000000000000000000000000000081526020015060200184815260200183815260200182815260200193505050506000604051808303816000866161da5a03f191505050600060005060008281526020019081526020016000206000505492506101db565b505092915050565b60004340848484604051808581526020018473ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140183815260200182815260200194505050505060405180910390209050610240565b9392505050566060604052610148806100136000396000f30060606040526000357c010000000000000000000000000000000000000000000000000000000090048063471407e614610044578063e37678761461007757610042565b005b6100616004803590602001803590602001803590602001506100b3565b6040518082815260200191505060405180910390f35b61008e600480359060200180359060200150610090565b005b8060006000506000848152602001908152602001600020600050819055505b5050565b6000818301905080506100c684826100d5565b8090506100ce565b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff16828260405180807f7265676973746572496e74000000000000000000000000000000000000000000815260200150602001838152602001828152602001925050506000604051808303816000866161da5a03f1915050505b505056" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json index bbd9904d9c7e..0eaa3f867ab3 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create2_action_gas.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf6c", + "gas": "0x19ed8", "init": "0x6000600060006000f500" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json index 19ae5fc5d3f0..132b84df3618 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_action_gas.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x19ee4", "init": "0x5a600055600060006000f0505a60015500" }, "error": "out of gas", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json index a62d4bb64525..28e96684b2df 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json @@ -61,7 +61,7 @@ "from": "0xa3b31cbd5168d3c99756660d4b7625d679e12573", "to": "0x76554b33410b6d90b7dc889bfed0451ad195f27e", "value": "0x0", - "gas": "0x2e138", + "gas": "0x33450", "input": "0x391521f4", "callType": "call" }, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json index 792845538f98..c3191d61bc4e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_pointer_issue.json @@ -99,7 +99,7 @@ { "action": { "from": "0x5409ed021d9299bf6814279a6a1411a7e866a631", - "gas": "0x215c47", + "gas": "0x2c8c7f", "init": "0x60806040523480156200001157600080fd5b5060405162002d2c38038062002d2c83398101806040526200003791908101906200051d565b6000805433600160a060020a031991821617825560018054909116600160a060020a0386161790558251849084908490849081906200007e906004906020870190620003d0565b50825162000094906005906020860190620003d0565b50620000b0836010640100000000620019476200036f82021704565b9150620000cd846010640100000000620019476200036f82021704565b60028054600160a060020a03948516600160a060020a031991821617909155600380549285169290911691909117905550600154604080517f4552433230546f6b656e28616464726573732900000000000000000000000000815290519081900360130181207f6070410800000000000000000000000000000000000000000000000000000000825291909216945063607041089350620001739250906004016200068e565b602060405180830381600087803b1580156200018e57600080fd5b505af1158015620001a3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620001c99190810190620004f4565b9050600160a060020a038116151562000219576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200021090620006b0565b60405180910390fd5b6002546040517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a039091169063095ea7b39062000268908490600019906004016200066f565b602060405180830381600087803b1580156200028357600080fd5b505af115801562000298573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002be9190810190620005a1565b506003546040517f095ea7b3000000000000000000000000000000000000000000000000000000008152600160a060020a039091169063095ea7b3906200030e908490600019906004016200066f565b602060405180830381600087803b1580156200032957600080fd5b505af11580156200033e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620003649190810190620005a1565b50505050506200077a565b600081601401835110151515620003b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000210906200069e565b506014818301810151910190600160a060020a03165b92915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200041357805160ff191683800117855562000443565b8280016001018555821562000443579182015b828111156200044357825182559160200191906001019062000426565b506200045192915062000455565b5090565b6200047291905b808211156200045157600081556001016200045c565b90565b600062000483825162000711565b9392505050565b600062000483825162000742565b6000601f82018313620004aa57600080fd5b8151620004c1620004bb82620006e9565b620006c2565b91508082526020830160208301858383011115620004de57600080fd5b620004eb83828462000747565b50505092915050565b6000602082840312156200050757600080fd5b600062000515848462000475565b949350505050565b6000806000606084860312156200053357600080fd5b600062000541868662000475565b93505060208401516001604060020a038111156200055e57600080fd5b6200056c8682870162000498565b92505060408401516001604060020a038111156200058957600080fd5b620005978682870162000498565b9150509250925092565b600060208284031215620005b457600080fd5b60006200051584846200048a565b620005cd8162000711565b82525050565b620005cd816200071d565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601881527f554e524547495354455245445f41535345545f50524f58590000000000000000602082015260400190565b620005cd8162000472565b604081016200067f8285620005c2565b62000483602083018462000664565b60208101620003ca8284620005d3565b60208082528101620003ca81620005de565b60208082528101620003ca8162000634565b6040518181016001604060020a0381118282101715620006e157600080fd5b604052919050565b60006001604060020a038211156200070057600080fd5b506020601f91909101601f19160190565b600160a060020a031690565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b151590565b60005b83811015620007645781810151838201526020016200074a565b8381111562000774576000848401525b50505050565b6125a2806200078a6000396000f30060806040526004361061006c5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166318978e8281146100c8578063630f1e6c146100f25780638da5cb5b146101125780639395525c14610134578063f2fde38b14610147575b60025473ffffffffffffffffffffffffffffffffffffffff1633146100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612388565b60405180910390fd5b005b6100db6100d6366004611df1565b610167565b6040516100e9929190612488565b60405180910390f35b3480156100fe57600080fd5b506100c661010d366004611eec565b6102f7565b34801561011e57600080fd5b50610127610388565b6040516100e99190612337565b6100db610142366004611d0b565b6103a4565b34801561015357600080fd5b506100c6610162366004611ce5565b61050a565b61016f6119fa565b6101776119fa565b6000806101826105bb565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610100600188161502019095169490940493840181900481028201810190925282815261025c939092909183018282801561022d5780601f106102025761010080835404028352916020019161022d565b820191906000526020600020905b81548152906001019060200180831161021057829003601f168201915b50505050508c600081518110151561024157fe5b6020908102909101015161014001519063ffffffff61069616565b156102875761026c8b8b8b6107c3565b935061028084600001518560600151610ac1565b90506102ae565b6102928b8b8b610b03565b9350836060015191506102a68883896107c3565b845190935090505b6102c2846020015184602001518888610d15565b6102e98b60008151811015156102d457fe5b90602001906020020151610140015182610f29565b505097509795505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610348576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612438565b61038383838080601f01602080910402602001604051908101604052809392919081815260200183838082843750879450610f299350505050565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b6103ac6119fa565b6103b46119fa565b60008060006103c16105bb565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152610441939092909183018282801561022d5780601f106102025761010080835404028352916020019161022d565b156104925761046a670de0b6b3a7640000610464670de0b6b3a76400008a611045565b3461108f565b92506104778b848c6110e7565b945061048b85600001518660600151610ac1565b90506104d6565b6104ad670d2f13f7789f0000670de0b6b3a76400003461108f565b92506104ba8b848c6110e7565b9450846060015191506104ce89838a6107c3565b855190945090505b6104ea856020015185602001518989610d15565b6104fc8b60008151811015156102d457fe5b505050965096945050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461055b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612438565b73ffffffffffffffffffffffffffffffffffffffff8116156105b857600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b600034116105f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612398565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004016000604051808303818588803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b5050505050565b6000815183511480156107ba5750816040518082805190602001908083835b602083106106f257805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016106b5565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0180199092169116179052604051919093018190038120885190955088945090928392508401908083835b6020831061078757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161074a565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916145b90505b92915050565b6107cb6119fa565b60608060008060008060006107de6119fa565b8a15156107ea57610ab2565b6004805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561088e5780601f106108635761010080835404028352916020019161088e565b820191906000526020600020905b81548152906001019060200180831161087157829003601f168201915b505060058054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152969e509194509250840190508282801561093d5780601f106109125761010080835404028352916020019161093d565b820191906000526020600020905b81548152906001019060200180831161092057829003601f168201915b50505050509650600095508b519450600093505b838514610a7857878c8581518110151561096757fe5b6020908102909101015161014001528b5187908d908690811061098657fe5b60209081029091010151610160015261099f8b87610ac1565b9250610a068c858151811015156109b257fe5b9060200190602002015160a00151610a008e878151811015156109d157fe5b90602001906020020151608001518f888151811015156109ed57fe5b9060200190602002015160e00151610ac1565b8561128b565b9150610a418c85815181101515610a1957fe5b90602001906020020151838c87815181101515610a3257fe5b906020019060200201516112e6565b9050610a4d898261135e565b610a5f89600001518a60600151610ac1565b95508a8610610a6d57610a78565b600190930192610951565b8a861015610ab2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612418565b50505050505050509392505050565b600082821115610afd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123b8565b50900390565b610b0b6119fa565b606080600080600080610b1c6119fa565b60008b6000815181101515610b2d57fe5b6020908102919091018101516101400151600580546040805160026001841615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190931692909204601f8101869004860283018601909152808252929b5092909190830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505096508b519550600094505b848614610cdb57878c86815181101515610c0b57fe5b6020908102909101015161014001528b5187908d9087908110610c2a57fe5b6020908102909101015161016001528851610c46908c90610ac1565b9350610c898c86815181101515610c5957fe5b9060200190602002015160a001518d87815181101515610c7557fe5b90602001906020020151608001518661128b565b9250610cb58c86815181101515610c9c57fe5b90602001906020020151848c88815181101515610a3257fe5b9150610cc1898361135e565b5087518a8110610cd057610cdb565b600190940193610bf5565b8a811015610ab2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612418565b600080808066b1a2bc2ec50000861115610d5b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612448565b610d658888611045565b935034841115610da1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123a8565b610dab3485610ac1565b9250610dc086670de0b6b3a76400008a61108f565b915082821115610dfc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612428565b6000831115610f1f576002546040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690632e1a7d4d90610e5b9086906004016124a4565b600060405180830381600087803b158015610e7557600080fd5b505af1158015610e89573d6000803e3d6000fd5b505050506000821115610edb5760405173ffffffffffffffffffffffffffffffffffffffff86169083156108fc029084906000818181858888f19350505050158015610ed9573d6000803e3d6000fd5b505b610ee58383610ac1565b90506000811115610f1f57604051339082156108fc029083906000818181858888f19350505050158015610f1d573d6000803e3d6000fd5b505b5050505050505050565b6000610f3b838263ffffffff6113c016565b604080517f4552433230546f6b656e28616464726573732900000000000000000000000000815290519081900360130190209091507fffffffff0000000000000000000000000000000000000000000000000000000080831691161415610fab57610fa6838361142d565b610383565b604080517f455243373231546f6b656e28616464726573732c75696e7432353629000000008152905190819003601c0190207fffffffff000000000000000000000000000000000000000000000000000000008281169116141561101357610fa6838361161b565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123f8565b600082820183811015611084576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123e8565b8091505b5092915050565b60008083116110ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123d8565b6110dd6110d78584611703565b8461175e565b90505b9392505050565b6110ef6119fa565b60608060008060006110ff6119fa565b89600081518110151561110e57fe5b6020908102919091018101516101400151600580546040805160026001841615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190931692909204601f8101869004860283018601909152808252929950929091908301828280156111c65780601f1061119b576101008083540402835291602001916111c6565b820191906000526020600020905b8154815290600101906020018083116111a957829003601f168201915b5050505050945089519350600092505b82841461127e57858a848151811015156111ec57fe5b602090810290910101516101400152895185908b908590811061120b57fe5b90602001906020020151610160018190525061122b898860200151610ac1565b91506112578a8481518110151561123e57fe5b90602001906020020151838a86815181101515610a3257fe5b9050611263878261135e565b602087015189116112735761127e565b6001909201916111d6565b5050505050509392505050565b60008083116112c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123d8565b6110dd6110d76112d68685611703565b6112e1866001610ac1565b611045565b6112ee6119fa565b606060006112fd868686611775565b600154815191935073ffffffffffffffffffffffffffffffffffffffff1691506080908390602082016000855af1801561135457825184526020830151602085015260408301516040850152606083015160608501525b5050509392505050565b8151815161136c9190611045565b8252602080830151908201516113829190611045565b60208301526040808301519082015161139b9190611045565b6040830152606080830151908201516113b49190611045565b60609092019190915250565b600081600401835110151515611402576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612468565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b60008061144184601063ffffffff61194716565b604080517f7472616e7366657228616464726573732c75696e7432353629000000000000008152905190819003601901812091935073ffffffffffffffffffffffffffffffffffffffff8416919061149f903390879060240161236d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931783525181519192909182919080838360005b8381101561154357818101518382015260200161152b565b50505050905090810190601f1680156115705780820380516001836020036101000a031916815260200191505b509150506000604051808303816000865af1925050508015156115bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612408565b3d156115dc575060003d602014156115dc5760206000803e506000515b801515611615576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612408565b50505050565b60008060018314611658576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612478565b61166984601063ffffffff61194716565b915061167c84602463ffffffff6119a816565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8316906323b872dd906116d590309033908690600401612345565b600060405180830381600087803b1580156116ef57600080fd5b505af1158015610f1f573d6000803e3d6000fd5b6000808315156117165760009150611088565b5082820282848281151561172657fe5b0414611084576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123e8565b600080828481151561176c57fe5b04949350505050565b604080517fb4be83d5000000000000000000000000000000000000000000000000000000006020808301919091526060602483018181528751608485019081528884015160a48601529488015160c48501529087015160e4840152608087015161010484015260a087015161012484015260c087015161014484015260e08701516101648401526101008701516101848401526101208701516101a4840152610140870180516101c485019081526101608901516101e4860152610180905251805161020485018190529394919384936044870192849261022489019291820191601f82010460005b8181101561187c57835185526020948501949093019260010161185e565b50505050818103610160808401919091528a0151805180835260209283019291820191601f82010460005b818110156118c55783518552602094850194909301926001016118a7565b50505089845250848103602093840190815288518083529093918201918981019190601f82010460005b8181101561190d5783518552602094850194909301926001016118ef565b5050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08883030188525060405250505050509392505050565b600081601401835110151515611989576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd90612458565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b60006107ba83836000816020018351101515156119f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906123c8565b50016020015190565b608060405190810160405280600081526020016000815260200160008152602001600081525090565b60006107ba8235612540565b6000601f82018313611a4057600080fd5b8135611a53611a4e826124d9565b6124b2565b81815260209384019390925082018360005b83811015611a915781358601611a7b8882611b41565b8452506020928301929190910190600101611a65565b5050505092915050565b6000601f82018313611aac57600080fd5b8135611aba611a4e826124d9565b81815260209384019390925082018360005b83811015611a915781358601611ae28882611b90565b8452506020928301929190910190600101611acc565b600080601f83018413611b0a57600080fd5b50813567ffffffffffffffff811115611b2257600080fd5b602083019150836001820283011115611b3a57600080fd5b9250929050565b6000601f82018313611b5257600080fd5b8135611b60611a4e826124fa565b91508082526020830160208301858383011115611b7c57600080fd5b611b8783828461255c565b50505092915050565b60006101808284031215611ba357600080fd5b611bae6101806124b2565b90506000611bbc8484611a23565b8252506020611bcd84848301611a23565b6020830152506040611be184828501611a23565b6040830152506060611bf584828501611a23565b6060830152506080611c0984828501611cd9565b60808301525060a0611c1d84828501611cd9565b60a08301525060c0611c3184828501611cd9565b60c08301525060e0611c4584828501611cd9565b60e083015250610100611c5a84828501611cd9565b61010083015250610120611c7084828501611cd9565b6101208301525061014082013567ffffffffffffffff811115611c9257600080fd5b611c9e84828501611b41565b6101408301525061016082013567ffffffffffffffff811115611cc057600080fd5b611ccc84828501611b41565b6101608301525092915050565b60006107ba8235612559565b600060208284031215611cf757600080fd5b6000611d038484611a23565b949350505050565b60008060008060008060c08789031215611d2457600080fd5b863567ffffffffffffffff811115611d3b57600080fd5b611d4789828a01611a9b565b965050602087013567ffffffffffffffff811115611d6457600080fd5b611d7089828a01611a2f565b955050604087013567ffffffffffffffff811115611d8d57600080fd5b611d9989828a01611a9b565b945050606087013567ffffffffffffffff811115611db657600080fd5b611dc289828a01611a2f565b9350506080611dd389828a01611cd9565b92505060a0611de489828a01611a23565b9150509295509295509295565b600080600080600080600060e0888a031215611e0c57600080fd5b873567ffffffffffffffff811115611e2357600080fd5b611e2f8a828b01611a9b565b9750506020611e408a828b01611cd9565b965050604088013567ffffffffffffffff811115611e5d57600080fd5b611e698a828b01611a2f565b955050606088013567ffffffffffffffff811115611e8657600080fd5b611e928a828b01611a9b565b945050608088013567ffffffffffffffff811115611eaf57600080fd5b611ebb8a828b01611a2f565b93505060a0611ecc8a828b01611cd9565b92505060c0611edd8a828b01611a23565b91505092959891949750929550565b600080600060408486031215611f0157600080fd5b833567ffffffffffffffff811115611f1857600080fd5b611f2486828701611af8565b93509350506020611f3786828701611cd9565b9150509250925092565b611f4a81612540565b82525050565b602381527f44454641554c545f46554e4354494f4e5f574554485f434f4e54524143545f4f60208201527f4e4c590000000000000000000000000000000000000000000000000000000000604082015260600190565b601181527f494e56414c49445f4d53475f56414c5545000000000000000000000000000000602082015260400190565b600d81527f4f564552534f4c445f5745544800000000000000000000000000000000000000602082015260400190565b601181527f55494e543235365f554e444552464c4f57000000000000000000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b601081527f4449564953494f4e5f42595f5a45524f00000000000000000000000000000000602082015260400190565b601081527f55494e543235365f4f564552464c4f5700000000000000000000000000000000602082015260400190565b601781527f554e535550504f525445445f41535345545f50524f5859000000000000000000602082015260400190565b600f81527f5452414e534645525f4641494c45440000000000000000000000000000000000602082015260400190565b601481527f434f4d504c4554455f46494c4c5f4641494c4544000000000000000000000000602082015260400190565b601a81527f494e53554646494349454e545f4554485f52454d41494e494e47000000000000602082015260400190565b601381527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000602082015260400190565b601881527f4645455f50455243454e544147455f544f4f5f4c415247450000000000000000602082015260400190565b602681527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560208201527f5155495245440000000000000000000000000000000000000000000000000000604082015260600190565b602581527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160208201527f5549524544000000000000000000000000000000000000000000000000000000604082015260600190565b600e81527f494e56414c49445f414d4f554e54000000000000000000000000000000000000602082015260400190565b805160808301906122f9848261232e565b50602082015161230c602085018261232e565b50604082015161231f604085018261232e565b50606082015161161560608501825b611f4a81612559565b602081016107bd8284611f41565b606081016123538286611f41565b6123606020830185611f41565b611d03604083018461232e565b6040810161237b8285611f41565b6110e0602083018461232e565b602080825281016107bd81611f50565b602080825281016107bd81611fa6565b602080825281016107bd81611fd6565b602080825281016107bd81612006565b602080825281016107bd81612036565b602080825281016107bd8161208c565b602080825281016107bd816120bc565b602080825281016107bd816120ec565b602080825281016107bd8161211c565b602080825281016107bd8161214c565b602080825281016107bd8161217c565b602080825281016107bd816121ac565b602080825281016107bd816121dc565b602080825281016107bd8161220c565b602080825281016107bd81612262565b602080825281016107bd816122b8565b610100810161249782856122e8565b6110e060808301846122e8565b602081016107bd828461232e565b60405181810167ffffffffffffffff811182821017156124d157600080fd5b604052919050565b600067ffffffffffffffff8211156124f057600080fd5b5060209081020190565b600067ffffffffffffffff82111561251157600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b73ffffffffffffffffffffffffffffffffffffffff1690565b90565b828183375060009101525600a265627a7a72305820d9f418f11e0f91f06f6f9d22924be0add925495eeb76a6388b5417adb505eeb36c6578706572696d656e74616cf5003700000000000000000000000048bacb9266a570d521063ef5dd96e61686dbe788000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000024f47261b0000000000000000000000000871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f47261b00000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e808200000000000000000000000000000000000000000000000000000000", "value": "0x0" }, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json index 26ae2f0604b5..bd6059faefa1 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/oog.json @@ -52,7 +52,7 @@ "action": { "callType": "call", "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", - "gas": "0x7045", + "gas": "0xca1d", "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json index 0216c318b55a..8888d3e68a82 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/option_convert_parity_errors.json @@ -55,7 +55,7 @@ "action": { "callType": "call", "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", - "gas": "0x7045", + "gas": "0xca1d", "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json index f58d20cd2b04..62baf333b6e3 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/result_output.json @@ -68,7 +68,7 @@ "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "to": "0x531f76bad925f6a925474996c7d738c1008045f6", "value": "0xde0b6b3a7640000", - "gas": "0x3b920", + "gas": "0x40b28", "input": "0x", "callType": "call" }, diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json index 897aebb0e05b..b0346d860399 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert.json @@ -50,7 +50,7 @@ "action": { "callType": "call", "from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9", - "gas": "0x2d55e8", + "gas": "0x2dc6c0", "input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000", "to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json index 62dbaf20dc94..6759b05e5206 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/revert_reason.json @@ -55,7 +55,7 @@ "action": { "callType": "call", "from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", - "gas": "0x2d7308", + "gas": "0x2dc6c0", "input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json index cd34d0b6d063..74fd87cc6c4d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xcf08", + "gas": "0x19ecc", "init": "0x605a600053600160006001f0ff00" }, "result": { diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json index 6d084410a366..a7244e97470e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/simple.json @@ -61,7 +61,7 @@ "action": { "callType": "call", "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json index d530fe908b2a..96060d554539 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json @@ -54,7 +54,7 @@ "action": { "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", "value": "0x0", - "gas": "0xd550", + "gas": "0x1aab0", "init": "0x7f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b57f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000945304eb96065b2a98b57a48a06ae28d285a71b5547f000000000000000000000000000000000000000000000000000000000000c3507f000000000000000000000000000000000000000000000000000000000000c3507f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000037f055" }, "error": "out of gas", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json index 9291149bdb69..45ffbe2db975 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/staticcall_precompiled.json @@ -65,7 +65,7 @@ "balance": "0x0", "callType": "call", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "gas": "0x4053e", + "gas": "0x48196", "input": "0x200b1e64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001b9af799918107e9a339eba0584b8b60b35aae6f087c74f6bfc00c9301849b204d094ed65e09c76c2597f5516f9440aad2921e50dde096e7caaa65a536d4d9265e00000000000000000000000000000000000000000000000000000000000000504269747669657720697320616e20616d617a696e6720776562736974652e20596f752073686f756c6420646566696e6974656c792061646420796f75722070726f6475637420746f2069742e20e282bf00000000000000000000000000000000", "refundAddress": "0x0000000000000000000000000000000000000000", "to": "0x8521f13dd5e4bc3dab3cf0f01a195a5af899e851", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json index bd9e057c0229..16d43767d552 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/suicide.json @@ -55,7 +55,7 @@ "action": { "callType": "call", "from": "0x877bd459c9b7d8576b44e59e09d076c25946f443", - "gas": "0x445708", + "gas": "0x44aa20", "input": "0x41c0e1b5", "to": "0x8ee79c5b3f6e1d214d2c4fcf7ea4092a32e26e91", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json index b119bed5289a..a001178a42c7 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/throw.json @@ -54,7 +54,7 @@ "action": { "callType": "call", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", "value": "0x0" diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json index 8557f8efd69b..df0b2872b48b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/create.json @@ -47,7 +47,7 @@ "input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f", "result": { "from": "0x13e4acefe6a6700604929946e70e6443e4e73447", - "gas": "0x5e106", + "gas": "0x897be", "gasUsed": "0x897be", "input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", "output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json index ef28a930b3bc..80fc0b0ada68 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/deep_calls.json @@ -404,7 +404,7 @@ } ], "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "gasUsed": "0x1810b", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", "output": "0x", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json index c4c1390fa257..2cd28bacc4b0 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/delegatecall.json @@ -86,7 +86,7 @@ } ], "from": "0xa529806c67cc6486d4d62024471772f47f6fd672", - "gas": "0x2d6e28", + "gas": "0x2dc6c0", "gasUsed": "0xbd55", "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", "output": "0x", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json index 0b60e34d0e11..07fda21d4b35 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_create_oog_outer_throw.json @@ -67,7 +67,7 @@ ], "error": "invalid jump destination", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", - "gas": "0x435c8", + "gas": "0x493e0", "gasUsed": "0x493e0", "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json index c1ed766ef902..16e413623048 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_instafail.json @@ -54,7 +54,7 @@ "from": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", "to": "0x6c06b16512b332e6cd8293a2974872674716ce18", "value": "0x0", - "gas": "0x1a466", + "gas": "0x1f97e", "gasUsed": "0x72de", "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000", "output": "0x", @@ -64,7 +64,7 @@ "from": "0x6c06b16512b332e6cd8293a2974872674716ce18", "to": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31", "value": "0x14d1120d7b160000", - "error":"internal failure", + "error": "internal failure", "input": "0x" } ] diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json index 2be2dee23f26..a023ed6d9bd7 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/inner_throw_outer_revert.json @@ -71,7 +71,7 @@ ], "error": "execution reverted", "from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826", - "gas": "0x78d9e", + "gas": "0x7dfa6", "gasUsed": "0x7c1c8", "input": "0x", "to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json index 8022f53a992d..333bdd038cf5 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/oog.json @@ -50,7 +50,7 @@ "result": { "error": "out of gas", "from": "0x94194bc2aaf494501d7880b61274a169f6502a54", - "gas": "0x7045", + "gas": "0xca1d", "gasUsed": "0xca1d", "input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000", "to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json index aee894d11fde..3207a298a98b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert.json @@ -48,7 +48,7 @@ "result": { "error": "execution reverted", "from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9", - "gas": "0x2d55e8", + "gas": "0x2dc6c0", "gasUsed": "0x719b", "input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000", "to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json index 4f7fee97d930..5c7e5629e9d6 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/revert_reason.json @@ -53,7 +53,7 @@ "result": { "error": "execution reverted", "from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", - "gas": "0x2d7308", + "gas": "0x2dc6c0", "gasUsed": "0x5940", "input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1", "to": "0xf58833cf0c791881b494eb79d461e08a1f043f52", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json index 55b63dbdb6c9..11b23a990e9e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/selfdestruct.json @@ -62,7 +62,7 @@ } ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "gasUsed": "0x6fcb", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json index c9192a19f923..37723f17dd6b 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/simple.json @@ -67,7 +67,7 @@ } ], "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", - "gas": "0x10738", + "gas": "0x15f90", "gasUsed": "0x9751", "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", "output": "0x0000000000000000000000000000000000000000000000000000000000000001", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json index 76fae3c392b3..499b449a6ece 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_legacy/throw.json @@ -52,7 +52,7 @@ "result": { "error": "invalid jump destination", "from": "0x70c9217d814985faef62b124420f8dfbddd96433", - "gas": "0x37b38", + "gas": "0x3d090", "gasUsed": "0x3d090", "input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json index b18c80e58ec5..9264f1e2fdf3 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json @@ -77,7 +77,7 @@ }, "result": { "from": "0x4f5777744b500616697cb655dcb02ee6cd51deb5", - "gas": "0x2dced", + "gas": "0x33085", "gasUsed": "0x1a9e5", "to": "0x200edd17f30485a8735878661960cd7a9a95733f", "input": "0xba51a6df0000000000000000000000000000000000000000000000000000000000000000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json index 2c82138022ec..f63dbd47dc5c 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json @@ -134,7 +134,7 @@ }, "result": { "from": "0x3de712784baf97260455ae25fb74f574ec9c1add", - "gas": "0x7e2c0", + "gas": "0x84398", "gasUsed": "0x27ec3", "to": "0x6ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5", "input": "0xbbd4f854e9efd3ab89acad6a3edf9828c3b00ed1c4a74e974d05d32d3b2fb15aa16fc3770000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000080d29fa5cccfadac", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json index 649a5b1b566d..5e5d9538672e 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json @@ -299,7 +299,7 @@ }, "result": { "from": "0xbe3ae5cb97c253dda67181c6e34e43f5c275e08b", - "gas": "0x3514c8", + "gas": "0x3567e0", "gasUsed": "0x26e1ef", "to": "0x03e3d4561a8f8e975fdcd798d32857a20cf25e7e", "input": "0xbe9a6555", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json index 858931558a99..1ffffd240e7d 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json @@ -167,7 +167,7 @@ }, "result": { "from": "0x3fcb0342353c541e210013aaddc2e740b9a33d08", - "gas": "0x2b0868", + "gas": "0x2dc6c0", "gasUsed": "0x2570bf", "to": "0x350e0ffc780a6a75b44cc52e1ff9092870668945", "input": "0xe021fadb000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000006e00000000000000000000000000000000000000000000000000000000000000d4000000000000000000000000000000000000000000000000000000000000013a00000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000002fd000000000000000000000000000000000000000000000000000000000000034300000000000000000000000000000000000000000000000000000000000002fd0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003900000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003900000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000032fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebebebffffffffffffffffffffffffffffffffffffffffffffffffffffffffff888888ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3b3b3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3e3e3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e3e3effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbdbdbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f4f4fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0b0b0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0a0a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b5b5bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9a9a9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb9b9b9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababaffffffffffffffffffffffffffffffffffffffffffffffffffffffffff636363fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f9f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9c9cfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4d4e53ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f494b00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000011c37937e08000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json index 09aa7af461e0..116606b3c7e5 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json @@ -102,7 +102,7 @@ }, "result": { "from": "0x6412becf35cc7e2a9e7e47966e443f295e1e4f4a", - "gas": "0x2bb38", + "gas": "0x30d40", "gasUsed": "0x249eb", "to": "0x50739060a2c32dc076e507ae1a893aab28ecfe68", "input": "0x", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json index 1a03f0e7fb28..30f1777067ef 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json @@ -63,7 +63,7 @@ }, "result": { "from": "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb", - "gas": "0x1f36d", + "gas": "0x24d45", "gasUsed": "0xc6a5", "to": "0xf4eced2f682ce333f96f2d8966c613ded8fc95dd", "input": "0xa9059cbb000000000000000000000000dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb0000000000000000000000000000000000000000000000000000000000989680", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json index 4e0aec529f0a..30346d07f1ff 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_failed.json @@ -137,7 +137,7 @@ }, "result": { "from": "0xe6002189a74b43e6868b20c1311bc108e38aac57", - "gas": "0xa59c8", + "gas": "0xaae60", "gasUsed": "0xaae60", "to": "0x630a0cd35d5bd57e61410fda76fea850225cda18", "input": "0xe1fa763800000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json index 8df52db23c85..eb2514427c91 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json @@ -75,7 +75,7 @@ }, "result": { "from": "0x01115b41bd2731353dd3e6abf44818fdc035aaf1", - "gas": "0x28e28", + "gas": "0x30d40", "gasUsed": "0x288c9", "to": "0xcf1476387d780169410d4e936d75a206fda2a68c", "input": "0xb61d27f6000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c18941300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008861393035396362623030303030303030303030303030303030303030303030303930643363313831326465323636396266383037626437373538636562316533343937616337653430303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303031633662663532363334303030000000000000000000000000000000000000000000000000", diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json index c805296adb02..e73081107f61 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/with_onlyTopCall.json @@ -78,7 +78,7 @@ }, "result": { "from": "0x4f5777744b500616697cb655dcb02ee6cd51deb5", - "gas": "0x2dced", + "gas": "0x33085", "gasUsed": "0x1a9e5", "to": "0x200edd17f30485a8735878661960cd7a9a95733f", "input": "0xba51a6df0000000000000000000000000000000000000000000000000000000000000000", diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 33298f3097fa..2a2789e93d31 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -235,7 +235,7 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr t.ctx["from"] = t.vm.ToValue(from.Bytes()) t.ctx["to"] = t.vm.ToValue(to.Bytes()) t.ctx["input"] = t.vm.ToValue(input) - t.ctx["gas"] = t.vm.ToValue(gas) + t.ctx["gas"] = t.vm.ToValue(t.gasLimit) t.ctx["gasPrice"] = t.vm.ToValue(env.TxContext.GasPrice) valueBig, err := t.toBig(t.vm, value.String()) if err != nil { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 88fc2be40c25..c3db1ad034df 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -133,7 +133,7 @@ func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad From: from, To: &toCopy, Input: common.CopyBytes(input), - Gas: gas, + Gas: t.gasLimit, Value: value, } if create { From ab1a404b0133252dca1a1d4daec2548292b295ff Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 4 Apr 2023 09:50:13 -0400 Subject: [PATCH 695/715] all: remove debug-field from vm config (#27048) This PR removes the Debug field from vmconfig, making it so that if a tracer is set, debug=true is implied. --------- Co-authored-by: 0xTylerHolmes Co-authored-by: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> --- cmd/evm/internal/t8ntool/execution.go | 1 - cmd/evm/internal/t8ntool/transition.go | 1 - cmd/evm/runner.go | 1 - cmd/evm/staterunner.go | 1 - core/blockchain.go | 1 - core/blockchain_test.go | 2 -- core/state_transition.go | 6 +++--- core/vm/evm.go | 15 ++++++++------- core/vm/instructions.go | 6 +++--- core/vm/interpreter.go | 10 +++++----- core/vm/runtime/runtime_test.go | 5 ----- eth/tracers/api.go | 3 +-- eth/tracers/internal/tracetest/calltrace_test.go | 6 +++--- .../internal/tracetest/flat_calltrace_test.go | 2 +- eth/tracers/internal/tracetest/prestate_test.go | 2 +- eth/tracers/js/tracer_test.go | 6 +++--- eth/tracers/logger/logger_test.go | 2 +- eth/tracers/tracers_test.go | 2 +- internal/ethapi/api.go | 2 +- tests/state_test.go | 3 +-- 20 files changed, 32 insertions(+), 45 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 5f796c1d6639..156bce7edb4d 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -174,7 +174,6 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, return nil, nil, err } vmConfig.Tracer = tracer - vmConfig.Debug = (tracer != nil) statedb.SetTxContext(tx.Hash(), txIndex) var ( diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index f63635687b9b..0b87edd11cc1 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -180,7 +180,6 @@ func Transition(ctx *cli.Context) error { vmConfig := vm.Config{ Tracer: tracer, - Debug: (tracer != nil), } // Construct the chainconfig var chainConfig *params.ChainConfig diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index d6ec8ae7527d..18ec3330c426 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -218,7 +218,6 @@ func runCmd(ctx *cli.Context) error { BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), EVMConfig: vm.Config{ Tracer: tracer, - Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name), }, } diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 5eba25c725a3..e9229eaeca21 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -92,7 +92,6 @@ func stateTestCmd(ctx *cli.Context) error { // Iterate over all the tests, run them and aggregate the results cfg := vm.Config{ Tracer: tracer, - Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name), } results := make([]StatetestResult, 0, len(tests)) for key, test := range tests { diff --git a/core/blockchain.go b/core/blockchain.go index d7094c516acd..804375bf164f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -233,7 +233,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis if cacheConfig == nil { cacheConfig = defaultCacheConfig } - // Open trie database with provided config triedb := trie.NewDatabaseWithConfig(db, &trie.Config{ Cache: cacheConfig.TrieCleanLimit, diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 0f9ef6a1921a..01ad157cc290 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -3024,7 +3024,6 @@ func TestDeleteRecreateSlots(t *testing.T) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ - Debug: true, Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) if err != nil { @@ -3102,7 +3101,6 @@ func TestDeleteRecreateAccount(t *testing.T) { }) // Import the canonical chain chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ - Debug: true, Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) if err != nil { diff --git a/core/state_transition.go b/core/state_transition.go index 1802f1daf70a..fedccf1a711b 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -324,10 +324,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, err } - if st.evm.Config.Debug { - st.evm.Config.Tracer.CaptureTxStart(st.initialGas) + if tracer := st.evm.Config.Tracer; tracer != nil { + tracer.CaptureTxStart(st.initialGas) defer func() { - st.evm.Config.Tracer.CaptureTxEnd(st.gasRemaining) + tracer.CaptureTxEnd(st.gasRemaining) }() } diff --git a/core/vm/evm.go b/core/vm/evm.go index 0084e4ca51fc..01017572d178 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -182,11 +182,12 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } snapshot := evm.StateDB.Snapshot() p, isPrecompile := evm.precompile(addr) + debug := evm.Config.Tracer != nil if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { // Calling a non existing account, don't do anything, but ping the tracer - if evm.Config.Debug { + if debug { if evm.depth == 0 { evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) evm.Config.Tracer.CaptureEnd(ret, 0, nil) @@ -202,7 +203,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value) // Capture the tracer start/end events in debug mode - if evm.Config.Debug { + if debug { if evm.depth == 0 { evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) defer func(startGas uint64) { // Lazy evaluation of the parameters @@ -272,7 +273,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, var snapshot = evm.StateDB.Snapshot() // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Debug { + if evm.Config.Tracer != nil { evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value) defer func(startGas uint64) { evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) @@ -313,7 +314,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by var snapshot = evm.StateDB.Snapshot() // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Debug { + if evm.Config.Tracer != nil { // NOTE: caller must, at all times be a contract. It should never happen // that caller is something other than a Contract. parent := caller.(*Contract) @@ -367,7 +368,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte evm.StateDB.AddBalance(addr, big0) // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Debug { + if evm.Config.Tracer != nil { evm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) defer func(startGas uint64) { evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) @@ -450,7 +451,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, contract := NewContract(caller, AccountRef(address), value, gas) contract.SetCodeOptionalHash(&address, codeAndHash) - if evm.Config.Debug { + if evm.Config.Tracer != nil { if evm.depth == 0 { evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value) } else { @@ -493,7 +494,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } } - if evm.Config.Debug { + if evm.Config.Tracer != nil { if evm.depth == 0 { evm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, err) } else { diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 21d8cc215ad9..505aef412775 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -822,9 +822,9 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance) interpreter.evm.StateDB.Suicide(scope.Contract.Address()) - if interpreter.evm.Config.Debug { - interpreter.evm.Config.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) - interpreter.evm.Config.Tracer.CaptureExit([]byte{}, 0, nil) + if tracer := interpreter.evm.Config.Tracer; tracer != nil { + tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) + tracer.CaptureExit([]byte{}, 0, nil) } return nil, errStopToken } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 0ab520b90f0e..5b2082bc9e90 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -25,7 +25,6 @@ import ( // Config are the configuration options for the Interpreter type Config struct { - Debug bool // Enables debugging Tracer EVMLogger // Opcode logger NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages @@ -143,6 +142,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( 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 ) // Don't move this deferred function, it's placed before the capturestate-deferred method, // so that it get's executed _after_: the capturestate needs the stacks before @@ -152,7 +152,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( }() contract.Input = input - if in.evm.Config.Debug { + if debug { defer func() { if err != nil { if !logged { @@ -168,7 +168,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // the execution of one of the operations or until the done flag is set by the // parent context. for { - if in.evm.Config.Debug { + if debug { // Capture pre-execution values for tracing. logged, pcCopy, gasCopy = false, pc, contract.Gas } @@ -213,14 +213,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( return nil, ErrOutOfGas } // Do tracing before memory expansion - if in.evm.Config.Debug { + if debug { in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) logged = true } if memorySize > 0 { mem.Resize(memorySize) } - } else if in.evm.Config.Debug { + } else if debug { in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) logged = true } diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 607259106536..62953a43658b 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -335,7 +335,6 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode b.Fatal(err) } cfg.EVMConfig = vm.Config{ - Debug: true, Tracer: tracer, } } @@ -511,7 +510,6 @@ func TestEip2929Cases(t *testing.T) { code, ops) Execute(code, nil, &Config{ EVMConfig: vm.Config{ - Debug: true, Tracer: logger.NewMarkdownLogger(nil, os.Stdout), ExtraEips: []int{2929}, }, @@ -665,7 +663,6 @@ func TestColdAccountAccessCost(t *testing.T) { tracer := logger.NewStructLogger(nil) Execute(tc.code, nil, &Config{ EVMConfig: vm.Config{ - Debug: true, Tracer: tracer, }, }) @@ -837,7 +834,6 @@ func TestRuntimeJSTracer(t *testing.T) { GasLimit: 1000000, State: statedb, EVMConfig: vm.Config{ - Debug: true, Tracer: tracer, }}) if err != nil { @@ -872,7 +868,6 @@ func TestJSTracerCreateTx(t *testing.T) { _, _, _, err = Create(code, &Config{ State: statedb, EVMConfig: vm.Config{ - Debug: true, Tracer: tracer, }}) if err != nil { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 58ad0c3c9ad7..9eef8c2e06be 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -805,7 +805,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Swap out the noop logger to the standard tracer writer = bufio.NewWriter(dump) vmConf = vm.Config{ - Debug: true, Tracer: logger.NewJSONLogger(&logConfig, writer), EnablePreimageRecording: true, } @@ -965,7 +964,7 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte return nil, err } } - vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) + vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true}) // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index a70842d40c0a..e517d436af93 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -143,7 +143,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) @@ -246,7 +246,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { if err != nil { b.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) snap := statedb.Snapshot() st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if _, err = st.TransitionDb(); err != nil { @@ -352,7 +352,7 @@ func TestInternals(t *testing.T) { Balance: big.NewInt(500000000000000), }, }, false) - evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tc.tracer}) + evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer}) msg := &core.Message{ To: &to, From: origin, diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 9b51ba80ffa5..16c01de25c61 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -107,7 +107,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string if err != nil { return fmt.Errorf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index f578e2f0f5fd..5fc99dd12439 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -114,7 +114,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 1f3753721116..a61754352a09 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -62,7 +62,7 @@ func testCtx() *vmContext { func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { var ( - env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Debug: true, Tracer: tracer}) + env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer}) gasLimit uint64 = 31000 startGas uint64 = 10000 value = big.NewInt(0) @@ -180,7 +180,7 @@ func TestHaltBetweenSteps(t *testing.T) { if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) + env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer}) scope := &vm.ScopeContext{ Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0), } @@ -204,7 +204,7 @@ func TestNoStepExec(t *testing.T) { if err != nil { t.Fatal(err) } - env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) + env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer}) tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0)) tracer.CaptureEnd(nil, 0, nil) ret, err := tracer.GetResult() diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index 1bc7456d31c6..bde43e5ff71a 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -55,7 +55,7 @@ func (*dummyStatedb) SetState(_ common.Address, _ common.Hash, _ common.Hash) {} func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) - env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: logger}) + env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger}) contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 100000) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 46182db48b98..759e3a4dd38e 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -87,7 +87,7 @@ func BenchmarkTransactionTrace(b *testing.B) { //EnableMemory: false, //EnableReturnData: false, }) - evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer}) msg, err := core.TransactionToMessage(tx, signer, nil) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4e3985530996..b7ad30a6eacd 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1473,7 +1473,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) - config := vm.Config{Tracer: tracer, Debug: true, NoBaseFee: true} + config := vm.Config{Tracer: tracer, NoBaseFee: true} vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config) if err != nil { return nil, 0, nil, err diff --git a/tests/state_test.go b/tests/state_test.go index 787427f01e45..9d3862e1dc7c 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -115,8 +115,7 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { } buf := new(bytes.Buffer) w := bufio.NewWriter(buf) - tracer := logger.NewJSONLogger(&logger.Config{}, w) - config.Debug, config.Tracer = true, tracer + config.Tracer = logger.NewJSONLogger(&logger.Config{}, w) err2 := test(config) if !reflect.DeepEqual(err, err2) { t.Errorf("different error for second run: %v", err2) From b4dcd1a391f98a92d619966d0606a6b58a019851 Mon Sep 17 00:00:00 2001 From: Exca-DK <85954505+Exca-DK@users.noreply.github.com> Date: Tue, 4 Apr 2023 15:53:44 +0200 Subject: [PATCH 696/715] metrics: make gauge_float64 and counter_float64 lock free (#27025) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes the float-gauges lock-free name old time/op new time/op delta CounterFloat64Parallel-8 1.45µs ±10% 0.85µs ± 6% -41.65% (p=0.008 n=5+5) --------- Co-authored-by: Exca-DK Co-authored-by: Martin Holst Swende --- metrics/counter_float64.go | 38 +++++++++++++++++--------------- metrics/counter_float_64_test.go | 24 +++++++++++++++++++- metrics/gauge_float64.go | 22 ++++++++---------- metrics/gauge_float64_test.go | 23 ++++++++++++++++++- 4 files changed, 74 insertions(+), 33 deletions(-) diff --git a/metrics/counter_float64.go b/metrics/counter_float64.go index f05f62fed632..d1197bb8e0ae 100644 --- a/metrics/counter_float64.go +++ b/metrics/counter_float64.go @@ -1,7 +1,8 @@ package metrics import ( - "sync" + "math" + "sync/atomic" ) // CounterFloat64 holds a float64 value that can be incremented and decremented. @@ -38,13 +39,13 @@ func NewCounterFloat64() CounterFloat64 { if !Enabled { return NilCounterFloat64{} } - return &StandardCounterFloat64{count: 0.0} + return &StandardCounterFloat64{} } // NewCounterFloat64Forced constructs a new StandardCounterFloat64 and returns it no matter if // the global switch is enabled or not. func NewCounterFloat64Forced() CounterFloat64 { - return &StandardCounterFloat64{count: 0.0} + return &StandardCounterFloat64{} } // NewRegisteredCounterFloat64 constructs and registers a new StandardCounterFloat64. @@ -113,41 +114,42 @@ func (NilCounterFloat64) Inc(i float64) {} func (NilCounterFloat64) Snapshot() CounterFloat64 { return NilCounterFloat64{} } // StandardCounterFloat64 is the standard implementation of a CounterFloat64 and uses the -// sync.Mutex package to manage a single float64 value. +// atomic to manage a single float64 value. type StandardCounterFloat64 struct { - mutex sync.Mutex - count float64 + floatBits atomic.Uint64 } // Clear sets the counter to zero. func (c *StandardCounterFloat64) Clear() { - c.mutex.Lock() - defer c.mutex.Unlock() - c.count = 0.0 + c.floatBits.Store(0) } // Count returns the current value. func (c *StandardCounterFloat64) Count() float64 { - c.mutex.Lock() - defer c.mutex.Unlock() - return c.count + return math.Float64frombits(c.floatBits.Load()) } // Dec decrements the counter by the given amount. func (c *StandardCounterFloat64) Dec(v float64) { - c.mutex.Lock() - defer c.mutex.Unlock() - c.count -= v + atomicAddFloat(&c.floatBits, -v) } // Inc increments the counter by the given amount. func (c *StandardCounterFloat64) Inc(v float64) { - c.mutex.Lock() - defer c.mutex.Unlock() - c.count += v + atomicAddFloat(&c.floatBits, v) } // Snapshot returns a read-only copy of the counter. func (c *StandardCounterFloat64) Snapshot() CounterFloat64 { return CounterFloat64Snapshot(c.Count()) } + +func atomicAddFloat(fbits *atomic.Uint64, v float64) { + for { + loadedBits := fbits.Load() + newBits := math.Float64bits(math.Float64frombits(loadedBits) + v) + if fbits.CompareAndSwap(loadedBits, newBits) { + break + } + } +} diff --git a/metrics/counter_float_64_test.go b/metrics/counter_float_64_test.go index 44d9b4c20c85..f17aca330cbe 100644 --- a/metrics/counter_float_64_test.go +++ b/metrics/counter_float_64_test.go @@ -1,6 +1,9 @@ package metrics -import "testing" +import ( + "sync" + "testing" +) func BenchmarkCounterFloat64(b *testing.B) { c := NewCounterFloat64() @@ -10,6 +13,25 @@ func BenchmarkCounterFloat64(b *testing.B) { } } +func BenchmarkCounterFloat64Parallel(b *testing.B) { + c := NewCounterFloat64() + b.ResetTimer() + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + for i := 0; i < b.N; i++ { + c.Inc(1.0) + } + wg.Done() + }() + } + wg.Wait() + if have, want := c.Count(), 10.0*float64(b.N); have != want { + b.Fatalf("have %f want %f", have, want) + } +} + func TestCounterFloat64Clear(t *testing.T) { c := NewCounterFloat64() c.Inc(1.0) diff --git a/metrics/gauge_float64.go b/metrics/gauge_float64.go index 66819c957774..237ff8036e01 100644 --- a/metrics/gauge_float64.go +++ b/metrics/gauge_float64.go @@ -1,6 +1,9 @@ package metrics -import "sync" +import ( + "math" + "sync/atomic" +) // GaugeFloat64s hold a float64 value that can be set arbitrarily. type GaugeFloat64 interface { @@ -23,9 +26,7 @@ func NewGaugeFloat64() GaugeFloat64 { if !Enabled { return NilGaugeFloat64{} } - return &StandardGaugeFloat64{ - value: 0.0, - } + return &StandardGaugeFloat64{} } // NewRegisteredGaugeFloat64 constructs and registers a new StandardGaugeFloat64. @@ -83,10 +84,9 @@ func (NilGaugeFloat64) Update(v float64) {} func (NilGaugeFloat64) Value() float64 { return 0.0 } // StandardGaugeFloat64 is the standard implementation of a GaugeFloat64 and uses -// sync.Mutex to manage a single float64 value. +// atomic to manage a single float64 value. type StandardGaugeFloat64 struct { - mutex sync.Mutex - value float64 + floatBits atomic.Uint64 } // Snapshot returns a read-only copy of the gauge. @@ -96,16 +96,12 @@ func (g *StandardGaugeFloat64) Snapshot() GaugeFloat64 { // Update updates the gauge's value. func (g *StandardGaugeFloat64) Update(v float64) { - g.mutex.Lock() - defer g.mutex.Unlock() - g.value = v + g.floatBits.Store(math.Float64bits(v)) } // Value returns the gauge's current value. func (g *StandardGaugeFloat64) Value() float64 { - g.mutex.Lock() - defer g.mutex.Unlock() - return g.value + return math.Float64frombits(g.floatBits.Load()) } // FunctionalGaugeFloat64 returns value from given function diff --git a/metrics/gauge_float64_test.go b/metrics/gauge_float64_test.go index 7b854d232ba8..647d09000935 100644 --- a/metrics/gauge_float64_test.go +++ b/metrics/gauge_float64_test.go @@ -1,6 +1,9 @@ package metrics -import "testing" +import ( + "sync" + "testing" +) func BenchmarkGaugeFloat64(b *testing.B) { g := NewGaugeFloat64() @@ -10,6 +13,24 @@ func BenchmarkGaugeFloat64(b *testing.B) { } } +func BenchmarkGaugeFloat64Parallel(b *testing.B) { + c := NewGaugeFloat64() + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + for i := 0; i < b.N; i++ { + c.Update(float64(i)) + } + wg.Done() + }() + } + wg.Wait() + if have, want := c.Value(), float64(b.N-1); have != want { + b.Fatalf("have %f want %f", have, want) + } +} + func TestGaugeFloat64(t *testing.T) { g := NewGaugeFloat64() g.Update(47.0) From 2adce0b06640aa665706d014a92cd06f0720dcab Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Wed, 5 Apr 2023 00:34:52 +0800 Subject: [PATCH 697/715] eth/tracers: use atomic type (#27031) Use the new atomic types in package eth/tracers --------- Co-authored-by: Martin Holst Swende Co-authored-by: Sina Mahmoodi --- eth/tracers/api_test.go | 16 +++++++++------- eth/tracers/logger/logger.go | 8 ++++---- eth/tracers/native/4byte.go | 6 +++--- eth/tracers/native/call.go | 10 +++++----- eth/tracers/native/prestate.go | 10 +++++++--- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index b1eaf60b16c4..63430210384e 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -835,8 +835,8 @@ func TestTraceChain(t *testing.T) { signer := types.HomesteadSigner{} var ( - ref uint32 // total refs has made - rel uint32 // total rels has made + ref atomic.Uint32 // total refs has made + rel atomic.Uint32 // total rels has made nonce uint64 ) backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { @@ -849,8 +849,8 @@ func TestTraceChain(t *testing.T) { nonce += 1 } }) - backend.refHook = func() { atomic.AddUint32(&ref, 1) } - backend.relHook = func() { atomic.AddUint32(&rel, 1) } + backend.refHook = func() { ref.Add(1) } + backend.relHook = func() { rel.Add(1) } api := NewAPI(backend) single := `{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}` @@ -863,7 +863,8 @@ func TestTraceChain(t *testing.T) { {10, 20, nil}, // the middle chain range, blocks [11, 20] } for _, c := range cases { - ref, rel = 0, 0 // clean up the counters + ref.Store(0) + rel.Store(0) from, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.start)) to, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.end)) @@ -888,8 +889,9 @@ func TestTraceChain(t *testing.T) { if next != c.end+1 { t.Error("Missing tracing block") } - if ref != rel { - t.Errorf("Ref and deref actions are not equal, ref %d rel %d", ref, rel) + + if nref, nrel := ref.Load(), rel.Load(); nref != nrel { + t.Errorf("Ref and deref actions are not equal, ref %d rel %d", nref, nrel) } } } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 5e75318b9a92..c7f171c5bdf9 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -116,8 +116,8 @@ type StructLogger struct { gasLimit uint64 usedGas uint64 - interrupt uint32 // Atomic flag to signal execution interruption - reason error // Textual reason for the interruption + interrupt atomic.Bool // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption } // NewStructLogger returns a new logger @@ -149,7 +149,7 @@ func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common. // CaptureState also tracks SLOAD/SSTORE ops to track storage change. func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { // If tracing was interrupted, set the error and stop - if atomic.LoadUint32(&l.interrupt) > 0 { + if l.interrupt.Load() { return } // check if already accumulated the specified number of logs @@ -258,7 +258,7 @@ func (l *StructLogger) GetResult() (json.RawMessage, error) { // Stop terminates execution of the tracer at the first opportune moment. func (l *StructLogger) Stop(err error) { l.reason = err - atomic.StoreUint32(&l.interrupt, 1) + l.interrupt.Store(true) } func (l *StructLogger) CaptureTxStart(gasLimit uint64) { diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 1b4649baa33e..5a2c4f91115f 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -48,7 +48,7 @@ func init() { type fourByteTracer struct { noopTracer ids map[string]int // ids aggregates the 4byte ids found - interrupt uint32 // Atomic flag to signal execution interruption + interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption activePrecompiles []common.Address // Updated on CaptureStart based on given rules } @@ -93,7 +93,7 @@ func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to commo // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { // Skip if tracing was interrupted - if atomic.LoadUint32(&t.interrupt) > 0 { + if t.interrupt.Load() { return } if len(input) < 4 { @@ -124,7 +124,7 @@ func (t *fourByteTracer) GetResult() (json.RawMessage, error) { // Stop terminates execution of the tracer at the first opportune moment. func (t *fourByteTracer) Stop(err error) { t.reason = err - atomic.StoreUint32(&t.interrupt, 1) + t.interrupt.Store(true) } func bytesToHex(s []byte) string { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index c3db1ad034df..4ac03e512fb7 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -102,8 +102,8 @@ type callTracer struct { callstack []callFrame config callTracerConfig gasLimit uint64 - interrupt uint32 // Atomic flag to signal execution interruption - reason error // Textual reason for the interruption + interrupt atomic.Bool // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption } type callTracerConfig struct { @@ -161,7 +161,7 @@ func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco return } // Skip if tracing was interrupted - if atomic.LoadUint32(&t.interrupt) > 0 { + if t.interrupt.Load() { return } switch op { @@ -197,7 +197,7 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. return } // Skip if tracing was interrupted - if atomic.LoadUint32(&t.interrupt) > 0 { + if t.interrupt.Load() { return } @@ -262,7 +262,7 @@ func (t *callTracer) GetResult() (json.RawMessage, error) { // Stop terminates execution of the tracer at the first opportune moment. func (t *callTracer) Stop(err error) { t.reason = err - atomic.StoreUint32(&t.interrupt, 1) + t.interrupt.Store(true) } // clearFailedLogs clears the logs of a callframe and all its children diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 42ec4fe7828b..b71d5d62152d 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -62,8 +62,8 @@ type prestateTracer struct { to common.Address gasLimit uint64 // Amount of gas bought for the whole tx config prestateTracerConfig - interrupt uint32 // Atomic flag to signal execution interruption - reason error // Textual reason for the interruption + interrupt atomic.Bool // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption created map[common.Address]bool deleted map[common.Address]bool } @@ -136,6 +136,10 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, if err != nil { return } + // Skip if tracing was interrupted + if t.interrupt.Load() { + return + } stack := scope.Stack stackData := stack.Data() stackLen := len(stackData) @@ -259,7 +263,7 @@ func (t *prestateTracer) GetResult() (json.RawMessage, error) { // Stop terminates execution of the tracer at the first opportune moment. func (t *prestateTracer) Stop(err error) { t.reason = err - atomic.StoreUint32(&t.interrupt, 1) + t.interrupt.Store(true) } // lookupAccount fetches details of an account and adds it to the prestate From 9d37102134b27f8584441c488c026ae5a3081a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Tue, 4 Apr 2023 22:24:30 +0200 Subject: [PATCH 698/715] build: upgrade -dlgo version to Go 1.20.3 --- build/checksums.txt | 28 ++++++++++++++-------------- build/ci.go | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index e349d3eba03b..9b038582a844 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,19 +1,19 @@ # This file contains sha256 checksums of optional build dependencies. -4d0e2850d197b4ddad3bdb0196300179d095bb3aefd4dfbc3b36702c3728f8ab go1.20.2.src.tar.gz -c93b8ced9517d07e1cd4c362c6e2d5242cb139e29b417a328fbf19aded08764c go1.20.2.darwin-amd64.tar.gz -7343c87f19e79c0063532e82e1c4d6f42175a32d99f7a4d15e658e88bf97f885 go1.20.2.darwin-arm64.tar.gz -14f9be2004e042b3a64d0facb0c020756a9084a5c7333e33b0752b393b6016ea go1.20.2.freebsd-386.tar.gz -b41b67b4f1b56797a7cecf6ee7f47fcf4f93960b2788a3683c07dd009d30b2a4 go1.20.2.freebsd-amd64.tar.gz -ee240ed33ae57504c41f04c12236aeaa17fbeb6ea9fcd096cd9dc7a89d10d4db go1.20.2.linux-386.tar.gz -4eaea32f59cde4dc635fbc42161031d13e1c780b87097f4b4234cfce671f1768 go1.20.2.linux-amd64.tar.gz -78d632915bb75e9a6356a47a42625fd1a785c83a64a643fedd8f61e31b1b3bef go1.20.2.linux-arm64.tar.gz -d79d56bafd6b52b8d8cbe3f8e967caaac5383a23d7a4fa9ac0e89778cd16a076 go1.20.2.linux-armv6l.tar.gz -850564ddb760cb703db63bf20182dc4407abd2ff090a95fa66d6634d172fd095 go1.20.2.linux-ppc64le.tar.gz -8da24c5c4205fe8115f594237e5db7bcb1d23df67bc1fa9a999954b1976896e8 go1.20.2.linux-s390x.tar.gz -31838b291117495bbb93683603e98d5118bfabd2eb318b4d07540bfd524bab86 go1.20.2.windows-386.zip -fe439f0e438f7555a7f5f7194ddb6f4a07b0de1fa414385d19f2aeb26d9f43db go1.20.2.windows-amd64.zip -ac5010c8b8b22849228a8dea698d58b9c7be2195d30c6d778cce0f709858fa64 go1.20.2.windows-arm64.zip +e447b498cde50215c4f7619e5124b0fc4e25fb5d16ea47271c47f278e7aa763a go1.20.3.src.tar.gz +c1e1161d6d859deb576e6cfabeb40e3d042ceb1c6f444f617c3c9d76269c3565 go1.20.3.darwin-amd64.tar.gz +86b0ed0f2b2df50fa8036eea875d1cf2d76cefdacf247c44639a1464b7e36b95 go1.20.3.darwin-arm64.tar.gz +340e80abd047c597fdc0f50a6cc59617f06c297d62f7fc77f4a0164e2da6f7aa go1.20.3.freebsd-386.tar.gz +2169fcd8b6c94c5fbe07c0b470ccfb6001d343f6548ad49f3d9ab78e3b5753c7 go1.20.3.freebsd-amd64.tar.gz +e12384311403f1389d14cc1c1295bfb4e0dd5ab919403b80da429f671a223507 go1.20.3.linux-386.tar.gz +979694c2c25c735755bf26f4f45e19e64e4811d661dd07b8c010f7a8e18adfca go1.20.3.linux-amd64.tar.gz +eb186529f13f901e7a2c4438a05c2cd90d74706aaa0a888469b2a4a617b6ee54 go1.20.3.linux-arm64.tar.gz +b421e90469a83671641f81b6e20df6500f033e9523e89cbe7b7223704dd1035c go1.20.3.linux-armv6l.tar.gz +943c89aa1624ea544a022b31e3d6e16a037200e436370bdd5fd67f3fa60be282 go1.20.3.linux-ppc64le.tar.gz +126cf823a5634ef2544b866db107b9d351d3ea70d9e240b0bdcfb46f4dcae54b go1.20.3.linux-s390x.tar.gz +37e9146e1f9d681cfcaa6fee6c7b890c44c64bc50228c9588f3c4231346d33bd go1.20.3.windows-386.zip +143a2837821c7dbacf7744cbb1a8421c1f48307c6fdfaeffc5f8c2f69e1b7932 go1.20.3.windows-amd64.zip +158cb159e00bc979f473e0f5b5a561613129c5e51067967b72b8e072e5a4db81 go1.20.3.windows-arm64.zip fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz 75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz diff --git a/build/ci.go b/build/ci.go index 3e145b20b079..eab011752d62 100644 --- a/build/ci.go +++ b/build/ci.go @@ -139,7 +139,7 @@ var ( // This is the version of Go that will be downloaded by // // go run ci.go install -dlgo - dlgoVersion = "1.20.2" + dlgoVersion = "1.20.3" // This is the version of Go that will be used to bootstrap the PPA builder. // From 230df98e4d8b6af92281db6d0e51a55ff950e656 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 5 Apr 2023 10:59:32 +0200 Subject: [PATCH 699/715] core/txpool: disallow future churn by remote txs (#26907) Prior to this change, it was possible that transactions are erroneously deemed as 'future' although they are in fact 'pending', causing them to be dropped due to 'future' not being allowed to replace 'pending'. This change fixes that, by doing a more in-depth inspection of the queue. --- core/txpool/list.go | 8 ++++---- core/txpool/txpool.go | 34 +++++++++++++++++++++------------- core/txpool/txpool2_test.go | 28 ++++++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/core/txpool/list.go b/core/txpool/list.go index 639d69bcbed4..fae7c2fcac2d 100644 --- a/core/txpool/list.go +++ b/core/txpool/list.go @@ -270,10 +270,10 @@ func newList(strict bool) *list { } } -// Overlaps returns whether the transaction specified has the same nonce as one -// already contained within the list. -func (l *list) Overlaps(tx *types.Transaction) bool { - return l.txs.Get(tx.Nonce()) != nil +// Contains returns whether the list contains a transaction +// with the provided nonce. +func (l *list) Contains(nonce uint64) bool { + return l.txs.Get(nonce) != nil } // Add tries to insert a new transaction into the list, returning whether the diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 3a5ed695681c..9eb19b0094ba 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -745,11 +745,11 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e } // If the new transaction is a future transaction it should never churn pending transactions - if !isLocal && pool.isFuture(from, tx) { + if !isLocal && pool.isGapped(from, tx) { var replacesPending bool for _, dropTx := range drop { dropSender, _ := types.Sender(pool.signer, dropTx) - if list := pool.pending[dropSender]; list != nil && list.Overlaps(dropTx) { + if list := pool.pending[dropSender]; list != nil && list.Contains(dropTx.Nonce()) { replacesPending = true break } @@ -774,7 +774,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e } // Try to replace an existing transaction in the pending pool - if list := pool.pending[from]; list != nil && list.Overlaps(tx) { + if list := pool.pending[from]; list != nil && list.Contains(tx.Nonce()) { // Nonce already pending, check if required price bump is met inserted, old := list.Add(tx, pool.config.PriceBump) if !inserted { @@ -817,18 +817,26 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e return replaced, nil } -// isFuture reports whether the given transaction is immediately executable. -func (pool *TxPool) isFuture(from common.Address, tx *types.Transaction) bool { - list := pool.pending[from] - if list == nil { - return pool.pendingNonces.get(from) != tx.Nonce() +// isGapped reports whether the given transaction is immediately executable. +func (pool *TxPool) isGapped(from common.Address, tx *types.Transaction) bool { + // Short circuit if transaction matches pending nonce and can be promoted + // to pending list as an executable transaction. + next := pool.pendingNonces.get(from) + if tx.Nonce() == next { + return false } - // Sender has pending transactions. - if old := list.txs.Get(tx.Nonce()); old != nil { - return false // It replaces a pending transaction. + // The transaction has a nonce gap with pending list, it's only considered + // as executable if transactions in queue can fill up the nonce gap. + queue, ok := pool.queue[from] + if !ok { + return true } - // Not replacing, check if parent nonce exists in pending. - return list.txs.Get(tx.Nonce()-1) == nil + for nonce := next; nonce < tx.Nonce(); nonce++ { + if !queue.Contains(nonce) { + return true // txs in queue can't fill up the nonce gap + } + } + return false } // enqueueTx inserts a new transaction into the non-executable transaction queue. diff --git a/core/txpool/txpool2_test.go b/core/txpool/txpool2_test.go index 6d84975d83f9..7e2a9eb908d3 100644 --- a/core/txpool/txpool2_test.go +++ b/core/txpool/txpool2_test.go @@ -42,7 +42,7 @@ func count(t *testing.T, pool *TxPool) (pending int, queued int) { return pending, queued } -func fillPool(t *testing.T, pool *TxPool) { +func fillPool(t testing.TB, pool *TxPool) { t.Helper() // Create a number of test accounts, fund them and make transactions executableTxs := types.Transactions{} @@ -189,7 +189,7 @@ func TestTransactionZAttack(t *testing.T) { key, _ := crypto.GenerateKey() pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) for j := 0; j < int(pool.config.GlobalSlots); j++ { - overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 60000000000, 21000, big.NewInt(500), key)) + overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key)) } } pool.AddRemotesSync(overDraftTxs) @@ -210,3 +210,27 @@ func TestTransactionZAttack(t *testing.T) { newIvPending, ivPending, pool.config.GlobalSlots, newQueued) } } + +func BenchmarkFutureAttack(b *testing.B) { + // Create the pool to test the limit enforcement with + statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + blockchain := newTestBlockChain(1000000, statedb, new(event.Feed)) + config := testTxPoolConfig + config.GlobalQueue = 100 + config.GlobalSlots = 100 + pool := NewTxPool(config, eip1559Config, blockchain) + defer pool.Stop() + fillPool(b, pool) + + key, _ := crypto.GenerateKey() + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) + futureTxs := types.Transactions{} + + for n := 0; n < b.N; n++ { + futureTxs = append(futureTxs, pricedTransaction(1000+uint64(n), 100000, big.NewInt(500), key)) + } + b.ResetTimer() + for i := 0; i < 5; i++ { + pool.AddRemotesSync(futureTxs) + } +} From b946b7a13b749c99979e312c83dce34cac8dd7b1 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 5 Apr 2023 19:09:25 +0800 Subject: [PATCH 700/715] core, miner: drop transactions from the same sender when error occurs (#27038) This PR unifies the error handling in miner. Whenever an error occur while applying a transaction, the transaction should be regarded as invalid and all following transactions from the same sender not executable because of the nonce restriction. The only exception is the `nonceTooLow` error which is handled separately. --- core/state_transition.go | 2 +- miner/worker.go | 21 +++------------------ 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index fedccf1a711b..72f975775c1b 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -136,7 +136,7 @@ type Message struct { Data []byte AccessList types.AccessList - // When SkipAccountCheckss is true, the message nonce is not checked against the + // When SkipAccountChecks is true, the message nonce is not checked against the // account nonce in state. It also disables checking that the sender is an EOA. // This field will be set to true for operations like RPC eth_call. SkipAccountChecks bool diff --git a/miner/worker.go b/miner/worker.go index 9fbece865891..c481239d40e2 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -918,37 +918,22 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP logs, err := w.commitTransaction(env, tx) switch { - case errors.Is(err, core.ErrGasLimitReached): - // Pop the current out-of-gas transaction without shifting in the next from the account - log.Trace("Gas limit exceeded for current block", "sender", from) - txs.Pop() - case errors.Is(err, core.ErrNonceTooLow): // New head notification data race between the transaction pool and miner, shift log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce()) txs.Shift() - case errors.Is(err, core.ErrNonceTooHigh): - // Reorg notification data race between the transaction pool and miner, skip account = - log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce()) - txs.Pop() - case errors.Is(err, nil): // Everything ok, collect the logs and shift in the next transaction from the same account coalescedLogs = append(coalescedLogs, logs...) env.tcount++ txs.Shift() - case errors.Is(err, types.ErrTxTypeNotSupported): - // Pop the unsupported transaction without shifting in the next from the account - log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type()) - txs.Pop() - default: - // Strange error, discard the transaction and get the next in line (note, the - // nonce-too-high clause will prevent us from executing in vain). + // Transaction is regarded as invalid, drop all consecutive transactions from + // the same sender because of `nonce-too-high` clause. log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) - txs.Shift() + txs.Pop() } } if !w.isRunning() && len(coalescedLogs) > 0 { From 5aa5295cf940a36516a474ca9be9ffad4a7bdb60 Mon Sep 17 00:00:00 2001 From: Parithosh Jayanthi Date: Mon, 17 Apr 2023 10:15:25 +0200 Subject: [PATCH 701/715] params: new sepolia bootnodes (#27099) New sepolia bootnodes managed by EF devops --- params/bootnodes.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/params/bootnodes.go b/params/bootnodes.go index 45e27c441a78..4ae94cfbd322 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -31,10 +31,12 @@ var MainnetBootnodes = []string{ // SepoliaBootnodes are the enode URLs of the P2P bootstrap nodes running on the // Sepolia test network. var SepoliaBootnodes = []string{ - // geth - "enode://9246d00bc8fd1742e5ad2428b80fc4dc45d786283e05ef6edbd9002cbc335d40998444732fbe921cb88e1d2c73d1b1de53bae6a2237996e9bfe14f871baf7066@18.168.182.86:30303", - // besu - "enode://ec66ddcf1a974950bd4c782789a7e04f8aa7110a72569b6e65fcd51e937e74eed303b1ea734e4d19cfaec9fbff9b6ee65bf31dcb50ba79acce9dd63a6aca61c7@52.14.151.177:30303", + // EF DevOps + "enode://4e5e92199ee224a01932a377160aa432f31d0b351f84ab413a8e0a42f4f36476f8fb1cbe914af0d9aef0d51665c214cf653c651c4bbd9d5550a934f241f1682b@138.197.51.181:30303", // sepolia-bootnode-1-nyc3 + "enode://143e11fb766781d22d92a2e33f8f104cddae4411a122295ed1fdb6638de96a6ce65f5b7c964ba3763bba27961738fef7d3ecc739268f3e5e771fb4c87b6234ba@146.190.1.103:30303", // sepolia-bootnode-1-sfo3 + "enode://8b61dc2d06c3f96fddcbebb0efb29d60d3598650275dc469c22229d3e5620369b0d3dedafd929835fe7f489618f19f456fe7c0df572bf2d914a9f4e006f783a9@170.64.250.88:30303", // sepolia-bootnode-1-syd1 + "enode://10d62eff032205fcef19497f35ca8477bea0eadfff6d769a147e895d8b2b8f8ae6341630c645c30f5df6e67547c03494ced3d9c5764e8622a26587b083b028e8@139.59.49.206:30303", // sepolia-bootnode-1-blr1 + "enode://9e9492e2e8836114cc75f5b929784f4f46c324ad01daf87d956f98b3b6c5fcba95524d6e5cf9861dc96a2c8a171ea7105bb554a197455058de185fa870970c7c@138.68.123.152:30303", // sepolia-bootnode-1-ams3 } // RinkebyBootnodes are the enode URLs of the P2P bootstrap nodes running on the From 8fe807c8f27e33bbfd77e4670818522821aec979 Mon Sep 17 00:00:00 2001 From: noel <72006780+0x00Duke@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:29:27 +0200 Subject: [PATCH 702/715] cmd/devp2p: fix erroneous log output in crawler (#27089) cmd/devp2p: fix log of ignored recent nodes counter --- cmd/devp2p/crawl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/devp2p/crawl.go b/cmd/devp2p/crawl.go index 8c9755ac1cd4..1b964164d882 100644 --- a/cmd/devp2p/crawl.go +++ b/cmd/devp2p/crawl.go @@ -141,7 +141,7 @@ loop: "added", atomic.LoadUint64(&added), "updated", atomic.LoadUint64(&updated), "removed", atomic.LoadUint64(&removed), - "ignored(recent)", atomic.LoadUint64(&removed), + "ignored(recent)", atomic.LoadUint64(&recent), "ignored(incompatible)", atomic.LoadUint64(&skipped)) } } From bedf2856d1ed21b7c3eb6a67fd73495f7a1b6ecb Mon Sep 17 00:00:00 2001 From: Taeguk Kwon Date: Mon, 17 Apr 2023 23:36:47 +0900 Subject: [PATCH 703/715] signer/core: rename testdata files (#27063) Sets a meaningful name on test-files --- .../testdata/{expfail_extradata-2.json => expfail_extradata.json} | 0 .../{expfail_extradata-1.json => expfail_nonexistant_type2.json} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename signer/core/testdata/{expfail_extradata-2.json => expfail_extradata.json} (100%) rename signer/core/testdata/{expfail_extradata-1.json => expfail_nonexistant_type2.json} (100%) diff --git a/signer/core/testdata/expfail_extradata-2.json b/signer/core/testdata/expfail_extradata.json similarity index 100% rename from signer/core/testdata/expfail_extradata-2.json rename to signer/core/testdata/expfail_extradata.json diff --git a/signer/core/testdata/expfail_extradata-1.json b/signer/core/testdata/expfail_nonexistant_type2.json similarity index 100% rename from signer/core/testdata/expfail_extradata-1.json rename to signer/core/testdata/expfail_nonexistant_type2.json From cb66eba85ad9d64ffd33326f5ac6650a72d4588e Mon Sep 17 00:00:00 2001 From: Anusha <63559942+anusha-ctrl@users.noreply.github.com> Date: Mon, 17 Apr 2023 08:02:31 -0700 Subject: [PATCH 704/715] core: fix comment to reflect function name (#27070) --- core/blockchain.go | 2 +- core/state/snapshot/snapshot_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 804375bf164f..80fefac9b059 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -908,7 +908,7 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) { headBlockGauge.Update(int64(block.NumberU64())) } -// stop stops the blockchain service. If any imports are currently in progress +// stopWithoutSaving stops the blockchain service. If any imports are currently in progress // it will abort them using the procInterrupt. This method stops all running // goroutines, but does not do all the post-stop work of persisting data. // OBS! It is generally recommended to use the Stop method! diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index 6893f6001e33..249da10aa643 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -118,7 +118,7 @@ func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) { if err := snaps.Cap(common.HexToHash("0x02"), 0); err != nil { t.Fatalf("failed to merge diff layer onto disk: %v", err) } - // Since the base layer was modified, ensure that data retrieval on the external reference fail + // Since the base layer was modified, ensure that data retrievals on the external reference fail if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale { t.Errorf("stale reference returned account: %#x (err: %v)", acc, err) } From 5e4d726e2a05aee80a75e5f99fd699f220dd503e Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 18 Apr 2023 15:49:09 +0800 Subject: [PATCH 705/715] params: remove `EIP150Hash` from chainconfig (#27087) The EIP150Hash was an idea where, after the fork, we hardcoded the forked hash as an extra defensive mechanism. It wasn't really used, since forks weren't contentious and for all the various testnets and private networks it's been a hassle to have around. This change removes that config field. --------- Signed-off-by: jsvisa --- consensus/clique/clique.go | 4 ---- consensus/ethash/consensus.go | 3 --- consensus/misc/eip1559_test.go | 1 - consensus/misc/forks.go | 43 ---------------------------------- core/vm/runtime/runtime.go | 1 - eth/tracers/js/tracer_test.go | 2 +- miner/stress/1559/main.go | 1 - miner/stress/clique/main.go | 1 - miner/stress/ethash/main.go | 1 - params/config.go | 10 +------- tests/difficulty_test.go | 3 --- 11 files changed, 2 insertions(+), 68 deletions(-) delete mode 100644 consensus/misc/forks.go diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 1b9a1d923690..2345a5ca030f 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -304,10 +304,6 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H if chain.Config().IsCancun(header.Time) { return fmt.Errorf("clique does not support cancun fork") } - // If all checks passed, validate any special fields for hard forks - if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { - return err - } // All basic checks passed, verify cascading fields return c.verifyCascadingFields(chain, header, parents) } diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 8f1b497cbdfb..e3e0f28b3e92 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -326,9 +326,6 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil { return err } - if err := misc.VerifyForkHashes(chain.Config(), header, uncle); err != nil { - return err - } return nil } diff --git a/consensus/misc/eip1559_test.go b/consensus/misc/eip1559_test.go index 23cd9023de24..1a9f96bc4326 100644 --- a/consensus/misc/eip1559_test.go +++ b/consensus/misc/eip1559_test.go @@ -34,7 +34,6 @@ func copyConfig(original *params.ChainConfig) *params.ChainConfig { DAOForkBlock: original.DAOForkBlock, DAOForkSupport: original.DAOForkSupport, EIP150Block: original.EIP150Block, - EIP150Hash: original.EIP150Hash, EIP155Block: original.EIP155Block, EIP158Block: original.EIP158Block, ByzantiumBlock: original.ByzantiumBlock, diff --git a/consensus/misc/forks.go b/consensus/misc/forks.go deleted file mode 100644 index a6f3303ea6fa..000000000000 --- a/consensus/misc/forks.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 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 misc - -import ( - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" -) - -// VerifyForkHashes verifies that blocks conforming to network hard-forks do have -// the correct hashes, to avoid clients going off on different chains. This is an -// optional feature. -func VerifyForkHashes(config *params.ChainConfig, header *types.Header, uncle bool) error { - // We don't care about uncles - if uncle { - return nil - } - // If the homestead reprice hash is set, validate it - if config.EIP150Block != nil && config.EIP150Block.Cmp(header.Number) == 0 { - if config.EIP150Hash != (common.Hash{}) && config.EIP150Hash != header.Hash() { - return fmt.Errorf("homestead gas reprice fork: have %#x, want %#x", header.Hash(), config.EIP150Hash) - } - } - // All ok, return - return nil -} diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 56ff5eeabe33..005ef0c754ae 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -57,7 +57,6 @@ func setDefaults(cfg *Config) { DAOForkBlock: new(big.Int), DAOForkSupport: false, EIP150Block: new(big.Int), - EIP150Hash: common.Hash{}, EIP155Block: new(big.Int), EIP158Block: new(big.Int), ByzantiumBlock: new(big.Int), diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index a61754352a09..bf6427faf673 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -229,7 +229,7 @@ func TestNoStepExec(t *testing.T) { } func TestIsPrecompile(t *testing.T) { - chaincfg := ¶ms.ChainConfig{ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(100), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(200), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(300), LondonBlock: big.NewInt(0), TerminalTotalDifficulty: nil, Ethash: new(params.EthashConfig), Clique: nil} + chaincfg := ¶ms.ChainConfig{ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(100), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(200), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(300), LondonBlock: big.NewInt(0), TerminalTotalDifficulty: nil, Ethash: new(params.EthashConfig), Clique: nil} chaincfg.ByzantiumBlock = big.NewInt(100) chaincfg.IstanbulBlock = big.NewInt(200) chaincfg.BerlinBlock = big.NewInt(300) diff --git a/miner/stress/1559/main.go b/miner/stress/1559/main.go index c27875000d85..2e8b78d85e33 100644 --- a/miner/stress/1559/main.go +++ b/miner/stress/1559/main.go @@ -205,7 +205,6 @@ func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { genesis.GasLimit = 8_000_000 genesis.Config.ChainID = big.NewInt(18) - genesis.Config.EIP150Hash = common.Hash{} genesis.Alloc = core.GenesisAlloc{} for _, faucet := range faucets { diff --git a/miner/stress/clique/main.go b/miner/stress/clique/main.go index 688c2b698409..74962c6d51c1 100644 --- a/miner/stress/clique/main.go +++ b/miner/stress/clique/main.go @@ -153,7 +153,6 @@ func makeGenesis(faucets []*ecdsa.PrivateKey, sealers []*ecdsa.PrivateKey) *core genesis.Config.ChainID = big.NewInt(18) genesis.Config.Clique.Period = 1 - genesis.Config.EIP150Hash = common.Hash{} genesis.Alloc = core.GenesisAlloc{} for _, faucet := range faucets { diff --git a/miner/stress/ethash/main.go b/miner/stress/ethash/main.go index 6b6e7059d33b..6905bf01f164 100644 --- a/miner/stress/ethash/main.go +++ b/miner/stress/ethash/main.go @@ -139,7 +139,6 @@ func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { genesis.GasLimit = 25000000 genesis.Config.ChainID = big.NewInt(18) - genesis.Config.EIP150Hash = common.Hash{} genesis.Alloc = core.GenesisAlloc{} for _, faucet := range faucets { diff --git a/params/config.go b/params/config.go index 190eb737c48b..82d00bc8f515 100644 --- a/params/config.go +++ b/params/config.go @@ -62,7 +62,6 @@ var ( DAOForkBlock: big.NewInt(1_920_000), DAOForkSupport: true, EIP150Block: big.NewInt(2_463_000), - EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), EIP155Block: big.NewInt(2_675_000), EIP158Block: big.NewInt(2_675_000), ByzantiumBlock: big.NewInt(4_370_000), @@ -139,7 +138,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: true, EIP150Block: big.NewInt(2), - EIP150Hash: common.HexToHash("0x9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"), EIP155Block: big.NewInt(3), EIP158Block: big.NewInt(3), ByzantiumBlock: big.NewInt(1_035_301), @@ -231,7 +229,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), - EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), @@ -261,7 +258,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), - EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), @@ -291,7 +287,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), - EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), @@ -321,7 +316,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: nil, - EIP150Hash: common.Hash{}, EIP155Block: nil, EIP158Block: nil, ByzantiumBlock: nil, @@ -415,9 +409,7 @@ type ChainConfig struct { DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) - EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) - EIP150Hash common.Hash `json:"eip150Hash,omitempty"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) - + EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block diff --git a/tests/difficulty_test.go b/tests/difficulty_test.go index a8273303e31f..03e14df7c4df 100644 --- a/tests/difficulty_test.go +++ b/tests/difficulty_test.go @@ -20,7 +20,6 @@ import ( "math/big" "testing" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" ) @@ -31,7 +30,6 @@ var ( DAOForkBlock: big.NewInt(1920000), DAOForkSupport: true, EIP150Block: big.NewInt(2463000), - EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), EIP155Block: big.NewInt(2675000), EIP158Block: big.NewInt(2675000), ByzantiumBlock: big.NewInt(4370000), @@ -43,7 +41,6 @@ var ( DAOForkBlock: nil, DAOForkSupport: true, EIP150Block: big.NewInt(0), - EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), EIP155Block: big.NewInt(10), EIP158Block: big.NewInt(10), ByzantiumBlock: big.NewInt(1_700_000), From b1972627d9cf6b38f8f41a2093eb8b333ba0b16f Mon Sep 17 00:00:00 2001 From: joohhnnn <68833933+joohhnnn@users.noreply.github.com> Date: Tue, 18 Apr 2023 17:57:08 +0800 Subject: [PATCH 706/715] p2p: access embedded fields of Server directly (#27078) --- p2p/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/server.go b/p2p/server.go index b8a2f8fd211f..f7bf948b6901 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -443,7 +443,7 @@ func (srv *Server) Start() (err error) { return errors.New("server already running") } srv.running = true - srv.log = srv.Config.Logger + srv.log = srv.Logger if srv.log == nil { srv.log = log.Root() } @@ -501,7 +501,7 @@ func (srv *Server) setupLocalNode() error { sort.Sort(capsByNameAndVersion(srv.ourHandshake.Caps)) // Create the local node. - db, err := enode.OpenDB(srv.Config.NodeDatabase) + db, err := enode.OpenDB(srv.NodeDatabase) if err != nil { return err } From 3768b0074791169441ca5eb3a7c73c7b9e74c24a Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 18 Apr 2023 20:54:06 +0800 Subject: [PATCH 707/715] consensus/ethash: use atomic type (#27068) --- consensus/ethash/algorithm.go | 12 ++++++------ consensus/ethash/ethash.go | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/consensus/ethash/algorithm.go b/consensus/ethash/algorithm.go index d53918382283..a2a6081f55cf 100644 --- a/consensus/ethash/algorithm.go +++ b/consensus/ethash/algorithm.go @@ -163,7 +163,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { rows := int(size) / hashBytes // Start a monitoring goroutine to report progress on low end devices - var progress uint32 + var progress atomic.Uint32 done := make(chan struct{}) defer close(done) @@ -174,7 +174,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { case <-done: return case <-time.After(3 * time.Second): - logger.Info("Generating ethash verification cache", "percentage", atomic.LoadUint32(&progress)*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start))) + logger.Info("Generating ethash verification cache", "percentage", progress.Load()*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start))) } } }() @@ -185,7 +185,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { keccak512(cache, seed) for offset := uint64(hashBytes); offset < size; offset += hashBytes { keccak512(cache[offset:], cache[offset-hashBytes:offset]) - atomic.AddUint32(&progress, 1) + progress.Add(1) } // Use a low-round version of randmemohash temp := make([]byte, hashBytes) @@ -200,7 +200,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { bitutil.XORBytes(temp, cache[srcOff:srcOff+hashBytes], cache[xorOff:xorOff+hashBytes]) keccak512(cache[dstOff:], temp) - atomic.AddUint32(&progress, 1) + progress.Add(1) } } // Swap the byte order on big endian systems and return @@ -299,7 +299,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) { var pend sync.WaitGroup pend.Add(threads) - var progress uint64 + var progress atomic.Uint64 for i := 0; i < threads; i++ { go func(id int) { defer pend.Done() @@ -323,7 +323,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) { } copy(dataset[index*hashBytes:], item) - if status := atomic.AddUint64(&progress, 1); status%percent == 0 { + if status := progress.Add(1); status%percent == 0 { logger.Info("Generating DAG in progress", "percentage", (status*100)/(size/hashBytes), "elapsed", common.PrettyDuration(time.Since(start))) } } diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 6cb312482795..462f10956432 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -308,12 +308,12 @@ func (c *cache) finalizer() { // dataset wraps an ethash dataset with some metadata to allow easier concurrent use. type dataset struct { - epoch uint64 // Epoch for which this cache is relevant - dump *os.File // File descriptor of the memory mapped cache - mmap mmap.MMap // Memory map itself to unmap before releasing - dataset []uint32 // The actual cache data content - once sync.Once // Ensures the cache is generated only once - done uint32 // Atomic flag to determine generation status + epoch uint64 // Epoch for which this cache is relevant + dump *os.File // File descriptor of the memory mapped cache + mmap mmap.MMap // Memory map itself to unmap before releasing + dataset []uint32 // The actual cache data content + once sync.Once // Ensures the cache is generated only once + done atomic.Bool // Atomic flag to determine generation status } // newDataset creates a new ethash mining dataset and returns it as a plain Go @@ -326,7 +326,7 @@ func newDataset(epoch uint64) *dataset { func (d *dataset) generate(dir string, limit int, lock bool, test bool) { d.once.Do(func() { // Mark the dataset generated after we're done. This is needed for remote - defer atomic.StoreUint32(&d.done, 1) + defer d.done.Store(true) csize := cacheSize(d.epoch*epochLength + 1) dsize := datasetSize(d.epoch*epochLength + 1) @@ -390,7 +390,7 @@ func (d *dataset) generate(dir string, limit int, lock bool, test bool) { // or not (it may not have been started at all). This is useful for remote miners // to default to verification caches instead of blocking on DAG generations. func (d *dataset) generated() bool { - return atomic.LoadUint32(&d.done) == 1 + return d.done.Load() } // finalizer closes any file handlers and memory maps open. From 2b0a34bea6a61efe17b8cb860362547ba235e84b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 19 Apr 2023 06:46:56 -0400 Subject: [PATCH 708/715] cmd/devp2p: make crawler-route53-updater less verbose (#27116) Follow-up to #26697, makes the crawler less verbose on route53-based scenarios. It also changes the loglevel from debug to info on Updates, which are typically the root, and can be interesting to see. --- cmd/devp2p/dns_cloudflare.go | 2 +- cmd/devp2p/dns_route53.go | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/cmd/devp2p/dns_cloudflare.go b/cmd/devp2p/dns_cloudflare.go index bfe92257ee5a..798fdc733245 100644 --- a/cmd/devp2p/dns_cloudflare.go +++ b/cmd/devp2p/dns_cloudflare.go @@ -144,7 +144,7 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string) _, err = c.CreateDNSRecord(context.Background(), c.zoneID, record) } else if old.Content != val { // Entry already exists, only change its content. - log.Debug(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val)) + log.Info(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val)) updated++ old.Content = val err = c.UpdateDNSRecord(context.Background(), c.zoneID, old.ID, old) diff --git a/cmd/devp2p/dns_route53.go b/cmd/devp2p/dns_route53.go index 81734eb2ad87..400ab1b1cf05 100644 --- a/cmd/devp2p/dns_route53.go +++ b/cmd/devp2p/dns_route53.go @@ -221,7 +221,13 @@ func (c *route53Client) computeChanges(name string, records map[string]string, e } records = lrecords - var changes []types.Change + var ( + changes []types.Change + inserts int + upserts int + skips int + ) + for path, newValue := range records { prevRecords, exists := existing[path] prevValue := strings.Join(prevRecords.values, "") @@ -237,20 +243,30 @@ func (c *route53Client) computeChanges(name string, records map[string]string, e if !exists { // Entry is unknown, push a new one - log.Info(fmt.Sprintf("Creating %s = %s", path, newValue)) + log.Debug(fmt.Sprintf("Creating %s = %s", path, newValue)) changes = append(changes, newTXTChange("CREATE", path, ttl, newValue)) + inserts++ } else if prevValue != newValue || prevRecords.ttl != ttl { // Entry already exists, only change its content. log.Info(fmt.Sprintf("Updating %s from %s to %s", path, prevValue, newValue)) changes = append(changes, newTXTChange("UPSERT", path, ttl, newValue)) + upserts++ } else { log.Debug(fmt.Sprintf("Skipping %s = %s", path, newValue)) + skips++ } } // Iterate over the old records and delete anything stale. - changes = append(changes, makeDeletionChanges(existing, records)...) - + deletions := makeDeletionChanges(existing, records) + changes = append(changes, deletions...) + + log.Info("Computed DNS changes", + "changes", len(changes), + "inserts", inserts, + "skips", skips, + "deleted", len(deletions), + "upserts", upserts) // Ensure changes are in the correct order. sortChanges(changes) return changes @@ -263,7 +279,7 @@ func makeDeletionChanges(records map[string]recordSet, keep map[string]string) [ if _, ok := keep[path]; ok { continue } - log.Info(fmt.Sprintf("Deleting %s = %s", path, strings.Join(set.values, ""))) + log.Debug(fmt.Sprintf("Deleting %s = %s", path, strings.Join(set.values, ""))) changes = append(changes, newTXTChange("DELETE", path, set.ttl, set.values...)) } return changes From f2df2b1981fa1e014e4cb34cf9a8dd7b8519e0ac Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Wed, 19 Apr 2023 21:18:02 +1000 Subject: [PATCH 709/715] cmd/geth: rename --vmodule to --log.vmodule (#27071) renames `--vmodule` to `--log.vmodule`, and prints a warning if the old form is used. --- internal/debug/flags.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 3c8b569b4f38..d425a17db42b 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -45,10 +45,17 @@ var ( Value: 3, Category: flags.LoggingCategory, } + logVmoduleFlag = &cli.StringFlag{ + Name: "log.vmodule", + Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)", + Value: "", + Category: flags.LoggingCategory, + } vmoduleFlag = &cli.StringFlag{ Name: "vmodule", Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)", Value: "", + Hidden: true, Category: flags.LoggingCategory, } logjsonFlag = &cli.BoolFlag{ @@ -149,6 +156,7 @@ var ( // Flags holds all command-line flags required for debugging. var Flags = []cli.Flag{ verbosityFlag, + logVmoduleFlag, vmoduleFlag, backtraceAtFlag, debugFlag, @@ -252,7 +260,14 @@ func Setup(ctx *cli.Context) error { // logging verbosity := ctx.Int(verbosityFlag.Name) glogger.Verbosity(log.Lvl(verbosity)) - vmodule := ctx.String(vmoduleFlag.Name) + vmodule := ctx.String(logVmoduleFlag.Name) + if vmodule == "" { + // Retain backwards compatibility with `--vmodule` flag if `--log.vmodule` not set + vmodule = ctx.String(vmoduleFlag.Name) + if vmodule != "" { + defer log.Warn("The flag '--vmodule' is deprecated, please use '--log.vmodule' instead") + } + } glogger.Vmodule(vmodule) debug := ctx.Bool(debugFlag.Name) From 3f7afc3f573abdb1469d7afcbf9028cfe328d66d Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 20 Apr 2023 08:52:00 +0200 Subject: [PATCH 710/715] core/vm: order opcodes properly (#27113) --- core/vm/opcodes.go | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 9f199eb8f60a..910491c60078 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -204,6 +204,12 @@ const ( LOG4 ) +// 0xb0 range. +const ( + TLOAD OpCode = 0xb3 + TSTORE OpCode = 0xb4 +) + // 0xf0 range - closures. const ( CREATE OpCode = 0xf0 @@ -219,12 +225,6 @@ const ( SELFDESTRUCT OpCode = 0xff ) -// 0xb0 range. -const ( - TLOAD OpCode = 0xb3 - TSTORE OpCode = 0xb4 -) - // Since the opcodes aren't all in order we can't use a regular slice. var opCodeToString = map[OpCode]string{ // 0x0 range - arithmetic ops. @@ -290,9 +290,7 @@ var opCodeToString = map[OpCode]string{ BASEFEE: "BASEFEE", // 0x50 range - 'storage' and execution. - POP: "POP", - //DUP: "DUP", - //SWAP: "SWAP", + POP: "POP", MLOAD: "MLOAD", MSTORE: "MSTORE", MSTORE8: "MSTORE8", @@ -306,7 +304,7 @@ var opCodeToString = map[OpCode]string{ JUMPDEST: "JUMPDEST", PUSH0: "PUSH0", - // 0x60 range - push. + // 0x60 range - pushes. PUSH1: "PUSH1", PUSH2: "PUSH2", PUSH3: "PUSH3", @@ -340,6 +338,7 @@ var opCodeToString = map[OpCode]string{ PUSH31: "PUSH31", PUSH32: "PUSH32", + // 0x80 - dups. DUP1: "DUP1", DUP2: "DUP2", DUP3: "DUP3", @@ -357,6 +356,7 @@ var opCodeToString = map[OpCode]string{ DUP15: "DUP15", DUP16: "DUP16", + // 0x90 - swaps. SWAP1: "SWAP1", SWAP2: "SWAP2", SWAP3: "SWAP3", @@ -373,17 +373,19 @@ var opCodeToString = map[OpCode]string{ SWAP14: "SWAP14", SWAP15: "SWAP15", SWAP16: "SWAP16", - LOG0: "LOG0", - LOG1: "LOG1", - LOG2: "LOG2", - LOG3: "LOG3", - LOG4: "LOG4", + + // 0xa0 range - logging ops. + LOG0: "LOG0", + LOG1: "LOG1", + LOG2: "LOG2", + LOG3: "LOG3", + LOG4: "LOG4", // 0xb0 range. TLOAD: "TLOAD", TSTORE: "TSTORE", - // 0xf0 range. + // 0xf0 range - closures. CREATE: "CREATE", CALL: "CALL", RETURN: "RETURN", @@ -473,8 +475,6 @@ var stringToOp = map[string]OpCode{ "GAS": GAS, "JUMPDEST": JUMPDEST, "PUSH0": PUSH0, - "TLOAD": TLOAD, - "TSTORE": TSTORE, "PUSH1": PUSH1, "PUSH2": PUSH2, "PUSH3": PUSH3, @@ -544,6 +544,8 @@ var stringToOp = map[string]OpCode{ "LOG2": LOG2, "LOG3": LOG3, "LOG4": LOG4, + "TLOAD": TLOAD, + "TSTORE": TSTORE, "CREATE": CREATE, "CREATE2": CREATE2, "CALL": CALL, From ae93e0b484fa9345a3a9eb2a5f1ced9d450d2b52 Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Thu, 20 Apr 2023 15:36:54 +0800 Subject: [PATCH 711/715] metrics: use atomic type (#27121) --- metrics/counter.go | 14 +++++++------- metrics/ewma.go | 8 ++++---- metrics/gauge.go | 12 ++++++------ metrics/meter.go | 25 ++++++++++++++----------- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/metrics/counter.go b/metrics/counter.go index 2f78c90d5c64..55e1c59540f6 100644 --- a/metrics/counter.go +++ b/metrics/counter.go @@ -38,13 +38,13 @@ func NewCounter() Counter { if !Enabled { return NilCounter{} } - return &StandardCounter{0} + return &StandardCounter{} } // NewCounterForced constructs a new StandardCounter and returns it no matter if // the global switch is enabled or not. func NewCounterForced() Counter { - return &StandardCounter{0} + return &StandardCounter{} } // NewRegisteredCounter constructs and registers a new StandardCounter. @@ -115,27 +115,27 @@ func (NilCounter) Snapshot() Counter { return NilCounter{} } // StandardCounter is the standard implementation of a Counter and uses the // sync/atomic package to manage a single int64 value. type StandardCounter struct { - count int64 + count atomic.Int64 } // Clear sets the counter to zero. func (c *StandardCounter) Clear() { - atomic.StoreInt64(&c.count, 0) + c.count.Store(0) } // Count returns the current count. func (c *StandardCounter) Count() int64 { - return atomic.LoadInt64(&c.count) + return c.count.Load() } // Dec decrements the counter by the given amount. func (c *StandardCounter) Dec(i int64) { - atomic.AddInt64(&c.count, -i) + c.count.Add(-i) } // Inc increments the counter by the given amount. func (c *StandardCounter) Inc(i int64) { - atomic.AddInt64(&c.count, i) + c.count.Add(i) } // Snapshot returns a read-only copy of the counter. diff --git a/metrics/ewma.go b/metrics/ewma.go index 039286493ebc..ed95cba19b4f 100644 --- a/metrics/ewma.go +++ b/metrics/ewma.go @@ -75,7 +75,7 @@ func (NilEWMA) Update(n int64) {} // of uncounted events and processes them on each tick. It uses the // sync/atomic package to manage uncounted events. type StandardEWMA struct { - uncounted int64 // /!\ this should be the first member to ensure 64-bit alignment + uncounted atomic.Int64 alpha float64 rate float64 init bool @@ -97,8 +97,8 @@ func (a *StandardEWMA) Snapshot() EWMA { // Tick ticks the clock to update the moving average. It assumes it is called // every five seconds. func (a *StandardEWMA) Tick() { - count := atomic.LoadInt64(&a.uncounted) - atomic.AddInt64(&a.uncounted, -count) + count := a.uncounted.Load() + a.uncounted.Add(-count) instantRate := float64(count) / float64(5*time.Second) a.mutex.Lock() defer a.mutex.Unlock() @@ -112,5 +112,5 @@ func (a *StandardEWMA) Tick() { // Update adds n uncounted events. func (a *StandardEWMA) Update(n int64) { - atomic.AddInt64(&a.uncounted, n) + a.uncounted.Add(n) } diff --git a/metrics/gauge.go b/metrics/gauge.go index b6b2758b0d13..81137d7f7c5e 100644 --- a/metrics/gauge.go +++ b/metrics/gauge.go @@ -25,7 +25,7 @@ func NewGauge() Gauge { if !Enabled { return NilGauge{} } - return &StandardGauge{0} + return &StandardGauge{} } // NewRegisteredGauge constructs and registers a new StandardGauge. @@ -101,7 +101,7 @@ func (NilGauge) Value() int64 { return 0 } // StandardGauge is the standard implementation of a Gauge and uses the // sync/atomic package to manage a single int64 value. type StandardGauge struct { - value int64 + value atomic.Int64 } // Snapshot returns a read-only copy of the gauge. @@ -111,22 +111,22 @@ func (g *StandardGauge) Snapshot() Gauge { // Update updates the gauge's value. func (g *StandardGauge) Update(v int64) { - atomic.StoreInt64(&g.value, v) + g.value.Store(v) } // Value returns the gauge's current value. func (g *StandardGauge) Value() int64 { - return atomic.LoadInt64(&g.value) + return g.value.Load() } // Dec decrements the gauge's current value by the given amount. func (g *StandardGauge) Dec(i int64) { - atomic.AddInt64(&g.value, -i) + g.value.Add(-i) } // Inc increments the gauge's current value by the given amount. func (g *StandardGauge) Inc(i int64) { - atomic.AddInt64(&g.value, i) + g.value.Add(i) } // FunctionalGauge returns value from given function diff --git a/metrics/meter.go b/metrics/meter.go index 60ae919d04db..e8564d6a5e76 100644 --- a/metrics/meter.go +++ b/metrics/meter.go @@ -101,11 +101,7 @@ func NewRegisteredMeterForced(name string, r Registry) Meter { // MeterSnapshot is a read-only copy of another Meter. type MeterSnapshot struct { - // WARNING: The `temp` field is accessed atomically. - // On 32 bit platforms, only 64-bit aligned fields can be atomic. The struct is - // guaranteed to be so aligned, so take advantage of that. For more information, - // see https://golang.org/pkg/sync/atomic/#pkg-note-BUG. - temp int64 + temp atomic.Int64 count int64 rate1, rate5, rate15, rateMean float64 } @@ -173,7 +169,7 @@ type StandardMeter struct { snapshot *MeterSnapshot a1, a5, a15 EWMA startTime time.Time - stopped uint32 + stopped atomic.Bool } func newStandardMeter() *StandardMeter { @@ -188,8 +184,8 @@ func newStandardMeter() *StandardMeter { // Stop stops the meter, Mark() will be a no-op if you use it after being stopped. func (m *StandardMeter) Stop() { - stopped := atomic.SwapUint32(&m.stopped, 1) - if stopped != 1 { + stopped := m.stopped.Swap(true) + if !stopped { arbiter.Lock() delete(arbiter.meters, m) arbiter.Unlock() @@ -207,7 +203,7 @@ func (m *StandardMeter) Count() int64 { // Mark records the occurrence of n events. func (m *StandardMeter) Mark(n int64) { - atomic.AddInt64(&m.snapshot.temp, n) + m.snapshot.temp.Add(n) } // Rate1 returns the one-minute moving average rate of events per second. @@ -241,7 +237,14 @@ func (m *StandardMeter) RateMean() float64 { // Snapshot returns a read-only copy of the meter. func (m *StandardMeter) Snapshot() Meter { m.lock.RLock() - snapshot := *m.snapshot + snapshot := MeterSnapshot{ + count: m.snapshot.count, + rate1: m.snapshot.rate1, + rate5: m.snapshot.rate5, + rate15: m.snapshot.rate15, + rateMean: m.snapshot.rateMean, + } + snapshot.temp.Store(m.snapshot.temp.Load()) m.lock.RUnlock() return &snapshot } @@ -257,7 +260,7 @@ func (m *StandardMeter) updateSnapshot() { func (m *StandardMeter) updateMeter() { // should only run with write lock held on m.lock - n := atomic.SwapInt64(&m.snapshot.temp, 0) + n := m.snapshot.temp.Swap(0) m.snapshot.count += n m.a1.Update(n) m.a5.Update(n) From 99f81d27248f13a8e43731a0a1294044ced5d675 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 20 Apr 2023 18:57:24 +0800 Subject: [PATCH 712/715] all: refactor trie API (#26995) In this PR, all TryXXX(e.g. TryGet) APIs of trie are renamed to XXX(e.g. Get) with an error returned. The original XXX(e.g. Get) APIs are renamed to MustXXX(e.g. MustGet) and does not return any error -- they print a log output. A future PR will change the behaviour to panic on errorrs. --- core/rawdb/accessors_indexes_test.go | 3 +- core/state/snapshot/conversion.go | 2 +- core/state/snapshot/generate.go | 2 +- core/state/snapshot/generate_test.go | 14 +-- core/state/sync_test.go | 6 +- core/types/block_test.go | 3 +- core/types/hashing.go | 5 +- core/types/hashing_test.go | 3 +- eth/protocols/snap/sync_test.go | 20 ++-- les/server_handler.go | 2 +- light/postprocess.go | 12 ++- light/trie.go | 12 +-- tests/fuzzers/les/les-fuzzer.go | 4 +- tests/fuzzers/rangeproof/rangeproof-fuzzer.go | 6 +- tests/fuzzers/stacktrie/trie_fuzzer.go | 6 +- tests/fuzzers/trie/trie-fuzzer.go | 8 +- trie/errors.go | 2 +- trie/iterator_test.go | 26 ++--- trie/proof.go | 4 +- trie/proof_test.go | 20 ++-- trie/secure_trie.go | 54 ++++++----- trie/secure_trie_test.go | 20 ++-- trie/stacktrie.go | 10 +- trie/stacktrie_test.go | 30 +++--- trie/sync_test.go | 8 +- trie/tracer_test.go | 24 ++--- trie/trie.go | 97 +++++++++++-------- trie/trie_test.go | 82 ++++++++-------- 28 files changed, 256 insertions(+), 229 deletions(-) diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index 4734e986e272..c5447b16d2bd 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -45,9 +45,10 @@ func (h *testHasher) Reset() { h.hasher.Reset() } -func (h *testHasher) Update(key, val []byte) { +func (h *testHasher) Update(key, val []byte) error { h.hasher.Write(key) h.hasher.Write(val) + return nil } func (h *testHasher) Hash() common.Hash { diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index ed7cb963ad0f..0e583e6269ba 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -371,7 +371,7 @@ func stackTrieGenerate(db ethdb.KeyValueWriter, scheme string, owner common.Hash } t := trie.NewStackTrieWithOwner(nodeWriter, owner) for leaf := range in { - t.TryUpdate(leaf.key[:], leaf.value) + t.Update(leaf.key[:], leaf.value) } var root common.Hash if db == nil { diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index d46705d31e3f..68c2f574b873 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -230,7 +230,7 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, trieId *trie.ID, prefix [ if origin == nil && !diskMore { stackTr := trie.NewStackTrie(nil) for i, key := range keys { - stackTr.TryUpdate(key, vals[i]) + stackTr.Update(key, vals[i]) } if gotRoot := stackTr.Hash(); gotRoot != root { return &proofResult{ diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 1bac4fd5604c..546132e7dd80 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -161,7 +161,7 @@ func newHelper() *testHelper { func (t *testHelper) addTrieAccount(acckey string, acc *Account) { val, _ := rlp.EncodeToBytes(acc) - t.accTrie.Update([]byte(acckey), val) + t.accTrie.MustUpdate([]byte(acckey), val) } func (t *testHelper) addSnapAccount(acckey string, acc *Account) { @@ -186,7 +186,7 @@ func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string id := trie.StorageTrieID(stateRoot, owner, common.Hash{}) stTrie, _ := trie.NewStateTrie(id, t.triedb) for i, k := range keys { - stTrie.Update([]byte(k), []byte(vals[i])) + stTrie.MustUpdate([]byte(k), []byte(vals[i])) } if !commit { return stTrie.Hash().Bytes() @@ -491,7 +491,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) { ) acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) - helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e // Identical in the snap key := hashData([]byte("acc-1")) @@ -562,7 +562,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) { ) acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) - helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e + helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e // Identical in the snap key := hashData([]byte("acc-1")) @@ -613,8 +613,8 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) { { acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) - helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val) - helper.accTrie.Update(common.HexToHash("0x07").Bytes(), val) + helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val) + helper.accTrie.MustUpdate(common.HexToHash("0x07").Bytes(), val) rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x01"), val) rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x02"), val) @@ -650,7 +650,7 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) { { acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) - helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val) + helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val) junk := make([]byte, 100) copy(junk, []byte{0xde, 0xad}) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index aff91268aafd..090d55e473f9 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -213,14 +213,14 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { for i, node := range nodeElements { if bypath { if len(node.syncPath) == 1 { - data, _, err := srcTrie.TryGetNode(node.syncPath[0]) + data, _, err := srcTrie.GetNode(node.syncPath[0]) if err != nil { t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[0], err) } nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} } else { var acc types.StateAccount - if err := rlp.DecodeBytes(srcTrie.Get(node.syncPath[0]), &acc); err != nil { + if err := rlp.DecodeBytes(srcTrie.MustGet(node.syncPath[0]), &acc); err != nil { t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err) } id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root) @@ -228,7 +228,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { if err != nil { t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err) } - data, _, err := stTrie.TryGetNode(node.syncPath[1]) + data, _, err := stTrie.GetNode(node.syncPath[1]) if err != nil { t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[1], err) } diff --git a/core/types/block_test.go b/core/types/block_test.go index 49197c923764..966015eb015d 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -232,9 +232,10 @@ func (h *testHasher) Reset() { h.hasher.Reset() } -func (h *testHasher) Update(key, val []byte) { +func (h *testHasher) Update(key, val []byte) error { h.hasher.Write(key) h.hasher.Write(val) + return nil } func (h *testHasher) Hash() common.Hash { diff --git a/core/types/hashing.go b/core/types/hashing.go index 71295c107cf8..fbdeaf0d0793 100644 --- a/core/types/hashing.go +++ b/core/types/hashing.go @@ -62,7 +62,7 @@ func prefixedRlpHash(prefix byte, x interface{}) (h common.Hash) { // This is internal, do not use. type TrieHasher interface { Reset() - Update([]byte, []byte) + Update([]byte, []byte) error Hash() common.Hash } @@ -93,6 +93,9 @@ func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash { // StackTrie requires values to be inserted in increasing hash order, which is not the // order that `list` provides hashes in. This insertion sequence ensures that the // order is correct. + // + // The error returned by hasher is omitted because hasher will produce an incorrect + // hash in case any error occurs. var indexBuf []byte for i := 1; i < list.Len() && i <= 0x7f; i++ { indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i)) diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index 294a3977d03b..c5b9f690d801 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -219,9 +219,10 @@ func (d *hashToHumanReadable) Reset() { d.data = make([]byte, 0) } -func (d *hashToHumanReadable) Update(i []byte, i2 []byte) { +func (d *hashToHumanReadable) Update(i []byte, i2 []byte) error { l := fmt.Sprintf("%x %x\n", i, i2) d.data = append(d.data, []byte(l)...) + return nil } func (d *hashToHumanReadable) Hash() common.Hash { diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 0a6117972953..6a3b482d5d20 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -216,7 +216,7 @@ func defaultTrieRequestHandler(t *testPeer, requestId uint64, root common.Hash, for _, pathset := range paths { switch len(pathset) { case 1: - blob, _, err := t.accountTrie.TryGetNode(pathset[0]) + blob, _, err := t.accountTrie.GetNode(pathset[0]) if err != nil { t.logger.Info("Error handling req", "error", err) break @@ -225,7 +225,7 @@ func defaultTrieRequestHandler(t *testPeer, requestId uint64, root common.Hash, default: account := t.storageTries[(common.BytesToHash(pathset[0]))] for _, path := range pathset[1:] { - blob, _, err := account.TryGetNode(path) + blob, _, err := account.GetNode(path) if err != nil { t.logger.Info("Error handling req", "error", err) break @@ -1381,7 +1381,7 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) { }) key := key32(i) elem := &kv{key, value} - accTrie.Update(elem.k, elem.v) + accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } sort.Sort(entries) @@ -1431,7 +1431,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { CodeHash: getCodeHash(uint64(i)), }) elem := &kv{boundaries[i].Bytes(), value} - accTrie.Update(elem.k, elem.v) + accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } // Fill other accounts if required @@ -1443,7 +1443,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { CodeHash: getCodeHash(i), }) elem := &kv{key32(i), value} - accTrie.Update(elem.k, elem.v) + accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } sort.Sort(entries) @@ -1487,7 +1487,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) CodeHash: codehash, }) elem := &kv{key, value} - accTrie.Update(elem.k, elem.v) + accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) storageRoots[common.BytesToHash(key)] = stRoot @@ -1551,7 +1551,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin CodeHash: codehash, }) elem := &kv{key, value} - accTrie.Update(elem.k, elem.v) + accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) // we reuse the same one for all accounts @@ -1599,7 +1599,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas key := crypto.Keccak256Hash(slotKey[:]) elem := &kv{key[:], rlpSlotValue} - trie.Update(elem.k, elem.v) + trie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } sort.Sort(entries) @@ -1638,7 +1638,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo val := []byte{0xde, 0xad, 0xbe, 0xef} elem := &kv{key[:], val} - trie.Update(elem.k, elem.v) + trie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } // Fill other slots if required @@ -1650,7 +1650,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo rlpSlotValue, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(slotValue[:])) elem := &kv{key[:], rlpSlotValue} - trie.Update(elem.k, elem.v) + trie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } sort.Sort(entries) diff --git a/les/server_handler.go b/les/server_handler.go index 2ea496ac2c3a..39c7ace1c906 100644 --- a/les/server_handler.go +++ b/les/server_handler.go @@ -364,7 +364,7 @@ func getAccount(triedb *trie.Database, root, hash common.Hash) (types.StateAccou if err != nil { return types.StateAccount{}, err } - blob, err := trie.TryGet(hash[:]) + blob, err := trie.Get(hash[:]) if err != nil { return types.StateAccount{}, err } diff --git a/light/postprocess.go b/light/postprocess.go index e800a1f0f7f0..763ba27529ce 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -206,8 +206,7 @@ func (c *ChtIndexerBackend) Process(ctx context.Context, header *types.Header) e var encNumber [8]byte binary.BigEndian.PutUint64(encNumber[:], num) data, _ := rlp.EncodeToBytes(ChtNode{hash, td}) - c.trie.Update(encNumber[:], data) - return nil + return c.trie.Update(encNumber[:], data) } // Commit implements core.ChainIndexerBackend @@ -450,10 +449,15 @@ func (b *BloomTrieIndexerBackend) Commit() error { decompSize += uint64(len(decomp)) compSize += uint64(len(comp)) + + var terr error if len(comp) > 0 { - b.trie.Update(encKey[:], comp) + terr = b.trie.Update(encKey[:], comp) } else { - b.trie.Delete(encKey[:]) + terr = b.trie.Delete(encKey[:]) + } + if terr != nil { + return terr } } root, nodes := b.trie.Commit(false) diff --git a/light/trie.go b/light/trie.go index 2f8f71c61e9a..38dd6b5c27dc 100644 --- a/light/trie.go +++ b/light/trie.go @@ -109,7 +109,7 @@ func (t *odrTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { key = crypto.Keccak256(key) var res []byte err := t.do(key, func() (err error) { - res, err = t.trie.TryGet(key) + res, err = t.trie.Get(key) return err }) return res, err @@ -119,7 +119,7 @@ func (t *odrTrie) GetAccount(address common.Address) (*types.StateAccount, error var res types.StateAccount key := crypto.Keccak256(address.Bytes()) err := t.do(key, func() (err error) { - value, err := t.trie.TryGet(key) + value, err := t.trie.Get(key) if err != nil { return err } @@ -138,21 +138,21 @@ func (t *odrTrie) UpdateAccount(address common.Address, acc *types.StateAccount) return fmt.Errorf("decoding error in account update: %w", err) } return t.do(key, func() error { - return t.trie.TryUpdate(key, value) + return t.trie.Update(key, value) }) } func (t *odrTrie) UpdateStorage(_ common.Address, key, value []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { - return t.trie.TryUpdate(key, value) + return t.trie.Update(key, value) }) } func (t *odrTrie) DeleteStorage(_ common.Address, key []byte) error { key = crypto.Keccak256(key) return t.do(key, func() error { - return t.trie.TryDelete(key) + return t.trie.Delete(key) }) } @@ -160,7 +160,7 @@ func (t *odrTrie) DeleteStorage(_ common.Address, key []byte) error { func (t *odrTrie) DeleteAccount(address common.Address) error { key := crypto.Keccak256(address.Bytes()) return t.do(key, func() error { - return t.trie.TryDelete(key) + return t.trie.Delete(key) }) } diff --git a/tests/fuzzers/les/les-fuzzer.go b/tests/fuzzers/les/les-fuzzer.go index 924a749e5832..926de0458572 100644 --- a/tests/fuzzers/les/les-fuzzer.go +++ b/tests/fuzzers/les/les-fuzzer.go @@ -93,13 +93,13 @@ func makeTries() (chtTrie *trie.Trie, bloomTrie *trie.Trie, chtKeys, bloomKeys [ // The element in CHT is -> key := make([]byte, 8) binary.BigEndian.PutUint64(key, uint64(i+1)) - chtTrie.Update(key, []byte{0x1, 0xf}) + chtTrie.MustUpdate(key, []byte{0x1, 0xf}) chtKeys = append(chtKeys, key) // The element in Bloom trie is <2 byte bit index> + -> bloom key2 := make([]byte, 10) binary.BigEndian.PutUint64(key2[2:], uint64(i+1)) - bloomTrie.Update(key2, []byte{0x2, 0xe}) + bloomTrie.MustUpdate(key2, []byte{0x2, 0xe}) bloomKeys = append(bloomKeys, key2) } return diff --git a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go index bca93bbe19c7..2881c7a7c211 100644 --- a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go +++ b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go @@ -69,8 +69,8 @@ func (f *fuzzer) randomTrie(n int) (*trie.Trie, map[string]*kv) { for i := byte(0); i < byte(size); i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false} - trie.Update(value.k, value.v) - trie.Update(value2.k, value2.v) + trie.MustUpdate(value.k, value.v) + trie.MustUpdate(value2.k, value2.v) vals[string(value.k)] = value vals[string(value2.k)] = value2 } @@ -82,7 +82,7 @@ func (f *fuzzer) randomTrie(n int) (*trie.Trie, map[string]*kv) { k := f.randBytes(32) v := f.randBytes(20) value := &kv{k, v, false} - trie.Update(k, v) + trie.MustUpdate(k, v) vals[string(k)] = value if f.exhausted { return nil, nil diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index 435aa3a47cf8..809dba8ce593 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -175,7 +175,7 @@ func (f *fuzzer) fuzz() int { } keys[string(k)] = struct{}{} vals = append(vals, kv{k: k, v: v}) - trieA.Update(k, v) + trieA.MustUpdate(k, v) useful = true } if !useful { @@ -195,7 +195,7 @@ func (f *fuzzer) fuzz() int { if f.debugging { fmt.Printf("{\"%#x\" , \"%#x\"} // stacktrie.Update\n", kv.k, kv.v) } - trieB.Update(kv.k, kv.v) + trieB.MustUpdate(kv.k, kv.v) } rootB := trieB.Hash() trieB.Commit() @@ -223,7 +223,7 @@ func (f *fuzzer) fuzz() int { checked int ) for _, kv := range vals { - trieC.Update(kv.k, kv.v) + trieC.MustUpdate(kv.k, kv.v) } rootC, _ := trieC.Commit() if rootA != rootC { diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index 40dec76b8f84..c0cbceff31ff 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -147,13 +147,13 @@ func runRandTest(rt randTest) error { for i, step := range rt { switch step.op { case opUpdate: - tr.Update(step.key, step.value) + tr.MustUpdate(step.key, step.value) values[string(step.key)] = string(step.value) case opDelete: - tr.Delete(step.key) + tr.MustDelete(step.key) delete(values, string(step.key)) case opGet: - v := tr.Get(step.key) + v := tr.MustGet(step.key) want := values[string(step.key)] if string(v) != want { rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) @@ -176,7 +176,7 @@ func runRandTest(rt randTest) error { checktr := trie.NewEmpty(triedb) it := trie.NewIterator(tr.NodeIterator(nil)) for it.Next() { - checktr.Update(it.Key, it.Value) + checktr.MustUpdate(it.Key, it.Value) } if tr.Hash() != checktr.Hash() { return fmt.Errorf("hash mismatch in opItercheckhash") diff --git a/trie/errors.go b/trie/errors.go index afe344bed269..bd82b950aad2 100644 --- a/trie/errors.go +++ b/trie/errors.go @@ -22,7 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// MissingNodeError is returned by the trie functions (TryGet, TryUpdate, TryDelete) +// MissingNodeError is returned by the trie functions (Get, Update, Delete) // in the case where a trie node is not present in the local database. It contains // information necessary for retrieving the missing node. type MissingNodeError struct { diff --git a/trie/iterator_test.go b/trie/iterator_test.go index ac2a3d2a4c40..6dc38db6f1ac 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -58,7 +58,7 @@ func TestIterator(t *testing.T) { all := make(map[string]string) for _, val := range vals { all[val.k] = val.v - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -89,8 +89,8 @@ func TestIteratorLargeData(t *testing.T) { for i := byte(0); i < 255; i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} - trie.Update(value.k, value.v) - trie.Update(value2.k, value2.v) + trie.MustUpdate(value.k, value.v) + trie.MustUpdate(value2.k, value2.v) vals[string(value.k)] = value vals[string(value2.k)] = value2 } @@ -178,7 +178,7 @@ var testdata2 = []kvs{ func TestIteratorSeek(t *testing.T) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range testdata1 { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } // Seek to the middle. @@ -220,7 +220,7 @@ func TestDifferenceIterator(t *testing.T) { dba := NewDatabase(rawdb.NewMemoryDatabase()) triea := NewEmpty(dba) for _, val := range testdata1 { - triea.Update([]byte(val.k), []byte(val.v)) + triea.MustUpdate([]byte(val.k), []byte(val.v)) } rootA, nodesA := triea.Commit(false) dba.Update(NewWithNodeSet(nodesA)) @@ -229,7 +229,7 @@ func TestDifferenceIterator(t *testing.T) { dbb := NewDatabase(rawdb.NewMemoryDatabase()) trieb := NewEmpty(dbb) for _, val := range testdata2 { - trieb.Update([]byte(val.k), []byte(val.v)) + trieb.MustUpdate([]byte(val.k), []byte(val.v)) } rootB, nodesB := trieb.Commit(false) dbb.Update(NewWithNodeSet(nodesB)) @@ -262,7 +262,7 @@ func TestUnionIterator(t *testing.T) { dba := NewDatabase(rawdb.NewMemoryDatabase()) triea := NewEmpty(dba) for _, val := range testdata1 { - triea.Update([]byte(val.k), []byte(val.v)) + triea.MustUpdate([]byte(val.k), []byte(val.v)) } rootA, nodesA := triea.Commit(false) dba.Update(NewWithNodeSet(nodesA)) @@ -271,7 +271,7 @@ func TestUnionIterator(t *testing.T) { dbb := NewDatabase(rawdb.NewMemoryDatabase()) trieb := NewEmpty(dbb) for _, val := range testdata2 { - trieb.Update([]byte(val.k), []byte(val.v)) + trieb.MustUpdate([]byte(val.k), []byte(val.v)) } rootB, nodesB := trieb.Commit(false) dbb.Update(NewWithNodeSet(nodesB)) @@ -314,7 +314,7 @@ func TestUnionIterator(t *testing.T) { func TestIteratorNoDups(t *testing.T) { tr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range testdata1 { - tr.Update([]byte(val.k), []byte(val.v)) + tr.MustUpdate([]byte(val.k), []byte(val.v)) } checkIteratorNoDups(t, tr.NodeIterator(nil), nil) } @@ -329,7 +329,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) { tr := NewEmpty(triedb) for _, val := range testdata1 { - tr.Update([]byte(val.k), []byte(val.v)) + tr.MustUpdate([]byte(val.k), []byte(val.v)) } _, nodes := tr.Commit(false) triedb.Update(NewWithNodeSet(nodes)) @@ -421,7 +421,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) { ctr := NewEmpty(triedb) for _, val := range testdata1 { - ctr.Update([]byte(val.k), []byte(val.v)) + ctr.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := ctr.Commit(false) triedb.Update(NewWithNodeSet(nodes)) @@ -540,7 +540,7 @@ func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) { binary.BigEndian.PutUint64(val, uint64(i)) key = crypto.Keccak256(key) val = crypto.Keccak256(val) - trie.Update(key, val) + trie.MustUpdate(key, val) } _, nodes := trie.Commit(false) triedb.Update(NewWithNodeSet(nodes)) @@ -580,7 +580,7 @@ func TestIteratorNodeBlob(t *testing.T) { all := make(map[string]string) for _, val := range vals { all[val.k] = val.v - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } _, nodes := trie.Commit(false) triedb.Update(NewWithNodeSet(nodes)) diff --git a/trie/proof.go b/trie/proof.go index f11dfc47afab..65df7577b9b6 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -498,7 +498,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key if proof == nil { tr := NewStackTrie(nil) for index, key := range keys { - tr.TryUpdate(key, values[index]) + tr.Update(key, values[index]) } if have, want := tr.Hash(), rootHash; have != want { return false, fmt.Errorf("invalid proof, want hash %x, got %x", want, have) @@ -568,7 +568,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key tr.root = nil } for index, key := range keys { - tr.TryUpdate(key, values[index]) + tr.Update(key, values[index]) } if tr.Hash() != rootHash { return false, fmt.Errorf("invalid proof, want hash %x, got %x", rootHash, tr.Hash()) diff --git a/trie/proof_test.go b/trie/proof_test.go index 6b23bcdb27d8..69e3f8e9ceea 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -403,7 +403,7 @@ func TestOneElementRangeProof(t *testing.T) { // Test the mini trie with only a single element. tinyTrie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) entry := &kv{randBytes(32), randBytes(20), false} - tinyTrie.Update(entry.k, entry.v) + tinyTrie.MustUpdate(entry.k, entry.v) first = common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000").Bytes() last = entry.k @@ -477,7 +477,7 @@ func TestSingleSideRangeProof(t *testing.T) { var entries entrySlice for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} - trie.Update(value.k, value.v) + trie.MustUpdate(value.k, value.v) entries = append(entries, value) } sort.Sort(entries) @@ -512,7 +512,7 @@ func TestReverseSingleSideRangeProof(t *testing.T) { var entries entrySlice for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} - trie.Update(value.k, value.v) + trie.MustUpdate(value.k, value.v) entries = append(entries, value) } sort.Sort(entries) @@ -619,7 +619,7 @@ func TestGappedRangeProof(t *testing.T) { var entries []*kv // Sorted entries for i := byte(0); i < 10; i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} - trie.Update(value.k, value.v) + trie.MustUpdate(value.k, value.v) entries = append(entries, value) } first, last := 2, 8 @@ -693,7 +693,7 @@ func TestHasRightElement(t *testing.T) { var entries entrySlice for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} - trie.Update(value.k, value.v) + trie.MustUpdate(value.k, value.v) entries = append(entries, value) } sort.Sort(entries) @@ -1047,14 +1047,14 @@ func randomTrie(n int) (*Trie, map[string]*kv) { for i := byte(0); i < 100; i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false} - trie.Update(value.k, value.v) - trie.Update(value2.k, value2.v) + trie.MustUpdate(value.k, value.v) + trie.MustUpdate(value2.k, value2.v) vals[string(value.k)] = value vals[string(value2.k)] = value2 } for i := 0; i < n; i++ { value := &kv{randBytes(32), randBytes(20), false} - trie.Update(value.k, value.v) + trie.MustUpdate(value.k, value.v) vals[string(value.k)] = value } return trie, vals @@ -1071,7 +1071,7 @@ func nonRandomTrie(n int) (*Trie, map[string]*kv) { binary.LittleEndian.PutUint64(value, i-max) //value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} elem := &kv{key, value, false} - trie.Update(elem.k, elem.v) + trie.MustUpdate(elem.k, elem.v) vals[string(elem.k)] = elem } return trie, vals @@ -1088,7 +1088,7 @@ func TestRangeProofKeysWithSharedPrefix(t *testing.T) { } trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i, key := range keys { - trie.Update(key, vals[i]) + trie.MustUpdate(key, vals[i]) } root := trie.Hash() proof := memorydb.New() diff --git a/trie/secure_trie.go b/trie/secure_trie.go index b25bf758c15d..5bfd246501cc 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -19,7 +19,6 @@ package trie import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" ) @@ -72,14 +71,13 @@ func NewStateTrie(id *ID, db *Database) (*StateTrie, error) { return &StateTrie{trie: *trie, preimages: db.preimages}, nil } -// Get returns the value for key stored in the trie. +// MustGet returns the value for key stored in the trie. // The value bytes must not be modified by the caller. -func (t *StateTrie) Get(key []byte) []byte { - res, err := t.GetStorage(common.Address{}, key) - if err != nil { - log.Error("Unhandled trie error in StateTrie.Get", "err", err) - } - return res +// +// This function will omit any encountered error but just +// print out an error message. +func (t *StateTrie) MustGet(key []byte) []byte { + return t.trie.MustGet(t.hashKey(key)) } // GetStorage attempts to retrieve a storage slot with provided account address @@ -87,14 +85,14 @@ func (t *StateTrie) Get(key []byte) []byte { // 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) { - return t.trie.TryGet(t.hashKey(key)) + return t.trie.Get(t.hashKey(key)) } // 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. func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) { - res, err := t.trie.TryGet(t.hashKey(address.Bytes())) + res, err := t.trie.Get(t.hashKey(address.Bytes())) if res == nil || err != nil { return nil, err } @@ -107,7 +105,7 @@ func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, err // account hash that is the hash of address. This constitutes an abstraction // leak, since the client code needs to know the key format. func (t *StateTrie) GetAccountByHash(addrHash common.Hash) (*types.StateAccount, error) { - res, err := t.trie.TryGet(addrHash.Bytes()) + res, err := t.trie.Get(addrHash.Bytes()) if res == nil || err != nil { return nil, err } @@ -121,19 +119,22 @@ func (t *StateTrie) GetAccountByHash(addrHash common.Hash) (*types.StateAccount, // If the specified trie node 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) GetNode(path []byte) ([]byte, int, error) { - return t.trie.TryGetNode(path) + return t.trie.GetNode(path) } -// Update associates key with value in the trie. Subsequent calls to +// MustUpdate associates key with value in the trie. Subsequent calls to // Get will return value. If value has length zero, any existing value // is deleted from the trie and calls to Get will return nil. // // The value bytes must not be modified by the caller while they are // stored in the trie. -func (t *StateTrie) Update(key, value []byte) { - if err := t.UpdateStorage(common.Address{}, key, value); err != nil { - log.Error("Unhandled trie error in StateTrie.Update", "err", err) - } +// +// This function will omit any encountered error but just print out an +// error message. +func (t *StateTrie) MustUpdate(key, value []byte) { + hk := t.hashKey(key) + t.trie.MustUpdate(hk, value) + t.getSecKeyCache()[string(hk)] = common.CopyBytes(key) } // UpdateStorage associates key with value in the trie. Subsequent calls to @@ -146,7 +147,7 @@ func (t *StateTrie) Update(key, value []byte) { // If a node is not found in the database, a MissingNodeError is returned. func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error { hk := t.hashKey(key) - err := t.trie.TryUpdate(hk, value) + err := t.trie.Update(hk, value) if err != nil { return err } @@ -161,18 +162,19 @@ func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccoun if err != nil { return err } - if err := t.trie.TryUpdate(hk, data); err != nil { + if err := t.trie.Update(hk, data); err != nil { return err } t.getSecKeyCache()[string(hk)] = address.Bytes() return nil } -// Delete removes any existing value for key from the trie. -func (t *StateTrie) Delete(key []byte) { - if err := t.DeleteStorage(common.Address{}, key); err != nil { - log.Error("Unhandled trie error in StateTrie.Delete", "err", err) - } +// MustDelete removes any existing value for key from the trie. This function +// will omit any encountered error but just print out an error message. +func (t *StateTrie) MustDelete(key []byte) { + hk := t.hashKey(key) + delete(t.getSecKeyCache(), string(hk)) + t.trie.MustDelete(hk) } // DeleteStorage removes any existing storage slot from the trie. @@ -181,14 +183,14 @@ func (t *StateTrie) Delete(key []byte) { func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error { hk := t.hashKey(key) delete(t.getSecKeyCache(), string(hk)) - return t.trie.TryDelete(hk) + return t.trie.Delete(hk) } // DeleteAccount abstracts an account deletion from the trie. func (t *StateTrie) DeleteAccount(address common.Address) error { hk := t.hashKey(address.Bytes()) delete(t.getSecKeyCache(), string(hk)) - return t.trie.TryDelete(hk) + return t.trie.Delete(hk) } // GetKey returns the sha3 preimage of a hashed key that was diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index d3e6c670690e..a55c10a60b6e 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -45,17 +45,17 @@ func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) { // Map the same data under multiple keys key, val := common.LeftPadBytes([]byte{1, i}, 32), []byte{i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) key, val = common.LeftPadBytes([]byte{2, i}, 32), []byte{i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) // Add some other data to inflate the trie for j := byte(3); j < 13; j++ { key, val = common.LeftPadBytes([]byte{j, i}, 32), []byte{j, i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) } } root, nodes := trie.Commit(false) @@ -81,9 +81,9 @@ func TestSecureDelete(t *testing.T) { } for _, val := range vals { if val.v != "" { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } else { - trie.Delete([]byte(val.k)) + trie.MustDelete([]byte(val.k)) } } hash := trie.Hash() @@ -95,13 +95,13 @@ func TestSecureDelete(t *testing.T) { func TestSecureGetKey(t *testing.T) { trie := newEmptySecure() - trie.Update([]byte("foo"), []byte("bar")) + trie.MustUpdate([]byte("foo"), []byte("bar")) key := []byte("foo") value := []byte("bar") seckey := crypto.Keccak256(key) - if !bytes.Equal(trie.Get(key), value) { + if !bytes.Equal(trie.MustGet(key), value) { t.Errorf("Get did not return bar") } if k := trie.GetKey(seckey); !bytes.Equal(k, key) { @@ -128,15 +128,15 @@ func TestStateTrieConcurrency(t *testing.T) { for j := byte(0); j < 255; j++ { // Map the same data under multiple keys key, val := common.LeftPadBytes([]byte{byte(index), 1, j}, 32), []byte{j} - tries[index].Update(key, val) + tries[index].MustUpdate(key, val) key, val = common.LeftPadBytes([]byte{byte(index), 2, j}, 32), []byte{j} - tries[index].Update(key, val) + tries[index].MustUpdate(key, val) // Add some other data to inflate the trie for k := byte(3); k < 13; k++ { key, val = common.LeftPadBytes([]byte{byte(index), k, j}, 32), []byte{k, j} - tries[index].Update(key, val) + tries[index].MustUpdate(key, val) } } tries[index].Commit(false) diff --git a/trie/stacktrie.go b/trie/stacktrie.go index 83034e29a530..030d2a596c88 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -202,8 +202,8 @@ const ( hashedNode ) -// TryUpdate inserts a (key, value) pair into the stack trie -func (st *StackTrie) TryUpdate(key, value []byte) error { +// Update inserts a (key, value) pair into the stack trie. +func (st *StackTrie) Update(key, value []byte) error { k := keybytesToHex(key) if len(value) == 0 { panic("deletion not supported") @@ -212,8 +212,10 @@ func (st *StackTrie) TryUpdate(key, value []byte) error { return nil } -func (st *StackTrie) Update(key, value []byte) { - if err := st.TryUpdate(key, value); err != nil { +// MustUpdate is a wrapper of Update and will omit any encountered error but +// just print out an error message. +func (st *StackTrie) MustUpdate(key, value []byte) { + if err := st.Update(key, value); err != nil { log.Error("Unhandled trie error in StackTrie.Update", "err", err) } } diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index 3e6cc8cd5785..ea3eef78820d 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -174,7 +174,7 @@ func TestStackTrieInsertAndHash(t *testing.T) { st.Reset() for j := 0; j < l; j++ { kv := &test[j] - if err := st.TryUpdate(common.FromHex(kv.K), []byte(kv.V)); err != nil { + if err := st.Update(common.FromHex(kv.K), []byte(kv.V)); err != nil { t.Fatal(err) } } @@ -193,8 +193,8 @@ func TestSizeBug(t *testing.T) { leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") - nt.TryUpdate(leaf, value) - st.TryUpdate(leaf, value) + nt.Update(leaf, value) + st.Update(leaf, value) if nt.Hash() != st.Hash() { t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) @@ -218,8 +218,8 @@ func TestEmptyBug(t *testing.T) { } for _, kv := range kvs { - nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) - st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) + nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) + st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) } if nt.Hash() != st.Hash() { @@ -241,8 +241,8 @@ func TestValLength56(t *testing.T) { } for _, kv := range kvs { - nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) - st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) + nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) + st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) } if nt.Hash() != st.Hash() { @@ -263,8 +263,8 @@ func TestUpdateSmallNodes(t *testing.T) { {"65", "3000"}, // stacktrie.Update } for _, kv := range kvs { - nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) - st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) + nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) + st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) } if nt.Hash() != st.Hash() { t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) @@ -291,8 +291,8 @@ func TestUpdateVariableKeys(t *testing.T) { {"0x3330353463653239356131303167617430", "313131"}, } for _, kv := range kvs { - nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) - st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V)) + nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) + st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) } if nt.Hash() != st.Hash() { t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) @@ -309,7 +309,7 @@ func TestStacktrieNotModifyValues(t *testing.T) { value := make([]byte, 1, 100) value[0] = 0x2 want := common.CopyBytes(value) - st.TryUpdate([]byte{0x01}, value) + st.Update([]byte{0x01}, value) st.Hash() if have := value; !bytes.Equal(have, want) { t.Fatalf("tiny trie: have %#x want %#x", have, want) @@ -330,7 +330,7 @@ func TestStacktrieNotModifyValues(t *testing.T) { for i := 0; i < 1000; i++ { key := common.BigToHash(keyB) value := getValue(i) - st.TryUpdate(key.Bytes(), value) + st.Update(key.Bytes(), value) vals = append(vals, value) keyB = keyB.Add(keyB, keyDelta) keyDelta.Add(keyDelta, common.Big1) @@ -371,7 +371,7 @@ func TestStacktrieSerialization(t *testing.T) { keyDelta.Add(keyDelta, common.Big1) } for i, k := range keys { - nt.TryUpdate(k, common.CopyBytes(vals[i])) + nt.Update(k, common.CopyBytes(vals[i])) } for i, k := range keys { @@ -384,7 +384,7 @@ func TestStacktrieSerialization(t *testing.T) { t.Fatal(err) } st = newSt - st.TryUpdate(k, common.CopyBytes(vals[i])) + st.Update(k, common.CopyBytes(vals[i])) } if have, want := st.Hash(), nt.Hash(); have != want { t.Fatalf("have %#x want %#x", have, want) diff --git a/trie/sync_test.go b/trie/sync_test.go index f404dc1cda80..70898604f845 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -40,17 +40,17 @@ func makeTestTrie() (*Database, *StateTrie, map[string][]byte) { // Map the same data under multiple keys key, val := common.LeftPadBytes([]byte{1, i}, 32), []byte{i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) key, val = common.LeftPadBytes([]byte{2, i}, 32), []byte{i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) // Add some other data to inflate the trie for j := byte(3); j < 13; j++ { key, val = common.LeftPadBytes([]byte{j, i}, 32), []byte{j, i} content[string(key)] = val - trie.Update(key, val) + trie.MustUpdate(key, val) } } root, nodes := trie.Commit(false) @@ -74,7 +74,7 @@ func checkTrieContents(t *testing.T, db *Database, root []byte, content map[stri t.Fatalf("inconsistent trie at %x: %v", root, err) } for key, val := range content { - if have := trie.Get([]byte(key)); !bytes.Equal(have, val) { + if have := trie.MustGet([]byte(key)); !bytes.Equal(have, val) { t.Errorf("entry %x: content mismatch: have %x, want %x", key, have, val) } } diff --git a/trie/tracer_test.go b/trie/tracer_test.go index 5e627c89c9be..1b9f441084f2 100644 --- a/trie/tracer_test.go +++ b/trie/tracer_test.go @@ -64,7 +64,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { // Determine all new nodes are tracked for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } insertSet := copySet(trie.tracer.inserts) // copy before commit deleteSet := copySet(trie.tracer.deletes) // copy before commit @@ -82,7 +82,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { // Determine all deletions are tracked trie, _ = New(TrieID(root), db) for _, val := range vals { - trie.Delete([]byte(val.k)) + trie.MustDelete([]byte(val.k)) } insertSet, deleteSet = copySet(trie.tracer.inserts), copySet(trie.tracer.deletes) if !compareSet(insertSet, nil) { @@ -104,10 +104,10 @@ func TestTrieTracerNoop(t *testing.T) { func testTrieTracerNoop(t *testing.T, vals []struct{ k, v string }) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } for _, val := range vals { - trie.Delete([]byte(val.k)) + trie.MustDelete([]byte(val.k)) } if len(trie.tracer.inserts) != 0 { t.Fatal("Unexpected insertion set") @@ -132,7 +132,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { ) // Create trie from scratch for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -146,7 +146,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { trie, _ = New(TrieID(root), db) orig = trie.Copy() for _, val := range vals { - trie.Update([]byte(val.k), randBytes(32)) + trie.MustUpdate([]byte(val.k), randBytes(32)) } root, nodes = trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -163,7 +163,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { for i := 0; i < 30; i++ { key := randBytes(32) keys = append(keys, string(key)) - trie.Update(key, randBytes(32)) + trie.MustUpdate(key, randBytes(32)) } root, nodes = trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -177,7 +177,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { trie, _ = New(TrieID(root), db) orig = trie.Copy() for _, key := range keys { - trie.Update([]byte(key), nil) + trie.MustUpdate([]byte(key), nil) } root, nodes = trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -191,7 +191,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { trie, _ = New(TrieID(root), db) orig = trie.Copy() for _, val := range vals { - trie.Update([]byte(val.k), nil) + trie.MustUpdate([]byte(val.k), nil) } root, nodes = trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -210,7 +210,7 @@ func TestAccessListLeak(t *testing.T) { ) // Create trie from scratch for _, val := range standard { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, nodes := trie.Commit(false) db.Update(NewWithNodeSet(nodes)) @@ -260,7 +260,7 @@ func TestTinyTree(t *testing.T) { trie = NewEmpty(db) ) for _, val := range tiny { - trie.Update([]byte(val.k), randBytes(32)) + trie.MustUpdate([]byte(val.k), randBytes(32)) } root, set := trie.Commit(false) db.Update(NewWithNodeSet(set)) @@ -268,7 +268,7 @@ func TestTinyTree(t *testing.T) { trie, _ = New(TrieID(root), db) orig := trie.Copy() for _, val := range tiny { - trie.Update([]byte(val.k), []byte(val.v)) + trie.MustUpdate([]byte(val.k), []byte(val.v)) } root, set = trie.Commit(false) db.Update(NewWithNodeSet(set)) diff --git a/trie/trie.go b/trie/trie.go index 17bacba00fdc..4b6f6a55bbc4 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -105,28 +105,30 @@ func (t *Trie) NodeIterator(start []byte) NodeIterator { return newNodeIterator(t, start) } -// Get returns the value for key stored in the trie. -// The value bytes must not be modified by the caller. -func (t *Trie) Get(key []byte) []byte { - res, err := t.TryGet(key) +// MustGet is a wrapper of Get and will omit any encountered error but just +// print out an error message. +func (t *Trie) MustGet(key []byte) []byte { + res, err := t.Get(key) if err != nil { log.Error("Unhandled trie error in Trie.Get", "err", err) } return res } -// TryGet returns the value for key stored in the trie. +// Get 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 MissingNodeError is returned. -func (t *Trie) TryGet(key []byte) ([]byte, error) { - value, newroot, didResolve, err := t.tryGet(t.root, keybytesToHex(key), 0) +// +// If the requested node is not present in trie, no error will be returned. +// If the trie is corrupted, a MissingNodeError is returned. +func (t *Trie) Get(key []byte) ([]byte, error) { + value, newroot, didResolve, err := t.get(t.root, keybytesToHex(key), 0) if err == nil && didResolve { t.root = newroot } return value, err } -func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode node, didResolve bool, err error) { +func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode node, didResolve bool, err error) { switch n := (origNode).(type) { case nil: return nil, nil, false, nil @@ -137,14 +139,14 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode // key not found in trie return nil, n, false, nil } - value, newnode, didResolve, err = t.tryGet(n.Val, key, pos+len(n.Key)) + value, newnode, didResolve, err = t.get(n.Val, key, pos+len(n.Key)) if err == nil && didResolve { n = n.copy() n.Val = newnode } return value, n, didResolve, err case *fullNode: - value, newnode, didResolve, err = t.tryGet(n.Children[key[pos]], key, pos+1) + value, newnode, didResolve, err = t.get(n.Children[key[pos]], key, pos+1) if err == nil && didResolve { n = n.copy() n.Children[key[pos]] = newnode @@ -155,17 +157,30 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode if err != nil { return nil, n, true, err } - value, newnode, _, err := t.tryGet(child, key, pos) + value, newnode, _, err := t.get(child, key, pos) return value, newnode, true, err default: panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode)) } } -// TryGetNode 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. -func (t *Trie) TryGetNode(path []byte) ([]byte, int, error) { - item, newroot, resolved, err := t.tryGetNode(t.root, compactToHex(path), 0) +// 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) { + item, resolved, err := t.GetNode(path) + if err != nil { + log.Error("Unhandled trie error in Trie.GetNode", "err", err) + } + return item, resolved +} + +// GetNode retrieves a trie node by compact-encoded path. It is not possible +// to use keybyte-encoding as the path might contain odd nibbles. +// +// If the requested node is not present in trie, no error will be returned. +// If the trie is corrupted, a MissingNodeError is returned. +func (t *Trie) GetNode(path []byte) ([]byte, int, error) { + item, newroot, resolved, err := t.getNode(t.root, compactToHex(path), 0) if err != nil { return nil, resolved, err } @@ -175,10 +190,10 @@ func (t *Trie) TryGetNode(path []byte) ([]byte, int, error) { if item == nil { return nil, resolved, nil } - return item, resolved, err + return item, resolved, nil } -func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, newnode node, resolved int, err error) { +func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnode node, resolved int, err error) { // If non-existent path requested, abort if origNode == nil { return nil, nil, 0, nil @@ -211,7 +226,7 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new // Path branches off from short node return nil, n, 0, nil } - item, newnode, resolved, err = t.tryGetNode(n.Val, path, pos+len(n.Key)) + item, newnode, resolved, err = t.getNode(n.Val, path, pos+len(n.Key)) if err == nil && resolved > 0 { n = n.copy() n.Val = newnode @@ -219,7 +234,7 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new return item, n, resolved, err case *fullNode: - item, newnode, resolved, err = t.tryGetNode(n.Children[path[pos]], path, pos+1) + item, newnode, resolved, err = t.getNode(n.Children[path[pos]], path, pos+1) if err == nil && resolved > 0 { n = n.copy() n.Children[path[pos]] = newnode @@ -231,7 +246,7 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new if err != nil { return nil, n, 1, err } - item, newnode, resolved, err := t.tryGetNode(child, path, pos) + item, newnode, resolved, err := t.getNode(child, path, pos) return item, newnode, resolved + 1, err default: @@ -239,33 +254,28 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new } } -// Update associates key with value in the trie. Subsequent calls to -// Get will return value. If value has length zero, any existing value -// is deleted from the trie and calls to Get will return nil. -// -// The value bytes must not be modified by the caller while they are -// stored in the trie. -func (t *Trie) Update(key, value []byte) { - if err := t.TryUpdate(key, value); err != nil { +// MustUpdate is a wrapper of Update and will omit any encountered error but +// just print out an error message. +func (t *Trie) MustUpdate(key, value []byte) { + if err := t.Update(key, value); err != nil { log.Error("Unhandled trie error in Trie.Update", "err", err) } } -// TryUpdate associates key with value in the trie. Subsequent calls to +// Update associates key with value in the trie. Subsequent calls to // Get will return value. If value has length zero, any existing value // is deleted from the trie and calls to Get will return nil. // // The value bytes must not be modified by the caller while they are // stored in the trie. // -// If a node was not found in the database, a MissingNodeError is returned. -func (t *Trie) TryUpdate(key, value []byte) error { - return t.tryUpdate(key, value) +// If the requested node is not present in trie, no error will be returned. +// If the trie is corrupted, a MissingNodeError is returned. +func (t *Trie) Update(key, value []byte) error { + return t.update(key, value) } -// tryUpdate expects an RLP-encoded value and performs the core function -// for TryUpdate and TryUpdateAccount. -func (t *Trie) tryUpdate(key, value []byte) error { +func (t *Trie) update(key, value []byte) error { t.unhashed++ k := keybytesToHex(key) if len(value) != 0 { @@ -363,16 +373,19 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error } } -// Delete removes any existing value for key from the trie. -func (t *Trie) Delete(key []byte) { - if err := t.TryDelete(key); err != nil { +// MustDelete is a wrapper of Delete and will omit any encountered error but +// just print out an error message. +func (t *Trie) MustDelete(key []byte) { + if err := t.Delete(key); err != nil { log.Error("Unhandled trie error in Trie.Delete", "err", err) } } -// TryDelete removes any existing value for key from the trie. -// If a node was not found in the database, a MissingNodeError is returned. -func (t *Trie) TryDelete(key []byte) error { +// Delete removes any existing value for key from the trie. +// +// If the requested node is not present in trie, no error will be returned. +// If the trie is corrupted, a MissingNodeError is returned. +func (t *Trie) Delete(key []byte) error { t.unhashed++ k := keybytesToHex(key) _, n, err := t.delete(t.root, nil, k) diff --git a/trie/trie_test.go b/trie/trie_test.go index 089bb44a9741..82ead8b44127 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -56,8 +56,8 @@ func TestNull(t *testing.T) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) key := make([]byte, 32) value := []byte("test") - trie.Update(key, value) - if !bytes.Equal(trie.Get(key), value) { + trie.MustUpdate(key, value) + if !bytes.Equal(trie.MustGet(key), value) { t.Fatal("wrong value") } } @@ -90,27 +90,27 @@ func testMissingNode(t *testing.T, memonly bool) { } trie, _ = New(TrieID(root), triedb) - _, err := trie.TryGet([]byte("120000")) + _, err := trie.Get([]byte("120000")) if err != nil { t.Errorf("Unexpected error: %v", err) } trie, _ = New(TrieID(root), triedb) - _, err = trie.TryGet([]byte("120099")) + _, err = trie.Get([]byte("120099")) if err != nil { t.Errorf("Unexpected error: %v", err) } trie, _ = New(TrieID(root), triedb) - _, err = trie.TryGet([]byte("123456")) + _, err = trie.Get([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } trie, _ = New(TrieID(root), triedb) - err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) + err = trie.Update([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) if err != nil { t.Errorf("Unexpected error: %v", err) } trie, _ = New(TrieID(root), triedb) - err = trie.TryDelete([]byte("123456")) + err = trie.Delete([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -123,27 +123,27 @@ func testMissingNode(t *testing.T, memonly bool) { } trie, _ = New(TrieID(root), triedb) - _, err = trie.TryGet([]byte("120000")) + _, err = trie.Get([]byte("120000")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } trie, _ = New(TrieID(root), triedb) - _, err = trie.TryGet([]byte("120099")) + _, err = trie.Get([]byte("120099")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } trie, _ = New(TrieID(root), triedb) - _, err = trie.TryGet([]byte("123456")) + _, err = trie.Get([]byte("123456")) if err != nil { t.Errorf("Unexpected error: %v", err) } trie, _ = New(TrieID(root), triedb) - err = trie.TryUpdate([]byte("120099"), []byte("zxcv")) + err = trie.Update([]byte("120099"), []byte("zxcv")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } trie, _ = New(TrieID(root), triedb) - err = trie.TryDelete([]byte("123456")) + err = trie.Delete([]byte("123456")) if _, ok := err.(*MissingNodeError); !ok { t.Errorf("Wrong error: %v", err) } @@ -311,8 +311,8 @@ func TestReplication(t *testing.T) { func TestLargeValue(t *testing.T) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) - trie.Update([]byte("key1"), []byte{99, 99, 99, 99}) - trie.Update([]byte("key2"), bytes.Repeat([]byte{1}, 32)) + trie.MustUpdate([]byte("key1"), []byte{99, 99, 99, 99}) + trie.MustUpdate([]byte("key2"), bytes.Repeat([]byte{1}, 32)) trie.Hash() } @@ -460,13 +460,13 @@ func runRandTest(rt randTest) bool { switch step.op { case opUpdate: - tr.Update(step.key, step.value) + tr.MustUpdate(step.key, step.value) values[string(step.key)] = string(step.value) case opDelete: - tr.Delete(step.key) + tr.MustDelete(step.key) delete(values, string(step.key)) case opGet: - v := tr.Get(step.key) + v := tr.MustGet(step.key) want := values[string(step.key)] if string(v) != want { rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) @@ -509,7 +509,7 @@ func runRandTest(rt randTest) bool { checktr := NewEmpty(triedb) it := NewIterator(tr.NodeIterator(nil)) for it.Next() { - checktr.Update(it.Key, it.Value) + checktr.MustUpdate(it.Key, it.Value) } if tr.Hash() != checktr.Hash() { rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") @@ -595,13 +595,13 @@ func benchGet(b *testing.B) { k := make([]byte, 32) for i := 0; i < benchElemCount; i++ { binary.LittleEndian.PutUint64(k, uint64(i)) - trie.Update(k, k) + trie.MustUpdate(k, k) } binary.LittleEndian.PutUint64(k, benchElemCount/2) b.ResetTimer() for i := 0; i < b.N; i++ { - trie.Get(k) + trie.MustGet(k) } b.StopTimer() } @@ -612,7 +612,7 @@ func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { b.ReportAllocs() for i := 0; i < b.N; i++ { e.PutUint64(k, uint64(i)) - trie.Update(k, k) + trie.MustUpdate(k, k) } return trie } @@ -640,11 +640,11 @@ func BenchmarkHash(b *testing.B) { trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) i := 0 for ; i < len(addresses)/2; i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } trie.Hash() for ; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } b.ResetTimer() b.ReportAllocs() @@ -670,7 +670,7 @@ func benchmarkCommitAfterHash(b *testing.B, collectLeaf bool) { addresses, accounts := makeAccounts(b.N) trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Insert the accounts into the trie and hash it trie.Hash() @@ -683,22 +683,22 @@ func TestTinyTrie(t *testing.T) { // Create a realistic account trie to hash _, accounts := makeAccounts(5) trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) - trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001337"), accounts[3]) + trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001337"), accounts[3]) if exp, root := common.HexToHash("8c6a85a4d9fda98feff88450299e574e5378e32391f75a055d470ac0653f1005"), trie.Hash(); exp != root { t.Errorf("1: got %x, exp %x", root, exp) } - trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001338"), accounts[4]) + trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001338"), accounts[4]) if exp, root := common.HexToHash("ec63b967e98a5720e7f720482151963982890d82c9093c0d486b7eb8883a66b1"), trie.Hash(); exp != root { t.Errorf("2: got %x, exp %x", root, exp) } - trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001339"), accounts[4]) + trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001339"), accounts[4]) if exp, root := common.HexToHash("0608c1d1dc3905fa22204c7a0e43644831c3b6d3def0f274be623a948197e64a"), trie.Hash(); exp != root { t.Errorf("3: got %x, exp %x", root, exp) } checktr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) it := NewIterator(trie.NodeIterator(nil)) for it.Next() { - checktr.Update(it.Key, it.Value) + checktr.MustUpdate(it.Key, it.Value) } if troot, itroot := trie.Hash(), checktr.Hash(); troot != itroot { t.Fatalf("hash mismatch in opItercheckhash, trie: %x, check: %x", troot, itroot) @@ -710,7 +710,7 @@ func TestCommitAfterHash(t *testing.T) { addresses, accounts := makeAccounts(1000) trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Insert the accounts into the trie and hash it trie.Hash() @@ -820,7 +820,7 @@ func TestCommitSequence(t *testing.T) { trie := NewEmpty(db) // Fill the trie with elements for i := 0; i < tc.count; i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Flush trie -> database root, nodes := trie.Commit(false) @@ -861,7 +861,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { } prng.Read(key) prng.Read(val) - trie.Update(key, val) + trie.MustUpdate(key, val) } // Flush trie -> database root, nodes := trie.Commit(false) @@ -899,8 +899,8 @@ func TestCommitSequenceStackTrie(t *testing.T) { val = make([]byte, 1+prng.Intn(1024)) } prng.Read(val) - trie.TryUpdate(key, val) - stTrie.TryUpdate(key, val) + trie.Update(key, val) + stTrie.Update(key, val) } // Flush trie -> database root, nodes := trie.Commit(false) @@ -948,8 +948,8 @@ func TestCommitSequenceSmallRoot(t *testing.T) { // Add a single small-element to the trie(s) key := make([]byte, 5) key[0] = 1 - trie.TryUpdate(key, []byte{0x1}) - stTrie.TryUpdate(key, []byte{0x1}) + trie.Update(key, []byte{0x1}) + stTrie.Update(key, []byte{0x1}) // Flush trie -> database root, nodes := trie.Commit(false) // Flush memdb -> disk (sponge) @@ -1017,7 +1017,7 @@ func benchmarkHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byt b.ReportAllocs() trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Insert the accounts into the trie and hash it b.StartTimer() @@ -1068,7 +1068,7 @@ func benchmarkCommitAfterHashFixedSize(b *testing.B, addresses [][20]byte, accou b.ReportAllocs() trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Insert the accounts into the trie and hash it trie.Hash() @@ -1121,7 +1121,7 @@ func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [] triedb := NewDatabase(rawdb.NewMemoryDatabase()) trie := NewEmpty(triedb) for i := 0; i < len(addresses); i++ { - trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) + trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } h := trie.Hash() _, nodes := trie.Commit(false) @@ -1132,15 +1132,15 @@ func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [] } func getString(trie *Trie, k string) []byte { - return trie.Get([]byte(k)) + return trie.MustGet([]byte(k)) } func updateString(trie *Trie, k, v string) { - trie.Update([]byte(k), []byte(v)) + trie.MustUpdate([]byte(k), []byte(v)) } func deleteString(trie *Trie, k string) { - trie.Delete([]byte(k)) + trie.MustDelete([]byte(k)) } func TestDecodeNode(t *testing.T) { From ea9e62ca3db5c33aa7438ebf39c189afd53c6bf8 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 20 Apr 2023 20:14:51 +0200 Subject: [PATCH 713/715] params: go-ethereum v1.11.6 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 7df3a82b3ddc..7348093042e9 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 6 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 5d2436cb1cb33ae68080ed61645ce3276d44a724 Mon Sep 17 00:00:00 2001 From: Yakov Gaberman <81639957+ygaberman-px@users.noreply.github.com> Date: Mon, 1 May 2023 11:01:29 -0400 Subject: [PATCH 714/715] fix merge conflicts --- accounts/abi/bind/backends/simulated.go | 2 +- accounts/abi/bind/backends/simulated_test.go | 3 - cmd/puppeth/module.go | 161 ----- cmd/puppeth/module_dashboard.go | 661 ------------------- cmd/puppeth/module_explorer.go | 194 ------ cmd/puppeth/module_faucet.go | 254 ------- cmd/puppeth/module_node.go | 273 -------- cmd/puppeth/puppeth.go | 65 -- cmd/puppeth/ssh.go | 271 -------- cmd/puppeth/wizard.go | 312 --------- cmd/puppeth/wizard_genesis.go | 285 -------- consensus/misc/forks.go | 43 -- core/blockchain_reader.go | 6 - core/state/database.go | 3 - core/state/snapshot/generate.go | 2 +- core/state/statedb.go | 7 - eth/api_backend.go | 3 - eth/backend.go | 1 - eth/catalyst/api.go | 229 ------- eth/ethconfig/gen_config.go | 3 - eth/filters/filter.go | 19 +- eth/filters/filter_system.go | 1 - eth/protocols/snap/handler.go | 1 + eth/tracers/native/call.go | 4 - eth/tracers/native/revertreason.go | 108 --- eth/tracers/native/tracer.go | 83 --- go.sum | 14 +- internal/ethapi/backend.go | 2 +- mobile/accounts.go | 221 ------- mobile/ethclient.go | 315 --------- mobile/types.go | 377 ----------- params/config.go | 5 - trie/proof.go | 1 - trie/stacktrie.go | 10 - trie/tracer.go | 5 - trie/util_test.go | 124 ---- 36 files changed, 9 insertions(+), 4059 deletions(-) delete mode 100644 cmd/puppeth/module.go delete mode 100644 cmd/puppeth/module_dashboard.go delete mode 100644 cmd/puppeth/module_explorer.go delete mode 100644 cmd/puppeth/module_faucet.go delete mode 100644 cmd/puppeth/module_node.go delete mode 100644 cmd/puppeth/puppeth.go delete mode 100644 cmd/puppeth/ssh.go delete mode 100644 cmd/puppeth/wizard.go delete mode 100644 cmd/puppeth/wizard_genesis.go delete mode 100644 consensus/misc/forks.go delete mode 100644 eth/tracers/native/revertreason.go delete mode 100644 eth/tracers/native/tracer.go delete mode 100644 mobile/accounts.go delete mode 100644 mobile/ethclient.go delete mode 100644 mobile/types.go delete mode 100644 trie/util_test.go diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 82f31fe451af..5c9edd381ced 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -129,7 +129,7 @@ func (b *SimulatedBackend) Commit() common.Hash { blocks, _ := core.GenerateChain(b.config, parentBlock, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { - for _, tx := range append(b.pendingBlock.Transactions(), b.stuckTransactions...) { + for _, tx := range b.pendingBlock.Transactions() { if b.marketGasPrice == nil || b.marketGasPrice.Cmp(tx.GasPrice()) <= 0 { block.AddTxWithChain(b.blockchain, tx) } else { diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index 48c421b46588..698bfc576573 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -27,9 +27,6 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" diff --git a/cmd/puppeth/module.go b/cmd/puppeth/module.go deleted file mode 100644 index 771ae38058bc..000000000000 --- a/cmd/puppeth/module.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "errors" - "fmt" - "net" - "strconv" - "strings" - "time" - - "github.com/ethereum/go-ethereum/log" -) - -var ( - // ErrServiceUnknown is returned when a service container doesn't exist. - ErrServiceUnknown = errors.New("service unknown") - - // ErrServiceOffline is returned when a service container exists, but it is not - // running. - ErrServiceOffline = errors.New("service offline") - - // ErrServiceUnreachable is returned when a service container is running, but - // seems to not respond to communication attempts. - ErrServiceUnreachable = errors.New("service unreachable") - - // ErrNotExposed is returned if a web-service doesn't have an exposed port, nor - // a reverse-proxy in front of it to forward requests. - ErrNotExposed = errors.New("service not exposed, nor proxied") -) - -// containerInfos is a heavily reduced version of the huge inspection dataset -// returned from docker inspect, parsed into a form easily usable by puppeth. -type containerInfos struct { - running bool // Flag whether the container is running currently - envvars map[string]string // Collection of environmental variables set on the container - portmap map[string]int // Port mapping from internal port/proto combos to host binds - volumes map[string]string // Volume mount points from container to host directories -} - -// inspectContainer runs docker inspect against a running container -func inspectContainer(client *sshClient, container string) (*containerInfos, error) { - // Check whether there's a container running for the service - out, err := client.Run(fmt.Sprintf("docker inspect %s", container)) - if err != nil { - return nil, ErrServiceUnknown - } - // If yes, extract various configuration options - type inspection struct { - State struct { - Running bool - } - Mounts []struct { - Source string - Destination string - } - Config struct { - Env []string - } - HostConfig struct { - PortBindings map[string][]map[string]string - } - } - var inspects []inspection - if err = json.Unmarshal(out, &inspects); err != nil { - return nil, err - } - inspect := inspects[0] - - // Infos retrieved, parse the above into something meaningful - infos := &containerInfos{ - running: inspect.State.Running, - envvars: make(map[string]string), - portmap: make(map[string]int), - volumes: make(map[string]string), - } - for _, envvar := range inspect.Config.Env { - if parts := strings.Split(envvar, "="); len(parts) == 2 { - infos.envvars[parts[0]] = parts[1] - } - } - for portname, details := range inspect.HostConfig.PortBindings { - if len(details) > 0 { - port, _ := strconv.Atoi(details[0]["HostPort"]) - infos.portmap[portname] = port - } - } - for _, mount := range inspect.Mounts { - infos.volumes[mount.Destination] = mount.Source - } - return infos, err -} - -// tearDown connects to a remote machine via SSH and terminates docker containers -// running with the specified name in the specified network. -func tearDown(client *sshClient, network string, service string, purge bool) ([]byte, error) { - // Tear down the running (or paused) container - out, err := client.Run(fmt.Sprintf("docker rm -f %s_%s_1", network, service)) - if err != nil { - return out, err - } - // If requested, purge the associated docker image too - if purge { - return client.Run(fmt.Sprintf("docker rmi %s/%s", network, service)) - } - return nil, nil -} - -// resolve retrieves the hostname a service is running on either by returning the -// actual server name and port, or preferably an nginx virtual host if available. -func resolve(client *sshClient, network string, service string, port int) (string, error) { - // Inspect the service to get various configurations from it - infos, err := inspectContainer(client, fmt.Sprintf("%s_%s_1", network, service)) - if err != nil { - return "", err - } - if !infos.running { - return "", ErrServiceOffline - } - // Container online, extract any environmental variables - if vhost := infos.envvars["VIRTUAL_HOST"]; vhost != "" { - return vhost, nil - } - return fmt.Sprintf("%s:%d", client.server, port), nil -} - -// checkPort tries to connect to a remote host on a given -func checkPort(host string, port int) error { - log.Trace("Verifying remote TCP connectivity", "server", host, "port", port) - conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), time.Second) - if err != nil { - return err - } - conn.Close() - return nil -} - -// getEthName gets the Ethereum Name from ethstats -func getEthName(s string) string { - n := strings.Index(s, ":") - if n >= 0 { - return s[:n] - } - return s -} diff --git a/cmd/puppeth/module_dashboard.go b/cmd/puppeth/module_dashboard.go deleted file mode 100644 index fbbbb66501a7..000000000000 --- a/cmd/puppeth/module_dashboard.go +++ /dev/null @@ -1,661 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "fmt" - "html/template" - "math/rand" - "path/filepath" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/log" -) - -// dashboardContent is the actual dashboard HTML content to serve up when users -// load the dashboard website. -var dashboardContent = ` - - - - - - - - - - {{.NetworkTitle}}: Network Dashboard - - - - - - - - -
-
-
-
- -
-
- -
-
-
- - {{if .Ethash}} - {{end}} - - -
-
-
- - - - - - - -` - -// dashboardMascot is the png dump of the mascot to display on the dashboard about page. -// nolint: misspell -var dashboardMascot = []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01s\x00\x00\x02\x00\b\x06\x00\x00\x00p\xe4\x8c`\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x00\tpHYs\x00\x00\v\x13\x00\x00\v\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\atIME\a\xe1\x03\x1d\x0e0&\xf3\xca\t\x11\x00\x00\x00\x1diTXtComment\x00\x00\x00\x00\x00Created with GIMPd.e\a\x00\x00 \x00IDATx\xda\xec\xbdw|\x15U\xfe\xff\xff<3s[\x12BB\x12H!\x90\u0411&H\a\x01i\"V\xb0!b\xc1^>\xbb\xee\xae\xdd\xd5u\xed}-k/X\u058e\xa8\xa0\u049bH\x87\bH\xef\x04BI\x81\xf4[\xa6\x9c\xf3\xfbcnB`\xdd\xef\xcf\xdd\xd5\xddU\xe7\xf9x\\\u023d\u027dw\xee\u0339\xafy\xcd\xfb\xbc\xcf\xfb\r\x1e\x1e\xff\";wn\x17\xb7\xdf~\xabQw_)\xa5+\xa5\x1a)\xa5\u0494R\xc9J\xa9D\xa5T\xf0\xb8\xa7\xe9\x1f|\xf0\x9eQYyXx{\xd0\xc3\xe3\xc7\xc3\xfbBy\xfcK\xbc\xf3\xce[\xe2\xd2K/Wq\x11o>y\xf2G'\xaf[\xb7\xae\xff\u05ad\xdb2\xa5\x94\xa9\xd1h\xb4:---\u06b9s\xe7HJJ\xf2\xb2f\xcd27\x9e}\xf6\x98\"!\xc4\u07ba\xd7x\xf6\xd9g\xb4\xcb.\xbbD\xa6\xa4\xa4\xb1d\xc97\f\x18p\xb2\xb7c=<<1\xf7\xf8O\xf0\x97\xbf\xbf_\x89\xef\x15u]\x86B!\x99\x93\x93\xa3\xfa\xf6\xed\xab.\xb8\xe0\x82\x8a\a\x1e\xb8\xef\x83}\xfbv\xf7k\xf8\x1e\u007f\xf8\xc3\x1f\xc4\u0739\xb3\xbc\x9d\xed\xe1\xe1\xe1\xf1S\xb0r\xe5r\r@)\xd5\xee\xf6\xdbo\u06d2\u07fa\xb5\x02$\xa04]W\x86\xe1S\t\u024dUjV\xaeJ\xcdn\xa9\x12S\u04d5\x10\xe2\x18A\x17B(\xbf\xdfo'5jde\xe74W\xfd\xfa\xf5WW^yE\xe5k\xaf\xbf\xfa\xa0R*\xb1\xee\xbdz\xf7\xee#\xdex\xe35o\xa7{x\xfc@\fo\x17x\xfc\x10\x94R\x9cz\xeaH\x00\xfe\xf6\xb7\xb7\xaf\u0634yK\xfb\xdd;w\u0680\xa1\xe9:\x86\xcfO\x93\xdc\xd6t\x18r\x06\x19m\xbb\xa0\xe9\x06f\xd5\x11\xcavmd\xff\xa65\x1c\u06be\x91pU\x05J)L\xd3\xd4\x1d)\xb1\x1d\u01e9\xae\xae\xe1\u0421\x83\u027bw\xef\xfe\xe3\x96\xcd[\u03999s\xfam\xa3F\x8d\x9e\xber\xe5\n\xb5r\xe5\n>\xfa\xe8\x03q\xe1\x85\x17)\xef\bxxxx\xfc\b\u0318\xf1U\x9d+O\xbe\u66ab\xe7\xb6\xcc\xcbW\x80\x85\x10J7|\xaay\x97^\ua497\xa7\xab{\xd7Ku\xcfw\x8e\xbao\x83\xa3\x9e\xd8\"\xd53[\x1d\xf5\xe0\xd2\xfd\xea\xca\x17>Q\xfd/\xbcZ\xa5\xe5\xe6\xff]X&!1Q\xa6\xa5\xa5\xa9\xf6\xed\u06ebs\xce9[=\xfa\xe8#\x1f\u06b6\x99Y\xf7\u0793&\xbd\xe1\x99\x0e\x0f\x0f\u03d9{\xfc\x18l\u0630A\x03\xe4\xf4\xe9\xd3z\x95\x1d>\xd2\xfdPq1\x80.4\x8d`R2\x9dF\x9eG\xab\xc1\xa7\x11\x8dJ|\xd2B\xf3\t4\f4M#%3\x9b\x93\xce<\x97\x13O=\x97\xc2u+Y\xf1\xc9$VM{\x8fhm\r\xb6\x94H\xc7\x11JJu\xe8\xd0!QYYIY\xd9\xe1\v\v\v\v{\xbf\xfa\xea\xcb\u007f\xbc\xfa\xeak?\x12B\xd8c\u019c\xa3=\xf0\xc0\xfd\xaas\u7b9eK\xf7\xf0\xf0\xc4\xdc\xe3\xdf\b\xb3\u803dq\u00e6v\xa6i6\x89E\xc2\x12\xd0p\x1c2\xf2\xdb\u04a6\xcf`t\xc0pb\x04|\x02\x03\xb0-\vi\x83\xa6\t\x10\x02C\xf7\u0476ooZu\xefM\x87\x81#\x98?\xe9iv\x16,AJI$\x12\x11J)4Mc\u02d6-\x1c\xe7\xc9'\x9f\x10II\x89\xea\xba\xebn\xf0\x0e\x8a\x87G\x03to\x17x\xfc\x10\xe6\u0319\xeb(\xa5\xf4\x85\v\x17\\\xb5x\xf1\u0493JJJ\x00\x84\xa6\xe9\xe4\x9f4\x90^\xe7\\\x8a\xdf\x1f\xc4'\x1c4\x01 @\x80B\xe1(\x85t\x14\xb6\xed`\xc5\x1c\x84\xd0\xc9\xed|\x02\xed\xfb\x8d\xc4\x17\brp\xebz,3\x86m\xdbH)\xd14\r\u02f2\u063f\u007f?\xd5\xd5\xd5\x1d\xb7n\xdd:\xfc\xfd\xf7\u07dd\xf3\xf4\xd3\xcf\x1c\x99={\x0eYYYb\xfc\xf8q\u031e=\xc7;0\x1e\x1eq4o\x17x\xfc\x13\xe4X\x96\u0569\xa2\xa2<\xae\xd6`\x04\x83\xa4d\u5498\x92\x8a\x81D\x17u+\xd1\x14(\x85T \x158\xb87KB,\x16\xa5\xb6\"L\x93\x9c\xe6\x9cu\xcb\xc3\\\xf9\u0707\xb4\xee\xd1\x1f\x00\xd34\xa9\xad\xad\xc54M\xa4t\xd4\u06b5\xeb\x983gn\xe7G\x1ey\xec\u04d2\x92\x03\xb9\x00\xaf\xbd\xf6\xba*--\xf5V\x17yxxb\xee\xf1\xafP[Se\x16\x15\xed\x8fX\x8e\x13Wk\b$$\xd18\xb39\x9a\x06\x02\x85&@\x8b\vz\xc3\u015c\ueb27B\x01\xb6\u0490B'\\S\x8be\xd9t\x191\x8a\u02df\xf9\x80\xbec/\x03\xc0\xb6mjjj\x88FcB\b\xa1v\xed\xda\u0152%K\xbb\xfc\xe1\x0f\xb7~\xban\u0777-\x00\x1e{\xec\t5c\u0197\x9e\xa0{xxb\xee\xf1\xcfR\xb4\xbfH\x84\xc3a\u0371\xed\xfa\xc7|\x81 \xa1\u4538\x11W8J \x95\xa83\ueba0\xbb&\x1d\xea\\\xbar\x1d\xba\x12:\u04b1\xa9\xad\xb6i\u05a6\x05\xe3\x1fy\x83\xb3n~\x88P\xa3d\xa4\x94\xd4\u0506\tG\"BJ\xa9\n\v\vY\xb7n]\xcfG\x1ey\xec\x8b\x193\xbe\xec\fp\xdaig\xa8\r\x1b\xbe\xf3B\x85\x1e\x1e\x9e\x98{\xfc3\xa4\xa4\xa4\xa0i\x9aRR\x1e}P\b\x94Tq\xe7-\u0730J\u0703\u02fa$\u0138So\x98\x86\"\x15\xd8R\xa0\x14(\xe9P]a\xe2O\xd09\xf5\x86\xbb\xb8\xe0\xde\x17H\xcdj\x8e\x92\x0e\xe1p\x98H4*\x14\xa8\x83\a\x0f\xb1a\u00c6\xae\xef\xbf\xff\xc1\x97\v\x16\xcc;\x1f\xa0s\xe7\xae\xce\u0319\u04fdq\xec\u1279\xb7\v<~(\u035ae\xeb)\xa9\xa9\xbe:\xd3\r`\x9b&\xe1\x8a#q]\x17\xf5\x95\xdb\xd4q\xff\x1f\r\xb7\xa8\xfa\u01dc\xb8\x93\a\xd7\xd5\xd7VE\xb1\xa5\xa2\xf7y\x13\x18\xf7\xd0\xeb4ks\x02(E4\x12!\x12\x8d\n\u02d1\xeaPq\t\u02d7\xafh\xf9\xe1\a\x1f~\xfc:\xad{\x0f\x06\xc0\x8eE\x89\x86\u00d8\xb6Cyu\r\xf3\xe7/\xe0\x93O\xa6<\xb6h\xd1\u009b\x00\xfe\xf4\xa7{\u055a5k\u0164I\xaf{\a\xcc\xc3\x13s\x0f\x8f\xef\xe3\xfe\a\xfe\xac\x03\xb4i\u04fa\xbcY\xb3f\xf5\x9a,\x1d\x87\xaa\u0483T\x1c\xda\x17\x9f\xect\xeb%\xba\x99,\xea8\xf9v\u007f\xaf\xe2.\xbc\xee/l)p\x94h\x10W\x17\xeeB\xa2\xea(\xb9\u077ar\xc1C\xaf\xd3a\xd0i\xae\xa0\x9b1\xccH\x18\u01d1T\xd4\u052a\xb9\xf3\x17\xf0\u059bo=\xb3`\xfe\u071b\x00\x1e~\xf8\x11\x15\x8b\u017cq\xed\u1279\x87\xc7?\xc0\x01h\u07fe\xfd\x16M\xd3\x0e\x01B)\xa5P\x8a\xea\xb2b\x8e\xec\u0749\xe1sE\xbc\xae\xc1\x84\x10 \x8e\x9f\xfa\x14\xaa~R\xb4>$\x03\xd8Ra\xab\x86a\x18\xe1\xc6\u02ebbd\xb5o\xc3y\xf7\xbfD\x87\x93G\xb9\x82n\x99\u0122a\x1c\xa9DyU\x8d\x9c5g\x1e\x93&\xbd\xf9\xccg\x9f~\xf2;\x80\ubbffQ~\xfa\xe9'\xde\xd8\xf6\xf0\xc4\xdc\xc3\xe3x\xfa\xf4\xee\xad\x00\x86\x0e\x1d\xbe==#cKBR\x12\xae\xc1\x96\xd4\x1c.\xe6\xd0\xf6\x8d\xf1\xa5\xfb\xc7\x0f\xa9\xe3\x03,\xc2\x15\xf4\x06\x8f\v\x14J\x81\x1d\x8f\xb3\x83B\x13\n\x81\xe6\nz\xb5Ef\xbb\x96\x9c\xff\xd0kt\x19y\xae{f1M\xccH\x18\xe98Zyu\xad\x9c\xbb\xe0k>\xfc\u88e7\xdf{\xf7\x9d\xdb\x01\u018e=O\xae^\xbd\xd2K[\xf4\xf0\xc4\xdc\u00e3!C\x87\x0e\x97\x80\x10B\x1c\xc8i\xde|k\x8b\xdc\\\x00[I\x89\x15\rS\xbag;U%\xc5\xe8\x86\xcfm\xff\u01b1\xee\\\x1c\u04e1P\x1c\xa3\xf3*\x1e\x9d\xc15\xfa\rD\x1f4\xcdM]\xac=b\x91\u05a29c\xef}\x81\ue9cfs\x05\xdd2\xb1\xcc(J)\xad\xaa6\xa2\xbeY\xb2\x8c\xaf\xa6O\u007ft\xea\xd4Oo\a\xe8\u0673\xb73c\xc6W\xde\xc2\"\x0fO\xcc=<\xea\xe5W\b\x9ey\xe6\x19\r\xa0u~\xfe\xdaF\x8d\x1b\x03\xf8\xa5m#\x1d\x87\xe2]\x9b9\xb4s\x13\xbe@\xbd<\xd7GR\xc41.\xbdAz\v\r&G\xd5\u047fQ\xf5r\xee\xfe\xa4\t\x01\xca!V\x15%-\xa7\x19c\xee~\x8e\xeeg\\T\xef\u042dh\x18)\xa5\xa8\xac\x8d\xb0h\xf1R\xbe\xf8\xe2\xabG\xe7\u039d5\x01\xe0\xb4\xd3NW\x0f,L3\x9a\xf7\u007f7\u07980{\xf6\xec\xb9\v\x17~\r\xc0k\xaf\xbd\xca\x17_|\xe1\x1dD\x0f\u03d9{\xfcz\xb9\xe1\x86\xeb]\xc1\x15\xe2\u0420\x81\x03\x16d\xba\xee\xdc\xcd\x15\xb7,\xf6|\xbb\x94\xdd\x05\x8bQJa\xf8|GE\xbb>\x98\u00b1\xf1\xf3\xfag\x1f]`TW\xac\xcbQ\x02[\x1d\x9f\xc4\xe8.0B\b\x94c\x13\xaeth\u0465\vg\xdc\xf9\x14i-\u06c0RX\xb1\bJ\xda\xc2r\xa4Z\xb7~\x13\x05\x05\x05\xb7\u035e=}\f\xc0\x94)\x93\xf5\xab\xaf\xbe\xc6;\x90\x1e\x9e\x98{\xfc\xba\xb9\xf6\u06ab\xeb\u007f>}\xf4i\x9ft<\xa1\x83\n%$\xba\x8a\xac$\xe1\x8a26\xcd\xff\x9c\u0292\x03\xf8\x03:\xba\x00\xedh\xbb\x8a\x06\x01\x95\x06%\x15\x1b8\xf2\xba`\x8a#AJ\x15\xaf\xaa\x18\xbf\xc5\v\xbe\xd4M\x90\n\x01\xca6\x89\xd5Z\xb4\xedw2\xa7\xfd\xfea\x12S\u04d0\x8e\x83m\xc6\x10(Q\x13\x8eX\x9b6oe\xc6\xf4YW\x01\x9c{\xee\xf9\xce\u0295\u02fdq\xef\u1279\u01ef\x9bn\xddz0y\xf2\xc7\x00\xe4\xe7\xb7^\u04a3[\xb79\xd99\xd9\xf5Z,m\x8b\u00b5+(\\\xbb\x1c!\xc00\f4\xa1\x8e6\xach \xe0\xa2\xc1?nhE\"m\a\u01f4pL\x13\u01f6\xdd>\xa2\xf1a\xea\x98Ql3\x86m\xd9HG\xba\xb1u!P\x8e\x85\x15u8q\xf4\xf9\f\x9ax\v\bp,\v\xdb4\xd1\f\xdd\xd8Y\xb8\x97\xad\xdbw\x8c\xfe\xf8\xe3\x0fo\x04\xe8\u077b\xaf\xfa\xee\xbb5\xde\xc1\xf4\xf0\xc4\xdc\xe3\xd7\xcd\xf9\xe7_P\xffs\xcb\x16-\x1e\xec\u043e\x1dqw\x0e@e\xf1~\xd6N\xff\x98\u02b2rt\xbf\x8e@\xb8\x0e\xbd~y\u007f\u0709\xd7?\xa6PR\"-\xcb\x15k3\x86c\x9b\x14\x16,a\xf6Sw1\xf7\xaf\xf7rp\xdb\x06\x84\xeesE:\x1a\x8d\xf7\fu\x90\n\x84\xa6\xe3X&\n\xe87\xfez\xba\x8d\x1eW/\xfe\x8ei\nG*\xb9u\xfbN\xbe-\xf8\xf67J\xa9\x96\x80\x9a9s\xb67\x19\xea\xf1\x8b\u009b\x00\xf5\xf8\x97\x989s\x86x\xf7\xdd\xf7\xf8\xec\xb3\xcf\x0f.[\xb6\xb4WQQQ\x9b\xca\xca\xca\xfa\xdf\xd7\x1c)\xa1i\xab\x0e4?\xa1\x13\x8eS\x97\x9a(\xe2\xf9\u3abe\xad\x9c\x06(i#-\vi\xdbH\xdbB)\x89c[\xac\xf9\xfcmV|\xf0\x02\xfb\xd6-\xa7t\xf762\xdbu%9#\x13;\x16E9\x0e2\xde$C\x17\x02M\u05f0-\x8bPr\x12\xa9-:\xb0k\xd5\"j\x8f\x94 \x1d\x1b\xc3\xf0\x8bp4\x8a\xa6\x91n\x9b\x91\xa2i\u04fe\\6g\xce\\f\u039c\u03bb\xef\xbe\xe7\x1dL\x0f\u03d9{\xfcz\x195\xea4w\xe1\xbd\x10V\x97\u039d\xa6\xb6i\u075a@0T\xff\xfb\xda#\xa5\xac\xfd\xea#*\x8b\xcb\xf0\x05\xf4z'\xae\x8b\xa3\v\x88\x04\xa0\xa4\x04\xdbF\xd9\x16\u04b6\x90\x8e\x83\xb4,t\xdd 5;\x8fPr*\x00\xbbW.\xe4\x9bIOR]V\x8c\xee\xf3!-\x13\u01ccaG\xa3\u0626+\xee\x9a\xd00\xc3&M;t\xa6\xcfe7\xa3\xf9\xfc()1c\x11\xa4\x92l\u0676\x83\xd5\x05k\xae\t\xd7V\xe7\x02L\x9c8\xd1s\xe7\x1e\x9e3\xf7\xf0\xa8\xe3\x8b/\xbe(.(X5\xbch\xff\xfef\xb5\xe1\bR:\x00T\x1c\xdaKJ\xb3\x1cZ\x9e\xd8\vi+\x94\x92\xf5\x8b\x81\xa4\x02\xa9\x14\u02b6Q\xb6\x8dt,\x1c\xc7A92\xbezT\x91\x9e\xd7\x16\xcd0(\u0779\x19\xc74)?\xb0\a#\x98@\xf3N'!m\x1b%%B\xc9x-\x18\x88w\x95F\t\x1f)\xf9\x9d)\u07fb\x9d\xd2\xed\xebQn\x03j,[\xe2\xd8vZ\xf9\x91\xb2\xb2\xf9\xf3\x17|SSS\x8bR\x92\xfb\xee\xbb\xcf;\x88\x1e\x9e3\xf7\xf8\xf5\xb2c\xc7\u05b89\xd7\xf6\xf5\xec\xd9\xf3\xf5.\x9d:\x11\b\x06\xd0\r\x03\x003\\\u02ea\xcf\xdf\xe1\u040e\x1d\x18A\xb7\x00\x97T\x10\xb3%Q\xcb\xc1q$B)7\\\"\x15\x9a\xaa\x13g\x89c\x99\x18\xfe }\xc6]\xcf\xc0\x897\u04e8i6V4\xc2\xe6yS)Z\xbf\x1a\xdd\x1f@96R\xd6M\x9a\x9a(+\x86\x94\x92X$\x8a\x11\xf4\xd1k\xfcoIHM\a\xeaV\x88\xc6\xd8[T\xc4\xe6-[\xafUJ\xba+\x9e\x84\xf7\x15\xf0\xf0\x9c\xb9\u01ef\x9c\xe7\x9e{\x9e/\xbf\x9cf\xbc\xff\xfe\a\xf2\xb3\xcf>\xdf\xf5\xdd\xfa\xef\x86\x1eY\xe7zWN\x99\u0136of\x12Lr\x1d\xbbO\x17\x04}\x1aZ\xbc\u035c\xc2\x15b'\xde4T(U\xbfX\u050aF\x90\xb6M\x97Q\xe7\xd3\xed\x8c\xf1\x18\xc1\x10;\x97\xcfg\xc7\u04b9h\x9a\x8e\x00\xa4\x94\u060eD:\xd2\x15w\xe5\x80\x19!\x10\xd4\xe8|\xda8B)\xae;\x97\xb6I,\x16\xa5\xb8\xb8\x84\u056b\v\xaePJ5\x05\x188p\x90w =<1\xf7\xf8al\u07bc\xe1\u07dal[\xb3\xa6\xe0\u007f\xb2\xea\x9f\x10\x82\u0673g\xba\xd5\x14/\xbaxr\xabV\xf9S\xf3Z\xb6@\xd34G\xb8\xa5\x0e\xa99\\\u02827\x9e\xe4\xf0\xde\x03$$'\xa0\xa1\u0705D\x02\x948Zd\xcb\xed\x17\x1a_\xbc_W\x17W)\xcch\x18!4:\x8f<\x8f\xfc\x9e\x83\x88V\x1da\xc3\xec)\x1c.\u070e\x11\f\xe1H\x85\x94\xf1\xd5E\xd2A96\xb6\xe3\x10\x8bJ2\xdau\xa5\xc3\u0433\u074dU\n\u01f69|\xa4\x9cM[\xb6\xb4\xff\xec\xd3O\xeas,\xa7O\xff\xd2\x1b\xa4\x1e\x9e\x98{\x1c/\xdc\x1b\xffN\xb8;v\xec\xac\xfe\x9d\xd7\xec\xde\xfd$\x95\x95\x95\xf3w\x8f\xef\u06f7\xe7\xbf\xfaY\x8b\x8a\xf6\u04a2E\xbe\x9a>\xfdK\r\u0b33\u039a\x94\x97\x97\x17m\x94\x94\xe4\xf3\x19>U\x97W\xbec\xf9|\xbe\x9e\xf4$2f\x13LH<\xdaRN\xd3\x11\xba\x01B\xe0H\x85-\xdd0\x8b\x8aOl\xd6aE#4JoF\xd7\xd1\xe3Hm\u078aC\u06fec\u04c2/\x88\x86k1|~\x90\x12\u02d1\x98\x96\x83m\xdb\b\xe9\xe0\xc4\xc2\x04\x1b5\xa6\u07503\xf1\x05\x13\\w\xee\xd8D\xa2QJJ\xcbX\xb0p\u163a\xd7\x1f=\xfa\fo\xe0z\xfc\xac\xf1R\xb3\xfe\r\x94R\u031f?W[\xbbv\x9d\xb6k\xd7N\xfd\x85\x17^\x8a\x1d\xf7\xfb\x04)\xed\xc0\u0739s\xd2g\u03de\xa3L\xd3N\xea\u07ff\uf165\xa5\xa5I\u06f7\uf215\x96\x96\x12\x0eG\xb0m7\x93C\xd7u\f\xc3 11\x91\xa6M\x9b\x92\x97\x97\xe7\xcf\xc8H\x0fo\u077au\xea\x91#\x87\xcbN9\xe5\x14\u0577o\u07f2\x9c\x9c\x16\xa6\x10\"|\xdc\xe6\x18\x8f=\xf6\xa8\xc8\xc9\xc9v.\xbe\xf8\x12)\xc4\u007f\xef\xd0>\xf8\xe0\xfd\x0f|\xf5\xd5\xf4\xbb7n\xdeJ$\x1cV\x96e\n\xe2\x19'g\xdd\xf9\x17\x06^z\x13\b\x81m\u0190\nl\xd3$V[K4\x1aA\xd96B\x88x\xfdrw\x88\xaa\xb8\xab\xd6t\x1dG\x18,\xfb\xf8u\xd6M~\x89\x84\x944\x86\xff\xdf}\xb4\xee=\x18+\x16\xc1Q\x02\x89@7\f\x94\xe1G\xe9>\xfc\t\x89\u012a\x8e0\xe3\xc1\xeb\xd9<\xf73\x00t\u007f@\xa56N\x16}\xfb\xf4\xae\xbe\xf7O\xf7\\\u052bw\u07ef\x00\xbe\xfbn\r]\xbbv\xf7\x06\xb6\x87'\xe6\xbf&\xbe\xfa\xea\v\xed\x0f\u007f\xb8\x85\xad[\xb7\xca\x06\xe2ml\u0630\xb6\xcd\xe4\u025f\xa4WUU\xb7\xf6\xfb\x03\xc3\xf7\xed+\xca\b\x04|\x03\x0e\x1e<\x94\xb4\u007f\xff\x01\xc2\xe10\xb1X\x94X\xcc\xc4i\xb0\xf0E)U_\x94J\xd34\fC\xc7\xe7\xf3\xe1\xf7\a\b\x85\x82dee\u046cY\xb3\x9ah4\xba8''\xa7\xaci\u04cc-J\xa9UC\x86\f\xd9;h\u0410\"!DM\xddv\xa4\xa5\xa5j/\xbe\xf8\"\x17\\0\xee\xbf\"\xeaJ\xa9\x8c\x1b\u007f\xfb\xdbY\u04e7\xcf\xe8^\\\\\x8c\x15\x8bb[\x16\x00\xa1F)\x8c\xfd\xd3_\xe9u\xee\x04\xa2\x11\a\xe9\xd8\u0636\x85Y[K,\x12\xc1\xb6,\x84R\b];Z\x90K\xc5\xc3/Rb\x1a\t\x1c\u06b7\x97o'=\xc8\xfe\xb5\x8bi?\xf8L\x86]\u007f7\xc1\xe4\x14b\xd1\x18a\a\xfc>\x03\u007f\xc0\x87\xa3\xfb\xd14\x8dPJ\n\x05\x1f\xbd\xca\xf4\a\xae\a%\xd1t\x03\u007f {\x9d\xd4C\x1b}\u06a8G\xee\xbc\xeb\x8fwy#\xda\xc3\x13\xf3_\t\xf3\xe6\xcdf\u0630\x91L\x9a\xf4\x12\x13'^W/\xbcJ\xa9\xd0\xec\xd93\xfb\u035a5+\xaf\xa4\xa4\xb4\xb7eY\xa7TTT\xb4\u06f3\xa7\x90\x92\x92\x12,\xcbB)E0\x18\xa4q\xe3\xc6$''\x93\x9c\u0708\x84\x84D\x12\x12B\x04\x02\x01t]G\xd7uw\"\u03f6\x89FcD\"a\xc2\xe1\b\xd5\xd5\xd5TUUQQQA4\x1a\x05\xc0\xe73h\u04a4\t\xf9\xf9y4i\x92V\u0628Q\xa3e\u035b7_\u06f6m\x9b\xe5\x13&\\\xbaR\b\x119\xea\x92\x1f\xc4q\x14\xfd\xfa\xf5d\xe4\xc8\xd3~\xd2}t\xf7\xddw\xf1\xe0\x83\x0f\x030k\xd1\xe2S\x9e{\xfa\x99\x99\u02d7.\xf6\xd7VWc\u01a2\xc8x\xbewjV.\x17<2\x89\x0e\x83\x87\x13\xad\xb5\xb1\xad\x18v$\x82\x15\tc\x99\x16\x8eTG\xfbV4\xa8\xb4(\x95\xa2*\xea@0\x89\x03K\xbed\u065b\x8f#\x1d\x87\xc1W\xdfA\xe7\x91c\x89DbT\xc7,\x82>\x83P\u0407\xd2\xfdh\x86N\xa0q\x13\x0emY\xcb\u053b.\xa3x\xdbw\bM\xc3\x1f\bZ\xad\xf3\xf3|C\x86\f\xfa\xfa\x85\x17^\x1a%\x84\x88\x1e<\xb8Ode\xe5*o\xb4{xb\xfe\v\xa4\xa4\xe4 M\x9bf\xfd\xdd\xe3{\xf7\xee\xea2y\xf2\xa7\x97-_\xbe\xbc]MM\xcd\xe0\x8a\x8a\x8a\xe4\xad[\xb7Q[[\x8b\xae\x1bdee\u04be};\xf2\xf2\xf2\xc8\xc9\xc9&++\x8b\x8c\x8c\f22\xd2INN&!!\x81P(\x84\xdf\xef\xbaGW\xcc\x15\x8ec\x13\x8b\u0148D\"D\xa3Q\xaa\xaa\xaa)++\xa3\xa4\xa4\x84\xe2\xe2b\x8a\x8a\xf6SX\xb8\x97\xed\u06f7\xb3\u007f\xff~b\xb1\x18\xc1`\x90\xb6m\u06d2\x9c\x9c\\\x15\f\x06\xbe\xee\xd9\xf3\xa4\xcdc\u01ce\xfd\xb8{\xf7\x93\n\x8e\xdf\xee\u077b\xb7\x93\x9f\xdf\xf6'\xd9W\x05\x05\xab\x985\u007f\xa1\xb8\xeb\xd6[\x15\xc0\v\x93\xdez\xf1\x93\x0f?\xbc~\xf5\u0295\u0122\x11e\u0162\xa2.\x0e\u07b2[\x1f\xce}\xe0Ur\xbbv%R\x15\u00caF\xb0\"\x11wE\xa7\xe3\xb8\xcd+\x94jP[\xd1Mo\x89\xda\x12\xcd\xf0#\xec\x18\x8b_\u007f\x94Ms>#\xf7\u013e\x8c\xb8\xe9A\x82\xe99T\xd7F0\f\x9d\u0120\x81\xe1\xf3#u\x1f\xba?\x00\x02f>\xfc\x1b\xd6|\xf6\xa6+\xe6\xfe\x80\u04f8qc}\xc8\xe0\x93\xf7>\xf5\xd4\xe3\x17\xe5\xe6\xe6/\xfd\xfc\xf3O\xc59\xe7\x8c\xf5\xc4\xdc\xe3g\x89\xe1\xed\x82\xefg\u0294\u027c\xf3\xce;\xa2i\xd3,u\xdc\xe3\xe7}\xfe\xf9\u0511\x97]v\xc5\u041a\x9a\xda\xd6;w\ue92a\xaa\x8aF\x8d\x1a\xa9.]:\x8b\x9e=O\xa2{\xf7\x1e\xe4\xe7\xbb\"\x9e\x91\x91Abb\xf2\xf1\x81\b@\x1d3\xc9W\xf7\xbf\x887np\xd3\xfa\xfe\xbe\xf2w8\xec\x8a\xfb\xc1\x83\a),\xdc\u02da5k((\xf8\x965k\u05a8\x8a\x8a\xaa\u4924\x843\xf7\xef\xdf\u007f\xe6\u0085\x8b.\xbc\xfc\xf2\xcbV\x8c\x181b\xf2\xc5\x17O\xf8\xa4\xee\xf9uB>s\xe6tF\x8d\x1a\xfd\xa3\uecd3N\xeau\xd4J\x037L\xbc\xec\xee\u28bd9\xd5\x15G\xce\u06bcy\xb3@\xf91c&\xa0(\\\xb7\x82\x99O\xdf\xcd\xd8\xfb^\xa2I\xf3\x1cl\xdbF7,\x94\xae\xa1\x94\x83-\x05R\xe0\x86\\\xe2\xcbF\x95\x02\xbf\xae\xa1\t\a\u007fr\n\x1dO9\x93\x03\x1b\v8\xb4e-[\xbe\x9eA\x971Wa\xe8\x1aR),[\xa1\xeb\x0eB\xd3Q\x8eE(5\x85\x8cV\x1d\xdd}-%RJ-\x12\x8b\x12\xae\xad\xcd]\xf4\xf57\ud065;v\xec\x10\r\xb7\xdf\xc3\xc3\x13\xf3\x9f1_}\xf5\x05\x8b\x16-\x12\xe7\x9e{\xfe\xd1\xc6\xf1J\xa5\xbd\xf9\xe6\xeb\x17O\x9d\xfa\xc5\x19\x0f>\xf8\xf0\xc9ee\xa5\xc1\xe2\xe2\x12\xfc~\xbf\u0763G\x0fN=u\x84\u07bbw/\x91\x9f\u07caf\u035a\x92\x94\u0538^\xb4m\xdb$\x1a\xad=&3\u37c9c\x1f\x15{\xb7\xff\xa5\xdf\xef\xa7E\x8b\x96\xb4h\x91O\x9f>\xfd9\xf3\xcc3(--e\xf7\xee=b\xe5\xcaUj\xee\u0739\xce\xea\u056b\u067auk\xcb\xed\u06f7\xb7\\\xbd\xba`\xf4\x84\t\x13\xee9\xf5\xd4\x113&L\xb8\xf4q!\xc4\x11\x80Q\xa3Fs\ubb77\x88!C\x06\xab\xd3O?\xf3G\u0747u\xf1\u007f!\xc4\x11\xa5\u0504CE\xfb>\x8aE\"\xa7\xed\u06bd\xcbM54-@\xb1i\xc1\x17$7\xcba\xf4\x1dO\xe3OL$b\x9a\b\xc3@H\x89\xa6\x1c\xa4\x12G\xd3\x14\x1b4\xa9PRa\x9bQ\xb2;\x9dD\xab\u07a7\xb0\xf6\u02ff\xb1c\xd9\x1c\x9au?\x99\xf4\xbc\xf6\u0122\x11L\xdb\x01M#\xa89 u\x90\x90\x9c\x99K09\x95hU9JI\x11\x8b\xc6,\xdbq|\xc5%\xa5\x1d\x00\xaa\xaa\xaa\xbd+U\x0fO\xcc\u007f\tTU\x95\x8b\xe4\xe4\u0506mox\xf6\xd9g\xae\xba\xf2\xca+\xee[\xb6ly\xf6\u07bd\x85\x84\xc3\x11\xb2\xb3\xb3\xcdq\xe3.\xd0/\xb8\xe0|\xa3{\xf7\x1edd\xa4\xe3\xf3\x05\x01\xb0\xed\x18\xe1p5J)4M\x8b\v\xb7@\xd3\xfe5\x9d8^\xf8m\xdb\u01b2,\xa4\x94\b!\xf0\xf9|\xb4h\x91O\x8b\x16\xf9\f\x18\xd0_\\~\xf9\xa5\xc6\xfa\xf5\x1b\x98:u\xaa3g\xce\\\xb9}\xfb\x8e\xa4\xfd\xfb\xf7w]\xb3fM\xd7\xf9\xf3\x17\\\xfe\xfa\ubbfd|\xe5\x95W\xdd/\x84\x90O<\xf1\xa4z\xe2\x89'9r\xa4T4i\x92\xf1\xa39R!\x04J)\xee{\xf0\x01\x9f\x10\xa2z\u03de\x1d\xf7\xff\xe5/\xcf\f\xa8\xae\xaeJ.--SJ)a\xdb6J)\x96\u007f\xf82\xfe\xe44\x06\xdf\xf0gT\xa0\x11\xb1\xa8\x89\xc2F)\a\x15oN\xd1\xf0\xe2\xa4.\xd5Q:\x0e\xbeP\x02\xed\x06\x8f\xa6p\xcd\x12\xcavof\xd7\xf2\xb9\xa4\u4dad\x0f\xc98\x8e\xc4r\x14>]\"\x1dE\xa3\xf4L\x12\x1a7\x89\x8b\xb9['\xecHy9\u06f7os\xdc\x10\xd4n\xefK\xe0\xe1\x89\xf9\u03dd\x993\xbf\u0493\x93S\x9d\xb8\xb3\f=\xf3\xcc3#\x97.]r\xe3k\xaf\xbd>\xa2\xa8\xa8\x88H$B\u01ce\x1d\x195j\xa4\x1a3f\x8c\xbf[\xb7\xae\x04\x02\t\xf1g;XV\xf4hIV\xfd\xa7\xab\x92P\x17\x86q\x1b&\xbb\xab\x1fc\xb10B\xb8\xae=##\x93\xa1C3\x192d\xb0\xbe{\xf7n\xfd\xf3\u03e72m\xda\x17j\xed\xdau\xe2\xc0\x81\x03\xcd\n\n\n\xee\x9d5kV\xffg\x9e\xf9\xcb\xf37\xdd\xf4\xfb9B\x88H\x93&\x19j\xe6\xcc\xe9\xfa\xa8Q\xa3\x9d\x1fs;\xcb\u028a\xed?\xdf\xf3'\xf2\xf2\xda,_\xb4h\xc1\x05EE\a\xfe\xb6d\u0252\x8cp8\xecD\xa3\x11\u0772\x1dP\x8aE\xaf>\x04\xbaA\x9f\x89w \x83\xc9D\xa2&8\x02\xa4[tK\b04\x81\xae\xc5\xc3N\xc2]d\xe4\xd8\x0e\xe9m:\u04e2\xd7\x10\x8e|6\x89}\xab\x16\xd0\xf2\xa4!4m\xd3\t\u06cc`\xa1\x10\x8e\u0110\x12\u01f2\t5iJ0\u0794Z\u0157\xf7G\xa31\x8e\x1c)\a\xa0\xbc\xbc\x9c\x993\xa72j\xd4\xd9\xde\x17\xc2\xc3\x13\xf3\x9f\x1b;vlc\xc0\x80\x93\u0168Q\xa7;\x00K\x96|3\xec\xe6\x9b\u007f\u007f\xc7\xe2\xc5K\x86o\u0672\x95H$\xc2\t'td\xec\u0631j\u0738\vD\xbbv\x1d\xc5\xd1\x10J\f\xc7q\xfe'>\x87R\x8aX,V\u007f21\f\x1f\xad[\xb7\xe3\xe6\x9bo\xe5\xe2\x8b\u01cb\xa9S\xa71y\xf2dV\xacX\xc9\xee\xdd{F\x14\x16\xee\x1dQX\xb8w\xee\u0085\xf3\x1e\x1d2d\u063cQ\xa3F;-Z\u42af\xbf^\xa8\xf2\xf3[\xff(\u06d4\x9e\xdeL-[\xb6X\xf4\xeb7P\r\x1at\u02ac7\xdex\xedV\u04cc\xbd\xb5r\xe5J\xddql\th\x96e\x03\xb0\xe8\xa5\xfb@)\xfa_u\x17\xaaq\x1a\x91#%8\xb6\u0114\uef02O\x13\x04\r\x1d]S\xf5\u92a6i\xa2\x05\x13\xc9:i\b;\x96\u03a6\xa2p\x1b%\x9bV\u04fcCg\x94\xa90\xa5\xc4q$\xd2qP\xd2\u0097\x90T\xbfx(\xfe\x12H\xa5\x88F#\x0e@ff3O\xc8=~\xb6\xfc*c\x84EE{\x99:u\x1a7\xde\xf8\u007f\r\xc50\xf9\xa6\x9b~{\xe5\xb6m\xdb\xfe\xbca\u00c6\u48a2\xfd\xe4\xe66g\xfc\xf8\xf1L\x980\x9e\u039d\xbb\u015d\xb0uL~\xf8\xff\xf4\xc1\x15\"\x9e\xf6\xe8\a\xe0\xc0\x81}|\xfc\xf1d\xde~\xfb\x1d\u05ad\xfb\x8e\xec\xec,\xbat\xe9R\u0561C\x87??\xfd\xf43o\b!\xaa\xea\x9e\xfb\xf6\u06d38\xe5\x94Sh\xd1\"\xff\xdf\u078e\xab\xae\xba\x92\xd7_\u007f\x03\x80G\x1ey\u8669S\xa7\u0774e\xcb\x16,\xcbR\xa6i\t+\x9e\x83\x0e\xd0\u007f\xe2\xad\xf4\x9dx;\x18A\xc2e\xc5\u0636\x8d\xe9Hl\x05\xba&\xf0k\xe0\xd3\xdc@\x8a\xa3\x14\xd2\x1f\xa2\xb6\xb2\x825o?\xce\ue15f\x93?`\x14C\xae\xb9\x93\xa4\xd4tjL\x1bt?\xc1\x80ABR\x12\xb6\x19e\xca\xed\x17\xb3s\xe9\x1c4]\xc7\b\x84\x9c\u071cl}\xf4\xa8\x11\x9f>\xf7\xdc\xf3\x13\x84\x10\x91\xc2\xc2]\xa2e\xcbV\xde$\xa8\xc7\u03ce_\xe5r\xfeo\xbeY|\x8c\x90/^\xbc\xa8\xef\x84\t\x17\u007f5s\xe6\u033f\u031a5;\xf9\u0421b\u018c9\x87\xd7^{\x95G\x1f}\x84\u039d\xbba\xdb1b\xb1p}\xbc\xfa\xe7\x80R\n\u06f6\xe3\xdb\x1d%;;\x97\xdf\xfd\xee\x0f\xbc\xf1\xc6k\xdcp\xc3\xf5\xc4b&s\xe6\xccM\x9e1c\xc6_.\xbf\xfc\xb2\xaf\u05ac)\xe8[\xf7\xdc\xcb.\xbb\x82\xa5K\x97\xfd(\xdb1n\xdc\xd16sw\xde\xf9\xc7\xdf\xf5\xee\xddkR\u02d6y\x18\x86!\x02\x01\xbf\xf2\xfb\xfd\xf5s\x03K\xdf|\x82yO\xddL\xf8\xf0A\x92\u049a\x12\xf0\x1b\x18\x9a\xc0\xd0\x04R*\xa2\x0e\x84-E\xad%\x89\xd8\xeed\xaa/)\x85f\x9d\xfbb\x84\x12(\u0771\x9e\x8a};\t\x04\x02\b\xe9\xa0\xe2\xee\u0736\x1d@\xa05\x98\x83\xd04!\"\x91(MR\x9bt\x06\xda\x03\u0636\ud578\xf0\xf0\xc4\xfc\xe7\xc0\xa2E\v\xc5E\x17\x8d\xaf\xbf\xff\xf8\xe3\x8f]\u007f\xd7]w\u007f2k\u05ac\x81\u06f6m'??O>\xf2\xc8\u00fc\xfc\xf2\x8b\x9cz\xeai8\x8eM$R\xf3?\x13N\xf9W\x91R\x12\x8d\xd6b\x9a\x11z\xf4\xe8\xc5\x13O<\u018b/\xbe@\x9f>}\xe4\xb6m\u06d81c\xc6\xc0[n\xb9e\xf2s\xcf=\xf3\x1b\xa5T\xc0\x15\xe1\xf1\u03181\xfd\xdf~\xef\xe1\xc3Oe\u0294\xc9\xf5\xf7\x9f}\xf6\xafw\x9e}\xf6Y\x85\xb9\xb9-\x10B\b\xbf\u07e7|>_\xfd<\xc0\xba\xa9o3\xeb\xa1\xeb)\u07bc\x8a`\xe3&\x84BA\fA\xbc@W}).\xb7\xe2\xa2\x02#\x10\"\xa5U'\x92\x9a\xe5R{\xb8\x98\x8a};\xb0L\xab\xfe\xaf\xed\xf8D\xaa\xb2-l\xdb>\xbaO\x14*\x10\nRU]\xb5\x1d\xd8\x1d\x0fQy\xae\xdc\xe3g\u026f*f>o\xdelm\u0420!2\xeeZ\x1b\xdd~\xfb\xad/\u007f\xf4\xd1\xc7\xe3\v\n\n\x00\x9cQ\xa3N\x15w\xdcq\x9b6x\xf0\x10\xc0\xcd\xe9\xd64\xad^d~\xf615!\x90R\x12\x0eW\x13\f\x069\xff\xfc\v\xe8\u05ad\x8b\xf6\xdcs\xcf\u02f7\xdf~G\u035b\xb7\xa0yuu\xcds\a\x0e\x1c\x1c\xa0\x94\xbaB\b\x11>\xed\xb4\xd1,]\xbaX\xeb\xdf\u007f\xe0\xbfu9r\xee\xb9\xe7S^^Fjj:B\x88\x92}\xfb\xf6^\\YY\xf5\xf1\xb4i\u04f2\x8b\x8b\x0f\t\xbf\u07e7\x84\x10\u00b2m\xa4\xe3\xb0{\xd6vD[\x00\x00 \x00IDAT\xf9\\j\x8a\x8b\xe8?\xf16\xf2\xfa\x8e !1\x89\xda\xdaZ\x1c\xe9\x80\x10\bM\u00f6lJ6\xad\xc0\xb1LR\xf3;\x92\u07be\a\x15\x85\xdb(\u07f7\x93hM9\x9a?\x19G)lGaK\x90\x910\x8e\x19\xab\xdf\x17\x80\n\x85B\x1c8pp\xa3\x10\xa223;K\xcb\xcd\u0353\x9e,xx\xce\xfc\u007f\x98\xd7_\u007fM\x1b6l\xa4\x04X\xb1bY\x9f\xf1\xe3/\x9a\xf5\u99df\x8d/(( 11Q\xddv\xdb-\xda\xdf\xfe\xf6\xb66x\xf0P\x00\xa2\xd1\b\xba\xae\xf3\xdf,X\xf5S\t\xba\xae\ub626\x89\u3634k\u05d1\xe7\x9e{Z{\xfa\u99f4\xbc\xbc\x96j\xe5\xcaUL\x992\xe5\xc2\xf3\xce;\xf7\xf3\x82\x82\xd5]\x00\xfa\xf7\x1f(?\xf8\xe0\xbd\u007f{\xac\xa4\xa6\xa63c\xc6W\x1a@nn\x8b%c\u01desf\x8f\x1e=\xf64i\x92\x86\x10B\x05\x02~\xfc>_}6P\xe9\xee-\xcc|\xf4&\x96\xbf\xf98\xe1\xb2\xfd$%7\xc6\xef\xf3#\xa4D\xd7t\x90\x0e\aV\xcfc\xcd[\x0f\xb3o\xe9t\x1ae\xb6@\xf7\xfb).\xdcAuy9\x9a\u03c7\x94\n)\x1d,\x05U\xe5e\xc4j\xea\x9aN\v\xea\u02a6\u06cek\xd7'\x8c\x1f\x1f\xb8\xf3\xce;|g\x9ey\x86~\xe3\x8d\xd7\ubbfe\xfa\xb2>g\xce,}\u04e6\rZ\xc3u\x02\x1e\x1e\x9e3\xff/\xf1\xc8#\x0f\x8b\xab\xae\xbaZ\x02|\xfc\xf1G\xe7>\xf1\u0113o-X\xb00\xe9\xf0\xe1\xc34o\x9e\xa3\xee\xb8\xe3vq\xe3\x8d7\x00:\xb6\x1dsK\xa8\x8a_\xf6\u0730\x10n\xd7\x1f\xc7q\xf0\xfbC\\u\xd55\"77\x97\xbb\xef\xbeG\xae^]\xa0UTT\x8e\b\x85\x9e^2}\xfa\x97\x13G\x8f>c\xcaE\x17],\x9f}\xf6\x19q\xd3M\xbf\xfb\xb7T\xed\xb4\xd3N\x97\xef\xbf\xff\x9e\x18?\xfeb5x\xf0)\u07fe\xfa\xea+cm\u06da\xf2\xed\xb7k\xf2\xcb\u02cfH\xc3\u0405\x10BX\x96\x1b\x12\x89\x85\xabY\xf5\xc1\xf3\x14o]G\xb7\xb1\u05d0\u0575?\xbe\xe4T\xccH-\t\t\x89d\xb4\xeeD\xe1\u0499\xec\x98\xfd1M\xf2;\xe0\v%RUz\x90\x8a\xcaJ\x82\xb9\x06J\xc4\xdcu\xb4B\x10\xa9\xac \x16\xae\x89\u007f~\x90\xd2\xc1\xef\xf7\xd3(\xa9Q-\xc0\x93O>\x15\xf9G\xdb=p\xe0@\xfdO\u007f\xba\x1b\u01d1j\xf8\xf0a\xea\xe4\x93\a(\xc3\b\xb2g\xcfN\xf2\xf2Z{J\xe2\xf1\xdf\xffN\xff\x92?\xdc\xef\u007f\u007f\x13\x8e\xe3\x88\xe7\x9e{^\x01<\xff\xfc_\xc7N\x9b6\xed\u0765K\x97\x85jjjh\u06f6\xadz\xfc\xf1G\xc59\xe7\x8c\x05\xc04#\xfcZ\x1dX \x10\x044\u05ae\xfd\x96;\xee\xb8S\u035a5[\xa4\xa44f\u0420A\x911c\xc6L\x988\xf1\x8aO\x01n\xbd\xf5\x16\xe1\xf7\xfb\xd5C\x0f=\xfcO\xbf\u01de=;\xf9\xeb__\u2a67\x9e\xe4\uaaef\xe6\xb5\xd7^\x03\xe0\xbd\xf7\xde\xed>u\xea\xd4OV\xacX\u046a\xa4\xa4\x04!4%\xa5\x8c/,r\x87\xa9t,\x92\x9ad\xd2\xfe\x941\xb4\x1dq.\xa9y\x1d\x11\x02\xecX\x94\xed\xf3\xa6\xb0i\xc6\xfbD*\x8f\xa0l\x1b4A\xff\xdf\u00d0\xb1(J@Bj\x06{\x17\u007f\xc1\xdc\xc7~Cmy\x19\x86\u03cf\x12\x9a\u04f6Mk}\xe4\xf0\xa1\u04c7\x0f\x1b\xf6F\xd1\xfe\xfdM5M\v\xef\u077bw\xe5\xc9'\x0f\x8c\x0e\x1f>\xd40\x8c\xa0\x01\xec\xfd\x9e\x92\xc3\xc7T\xba\\\xb6l\t\xfd\xfa\r\xf0\x14\xc5\xc3\x13\xf3\x9f\x82\x1bn\xb8^\xbc\xf8\xe2K\n\xe0\xc5\x17\xffz\xfaG\x1fM\x9e\xbcr\xe5\xaaP$\x12\xa1[\xb7\xae<\xf9\xe4\x13\f\x1f>\x12)M\xea\xf2\x9d\u007f\u0543A\b\xfc\xfe\x10\x85\x85\xbb\xb8\xf3\xce?\xf2\xe1\x87\x1f\x92\x90\x90\xc0\xc0\x81\x03#\xe3\u018d;\u007f\xe2\xc4+\xbe\x02\xb8\xed\xb6[\xc5\xe3\x8f?\xf1\x0f\xcfz\xdf~\xbb\x9a\x1e=z\xfeS\xef]SS\xde\xea\xce;\xef\x992s\xe6\xac\x13\x8b\x8a\x8a\\\xb1\x94\x12\xa9\x14\b\x1d!t\x94t\x90\xb6EZ\xab\x8et\x18u\x11m\x06\x9fIJ\xb3\xe68\xb10;W-b\xeb\xbcO)\u07b8\x12'\x16\xa5\xf7\xb5\xf7\x91?\xe8\f\x84\xb4\xd1\x04$\xa5g\xb1\xe1\xb3W\x99\xf7\xd4\x1fp,\v\xe16\x0e\xc5\xd05\u0661C\a-'';~\xa5\"),,\\\u05e8QR$33\u04d7\x96\x96\xee\x03\xb9\xc3\xe7\xf3\xefh\u07fe}E\xf3\xe6\xcd\x17]r\u0265\x87\x85\x10[\xbe\xefs\xfc\xf1\x8fw1x\xf0 F\x8e\x1c\u5a4b\x87'\xe6?\x06o\xbe9IL\x9cxE\x9d\x90\x8f\xfe\xf0\u00cf\xdf[\xb5jUJ$\x12\xa5W\xaf\x9e<\xfb\xec\xd3\xf4\xeb7\x10\u02ca\xe28\xce/>\xac\xf2Cq\xcb\xf5&RZZ\xcc\x1f\xffx7\x93&M\xc2\xef\xf73`\xc0\x80\x8aK/\xbd\xf4\xe2K/\xbdl:\xc0G\x1f} .\xbc\xf0\xa2c\x04\xfd\xb3\u03e60f\u0339?\xe4=\xda\xee\u07bd\xa3\xe3\xea\xd5\x05r\xf7\xee\u0772\xb2\xb2Jj\x9aV2l\xd8\xd0\xd3\u05ee]w\xff\xfb\xef\xbf\u03d6-[\xb0m\xc7\xcd\"\x12\x1aB\xe8\b\xcd\x00\x01v4\x8c\x11\b\u0462\xe7`N\x18y.-N:\x05\xbdq\x06\xbbW-`\xc5\xcb\u007f\xa6r\xdf\x0ez]s/\xad\x86\x8dE\x03\f\rR\xd23Y\xfc\u04bd,\x99\xf4\x88\x1bc\xf9\xfe+0\xe5\x9e\xd3D})\x06M\xd3HJJ\"++\x93\x94\x94\x14,\xcb\u079b\x99\x99Y\x99\x9f\x9fw 77w\xe6%\x97L\xf8\xb2Y\xb3\xac\x1d\xff\xaf\xfd\xe9\x8d-\x0fO\xcc\xffEV\xae\\&z\xf7\xee\xa7\\\xd1\xf9p\xf4\xcb/\xbf\xf2\xde\xe2\u014bS,\u02e2w\xef\u07bc\xf0\xc2s\xf4\xec\xd9\a\u04cc\xd4\xd78\xf18\x8a\x94\x92P(\x89\x8a\x8a\xc3\xdcq\u01dd\xbc\xfa\xeak\xe8\xba\xce\u0211\xa7V\xfc\xfe\xf7\xbf\xbbx\u0108\x91\xd3\x01V\xaf^!z\xf6\xec\xf3\x0f\x1d\xfa\xaaU+\xfa}\xf6\xd9\xe7\xadJKK\xba$$$\x0e\u07bd{O\xb8\xac\xacL$$$\xe4\x80\u02a8\xaa\xaaR\xb1XL\u0555\xfe5\f\xa3\xa6}\xfb\xf6\xd9EEE\xbe-[\xb6P[S\x8b\xed\xb8\x95\x0fu\u0747\xa6\x1b\bMC\xd3t\x1c\xdb\u010eFH\xca\xc8&\xb7\xfb@:\x9c~\t\xca\b\xb0\xf4\x85\xbb(\u07fd\x99>\xd7\xddG\x9ba\xe7!P\x18~\x1f2Z\xcb\xfc\xc7\u007f\xcf\xf6E\xd3\x10\x9a\x86j\xb0V\xa0\xaeDB\x03\x01\x96\xc7=\xae\x1c\u01d1\x80\x1e\n\x055\x9f\xcfOVV&\t\t\x894j\x94\xb4\xbbC\x87\x0e\xbb\xf3\xf2\xf2>\x1f>|\xd8w\xbd{\xf7\xfd\xfa\xfb\xf6\xc5\xff\xfd\xdf\r\\{\xed5t\xe9r\xa27\xc0<<1\xff!\xbc\xf3\xce[\xe2\xd2K/\aP\xdf~[0\xfc\xfe\xfb\xef\x9f2}\xfa\x8cd\xd34\x9d\xee\u077b\ubbfc\xf2\"\xbdz\xf5\xf5\x84\xfc\a\nzyy\x197\xdf|+o\xbe\xf9\x96\x13\b\x04\xf41c\xc6T\xdd{\xef=c:v\xec4?\x18\fj\xd1h\xb4auI\u07c2\x05\xf3:~\xf8\xe1G\x83\x0e\x1e4]\a\xb4x\x98\x04\xacH\x18P\xa4\xb4hKbz6\xe5{\xb7a\x9b\x11\x86\xde\xfa,\xad\x87\x9c\x8dm\x9a\x04\x92\x1aQ\xba\xa5\x80\x19\u007f\xbe\x92\x92m\xeb\xfeN\u033f/\xdcTGC\x87\x1e/ \xe6(\xa5\xb0,\xcb\xd14\xcd\u07e8Q\x12\xa9\xa9\xa9\x04\x83A'9\xb9QU\xabV\xad\xcb:v\uce22}\xfb\xb6S\x87\r\x1b\xb6*##\xb3\xf0\xf8\xd7_\xb6l\x89\xe8\xd7o\x80\x97\x1e\xe3\xe1\x89\xf9\x0f\xb9\xa4-**l\xf5\xdb\xdf\xfe~\xfa\xfc\xf9\xf3\xdbWTT\u0431c\a^\u007f\xfdU\xfa\xf7?\x19\xa5\xdc\x06\x10\x9e\x90\xff\xff\f\x8ex\f\xfd\u02112\xae\xbd\xf6:>\xf9d\niiM\x18:t\xe8\xc6\x17^x\xee\xf4\xa6M\xb3\v\xe3\xfb=\xf5\x81\a\xee;s\u04e6\u037f\u0674is\xcf\x1d;v \x84 \x1c\x0e7\x9cP\xae\xaf\u007fX\x97\x1e\xf9}\xf9\xfbu\xc7\xd00\x8c\xfa\x15\xac\xb6m\xbb\xee\xdc\xf0\xa3\xeb\x06\x9a\xa6\xe3\u0583\xaf;\xf1\xd8H\xcbD\xd3\f4\x9f\x8f\xa4\xa6\xd9\xf4\xbb\xf2.\xd2\xdbt&RSE \x94\xc8\xc1\x8d\xabX\xfa\xda\x03T\x97\x1e\xa8\xaf\xeaX\xf7\x15h8\f\xea\xab4\xba\xa7\xa7\xef\x1d#\rJ\xfc\"\xa5T\x80\xd0u\xb7\xcd_rr2\x81@\x80\xb4\xb4&t\xea\xd4\xc9NII\xf9\xa8m\u06f6_\xe6\xe7\xb7Z}\xd6Yg\x954,\x99\u0423G\x0f\xe3\xba\xeb\xaea\xe4\xc8\x11N^^kO\xdc=<1\xff\x9e/[\xfa\x84\t\xe3\u07de7o\xfe\xe8C\x87\x8a\xc9\xc9\xc9\xe1\xf9\xe7\x9f\xc3\xcdZq\x88F\xa3\x9e\x90\xff@4M\xc3\xe7\v\xb2c\xc7V\xae\xb9\xe6:\x16,XHNN6#G\x8e\xfcj\u04a47\xcf\x02|\xbf\xfb\xddM\x9f~\xf3\u0362\xd1\x1b7n\"\x163\x8f9\x14\xc4c\xd0J\xb9\xa1\xea\xba\xfd\xfe}9\xfc\r\ufeee\xdd}\t\xdbvk\xe1h\xba\x0fM3\x10\x9a~\x8c\x007\x8c\x81\vM#\u0538\t\x89M\x9ab[&V,\x82t\x1cb5\x95\x84+\u0290\x8e\xddP\xad\u007f2|>\x1f\xc1`\x90`0H\xeb\u05ad\xc9\xc9\xc9.MKK[\x92\x96\x96V\x90\x92\xd2x\xfem\xb7\xddQ$\x84\xd8[\xf7\xf7o\xbd\xf5\x866r\xe4\xa92;\xbb9\xf3\xe7\xcfe\xe8\xd0\xe1\xde\xe0\xf3\xf8\xf5\x89\xf9\x8c\x19_\xb1p\xe1\xd7\xe2\xb1\xc7\x1eW\x00\xf7\xdcs\xf7\vS\xa6|z\u00e6M\x9bHHHP\x8f?\xfe\x98pk\xb1(\xa2\u0470'\xe4\xff\xe4\u054ea\x18\x18F\x80\xe5\u02d7r\xf5\xd5\u05e8\r\x1b6\x8aN\x9dN\xe0\x8a+&>\x9e\x94\x94\xd4\xf4\xd9g\x9f\xbb|\xf3\xe6-\xff0\xad\xb3n\u007f7lX}\xb4\xd6\xfb?h\u05a1\x14R)\xb7T\xadRnHL\xd3\u30ae\xd7\u05c9o(\xca\xf1P7B)\xecX\fG\xd9?H\xb2u@\xd3\x05\xb6\xa3~\x12\x897\f\x03\xbf\xdfG(\x14\"33\x93\x9c\x9c\x1c\u0574i\xd3\xe5\x19\x19\xe9S\u018e\x1d\xb3\xec\u44c7,=\xfe93g~\u0168Q\xa7{\x03\xd0\xe3\xd7%\xe67\xdex\x03/\xbc\xf0\"\x00\xaf\xbe\xfa\u0288\x17_|q\u06bau\xdf\x05\x95R\xfc\xe1\x0f\xbf\xe7\xd1G\x1f\xc6\xe7\xf3y\x8e\xfc\xdf\x10tM\xd3\xf0\xfbC|\xf8\xe1\xfb\xfc\xf6\xb77QZZF\x9f>\xbdcyy-\x03\v\x16,\xa4\xa4\xa4L\x89x\xe7\x88\xe3E\xfd\x18\xc7]\xe7\xa4\x1b\x8a|\x03\x1b\x0f\n%]!\xff\u01c36^b\xa1>\xde\xee\xde\xfc\t\x894JoF()\x19_(\x01_ \x88\xe1\xf3\xe1\xf3\x19\x84\xfc\x06\x86\xc0\x9dh\xd5\x04\x89\x8d\x92\xc9h\u0782\xe4\x8cl\x84\xe1\aM#\x1251-\x13G\xbaW\x03V\xa4\x96HM5\xb5U\x15T\x94\x1e\xa2d\xefN\x8e\xec\xdbE\xac\xb6\xa6~\xfb\xea?O\x83\xab\x83\xff\xd7IM\b\xd04\x9dF\x8d\x1a\u047auk\xd2\xd3\u04cb\xf3\xf3\xf3\xbe>\xf7\u0731\x8b\x86\r\x1b\xf1\x8a\x10\xa2>G\xf6\x92K&0b\xc4p\xe2s@\x1e\x1e\xbfl1\u007f\xe2\x89\u01f8\xf5\xd6\xdb\xeb\xbeDY\xa7\x9f~\xfa\xeco\xbe\xf9\xa6suu5g\x9cq:o\xbc\xf1\x1aM\x9bf\x11\x0eW\xff\xa4M#~\xe9H\xa9\xf0\xfb}\b!\xb8\xff\xfe\ax\xf8\xe1G\xd1u\x9d\xe4\xe4d\x94\x92\xaa\xb2\xb2\xaa\xbe{\xd0O\xb1\xf0J\xd7\r\x8c@\x00_ \xc1m\xd4l\u06d8\xd1\bB\bB\u0269d\xb4\xea@\xeb\x01\xa7\u04b4M\x17t\xbf\x1f_ \x80?\x10\xc4\xef\xf7\x91\x14\xf4\x91\x92\xe0\xc3\xf0\xb9\xd5\x195\x01\x9a/@(9\x15\x15\x00G\x82\xe5\x80%\x8f\x9eT\x1c\a\xa4\x05\x96\x19\xc32\xa3\x985U\u0516\x1f\xa6\xa4p'\xfb\xb7\xac\xa1\xe8\xbb\x15\x14\xef\xdcL\xb4\xaa\x1c+v\xb41\x89\xe6\xaau\xbc\u035d\x02)\xff\xce\xed\xc7E]*\x05~\xbfO\xcb\xcf\xcf'//\x8f\x13N8a\u0168Q#\xdf\x1e1b\xd4K\rO\x80\u007f\xfd\xeb\xb3\xe27\xbf\xb9\u024b\xa9{\xfc\xb2\xc5|\xc1\x82\xb9\xe2\x94S\x86+\x80K/\xbd\xe4\x91y\xf3\xe6\u0771\u007f\xff\x01\u06b5k\xab\xde~\xfbM\u0477\xef\x00\"\x91\x9a_L\xb1\xac\xff\xae\xa0KB\xa1D\xca\xcaJ\xb9\xfa\xeak\xf8\xfc\xf3\xa9\xca\xef\xf7\x8b\xc4\xc4$\x1c\xc7&\x1c\x0e#\xe3\xcd$\xfe\x91\xa0\a\x02A\xfc\xc1 >\u007f\x00M\xd7\x11\x9a\xee\xe6\x91\xeb\x1a\x9an\xe0\v\x04\t&5&)-\x83\x94f9$7\xcb!9\xad\x19IM\xd2\t5N\xc5\x1f\b\xa1\xa4\xc24c\u0516\x97Qqp?\xc2\xf0\x91\x9a\u05d1\x94\x96\xed\xd0\x02!l\xc7F\x17`h\x1a\xba\xa6\xe1\xd3\x05~C\x03MG\x02\xb6\x84\x98\xa3\x88\xc6Lbu\xd50\x95@\x89\xba/\x85\xdb\xcdH\b\xf7\n\xc0gh\x04|\x06\x01\xbf\x0f\xa5 RSM\xb8\xe20\x87\xf7\xed\xe2\xc0\x96\xef\u063f~\x05%\xdb\xd6Q[v\x88XMe}\xa6\x8c\xd0\u2379\x1b\x84\x8b\x8e\x17uM\x13\xd2q\xa4\r\xf8[\xb5jEnns:w\xee\xfc\xdd\xc9'\x0f|l\u0738\xf1\xef\x1f\xbf\xff\x16/^$\x06\x0e\x1c\xe4\t\xbb\xc7/G\xcc\xdf\u007f\xff]\u018f\x9fP\u007f\xff\x85\x17\xfez\xfeK/\xbd\xfc\u0386\r\x1b\x83III\xea\xe9\xa7\xff\"\xae\xba\xea\xea\xff\xa9n@\xbf\x14\x02\x81\x04V\xadZ\xc1\xd5W_\u00fau\xdf\u0468Q#\xfc~?\xd55n\xa9`\xa5\x14\xb2\xc1>Oi\x9aI\u04fc\xb6\xb4\xec\u0503\xdc\xf6]H\xcbjNb\xe3\x14\x94\xe1\a\xcd@\t\x1d\xdd\xef\xc7\x1f\bb\xf8\xfdh\x86\x0f\xdd\xe7G\xf3\xf9\x11\x86\x0f\xc3\aq\xcdwO*\x8e\xeb\x9c\x1d\x1b\xccH\x14\u04f2\x89Y\n\xd32\xe3B.\xd04\x1d]\xd7PB\xc3A\xb8\xff+0\xa5\xdbrNA}\x8c\\*7n.\x04\b\x14*^[W\x13\x02\x05\xe8\xc2-\xb7+P\u8e86\xe6\xf7\xe3\xf3\xfb\xdd\x05L\xa6\x83\x19\rS]\xba\x9f\xd2-k8\xb0v\te\xdb\xd7S}h\x1f\xe1#\x87\xb0\xa2\x11@C7\f\x84\u0410\xd2q;\x1f\xa9\xefM\x8dTB\b\x91\x99\x99I\u02d6-\xe8\u0673\xe7\xa6\xe6\xcds\x1e:\u55213{\xf7\xeeS)\x84\xa8\u06e9\xdaSO=a\xb4i\xd3\xda:\xfb\xec\xb1\xea\xd5W_\xe6\x9ak\xae\xf3\x06\xa6'\xe6?_\xbe\xf9f\xa18\xf9\xe4!J)\x95w\xe1\x85\x17\u03181cF\x87\xea\xea\x1a\xfb\xf2\xcb/7^\u007f\xfd\x15t\xddO4Z\xeb\xc5\xc9\u007fd\xdcf\x12\x06\x0f?\xfc\x10\xf7\xdcs\x0fR*\x02\x81\x00\x8e\x94\xd8\xf1\xaeA\t\x8dS\xc8l\u0749\xdcN\xdd\xe9|\xf2\bZu\xefO\xa8qj}\u03b6\x03H\xe2m>\x05\xf8}\xf5\xd1\t7\xf4,\xe3\xa1\x0e\x89[\xf6\xf68\xc7_\xefr\x85\xc0\xb4$\xb5\x11\x13+\xbe\x92\xd7\xd0\x056\x1a\xb6\x128\b\x1c\xa9\xb0\xe2o(\x94B9\xa0I\xe5\x164w\x14\x9a\x12h(\xa4\x00\xa1@\xb8\xadG]a\x8f\x8bCH\xcf\xcd\xc3\x10`9\xee*O\xe5H\xa4\x94X\xf1IN\r\xf0\xf94|\xba\x1e\x9f?\xfc\xfb\x8c\x12\xe9\x06\xa0\xe3\xf3\xa6\x02\xd5`\xf0*\x14Q[Q\x13s\x889\nG\xba\xae\xdav\xc0\xb6\x95+\xe0\x8eB\xd9\n\xddQ\xe8\x12\x84T\x88:{^\x97O\x1e\x0f\xaf(\x11?\x9b\xc4\xdfO\xe1\u693b\xb1pp\u217f\x10\xf1\t\xd0\xf8k\b@\xf3\x19\x88\x80\x0f\xcdo`\xf8u|\x86\u00ac,\xa5l\xc7:\x0em_\xc7\xc1\xed\xeb8\xb0m\x1de\xfbw\xe2\x9814\xddp_K\xc9\xf8\xa4\xef\u07fbu\x9f\xcf \x18\f\x91\x92\x92B\xeb\u05adHKK\x9bw\xc2\t\x1d\x17\x0f\x1atr\xc1\x88\x11\xa3\xbe\xa8\xfb;]\x0f\xb0e\xcbwL\x9d:\x8d[n\xb9\xd5\x1b\xa4\xbf\xc6\xef\xe5\xcfu\xc3\x1fy\xe4a\x03\xb0W\xae\\\xde\xe6\x96[n\x9d\xb8c\xc7\x0e\x00\xe7\xd2K/\u047bv\xed\x0e8\x9e\x90\xffT\x0e@\b\xa4t\x1dx\xe3\xe4d\x8e\x94\xbbF1-\xbb\x05g\xdd\xfc0-\xfb\f!f\x81m;\x84\xc3Q4%\xd1\\I\u018a\xbb\xdeXD#\xdc\xfct\u074dq\xfb\xfc\x01\x8cP\x10\u007fB\b\u007f(\x84\x91\x10\xc4\x17\f\xa0\a\xfd\xe8\x01?F\xc0\x8f\x11\xf2c\x04\xdd\x14\xc7@(H !\x84?\x18\xc0\xef\v\xa0\x1b\x06\x1aZ\xbd\x90\u05c9:\u01c9=\x8eB\xd8\xeee\x84c;D\xa3\x11L\xd3$\x98\x94F\xb3\xfc\xae\xb4\xe8\u060f\xacV\xdd\x10B#Ru\x183Z\x8b\x94\x0e\x9a\x86\x9b\xe9s\xdcITJ\x89\xae\xebB\xd7u*\xca\xcb\xed=\x85{\xb4\xe2\xe2\xe2\xdc={\n/\xbc\xe8\xa2\v;,^\xbcd\xf9}\xf7\xddW=k\xd6l\x1e~\xf8Am\u07bc\xf9\xde\xe5\xa9\x17f\xf9\xdfd\xc1\x82\xb9\u0525\"\xbe\xfd\xf6[\xa3\u05af\u07d0\x020`\xc0\x00F\x8d\x1a\x15\xbf4\xb5\xbc#\xfb\x1f\xc0\x8eE\x89\xe0#\xbf[_\xfa\x8c>\x9f\xd9o=\u02eeU_\xb3\xe7\xdb\xc5t8\xf5B\x1ca\xe0H\x87\x04\x1d\x92\xfd\x10\x8b\x82\xa3\x14\x8e\x04\xbf\x00\xbf\x13W]\x9fpSFp\xc5W:\xb8jo*\x94%Q\x96D8\xa0\x1c\x85\xb2%\xa6\xa3\x88\xd8no\xcf\xfa\x90\b\u2a17mPwE\xf7\xf9\xd1\xfd\x01t\xbf\x1ft\x81\xe3XH'\x86\xe9DP\x96\x85f[H3\x8cY[\x89\x15\x8b\xe2\xd8\x16\x8e\x1dC\xd96B\xd30|\x01|~?~\u007f\x10\u007f\xb0\x11>\u007f\"\x9a\x1e\x00\u0347\x1e\xf2\xe1\x0f%\xa2\v\x03iK\xac\x98\x89\x8a\xc5pl\u06dd\xb9=\xbaA`\xc7C?\x9a@\tI$Z\t\x9a\xc0\x1fJ\xa7\xcdIg\x91\xd3~ E[\x97\xb3i\xc9\x14\xf6o[IeY\x11\x8e\xed\x8ec\xa1\u05657R_\xafF\xd34t]7\x84\x10r\xff\xfe\x03\xce\xe1\u00c7}ee%\xe3\x0e\x1c8\xd8w\u07bc9w\r\x1b6\u20fb\xee\xba[\xe6\xe6\u62bd{\xf7*/\t\xe0W\x10\xfe\xfc\xb9n\xf8\xfb\xef\xbf\xdb\xea\xe5\x97_\x99\xbft\xe9\u0496Bh\xbc\xf2\u028bL\x9cx\x95\x97\xbd\xf2\x9ft\x02\x02\xaab6[U23\xe6\xaf\xe0\xc5\xdfM\xa0\xacp\a\x9dF\x8c\xe5\xf4\xbb\x9f')=\v'\\C\xcb$A\x93\x00\xec\xa8V\x14V+b&$*H\xd4\xdcE6\x9a_C\v\xb8\x82ET\xa2\xa2\x12,\xe9f\x95HE]B\x9e\x9b#\xae\x88\u064a\x98T\u023a\xd4\x17\x11\x9f\xbcT\x12)\x14\x9a\u03c7\x16L@\xf3\xf9\xb0c\xb5\xc4\"\x15\xc4j+\bW\x16SY\xbc\x9b\x9a\xb2}\xd4\x14\xef%r\xf8\x00\u044aR\xccp\r\xb6\x19E\u019bI+\xe5\x06\xf6\x15\xc4K\b\xb8\x8e^\xf7\x05\t&&\x93\xd0$\x83\xa4\xf4l\x92\u04f3Ii\x9aG\xe3\xb4<\x12\x933\t\x06S\b\x05\x1ac\xe8A\x1c\xd3\u008a\x85ql;\xbeJ\u050d\xe9\u0539w\x15\u03d0Q\x024C\xc7\b& \x84\x86\x15\xae\xa4\xb8p=\xdbW~I\u0476\u5517\xee!RS\x8eR2^`L\x1c\xb3}\x9a&\u0404@JG*%\xb5&M\xd28\xf1\xc4nj\xc0\x80\xfew\xdc{\xef}\x8f\xd7\x1d\xab\xfb\xef\xbf\xcf\xf8\xdd\xef~\xeb$'\xa7zN\xdds\xe6\xff[l\u0738\xf1\xe2\xc2\xc2\u0096\xb6\xed0d\xc8\x00\x86\r\x1b\x06\x80\xe3H\f\xc3[\xe9\xf9\x9f@\x01~C\u00e8\x8e\u04aa\xf3\x89t\x1dz\x16\xf3\xdf\xfc\v{V/\xa2t\xfb\x062\xb2\xb2\xc0/\b\u06cajKP\x1e\x83\x98\x03\xd2V\xf1\x15\x92n\xf8A\x85\x1d\xa4\x16?\x01[\n\xe1\xb81\v\xd5\xc0mK\xa9\xea#)\x86\xe1\xc6eL\xa9\u0710\x8cP(CG\x0f5\xc2\b\xf9\x89\x85\xab\xa8,\xd9N\xd5\xc1]\x1c\u07b9\x8e#{6pd\xcf\x16j\x8b\xf7aEkp,\xeb\u01e9\xb3%p\xcb\x05\x04\x13I\xcdjE\xd3\x16'\xd04\xa7\x13\xe9\xd9\xedHMoIJZ\v\x92R\u04f1b1\xa2\xd1p\u072d\x8b\xfaP\x90\x92\xee\x0fR9\u011cj\x84a`\xf8\x12h\u07a6\x1f\x99\u037bQQ\xbc\x8b\xa2\x1d+8\xb8\xb3\x80\xb2\x03[(/\xd9E\xa4\xb62^hL;f;t\xdd\xd0\x04\x8a\xf2\xf2\n\x16/^\"\xaa\xaa\xaa\x1e\x9b8\xf1\xf2\x93\a\r\x1a\xf4\xc8\xe5\x97O\\&\x84\xb0\xff\xf4\xa7{\xf9\xec\xb3O\xb4s\xce9W\n!\u0639s\x1b\xad[\xb7\xf3\x06\xb2'\xe6\xffy^y\xe5eq\xed\xb5\xd7)\xa5\x94\x187\xee\xc2\u02cf\x1cq\xb3(\xce8\xe3\fZ\xb4\xc8'\x1a\xadE\u05fd\x95\x9e\xffI1\xf7\xe9\x1a\x8d5\x8b\u018d\x1a\xd1i\xd0\b\n\xbe\xfa\x90\u0292\x03l_<\x936\xbd\ac\x18AJ\xc3\x11bRa\xd5\t\xb8\xed\u01b9\x95r\x85]\xd8\xf1\xec\x10#^|K\xa8\xfaKF7Y$\x9eQ\"@\xd7\xdc\xa2h\xc3jb5\xf1\xc6=\x9aARF\x16\xf9]{\xd1u\xf0H:u;\x89\xbc\xdc\x1c\xba\xb4\u0320u\x8aA\b\x00\x1b\xcb4\xb1l\xc7\x15\xbc\xffG=\xf5c\xbb\x11\x1d\xfd\xacuY%\xa0\xd0\x04\xfc\u007f\xec\x9dw|UU\xba\xfe\xbfk\x97\u04d2\x13\xd2h\xa1\x86^D@)\n\x88\xbd\x01\x96\xb1\x97k\x1d\xb1a\x1f\xcbXf\xece\xf4\u07b9\xe3X\xc6^\u007f\x8c]\xb0PT\x8a\x02\x82\bH'\xa1CBB \xbd\x9c\xba\xcb\xfa\xfd\xb1\xf7>I(\x8ewF$\xced}>\x87\x84\xe4$\xd9\xe7\ucd5e\xf5\xae\xe7}\xde\xe7\xd5T\x15M\xd7A\xe8H\xa02nR\xbc\xbb\x8a\xcdE%,]\xb6\x8c\x85\xb3f\xb2j\xf1Bj\xcb\u02fc\u07c0/\x10\"\xaf\xfbP\x0e\x1d}\x01}\x0f\x9f@Zf\a,\xd3&\x11\x8f8]\x93l\x13\xcb4\x90\xb6\x89\x94n\u027f[\xf4$\xa5\x8dD\xa2\xeb\x014M\xa5z\xd7fV-\xf8;\x9bV~I\xa4\xa1\nE\xf3\xa3*\x9a\xa3\x9dW\x85\xfb\xde\n\xa4\xb4\xedx<&\xc3\xe9ij~~w\x86\r;l\xe6]w\xde\xfe`~~\xef\xef\x00F\x1d9J\xfc\xfe\xee;\xe5\u99df\xd9:\xa9[#\xf3\x037\x16-Z\xc0\x91G\x8e\x01\xe0\x95W^>\xff\x89'\x9e8\xa4\xa1\xa1\x811cFs\xec\xb1\u01f0\xbf\xf6^\xad\u35cb\u03b3\xfd\x82\x8e\t\x83.}\x06\xd2}\xc8H\x8a\xd7\xfe@\xc9\xea%Tm\\OV\x87~(\x8a\xc3A;\x05\x94N\xc1\x8e\xd4@Z\xb8\x05C\x8e\u02e0/\xa8\xe0\xcf\xd0\xd13T\x046\x9a\xee#\x10T\xa9/\xaff\xf5\x17\x1f\xb2\xf4\xe37(Y\xb7\f3\xe1P)\xbeP\x98.\x87\x1c\xc6\xe0\xa3Of\xd4\xf1\xa7\u043bO\x1f\xdae\xa6\xd19\x03rT\b\xd8\x06\x981L[\xe2)\x19\u007f\xea\tn\xafNH\xce\x17\x9b}\u0352`%\r\x14a\xa0\nAn@#\xb7k;\x86vm\xc7o\xc6\f\xa5\xf2\xb7\x17\xb1rM\x01\xd3?\xff\x9c93g\xb2~\xdd\x1a\x12\xb1\x06\xb6\x15~K\u0676\x15\xac^\xf8\x1e\x83\x8e\xba\x88^\x87\x9eLZF{\x8cd\x8cD,\xd1\xe8\xb4h7z\xd1x\x1d\xed\x04\n\x86\x11\u01f6u\xb2;\xf6c\u0504\xdb\xc8\xcd\xeb\xcd\xea\x85\xefS\xb9k\v\xb6\xb4P\x15\x1d\xdbvr\x11\x8a\xa3\x84W\xfc\xfe \xd1XB\xae][(jjjOI&\x8c\xe3f\u0318v\u07a9\xa7\x8e\xffd\u1885\xb2\xbc\xbcB\x00\xf2\xb9\xe7\x9ec\u04a4I\xad\x13\xfb\xd7Fy\xfe\x1a.\xf2\xd5W_K}\u07b6m\xdb\x1b\n\n\n\x8e\xa8\xafo\xe0\xf4\xd3O\xe3\x82\v.r\xb4\xc3?\u04a0\xb7u\x1c\u0623\x9d\r\xf8\\\xaa\xa4\x16\x9d\xf2\xcaZ\xd6/\x9aM\xb4\xae\x86\xbc\u0783\xe9\xd4{\b\xa6ab\xdb\x0e I!\x90\x9a\xc0\xf6)\u062a+\xd3S\x05\xfe\x80B\u042f\xa2\xa9\xa0\x06T\x02\xe1 \u04b0\xd9\xf8\xedl\xbe\xf8\xcb},x\xebi\xaaK\xb6a[\x16\xbe\xb4\fz\x1fy\x1c\xa7^\xfd;.\xb9\xe3\x01N\x9fp\"c\xfav\xa4\u007f\xb6\x8f.\xbaA\x86L\xa2\xd9\u03bc0\xed\x03\xdd$\x8e\x94\xfb\xa2e\xd9H\xdb\x00\xdb@U \xcd\x1f\xa0g\xe7\xd2J\x12\xa9)#\x11m@(\x9a#\u007f\x942\xd5<[Q\x15!\x84\"kjk\xc5\u039dej\xf9\xee\xddg\xdes\xcf\xef\xd7|\xfc\xf1\x94\xf5\x9f~\xfa)\xd3gL\x17\x17_t1\bv\x99\xcf\x00\x00 \x00IDATO\xff\xf5if\u0398\xd9:\xc1[\xc1\xfc\xe7\x1dEE[\xf9\xdf\xff}\x1a)e\x9b\xbf\xfd\xed\xf9{\u05ed+\xe8\x18\x0e\x87\xe55\xd7\\-\x06\r:\x14\xcb2Z}X\x0e2\xa0\v\xc0\xa7\b\"\xb6N\xbd\b\xb2f\xfeWT\xef,\"\xb3}Wz\x1fq2\x96e9\xf2BM C\nvH%\x99\xa6`\xe9\n\xc2r\x8a\x88\xfc\x9a\x82\x8aDS5\xfc\x19!\xcawlf\xde\xcb\u007f\u2aff\xdeO\xc9\xdaeH\xdbB\xf1\a\xe9?\xf6\x14&\\{'\xe7\xdf|\x0f\xa3\x8e>\x82\x1e\xd9A\xfa\a-rE\x02\xd54\x1c\xe3*<;\x80\x83C=y\xc0nY\x06H\vE\x856\xe1\f\x8e\x18q\x18\xc7\x1cs\n9\xb9\xf9\xd4\xd4\xd4SV\xba\x1d\xcb2\xa8,\xdb\u0226U_\x11m\xa8\xa0MN\x17\xda\xe4vv]\x15\x8dT\u0751l${R\x04\xa9Db\xdb&RB\x9b\xb6]\xc9\xeby8\xe9m\xdaa&\"\xd4W\xef\xc42\x9dF\xd7N\x929E\xbb\bEQe}}\x83\xa8\xa8\xa8\xd0*+\xab\u03bc\xf9\xc6\x1b\xd7L\x9f1c\xfd\xe4\u0253\x99\xfa\xc9\x14q\xf9e\x97\xb7N\xecV0\xff\xf9\u01e0A\x87\xf0\xc9'\x9fq\xec\xb1c\xc7~\xf8\xe1\u01d7\x97\x94\x94\xa6\xf5\xea\xd5S\xdcr\xcb\xcd\xe4\xe6\xb6u\x16L\xeb8\xa8C\x02>\x15,\x14\xea\xf40k\x16\u007fK\xe9\x865\x04\xc2\x19\xf4\x1du\x12\xc1p\x1a\xaa_\"\xd2U\x94t\x15\xcb'0\x85@*\x02\xc5\x02\xdd\x06](\x04\x02!\x04\x925\xdfLa\xfa\xd3w\xb1j\xc6\xfb$c\x11\x00\xf2\x0f\x1b\xc3\xe97\xde\xc3\xf97\xdd\xcdQ\u01ce$7\x18 \xcd6\xc9S\x93d*f\x13?\x97\x83\x03\xe2\xfb}o\xa4t73\x03\x81Mvv:\u00c6\re\xe0!c\xc9\xca\xe9Bee\x05U\x95;1\x93qJ6/\xa5l\xfbJ\xd2\u04b3\xc8\xed\xd0\x1bE\xd3\xddJ\u0426\x15\xa5\xa4<\v<'I\xc7\xc2\xc2@\xf3\xa5\u046e\xeb :\xf7\x18B\x9b\x8cl\xea\xabJ\xa9\xafs\xc4\x02\x8a\xa2:\u0564Bq\xc4C\xaaB,\x1e\xb7*++}UUUgN\x9cxU\xe1\xec\u0673\v\xde}\xf7=\x1ex\xe8\x01q\xe7\x9dw1y\xf2\xe4\xd6\xc9\xdd\n\xe6?\xdf8\xf7\xdcs\xc5\xc7\x1fO!?\xbf\xc7y+W\xae<\xa3\xa2\xa2\x82\x91#Gr\xcd5\x13QU\r\xd3l\x05\xf3\x960\x14@U\x15\xaa-\x1f\x9b\xb6l\xa5\xe0\xdb\u0668\xbaN\x8f#\x8e!+\xbf;>\xbf\x81\xeeW\xb0qx\\\x81\xdb\xf4AJt\xa9\x92\x9e\u0786H\xed.\xe6\xbd\xfb\x14\xb3_\u007f\x88\x8a\xed\x1b\x01\bf\xb5\xe5\xc4\xcbo\xe4\xd2{\x1e\xe3\xb8S\x8f\xa3mZ\x10%\x91D\x97&\x1d|6\xed\xfd\xb6\xe3\xef\xf2\v!\xb8\xa2(h\x9a\x86\xae\xebh\x9a\xf7\xd0\xd045\xd5\xd1j\u007f'E\xdbv\"iU1\xe8\xd0>\x87C\a\x1fI\xbf\xfe#\xf1\xf9\xd2).\xdaB<\x1e\xa1\xbe\xba\x94\xe2\r\x8b0\x8d\x18\xb9\x1d\xfb\x11J\xcf\xc62\x93N\xe5g\xd3>\xd6{6\xb5\xb6\x9d\x1e\xa7\x96\x99$\x18\u03a5k\xcfat\xea\u069fD\xa4\x9a\xdd;7!m\x1bU\xd5R\xbdS\x05\x02EU\x95D\xc5o.\xbf\x8a\ue773Q\xa2\t|\xb6I\xa6.\xe9\x14\x90\xe4\xfa$\xaaH\u016d\at\xf8|>4\u034f\xaaj\b\xd7\xd9PJ\xdb}H\xb7\xb7\xa7\xe6\xf4+\xd5t4\xcd)\xe0\xd9\xef\xe2SM\xfc~\x83\xee\u077a2d\xe8\x18\xf2{\f\xa2\xbc|\x17\xa5\xa5[I\xc6\x1b\u0631y)uU\xc5d\xb7\xcf'\xabm7\xc7j\xc0\xb6HeB\x9bR/\x82Ta\x95\x94\x12#\x99\xc02mr:\xf6\xa4k\xfe`\xccX\x1de%\xeb1-\xd31\x1b\x13\x8d-\xedTUU\x12\u0244U]]\xed\xab\xaa\xae:\xf5\x81\a\x1e\xe8>\xe5\xe3\x8fg<\xf8\xe0\x83\xd6\u0529Sy\xe6\xd9g\u014c\xe9\xd3[\xe7w\v\x1f-^\u0372y\xf3\x06\u0473g\x1f)\xa5\f\x9dt\u0489\ud28b\x8bIK\v\xa9\x83\x06\rr#\x9d\xd6\xc4g\u02e1\x13@\x936m\x03\u042dG/\xd2s\xdaS\xbei-\x95E\x9b\x10@\xd4\x14\xc4-\a||\x8a@\x15\x92@z\x1a>\xbfB\xe1\x97\xd3\xf9\xea\xd9\xfb\xd9Q\xb8\u0519\x98iY\x9c}\xd9U\xfcv\xd2\rt\xcb\xefJ<\x9eD$\"\xa4\x05\x14\xc2\x1a\x844\x89.R\x01\xe9\x01\xa5H\xfc~?B8K\xa5\xba\xba\x82M\x9b6\xb3z\xf5j\xb6n\xddFEE\x05\x91H\x04]\xd7i\u06f6-\xf9\xf9\xdd\x190`\x00}\xfb\xf6\xa1]\xbbv\xf8|\x8e(2\xb1G1\x91t\x9b\\\xf8t\x81\xa64\x90\xdf\xddG\xe7\xff:\x8d\x11\xc3\a\xf1\xea\xab\xcf\xf1\xe6\x9b/\x90\x887\xb0\xee\xfbO\xa8\xad(b\xec\xe9w\x90?\xf0X\xe2\xf1(\x89D\xa4\x11\xc4]\x95K3^I\b\x14T,\u06e4\xa6\xa6\x92P\xb8#\xa3'\u0702/\x98\u0392\xf9\uf4ccG\xf1\aB\xa8\x8ak?\x8cDU55\x96HXK\x97\xfe\xa0J)/\xaf\xaa\xaa\n\x02\x17\x00\xdcx\xc3\r<\xf3\xec\xb3\xdcx\xc3\r\xad\x93\xbc\x15\xcc\xff\xf91g\xce\\\x01\xc8m\xdb6\xf7\x8dD\"=M\u04e4c\xc7\x0eb\xe0\xc0\x81\xad`\xde\xd2\xc0\x1c'!\x97\ud0ce\xedrh\u06f5\xa7\x03\xe6;\xb6QW\x17#j\xab$-\x13]\x11\x98\x96M(\x14\x00i\xb0x\xf2\xeb\xccy\xe91jv\x16\x03\u042d\xff\x10\xae\xbf\xedn~{\xe9y\xe4\xf8 a$0\x83NoO\x95\xc6f\x12\xf2\x00'8\x9d\x06\xd6\xe9\x80Ea\xe1Zf\xcc\xf8\x82\xa9S\xa7RX\xb8\x9e\xfa\xfa:\x12\x89d\xb3\xf9'\x84\xc0\xef\xf7\x93\x96\x16\"??\x9f\x13O<\x91q\xe3Ne\u0108a\xf8\xfd!\xe2\xf1H\xeayMA]QUTa\x11\xf0'\x181\xbc;C\x06?\u0148\xe1\x83x\xfc\xf1\xc7\u067c\xb9\x90\x92-\u02d9\xf6\xd6\xef8\xf6\xcc\xdfs\u0211\xe7\xa2(\x82x<\x82\xeb\xf4\xd2\xecd\x84\xe7\xad.\x1c\xe2K\u0692h\xb4\x81`(\x97#N\xb9\x01\u0757\u0192y\xef`\x1a\x06\xc2\xe7kTZJ\xd0\x14U5MS~\xf7\xdd\x12\x11i\x88\x9c\xff\xf0#\x8f\x88\xfb\xee\xbd\xf7b!\x84\u0675k\x17\x15\xb0\xa6L\x99\xc2o~\xf3\x9b\xd6\xc9\xdeJ\xb3\xfc\xdfG\u06f6m\xc5\xf2\xe5+d\u06f6m{~\xf7\xdd\xe2\v+++\xdbt\xef\u078dI\x93&\x89\xb4\xb4tL3\xd9z\x17[\x16\u04c2OU\xa9L\n\x96\xafX\u0156\x1f\x16\x92\x9e\u06d1\xbca\xc7!\x82\x19\x98\x96\x89%%\x81@\x00U\x1a\xcc\u007f\xe3\u007f\xf8\xea\xb9\ai\xa8*\a`\xf8\t\x13x\xe2\xcf\u007f\xe1\xca3O \xa4\x82iD\x11\xb6Ds)\x19\xb7\xc7\xc4\x01\x05q\xaf\xf9F \x90\u01ae]\xa5\xbc\xf8\xe2K\xdcw\xdf\x1fx\xf7\xdd\xf7\u063au+\x91H\x04\u06f6\xf1\xf9|4iE\xdaX\xfa\x1f\x8bQZ\xba\x93\x05\v\x160e\xcaTv\xec(\xa1G\x8fnt\xec\xd8\x19!\xc0r{\x95\xee\x19\xa9;\x15\xa8&>\x9f\xcea\x87\r\xe6\xb0\u00c6\xb3~\xc3V\x8a\x8b\xb7\x92\x885P\xbc\xf1;\xd2\xc3Yt\xee1\x14E\u0571,3\xf5\xa6\xefS\x13/\x1b?1M\x03\u0557F\xe7\xfcCQ\x05\xec,ZC\xd2H8\xfe.\x1eG\x83@(\x8a\x90H\xb9{W\xb9\xa8\xae\xae\x1eX^Q\xdeo\xf6\xacYS\xfb\xf5\xebg\u03593G\x1d7n\\\xabl\xac52\xff\xe7F8\x1cV\x00[Q\u0120\xf4\xf4\xb4.\x00\x9d:u\x12\xa1P\xa8\xf5\xee\xb5\xd0\xe8\\`\x93\x1d\xd2\xe9\u0439\v\xa0PWUNmu%9\xb9\x9d\x90R\x12Ho\x83\x99\xa8g\xce\x1bO0\xef\xf5\xff\xc1t\xbdT\x8e=\xe7\x12\x9ex\xe21F\xf4\xec\f\x18$\x13\xc6>[\xc7\x1dX\xaaH\xba\xc9L?\x8b\x17/\xe2\x91G\x1ee\xe6\xcc/R\x1e\u22a2 \xa5t\xf9s\r\xd3\xf5?Q\x145U5\xea\xd9\x02H)\xa9\xa9\xa9\xe1\x85\x17^d\u039c9<\xf6\u0623\x9c}\xf69\xa8\xaaJ<\x1e\xdf/\xa0'\x12Q4Me\u0318\x91<\xfb\xcc\v<\xf0\xe0\xc3|\xfe\xf9;D\x1bj\x98\xf5\xc1#\u0636\u0270\xe3~\x8b\xaa\xa84D\xebphtoW\x91\xcd{\xeb5\":\xf1D\x84\x80?\u0110\xa3/\u00d6\x92\xef\xe7\xbeE\"\x1e\xc5\xe7\x0f9\x85Tnd\xaf\xaa\x9a\xb0\xb1\xe4\xbau\x05B\xd5\xd4\xf3\xc2\x19\x19H)/\x11B$g\u03de\xad&M\xd3:\xf5\xe4\x93['{kd\xfe\u007f\x1b\xfd\xfb\xf7UV\xacXi\x0f\x1c8p\xdc\xe6\xcd[\x8e\u077d{\xb7y\xdcq\u01ea\xa7\x9d6\x01U\xd5Ze\x89-qR)\x02C\xd5X\xb1a;\x8b\xbf\xfa\x1cEQ\xc8?\xf2D\xb2\xba\xf6D\xd5|\b\xcb`\xd1\xcb\x0f\xf3\xed\xebO9v\xb4B\u5b097\xf1\xa7?=\xcea\xdd\xdac\x9bq\x92\xc6/\x9f\xd4\xf6\xf8qU\xf51s\xe64n\xbc\xf1&\x16,\xf86\x05\xe2\x9e\u007f\v\x80i\x9a$\x93\xc9\x14h{\tPUUS\x80\xdfT\xd1RYY\xc5\xe7\x9fO#++\x93\xe1\u00c7\xa3\xaa\xaa\xbb\x11\x88\xfdP<\x12)M:uj\xcf\xe0\xc1G\x11\x8dI\n\nV\x10\x8f\xd5S\xbcy\x19i\xe9\x99t\xeb3\x02M\u04f0\\\x9d9{)hd\xaai\x87\x87\xeb\x96e\xa0\xeaA:v\x1d\x88\"MJ\xb7\xaf\xc60\x92NR\xd7;\xfdH\x10\x8a\"\x84\xa2\xc8]e\xbbD}]\xdd@\xa1\xd0y\ua529\x9f\xbc\xf5\xd6[R(\xaax\xe0\x81\ax\xef\xbd\xf7Z'{+\x98\xff\xf4\u0467O\x1fu\xed\xdau\xb6\xdf\xef\x1fQZZzb}}\xbd\x9c0a\xbcr\xdcq\xc7\"\x84lU\xb2\xb4@\x9aE\x11 u\x8dU[\xcaX0}\nf,B\xaf#O\xa0\xeb\xd0C0c&\u07ff\xf1\x14\u07fd\xf6\x84\xa3\x9fV}\\t\xe3\x1d<\xfa\xd0\xfd\xf4o\x1f\xc6H\u01b0\xec\x83s\x92\xd7u\x1dE\u04595\xebKn\xbc\xf1f\n\n\n\xc9\xcc\xcc\xc4\xef\xf7\x13\x8f\u01db\x81s\xd3(\xbd\x11\x80\xed\x94U\xc0\x9e\xf3RQ\x14\x92\xc9$\xb3f\u0362]\xbb\xb6\f\x1b6\u048d\xec\x8d\xfd\x02\xba\x94`\xdbI\xb2s2\xe9\xdb\xef\b\xa4\xf4\xb3b\xc5w$bu\x14m\\JFf[\xba\xf7\x19\x01B`Zf3,oz]\"\xa5g\u013d6\x03\xcd\x17\xa2C\xb7C\xc0JPV\xbc\x163\x99L\x9d.\x9a \x10\f\xa1\xea:F\xb4\x1e;\x11!\xe0\x83\x95\xef?\xcf\u04b7\xfe\x1b\xcbH\x82\xaas\u044dw\xf0\xf0\x03\u007f\xa0WN\x90x,\xc2A\xc2q7\xaa\xf6\xb1aC!w\xdf}\x0f\x1b6l$\x1cN\xa7G\x8f|\xc2\xe1\xf4\xbd\x12\xed\xd9\xd9\u0664\xa7\xa7\xa7~\xb6\x11(-L\xd3\xdc\u06e4\xcb\xe5\xe1\x93\xc9$\xbf\xff\xfd=\u03181\rP\xd0u\xfd\x1f\x9c\x16\x04\xc8\b]\xbb\x84\xb8\xe6\x9a[\xf8\xedUw\xa3\a\u04895T\xf2\xe5\xfb\x0f\xb3z\xf1T\xc2\xe9Y\xa4\x87\xd2\xd1u\xdd1\xd9J\xa9\xf8\xd9\xef&\x11\x8fGA\vq\xf8qW0\xec\xe8\vP5\x95d\"\x86e\xd9)\xf0O9\t\b!\x97|\xbf\x94\u0253\xdfy\xe4\xed\u0253\xcf\x03X\xb3z\x85\xfc\u04df\x9e\x14\x85\x1b6\xb4N\xf7V0\xff\xc7c\u04e6M*`I);\x1fr\xc8\xc0\xe3\xea\xeb\xeb\xd0u]\xe4\xe4d\xe3T\xbd\xb5*YZ\x1e\x8c;\xc5;\x01 '\u034f\xe2v\xc41j*X\xf3\xf1T\xbe}\xe9\x11\xe2\xf55\b\xdd\u03f97\xdc\u0243\x0f=@\x8f\xcc F\"\xbeW\x03\xe3_r\xf8|~\xa2\xd1z\x1ey\xe4Q\x96.]\x86\xcf\xe7#++\x9b\xea\xeaj\x8a\x8a\x8a\xf7z~CC=\x86\x91\xdc+\n\xb6m{\xafy)\x84H\x15\x13\x01\xd4\xd4\xd4p\xd7]\xbf\xa7\xb8x\x1b\xaa\xea\xfb\t&q\x82\xa0?N~\xf7 \xd7]w+\xd7^s\x1f\x81`\x98\xba\xea\x9d\xcc\xfc\xfb\x1f\u0670\xf2KBi\x19\xa4\x05\xd3\xf0i:\x9a\xaa!\x14\a\xd0=P\xf7\xca\xf9\x9b\x02z\"\x1eE\rf1\xe2\xe4\xab9\xfc\xd8\v\xd0\xfd\x01,\xd3\xc0\xf6\x1a`\v\xc5K\xae\x8ah,\xce\u04a5\u02d4\x8f?\x9e\xfa\u03b4\xe9\xd3\u007f\x030c\xfa4\xa9\xbb\xcd`J\xcbv\xb6N\xfe\x83=J\xe7N~\xae\xbcr\x12\x91H=o\xbe\xf1\x14\x95\xbb\xb60c\xf2}\x9c}\u074bt\xea>\x04a[\u0130\x91\xb6\x8d\xad\xe0\xf6\vu\xb4\u4379P\x91re\x8cE\x1b\b\xa5\xb7a\u0109\x13\xc1\x96\xacX0\x05\xcb4\x10\x9a\xee\xde\x11\x05\x90h\xba.kj\xeb\xc5\xf7\xdf\u007f\xafdee\xbe\xbbf\xed\xdas\x0f\x198\xf0\u04de={\xb5v-j\x05\xf3\u007f<\xaa\xaa\xaa\xbcO\x8d\x86\x86\x86$8\xf6\xa5>_\xa0\x15\xcc[\xf0\xf0\xa0-S\x93\xe0&\xa8\xb7.[\x90\x02\xbd\x11\xa7\x9e\xc5\xed\xf7=\xc0\x90v\x01l3\x86y\x90o\xa3\xae\xeb\xd4\xd6V\xf1\xfe\xfb\xefS[[K\x9b6\x19\b!\xd04\x95+\xaf\xbc\x82\x1bo\x9cD\x8f\x1e\xbd\x9bD\xdf\x06_~\xf9%\x8f=\xf6\x04\xdf~\xbb\x10UU\xb1,\xa7C\xa9\xa7\x86\xf1d\x8a\x9e\xc2\u0176m\xd2\xd2B\xa8\xaaB$\xe2\x14\x10\xbd\xfb\xee{\\~\xf9e\xf4\xeb7`\x9f\xfe\xe9\xcd\xdeS\x1b\x14\x05B\xc18\xf9\xddC\\w\xedmTW\x973\u58d7(\u0776\x8a\xd9\x1f<\u0339\u05fdB \xad\r\xa6i`\xa9\x16\xa6\xe54\xbd\x964\xa9P\xa5\x89\xf2\xc5\x05\xf5x\xa4\x81P8\x8b\x91']\x8d\xb4,V,\x9a\x8ai&Q\x15\xcd\xdd\xe8\x1c\xe3\x05]\xd7eyy\x85\xf8\xe6\x9by\xbe\x8cp\xf8\xb5\xfa\xfa\xfa\x13\xc3\xe1\xf0r!D\x13O\x81\xd6\xd1J\xb3\xecc4\x8dVL\xd3LE8\x9a\xd6\xda\xe7\xb3eG\xe6\xce\xc7t\x1d|\xba\x9a\xa2\x1f\x00\xfa\x1d6\x92\xbb\xfe\xf8\x00\xa3{d\xa1\x99qLK\x1e\xe4k\x95\x80\xca7\xdf\xccc\u0672\xe5\xf8|:\xa1P\b\u02f28\xed\xb4\xf1<\xfe\xf8\xa3\xf4\xe8\xd1\x1b\xdb6\xb0m\x03\xcbJ\xa2(\n\xa7\x9c2\x9e\xc7\x1e{\x94~\xfd\xfa\xb8\xba\xf1\xc6\xdf\xe9\xa9^\xf6\xe4\xd2\x13\x89d3\xcae\xfb\xf6\xed|\xf8\xe1\x87xA\xca?\xdc$m\x87\xfe\b\xf8c\xf4\xef\x9f\u036d\xb7\xde\xc3\xf0\x11'\x00\xb0n\xe9t\xbe\xfb\xeaE\x14EC\xf7\x05\xf1i*\xba\xab\xac\xf1\xeco\xc1\x05w)\x91\xee\xc6#\xa5\xd3X:\x1ai@\x0fd1\xf2\xe4\xab\x198|\x1cB\x82i$\x1b7\x18\x97?\xf7\xf9\xfc\x94\x96\ucd27M\x9f\x91\xf3\xd0#\x8f\xbe!\xa5\xec\x04\xc8W^{\xad\xb5\xcdW+\x98\xef\u007f$\x93F\x93\x89\u072aZ\xf9\xb5\x8d\xdc\xecl\xb7\u035a3\xdaw\xcc\xe3\xc1\a\xefg\xc2\x11\x83\xf0[IL\xcb>\xe8\xe1\x9c\a\xac\xdf}\xf7\x1d\xa5\xa5\xa5\x84\xc3a\x84P\xc8\xcb\xeb\u0239\xe7\x9eC \x90F<\x1e\xc10\f\f\xc3\xc04M\x12\x89\x04\xb6m0f\xccXN>\xf9\x14\xb7xho\xde|O\xaa%\x99Lb\x18f\xb3\xa4\xe7\x9c9s\x89\xc5\x1a~r\xc3\f\xe9\xf2\u067a\x16a\xe4\x88n<\xf0\xc0\xe3t\xeb\xd6\a\x80\xf9\u04dee\u00ca/\b\x04\u00e8\xaa\x8a\xae*\u8aa3\xbaAx}Mid\xd2]\x91\x8b\rH\xcb\x01\xf4@(\x97Q\xa7\\G\xff\xc3N\u0136\r\x92\u0244\xdb|Z\xa4\x1e\xbaO\x17%;J\xf8\xfc\xf3\xcf\x0f}\xf4\xf1\xc7\u07d6R\xe6^u\xe5\x95\xd6\v/\xbe\xa4\xae\u07f0\xbeu\u2dc2\xf9>8 M\xdbk\xd1Ii\xbbG\xda\xd6\xd1b'\x95\x17y\x16\x15QSS\xedF\x9e\nw\xdd\xf9;\u039bp*\x8a\x11\xc30\x8c\x83\x0e\xe4RJt]g\xf7\ue76c[\xb7\x0e\x80\x9c\x9c\\\x84\x10t\xed\u0695\xbe}\xfb\x02\xd6>\xf9`Oz8l\xd8\xe18\t\xf9\xc6!\xd2\xd3\xd3R\x9f\xfb|\xbe\xd4\x02\xf4\x16Rk\u04a5e\x0e]\x0f\x10\x8fG\xf8\xdf\xff\xfdKJ\tr\xf1\xc5\x17s\xd5o\xafDJ\x93\xa4a\xee\xd5~\xed`\x81\xb9\x10\x1aEE\xc5\x14\x15\x15\xe3\xf7\xfb\xc8\xca\xca\xc40\x1c*%\x18\f\xfd\x03z\xc6I\x94\x06\x83\xc1\xbd\xc0\xdc)\x1e\x12\xfb\xa0J\xec\x14e\bN\x92\u007f\xed\u06b5\xff\x14\x95\xe5\x045&\x97^r6\xb7\xdcz+\x00[\n\xe6\xb3\xf4\xeb\xb7P\x14\x15Us\xfa\xa6j\x8a@W\x9c\x9e\xa7\u04b3Vt\xd5-.{\x92\xb2I\xb0%D#u\x84s\xbar\xd4i7\x92\xdfo$\x96\x11\xc34\f\xa7\x85\x9d\x10^\xf7\"\xa1\xea\xba\\\xb1b%_}5\xeb\u0799_|1\x11`\xd6W_\xc8{\xef\xfdC\xeb\xc2l\x05\xf3=\x8e\xe9\xb99)|\b\x87\xc3>\x00\u04f4\x88\u0162\xadw\xae\x85\x9f\xa6^{\xed\xf5\x942d\u0630\u00f9\xfb\xee\xbb\b\x873\x89\xc7\xe3?\x99R\xf8\xa5\u01ae]\xbb\xa8\xa8\xa8@UU6m\xda\xc4\xee\xdd\xe5l\u0672\x95\xd2\xd2\x12@\xfdQ\t\xec\xb6m\u06e8\xaf\xaf\xdf\v\xe8\x1d\xaaE6\xfbZ\xd32\u007f\x0f\xf4\xe3\xf18;v\xec\xf8\xa7\xaf=\x99t\xe4\x91w\xdc~\vc\x8f>\x11\x80\u0173_g\xcb\u06af\xf1\xf9\u04f0\u0756q\xaa\x10(\u00a1X$`#\xdd*\xd3\xc6k\xf3\x14.\x96m\x13\x8b6\x90\u04f9?\u01de};]{\rs\xbay\xe16\x96\x16\x8a#}\x14\x8a0-\x8b\x1f~X\xc1\xab\xaf\xbd\xfe\u0127\x9f}:\x02\xe0\xd5W^\x96\x0f=\xfcH\xebbh\x05\xf3\u0191\x93\x93\u3b46J\u02f2w\uae8ei\x9a\xb2\xb6\xb6\xae\xd9q\xbeu\xb4\x8c\u0474\xf0\u6957^\xc60\f22\xc2\\\u007f\xfdu\xf4\xeb7\x10\u00c8\xb7\xa8{\xe6\x81jmm\x1d\x91H\x14\u06f6\xa9\xact\x14Tk\u05ac\xe1\xddw\xdf\al\x02\x81@\xb3\x8aN\xc7d+H}}\rs\xe6|MUU\xf5>\xc1\xfc\xc7\xd4){&G\xe1\x9f;\xac8\x11z\x82\xcc\xcc,n\xbb\xf5v22r\x89\u0515\xb3\xe4\xeb7\x89\xd6W\xa2\xfb\x82\xce\xc6\xe2\xd4\xe6:\u007fW\x8af\u0562\x8e\x0eG`#\\\xf5\x8b\xc02M\"\r\xf5\xb4\xebv(\u01ddu\v\x1d\xbb\xf4\xc30\x12\xa9&\u04e2Io\u044a\xca*f\u035a\x93\xfd\xdcs/L\x9e:uj\x1f\x80?\xfe\xe1>~\u007f\xf7\u077c\xfc\xca\u02ed\v\xa3\x15\xcca\xc0\x80Av\x87\x0e\xed5!DUaa\xe1\xa2p8\x8ca\x18\xb2\xa6\xa6\u0199~-\x98f\xf18S\xaf+\x8d\xcf\xe7K=4MsU\x06\xe2\u07ca*\xf2\"\xeeW_}\x95\x95+W\x010~\xfcx.\xbc\xf0\x02\xa0\xe5Z/4m0\xd1(\u0143g\x9f}\x8e\x97_~\x19!4B\xa10\xba\xae\xa3\xeb\xbak\x8bk\xf2\xec\xb3\xcf3\u007f\xfe\xfc}\x82vS^|_\xf7\xb8\xa9\x14\u0463i\xfeY\xa5\xadC\xdbH\x8e?\xe1x.\xbc\xf8*\x00\n\x96\xcd`\xcb\u06b9h\xba\x0f\u02d68i&\x97\xcbW\x1a#t\xefO\xca&\x9b\x83m;t\x8biZD\"\xf5t\xea3\x82c\u03fc\x91\x9c\xdcN\x18F\x1c[\u068dQ=\xa0\ubeac\xad\xad\xe3\u06c5\x8bz\xbd\xf0\xe2K\x1f\xaf]\xbb\xba7\xc0\x13\x8f?\u0395W\\\u054a\xb2\xad`\xeeL\xf8\x11#F\x00\u0436m[\xdb+\x9f./\xaf\xc0\xb6M\xa7B\xad\x05\x02\x9a\xdf\xef\xc7\xe7\v\xe2\xf3\x05\xd1\xf5\x00RJ\xea\xeb\uba69\xa9\xa1\xa1\xa1\xc1Q#\xe8\x81\xd4s|>\u07ef\xfe\x94!\xa5DU},\\\xb8\x80\x8f>\x9a\x02@\xe7\u039d\x988\xf1*\x02\x814\x92\xc9x\x8b\u0778\x02\x81\x00>\x9f\xaf\xc9\xe6\xea\x00qmm-\xf7\xdcs/w\xdf}\x17\v\x17.\xa0\xaa\xaa\x8a\x9a\x9a\x1a\xbe\xff~\x11w\xddu\x0f\u007f\xfb\xdb\vMk!\xf6\xe1\x82(\x9b}\xdcWd\xee\xf7\xfb\xc9\xce\xce\xf9WW\n\x86\x11#=M\xe5\xa2\v/\xa5g\xaf!\u0636\u024ao\u07e7\xb6\xb2\x04\u055f\xe6F\u070d\xcfol9\xd7\u0737E\xba\x91\xba-A\xda`\x99&\r\xd1(]\xfa\x8fe\u0538\xab\t\xa5g\x92\x88G\x9a\x9c<\x04B(\xc2\xef\x0f\u0206\x86\b\xdf-\xfe~\xe0S\xff\xfd\xbfS\xa4\x94}\x00~\xff\xfb\xbbZ\xf9\xf3_\x8a\xe2l\xc9\x17\xb7sg\t\xf7\xde{\x1f\x00\xfd\xfb\xf7\xd7JJJ(**\x92\xa5\xa5\xa5\x98\xa6\xe3\xfb\xdcbvEEA\u05ddb&\u00c8\xb3z\xf5r\xbe\xff\xfe{6l\xd8\xc8\xee\u077b\x89D\"\x98\xa6\x85\xaek\x84\xc3a\xf2\xf2:1p`\u007f\x86\x0f\x1fN\u07fe}\u071f\x95$\x93\xf1_]1\x94\xa7\n\xb1m\x83\u0253\xdfa\xf3\xe6\xcd\x00\x9cs\xce\xd9\x1c{\xec1\x80\xd5\"_\x93\a\xa8YY\x99dddP[[\x8b\xa6\xa9)\u0149\xa2(TTT\xf2\xc4\x13O\xf2\xe1\x87\x1f\u04ff\u007f\u007f\x82\xc1\x00\x9b7oa\u02d6-\x18\x86\xe1\xf4\x1eu9\xf5\xa6\\\xf8\xfe@|\xcf\u0476m[\xbaw\xef\xf63\xdc\x03H$\x1a\x18:\xa4?\xe7\x9d\u007f%\x8f?z\x13[\n\u6ce5\xf0[\xfa\r\xff\x8d\xd3+\xd7J\xba\u0478H\xb5\x99s\xaeQ\xa6\xe8\x16\\\x80\xb6\x05(R`\xdb`\x1a\x06q\x04}\x87M \x11\xade\ue53f\x92\x8cG\xf1\x05B\xde\x1b\x89\x00\x11\f\x86dMM=\xb3g\xcf\x1dx\xdf\x1f\xfe\xf0\xb6\x94\xf2\f!D\u0663\x8f=\xae\xa4\xa5\x85\xec[n\xbe\xb9\x15q\xffS\xc1\xbcc\xc7N\\w\xdd5\x12 ##\xbc\u057b\u6492\x12\x99L&\x85\u05d2\xeb`\x03\x99\xd7V,\x99\x8c\xf1\xd5W\xb3\x98<\xf9\xef,_\xbe\x82\xb2\xb2\x9d\xd4\xd4\xd4\xee\x17Hrrr\xe8\xd4)\x8f\x11#\x86s\u99572f\xccQ\xf8|AW\u07db\xfc\xd5P0\x8e[\xa0\x8fo\xbe\x99\xcb\xf4\xe9\xd3\x00\xe8\u07bd\x1bW^y\x05\xa0b\x181Z\xf6<\u02e3}\xfb\xf6l\u0672\x856m21\x8c\x9a\x94V\xdc;1m\u06b4\x89M\x9b6\xb9^\xe7\x0eMf\x9a&\xa6i\xeds\x83h\n\xec{\x82\xba'S\x04h\u07fe\x1d\u077a\xfd<`\xee\x9c2l&L8\x9d/f~\xcc\x0f\u02fef\xed\xe2)t\xe97\x96P\xb8-V\xd4Db\xbb\x8d4\x1acq\xdbkL\xd4\u060c\u03b5\x10\xb0Ql\x81\xb0\xc10\x12(\"\xc0\xa0\xa3\u03a3\xben7\xdf}\xf16\xa6\x91@\xd7\xfd\xc8T\xb0/DZZ\x9a,.)\x95\x9f~\xfa\xf9\b\u02f4\xee\a\xae\xbb\xf7\x9e\xbbm\x80\x0f>\xfa\x88s\xcf>\xbb\x15u\xff\x13i\x16wQH\x80\xcc\xcc\u0302d\xd2\xd8\x04\xb0c\xc7\x0e\xdb\xe1\xcd\x0f\xae<\u0476mt]G\b\x95\u014b\x17q\xc5\x15Wr\xd9eW\xf0\xce;\xefRXXHMM-\xaa\xaa\xee\xa57\xf6\x16{EE\x05+W\xae\xe2\xe5\x97_\xe5\x82\v.\xe4\xfa\xeb\xafc\u035a\x95(\x8a\xeeF\xba-_O\xefE\xe5\xa6\x19g\xea\u0529l\u06f6\x1d\x80\v/\xbc\x90A\x83\x86\x00\xcdU\x1d--27\xcd\x04=z\xe4\u04f7o_l\xdbIv6-\xea\xf1\x80\xd8\xcbqx\xd2\xc2h4\x9aR\x92\xec\xeb=\xf9\xb1\xb9\xa9\xaa\x8d\n\x99\u07bd{\u04ebWO\xa44\u007f\x96\xe5l\xdbQ\x86\f\xe9\xc6Yg_\x8a\xaa\xeal-\xfc\x96\xe2\r\v\x9d\xe8Y\xd3\x1dO\x00!\x90BA\xba2C\xa1\xb8\x92\u0166f\\\x12\x90\"E\xb7H\x04\xc9d\x02\u0157\xc6\x11\xe3&r\xe8\x91\u3476\x85\u0133\th,E\xf2\xfb\xfc\xac+X\xcf\xf4\x193\xaf\xbd\xe1\u019b\x9e\xf2\xae\xee\u0733\xcfn\xb5\xe0\xf8O\x06\xf3\x13Np\u0295o\xba\xe9\x96h\xbbvmc\xe0\xb8\xce\x15\x15\x15\x1dT0\xf7\"r\u06f6y\xf9\u55f8\xe4\x92\xcb\xf8\xfb\xdf\u07e5\xb2\xb2\xb2\x19X\xec+\u0269\xaa\xaacW\xea\x96[\x03\x94\x94\x94\U000b7ffd\xc8\xc5\x17_\xc2G\x1f}\xe0r\xef\xbe\x16\x0f\xe8\x96e\xa1\xeb\x01\x96/_\xc1\xb4iN\a\xf7\xfc\xfc\xee\x9cw\u07b9\x00$\x93\x89\x16{\xedB\b,\xcb\xc2\xef\x0f1t\xe8P\xc2\xe10\xb1Xt/\xe9dSu\u029e:\xf1\xfd\x01\xb9\xe7w\xbe/:\xce{NFF\x06#G\x8e\xc4\xe7\v\xfel\xc9a\xa7:\xd4b\xfc\xb8\xf1\f\x1b~\f\xb6e\xb2a\xf9t\f#\x86\xa6\xfb\x11( \x14\x84\ua078\u04b8\x8e\x14\a\xd0e\x93\xe8\x1c\xc0\xb2%\xa6ec\xd96\x91\xfaz\xb4`\x16\xa3\u03f8\x8e\xfc~\xc3H\xc6\x1be\xc2\x12/w\xa2\n\xa1(r\xe3\xa6-,Y\xba\xec\xf6?\xfe\xf1\xfe?\xed\x19\u0334\x8e\xff@0\x1f=\xfaH\xe9N\x82\x02\x9fO\xdf\x10\n\x05\xa9\xa9\xa9\xb5\v\n\nS\x8b\xe3`\x8c@ \r\xd34y\xea\xa9\xff\xe1\xb6\xdbng\xe3\u018d\xfb\\\u0626i\xa6\x00\xd9+&\xf1>\x06\x83\x01\xfc~\u007fJ%\xa1\xaa\x1a\xabV\xad\xe6\x86\x1bn\xe4\x85\x17^\x04\x04>\x9f\xbfEG3\x8e\xae\xdcb\xee\u072f\u0678q\x13\x00\xa7\x9dv\x1a\xfd\xfb\xf7k\x06n-}\x1c\u007f\xfc\xb1\xf4\xe9\u04d7\xba\xba:TUiv\x0f\xffQ\xa4\xbd\u03c5\x95\xaaX\x96\xfb\x05\xf3\xee\u077bs\xe2\x89'\xa4Ny?O\x90!@&\xe9\u07ff\x1d\xa7\x9c\xea4^\u07b6~\x11\x15%\x85\bE\x03UE\xb8\u0560RU\x9c\xc2SE8\x0f\x0f\u061b\x81\xb3\xb7\x99\x81e\x83mY4\xd4\u0551\u046e\a\u01dc=\x89\xdc\x0e]\x88\xc7\"N\xc4\xdf\xe4\x87uM\x17I\u00d4\xeb\xd6\x15\xf0\xfd\x92\xa5wN\xfe\xfb\xe4\u06fck|\xfeo\u007fkE\xf4\xffD0\xef\u0631\x8b|\u5557\x04@\x9f>}k;w\xeeB\"\x91\xb0=\xe9\xdb\xc1(@\xf1\xfb\x9dD\xe73\xcf<\u01e3\x8f>FCC\xc3O\x8e\x9aTUu9W\a\xa8u]G\xd34TUC\xd75\xfc~?ee\xbb\xb8\xf7\xde?\xf0\xf6\u06d3QU\x1d\xbf\xbf\xe5\x02\xba\xdf\x1f\xa2\xb8\xb8\x98\xcf?w\xb8\xf2\xcc\xccL&L\x18\x87\xdf\x1f\"\x99\x8c\xfd*\x16\x81e%\xe9\xd7o '\x9exB\xaa\x9d\x9b\xdf\xef\xdf\xe7\xe6\xdc\xf4\xb4\xf5cN\x87^\xe9\xfe\x9e\xf7\xdf;\xcd\b\x01'\x9ex\x02\x03\a\x0e\xe0gO\x10K\x89\xdf'9\xef\xdc3\xe9?`(\xf1\x86j6,\x9f\x81P\x15\x14UsA[`\xab\x02\u02efb\xeb*R\x15HE \xf7B\x04\x99\x92\xb8XR:\xc9S)i\xa8\xaf\xa5c\x9f\xe1\x1cu\xfaU\x84B\xe9\xa9NE4\xb1\v\xf0\u9e88\xc5\xe2,]\xf6\x03\x9f|\xf2\xd9\xfd\x8b\x16-<\n\xe0\xfa\ubb93\x1f\xb8\x06c-y\xac_\xbf\xee_\xfc\xf9\x82V0\xdfs\xec\u0631C\x02t\xed\xdau\x99\xa2(\x12\xf0\x17\x16\x16\x12\x8d6\xfc\xe2/\xc1\x89D\x15>\xfdt\nO>\xf9$\xd1h\x94\xb4\xb4\xb4\xbd\x9ew\xf2\xc9'q\xc7\x1d\xb73q\xe2U\xa9\x04\x97\x97PSU\x15)!\x1a\x8d\x12\x8b\xc5\xdc^\x92V*r\v\x04\x02TUU\xf1\xf0\xc3\x0f3o\xde\\\x84\u041a\xf9\u0534\x98H\xc0\x8d\xc6V\xacX\xc9\x0f?,\a`\xec\u06238\xf4\xd0C\x01\xfbW\x13\x95{\xa0{\xc5\x15\x971d\xc8\x10b\xb18\xc1`\xe0'\x95\xf3\xefo\xd3\xdeW\xa4\xdd\xe8^\b\x03\a\x0e\xe4\xca+/\xc7I\x10\xff\xbc}l\x1d\x9e\xdbd@\xff\x8e\x9c~\xfa\x04\x00\xb6\xae[@\xbc\xa1\x12U\xd7A\x11)\x9e\xdb\xd6\x15\x8c\xa0\x82\xa9\v,\r\xa4\xe2x\xa7\xbbt:\u04a3]\\Su\xcb+*\xb2m\x1a\xa2\t\xfa\x8f9\x8da\u01df\x8em\x19\u0636\xebc\xd3D_\xafi\x1a\xd5\xd55|\xbbpQ\u01bb\xef}\xf0\xb6\x94r(\xc0\xb9\xe7\x9c\xd3\"\xe6\xc7\u018d\x85\xfb\xfd^\u07fe\x03\xfe\xa5\xdf\u0777o\xff\xbd\xbe\xb6e\xcb\xc6\x03\x87M\xbf\x86\xc56d\xc8`\x00\xce>\xfb\xcc\xd5\x1f~\xf8\xe1.\xa0CQQ1\x1b7n`\xf0\xe0\xc3\xfe\xa1\x17\xf4\xcf\u0271\xaa\xaa\x8f\xe2\xe2\xed\xfc\xf9\xcf\u007fa\xf7\xeerrrr\xc8\xcd\xcda\xfb\xf6b\f#\xc9\xd1G\x8f\xe5\x96[nf\u0528#\xc9\xce\xce&\x91HPPP\xc0\x9f\xff\xfc\x17\xfe\xfe\xf7wH&\x13dffb\x18&\xf5\xf5\xf5\xa9\xeb\xb6,\vEQ\xf0\xf9\xf4\x94V}\xf3\xe6-<\xf1\u0113\f\x192\x84\x8c\x8c,,\xabe\xd9\x18\xe8z\x80X\xac\x81\u0673g\x13\x89D\x00'\xdal\xdf>\x8fX\xac\xe1W\xa3\x9dw\xfc~\x92\xf4\xee\u074f\x9bo\xbe\x89k\xaf\xbd\xce\xf55w|Z\xf6\xe4\u021b\xea\u01fd\xc20E\x11n\xbb\xb8\x1f{\xbf4\f#Izz\x1a\x93&Mb\xc0\x80AHi\x1e\x90\xbc\x88\xe1Jw/\xba\xf0l^}\xe9\x19\u028b\v\u0639u\x19=\x0e\x1bO\xd2H\x80\x90\b\t\u00b2As\xa3r\x01\x12\x05M\u06a9\x86\x18 \x91\xb6\xa7F\x97\u062e\\Q\x95\x02#\x99\xc0\fe0\xea7WP\xb6\xbd\x90\xf5\u02d7\x12\b\xa55\xd9\t\x9c\nQM\xd3)/\xaf\xb4\xe6\xcc\xfd\xba\xdb\x1f\xfex\xff\x93R\xcaqB\b\xe3\x8c3~sP|\u043f\xfcr\xa68\xe9\xa4S$@\xef\xde\xfd\xfe\xd1\xdc\u040b\x8b\xb7\x1d\xbbl\xd9\x0f\x9d~\xf8\xe1\a\xa3\xacl\x97\x15\b\x042\xbbw\xefv\x88\xcf\xe7\u03c8D\"\xbb7l\u0638\xda\xef\xf7%{\xf4\xc8W\x87\f\x19\xa2\x0f\x1e|\xe8\xf6v\xed:\xce\xde\xd7\xef\xf3|\xf1\x9f~\xfa/b\xe8\xd0!r\xec\xd8c\xfe\xb3\xc0|\u0528Q\x00\xf4\xea\xd5o\xfe\xf8\xf1\xe36\x86\xc3\xe9\x1d\x8a\x8b\x8b\xf9\xee\xbb\u017f(\x98{\x94\u039bo\xbe\xc5\xf7\xdf\u007f\x0f@,\x16\xa3\xb8x\a\xe3\u019d\u00ad\xb7\xdeB\xbf~}\xc9\xcdm\x0f@2\x19E\xd7u\x86\x0e\x1d\xc6s\xcf=\x83a$y\xef\xbd\x0fH$\x92)u\u011e\u05a9\u0264\x81\xdf\xefD4\x86\x91d\u039c\xb9\xbc\xf7\xde{L\x9cx-\xba\xae\xff\xecQ\u073f:v\xef.g\u07bc\x0584Xo\x86\r\x1b\xf6\x0f#\u05d68L\xd3DUU.\xb8\xe0<\u05ad+\xe0\x89'\xfeD\xc1 \xe3A\x00\x00 \x00IDAT]]\xad[\xca\xefT\x88\xee\xebu)\x8aB8\x1c\xc64M\f\xa3\xa1\xd9s\x9a\xde_]\u05f1,gS\x988q\"\xff\xf5_\x17\xe1\xd4\x15$\x0f\xd8\x06\x050\xa0\u007f_F\x8d\x1e\u00e7\x9f}\xce\xf6\xc2\x05\xf4\x1dq:BU\xb0\xb1Q$\xf8\xa5\xc0\x92\x12Kq\x146R\xb3\xb1m\x81\xb0%\xb6\x02B*\bl\a\xe8\xdd\r\xc0\x96\xa0HP\x10D\x1b\x1a\xc8\xed\u0715\xa3\u03fd\x92]E\u06e8\xad\xac$\xe0\x16\xf7y\u01b9\xaa\xa2 \x84\xaal\u07bc\x95\x99_|yBfV\xe6\x8bR\xca+\x85\x10\xf2\xfd\x0f?P\xcf;\xe7\xdc\x03Z\x1a\xbcr\xe5\x0f\f\x1e|X\xea\xff\x1e\x90\xbb\xefS\xa0\xa4\xa48TXX8z\u0252%\xf9\xb5\xb5\xb5\x87\xf9\xfd\xfe\xa3\x8b\x8a\x8a\xa2\xf5\xf5\xf5\xf6\xc9'\x9f\xa8\x1b\x86\xd5.\x12i\bF\xa3\x11\x99L\x1a6\b_(\x14\xd4\x15E\xc54\r\xa2\xd1X\\Q\x84\xbd`\x81_|\xf4\xd1\x14%\x1cNo8\u7733\xcb{\xf5\xea\x95\x00\xb9\xb0c\u01ce\x9b\x86\x0e\x1d\xb2}\u0420C\xe6ge\xb5\xdd\rp\xf3\u0377\xc8=\xe9\xbb\xff\b0o\u05eec\xea\xf3^\xbdz}\xb3j\u056a\xa3\x8a\x8bw\xb0`\xc1\x02&N\xbc\xaa\x99\xd4\xeb\xc0\x82\xb9\x8f5kV\xf2\xd1G\x1f\x11\x8b9\x15\x8d\u0468\x13-\x8f\x1e=\x8a1c\u01ba \x1e\u00f6mW\xfa\xe64\xf7\xcd\xc8\xc8\xe2\xb6\xdbn\xe5\xeb\xaf\xe7\xb1k\xd7.4M\xdb\xe75\u06f6M\"\x91$\x10\b\x10\b\x04\x88Fc\xbc\xfe\xfa\x9b\x9cv\xdait\xe8\xd0\t!\xcc\x16\x01\x94\xde\u01b6l\xd926mr\x12\x9fc\u018cf\xf0\xe0CS\r\x1c~m#\x91H\xe0\xf7\x87\xb8\xfb\xee\xbb0M\x83\xe7\x9e{\x9ex\xb6\xaa\xaa\xaa\xe7\xb6m\xdb\xd5\xda\xda\x1aa\xdb\x16\x8a\xa2\x92H$\xb0,\v\xc30\x89\xc7cn\x9eC\xb8\xef\xabt,\x9c\xa5\xed\xe6\xc0\xf4\x80s\x10\x91\x9eT\xd7\x1f\x0e\x87sV\xacX\x010\xd8\xe7\U000d16dbK\xf7\xee\xdd\xe3\xb7\xdf\xfe\xbb)\x1d;\xe6\xbd\u007f\xd2I\xc7\xfd0h\xd0\xd0\"o\u04ff\xef\xbe{\xb5+\xae\xb8\xdc\xee\u0673\xb7\xfdo\r\xe6M\xc7\t'\x1c\xff\u0357_~u\x13\x90\xb1j\xd5\x1a\u05ae]\u01e0A\x83\x81\x03\x1b\xb1z7r\xe6\xcc/(,,l\xa6J\x00\xa7$\x1c \x12\xa9C\u04f4\xbd\x8c\x944\r\xfa\xf5\xebO\x97.\x9d\u0675k\u05cf\xca\xdbl\xdb\xc60\f\xfc~\xc7\xf6\xb7\xb0p=_}5\x8bK.\xb9\xec\x17;\x85\xfc\xe3\u0701\x0eX,X\xf0m\xca5\xf0\xf0\xc3\x0f'\x18L\xffUQ,{\x03z\x94\xb4\xb4\f\xee\xbf\xff\x8f\xe4\xe4\xe4\xf0\u05ff>CII\t\xc1`\x10U\xf5\xa3\xaa*\xc9d2\xb5\x89\xefi\xc9\u073c\xef\xa7s\xc2J&\x93dggs\xed\xb5\xd7\xf0\xbb\xdf\xddF\x9b6\xd9\xc4\xe3\x91f\xf3\xea@\x9d6|>\x9d\xa1#G\x93\x99\x95\u016e\x1d\x85T\x94\xae\xa6\xef\xb0\t\xd4V\xc6\x01\x81%,\xa4\x10(\xd2F*N\xa7\n\xa9\bPAZn\x8b9\xd7\xfaV\n\u0464\xdc_\xa2I\x81*!\x19K\x12\xb5\xd2\x18>\xe1|6.[\u0136\x8d\x85(\x9a\xe6\xb0-\x12\xa4\xf0\\\xd4Ql[\xca\u014b\x97\x88\x8cp\xf8\x8e\x05\xdf~\xbbl\xcc\xe8\xd1\x1fuh\xdfA\xd6G\xea\t\xa7\x85\u007f\xf2k+,\\K\xbf~\x03\x91R\xf2\xc9'S\u0122E\x8b\x94\x01\x03\x0e\xb1\x00\uf0542\f\xa4O\x9b\xf6y\xc6\u018d\x1b\xf2KJJ\x87M\x9cx\u0571555\xc7l\u0738I)/\u07cdiZX\x96I<\x1eO\x15\x8a\x99\xa6)\x15E\x11N#\x10\x87B\u06f3VDU\xb5\x94$\u007f\u03e0,\x99L\xb2{w9R\u06ae\xd8Ae\u01ce\x12\u05af_\x1f\xf0\xfb\xfd\x17v\xeb\xd6\xed\u0082\x82\xb5e\xf7\xdc\xf3\xfbWF\x8d\x1a5g\xfc\xf8\xd3\x16\n!\x12\x8f<\xf2(\u007f\xfd\xeb_\u052b\xae\xfa\xad\x15\n\x85Y\xb7n5\x03\x06\f\xfa\xf7\x05\xf3\t\x13N\x9f\xfb\x97\xbf\xfcu]I\u024e#\n\v\v\x99?\u007f\x01\x83\x06\r>\xa0Me\xbd\u0098\xfa\xfa\x1a\x96.]F<\x9e@\u04f4f=\x1e\xcb\xcb+R\xc7\xee\xfdo\b\xec3\x91\xd9\x14\x04\xbc\xd7\xe0\x1d\xfb\x03\x81\x00\xd5\xd5\xd5\u031b7\x9fK.\xb9l\x9f\r\x84\x0f\xceP\xa8\xaf\xafa\u0672\x1fp\xb8\xc7\xde\f\x1e<\x98\u007f\x87\x11\x8fG\b\x06\u04f9\xe3\x8e\xdb\xe9\u07ff\x1f\xcf?\xff\x02\xf3\xe7\xcf'\x1a\x8d\x10\x0e\x87IK\v\xa56\\\xa7\xefg\xa3\u4c39\xbb\xa2#M\x1d3f\f\xd7\\s\r\xe7\x9f\u007f.\xaa\xea#\x91\x88\xfe2zk\xefd\x90\u04c1\x01\x87\x8fd\u1b19\xec,Y\xc9\u19ddOL\xd6b&-0\xc1\xb6l\xb0\x04~U\xa0\xa2:RD\xd5y-\xb6\x05\xb6pZ\xcba:\xe0.\x15\x1c\x8d\xba\"\x10\x8a\xc46-jj#du\xec\xc5\xf0\t\xe7\xb3\xf3\xf9'\xb0L\xc3\xdd\xf0\x1b\xbdn\x1c;^!b\xf1\x18\x8b\xbf_\xaa\xf5\xeb\xd7\xf7Y)\xe5:!DA8-\u0316\xad[\u945f\xff\x0f_\xd6\x17_L\xa7_\xbf\x81M\u05cb\xf4\x00|\xfb\xf6\xad\x87|\xfe\xf9\xe7\xc3W\xaf^\xdd\xfe\x9ak\xae>\xbc\xb2\xb2*'\x91\x88w6M\xb3\xf7\xb6m\xdb(//'\x99Lb\x9a\x16\xb6m\xb9\xf5\x03\x8dEa \xd04]\xec\x19\xc4\xed\xfd9?b\x94'S\xbeQ^m\x82\xd360\x81\xaa*\xd4\xd4\xd4RXX\xd8!//\xef\xbeM\x9b6\xdf\xfb\xf5\xd7\xdf|\xf0\xe1\x87\x1f\xbcu\xce9\xe7N\xbb\xe9\xa6[\xac\x9bn\xba\x85\x17_|\x9e\x8d\x1b7\xff{F\xe6\xf3\xe7\u007f\xc3QG\x1d\x8d\x10\u00ba\xe3\x8e\xdf}SP\xb0\ue23a\xbaz\x16.\xfc\x96+\xaf\xbc\x1c\x9f\xcfw\xc0J\xe0\x1d\x9f\x0e\x9d\x8d\x1b7\xa6|G\x9aj\u01e5\x94\xacZ\xb5\x8a\xda\xda*\u06b4\xc9$\x1e\x8f\xeds\x12\x94\x95\xed\xa2\xbc|\xf7~\x8f\xe3M\x9f\ub045\a\xfe\xabW\xaf\xa6\xb4t\ayyy?\x1a\xd5\xff\x12\u00fb\xc6m\u06f6\xa5\xbc\xb8{\xf6\xecI\u07fe}\xd8_g\x9e_\xd3\x10B\x90H8\xf9\x8e\t\x13\xce`\xe8\xd0\xc3\xf8\xec\xb3\u03d86m:\xf3\xe7/\xa0\xb2\xb2\x12EQ\xdd\xc8L\xa4\xf2}M;`\x85BA\x86\f\x19\u00b8q\xa7r\xfe\xf9\xe7\u04eb\x97\xf3\xde\x1chje\xcf\xe0\xc1\xc6\xc6\x17J\xa3\xff\xd0\xe1,\x9c5\x93\x92\xad\xab\x88\x8bJ\u04bbeR_[\x0f1\x05b&\"ia\x1b\x02M\xd8H\xdbi\xe7\xa7\t\x05K\xb1\x1d\x8d\xb9\x05\xa6%\x91\xb6C\xb1\b\u06e1X,\x17\xbc\xccx\x82\xb8\x11\xa0\xe7\x11\xc7\xd3g\xf17\xacY8\u05c9^\x9b\x18\x05\b!R\r.**\u02993\xf7\xeb\x0e}\xfa\xf4\xb9\t\xb8\x0e`\u02d6\xad\xec\xdcUF\xc7\xf6\x1d\xf6z-\xc5\xc5\u06d86m:\xd7^{='\x9f9~\u04e6-G^{\xedu\x03l\xdb\x1eTVVFYY\x19\x89D\xd2\xcdg\x18)\x16\xbf\xf9zSR\xc0\xdc|~;\xf7\u054b\u029dG\xa3\x0e\xdfk\x8a-]1~c\x91\x95\xe7&\xe99\x9b\x89\xd4)\xad\xe9\x89\u0272L6o\xde\u0136m\xdbD\u01ce\x1d\xcf+,,\xfc\xcd\xef~w\xdb\xfb\xe7\x9cs\u059bG\x1e9\xe6\xabk\xae\xb9\x1e\x80%K\x163|\xf8\xc8\u007f/0\xef\u0631C\x13\xaa\xe5\xb8\x17\xbe\xf9f\u078d\xbbw\xef\x0e\u035f\xff-K\x96,\u1a23\x8eA\xca\xc4\x01\x05\x92\xa2\xa2bJKK\xf7\x99\b\x9b;\xf7k\xbe\xfbn1'\x9f|*\x81@\x90d2\x912k\xf2\f\xb8>\xfex\n;w\x96\xb9\xaa\x06s\xbf\x1bGS@\xf7\x80\xbb\xb4\xb4\x94M\x9b6\x92\x97\xd7\xf9\xe0\xc7\xe4\xee\xe9c\xf5\xea5)\xd7\xc0\u07bd{\x92\x9b\xdb\x1e\u00c8\xff\xdbT\xf99\x00`\u0429S\x17\xae\xbd\xf6z&L\x18\u03d2%KY\xb1b\x05\x05\x05\x85\x14\x15\x15S]]\x8da8ADFF\x06\u077au\xa3_\xbf~\f\x192\x98\xa1C\x87\u0437o?@!\x91\x88\x1e\xd0\xd3\xe3\xfe\x02s\xdb4\xc8\f\xf9\xe9;\xe0\x10\x00vo\xddH\xd5\xce\":\x1d2\x94x2\x06\x9a@\xf8\x05VRAIZ\x88\x84\x8dL\x9aH\xc3FJ\a\xc4l/\x02\x176\xb6\x05\xd8\x12i:\x85D\xd8\x02Ew\x14.\xb1h\x946Y\xed\x18v\xea9\x14\x17\xac\xa2\xa1\xbe\x1e\xdd\x1f\xf0\x10/\x05t\xb6\x9bP.,\\\xcf\xd7\xdf\u033bDJ\xf9\x8a\x10b\xd9\t\xc7\x1f\xc7\xd6\xed\xdb\xf7z\x1d_~9\x93.]\xba\xef\xb9N\xd4Y\xb3\xbe8g\xfa\xf4\x99'\x9fq\xc6Y\xa3\xaa\xaa*\xfbVVV\xb2k\xd7n\xa2\xd1(\x8a\xa2\u062a\xaa\n!R\xddNS`\xbb\xaf\xc0\u010b\u031d\x8f\x8eE\xb0\xd7(\xd5m\x85\x8d\xf4\xac\u007f\xbd\xc6\x1e^\x03\x12ic\xe36\xf7p\xbf\xef\xd9\r\xe3Ya\xa7TOJ\x93\xa8\x1d,\u02d2EEE\xb2\xa4\xa4T\u07fau\xeb\xc5\xc5\xc5\xc5g=\xfb\xec3\xafM\x9at\u00fdB\x88\xda\xe1\xc3G\xf2\xd4S\u007f\x12w\xdcq\x97\xfc\xb7\x01\xf3;\xef\xfc}\xea\xf3\x93N:\xb5\xcd\xdbo\xff]]\xbdz\rEEE\xbc\xf9\xe6[\f\x1e<\x98p8L\"q\xe0\x00\xbd\xb2\xb2\x8a\xda\xdaZ\x14E\xa4\xfcF\x9f\x02({6\xd4\xf6\xd6X\xf3\xfb RHo#\xb1M{\xaf\xf5g[\x0e%c\xfd\x9f<\x86\x9a\xffm\xab\xc9\xdaQT\x15MU\xbdz\x13\xe1\xf0\xf3\xd2\u07bau\x9b]^^\x11,))\x99TYY1DJy\xb9\x10b\xd3\x1dw\xdc%O;\xed4\xf1\xfc\xf3\xcf\xc8=7\xb5_\x1d\x98O\x9d\xfa1g\x9ey\x16\x00\xf5\xf55C\xee\xbf\xff\xfe\x0f\u05ef_\xef\x8f\xc7\xe3\x00\xbc\xfd\xf6d\xbav\xed\u01ad\xb7\xdeL \x108`\x9cr\"\x11wmO\x95\xd4\xed\xf1\xa2-)%\xf3\xe6\xcd\xe3\x82\v.\xe2\xea\xab'2z\xf4h\xc2\xe10\xe5\xe5\xe5\u03181\x83\xb7\xde\xfa\u007f\xec\u0739\x93`0\xf8\xa34\xc9\xfe\x12\x9c\xb1X\x8c\xda\xda\xda\x16\x03\u6595\xa4\xb0\xd0)\xb8\xc8\xcb\xcbc\xc0\x80\xfe\xfc\xbb\x0eo\xf3J$\x1c\xfa\xcc\xe7\xf3\u047e}\x1e\xed\xdb\xef\xef'l\xa7\x89\x83;\x0f\x0ff2\u061bJ\x83\xf2\xf38\xe6\xb8\xe3\xf9t\xea\x14j\xcaw\x82\x04U\x15(\x96\x03\u0336G\x1d(\x02\xe1S\x10\xba@\x06U'R\x8f\x99\u0204\x85\x86\x8de\xb9d\x85l\xf4b\x91\xa6D\x899\x96\x00I#F\xa8]\x16\x87\x9et6\xdb\xd7.\xa7\xacx\x1b\xbe@\b)\xad&\xe0\x99\xf2\xba\x91\u06f7o\x17\xb3f\xcd>#\x1a\x8f\x8d\v\x05\x82\u04fd5\xf5\xd8c\x8f\xea=z\xf41\xdc\xff\xa7\xbf\xf7\u07bb}\u05ef/\xbc\xf8\xa2\x8b.\xbcp\xed\xda5\x1d***\xa9\xac\xac\xf6\xfa\xb5J\xc5\xe11\xf4=\xd7~s\x8a\u0109\x99m)\x9b\xb9FJ\x01\xd86\xb6e\xa5(\xa6f \xa9\xfb\xd0C!B\x81\x10z \x88\x1e\f\xe1\x0f\xa5\xe3\v\xa5\xe1\xf3\a\x91\xaa\xcf\u9deai(B`\x18\t\x92\xb1(\u0246:\x12\xf55\xc4\x1bj\x89\xd5V\x93\x886\xa4\x92\xac\u0496\xae0Bs\xe7\x87T\x84\x10JCC\xbd\\\xb9r\xa5hhh\x18\xbdk\u05eeO?\xff\xfc\u04f3'L8\xbd\xe0\xb3\xcf>\x93\x17_|\xe1\x8f\xea\xf2\u007f\x15`\xee\x019\xc0_\xff\xfa\xccog\u0318\xd9s\xe5\xcaU(\x8a\"-\xcb\x12\xc9d\x92\xb7\xdez\x9bc\x8e\x19\xcb\u0631cS2\xb2\x03\xc3\x15\x8b}\x82\xae\x97\x10]\xbbv\x1dw\xdf}/m\u06f6\xc5\xef\xf7\x13\x89D\x9a\xa9W\"\x91H\xb3\xe3\xf6\xfe\"q\x0f\x04\xfc~\u007fJ9\xd1r\xe8\v\x85\xf2\xf22v\xedr\xf8\xff\xdc\xdc\\\xb7\xcaU\xfe\u06fb\xe2I)I$\x12\xbf\x9e\xebu\xe3\xc2v\x99\xe9\f\xe8\u06db\xa9\x96EEi\x11\x89H\x12MU1\x15\v\u06e5\x01\xa4t\x13\x9d\xd2%\xdc\x15\x10A\x05|:2\xa1 \xa2&:N\xa4\xeaq\u0136\xed\x16|J\x89L\xd8`@\u012a\xa5}\xf7\xc1\x1c2v\x1c\x15\uff88\xb4\xf7P\xfb8\xa5\xa5(B\x88\x9a\x9aZ\x96,Y\x1a|\xe7\x9d\xf7\xae\x91R\xce\x12B$\xcf8\xf3L\xed\xd3O>1\x00\xdeyg\xf2\xb8\a\x1f\xfc\xe3\xbd?\xfc\xb0r\u052aU+ihh\xa0\xa1!B2\u9038\xa6iBJ)\xf6\x06p\x1c{\x01o\x9d\xb9fa\xa9^\xacV\xf3\x80J\xf3\xf9\b\xb6\xc9\xc1\x9f\x1e\u019f\x96\x8e?-\x03\u007fZ\x06\xa1\xac\xb6\xb4i\u05d1\xb4\xb6y\xa4\xe7\xb6'\xb3m\x1e\xa1\xac\\|\xe1L\xfc\xc1\x90\x03\u07b8.\x94\xb8'\x16\xe9P\xa4\xb6\x91 QWE}Y1\xe5[\n)[\xb7\x94\xe25K\u067d\xb9\x00\xcb2\xb1,'I\xae\xeb\x1a\x9a\xa6\xba\x1b\x8c\x10\xb6m\u02cd\x1b7\x8a\xfa\xfa\xfa\xfe55\xb5\xd3\x16,\x98w\xe7\x981c?\xbc\xe0\x82\x8b\xe4s\xcf=\xc7\xf5\xd7_\xbfO,h\xf1`\xbej\xd5r\xc2\xe1\f\xf2\xf3{\"\xa5\f\x9dp\xc2\xf1\xa3\v\n\nH&\x93R\xd34\xe1M\x90\u035b7\xb3f\xcdZ\x8e:\xea\xa8\x03\xa6;\x0f\x06\x83\xf8\xfd\xfe\xfdz\xb1\xf8|>\f\xc3 \x1a\x8d\xb2}\x1f\u071f\u01c3\xef\xc9\xd7\xed\v\xc8\xc1\xd1rgff\x12\x8dFS\u0296\x83=\xbc\rm\xe7\xce2<\x1b\xe2\xdc\xdc\\:t\xe8\xe0\xc6w\xad\xa3\xa5\r\x87\xda\v\u0465Kg\x84\xa2PWVJ\xb4\xbe\x16\xdd\x1fBS\xc0R@X^\xcc,\x1b9\x11w:\nU \x82*\xaa.@\x15(\xa6D&m,KbI\xe7\xae+\xe0\xfa\b\b\xac\xa8A\xb4\u06a4\xef\u19f2q\xe9\xb7l+\xf8\xc1md!R\xc9C\xcfS]QT\xb9q\xc3F1o\u07bcqg\x9c>\xe1:\xe0\xe9O?\xf9\xc4L\xc4c\xdd\xee\xbe\xe7\xee{\xdf{\uff49\u02d6-\xa7\xba\xba\x8aD\"\xd9\xcc\x12\x03\x10{\xaa\xc0\x1a\xbf\xe7\xca(]%\x89m[\u0626\x99\nk\x03\xe9\x19du\xeaNF\x87.\x84\xdbw&\xabcW\xdat\xe8L0\xbb\x1d\xe1\x9cv\xa4g\xb5\u00d7\x9e\x81\x16LCSU\x04`z\u007f\v0l\xe7/\b\x01\x9a\x04\xd3v\xde7E\x80\x94\nR\x82?\x10\"\xd8&\x9b\x9cn\xbd\xe93\xfa84\x01\xbb7\xae\xa5\xf0\x9b\xe9\xac\xfej*\xdbV,\u00b2LG!$mt\xdd\xe76;q\xf6\xbd\x9d;w\x8aE\x8b\xbe\xcb\x0f\x85B\x1f|\xf9\xe5\u0309'\x9dt\xca+\x93&Mb\u04a4I\xbc\xf9\xe6\xeb\\v\xd9\x15\xbf.0?\xf4\u0421\xfc\xfd\xef\xffO\x00\xf2\xf5\xd7_;\xa3\xa4\xa4d\x80\xdbzM\xec\t\xd8k\u05ee\xc30\f\x97\xaf\xfe\xf9u\xe7m\xdb\u6493\x93M}}\xfd^\xfd\x1dM\xd3l:\u0270m\x99\xf2[\xd9W\xc2\xe5\xa7\xf0\xcbR\xcaT\xc5gzz:\xb9\xb9\xb9-\u6f94\x96\x96R[\xeb\x80y\x87\x0e\x1d\b\x04\xd2~&O\xee\xd6q \xc0\\U}\xe4\xb6k\x8f\xee\x0f\x10\xad\xa9$\x19i@\xf7\x87\x1c@\x15\x8d\x8a\x1c\xe1\xa4\xfaR`\xeeQ*\x02\x89\xa2*\u0220\x8a\x1dT]\xfd\xb8\xc42m,)Q\xa4\x13\xdd#\xc0\xb6\x05\xf1\xfa\b\xe9m\xba2p\xe48vm\xdf@<\x1eE\xf7;y$\xe1\x05\xd2B\"TE\xc4\xe2q\xeb\x87\xe5+\xb4\xe93\xbe\xb8PJ\xb9\xe0\xaf\xcf<\x93\u007f\xe9e\x97=\xb9l\xd9\x0f\xf9\u06f7ow\x03 \x81\xa2\x88f\x94US\u00f3\x94\x9d\xb4P\x90H\u01f6\xd70\xb0\f#\xb5\x0eC\x19Y\xe4\r<\x9c\x8e\xfd\x87\u04b6\xd7@\xb2\xbb\xf6!\xbbs>\xc1\xecvh>\x05lG\xb1\xa3\xba4P\u04b21L\x03\xd3H\xa2\xe2\x18\x8dY\xb6\xd3\x1a\u06e3\xd6U\xc5q\x93\x94\x80\"$6`\xd9\xc2\xf5\xa5\x01UU\x1c\x17N\xa9`\xab*y\xfd\x06\xd2e\xe0@\x06\x9fr.\xdf}\xf0\n\x8b\xde{\x89\x86\xaarL\x04B\x98\xf8\xfd>\x84\xb0\xb1m[\xa8\xaa\u02ae]e|\xf5\xd5,TU}y\xc1\x82o\xca\u018c9\xfa\xf3;\xef\xbcC\\v\xd9\x15\xf2W\x17\x99\x1bF\f]\x0fJ\x80\x0f>\xf8\xe0\xf8\xd2\u049d~\x97\xb0V\xf7\x04\xf3/\xbf\xfc\x92\x82\x82\x02\x06\x0f>\xacY\x92\xf2\xe7\x89F\xa1s\xe7.\xe4\xe5ud\u06f6\xed.ol\xed\x15u7\xe5\xd0\xf7\u03c3\xcbf\x1e\x1e\xfb\x02x\u03ec\xa9\xba\xba\xca\xddH\xda\u04af_\xbf\x16s_\xca\xca\xcaR\x1c~^^\xdeO\u069cZ\xc7\xc1%\xceC\x19Y\xa4\x87\xdb\xd0P]I\"\xda@ZN{$\x12U\x11h\x9a\x02\x86t\xacl\xed\xa6\x80\xeeT\x89\xba\x04\x82\u04c2BU\x90>W\x9f(\x14\xa4%\xb1\\6W\xd8N\xa8.5I2\x91\xa0\u03f0\x93\u067af\x11k\xbf\xff\x12[\xf77\x82\xb1\x10N\x85\xa9\x94\xf8\x03\x01e\xe3\x86M\u031e=wP]m\xed\x9b\xef\xbe\xfb\xde\xc0\x82u\uba29\xa9F\xd34\xe9IR\x9a\xae\r'pRP]\xc7Q\x89\xc0\x966\xa6i\x91\x8c\u01f1M\x03\t\xa8\x9aN^\xdfC\xc9\x1fq,]\x0f\x1bC\xdb\u0783\xc8\ua50f/\xa0\x12\x8bK\xa4i`$\xe3\x18qGo.\xdc\xfc/\xd2=uH\xf0\xb9o\x8d)\xdd\xcaW\xf7-U\x04\xa8R\xa2\xbaI]7\xbcCU\x15\xfc\x9a@W\\\xba\a\x89\xb4-,\xdb\"n\n\x14\xa0]~w\xc6\xdf\xf6\b\xed{\xf6g\xe6\xd3\u007f\xa4\xa2x\v\x00\xba\xa6\xa3\xfb|\x18F\xe3)\xa4\xa2\xa2\u009c3g\x8e\x16\b\xf8\xff\xec\xea\xf2\xb7\xbc\xf1\xc6k\xea\xe5\x97_i\xfd\xaa\xc0\xfc\x99g\x9eS\x00{\u04e6\xc2\xfe\xe7\x9e{\xc1\xa8\xba\xba:\xf7\xbe\xee\r\x1c\x9b6m\xe6\xb9\x17^\xe6\u017f=\x87\xae\aI&\xa2?\x9b\x8b\x8fm\x1b\xf4\xec\u0643\xee\xdd{\xb0p\xe1w?\xda\xe7\xf1\xc7<\xb0\xf7l^\xe0%D\xf6\x04\xfc=\vP\xbaw\xef\xf63v\xa4\xf9\xd7GEE%\x91H\x14\xbf\xdfO\u06f6\xb9\xad`\xfe+\x18\xa1p\x069\xed\xda\xd3P]I2\x16I\u9f85\x04MQ\xb0UW#-,\a\xbaE\x93~\xa1\x02W\xaa\xe8&L]\xac\xb7\x14\a\x98\xa5\xe5&B\xa5\x1b\xa1\x9a\x82D\x12\tG\u07aci\x9a\xb6s\xe7Nk\xf1\xe2%\xbd\x1fz\u807b\x80k.\xbf\xfcJ\xeb\xbb\xef\x16*G\x1c1\xcan\xccd\xb5\xf0Q]]\xad8\x89\x90\xf7G\x00\xfd] \u072f\x89\xf9\xbb\xef}\xc0\x1b\x1fNs9l\x95\x9f#g\xe8y\xac\xa4\xa7\xb7a\xf8\xf0\xc3\t\x87\xd3\xd9W\xd6|\xcf\xe3\xdf\xdeI\x99\u01afk\x9aJ \xe0\xdfo\x13\x83=\xc7q\xc7\x1d\v\xa8?[G\x9a\u007f\xf5\x94\xe2\x9d\x18\x02\x81\x00\xd9\xd9\u066d`\xfe+\x18\x19\xe9id\xe7d\x13\x8f4`\xc4b\xa9\xee\x13\xb6\xab\x8f\x16x\xa0\u04f4\xd0\xc7\x13i7\u2ba7\x1a7%\u0616t8\a[b[\xce\x03\v\xa7\xb24i\x13\x8f\xc7\xe9\xd4g\x04\x03\x86\x9f\x04\x12,\xd3H!8M\xdc'\x15U\x15\xbbv\xed\x92E\xc5;,\u007f UUU\xa5\xb4\xf7\n~\x9c\xa4\xa6\x82iY$\x92\x06\u0446:\"u\xb5$\xe31\x82\xe16t\x194\x82\xe3&\xdd\xcf\xf9\xff\xfb\x01\xe3\xee}\x96\xc1g\\F\xdb\u0783\x90\b\xea\xabj0\xa2\x11t\xe1PF\xaapZ\xe8y\ax[:\\x\xd2r\x94\x99q\x13\x92\x96$fB\xdcr^\xa6)%\x86\xed\xbeg\xd2\x01y\x84@SU\xfc\x9a\x82\xae:\xe5\xff4\xed\xbe\x97z\xfb\x9a`\x84\xa2`$\xe3$\xa3\x16\x83O\x19\xcf\xe9w\xfc\x89\xb4\xcc\x1c\x12\x89\x04\xa6i\x11\b\x04S\x9e\xfa\xae\xeaE\u0670a\x03\xeb\xd6\x15\\=m\u06a7\xe3\x01\xde}\xf7]\xf5W\x13\x99K)\xc9\xce\u0392\x00\x05\x05\x05=\u0768\xdc\xdc\xf3\xba}\x814\xba\xf4\x1dJy\xf1F\xea\xaav\xf1\xe4\x13\xffM\x87\xae\x87r\u0310nhD\u070d\xff_\xbf\x16\x80\xf1\xe3\xc7\xf1\xe1\x87\x1f\xf1\xed\xb7\v\u007f2\xf0y\u050b\xa3+u\"n\xa7\x11\xf0O\xe3\xf5{\xf5\xea\x95j\xc3\xd6R\xda\xc8y\x96\xb7~\xbf\x8f6m\u06b4\"eK^G\x0e$\x90\x95\x1e '3\x83u\x898f2\xe9\x02\x92K\r\x02\xaap|Yl\x84\xc3k\x8b\xa6 \u07ac\xa0\x11\xcbv\xc0\\\x91\xa0\x9a\xeeF\xe0VW\xdaB\xba\xa9T\x81\x11K\xe2\xcbl\u00e1c\u03e1h\xc32\xcavlD\xa2\xa7:\x86\xa6*)m\x89\xaaiB\xd3T\xd59\xd9:rB\xa7\x01\xb5H\x81\xa1\xed6\xc70\xe21\xa4\x94\x84\xdad\x91\x99\u05ddN\x83F\xd0k\u0329t\x188\x9c\xb4\xdc\x0e\xe8>\x05\u06c4d<\x86i\x99h\x02\x14UC\xb8{\x8d\a\u0216\x14\xa9\x86\x1b6{tW\xf2\xf6\x1c/\xf7@\xa3$S\xc1\x89\xb4}\x9a\x82\xae)(\n\xa8B\xa04\xba\xffz\xf9`\x8fU\x02!S\xf4\x8cpv(,\xcb\xc02T\x86\x9dy6\xb5\xbbJ\xf8\xec\u007f\xee!\x1a\x8d\xd0&\xb3\r\xd9\xd99TVVx\xa6_\xc24-\xb9j\xd5*\xb1d\u0272{\xa5\x94\x8b\x85\x10\x15R\u06a9\"\xa4\x16\x1d\x99\u007f\xfa\xe9\x14\xa5\xba\xba\u0192R\x86jjj\xfa\xef\u06b5\x1b!\x84\xb2g\x04\x98\u06f97\u01dcw7\xdd\x06\x8c\x06\xa0p\xd9<\x9e\xfe\xf3\xb3,^\x1f'\x12W\x11?\x13\xd9\xe2y^\x9fv\u0684\xbd\x1aR\xecI\x914}4MDy\x91\xb5cw\x9blf\u04b4\xbfq\xe1\x85\xe7\u04ed[\x0f\xa4<\xf8\x8e\x89\xceuJb\xb1\x98{\xc2\u041a\xa8lZ#\xf3\x96\x1c\x18\xa5\xf9u2BA\f\xd3\xc42\x12\x0e\x9f\x90j\v'Q\\5Fc\u0562\xdb\xfc9\u0144\b\xb7\u0273\xc0\xb4\x1d\xf0p\u0336\x04\xc2rM\xba\xa4\x9b\x10t\x1bA[\x96E<\x16!\xb3c>\x83\u01dc\x89\xae\xfb\x91\xaeX=\x15d\xb9\n)e\x8f\xc6\x16B\xa8(Bi\x8c\x82m\x9bd<\x8a\x11\x8f\x92\u06ed7\x87\x8c\xbb\x80\xa3o\xf9\x13g>\xf5>\xc7\xfd\xfeY\xba\x1e}\x06zN\x1e\r\t\x93\u02aa\x06j\xea\x1a\x88&-\x926\xc4m\x88\x9a\x92\xa8%\xa9KJ\"\x06DM\a\xd4\rK\x12\xb7\x9c\xa8\u0734\x1b#pO\xa9#\xf6\x00h[\x82\xa6\b\xd2|*A\u0761V\xbc\u04cc\xe2n\x8a\xba\x02~\x15|\xaa@\xf5z\xab\xcaF\xa32p\xe8\x18\x80D,\x81\xb4a\xf4\x05\x13\x19~\xfaE\x98\xa6IMM-\xa1p\x06\x99Y\xd9)\xdf\x1f!\x84\u0639\xb3\x8c\x82\x82\x82#\xdfyg\xf2a\xce\xfb\xa4\xfc:\"\xf3\xe5\xcbW*\x80=o\xde\xdc\x1e\xb1Xl\x90k;\xbb\x97\x8a%\xaf\xe7at\xedw4\u0246\x04E\x05\x8b\xa9\xad,a\xfe\x8c\xb7\xe8\xdas(\x81K/\xe0\x90Nq\xfc>\xf8W\xf3\xa1\x8e\xf9\x95\x8fK/\xbd\x94\xb9s\xbf\xe1\x8b/\xbe\xd8o\x04\xbf'\x00\xee\xcb\xe3\xfa\xa7P\x13\xf9\xf9\xf9L\x9cx\x15\xc0A\xf72W\x00MuZ\x8ey\x8bN\xd5tTM\a\x1c\x1d/\x12Z{\xf6\xb6H4O\xf1\u0376ma$\x13H\x17\xccE\x13\xe5\x8a\xf7\u007f\xa9\xb8\x06Y\xd2u\au\x13|R8`g\xb8\xe0+\\\x13-'d\x95\xa9\xed\xdcvs\xa9H\x81\x15Obj\x1a\xf9\x83\x8f\xa1\xeb\xcayl.\xf8\u07b1\xc8udx.\xed\xe0l\x14\x9ew\x8b\xf7\x90\xb6DZ\x166\xa0\xfb|t\x1c|$\x9d\x87\x1dC\x8fQ'\xd3a\xe0p\xec@\b\u06f4\x89\x18&v<\x8a\xb4\xadF{^\x9a\xf2\xd4\xce?V\x93\x90Cu\xbfg7\tElI\xea5y*\x1eM\b\xcc&\xbf\u03ef)\xa4\xfb\x14|\xeeRHu\xd6\x13\x12\v\xc7\xda\xc0k\xab\x8at*m=\x9e\xddF\xa04v\xe2\u00d3P\xc6\x1a\x12\x842\x82\x1c}\xe9Ml_\xb5\x84\x1d\x05+\xa8\xaa\xa9\xa1mN\x0e\xd1H\x84\x86\x86:\xc0Q\u022d\\\xb9\x8a\xbe}\xfb\x9c%\xa5\x9c#\x840\x17-Z\xc0\x91G\x8ei\u0651yeE\x85\x020o\u0782n\x96e\xf5\xb5\x9cb\x85f\t\x11\xdd\x1f\xa0]\xb7CAjt\xe9=\x8a!G_\x8a\xa6\xfb\x89\xd6\xedf\xda;\u007ff\u019c%\x945\x04\x11H\u051f\xe1\u055af\x82\x8e\x1d;q\xdbm\xb7\u042d[\xd7\x1f\x8d`\xf7\x17m\xef\xeb{\xfb\x03\xf5\a\x1f\xbc\x9f.]\xbac\xdb\xc6A\x8b\xca\x15G^\x8c)\x14j\x92\xb0`\xe9\x0fl\u073c\u074d\xccu\x84\x10\x18\x86\x81\x914S\xfe\xed\xad\xa3\x05R-B \x14\x05i\xdbX\xa6\xe7\x18\xe8\x16\xd2\xe0&\u294dg'%\x84\x82PDc\xbb;\xe1D\xe5\x86\xddX\\$\xbc\x877\xb7S2u\x99\xda\x04\xa4\r\xf1\xfa\b\xe1\u030e\f\x18y\n\x81`h\x9f\xa78\x8fJ\xf1|Ql\xdb\u00b6LT]\xa7\xeb\xe1c9\xe6\xd6\xff\xe6\xa4\xfb_\xe5\xc8I\x8f\xd2\xf6\xb0\xa3\x89K\x95XC\x84x4J\"\x9e aX$-\x97\xdep\x81\u0652\x8d\x11\xb7\xe5\tt\x9c\u032esZv\x9fc\x81K\xb9x\xd7@\ua512p\u007f^U\x04!\x9fJ\u062f\xa0\xb9t\x94\x94\"\x15\xad{\xf9\x84\x14\xf7\xeeF\xf86\x8d\a\x10\xd1d\xb3\xf3\"\u007f\xe7\xff\x92h}\x9c.\x87\x1c\u00a8\xf3~\x8bP5\xca\xcb\xcaPT\x95\xac\xac,TEK\x9dNjkk)))\xbdp\xf6\xec/\xdb\x01l\u06f6]\xb4x\x9a\xe5\x99g\x9f\xb3\x00\xca\xcav\xf6/\u06f5\xcba\u063c\x12iU\x03\x04\xd9y\xbd\xc9\xc9\xebC|\x91'\xe3\xfe\xfe\x05\xdd\x16\u0590\xab\xaf\xfec\xae\xb9\xe6s\xbf5\xc9=\u059d\xff&<=)\x96\xd1b\x1e[\xd8?\xf3\x99O\xf3w\u007f\xf7\xbf\xd1:\xa4T*\xbc&\xa3\xfcR\x80#\xa0\xab(xn\xc0\xe5\u0387\x9f\xe1k_\xfeg\xb6n\u0708\x9b\xab\x01\xa5\b4\x14\xfc\x900\xb4\xb8k\x18j\x82P\x13\x84!\xfad\x87\xfe\xbak\u03f56\b)m\x94\xdb\x18\x9e#5\xf4\x99\xae>VK.\x04\xa1\x11\x94C\x13\r\xc8\u0204(\x14X\\8^\xa2\xb1ml\x8c\x9b\xdb.^R\x1e-P\xd78\x89\x99\x8bW\x93\xc9\xe6\xd1:@D.\x82\"ZpZ\a\x94\x8b#\xd45\xb6p\xe6{?\xca\x1b?\xf3u\x16\xbd\xfd\xc34L\x9a\xce\xc8\xd0\x10##C\x16\u0089\xbeYhD\x02\x9d\xa4\xbb^\x13\xad\xdfT\x13\x9e\xa8s\u049d\xb1I?\xe2\r \xfa=\x88\xb2Ok3\x92\xa6\xbc$\xe7V\xfb\x99W\u03caT:}\x13\xd1\v\"\xe9\xf1I\xac\x12td\x8f\x9bl>1m\x10\xe1\u07e5B\x89\x96)\x93Xu\xe9{\xc9\xd55p\xac\xbb\x8b\xd1\u0451*\xe5[\x18\x06\x1c=z\x8cm\u06f6\xaf\x8c\xbf\xff\x81\x03{_\x9f\xc5\xdc\x18\u00e7>\xf1\t\x03\xf0w\x9f\xfe\u07e7\xbd|\xa4\xfb\xb2\x91\xe1\xca\b\xbd\x90\x12\xa4$W\xdf\xc8\u0139\u02e9ik'\b\x03\xb4\x0e\xf1J\xa3L\x99u*\xe7^\xf2\t\x9a\u06a6\x10\x06\x05\x9e\xb8\xef&\xbe\xf1\xb5\x1byd\xe7\b\xa3\xa1\x83#\x19\xb3\x8c\xff\xebW\xa9TB)\xc5\xff\xfc\x9f\x1f\xe7{\u07fb\x89\u014b\x17Uu\xe4\xe9\"\x1dc\x95\xe9\xa9Q\x1b\u079c!\x93\xc9\xe0\xbanR\xe0\xdb\xda\u06b8\xf1\u01af\xf2\x0f\xff\xf0\x8fH\u9f22.\x90\xff\x99b\xdeW\xd2E\xe3\xf4Ex\xe5\x12\xa3\x03}\xd6O\x1dY\xe9\x9c\xe3\xcd\xc4T\to*\x8a\x14D\x82g\xc7\x18\xb5I\xc9\x10\xc7v\xec&\xc5\x1b\x84\x91\xea\xa4!\xa7h\xcaI2R$|\x90H\x1a1\x128FF\x9b\x99\x92\x15,\x9eH\xd3c\"\xf9\xa7\x8eI\xe4D\xdeY\xed\x83\x1ek{\x02\x0f\x96\xbd\xf1\n\u67f3\x86r\xb1@oOo\xd5ty\x18\x86\x94J%\x8e\x1d;\xfe\x16cL-\xc0\u05293^\x9f\xc5<%\xe9k\xda\xf7r\u05e7\xb6\xed\u0611>'\"\xa4\x83\t\x02\x9a&Lg\xe2\xdceh\x13\xa0\x85u?\vB\x8fR\xa9\xc0\xac\xa5o\xe0\xd4\v\xff\x84\x9a\xbaf\xfc\xf2\x00\x8f\xde\xfe5n\xfa\xee-\xc2\xf4\xe9\xd3S]9d\xb3Y\x9a\x9a\x1aijj\xa2\xbe\xbe.\xc9\xf6\xcc\xe5r\x94\xcbeJ\xa5\x12\x9e\u7854\xe2\roX\xc3]w\xdd\xc9G>\xf2\xd1h\xc3(\xbcf\x8e{BX\xc2wg1\xc3\xd3[\xf7q\xff\xb7\xbe\xcc\u02db\x9f\xa6\xa1m\"\x8b/y?\x8d\x1d3-\xfc\xe3\xfb\x1c\x1f\x1a\xa5\x14D\x04X\xea\x11\x17\xf5\x93\xd7\xeb\xe3\x9e\xf2<\x9fR\xa9\x84\xe3\xba(\u05ed(G\xd2 \x8c\xf9\xcdx\xbb\x01J\x91\x17K\xacp\x11\xd1\u007f:\xe9ze\xa5\x80\xa5\xfd\xcbM\xe4}n\x04\xe5B\x89\x9a\x86\x89L\x9fw\x16\xd9\\\xad\xf5K1\x10\xfa>Fk\xe6\x9d\xfd\x06\xde\xf6\xa9\u007fa\xd6y\x97\xe0\x87\x9a\xc2@\x0f~\xb9\x80W\xf6\b\xcbeL\u08c3\xc0\x8e\xe9\xfb\x1e\xc6\xf70\x81\x1f=\x02\xc2 \xb0|@h\x1f\xc6Da\x1b:\xd2\xc2\xc7\xda\xf0\xdf\xc2+\xc4\x1d\xb7#\x05\rYI]F\xe0\xa4D7\xf1C&\x9dw\xf5C2\xb6#\x8f\xcf?qa\xaf\x04ZXX&\x9e4\x15\xc9\xe6\xe9{\x1e5-\xb5,\xb9\xe82\xeaZ\xda\x18\x1a\x1c\xc0\xf7\x03\\\xd7M\x92\x95FGG9x\xf0\xe0\x94M\x9b^<#~\xfe\xaf;5\xcb\xc3[\xf6\x8b\v\x16N3\x00\xff\xfa\x9d\xef]\xbde\xcb\xd67\rG\x86N\x90J\x06\x91\x92q\xd3\x17\xd1\u06b9\x800(\x81cU\"\"\x14\xf8\xbe\x87\x11\x92\xc5g\xbd\x87\xc2H\x1f\xcf=z3\u0151\xe3\xfc\xea\xe6/\xe3\xe6\xf2\x94>x\x15+&\xb8\x8cw}\xa4\xb0\xbb\xf0\xefz\x83\x94\xcbe\\\xd7e\xe1\xc2\xc5\xdcp\xc3\xf5\xbc\xfd\xed\x97r\xc7\x1dw\xb2a\xc3s\xec\u07bd\x87\xa1\xa1AFF\xc2\u0102\xd3J\x11\xad\xe6<\xf6[\x99?\u007f\x1e\xef~\xf7\xbb\xb8\xf2\xca\xf7\x90\xc9\xe41&xM;r\x00\x13\x84\f\x84.On;\xc0/\xbfs\x1d\a\x9e}\x84\x9a\xa6q\x9c\xf1\xa1O\u04be\xf4lv<\xf5\bB(|\u07e7o`\x18?4d\x18sl\u0546\x93H\xcb\xeb\u5494JE\x86\x87\x87\xc9\xe4\xf2H\xc7M\x06\x85\xa2\x066\x1a\x0eJK\x11\xa3\xc6\u0280\xa7\r^\x84K\x88\x04\xaf0\x952&Rmm\xbcE\xa4\x8c\xa9t\xd4\xf6*\t\x81\x1f0g\xe9E\x1c\xd8\xf1\x14{\xb7=\x89T\x0e\x99\\\r\v/x\x1bg\xbc\xe7\xcfh\x1c\xdf\xc1\xc0\xf0\b\x81\xd6\bc\xbd^\xb41\xd6* \xf4#\xff\x15\"\xf5L\xb4\xa5\b\xfbg\x1d\x85B\x04\xa4\xa2\xdd\xe2\u009a\xb4\u0572B\x06G?_<\xd9i\x8c\xc1U\x82\u01ac\xa4&##\xe3\xac4\x142\x16\x86\x8a\xbfG\xdco\x8b\xb1\x1fN\xe1\xf9\x95\xff9\xdeFu\xca\xda#\xde\n\x851\xf8e\x98s\xe6E\xb4\u03d8\u01de\r\xebl\u4723\x92\xc2S\xf6\xcatww\xf3\xd4SO/\x06\x1e|\xdd\x15\xf3\rG\x06Y9\xa9\xd1\x00\xf4\x1as\xee\a\xaf\xfc\xe0\xff\xdal\x13\xae\x13xEHE\xe8{\u050d\x1f\u03d4%\xe7\xe1d\xea\t\x87\aQ\nK\xb4hkG\xe9{%2\xd9ZN\xb9\xe0j\u02a5a6=\xf9\x13\x06{\x0e\xf2\x8bo}\x01\xad4\x85\xf7\xbf\x8f\xa5\xad\x19:\xb3\x1eY\x19a]\xbf\xe3\xf3\xb6\x1e\xe7v\xe7\xbc\xe0\x82\x8bY\xbdz5\x9b6mb\xe3\xc6M\xec\u0673\x87#G\xba\x18\x1c\x1c\x8cB\x9a\xb3\xb4\xb5\xb5\xd1\xd99\x85\x8e\x8e\x0ef\u0318\u03aaU\xab\x90\xd2\xc5\xfa`\x17-\xae\xf9\x1a\x16\xf20\b\xd02\xc3\u04fb^\xe6'_\xfb\x17\xb6\xfc\xf2\x87\u0535\x8c\xe3\xd4\x0f|\x92Yk\xdeE\xc1\vP5\r\xb8\xf9:\xfcr\x99\x91\xc1~\xeb\xe1Aug\x1e\xc7n\x9d\xbc^\x1f\xd4\xe7\xf0\xf0\b=\xbd\xbd\xe4\xeb\x9a\xc8ds\xb6\u0324\x8a\x95I\xad9\x19\xfd]G\x05\xa7\x14X\u065d\x13O2#\x11\xd1{l\x03'D<\u0493*\x9e&E\xbbF\xe3\xf0\xc6\xe0\x97\xcb\xd45Mf\xde)o\xa1\xeb\xe0V\x86\xfb\xba\x19?u>K\xdft%\xf9\xb6\xc9\f\x0f\x0e\xa0\x84 @F\x10\x8d\xd5\xc0\xa3\xed0\x91\x91\xca\x16\xed\u0529!\xf6d'5\xa1j\xf9\u0644\xf2M\xac\tb\x1e\xc0\xaau\xe2\xc2n\xfb\ua332\x1dy\x8d##7\x9aJ\x017T|\x1f\x05\x95\x13J\xfa\xa3\x95Bn\xaa\x9eK\xe5\xb3L\x15$\x14\xff9q\x1e\x8e\x88P\x11h\x9a&\x8cg\xea\x92S\xd9\xf7\xfc\x13\x14K%\xb2\xb9\xbc\xb5\xda\xd5Vd\x10\x84!\u01cf\x1f?\xfdu\u05d9\xef\xe9\x1fefsm\f\xaf\x9c\xfb\u037b\x1e\xfc\xf1\x86'\u058d\u04e1\x9f\x9cq\x84T\xc9\xca\x1b?\xfb\x14\xa6,:\x87\xb0XB\x87\x1aGY\xb3\x04-L\xf2\x92\x95K\xa3dk\x9a8m\xcdG\b\xfc2\x9b\x9f\xbe\x83\x81c\xfb\xf9\xc5\u05ef\xc1\u01e7p\xe5\x87\xe8k\xc91'W\xa45+\x12,\xeew\xc5\xf9-1j!\x93\xa5KW\xb0t\xe9\n\x00FF\x06\x19\x19\x19\x89\xc6r]\x1a\x1b\x1b\xc8\xe5*CGa\u8f6a\u0650\xff\xd1\x15\x04!\x197\u02c6]\x87\xf8\xfa\xf5\xd7\xf3\xdc=\xb7\x92\xcd\u05f0\xec=\x1fc\xe6EW\xe0\xf9!\u0294\xc856\xe3\xe6k)\x0e\xf7S\xec?NV\x1a\x1b\xfe\xabu\x82\xb1J%\xff\xdbD\xc8\xfd\xff]\xc6\xed\xd5;8\xcc\xf1\x9e~\x1a\xa7\xce%\x93\xaf\x89\x94 i( E\xeaI\u06f9\n$A\b~d0\"\x84\xed\x85e\xba+\xaf\xa0\xc8X%u\x1c\x9cV\t\x84H \x17\xec\x1a)\x97Kt\xce=\x8b\xa9s\u05f3\xfd\xf9\xfb\x18:~\x84\x83[^$\xdf1\x93\x92\xafq\xa4\xed\xae\x8d\x01\x95\x10\x93\xd2B$&LHY\x11\xdd{!V\xab\x9eH$\x11\xa9gd\x12\xfc<)\xbcFG\xa7\tk\u022e5()\u027b.9iU'\bQ\u054d'\xaf\x8d\x11U\xc4\xe5\xd8\x12\x9d*\xf7c\u0781\n\x8e.\x10U\x9b\x83\x89\xbe\xae\x10V\x11#\x02\x8d\xceH\xa6.YE\xbe\xbe\x89rq\x04'\x93\x8dN%!Zkc\xb4\x16CCC\xf3_W\xc5\u0718\x12k\x9e\xc9\xc6Eq\xfc\xbac\xfe\r\xb7\xdf\xf6\x83\t\xdd\a\xf7V\x93\x9e\x80\x0e\x03jZ\xc73\xef\r\xef%\xdf\u070e\xd7\xdfoM~\"\x12\"\x99B\x8e\xce\xfa\xa5\xe20\xf9\xfaq\x9c\xf1\xe6\xbf\"\fC\xb6m\xf89C\xc7\x0eq\xff\x8d\xff@qh\x90\v\xde\xf7aF&7\xb2\u0414\x98\x90\xd5\xd6\xdfY\xff~\xe4\xa8\x1d\xd7\x1fM2@\xf3\xf9<\xb5\xb5\xb5\xc9\xc0\x90%0*!\x15\xaf\x97\x82\xa7\xb5!\x93\u0272i\xdb.\xbe\xf4\xa5\xebx\xf4\xee;\xa9o\x19\xc7\xe2w\xfe\x053/~\x0f\x81\xd6\x04\xbe\x87P\x92l}+\x99\xda:F{\xbb\x18\xe9=\x8aB'\xa4T\x95N\xf9\xb7$'\x9d\xbc^E\x80%:\x1d\x1d:\xd6\xcf\xf0\xc80\x1d\xcd-dr\xf9\xc8\xe7;\x9ar\x8c\x8b\xad\x88\x8ap\u0535J\xa1\bBA \x05J\tT Q\x0e`4\"\xf0\xa3\xe2])H\xf1z\xb6\xfauRU\xb0\xe2\x96\x1e\x1a\xf0}\x8fL\xae\x81\x05\xa7_\u0391\x83\x1b\x19\xe8\xda\u03ce\xc7\xef\xa5}\xd1*r\xed\x93\x18-\x160\xd2>w\x19\r\xed\x84F\x83\x88\x02'\xa4B\xb9\x0eJ\xaa\b*1Ud\xa7-\u4552jL\x94\xc7\x19oB\xe9IS\xc0\bI\xc6U\xe4\\\x85\x92\xd2nV\xc6$Dp\f\xef\xc2\u0621\xb8\x13;\xed\xb1\x9dz\xa5\xc0\x9b\x04\xd3\x1a\x13\xa7Q\xe9\xe7\xa3\xc1+\xad\xed\xfd4n\xfa<\xf2\xf5\x8d\x14\x87\xfa\xad\x8b\xa2\x90\x84\b\x84T\xa2X*q\xe0\xc0\xc1\xe2\ub998\x1f\x19\x1a\u5fae\x8c|\xe04\xa1\x8d1\xe2%\xc3\xf5?\xf9\xe1\x0f\x97>t\xfb\x0f\x13\xcf{!\x95\xf5i\xd0\xf6X8\xed\u07372\xe1\xac5\x94J\xc2\xfe`\bth\xb1<\x19\xb9\x02\x89T\x01)\x95\x86\xc97\x8c\xe7\xccK\xfe\x1a'\x93e\xcbS\xb73\xdcs\x84\a\xbf\xf3E\x06{\xba\x19\xfd\xd3O\xe0\xcd\xef`\x8e\xf6\x99\x9a\xf3\xad\xe5\xe5\xefY\xd0\xd3E\xda\xf7\xfd\x13,q_OE\xdcz/;\xf8\x81\u6a67\x9f\u57fer\x1d\x0f?\xf0 \xcd\x13\xa7\xb0\xfc\u028f\xd1q\xe6\x9b\xd1BP.\x95PB`\xb4&\xd7\xd4F\xa6\xa6\x1e0\f\xf6\xf5R(\x14\xc8fs\x95\xee$\xf2\xa989\xe2\xff\xdaw\xe5J)\x86\xbc\x80\x03]\xc7\b|\x9f\xda\xc6\x16T&G\x10\x84)\x89\\\x05K0\xc9H\xbfD\v\x89'\x04\xc2u\x11J\xa2\x82\x10\x95q\x80\x00\x11D\xbai\x01&\x12L\xeb\x04\xfb\x15\t\rZY\xe7\x95\x13\x80\x1fj\xf0<\xc6MY\xc8\xf4E\u7c79\xff(G\xb7?\u03c1\rk\x99\u007f\xc9{-\x84a\f\xa1\x16\x84R \x94\x83\xe3f\x11\xcaE\x1bM\xe8{\x04\xa5\x12^\xe0\x11ze\x82\xe2\bAq\xd4\x12\xa0~\x19\xed\x951:@\x87\x9a0\b\x18\x1b\x9cb\xa2\rF)\a\x95\xc9\xe2\xd4\xd6S\xdf\u0502jmA\xd7\u0510\xc9\xe5psy\x9cl\xce\x16\xd70\xc0\u8832Y\xa5\x02\x9f\xd3K\xbc\xba\xdb6\x15\xc8)!\x98+\xffF\x15\x1cS\xbd!\xc6\xde0u\ud4e8il\xa6\xf7\xf0>\xb4\xd6(\xa9\x92S\x8e\xe7\a\f\f\x0e\x8a\xd7M1\u007f\xf28\xe2\x1d3\xa56\xc1\u05dc\x8d%n\xb9\xef\xd7O\xbe\xe7\u07ef\xfb\x02\xc4QSR&]\xb91\x9a\u018eY\xcc~\xcb\x1f!\x9b\x1b(\xf4\x0f\xa2\xea2\xa8Q{,\x11\x84 t\x12\x1b\x15\xbfa\x00\xe5\xf2(\xb5M\x139\xe3\xd2O\x92ije\xe3#\xb7P\x18\xe8a\xfd\x0f\xbf\u03b1\xfd{\xe8\xfb\xcb\xcf1\xb0r%\xbdy\x98\x93/\u04d4\x93\x04z\xec\xfe\xfa\xfb\x17\xf6\xd7\xd5\x15u\x01n&\xcb\xe8h\x81\xbb\xef\xfe%\xff\xf7\x86\x1by\xe1\u0157\u8637\x843\xde\xffW\xb4/_\xcdh\xa9L\xe0\x95\x93\x13\x8f\u059a\x9a\xd6vj\x1a\x9a\x018\xde\xd3C\u05d1nf\u035a\x811\x12\xc7Qd\\'\xf2\x948YP_\xebj.\xa4\xa2o`\x80\x03{\xf7`\xb4\xa6\xb1}\x12nM=\x85b1\x9a\xb4\xa4\xe2\xfd\x1f\xfb\xa4 \"\xfbWM9\x10\x11\x84\x11!\xe2R!\x1d\x89p\x01\xcfD\u49b4\xddx\nX\xf9M+>\u0351\x06\x81G\xb6\xae\x819+\xde\xcc\xcb;\x9f\xe5\xf8\xa1m\xec]w/\x13\x16\x9dJ\xe3\x94\xe9\x84a\x80v\xf3\xb6\x93/\x15\xf0\a\xfb(\r\xf53r\xfc0\x83\x87\xf70\xdau\x90B\xcf\x11\xcaC\xfd\x04^\x89\xd0\xf7\xac\xef\x8b\x0e\xaa\xa6[#l&u?Vj\x83\x88\x88P\xe1\xb88\xd9<\xf9\xfaF\x1a\xc6M\xa0\xa5c:\xadSg3n\xfa|\xea\xdb'\x90ol!_\u05c0\t\x03|\xaf\fJ\"\x1d\x17\x19\x9f\f\xc6\xf4\xdfT\x9dE*8\x8d\x10\xa2\xaa\xa6$\xf8z\xa2\x8d\xafl\x05Z\x83\x93\xaf\xa1\xa6\xb95B%Bdd\xa7!\x84\xf5\x8b\x17B4\x19c:\x84\x10\x87_\xd3b~\u02ce\x11\U0004e675\x06`\xb3\xf7\x17\xff\xf8\u0736\xc3W\xde\xfc\x95\xcf\xd3\u007fx\x9fA\b)b\x9c<\xfa\x81\xa5\x94L;\xf72Zf/\xc5/\x87h)\xd0\rY\x8c\x12\xa8\x11\x1f\xe1\x03\xa1\xed\b\x8d\xd4\x15\x1aY\xc4\u064d\x05\u071a&V\xbc\xf5\xa3\xe4Z\xdby\xe9\x17\xdfb\xa0{?;\xd6\xfe\x82\xa1\xe3/s\xf4C\u007f\xcd\xe9o\xbe\x9c\xd1\xf6Z\xe6\x86\x05&\xe4\xad\xd7q\xf0\xdfP]g\x8cA)\x85\xeb\xe68t\xf8\x10\xb7\xfc\xe0\x87|\xf3\xdb\xff\u0191\xaen\xe6\x9c~>g\xbc\xf7c\xb4\xcf[\xc1\xf0h\x01\x1d\xf8\xa9\xde\xc1\xfe\x9aoh\xa2\xb6\xb5\xddb\xb1\xbd\xbd\x1c>|\x98\x85\v\u7864$\x93\xb1\x99\x86\xe2d_\xfez\xe9\xcd\x19\xea\xef\xe3\xe0\xee]\xb8n\x96\xfa\xb6v\xa4\x9b%\x18\x19E\vI\xd97\x14\xfd\x10)\x05\x19G\xa2\x94\x81\xc0\xe0\xa1)\x04\x10b\x13\xe5\x851\xc8x\xbc\x11cG\xcc\x1d\xd7f|\x1a\x1dy\xa3\xc70\x86I\x8a\u007f|*\x8d\x15(\xb1\x02\xc4\x18\b\xca%\x9a\xdbg2k\xe9\xc5\f\x1c;\xc0\xb1]\x1b9\xf2\xecZ:f\xcdg\xa80L\xcf\u07ad\f\x1c9\xc0\xe0\xa1]\xf4\xef\xdf\xce\xd0\xe1=\x94\x86\xfa\b\xcb\x05\x82r\t\xed\x97O \x19S~\x1fv[\x12\x95M\xaa\xfa\x95\x89\xe0 \x1dF\xb8\xba\xfd\x8c.\xa1P\x99\x1cN&\x1b\u017e\xcdb\xf2\xc2S\x98\xbc\xf0\x14\xc6\xcfZ@\xe3\xf8\xc9\xd6\u07e6P\xb0A\u03ae\x83P\u059a7\u0749\x8b\xb1P\xcc\tR\xd0\x18\u007f7i\xda8\xf9\fk\xaf\xebP\xd3\xd8\x12y\xcfW\xc3\x05e\xcf#\x9f\u02f5\x06~i\t\xf0\xda\x14\U000d738d0\xec#\u039e\\g\x00^\x1a6\u007f\xbd\xad\xab\xf8\xa9[\xbez\x1d;\xd6\xfd\xda\xc4o\x03\x91#\x98\x10\x02\x1d\xf84\xcfX\u0234\x8b\xae@\xe5k\xf1\v\xc3\b#0J\xe1\xd7f\xd0\x02\x9c\x11\x10:\xb4\x93V\x91-g\xa5\x15\x10\x18!(\xfb\x05d6\u01e2\v?Dm\xcb$\x9e\xff\xf9W9\xb6\xfbE\xba\xb6=\xcf\u03ff\xf4I\x8el{\x91s\xdes5\xbd\v\xe617\xf4\x99]\x13P\xebZ\xd8E\xff7\xaaL\xb9\\\r\xc6h\x1eyl-\xdf\xfc\u6df9\xff\xbe\xfb\xf0\x85\u00eaK\xdf\xcf\xf2\xb7\xff\x11\u0353gP*\x8cb\xc2\xd0\x12P\u046b\xa8\x845br\x1c\x87\x96\xc9S\xc9\xd5\xd4s\xb4\xbb\x9b\xbd\xfb\xf6R_WK\xb1XD)\x99`\u007f'\xaf\xd7\xfe\xf4\x050\xd8\xd7\xc3\xc1\xdd;i\x1e\xd7NC\xebx\xcaAH)\u0414BC9\x88\x92\x854\x94\xb5\u5374\f\xf0\x8dU\xb0\b'\x9a\x88\t+\x86[\xf1\x9b+\xa5\x8bQ!\xda\xe8$9\xc8\xf2U\"\"\x11+\u05b8q!O\xab@\x02\xcf#WS\xcb\xf4\x85\xab9\xb0u\x1d]\xfb^b\xff\xd3\x0fP\xd7\xd0H\xcf\xf1\xc3\xec\xdb\xf0(#\xdd\a\t\xfd2&\f\xac\x1f\xba68\xb9\x1c5m\x13\xc97\xb7\x93kh\u00adm\xc0\xc9\xd5\"39\xa4\x93A(\x85r3\xb6\x19\x14$]x\x02\x99':p\x8d\t<\xfc\xd1aJC\xfdx\xc3}x\x83\xbd\f\x1f{\x99\xe2`?\xa5\xe1~\x06\x8f\x1cd\xff\xb3k\xc954\u0471x\x15\xb3\xcfZ\xc3\xf4U\xe7\xd2\xda9\x9b\xc0+\x12\x94KH\xa9\x10\x8e\x83t\x1c\xdb\u96f8\xf5\x11\x95\x01\xac1\xc7\xfcx\x8f\xd1\x11dc\f)\x8d\x8e\xfdM*E\xae\xa1\xd9\xdaf\xe8\x94\a<\x10\x86\x1a)e\xaeX*\xb6\xbc&0\u02c6\xae\x11\x06=\u0139\x1d\xb6\x90\xef\xf3\u037b6\xf5\xf0\xa5{~\xfa#\x1e\xfd\xc1\x8dQ\xed\xb6lf\x85L1H7\u00cc\x8b\xdfc\xbb\xf2\xe2h\nB\xb1\xdd{X\x13\rA\b\x0f\x8cF\x9a\xc8\xf6&u|\xb4\x83jV\x1a%1\xccX\xf5f\x1a'Na\xe3\xbd\xdfb\xe7\u06bb\x19\xed\xeb\xe6\xf1\x1f\xdc\xc0\xc1-\x1b8\xe3]\u007fF\xd7Eof\xb8\xb3\x89Y\u01a7\xcd\r\xc8\bC`\u018c=\xff\u007ft))q\xdc\f 9t\xf8\x10\xff\xfe\xc3\x1fs\xcb\x0f~\u020e\x1d\xdb\x197y:g\xbf\xe9C\u033b\xe0r\u0716F\xfc\xe20FWf\xd6\u048bPk\x8d\xc20\xaes\x165u\r\xf4\x1d{\x99\x9d\xbbw\x01\xe0\xba\xcek\x1e\xa0q\xf2\xaa\xc0{\x18\xf0\x03\x8fC\a\x0e\xd0\xdf{\x8c\x19\x8bW\xd0\xd0:\x8e\xc1\xd12\u00de\xcd\xca4Q\xa1\xd3X\x13-\xdf\x18L\x18\u0372K\xa7\"\xdf3\x06\x19\x8e\t\x95\x90\x02\xa5\\\v\x8b\x1aM\xa8u\x05h0Q\x11OKB\xc4\x18Y\x9e\x81Rq\x94\xe6q\u04d8\xb5\xf4\"z\xbbw\xd3wd7\xeb~p-~\xb9\x801\x1a\xe1\xb8dj\x1b\u0237\xb4S7\xbe\x93\xda\tS\xa8\x9f4\x9d|\xebD\xf2\xcd\xe3\xc8\xd67\xe2\xe6\xebPY\xab\x9f\x17\xcaI\b\\De\x9c^P\x19\x15M\x80\x11a\xe1\xa1\xd0+\u23ce\xe0\x8f\xf4#\v}\x04}\xdd\xf4\x1f9H\xcf\xdem\x1c\u0779\x91\xc1\xae\x83\x14\xfa\x8e\xb3\xfd\x91{\xd8\xfb\u0323t,Y\u0172\xb7\\\xc5\xfc\xf3\u0782[S\x87_*$Cs\xcaq#hX\x9c@pV\xce\x04\xd5\x1fM \xb1\xb1p\xba\x14\xb8\xb9\x9a\x14\xa9\\)\xf4\xae\xe3\xe0y\xde`}}\u04de\u05e4\x987d`e\xab-\xe4]\xa5\xf0\x8am\xa3|\xef\xf1\xc7\u05b9w\xff\xeb\xe7\xed@\x80\xdd\xee+\x18\xb3\x90h\xbfD\xc7i\x173\xe3\xe2w[\x02\xa4\\Np\xf4\xcaiE\x12\xe4\x15h\a\xe9Ysb\x13\x92\x1c\xe9*>\x956\xa7P\a\x1e\xda\xd3LY\xb8\x8c\xf1\xb3\xff\x0f\xe3f\xce\xe6\u017b\xbe\xcf\xe0\xd1\xc3\xec}\xf61\x8e\xef\xdd\xc1\x8e\xf5\xbf\xe6\u0eeef\xe5\x19g2\xbb)\u03f4|H\xb3\xf4QBW\x19\xe9\xbc\xde\x0f\u064e\xa3\x90\u02aa\x85F\xcbe\xee\xbc\xeb\x1en\xb9\xf9\x16\x1e_\xfb\x18A\xa0\x99\xbb\xec|\x96_\xf8>\xa6.9\x9b\xc0\u04d4\xba\a\x10\xf5\n2\xc2\x06\x16D\xb7g\xec\xe6\xe1\n;X\xd1:u6nM\x1d\x00\xbbv\xed\xe6\xe0\xe1\x97\xe9\xec\x98L\x10\x04'%\x89\xaf\x13(MH\xc5\xf0\xf0\b\x9b6m\xa1T,2\xb5\xb3\x93\xd6q\xed\xec\x18\xf1\b\u3390\x8a_\xb9L\x95\x1d\x13%V\xc4\xf7\x9a\x88\x9d\x12\x13a]T\x18\xa5\x83t2h\x1d\"D\\pL\xc5L\xcaD\xb2A\xf1\x1f\xc5,\n\xa6\xcd=\x8b\xfd[\x1f\xe7\xf0\x9egq\x9c,H\x89R.n\xae\x96|\xdb\x04&\xad\xbc\x80i\u7f55|\xdbdT&\x17\xf17!h\x8d1\xf6w\x1d\x04\x10\xf8Ie\xb4\xcf\xddDj\x96\x8az%\r\xbb\xe80@\x87>N6\x87\x93\xef\xa0&;\x9d\xa6\xba\x1c\"\xf0\x18\xed=\xc6p\xf7A\x8e\xed\xde\u010e\xb5\xf7\xf3\xf2\x96\r\xf8\xc5\x02\xbb\x9f|\x90\xae-/px\u04f3\x9c\xfd\xa1\xbf\xa6q\xfcd\xca\xc5QL`'beR\xd0S$\xa8H\x17\xf6\xdf\"e4&\r\xb1c\x8c@erV>\x99\xf8\x1d\xd9G.\x9bedd\xa4K\b\xf9\xe4kR\xcc7\xf6\xc7<\x9an}|X\\\xf3\xe2\xf6\xae\x9a\x9f|\xe5\xd3f\xb0\xeb\xa0H\b\xcf\x18^\x91\n\ud5e9i\x9b\xc8\xdc\xcb\xfe\x94\x86)\xb3\xf1F\x86*\x8b\v\xa2\u022b\x10\x11\x86\xa8\xb2\xc6)\x9b(%E\x82\xd4cH\x97hzMG\xde\xceyA\xc00\xb5-M\x9c\xf1\u078f2i\xdeR6\xfc\xf4\xbb\x1cxa=\u00fd\xddl\xb8\xeb\xfb\x1c\xde\xfc\x1c/\x9e\xffVN\u007f\u06fbY\xbah\x01\xb3\x9asL\xad14\xcb2\xae\xd1\x15\u00de\xd7\u064d,\x85\u0779\x91\x19\x00\xfa\x8ae\x1eY\xf7\x14?\xbe\xf5V\x1e\xb8\xf7\x97\f\x1c;\u02b8\x8eY,>\xedm\xcc]y\t\xf5\xad\x1d\x94\a\x8b\x04\x04\xe0(\x8co\x90\xf5\n\x99\x17d\x1cA\x10V\x16\\F\x1a\x1c)h\x9c4\x95\xfa\xf1\x939\xba\u007f\a[\xb7\xed\xe0\x85M[\xe8\xec\x98\xf2\x9fr\x84L\xae\xa1\x95\x902\xa1\x86\xb2\x16d5\xc8\xc0\xa7\x9ez\xf6yv\xbc|\x94\xb9\x93[)\x16K'@a'\xafW\xef\xd2\xda\xde\xf8\xe5\xb2\u01c6\r\xcf\xd1\xd7\xdb\u00fc\xe5\xe7\x90k\x9b\xc9\xc0P\x11\xe9\x1b\x84\xaf\xed@\x91\x12h\u01e0\x95\xc48\x12\xed`\x8b\xbcR\x18e\x87td\xa8\x11\xa1\xa9\xaaGBT\xf5\x93H\xa5\x90\xcaA\x87~\x95\x83.\txc\xaa\xb0|\x91\x82b\x84\x10\x94\xca%\x9a[;\x98\xbf\xe4|\xba\x0fo\xa30:\x80\xebf\xad\u076eT\x88l\x1eod\x90\xcdw|\x03\xaf8BC\xe7lr\r-d\x1b[\xc85\xb7\x93o\x19\xcf\xc0\xfem\xbcp\xf3?s|\xeb3\x04\xc5\x02\xa1WD(\a\xe5f-1*\x15\xd2u\"\vm\x89p\x9ch\x94\xbf\U00084170A\u03a5\x00\x1c\x19\xf9\x97\x87\x01\xc5\xe1\x01\xb25u,Z\xf3\x0e\x8a\x83\xfd\xdc\xfb\u5ff1N\xad\xe5\x02\xc7\xf6lG\x87aEzhl\xf1\x8d\xcd\xc8\xcc\x18\xe2uL4M\x85R\x88a\xa9\xb8\xe9\u0506\xd0+\xd9F+Eh\x1b\x03\xb9l\x96\xce\xce)\xaf\xfe\xd0\xd0\u06a3H \xdc\xdd3t\xf1^\xdc\xcf>\xb9\xfe\t~\xfd\xad/j\xc2 \x19\f\xaa\"\xd9B\x9f\xda\xf6\xc9\u033f\xfc\u007f\xd04m\x16\xe5\u0442\r\x8a\rBD9@\x15m7.\xfd\x10\xa1+\x13\x9fF\b\x84\x0e\xab(\x86\xc4`G\xa4\xce5\x1a(\x1b\x18\t!\u0087\xb5\x0e(\x17\x86Q\x8eK\xdb\xf4y\\\xf0\xe1\xcf0\xf3\xb4\xd5l}\xf8n\xf6nXG\xcf\xfe\x9d\f\x1c\xde\xc3\xf3G\x0e\xb2\xf9\xc1\xbbX\xbf\xec4\x16\x9cq>KV\xac`\xd5\xc2Y,\x99>\x89\xf1\xb5\x0e9\f\x84\x1e^`1\xae?dQ\x8fG\f\x1c)q\\\x17p\xf1\x81\x97{\xca\xec=\xb0\x8b\xed{w\xf3\u0533O\xf3\xe8\xaf\xee\xe5\xc0\xf6\xcd\xe0\x15q\xb2uL[t6\xb3\x96^\xc4\xcc%khh\x99B\xe0y\x94FG\"WCSE\n\x99h\xc4Y`\x03{\u0168&+C\x8c\x92hW\xe2FR,#a\u072c\xf9\xb4u\xce\xe4\xe0\xa6>^\xda\xf04O<\xbf\x89\xb9\x93/\xaa\x1a\xda:y\xbd\xfaW\x10h\x10\x92\xe1\xe1\x11\x9e|\xf2I\xbc \xa4u\xda|L];\xe5\xbe\x11{\u007f\xe8JR\x90\f\r\x9a\x10\u0436\xa0g#_\x11\t\xc65Hm!\x96\x98\xb4\x94P\x05\x1f\xc4\xe8\xafT\n\xa1\x1c\x8452O\xec]\u01de\x8eI\xe3\xc7\xd1}\xa9\x81\x92\xe73w\xf1jvo~\x94-\x1b\x1fAJ\xc7\u00ae\x91L\xd9\xc9\xd7Q\xe8\xed\xe6\xa5\u007f\xff\x17T&\x87[[O\u0744\xa9\xb4\xccZ\u0338\x05\xabpj\xeai\x984\xcdz\xc0\x14G\b=\x8f\\S+\xf9\x96v2\xf5\u0378\xf9:\xb2\xf5\x8dd\xeb\x9bps\xb5H\xd7%\xd74\x0e\xb7\xa6\x81 \xf0*\u0773\xb6\xb9\xa09mpb\xbc\x1d\xf0\n#H\xc7e\xd1\x1b\xae`\xcf\xd3\x0f\xb3\xf9\xc1;q\x9c,M\x93:\x93\x0e\\V\xba\xad\x13\t\xe04\xb7i8\x11z\x12U\xb80ZkJ\xa3\u00f6sO\rve\\'\xfe&\x8f\xbf\xaa\xc5\xfc\xf9\xeeQ\xb1bBmh\xf6\xfc:\xf7L\xa6\xfeo\xb6o=\\{\xd7\xf5\x9fg\xf0\xc8~\x19\x9b\u0724\v\x9e\t\x03\x84\x90\u0338\xe0\n\xa6\x9e\xfb6\x02/\xb4\x129O\xa3\n>\xaa\xe0#\xcba\xc5\xc1-R]\xd8\x01\x01\x8d\bmjI\x1c\x95m\xa4\xc2\b\xab-\xb4\x8bP\xe0(\x81\x02L\u0672\xf6\xa2\xc1\xb1\xba;\xac\x1dg)\xf0Q\x8e\xc3\xd4\x15g\u04f1p\x15\x87\xb7l`\xd7S\x0f\xb3\xf7\u0675\x1c\u06f3\x15o\xb8\x9f\xed\x8f\xff\x8a\x1dO<\xc8#\x13;\x99\xbap9s\x17-b\xf9\xc2\xf9\x9c\xbal!\x8b\xe6\xcc`\\mM\xbaW\xc2\x18\x9d\x04V\xc4\xef\xcao\xaby\xa2*\xd8VDV\xb8\x95\x93K\x00\xec9\xd6\xc7\xc6-;xi\xe3v6m\xda\xc2\xd6M/\xb0o\xfbF\xcaC=\x00\xd46\x8dc\xf2\xf2\xf3\x99\xb6\xe8\\\xa6\xcc?\x8b\xa6\xc6NB?\xa0T\x18\u0184a\x92rb\x17j\xd4%%\xfffC\x1c\x05\xa0B\x83S2\x04\xa3\x86 \xa3Py\x97\xacR\xe8 \xd7\xd4\u01b4SWsp\u04f3\x8c\x1c?\xc2\u06a7\x9e\xe1mo\xbc\x88&G&\xb9\x89'\xafW\xbf+\x0ft\x88\xa3$;\xb6\xef`\xeb\x96-\u0535L\xa0}\xfeJF\xb5\xb5]\xad8\x01\xc6)C\"I\x90\x17\x81FZ'\x14\xf0\x02BW 4\u0220\xd26\xc6E\xca6O\x95\x82%\xa4c\xbd\u024d\u0104\xe6\x841\xf6\xb4\x8a\u00cc\xd5u\x18C\xc9\xf7h\xa9og\xc1\xd2\v\u0637k\x03\xc5r\x81L&\x97nJQN&\xc1\xbc\x83r\x81BO7G7=\xc9\xee_\xddJ\xcb\uc974/\\\xc5\xcc7\\I\xf3\xccEH7\x83r\xb3\x89\"\u013a\x12Z\x88VD>\xe3a\x10\x10\xf8^\x15!\x89\x90\x84\xdaP\f\f\x8e2\xb8\x91\xef\xad\x04\xbc\xd1!\x9c\\\r\xe7^\xfd)\x1a'vR\xd3\xd8\u00ac3.\"\xf4\xbcd\xe8'\x9em\x91\xe6D}y\xfc\x9a\xc4\x19\xaa\xb1\x90\u008c\x11\xbfHi\xdf\u02d1\x9e\xee\b\x86\x16),]RSS\u00e2EK^~\u054a\xf9\x86\xee\x11VL\xb0\x83A[&\\\xfc\x8e\xfdG\xcbk\xee\xfe\xb7\x1b\xd8\xf3\xe4\x03Q\xb1\x92U\t\xd3\xf1.>~\xc9\xe9\u033f\xe2\u00e8l\x8e``\x98l)D\x16}d)\x88r\x99t\xb2\x83\xc5\xc7\x11\x11\u0623`\x92I\xa8e\x1c\xe4Wy%\xc3Hq%\r2\x8e!)i\x8c\f\x10\xf5N\xb2\xad\x1ac5\xb0\xa1\uf8e4b\xda)g\u04f1\xe4T\x16\\\xf06\x0eo|\x9a}\u03ed\xe3\xe0KOS\x1a\x1ed\xe0\xf0>\xfa\x0f\xef\xe6\xc5_\xdd\xce=\xad\x13\x98:k\x1esf\xcfd\xe1\x9c\x19,\x9e;\x93\xe9\u04e60i\xe2\x04\u018dk\xaf2\xd8\xfa\xcf^~\xe8\xd1\xd5}\x8c\xae\xa3\xc7y\xb9\xab\x8b]{\xf6\xb1}\xd7\x1ev\xef\xdd\xcf\xce\xed\xdb\xe8\u06b7\x1b\x82\xb2]\xe8\xcae\u0714\xb9L]v\x1e\x93\xe6\x9e\u0284)K\xa8k\x9c\x84\xf6|\xca\xc5\x02\x84:\xc9f\xac\xe0Yc\b\x9a\u06379\x9a\xed\x16Q\xfa\xba\xe3\t(J\u00bc\xc4S\x90-\x97\xa9\xa9\xabc\xfa\xa9\xaby\xfaG\u07e4<:\u0313\x8f<\xc8\xf3W^\xc5\u014b\xa6a\xbc\xc2\xefl\\v\xf2\xfa\xdd/?\x88B\x8d\xb5\u6847\x1f\xa6\xeb\xc8\x11&/?\x97\xe6\xd9K)\x95<\b-\xf6-\f\x89\xef82vB\x8c\xd1Z\x89\x8a\xf8\x13U\xb2\u0713\x8cn9\x13y \xe98\x861n\xaa\"\x0f\x13\xa52\x18\x13F\xa4\xa3\x8eh\u0394@\xbd\u2ddb@1q\xeeg\xa85\x05\xcfg\xfa\x82s\x98\xdcy\x0f;\xb7?m\vo\x94\x04\x11\xdb\xef\x1a\xa5\x10FYO\u01e8\u0287^\x89\xee\x97\xd6\u047b\xebE\xba^Z\xcf\xf8%g\u04b1\xeaB\xc6\xcd_\x89r3\x98\xa0\f~\x19\xc2 \xf1^\x89\xa3\xe5D\xe4\xefbR)E\x00\xe5\xd0\xe0\x866\xffS\x1a\x83\x89\x14*~\xb9H\xeb\xd4Y\x9c\xff\xe1\xbfKN\r\xa1\xefY\u062a*\x9c\xe27\x9d\xabM\u22de\xda\xe7*\xc0DdC,$\x04^\x89\x81\xeeC\x89 \u013e\x01\x9a\\\xae\x86q\xe3\u0195O9e\xf9\xab\u04d9\x1f\x19\x1c\xe1\xd1cQ\xd3\uc3f6=Q\xe0\x8bk\ufedb\xb5\xb7}+*\x1a\u056ezB\b\xc2\xc0\xa7v\xdcD\x96\xbc\xfb\xafh\x9d4\x8f\xf0\xd80\xd9Q\x0f\x15\x00\x81\x8e<\xb2M%4V\u0605)=[\xc8\x11\xa6\xc2\x06\x1bK\xc4\bm\xc7d\x8d\xb4/\xa4\xd4 C\x99\xec\x84B\x02%\x03\x8e\x86\x1aY\x95\xb8\r\x10\xe8\x90`h\x10\xa9$\x93\xe6-e\xe2\x9c\xc5\xcc=\xf7\xcdt\xef\xdc\xc4\xe1\xcd\x1b8\xb8\xf1i\xfa\x0e\xed\xc3\x1b\x1d\xa1\xd8{\x8cm\xbd]l{\xfa\x11~\x8e\xa0\xb9m\x1c\xe3\u01f5\xd1\xda\xd2D[[\x1b\xadmm475\xd1\xda\xdaB}}=\xd9\\\x0e\xd7\xcdD\x836v\xc4\u0646\b\x94\xe9\xeb\x1f\xe0\xe8\xb1\xe3\x1c;~\x9c\xe3=\xbd\xf4\xf5\xf7\xd3\xd7\xdb\xc7\xf1\xa3]h\xbf\x92\t\x9a\xcd\xd5R\xd36\x81q\xd3\x17\xd11\xff,\xc6O]B\xcbf\xa3\xc1\x82\x00\x00 \x00IDAT\xa4\x99d\xf2\x8d\xe8\xd1\x12\xa5\xc1A\x9b\xcen\u0184\x0f\x881\x06\x9ecL\xf8e\xf4\x9e\x18$Z+T\xe8\x90)I\xfc>\x8d_+p\xb3\x06\x9c\x80\t\xb3\x171u\xd9\xe9\xec\\\xff\x00;\x9f{\x8aG\x9e\xda\xc0\xf2\xf9\xd3hS\x12\x1d\xe8\x93\xc3C\xafvW\x1e\x84(\xc7\xe1\xc0\xfe\x03<\xb1~=\x81PLYt\x06\x8e\xd3@a\xb8\x80\x0el\xc7h\vz\xa5\xa0\x1at\xe4\xa9#PH\xa4\x0fF\x9a\x8a\xe2BG2;i\xd0J`\x14\x84R \x8d@\x06\xd1\xf4\xa7\x14\b\xe1 \x8dk!\xbctdb<\xb6n*^\xe3\xe9\x8f\u0152A/\b\xc8\u05f6\xb1h\u0645\x1c\u073f\t\xdf\xf7q3\u0654\xe5m\xf5\xf0LlK\x81\x90(7\x8b\x0e\x02z\xb6=G\xcf\xf6\xe79\xb8\xf6n&,9\x93)g\xbc\x81\xc9\xcb\xce\"_\u05c8\x0e}\xc2R\x11\x13\x06\xf60.L\x14\xe5f\xed~U\xd4\xc8H \xc4P\xf45\xae\x14d\x85\x8c\x8c\xe4l\xf3\xe9\xfb\x1e*\u04b2\x1bm3\v\xd2F\x06R\x8a\u02ae0F\xfd\x93D\xdcE\xbfK\xaa\x05\x8b\xb1%\xc9\xf0\xf1.\x86\x8e\x1dI5\xbe\xf6g\xad\xa9\xc9\xd3\xd1\xd1\xf1Rg\xe7\xf4\x97\x00v\xed\xda\xf1\xca\x16\xf3m\x83\x88\xabf[M\xf9N\xa7\xe6\xcf7<\xb7\xb9\xe3\xe7\xdf\xf82\xde\xc8P\xc5C8\xfd\x86\xea\x10\xe5\xb8,^\xf3G\xccZ\xb4\x06ul\x14Y('\fzl\xfc\x9b(-\x05\x88\xd0 }\x1d\r3\xa4X\xe3d\x81\x88\xca\xc8l\xec\x02d\"\xf1\x94\xa8\u021a\x84\x06S\b\x11\n\xc8\xc9\xea\xe2\x86\u0571k\xad)\x0e\r\x80\x10\u0536\xb63\xe7\xac7\u0439\xfc\f\x96\r\xbe\x97\xfe\xc3\xfb9\xb2\xfdE\xbavl\xa2g\xff.J\xc3\xfdx\x85\x11\xfa{\x8e\xd1\xdfs\xec\x84\xd7F\np3\x19\x1c\u01f58c\x14{d\xb4&\fmZJ\xf9\xb7\x848g\xf3ud\x9b\u06e8in\xa7m\xd6b\xc6\xcdXF\xfb\xe4\xf9\xd47M\"\x9fkB\xe1\xe0\x97\n\x94z{\x11Z$\x1d\x80\xd1&\x05\xab\x90\u023a\xaa\xe2\x1e\x93p]S!\x92\xa5\x02\xe1 \xb4\x83(\x83\xf2B\xf0\fA\x9d\xa4\xe4\r\xd3\xd8:\x89\xb9\u7f45\x9d\xeb\x1f\xc0xE\x1e\xfe\xe5=\x9c\u007f\xe1\xc5\\<\xbd\x11',\xe0\x9f\xac\xe6\xaf\xf8%\x84\xf5W\xf1\xfd\x900\f\xc9fs<\xf2\u0223l\u077a\x95\xd6\tS\xe9\x98}\x06z$\x80r`\x15\xbb&\x1d*n\u05de\x8c\xd15%\x90Q\x97NhR\x1dqtOi\x8b\xf7j!\b]\x81\xd1\x12\xa1\xb5\xbdO\x8dU\xb6\b\xe5 B\x1f\xa3\xd3\x16\xafT\x85>\x8b\xb4{a\xfcA#\b\x82\x10\xdfHf.8\x8b\xc9\xcf\xfe\x82}\xfb\xb6\u0635+\u0485<\xa5\xd1\x16\"j\xdc*\xae\x83\"\"n\x87\xbb\xf63\xd2}\x88\xae\x17\x1fg\u0082UL;\xeb\x8dLZ~.\xf9\xc6\x16k\xd0U*\xe2\b\xaa\xf0nA\xf5p\xa0\u0586R\xa0q\x94\xc0!\n\u0280$pF\x18\x91\xd8\xf1\xc6E\u061e$*\x83C\x82\x94\xbdA\xb2a\x9c\xe8\xfd\x14\x8d:\xa2\x94B\n\xe8\xda\xfe\x12\xc3}\u01d3\xcd\xc1\xdapHr\xb9\x1cs\xe6\xcc~\"\xfe\xfff\u03de\xfb\xca\x14\xf3\x83\x03#t6\xd5qag]T[\xcd\xe2\u06f7\xf7|\xfa\xc7_\xbf\x8e\u00db7\xfcFxE\nI\x18\x86\xcc8e\rK.\xf8cra\x0eot\xb8\xc2\xfe\xc6$\x89\xa80\xc32\xb4\x8c\xbc\b+\v\x04\x93\xda\xe5\xa9\x18\xea\x98\x04\x96\x13\bi\x1d\xc9|$\x19a\x902\xaa\xae\x010\xaa\xed\xa0\x84\x9bJ\x1eO0\xb0\x94\x13b\xb1@ \x04N&K\xcb\xe4\x19\xb4t\xcc`\ua2b3\xf0J%\x06{\x8fs\xec\xc0^\xfa\x0e\xef\xa6\xff\xe0\x1e\x06\x8f\x1e\xa68\xd4Oyx\x00\xbf8\x82_*\xe1{%\u029eO\xb9<:\xf6\xb6\x04\xe5\"3YrMM\xb8\xb9<\x99|-\x99\xdazr\r\xcd\u050f\xef\xa4y\xea\\\x1a\xa7\u03a6~B'\u0646\x16\x1c\x95%\xeb)\x18\xf5\u0445\x02a\xb9h\x8f\xd2(\xabJ1\xa6z\xdb7\xa6\x1a\x97\xa7\xe2\x05m\xa8V\x04\t\xa9\x90\xd2E\xaa\f\x02\x05\x81]n\xca\xd8\x00g?\xab\xc9\xe7\x05S\x97\x9d\xcf\xc4\x05\xcb\xe9\xda\xfa\x02/<\xf4\v\x1eZ\xff^fO^C\xa7\x94\xc8\xc87\xfb\xe4\xf5\xca]\xf6T\x17R\xf6|\x94r8p\xe0\x00\xf7\xdd\xff+\x06FF8\xfd\x9c\xb3hn\x9eN\xe0\x85\t\xe9Y9\x8e\x99\xe4\x18&\x8c\xb4]v\xe4RJ\xc5f%)\xc2I\x90\xb1 \x95\x9c\x1c\xed\xf9\xc2rUV\x8b\xa0,, C\xdb\u045b\xf4]\xa9\xab\x03\x89\xc6\xe8\xd6\rP\xf4<\x9a\x9a:X\xba\xf2M\x1c9\xb2\x97 \bP\u02a9\x10\x86\xa6\x02\x87\x86a\x88\x10hG9\"\fC\xa1\x03\x9f0\x88\f\xf7\xa4-q\xc3\xdd\a\x19=v\x84\x97_x\x9c\x89KNg\xfe\x9b\xaeb\u0082Udkj\xc0+B\x18\xa2\xa4\x8d\x88\u04c0\x17\xa6\x03\x9e\x05\xa1\xb1\x01\x1d\xb5\xd2$\xd8u\x1c\u0111l\x88\xa2\x12\xa5\x97\x14u\xaa+\xb6\x10)\x188\xc5\x05\x1b\u049b\x1cH%\t|\u0631\xeeW\x84QS'\x85\x04cp3\x19:;;\x99>}\xfa\xa3\xe95\xf0\x8a\x14\xf3\u03a6:\x8e\x8c\x96\x99Tk\xa7\x0e\x9f\x1d\xe5\v\xbf\xba\xeb\x8e\xdc\x13w\xdc\x12U\xee\x8a\x13\xa2\x05\xfa\x15:\xf4i\x9d<\x9b\x15o\xf9\v\x1aZ;)\x8e\f&8\x9a\x88\xbc\x1eLD\x02\x1a\xa1\x11\x81%d\x84\xa6\x92p\x93\xb2\xbe5b\xcc\xd1&\x15\xfddM\xf25^`\xacw\xb1\x93\xac*K\x88\x8e\x82hP\x95x\uf60d7\xa6*B\xca\x18CP.\x13D\x13\xa9\xc2qqs5\xb4M\x99N\xd3\xe4\xe9hs\x01A\xa8\x19-\x96\x19\x1d\x1a\xa0\xd0\u007f\x9c\xd2@\x0f\xe5\xe1~\xbc\xd1a\x82b\x81\xc0+\xa0\x83H\x9b+%N&\x8b\x93\xad\xc1\xa9\xa9#[\xd7H\xa6\xb6\x9elC3\xb9\xa66r\xf5M(7WI\x8f\x05t\x10\x12\x84>~P\xc0\xf1}T\xa0\x13\x85B%p0-\x1c\x88\x19\xf6\xf8\x06\x16iuY\nw\xb27\x82\x90\x0eB\xb9v\x80+\xe9H\xc0\x04\x91\xb1\xbf\x94\x94\x06\x86\x187~.s\xcfz\v][_\xc0\x1b\xee\xe3\xa1;o\xe3\x8cs\u03a5\xa5#G\x9d(\x9c,\xe6\xafpW\x1e\x04\x9a\xb2\xe7\xe3\a\x01\x99l\x96G\x1f[\u02f3\x1b6\xd0\xdc6\x89\x99K.@\xca,Aa4\x9daV\x89o0\x15\xcc\xda\xe2\xdb\xf2\x04\xf5\x85 \x95t\x9f\x92\u0449\xd0~\xaa\xebH\x9c\x88 \xb1\x84\xaa\"t\x1ckb\x15\xc1\xa1\x15\xb5Fe\u011e(\xad\u0224<\x94$\x06?\xf0(gj\xe9\x9c}\x1a\xe3\xda\xef\xe6\u0211\xbdQ-\x90\x91\u72c98\"I]}\xab)\x16Kr\xa0\xf78H\x11*\x89\xc4\x18\xa1CKrZ\u0264\v\x02\x8a\x83\xbd\xec[w/=;^b\xc69\x970\xef\xc2\u02d80s.\x19GQ\x1a\x1d\u0173)\x17d\x94\xed\x9eCc\vy`\x04~\xe4c\x93\u02d0H\x18IQr2vG\x15\xe2D\xd1NU\xf1Oo`c\x06\xfd\xa3\u04f1r\x04\xc7\xf7\xecd\xdfs\xeb\x00R\xf9\x9f\x06\xd7\xcd\xd0\xd9\xd9\xd9=y\xf2\xe4g\x01\xae\xbb\xeeZ>\xfe\xf1O\xbc2\xc5<\f\n(\xc7\x16\xf2\x97\x8d\xf9\xd8m\xf7={\xd9\xdd\u07f9\xde\xc6s\x83\x90c\x16\x8a\xd6!\u065a\x06\x96\xbd\xf1O\xe9\\|>^i$\xe5\xbef\a\x19b\xa3,!%\xb2,\xec\x00C*\x930\xc9\xeeHgIUy\nW\xceR\u0080\t\xad\x87\x84\x0e\xac\x86\xb5*\xe2{Tc\x14\x88\xdaH\xab\xae\x89\xa4V\xd5T\x86I\x919Bk\xf0\xca@9\xe9j\xa5T\xb8B\x91\xcfg!3\x81|\xdb\xe4J\x8cZ<( \u04a9%\"\xbe\x13\"c\xba\xf8\xe8\xa8#\x9bQC\xa8C\x1b^\x1b\xb9\xd4\xc5x\xa1q\x05\"\xa7\x90e\x93\xe8\xea\x05\xd5\x1dy\u0711I!\x93\x9b\u0264N=\t\xeb.\x94\xbd\x01\xa4\x8bRN\xe4_a\xaa\xa6\x04\x85\x89\n\xbag\bU@\xb6\xd6a\xf6\xca7\xb1\xf9\xc1\xdb\xe9\u0677\x9d\xadk\xef\u7a67\x9faJ\xeb\xb9,\xccJ\x94\xd0'\xc9\xd0W\xa4\x90\v;%\xe9\xfbx\x9eG6\x9b\xe3\xf0\xe1\xc3\xdc{\xdf\xfd\xf4\x0f\f\xb0\xea\xfc7\xd02y>\xa1\x1fB\xa0#\xbf\"\x12\x88\xc3\xca\f#\x92\x1b\xab\x9a\x12B\xd9\xf7WX\xb23N|\u0462:?GG\xd0BNJ\xb2Y+$ 4\x18\x19}L\xabJb\f\xf1\xa8\xe9\x18\x9f\x12\x93Z\xfb\xa9/n\xb4\xa1P*Q\xdf<\x85y\v\u03a4\xbbk_J\x9e\x17Y\x0fD\x039\xabW\x9f+::\xa7\xbd\xfc\xc2\u018d\x93w\xef\u06a9\xf6\xef\xdcn\ub0b4~&:4\x11\x89j\u05f5\x00\x86\x8f\x1eb\xe3\u03feC\xf7\xc6\xf5,\xb8\xf0r\xe6\x9f\u007f\tM\x13;\x19-\x96(\x95\xcbv\x03J\fj+\x9a\x1b/4d\xb4\xc1Q\x95\xe7\x11\xf3\f1\xf9\x99\xa44\xa5\x92\x8a\xe2B\x9cL\xacF7\xa5L\v\u0222_\xa5P\xb8\x19\xd8x\u07cf9\xbe\xdfz\x1eIe}\u0305\x90477\xd1\xd8\xd8p\xeb\u99dfy\x04\xe0\xf2\xcb/}\xe5\x8a\xf9\v}B\x02\xda\x18s\xfa\xdd;\xfb\xfe\xe9\xce\xef|\x95c{\xb7G\xb4\xb6\xb5r\x14VRb\x85\xf5\x02f\x9dv\t\v\u03bb\xca\x16Y/\x88\n\x87\xb1\xb0J$\x19\x14\xda \x03\x81\xf4\x05\xf8Q\xdd3q\xe7]\tI\x8d\xb3\a\x8d\xa9:\xc0$\xb8[\x14\xa7\x12\xad+\x83\x0e\xc2h\x047\xeaV}\"\x8a\xdbA\xd4\xc8\x13:r\xfb\xb5S\xbe\xb81\xfb,\xd2\u040e\x86P\xa3M\x00\x06B\xdf\xee\xee1\xd6fDu\xa3R\x95P\x12\x1dI\rc&X\u0349\x98\xb7I\x1d_\x83\xacDf\xa5\xdd\xe8b2\xcaT\ba#H\x05\xf6\x926g\xab\u0605FS\xb8\u05ab\u0669$\xb1\x8c\x91\xc0\xc6I\xe4\u06b7)\xbd\xe5\xa1a\xa6\xccX\xc1\xfc3/\xe1\xf1}\xdb)\xf4v\xf3\xf0m7\xb1h\xe5\u9d0c\xcf2\xc5-\x9e\xb4\xc4}\x85\xf0\x95 \b\xf1\xfc\xc0F\x9f)\xc9#\x8f<\xc6\xfa\xf5\xebii\x9b\xc8\xecS\u0788r\xeb(\x15KQg\x1b\xdd\x1f\xa6\u04bf\xc4P\x8a\x10\n%\xdd$\x872>\xb9\x19a\tO-\xa5%M\xa3\xc9F\xa3\xb0\u0120\x13\xf1|\x0e\xa9p\xe2\xc8$/\xe6\u0174\xb40\xa6\xd1T\a\x8f&r\x96d\xb6!n@\xfc\xc0C\xe4\x1b\u9735\x92\x86g\xefchx \xcab\x96\x897\xb8\xef{\x94\n\x05\xae|\xd7;~\xfa\xa1\x0f\xff\xd9\xfao|\xe3;\x97n\u06fa\xe5\x8a\xed\x9b7\xe5\x8e\x1e>@\xe0{\x91\xaa&\x88\x1cU\xa3\xcdJJ0\x9a\xae\x1d/\u0473\u007f'\x877>\u0242\v/\xa3s\xe5j\xea\x9b\xda(\x97J\xf8\xbe\aZ#\x05\xf8\xa1\x85H\xe2\x00x7\n_Q2.\xe4\xd2n\x84\xca\xde?FV\":D\x95\u0657\x957J\x11)i\xc6\xeem\xc6P\xd3\xe0\u0435}'\xcf\xff\xe2G\x16>q\x1c\x94\xb4V\xbeJI\xa6M\x9b\x1e.[\xb6\xec\x81\xf8\xff\x99>}\x96=\xa5\xfc\xa1\xd7\u05be\x82\x91\v\x9b\\\r\xf0\x96\xff\xf5\xf9/\xfd\xf0\xdb\xdf9\xe5\xeeo|9\x04T\xeae\xe4\x8bdHd\x1d\x95H\xb9\xd4\xfd\xab\x1d(\xd7Jd[\x86\\s\x06\x91\x89&4\x1da\xff\xec\xdaiN#\x04B\xc9\xc4J\xc3(\xecC$\x06\xa6\x89-E\xfc\u0426\xb2\u07a5\x90\x94\xbc2\xd9\xc6\tt\xce\\N\xc6\xcd\u0606H\xa4\bF)\x18\x18\xe8\xe7\xf8\xb1\xe3o\u0771s\xd7B\x80\xb7\x9fs\xca\x03\xdf\xfe\xca?~\xe0\xfd\u007f|\xf5\x9b\xdey\xd5\xfb\u007f\xb5\xf2\u0333i\x9d0\t\xa4\x93\x0e\xdb\u0104!\xa1_\xb6\x1e\xe9\x02F\xfbz\xd8\xf2\xe0\x1d\xfc\xfa\xfa\xbf\xe5\xa1\x1b>\xcd\xd1-\xcf\xd0\xd0PO\u02f8\xf146\u0593\xc9f\xc1\xcdbT\x862\n\xed\xb8\b7\x13=\\\x90\n\x13E]'gkQ\x11p8R$J\xc5Tnv\xd2df\xf2y\\\a\x1e\xbb\xe9Z\x9e\xfa\xc9wm\xb7\xed8\x11\xf4\x85\tC-\x16-Z\u013cys~$\x848>n\\\x9bZ\xb0`qr;\xfdA;\xf3\xa7\x0e\r\x88\xf3\xa75\x85\u0198\xa6\xfb\xb7t\xfd\xeb\xbf]\xfbOSv<\xfdh(b\x11uJEa\x8c\xc6q\xb3\x9c\xf5\u058f\xb3\xe8\xac+\xf1K%K\x04\xc6<\x896\xa8\xc0X\x82E\xa7\x18\xe0\x8a\x99\x83=.\xc5\x1dA\xfc\xfbX\xe8\xa3J\xd5)\xaa\x8c\xf1\x13T#6\xaf7\xd5\x04\x86\x9d\x8c0V\u0652U\xd5#\ufc5f\x82H\xdd\x14\xa9\x82\x19w\u035e\x86b\x90\xf2\xd8I\x9f\x0e\x12\x83|\xfb\xd6[\xa2h\f\xfcq\xc2\xc8/'<\u007f!R7\x9c\x10v\x98\xc3\u0122\x01\x11I\xc6R\xafQ,\x9b\x8a'\xf6\x1c\x17\x91\u0260\x1c\xbb \xb5J\xe9cS\xafk,\xbdJ`\x19Y\xbdO\n@e2\xb4u\xcc\xe0\xe5\x9d\x1b\x188z\x88\x81#\a\xc9\xd471a\xf99\u4961\xd5\xd5'\x90k'\xaf\xffb!\x8f\u0580\xe7\x05\x94\xca\x1e\xc6@]m\x1dO=\xf54\xd7^\xf7\xaf\xf4\xf5\xf5\xb1\xf2\xfc\xab\x98\xb9\xfc\u0354\u02be\u0748\xe3\xb5l*\x837\x96l\x94\b\u9814\x9b\x14\xf3*\xf6.\uaa0d\xac,\xdc\xc0\x11\x98zEc\xa3C\xaeVAF\x8e\xa9Pv\xdd\xfb\xc6j\xd75\x1a\x1d\xf9$Y\x8bQ]M\x10\xa61\xe34Y\x18\xe1\xcc\xca\u0252s$G\x0fm\xa1\xbf\xefh\xc4\xe3Tn\n\xad\r\x19\u05eds\x1c\xe7\xc1\xfb\xef\xbbo;\xb8\xea\x9ak>\xa7\xef\xbd\xf3\xa7{\x9f]\xbf\xf6\xd6\xfaq\x13\x0f\xb8\x8eZ822\xd2R,\x96D\xe0\x95\x01aD\n\xff0QL\xa5T\x8a\xd2\xf0 \xc7vm\xe2\xd0KO\xe1\x15Gi\x9e4\x95|\xdbxL\xb6\x16\xa3\r\xa1\x94h\xe5D\u0779\x8ax\xaf\xd4t\xa6\x00W\u0187^\x81\x12\x16\xeb\xafVb\xa7g_\x05\xf9\x86\x1cJ\xc0\xba\u007f\xff&\xf7|\xe5o\t}\x1f\xc7q\xad@CJ\x82 \xd4\x13&L\x90+V\x9c\xf2\xe0\xe7>\xf7\xf9O]s\xcd5\u07bd\xf7\xfeB\xde|\xf3\xf7\x93r\xf0\a\xed\xccO\x9f\xd2d\x00^\x1c\xe1\xf2\xfb~\xfc\x833\xd6\xdf\xf5C\xbba\x981\x9dlT|\xe7\xad|+K\xcfy?B+t\u0673\x9a\xf1\xd0 \x83\xa8\x90k\x93\x14\xf2j\xb2\xa4\x82\xb5\xc9(\xe8U\xa9\fJ:Q\x81\x97\x95\x02O\xcac2)\xba\xd5\xf5D\x87\x10\x84\xb1A\x96H&\xe0@@ \xa0`\xc1-\xa1RE0\xaadf\xccfB\x14\xf6j\xb0\u01f1b\b^\x84\xd1K\x91\x86\xbe-\xf9\x14K\x9f\xd2A\xe6c1\xed\u050cDu!\x17\x15hE\xa7:h-\x05~N\x11\xba\x12\xa3\x04F\u026abo\x84\x04\xa5\xec\xa8s&\x87\xccd\x11n\x06\xa3\x94u\xcfs\x05AF\x10:\x820\xfa\xbbQ\u0092a\xa9<\xd3D\xd2(m^d\xe0\x19\xc2b\x89\xd6\t38\xe3\x1d\x1f#\xdf\xd0L\x18\xf8\xac\xbd\xf5\x9b\xac\u007f\xf8!\xb6\x15\xb3\xbc<\xaa\x91\x9ctT\xfc\xbd`r\xb0\x83e\xe52A\x10\x92\xc9dx\xf9\xe5#|\xeb\xdb7\xb1s\xc7\x0ef,<\x93\x85g\xbe\x03T\x8e \x8c\"\u03f5\x1d\x96\x8bo\x85\x8a^>\xf0\x12\xa5r!\"\x1c+\xcfW\xeb\x90q\xe3\xda\xe6ds\xd9;o\xbb\xf5\xb6\xaeo\u007f\xfdk\u0737\xf6\tf\u031e#\xd6>\xf4 \x00\x8f<\xf8\xe0\xba\xc7\x1ey\xf0\xa1\xc1\xa1a\x84\x10\x1d\x9e\xef\xd5\x0f\r\x8f\b!\xa4\x96R\x89\xc4\xdf)\xad\xd8\t\x03\x06\xba\x0er`\u00e3\xf4\xed\u07c9R\x0e\xf5\xcd-\u0536\xb4Y\x8f\x980\xc0\x11\x06%\xad\ubd8c\xeeSM\xac\xb2K\x87R\xa4\xd1\x02\x83r]j\x1b2\xf4\x1c8\xc4\xfd\xff\xfa\xf7\xfc\xea\x1b\xff\x94\x88C\\\u05cd\xe0\x15a\xc0\xc8\x05\v\xe6s\xf9\xe5\x97\xddt\xe5\x95\xef\xbd\x01\xe0\xfb\xdf\xff\x9e\xb9\xfe\xfa\x1b\xf8\x83\x17\xf3\xdbn\xbf\x9dw\xbey\r\x00SW\xad\xfe\xe0O\xbe\xf7\xed\xab\xb7?\xff\x94]6\xd1\x00B\xa50\n\xb2\xb9Z\xcex\xe3\u01d8\xb7\xf2R|\xafhM\xe4\xc7\xe4U\xff\xb6\xa3\xb8\xf8\x0f\x96z\xec\xbf\x1c\u007f\x9fd\xca,u\xb0I\x13\xa2U\r\xae\x10(!\x927C\b\x81P\")\xa2\xd2\x11\xd6\xcc[\xc9\u0502\x8b\xb5\xa5\x95i/\x1dg\x8dj\x18\xf6Lb\xfcobC\x9d\x94\x83\xa3\x11\x15V6\xfd\x86\x8b\u0602 *\xd020(/\xe2\x0f<\x83S68\xbe\xc1\xf1\f\xaa\xa4Qe\x8d*\x1b\\\u03e0J\xd1\xe7\xf8\x06\x11\n\xa4\xb6Gi),.\xaeT\x06\xa5\xa2\"\x1eMz\xa4\x9a\x1c[\xcc\xd3p\u0558l+a\xa8\xba\u046a\xce\xfd\x11,kB\x9fl\xbe\x9e\x86\x89\x9d\x1c\xde\xf5\f#=\xdd\xf4\x1c\xd8\x05\xd9<\x13\x96\x9dC]\u01a1=\xa3c>\xee\xe4\xf5_(\xe7\xbe\x1fR*\x95\xf1}\x9b\xa6S[[\u01e3\x8f>\xc6W\xfe\xe5Zzz\xfb8\xf5\xc2+Y|\xf6\xbb)\x95}\xc2\xd0J[e\\4\x93\x81\x16\xa2\xf0a\xebA.\x1d\xf7\x84BN\n7O\xbb\x8f\uab24\xa6-CM\xde\x0e\x18U\xa9\xac\x88< \\\x89\xcc)\x9c\xac\xb4\xc5\u0704\xa0\xc3\xd8\xf1?\x81\x1bBm\xc64h\xa2\xca\u0714\x14\x1c\xa9\x81\x86\xda\x1a\xba\xf6o\xe4\xf8\xb1CH\xa9PJ\xa5,\x024\xc5B\x91\xfa\xfa\xfa\x17\x1e_\xbb\xf69\x80/\xfe\xc3\xdfs\xd9[\xde\u00b57|\x95\xd0\xf3\u0637o\x1f\xd7^{]\xd7\xfau\xeb~q\xf3\xf7\xbe\xf3p\x10\x84\xadm\xad\xad\vF\x87\x87\xc5\xf0\xf0\xb0\xad\x1d\xc8\xdf\xe8r\x1axe\x8e\xef\xd9\u0281\xa7\x1f\xa0o\xffN\xbc\xe1Ajjkhnk\xa7\xb6>\x8b+\x9d\xe8\xa0,*[a\xea\xd4n\x930\xad\xeaE9.\xf9\xfa\fRJ\xb6>\xf2\x00w\xfd\xf3\xdf\xf0\xdc/\u007f\x9c|/\xa7\xba\x90\x8bi\u04e6\xb1f\xcd\xc5\xcf|\xfa\u04df\xf9\xe3k\xae\xb9\xa6x\xf3\xcd\xff&V\xaf\xbe\xf0\x84[\xe7\xf7\x96&~\xff\x96\xefs\xe5\x15W\xc4\xd8\xef\xacw~\xf0O\xfe\xfe\x99\xc7\xecN(\xe2\xc2\x1a\xb5\xdbR*\xc2\xc0c\xfa\x82\xf3\x98\xbf\xf2R\x00\xc2 H\x82\x9b\xd3\xed\xa90'\x1a\xe0S\xa1\v\u007f#\x8a\x98,Y\xa9P\xd1\xd1\xd1\xc6JE\t\x1dq{\xa1OTtTO\xa1\xa5gm#\u054dg\x10%\x83\xa8\xa9hD\xab\x95\"&\xd1Q\xfb\x1aF|\x83\x1f\rD\xe8\xcag\u06db)\xf6\xb9\x88d\x83\x96\x17\xa8\x98\x19\xc5$\x95\xd4$#\xd2\xc9\xe4^<\x82\x1d\x9b9\xe8\x8aBE\x88\xb8s\x16\t\x14$\xa5\xb4_\a\xfbzXZX$\x01\x1d:\xd6\xfd\xa6HRK2\xc9$?\u057a6ZH\xc5(\x13\x195\xa5<\x9aSu@\x1b\x83\xe7\x01\x03CL\xecX\xc4\xd9\xef\xf98w_\xf7Q\xcaCC\xe0[\x00;w\xec\x00\xe0\x13\u007f\xf91^z\xe9\x05\x96.]\x9e\xfc\\\xabW_\xf4\xbc1\xe6\x03?\xfc\xe1\x0f\xee\x986\xb5\xf3Ov\xec\xd8q\xe1K/md`p0z\xbd\x94\x95-kS%C\x1e\x1d\xe8g\xf3\xaf~\u02ae\xb5\xbfd\xca\xe2UL]v&\xd3V\x9c\u0174\xa5\xabh\x9a\xd0n\xa5\x8ba5\xc1\x19\xf3ZRY\x88h\xa4o\x80\xfd\xcfmd\xf3Cw\xb3\xe1\x9e\xdb\x18Ly\xaf(%\xad\u07cbMc\x13\xed\xed\xed\x9cz\xea\xaa\x1d\x1f\xfb\xd8G\xaf\x16B\xf4\x02,_\xbe\xfc7\xbeY\xbfw1\xff\xecg?\x9b\xfc\xf9/\xff\xe6\x93\x1fY\xff\xc8\x03\x13\x83r\xc9v\xb31;n\fR:\x84\xa1Gc\xeb\x14\x96\x9e\xf3~\xeaZ&S*\x0e\xa7\n9't\xe7I\x896\x95\x9d\x9bTa\xac\x02\x95S9\xd8\xd1N\x82T.B(\x8c\b\xd0\xc2&\x88W\xa6g\xac\xec\u0764\xc0\xe9\xf4\x10ME\xdc\x1f-\xfc\x10(j\u06dd\xbb\"\x19T\"\xe9\xba\x05F\x1a\xfc\x10\x86}M94Q\x87\x1d\x15\xe8\x88\x0f\xb0\xb0\x88\x88\xd2X\xe2\xc1'\x11'\u070d1\nK\xfdt&u\xbeHOC\xa7\xb8\x01i\xa2\xa2\x1du\xe2\x91O\x01B\xc5\x03I\xa6\xca@LK\x119\xe0\xc9dH\x84\xe8\x18\xac\x04H\xd7~M\x95z\xed\xb5\x16\x11\xa9e\x12#}\x1d\xdd\xc1\xb1\t\u007fh \xf0|\xc4h\x81\x05g^\xc6\xd1\x03[X\xfb\xbd/Q\x1c\xe8\xe5\x81o\xfc#\xed\x1dSi\xba\xf0tj\x95\xa6\xd5\r#\xa2\xec\xe4\xf5\x1fI\x10+\x13\x9e!A\x10\x92\xaf\xa9\xa1\xaf\xb7\x8f\xaf\u007f\xfd[\xac[\xf78\xe3'\xcd\u4d0b\xaf\xa6\xbeu*\u00e3#v87\x9eGO\xcf\xc0GJ\xa6\xf4)V0\xb6q:\x91\xa3\xd2\x00\x8e [\xef\xe08\xb2bn\xf5\x9b\x98Y*>/d$\xb21\x834\x01\fht\xd1@`UR\xd2\x11v\xbe\u00c8\xe4\xebUZ\x9e1\u007f3\x86\x92\x96L\x9e\xb1\x9c\x86\x97\x1e\xa2\xa7\xe7\b\x86\xac\u0154\xad/\x93)\x97\u02e2\xab\xab{U\x10x3\x1d'\xb3\xe7\xc2\v/N\x9e\xda\u04a5\xcby\xe8\xa1_s\xe1\x85k0\xc6\xf0\xd5\x1boPB\x88\"\xf0#c\xcc=\xd7_\u007f\xed%\x1d\x1d\x93\xfff\xf3\xe6\xad+\xf7\xec\xd9C\xa1X\xc0D\xba}m*\n\xb5\xb8\xe1,\x17\v\xec~\xe61v?\xf3\x18M\x13:\x980k\x01\x93\xe7-f\xd2\u0725\xb4M\x9bMMC3N&\x83#\x05\xbeW\xa68<\xc4\xc0\u04579\xb8\xe9Y\x0eo}\x91#;7\xd1\u007f\xe4P\xd5=,\x95\xaa*\xe4mm\xe3X\xb6l\xf9\x81\xcb.\xbb\xec\x1d\x9d\x9d\u04f7\x00\xdcr\xcb\xcd,]\xba\x82?x1\xff\xc2\x17>\xcf\xe7>\xf7y\x00\xee\xf8\u065do\xbb\xe6\v\xff\xe7O\xbb\x0e\x1f\x8aX\xe1\xc8GA\x9b\x84\x95\x96B1\uf5372m\xc1j|\xafT\x95\x9c=\xd6M\xac\xaaS\x16\x86\x8a\x9dd\x95\xa9C\xd5\xfa\xab\xea\u06a3\x91\xf5X/-\x8cFF\xc1\xafFT\x8c\xf3c\uf4b8\xb3\x16\xc6Nr\u0274\xd66.\ua041\x92\xb6\xea\x96\xd8\x18\v\x83\xb1\xc1\xe4\xe8\xc0P.\x85\x84e\x8d\x1b\xe5%&\x98v\u0509\x93\x1e\x9f\xaf8\x83Uu\xb7\xc9\"\x8e\xd4-\x15[\x83\x94z\xc4\xc8H~)+\xd3{\bl\u53a4\x9a\xe67l|\xa2\x8a\u07cad\x8b\x95\xe1%G\br\x11w \x85\xdd\x0f$\xc90\xaa\ud0a4$\bt4\x19K\x1c\x17i_\xcf\u8865\xc0+{\xe4\xca\x19\xcex\u04df\u04f3{\a[\x1f\xbf\x8b\ue75b\xf8\xf9\xbf\xfc\x1d\xed\x13\xbeG\xc3\xf2Nra\x89\x1a\xa5\xf1\xf5\u0262\xfd\xdb$\x88a\x18\xe2y>\x9e\x17\xe0\a\x01\xd9\\\x8e\xb2\xe7\xf3\x9d\xef\xdc\u011dw\xdeA\xbe\xb6\x81\x95\x17}\x80\u0273O\xa5P\x18%\f\xc2\xc8\x02\xda$\xa6r\t\xe7\x92\xccW\xd8\xe1\x16Q\xa5\x81H\xb9\xf3\x88\xd4L\x82\xb1\xfc\x89S\xa3\xc8\xd5\u02a8\xdb\x14c\uee0a>\xbcJuf\xacp@\xd6: 2\x18\x05\f[\x82\xc5\bc\xe7\xf7\xc4\x18W\xdc(\xfdb,\xd4\xe7\x05!\xed\x9dKhi\x9bB\xcf\xf1\xc3h\xadQ\x11\xdf#\xa5\x12\x85b\x91}\xfb\xf6\xca{\xef\xbdw%\xb0g\xecky\xe1\x85k\xd2Ma\xf8\xf0\xc3\x0f\xc9{\xee\xb9\xc7\x11B\x8c\x02?6\xc6\xf4\xc1-[\xb6\x8c\xeb\xee\xeeft\xb4\x80R\x8eA\"\xaa%\u0155\xaeo\xa0\xfb0\x03\u0747\u067e\xee\xd7\xe4\xea\x1a\xa8mj!SSg\x9d\x1e#'X\xafT\xa484\xc0p\ufc6a\xf76&_\x85\xact\xe4Z\x87b\xe2\u0109\xac\\\xb9\xf2\xc0y\xe7\x9d{\xf9\xdb\xdf~\xc5\x16\x80\x1bn\xf8\xbf\xe2\x03\x1f\xf8\xd0o\xed{~\xafb\xfe\xd9\xcf\xfe=\x9f\xfb\xdc\xe71\u01a8\xcb\xdf~\xf9\xe7\x0e\x1e\xd8_\x8b1HiI\x99x\xba3f\x8a;f\x9f\xce\xf2\xf3\xaf\xc6\xcd\xd6Q*\xfe?\xf6\xde;\u0732\xab\xba\xf2\xfd\u0375\xf6>\xe7\xe6{+\xe7*\x85RD9`\x81$\x04B \x92\rn0m\f4B\xed6\xc16m\xbb\xbb\xdd\xee\xee\x87\xc1&\xf8\xb5\x03`c\x03\xc6 \x82\xdbX\xc6&H\xc6`L\v\t0 \x19$\x94\x91J\x15\xa5\n\xaa\\7\x9e\xb0\xf7^\xf3\xfd\xb1\xd6N\u772a\x92\x84x_\x9b\xea\xfa\xbe\v\xa5[7\x9c\xb0\xf7Xs\x8e9\xe6\x18\xd3 \xa6>\xe7D\xfb\\\xc4J@\xef-\xc6\xf5\xd8\xe3\xfe\x9a\xc3M\u0e6d\x05\xa2B\xff\xed\x01\xbd\xbe\xc8\xe3\x03\xa2\rX?\xc0\xc1\x80D\xc6\xf7\x85N\x83U\xae\xcfN\x94\xc4y\x8b\u05eeC;J\xdaq\xd0u\f\x17\xaa\x01\xed\xd1[Ulu\xb4\"&\xaa\x96FR\x1a^\xf9\r\u03bc\u0291\xca\xd6^\x0e\xe2\xb64+\xab\f\xa9\x8a\x90\t\xa9\x94\xf4\x15\xb5\xa5\x0f\xec\xf0\xab\xda\xd2\xf0[\xa3\x00\x91\x85!\xeb\u0346\n]O\xb1\xecPv\bF\x15q\xc6o\x1c\x86\xe9\xbd\x03\x92\xc4!\x89\ay\u007f0\x1a\xba\xd3\xf3LN\xad\xe6\x9a\u05fe\x83\xf9\xc3\xfb\xd9q\xff\xb7\xd9|\xc7\xd7\xf9\xebw\xfd'\xec;\xfe\x18s\xf6j\xcen\xce\u04f4\x92\x1b\xf4\xfd\xdf?5j%\xa3\xd3\xe9\x86\xc5 o\xb3\x9a$)7\xdc\xf0)>\xf2\x91\x8f\xd2M2\x9e\xfd\xfc\u007f\xc7Y?\xf5r2'dIRvn.\x18;Uc\f%l@\xda(t\xcez\x94\xe1Hy\xdbe\x06h\n\xcd\u0248\xa8a\x8aJ\xba\x8fZ\xae\xeaj+\xffh\x8c\xc1X\x83\x0ey\xf7M\xc4\xc1\xacCS\x83D\x95\x03!-\xfd\x8fLAe\xe6A\x18~\xc8\x19\x8d-c\xdd)\xe7\xf1\xe8\xb6{H\x92\xa4\xb0\xa0\x15\xe3\x03\x8fgg\xe7\xe2\xef~\xf7\xf63\x9e\xc8k{\xf5\xd5\xcfw@\xf7\xc3\x1f\xfe3y\xcb[~YE\xe41\xe0\xbft:\xad\x0f\xbe\xf3\x9d\xbf\xf3k\xb7\xdf~\xfb/n\u0672u|\u03de\u0752e\xae\xdbh4bU\x95,\xcbJm|\xa5\x93\ah\xcf\xcd\u041e\x9b9\xee\xef6\xf9\xba\u007f\xf8\u007fk\f\xaa\x9a\x1ac\xa2\xd3O?\x8d\xcb/\xbf\xfc\xa1\u05fd\xeeu\xaf\xba\xe2\x8a+\x1f\x00\xf8\xe5_~\xab\xbc\xedm\xbf~\xcc\x06\xf6)\x81\xf9g?{#\xaf~\xf5\xcf=\x05\xff\xf0\x00\x00 \x00IDAT\x17\x15\xeb\u007f\xff\xef\xbf\xf5\xae\xfb\xef\u007f\xe0\xe2#\x87\x0e\xf9\x9a\xd1\xd6WC\xb24alj\x05\xe7_\xf9:\x96\xad=\x9bvk\u059f\xe9Zsw\xaa\xd4\xdeR\xd7\xe4I\x8f\x1a\xb5\xee\xe4\u0783\xe0R\xf3\xe9\xeeUhK\x18\x94\x92\x0fO(\xb7u\xb4R\xfbK\x84\x97QY\x81X\x8a\xe9\x9ev\x80T\x90\x18\x9c\n\x92x\xdf\u7d2b\xb8\x14\xe2\xa0\x1c)x\xff\x8a\xefJ-\xbe\xae\"\x0e\xad\xaa\x05j\xa6G\xf9\u07f5^\x9dKE\x8d\xa3\xbd\x0ex\xda\xeb\x8aW\xbfU\x9d\b\x1a\xf9OD\x91!\x1a3\xd8E\rl\xecA\xdcJ]\x9aFO\ua560X\x04\u027c$\xcbW\xee\xe1\x86K\x95d.\xf5V\xab\x99w\xa1\u031c2?=\xc3\xca\xf5\xe7\xf1\x82\u05fe\x93\x9b?\xf4\xab\xec{\xec!\xee\xfe\xa7\xbf\xc3D\u00d8\xff\xf1\xfb\x8c\x9c\xb3\x92\x8d2\xef=\xe7\xff/~\x17\u007f\x92$\xa5\xd3\xe9\xd2MR\xd2,%n4\xc82\xc7g>\xf37\xfc\xe9\x9f~\x88\xb9\xf9Y.\xbc\xfcg\xb9\xf0\xaa\xd7a\xa3a\x16\xe6\xe7Kh\xd6z\x17V\\?\xb9\xa2\xc9D=\xb3\xa6\xfe2JC\xd7\xe6\"C<\x1a\xd1\x18\u036d\x9a\xf5\xb8\xb2\x1b\xa1\xec\xa6ErE[\xe2\x1b\xc7q\xef\x85d\xd5\xf9\xeb\xcd:\\\xaad\x9a\x15\u02b2\xc2>BJ\x95[FB\xd7\u016c>\xe5bFn\xbf\x89C\a\xf7\xe2\xe2\x18\x1b\xf9\xc8\xc94M1\xc6\xd0\xedv_\x04\xfc.\xc0\xe6\u035b\u0638\xf1\xf4c>\u0737\xbc\xe5\x97U+\xf1\x8e\xcd\xe6\xf0\xa3\xc0o|\xf5\xab_\xf9\xc7/|\xe1\v\xbf\xf3\xe0\x83?\xbcl\u01ce\x1d\x8d\x9d;w\xa1\xaai\x1c\xc7VUE\x8b<\xcez,\x9e\xcb\xdb\xd8*u\x94\x0fw\x03x\x17\x15\xb9\xf7t\xd14M\xdd\xc4\xc4Dt\xca)\xa7p\xed\xb5/\xfc\xa7w\xbe\xf3\x1d\xff%\x8a\x9a\x0f\x00\xfc\xfa\xaf\xff\x9a\xbc\xff\xfd\x1f8\xee\xad\xf1\x94t\xe6\xaf~\xf5\xcf\xf3\xc1\x0f\xfe\xb1\x05\xb8\xed\xb6\xafo\xbc\xed\xb6o\xfe\u008e\x1d;\x00\x12k}]W\xf2\u007f\xb7t\x9d!q\x11\xa9\xb3\xa4\x1a\x91jLFL&M2\x19\"3C\xa4v\x88\xcc\f\xe3\xec0\x1a\r\x03C\x18mbhb\xb5I\x94\u0158,\xc6h\x03#MT\x9b8i\x10\xd9!\xa2x\b\x1b7\x89\xa2!\xa2\xa8\xe9?g\x87\x88l\x83\xd84\x88\x8cW\x93\u0628A\x145\x88L\x93H\xe2\xfa\a\x11\x111\x111\x96\b+\x91W\xa4`\v};=\x1dM\xf5P\xa2\x92$$\xc5\x10\x95B\xd9`RG\x94)C\xaa4Rh\xa04\x9b\xc6W]\x91\xff\x90\xd8x)\xe6\x90A\x86\xa4\xf8\xbb\x19\xb2\xd8a\u007fs\u01e3\x16\x19\xb20d`\xd8\x12OD\x98\x89\x18\x9a\x96\xb0}L\x16\xfc\xa9\x17ff9\xe5\u072b\xb9\xfa\u07fe\x9d\xc9%k\x00\xb8\xeb\xcb\u007f\xc9_\xbd\xe7\xbf\xf1\xad\a\xf7\xb1\u06cd\xfa\x83\xe2\x04/\xcd\xf3C\xb3\x9b\xa4\xb4\xda\x1d_\x91\xa7)\x8dF\x13k-7\xde\xf8\xb7\xfc\xd1\xfb>\xc0\xfe\x03\xfb8\xfb\xa2kx\xd6K\xde\xc2\xd0\xf8R\xda\v\xf3\xfe^s=\x90\xac\xd5\x05\x1c\x0f\xaa\xc6D=\x86W\xd2W\xf8\x14\xdeXV0MCs\xccb\x1b&tj\xdaS0\xd5|i\x8bR\xa3J\x8b\x16\xdar\r\x8a\x8e\u0448xQL\xf5_i\xcd\x1f\xe1\xce/\u007f\x12#\x86\xf8\x1d\xef\xe5\xa5\x17\xac`\x95i\xa3\xa9\u00dd\x90@\ue2e0\x1c\u023b\xdd\x04\xe7\x1c\u0366\xcf\xc0\xfc\xf4\xa7\xff\x8a?\xf8\x83\xf7\xb1o\xdf\xe3\x9c~\u0795\\\xfe\xd3ocb\xd9\x06\xda\xf3\xb3!\u078f~\x806\xa1\x1f\r\x1b\xd3&X`\xe4r\x01A\x06z\x1a\xa9\x88\x1f\x90GBc\xd8\xf8\x83\xdb\x1cM\xf5R\xad\xc2{\xaf\xc6RY\x95\xdblHX\xae\x91\xa1\xc8\xdf\xdb\xf8`\x18\x13y\x03=\xa7\xa5*R+j\x10\x102\x97\x11\x0fO\xb2\xfa\xe4\xf3xt\xeb\xbddY\xf09\x0f\x1d\xc0\xec\xdc\x1c\x87\x8e\x1c^\xf6\xe0\x83\xf7=\v\xf8\xa7'\xfb\x1e\xbc\xf1\x8d\xff\x9eO|\xe2\xe3l\u07fe\x83\xdf\xf9\x9d\xdfED\x16\x80\x0f\x01\x1f\xfa\xc2\x17\xfe\xee\xd5_\xfb\xda-W\x9ey\xe6\x99/\u07bf\u007f\xff\xa9\x0f?\xbc\x89\xd9\xd9Y\xb2,+\ue0fc\xc2/\xabq)l\xa7\x15\xaf\n\xf3n\x8f\x868\x8eY\xb6l\x19g\x9cq\x06\xeb\u05ef\xbb\xf95\xaf\xf9\xf9\x0f\\u\xd5\xf3n\xcd\x1f\xcb?\xfe\xe3\x97y\u044b^\xf2\x84\x9b\xd5'\r\xe6w\xdf}\x17\xef~\xf7\xbb-\xe0n\xb8\xe1c/\u07b1c\u01db\xf6\xef\u07c7\x18\xa3\"\xf5\xba\xcae\x19C\xa3S\\|\xf5/\xb2\xe2\xa4\vH:\v~S\xaag\u02cb\xca\"\x8d\xf6L^\xacu4\xa3\x94\x86\xcd\x18\x96\x84\x86\xa4\fI\x97a\xe92b\x13\x9a\x92\xd00)q\x0e\xe6&+9\xac\x82\xb7\xf6\v*V|[\xe7\x804\x04\x19f\xea\u056fF\\q\x11:\x04U\x03\x91\xc5\x19K7\xb3$YL\xd7\u0174\\L[c:\x123\xa7\x11F\x84Fp\x8bS'\xb8\xcc\xe0\x9c\xff\xb9\x19\xa6\x18h\xf6\xc4\x1e\xd6\x14]\xa6\xea'\xaeT\x92\xed\xeb\x19$\xd5\xd7E\n(\u05c1\xf3\x02\xa9\xef\x9a\xd1\x176\x98\x17X\xa9C\xe6\x1dL(\f\x1b\xfa\xcd\xcd{\x84\xa1R\x0e\xba\x8cJ_a\x16\x19C\xbbaH[Bd\xbd\x8aG\x9d7-\xeb\xb6\xdaH\n\x17^\xf9z\xd2\xd6<_\xfb\xec\xef\u041a\x9f\xe6{\xffp\x03Y\xda!z\xe7\xef\xf1\xaa\xcb\xd61f\xbb$\xdd\xf4\x84\x92,V\x81\xbc\x9d\x03\xb9*###\xb4Zm>\xfd\xe9\xbf\xe4\x83\x1f\xfc\x10\xfb\xf6\xede\xe39\xcf\xe2\xaaW\xfc'\x96\xac:\x9d\xf6\xfc\\!\xed\u04f0}\x9c\x83_!\xd5\x15?\x18\x97P1J\xbf\\\xa0\xf6~kP99+D\rCc\xd4z7\xce\xda\xf5U\u05dd)\x83\xae\xd9z%\xa1H\xcfj\x82b\x9a\x06\x9d\x8cQ#\x18u\x98Lp\xa9\xef\xe8\xb3\xf0\x18sS-\x05\xd24\xa11<\u02aa\xd3/f\xe8\u06dfgnn\x16\xa7.\xb8\n\nY\x9a17;?~\xdbm\xdfX\xffT\u07cb7\xbe\xf1\xdf\xd7\xfe\xfb\x93\x9f\xbcA\xae\xbb\xeez\xfd\u065f}\xd5g\x81\xcf\xee\u0739\xfd\xec\x1bn\xf8\xe4E\xe7\x9dw\xfe/\xec\u07bd\xeb\xca\xc7\x1e\xdb9\xb6g\xcfnZ\xad6Y\x96\x9bx\xd5\r\x05}\xd5ni4b\xc6\xc6F9\xe5\x94SY\xbcx\xc9c\x13\x13\xe37?\xebY\xcf\xfa\xf6u\u05fd\xf1\x8bA]\xc3_\xff\xf5g\u456f\xfcY\xfd\xe2\x17ozR\x8f\xfbI\x83\xf9[\xdf\xfa+\xf2\x9d\xef|'QU\xfb3?\xf3\xd3o\xbc\xf7\xde\xfb\x82\xca\u0358\xdcs\xa5\xfa\x86\x9eu\xf1\xcfp\xe6\xc5?\x83s)i\x9a\x14\xff\x96\x05g5*\xa0dEi\u0614!\xd3e,\xea0\x16\xb7\x19\x8a\x12\x86\xe2\x84f\x94\x10\x9b\x8c\xa6&44#\x96\xd4W\xe1\x15@s\xf9\v\x17\x92L\xf2\u007f1E\r\xa2\x95\\g\xc1\xa9\t\x16\x95a\x80n\xb4\xc2\x15\xe6\xaelJf\xfd\xae|\x86\r\U0010d84b\xa1E\x8c\x03\xac\x962=\xd4\xcb\xf7<\xa5\x13\xd1\xca\x1a\xb4\xb3\x98D-i\xc8\xd2L\xd4\xd0\xcd,\x1d\x17\xd3uQi\xf4U9\x80\xf2}Q#\xa5\x11W\u0756@\x8f\xcaWr\f-~\x11\xc2\xe1r]\xa1@'C\u06e1:\xef\xfbV\xad5N\"\xa5}\xa3\x88\x86%\t-\x00$\xb2~\x13\xb0\x13\xf2V%\x8fn\xf1V\xf6t:m\xd4)\x17=\uf348\x8d\xb9\xe5o\xdf\xc5\xdc\xf4>\xee\xfa\xea_\xf1\xfbs\u04d8\xdf{\x1f\xff\xf6\xca\xd3h6\"\u04a4M\xe6N\x1c \xeftSZ\xed6\xddn\x02x\xbf\x95\xfd\xfb\xf7\xf3\x17\u007f\xf1q>\xf1\x89O23}\x98\xd3\u03bd\x9c\xe7\xbc\xe27X\xbe\xee\x19\xb4\u06c1ZQ)\u02e3\xea\x06X^\x1d\xe6\x89Q6\xea3\x88\xeb\xab\x02BI\xec\x8c@$D\u00c6h\xccz\x95\xabj\x0f\x0f_W\x95Uw\x1c{y\xf8\xde\rfo#\x10$\x89\rA',\x96\x98\x86\x80\xeb*\x9a*Y\xe6z\xe8y\xc1\x89\x92\u0186\x89u\x1bY\xbcj\x1d\xb3\x0f\xdd\xe7\x15&\x01\xcc\xd34\xc5X\u04dc\x99\x99\xbd\x1c\xf8\u060f\xfa\xde|\xf4\xa3\x1f\xe1\xba\xeb\xae\xd7/}\xe9f\u067au\xab}\xdb\xdb~-[\xbb\xf6\xa4\a\x81\aU\xf5+7\xdc\xf0\xf1\xa5\xd3\xd3\xd3\xcf\u0777o\u07f3\xf6\xee\xdd{F\x9a\xa6\x97\xee\u0673\xc7\xce\xcd\xcdfI\xe2+\xf6f\xb3!\xabV\xad2\u02d6-\xdf\x1fE\xf6\xd6\x15+V\xdc\xdbj\xb5o\xbb\xf6\xda\x17\x1e\xb8\xea\xaa\xe7=\xfc\u044f\xfe\x05o|\xe3\xf5\xbc\xeb]\xbf\x1b\xbd\xf5\xado\u0396,Y\xfe\x94\u0298'\x05\xe6\u007f\xf5W\u007f\xc9k_\xfbz\x05x\xff\xfb\xdf\xf7+[\xb7n}\u0561C\x87\x101&\x0f0\xc8\u06dd,\xed\xb0b\xfdy\\\xf0\xdc724\xba\x88n\xa7\x85SC\xa6~\xa8bP\x1a&e\xd8&LF\v\x8cGm\u01a2\x0e\xc36a\xc8vi\xda\x04k\x1d\x91u\xc46\r^\xc9B\x949\xbf(\xa3y\xe8jYaD\x92o\\j\xe1\x87.\x95\xaaV+2-\xff\xb5\xfe\x00)\x82\xe6*b\x13'%\xf4[\xc90Vi\x900\f\xa5\x99\xb7U\x0f\xb6A\xe1\x81+I\xbe\xdc0,\u0448\xc4Y25t\u0552:K\xa2\x96\xc4YZY\x83\xb9\xb4\xc9|6D;\x8b\xe9d\x11\xed,\xa6\xed<\xf8g\xcex\x85Gx\xbd$\x1cL\xf5\x84\xf3\xa3\u0718\xb9t\xac\"\ub522\x82\xf2\xca\x112\xf5+\u0459\xc2B\x06\x13.\x80o\x0f\x87Z\x1d\xa6\xa9\x1fJ\x99\x1a\u0397z4\x01\x86\x87,:bI\xdb\xce\xfbT4(\xaas\x14\xba\x9d\x16\x99\x89\xb9\xe09\xff\x8e\xb81\u00ad\x9f{7\a\xf7n\xe3\x87\xdf\xfe\x12\xefz\xdb\f\x87\xfe\xeb\xefr\u077f\xb9\x8a\xa9\xc6\b\x92.\x90\xb9\xe3\xcf\xdc\xfe5\x03\xb9s\x8eN\xa7\uba55$\xa3\u0448i4\x1b\xfc\xf0\x87\x0f\xf1\xa1?\xfb\b_\xfc\xe2\x17I\x92.\xa7_p5W\xbe\xfc\xd7X\xbe\xf6,Z\xf3sE`H>0\xec\xe5\xbf\xf3hF\x9f\x16\x15\xd5b\x1a\xebB\x83\xf2\xfbT\x84\u0302\xb3\x105\x84x\xccb\x1af \xaf\x9e\u007f\x97\xab\xca\x19\xe9\x8dB+7\xcb\nc6\xa9\u020d\xf3\an\x053f\xbd\xc4u.C\x13\x87I\xfd\x02\x8es\x81\x8e\x14\x1f0\xddM\x13\u2265\xac9\xf3Bv<|\x1fY\x96\x95\x1d\x87\x88v:]\u067am\xdb\xe8\xd3\xf1\xfe\xfc\xd2/\xbd\xb9x\xb9\xde\xf6\xb6_K\xb7l\xd9$\xdf\xfc\xe6\xb7\xe2\x1bo\xfc\xac\x84%\x9e\x83\xc0\u00ea\xfa\xc9\xe9\xe9\x83c\xb7\xdcr\xeb\xe4\x9dw\xde%{\xf7\xee\xd5V\xab\x8ds\x8e\xf1\xf1Q\xb9\xe0\x82\v\xe5\xf2\u02df\xdd9\xff\xfc\v\x0f\x06\xea\x86\xf7\xbe\xf7\xf7\x00x\xd9\xcb^\x1a\xfd\xc6o\xfc\xba\xbb\xfa\xeak\u04b7\xbf\xfd\xb7\x9f\xfa\xb5\xf4T\xbe\xe9;\xdf\xf9\xf6\xea\xf7\xbc\xe7=\xdf\xfd\xfa\xd7o]\xdfj\xb5\x82\xbfGXo\n\v(\xcd\xe11\x9e\xf7s\xef\xe0\x82\xe7^O\xbb\xe5\xe9\x15c\x1cC\xa6\xcbx\xd4f2n1\x15\xcf3\x1e\xb7\x18\xb3\x1d\x9a&\xc5\x18_\x89\x1aQR1\x18\xeb\u0273\xcc\x18\xc4(F\x15\x9b\xf9\xe0X_X\x8a\aS\xa9\f^\xd4ar}uu\xa8\xaau\xa6\u064a\xab\x0f\x12\xf3!k\xc9\x0ec$\x0f}\xf6\x15\xba\xcd\xd70\x8b\xc8(\xadK\xb2\xd4oFV\x01\xbd\x9e}(\xc1\xb6\xd6\xf3\xf2\x8a\x1f\xe0v3K\xe2\":.\xa2\xed\x1a,\xa413\xe9\b\x87\x92Q\x8e$\u00f4\xb2\x06Y\x18\xe4\xaa\xfaX-\x11\x87\xad\xcc\x06t\xc0[YU\xee\xf7\xd6\xf4\xf9\xf3\x1a\x8a\rQ$\u0218\u016ci\u0090\xad\u0336\xf4(\x17J\xdd'\xa7\\\xf5\x0f\xfa \x11\xba\xad\x8c\u03be.\xe9B\xe6_\xd1\x04\xa4\xebB\x86\xa8?\x15\xa2\xb8\xc9Ps\x84\xed\x0f\xde\u02ad\x9f\u007f\x0f\xdb~\xe8#\xb2&W\x9c\xca/\\\xff\x1b\xbc\xe9\xba\xd7q\xe6\x86\t\u0439\x90\x1a#?A \xee/\x93$H\x0f\xfd\x8a\xbe\xf7$\a\xf8\xdf\xff\xfb\x16\xfe\xf4O?\xcc\x1dw\xdcA\xa39\u0139\x97\xbd\x8c\xcb^\xf4&\x16\xaf\xdaH{a\x864I\xcb\xf9\x8cJ\xb0G\xf6T_\xfe\x1e\xf8\u0160\xc8\xe7\xb7\u06a8\xef=T\xd5>\xabB\x17\x19\xd2\xd8+\xb8\x86'\"\x86\x975\xb09\xc52\xb0\x1b\xec\x8d%\xee'\xf7\xc2\xee>I\xbbE\x9a$a#\xdbk\xb6\x9d\xba\xc2\xd8G\x83\x8d\xb3.d\xb8\xd9\f\xd7\xf5\xd6\xd1Y\x9a\x87\x94\x85\x1fl-c\xcb\xc7\xd9\xf3\xd0W\xb9\xe9\x0f\xff3\xdd4\xa3\xd1h\xfa\x19M\x96\xb1x\xf1\x14\xe7\x9fw\xce?~\xe9\xef\xbf\xf4b\x80Gwlc\xfd\x86\x93\u007f,\xef\xe3\xddw\xdf)\x17\\p\xf1\x93.5>\xf8\xc1?\x91\v/<_\xaf\xb8\u2aa7\xed\xb1<\xe1\xca\xfc\x86\x1b>&\xd7_\xff\x8b\n\xf0\xb9\xcf}\xee?\xdfs\u03fd\xeb[\xadV\xb12\xae\x85\x1e\xd9\xe0\\\xc2I\u7f00\x93/x9I\xeah\xd2fj\xa8\xcd\xe2\xc6,K\x9b3LF-\x86l\x12\x86\x95.\x00k\xa9\xadQ#\x88U\xc4\xf8\xab\xd5\xe2\xbc;Cn\x8e\xdf\x13\u03e3\x02\x11\xce{P8oA\xa99\x8dS\xc4\xc7\xf5\xd8\xceV\xeb\x87\xf0W\x93[\u0245\x03B\xc2\u007f\x8bh\x1f4\xd6d\x81\x15\xfd\x9eV\xdd\xd2\\8\u07e8\xef\t\xe5\x81\u0222\x10\x89\xa3iRT\u06e1s\xf0|{\xa2\x1e\xd8\xe7\x92&3\xe90s\xe9\x10sY\x93\xb9\xb4I;k\xd0v1\x9d,&US\x1c\x80\xa6\x10\x97k\x11\x1a\xa1\x03\xd9K\x8a!T>\x84%QoY0\x94'\xa9K\xb1*\xcd1H\x1bz+\xf4\x9c2k\bQ\xd3\xe0:\x19i\nQ\xee@ \xe5\xe9\x99$\x1dP\xe5\xa4s\x9e\xcf\u02e6\x96s\xdb\xe7\xdf\xcb}\xdf\xfd\x1c\xd3{\xb7\xf0\x91?\xf8M\xb6\xfc\xf0>\xde\xfc\x1f~\x85\u02dfy6\xe3\xa3]\xa2(\xf5\xaf\u047f\xf2*]\x80,s\x85\x85m\xa7\xdbE\xc4099\u026e\u077b\xf9\xdc\xe7>\xcf'>\xf1)vl\xdb\xc6\u0112\x95\\z\xf5/p\xe1U\xbf@sd1\v\xb3Gp\x9a\x15\xf5o\xd9\fJmP\x98\x87q\x8b\x8d\x91\x82'\x1f !\xac\x8cR\xd4\b\xce\xfa\xfd\x83F\xc3\xd0\x18\xb3\u0626\xfch@N)f\x10c\xbc\xfcT\f\x98P\u03c7\xa7\xa2&l\x83\n\u0208/\b\x99\xf1\xdeDe&y\u0634\xce2\\\n\xe3+Nb\u046a\xb5\xec\u067e\x05\xd5\x06\x1a\xf6Ifff\x19\x19\x19=OU\x9f+\"\xb7\xed\u06ff\xff\xc7\x16r\xf5T\x80\x1c\xe0W\u007f\xf5mO\xfb\xe3yB`\xfe\x8ew\xbc\x9d\x1c\u023f\xf1\x8d[/|\xf7\xbb\xdf\xf3\xeb\xfb\x0f\x1c\xf0\xb8k\xad\x94\v\xbfB\x9a&,Zy:\x17_\xf5Z6,\x1fa4\xd9\u02b2\xb1y\x964f\x19\xb1\x1db\x93\x16tAUl/a\xffW\x83\x0e\xdaX-\x92uL\xa5as\x01\xd0\x05%B1\xeaC[\xadj\xa1V\x91Z\xb1\xec\xe5q`\u020aX\xaa\xd2\tP\x04\xacq~\x81\x06\x10\xe3j\x1b\xa5\xf5\x14\x94\x92{\xd7\xdeK\xba\a\xd9D\xf0{\xf0\xa6\xde\xd2JE>\xe6zt\x04&\x1cj\x16\xa1I\xc68m\x966\xfc\xefs\b\xa9\x8bh\xb9\x98\xf9\xb4\xc9L2\u0311d\x84\x83\xddQ\xa6\x93\x11f\xd2a\xba\xce\x06.\u0495@-=\x83\xd7\xea^Gx-\x9c\x06\xd7\xc5N\x99cU\x8clU\x06\xc8\u0434\xf4\xb3\xd1j\xd6G\xa9\u007f\x17\x03v\xc8`\xe6\x8dW\xa78\x17|B\xea`\x90\xa6]\x16\xe6\xa6Y\xb2\xfa\x19\xbc\xe8\xf5\u007f\xc8\u0112\xb5|\xff\x96\x8f\xd3i\xcd\xf1O_\xfc\b\x9b\x1f\xfa\x01\xaf\u007f\xfd\xaf\xf0\xaaW\xbc\x82\x8d\xa7\x8e\x11\xd9\x0e\xe0\x82g\u01bf\xcej\xbc\x9b\xa6t:\t\u076e7\xc3\x1a\x19\x1e%u)\xb7\xde\xf6\r>\xf5\xa9Os\xeb\u05ff\xce\xdc\xfc<\xabO>\x9b\x9f\xba\xf6\xdfs\xe6%/\x05c\x99_\x98\r\x87\xb4)\xfc{\xaa\U000196e0i\xd0u[\x1bC\u0413\xf7\x8f\xb4\xc3\x15]\xd9\x15r\xd6\a\x9a\x98Hh\x8cx\xae\\\xe4h\xbar\xa9\u02e6D\x06\xb6\xfcZQn\xe5v\xc99\xe5Y\xec^h\xe9\xcb+\xaa\x9e\xff\x1e\x01\xe3\xac\x1f\xce\xe7a(\xb9U\x84\x13\xba\xf3\x1d\xa2\xc6\x14K\u059d\u02ae-\x9bp\xea0j\x8a\x8e\xe3\xf1=\x8f\xa7\xb7|\xfd\x96\x04\u0ef7\xdfqB\f\u045f\x10\x98\xaf\\\xb9\xb2\xf8\xfb\x8d7\xfe\xcd\xff\xb8\xe7\xde\xfb\xe8\xb4\xdb\x18\x13\x891\xd6k=\xf1-N\xdc\x1c\xe6\xaa+\xae\u19df\xb9\x8e){?\xa3#s4M\xeaU&5\x11S\xd8N\xab,Gj\x0e\x80\xd6S\ty\xa5\xaa\x05\xf0\xf9*\xbdAF\xa4Y\xc1K\xe7\xa1\xce5hT\u03e7;\xf1\xc6R\xb9g\x9b\xa0\x18\xeb)\x1fc\xb4\xcf\x1d\xdfU\x00\\\x06\xd0\f2\x803\xa4F\xd8\xf4\xaf\xcfk\xb5\x1f\xc8}\xb0r\xbe>\x1f\xd4\xf6\x82l\xe0\xfb%\f\x1a\xad8\x1a\x921\x12uX\x1c\u03e1\u00de\xa2ie1G\x92\x11\x0et\xc69\xd4\x1d\xe5p2\xcaL2\u0302k\x92\xfa\x8d$\xff3\xf2\xdf]\t\xf3\xcc\xfd\xd4s\xcb\x01M\xfc\xf2\x86D\xd5\v\xa3W-S\xbe\x83Z\x1b\x8c\xf6v,\x826\xbdf]\xbb>\xcb\u0569\xab\xf8h\x97\xff\x9fe)\vsG\x18\x1a[\xc6U\xaf\xfc\u007fX\xb1\xfe\\\xbe\xfb\xe5?a\xcf\xf6{\xd9\xfa\xd0\x1d\xfc\xbf\xefy\x98\x1f\xdc\xf9\x1d\xae{\u00db\xb8\xe2\xd9\xe735\tQ\xdc\xc5e\u067f\x1aP/\xd4*\xdd\xc4\aF8%\x8ab\xe2\x86a\u04e6M|\xfe\xf3_\u099bnb\xeb\x96\xcd4\x1aM\u03be\xe8\x1a\x9e\xf9\xa2_d\xf5)\x97\xd0I\xbat\xdb\v!\u4efa8\x96'?yE\x94\xe6\xaa\x151\x9e\xfa\xb4qE\xef]\x16'\x94S\xa2R\x8d\x12xr\f4\x86\f\xf1D\xe4\xe7'z\xac\x81{\x8f4\xaa\xe7_\xb4RIh\uf234\x92\xf9\xe9\xfa\x0e\b\xdf6\x9aQ\xeb\xbfo&-\xae\xad\x00\xd7d\x9d.\xcd\xc6\x18\xe3\x8b\xd7x\u05be\x90\x05B\x96e\xb4;\xed\xc9\xfb\xee\xb9g)\xc0\xc2\xfc\xfc\t\x11?\xfb\x84\xc0\xfc-o\xf9e\x00>\xf5\xa9\x1b\x9e\xfd\x81\x0f\xfc\u0275\xd3G\x8e\x14Uy\u0357A3\xce\u06b8\x91\u05ff\xe8RN\x9f\xd8K\xb7\xbd\x00\xa2\x85\xf6\x1b\xb4\x00\xe5\xfc\xe22\x81\u05b0\xe2.\x979Cwa*\xdby\xf9\x9c2\x1f\xd4\x16^'Z?-\x02m\xa4\xd4Z\x00\xac8\u01a3\x0e\x13Q\x9b\xb5\u00c7\u9e88\u0664\xc9t2\xc2\xc1d\x9c\xc3\xc9(\xd3\xc90\u04e9\xe7\xddS5\x98bh\xac^d\x92{\xe78\xc5%\x0e\xd7\xcdhD\xb6\xbc\xf1e\xf0-\x9c\x1bj\u55a6\xd5\n>\xb7\xa0qF\xc8b?0\xd5pP\x9az\xc0^e\x96\xa1\xb4\x17f\xb0\x8d\x06\xe7\\\xf1\x1a\x96o8\x9b\xef}\xf5\xc3<\xf0\xdd/\xd0^8\xc2\u035f\xff0\x0f>p\a?\xfd\u04ef\xe5U\xaf\xfc\xb7<\xe3\xec5L\x8cCd\x13\xd24)d\x8c\xff'\x02{1\xe4\xec\xa6d\x99\xa3\xd1h\x80\b\xbbw\xed\xe6K\xff\xf0e\xfe\xee\xef\xfe\x8e\xbb\u007f\xf0\x03\x92\xa4\u02d2\xe5k9\u7c97s\ue56fat\xf1:\xe6\x17\xe6H\xb3^gQ-=u\xb4\xea\xc1\x13\xb6\vm\xe4\xf5\xe4\x95\xd9F\xff\x9et\xa5\xbf\x14p\xd6x)b$4\xc6\"\xec\xb0=\x06\xbdBeVt\xb4\xc9\xdb\xd1.\x9c:\xfc\xe7y\xb9\xb9\xec\xd5I\xe9\x0e\x8a\x11\u0730A[\x02]\x17\x16\x87$\u0200S\";\xc5\xf8\xc4j\xaf3\x0f[\x98\xde\xee \u0262\xc8N\xce\xce\xcd]\x04\xdct\xe8\u0421\x13b\x15\xed\xb8`\xfe\xe8\xa3[e\xfd\xfaSTU\u01ef\xbf\xfe\xba\xdf\u06f1\xe3\u0471N\xa7\x83\xb1\x91\xe4\u0546\x15%IS\xc6\xc6\xc6\xf87/\xb8\x8asNZL\xb7;\x1f\xb8\xdc|PG\x9f\xc9S\xfe\x9e[\x93\xf9ac\x14\xacV\xd5W\xe5\xa2\x10k\x86\xa8\xd2$\xf5\x03H\xadT\xf6\xf4.\xd6\xe4K:e\xb5\xab\x95\u0163\xd4\x18\x1f\xcc\n\xc1Y\xd9W\xfa&\x1c2B\xa9\x98\xf5\xa0W\x17ZQY\u0411ZUr\x94J]\x06\xb2\x1b>\xb1\ajUj\xde=\xa3G\xd1\r\u0200\x9bD\xa9t-B\u04e44\x9b\tK\x9a\xf3\xacs\x87ie1sY\x93\xc3\xc9\x18\xfb:\x13\xec\xedLp\xb8;B'\x8b\x83\n\xcd\x0f\x9fr\x1c\xeev\x1c\xdar4\x86\xad\x9fW\x1c\xe5\xa8R\xf2\u03ae-w\xb1\xf9\xe1\xbb\xf8\x93-\xf7\xf3\x8d\u06fe\xc4+^\xfe:^\xfc\xe2\x97p\xc6\xe9+\x19\x1f\x8f\x81 }\r-\xf9\xff)\x1a\xf5\x1c\xc8U\x85F\xa3I7\xe9\xb2o\xdf\x01n\xbd\xf56>\xfb7\x9f\u5bbb\xee\xe4\xf0\xa1\x03\x8cM,\xe6\x94s.\xe7\xfc+_\xc3\xda3\x9f\rv\x88\xd9\xd9#%h\x86*E\\X\xe8\x91\xea\xec#\f\xf9\xc5`L\x8c\xb1q\t\xfeG\xad\xa9+\n\x94\xbc*\x0f\x16\xb7v\xd4\x06\xa7\u0363T\xe5\xc7RR\x95\u00e9Z\xdbVv\xa6%}Z\xfdr\xcde\xc5Z\xce{2\xf5\xb4+\r\x03\xad\xb0\xf2\x9f/\xe08\x05\xb5\x8cN\xae`dl\u048b,\xac\xb7\xad\xb5\xc6\xea\xbe}\xfb\u067d{\xd7Ya\x89'{\xfc\xf1\x9d\xb2r\xe5\u069f\xe8\xea\xfc\xb8\xe1\x14\x87\x0e\x1d\x92{\uee57ukW\xbf\xf5+_\xf9\xc77m\u0672\x05D4\x8a\xe2B\xfb\xe1\u0375\x84k.\xbf\x8c\xb7\xbc\u654c\fY\u04b4\x8b1\x1a\\XC\n\x8f)\xe5\u007f\x0e\xc1\x18%6\x19\xd6(\x1aU\xd4T~\u007f@\x11\xa9\x01\nEt\x9e\x11e\xd4v\x18\xb1\x1dV4f8i\xe4\x00\xfb:\x13\xeciO\xf1x2\xc9\x117BK#T-MBu4 \x06(\u007f\\\xf9AX\x030\xf17g\xea`\xbe\xeb\x98K\x1c\x99z\xb32\x97o\xf0U\xed\x84+s\x93j\xadX0\xbb\xaat\x17\xe6\u0212\x06\xa3S\xeb\xb8\xfc\xe5\xbf\u0269\xe7]\xcd}\xdf\xfe,\x9b\xee\xfa*\xfbwm\xe2\aw\xde\xc2=w\u007f\x9b\x9bnz&\u03fd\xea%\\\xfa\xcc\xcb9\xed\xb4SY\xbf~\x19\x13c\x06c\xbb\x88\xa4\x15J@~L\x00^\x1a.\x19c\x18\x1a\x1a\x06,Y\x96\xb0\xe3\xb1\u01f8\xf7\x9e\xfb\xf9\xd6?\u007f\x87[o\xfb\x06[6oaf\xe60\xd6X\xd6m\xbc\x80\x8d\xe7^\xc9i\x97\xbc\x94\u0255\xa7\x93e\x8eVk\xde\a\xaaH\x91A\x86:\xa9\f7)\xe8\x95\"\xcd&O\f\n\x15y\xfd\xaa\xae+\xb1*\x11.\xbe\x832!\xe3\xd5\bi\x03h\n\xc3F\x8e\xbe\x96\xa6u\xb6\xbd\xa0\xe3BA\x93\xef\u007f(up\xef\xe3\r{7P\xb5\xfc.\r\xee\xa5\xdd\f:\xed\f\xd7J\x91\xd4\xfb\xf6D\x95\x94\xaf\xa4\xdbab\xd1*\x16\xafX\u03ceG\xeeF\x1b\xc38\x1cVD:\x9d\x0es\xf3\xf3g\xddx\xe3gO\x03\xee\u0773\xe7q\v?\xd9.\x11G\x05\xf3\xbb\xbe\xf7\x1d\xce?\u03db\xa0\xbf\xff}\u007f\xf4s\x0f=\xf4\xf0%\xd3G\xa6\xb1\x91\xb5\xd6V\xc7\x16\x8a5\xc2\xf3\x9eu1\x97\x9c{&I\x96\x90\xe2\u021a\x96\xc8xm\xb6\x84\x05\x1d\u07d3\xfbIvL\x1alUC\x85\x1b<\xbf\xab\xc0j\x8e\x9aI_\xb7\xe9\xf4\xd5x/\x05Q\xfaN\xf8'\x9aa\xaa\xd5v\x0f`\x0f\xfa|\xfd'j\xcd8_+\u0740\x1c\x85)\xd4c3\x88\xc7\xe9\xcfC\x84\x9b\x96R\xc1\xa2\a\x19\x14\x84\x9a\x83\xb7\xeb}\xd4\xf5\xd7+2)K\xe3Y\x16\xc7sl\x189\xc8\xe1t\x84=\xdd)v&\x8b8d\xa7\x10\x1d#u\x06\x1bUm\x05J\xb8uZ\x06S\xf7V\xa4\xdd\f\u6e8e\x85\u0115C\u047cC\xa2\xb6@\xd838\xa5\xb7\xe7.Z\x98,Ih\xa5G\x88\xa2\x06\xcb\xd7_\xc4\v6\x9c\u03f9\x97\xbf\x92\a\xef\xf8{\xb6\xdc\xfbuvm\xbd\x87{~\xf0M\xee\xf9\xc1wX\xb5\xfa$\u03bf\xf0r\xce;\xf7\x12\xce:\xf3,\xce:\xfbTN9e5##\x16#)\u05b8\xe0_\xdf;\xfdx\xe2CT\xe9y\u074d\x91\x90\x16\x1f\x85\u7532c\xc7c<\xf4\xf0#\xdcs\u03fd\xdc~\xc7\x1d|\xf7\xbbwp\xe0\xc0\x01\u04b4K\xdc\x18b\u0769\x17p\u0499?\xc5\x19\x17\xbe\x80\xa5\xeb\xcf!q\x86v\xbbE\x16\xf4\u05e5o\x8f\x94iV\xb9@\xc0\x14\xe1o\x14f\xc8&p\xe4b*Wf=.\xb1\x8f\xeeSBU.>\f\xdcB:li\xc6&\x80\x82\u053f\xa3G~:\x88:\xaf\u0280k\x15y\xf86c,N\xd2\xda04\xf7W\xd7\xca\xf6j\u6105\xaec\xae\xe3H\xda\x19\xcd\xc4\xd1\u0410tU\x19\u00a7i\u00a2\xa9\xa5,]\xb1\xbev\xb5\x87\x82\xdf\x1d>|\xc8l\u07fe\xfd,\x80\xb7\xbf\xfd\xb7\u007f\xe2w\x89\x8f\n\xe6\xf7\xdds\x8fg\xe9TW\xbe\xeeu\xbf\xf0\x86M\x0fo\xf2\a\xb9\x11\xbf\xb6\x1f\x02bS\xa7\x9c\xba~-/\xbf\xf6y\x8c\x8e\x8f0\xdf\xed\xfaTxc0\xa4Xu\x1e\xc8\xc9\x17\x19\x94H\x9d\xaf\xbe\xc3\xe2\x8f8\u05e3 \x19D\xcaI\xed\xfa*+\xf0\xc1\x15pu\xa2.(1Ye\xff\x91\x01\xb6\x9f\xfd\x9f\x91~8,\xe0\xfb\xa9\x9a\xb5>\xe9\xe6_\xeaC&=\xc6\xd7iX\xcb\x14W\xef\x12\xea\xc9Ee\x18\u0148m3\x1auX\u079c\xe1T\xb7\x97\x83,\xe2\x80]\xc6\xfet\x193\xf1\x04\xa9D\xde/#\xf0\x94N\x198Ps\xaa\xb4S\xc7\\W\xe9dZ?g\x8c\xa0qE\x02\xa7\xfd\xd4XM\u03a95c\x91B\xf5\x9a&]\xb2,\xc1\u0688\x95'\xff\x14\xabO\xbe\x84\xf3\x9e\xfdsl}\xe0\x9bl\xbe\xfbk<\xb6\xf9\xfb\xec\u067d\x99=\xbb7\xf3\xb5\xaf\xfe\rk\u05de\xca\xc6\xd3\xce\u1b33\xce\xe3\xb4\xd3O\xe3\xb4\xd3N\xe5\xe4\x93\u05b1b\xf9$\xe3c\x11qD!\xe9)\xaaU\xc9\x13e\xfay\xef\xf29\x19\xeaf\xa3\x8e\x03\a\x0e\xb0e\xcbV\x1e~x\x13\x0f\xfe\xf0!\x1ex\xf0\x87\xdc{\xef\xfd\xec\u07bd\x8b,\u02c8\xacedl\x82U'\x9d\xcb\xfa\xd3/c\xdd\xc6KY\xbc\xeat\xc4\xc6,\xccuH\xb3\xcc\x1fzZ\xd3y\x96\x9d\x9b\x04\xaf\xe1\xab\xba|o\xa1\xd7\xee!7d\xab\xf8{\x9b\x9e\xd3Z\xfcp\xccW\x02N\xea\x93\xd0\u028f\xcaTi%\x8e\xd9VF\xe2\xbcL7\xf76\xd7\xfc\x1a\xcf\xd4o\x8a\x8a\"&f\xf1\u04b5\x8c\x8c\x8c\x91d)Q\x14\xf99\x9e\xb5\xb2g\xcf\xe3\xcc\xcf\xcf]\xa4\xaa\x93\"2}B\x82\xf9\xe6\a\xefd\xe3\xd9^\f\xffG\u007f\xf0{/\u007f\xf0\xfe\a.\x99\x9b\x9f\xc7\x18cLem\x1f\x81\xd8Z^\xf2\xfc+9\xfb\xec\xd3h\xa7]2\vj\fq\x90\x0fVR\x12|\xc6e\x05\xc8sS)\xe9\xc9\xc3\xe9\xa3\"jU\xb8\x1c\x15\t\xb5oPW\xd5>k\x1f\x84\xf4\xd6\u294b\x9c\x1es\u03a3\x95Fq\x90\x19m/\xe4\x1d\xebsOk\xe3_\xf0\xa9Z\x13\xc4\x14\x80\xdes\xf3\xe4\xaf|$\x8e\xa9x\x81)\xd3f\x9d\x1cb:y\x9c\xddf9\xbb\xa3\xe5\x1c1\x93$\xc4\xc1\xa3\xd9U\xba%\x0fz\x9dLYH\xfd\r\x98\xb8\xf2F\xae\xfe*'\x12\u031b\U0008391e\xd4R\x02\x98\xf6(\x93\xa4^\x14:%u\t\xe9\xcc462,]s6K\u05dc\xc5i\xe7_\xc3\xe3\x8f\xde\xc7\xceG\xfe\x85\xc7\x1e\xbe\x83\x03\x8foe\xe7\xceG\u0631\xfd\x01n\xfb\xfa\x17X\xb2l\x15\xabVm`\xf5\xeau\xacY\xb3\x9aSN\xde\xc0\xa9\x1b\u05f3j\xd5r\x96-]\xc6\xc4\xe4\x14C\xcd!\xe2\xc8\xd2lZ\x1a\x8d\xa8\x06\u058a\xd2\xedt\x99\x9d\x9d\xe5\xe0\xa1C\xec\xdf\u007f\x80\u077bw\xb3}\xdb\x0ev\xec\xd8\u03ae\xdd{\u063a4\xa7\n\x00\x00 \x00IDAT\xbe}\a;v<\u0291\xc3\a\x01\x88\x1bC\f\r\x8f0\xb9d5kO\xbf\x84u\x1b/e\xf9\u06b3\x18_\xb4\x864\x83v\xbb\x85s\xed\xf2\xc2\xcez{\xa0\xb0OQ\x84/\u7b85\x06\xa3>\xecA\x8c\xc5`\a\\Ez\x9c^\xd1'e\x15Uy\xc3\u0418\x88\x19i\x1a\x1a\x86b~Q\xab\xf0\x85\xbay\u0500\x8a\x9c\xaa\xc1\x9dT\xa6\xdc9\xa0\x1b\x1f%\xa9d\x15)n\u0391\xfb\xfflg0\x9fx\xa5U\x1e\xfc,\x15\xea\xd0\x05\xff\xfc\\\xff\x9e\xa4)K\x96\xaebjj)\xbb\xf7\xee&\x8a\xe2B\xf2\xdciw\xd8\xf9\u062eE\x0f\xb5\x8a\u0265\xeb9\xe9\xcc\u02d9\xbdb7\x87\x1e\xdf\u009em\xf7\xb0{\xfb=\x1c\u07bb\x8d\xb9\xf9i\xee\xbf\xffv\xee\xf9\xc17\x111\x8c\x8eN2\xb5h1\x93\x93\x13L\x8cO2>1\xc5\xc8\xc8\x18CCC\f\x0f7\x19\x1e\x8ei\u013e%hw\xba\xb4[m\xe6\x17\x16\x98\x99\x99\xe6\xf0\xe1ifff8r\xf80\a\x0f\x1c$I;\xa1\x03\x89\x19\x19\x1bg\xe9\xea\rL,Y\u0272\x93\xceb\xd5)\xe7\xb3x\u0169LL\xacfhh\x8a4I\x99_\x98\xf7^#b\xe8[\xe6\xd1r\x10\x9e\xf3\xc2B\x1e}\xe8kT\xa3\x12\x92\x82\x82\xb7\xbd\x1bTvT\x87\x90\xd2s\x9d\x86n\xcaz\x19\xb0\xb3\x06;\x161X\xd89\xad\x9d\xb5\x03;\x19)\xa3O\xeb\x83\xc5\xcb\xd6\u04b0c\x183\x02\xa9\x90\u0336\x98\x999\x12\xb6\x1eM\xbd\tQ_\xfbK\xd1\u0494\x85\x8c\xe4\xe1\xaa\xc1,\xcb\xe2o\f\ttK\r1u\x90\xba\x8b~\xff\x15\xbc\x141\vC\xcfh\xc4\u041c\x88\x88\xad\x10\x99\x90\xe5J\x9f\xfbN%\x01\xb1'\xc36\xbf7\xf2\x9c\xdf\xda\x1c\xaaz\xb5W\x12w\x8cx\x0f\x19-\xfdvT\x95N\xeaH3\xafV\xc9[\x15\x13\xd4m\u04ab\xce\t\x85\xa1K\x1c\xcd\xc6\x18\xf1\xd0\b\xe41\x95\xe1\tdiF\x96ef\u07fe}\x8b9\x01\xfe\xf4\x81\xf9G>\xfc\xa7\xf2\xe6\xb7\xfc\x8a\xaaj\xf3-\xff\xe1\x8d\xffq\xeb\xb6G\x01\xb0\u0592+X\xac1t\xbb\t\x17^\xf4\f\xaey\u03a5\x18\x11:\xce\x12\x19\xa1\x11\xf4\xe0y\x80\xb1uZ;\xb2{\x17_T\xca1e1\xc8|\x92 \x9e\xff=\xc3\xd0\xc1\x1b\xdeG\xb8\x02\xa0\xb5OR\xe5\a\xb3\xb6\x10\xc3y_\x13\xd3\xf3\x95\xda\xc3<\xf6\x91%\xa1\xa2w\b]\xe2`1\x90\xd5\x06\xb7\xdeU\xc6\x06=\xbb\x1b \xab\xa4\u03d6T)Ez\x83\x8e<\x8e\xf3\xb9~0\x95\xb0*->\x86\xab\xfao\x96\xc2\xc9N\x8d\x9fi\x94\u06f4J\xa4\tK\xdda&\xb3Y\xd6\xcbn\xb6\xb2\x8c\xfb\xb2\x95<\xea\xa6\xe8h\x03+\xfe9\x17G\x9f\xd4+\xcd\x1c\xc4]8\xefr\x83\xaf\x1c\x99\xb52\xf8\x10\xad\xce?\xfdB\x99\u04de\xbc\x8c\x9e'\x9dyS\x11\xefS\x9fet\x16\xe6\xc0\x18\xa2x\x98\xf1\xc9q\u01a6V\xb3b\xc3\x05\xa0\t.Kh\xcf\x1fa\xe6\xe0.f\x0f\xef\xa55\u007f\x88\x85\xb9\xc3,\xcc\x1e\xa6\u04de'\xe9\xb6H\xba\x9d`\xd5\xec\x13\xb2\xc4\x1aL#\"j6i\f\x8d0<1\xc5\xc8\xe2e\x8c,Z\xc2\xd8\xe2%L.[\xc5\xf8\x92\x15\xc4\u00e3\xa8X$\x8a0\b\xe9L\x87\xee\x91\x16\xddVB\x9af%\u0329+\x02\u0335\xb7\v5R\xef\xf5\x82<\u0408\u0146\x94)\x0ft\xe1\xea\xecuZ\u8ece\xa4\xcfD_E\xc8bCf\r\u0450\xa1\xb9(&j\n6\xa75\xa8[\xd9\xf6\xa1\xb9\xd6\xff.}\x95\xbfV\x92\x8d\x06\\\x9ba\x05Z\xabn\xbd\b]\a\xad\xb44\xb6\u00c8\xb7\x98\u02028\"\xffy\xc1\x8c&\x97j\xaa\u02c8\x1ac\u010d\xd1zL\x1b\xbe\xf8\u073b\xf7q\xee\xbf\xff\xbe\xe4\x84\x04\xf37\xbf\xe5W\x14\xe0\xbd\xef~\xe7\xd9\u07fd\xe3{g/\xb4Z\x1e\xccM\t-\xce)\xe3c#<\xff\x8aK\u0670~-\xfb\xe7\x12\x8c14Ih\x90\x16~)\xb5\xe4\x13\xd5\xfa\u025a\v\xb2\xf3\x05\b\xe9+\x04\x8e\tR\xdaC\xa5\xa4\x18\xba\x1a\xd1\x15KLV,\x03U\u056b\xd6\xd7@\b\x10\x91\xfa\xea\xbdpI\xac\xfb\x0f\xea\x00~{\xf0c\xf2\xdfms\x97\xa0\xa2\xa1\x84|\xe3\xd5\xd4l\xbd$\xac\xda\x1c\x9bb\xe9\r\x0e\xd0\x01\xdc\xfc\x13\x16\xdb\xe5\xb3\x06\x13\xd2\xd2+\u06e7\xb9'Mi;\xa0\xb5\xda\u0285\x1e\xcbi\xc6X6\xcb9\u0332\x81\xddl\x91\xe5\xfcPV\xf3\x98.f\x8e!\x9f\xfc\xa4Y9\xbb\xec\rL\x92j\x958\xe0Y\xea`2\xab\x8c\x9c\xd4\x1e\x85F\xf8y\xe1\u07camT\u007f\x81\x92t\xdat\xdb\xfe\xf7Yk\xbdEj\x1c3\xbax\x94\xd1EkX\x1dN\a\t\x8f\xcb9\xc5e)Y\xda%s\xa9/\x88\u0160V\x90\xe1\x88hx\x88\xa8a!\xb6d\xc6'*EQ\xa9\xc5vY\x86f\x19Y\xda&I3\x9cq\u0210b3AS!u\x8afZ\fX=X\a\xf0\n\x87h\xe9l,\x15P\xb3X\x13\x87\xcc\xce*\xb0J\x9f\xda\xe8h\u05d4V\xba\x1cg\x84\xcc\nQShN\xc5D#\x16#\x14`\x9eW\u0245+\xa8\xf6\xf0\xe3U\xfd~\xcf$\\z\x93+zd\x04B\x99PU}/3\xf5@\x9e\vy\\\x00s#\x82\xc9*\u0770\n5\a\x8e\xd0\xf1;bT\"\u007f\x8dT\x8bG\x81\xf9\xf9y\xf6\xed\xdb\xcf\t\a\xe6\x9f\xfa\xd4'y\xc3\x1b\xae\x03`\xdf\xfeCo\u07f9k\x0f\x99sXk\xc3p#7\xd3J9\xf7\u0333\xb8\xe6\x8aK\xe8\xa6\xfev\x1f\r@nU}U^\xbb\x93\xfbU)\x1a\x8c\xf0\x9d\x19\xdc\xdc\x1e\xab\x12\xad\x02\x9c\v@\x9e\xe1}\x1c\"\xf5qryU<\b`\a\xc1q\x17S9\x00\\52\xf9\xa8\xdd@\xfe\x15&\xa8eJ\xbe\xbc\x94n\xda\xf0Y\xa5\xee\x8dq\xac\x01\u0560\xdf*\xa1\xf3\xc8B\x0f!\xc1\xa3f\xb0\xf9\xed\x80?\x86P\x05k\x1f\x87Z\x85J-8o_5\xbb\xa0\xf9\xd5J\x8b=)m.\xe6QNc/[X\xce&V\xb2C\x970-\xc3\x18\xbcZ\xa96\u0516\xea{\x96k\u0635\xae\x8d\xcf\x1f\x912\x80n\xa1\xd8\x1bp\x85\x9e\u065fD\xe2\xfc\x01\xed\r\xd5\xf2MBW\xbe\x8eNq\x9a\xe0\\\x82K\xc2s\x0e\x89\xee\xd6HI\xbd\t~\xf1&\x1e\xf6[\u00a2\xb8,|}*\xe8\x02tZ\t4\x12\x88\xc0\x841o\xea\x1c\xear%\x87\x16^1j\x05F-\x91\xf5\x1d\x86\x11p]G\x9a\xfa\x9f\xab\xf9i*ZZ4Ky\xb5J\x11\xb5fJ\x1f\xf2Z\xf4\x9f\x1eC\u07a4\x03\x8a\x1e\xff\xebR\v\xb6!4\xc6-f\xcc\xebD\x82\x1d\x12=\xfbp\xa5\xc3\xf31\xab+\xad_\xd7rl\u05af\xa6p\x14A\x9d\x1f\xa2w\xb3\u04b7\u0204=\nu`\\\t\xfe\xf9\x82b!\xcc\x14\x83:o\xbcU\xdd\xf8-\xe7EB\x969\x92$=\xf1\xc0<\a\xf2n\xb7\xb5\xf2\x85/|\xd1U\v\v\v\x9e\xc26\"\xa5\xb63crb\x8c\xe7_y)\xeb\u05eeb\xba\xd5a\x98\x94\u0607\xa4\x15Ugq\xba\x17\xc5q\xb8\tM~sW\xe4jO`\x188\xc8\xcaU+cF!\u00c8\x90\x15\xd3\xfdrE\xc2\xf4\xd4\a\xf9\x1a\xba\xf6\x1aF\r\xf0_9\xba\u0250\xf4\x18\x87U\xb74\xb5\xa7&\xa9\xd7\xd7R\xfb}G;&\x06\xcf\x04<\xa5\xe3\x87a\x16\r\x1d\xc1\x13\x1c\x9e\xf6\xe53\xd6o\x00\x97?\xa2\xf0\xc68u=L\xb2G\xda|\xc0;N\x87\v\xe41Nc\x1f\x8f\xcab6\xebr\xb6\xb1\x8c\x83\x8c\u1430\xb5\xab\xc5T\xa0\\t:\u01aax\xcd\u0295\x92N\b\ufa69\xe4\xa9J\xde\xd9i\xd9z\xbbJ&i^i\xbaj>\xa67\xf6\xf0\xfbiR/2\x8b\xdf\x19\xac\x94]\xde\xdew\x02\xfdg\x05\xed(f\u0220\x8d\x88,\xb6%\x90\xe7\x86i\xb9\xd41\u007fZC\x06\x91\x88H|\xe1\"\x89\xa0]G\x96iPrI)I\fT\x8b\x02V\xbc$\u03c6\xf7z\xe0\xcaE\x0f\xf8\xd6\x05\x05\xfd.Bi\bgn\x8cZ\xcch\x14\xf6;\x14c\xfd\xe1\xe1(3l\xa5\x17\x82\aJ\xcc\xfa\x03(\x8ev\xe7\x94~\xa3\xf5qY\xa6\xd0I=\xfdc\xaa\xc3U\xc1W\xe5\x15*\xa7W\xb5\x9c?\xc6j\u982a\xb5\xd7 \xcb2\xba\xdd\u0389\x05\xe6_\xfb\xdaWy\xc1\v\xae\x05\xe0\x03\x1f\xf8\x93\x9f\u06fcy\xcbD\xab\xdd\xc6Z#\xa5\x1cQ\u025c\xe3\u0513\xd6p\xcd\x15\x97x\xbe\xca%\x05\xdf\\\xb1\xaa\xa6w\x9b\xba\xba\xf4p\xd4\xd3Z\xfb\xa9\x96\xa3\xa1\x92\x14f\\\x8a\xadU\aYm\x01Hj\xff&\x94A\xf5R\x8c-%\xf0\xe7\x1c\x0fd\x8eR\xf5T\x0f\n\x83\x1bx\xf0\xc8\xc0q\xef\x13\u05ea\xfb\x0e\xc0\xd1\b\x9d@\xb9\xb2e\xca\x03\xf4GT\xc3\x14\xac\xc51\xd46\xd5\xe5\xa9\xfc&\x1a\xa1\xcbY\xec\xe6$9\xc0>&\xd8\xc626\xb1\x82\xdd:EBDD\x86\x13Wn/\xf6\r\x97{\xdfs\xad\xad\xc5he\xde\"aP\x9aW\xebN\r\xc6e\x85iZ\xd1\f\xaa\x92U\xf0E2-\xbeW\xaby\xabT6X\x1d\xe5\x82VX\x1d\xaf\xea\xe3\x9d\xf3\x9f\x88\x1a\x82f\x12\x12\x90\xca\x1fT|\xbd\xd6\xdfmi\b:i\xb1\r\xc1\xb4\x14\x8d\x1cY'C\xb3\xde!q(\xe1\xadE\xd5\xfa\u047d5\x85\x84\xb3\xda9\xf5]\x1c\x85LE\xfa.YU\xbc\xb5\xed\x90!\x1e\x8f0\xe3\x11&\xf2\a\\^\xfa\xb8^)kM\xf6$\xf4\xa6Ni/\xf1%\xbdc\xd3\xd2\ufa38\xb6D+\xc0\xeb?:\x99zI\xab\x8a\x1f\xc2W\xc0>\xe7\xcb{'W*\x82q\x14IK\xfe\xec\x1d@A\x1a\xc19\xf5A\x1e'\x12\x98\xe7@\x0ep\xf7\xddw\xbf@w=u\xfe\x8f\xcf\xe1S\x8e\t\xea\x9e\xffw\xc1\xad\xa9!)'q\x805r\x98\xb3\xd8\xcdfV\xf0CV\xb1\x87I\xbab\xc1@S\xd2\u00b7\x9d\x819IZToZM\xf2\x93\xbaJ\xdf \x181\x1e\x8d4D\t\x86.E\xb5b\xbd\xaa\xe5 Zz\xd0H\xa4N\x03i1\xa9\xf5\xc3\xe2\xda\x01\x13\x02ql\xe4\xaf!\x97\xa9\xa7\x00l.\xbf\u0492\xcf\x12WZ\xb4\u57cf\f\x8c\xfa\xb9E,\x8aSC')\xb70\xfc\xf4\u0440\xf5\xb4J\xbe0=h\x06Y\xbamV\x1e\x9f\xe4\x8b5\x15\\\x95\x12\xdf\u0350\x10OX\xccT\x04\xc1#\xdf\x1a_\r\xbbL\xc3\xfc@\n\xb37=j\x9aEO)S\xbc\x9cR(\u0574\x06\xe8\x15\xe1\x83+\xfd\xcd\xf3\x85\xc3v\xea\x818\u03fa\xcd\v4\u3d28\xcc\xcb\x01\xb9T\xde3\u03df#~\x86\xe7\xdc\x13\x13J\x9cP\x03\u043d{w\xaf\xbb\xe6\x9a\x17\x9e|\xf0\xe0!O\xb1\x88H^\x95\xbb\u0331~\xfdj^\xf2\xbcg\u04b0\x86\xb9N\xb7\x06\xe4\xbdn\x88G\x83\xab'\x10K|||\xaf-\t\xd6o\xd5^H5}U\u07e0){\xce\xc3\x1e\x8dq<\xca\x05\"\xe5\xf0\xae\x94n\x1d\xfd\xfb\xe4\x18\xc7\u00d3;\xef\xb4\xe6\xb5\xf1\xe3\x02\xf2\xe3\x01:\xa1S(\x80\x03\xbf0\xb6\x86#,\x939\xced7\xdb\xec2\x1e\x8eW\xb2?\x9d IlH+\xcfz\x16e\xfa_#Wl\x83j\x9d&\ntJ\xae\xc216\xf6\xab\xe2\xaeLF\xf7\x9c\xbf\xab\r\u07b5\x8aR=\xd9\u01c5\t\\@\xedb\xd2R\xb1\x18\xf0\u0671\xa6\xb4X\x90\xd2\x18>7\x8e\xd2\xde\"\"\xb7f%$h\x8d\b\u0608\x86q\xd0vtSj\x9d\xa3*H\xe6\x02p\x95\xa7\x99\f\xaa\x9b\xfb\xf60*:\xfe\xd0\x01;\x01\xd304\xa6\"\u0322\x18m\x94\x12!U\x0f\xa8\x05\u0154SX\"\xd8 U\xad\xf2\xe5\xf9 \xba\x06\xd0E\xaeD\xa9\xae\xa9\x96Py\xc5o\xf2\xb9G\xe8\x96R\xa0\x9d:\x12\xa7\xc5<$\xa7]\x14\xc1\xa6\x0e\xeb\xf2\x83\xd8o5\x9b\xe0GcB\xf9\xae\x94[\x1cZ\x9f\x0e\xf4w\xfc'\n\x98\xdfy\xe7\xf7\xb8\xf8\xe2K\x01\xf8\xf4\xa7\xff\xd7\xcb\xe6\xe7\xe7\u05e5i\x8a\x91\"\xaf\x06uJ\x14E\\\xfc\x8c\xd3\u0638a\rY\x96\xf9\xb0\x01\xaaaaz\\\x84>\x9a\xdb\u02a0RU\x9e \xd8\xf4%\x81\x0fPz\xc8q`\xb3\x1aKE/\x1f\x9fK\xf7\xd0J\xa8CUc\xab\xc1\x97\x9dB\xae\xd5ov4\xb8B\u007f\xd2M\xc9q\xe6\n\xfa4\xfc\xcc'W\xa1SL\xcb\xf2\xae\xc7\xf9\t\x06\x06\xc7R\xe6Xd\xe69ed\x1f[\xcdr\xb6\xe8\n\xf6\xbbq\xda.\xc6\xc7g\xb8\xa3\xf4?A\xf7\xa3e\x17&Z\xe5\xfd\xb5R\xd6z\xf9\x9eD\x06\xa31\xaa.|(\xea\xb2|\xc70\xd0$\x01\xb0\xabUs1q\xd5\u06ba\x8d\xa1\n\xfcBd\xfc\xd0TB\xe0I\xf1\xb5\xd2S\xa9R\x82{\xfd\x00\x0f\xb2\x91\x91\b\x89\x95\u01bc\u00f4\x1c\u074e\x06P\xcd/.\t\x83\xe0 &\xb0G\xa9\x8e+\x06s\x85\xc2\xc5J\xe1u\xae\x026\x16\x1a\xe3\x11vq\x03\x86\xbc\x99]\xeec\x8f\xfa\xeb62\x82-\xb67\u00dd\xac\xa1\xeb\t|\xa9Sj\x96\x0eE'\x13T8\x92\x1fD\x94A%U;\u072a\xa7\x8a\"\xdeD+\v\x11\x8f\x15jJ\xc5\xcf+l\xe2\x15q*\xf9\xe6x\xa0\\\x8c\x0f\x06\xafJ\t\x9cs\x14\x9cU\x8f\xd8\xc6\x1aK\u0708O\x1c0\u03c1\x1c`\u01ce\x1d\xcf\x1111\xd0\x11#\xcd\xfc\xc6r\xea\x18\x1d\x1e\xe6\x99\x17\x9c\xc5\xc8P\x83v7\xa9\xe7\a\xa2\xc7<\x05\xf5I\xa0\u0493\x01!\ud66bs\x94\x15\xfbz\x04\x9c\xd6\xf3@\xc5`m\x8c\x8db\xd4Z\u007f\xc3\xe6\n\t\x97\x91e.\xe8\xeb\xfd\r\x1eE\x9682a\x131#I\x13\xb2\xa4\xeb\xdd\xee\xe85\xa8\xd2\xe3\xd6\xd0Oy1\xe88\xac\xbe\xf6\t\x1c\x9f\x9eJ]\x8f\xfa\xde\xf5\x1fay\u03f4\xc4\xcc35\xbc\x83S\xe2\xfdlm,g\xd3\xec*\x0e\u034f\x92\xba\x88X\xb2\x01A\bU\xa9\xa2T\xdc\xfa\xaa\U000b6cbc.L#\xf2\xb4\x1d|0\xb5\x1a\x87\xe2\xc1]\x8c\v\xc3M\x17\xec\x85u\xc0u+}v\xc2\x1a\xacQ\xac\t\x8bs\"X\xe3\xd7\xe9\u0542f\x0e\u056c\xa0A\\\x95\xc8\x13jFi\x84\x8a\xdb4\r\x1a\x19\x88\x1d:\x9f\xe1\xda>\xd72\x1f\x14kF\xcd`\xabj\u00ec\x15]zAg\x86\xf0\x12\r.\x95*\u07b1\xb21\x12\xa8\x95\xe1\xf0\xaa\x99\xca\xd05,\xa2J\x1e~R\xe4\xf8\xfa\u1dc4\xa1\x83J\x91RW\xd0R\xd2+=\xad\xddo\x95\xc0\x89\n\xaek\xb8\x17\x12\f\v\xa9w\xd8\xcc\xd7\xea\xf2 \x18\xf0rD*4\xb78\xf1\xea\x9d<0]\xa4\xa6\xfc\u0272\x94,K\xfb:e\x14\x8c54N$0\u07fau\xb3\x9cr\xcaFU\xd5E/z\u044b\xd6\xed\u06b5\u02ff\xa7\x95\x8aC\x15\x16OMp\xc6\xc6\xf5\x18\x1b\x93d\u0770\xf03\b6\x8e\x0f\xe0G\x03\x86\x1f\x1d\u0334\xe6\xb7Ru\x13\xf1'\xb5?\xad\x8d5DQ\x8c\xb1\x11\x9dn\xc2\xdeC3\xec;x\x84#\xd33\xcc\xcc\xce177\xcf\xfcB\x9b\x85v\x9bN'\xf1\x12M\x11\x8c\x11\x86\x87\x1aX#\u0111e\u0572\u015c\xb4n\r\xa7lX\xcd\xe2\xc9q\xb2$!M|\xa4Y\xear\xdd\xeb\xb1\x0f\xa2\xbal\xf1\xe9\xeb\t\x95r'O\x8a[\xe9\xe9\x01u}\x92\a\x80\vJ\x94%\xf1\x1c\x8b\xc6\xe7Y\x1b\x1fbs\xb4\x82ms\xcb8\xd2\x1d\xf1\x8e\x8e\x15W\xcbz\x180T\xa7\xa0J\xff\xa0\x9d\x17\xcdu\xf9\xf9\x90\u04d0t[\xa4\xddN\xe9\xe3RI%n\xc41\xa3\xa3\xa3'\x0e\x98\u007f\xe7;\xdf\x05`\xf3\xe6M\xe7\x1c:th}\xbb\xdd\xc6\x18cD\xeaV}g\x9e\xba\x9e\x95\u02d7\x929\x17\xde\u0132*\x10\xd1\xe3\x80\xf8`A\u078f\x02\u40f2~\xf2P4W\xf9\x00\xc1F\x96(\x8a\x88\xacg\xd1\xf7\x1d<\xcc#[\x1e\u246d\x8f\xf2\u062e\xc7\xd9\xfd\xf8~\x0e\x1c>\xc2\xfc\xdc\x02s\xf3-f\xe6\xe6\x98_h\xe1\xb2\uc60fa|l\x94\x95\u02d7\xb2v\xf5rN;e\x03\x97\x9e\u007f\x16\x97]|.\x8b\xa6&1Y\niB\xb7\xdb\r9\xa9\f\xf0y\x91\x01\xa0\xaeO\x19p\xab\xf3\x02W1\x1b+f\a\x05%\xf2\xa3u\x02\xf2\x14\xe8\xc8\xfc\xbd0(\xab\xe2#,Y4\u01c6\xe6\x016\u03ef`{k)s\xc9P\xe0\xa5]9H\x13\x1d\x9cC\xa9\xd4\U000a628d]\xa9S%9x\x16\xda\x18\x01c\xf3OG~\a@\u0577\xf7\xf9\x81\xe1\xb4F\x91\xe4\xbc-\xc6gk\x9a8\xc2\xc41\xa6\u0440\x18\xe8&\x1e\xc8]\xeaW\xca+A)\xc5;*u7I\xadX\xdcJl\xb0\x9104dH\xdb\x0e\xed(\x9a\b\xa6k\x82[b}8_X\v\x9bJi,e\xc5j\x8d0\xdc\xf49\x9ef<\xf2\x86]\xf9\xb0\x90R6\\\x04\x82x\xb5fy\xd0T\xa8DU%\r\xbe)i\x00\xfa,\xfc\xb7+R\x81\xca*\xdd\u4389\x15\xf9\xa0\x15\xc1\x86\xa7\x91*\xdes\xa5\xe2K\xae\x95\xca\x1d\x85(\xf5\x03\u043c\v\xab\x9a\xf2\xf5\xe8\x9d1b\xe8\xb6\xe7\xe9v\x17JW\u01fcCSel|\x9cU\xabV\x9b\x13\x883\xff\xbe\x00z\xf3\xcd7\xaf\x9c\x99\x99^\x1c^\x8cZ\xf3\x1cG\x96\x8b\xce=\x83\xa9\xc9\t\xda\u0764\xa2\x1a\xad@\xb4\x0e\x8eR\xeb\xd7w<\xb5\xe1\xdf\xf1i\x96R.\x97/\xd84bK\xb3\xd9\xf4i/G\xa6\xb9\xff\x81M\xdc\xfe\xfd{xx\xf3v\xf6\xec\xdd\u03c1\x83\x87i\xb5;\x81:\x89\xe9&yjzV\x02p~\xe1U\u03efp\xa1\xcf\xce\xcd3;7\xcf#[wp\xeb?\u007f\x8f\xcfNNp\xea\xc9\xeb\xb9\xf8\x82gp\xcds~\x8a\xf3\xce<\x99\xb1\xd1Q\xc82\xda\xed6Y\x96URu\xf2g`zh\xa1~\xc5\u0353\xedN\\\x10\x8c\xd6\x01^C;[7Q2uB\xe3G\xe2\xec\x8f\xfd\xb5\x95\x90k\x11\xaf~\x199\xc8\xf2\xe6,\x1b\xda\ayxv\x15\x8f\xb6\x96\xd0u\x91W\xe8\x19W\xb1U8\x96\x8c\xb1\xfeI\x95\x9a\u0322\xb6\xd2^\xd2\xcd\xc1#Dm\x19,\x9e\x9f \x01$\xf3\xed\xd0B\x06n\r&\xb2\xd8\xc8bl\xe4\x95'\x91\xc1:\u023a]\u0124\xe1,\xa8\x9a\xbbU\xcaE\xca\u02bd\xd8\x00\xd5\xd2\xfa\xd64\f\x8d\xa6\xf5\xdcp\"\x98\xc4\x12\xa5\x11\x92\x19\xd2\xc4y\u0146\x84\xf0e*\x19\x00A\xf6\x87\b6\x12\x1aV\xfcf\xe7d\x84\xc4R\x94\xcfN)\xf6+\xea\x81\xe3!\x99\xcb)\x99\x83,\xf5\xa9>\x9d\xf0\xff\x89\u02fd#\x01+Hd\xfa\u0788\xbe,#-\xd55\xce\xf9Ak\xc1O\xa1\x9e\x04\x8b\\)f\xa4tU\u0334\xbe\xdf\x14\x80\x06\xd3uu\xab\x82\x9a\xbfW-x\xd6\xdf\xf1b\x98\x9f\xdeO{a\x1a\x1b\r\x05\xae\xc7\u007fw\x14\u01d2en\xcb\xe5\u03feb\xdf\t\x01\xe6\xdf\xff\xfe\x1dr\xc9%?\x95\xaa\xaa\xb9\xf0\xc2\v7\x1c\x12\xac\xb2uXT/\xaa\x83\x82C\xca\x16_\x9e\xccx\xf4\x89\x83V\x16@\xdc!8\xb1\x8c\x8c\f\xd3\xee$|\xed\xd6\xdb\xf9\xcc\xdf\xfd=\xdf\xff\xc1\xfd$\x897M\xb3\x91er|\x9c\xd1\xd1Q\x8c1\xcc\xcc\xce07\xb7P\xab\xbc\xa3(\n`\xac\xfd\x8fQ\x95\xd6\xc2B\x81\b)e\xfaz\x1e\xde\x1b\xc51.P4Y\x96\x91\x05\xce\xfd\x9f\xff\xe5nn\xbf\xeb~\xae\xff\xf9\x97q\xfd\u03ff\x94\rkV2;7_.;h\x95\n\xd0\x01\xa0\xf5\xc4\x01]B\xc5\xdbk\x1cVMrr\xde\u06f2\xe0\xe7\xf5)\xd2:\xc7;l\a\xbe\xdbR.\xbdHOXF$\x19\x8b\x1bsLD-\u058e\x1c\xe2\u0445%l\x9d_\xc6\xfe\xee8\x9d,\xc6J\x16\xfc\xe7{\x0f\xb9:9\u0557\x88#u\xf8\x96\nG\x9bs\xad\xfdFg\xdaw=;J\xa7\xda\xe2\x00Q\xe7\x15-\xc1\x06 '\x9d\xfb_S)*L\x05Z\x99#s0\u0590bXh\x82\u0574\xb5\x96\xc8z\aFg\x14\x1d1hf\u04594x\xc7K\x90\xeeU\x0e(\xe3W\xf6Q\xa5\x91\x80\xa6\x8at\x95l!#1B\x1aA7\x12\x92HH\fE6kI\x93\xf8\u06575`\x9a\x86,Q\x9cG\xfa\x82K\x0f\xedT\xc0L\x87D\xa67\xcf|\xa0\xc0\xc9\xef\x06H\xed\x8c\x15\xa4\u0432;QL\xaa\x98\xc4\xd5_lWJ&\xa9\x1c^\x85r\u0265\xb4\x17\xa6I\x93\x84(\x1e\xae\xa5\x17\x18#\x9c~\xc6\xe9\x13\xcbW\xac\x1a>!\xc0\xfc\x96[\xben\x80l\u05ee\xc7N5F\xce\f\xa0&\u057d\xc2f#\xe6\xe4\rk\x19\x1b\x1fgvn\xc1'w\xd7\xe0z0<\xf5U\x96\xc1\x1a\xe3U@\xceq\xc7]\x0f\xf0\x1f\u007f\xfb\xfd\xfc\xb7_\xfdw\xbc\xec\x9a\xcb\x11\x91\xe0\xec&\xb5\x9c\xd2\xfc\u0412\xd2\x11\xfc\t\xe2d\x90\xe1\xf5\x01\\p\x1e\xacU\xe4n@\x16\u04cf\x05\xbb\xfb\xc1\xd1\xe4\x8b \xbdu\x81\a'\x14\"IY\u059ce\xaa\xb1\xc0\xaa\xe64\xdbZ\xcb\u063e\xb0\x94C\u0771`\n\x15\f\u07a4\xbf<\xac\x99\xf9\xf6\xc8l\xfb\x00=\xff_\xa75\x9fm*Fa9\xb5\x12\xca\xe8pP;\\\x9a\xa0YVKw\xea_?\u0329\x1a_\x8d\xa30\x12\x19\x0f\xacR\x89H\x93|\xaeaH\x9c\x90\x89\xd2\xed8\x92\x83\t\xc9l\x8a&Z0\x1e\x1aI}\xdb9\xf3+\xf0>K\xb3r\x00\xd9p\xad\xe6\xcfO\x15\x9b\n\xdaq\xb8\u06106=\xb0k$\xc5p\xba\x1cx\x12R8]\x91\xf8T\xbc\xbeN!\xad\x04k\xf4X\xe0\x1a\xa9\x843\x8a\v\u0665\xe1,\xc8\xc3,\xf2\f\x83T1\x9dJ\x9c\xa4\xcb3\x82\u02d7T(\xa9_\u007foY:\xadYZ\xf3Gz\xcc\u0494,K\x98\x9a\x9ad\u7b9d\xdf\x13\x91\xec\x97\xde\xf4K\x8d\x8f\xfe\xf9G\xbb?\xd1`>==m\x00\xb6m\xdbv\x92\xaa6\x8aN2\xac\xdef\x99c\xdd\xea\x15\xac\\\xb1\x8cV\xe2\xfc\xc6\x18Y\xc9\xd9\x1dc\xd8%\xc5e\xf9\xf4\x01y\xe6c\xa2\xfd\x96[\u042a\x8e\x8e\x8d\xf1\xe0#\xdb\xf9\xfd?\xb9\x81o}\xfb{\u0638A\x1c\x19\xda\v\xf3\x00\xbc\xe4%/\xe2\xcdo~3\x97\\r1\u02d6-#\x8a\x9a\xc5\xcf}\xc5+^\xc1\xcc\xcc,\xd3\xd3G\u0633\xe7q\xbe\xff\xfd\xefs\xe3\x8d\u007f\xc3\xfd\xf7?\xc0\x81\x03\a\x98\x9a\x9a\n\x11V\xd9\xf1\x1f\xa3j\x0fo\x1a\xb6\xd3\xc2.\xa1\x84e\x13\xa7\xca\xce=\xfb\xf8\xad\xf7~\x84\xf9V\xc2\xcf\xfd\xf4\xf3h\x1aC\xa7\xdd\xed\xc9\xc0|r\x15\xf9\xa0?f@\u022f\x14\n\x16\t\x16\xbdZR0OsY~\xac\x1f\xa7\x86\"N/_\xa1\xd7\xca\xd6 \x15*&2\x8e\x95C\xd3,j,\xb0f\xf80;\x16\x96\xb2}~)\xd3\xdd!\xef\xd0(\xae\x9c\xcb\u0220\xf7\xa6w\x96\u04eb\x89\xa9\x1eh=)>\xc5PS\xfa\xaa~M3\x0f\xe6\xce\xd5N$? 5\x18\xebm\xe0\xc8\x14\xe7\xb20T\xf4\x1cyd\xbceK\x8e\xe2\x12~h\x06$\x99\xd2\xe9d$\x89\"\xd3)2\x9b\xf9 \xe3\xf0d\xa4\xfaV\x85\x83\xcf8*1r\x94\xe1\x11\x198[\x1e\x90\xb9\x85\xae(\x98,\xc3v\x85\xac\xad\xb8\x86\xe0\x1a\x824\fD\x94\x9e\x97\xd6?\x17\xe9:4\xed9\xf0\x83O\xbb\x982tBzl0\xf2m\u06b2\xf8\x97\x9aK\xa5(\xd0\r*\x16\xf5\U000c0a85\xb6jM\xf2\x12\xdec\x1f\x1e\xd2\xed\xcc\xd1i\xcf\xd6<\xa4P%MR\x9d\x9a\x9c\x94s\xcf9w\xfc\xe6\x9b\xfe\x1eu\xee'^\xd1\x12}\xe4#\u007f\xde\x05\x98\x9b\x9b=\xe9\xb1\xc7\x1e\x030Z\x88\xf4\xfd\xab\xbdr\xc52\x16OM\x92%\t\xb1\xb8\xa2\xea\xabUY\x03\xd6\x02\r\xfa#i\xa6\xfb\x95\x19\xf8\x19L\xd3\x00\x00 \x00IDAT\x86.Q\xe1i\x8d*c\xa3#l\u06f5\x8f\xf7}\xe8/\xf9\u05b7\xee`dr\x92\xd8Z\xe6g<}r\xfd\xf5\xd7\xf1\xeew\xbf\x8bU\xab\xd6\xe2\x95;-\x16\x16fQ\xf5C\xa6\xc9\xc9I\x16-Z\x02\b\xe7\x9d\a\xd7^{-\xaf~\xf5\xab\xf9\xfd\xdf\xff\x03>\xf6\xb1\x8fs\xf0\xe0\xc1\x10\x97\xd7\xf3\xec\x02\xb7\u9723:,\x1e\x04\xf0\xf9A \x81\xb7\x8f\xc4\xe02\xc7\xec\xdc\x1c\xbf\xfb\xfe\x8f142\u032b^\xfa<27G\x92$E\xcdl\xa4\xf4\x16\u0441U\xfb\x13H\x19\xa2\x8eo}1^\xbd\a\xad<}`=H\xe1\"\xfd\xa7M\xb8\u0524\xcc*\xed1m\xf3]\xa2_\xa6id\tk\x86\x0f\xb1\xb41\xc3\xda\xe1\x83l\x9e]\xc1\xf6\x85e\xb4\xb3\x18+>]\xaag&YqN-\x97k*\xa3\x9e\u0497\xa7w6\xa1u\x85Q\x9e\x1eo\x83\t\xb8:\x87K\x124\xcd\x02\xc0jA\xc5\xd9(\x06c\xc8B\x97G\x14\xa3b\x8bMb[XDT\x06\xf9\xea]\xfe:\x0e\xda*d\x89bgS\xe2\x85\f\x93\xe5+\xed\u07a7\xa4\xf0\x8fq\x83\tN5R\x02b\xbenoKUHMq\xe2 \xea8\xe8\xf8\xe1\xa16\x8c\xff\x88\r.\n\xbe5\xc6K'\x1d\x9e\xc2\xd1\xfc\xec2~1\xce\xd4y\x16\xaa\xf3J\x18\x14\x82\x9eK8\xfd\u01a7\xe9:$+\xccX*\xd66=I\x00A\u032e\xea\xedE:\xadiZs\x870\xc6R\xb5hTU\x19\x1d\x1de\u035a\xd5\x1d\x80\x95+W\x9c\x18j\x16U]\xf5\u05b7\xbe\xf9\x92\xb9\xb9\u067e[\xd1Z\xc3\xdaU\xcbX41J\xbb\xd3%\x92\xca\xd0(\xf8G\f\uea5f\x1e \xa7\x02\xe4\xa5\u046e\xe7\xa1\x1b\x8d\x06\xfb\x8e\xcc\xf1\xc1\x8f}\x86[o\xfdg\u0196.crb\x82\xf9\xc3\aH\u04c4\x97\xbe\xf4%\xfc\xe1\x1f\xfe\x01\x8b\x16-\xa5\xdbm\x15\x83JkK\xb3\v?\x1c-S\xa5\x9a\xcd&\xa7\x9dv\x06\x1f\xfe\xf0\x9f111\xce\xfb\xde\xf7\x81\x822\xa9\xfei4\x1aDQD\xab\xd5\xea\x931V\x01_{\xac9\x9dSo\x05`=\xed277\xcf\xff\xfc\xe0'X\xb3z%\x97\x9ew\x06N\xe7\u0086\xa2T\xb8B\x18\xb0\n\xd3'0<^\xf73H\xc9.O\xcb \xfa\x89\x02\xfaQ\u010bR\x16\x04\xd2[\x1d\x88\x14\x99\xb0b\xbc6\xc7:\x88m\xc6\xc8\xf0\x01V4fX3t\x98\x87\xe7V\x05>\xdd\u0516\x8e\xaa\xd4Sm^_qZ\xef\x9bs\xd7\u01a4\u055f\xe0\x15 \x9a{\x91Wl\x1c\xb4\xc2\a\x18kI\x93\x0e{\x1fy\x80}\x9b\u007f\x88s\x19\x93kOa\xc5\xc6s\x18\x19\x9f \xa4^\xf8\x85\x9c\u04359\x85\xaeS\xda\x0e\x92\xc8\u03c0\x1a\v\x19\xf1\xbc\arq\x81O\xce\xc1\xbc7\xb0\x9b\xba\u04e1\x14\xe9\x12\xfe\xf5\x13\xa5\xf4twR\xd0\x1cyu\ud36c\u00b5\xd1q\xa88L\f\xb6ap\x91\x906<\xbfN\xb8n\xb5\xdaI9\x87\xba\x10\xfa1\xd0)I\v\x17H[\x8dc\f\xef\xbb\xc9\x14\x9b\x849E\x90$\xaa\xcb\xfd\u07a9\xa5~ke\xbadl\xc4\xcc\xe1\xbd\xcc\x1c\u068d1\xd6\xd3>^J\ud187\x87\xcc\xec\xec\u0716\xd1\xd1\xd1;\x00Z\xad\xb6\xfbI\as\x03\xf0\xf8\xe3;\xd3M\x9b\x1eiW;\x11\r\x14\xc1\xe8\xc80\xabW,\xa3\xd9h\xe0\x82\v]\x8d\xa9\xcb#L\xfa\x86w\xcc\u06b5k\xf8\xad\xdf\xfaM\x16-ZJ\xbb=\u007f\xcc\xea\xb9\xfa\xa7\xd3\xe9\xd0\xed\xb6\x88\xa2&\xbf\xfd\xdbo\xe79\u03f9r`U\xdel6\xb1\xd6\x1e\xf5\xe7\xd6\x16\x8dz*\xf54s \x86F\xec=#v\xed\xde\xcbG>\xf9\xb7\x1c<2K\xa39\x84\x18\x9f\xb7\xeaz\"\xb7\x8e?\x16>\xfek\xd8o>\xf6\xe4\x17\xfc\x95\xbe\x9c\x80'\xf0(\xe8s\xd7\u0523\xf0\xe8j\x14\xb5\x12\xbcG@\xabv\u06a6\x944\x1aq\x8cEm\xce\x18\xdf\u00d5K\x1e\xe6\u00a9G\x99j,\x90\xa9\x1f\x8eW\x96\"\xfbsV\vu\x86\x14\u04b9\xa3\x0f\xf4\xa5\xc2g{\x83\xa8\x99N\xca|\xab\xeb;)\x97\x15\u065e\xbe\xdd7l\xff\x97o\xf2/7~\x84\a\xff\xf7\x17x\xf8\x1b\xff\xc0\x03_\xb9\x91G\xbf\xff\r\xd2n\v\t\u05cd\xaa\x97\b\xb6Re\xbe\xebXH\x95D\f\xd8\xff\x8f\xbd\xf7\x8e\x92\xe38\xefE\u007f_Uw\xcf\xcc\xeeb\x01,r \x88@\x80A\xccA\x04\xb3$\x9a\x92\xa8@E\u0496D\u0274l_Y\xbe>\x96l_\xf9\xfa\x9e{\xed'\xd9\xef\x1d\x9fg\xeb:\xe9]\xcb\u05b3h_\xcbV\"MR$%J\fb\x00s\x06!0\x00 r\\\x84\xcd\x13\xba\xab\xea{\u007fTuw\xf5L\xcf\xee\"\xf0<\x1f\xc1s\u0392\x8b\xdd\xd9\xd9\xd9\x0e_}\xf5\xfb~A\"l2\u00ba\xca0p2\x16\x13\x87F\u0198!?(\xdd/\xe2\x9c\xd1GrV\x88+\xfa\xa4Sow\xce$\xfa\x94a\xe19\xffR(\x83\xa0i\x10\x8d\x1bD\xe3\x1a\xd5\x11\x85\xeap\x82\xa8i\xdd\f)\xcb\xe8K\xb38\xb9\x80e\x15\xdc=3\x8b\\\u4ed2\x141ag\xaa\xe5\x06\x9e\"\xc3\u033d\xdd\x15\xf9\xc3\xcd\xd4)S\xc0h\x85\x91\u00fb\xd1l\x8c\x822Y\xafe\x17\x85a\x809s\x06\x0e}\xe63\xb7\x1c\x06\x80\x8b.\xba\x90O\x8ab\xfe\xdcs\xcf\u03cb\xa2\xca\x1a\u02ea\xc8\x1f\xda\x18\xcc\ua7c1\xb9s\x06,\x8f\x1f\xc2\xcf\xf1*/\u0669\u007f\xc2\t\xf3\x18\xf1\xec\xb1R~\xb0\u327f\xf6\xc6\x16|\xef\xce\x1f\x81c\x85@\x12\xf6m\u07c2}\xbbl\x00\xf5\xfb\xdf\xff~\\y\xe55\xd0:\x9eV\x11\xef\xbc\xd1\x15f\xce\x1c\xc0M7\xddX\xfa\x9c$I\xd0l6\v\xf8x{1\xef\xf6\xef\x94\xd9\x02BV\u041f|\xe6E\xdc\xf7\xe0:DQ\x05\u0489\x1f\f\x93\a_\xf11\x1f\xd3\xc9\x13\x9b\xe8\x04\xcc2\xa6ge\u0325\xef\x87:\xb9\xe1i\x05\x16%\xbe\xda\u0085P\vd\x1e\xd8\x01\x19\u0329\x8c\xe3\xfc\x99\xdbq\xd5\xc0\x1bX\u077b\x1f\xa1\u0408Y\xc2\x18j\xdb\xc1P\xa9\xc8%\xfb\xbc\x8d\u0398\xef2s\x06\x86\x01c\"N0<\xd1\xc4\xc8D\x82zK\xbb\u0754\x86\x8c*8\xbc\xebMl\xf8\xc9\xed\u063f\xf9g\x98\x18>\x84\xfa\xd0A\x1c\u0679\x05\u06de}\x18\xc3{v@\x86\u0591>a\xa0\xa9\x18-\x05(&\x18!@2@\xd4\x12\x88\\G\x0e\xb8n<\xfd<-\xca\u0736*\xa6\x05\x10\x19\xa4\xecX!\xa978 \x94}\x9dla \xce\x16\u0334\xcdN\x03\x93\xd3\xd7\x13\xca@$\f\x910d\u04e02\xa6Q\x1b\u05c8\x9a\x06B\xe76\xb4E_k\xdbY\u06cf|x)|\xc8%\xe5\xdbk\x06Z\xc6\xce\x03\x98<\x16\v2\x87\xd2\xf6Z@ H\x19\xa211\x84\xc3\xfb\xb7\x80\u074e;}\x8aVZ\x0f\f\f`\xf6\xec\xd9\u06c8h\x1b\x00\\v\xd9e'G1\x1f\x1b\x1b[5s\xe6\x8cU)\x1f\xdb/j\xfd\xfd}\x98=\xab\xbf\xe0Q\xc2\xecd\xf3\xae{4De\xb5\xf7\x84\r\xd0l!\u03e1\x96\xb0RE\xbd\x11\xe3\xbe\a\x1f\u014em\xdbA\x81@k|\x14\xadF\xbd\xd0a7\x1a\xe3\x19m\xf0h\x1f)\u03bdl\xd9)\b\x02Y\xda\xc1+\xa5&\xc5\xca\xcb~o\xfau\xcbC\xb7\x17a\x14\x06\x98\xa87p\u03cf\x1f\xc1\xe0\xfe\x03\xe8\x89B\x80\x04\x98\x84c\xb3\xe4v\xab'\x92i\u00a5{\x9f\xe9/\x0e\x1eWa\xda?\u05feK\x98\xca\u317a\rN]{g\xa5\xf8\xb6\xfb\x8bHci\xed\b.\x1b\u0602\xb7\xcf\u078a\x05\xd5\x11(\x12HXf\x96\x00\u0183\xac\x8a\xd3\x03W\xe8\x8bI%\x056E\xaa\xa2\xd4l\xa0T\x82VKa\xbc\xa50\xd4\xd0\x18j\x1a4b\r\xc8\x10{__\x8f\xfdo\xac\xb7\xf1t\x89\x85b\x92f\x1dC{\xb6a\xe2\xc8 \x88$\x12m\u0408\x8d\xa5(\x12A\x93\xe5\xe5\u0216@Xgk\xdce\\A\u0576\xbb\xee(\xe2\xd3\xd9\xca\"g\x87\b\x9d\x17u\x19[h\x03\x9c{\xbe\xf8\x8b\x85\xff\xb3\xc20\xa4\v\xe3 \xc3\bbFe\u00a0:n\x10\xb5\xac\xc8'\u0760\xa7\xb9\xab\xac\xed\u0417\xb5\xb1\x9fgktq&!\x13\x03R\xce\xee\xd6\x13\\\x11\xfc\u0646g\x94\xee\x16W\x19D\x98\x18=\x8cC{7e\xc3\xcf\xf4\xacj\xa3\xe5\xc0\xc0l\u031f?o=\x00\xfc\xf1\x1f\u007fY._\xbe\xf2\xe4(\xe6\x1b7\xbe\xaa\x06\a\a\xb3A\x9f\xaf`\xeb\xed\xe9A__/\x8cq\xd1j\x1e\xf9\xdf\x0e\xcf\xe9-\xf3~7Y^g\xfe;\x04Y\\{\xeb\xae}\xf8\xe9c\xcf\x00\xac\xc1\xaa\x93q\xf4\xd0C?\xc5#\x8f<\n\xa2\x00\xc7P\xcb\x11\x046\xb7c\u02d67a\f\xa3R\xa9\xa0\xaf\xaf\xaf\xd0]\x9b.\xf1&e]y\xe9\x82BdS\xe3I \f\x02\xbc\xbey+\xd6=\xf5nAA\xa3\xecN,\x8eaT\x02\b\x89\xa6f4b\x03\xc5\x04&\x81\x04\x84\x04\x04\xd1\x12\b\x1b\xce\x02\u0597\x9cr\x8emw\xc2VS\\%\u073ek\xb6\xf0\x8c\x15\xe80d\xcbv\xde\xc4m\x8b\x19\x173VH\x1b\xdb\xd9\x1b\xc7\xccd \x88\r\xaa\xe3\x1a\xb5\t\x8d\xb0e t\t#\x93m\xf7M\x86\xddB\x98\x8f\xf2Y3\xa8e\xa1#\x06\xdbP\x0e\xb7\x80\xb1\xe1\u04acS\"\u01dc\x010zd\x0fF\x8f\xec\xc9\xee7v\xbb\x820\bDT\xa9\x1e\xbel\xed\xda\r\x00\xd0\xdb\xdb\xfbs\x8f\x97g\xc5|\u03de\xbd\x18\x1b\x1b/\x14\xa1\xf4D\xf6\u052a\xe8\xed\xadA\x9b\xd4ZV\x14\xd8%\x9aDi\xfft\"\x18,9\xb4\xe2\xba$X\xdb\xd9$Qx\xe9\x95\u05f0w\u07c1\u049f\r\xc3\x10\xbbv\xed\xc2]w\xfd\x00Z\u01e8\xd5z;\x86\x93\xdd!\x16\xb8N\\\xe2\xe0\xc1}\xb8\xed\xb6\xdba\x8c\xc1\x9c9\x03\xe8\xef\xef/\fO\xfdb]\xc6x\x99\xb2\u023b\xf7$\xa4D%\n14:\x81'_\u0608\x91\xb1\t\bY\xec\x96\u028b\u0431\xc3-8Nw\xc6\xe9\xa0\xf7<\t\xd43\x95?\u03d4E=\xc3\u05d1:2\x81\x04C\n'\x1b\x17\x8c\xf9\x95\x11\\2k+.\x1d\u0602\xf9\x95Qh\x16HXt.\xeel\xfd\xc8\xd9\xd8\x0f\x93\x89\u007f\x00_\xe3\xcf00:\x86\xd61\xb4\u0459\xe5-\x01\x10l\x80\xb0\x8a\xc1]\xdb1\xb8e\xa3\xf5\xc6\xf7\xa6\n\xba\xd5@\xcf\xdc\xc5\b\u7702\xb1F\xcb\xc2* (\"(\x10\x82\x16\xa1\xda$\x04\x9ar\u1303X2\x8eu\xdb\x11\xe2\xc9\x0e&u\xc20\xed\xc5\xd1\x0e\x1e\rdl R\U000bbdc0\x907t\x04\xac\xa7\xb8L\\QO\xb1k\x06\u0096AuB\xa32\xae![^\xb4\x90scd\xc30:\xb7\x83Na\u007f\xa9\fD\xa2s\xe8\xc8\x15\xfd\xfc=\xd87[8\x1fD\x10A\x00\x954ph\xef\x1b\x88\x9b\x13\x10Bf]\xbf1\x86{{{10{`\xd7G>\xfa\xf1\x97\x01\xe0\xf2\xcb/\xc3IS\u0337n\xdd\xdaj4\x1a\xa5\u017c\xb7\xa7\x8a\x9ej\xc5%\xebp\xe6H\u01c0\x1b4\x15\x15\x1f'\x14\x06\xf0H\r\xa9<=\f\x024\x1b\r\xbc\xfc\xcaF$q\xdc\x15\"\x91R\xe2\xb6\xdbn\xc3_\xfe\xe5_\xc1\x98\x04\x95J\x0f\xaa\u055eI\xf1s!\x04\xaa\xd5\x1eHY\xc1\xd0\xd0!\xfc\xe1\x1f\xfe\x1fx\xfa\xe9\xa7\xd1\xd3\xd3\x03\"\x01{\x8cDa\xfb\x97\x0e@}X\xa5\xfd\xff\xdd\x06\xa2\xa9\xe4\xdf\xf2\xcf\xed\"\xb1y\xfbn\xbc\xb1c/(\b\xf3F\x8c\x8e\xbf\xc0v\xde\xcb\xdcm\xea1\xed\xd7,-\xc0\xdc\xd9G\xfbW\aO\xf1zG\x15\x9dG\x80\x91\xf6#\xa5\u03f1d\x904\x10\xc26cU\x19cM\xdf~\\=g\x13\xce\xe8\u06c7\x904\x12\x0e\xb2\xdcX6\nF\u06ee\xd9h\x05\xa3\x95\x15\x00\x19c\x8b\x88\xfb}\xc6\x18(\x1dC\xe9&4+K746\xf4\x02N\xcc\"%\xe1\xc8\xf6\xd71\xb2{+d\x18Z\xbb\xc0\xecZ0\x98\xb9\xe2LD\x8b\x96#Nb\xb0\x14PD\xd0L\b\x9a@\xa5\x01H\x96 \a\xed\xb0+n0%\xf88\nU\u0583\xe1:q+\xa2I\x86\x1c).\xaes\b\x86<\xdf\xf0\x8c^$rA\x15\xa50\x8d\xe79N\xb0\x01\xcbA]\xa3:\xaa\x10\x8d\x1b\x88\x98\x8bR\xfe\x14z\xa1|6!2n9\x1cf\xee`Hmrr\xb9\x9f[\xe7\x86\x01RFhN\x8c`\u07f6\x97aX\x81\x84\u022c\x01\x94R4o\xfe<\xacX\xb1|\x1b\x11\xed\x01\x80\xb5k\xaf8y\\\x13W\xacX1\xe7\xe0\xc1\x83mrg\x06\x91@__\x1f\xaa\xd5j\xb6\xaa\x8a<\xab+\x0fa\xed0\x14:1\x83O\xe6\xdc\u0396\x1d\x8fIJ\x81\xb1\xf1:\xb6l\xdd1i\a\xcc\xcc\x18\x1a\x1a\xc6\xff\xf8\x1f\u007f\x84\xad[\xb7\xe2s\x9f\xfb\x1c\xce>\xfblDQ\u037b\x9a\xd3\xddW\xdem\x8f\x8d\r\xe3\xb9\xe7\x9e\xc3_\xfc\xc5_\xe3\xbe\xfb~\x840\f\xd1\xd7\u05cbF\xa3\x81\x89\x89\t\x18\xa3\n\xf8w\xd9\xe7\xdd\xdeS;,\xc3\xccPJ\xd9E\xa4RA\x14\x86\u0633\xff\x10\xde\xdcy\x00\xabN[\x05\xc3\rOP\xc7G\r\x8a\xe4\xae+\xe4\x05w\x94\xe1\xde\xc7\xd7\xed\x17zF\xe2i\xf5\xed]\xbd<\xa6\xf9\xbe\n\u040c\u021d\x03\xb3\x81.3\xa4+J\x02\x1a\v\xab\u00d8\x1140\xa72\x86\xd7\u01d6\xe0H\\\x03\x99\x040IfA\x9b\xdf\x00\x1e\x01\x9d\xac\xb3\x9f6\t\x14+(\xd2Pnn\xc4Y\aK\x10Q\x15c\a\xf7a\xf7\xf3\x8f i\xd4!+\x95\xac\x90\xeb$F\xcf\xc0B\xcc[y>$\"$\xba\t\x04V{\x1f4\x19QL\b -\xbd.-\xc0&\x87U\xc8cw\xb4w[\xbe\x10\xa7c\x89%\x14B6:\x96N\xff\xe9\xda\u044c\xdb\x17\x03\xedL\xca\xd9[\xfc\x8d\xa5\x87\x8alwdM\xceSk\x01\x91\x18\x04\x82\x90T\b*\xb2\xb35\x18\v\xb7\xb0K\u0720XC45\xa0\r\xc8\x18\x90vN\x93\x86Q\xd0\xf702\x85)9!\x163chp+\x0e\xee}\x1di\f\x94\x15\x9fYk\x8d\xfe\x19\xfd\xb8\u448b_\xec\xb6#\xfe\xb9-\xe6\xcc\\\xf9\xda\xd7\xfe\xfa\xba\xc7\x1f\u007f\xc2Q\xab\xd2H)\x06I\x81J\xb5\n\x11F.\u02638\x1cI\xf3\x1b\xa9M\xa4q\x82Jyf\u07aa!m\a\xe3\x9c\xea\xc7\xc6\xc70661)\x1e-\xa5t\x8e\x88-|\xfd\xeb\u007f\x8f\a\x1ex\x107\xde\xf8q\\~\xf9\x15X\xbat\tf\xce\xecG\xa5R\x05\xb3\xc1\xc4D\x1d\x87\x0e\x1d\u009bo\xbe\x89\a\x1f|\b?\xfe\xf1O088\x88(\x8aP\xadV\xd1j\xb5\xd0t\x1e*\xedB\xb2\xf6\xae<\xc3\xef\xa6\t\u0527\x05\xdd0#\f\x03\x8c\x8cO\xe0\xf0\u0430\x1d\xdcN\xa3\x1b\x9e\xea\x18v\xf1\x13\xcc_}1j}s\xa1\x1a\x13\b \x00e Y@\xb2\r\xba \x9b\x9e\xec\xe2x\x8c\xc5\xcd\x1d\xae\xdd\xee[\xe3S\x83\xbb\xda\fS\x11\xf2/\x1ea*\xc1\\\xa8}e\xc8\xe1\x96IN\x90\xe0\xb4\xe3v\x87N[\xa6\x11\t\x824\fj\x1aH\u0148k\x02\xa6F\xd0\x06\x10-\x05\xd9T@\xcat\xf1\x84P\xc4%\xa3t\x8f\xf9(\x84D\xdc\x18\xc1\xbe\x1d\xaf@%-\x9b\u0104\xdc\\k\u05acYX\xb6\uc517\x06\xe6\xcc\u007f\x19\x00n\xbd\xf5\x1f\xf0\xd9\xcf\xfe\xdaIS\xcc\xcd\xf8\xf8\x84\xb2\xea\xc8\xf6\xb9\x90\x8d\x87#O\xfak\x9d\xce\u0716\x06o5\x14e\u007fG\x00\xbb\xb5\xd5,\xc0\x9cg1NVP\x93D\u0658\xb8\xcc\xd2\xd6~4\x1a\r\xbc\xf6\xda\xebx\xed\xb5\xd7\xdb:y\x01!l*Q\xfa\xbbS\v\xdb\xd4\x1dq\xb2\x9d\xc0d8<\x11ux\xbb\xb4o\xfd\xb4\xd6v\xf0Jde\xdf\xe9\xce\xe7X\xecR\u0607?\xca\xfb\xe7\x13a\xc1R\x9c\xb1\xe5\x11}HM\x99\xb2!+OVk\xba\x0e@\x8f\xb7\xb8\x17\x1aV\x01\x10\x1b\u8111$\x06\xb3\xc2\x18\xe7\xf6\xc7\xe8\x93-l\xae/\u0138\xa9A\xa6>Bl\xb1p\xc3\x16;gg\xfc\xc5\x04ha\xa09\x8b\x9b\xb2\xc7X\x06\x18\u06ff\x03\a6>\xe3\x1c\xfd,\xfc\xdc\u03f4\x93\x9fL\xe19\x9d\x0e=}\x1d\xff\xb8\x96\rd\x02)\xa1\x12\x85\x19\xfd\xfd\x98;g\x00P\x89\x8b\xdc\xe0\xa3,\xac\xdd\x06\xa1\xd3h\xb0\x8e\x037\xb7;(ktea\x96\xdc-3\u035d\xe4B\x91\xe7\xa73\x9b\x91\xdb \x16\xf6\xfe\xc5m\x03\xb72\x04\x17m\xcf/K\x02\xa2)\x8azZ\x9bbePO\x14Z\xda@\xbb\xf0cCl\x8d\xbb\x84A$\x13\x9cR=\x88\v\xfa\xb7\u151eA\x18\xa1m\xd6&\x19\x1b\xf8\xe0B\x1f\x8c\x042\u0751\vxf0\xf6\xbd\xf8(\x86\xb7\xbf\xe6-\x1e\f\xa3\x15\x82J\x0f\x16_p\rj\xa7,G\x12\xa5\xbclw\x8f\x91\x84\x10\x81\x1d\xb8:\xb7E\x169\x13\xa7-\xdf\u00a5u\xf9\xd6\xc0T>\xbc\xf0W\xba\xec \xe5]6u$\xf7\x96X\xb7\xb9\x00\xeaN\x8eZ\xf9\xcc%\xb5\x0f\u0228\x8b\xe9\xa03\xb5\xd9Mi\x96-\rn% \xa5A\x89\x06%\x16b\u024c\xd4R\xa5g\xa7\x8e\xdf\xd5&\x89\xa1\xfd[ph\xdf&h\xadlg\xee.~!\t\xb5Z\rk\u05acy*\xfd\x99w\xbd\xf3]'W1\xb7\x85E\xef\\\xb2d\x91\x17\xb8\x90\xe3\xd1\xfb\xf6\x0fb\xf7\x81C\xa0 \x82f@\xb1\x80rFF\tK/\x1c\xf8\xd8\x13\xe5\xa7[\xd0\x05\x18P-\xf4\xd6B\x9c\u007f\ue648\xa2\bR\n\x04%B\x9e\xb2!c\x8e}s)~\xcd\x05Iq\x97\xf72I!?\u0582/R:\x90\x90Xu\xda*\x9c\xbax\x81\r\u0560\xce>\x94\xa7\xdeEg\xf1_\xed\x16\x00\x85e\xe1-ak\xe5%\xbbH\x85\xccc\u0734o\x8cL\xe5FbT\xc0\xf6\x8b\x85\xbf\x9dr\u074d\x9b\x9e^\x8dqb\u040a5bm\xa0a`\x88\xed \xd3a\xe0\xf6s\x03\"\x8d\xb9\xd10\u039e\xb1\x03\xa7\xf6\f\x02\xd2 \x11\xd6\x02V\t\x82\x16\f\x0e\x8a]\xb2\b+\xa8\x1f\u0687=\xcf=\x00U\x1f\x87\x90\x01RoXf\x83\x9e9\v\xb1\xe0\xbc+Aa\bE\x06p\xf3\x13!$\u0205@\x93\x8b\xe31.~\xad|\x97EE8\xa2D$D\xe8\x92\xcc\xc8\u0716\xe1\xc6m;\x1f\x9e|\x95\u6a7e\x99/<\xa9\x17LZ\xc8ar\x0e<\x19\x9d\xd9\x05\xb31\x99\x0f\xba=^\u02024\xc8[\x10\xb3\xe1gz\x92\x05ap\xf7\xabh\x8c\x1d\xca-o]\xf7\"\x84\xc0\xa9\xa7\x9e\x8a\x8b.\xbeh\f'\xe9C\x00\xc09\xe7\x9cs\xa8V\xeb\x19I;]\xbf0\xed\u067d\x1bol\xd9\x0e\x11F\x0e\xf2\xb0)6\x99y\x0e\u02b9\xe6o\xd5@\x94\xb5BU\x18\x9c\u007f\xe6J\xac\\\xbe\x14Z\x1b\xd4*\x95\fC\x9f\x0e\xe3\xa4\x1d\xf2(\x13\xfc\xb4\x1f\a\xff\xdf\u077a\xff\xa9\x86\xa4\xed\x8bF\xf6\xbaB\xa0\u054a1{\xde|\xac\xbd\xe4\x02T\xa5U$\u0494\v\\\xb7\xed4g[SP;^z\xfcA!\u04c3y\xb8\xa3\"p\xb7\xad{\x17\u0225\xd0\xd9Sw\xbdj\xc7\xf2\xec_\xadV\v\x85\x8b\b0q\v\xeb_y\x15\aG\x1a\x90A\x94y@\v6\x1e\xa6k\xcf\xde[\xc9\xcd'\xef\x06O\x9a\r\xacX4\a\xef\xbf\xf6\n\x1b\xfe`\fz{z\nR\xfb\xfco\xa0)\vy\xd9\xd7\xcb\x16\x81\xe9`\xe4Sa\xe9e~.\x96k\xaeq\xf6\xd9g\xe2\xf2\v\xdf\x06\xd5j8/\xe7\xee\x1b\u074ecCE\xf7C?\u00ac\fu~\xabe\x14\xbe\xea\xb3\xe8\xc7RfH\x8bB\xf9.\xff\x9by\xca\xe3\x90b\xf2\xc6\x10Z\x89F+\xd6HT\n\xa7\u5fd7Hd\xfe\x1e~\x97\x9f\x9a\xc6\xf5\xc9&\xde\u05b3\x1bg\xf6\xecA5J\x90\x04\x12:\x12v!p\xe7KTj8\xf4\xfa\v\xd8\xfd\xf4O\xa0\x93\x96\x1d\xcei\x9d\xe5\x99\xd6f\xcf\u01d2K~\x01\u044c~p\x1cC*\x9b\xedIA\x88 \xeaAX\x9b\x81 \xea\x01U\"\x10\xdb\xfc\xcbT\x00\xd5^c\xb9\xc4\xd1\u0187\xc1}\u031b\b%\xfe\xc4\xed\u017bDB6i\xf1\xc7\xf4a\xba6a\x13ke\xad\x12\xc8\xd9%\xb8\xc5.\xb3Vg\xbbS\xe2\xc22OY~if\xeb/\x04\x9a\x8d\x11\xd4G\x0f\xc3h\x95\xeaNA\xb0\x011Q%\xc2\xd9g\xbf\r\xbd==k\x98\xb9\x17\x00\x16-Xx\xf2\x15s\"\u06bfx\xf1\xe2\x17\x97,Y\f\xad\x15\xa7t\xba\xf4\f\xbf\xf0\xc2\xcb\u0630y'\x82\xde>$\x06.C\xb2\xbd{x\xeb\x1f\xe9\xefH\x92\x04Q(q\xdd\u0557\u0f37\xadF\xbdaC\x97\xa3\x8c\xe125d\u04ad\x90\xfb?\x9f\xb2QR\xdf\xf22\x1c\xbd\xfdg\xa7\xea\xc8\xcb\x16\x0e\xa5\x14f\u03dd\x8b\x8f\xdf\xf0n,\u83e0\x9d{e7Z_g!\xf7\x90f\xf2h\x89\\\x84Zh:p\xcdQ\u0737\u075e\xe7g\xc3\xf8\v\x89\x81\x80\xcaF\x8f\xd41\a \x94\xd1]=\xdf\xf16\x90\x80J\xd0[\u0144\x96\xd2h%\x06\x8960i\xf7\xe7\x89hR\xf4\xc1\xea(\x9c\x96\xc2\xc0:\xfc\xb9\xc56\"\x85\u0555}x[u\x17*Q\x82$\xb4\x8d\x02k\r\x11U\xd1\x1c9\x82]\xeb\xee\xc5\xc4\xe0\x1e\x90\b\\\xa1\xb2\x1d\xa5\x90\x01\x16\x9c{\x05\x06N?\u07fe+e \rA\x86UT\xfaf\x81a0\xb8\xfd\x15\xec\xd9\xf2\f\xc6G\xf7CBXO\x16\xe7\u007f\u4670\xa3\x8c\x8a\x98\r;}\xaf\xf7)\xb8\x9e\xed;\"\uee8b\x9atDZ(\xd4\xe5\xa3j\u01ddJ\x83\xa6\x8d\xa3x:\x98\u02a4\x10Jz\xdc\xe1\xabx\xd3y\x1c\xb2\x9cU\x16\x9cE\xf0%q\x1dq<\x81v\x034f\xc6\xec\u06730\u007f\xfe|0p\xca\xfe\xc1\xc1\x15'%\xcc\xf2w\u007f\xf7\xb7\x11\x00\x9cy\xe6\x19\x8f.[\xb6\f\xb6\x86\x11\xfb\xc6Q\x87\xf6\xec\xc4\xf3\u03ff\x88Fl d\xd0&\b\xe1\xd2\xc1\xd4[]\xd0\x1b\xf5:V\x9f\xba\x18\x9f\xb9\xf1}\xe8\xed\xa9adtlZ\x01\x14~\x10s\x19\x9c\xe2\x17\xdd\xf6\xe7v{\xbd\xa9:\xf5n\x98\xbaOO\xfc\xf0\a\u078dw\xad=\x17\xbaU\u03feF\xd3=\x9e\x85y\x11\xb51\x02\x90m[\t\xc7&\xe3'\x0f~\x9d\xee\xf3E\xa1\x88\x13\xb4#\xfc\t/\x98\xba\x9b\x11\x17M\x8d\xd2vl\xfc\xc9)\x00\x13\xa5\xd0J4b\xcdP\xa6\xe8]\x9e{\x85pV\u0233L\x06\a\a\xe4\x9f\x03\x01i\x9c\x1a\x1c\u009ap?\"RPL \x19\x02`\xecy\xea>\fn|\x06$\x84\x83\x0f8\vH\u8677\x18K.{/*3\xe7@\xc7-\x04\bP\xad\xf5\xa3\xda7\x80\xc3{7c\xddm\u007f\x8cG\xbe\xf3\xdf\xf1\xcc=\u007f\x81W\x1e\xf8&\x0e\xee\u0610\xf9\x9bP\xfa\x9e:'\u02c5\x93g\u00d7)\xd3\xf90g\xc1B\xc5\xed\x19O\x1f\x18+37\u0387\xa2\xed\xab\x03\x95\xee\xf4\n\xbf\xde0\xd8\x1bhZh\xcb\x0e\x94\xdd\x06\x06B\n\xab\x1b\x91\x00\x02\xfb|f\x86\xce1\x00\xb7x1\x94N\xa0un\xbf\xe0\xdfS\xbd\xbd}\b\x82\x10\u0198\xc0\x18\xb3\xf8d,\xe6\xc1\x19g\x9c\xae\x00\xe0\u04df\xfe\xe5\xd7\u05ed{\xfc\x95\x81\x81\x81s\x87\x86\x86\xb5\x10\"\xf0\xb9\u044f>\xfa\x04\xae{\u05d58g\xc5B\x98\xc6h\xc7\xcdM\xc7\xd1\xd1\x1d\xed\xf6=\xbd\xd0T\x92\xe0\xfaw^\x867\xb6\xec\xc07\xfe\xe5.\u0109\xea\x1a\xbe\xdc\xceR)+\xc8e\xf0J{`\xc7d]\xf7d\xde\xe6e\xbc\xf5\xf4\xf3+\xaf\xb8\x14\xb7\xfc\xe2\a\xd0\x1b0\x92\x89\xb8\xa4\x93\x9a^\x05M3\x1f\xb9\xacu\xe5Ni\xfdQ/\xba\u053dw+{rj1\xe2\x17x\xea\u03a1(_@\u0494\x9f6V\x8f(\xbc\x0f\xb2\xb1kJ#I4\x942\xce\xf8/}\xae\xb7#1\xb9\xb29+\xdc\u0739\xb0\xd8\xee\x92Q\x81\xc22\x1c\xc6(j\xd8&\x17\x82\xc3\x1a\x06\xd7?\x86\xed\x0f\xdf\x01\xd5\x18w\xb0\x8e\xce~JFU,\xbd\xecz\xccY}\x1e\x8cJ\x10\xf5\xf4\xa3\xda\n\x11\x1f\x1e\u0096\xf5wc\xfdO\xbe\x81\x83\xdb\xd7C\x06\x15\x04\x95\x1e\x1c\u067b\tZ\u0168\xbd{.f\xcd\\\x04\xc4-\x97\r\xea\x18\xd7e\x91vm\xc3\xc2\x02\x15\x9b\vzN\x97\xf9Yf\xa4\xc0%M\xb9\xe7\x8cE\xed{8*\xc1\xdcK5\xa4\xb9\xf5\x1e\u5db4\fc\xbf!\xad\xb9\x98\x88\b\x81\x04\xa4\x84\v\x87\xb7_W*\x8fLd'\xf6\x82\xb1\xdd:\t\x99\xbd\x96/\xf3\x17\x82\xd0l6\xa1\xb4\x02\x119\u01d8\x93\xb03\u007f\xc7;\xae5\x1f\xfa\xd0\r\x92\x88\xde\\\xbdz\xf5\xed\xa7\x9d\xb6\nJ%$\x84(\u063an}\xf5U<\xfe\xf4Kh*\x03\xc8\xc8c\xb1\x14/$?\xaa\xeb-\x85\\\xc8\x0eDf\xd4*\xf8\xfc/\u007f\f\x1f\xff\xe0\xb5\x16\xcb\x14\x02A \u074a/\xa6\xd5A\x97\r?\xa7\xd3}\xd34(\x91\x9d\x03R*\x18\xef_|\xd1\xf9\xf8\x83/\xfc\x1aV.\x99\x87\xa41\x81\"1\xef(\x8e\x87o2W\xb2\x9aNWV?9\xccB]Xp\xd4uqH\xa5\xfd\xb2\x00\xa1\x14\xa5\xfe<\xe5\xfa\xc1\x93\xa2\xea\x86\x19\xb1\xeb\xc8\x13m\xd0NXJ\xc3s\xb4\xb1\xf4S\x93u\xe6^A7\\$\x8b8\x88J\u00a0\x0f-\xac\xa0\x83X\x1c51\xba\xf3\rl\xba\xf7\u007fcl\xdf\x0e\x80lt\x19\u0600\x84]\xac\xe7\x9f{9N\xbd\xe6C\bzf \xa8\xf6@\xd7'\xb0\xfd\x99\x1f\xe2\xfe\xff\xf5y<\xf0w\xbf\x89\xfd[\x9e\x87V\tT\xdc@c\xf4\x10\x86\xf7m\xc1\xf6\x97\xeeG\xfd\xf0V\xf4\xf5VQ\r\x05\xa2\xc0\xfa\x10Q\x19w\\x\xe1q\x18\xd1\xfd\x00\x00 \x00IDAT\xd7\x1eP\x9e\x96\xaf\xa2-.\x95br\xdc\xd1aSgW\xc0m\u06c2\x12\xdf\x00\x9f\x19\xd6\x16\x14W0@3\x86\xf3\xfd\x18\x01\x14\x10\xc2~\x89hN\x80\xb0*\x10HB \ba@\x90!\x15h9\xe9.\x93\x89\x11\xd5z\x11Vz\xbc\xeb\xdc\xcd!H`hx\b\x87\x0f\x1d\x063\u01f5j\xed\xe0IY\xcc\x01\xe0\xf3\x9f\xff\x1c\x03\xc0\x97\xbe\xf4\xfb\xff\xb0`\xc1\x82W\xe7\u035b'\xb5\xd6I\x8e\x9d\x03\x80\xc6c\x8f?\x8d\xbdG&\x10Uk@\u6652\u039a\xf3\x05\x8d\xd1!\x90N\n\f\xa1\xa39\x16>\x83\x8f\xa9[\x97{l\xbb t \xa3\x9dI\xa2\x9d\xc8k9y\x90\xc0^h\fO\xb9\xab+[\u0532m<\x01\x86\xad\xaa3Nlr\x931~\xa2\xbbU\x19\xb2a\xe8\xf4\x1c\xc1\xb3d5\x1e\u0312\x0eA}\xa6Qv\xae\x193\"\u00bc\xe6~\xec{\xe4v\x1c\u07ba\x11B\x06\xd9@\u03fe\x9e\xc6\xccS\xd6`\xcd\an\xc1\xc0i\xe7\u00a8\x18\a6<\x85\x17n\xfd\n\x1e\xfb\xdb\xdf\u014e\xf5\x0f\xd9\u008f\xd4w[g\u007feR\x1fA%\x14\xa8\xd4$d\b\x04\x92\x10\n\x82\xf4\xb8\xe4)\xcf=KXB.2b?j\u03c3\xda\v;\x9aB\xc25M\r\xb3L\x87\xcd@\xe5\v.\xda\x03\xa6\xdd{c\x00$\t\x95\x9aD83\x80\x9c\x19@\xce\b@\x91\xb5\xb0\x15\x82 #\x01\x11\n\x8b\x97S\xbe\xa34l\x10\xf5\xf5\xa3\xda7\xdb\t\x8cR3\x17\xfbs\xf5\x89:\xb6n\u074aV\xb3\u065a=k\xd6\xf0I[\xcc\xdf\xfb\xde\xf7\x9b\x83\a\u007f\x06\"\xdaw\xdey\xe7\u07fex\xf1\"\x18c\x82\xf6\u0405W_Y\x8f\xf5ol\x87\x96\x15\xb0\x88\n\x81\xc3\xfe\xb0\xe6X\xb1\xd9c\x83]\x18\x13\xe3\x138e\xe1\\\xfc\xe1\x17o\xc1-7}\x00RJ\xb4Z\xb1\u06c2\t\xaf\xf0\xa2t\x88\x99\x16\xe70\f2FL\xfa\x9ct\bZV\u0627\x1b\x19GD\b\x83\x00Q\x18@\x1b\x03!%\xde\xf7\vW\xe2\xff\xfa\xaf\xff\t\x17\x9d\xb9\x1c\xad\xf1\x11\xc0$v\x11\xe4\xe3\xc8\xfa,\xe1\x06w\u04d3L\a\x06\xa3\xd2\r\xb6/\xe4!\xb4k4\u065b\xa4\x14\xf0m?K\x93\xa6\u0388\x9d\f\xbeI_[k\xb6<\xf2\xc4@i\xce\nq\xdaYg\x10\x8a\xd7yk\xb6\u0676\x99\xba7\xed\u0239\x04KwEM\xca\x00\xa1\x14\xd8\xf9\xe2:\xecy\xfe\xe1\u0316\u0546Y\x18\xb0V\xe8_r\x1aN\xff\xe8\xe70c\xc9*\xecy\xe6\x01\xfc\xec{\u007f\x8d\xe7\xfe\xd7\x1f\xe0\u0347nCc\xfcH\xe1\x04\xa5@Xz\x8d\xac\xb9\xecz,Ys!\x94j\x81\xa2\x00\x14\x10\x84\x04Bi=\xd2\xf3\x18{r\xd0\x05\x15l\xe3\v\xd4\xe0\x8ek\xa0\x18p\u0285E\xb6\u06d5Q\xb6\x9cs\xd7U\x9e\xdb!3\x8f\xff\x9d\x82\xf9i4]\x10\x10\xc2^\tY\xb5\xa1\xe5\xa8\x12\xb8O\x80+\xb6\xe0KA\bB\x02\x059L\xc3l\a\xcf2\xac\xa0\u007f\xeeR\x04Q\u0545h\xa7\xf5\\@%\t6l\u0600\xf1\xf1\xf1\x04@|Rb\xe6\xe9'\xf3\xe6\x9d\r\x00\xf8\xf2\x97\xbf\xfc\u05ef\xbc\xb2\xfeS\a\x0e\f\xae:x\xf0 \v!\xc8hmW\xc7\xc68\xee\u007f\xe0a\\\xfe\xf6\xf30/\xea\x81i$n\xa8E\xe0\xe3\b\x1cFigw\x14\xc396\x18\x9b\x98\xc0\xbc9\xb3\xf0\a\xff\xf9f,\\0\a\xff\xf8\xdd{\xb1\xef\x80\xddm\x05\x81\x8df\xb3\xa2!\xd3u\x90g;;sTC\xce2\x1c<\xe5\x8e\vB\xb6c\xd1Z#I\f\xe6\x0e\xcc\u00a7>\xfa^\xdcr\xd3\xf5X0w6\xc6\xc7\xc6\xf2N\x9c\x8fn\xd2\xd0\xce5\xeff\x99;\tb\xda\xf5\x98\x97\ty\xca;u?\x8a-\x85[\x8aT\xc0b\x01\xe0i_\v(\x81s\x00\x02\x1b\x03e\f\x942P\x86a<\xd6\n\xbcn.\xeb\xb8\xfd\xee\u06dd\u007fk\x16\x87,t\xc5\xd7\xe5\x14\xf1X\x81J%\xc4+?\u06c8\xc7~\xf2c4\xc6G\x10\xc8 \v\xb0\x00\x00Y\xa9\"\xac\xf5\xe1\xf0\x1b/a\xd7\x13?\u0111-\xaf`\xfc\xc0.\xdb};\xac\x97\xbd\xa0\x8a\xec\x98\n\x81\xb7\xff\xe2o\xe0\x1d\x9f\xfdo\xe8\ud7cf\xf8\xd0((\xb0v\xbd\xc4\x02\x82\r\x02\x10X[H(u\xea\xed\xd8y\x15`\x95\xfco\xf1=\xc8;\x05}\xdcf`E\xe8n\xb0P\xb6?\x9b\xfc\xdc1\xe5\xda\x02\xe3\xbar!\x80\xa0B\x10\xbd\x02$`=\xd0\xc1@\x85l\xe6\xed\x98\x01\x9a\x1a$\x800 \xb0\x01\xb4rW\x98]\x851g\xe9\x19\xa8\xf6\xcd\xc2\xd8\u1f50A\xba\xc6\x11\x12f\xbc\xfe\xc6&l\u07f1#:\xf3\x8c\u04eb'mg\x0e\x00_\xfb\xda\u07e4\xc5\xe9\xc85\xd7\\\xfd\xed\u014b\x17AJA\x00Xx\xfc\xedg\x1f_\x87\xa7\x9e\xdf\b\x84\x15@\xe4~-\xbe\a>\xb7\xc1q\xddvle\xf9\x90|\f\x85,\x1d\xfc\x8d\x8fO \x8a$>\xfb\x89\x1b\xf0\xe7_\xfe\x1d\\\u007f\ud568U+PJ\xbb\xf0e{s\n\xf7\xc6|(\x85\x99\v\xde,\x19\xde\xea\xbc]\xcaR\x84\xca:\xf0J\x14\xa1\xbf\xaf\x17\xbd\xb5\n\xc2@\xba\"n\xe5\xfc\x97_|\x0e\xfe\xe7\x1f\xfd\x16~\xe7\xd7n\xc4\xfc\x81\x99\x18\x1f\x9b\xc8\xfbL\xe6)C\xe1\u0288\r\x93A)e\x86\xa74\xc5\xebLVP\xc9y\xae\xf8\xc3\u0254f\xa8\xb3\xef\x14\u007f\xdex\xbd4\x1d\x85B\xb8\xdb{\xd3\xc6 q\xb0J\xa2\f\x8c6\xc5\x01&\x17\xab\x9d\x0f\xa1\xd8N\x1c\x9e\xab\xa4\xbdn\r\xdb@\x04\xbf\x90\xb3[\x84\xab\x95\n\xb6\xed\u0703{\xee\xfd\t\xf6\xee\u0647@\x06 \xe3(\x8c\x9c\xefE\x87\xb7\xbf\x8a\xd7\xef\xfa\u007f\xb1\u3c7b1\xbe\u007f\xa7\xed\xf0\xb5\x82Nb\xdbE\xb6\x1d\u0359\x8b\x97\xe1#\u007f\xf2\x0fx\xdf\u007f\xfd\v\xcc^\xb1\x14\xaa\xd2\x02\u034d\x80>\t\xaaJ\xa0\"\xc0!A\b@z\xd3^r\x01\xcb\xd4n\x8a\xc5\xc5\x15=\x8dQ\xeb6-\xe1\u0098\xbam\xc8\xc9\u076e\x94\xac\x15n[`\u06f6\x87\xd9\xf6\x8b\xac\r\x88\xf3\x9e\t#B8#\x80\xac\x884\xe7)_mC\x02f\x04\xe0\x1e\t!\tR\x10\"ae\xfaLn\x80\xaa\rf/X\x89\xdeY\v\xb3\xc8>\x9b\xf4d\x11\x84\x83\a\x0f\xe2\xd1G\xd7U\x01\xcc:\x19\x8byV\xa5\xef\xbb\xef>\xe4\x9f\xff\xf8\xf9\xe7\x9e{\xe6\x86\u077b\xf7\u032f\xd7\xeb$\x84p\x1d\f\xa0[M(\n\xb0\xf6\xca\xcb\xd1\x1b\x00\xa4Z\xb9\n\x14>\u038cLxT&\xbb\xe6)\x98\f\u01c2\xa5\x83\bIb\xb7_+O]\x8aK/>\x0f+\x97/\xc5\xd8\xc4\x04\x8e\f\x8d\xa2\x15\xe7\x9e\xe4\x16O\x9fj/P\xc4\xcdE\xdaq\xb7a\xf1A \x11\x06!zjUDA\x00\xa5\x12L\u051bH\x94F\x10\x068c\xf5r\xfc\xc6\xcd\x1f\xc1o\xdd\xf21\\|\xee\xe9H\x92\x04\x8df\xcb.*<=4{2\xfa\xe7\xd1`\xe2t\x14\xc7sRn{\x16\xea-\x9c\x8f9\n\xe5\xc1\xef\u0667\xc2\u01e7\xfb~\x94f$Z#Ql\x87\x99\x1e\x94\xd2\x0eo\x15\x98*\xe9\x87\xc9\v\b\x15v]T0\xb8\xb1\x9d%\xa1Z\xaba\xff\xc1#\xf8\xce]\x0f`\xc3k\x9b!\x88\xa0\xb3\xc5\u0763X\x1a\r\xa3\x14H\xda\x0e\xd3\x18\x03\x9d\xb42\x8c\xdc\u007f\x84=3p\xce{o\xc2\xf5\xbf\xff\xe78\xfb\xba\x0f\x00\x14 \x9e\xa8[Ec(l!\x0f\xc8S\xef\xe7<\xd5\xe2\xdc\u05a3\xfb\xdc\xc7\u051d\xd3\xf7\x04\xa0N\x02{\xd1\x1e\x82\u0684`y1OU\xb6 \x82\x11\xd6\a'\f\x80\xea\x8c\x00\xb2O\u61da\xdbV[\x01P(l=\xf1h\x9a\xc6\xc1a BT\xe9\xc1\xc8\xc1\x9d8\xb8s\xa3\x1b<\xcbl\b\x9a$1\x94J\xa25kV?}\xeb7\xbf\xf9\x12\x00l\xf8\xd9\x06|\xfdo\xbf~r\xc1,\x00\xf0\xcf\xff\xfcO\xf8\xccgn\x01\x11\x8d\xddy\xe7\xbf\xfd\xfe\xe6\xcd[~8::\x9aejjG\xd3{\xee\xc9'p\xff\xe3\xd7\xe2c\xef\xba\x18\x11\xd5!\xd8\xf6h\x06V\x19\xea|z\\\u03ae\xbd\xf0L!\xee\xc4\xcfvo\xff\na\xf2h\x94\x92A\x98\xf7oA\x04\xc3\x1a\xcdF\x1ds\x06f\xe1c7\xbc\x1b\xef\xb8\xe2b<\xfd\xdc+\xf8\xc1\x8f\x1f\xc1\xc67\xb6\xe0\u0411a\xc4q\x92]\xb3\xa1sS\u0303c\xadC\x9b\x10\x02\x81\xb47g\x10H\x84a\x80@J0\x03\xcdV\vq\xac\x1c\xceg\xcbV\xa3i\vx\x14\x04X\xb0`.N_u*\xde}\xf5\xa5x\xe7\x15\x17\xe2\xd4Es!\x880Qo@+\x93\xfb\xb1\x1cC!o\xff&s\xf7\x8ez\xba\f\x16\x9e\xe2y\x9d\xb4F\xfb_\xe1\x06\xe1\x94\xf5\xe5m\xbcc\x86\xe7\x13s\xec\xf0\x9b\xd2\x06q\xa2\xa1t^\u023b\xc17&c\xaaX\x9a[\xb6\x8bB\x1e\x05\xc7\xce>\x04\x19\x14\x96\xe3\u0646\x81 \xac`\xdf\xc1a|\xef\xae\a\xf0\xcc\v\xafd\xe5Li\x95u\x85\xfe\xae\x10\xb0\xbb\x04\xad\x94\xe5B\x1b\xed\"\xcel\xd1\uf67b\x10\xa7]\xf5>\\\xf8\xe1_\u018a\xf3\u05e2\xda\x17A55t\x12\u06f8\xb8\xb4\xb0I\x003$\x10\x11DU\xc0\x8c\v\u0206\x06\xb7\fLb\xe07\xf9T\xb0\x9f\xf5\x8ac[t\\\xc7}\xd7\xee\x91\xce\x00\x89\xa2V\x81\xb8\x1b\x82\xce\x1e1\xb1Dn\xeae\x86\u06a2.\x11\bF\xb5F\x90\xfdd\xff>\xc3\x1d\x17Zv<%\x03}\xd2>o\x9c\xed.\x84\xac2\xd7h\x8d \x8c\xb0\xec\xac+\xb1m\xfd\x03\x18\x1f\xda\x0f\xe9\u03ad\x10\x84\xb8\xd9\xc4\xe0\xe0 ~\xfa\xf0#\xb7\x00\xb8\x15\x00\xce9\xfb\x9c\x93\xaf3\a\x80;\xef\xbc\v\x9f\xfe\xf4\xa7\xe8\x95W6\xe0{\xdf\xfb\xfe\xe6\x9bo\xbe\xf9\x8a\u077bw\xaf\x1a\x19\x19q~\xdb\xf6\xc0\xa9V\x03\a\x87\xc7q\xee\x05\x17`\xc1\xac^h\x15\xbb\x9c\x14\xeeX\xa9\x05\xa5\x1d\x1c\xa6t\x05i/\x06G\xd3E\x16;t\xbb\x93h%\x1a-C\xe8\xef\xeb\xc1\x19\xabW\xe0\x1dW\\\x84\v\xcf9\x03\xf3\xe7\x0e\xa0Z\x89\x10\x86\x12Ji4\\\x1a\x11{\x16\x9c\x96yb\v\xba\x10\xd6\x14\x89\xd9 I\x14Zq\x828I\x10+\x05\xad\xed\xb6?\b\x02,\x987\ag\xaeY\x89\xf7\\{\x05>\xfb\xc9\x0f\xe3W?\xf9!\\v\u1658\xdd\u07cb$\x8e\xd1h\xb62\x95 xz\x1e\xe54I\xa7\u0716\xa8\xd5q\x1c\u02e4\xf1S\x15\xf1\xc9\xf6+T\xb6s\xc9(\x87T\n\xed\x1co!\x87W\xc8\x13e\xa0M\x1b\xe5\xd3\xfd7E\xc7\xd8%c\xa5\xb4C\x98\u0734)\x03\fr\x97\xd7\xccy/\x9f\xd9\x11\u00a8\x82##u\xdcv\xefCX\xf7\xf4K0ly\xeb\x16.3\x05\xb0\"\xdd\xea\x1b\xada\x8c\v\x84v\x1d#\xb3\x81\x88jX~\xcd\rx\xe7o\xfd\x9f\xb8\xf23_\xc0\xa2\xd3V@\n\x89\xa4\x11\xdb\u039d\xa8\xb0\x9b\xc9p\xfb\x80@U\x01\x11\u065d\xa0$B@\x94u\xab\x85\xf9J!\u05c1\xa6X\xa2i\x92\xe99O~\xc6\u067f\u6f06\u0311\xde-\u00db`\xd2\u0667$ \x14\xa8V\tQ\xbf\x00E\xe4\xe6\f>\xc3\xc6g\x0f9\xf5\xa8 P(\xec\xb9L\x87\xdb\xee7J)Q\xe9\xed\u01e1]\x1b12h\xe9\xa1\xf6\xfc\x11 \x88\xe3V\x93\x84\x103\u05ad{\u426f\xfe\xf9Ww\x01\xc0\x0f\xee\xbe\v\xdf\xfd\xcewO\xae\xce\x1c\x00n\xbe\xf9f\xfe\u05b7\xfe\x15\x00\xf0\xb1\x8f}\xf4\xcb\x1b7\xbe\xbafdd\xe8\xd4\xf1\xf1\t\x04\x1c qE\xef\x8dg\x9f\xc4\xf7\xff\xed^,\xfd\xf5\x9b03\xac\xa2\x157\xec\x1c\x03\xbap\xf2\r\x8a'?s='\x1f\x9f+\u0798\xdd:\xef)\a\xa1)\xae\u02e9\u007f\x8cF\xac\x12\x8c\xaa\x04\x95\x00\xa8U+\xb8\xf4\xa2sq\xe9\xc5\xe7ahx\x14[\xb7\xed\u0126\xad;\xb1u\xc7\x1e\xec\u06bd\x17\x87\x8e\fatl\x02\x13\x13\r\x8c\xd7\x1bh\xb5b(\x13g7\x8f\x10\x840\fQ\xabV1\xaf\xaf\a\x03\xb3\xfb10{&\x16\u039b\x8b\xe5\xcb\x16\xe3\xf4\xd5+p\xc6i\xcb1o\xee\x1c\xabtT1Z\xcd&\x94\xd6Y 62\xc6\xca\xe4\u007fYG!\xa7\xa2\xa0\x8f<:0g\xdd9\x15\xc6ZeCOB\x99@f\xfa\n\xcc\xf4sS\xe2\f\x95E{u\x89\x8c;\x96G\xa2\r\xe2\xd8 q\x1dy\n\x9f\x14\xf8\x17\xe9V\xdc}O\xbb\xffS\xc7\xd5d\x1c\xd4R\x98\x9e\x17p\xdeZ\xa5\x82\xfd\x87\x86q\xfb\xbd\x0fc\u0753/d3\x14\xed\xf2_\x89\xf2\xe0\u2b10\x1b\r\xa3\x13h\xad\xb2\xfc\\f\x8d\xfeS\xcf\xc4\x19\xef\xff4.\xfd\xc5\xff\x84\x85K\xe7\x80\x12 \x99HlxEV\xccr;Z\xff\x9cQ\u0298\xe9\x11\x90\x01A\x84\x04\x1eW \xc1\xe0\x86\x81J\xf2\xa2^\x9e\xa1\xcd%g\x87\xbao\xb9\fw\xf2\x89\xdb\x02*\x88\xbaL\xb5\xc8\x19\x1e\x93o\xfae\xb3R\xab\x91@\xb5_\x02\xbd\x1aF%\x85\xd0\xed,!(C}(\xd7K\x10@\xbd\x02\xa4%\xc8%/13\x14+D\xb5~\x9cr\u0595\u063b\xe99\xa8\xb8\t#\x04\x041\xa4\x1046>\x81}\xfb\xf6\r|\xeb[\xffz#\x80'\x00\xe0C7|\xf8\xe4\x83Y\x00\x9b\xccq\xc7\x1d\xb7\xd3G?\xfaq\xbe\xf0\u008b\x9f\xfc\xf6\xb7\xff\xe5\xbf\x11\xe1\xdb\x0f=\xf4S0\xc0ZI2\x8e_\xfb\xc0=\xf7\xe0\xfc\xb3V\xe1\x86k\xd7\xc2\xc4\t\x88\x15$\x11B\xe8L\x05\xa6\u0754\xd5\x06t\v7\xec\xcb?'\U000b71b9Y\x97\x1f\x14>]@\"\u007f\xbeM\x92\xb1#\xb9\x04\t$\x94\x02\x8cj\"q\x98w\u007fo\x15\x97\x9cw&.\xbf\xf8\x1c\x18\xadq\xe4\xc80\x06\x0f\x1d\xc6\xd0\xe8\x18\xc6\xc6\xea\x18\x19\x9f\xc0D\xbd\x89X\x99lK/\xa5@\xb5RAoo/f\xce\xe8\xc1\xbc\x81Y\x98;g\x16\xe6\xce\x19@\x14\x06H\x94\x82N\x12$\x8d:\xd8(\x10k\x14\x93QyJ\u018ao\xc91\x15\xbd\x93K\t0\x9d\x0e\xe8\x93\xcd*\xcaX-\x8c\xa9\xb8\xdf\xe5\xfb\xa9N\\\x9f\x8f\xbf\x90;\x8f\x15m\x8a>+\xec\r\u074d[\xe5\xd8+\xea\xe9n\xb0 i\u271cW`\u007f\x00\x10$Q\xadF844\x8a\xef\xde\xfd \x1e}\xeaE\x18c \x85\xcc\x02\xb7\x995X\xbbW%\x8b\xe3\x1a60*\xb1\x96\xc5\xeeQ\u96cde\xef\xfc(N\u007f\u07e7p\xfa\u06ef\u00ac\xde\x00z\"v\x05\x93;\xa9(\xdc~ls:!\x81\x80\x88\x80Y\x04\x84\x04!\x05$'\xd0F\x83U\xdb\u0312\xf3\xb3GGA'`\ued01!t\xb2f\xca2~\xb3\xb6\xc4\x17$\x11\xa0% #BuF\x88\xa0\x9f\xa0\xc1\x80&KQ4\\\xec\u0385\xb0Ceo\xdea\xbb'\x80\xfa\x02H\xc3\xc0\xb8\x86\xd66\xf4\x03\x82\xb0`\xf9y\x985\u007f\xb9\xc3\u0383\xec\xaf\x0ed\xc0\a\x0e\f\xd2\xd3\xcf<\xb3\x96\x99{\x89h\xe2\x99g\x9f\xa6K\u07fe\x96O\xbab\x0e\x00g\x9ey\x06\xff\xcd\xdf\xfc5\xfd\xf6o\u007f\x81?\xf1\x89O}w\u01ce\x9d\x17\xef\u0739\xf3w7m\xdaDA\x18\x98VK\v\x00\x18?\xbc\x1fw\xdc\xf9C\x9c}\xe6j\x9c\xbeh&Z\xe3#\b\x1c\x13 \xed\x92\xd1\xfd\xb0\x02\xd7\xd1\x11\x15\xbe\u05ae+$.z\xefOBq\x9d\xa4(rF[\x94\x99\xb0\u0240\xb4\xb6)\xe0\u0292Qc\x87\xeb\xcf\xec\x8d00s)\x02!!\xa4\x04\x89<\x88\u00f8\xad\xb0v]\x85a\x86QvK\xad\xb5F\u0728\xa3U\xf7L\xf5\xc9\xce\x0e:\xcb\xeb\u051d*\x95\u031e|\xeb\x84BG\x0e\x94\xda'\x91\x1757\x99\a\x13w\xe9\u0727\xc2\xdd\xfd\b\xba\xf6\xe1X\x99\xac\xe8\x98\n\xb9J\v\xb9v\x18\xb9\x1d`\x1a\x8f\a\x9e\x0f=\xdb\xff>G\x93\xe4\x1c\n!/\u07cc\xbc\x95\x92a\x17\xf7j-\xc2\xc8\xe8\x04n\xff\xe1#x\xf4\xa9\x97\xa0\x8d\x81\x14\"\u03cf\xd5\x1a:i\x02\xb0.\x9d\xa9\xb1\x96\x0f\xf9\xf4\r,\xc6)\xe7\xbf\vK\xdf\xf9a,\xb9\xfc]\x98?o6\xaa&\x86i6\x8b\u0175=z\x8d\\0\xb2\xdf\u9ca7\xaa5\xb0.\x8f}\x01H\n\xbb;PV\xcd*\xdc\\\xa0]\xb2\xcf\x05\x1f\xfb\x829BfN\xc5\x1e\xbe\xcep\\u\xea\f\x15\xa4.\xe6l\xedWX\xca}\u05c2@\x01\xa1\xd6\x1b \x9c\x19\x80\xab\x04\x8auf[\x9b*XS\xc8\xd1\xe6'pg\xdc)\xac\xc8H\xf6\x05\x16F\x9b\xb0;\\\x9d\xc4\u86fd\x10\xa7\x9c\xb1\x16\awnty\xad\x96\xa5&\x03I\x83\x83\ay||\xe2\u04bb~p\xe7\xaf\x03\xf8\xab\x17^xA\xb8\xbe\xf2d,\xe6g\x03\x00\xdf\u007f\xff\x8f\x03\"R\xcc\xfc\x95#\x87\x0f_1>>~\xe9\xb6\xed; \x85\x84v\x93\xfa\xf5\xcf=\x8b\xbb\xef{\x18\x9f\xbf\xe5\xe3\xa8Uj\xe0\xa4\x01C\x021\v\b\x17#f\x03~\xdd\xc5I\x1e\xc7\xd7\x15wIE\x8e:Q\x9b\xf7\x86\xe7?Q\xec:i\x12\x94\x8f3\x9f\x88\x00\xda+7E\xdd;9\v\xce8\xd6\xe08\xbf6\v\xc6U~\a\x82b\xcee\xfb\xfb\x05\xf9\xdd :n\x88\xc9\x17\x1f*\xfa\x17qI\xa2\x10\x8a\x05\x9e\x8fb\x91\xa3i\xfe\x9bJn_.-\xf2\\p\xe9\xa0c\u0499vB>\x896\x88U\u0691[\u06a0q\xaaM\xe31\x1c&\x03\x17l\x01\xf7\x80\xe6\xd8\x11\xb4&\x86\xc1\u0318\xbf\xf2\x02,\xbf\xf0:\xcc=\xedB\xd4V\xaeFu\xe9<\xf4\x06\t*I\u074a\xee|\xba\t\xba\x0f&\x88\xda\xf6T\xfe\xf7\x8d\xbb\xcej\x02\x8c\x10\xb1b\x18V\x88Z61\x89\x8d\xdf\xf8\xe4\x05\xddU\xe9\x8e3\x96z\xb6p\xfb\xc04+\xe8e\x9e\x94\x93\xc08\xc2\xdel\xc6\xf9\xafT{\x02Tf\x05@\xcd\xd2\x10!\x03\x18\xa1@Bg0hv\x93\t\xb8@haC+\x90[2\b\x02(\x12P}\x12Z\x19\xc8&\u00e8\x18Q\xb5\aKN\xbf\x04\x9b\x9f\xbb\x17c\xc3\a]XE\xba\x83\x96j\u01ce\x9d\xe1\x03\x0fx\xedZ\b0t\xdct|]\x01\x05'*r\u05f2L\v;Q\xdeC\xb1\x87\xc0\x12Cp\xfb\x8d\u0649\x01s\x89/7\x95l\xffDv;{\x8aEo\xf9/\xa4\xbb\xa4-qfND\x9eq\x90\xc9::fn\xebx\x8a\xfd,\xe5\xab\xd64q\xfe|P\xdcm\aRz{\x95\xee\xa4;\x91\xe2\u92b1:\xed\x93\xfc$ .,h\xd4\xf1\f\x00\xc7\u0451\xa73\x81D\x19\xb4\x94\xe3\x90;h\xc5/\xe4\xc6\xf8\xe8\xbc\xd7\x15\xb2\xb7\x843w:*\xb6\x1fC7\x03\xa9U+8ph\x18\xb7\xff\xe8\x11<\xf2\xf4\xcbH\x94\x82\x94\xc2v\x80Z#Nb4\xeb#Xu\xd6y\xb8\xe2\x96?Fm\xfeyH&F\xa1\x9bu$\xad&d\xb5\x8a\xdeY\xf3Q\x9d5\x0fI_\x15I\xb5\x85\xaa\x19C\x0fKH):\xad\xc2\u0476\xe5\xccL\xc9\v\x88\xb9-\xec%\x97\x97\x00 #\x01\xd5\x1fX\x99\u3a36A\xc9\xcc\u0747\"]\xc06.1\xcf\u028b?\xb5\xdda\u0735=`\u07cf\\\x10\u00aa@uf\x00\u0457\x97\x17!\x05D\x108K\\\x06\x9c\x101SQ\v\x91N5\x1c>\x96\x0f7\x04\x11\u008aD2\x03`N`Z\f\x95\u0118\xb3h5\x96\xae\xb9\x04?{\xf2N\x04a\x04\xc3\fA\x84\xa8R\tv\xee\u0705\u077b\xf7\\\xf7\u063aG\xae\xbe\xfa\xaaw\x8b\xa51\xeb\xbb\t\x8e\xdf\xd5\xd9\xc1\x94\xe1\x91\xe9\xff\x05\xca\xe7N\xfe\x93\x89<\u04e5\xb6\xf8\xb4no\xfehL\xb5\xa8\u02f3}\xc0\xc4x\x8e1\xe5\xf5\xe2\xf8#\x03\x13\xa5\xd1Lre\xa7\xf6?\xf4\xf4\xccF\xdf\xecE\x981\xef\x14\u0318\xb3\b\xb2\u0683\x96L\xa0k1\xfa\xfb$\xfa#im]SC\xac\xec\xb2)\x02\\\xcc\xe4\xe5^\xe6\uf66d\xd9K\xa6\x1a%\xf8\x0ev\fA@\x18\n\xe8\x90\x10K\xb7P\xb9\xc0d\U000b72e5K:\xa1d\x85ikh\xdaH.\x1d@Z\xfagP\xceZqL\x96\xa0G\xa26\x10\"\x9a\x1dX\xde}\xda\x12e\x17\xb1\xcf\x1a\xa3\x9csN\u0536fPA\xab\"\x84\x1d\x02+\x02X1\x90$\xe8\x9b9\a\x9c\xb4\xb0\xeb\x8dg\xa1\xb5r|s\xfbbI\xa2LT\tjc\xa3\xa3;\x9e}\xf6\xb9G\xef\xb9\xe7\xde\x13\x1dO\xfc\xef\xee1\xa5U\xe4\x82\x05\x8b\xf9\v_\xf8m\x00\xc0\xb5\xd7^\xf7\x8d\xab\xaf\xbe\xfa\xcf\xce?\xff<\xf4\xf6\xd4 \x82 +]\xfb\xb6m\xc1\u05fe\xf6u\xac\u007fu3\xaa\xbd}\x99:\x94\x19\x99BP\xb1\x84\xce\xf0\x03\xcbK\x97\x04\x04\x94\x1761\x9d\x81_\xc9\xd73\x93\xfb6\x1de\xc1\\n\x92B\xceSa\xf3T\x9c\xcar\xbb\xae\xb1\x8de\xd1\u0669\x96'\xe8LZ\xc81\xb9\u043a\x13\xbb\xc41\x16T.\xed\xda\xd2\x1c\xa9\xf4\xfc\xa5\xf9\x9d\xa6C.\xc2\xc7\xc5\\a\xb0\xed\u0213\x9cKn\x8c\u0166\xd3b\x9e\x1ac\x15\xfe>\xceY<\u0145Ix\xb517\x81\xb3X\xb1\xd5\x15T\xa2\n~\xb6i\x1bn\xfd\u07bdx\xf2\xf9\r0\xc6r\x95\xad(\u0206p\xb7\x1a\x13X\xb1r9\xae\xff\xe5/a\xe6\xcak\xd0\x18m\xc04&\xa0\x9a\x13\x88\x1bc\x88\xeb\xa3h\x8c\x0f\xa3a\xea\xe0\x19\x84\xfe\xfe\x10\xbd\x01\xb9\x05\x9a\xba\x9c\xb0\x9cuC~\xd7\xec\xfcGT\x12C\xb5\x9aH\x9a\r\xa8f\x03\xaa\u0544\x8acOIj_\xbb&\tsj\x12\xfd\x03\x01\xc4\xfc\x10jV\x80$\x12.\u06d4\u06ba\x1c.\x1d\xccPG\xf4\x1by\x83T*\xccl(\x03\x17\xdb\x1ayw\xc32\u0641g43@8+\x00\x82\xb4\xb1\xf1\x82\u02e5\x84\fB\x9b\x89 \x05\x84\x14\x16/\xf7S\xc1<\xf1\x96\xbf\xf4\t\x00\x91 \u022a\x04\xf5I\x84U\t21\x16/?\a\x8b\x96\x9f\x03\x157\xad%\x80\xdb\xc1\x85QH;\xb6\xef\u0091\xc3C\x1fd\x93\xac8\x190s9\x9d'\xfd\x97\xff\xf2\xbb\xb8\xed\xb6\xdb\x01\x00\x0f>\xf8\xe0\xcb\xeb_~\xe9\xc2\xc1\xc1\x03\xab\xea\xf5\x06i\xe6\xec\";28\x88m;\xf7b\xd5i+\xb1t\xd1B$Jyy\xb2\xe4\x8a5#\x00[\xb8\x85\x01I\x8c\x88L\xae\xb0\xf4\v3O\xd98w\xed\u01cfv\x19\x9e\nO\xee\xfe[\xf2\xff\v\x0f\x1b\x17(Wm\n\xbf\x1b\xa7\xeeE\x1c]\n\xbd\xefg\xcdDG\xfd\xbe\xa7*\xe59D+\xa1!]G.Jv64\xfd\xf0\x8ci\f;[\xb1\x85V\xb4\xb6]\xb86)[\xa4\xcd>\x98\xba\x9f\x8d\\L\xe8\r\xff2\x15\xb2\x84!\x89\u0219\xa9=\xf9\xc2\xcf\xf0/w\u070f\u05f7\xec\x00\t{\xedi'\xfaI\x92\x04q\xab\x893\xcf:\x03\xd7\xdf\xfc\x05TW^\x87\u047a\x85\b\xadq\x9b],\f\x01\xaa\"@\xb3\x03\u0318i\v\xb9\xec8 y\x81J'\v\xa9}\x80Q\n&I\xa0\xe2\x16T\u0482j5\xa1\xe3\x16t\x12\xc3\x18eM\xbc\xd2\x04#cR\x16v\xa6\xb4\x0e\x88P\x91\x02\x95H@\xf6Hk\u0125\xd3E\x8f<7[\xcam\n\xfcXXj\u03dc+\x0e\xec\v$\x84\x0e\x88\x8f<\x81\x90\xb5\xae\x8df\x85\b\xe7\x86\b\xaa\xd2m6J\xae,!,W\xde\xcb\a-t\\\xdc%\r\x89r\xd6M\x10\tDB\x00\xcd\x043\xfa\xe6b\xec\xf0^\xec\xda\xf2\x02\xac\xed\x88=\x97B\x10)\x95`\u018c\xbe\u015b7o\xfe\xfe\xbau\x8f\xef\xfa\xbb\xbf\xff:\xdd{\xef\x0fO\xeeb~\xdbm\xb7\xe3\x87?\xbc\a\xdf\xfe\xf6w\xf0\x95\xaf|\xa5\xf1\x8do|\xe3\xf9\xd1\xd1\xd1_\u077bgOPo4\x9cT\u06b27\xf6\xed\u074b\xdd{\a\xf1\xb6\xb3\xd6`\xe1\x82yH\xe2\x96\xdf+\xd9\x13\ufdb9\x12\x8c\xc0\xf5\xea\xe9\x10\x91\xdb:m\xfawx\u040aB\x1e\xbf\xb8qG\xca\x0eP\x12\x14C\xdd!$\x97\x96\xd5Q\xb4:\xdc\x0e3\t\xf6\x89)\xaa\xdc\xe6\xc3\xd1D\x88:\"\x00\u0085x\x1b\b\xb2;)ry\xaf\xe2x\xcd\xd5\x18\x88\xb5\xed\xc8\x13\xa53.y\x86\x8f\xa7|\xee.\u02d4\u007f\xdb3S\x86\u074a\\q`U\x88$`H\"\xa8\xf4@\x1b\x8d\a\x1f{\x16\u07fe\xf3\x01\xec\xde\u007f\xd0F\x02\xc2\xc2*Zk4\x1a\r\x04\x02X{\xd5\x15\xb8\xf6\x93\xbf\x05Zr\x15\x86\xc6\x00i\xf2\x80m\x12\x02,\x04tU@\f\x84\xe8\xeb\x0f\xd1\x13\tH'+\xb7]\xa6/\xcfLC\x8d\x9dB4\x8eaZM\xa8f\xd3v\u07ad\x16t\u0702Q\xca\x1ax\xb1K\xaf\xef\xf0\xff\xc9}|\xb2\x8e\x16\x80$B\x14\nD5\x89 \xb2\v\xaf-\xea\x1e\xba\xc3\u014e\x82D\x97\xe5\x9f\U000ee768[\xa3\x90c\xe5F\x10\xa4\x04\xc2\xfe\x10r^\x84\xa07\xc8]\x1c\xcb`Ka\x8fQjM\x9c\xedR\xb2\x85\x9a\xbc\xd0\xe7\xce\xf4\x1bA\x96\"L\x02\xe0\x86F\xc0\x01X+\xec\u0776\x1e\xf5\xb1#\b\x82\xa8x\xcf\x18\x8dE\v\x17\xecz\xfe\xf9\x17\x1e\xfdy.\xe4\u04c2Y\xd2\xc7\xfb\xdf\xffA|\xff\xfbVEu\xdey\xe7\xbfv\xd3M7~\xee\xdak\u07e5\xe7\u03db\x870\x8a \x830{\xee\xd3O=\x83\xbf\xfc\xdb\u007f\u00ae\xfd\x87\xd17\xa3/\xe3\x05\xa7%\u0278N/e\xb6h&hCP\u01a9\xc9\x18\xa5,\n\xfewV\xd0\xf3\xa8Fg@E\x9c\xdd\u0113\xc1F\xecc\xbfmE|\xda\xed3\xbb\x1b\x86\xf9h\xeb\xe7\xa4\xff\xb69\x9d\x12\x89]r\x11@!\x84\x86$\x03\xc9\xda\x0e\xab\x19 6\xc7~F\xdc)\x8e\x95F3Vh\xc5\x1a\xb1b\xa8\x94On\xfc\xce\xcd+\xd8\xe9U\x94\x168\xcf \xcb\xc0\xa7(z\x16\xb1L`\x92\x88\xaa5\x8c\x8eM\xe0\xce\x1f=\x8c\xef\xfe\xe0\x01\x1c8x\x04R\bh\xa3\xa1\x12\x858NP\x1f\x1f\u01cc\x9e*>x\xe3\xc7\xf0\v\xb7\xfc\x1e\x9as\u07ceC\xc3\x1a\x82\xb5\x85\x05\xb5\x82V1\x94\x8e\xa1B\x86\x98\x15\xa2\xb7?@o(\xac\x02\x9a\x19\xac\xadD_\xb5b\u8e05\xa4\xd9@\u04a8#\x99\x98@k|\x1c\xf1\xf8\x18T}\x1c\xaaY\x87\x8a\x9b\xd0q\fVy\x17n\xb4\xe5\xb2\x1bcla\xd7\x1aFi\x98D\xd9N\xde}h\xa5\xdc1r\u05c2\x01d@\xa8\xcc\x0eP\x9b\x1f!\x9a\x1d\x02\xa1\xc8!\x17\x81\x82\x01\x96\x95\u06a7\x17\x9d\xef\xf5\xc2\x05\b\xab\xfc\xbe\xe3\fb\t\x04\x10\xf5H\x88\x81\x10\xb2W\xe6\v\xfc$X)\ta\xe3\xf7\x84\xc8\xe1\x15\xe1\xcf6\x04r\xae\xbc{\xa1t`\xe2\u4ed6o\xceh\xc5u\xcc]z\x06\xe6-Y\x03\xad\x93\x82\xbf\x0e\x91\xc0\xe1#C\x18\x1b\x1b\xff\u022e]\xdb\x17\xd8\x19\xe0\x9d\xf4\xf3Z\xcc\xe5\xd1<\xf9\xb6\xdbn\xc7K/=/\xfe\xfe\xef\xbf\xc1\xb7\xde\xfa\x8f\xeb\xbf\xfa\xd5?\xdf\xd6l6o\u063f\u007f\xbfh4\x9a\f\"2\x8e_\xbdm\xdbv\x8c\x8eO\xe0\xfc\xf3\xcfE\u007f\u007f\x1ft\x12\x03\xccH\xed\x99S\x87\xba\xb4\x935>\u036e,\f\xe2\x18\xa0\x92\xff_Z\xf5\x927CS-\bS\x04y\xf04\x82\xd2\t\xc7\xfe\x1cn\x1bz\x02V\xf8UC\xe2\x86\u04e6\xb0(\x1d\xaf9\x9a1\x8c8\xd1h\u0116K\xae\x8d\x1bxj\x93+e\u0459\xf1\x99\xee\xb5\xdb\xf9\xd1\xfe\xf85\xb7(qL$!\x11Vj\u0631\xef \xee\xb8\xfb~\xfct\u0773\xa87\x1a\x10B Q\x89\xa5\x1e&\t\x92V\x8cU\u02d7\xe0\xc37\u007f\x1a\xa7]w3\xf6%K0>\x9c \x022X\x85a`\xc00! g\n\xd4z\tU\x18\xc0\xc9\xf8-d\x92v\xda1t\xabe!\x948\xceqo\xa5l\xc16\xd6\x05\xd0?\xb9\xd46%\xf1\xfd_\n,\x1dW\xf4\x84\xb4\xc6o\xe9,\x87\xdc\n&\"\x01\x8a\x84\x9d;\xb4l\x97O\xa9\xaa\xd2?\xd7\xee\xa4R\x99\u027d\xc7\xc7\xcf\u0198~(6\x01R\x12\u008a\x00\xe6D\bf\x87\b\x04\xd96\x8d&\xbf\x963\xa7R\xe3\\\x0f\xb9\xe8\x1a\u019eL\x97\n\x9d\\\xaa\xae5@\u02c0[\f\u048c0\xea\xc5\xc8\xe1\xbd\x18\u0739\xd1y\xe2Pv\xce\xc0\x06Q\x14.\u073dg\xf7\xb7\x9ez\xf2\xa9\x03\xdf\xfd\xee\xf7~n;\xf3\xe0h\u007f\xe0\x82\v.6\xeb\xd6=*\xae\xba\xea\x1a\xf3\xcew^\xfb\xad\u035b^o\xd5j\xd5[\xef\xbc\xeb\xee\u0783\x87\x0e\x19\x80\x85R6\xe0\xf6\xae\x1f\xfc\b$\x04\xbe\xf8\x9b\xbf\x82\xc5sf\xa0>6j\xbb)\x12`\x92\bX\xb7\t`\xc8R\x00\x8b\xd6\r\xedb\xbd\xa3\xc2~\x8f\xb7\bN\xf5\xbb\xd2 a\xff\x8by\xacW\xc1\x9e\xaf V!tr\xc6A\x1d\xf7S\xe9\x0e\xe5h\ni7\x1e~Y\ta\"\xc8\xcc{$\xdd\xd2\u04d4\u01fe\x9d>\u0775\x88\xb3\xed\xbe\x13e}s,Fn\xa9j\xda\xf0\xa4|\x98\xe2\x0e\xadS\xaa\xc8m\xef\xc00C:\xc8\xe3\u535b\xf0o\xf7>\x84\xd7\xde\u0612m\xd5ce\xdd5\x8d\xb1\xa6gW\\\xf1v\\w\xe3/\xc1\xac\xb8\f\xdbFfB\x0f7QqT70\xdb\x10b6@@\x88f\x00\x95\x9aB\xa04r\xe1g\x8aU;\xf8\xc0\x15\xaa4\x9e\xae}H\x9c\xa6!Y& e\x05\xb2\xa8\x9c\xf5\xf8\xfe\xc6\xd22\x89\xb5\x15\x10\xb1\x00sP\x84\xb9\U0008a360W\xa2**\x80\x00\xf4\x91\x04\x1csg\u01b7A!g3\xe3\x98\x17|_\xa835\x0e\x80\f\x04\u0090@\xb3\x02\xd0@\x88 @F)\xb6?\xc3]\x9b\x12\x9b8$ \x03\xeb\vo\x8c\xce\x17*a\xbfg\xb7[\x94\xef\xc0\xd8W\xde\x02H\f\xb4\xd2H\f\xc0\x94`\xe9\ua2f1\xe9\xc5\xfbph\xef\x16\x84Q\xd5\xd5\x0f\x01\xa5\x15\xf6\xee\u06c7\xbe\u07be\xcf\x02\xf8\xe2\xcf3\xcc\x12\x1c\xcb\x0f]u\xd55\xe6\x81\a~\"\xae\xbb\xee=f\xf5\x9a3\xbe\xff\u66dbxdx\xf4\xd6\x1f\xddw_\u07e81LD\x94$\t\xc0\x8c;\xef\xbc\x17:\x89\xf1{\xbf\xf5+8u\xf1|\x8c\x8f\x8eBi\xe3\x06E\xe4.t\x82\xc86\xd3%\xfa\xc4\x13\xd8rwS=\x1eMa/\n\x88r\xbc\x9c=\f\xc1\xff\x1c\x9e\xe5g7\x1b$\u007f\xc03\xd9`\xf4X\xf8U\x93\xcb\xf49\xf3\u02a1\xb6R\x99)t\xb9\xfb\xb1\xe2i.\xa6\u06b0\r\\N\x95\x9d\xcaX\xba\xa1\xc9\u04c1\xdam\x1b\n\xdcv\xcfG\x9e2\xbadn!L\x9e\xaa\x98\x19\bC\x89@\x06x\xf2\x85\x9f\xe1\xbbw?\x84\x9d\xbb\xf6@Jk\xbf\x1a+;TTI\x82(\fp\xf5UW\xe2\u068f\u0708#\x8b/\xc4\xd6\xe1*\u0091\x16*\xdad;G\x8b\xef\x02\x88\x80\xa0_ \xecaH\x9d\xc0$\xbeN\x92\xb3\xf3\xc7\xe9\xcfx\xe2\xa6\xe2\xf1\xe2\xdc\u007f\xa4M\xb0S\xb0,\u02c4c\x9c\x15Hr\x8b\x06\x1b\xdb\u0676\ufb6dw\x8c}\x05Y\x13\xa8\u032f\xc0\x04\x02\xeaP\f\u0772\xb1z\xd4\x01\x99g\xb9\x9d\x00\x00 \x00IDAT\u0561\xcde\x8d\v\x17\x1f\u00df\xd83d@\b\x02\x82\xe8\x91\x10s\"\u020a\x00\x99\xa2\x81\\g!\xf7--\x9c\x96CJ\xabh\u054e+C\x9c\rk\x99\xa8p\xbc\bN0\x06\x02\fC\u0156\xc2j\x1b$\x8d\x81E+\xd1?\xb0\x04\x87\xf6lvL\xa1\xdc\x1a\xa0>\xd1\xc0\xc1\x83\a\xdf\xcd\xccU\"j\x1e8\xb0\a\v\x16,9y1\xf3\xf6\xc7u\u05fd\u01e4\xf8\u04eaUkn\xbb\xfe}\xef\xf9\xb5\xcb/\xbb\f\xfd3fP\x14\x85\x1c\x85Qv\x83\xdd}\xef\xfd\xf8\xef\u007f\xf2Wx\xfc\xb9\r\x88\xaaU\xf4\xd4*\x8e\xb5b\xe9n\x86rq\x05\xa1\x18\x12\x9c}\xdd\x13\xa6\xd1\t(\xe8e]*\x97\f\x1a\xdb?LF\u0663\u008e\xc2d\xd1\xc5\xc5!g\xa1\"S\x113o\x87\xbc\xa9=\n\xac\xa3H\xf21\x17r`\n\xf9\a\xb3g\x00V\xb2s\x98\xe45'\x9bg\xa4B\xa0fK\xa1\xd92h\xc6\x06J[\\<\vW\xce\f\br\xd6\au\x8c\u073c\u063e\xb9B\xdef\x95\xcb6\x81I\x04\x01HH\xbb\xdb\xc8\xdc+\xc9\xfe\x1bT\\W\xd86}F\x19$\xb1\x816\xe9\xa2n \xa2\bs\x97\xacAT\xed\xb5\xe7\xcb->\x82$\x12\xa5\xb1c\u01ce\xd5/\xbf\xfc\xdc\"\x00?\x97\x85\xfc\xa81\xf3\xf6\xc7'?\xf9\t\x9cw\xdey\xf4\xe0\x83\x0f\xe1\xb6\xdb\xfem\xe3\xef\xfc\xce\x17\x16\f\r\r_\xb2\xff\xc0~\xeb\a'\x88\x8c\x1b\\\xec\u0735\a\u03fd\xf8\n\xa4\x108u\xd9R\xf4\xf7\xcf@\xa2\x8d-\x8c\f\xebW\xec\xd6\x16Q\xd8bR\xe6'\x91]s\xe2\xc4LC\xb9C\xe5V\xd6\x05\xe7\xfc\x94n\xae#^)j+?m\xc0\x01\xb5\xd5\xf5\x92\xd0\xf3n\x90E\x19\x0419\x0e>\x05V\x8f\x12\x96\r&g\xc5\xf0tw\b\xee\x05\x94\xb6\xd8x3\xd1V\xd5\xe9\xe4\xf9:\xf3W!\xcf\x12*\xff\x1c(\b\x11\xbb,b\xe4\xf9k;j\xa8 \xd4j\x154[1\x1eX\xf7,n\xbb\xe7\xa7\xd8?x\x18a\x10\x80\rCi\r\xa3\r\x1a\x8d&\xe6\x0e\xcc\xc6\xc7o\xfc\x10.\xb9\xfe\xa3\xd8Z[\x89\xad\xcd\x1a\x82\x98QmiH\xe5e4\xa4\xb9\xa0\xc4@\x00\x04\x11l\x82|\xa1\x9b\xf6\xbc*\t\x85\xecQ\x12T`\xc1\b\x19 \x8c\xaa\b\xabU\x04a\x04\x19F\x96\x1dS\x18(S\xc7\xf5\x05\xe1\x162a}\x83D !\x82\x10\xe4\xaa3y'\xc5\x17\xf8\b\x06D@\xa0\xaa-\x98B\xc3v\xd1\xde.\x87\xfc\v\x92\xca\aA$l7\x1e\x04\x02\"\"\xc89!\x829\x91\vW\xf6\xad\b\xbc\x06\xbc\xf4J\xf1\x96\xea,\xe5\u02e4\xc9!E]\x95?\xe8N\xcf\x03\x80V]C7\x8c\xfd\xdb\\\ve\xed\x174v\xbd\xf1,\x9a\x8dQ\u0220\x92\x89\x88\xb4V`c\xc4\xf2\xe5\u02df\xbd\xfb\xee{6\xfc\xc7\x00\xb4\xe4\xf1\x9d\xef|\x17\xd7_\xff^\xdc\u007f\xff\x03\x00\x80{\xee\xb9\xf7\u01fbw\xef8\xad\xd1h\x9es\xe8\xd0!J/n\xe3\x9c\xe6FG\xc7\xf0\xcc\v\x1bp`\xf0\b\x16\u031f\x83\xc5\v\xe6B\b\x91\x19)\x19\x88\xccMQ\x90_j\u06f8\xcd\x1e'\xfdXg\x95\u9ad9l\xfe\u07aet\xa4\x82\xea\u0447W|\x9b0\xf2\x1c@\xba{\xb1{e\x8a&\xe7\xb4w\xe88\xa6\xb9\xbb8\xdeY\xc0t\x06\xa8\xd3}h\xc3H\xb4\xb1~\xf2\x0e\x1b\xb7B\xa04\x00\xa4\u0762\x81\vXr\x0e\xd9z\xdb|\xcf\x11\u0424\xb0K\xba \b\x81 \bP\xadD\u0635\xef \xfe\xed\x87\x0f\xe3\xc7\x0f?\x8d\x91\xd1q\b\x17.\x92R\x0f\x9b\xcd&\x96.\x9c\x87O\xdc\xfcK8\xe3\x1d\x1f\xc0\xab\xb4\x14{\x92*\xa4aT\x9a\x1aA\x92\x17\x12\xf2\xa8\x91l)<\b\x88!B\x80d\xfe\x9e\n\xe7/\x1d\xbe\x91\xb0\"\x19ae\xecA\x18BV\xaa0I\x82\x03\x9b7`\xcb\x13\xf7c\ubccf\xe2\xe0\xd67 \x84D\xcf\xcc\x01\x17f\xe1\x0f3\xbdE\x9e,\xbf\u074aml!\x97A\xe0\f\xe1<\x0e\xbe\xa7\xbb\xf1wz\x90\x04\xaaX\x93.\xa1\x1c^\x9e\x0e5\x99\x8ab8\xa2B\x87.$\x10\x84\xc2\x05-\x13\xc4\xec\x10r~\x04\n(\x17\x06Q\xb7\x96\xa1\xfb\xfe\x90\xf8\f\x02\x89(\n\xa1\x94\xc2\xd3/\xbd\x8a{\x1f|\x12\xafm\xden}\u0209\xa0\x13e\xe9\x87J#n\xb5\xb0r\xd9R\xfc\xe2\xa7n\u0092\xb5\xef\xc1\xcb\xf1\\\x1cIB\x04\xc2 L\fd\xe2\x16\x88\x94\x1dbl\x04\x0fI\x17\x15(\x81\x80%\x02- \xc2 \xf7\x01/`\u0294\xc1G\xa9\xc531P\x1f>\x82]\xaf<\x8b\x9d/=\x81\xc17_\xc5\xf8\xa1\xfdPI\x82JO\x1f\xf6\x9ey>.\xb8\xe1\xd3Xx\xfa\xb9\x801\xd9\f\x83\xdb|\xe13\x1e\xb6\x83%\v\x1eZ\x93\f\x1e\x01\x17\x06\x1d\x10\u012c\xd0r\xf1\x87\x12P\xc3\xc2]>|\xc5\xf6D\xe6l \xb2\x85<\f\\JP_\x00\x9a\x17\x82B\xe1\xcc]\xb4\x1a\x83\xbb^\x831\x1a\"\xc8\u0565q\x92`\u04d6\xcd\x17\xa6\xbf\xfb\xca+\xae\xfa\x8f\x01h\xe9\x85\xe2,5\x17/^@D\xd4`\xe6\xdf\xe8\xef\x9f1X\xadV\xbf\xb8a\xc3\xcfp\xe0\xc0~03\xc7IB\xa9\xb8\u854do`\xcf\xde\x03x\xed\xcd\x1d\xf8\u055b?\x86\x95K\x17\"N\x12\xa8$\xb1\x1d\x1d\vH6\b\xa1\x10\xb0C\xa9\xa9\x8bS\"\x15g/G\xa7\xfcd'V\"w@4\x82\f\x15/w;\x14\x05.H\xb1|\xa6\xaf\xa3=\x01t*d)\xf3\xf6\xe7\xe3(\x9e'\xa2\x90\xd3q\x16\xf0\x94q\x94\xe6s*\u05c5\xa7TC\u035c\x8bC\u041ejFY\xdef\x16\x15\xe4\vm\xbcX7\xf6\xd8\x1a\xe4\xb6\xfd\xd5J\x15a \xb1{\xffA<\xf8\xf8\xf3x\xf8\u0257p\xe8\xc8\b\x84 \x186P\x89\u016e\x95\xd2\xd0*\xc6Y\xa7\xaf\xc0G~\xf1&\xcc=\xf7j\xbc\u051c\x8b!\x15 $\x03\xd2\f\xd1\xd46\x04\x81$d\xe4\xe0\x8bD\x83\xb5\x82\x86\x82Jb\x98\xa6\x027\x19aS@$\x01\xa8\" D`c\xcd\x18PI\x8c\xe6\xd8\b&\x0e\x0f\xa21z\x18I\xa3\x0e\x93\xc4\x18\x1d\u070b}o\xac\xc7\xd0\xeemh\x8d\x8dX\xf5fda\x16\xad\x12\xec}\xf5E\xcc^\xba\x02\xb3\x97\x9d\x86\xb0R\xb5\xf8\xbb\u020b\xac\xf0\xf8\xd7$\x85\x85K\xb2,Z\xce\x06\x9fS^\x1bi\x82\xd1\xcc\xc0\xed<\x14$3\xa0\xbdE6\ud4055\xf4\xaa\x046\\\x19\x82\x80\x1eKCDE\xe4\ucb2eq'\xf0\x98F\xdc\xe5\x9at\u0443BB\x04\x12l\xa4m\f\xd9X\xdfsw\\\x8d\x01Z\x9a\xd1L\f\xa2\x84!\r{a\x16\xee}$\n$\x02,8\xe5llz\xe9'\xd0*\x81\x91\x01\x04\bA\x10bl\xbc\x8e]\xbbv/x\xe1\xc5\u7bbb\xe8\xc2K\x1e\xf8\x0f6\xcb\x14\x05\xfd\u99df\xc4\u06b5\x97\x83\x88\xc6\x00\xfc\xce\x13O\xac{\xfa\xae\xbb~\xf0\u01cf=\xf6\u061am\u06f6\xd3\xe8\u0628VJ\t\xa54\x81\x19\x87\x87\x86\xf1O\xffz\a\xf6\xef?\x88\xcf\xfc\xd2\r8e\xf1\x02\xf4\xd5\"\xf4\xf7\xf7C1\xa1^o 1\x12\xa1\x90\b\x9chEd\xae\x8a\xdc\xe9}\\t\x01\x9a\xd4\u00ef\xddN\x97\x00DPmE\x9a\xba\xbe\xceT_K\x87\xa2>\xf7\xc5\xef,i\x1a\x05\xf2h\xa0\x93N\xaa!\x1f\xd7b0mHE[HE)\xceB$\xb4\xb6\x18\xa7f.\xaa\\\x19\x1dA\x1d\xa9\xbc\x9d<\u0715\xbc\x00\x8aB2\x8d\u00e1\x830@%\n161\x81\x176l\xc2=\x0f<\x81\u05f6\xec\x80R\x1a\x950\xb0\xbf\u07e4\u0656\x84\x9e\x9e\x1a\xce9\xfbB\xbc\xf7\xa3\x1fEe\xf5Z\xac\xaf\xcf\xc0\xa8\x91\b\xa5\x01\x91@\x90\x00\x91\b!\x03\x03\xd5j\xa01v\x18qs\x1c\xcd\xd1\u00d8\x18:\x80\x89\xe1\xfd\x98\x18\u068f\xb81\x0e\u05b1\x85*\"\x89\xa0VEP\xadA\b\x89\xa4\xd5Bsl\b\x8d\x91!\xc4\xf51$-+\b2*\xb1>+I\vB\x06\x90a\xe82?M\x16\x1bW\x1f>\x8c\xc3;\u07c4j5\x11\xd5zm\x97\x9aA6\xb6C\xb5B\x1b\x99\xbfF\x10\xa2`\x14=\xcd\u055b\x00\x88P\x00\xb3C@\x10\xe4\b\x01\xb1\x014\xa0\x13\x83\xc4\x15_)\b\x95\x80\x10Fv\xf1@E\x80g\x05@U\x80\x8d\v\x9dqP(qq\xb8\xef\x13\x00\xda=8\x19E\xd6V\x16\xb0.\x03\x18\xa9AZ[k\xect7G\x84D\x03\xf5\x96\x86I\f(6Y\x8a\x14\f@\x9a\x9dy\x9a\x86\x90U,Xr&z\xfa\x060:\xb4/\xfbE6\xec9\xc1\xf0\xf0\xe8\xec\x87\x1e|\xe8b\x00\xffQ\u0327z\xac]{9\xa7\x90\v\x00\\q\xc5U\xdfc\xe6\x9f\xfc\u065f\xfd\xd9o>\xf1\xc4\xe3_\u06bcy\u04ec]\xbb\xf7\xa2\xd5j\xb1J\x12JO\xe4\x8f\x1fZ\x87\x177\xbc\x8a\xd3V,\xc3\xcae\x8b\xf1\xb6\xd3O\xc3\x05\u7781\xd3O[\x0e&\x89\xb1\x89:\x9aZC\x92\x84dv>\xe9\xd6\xf6\x899\x87.\x98\x8f\x06\x05\xee\xe2nX\xb2%\u0325\xc9\xdc\x01\x9f\xf8\xd1\x1aT\xd2\xf5\x17Cp\xbb\x8f\x0e\xdb\xe1\x96\xf6\xa7uc\xa2\xd0q\x94d\x9a\xe6B\u046d\xf0+m\xe9a6\x9b\xb3]\x8a\xdf)\x1fL-\x00\f\xa7v\r\x94\xb3=\x88\x8b\x8e\x87(H\x80\x00\x00Q\x18 \x8aB\x8c\xd5\x1bxu\xe3\x0e<\xb8\xee9<\xf1\xfc\x06\f\x8f\x8c#\f$\x82@Bi\xe3\x15\x16F$\x03,;u\x19.\xba\xe6]\x98\x98\xb3\x06/\xef\xd7ha\x02\xa1\xb4\xe97Fk\xa8\x91\t4\x8e\x8c\xa21<\x88\xe1}\xdbpx\xcf\xeb\x988\xb2\x17qs\fI\xab\x01\x1d7]\xb6g\xee\xfc\x92\x05-\xa4CP\xa3-\x17\u06a7\xf39\xae9\tB\xa5\xa77\x17\x1f\xa52}\xad\x11\xd7\xc7\x11\xf5\xf4a\xf1\x19\xe7\xa3\xda7#\x17\xbdd3I\xab\xd4$\x87\x93\xa7CSHYlb&=Y\xd4I1\n\bbf`\v\uaa06hh\u02002\xbb\xe1\x00\xb0\t?\x86\x81\x8a\x80\x98\x19\x80{\x84\x9bW\xf8\xd7iz\x8fP\x9b\xf6\"]\x9c\xfd\xa6\xc8\u3d34[\x05\basS\xc9*\u008d\a\u02754#\xd1@\xa8l\xf1\xce\xe6\x02i4`F\xff4\xe8\x9d1\a\x03\vWal\xf8@\xfeur\r\x03\t\xec\u077b\xef\x1d\x00\xfe\x14\x00\x9e|\xf2q\\~\xf9\x95?7\xc5\xfc-\x13M\xfe\xe3?~\x93~\xe5W~5\xbb\x95\x1fz\xe8\xfew\xdf}\xf7\xbd\u007f\xf2\xf4\xd3O\xbf}\u02d67111\x818I`t\xb9\x99\xd9Y\xa7\xaf\xc4\a\xdes\r.\xbd\xe8<\xbcm\xcdJT\xab\x15\x8c7Z\x88\x95-\xe6\x15$n\\\n\x87zs\xdb\x14\xfd\xc4<\xba\xb1(\xb8\xf0yqPk\xda\xfa\xe2\xb43\x17\x05^\xcc4@}/v\xfd\xe8f\x01\u04c7X\x8eZh\u0140r\xcc\x10\xad<{Z\xe7p\x98\xfa\xa9\x982\x17\xc9\xff\x8f\xbd7\r\xb2\xe4:\xaf\xc4\xcew\xef\xcd\u0337\xd5^\xd5\xfb\n\x10\r\x80X\tb\xe3Np\x81(B\x94DK3\x1cihY\xd684\xe3P\xcc(\x183\xa6\x15\xe1\t\u02e3\x88\xb14\x94\x1c\x1e\x85\xc2\x16I{,\xc7\f\x15Z\fQ\x96\xc4m8\xdcA\x90\x00\xb1/\xc4\xd6@7\xba\xbb\x1a\xbd\xd6\xfa\xf6\x97y\xef\xe7\x1f\xf7f\xe6\xcd|\xf9\xaa\x01nSptF\x14\xd0\xdd\xf5\xeaU\xe6{\xf9\xce\xfd\xee\xf9\xcew\x0e{\xbe;\xec\xf1\xe1\xa9\xee\x98\xf3+M\xfd\u0749\b\x81\xab\xc4/\xaem\xe2\xd9\x17O\xe2\u0467\x9f\u01c3\x8f=\x83\xd3g.\xd8\u079ep\u0563\xbfj\xc0r\xf4J\n\xcc\xce\u0361\xb9\xb4\a\xa3\xda,X\xd5\x10F\x01\x94\x8a\xec4\xe7h\x04\xbd\xb9\x81\xde\xca9\xf4\xdb\x17\x10\x0f{\xcez\x16\xde|@\xb1kM$\n\x00U\x90(ybs.v\xf3\n/z\x12[/\x96\x1dW\xbe\x11o\xfa\xb9\xff\x12ox\xeb\xddPa\xe4\x85<\xbb\xa6\xa7\x14\x10A\x00\x15FPadm3\x84\u020a\x18P\x15oWV\xb5\xe7Z}\u00dc\u075f\xd6\xdf\xc4\x00\xe7G\xa0N\x02c\x80\x81{OC\x82\x95 \x06\x04\x9a\r@\x8b\x01\x8c\xb4 \xcdd\xfd`R\n_PQ\x1b\x9fs\xe5<\xa6h\xc9*\xf3\n\x9fw\xa3\x13\xc4\xfd>\xe2Q\xec\xb2U\r\xfa\xfd\x18\xeb\xed>\x92~\x8c\xa8\x1bC%\x06R\x00\x01\x03\xd0\fh\xeb\xf1\x04\x86\xf5e!\xc2c\xdf\xfaS<\xf2\xf5\xff\xdb6\xa0\x9dm\x80N\x124\xeb\x11n\xb9\xf9\xfa\xa7?\xff\xf9\u03fd\x87\x88.\\\xae\xcc_\xe5q\xe3\x8d7\xf2'>\xf1\t|\xfc\xe3\x1f\a\x00\xbc\xf7\xbdw\u007f\x99\x99\x1f\xfaW\xff\xea\xb7\xff\xf1\x13O<\xf9?>\xf3\xcc3\xf5W^9\x83~\xbf\x8f$I\xc6~\xfe\x99\xe7\x8f\xe1\x99\xe7\x8f\xe1\xe0\xbe\xddx\xe7[\u078c\xf7\xbe\xebN\xdcz\xf3u\x98m\xd6m3U\v\xd8E\u06a0\x18%Q\xb2\xea|\x95\x15ieu\xea\u0758E\xba\xa3z\u0528l\xc0UUR\xb3\x9f\xc4\x0e\x14$e\x93\x90\xb6*\xddh\xf2>\xa2z\xff\xf0\x83\xae\xe2)\x96\x19cUI\xb1\xb1\x94J\x9e\xfaS\xde\x15\xe5\xd5P\nt\xe9LA*\xee\x14p\xd9S\xe9\xf5\trS\x90\xec\xf9WK\x04JA\t\x81\xf3+kx\xfa\xe8q|\xef\xf1g\xf1\u0533\xc7pqu\xc3\u01baI\x91\x9f\xa5\x1f>\xec\xe8\x1d\"@\x1b\x83\v\x17.\xe0\uc673\x16tDn\x86\x95\xf3Y\xe9X\xbc\xafe\xa7|]\xa0\xf1\xb6t\xae\xc4\xf0\x16\x0f6\u067f1\xe7u({\x1aq\xa3\rt<\x04\x18\xb8\xf6\xae\x0f\u1dbf\xff\x8f\xb1\xf3\xaa\xeb0\xec\xf5`t\xe2\x940\xf6<\x85R\x10A\b\x15\xd6 \xc3\u0426\xe9\x00\x85\xa1\x98R:u\xc5\xddIYsZ\xfb*\"\x01 \xb6\u065aF3X\x10\x928o\x88j\x00\xd2]\x9b\x88\rL[\x83[\xd2:\xade}\u07f42v\xaa\x17b\bL\x8a*\xc9\xefI\xa2\xea\x1b\xdd\xf7/O\xafch\x18\x9a\tR3\x843\x0fK\xef=2\u0206\xaa\x88\x81$\x89Q\xab\xb7\xb0\xb0\xebJ\xc80\x82\x8ec\xa4\x01DRH\xf4z=\xac\xae\xaf\xed\xfa\xd2\x17?\u007f+\x80/^\x06\xf3Wy\xbc\xf9\u0377e\u007f>}\xfa$\xfd\xcb\u007f\xf9\xdbDDk\x00~\xef\xcb_\xfe\u04a3_\xfa\xd2\u007f\xfc\u0503\x0f>x\xe8\xc9'\x9fB\xbb\xdd\x1e\xc3\u04f4\xa9zb\xf9\f\xfe\xc3\xff\xf39|\xe9k\xf7\xe3\x9doy3>\xfc3\xef\u016d7_\x8fz\xad\x05\x13\x0f\xc0\xc9(\xe3\x18\xdd~\xad0\xfcR\x05\xdaU\x80\xe6\x9b\u0231\xa7\xbc\xc8e^T\x01\x9d\x19\xc1\xe3Et\xf9|~9\x93\x87\xe1\xe7\u07fd:@\xe5B\xd5\u03d7`\u0479:\x93h\xe2b\xb6\x15o\x0f\xd8\x0fN\xa2\xd9\xd2)n\xd8'\xd5P\xe7\xa6W>WJn\xea\x913\x8b\x00O\xba\xe0\xc9\xf9(\v\xa7'\xa4@.\x10H\t\xa9$\x8ca,\x9f9\x8f\x87\x9fx\x0eO<\xfb\x12^<\xb1\x8c\x15\xd7\xdc\x14\x04h\u0599\xd5+\t\xdfm\xdbQ7^\xfe\x9e\x90.\xd75G\xe1\u0716\x96\xb7&\x99R|\xce\x1f\xe2\xe0*\x05{\x81\x82\x97}6z\xee\x82[\u04a1\xa3\xf4\xcb\x18\x83Zk\no|\xef\x87q\xe7/\xff\x06\x9a\x8b;1\xe8lzT\x83\x93\x1f\x06!d\x18Y\x10\x972\xcb\xed\u012b\\\xa2\x99\xd2\xe0t\xbbK\xd2\xc6s\x97\x14\f3b`-\x01w\x12g;\xec\xde\v\a\xa4\x9a\x80>\x01\x92\x19r` \xe2\xd8V\xc2S\n\xc25@\xb3\r\x87\u06cd\x18\xa6\xcc{\x89\xb2\xa6lu\xd1A\x15\xea\x17\xc0\x99\u007f\xb9k\x1d&\x8c\xa1\xf3\x99W\xda)r\xd2\xdfk\xac\xda\u021ff5l\xef\xcf\xd6\xccN\xb4fvb\xfd\xe2\xc9\xcc7\x9e\x04!\x1eiN\x12\xbd\xf8\xf0\xa3\x8f\xdc\n\xe0\x8b\x9d\xce:\xb5Z\xb3|\x19\xcc_\u00f1w\xef\x01\x86\xcd\x14\x95w\xdf\xfd\x01}\xf7\xdd\x1f\xf823\xdf\xfe;\xbf\xf3?\xfd\xdbVk\xea\x97\x1f{\xec1\x9c?\u007f\xbeP\xeaf\x8d\x11a\xb7v\x17V\xd6\xf0W\x9f\xfb\n\x1ex\xe4)\xfc\xd4{\u078a{\xde\xf7v\\s\xd5!\xcc4\x1aP\xd0H\xe2\x18q\x1c\xdb\u02a2\x94\x95I|\u9294\\\xf52r\x9e\u06a9\x97v\x9ar\"\x05Y\xf5@aK\xe9\u03f9S\u05bc\xf3\x15\x18\x94i\xa3\xd9Q-T\x92t\xf0\xe4\x91\xd4Kp\xecE.\x1e\x85\xdd\u026b\xa9\xc6'%-1[\xad\xb8\u05b9\xccP\xeb\xbc\n\u03f7\xec\xe3K\xce\x18h\xbb\xd2^P\x1e\x1dB\u0796\x842><@\x10(\f\x86#\x1c;\xb6\x8c\xef<\xf24\x9e\xf8\xfeQ\x9cx\xe5,\xba\xdd~\x0e\xe2I\x82D\ub8bf\xb9\x11\x05\xc4\xf5\xdb\xd0i)\xca^\xf6l\x1a\x98\x9cJ\xfc\xf2\n3\x05B*\xc4\"g3\xaa~@\xab%\xc5\xf3\x85_k\x18\x13\xc3$\xb1\xa5J`w\x17\xb6i\x19@\xd6\xea\b\xeaM,]\xf1F\\\xf3\x9e\x0f\xe1\xd0-oG\u051c\u00b0\xb3\xe9\x02\xc4\xedh\xbb\x90\xca\xd1*5\b\xa5<\x83\xa2\x92-\x00\x97\x03\x1cx\x8c\x0e3\u0657U\x17%\x06\x88\x8d]\x98i3\x81\xe8h\v\xd0\xc6\x01%\x91}I\x8c\xb5j\xd1\x00\xe2\u0600b\xb7\xe0\x8e\fxh\x80\xf9\x00A \x10\xc0R,\x82r\xd2)\xad\xfe%\xa5!\x1d\xbc\xe5}\xc7^\xd4\"\x93\xe5\xcdA\x02\x9a\r\x06\t\u00f0\x05r\x99x\xbd\x14\xc3 \xe3\xf9\xb6\xe7\xac\x17\xb4\x8eQk\xcc`a\xe7a\xac_8Q\xbc\xaf\rF\xbdn7z\xf9\xf8\x89\xeb\x00\xa0\u055a-\xf4\xf8.\x83\xf9k8\xee\xbe\xfb\x03\xfa\xbb\u07fd\x9f\xde\U00096df1\xe3\xac\xfe\xe1\xe7?\xffw\xf7\xdd{\xef_\xfd\x0f_\xff\xfa7\xf6-//S\x92$\f \x91R\x06\xc6\xe4\u06fe\xac\xca?s\x0e\xff\u05df\xfe5\xbe\xfe\xed\xef\xe1\xe6\x1b\xae\xc5\xfb\xde\xf5\x16\xdct\xf5\x01,M\xd5\xd1j\xd4 \xa5@\x1c'\x8e\x8fw\xa6Q\x82\xbcq\xf0q\x0e8\x05\xf2\xcc\xfc\u0254\x12\xe0\xe19\x1c\n\xca\x00*\xad\xd8\r\x17\xedk\xa9d\xfa\x9fZ\xfd\xda\xf1\xe2\x1c\xf0S\xb9b>\x04UE\x10\xf1\x96\x11p\x97\x8c\x87\u02ea\u03ca\xb0\vWys\xf6\xe1\xe7\f\xc8\x13\xe34\xe2\x06^\xcc\x172\x10-\x0fx\x8c)\xd2\xc0\xce\x10*\xd7\x031\xfb\xe7\x04h\xb6UW\x14\x86H\x92\x04/\x1e}\x19_\xfd\u03a3x\xe4\xc9\xe7q\xe6\xdc\x05\f\x86C+\x8bc\x83\xd10\x81N\x9b\x9b$2\x8d\xb2T\xcaM\x0fR\x9e)Ib\x82\x1c\xa88\x11@.\x8f\x16\xe5k\x01g\v2\x15\xc6b\u0269P,`\xb3\xb1v\xb5iU-\x82\b\xd1\xcc4\xc2\xe6\f\xa2\x99\x05D\xd3s\x88\x9aS\x98\x9a[\xc0\xec\xee\xfdX8t5\xe6\xf6]\x81\xe6\xec\x02\x88\xadU\xae\b#\x90T\x80\xfb\x12nQ\x13\x82<>~<\x9d\xb5j\xbf\xc9^\v\x82a\x81{\xa4\x19\xa3\x84m\x13\x91\xad\u03f9\xeaj\x04\x1d\x9d\xb9)J\r\x906\x85\xf4:2VVn\x90F\xf4\xb8\x02G\xc7\xd0\xcc\xe8N\xdbs\f\b\b%\xd91\u007fApsD\u064e\xc06\x8bKq\x90^hz\x96\xb1\x9b\xaa_\xa4\x02d\x82x\x94`\xe8V#\x19[\xa5\xa6I\xcd\u0334\xef\x83\u3337\u049d\xa4\x8eQo\xce`i\xf7\x11\x1c\xfb\xfe7=\xd5\x14\x10\x06R\x9d>\xfd\n\xd6\xd77\xaeg\xe6\xeb\x88\xe8\xfb\x0f<\xf0\x1d\xe1.\xf32\x98\xbf\xd6\xe3-oy\x1b\xff\xe1\x1f\xfe\xaf\xf8\xcd\xdf\xfc\x18\x01\xe0{\xee\xf9\xd0'\x99\xf9O\u007f\xeb\xb7>\xfe\xb1\xaf}\xed\xeb\x1f=}\xfa\xf4U\xe7\xcf_\b\x1c\xa8kr\xdd&\xe6bK\xfe\xf8\x89\xd38y\xfa,\xbe\xf5\x9dGp\xf8\xc0\x1e\xbc\xf9\xfa#\xb8\xe5\xfa+q\xc5\xfe\xdd\u06390\x87\xd9\xe9&\xea\xad\x10Z\x1b\f\x86\xb1\xe3\xe5\xd3j\xae\x18Ll\x00\x9b\x06\x9f\u4cba\x8cB\xf0@/\x05\xea\\vE\x13Io\xf6V\x8e\xbc\x92/\xf2\xeb\xc2q\xc4R\x90\xb5\x0f\x15y|\x96\xc8\x02}\xe9\x92\x16\xb9\x97\xecX\x96\xcf0\xab\xd6,\xff\xad\xbd\xf1\xf3\xb4\x92\xcb\r\xb0\u0704\x1e\xa8\x04\x1b\x18k&\xa4\u065a)\xd02\x8a\xf9\x9c\xe9K\x92\xaa9\xeaQ\b\"\x81S\xaf\x9c\u00f7\xbe\xf7\x04\xee\xfb\u07938\xb9|\x16q\x1c\x83\x88!\x05C'\xf6\xbd3F\x17\x16\xf6\x99f\x1d,\x02\f\x13\r\b\xe5Y\xa9::\x82\xca\xd1\xd4\xee}O+u\xe1\xde\xff\xf2\xf6\x82<\xbb]r`\xa15\x92d\b\x9d\xc460\xb8>\x8d\xc6\xd4\x02\x82Z\v\xaa\u0442l4\x10\xcd.\xa2\xb1\xb8\x1bS{\x0ecz\u07d5\xa8\xcf\uf08cj\x10B\"\f\x15\x1aQ\x80Z\x18@\bB\x92\xc4\xf6\xfd\xaf\xd5\x1d\x85\"\xa1\x85Mv\"a\x13\x84\xc0\xe3\xadl\x86\xbf\xeb\xc9{/\xc6\x03q\xe3\x16\xc9X\x03\x83\u0120\x9f\u062a<\x9d\xef\t{\x1aa\xcf\x05\x002 \x13\x06\xa5#\xfe\xeey9\r I\xe1Rx\x8e\x8e\x9a!:\x1a,\bqCbD@?a(\x01\x04\x82\x10)\x81@\x00J\x10\xa4p\xe7lJ\n-\"+/vU\xbd\u007f\xee ;\xa0\xdfO\xec\xdfe\u0090\t\x17\xed\x1e\xb8L\xdb\xe4K\xb4\xd1\tT\xd0\xc2\xcc\xc2>\x04a\x03:\x199+\x04{K\x8c\x86C\xac\xac\xac\xcc}\xfd\xeb_Y\x04\x80\x87\x1ez\xe82g\xfe\xc3\x1c\xbf\xf9\x9b\x1f\u00d7\xbe\xf4y\xfe\xdd\xdf\xfd=\xfa\xe67\xefc\xa7K\xff\x1df\xfe\xc3\u007f\xf6\xcf\xfe\xe9o>\xf2\xc8#\xbf\xb0\xb6\xb6~\xe3\u0253'U\xb7\u06ddH\xb5\xe9Dceu\r+\xabkx\xfc\xe9\xe7\xf1\xe7\x8d:\xf6\xeeZ\xc4\rG\x0e\xe1\xea+\xf6\xe3\xf0\x81=8\xb0g\t\xbb\x97\x160?;\x05%\x05\x86q\x828N\x9c\t\x12\x9c\u0740\vFH\xb5\xd1i\x13\r\xc5(\xb2t\x84\\x\xe8J\x9c\xfbqT\xc1:gU\x15gF]\xec*>\xe1l\v\x04\x11F\xe9vU\xb8x=7\x8aL\xd9v\xd5U\xf0\x8en \xaf;[H.\xe2\x94#-\xce\xcc[_\v\xf6>8\x9c\aA\xf86\xa7\xde8\xbdU.\xe4\\0{WS\xf8l2\x8fy\x8f\xb3\xdf\xe0\xf4\x99\xa8tj3\b\xb0\xb2\xbe\x89\a\x1e\xfd>\xbe\xfc\xad\x87p\xf4\xe5eG\x93i\b\xc1\xd0:A<\xb2\x15\xb0\xf1\x16\x84\x85\xd9)\\q\xcb[\xb1\xef\x8e\xf7\xe3\xc2\xc55<\xf1\xf9?E\xfb\x95\x97\x01\x00A\x10\x81\\t\x98]L\xc8k\xc62\xd8P\u039b39\x90\x19\xb7\x84\xe4Tj\xa8ch\x1d#\b\xeah\xcd\xed\xc1\xd4\xfc>\xcc\xee\xb9\x023{\xaeDki?jsK\x90K\x8b\xc0L\x13*j@H\xe5M(\xe7J\x8e\x04@;\x06\x86\x9c\xa0\x11)\xd4ju[\xc9;\x15\x0e\x91\xb0\xc0\n\x86\x12\xbe\xa3\xa2\x0fU\xa5\x05\x94\xfc\xc57\u007fOc\xc3\xe8'\x8c~l{\x1d\xbeY\x9d\x1a\x18\x84=\x03\xa1\x1d\x90\u01f6\xa9\x98V\xe8>\xedg_\"\xceR\x83X\xe44\"%\x8c\xa8\xab!\b\x186\xa4\x93\xa9\x02\xb1f\xf4\x13\r%\b\xa1\x00\x02%\xec\xff\x85\xf3\x96\xe1\\\x0f\xa6\x992/\x11.\x15\tCc\x1b\x9fd\x00\x15\xc36>\xc9\x1a\xf2\x11\x93]xD\xfax\xe1\x8a\x1d\xce\xc4\x05\xcc\x1a\xf5\xd6\x02\x9a3;\xb0~\xf1$dn@I\xa3\xd1\bI\x92\xecy\xf2\u0267\xae\x05\xf0\xcd3g\xce\xd07\xbe\xf15\xbc\xfb\xdd\xef\xb9\f\xe6?\xe8\xf1\x81\x0f\xdc\x03\x00\xfc\x89O\xfc\x1b|\xfc\xe3\xff}\xfa\xa1\xdbp\xa0\xfe\xe9O|\xe2\xdf\xfc\xbd\xaf|\xe5+w\\\xbcx\xf1M\xab\xabko\xbcp\xe1\x02\xf5{\xbd\x89M\xbb$I\xb0\xb1\xd9\xc6\xe6f\a\u03fft\x12\x81\x92\x98j5qx\xff.\\}\xc5~\xbc\xe1\xe0^\\}\xc5~\x1c\u063b\x03{v,`\xba\xd5p\xcd=\r\x8c\x12\b\x9d'\xe80\xa7\xe3\u031c\r\xb5\x14\xa8\x89\u031b\x9c\xf3\x06\x90\xc3\b]\xb007\xd9$\x93\xd7\x12t\x80n}2\xa4I}hr\xd0\xcf\x03+<\xbf\rg\xf3*D\x1aO\xe6\xd1\xf6\x94\x876hf\x1b\x19\xc6~\x02\x0fg\x95O1\u0601=f\xd8\a\xe2\xb1\xfek\xc1\x1f\xc5\xdf\u044cW\u0754\ro1\xb8\xe0\x86)\x85D-\f\xd1\x1f\x8d\xf0\xc0c\xcf\xe0\xab\xf7?\x82\x87\x9ex\x16\xdd^?\xb3\x9a5\xdaN[\xdaj<\xff\r;\x17fp\xed\xdb\u07cf\xddw\xfe4\xe6n\xbe\vb\xf7aLo\xf4\x10\x1c\xba\x01\u01fe\xfcg\xb8\xf8\xec#\xe8\x9e_\x06b\xbf\xa9M\xb9#\x1f\u0195*Y3\x8d\xf2\xf7\x8b@PA\x1d\xad\x99]\x98Z\u060b\x99\x85\x83\x98\xdbq\x18s;\xaf\xc0\xcc\xce+P\u07f9\a\\\x0fa\x8c\x86\x96\x8c$\x12\xd0!Y\xd9\x1e\xb4\xf5\xe0\xce$M\x02p`\xcdB`(m\xfa- Q\x93n'\xe6^#\xe9^?\u9a38K\x1a;0C\x1b{\xbf\xc1Q\x1a\xfd\x84\xd1\x1d\x19\x8c\xb4?=k\xd5Bj`,\x00k\v\x922f\x88\x84=\x0f\x1a\x14\xf5/\x8e\xff \xb2\x14\x87\xf6\xfb\x94\f\x88\x04\bz\x06F\x10t]\x14*\xad\xc40b\x03\x90\x03\xf6H\x12j\xca\xfe_\n\xbf7\xe1\x9e\xd7S\xe4\x8c\f\xa3\x97\u061d\x84t\u7656\xf0\x04\x80\xd2\x05\xb9\x9c\x15\xea\xed\xb6\xb5NPk\xcc`jv\x17\xd6\xce\x1fw\xbb\r\x06\x98\x89\x99\x93n\xb7\xa3\x9e|\xf2\xa9E\x00\xe8\xf7\a\xe2\xdd\xef~\x8f\xbe\\\x99\xff\b\x8e\x14\xc8\xff\xe0\x0f>\x81\u007f\xf1/>\x8e\xcf~\xf6^\x10\xd1Y\x00\u007f\x04\xe0\x8f\x1e}\xf4\xa1k\xfe\u077f\xfb\x93[VVV\xff\xeb\x97^|\xf1}'N\x9e@\xbb\xdd\xc1p8,|\xd8\xfdJ\xd8\x18\x838f\xacmlbmc\x13\x8f<\xf5<\xa20\u011e\x9d\v8\xb8g'\x0e\xee\u06c9\xc3\xfbw\xe3\r\a\xf7\xe2\xe0\xbe]X\x9c\x9bA-\x8a \x94\x1d\x821\u0330\x8e\xa6\u059c\xc9h.\x86\x9dL\u0a33\x01!\xbf\xd8c\xf6\x92\x93\xbc!$\xa4`\v\x8c\x91\xb6Y\x95h\xe0u\x87\\Ui\n\xbc\u007f\xce\xf2\xf8q_9H\x1b\xe61\xe0\xf2\u01f0\xfd\x19W\xeb#\x9d7\xa4*\x98\x94L\xf7c|\xf6\x99\xf2\x9d\a\xf9i\xf0d\xd5\rRZ\x99\xa11\x8cg_:\x81\xaf?\xf08\xee{\xf0\t\x9c\xbd\xb8\x9a-L\x16\xc4c\x8cFCho\xf6`\xef\ue778\xfe\xdd\x1f\xc0\x9e\xb7\xfc4\xa6\xae{\aF3{\xd0\x19&\xc0z\a2Px\xc3\xdd\x1f\xc1\xee7\xbd\x13\x1b'\x9e\xc3\xe6\xf21l\x9ez\x01\x1b'\x8f\xa2{~\x19\xfd\x95\xb3\x88\xbbm\xb0N\xf2IJ\x12\u05a4*\x8clcR\x86\b\x82\x1a\xa2\xda4\x9a\xd3;05\xbb\v3K\x870=\xbf\x0f\xcd\xd9\x1dh\xcd\xecFT\x9f\x86\xd61\xb4\xb1v\x13\tb\x98@\u0606]\fH&P `j\xcaV\xd9BZw*\x91Rz\xf9\xffcfl\x0e5FZ\xa0\x19\nD\n\x10\\}Gqe\x13\xdcI\a\r\xb2]d\xac\x81^l\u040dm\x8f\xa3\xb0^\t@\xc4\x06AGC\xc6v7*c\x03\x11{\xd5xy\xf5N\xdf>c\xf9n\x86\x05t\xf6\x82V\xc0\x96\x9e\x89\xba\x1a#\x02\u26a8\xf4\xeb\x1fiF\xac\x19\x83\x84\x10J\xa0\x11\b\u02f1\v.\xb65\x98\x900\xd0\x191\x86\xc6\u07a3rd\xad\x16\xb2\u05cfE6\x8b\x90G\x8cZ\xc2\\x\xeb\xb3\xd11\x1aS3\x98\x99\u07d5\xd1o\xe9g3PJ\x9cy\xe5,\xae\xbbnxC\xeao\xfe\xd0C\x0f\x8a\xdbn\xbb\xe3u\u03dbo\xcb6\xeeW\xbf\xfae\xfa\u02ff\xbcW|\xeaS\x9f\xd6y!\u008dO~\xf2\u007f\xffo\x9fy\xe6\xd9\xdf~\xf8\u11e7\x8e\x1d;\x86N\xbb\x8d$\xd1\xd6\xf3e\x82)\xbe\x10\x02J\xda-\xad1\x96Z\x10\x044\x1bu\xecX\x98\xc3\u03a59\xec\\\x9a\xc7\u03a5%,-\xcec\xc7\xc2\x16o$\x1a}B\xa4\x15\x94\x88\x10\x85M\x84\xb5&T\xd8t\u05a91L2\xb2\x8dNA`!\x00%\xc1\x81\x80\x8e\x14L(\x01!,\xff+\x04\x92\x86B\u04b0N\x86\u9389\xb9\x1a\x96\x99m\xe3\xb0\x11\x10\xeaJ \x90\xf9\xa0\x94\xf4$\x82\xe5\x06\xa7\xa3\xa0\xed\xbd\xec\xaa\xf1\xde\xc8`\xa8y\xec\xfe`\x02\x84\x01\x82\xb6F\xd0\xd3\x10\x86!b\x86\x1cq\xd6\x14\xcf\\\x0f1i8\x8d`\x84\x15\f\xb1\xeb5\xd8F\xa5\x00\xa4\x95\x12&\x11a\u0612\xd05Q\x88\xa1\xe3\n\x95\xad\x10@\xa4\b\r%\x10\xcaT\x82lw\xbb\xbd\x98\xd1M,\u0146\xde\x00\xc1\xc5.\xe4\xc0\xa6\x96q\x92\x80\xfa\t\x10\x8f\xc0.\x93\x95\xbc`\x12\x99\ue01d\u02a81=\x83'\xbe\xf3\x17x\xe0\U000df10a\x1a A0\xf1\x10\xa3a\xd7H)\xc4\xdd\xef\u007f\uf4df\xfe\xf4\xa7>\xb2\xb4\xb4\xeb\xb9O\u007f\xfa\x93\xf2\xd7\u007f\xfd\x9f\xbc\xee\xabs\xb5\x1dO\xea\xbd\uff5b\x01\xe8\xe7\x9e\xfb>}\xf5\xab_\x13\xbf\xf1\x1b\xff\x94\x88\xa8\a\xe0\u007f9w\xee\x95{\xbf\xf0\x85/\xfe\xd2\x03\x0f<\xf8\x8bO>\xf1\xe4-O>\xf5\x14\rG\xa3L\x97^>\x8c1\x18\xb9h0!\x05\xa4\x14\x90B`0\x1c\xe1\xf8\xa93x\xe9\xe4i\b!Q\xaf7\xd0l6\xd0l4\xd0j6\xb1\xb40\x8bC\a\xf7\u16ab\x0e\xe3\x8a};13\u0570\xe3\xe4A\bU\x93\xaeq\xe3\x05,\xa4\xd5\n\x91\xa7\x84\xb0\x1a\xe71\xb5\x01\x8a\x86\xec\xecM\u0325\xdbg\xe3\xbaF\xb9\xe6\xdd\xe4A\xbf\xde'%\xeb\xe6\xbb'2\x15\nG\x1aSux\xe9=\xe4\x19&\xf9\xfc{\x19\xd0K\x95\xba`\x1fp\xf2\u6c12\x12\xb5(\x80\x10\x02\xbd\xfe\x00\u03fft\n_\u007f\xe01<\xfa\xf4Q,\x9f\xb9\x88\xd1h\x04\xa5\xec$G\x1c\xc7\xd0\xfbeH\x9c\x00\x00 \x00IDATI\x8c8\xb1\xd4\n\x00\x04a\x88\xeb\xde\xf7a\\\xff\v\xbf\x8e\xa9\xabo\x83\x0e[X\x1b\f\xc0\xed6\xa4\x80\xf3\xfe\xf6w\x04\xf6C:\x1c\xf6\xc1`\b\xa1Ps\xcdH!E\xee!oRE\x86\x81a\x031\x18!\u060c\x11n&\x90#\r\xc4\x1a&\x89\xc1&A2\xec95\x8etS\x98\n\x10\x04\x0e%X);\xd0\x04\x01M\x02Z\u0694\x1db@\x0e\b\xa4\x80\xa4\x96\x0e\xeeVF!g\u02a8\xd806\x87VO\xdd\f\x05j\n\x19\u0152\xca\xfa\xd2j7\x9f\x9a\xb5\x80\x15\x1bF7\xb6\xb4J\xb9\x1a\xf7\x95\xb3AW#\x18\u0608\xf3\xef\xe9\xa3\x1f\xfd\x15\u07b9s\xcf\t\x00\xbf\xc7\xcc\u007f\xfc\xb1\x8f}\xec\u007f{\xea\xe9\xa7\xff\xe1V\xcf!\x84\xa3\x05\xd8\xc0$\x1a\x80\xcen\x80T9\xc2\xcc\x18\f\x87\x18\x8eb\xac\xacm\x82aG\xc4\x1f|\xec\xfb\x98\x9aja~f\n{v-\xe2\xf0\xfe=8\xb0g\av,\xcea\xbaUG=\x8a2O\x10)\\\xb5m\xf2\x84y\xadmXp\xa2\r\xe28A\u007f\x14\xa3?J\x9c\x0e\xb7\xa8\xb2\b\x02\x850P\b\x02\x05\xa5\x94\x9dnt\x93\x8aRX\x90\xac\x87\x01\x820\xb0\xbf+\xf5zv\xc6V\x89\xfb\xbd\x99\tQ!\xb9)\x9b\xe2(*<\u01a2\xb9\xa8z\x14\xc97\xbeB.+3\xae\x19,%!P\n\x81R\x88\x93\x04\xe7V\xd6pr\xf9\x1c\xee\xfb\u0793\xf8\xde\x13\xcf\xe1\xec\x85\x15\x8c\\%N`\xf4\a#\x9b0o\\\u2f63Uv\\\xf3&\xdc\U000abfc5\x83\xef\xfcyP=D\xbf\xaf\xa1\xbb]\xab\xec\x91b|w\xe0\xb7\\\u04e1 \x00&\x19\xc1$\xa3\x12(\xe5CJrd\xa06c\xa8n\x02\x8c4Lb\xab<;\xb4\x13B\xaa\xa8\xc0\xa5\xdb\x12\x97\xc0\x81\xb0\xf4\x89\x93\xee\x89! \xb4q\x13\xac\x96X\x16\x9b\xdaR\v\rY\b#\x99$+e\xd8\x11\xfa\x91\u05b6b\r\xac\"D\x11\xf9Im\x19\u0367\r0L\x18\xdd\xd8*U\xc0\x13\xbcY\x18\b\xfa\x06AO\xdbsM\x81\xdcp\x85\xe72\x8f-\xe0e\xf5Sj~\x96%~ymK\xe9\xaaa\x100$\x82\ti\uceb3\"\xc0\xbb\x8e\xbe\x19\xb7#H\U000e90c4@i\xff!\xfd\xbd\xec\x87\xc5\x18\x17\xe8\x01/!>\xed\x93\x10t\x12\xa31\xb5\x84\xe6\xec\x0e\xac\x9d?\x01\xa9\xac\xc1\x99\r\xf3`>w\xfe<=\xf6\xf8\x13\xfb\x00\xe0\xaf\xff\xfao\xfe\u007f18\xa4^/'\xfa\u044f\xfe\n\xdf\u007f\xff}\xf8\x9b\xbf\xf9\x1b\xfa\xc4'\xfe\x80\x01t\x1ez\xe8{\xbb\xfa\xfd\xfe\u011f\x99\x9e\x9e\x02k\x8dv\xb7Wb&\xb8\xf0\u007f\xfbB\x10\xa4\x12\x90\xceG\x99@H\x92\x04\xab\xab\xebX]]\u01f1\x13\xa7\xf1\xe0\xa3\xdfG\x18(\xd4k\x11\xa6\x9a\r\xcc\u037405\xd5\xc4T\xa3\x8e(\n-\u007f9\x8am\xda{\xac\xd1\x1b\f\xb0\xd9\xeeb0\x8c\x11'1\x86\xa3\x04q\xa2\xb3\xada\xda\xe0\xb4\x15\xad\x82\n$jQ\x88F\xbd\x8eZ-\xb4\xff\xa6\x14j\xb5\x10\xcdz\rK\v\xb3X\x98\x9b\xc6T\xa3\x810\f\x10\x86\x01\xea\xb5\b\xf5Z\r\xf5z\x1dQ\xad\x06%\t\xacu\x9a\xae\xe2\x00\x1e\x05c\xbd\xdcn G|\xe6\x92\x05\t{4\x8e\x10P\xca\xeehD\xf6\xe5*\"\xad1\x18\x8epqm\x13\x17.\xae\xe1\xf9c\xa7\xf0\u0413\xcf\xe1\u0157\x97qqm#\xa3S\u0229\x8f\xb4\v\xf05i\x90/\x80\xe6\xd2^\\\xf5\xc1\x8f\xe2\xda\xff\xe2\x9f`\xe6\xe0!$CF\xbc\xd9\x05\x1c%\xe6\xef\x0e\xaajH\x1f\x93\xb8\u0510\xcd\xf6/\xcc\x0e\xc8\x19\xe1\xa6F\xd03\x10\x9a `\xabo\b?\xb0\xb0b$K\xd8\xecI\x03\xdb\x03a0(a(M0\x92a\xdc\x00\x81\x18\x01\xa1\xd1 \x06\xe2\xba\x04\xcb\xf1V\xc8\x18\xa0{\x15\xebH3\x1a\x01\xd0\f,\xf5B\xb9t\x05\xb1\x01:#\x83^l\x90TU\xe3\xfe\a{`\x10t\xb5\x95\x1d\xb2mv\nS\xe2\xcch\xf29\x15-\x12\xca\n\x1dW\x1c\v7|\xa5\x19$\x009d\x84\xd0\x18MI\xe8\x80&)XK\xef\u0378\x92V&\f\xa9\tl\\\xe4\x9csG\xf4\xcf'\x9d\xfcMUVy7\u01e9\xc6t\x82fs\x1e\x8d\xd6\xdef\r\xe5\x19\x00~\xeb\xb7>\xfe\xae\v\x17.\xbcWO0\xea\xaa\xd5j\xf8\xd5_\xfdU\\\xf7\xc6k\xf1\xf0\xf7\x1e\xc0K\xcf?\x8bg\x9f?\x8as+\xeb0\\\xad\x86a\xa7~\x10d\a^\x04\x89L\x1eH\x00\xe28\xc6h4B\xa7\xdb\u00c5\x95\xb5,\xce\xcb\xdfG\x8e\xd1\x14\x9eJ\x80\xbd\u01a7?\xafY\u04a2\xb9\x9b]\xe4zv\xb2\u0a64\x95\xf4EQ\x88Z\x14\xa2^\xafaz\xaa\x85\xb9\xb9\x19,\xcc\xce`nv\x1a\v\xf3\xb3X\x98\x9d\xc6\xecT\x1d\xf5(D\xb3Qszn\x02\xb3\x86N,U\x834\xa6\x8cr\x85G\xea\x13nw\x03\x02\x81\xb2\xe9\xef\x83\xe1\b\xdd^\x1f\xbd\xfe\x00\xfdA\x8ca\x1c\xa3\xd3\xed\xa3\xd3\xeda\xb3\xd3\xc3\xca\xea\x06\x96\u03dc\xc7K'^\xc1\xb9\x8b\xab\x18\x8eF\x96\x0er\u05db\xc4\xec\x00<\xc9\x00\x1c\x00\xa6\x16\xf6\xe2\xd0-?\x85\xab>\xf8+X\xbc\xfd\x1d0\x01a\xd0\xeeY?\xefR)KeN7\x1d<)\xb9\x8b\xf9\xfd\x85\x02R\t\xeb1\x12\xb65T\xdf5\x005;\x90Hw&[E\x9c\xb8II7\x1e\u039e4U\xb8\x0e!K\xcb/\x8b\x84\x10\xb65(f\xc4M\x01\x1d\x8a\u0262\x94\x12\xb8i\x03l\x8e\fb\xc3h\x05\xc2\xd2\x10\xb0Z\xf1nl\xa7\"\xb94\xa4VFb94\b;\xda59\xd9\xc6\xe0\x19.\xc8E\xfd\xac\xd9\t\xb0\x8a\x02\xda\x13\x17\xe5K\x94N\x8d\xda\xc5M\x18\x00\x9a\xa1\x86\xaeBoI\x98\x90^\xd58N\xf6\x16\xa6\xebfl\x157\xec\xe5\xa3\xda\xe7\x19\xf7\xd5e\xce\xfbE\u067bG\u05b4\xab\u079cC\xb35o)!JS\x93\x14HJ\xb4\xdb\x1dlll\xdc\u011c\xec\x06\xb0|\x19\xcc\u007f\xc2\xc7\xfd\xf7\u07d7\x02:\x9e~\xfa\xfbw\x9e8qb\xac\xdaN\x8f\xa5\xa5E\xfc\xf2/\xff\x03\xdcq\xc7[\xf1K\xbf\xf4\x0f\xb0|\xfc(\x8e>\xf90\x8e>\xf74\x9e;z\x1cO=\u007f\f\xc7N\x9d\xc5z\xbb\x9bU\xcb:\u06da\v@*[\x89\xa6C\x80]\xd7\xdc\x01j\xd4\u047b\xd8A\xd2\x008\x14\x95\x01\xa8\\\n\xf7\xf0m\x1a\x88\xb6n\xef3Y\x05G\xd8\xd6\b\x06\xc6R\r&\xa5\x1c\xb82\a\xb6 F\xa5\xbc\xca$O\xd2d\x03\x14\\\xc3\u05cd-\xb0\x15]\x804\xdb\xe1\x1c\u0348\x9b@R\x13\u0145g\x12\xa8\xb9\xe7\x1b$\x96:S\"w\xaa\xd4\x06y\x90\xf5\x84'\x101#\xec\x1a\x88\xc4%\x1d9\x90%FiBw\xb2\x1d\x1d\x97UR\xec\xe3\xa8'ka\xef\xe5q[;b\v\xe8L\xc0\x88$\x8c\x12\x93\xb8\xb1jZ\xd4 W\u06a4U\xb8\xc9\x04]\xee\xf3\xe6\xfc[L\xeeL\x99\xf6\x15\x84\xa3MM\xa2Qk\xb4\xd0h\u0343\x84t\x16\xb8\x80\x94\nB(\x8cF#\xc4q|\xeb\xbd\xf7\xfe\xd5.\x00\xcb\x0f\xec\u0673\a\x80A\xbd\xd9\u01357\u074ekoz\x13\xd0>\x83\xd5S\xc7\xf0\u02a9\x97qj\xf9\fN\x9e>\x8b\x93\xa7\xcf\xe2\x85\x13\xa7q|\xf9\x1cN\x9f\xbb\x88\xf5v\x0f\x83\xe1\bZ\x97\xbb\"\"K\x11\u03ebv\u1188\x8a9\x9fy%>>*N\xbe\u0169\xd7\xc8\u02dd\xf8\xbcf.\xe5\xfc6g\x9ab\x064\xd94\x18!A\x8c\x8c\xf6\xb0\x15\xc7&\x8eq>d\xa4\x94\xa5\x86\xe6fZX\x9a\x9f\xc3\xd2\xc2\x1c\xe6f\xa71;\xddD\xa3Q\x87\x92\x12Zklv:XYY\xc7\xea\xfa\x06V\xd77q\xe6\xfc\n\xd66\xdav\x98G\x97\x06\x83\x1c\xf0\xa7\x15x^\x89\xbb\u01b0\xb6C7\xa9|4\xa8\xb5\xb0c\xffux\xc3-\x1f\u0121\x1b\u07c3\x9d\x87o\x86\x10\x11F\xbdM\xe8n\x0fA @#\x81\xe1L\x80$\x12\x05Kc\xc03(D\x01G&\x03c>(\t\x91\xc0\x02y\xca\x1fk\x86(\f\u028c\xc1wE\xa9_\xfd;\n\x14\x90\xb6*r\x1d\xe4\u0563\x1c\x1a\xfb\xbb\x12\x89\xa4!ad\x81\xa6\x1e\xe3\xd3\xfd_\x17;\xbdv\n\x98[Y\x880Yz\"\xecj\u0221\x9b\x99H\xc3\x1bR\u0547\xd74\xa7\n\u0687\x8a\xec\x9a#\xaa\U000f26483O\x98\xbc\x9bO)]\x9e\xff\xb0a\xa8\x81\xfd\xe4\x8cZ\x04\xad&\xa6\u064d\xbd\xb4\"a+I4\xb0\rh$\xb6\xd9\xee/=\\\xbc\x0fQ\xb8'\xf2\xc9U\"Bsf\x11a\u0530>\xf1R\x82\xa4\x82T\nF\x8fp\xfe\xfc\xf9\xf0\xa1\x87\x1e\x9e\x02\x80\u007f\xfd\xaf\xff\xe7\u02d5\xf9O\xf2\xf8\xdc\xe7>\x0f\x00\xf8\xecg\xef\xbd\xee\u0739s\xd7UY\xe7\xa6\u01d5W^\x81\xfd\xfb\x0f!I\x86H\x92\x04\xf1h\x04&\x01\x11.b\xf6\xcaY\xcc\x1f\xbe\x16\xd7\x0f7\x80\xf6\x1az\xed\rln\xaec\xb3\xdd\u0145\x8b\xabx\xf1\xc4+x\xe2\xf9\xe3x\xf4\xfbGq\xf4\xc4+X\xddhc0\x8cm\xcf\xdc\x15\x98\xaf\xad\xf5M\x90*\xb4\xcd\u0634\xbc\xa4t@Hd\xa1\x05 \u06f0e\xa7\x90I?\x18\xbe\xb9\xb6o}k\xaba\x032n\x98HHk\n\xa6\x14\x94G/23z\xfd>:\x9d.N\x9c:\x03\x80\x10\x84\n\xb50D\x10(\xeb:\xa8\r\x06\xc3!z\xfd\x01\x92D[e\x88\xa3w|\x90N\x17\x14\xceF\xfeM\xd1C$=m\x93@\x06\x11\xa6\xa6\x96\xb0t\xf0z\\u\xf3O\xe3\xc0\xd5o\xc3\xf4\x8eC\x10*D\xdc\xeb\xc1\xe8v\xb6\x18R\xcc\x10Z\x83\fa0\xa7,\xa0W,\x86\x85`\x03.J\xec\xc7\x12\x9a\x04\x814#\xea$\x19\x90\x93\v\x00\xceS\x16\x8a\xae\u06d5\u068e2\x8ap\x1emG\xc6n\xe4\xf2\tIKk\x18IY$'%@\xd8\xd5\x10\t#n:\xfa\xe1U\x98\xc9\xd3%\xf8e\x1f\u0205\x01\x82\x9e\x86r;\x8fl\xf4^\x97\x16\xad\x94&\xc2d'\xd1\xfc5\xa6bk\xb420%\ud193\xa5FR`w\xe7C\f\f\x1d\x87Nf\xeb\x8b%\xb6\xcdi\xa1\xd9J \xd3\xe9X/\xac\x84\xbd\xc72\x8d\xf9D{V\x04V\xc9Vo. \xacO\xa1\xdfY\xb3\x86f$ U\x88x4\xc0\u0253\xa7\xf0\xfe\xf7\xbf\xef=\x00\xbe\xfew\u007f\xf7\xf9\xcb`\xfe\x93:\u039cY\xc6\xee\xdd\xfb\x00\x00_\xf8\xc2\x17\u007f\xf6\u0739s\x98\xa4-\x97R\xe2\x96[nq\xa0b2\u054a\xbd#\x04b\xaa\x01\x14\x81\xeaS\x90\xd1\x0e4\xe6zh$\x1d\xec2#\x1cIb\xbcm\xd4G\xd2\xedb\xb3\xd3\xc1\xcb\xcbg\xf1\xcc\u0457\xf1\xe4s\xc7\xf0\xfc\xf1e\x9c\xbd\xb0\x86\x8dN\x17\x1d\xc7!\x0f\xe3\x04\xc3QR\x18t\x91B@)\t%\x05jQ\x00\x90@\xb77\xc4(\x1e\u066a^\b\b!a`\xacQ\x94Kf1\u01a0\x16E\u0635k\x17\xc2(\x82q\x89\xf2\xc3\xd1\x00\xf1(vZ\xec\x11\xe2$\xc1h\x94 \xd6\x1aqb\x15%a\x10@\x90\x80\xd6\x15\xed&_\u0152\u068b\x0e\x86\xe8\xf5\xfa.\x1d\a\x19\r\xe2\xeb\x9b\r\x19\x90.\u058by\xb2\x0eg\xbax\u03a6f5\x8c1\x88\xea\xd3\xd8s\xe8&\xec\xbd\xeav\x1c\xba\xe1=\xd8u\xc5\u03687\x16@\x10\x88G\x03\xc4\xfd\xae\xe5\x9aS\xe3a7\x80\x02M\xa0\x8e\xd5\x15\xf7\x17\x03\vz\xba\xbaI\xe61\x1f\x05\xed6\xf2\u034d\x05\xf2v\x82\xc0M>\xc2\x01\x1c\x95\x00\x8e\xb6\xe4h\xb6\xc0\x1f\x93\x03\vL>\x1cF\xda-\xb9\xa9d\xc9X^=\xe8k\u02041jJK\xbb\x88\x92\xf1&.\xf9+'\x82`\xd03P}\xe3\x1a\x9e\x94/Zi\xdf\u0420\xb0k\x9c4\x92\xe4\xb3+9\xb7QvQ+\xe6\u0125\xf4\x910\x06\xd0\xc5\xd7M&\tH3\x06\xb3\nZ\u0456\x15\xbaH\xac\xdd.\x19\x17\x00\x92\x1a\xaa\x15\xe6\xde\xdct\x03\t\x10\xe5\xc5U\xc1\x84\u051d\x93I\x124\xa6\x16\x10\u0567\xd0k\xafdW*\xa4\x02\t\x85\xcd\xcdM\x1c?\xfe\xf2\xad\xcc\xfa\xfd\x81\xd5\xc7\xc71\xfa\xfd!\xda\xdd\x0e\xd6V\xd7\xd0\xed\xf6p\xe1\xe2\nVVWQ\x8bB4\x9b-LOOaff\x06\v\xf3\xf3\u063d{\x17v\xef\xd9\r%\xc3\x02\xa0\x19\xc3h6\x1b\u0540\xe3}\xa2.,?\x83ao\x13\xb5\xd6|\xb6) S\xad\xe4\xe0B\x022y\x1fpv[tk\xe4\xe4\x03\x05U\x045A\xb8E\xa0\xe3\x14\x1d&'L\x84\x01D\x89\x9a+\xe7\xbf\xfaCU<\x11\xecP$\xec\xbd+\xc8\xdf%\x9fr\"\xc8\u0100\x98\xa0\xc3\xf8]\xdcq\xc7[.\x83\xf9\x8f\xeb\xd8\xd8\xd8 \x00\xfc\x99\xcf\xfc\xfb\x0ft\xbb\xddk:\x9d\x0e\xa4\x94\x94s\xc0\xf9q\xfd\xf5\xd7\xe3\xb6\xdbn\u035a\x9f?\xfa\x83\xc7\xcc\xf1/u\xa4\xe1\n\x85f\x8f\x1b\xc9O\xc1<=W\x02\xa3^\x8fP\v#\x98V=W\xba\x94T\r\x13\xf3\x9f\x19\x18%\x89\x05\x91\xb0\x8e\xe9Z3\xf7A\x17\x02\xb9\x8b4\xd0\xedn\xa2\xd3\xe9bn~\x0ea\x10\x00\xf0+m\x8d8\x1ea\x10ws\xafv\"\xec\u0631\v\xd7\\s\r\xbe\xf0\x85\xad\xf3p\x87\xbd\r\xac_8\x8e\xe9\x1d\a\x1c\xf7\xa9\x8bzB\xaeh\xf9yZ?\"\xbb.\u02a1A\xe8\xc0/\xad\xd0=?\xb2\xfc\xda\xc9V\xdeaGC\r\xd8\xf1\xd3\xde\xebm\xbc\x99\xf8J\x19\xe28\xe5P\xdd\x13%\x94'\x97\xa8\x9c\xef\xea+/8\xe7\x93e\f\x18i\x95\x1a~\xcf@\x8c\x80P'\x19\xa0'\x91\x18\xabp\u02e7\x915<\xd3\x06d\xdah-{\x94\xbb\xc1\x1e\x9atY\u07a9\x17\xbc\x1a\xc6\x1a\xa5\xbe\xd8\xdc\xf9\xa5\xf89\xa0n\x95)\x18\xba\xa5\xef\x95qrA\xe7Q\x1e\fL\x01\xd0\xd5\xc8\xca\x11\v\xc6\x12\xee\x9c\x04\xa8@\x162\xb9\xb6W\x99=,uA\xd2A?A\x12Q\xad\t\xa9\x82\xcc?)-\x88H\x06l\x18\xb4\xbe\xbe~\x13\x80\x10\xc0\xf0\xde{?{\xb92\xffq\x1d.\xa3\x8f\x01\xe0\xfe\xfb\xbfs\xd3\xc6\xc6\x06\x88(!\"U\x06r\xa5\x14~\xfe\xe7\u007f\x0e33\xf3`N\xb6\xcd5\xc4\u039f;\x05D\xf2\x06\x91R\xfa%\xbd\x96\u010d\u29c0\x9fz\u02cc\x93\u00d3K&\x9f\re\x9d\x14\xa3\xbf8\xe7\x0eG\xa3\xa1\xb5!0\x06\x83\xc1\x00\xfe\xe2\xe8\x9fgff\xe4\x16\x9c;\xef\xbc\x13\xd3\xd3\u04d6\u04dft\xcd\xc3\x1e\xd6\xce\x1e\u00fek\xdf\x01\x01\x01\u05ba$s+\x0e\xe2p\xa9$\xe6\xd4\xc3\xddyZ\xa7M\xb4\xa4N\xb9%k\xa9\xb8\fz\x1aA?\x1fa\xf7\xb7\xfad&\x039\x95\xaa\xf3j\u04ba\xb8\xf8PE\r\xcf\xf0\ar\xc6w-V\xa5\xe1\x93\xea\xf9\x0f\x92\xb6\xb2\xf5\"l4:kg\xdd(5\xd2`\u0209\xe7X\xacx\x91i\rS)\xa1\x1c\x1aD\xed\x04j`\x8a\u041a6<\x9d\x17\x89\xf0\u0324\xc8G\xe8\t\x9e\xe1\xe3\r\xc7\xd2$\u0418/@\x99\xf2'g\x04@\x05&\xa6\xfc\v\u04a6+\x19[9\xdbp\b\u05f0t\ra\xe1\xc6\xe1\xa3M\x8d\xa8\xe3\u4525\u0758\x8c\x19a'\xb1\xa1\r\x8cl\xb1SCc\xadm\xc7v \u049b\xf0\xe2\u014b\x8ef\xf1\xd2\xe2\x19XXX\xc0\xe2\xe2\x12\xa4\x14\x85\x9b6\xbd\x86\xd7J\x83\xfc$\x8f\x03\a\xf6cvvv\xe2N\x1b\x00\xe2a\x17Z\xc7VZF^\xfd\xc6\xe3UVUm\x9c\x8e\xc9Sb\xb2*\x94\x9c\xc4P\x8e\x18\xd1f\x82h3\xc9\xd2s\xc8\x14<(\xf3m\xbb).\x1a%bd\x8c\"\x98h\x81[\xe2\xceil)\xe0\U00045a7a\x9e/^s\x89\x82\xb1\xf6\xafy*\x85\xdf/ ]\xc4V\xf6\xa5\x92\\\u0352\xe4\x97E\xd5\x15\xfaV\x8c\xe4\x18\xc5R\xf4\n*\xfe..\x18;\xfbt\fy\x14P\xba\xab\xf0\xcd\xce\xc8 7\xec\xf2{&\x94\xe7\v Wv\xe6\v\xa6\x97\x9a\x95\xf7\x96\u0606\u0478>p\u0618B\x10\u05b2\xe9\xe7l\x91\x80}nm\x80~\u007f\xb0\xe3[\u07fa\xef\xb6\xcb`\xfec:\xbe\xf2\x95\xaf\x02\x00\x9e|\xf2\xc9\xfd) \xa6\x1e&>\x98\xdfu\xd7]\xb8\xf3\xce;\xb0\x9d\x92\x9f\x98\x19RJ\f\x06=\x9c;w\xce\xed (\vv`6\xbc\xb8\xb8\x88\xc5\xc5\xc5\xec\u3402w\xa7\xd3\xde\xf6`\xbeg\xcfn\xcc\xce\u030c\u05fa^E8\x1at0\u8b3b\xc1\x92\xbc:\x1foA\x96A&\xafb\xd3\x11|\x91\x18\x88\xc4d`G\xda\x0e\xa1\x84\xa9\xef\x8aO\xf1\xfaO\xa7\x91+;x\x12R\x95\xbb{\x15 _Q\x02\xf3%8\xf7\x94N\xf0\xab[\xda\nI=u#a\xbcj\x17\x89\xe5\xd9\xc9\u016be\x8a\x98\x8ak\xcb\xcd\xcf\xf2\x05\x94+\x17\x13.]3UL\xc7\xfa\x12L\xaf\xa3K\x97\xc0\u007f\xef/i\x837\xdd}X\x130d\x8d\xf1|\xb9\xa3\xc2\xe2d?\x18\"\u05da\xfb\x97\xe4}>\xb2\u0701\xb1\xb4sF\x10\u05ad\xd6\xdc\x19\xd51\xe7=\x9c\xd4\xcb?I4\x8e\x1d?\xfe\xe6\xcb`\xfec:>\xfb\u067f\x1e1s\xb3\xdd\xee\xdc\xf5\xd2K/e\xda\xecL\x93M\x84\xc5\xc5E\xdc}\xf7\xdd\u0631c7\xfa\xfd\xbe'\xe5\xfb\xcf\u007fH)\xb1\xba\xba\x82W^9\xe3\xe1\\\xf6\xa1\xa1\xe9\xe9\xe9daa^KY4\xac\xe8t:H\xe3\xed\xb6S#7\xa7Y\x18\a\x0e\x1c\xc0\xae\u077b*Y\x96\xf4\x03\x95\x8c\xfa\xe8wW*\u22f6\x9c\xa1D\x85p8\xab\xca-\x18X\x0f\x0f\x998\xe5CR\f]`\xd7=M\xab\xdd1)P\x01Z\xab\xd4*\\\xcd%s\xd5u\xe4\xb1\x19T\xb5\xb3\x98D\x85\xa0\x94\xfa\xe4I\xf7\x84W\xb9\xca$\xe7\u01b3\xa6\xb03\r3\"\x9f&\x9d\u073b\xad\x18\x10\xaa\u0715x\x8f\x13\xe4\xd3\xe4[\x97\xf1\x13\xa2\xf1\xaa\xa2\aS\xed{A*\xca\\\x99\x15\x9aSE\x15\xd4\x11\xd1\x18;\x97[\xafsa\xc6K\x1b\x06\x84Dcz\x11B\x05\u0678?\xdc\xf0\x143 U\xc0k\x1b\x9bX>\xfd\xca5\u033c\x04\x00\x0f=\xf4\xc0e0\xffQs\xb3\xcf<\xf3\xd4\xe2\xf2\xf2\xf2\xf5\xa9\x17K\xd97\xfb\x86\x1b\xae\xc7-\xb7\xbci\x9b\x9e\xbf\xc4\xea\xea*.:\x83-\xf6R)\xa2(\xc4\xe6\xe6\u01a3\xccx\xb1^\xaf;\x89o\u0299\x0f\x91$\xf16\xae\xcc\rv\xef\u078d\x03\xfb\xf7W\\w~\x1d:\x1e`\xd0]\xf7\xb24=\xdeSL\x029_\xcb]\xaa{9\xa5S\\\x95\x97\xd2'\xee\xef\xb6\x1a\xf6\xb7\xff\xec\xe5\x97Va\xdb\xe4\x99\xcfJ\xe8\xa5\xf2\xa2S\x04\xc1\xf2d%\xf1\xf8\xba\xc0\xd9uQ\xe15K\u007fF8n\xc0\xf2\xc8\xc8\x1d\x1eK\xe1\x12\x82\x91}\u007f\xe2\nI\x84KxB\x8e\u007f\x9f\xca\xc0?\xb9M\\\xa4\u04cb\xa4\x13\x97h\xa4\ft\x99KE}\xc9*\xc0\xf5\v\xb2\xc1*\xf7\x021sa\xea\x17\xdeD4;\x9bg\xf6\u04d1\xdc{\x94\xba\x826\xa6\x16 \x83\xc8\xd9L[\xf9\xadt\xf2[)\x15u{\x03\xb4\xdb\xed\xbd\xdf\xf8\xc6W\xdf\f\x00\x0f<\xf0=z\xfe\xf9g.\x83\xf9\x8f\x92o\xfe\xeew\x1f\xb8\xa2\xdf\xef\xdf<\x1c\x8e\n\x14\x8b}\x13$n\xbf\xfdv\x1c9r\x04I2\u0716\u0dfe\xbe\x81\x8d\x8d\xf51\xc0SJ\xa1\xd3\xe9.\x03\xb8\x10\x04AA\x156\x18\f\x11\xc7\u0276\x05sc\f\x84\bp\xe8\xf0!\x04a\xe8\xde/Q\u0612\x03\xc0h8@o\xf3b\xb6\x95\x1d\xa3A\xca3\xf4\xa8\xaa\U000386be5\xe34\xae0\u0784\x9f\x86\r\xd64\\fn\xc6+\xd3J~\x9b*P\x8bQ!\x8es~+\x13\b\x94\t\x8bU\xc1E\xdd\xef\xe4\x19/&\x8d\xb9\xe8\x1b\xe4-\x19\xe94#U\xbdp\x15\xd5\xebX5=\x19\xc1+\u007f\x80\xb6\xdaHU\xf6\x19J\xa6\xf3\x85]VYic\r\xc1\x8c$\xbb\x18g\x93\xab\xe9\x1f\u075bm\xf2\xd7\xc3.\fn_\x94\xe9\xd1}\xab\x02\xcf7\x97\t\xf5\xc6\x1c\xa4T\xf9\u0535\x90Y\x1c\xa3\x10\x02Z\x1b6\x9aw<\xfa\xe8\xa37\x02@\xb3\u0660\xab\xaf~\xe3e0\xffQ\x1e\x17/\xae\xdc\xf1\xd2K/\x15\x12m\xd2\xcaw\xff\xfe}x\xeb[\xef\x84R!\x92d{\x82\xdf\xc6\xc6FiR2o\x82\xee\u0631C\xd6\xebuYV\xdf\f\x06\x03\f\x062\b\u0272\x00\x00 \x00IDAT\x83mE\x19U\xed\x9a\x0e\x1f>\x84\u9a69\xb1\x0fl\xba\xd8&\xc3.:\xeb\xe7,\xb0\b\x0f\\\x04\xc1\x10U\x83\xdd\x16\xdc6y\xab\xa1\x9f\x9eC\x1e\xc0g\x14E\x95\x05,\x97\xaa\xec-\xe9\x0f\xae`\x87h\xac\x06\xcf]B\x18[\xea\xd4y\x12oQE\xcf\xe4\x8dP\xcaV?\xf7{\xd3T\xab\u0523\x9e\x8a_\xd5\x05\xb7G@\xf3$\x90/7\xa7/\xd1[(}\xffR\x8f\x18_\x84\xb9\xb0\xf8\xb0\xb0\xbb5#\xc9\xd2G\xde\xee\x80Y\xdbIO\x14\x15\xe5\xe9k@yW\xd4\xfa\xec\xa7\xf3\xfeY\xc5\x0e\xd4[s\x90\xd2N;[\x03/k\xd6k\\\xffA\xca \xd9\xd8l\xe3\u0631\xe3\xd7\x01\xc0\xaf\xfd\xda\u007fc\xb6\x1b\xc5\xf9\xba\x04\xf3\x17^x6\x05\x85\xc6\xf9\xf3\xe7\xefX]]-LC\xa6\xc7\xcd7\xbf\tw\xdcq'\x00\xb3m\xab\xd8N\xa7\x83^\xaf\xe7\xed8\xd8\xf1\xe9\n\xbbw\xef\x0e\xa2(\x94eJ\xa5\xdb\xedf\xfc\xffv\xbc\xa1\xd2s\u06b3g/Z\xadVa'\x95]\xa7\x10\x88G=\xf46\xce\xe7\x8a\v\u05c02\xe9\xcc5Uh\xb1\xc9\x17\xf6Q>8\xefeQ\x92\xcb\xde\x1c\xab&\x9dv9\xe5\xd0s\x19\x1bc\xa2\xeb\n\xf3\x18\xc8\xfa\x93\x9dE\xb8\u326al\xa2\t\xca\xf2R(\x84O@\x8c\xd7\xc3\xf9.B\xf8\u050a3\x912 (E\b\x03\x81P\xd8\xec\x8b\xc9q\xa0r\xa0vE`\xad\xb5\x00\x19\xd4\xc0Z\xc3\xc0\a~[\xf1\x87a(\xce_\xb8\x88\u04e7\xcf\x1ca\xe6\x03\x00\xf0\xb9\xcf\xfd\xad\xb8\f\xe6?\xe4\xf1g\u007f\xf6g\x00\x80\xfb\xef\xbfof}}\xfdm\xa3\xd1(\x03\xf2\xb4\x8am6\x9bx\xe7;\u07ce\x9d;w#I\xe2m\xfb\x02\xf7\xfb=\xc4qR\u079br\xad\x16A)\xb9<\x1c\x0e/R\xe6\xe4fo\u0635\xb5ulll\xa2h|\xb5\xfd\xc0|ii\x11\xadV\xb3\xa2\xbe\xb4\n\t\x93\xc4\xe8\xb5/ \x89\a\xce\x1a\x18\xa5\x00\x1f\xb6\x91k4\x89\x06\xc8a\x8f\xfd\xea\xab\x04&\\\x1a{\x1c\x93\xe5y\xcd4\xa6I\xac\x82\xaf\x14/\u007f\x8b\x8b\xe7\xbc\x05A\xe1\xab\xce\v\xc3<\x15\x89B\xd5\xc4\xc6\xf8\xa4,\x180\x12\x90M\x89\xa8\xa5\x10\x86@ \tJ\xe6>\xf4\xc4\x15\r\u05can$\x8fq\xe2\x97F\xf7\\\xc7R\x150W\xfe\x15\xc5&\x01c2{\xc5\x00H\x11\u0114\x84lI\x04\x01!\n\b\xb5@ \f\x04TV\xa1;\xddb\xd5$+\xe5\x9c:\x17\x9a\xb1\x949*\x02@\x106\x11\u0567\xb3\u0140\xa4\xcc\x1dH\xad\xfcQ\f\x87#lln^\xfb\u007f\xfc\x9f\x9f~\x03\x00\xbcp\xf4\xe8e0\xffa\x8f\xdf\xfe\xed\xdf\x01\x00\x9c={\u6593'O-\xd9!\x1a\xce\xfcM\x00\xe0\xdak\xaf\xc5\a>pw\xc6\xe1nW\u03bf\xdd\xeed&[)\bZ\x1b\xd9&N\x9dZ~\xe4\u0529S/*\x15xJ\x17`mm-\x1b\xe9\xdf\u0395\xf9\x8e\x1d;0==3\x0emi\xf1\u010c\xc1\xe6\n\x86\xed5\xab\x15N\xa9\x11m\xdcT \x95\xfa\x88\xc5\xe4\xf7\xb1\xd6${\x9c\xabo\x8d\x9am\u0569dKR\x04\x95,6\x8f\xb6\xc6\xcf\u025c\x0f\x15\x95\x13\x19\x85K\x15\x04L\xe9\x19y\xacN\xf5\xe0\x9agF9n\x9e\xaa\xc2\xe0\x90\xed\x02\nU$\x97\x99\x80\x8am\x02\x95\x1a\x9e\xa5\tN\x06\x17\n\u0182\xbb\x1f<\x1e\xa6b\xa2t\\UB\x85\x06\xb1\x0e\bIK\"\xdc\x11!\x9c\r f$h1\x80\x98\x92\x10\x81\x00I\v\xeae\x0e=\xd5a\x17TC\\E\xdb\xd3\x18\u060eW\xdf\xc5\xf0\x16\xe6I\xb2E\x14'@\xa9\x94?\x97>\x8b\x80\xa3\x8b\bAK!\x9cRv\xc71\xab C\x01!\t\" \u021a\x80t\xa9D\xcc\xc5\x1d\x12\xfbrt\xdf\n\xdf\x05\x84\xa3\xe0\x9eh d\x80\u9e7d\x10$a\xb4v\x01\xebA\xf6\x9c\x86\x19R\x05|\xe6\xcc9\xf4\xba\xbd\x9fb\xe6\xc5S'N$\x97\xc1\xfc\x878^~\xf9X\xf6\xe7S\xa7\x96\xdf\xea\xab:\xd2\n|\u07fe}\xf8\u065f\xfd\x10\x00\x8c\x01\xe5v\xaa\xccG\xa3\x18\x9dN\xb7\xb0s \u05d4i4\x1a8t\xe8p\x90$\x894.\x9d&\xa5Y:\x9dv68\xb4}\x9b0\x8c0\f\xb1\xb8\xb8\b%U\x11<\xbd\xff\x8d\xfam\f;k\x99\u01ca\xc8\x1a\x96\\P5\x14E-\x13\\\x14\xab\xceB\x10\x92\x9aDR\xb7\xde\xd8,\x8b\xcd@\x1f\x18\x99\xa80\x0e\xee+\u034b\xd4CU\x1d\u0293Kx\xf67\xf6\x1e\xd7N\xbeR\x851\xa9\xf6\xcd\x11\xa9\x88\x8a\x86\x80$\x10\b\xe7\x034g\x94\u0376\x04A\xb4\x14\u010e\x104\xab\x104\x04\xa2\x86DX#\xc8\xc0\xaa3\xca\x16\x88\\-\xb6\xc1\x98\x82\xe7UD\xe4\xb1'\v\xe2rhK\xc5N\xa6J\x97.\xa5@(\t\"\x14\x10S\n*\x10v\r\xae\vPS:\x87D\x86P\x04\n\x90\xc9\x14\x99`\x1b\xe7\xee\x1a\xb3\xf5?\xf3\ua9ca\u05d6\xc0\xc6@H\x89\xa9\xf9\u0750*\x84\x8e\x87\x10BB\x85\xb5\x8c\x8f'\x10\xa4\x90\xd4\xeb\rq\xf1\xe2\u0291o~\xf3k\xfb\xf1:;\xb6\x1d\x98\x1f:t\x85\x03\xb4\x8d#\x17/^\xbc15\xa0\xf2\x03\x9c\xef\xba\xeb\u0778\xf1\xc6\x1b\xb7-\xc5\x02X\xbf\x98\xd1h\x84^\xaf[Y\xed\xd4\xebu\xec\u06b5\xdb-F\xc5\b\xba~\u007f\x80~\u007f\xb0\xcdo\x1d\x03\xa5\x14v\xed\xdam\u524c\x92\x0e\x98A$0\xe8m\xa0\xbfy\x01\u0485Xg\xfc\xae\xa3A}\x8e=W`O\xe0\xae=\xe0Kk\\\xa9\b\xc1\x9cB\xb8+B4-\x11\x04\xae\x9a\x93\u00abP=m\xbb(\xf3\u9503\x00y\x89N\x15\xa0\xc7>\xe0\x15x\x96-p\xb24\tC%v\x19%\x83)\xbf\xfa\u0512\x10\xce(L\xcd\a\x90\x8a\xb2\xea\x94\x00P]\x82\x16C\xc8\xf9\x10\xb2%\xa1\x9a\x12a3\x05v\x01\xa1\xc4Xq\xfc\xc3\x05\x9e\xd2$W\u0742\xb4r\xac\xd7P\x9eG\x12\x84@\x00R\xa6\\\xb9\xb0k\x9e\x81m~\xb6\xa4\xbd6W\xd8hg>f\xdf?\x02K\xf7\xe5/Zd\x1b\xa6\xe9i\xd8\xde\x1a\xe7\n8m@$\u0418^B\x105a\x92\x11\x88\x04\x82\xb0\x9e5p]\u07ca\x12m\x10\xc7\u0261\xfb\xee\xfb\xf6^\x00\xf8\x8b\xbf\xf83\xba\f\xe6?\xe4q\xff\xfd\xdf}\xfb\u0673\xe7\x9a\xddn\u01fd9:\x03\u024f|\xe4\xefA\xa9\bI2\u07364\x84\xb5\x8b\xd5^s\x96\xb2b\xcd\x18\u00edV\v\xfb\xf7\xef\rF\xa3xl\ua0d91\x1c\x0e\v\x00\xbf=\xafQb\u03de\u0748\xc20\xf3\xd1@\x01\x9f%F\x83\x0ez\x9d\x15\xa7C/\x19\xb2O\xf2*\xa9\xa0_\v\x01\ri\xb8\x80\"\u0526\x14\x9a\xf3!\xa6f\x034\x97B\xd4\xe6\x03\x845\t)\x01#,\x18he\xbf\xd8\xe3\u05ab\x16\x86q=J\x95\xab\xa0w\x19c\xdb\u007f\x06ck\xba\x82_\x05l\x02\xb6*W-\x85\xd6R\b\x15\n\x97\x1f\xee\xe9\xaa\rCD\x02b.\x80\x98Q\x10\x91\x80T\x02A] \xaaK\u051b\x12Q]Zj\xa9\\\xa5W\xf6\x05\xb8\xe2\xef[xLr\xb1/Q\xb4\xdf\xe2\xca>\n\x13 \x05!\x10\x04D\x041\x13\x80\x94p\x13\xacNG\x1e\x120\xa3@\x91\vr\x16v\xc7\x01o\xc7e$`\x04\x175\xf5Y\x95^\xbc\fv1zF3\xc2h\n\u0359\x9d0\xc6\xc0h\x9di\xcd}\a\xc6 \bp\xf4\xa5\x97\xf0\u02993\xb7\x00\xc0G>\xf2K|\x19\xcc\u007f\xc8\xe3\xf1\xc7\x1f\u007f\xc3\xfa\xfa:\xe28v\xa1\u01f6\x8c\xbb\xf9\xe6\x9bp\xd3M7\xd9U[\xebm\xfd\xe2\xa6\x15\x02{\x83\x1f\xcc\xe0(\x8a\xd4\xc6\xc6F\xbb^o}\xc3'?\xf5\xe9]\x00p\xdbmw\\\x06\xf3\xd7z\xbc\xe9M\xb7f\u007f>~\xfc\xe5\xb9^\xaf_\b;\x06l\xfed\xad\xd6D\x1c\x8f\xf0z>\x1a\x8d\xba\xba\xf2\xcaCJJU9\xe9ii\x16\xb3\xadi\x16\x00\u0635k\x17\xe6\xe6\xe6\x9cE)\x8d}\x98\xd9\x18\xb4WO\xa3\xbf\xb9\x02!TA\a\\\xa5N\xe6\x02\x90\x97\xab}\a\xe4u\x89\xa0\xa5 f\x02@Z\xc9c\x01\x9f\x14AN+\xd4\xe6\x034[\x12\xb5P \x90\xb6R\xcb\xf8h%\xa0C\x01\xdej\xf2\x06\x93H\xe2\x8a\xc7l\xe5\x9a[\xad\xad\x19_\xcel\xe61DC\"\x98\x0f,(\x1b*\x00\xb9\xf103[z\xd8y\xbd\xd6$h!\x00MI;x\xe3\x1e\xa4\x02BT\x97P\x01\xc0i\x8a=\xa1\xdc\xe4\x98@\x00q\xd5*\x9b\xe3n6\xfcU\xa5\x9e\xf7\x8c\x81\x89 \xa5}ohZ\x82\x1a\xa2\xba\xdf\xc0.\xf89\xe5\xcf#@\x10CR\xdab\xe5,z\x8e\x05\xdb0\x8f\xec\xb51\xee+U\xa8\x98\f\u05d95\x88\x14\x9a3\xbb\x11\xd5g\x90$#\x00\x04)\xc3,\xfc\x82\\\x9f\aDx\xf9\xc4I\xb4;\x9d\xd7U\x94\u0736\xa4Y\x8e\x1e}\xf6g\xd6\xd7\xd7\x0f\xb6\xdbm(\xa52\x8a\xe5\x96[n\xd9\xf6\x8d\u03f1\x8a\x8c\xaa\xff-\bB\x04A\x1dJI7\xe9\t\xf8\x01\x15\x9dN\a\xa3\xd1h\u06cf\xf4\xcf\xce\xce\xe0\xe0\xc1\x83PJ\xa0<\xff\u01ce\x1f\xd8X9\x89\xf6\xdaiH\x15\x8cU\xabT\xfe \x13\x15\xb6\xee\x19^\x01 \xc1\b#\x81\xb0! f\x94U?\x94'@]\u04cf\x14A\xcd\x06\b\xe7C\xd4\x1a\x12\x8dH\xa0\x1e\t\x04\x82\x9cc\x1f\xc3( \t\x85\x954z\xa4|\xbeo\x98\xe0\xa4H\x15Z\xeaI:\xed\x82+ O\xa0c\x9cZ\x8b\x192\"\xd4v\x84\bZ\xaa\x10f\\\x984\xa5\xaa6\xad\x03\xb9P\x00s\x01hV\x01\x91\xbd.A\x84@\x11\xa2\x86\xb4\xfc{\u5fa1\xca[\x86's\xe0\xe9>\xa3\xf0\x92P\xf5\xf3\t@)XuJS\xdas\x134Y\xaa\xee\x16(\x0e\x004\xad\xa2\x85Rq\xbfa\x10\xe7\x03D,a+\xfcBw\xc26=\xcb=\x11\xd61\xea\xad\x05\xcc,\x1e\x86\xd1\x1a\xc3A\a*\xaaC\xa9\xc8=.=s\x81\xd5\xd55\x1c\u007f\xf9\xe5w1st\x19\xcc\u007f\x88\xe3\x1b\xdf\xf8\xd6\xc2\xc6\xc6f=\xedF\xa7\x14\xcb\xdb\xde\xf6V\x1c\x18\x80\x90\x02A$ \x9a\x12\xd4\x14\u0632\x1cf\xab\x83\x14-\t9\xa3 k\x02\xa1\"\xd4\x03B- \xfb\xf97\xae\x99\x16\x88\xdc\x0f\xa4\xb8ba\xe2\x84\xd1V&]\x99/9\x15(j\x1a{\\i\xb1\x92\x84p.@8\xa7\x1c54>y\xeaOb\xd2\xd8\xf9\xb0\xe5\u0195k\"\xce* \xccJW\xdbg\xa8K\u0210\nz\xf4I\x84?a\xf2\xda\u00d4S>\xbc\xc5N\x86\x85U\x1cII\xa0@\x80f\x03P]nyO\xa5.\x88\xd0\xda.H5\xe7\xa3b\t\x95\xac\x02O'?\r\x8c\x1d\xfb\xf7\x16\x1f\xbf\xa5\xcd\xc6\xc0\x18F\x12\x0f\x11\u05a60\xb3x\x10\x00c\xd0Y\x87\njPQ\x03\u0326d\x8fK\u8d3b?u\xfa\xe5\xa3!\x00|\xf3[_\xa7\xcb`\xfe\x03\x1cI\x92\u0726\x94\xac\xc7\xf1\xc8v\x9eMZ\x99\xbf\taX\xc7h\x14\xbf\x8e`\x9b*+\xf5\x14\u0327\xa6\xa6\x10\x04jLOnm\x00\xe2m[\x99\xdb\xddQ\x82(\x8ap\xf8\xf0!DQ*O\u0307P\xec5\t\f{\x1b\xd8\\}\x05Z\xfb\x1e4\x8cr\x13\x8d&#\xbdU5\x84\x04\x11\t\xa0\xa9\x00)&\xb3\x1f)mj\xec\x1d.\xa6\x14\xc4l\x00\x8a\x04\xa4\x04\xa2\x80P\x97\x84\xc0\r\xdah\t\x18\xe5\xa9\\\xbc\xc5e<\x1d\xf9\xd5|\xbb\x8a\xed\xa7\xc2w\xfc$\n\xbb\xeb\x00\xa2)\x85p)\xb4\xea\r\xe6\xca\n\x9a\xb6\xb8\xb7\xb2\xbf\xa7\u0297\x96\x02\xcd\x05v\a\xe3\xaaW)-\x8f.BQ\bw\xf0\x17\x84-]\x12\xdd\x0e\x8a\u0299\xae<~\x9eL\xee}\x13\xee\xf7OK\u0434\xac\xfa\x81\xf1\xb5\x80\x19Fk\v\xcbu\x01\xad\xa8\x90\x13j\xc1\xdd\x01\xbb\xb6`n\xd8@\x1b\xe3vC\xaer7\x9c\xed\xe4u\x12C\xca\x10\xd3s{\x10\x84\r\xc4\xf1\x00\xc6\r\x14\xf9\x94\x93\x10\x12q\xac\xf1\xfc\v/\x04\xdf}\xf8\xd1\xdb\x01\xe0]\uff0b/\x83\xf9\x0fp\xf4\xfb\x83}\xcc\x06I\x92p\n\xe4\x87\x0e\x1d\u0111#G&R\x17\u06cbZ\xb1\xa1\x12J)\x84aP\xf9\xfd\xd42vqq\x11a\x18\x8e\x81y\x1c'\u06deJ\xd2ZC\xca\x10\x87\x0e\x1dB\xb3\xd9\x04\x8d\u036b\xb8\x0f\x92N\xd0^[\u01b0\xbf\t\x92j\xecs<1<\xce\xeb5\x92\x84mf6%P\x17\x97\xd4L\x97{|4%!\xe7\x02\x88\x9a\xb4\xcd8E\xa8)\xb2L\x04;\xb3\xa7\xb0\u031f\xfb\x13G\xfe\t\xb9\xa6$U\xc78\xd3\x18\xdf_0\xcb\xf5*\\\xf7h\u05e8\x8c\x96\xacf<\xdd\x11\x14\x1d\x82+\xf25'\x82:\xf2\u0160)m5\\s\xce\\l\xd7\xc10\x12\xa0\x80,%?&\xe8\xe1\xb1\x19\xa6\xe2\n\x96n*\x8a*\xa0\u00a2E\x16]\xa4 (bP]B\xcc\a\xa0\x80r[\xe2\xca\xe7\xf7\x831\x9cQ\x96\x02\x92\x1a\x90\x10g\xcdN\x18\xb7+H)\x97\xb4]K9\xc5\xc7\xc6d\xbd\x01\xb2Sy`N\u041a\u074d\xe9\x85}`\x93`4\xe8@\x05a\x1e\xf8\xec\xceA\x1b\xc6\xda\xda:^|\xf1\xa5\xb7\\\xa6Y~\x88cuue4\x18\f\x01\x10\xa5\xc3BW^y%\xf6\xed\u06c7\xed\xdc\x14,V\xad\x06Q\x14\xa1\xd9lU\x9e/;\xbd\xe2\xd2\xd2R\x10E5\x18w\xa1\xe9c\xe38\xb6\x9e\x12\xdb\xf8Z}E\xcb\xc2\xc2B%\u0352n\xc6\u06eb\xaf`\xd0\u07c0P\n\x13`\xa2\x1a\xc5\x1df\xaa@@\u0525\xad6\xabT\x10\x18\xe7\x97\xcb\xcc\b\xb5,\xa0\u021a\x84 \x82\x14@\xa4\x04\xea\u03b0J+\xabt\xa9<1*k\xce\xc7\u03c1\xb6\xa0\x0e\u0199\xe8\x94\xcf\x06\u0080\x10\xcd)\x88Y\xe5=\xfc\u0485 OlV\xe6\u007f%fPC\x80\xe6\x02\x88\x86\x84P\x04\x99r\xe85\tR\x02\xc6\a\xeeB\x9a\x0f\x8d\xc5o\x94\u007f\x0f\x8f-d~\x8f\xc35=\x03\xf7\xfb\xeb\x12\xd0[Y9\x96^'\xf6<\xcc#\x01Q\x17\x10\xa2\xd8*\x17\xe9Tq:8$\x04\x84\xb7\x98\x12R\x99\xa2\x80 \x01\x9d\xc4h\xcc\xee\xc4\xcc\xd2!\x18\x9d`\xd8\u06c4TA\xd6\xcfI3D53\x12mp\xee\xdc\xf9w\xa5g\xf4\xf0\xc3\x0f^\x06\xf3\xd7z\f\x87\xa3l\xe23\xb7[\u074d\xa5\xa5\xc5m\x9e\xc0S\x04\xba0\f1==]:\xdf\u051a@\x13\x00Q\xafG\x17l\xd1P$mm\xdaP\xf2:\xb8V\xc6\xcc\xcc4\xf6\xef\xdf?^\x99{ \xb1\xb1z\n\xfd\u038a\xfd\xd0\xf0\xa5\xdcW\xbc\xa7 @*\x01U\x13\x10-\t\x8e\xc4%p\x8e'>+\x11\xac\xdcm.\x80\xacK\xeb\x01B@(\b\ra\xa9f\x1d\n\v\xe8\x84\n\xbd\xb8\x1f\r?I\x01R\x95Z49\xb8\"\b\b\xe1t\x00\xb1\x18\x82\x14Ys@\xc7Qp%\xe8\x95'-\xcb\xf9\xa5\x9e\u076f\xff\xad\xba\x80\x98U\x10N\xbah\x9b\xa2@X\xb3>(LEs\xafI\xec\xc7\xd8N\x83\x8a\x8b({\u0222\x84m\xbe\u04b4\x82\x9cQ\x15\xd4\u04c4EW\x00`\xe3\xeck\xed\xffCEh\xce(4Z\x12\xf5\x10\b$l#\xd4x\x80\x9f\xf2\xf8i\xc2\x14\x18\x865\x8cvT-3\x8cI\xa0\xa2\x06\xa6\x16\x0e@\x86u\x8cF}h\x9dX\xd9,\t/\xb1Np\x1c'X^^~#3\xd7\x00\xe0\xd6[\xef\xb8\f\xe6\xaf\xf5\x90Rf>%)\x98OOO\xa3^o\xbc.T,)\xcdB\xa4077\x8b \b\xe0W\u0756\xa20\xd8\xd8X\t\x9e\u007f\xfe\xe8\x97766\u06f5Z\xbd\x10H;\x18\f\u0728\xff\xf6\x06s\xadc\xcc\xce\xce\xe2\u0211\xab\xac?\x06\xa1\u020b;:\xa2\xbd\xf6\n:\x9d\xf3v\xab[\xa60\xaa\x02\x9d\xddC\x94\x04TD\x90-\t\x9aRn\xc2o\x82\xcf\t\u00c5\xf5\xa2Z\x80\x91\xfe[\u04daU\u0256\xb2\n\vE\b\x94@]Y\xd3*\x1d\t\x98\xc0sW\xf49\x9b\t\xa1<\x05m\xfa%\x17\x18\x02\t L\x1b\x92\x8b\x01\xe0\x86\x83\xf2\x11\xfc\xaa&g\xfe/\x95\xfd\x05\x1e\xcf\x02%\xa2|\u0769\t\xd0|\x00L\u0641*!\xad7z\xbdf-g\x89\xc6s83\x9f\u022cb/\xee\b\xd2\xde\x04yzI\u06ec&H)\xecnh)\x80\b\xa8b\xc7Q\xd4\xed3\xf2\xb8?\xd6\x1aF'\x96\x0f7\x06\x82\x18A\x04\xa8\x96@P\x13\x88\x027\x80\x94\x017\xf2&\xa9\xf1\x16\x027=\x9e\xfa\x9a\x83\x01\x9d\u0118\xddq\x18\xd3\xf3{\x91\x8c\xfa\x18\r{\x102\x80H\xc7G\x89\xa0\x94\xa2N\xb7\x87\x13'OM\u007f\xfb\xdb\u07f8\xe72\xcd\xf2\x03\x1e\x8dF\x1dR\xca\xd2M)\xb6=\xb0\x95h\x14\x00\xc0\xcc\u0334m\x0e\x96\x8e$\xd1t\xe1\xc2*\x1a\x8d\xc6@\b\x91\x94+\xf0tXj\xbb_s\x92h4\x1a\r\xec\u06f7\xcf)Z\xaag8G\xc3\x1e\xba\xed\x8b\xd0&\xa9l\x82\x8e\xcdQ\x12 \x89\xa0\xa4\xb0\xb4\u0234\x0f\b\xd5\xceQ\xa9\xcd\x15\xc0\x93\xeb\xf3\xf4W\xd6\x04h^\xd9\xe6\xa8\x04 \xac?xMX\xa0M\x02\x01\x13\x8a|\xb0(\xe5^\xb7|?\xe8U\xbc[\xf6\xf9\x02A\b#\x011\xa7\x80i\x8fz\xe2\\\xbf]\xad+a\xcfY\xb2\xaa\x84\x9eddnA\x17\x01\x81f\x953\xb4\xb2^)2\x14\x88\"\xfb%E\x89P\xa9Xo\xa9\xfc_\u02af\x9d\t\x80$(a\x9b\xd5b1\x80\xac\x8b\t@>.+\x05\xb9f\xa5N\xc0\u0680\x8dv\x92D\a\xc6\x01@!A(\x810\x90P\x822\xeew\xa8[Swuu\xf5(uK-\xa9\u0552\x00\v4\xa0\x81Qf\xe6a<\x80\x00\x93x9\xb1\x8d\x89\x87\x84\x10\x9c\u007f\xf2\xfe\xc9K\x9c\xbc8\xce\xf3\xb2\r\xbc\xb0\x1c\x9c\tX\xd8\x01\x83\x9e\x102\xc6\x0fd\x03\x92h\t\xa3yhuK=O\xd5\xd55\xdc\u1733\xf7\xfe\xde\x1f{8\xfb\u073a%!/\xbf\u040a\xea\xacURu\u056d{\xcf\x1d\u03b7\xbf\xfd\xfb~\x83\xff\xc8\x14E\x81}\xfb\xae\xcc\xda\xed\xb6\x1c\xee\u078a\xa2\x80\xd6\xe6\x82/\xe6\xd6\x1a(\xd5\u0116-[\xd0h40\xdam\x10`]\xa2\u05dd\x87\xe6\xd2\x05\x03\xd4:\xb3a\xba\x9f\u00f33\tg\xf3:\xa9\xa2T\xbd\xa6\xeec\x1a\x01\x05$\xf0\x04\x0fA\xde4T\xd8\x1a\x02\xb4A\x81&\x14D\xe6.\xfaL\x12\x1a\xbe\xa0[E\xb0\xa9RT8\xb5\xe1\xaa::T\xf0h\xcd e\x1f\x94 \b\rE\x10\x93\n4S\xc1+\xa9\x00sT\x02Sb\t\x81\xe7\x97 \r\x95\xfa\xa1\xe7N\xbe\xa0cR9\x11\x8fpP\x8bj8\ua9d4U\x90G\x88s\x1b\xbe\xb3\xe1\xfdA\xb4i!o\xa2\x95\x11\xc4F\x055\x95\xd5\xf8\xe8\xa3\xf1\x9b\xfaN.v\xd26\xd0\x0f]\x97\rk\x01\xc1\xe0&9\xda)\xac\x0f\xe7\xf0\xcc\x16k\xc1\xda8.zl\xaal\xfc^\x04\xd8\xc72\x94ja\xc3\xe6K\xd1lO\xc0\xe8\x1c\xd6j@\u0238xy\xb1\"\x17E\x81\xe3\u01cf\xbf=\x9cn\x96\xb5\u058b\xf9\x8b:)!\x9e\xb1\xd6B)E\xa1\x8b[ZZB\xbf\xdf_\u0571_\xe8G\xbb=\x86V\xab=\xf2w\x83A\x1f7\xdexC699!\x86#\xf1*\x98\xe5\u009f\r\x00\xc0\xec\xec,:\x9d\xb1\xd5\xe5\xc5\xeb\u05ad5\xc8{K0\\\x823\x91fP\xa0\x96\xa4\xe9\x8bA&\x9d\x9d+\x8fI\xe7\xd3!B\x9e\xa3\xaf2\xc4\xd1pkTM\x8dl\x88U\xbfO~`\x01(\xe1:\xd5\t7\f$\u12ad\xf4\xf7a\x15\xc14\xbdR\x14\x14\xdd\xfcj@|(n\xabL\xc4\xea\x10\x05\x93\x83\x1f2E\x0e\xbb\x9ei8\x0e\xb5\xad\xa0\x82\xf8\xf4j\u0557Gw\xe8#\x81\x9e\xbai\x18Q\x8a\x87$\v\x99\"\xc7r\x99T\x80r;\x13\xca\x04dS\"k\b(\x95\xb4\xca\u00b3n\u05b0\b\x8e*K_\x04\x95$\u0229\fjc\x96\u030d+\xc6Im\xf1\x1e\xe6wz~9\x9b\n/\xaf \x12\xcfb\x91N\xf0\xc5`\bb\bI1g6\xae[\"\x9d\u06cc\xb04\xb6%f\xb6^\x8e\xf1\xa99\xe82\x875\xdaw\xe6\x14\xbby\xa5\x14\x9d=s\x06\x8f<\xf2\xe8\xe6s\xe7\u03bcj\x1df\xf9[\x1cJ\xa9\xfd\xd6r\xb7\u0468\xe0\x89\x03\a\x0e\xe0\u0529S\x90\xb2\xf1\x92Q\u007f\xbab\xdeF\xab\xd5J0\xf3\xc0\xf7\x15$\x84\x90;w\xeez\xaa\xd9l\x9ck6\x9b\xb5\u03bd\xdf\x1f\xa0,_:|\xfa\xa9\xa9)l\u0738\xd1C\xe4\xc3v\x87\x04f\x8b\xa2\xbf\fkJgO+\x87\x82\x13\"F\ue2dd$\xa0)\xc0S\xd2\tG,\xeav\xe2UtP\x1a(\x14\xbb;Ak\x80\x1ea\u06ddt\x82\x94\t\xd0T\x06\x9aR\x10\x99\x80\xf4\vJ\xac;\x020\x99\xa8V\t\x1a\u00a91\xdc\xfe\xf3PG\x8dJ\xb4\xd3$\u020e\xb3\xafE\xa0!bDm\xe3\x90\xda1\\\xbbG\x81/\xc3\x05\x96F\x92\x06k\x1d\xb4u\"%\x9a\x92\xa0\xa9\f\u021c\xf1\x18Ig\xd2\xd5P\x02*]O\x12\x16\xce(\x83\xe2`Q+$ \xc7\xdd\x1c\x802\xb1\xea\xbcG\xa6\x15%\xef_eN\x97\x0e@\x1d\xccb=\x06\x0e\x82\xa3Z*\xb7\x83\x12\xd2\xef.\x84\xa3\xfc\x92W\x11\xdb@]\xf4CR\xf6n\x89\xe1\xff\x9d\xa99L\xcf\xee\x82\x10\x12V;C?!\xbd\x93\xa2\xef6\xba\xbd>\x16\x16\xce\xed\xfc\xecg?{C\n\x9f\xae\x17\xf3\x1f\xf1\xb8\xed\xb67\xcf\xcf\xcdm6Y\u0588\xea\xee\xfb\xef\xff>\xee\xb8\xe3N7\xc7i\xb5\xf0RI\xceN\x8byz\xd5\n!!\xa5\x90Dt\xa8\xd5j\x9d\xe8t\xc6\xfds\xaa\x02*\xf2\xfc\xc2W\xba\x06\xf5\xea\u018d\x1b\xb0m\u06f6h\xff;b\x88\x80\xa2\xbf\f\xa3K\x10I\xb7}W\xae\x80\x84\xad\xbc\x94\x84,#\bE\x80\x02xR\x82\xc7%\xb4e\x94\xb6N\x88s]\xa7+x\x14\xc1Z\xae\x93\xe6\x88kt\xb9\x14\xaap\x85\xb2\x12\u0650\xf2l\x8f\r\x95Z\xb4\xa5\xc8\xd58v\xe7g2\xaa\x02.j\v\x11\xd7\xf0c\x1e^\xc8\xe0\ng\xd6\x12\x90\xbe#\xa7\r^\xa8bQs.X\x9bQB\xabb\xa9y\xd5\"B\u03c3\xdb\xd7=^\x9c\xe4\x9da\x05\x81'=\u44b9\xe2H\x19\x81\u048cQN\x92\x93\u05a2\xb9{\x18J\x8dI\xa8M\x19\u460c\x8b\x00%\xbb\xa2\x10\xc2<\u0681\u04a7\x18\xd9\xca_\x98\r\x83\xad\x89E\x18\x81?.\x1d]\x91}\xe83\xc8\u07f7\xf7\xe7t\x8fc\x9cR\x14U~\xb0\xf1\"Dk4\x88$6_\xf4\n4\u06d3\xd0e\xee\xc2S\x84\x02\x91\xf0\xf5\x87\xe8v\x97\x90e-\xb4Z\x9d\x18\x04q\xe1\x15v\x8b\xf1\xf1qt:\x9dX\xf8\xc2d}0\x18\xf0\xd3O?\r\x00\x98\x99\xd9x<\xcb\x14\x88D\x04\x00\xfa\xfd\x01B\xca\u0485^\u03356\x98\x9e\x9e\u008e\x1d\u06e1\x94\xac\x158J'\x90\xe1\xfaU\xbe\xb3\r\xdc\xe0\xe0\u06e1\b$\x05\xa8! &%DGB\x06\xebT$\xd71%\xfe\xd9k\x18N\xd5\xca\xf6\xdaNX\xfe\xd4\xea\u014a\xc6%\xe4\xc6\f\xaa#\x915\xc8w\xe9\xc2y\xba4\x84S\xfa\f\x19N1\rei&6\x04\xaa)\\1\x1f\x97\xa0)\xd7\x01\xaf*\xb2k\u060c\xa7\v\x16\x0fc\x12\xabj4\x0f\xc5\xd6\xd5\x1f\"\xb8\x97\x18\xbf\x1b\x10\u00a9AE\xa8\x04\x13\x12\u0618\x01c\x12\xdc p\x96\xfa\xbe\xfb\x00\xee\xa4\v\x0f\xef\xa7\x11~\xe71\xad 7fn\xae\xc0\x95\xe2U\xf8B\x1es\xb8\x13\u03da:=\xd1\xf90Y\xad\u0757q\x9duE3\xb4n8\x1a\xa0\x13I\x10-\x01\xf2\xce\u0281\xcdR\x83\xd4D\xb2c\x1b2\xf6\xb4VC\x8dM`\xf6\x92WB5Z\u043a\x88!8l\x8dc^\x81D\xb7\xd7\u0179s\xf3;\xef\xb8\xe3\xcf\xf6:\x94\xe0\xfe\xf5b\xfeB\xc7+_ym\xfc\xfe\xf6\xdb?\xf8\xf9W\xbc\xe2\x15\agg7\xa1\xd1hF\xae\xf6\x993g\xf0\u044f\xfe\x1a~\xf1\x17\xff!\xbe\xf8\xc5/\xe0\x89'\x1eE\x96)\x8c\x8dMDY\xfc\x85R\u052d\xb5\xe8t:\x18\x1bk'\u015c\u0207m\xa8^\xaf\xdf\x04\x80\xa3G\x8f\xdd5\x18\xe45\nc\xc5f\xb9\xf0\x8b\xb91\x1aY\xd6\u009e={0>1Q\xcd4\x88 \xa4\x84\x94\n\x82\x04Z\x9di\xa8\xac\xe9\xe9f\t\xea\xc1\\\xcd\xc0\x04\x1cF>\xae\\\\\x183\x94/:af\x99:\xf5\xb9\xf7\x9bF\x16?pR\xf2\u05fc\xfc\x86\x13t<&;\xe6\n\xba\xecH\x90r\x85/\x13\u0085\x10\xd7d\xff<\x94\xe7@\xb5\u007f\u02cc\x905\x04dS8\x8c\xbc)j\xf8\u007f\x8c\x81[\u02dbf\xad8\xb6\x11~\xf0\xc3I?\xe9e`\xbdK.\xfb\xc7S\x92\xa0(q,\x0f\x1ds[\xc0N+7x\u039c\x1f\x8ejJ\xc8\xcc\r\x87S9\xbf\x15\xf0A\xda\x02j\\A\xcdd\xa0\x86g\xe6\xa4^\x91\x01M\xe2\xe1\xd79\xa5\x1b\xb9\u0398u\tk48\xc0*)~\x9e|\x05?\x16d\x00)\x00\x1eR1\x9ek\x1e`5\x1b=n\xea0\v\xb3Ei4\f\x03\x1bw\xecE\xa3=\u9b54)\x16sv\x9fcQ\x14\xa5VJM\x1d;v\xe2\x06\x00\xe8v\xbb\xeb\xc5\xfcG9\xee\xbc\xf3\xab\xa1H\x1c\xbd\xe9\xa6\x1b?q\xc5\x15W\x94\xe3\xe3\x13h\xb7\u06f5b\xf7\xc5/\xfe\t\xde\xff\xfe\x0f\xe0\xfd\xef\xff ~\xe37\xfe\t\xbe\xf4\xa5?\xc5\xf2\xf22Z\xad\x0eZ\xad\x8e\x17\x1e\x89\x1f\x9b\x822\xf8\xb0w:\xe3\x18\x1b\x1bK\xb0rAy\x9ec\xf3\xe6\xd9\xcbv\xee\xdcq\r\x00l\xd92WfY\x16\xa5\u0100\xa3b^\x88\x03P\"7h\x12B@J\t\xa5\x14\xb2\xccm\xabw\xed\u0685,s\x03j\xe1y\xbbB*\x88,\x83l4\xd1\xecL\x82\xbc\x02Tp\xe2Sb\x00.-\xacq\x96\xa6<&\xc1\xde\xc3#4\x86\x888(\xa2\xfc\x9c_\x88\xe4\xf1\x02\x1d9^\xa0\xbeS\xdb\xcb\xd0;N\\$\xa4\xc3\xf5\x95$\x84H\u04c0\xa1\xa7\x8f\x19\xfe-\x95\xa3\xfb\x89\x967\xbdZ\xcd@\xad\t\x84^\xe4;1\xa2\x93\xe7\xbammH\u0671\xce^W\x80\xbc\x8d\xc1h\xbe|@3\xa8%\x9c\xeb\u2e02jJdaA\x92\xc1m\xd1\xedDB\u0407h\t\xa8i\x05j\xc9\x1a\x1e\x9e\x12i\bnA\xaco\xd9\ua2f0\xd1\x06\xa6(\\Wn\x8d/\xa8\xa6\xf2_I\xbe\b\x0e#bb@q\xa2/p\x98y\xa4*\xc2\xc2x\x13.\xf6!7\x96\x03\xben\xc1l06\xb1\t\xd3s\xbb@B\x80\u0640\xad_\x04\xb8Zu\u03df?\x8f'\x9ex\x82\x00\xe0\xe0\xc1C\xeb\x98\xf9\x8fr\xec\u06f7\x0f\x9f\xfd\xec\u007f\"\x00\xf8\u065f}\xff\xff\xb8\xed\xb67\xff\xdb\u05fe\xf6\x06\x8c\x8d\x8d\xa1\xd9lal\xac\r\xa5T\xbc\xfdC\x0f=\x84?\xf8\x83?\u0107?\xfc\x9c\xd2\xd3\xda\x00\x00 \x00IDAT\xf7\xf0\xa1\x0f}\x18\x9f\xfc\xe4\x1f\xe0\u0211g\xa1T\x13Y\xd6B\xa3\xd1F\xb3\xd9F\xb3\xe9\xba\xfb\xe0\x1f\xfe?\xa7\xc83\xa4\x14\xd1\xf90\xc8\xf6\x8d1\xba\xd9l\xa2,\xcd\x0e\x00\xb8\xf6\xdak\xdb\xe3\xe3\x1d\xdf\xd1V\x17\xf6\u0673g]Q\xf81\xd11]\xe1\x16PJ\xa1\xd9l\xa2\xd9l\xa3\xd1h#\xcb\xda\u0232\x16\x94jB\xca\f\xd62~\xf8\xd0\x0f\xf0G\xff\xe9\xb38\xe3\xe7\x00 \x82\x94\n$\\zK\xa3\xd3A{n\x1b\xa8\xd5\xf2\x83\xac\n\x12\x11p\x81\u077a\xb0\xc8\x19\x184\x05\n\xf6A\f\xd1\x1a\xb7^\x1c\xd2\xee\x94\xd2\xeb<\xc1Vb\xafK/\xae\xa6\a\x9a!Y\xb8l\u034d\nb\xdc\xcb\xe0}Z\x8eLW\x19\u0090\x01\x95\xc7\xc9[\x12\xa2)@-\t\x1a\x97\x80\xac\x9a\xd1:\uf15egQ\xa1\x17t\xb2\x19B\xb5\x93\xe2\xcc0\xbe\x0eJr\xc3Lz\x9e\u05c2*<\xc6\x19\x92M+g5\x9c9\x93.\x12\x95\n4\u0707\x90@c\\B\x8cK\x17\xe3\x96t\xe5<4\xba\x88 \"\x8fp\x8ed\x86-K\x18]\xbaa\xa7\xa9\xe0\x15\xd808\xf5 \u007f\xf2of\xeb\x87\xe7\x0e\xce\t[>\x1b\x86\xa1\\\xd9\xf4R\x98eQ\xb2\xb33\x1a\xaa\xd9\xc6\xc6\xdd\xfb\x00!\xa0K\rcu\x14+1;\x87\u04d5\x95\x15<\xf7\xdca\xed\n\xfb\xe2\x05Y\xcc\u0545vB\xbbw\xef\x01\x00~\xcdk\xae\xa5\xfd\xfb\x1f\xe4\u007f\xf4\x8f~\xfd\xb7\xdb\xed\xf65\x00\xdes\xef\xbd\xf7\xa1\xdb]\x81\x94\x92\xad\xb5d\x8c\x89)\u073d^\x1fw\xde\xf95\xdcu\xd7\xd7\xf1\xd9\xcf\xfe1\xae\xbd\xf6Z\xdc|\xf3M\xb8\xfe\xfa\xeb\xb0s\xe7E\xe8t\xc6 D\xe6\x8bc\xfa\x81\u05c9\xda\xf2\xef\xbc\x1c&\xd3\xfb\x8a\xb2'\x84\x10EQ\xa0\xd7\xebZ\x00\u0631c\xfb\x9f\x13\xd1B\x96e\x1bz\xbd\xea\x12x\xf2\u0267P\x96\x03dY\xf6\xa2\xf3N]\xe7,\x9c\x87\xf8\xdf\u025am\xb0\xb4t\x1e\u01cf\x9f\xc0\x91#Gp\xfc\xf8\t\x9c\x00cl\xfc\xa4\xff\xf0\x87?\xc4\xe2\xe2\"6m\x9a\x83R\xcaE\\\xbd\xd8\x12l\n\x94e\x89\xb2,\xdd\x16\xd3\x1b\xf5\xaf.\xfeT\xf3\x86)\xcb\x12\xcb\xcb+8y\xf2$\x9e~\xfai<\xfc\xf0#8x\xf0\x10N\x9e<\x89\xf9\xf9\xb38wn\x01\x8b\x8b\x8b\xab\xa0 !\x84\x8bw\x13TQ-\x85\xc0\xc4\xec\x16l\u06b5\v\xa2\u04c0!\x86\xb4\x94^\xe3\xae\fy\x86\a\x9d\xd70Z`0&\xd1\x17\x04E@K\xba`\t\xe1;+Z+K\"tb\xb6\x1a8\xf3*\xb1\xca\xf3\x15B\x1ajS]e\xe4\xcc\a>\x18G\x97C\x11\f\xa1\xbc[\x9f\u007f|+\xe0\x84Ha\xa0;&\u0717/\xb0\xc4\u0568r5.\x9e&\x85R\xa2~J\xb924\xf2\x8c\xe3z\xc0\xe4!\x06\x1f\xecL\xf0\xd1s<\xa2\x9b\xf7\xc3\xc1\x04\xbe\xaa\xa0\x1f\xbf\xc06%\u0318\x85Y\x04\xac\xa9\xcf\x17\x049\aFa\xbc{\xa1?5c\x1dN.\xd3A\xb1\x1fZ\x83\xc3{R\xedI\xac\xd10y\x0eS\x140\xba\x04[\xedZ\xfc\xe4\u06b1\xfe\x04+\xd3,[\xb9*\x02n\xb1\x94\x00\xca\xc4x+\xce\u0753E\x88\x03'\xde\xc2\xc2\xe1\xfd,,\x1a\x13\x1b1\xb1e\x17z\vagY\xf1\u0549\x88\x8a\"\u01d6-\x9bw\x00\xc0\x9f\xfe\xe9\xff\xd0G\x8e\aV\t\b\xa3\x91\xb5'1\xb5\xfd2\x9c~r\xbf\xff<+\b\xa1\xc2g\x99\x8a\xa2\xc0\xec\xec\xecnf\xdeBD'\xf1\u0084\xd2\xf5b>\x8c\xd9\x02\xe0\xdf\xfd\xdd\u07e1\x8f}\xec\xe3\xfc\xeaW\xdf\xf0\x97\xcc\xfc\xe6\xff\xfe\xdf\xff\xeb\xffv\xcf=\xf7\xfc\xd2\xe1\xc3G\xdfx\xfc\xf8\xf1\u01a1C\x87\xc0l\xb5\x94JJ)I)\aKh]\x87P\xba\xdd.\xba\xdd.\x80\xe3\x00\x80\a\x1f\xfc\x01\xbe\xf1\x8d\xbf\xc0\xb6m[\xf1\xa67\xbd\to{\xdb[q\xcd5\xd7`\u06f6- \x1a\x8b\xf0B(\x80U\xd7N\x95q\u03e8\x8e\x87\x19\x8dF\x03R6\xb0\u007f\xffw\xf1\xc8#\x8f\u059eO\xa3\u0450y\x9ek!\xe8\xa0\xffy\xf1\xab\xbf\xfa+w\x18c\xaf\x96R\xc6b;??\x8f/}\xe9\u03d0\xe7\x05\x1ez\xe8!\xfc\xe0\a?\xc0\xc1\x83\x87p\xee\xdc9\xb8\xb0k\xa0\xd9la|\xbc\x83\x89\x89\t\xb4Zm0[\xcc\xcf\xcf\xe3\u0109\x93\xe8vW\x90\xe79\xca2\x9c\xbf\x19\xda)P\xf4\x1c\x0f\u07ff\x18\x8a'\t\x01!\xa4S\xcdI\x05!\x1c~EF;xE)\x90\x14\x98\xb9x\x0f\xf6\xdc\xfcV\xa8\xc64\xfa'\xcfC\x90\x80\x95\x1e\u03b0U:\x1bK'\x19g\x02d\u0260\x15\x03bF1.a\x05\xa10\x8c\xd202a\xd1\xca\x04Z\x8a\u0410\"F@\xba\xady(h\xec|\xae\x87\xdc7WA\x15\x9e\xed`9\x91\xfb\xd7\xec\u0513n\xd8\xd3\xe10\xa9\\\xa1X6\xe0\x81\x01t\x05MXCN\x8cSX\xb0P0\xd2CM\xab\xb2,|a\f\x16\x05\xb5\x1a\xef\u07cb\b\xf7\xa4[\xfe\xba\\?-\xd6a\x14\x11\xb1\xf1\xe1\xa0\xe9\xb0\xc8P\xeaT\xb8\x8aM\tm\x19}m\xd1-\x19\xb6k\xd0X1N\xdf\x14\x16\xaf`\xe3\fr\xe7h\x18\xb4l\xdc\xef'$\x023\xd1V(\x8e\xa7L\xa6\xe9\xae\x04k\xdc\xc0\xd3\x149LY:Z\xa0\xc7\u016d\xad[\xe0Zk1l\x04C\x9c:(8\x89\xbf{\xc1\xb8\xc2\xe6\xfd\xfb\x1b\x94\xa3a\x12\xab%\xa0\xa5\xff\xbb\xa2\x84\x18\xeb`|\xd36d\xcd6\xcaA\x1fBH\x90l\x00\xa6\x04\xc3\xc0\x18\v\xa5\xb26\x80\v6\x13\xf4\x82.\xe6\xe1\xf8\xd8\xc7>\u039f\xf9\u0327\xe9\x97~\xe9#LD]\x00\x9f\a\xf0\xf9;\xee\xf8\xca\a\xbe\xfd\xed{\xfe\u0791#G\xde\xf6\xec\xb3\u03e9g\x9f}\x16\x83\xc1\x00D\x8c,SPJ\xc2\x18\x05c\u071bQ/\xc8\xce3<\xcfs\x9c?\xbf\x80\x83\a\x0f\xe1+_\xf9*^\xf3\x9aW\xe3u\xaf\xbb\x15\x97_~9\xe6\xe6\xe60;;\x8b\r\x1b\xa6166\xf1\xa2\xceY\xeb\x1c_\xff\xfa\xd7\xf0\u06ff\xfdoq\xe0\xc03\xd1\x1e\x16\x80m6\x9b\xb2,\xcb\x03\x9b6\xcd>\x19n\xff\x8aW\xbc\xe2\xf4]w}}U!\xfd\u0527>\x8d?\xfc\xc3Obqq\xf1y\x16=8\xfa\x9f\u007f\x8c\x88iz\xe8$\xfc?\fR]\xb3\x13\xf2U\xd9\xc3.\xbc\x9a\xa7;bq%\xe1L\xfe\x11\xd9B\"^_\u0194\xf1\x82\x93J\xa23\xb5\x01\x9b\xf7\\\x8d\xab\xdf\xf5al\xdc{#V\xe6{\xe0\u0702\xd8\xfb\x1bJ\xc0\x12\x83\x02\f`\xad\xc3.|\xbc\xa7`\x8b\u018a\x1bD\xe6\xe3\xd2\xd9\xd22PX\xa0\xc8-\xba%\u0412\x16c\x99@S\x0e\x85\v3\xc5b\u00a3\xe4\xf7\xb4\x1ax\xb1pp\x81\xa5\x91\xe4\x16\xf7\xba\x19\xef\t3.\xdd\xcfK\xeb\x8a9\x85N\u0531G4\xbb\x8eU-\v\xf0\x84t\v\x95M\x89\x1c\xf9\xe4S;F\xe3\xda\xf5\">\xfc}\x1a1\x97B)\xe1{_\xb8\xf9\x85HzD\x04\xa9T2\xfd'\x80\x84\x13\xffd\x19\x1a\xad1\x8co\u068a\x99]\x97c\u64bd\x98\u06be\a\x9d\x99Y\xb4'\xa7\u045a\xd8\x0096\x01-[0B\xc1\x88\x06\x8a\xdcb\xb9?@\xd6+\xd1.Qc2\x90\xf5A\x04\xc1\xf1\xce\xc0o\xe3\xb9R\x1b\u00b5\xca\xd9\xc0\x80\xc0\xc8'\x15LC\x80\xa9\u2a57\x86Q\x96\x8c\xbee\x8cenP\x9aIJ \x16\xdfuS:(\xad<\xae\xeb\x905\xd5\xcc\x0fC\x17\xccL\xae`\xfb\xdd>k\x06V\f\x88\xbdp\u01ba\xc1\x9f\xf10\x06\xc1y\x8c\xe8\x9c\xc1\xe7J\xa0\xb0\xa0I\x05\xd5\x10\x88\"R\xaeZ\u22bf\xed\x9e/\x0f\x85\x98\x86\x1al\x93?c[)+\x89\u073f\x1dN\\\x87t\x1c\xb3eH?J\xee9\x15\x86\xd1--\xfa\xda\xc2\xf8\xa1)\t@\u632co\xe2L \x0e\xab\xc3\xceE\x00d\u072e\x89\x19\xd0\xd6u\u045a\x19\x12\x80\x9c\xc9 2\x01k\xbdM\x82p\x85\u0616\x1a\xba\xc8aB!\x8ftD\xed8\xde\xc1{\x85\x19ll\f\xa7\b\u0316`o\xcb\x1e\x9b\x93\x82<\x1f\xdci\x15\xb8t\xb7\xa3j\xb5\x84\xa7\xa0\xc0\x92t\x1d\xb9\xa8\x16n\xf2\u05c71\x06\xb2\xd9B\u0599\x8a\xf7\x97\xc2TB\b\xf4\a\xc5\x00\x00^s\xfd\r47\xb7e\xbd3\xff\xbb:\xee\xb8\xe3+x\xdb\xdb\xde\xc1\x0f=\xf47\xf4\xe0\x83\x0f\xca_\xf8\x85_4ss\xdb\x1f\a\xf08\x80\xcf3\xf3\xb6\xff\xf6\xdf\xfe\xcb\xdc\xe1\u00c7ggf6\xbe\xe9\u0739\xf3;\x1ey\xe4\xe1%)\xd5E\x1b6lx\xeb\xc1\x83\a\xd5\u0463G\xb1\xbc\xbc\x82\x95\x95\x15,//#\xcfs\x0e\n\xcd\xe1\x8e\xd5u\xdf\x05\u039c9\x833g^\x98\x16\x18:q)E\x847\xac\xb5\xbcy\xf3\\v\xf9\xe5{\x06\xb7\xddv\xdb\u007f\x01\x80\xc7\x1e{\x98\xf6\xed\xbb\x86?\xf8\xc1\x9f_z\xf2\u0267\xfe\xea\u0211\xa3\x1fx\u4447\xd1\xeb\xf5G\x16\xde\xf4\xbc\xc2\xf7C\x85\u007f\xe4\xdf\x11\x11Z\xad\x16\t!\xe2\x1c!\xfd\xbb\xb4\xf8K\x95\xa13\xbd\x01B5AY\x86\xf6\xe4\x06\xcc\\t\x19\xb6\\~\r6\xee\u078b\xf6\u62d0M\u03601>\r\xb4\xc6\xdd6\u057a\xf3\xe8\x97\x1a\xa56\xb0\u0682M\x0f\xb64\x10\xc6uy\xc2$\x92\xf9\x9a\xf2\x93]\xa7g\x03\x8c\xe0)e^\x90\x130c\u0577\x00k\x14\x13\n\xa6\xe9\v\x9cE\xbc\xb8\xf3\u04a2,\x81AF\x18oJ\xb4\x1aU\xa7\xce5x\x82V\xe1\xc4\xe9\x8bfb\x91\xe4\x88)k\xc3\u0425+.\xc62d\xcfB,\x1b\x90u\x85-\x868\b\xef\u07c2D\xe0h\x00\xbbl\u07023\xa9@\r\x82\x02\x90\x81\x90\x81#\a\x9c\xfd\xf3\x14*a\xa2\xa0\xdaYp\xbaCH\xb6\xfa\x82\xea\u04c0\u06ae$\xb0K\xb8>-\xd0\x06\xe8Y\x87\x8b\x97&Q\u0252\xdf\r\xf5-T\xe1vI,\xfc\xfba\x00\xd2\xd6\xe3\xfc~\x87\xe1'\xa8\x82\x00\xd6@I\x8cr\xd9@\nB\xb61\x83\xf23\x83R\x1bp\xe9\xf0q.\x1dk\xc5j\r\xa35\xd8w\xe4)\xac\xc2\u0182\x8d\x89\x83P\xa7\b\xe5\xa4kO\xb6\x1b\xecp&1\xb0\xb0%;s-\xef\xfbB\x11\xa7r,\x1f\xaey\xe1x(\xce/ \xa42H\xcflcx_u6\x00;\xe7\x97M\xb3\x9b'\x01`\xff\xfd\xf7\x99\x93g\x17\xd6\a\xa0\u007fW\u01fb\xdf\xfd\x1e\x8f5\xbf\x8a\x01\xe8\x13'\x8e\u04b7\xbf}\x8f\xba\u77bf\x12\x9f\xfc\xe4\xa7\n\":\x1e&\x9d\xcc\xfc\r\x00-\x00\xdaZ\u04fe\xf7\xde{7\x1e8p\xa0\xdd\xedv_\u007f\xe4\u0211\xf7?\xf6\xd8c?q\xf8\xf0\xe1\xa9n\xb7K\v\v\xe71\x188_\x14\xb7]\x17\x15\xc5\xcdo\xfd\xa8>?\x1b\x8aJ\xab`\x8e\xa4Sf\"A[\xb7n\xa3\x9bo\xbe\t\xb7\xdcr\u02ff\u0677\xef\xea\xbb\x01`\u07fekB\x90s~\xd7]_\xfb\xbd,\xcb\xde=>>>\xfe\xc0\x03\xfbiqq\xe9Gz-\xaa\xee_\xa1\xd9l\x12\x11\xa1\xdf\xef#\xcb\x14\x8f\x8d\x8dQ\xbb=\x06\",l\u07fe\xddn\u06f6m\xfe\xfc\xf9\xf3_\x1b\f\xfao\xfc\xde\xf7\xee{e\xea\xff\x12\x1c\xe1\xc6&7\xe2\u019f\xfbUl\xdc\xfbJ\xa09\x86\xf1\x99-hM\xcd@\xb6;0\xaa\x05C\x02eYb\xa5,\xa1\xcf/:\xb8*\xf0\x95\xa9JI'\x02\x98\x04Di\xdc@3TTI\xd5\xf7\x9c\x14\xf6\x00lp\xc5\xf1vX\xad\xc3iI\x00j`AF\xa3\x98\x94\xd0-\xe1=^b\x1d\x85\xb5\x8cA\xc1(5\xa3m\x04&\xda@K\xc8\xc4\xe3|m<\xbc\xb4\fm\x19\x03mQ\x9a\nk\xb6\xceb\x1b:wb\x16\xa9\x19\x8d\x15\vU\xb2\x87\xa1\x82\xa0\x06\x95\xe8\xa66\xcfd\bKP\x03\xbf\x18\x8dK\x14\x19\x01\xdaB\x18\x8bL\xb8\x9d\x84\x92\x04\xa5\b\x92\x9c\u06b2\xdaI\x84\xe2\x9d\xf8\x8cp`\xab\x84q\"\xc7\xcf)\xaa\x97..H\xe9B\x95kF\xcfX\xe4NG\x19\xcd\u0442Y\x95\xea[\u0201\x89wB\f@3\xa4\xf1,\x16\x03\b\xe6\x88\xd4 @\x16\x9eQd4C\x9f/Q\x12\xa31)\xa1\xd8\xc0\x16\x8e\xb1\xc2Z\x03F;\uee9fc\xc1\x98\xaa\x90\a>\xb9\x87A\xd9$\x1cs\xb6\x91c\x8e\x80\x99\xb3\x05\x97\f;0@a\"}2:4\"\xb11`@X\x86%\xaa\xbbf\x06\xdez\x80\x1d\xbdk\xa21\xda)G\x01\xc7\xcc\xf2\xa1\xcf\xd5\u02b7\u0799\xff\xffrl\u077a\x83\x01\xd4\xd2\x1c\x9e~\xfa\t\\v\xd9^\x90\xe3\xa2\x05\v\xc2\x12@\xa8\x92\x8f\x03\xf8\xf4\xf1\xe3G\xf6\xfd\xf1\x1f\xff\xe7\x9f9|\xf8\xf0\xcf=\xfd\xf4\x81\xd9~\xbf\xbf\x19\x80XZZ\u00993g\x90\xe79\x8a\xa2,=.-\x84\x10\x94b\xd1\u00d0\a\xbb\xc3Z\u02d4e\x99\u06b0a\x9a\xb6n\u074ak\xae\xb9\xfa\xec{\xdf\xfb\xde\xdf{\xeb[\xdf\xfe\u007f\x00\xc0\x1f\xfc\xc1\xef\u04ef\xfd\u06af\xf3\x17\xbe\xf09\xba\xfd\xf6\x0f\xf2\xdb\xdf\xfe\x8e\xfb\xfa\xfd\xe57\\t\xd1\xce\xffs\u01ce\xed\xb7<\xf1\u0113\x8dS\xa7Na0\x18@)\x85\xb2,K\xa5\xd4\xf2\xe4\xe4\xa4PJ\"\xcb\x1a\x12@\xbe\xb0p\xee(3z[\xb6\u0309]\xbbv5\xa6\xa6\xa6N?\xf5\xd4S\xff\u03d5W\xee\xed\xddt\xd3M\xadK/\xbd\xd4LMM|\xf3\xaa\xab^\xf9\x8c?\xbf\xe6\xdf\xff\xfb\x1f\xfe\xcf\xdf\xf9\xcew_\x19,k\x03\x9c\x026 \xa9\xb0s\u07ed\xd8y\u02ed\xe8\x19\x86\x06A\x1bF^\x14\x18\xf4s\xb05\xb1\xd0H)!\xa5\x88\x1d\xec\xaay\x1e[d\x85u\x83&O\x13$\x9bx\v&xFJ\x19\x8c\x9e\xdb)\x89#p\xa7K\x8b\xe6\x12\x83\x8cB\xd9\x11\xb1[Mi\x88\xdaX\xac\f\x18%\bc\xd6A/JT\x9d\xab\xf5x\xb5\xb5\f\xc3@a\x18\xb9\x1f\x06\u06e4\xcb\r\x1d\xb01\xae\x90\x90\x01T\x9f]!\x0f#\xa9\xcdU\xfdBg\xd8-p\xfd\u00a2[X\x18\x01\x88L\u01a4\x9ep{\x953\x1a=S=\a\x06\x84f\x90\xf6\xbb(\xeb0\xf4\xf0^\xa4\xf3\x06\xb7\xbb\xb2\xb1\xf8\x17g\v\xf4\a\x80j\x1ad\xa6pE\xdcxz\xa1\xadb\xe1\xc2\xc03\xf8\x98#t\xe2\xa6\xe2\x92G\v[\xe3\xfd\xcd\x03,ZZ\x98\xae\x86\xcd\xdd\xcf\xe3{b\xc9\u0767_\x04c\xb0\x89\x00l\x18\xe4\u05f6#\xc2\x0f_\r\xa4Tn\xbeV\x16a\x17\xc0\xadV\v\xcdv;\x0f\x9bo\xb7\x8f\\/\xe6\xff\u04ce\xcb.\xdb;\xf2\xe7\xcf<\xf34.\xbd\xf4\xb2\xf8\xefm\xdbv>\x06\xe01f\xfe\x97\xf7\xde\xfb\xdd\xeb\x1ex`\xffM\v\v\xe7_\xf5\xec\xb3\xcfN//\xaf\xec[^^\xdeND\x9ds\xe7\xce\xe1\u0739\x05\xf4z\xbd\x04/\xaf\x8a\xb9\x10\x8e1\xd2\xe9\x8ccjjRNMM\xa1\xd9l\xf6ggg\x0f]u\xd5U\xdf\xfc\xf0\x87\u007f\xfe\xd3ss[\x1f\x03\x80\xf7\xbd\xef\xe7h\u04e6\x19\x06\x80\xdbo\xff \u007f\xedkw\xd2;\xde\xf1Nn\xb7'\x1e`\xe6\u06ee\xbb\xee5\xb7\xdfu\xd7\xd7\xdf\xf5\xdd\xef~\xaf\xd9\xedvinn\xae\xdbh4\xbf{\xf3\u036f=\xf2\xaew\xbd#k\xb7\u06f0\x96\x1b\x9dN\xe7<\x91\xba\x87\x88\x06\xcf=\xf7\x1c\xee\xbb\xef\xfe\xf8\xbc\xbe\xf5\xado\xe3S\x9f\xfa\xbfG\x12\x8c\x17\x17\x97D:+H\x9b\r]j\fV\xfa(\x16\x80>\xaf@+G\xb7\xd3\\\x9f]\x06\x88\xe4\xf9\xecE\x84f\u021c\xbd\x89Q`\xa9$\x86F\x89\xc9\x16\xfb*\xcabd\xc4g\xac\xea\xc2\x12\xa8`4\xac\x06A\xa2\x1c\x93\x18\x8e\xbe\x16\x9e\x9fg\xc0X),\x06\x06hJ\x82\x0f\f\x82\xb1\x0ek7\x89\xe4=\xb0A\x86\x1e\xce\r\xf0\xfc\u03f2\x82\x91\xe5\xbe`\t\xf7\x1aH\xcd\x0e~\b,\x99\x94\xefg<\u03ac\xdc\x0e\x83\fC\r<\u04e2I(%\u0570m\xb0\x13\xe7\x14\x96=\xd4\xe2DS\xd2\xf3\u01a5p\xcf\xc1Y\n\xa0bQ'\x9c\xf2\xb8T\xfa\x81mQZ\xf4s\x8b^\xcen\xe1 @HQ\xdfa\x12 \r\x90\xf5\rD\xe9\x19 \xcc\x0e\x177\u026e*\x95\xd8&\x19\x9b\x1c\x02 `\x00m\xc1\xc2\x02\xb9\x81\x19\x18\xf4\xdb\x06J\x19\xb4\xc8\xe1\xe9\b\xbe*1\x1e\x8e\xa3\xdd-\x12qP\xc57\xf7\x81\x15\x89X\xc8\x18FQX\xe8\xae\x06\xe5\xa6fU\x1f\x98J\x14w\x1d\xceg\x80-\x03\x86\xc1B\xfa\x1cU\xf6\r\x84\xdbY9\xb7\xc6\x02\xc2\u04c3\x1d;\xcb\xdd\xf1X\xa7\x83\xe9\r\x1b\a\x00\xf0\v\xbf\xfc\xab\xb4u\xd3\xf4zg~!\x1c\xa1\x90?\xf6\xd8\xc3x\xcb[\u0789\xa3G\x0f\xa7\xdd\xf5\xf7\xfdW(6\xaf\xf8\xeaW\xbf\xbc\xf7\xe8\xd1c\xaf}\xf0\xc1\x1f\f:\x9d\xb1\xab\x1a\x8d\u019e\xc5\u0165\xb2(\n\x18\xe3\x042Y\x96\xa1\xd5j\u0271\xb16///?\\\x96\xfa\xe8\x15W\\Q\xec\u06f7\xf7\xe1w\xbd\xeb=\xf7\x12\xd1s\x1f\xff\xf8?\x03\x00\xbc\xf7\xbd\xef\xc1\x87?\xfc\xf3\x1c\xa0\"\x00x\xc7;\xde\xc9\u007f\xf5W\xff/n\xbd\xf5\x8da'\xf1y\xffU;>\xf3\x99\xcf\xfc\xad\x9f\xf7\xa1C\a\x82]BK)IB\xb8\xc1\xdd0\xe8`u\x89\xbc\u06c7^\xd10\xd0>\xb6\xcdC\x1d\x9c$\xb1F\xaa\x9cg\xba\xa0^\x1c\xc8\x02\xaa\xe0\xd8\xe5\x11\xfb\xa1\x19\b$\xb8\x1e\xda3\xd4\xd2\x13\xb9A\x1bQ=U,\x82\xd1\x02\x10\x1ah,\x1b\xc0\x00&\xab\x84\x8eQ\x96\xe2\x17X\x80}\a\u0315\xfd\xe9pr\x19\xd5a\xb3d\"\x8a #R\x1a\xc8r\x1b!\x05b@\x1a\xf7\xfc\xaa>\xad\xae\xd4$\xf8\xae\xd6\x12\xac\xf4E\xdd\x12Tn\xd1,\x9dK\xa1n\xb8\xd2#\xe06G\x94\x88?K\u02c8\x1a[r\x9d\xb9c\xbe\xb8b.C\x81\x17\fEa1r\x85\xbcdF^X\xe4\x03\x8b\xbc0\xfe\xf5&\a\xfb\xd0\xea\x18S\x99[\x88\xbc\xfa@\x90\xf5\x1c\xf2Z\xa6\a\xd5\xf0*f\v\xd6\xd6\v\xe8\r\xac\x1fb\x82\f\x98\f\x044\xa8\xb0\u8d41\\0Z\x02\xf0\x96\xe9\xc9{jcQG*\x18\x8a\x85\xdc\xcd*\xc2\xe3j\x03\xf4\xfb\x1a\xbao \n\v\x19\x86\x99\xfe=g\"\x18\xb8\xc5UD\x18T@\xa02\x1b\v\x10Tx=!\x04t>@\xd1[\xf2\xbb\x00\xe3rA\xfdy\x8e\x8fOb\xe7E\x17K\x87\x02l\xbb \xeb\xda\u02f2\x98\x87c\u07fek\xe2\xf7\xa7N\x9d\xc0\xdc\xdc\xd6Q\uc387\x00<\x04\xe0\x8b\xbe\xb8w\x00\\\xe2\xe1\x9a\xe1\xfeQ\xfa\x06\xebq\x1a%3\x04\xf0\u05b7\xbe\x15\x9f\xf8\xc4'\xf0\xda\xd7\u07bc\xeaw\xb7\xde\xfaF\x1c=\xfa\x1cv\xec\xb8\xf8E?\x97\x83\a\x9fF\xa3\xd1x\u07bf\xf5\x85\xdcw\xa0>\x1e\v\xa6>\x00\x00\x90\xf7\x96\xd1]8\xeb@\xabA\t\xce\b\xba)`\xd9\x0f$\x13\x18\x82\x13~\xb5\x1drV\x92\u05ba\xe2g\xfd\xb0\xcc\xfa\xa2\xe7)\x11\xf4|#\xdbT'\x13\a\x9d\x9c\xdc\xd6A\x17T02m\xc1\r\x81A[\xc0\u02aa\xa0\u04c8D\x1c\x1e\x01y\xa64>\u02d1\u679c\n\x83J\x8b\xac\xe7\xb0\xffpr\u00b3o\xc8\x0e\xe1\x1a\xc3\xd6\x00\xfe\x8eC\u0383\x95N %4\xa3\u0673 \x16(\x9b.FO\f\xf1\xdf\x05\ra\xfbn\xd6\a\xcd\xd1\xd36\xce'\x94\xa0\x1ac\xc70\xc3h\xf7\x05\x10\x04U\\\xc1\x9a.\u04cb\xb4T\xdf\r\xab\x01\a\xa5\xb8E(Y \xd9\x01O\x96C\x87\xec\xbai\x1b\x92~\x9c\x91\x80\u01f6\r\x98]3 4C\x82P6]\x91-\x89\u0410\x80\"\xe7\x9e\x19\xb8\xe2A\xbe\x1f\x86\x9fV\xdb8\xec\f_\x85\xb6\xe8\r\\\u01df\x95\xbe\x90'\xde6\x14\x06\x9d\x91zX\xa7\xc2:h\x8f\xa3\xe5\x04E\xc30\x05\x9d\xf7\x90/\x9fw\x9b\x03S\x82\x8d\r\x8c(j\xb7\xdb\u0631}{\x1f\x006\xcdlZ/\xe6\x17\xf21\xaa\x9033\xee\xbd\xf7\xbb\xf4\xe0\x83\x0f\xd0\xd2\u04b2\xbb\xb6\x9ch\xe9\xe1\x17\xba\xbf\x8f\u007f\xfc\x9f\xcaM\x9bf055\u016fz\u056b\xf8\xc6\x1bob\"\xc2\xddw\u07cd\xbb\xef\xbe{\u037f\xfb\xdb\x14r\x00\xb8\xe4\x92\xcb^\xd4\xed\x83#b\r\xef\xf7\xb4\x0f\xf2\xdd9\x9b\x12\x18\x14\xe0e\x06\x93\x02\x87|DO\u007f\v\x85Cx\xdb\u046a/\xa5\xd8\xe9\xa9\xc2\xe3\xab~\xcb.\x18#r-\xeb\xb5/0Z(\xf8\xb7\xc8\x04\xc0\x0e\xd7f\x80\xa8\x85S\x916z.\x95=\xefH\x87Q\xfb.7\x8c\aG\xfa\x13&4\x97\x10~\x1c\u050b\x14:r\x02Dn\xa1V\f\xd4\xc0-L\xc1cE\x9a\xb4`\x8c\x1a\xab\x0e5\xf8\xec\u0395\xe0pzA\xfeu\xe9\x19\x10\x00=&\"\x85e\x94\xab\xef0\xf3&\x8d\x1ce\x8f\xfb#\x11\x1aU\x8f\x9d\xec\x16\x86m\x81\xc3\x0e\xaao\x1d\xa7\u0727jS\xc4\xcc#\x01\xdf\x15n\xad\xc1\x1e[\x8e\x8a\xe2\xf0\x86\x04\vZ\xdf\u055a@Q\xb2\f\x05\x02\x93\x80V@\xdfZ\xe4%\xa3)\x81\x86\x00\xa4\xd7\xe4[c`\xb5\x01\xeb\xb0X\xa0\x1a|ZF^\x18\xf4s\x03S2\x1a\x06P\xa1\xb3\xf0|Q\"\x87\x93\x93\xb7i\x11\xf1\x9d\xaf\"\x9d\xd3l\xec h\x12B@*\t[\x0e\xa0\a]\a\xcf\x19\xed\xf1{a\xa5\xca\xe4`\xd0??>\xde\xf9\x1b\xbf\x1b\xe1\xf5b\xfe\x12;(j\xa2\xe3\xf5d\x9f}\xf6\x19ZYY\x11\v\v\xe7\xbdO\xca\x00B\b\x8c\x8f\x8fcbb\x02\x13\x13\xe3\x18\x1f\x1f\xb7;v\\l.\xf4\xe7\x96\n\x8d\\\xf1\x930\u05a2=\xb5\t\x9d\xa9Y\u75e15\xa8\xcb\x10\xc2\u008c+\x80$\x94\x94h*\x89\x8er\xe2\x96\xdc\x00\xb9q\x8d\xbca\x9f#i\u06337\xb8\xea\xf4\xc2\xe0\x93it\x15O@\xea\xa0t\x8c\xc6Tr\xa8\xa0yqQ\xb0\x9c&\x06\x1a\x03\x87e\xe7\x1d\xe1|Q<\x9f\x8f}g&\x92\x87K\xad\x188\xed\xf6\x87\x02\x96\x85f\xa8e\x03\xd5s]k\xb0\t\x10\x9aGx\x82\x8f\xf6_IU\x9b\xe4\xbbHa\x1cvm\x15A0\xd0\xe8:\xb8\xced\xfe\xb9\xda\u054b\x01\x0f}\x9f\n+\x13K\x97:\xc7|8\b\x9a\x87\"CAn\xd1\xed\xdb\xc8\x1b'c\xe12\xe5\x9c\u0692|\x00\xb2\xb5\x16\xec\xbd\u01a3B3\t\x99p]9;u\xa7\u05700\xb0d\xbdI\x8e/\xaem\xf2\"+\xa0o\x19\x05\x80\x8c-\x945\x10\x9c\xb8$\xa6P\x8e\x05\xf2\u0720;0\xb0\xa5Ef\xfc0\x99\xa8\x06\xd5\t\x1b:\xf2J5\x15\xf8\xe8Lu\xfc\x8c\u00c4]H\a\xcb\x18\x8d\xb2\xb7\x04\u05b9\xeb\xee=\xc3\x06\x04\u03b2\x06\xc6\xc6\xc6\xe6o\xbd\xf9\xc6S\x00p\u026e\x8b\xd6;\xf3\xff\x15\x8e]\xbb.\xe5:6\xf1\xd2<\x94R$j\u05a0.H\xc2\xe8\x12\u04db/\xc6\xcc\xd6Ka\xf2\xbe+D\x85\x81Xf(\t\xa0\xcdh\x801\x91\tlk\x13\xba\x86p\xaa\xcfCb\x14@\xf6-dnk\u04514\xf4\x1dV\xf7\u02a8\u0665V\x81\x91\x80\xf1\xe1\xcfI@M\x10\xda @\x1d`'.bF.\b\xdc\xf0\xde,\xb6j\xbd9\x8apFy\xc2r\xec\xc8\x1d\xf7\x9d\xa1z\x06\xaak \x8a$W\xd2\xfa\x0e\x9b0zQJ\x8a:y47\x9a\x81y0\\\xa4\x18\xbb\xa7j\x8a\x9e\x81\x96\x84\xa2\xe3\x02\xaf\x89\xebU\x9c\xd6\xda\x04\xd0j\u007f\x95\xd5\u007f\xc3\xf5\u074f\u01cdEi\xd1X\xd1P\x03\x03\xd2\xd6\xd1\x04=\x93\x04\x91.h\x00\x1f\xda\xc06\xfcn(\b\xc3\xe3\xe76t\xec\xde\x13\x9c\x03\xe3F\xc03b\x04\xd0\x12Q,Uh\x8b\xbc\xd0 \xb6h\b@\t\x06\xac\x89|sk\x19EiQ\xe4\xce\xeeZ1A\xf9\xd7\xce\x18\x87\x8b+\x12n\u0776\x9e\xba\b\xae\r\xf6\u067f\xa7B\b\xb0p\xb9\xa0L\x02\xf0\xcai\xa9\x14L\x99\xa3w\ue933\x15\xb0\x1a\u0194N\xf0\u0116'g&09>\xf6\xdc\xc6\u0249\xc7\x01\xe0\xdaW]\xb5\u0799\xaf\x1f\x17\xcca\a\x83\x81\xa6\xe4\xc2v_\x0ev\x99\u06b4\x03\xe3Ss\xd0y\x0e\xc1\x16L\x04QZ\xd0J\xe9\xdc\x0e%\x81\xacA\xc9\n\xda\xc2\xcb\xdf\x13\xcf\x13\xed\x04\x1c\x94\xd0\xdb\xc8>_\xe1\x1b\xb6{\xad\xb7\xa1\x01g\x0f\t\xf1\x9cH\x1c\xa9\xb6\x89v\x9445`@\x18\x94\r\x11;\xfapq\xa7\xdd\xfe\xa8\x90y\xf6\x95\x91\xc8q\xdaU\xdf@\x1a\xae\u01fc\x99\xb5h\u018c\x11%tu\xdf\x1e-\xbd9\x0e\x14\t\x0e\xda\u023a.R\xaf\x18\x97\xe0\u0107\x9cj\x03\xe7:\xee\xcfo\xaa\x82\x1e,i\x13\xf1N\x98'T\x01\x13\x15\x8e\x0e\xb6\x91Ji}Q\xb6l!\xfa\x16\x86\x85\x8b\x04\xd4\x1e\x1b7\xae\x1b\u05de\xad\x12\xe4\xf9\x96\x19\xd68\xe6\n3#cB\xe6\xc5d\xde\xe38J\xf2\x03\xccRE\xcbzk\x83\x10q\xe4\a\v\x04\xf2Fo\xce$\x8e\x84\x80P\r\x94+\xf3X9y\b\xd6j\u8c80\u0445\u007f\xad\xd8n\x9e\x9d\xc5\xd6-sG\x88h\x05\x00v]|\xc9z1_?~\xbc\xc7\x03\x0f|\x1f\xaf~\xf5u\xc8\xf3^\xb3(\x8a\rU\u01a8\xb7r\xb2\x16RJL\xcelA\xa62\x94\xdd~\xf4\x90\xb5\x02@nA+\x06F\ttK\v\xddw>&\xa5\xe7f\a\xbf)\x99[\x88\xc2\"u\x06\xac\xb7\x94#@s~\xbei\xf6\xc3_Q\x00\x00 \x00IDAT\xa8\xef\u01bds\x96\x15nX\u82b7\xdb-\xb3\xad{9e9C.\x1b\xe4D\xce\xcf%\xe9\xc4y\x04lQ\xc1-\xde\u042a\xe4\xaa#\xb7U[\x1d\xed\x06\xaa\xdc\xf75\xbcP\xd3\u0166\x8e\x9bG7\xc6Z:}\x80_\x18\x8d\xae\x06\xc0(\xc6\xd5\xd0b\x94@7#\x1f\xaf\x1a$\xc6\xf5\xd1X\x87q\x97\xdaK\xdb\x19$\x01+\x04Ta!\u03d7@\xee=\xe0\r{\x01\x8f\x89\x1e(\xd1\x0f,\xfc\x8c\xab\xc2\x1e\x87\u00fe\x98W\xe1\u02ee#\x8f\x03\bN\xa8\xa9\xa5\x81\xb0\x06Zy\v\x8a\xa8nr\xf7\x19\xbcj\x8cGA\x02\xe2\xa2\x18P\x815\xe4\x1f[\x10A\x06;\x84\x04o\t\"(x\xbfu\xeb\x19.\xcc\x16\xde\u0165*\xee\xc2\x05\x90\xaf\x9c:\x8c\xe5\x13\x87\xc0\u01a2\xcc\xfb0F{\xc1 \x1a\xadV\x13\x97_~\xf9\xa3\x17\xfcn{\xbd\u013d|\x8e\x83\a\x0f\x11\x00\xfe\xcaW\xbe2\x93e\xd9\xcd5?\x17r\x17Tsl\x12\x13\x1b\xb6T\xb8\xa5\xb5`\xeb\xd3\u7640\x9e\x86Q\x80!\x89\xc2\xe3\x00%\a/oDY\xb50\x88\xb1[\xc18k\xb4x\xfe\xf9\x8a\xfcj\xfbB\x0e\xf0\x8bq\x8c\x10p\xc5(a\xf2\xaaD?DT\x03\v@c0\xa1`\x9bT\xc1\x11C\x0f\x1f\x9d\xbcC!\xb7N\xce.\xca\xcad*.(5N>\xaf\x02Uj\xb0C\xba\xe3H\"\xf0j\u05b5\f\x10\v\xe7\xaaH\xd5.&\xeb[\x80\r\u028e\xf0\xe6V\xd5\xcea\xd8J\x97B\x18r\xf4\xff\xae|Gl\xaea\xcb2B# \x02\v\x82*-\xb2%\r10\x91\xe7M!<\u067f\xef\xa9t\x9e\x83\x978\xd8u\xec6\xc9w\xa2Du\xe9\xcdZ\xc2\x10;\x1ac%\xd9~\u04baA\xb2\t\x1cO;\x94\xfb\x17T\xa7\xfe\xf5\x94\xccP\xda\x0f\x9b\x03\x87\u072b9\x11\xe9\x96>\xc0\x82R\x9f\x1a\xe1\ny:\xbf\x00E\xd5.\bP\xcd&t\xd1\u00d9\xc7\xefE\xb1\xb2\x80|\xd0E\x91w\xdds\x90\x02\xe3\x9d1\x8c\x8d\x8d\x1d\xb9\xed\xb67\xfd\xc5z1_?.\x98\xe3\xe7~\xee}\f\x00\x87\x0f\x1f\xbd\xe2\xe8\u0463\x1d\xf6pBhj\x98\r:\x13\x1b19\xb3\x13\xba\f9\x8c\x1c\xa5\xe2L\x02\xa4-xE\xc3H\r\x9b5\xc0\x02\u0436\xa2\x83\xc9\u04b1\"R9(%6\x1a\xb4*d\x99F\xa3\x15D#\xb1aw\xf1Wj\xd1\u062c\x86\x02@\x1c%\xfe\xf0|\xee\x96\xd5\xc8'%L\xab\x12\xca\f\xd3\x0fA\x1c\xe3\xc4D\xe9\xf0\xfeXP\xfc\x13\xa0\xc8J\\K\xca]\xcbMJA\xf2\u06a8\x80\x12\x06M\xa0\x04\r\xc3\xef\xc2\vx\x82\x9f;gT\x9d\nP\xa5\xf0\x04I{\xf01\xf1?'x\xca_a\xc0\xdaT\xe6QB@\xb0\x80\xea\x1a\xa8\xae\x87W\x9cK\xd8*\u07df\x00\x9b\x04\x13\x1c\x8e0\x8bM\xd01Nr\x908v\xc4Q\x1d\xed\xb9\xe3\xae+\xae\x1c\u0365e\xd8\xcc\xdb\xd2&\xbe@\xe4!!cl\f\fQ6\x14*\xaa\x99\x93\xa5a\u0615\n\xb6\x82\\l\xb0\xe9\x8d\x0e\xa3\xae)\x11$\xc1R@6Z\x00I\x9c~\xec\xbb8\xfb\xf4\xf7\xd1\xef\x9eG>\xe8\xc1\xe8\x12B\bXcx\xf3\xe69\xba\xfe\xfa\xeb\xe7\xf7\xee\xbd\xea\a\xeb\xc5|\xfd\xb8\xe0\x8e\x13'N\xbc\xf1\u0631\xe3U\xac[\xa0\x9e\xc1\xa23=\x87\xe9\x8d\x17\xc1\xe6eT\xf5\x81\xc8yZ\x04\xac\xb7`\x88\x15\r\u06f60M\xe1\xb0M\u007fO\"\xe7\n+\x8f\x85kh\x1aGk\x10\xcb\u04e4\xddx\xfb:o\xbb\x86\xbd[$\x9d.\xfb\xce\xd9ue,\xc8\x1b(\x11Ta\x81e \a`Z\"v\xe8<40\f\xb6\xa8j`A%GC)'\xf6\xf4~25o\xd9a\x80\x85VA8\x15\xf0\x9f\aus\xe7\x17b\n\xa7\x03\xd0\x05\u0614\x0e\x13\x0f\xe6U\xb6\x8aV\xe3\x98.\x15\n\xbc\x85\xd0\x16\u064a\x86\xccMe`eS\x88\xc3e\xe0\u054a3\xb8\u05a9W\xde\xf8\xec\x98\x1f\xfe1l\x90\xe6\x1b\xeb\x04?6\xc9\xe9\xf4\xefQTezz'\xb4\x1brF\u007f\xfd$\xbfSZg\x95\x00\xcb0\x9e\xa9B\x00$\xeaA\xe0\x11\xff\xf6\xda\t!\xa4\x1f\xde\x10\x84\x94\xd1\x04(\xec\x84T\xbb\r\xa1$\xce>y?\x9e\xfb\u0397\xb0|\xe60\xcab\xe0\x14\x9f@p9\xa5\xd9\xd9Y\\s\xcd5O\xde~\xfb\a\xff\xaf\xf0h\x17j!_/\xe6/\xa3\xe3\xd2K/\a\x00|\xf3\x9b\u007f>\xf7\xcc3\a7\x17E\xeeY\x01\x0e^\xb0\xc6@eMl\x98\xdb\x05!\x9b\xce\x1b\xa3\xa6\xbeC\x84]\x9c5\x1eCu-\u050aF\xd8\xc1\xbb\xc1\xe7\x90\xe9v(\xe4r\xa8\xa3]\xa5\xe3\x1f\xa2f\xd4\xc484:\x95\xc7:>\xbbH\x1e/\xa6\xf2$\x18s\x18\x94\xca\u0722\xb9d\x90\rx5:O\xa1+w\x1dk\x8a\x92\b[Q\t\xa96~\x1cm S\xa3v\x0fS\xea\xb9>\xf4%\xeb-\x01<\x1f:\xf0\xf1\x85\xb6@Q\xba\\\u0322\x80X\x19 ;\u05c3\xe8\x0e\xbc\x87\x88\xb3\x8e\xb5Z;K\xc7\x00\x97p*\x87\xaf0hf\xebT\xac]\r\xd9\xf7\xf0\x8a\xef\xe6\x899\xc1\xc28\xc2'q\u01d6Z\xce&\x9dz\xbdsw\u007fk\xb5\xf1\xbeE\x1c\xb1\xed\xcaL\x8dc\xda\x12\xc0 c!Jw\xbe\xe4\x87\xc1\xe1\xe5\x91\f(\x1df\x16\x15\xfbH0U\x9e+)\xa7\xde\xffCx\x97S\xe7y \xdc\xe03(B\x05!k\x8d\x81m\x89\xe3?\xf8\x06\x0e}\xeb\vX>y\be\xdew\x8aO\x0e\xc6q\x12\xcdf\x13{\xf7^\x81w\xbe\xf3\x1d\x9f \xa2\x02\x00\xbe\xf8\xc5/\xac\xc3,\xeb\xc7\x05\xb4z\v\xf9\xe6s\xe7\xe6\x91\xe7E\xb4\xbc\r\x95\x85\x84\x84h4\x87\xe2\xba*\xa5%\x05\x01L\xa0\x8d0\xa0z\x06\x99\x00tK@\xe5\\\x85\x19\u0512\u042b\xa1\xd5jT\x85\x86\x18}k\tq\xea\xaaE$\x14\xf4X\xb8E:\u0324!%\xb7\x83\\dn\u0440\x06\x93\x84nz\x8d\xa0\u007f\rT\xe1\x15\xab\x11[q\xf0\x920Im\x16XM\x00\x1f\xb9\xb5\xa8o\xffk\u03c6\x91.3\xee|\r\xbb\x01.\x12Z\xa0\xe7\xbd[o\n%\xb4E\xa6\t\xb6C.B\xcfw\xf6\x8c49\x89+\xd1&\u06da\x8dm\x96[\xa8\xdcQF\xbd\x02?\x89\xacOv\"\xf1g\xc904\xe0\xf3\xb1\x90\aY|\b\u00a6\u02b66\fJ-j\xf0J\x94\xeb\xa3R_*r\x81\x1e\x9a\xaa\xe1\xabd\x82\nj\xe1\xd4R:\b\x8a\x82\xc68}\x9e\xd5\b\xb6\n\a\xf7\x8b\x8c\x90\nY\xd6\x06I\x81\xe5s\xc7q\xe4\x89{p\xf2\xc9{Q\xf6\xbb1\f\u00c5\x9a\x13\xa4\x92`\u02f8\xea\xaa}x\xdd\xeb^\xf7\x1f\xdf\xfd\xee\xf7|\x15\x00>\xfa\u044f\xd2\xfb\xdew;_\xd0\xd7\xf6zy{y\x1dKKKse\xa9\xfdE\x97\x94 \"Xk0\xc8W\xc0#:M\x1f\xc1\xe8qj\xcf\x06\xf0[\xe5F\u03c5\xfe\x8a\xe8Y\xee\xf1KOidO\xfe%\x1e\xeaVGu\xdb\xc35\x91\xab\x01e\xed\a4\fkT\nS\b\xaf\xe7\xf6\u007f\xc7IJ\x0e\x19\x86\x1cX4\x96-T\x81\xc8[\x17\x9a!\xbb\x9e\xc1\x82j\xb8'-Cr\xe2OO\xcf\u007f\xb2\\\u06d2\x8c(\xf3\xf1iT\u07be\u0387D\x83\x8b\x01l\xeeS\xeaKO',5\x10%\xf4\x16\"7h,\x97\xceo\xdc\x06/\x14\x93\xb0M\xc2\xe3\xa4\xee\x86\x16j\xa0\xa1r\xebw\x19\x1c\xe1\xa7t\xf7\xe5\xfcTL\x02\xa7\xd8X<\x81\x14\x8e\xe1\u029b\xc5T\xd0\xca0\x9eN\x1e\u06a9Ac\xf0\xec&[9-\x8a\x84E#\xe0\n\xb9\xb4\x9ez\xe8\xc3]\x04Q\xfc\x8aiP\\}v)\x11\x84!\x0e\xb9%\xb2\xac\x05\x10ci\xe1\b\x0e\xfd\xcd\xd7\xf1\xc87?\x8b#\u007f\xf3M\xe8\xbc\x0f\xa12\x17\u007fH\x0e\x8e\x91J\xc1\x1a\x8b\u077bw\xe3\xcdo~\xd3\xe3\xff\xe2_\xfc\xef\xff\f\x00~\xe6g~\x9a\xde\xf2\x96\xdb\xf8B\xbf\xb6\xd7;\xf3\x97]g^\x850\xd7\n\x8d\x10\xb0\xb6\u0120\xb7\xe8\xd3}j\x16\x84C\x05\x98\x12\xcbU_\xd0KS\xf3\xbd\x88\x05\vU\xe8A\xed\xf1hDXD\x8d\x88\x9d\fCiD\xe7;\xb2)\xa6\x8a\xd1\x12\\\xbah(\x17\xde\xe3\xdf2\xb7h,i\xe4S.(Z\r,dak\xc3Z\xb2n\x0e\x00\xfc(Y\x04#h\x97C;\x8d H\x8aV\xae\xa1\u02e5*\x12-(&#VM\x95\x0fwX\x91d\xc1hXF9&\xa0\x9bb\u0235r\xa8#f@\xe5\xce\xf0L\x1a$\x90T:\u04f0C\xe9=~Qb\x8eC\xc7\b\xa9p\n{P\xb4\x92\x8d\xae\x87\xa8\xbcpl(\xe4\xfe\xef*Q\x16\x92\xa1)A\xb1c\x9e\x18\xe1(\x88\x8a\xadw\x00\xa0\xca?\xc5&Cu\xaa\xad\xe4N\xd1\t\xf6\xbeA~\xc1\x90\x19\u02a2\x8f3G\x1f\xc6\xfc\u0267\xb04\u007f\x04\xcbg\x8e\xc0Z\x03\xa9\x1a\xee:\x00\xc1J\x05\x995`m\u0266,h\xc7\xce\x1d\xb8\xf1\xc6\x1b\x9e\xfc\x95_\xf9\x95\x9f%\xa2%\x00\xb8\xe5\x96[\xf8\xa7~\ua9f1^\xcc\u05cf\v\xeah\xb7\xdbOeY\x06)E\x15\x1b\xe7\xc4\x11`mP\xf4V\x92Z\x1a\xe8p\x14)^\x84\xaaH\x06\x95\x0e\x99\xca\xe6\xd6J\xbf\xe5\x0eb\x11/\xf4\x11\xb6Nba^\vv\xa6\xd1?\xe7\xa1\xda\xe8\u04cdyDkO\u05a9P\x8d\f9\x90ud\xc4\xd5s\u03eb\x16\f\xd3\x10\x90=\xafX\xb5\xc9I\xfa\xe7\x14\xec|\xe3\x02E\xc3\u0388\x8cQ\x88z=\xc0\xc4\x15<\x1b\x14\x96\xa8\xa0\v\x88\n\x1a\x89\u007f\xe8\x17\xb6\xb8\x96Q=\xf8Zj\x06y\xb5\xa8n\x8a\xdaZRQ\x16\x1927\xce\u007f\u0778!v\xf5<\xb8\xce\xebDU`+\xf6\x89\x8d\xafU\u0569W\"*\x8e\v\xa8\xf5b\x1fNT\xa9\xd503x\xa8\xb07\xacw\v\x96\xcb+\r\xcfI\xb2\xc3\xc33\xdfp\xb0\x17\x1a\xc1CI\x91zjy\xd5\xce\xd1c_\x11Z#!Q\xe6=\x1c;\xf0=\x1c;p/\xfa+\xf3\xaeOWM\xa8\x84\x11\xc3\u0110RA\xaa\x06\x0f\xfa+\u0632u+\xae\xbf\xee\xfa'\u007f\xf1\x17\xff\xe1{w\xef\xbe\xf4q\x004?\u007f\x86gff_\x12\xd7\xf6z1\u007f\x99\x1d\u059a\xefl\u06b4\x11Y\xd6\xf0\xb8y\u0569\x1b[\xa2\xe8\xaf\xc0\x98\x12\x14$\xd0q\xe7JUWe\xd9\x19MyN\xb7cdT]\x19+D\xae4\xfb!\x1fE\xee\xe2\v\xb4\xb8<\xe4}\x9b0Ix\xa8\u00a7!\fq\xdc\x19\xdc\x15\xb5ss4\xa2:\xe7\xaa\xe5\xe6\xb8-\u03fa\x16Y\x8f\xeb\x186\rm\x0eR\x1d=\x85x\xbbZ\xd4r\r\xcbO\xb2#+\xfc\x98\x11=Ol\xe899Y\x1b\x12ug\x8a\xabGn\xb9q\x11u\x10\x15\xebD2\xd0\xec\x1a\b\xcb([n\xb7D\\A\"r`\x90\r\x8c{\xaflE\x19\r\x90S\x85.\xa36\u8904\xc1b\xb9\xf2\x19\xb7\xde3%\r\xa7H$\xa2\xfe\xed\xe3jw\x10\x96\x8a`\x9aOT\xb1g\xa8Z\xf6\xd8r\xe5;\xceT\xc9\xf1}\xe1%\"? v\xb4\u01b8\x03\xe1\n\xdc\x12\x14\x18Y\x0e_[8u\x00\u01df\xb9\x1fy\u007f\t\xb2\xd1Nf#\xfe~\x02\x14D\x84R[\xda4;\x87\xd7\xdet\xe3\x93\xff\xf4\x9f\xfc\xc6{o\xbc\xe9\x96\xc7\x01Px\xec\x97\u032e{\xbd\xbc\xbd<\x8e\xa7\x9f~\x02\x00\U00016dfc}qvv\xf3q)e\x92\x14C\xb1\x9b\uebdcG\xde_\xae\"w\x12\x8b\xbd*\u6362\xbc^\x98P$\xd8[\xbc\xfad\x1a\u02f5b\x94\x0eBG\x17\xf1\x14\u007f\x19\xfe9\x8d\xbei\x8aj\xac\xc6x@\x06\x90E\xa5\x10\r\xe7\xe5,\x00\xdc\xffe\xc9P\xb9\xb7\u007fM\xf3\xe2\x14\xd5t\xfeU\x97]\x89cj\xcf\xc6\x17\x13k\n\x18=\x80\xd19\xb4\xcea\xb4\x0f/6\x05\xac)amj\x1f[%\xe7 \xc2\xd1\\1R\x12<\x1b\x9e\xe1\"K\x860\xde\xe1P[\xc8\u0720\xb1T\xa2\xd1\xd5 cb\xa7-\n\x83\xacg\x1c[\xc4\xdfV$y\x9a\x96\x13\u02a2\xef\xc2\x19)\xab%\x04){\xcfr\x9b\xc07IW\xcf\xdes%(b\x839\x96+\x84\"R_\xab]C\xaa\u016c\x16\u02cc\x05T\xf0h`\xef\xcb\x12>k\xe1M\xf1l\x15\x11\xfe/\x84\xf3V\xa1\xa4+\x97\x12\xba\xe8\xe1\xec\xd1G\xd1[\x99w\x8d\x8a\xad\xf2=\xd97\v\x82\x84\v\xea\xd6\x1a\x17\xed\u0709\xf7\xbd\xef\xfd+\xff\xe1?\xfc\xeeo\xf9B\x8e;\xef\xbc\x13ke\x12\xac\x17\xf3\xf5\xe3\xc7z\x84\b=\"Z9}\xfa\xf4\x97\x01\x80|vg\xca\xd3-\a]\xe4\u0765\xea\x02\x1a\u00a9E\x9a>\x13\vd\xbd\x8c\x86\xa81w-\xd2\b~\xf9\x1a\x85\x9c\u05c0\xa1\x87\xb0sZ\x033\xafq\u0343J0$\x01\x05\x9es\u02b6\xb1\x15O=\xdc\x16\xd6eDj\xe9%4f\x88#\x9e\xbc$A1\xca X\x1f\x00lt\xe1\xa4\xf5)4\x118\xd8<\xe42\x98b\xf95\nPb`\x1537\xabs$\xed\xa9\x8b\xda\x15[*-\xb2e\x8d\xac\xeby\xe6\xda\x19\x84\x91\xf6\xd2zckB.$E\x9c\xb9\x12\x04\x85\x02n\xbc\xd0'\x0e@=\xc6]\xa9wiUh\x84e\xaei\xc3\u023b\x18V\x8aYJ0o\x11?\x1b\x10\x02\x12\x14\x13\x80d0|K\x06\u035c\xe0\xe5B\b\xa8F\x1b2kA\b\xe9<\xf9\x93\x0e^\xaa\f\xc5`\x19K\vG=MQ\xc4\xddN\x1c\xce\xfa]\x811\x06Zk\xbc\u136f\xc7o\xfe\xe6o\x1c\u0771}\xfb\xb7\u00a3\xbe\xf3\x9d\xef\xe4\x97\xda5\xbe^\xcc_\x86\u01ee\u077bt\xa6T\x8d\xbf\x1b\x14r\xbap\xd1Y\xa8\rI\xb9\x06\xaf\n\x06\x84\xa5\xa1`\x06\xaa\x15R2\x88E \xd2\xe5\x80\xe7/\xecT\x83\x9e\xd7f\xba\xa4\xb5/\xfa\x9b\xd4\rvca\t]\xb9\xa5\u06a2\x11\n{0\x80\n\t4\xc4\f\xa3\x00\xad\x9c`\x87-\xaf\xe9$\x93\x9e\x905\xa5\xe7*\xdb\x1a%p\xd4*U\x1f\x89\xa6\ue0e8\u007f\x9f\xf2\xb3\xfdW\xe0\x8f\xbbw\xb4\xa2Mp\xf7\b\xb3se\xcb\uba60qTKCV\xbdT1X\xd2\xf3\x8c\xbc\xf7\xf8\x8es\x92\x9b\u0249i\xa5\x0f\xd3\x18\x9ac\x04\xdex\xfc>\xb0A\x98*o\x14f\xefxY\x050\x13\x10#\xfe,\x18\x86\x80\xa6\x90h\x90\x04\f\xe3\xfc\xd9g\xf1\xdc\xe3\u007f\x89SG\x1f\x8a\x9d\xf6\xd4\xccE\xd80{i\xf2\xdcS\x96\x92E\xa39\x8e\xed{\xae\xc7\xdc\xc5\u05e0,{XY>\x8d#\x8f\u0743S\x87\x1ev]:\t\x94\xf9\x00\xf9\xa0\v\x80\xb1\xb0\xb0\x80o}\xeb\xdb\xefd\xe6\xdf'\xa2\xe2\x91G\x1e\xc2\xd5W\xbfb\xbd\x98\xaf\x1f\x17\xd6\xf1\xd8c\x0fc\u07fek\x00\x00\xf7\xdc\xf3\xad7\xfc\xd6o\xfd\xf37\xe5y\xee/t\x91\\\xb6\f\xa92\b\u0568\xbalN\xbd\xbb+\xd3\xff8\x90d\x97\\\u00de_\xee\xac\aQ\xf3\x05!\xeb xJ\xf0\xea\xb5\xfc\u0369V\xd8\xeb\xf8\xf7\xea\f\xcc\xd5\xeeU4\xac\xbe\x8c\x9cw\xacR\xfe\x04?tG\xa3s\x85\x9c\x05\"/\x9d\x86r\x90+*\xa4\x81\xb1%\xac\xd1\xd5\xd9\xc7\x13\xe6zd\x1b\xf1*J\xe5\xf0s\xae\xadp\x91\xceX\x9d;\xa7\u06e4\x14~\x11\xe9\x16\xdb\xdf6P3\xadO\xeb\x11\x04\x96\u038dP\xd8*$48\x15F\xffr\x0e\x83lJ\xe8\x96\xee\u0770\x81R\xe8?\fb\x84\xb7\x0e{\xf6\ty\a\xcd`\xaf\\\xadU\t/?\xf8\xa5\x84\xb5-\fO\t\x10J\xa23\xd1F\xc3\x02\xfd3\xa7q\xec\xc0~\x1c{\xe6~\xac,\x1e\a[\x83\xe6\xd84\xb6\xef\xbe\x0e\x17_\xf9\x064\xc76@\x1b\x97\b\x94f\xd9\x02\"F\xd7\t\x99\xa1\xdd\u0684\x89\xd9\xed\x18\x9f\x9aA1\xe8b\xfe\xf8\x01W\u030b>\xac. \x84\xc0\xe2\xe2\x12\u039c9u\xe5\x9dw~\xf5\x16\x00\u007f\xf9\x8do|c\xcd}\xe4z1_?~lG(\xe4\x00p\xf7\xddw\u007f\xfc\u0631cY^\x14P\xaa\xe1\x99\x03\x14/\xeaFk\x1c\xad\xb1\xa9*\xf1<\u059dJ\x91I$\x12\xf1\x90\xff\x9d\xf2L\x84P`5\x83J\vmC\xf8\xf2*,au!g\xd4\xc53k^M<\xac\xea\xc7\xda\x0e\x8c\xf5\x01f*:r)>\x04\xf6\x90\x04\xab*/\x94=\x16\r\x93\fm}\xf2<\x9b\u0485\x1a{\xe1I\xec\xa4y\b\u02e7zi\\\xf3\xd9$\x90IM\x12\x13\xc9\xdau\xef\xf6T\x94D\x02qH[\x87\xa3\xb8\xf6\u007f\x8a\xef\x1dy=PJ\xd7\xf34D\xaf8\r\x81\x0f\x15\x86\x9e<\xbf\x04.\xa2\xaa\xf7O\x05\xa7q\x19\xa0!\xc0)\x8a\u0390\x84H\xc0\xc7\xc4\tBc\xac\r\xd9\x16\xc8\xcb\xf38v\xe01\x1c~\xe8\x1e,\xce\x1f\x81.\xfbPY\x1b\x1b\xb6]\x89\x8b\xf7\xbe\x1e\xb3\xdb\xf7A\xc8\f\xba\x1cT\x8c\"F\xa2\xf8\r\x90\xa1\x1bp\x9ab\x00A@gr36\xcc\xed\u00b9\x13\xcf\xc4YG`\xc1\x94e\xa9\x1b\x8d\xe6\x96#G\x8e\xbe\x1d\xc0_\xf6\xfb\xfd\xf5b\xbe~\\X\u01d93'0;\xebl;\u007f\xf0\x83\xfdo\xff\xc4'\xfe\xf9O\x9e=;\x0f!$\x93\x10DB\u0536\xf3\xad\xce\x06\xb4;\x1bk\x8c\x860\x8f\v[k\xf77\xbe\x83\x16\x04\x92@&\tR\x917\xa9fP\u18fd4\xfb\x82>T\u022b\xfd\xfbPGMC\x9d\xf0j\xf8\xbb\x12\x86\xd7d\x93@m\x81I1\xee\u0564\x9bXtd\xf5\x05fp\xe1=kb\xec}T\xb3\xb8A\xa7\xd5\x15?;Q\xb3\xd6 \x13\xa2\xd50\u03ea\x85\x86*\xc9)\xca\xd6\xc47\x1c9\xe2\xd5\x1e \xb1\xb3M\x9eD\x05\xb3\xd8U0\v\x00_\u0607\x86\xcc\xe4\x8al\xe0}\x93T`\xab\x91\xf7\x97\xd0\xeb\xcec0X\xc4`\xb0\x84\xc1\xca9\xf4\x97Nc\xf9\xec\xb3\xe8.\x9e\x811\x06D\x02\xad\xce\x04f\xf7\\\x8d\x8b\xf7\u0744\xd9\xd9\xcb!\xd1F\xbf\u06c3\u0579\xf3\x9d\x17\"IY\rV\xb7\x15k&\xce\x1a\xbc\nU\xca\f+\x8b\xa7p\xf4\xc0}\xd0\xc5\x00\xaa\xd1r\xf1yBF\x16\x8e\x14\xa4\xb2,\u00e6M\x9bN\x03\xc0\xf4\xf44\xaf\x17\xf3\xf5\xe3\x82:\xae\xbb\xee\x06\x00\xc0\x1f\xfd\xd1g\u007f\xe6\xf4\xe9\xd3[\xbb++Ve\rA\xe1B\v\xc3(v\x91q[.\xfe\x89(|\xa9\xa9@\x13\xa3\xadt\xa8%\x04A\t\xf7\u007fd\xe4\u0094\x05\x01S2F\xac3\x18\x8a\xad\xcb\v5\x95!\xd3\u8ac5V\x99$2\xd7\xfb\xf6\x80\xe9bx\x00J\x18\n\x19N;K\xf7#K\x00\tF&\x18\x92\x18\xdc\x04\xb8I\xee\xfb\x16\xc0\xe3\xe4\u0515\xc6\x0fD}A\xaf\x89z\xbc\x83!%])s\xe54\x99\x92\x13+\xb7\xc6\x04\x13\u786e\x9b\xea\xdd\xf1\b\x14\xaaF+$$\xb3\tA\x90\u0085X\vE\xdew^\xban\u0738\x9d\x86\r\xa6VBx\xa5'\xd5\x17\x87\U0003ace3\x1e\xa6\xf1l\x95\x1a\xb5\x1e$\x1d\x19$\u0273$\x92\x90B\xc5\xfd\x85\xd1\x03,\x9d=\x8c\x85\xb3\x87\xb08\u007f\x18\xfd\x95s(\x06\xcb(\xf2\x15\x94\x83\x15\x98r\xe0\f\xb7T\x06\xa9\x9a\xe8LOc\xf3%\xfb\xb0u\xefO`\xe3\xae=\x18\x9b\xd8\b\xbd8@\xb1\xd0s\u063a\x10u\x1dAt`LX5\xbe\x90W#\x1e\xb7\x8b\xb9\xf7\u0739\x054\x1aM\x05\x12\xae\n\x03Q\xbe\u0759\u070c=\xaf|;\xa4j\xa2,\xfa5\x17\xabp\u0344n>:\x0f\n\x17\xc5\x05\"\xa0\xe1\xbejT\xb4\t\xe5\xfc7\x16\xb5\xdf\x0232\xaf.\x8c\xb8\xf7*`\xbc\x8e=\xd7\vI\xa0\xb2\r\x03\x19\xcf\x17\x0e]\xdd5\x03P\xc4P~\xe0\xc9m\x80[\x89\"2\xc0\x1b\x1dw\xfe\xbc\b\xd8\x02\x10R\xb8\x8a\ue855\xe8\xefB\xe9yP\x05]$\xbcm\xa4\x8cE\xae\xf4\xa7\x18\x82\xd6\u04c4{\f\xdd\xf5j\xa6\x8a{>R\x02J\x12\xa0\xdc\xc2$[\x12bB\x82\x1b.\x9c\xc32\x83z\xda{\x98\x93\xe3\xfb\x03\xd0\xcc~qJ^_\x1b\x98\xf2\xc2u\xc1CR\\w[\x0fn\xb1\x05\t\xef\x03n\f\x06\xbdE\xe4\xfd%t\x97N\xe2\u0729\xa7\xb1p\xea),\x9d;\x86\xbc\xbf\x04!$\x9a\xedILo\xbe\x04Yk\x02\x8d\xf68:\u04db0>\xbb\x19\xe3s[0\xb1i\x0e\xad\x89\rh\xb4\u0690B\xc1\f\n\xe8\xfe\xc0\xc1t\x1e\u02b3\u02a9\x88a*\xb7E\x11\xb8\xae\t\xf54\x8d\x90\x8b\x88\x94\x90(\xfb]\fV\x16\x9c\xddB\xd6\xf0\xe2(\x1bEf\u030c\x99\x99Mx\xfd\xeb_\xf7\x9d/\u007f\xf9\xcf\x00\x00\xb7\xde\xfa\x86\xf5\xce|\xfd\xb80\x8e\xaf~\xf5\xcf\xc4\xe7>\xf7\x05\xc3\xcc3\x1f\xf8\xc0\xed?\xfb\xdcs\x87!\xa5t\xad\x91\xc7\n\x9dO\x87\x01\x83\xb1\xf3\xf2\xd7b\xeb\xaeWE'\xbf:\xd4\xe1\xbaRA\xd2\x0fL\xfd\xc6\xdb\xc3+\x9cB,i?#\\A\x87\xf7\u0486e\b\x16\xc8\x04P\x94\xb6\x8a.C\xbd\v\xac\xb3X\x86\v\xf6\xa8\xf8\x9e\x14?\xe6\u06b6\xbb\x86\xf9\x13 \x84\xf7\x0fo\x00\u0726J\xab\x13 \x8fP\x14\xc6\x00a\b\xb4L\b\xc4\x1e\x04\x9ae-\x0e\x82W[\x9b\xd30F>\xb4 \xd10\xb0N5f\b\rC\xed\xb12U\xab\x9f 89z\x80X\x1a\x02\xd4\x11\xee}\xb0\x8efI\x1d\xe9\x1ds\r\xc0\x06V\xfb\x9cSE\xd0\xc6\x11:\"\x84\"$B\xb5w6\xb4aA\xb2\xa8\xf3\x87\b\xa4$L\x99cq\xfe9,\x9e;\x823\xc7\x1e\xc1\xe2\xd9gQ\f\x96\xa1\x8b>\x88\b\xad\xb1\r\x98\x9e\u074d\x89\r\xdb19s\x11&gw\xa1=\xb5\t\xcd\xf16\xb2\x8e\x82\x1c\xcf \x9a\xca-\x1a\xd6\xc2\xda\x12\xe5\xa0\v\u03ad\xe3\xbb3`u\x12&\xad\x84O|\xaaXU\x11+G\x02\xbf\x90\x83\xc6\u020b\x94(\u0495\xfc\x1cDkg\xfef\xc3\x02l\xd1\xe9\x8ca\u02d6-\xa7?\xf2\x91_\xb9\xeb\x1f\xff\u33fdd\xaf\xf9\xf5b\xfe\xbf\xe8\xf1\xd0C\x0f)\x00\xff\x1f{o\x1ak\xd9u\x9d\x89}k\xed}\u03bdo\xac\xc7*\xb2XU,\x92\")Q\xd4\u040eE[\x92GIv \xc5v\xcb\xee\x8e\xed\xb4\xe1\xb8\xe18v\x8c\xfe\xd5\b\x108H#\x06\xd2H\xfe\x04n\xa3\xff\x04H\x1b\xe8\xd8\b:A#\xed\x8ch\xb8\xd1vK\xeeA\xb2-Y\x94<\xc9\x16\xe7\xa9X\xa48W\xd5\x1b\xefp\xce\xde+?\xd6\x1e\xcf=\xaf\xa8?,J\uaec1G\xbeW\xf5\xea\xbd\xfb\xce;g\xed\xb5\xbf\xf5\r\xcb\xdf\xfc\xcd\u007f\xfc\xd1\x1b7n|\xea\u06b5kh\xdb\t\xeb\x8d\u0369\xb8\x88w\xd8\u07bb\x80\xf7~\xf7\xdfD;\xdd\xc1r~\x98\vbY\b\x99\xf5\x81\x8f\x10\v)F\xab\xc5\x04\x90\x86\xebf5V\"\x03\u040e\x85\xf49\x1f\xd4B\xedG\xbb\x90\xbc^\x0e\xcfV(\x84i\xf0\x9a\a\x82\xe5\xc00\xe7\xc1Q\xfd\xba\x87\xfe'\x00\x98\x04lD\xef\xfa\xa9n@\xa7A#D\x00m\t\f\x04r\f\xf4\xc1\x00\x8a\xca\xd3\x01\xc9\n\xf7;\xa6\x1d\t\x95HF1<-R\x84ra\xafs8+\x9c\xbc\n\x80\xce\xc1\xc4\xd62\xd8\xe8\x06\u028d\xc2+\x98h\x91J\xa7\x83P\xd0\x01\xc5\xcf)\xf8\x92\x13ge\xae\x16\xbe\x12_\x96\x14\f\xa1\xd7Y\v\xa5\xf8 \x02b\x1df\xbev\xf5/\xf0\xf8\x9f\xfc\xbf8\xb8\xfeu\xb8~\x01\x88\xc7ts\x0f\xb7\xdf\xf5~\xdc~\xe1!\uc77f\x0f\xbbg\xef\xc6\xc6\xf69e\xdb@@-\xd0l2\xcc\x16\x03\r }\xa7\x18}\xe2\x9dS\x86\x92\xa2A\x1a\x91\xdaB0\x81\xac(\x05\xb1\x18\xb2f\xedZ\x91\x10U\xda 3a\xba\xb1\x8d\xe9\xe6^\xf0\xac\xe9\xe1\\p\xe7'\x86x`\xef\xcc\x19\xdc}\xf7\xe5\xafN\xa7[\x8f\xe8I\xf6\u007f\xc0\xaf\xfe\xea\u007f\xb7.\xe6\xeb\xf5\u03af\xaf|\xe5\x11|\xf7w\u007fd\t\x00_\xfe\xf2W>\xf1\xf4\x99\xea\x13\xc8\x00\x00 \x00IDAT3\u03c0\x98\x05\x14x\xe5D\xea\x9c\xe7\x1d\x98\x19\xef\xfb\xf0O\xe2\xe2}\x0f\xa3\xeffy\x00V\x15r\xed\xdc\xc8T\x92C\x18\x0e\u0130\x86A\rUP+S\xd1\xcd6\x04:cUH\x14\xe4\xe2\x16\x04\x0f\xc0\xf5\xa8\a\xa2\xc3\xc6{4_ndh\x1a\xe5\xf9\x05\x8e-\xf5\xe1B)\u0261\x90\u01ee|\x85\xdaX82\x1a\x06h[1\x12\xdaw\xe8\x8d\xc2\x11zB/B\x1a\u00a0\x14\xa1\b\r\x1b\xf6\x8c\x9bS\xfawCX%\xe7\xaaJ\xadlM\x15?\x98\u007f\u015f\x83\x94\x92H\xb1\x90o\xf0hl\xaaX\x00\x9b\f8\x06y\x17NC\xf1D\xe5\xd5\xe1WrPC\xe5\x99P\x9c\x1c\x88c\xf8\a\xc1\v\xe0\x9c\x83\xb1\x13\xdcv\xc7}\xd8\u0739\x03\x1b[g\xb1w\xfb}\xb8\xfd\xd2C\xd8\u07bb\xa0\x9f\xe7z8qp\xbd\a,\xd0Z\xa3\x8c'\x13\xbdd2K\x88\r\xeb}\xd4\v\xa4\xf3\x05\xaf\x9e5\xb8\"\xa41I\f:\x19\xccLjQ\x1b\u00acD?\xb6\xed\x14g\xef\xbc\x1f/>\xf3\b\xfa~\xa1\x0e\x8c\xc6(\x13\xcb\x1ax\x11\x18c>\x1f\xbf\xde\x0f\xfd\xd0\x0f\xad;\xf3\xf5\xfa\xe6X_\xfc\xe2\x17\t\x80<\xfa\xe8\xd7>\xf8\x0f\xfe\xc1\xaf\xfd\x9d\x97^|\t\xd64\x94\xbc\x9d\x83 \xa4\xef\xe6\xb8\xe7\xa1\xef\xc7C\x1f\xf9\x8fam\xabX\xf9\x00\xd0 \"\x80M\xa2qA\x02\x9b\u00c4\x87\xc5\x10\xa4e\x90\xd1b\xee\x11\xc2p8\x1c\x00$\xccD\xa7\f9cA\u0483\xe6\xc5@\x14\x8a\xdf\xc2K\xee\xfa\v||\x05J\x11\x19M\x9a\x1b2\u05c7\xaaO\"e\xaf\xc0@\xa9\x93v\xc0F\x17\xacl\x1a\x04Q!\u0536\x9ao\x91\xf3\xe8\xbd\xd2\"\xc5\xc5\xf4$\xaa\x10\x15B\xe9\xa8(\x15B2\xf4a_\xd9\xc0bT\x1c\n\x91\x10\xd5\x1b\x9b\tTP\nb-LI\x8b5\u05db_4\x10\x13\xaf\xbf\x00\xda4\xba\x19\xf4\xda\xf12\v`\u0507\xdd;$.}}\xa4 T\xd9\x12\x1e\x1aDa\f.\xdc\xfb\x9d\xd8\u067b\b\xb6\r\xa6\x9bg\xd0Nwa\x9b\t\xbc\xeb\xd1-\xb3\xa0\u01c7\x13L\xd32\u0314AS\xbdW\xe0\xc3=\x02B\xa1A\x03&\x16\xd2\xf5jY\x1c\x94O\x86\xd4A\xd1#\xde\\a\x04\x1cB\xc9K\x83\xaf\x94PT\x84\x8e\x13[\x9c\xbf\xfb\x03h'[X\xce\x0f\xe1\xd9\x06\x91\x11\x81\x8d\x85\xf7\x82\x83\x83\x83\x97\xe2u\xfe\xbe\xef\xfb\xc1u1_\xafo\x8e\xf5w\xff\xee\u007f)\x00\xf0{\xbf\xf7{\xdf\xfb\xd8c\x8f\xefz/`c\x82%\xa9\x16\n\xd7-\xb0\xb1s\x0e\x1f\xf8\xfe\x9f\u0159\xdb\xefA7;JY\xa0\x89\xb1\x1d:\x1b\xf5\x9b6\xe9A\xf7&C,b\t\x98P1\xac\x8bc\xb4\xc21/\u05ba-\xa3\xb8\xb9\xd3\x02\xce\x00\x1aa,{\x9f\xf5\x9c\xd1#DFb\xd9N\xe9\xcaSP\u0100\xa0Q\xd6H\x06\x94\xb52!\u0224TK\x16\xa2\xf3\x01\xa1\xa6\x82+\xb6\t\xa6S\x0fqu\xc7\xd59\x82/\xbdfB\x11A\xc1\xd7N\xe3N\xaa\x1b\xffj\xc7\xc9f39^u\xf8\x93\x87\xc2jX\x8b\x1f\x19\x807\x8c\xce$\xa2\xc7L\x04g\x06\xf2\u007f\x91\x00-mi\x87\x8ec\ar\u0280i\xc0\xf0,\xf0NB\xfe\x85$oxfJz\x83d\xe4\x15\xbe^;\xddQ\xa5\xb0\bDz\x888t\x8b\xe3\xe2\x17NI9k[\x86\x9d2h\x83A\x96C\xe0rqc\x14\u061c\x18\x81\x01\x01\xc7\x0e\xe8B\x188\xeb\xafN\x85gT\x18\x8a\xd1\n\x8bI7n^\xb1\xcc\u07fe\xed\x12\xb6\xf7.\xe0\xe8\xc6\u02da\x9c\x14EV\xe1\xb3\x1ak7\xbe\u055f\xfb\xb5\x05\xee\xb7\xd9\xfa\x97\xff\xf2_\x84\x1a$;W\xae\\\xf9/\x9ey\xe6Y\xbd\xb9\xd9\x14\x93\u007f\xf5\xa5x\xe0\xe1\x1f\xc1\xbb>\xf0\t\xb8\xe5|0\x95C\xe2iG\u0447\xb2XD\xbd\xa8\r\xa5\xc1\x1b5\x19{.\xc2\xe5*\xa8\xa1\u00a1\xb7-h\u01c0\xac&\xd3Y\xab\xf8\xafX\x827j\a\x10\x1d\nW:p\xa9;\xefa\xd7.9]l\xd0\xd5\v\x98Dq\xda-e\u007f$8Z\xe4-\x1d8\b\x00M\rh\x87aZ\x85_\x8c\x91\xa0\x9f\na\n\xac4F\x89S\xc9\xf25\x0f\x8d\xbeb\xa8\x03\r\xaf7F\x15\xf1\xf1\xd3\f\x87!3\x11\xa8a\u040e\x05\xb5\\\\\u3890\x17j\u0304E\xb7\f\u07b1\xa0M\x03\xb2a\x98\xc9\xfa\xc6Q\xf8\x15m\x84\x933\x1a\xd5v\xbe\x01\xaf\x12\xf1\xe8\x963\xf4}Td\x02d\x03\x14\x17\x18NB\x80i\x18\u0366\x85\u0659\xc0n4`\u00ea\x06\xb5\xe1\xcdpbIqp3\xa4\xa9\x05m5@\xcb\bLX4\x86\xd0X}\x9d\xe9\x0f\x83N\xa2\xcc\xe9L\x14ZP\x8e\xad\x13\x81\xb5-vo\xbf\f\xa2`\xc2\x15\xec+z\ufc71\xb9\x81\xcbw_\xfe\xd1\xf85\x9ex\xe2\xd1ug\xbe^\xef\xfc\xfa\xb1\x1f\xfb\xb4\x00\xc0o\xfc\xc6\xff\xfc\x1d\x8f>\xfa\xe8G\xe6\xf3\x85\xe2\u0764Gj\x88G\xbf\x9c\xe3\xf6w}\x10\xef\xff\xf8\u007f\x8a\xb6\xdd\xc2\xe2x?\xc9\xfa3\x9dC\x1f\x06f\vf\x9b;\xd8\u062d\x87B -\xd7\xee}A\x15\xba\x02\x8f\xc4V\xd9\x00\xb4\u06c0;\x81\x1c\xf5\x00\x01\r\x03\xbd#t^s;\x99bp\xef@\x918\xa8v\xa9\v.\xc4D\xa5\xadJzM\xa4\\k\x9a\x12dR@\"e;\xef\a5\xbdpK\x04\xd4\bJ6\f\xa4\xf3`q\xc0\x12\x89\xfb\xdd\u01df\xcd\xc7\xe0\x03_\xbd\xbeX\\\x93;a9\xa0\xa3\u06b7\x86V\xc0{\xfd{f\xe8\xc0\x93\x01\xb2\x04l[`\x83\xf3\xcc`\xe0\u03d2,y9t\xdaqc\xdd\b\xf7\x02\x11p\u0483:\xc0\x04\xa1\x97x\x01;\xc0\xc5{\x05\xc55\xaa\xc2@\x94\x11\x14y\xde\xe5\xe7\x88d\aCb\xc0n2\xecn\x03\u07b6\x01v\xf3\xe9s*\x9c;\xfe\x9c\xf1\xf7\xb8\xc1)@\x9c;\xbdn\r1:\x84\xccQ\xcf\xf5\xb6^\xbc\xbe\xa4\x04-~\x99l,6\xb7\xcf\xc6<\xbb\xf0m\x19\x86\x8d,\x17Kz\xfe\xf9+\xf7\xc5\xcf~\xef{\u07ff.\xe6\xeb\xf5\u0373n\xdc\xd8\xff\xf9g\x9f}\x0e\xbd\xf3`\x13\x8a\xb1wp\xdd\x12\xa6\x9d\xe0\x81\xef\xf94\xce\xdf\xf3\xd7\xd0]?\xc8~\xe65X\x1e:&[\x17\xbd\xb2\xe0\x9b\u0615S\xf2\xa7g\x9ey\xfa\uce98\xaf\xd77\xd5z\u9957\xbe\u007f\xd9\xf5\u4703\xb5MrA\x04\x11v/\xbc\v{g\xee\x06\xf5.p\xbb\aC+\x10\x88,\x88l\xfd0\x84NX\x8a\x937l\u044d\x97\x14\xc1\xdac0\xb3\"D\x8a\xce=\xc0\x11\xad\x01\x9d\x01\xc8\xf5\xc0\xdc\xc10\u0436\x04\xdf\t\x9c\v\xc5\xcc\xc5H\xb3REIE\x1d\x91\xaa\xb0\u01d7\u0361+\x97i\x80YJ\xba\xa3\xc4\x01\xe5i\x8d\xb8r\x9b\x87S\xd1\x14\xceA\x81\x92\xe9(\xe1\xb9`\t\\\xec\x02\xad\xa6\\\xd0\v)j5\xac\xab$\xb0\x85\xf0\x89)\x0e\x94\xa1*\xcf-\x03\x9a\x98\xf1}\xad\x84\x8f\n\xd7\xc0\xe0\xbb0\x88p\xe3\xfc\xc9\r\x01;z\xba\x92yNZ\x82S\n)\\\xf4r\xa7`\xc7 u\xb5\xcd\\J\x18#\xb0\x96\xc0m(\xe4\x1bF\xf5\b%\x9eE\u0671\xb1\xe2\xe1\x17\x1b\xbfO\x03J\xaa\u007f\x86\xcd\xf0\xfe\u072b\xc8\xc8\n\xd0{8W'\x1f\u9f55sGc\xb7\x1e=g\xe25\x97p\x0fXki\xff\xc6\r\\\xbfv\xfd\x9c\x88\x9c!\xa2\xfd\x17_\xbc\x82\u02d7\xef]\xc3,\xebu\xeb\xd7s\xcf=\x93\xde\u007f\xf5\xd5\u05fe\xcby\xa78y\xf4\xb6\xf0\x0ev2\u0145{\xbf\x03\x1b\xb2\tY\xf6%\x18\x8c\xa8\xf2ccal\x9b\x02(\u02beZ\xe2CK\x81Qa9w\x81\xc3\xe69=\x9a\x94\\\xaeJL=w`\x02l\x18p\xc0\u03c95~nbT\xae\xee,\xc17\x04_\bKd\xb8I\f\x11\x96\x88Q\x13@-TTc\xb0\x12G\x97\xbc\xba\xc3?\x12\x1a\xd6\xc6\xf1b\x1f\xad\x83\x01(\xa3d\x8b\x14w6\x04k\x04\xcc\xd9\xd8K\xaa\xe8\xf9A\xcb_2:\x06\x17\x90\x89`\x8cZ\xb4\x92e`\xd3\xd4\xe2 \xe44\xfb\f\xe7 \xd1\xf1rVk\xf8\x1a\xc4a\xf3\xaa\xbf?\x91\u0489h\xbb\x01O\x03\xb5\xd00\xb810\xad\x01O\x14\xff&\x13\xb2D9JP9\xd3\x14I4\xe8\x83\x19l\rx\x83A\x9b\xac\xf3\x14\x19$TQ~\xbf|\x8b\x94\xc5\xfcu\x91\x86\xa2\x11\u07e6hO0Q\xe1\x11\xd9p3F(\xa8\xbc\xc4\x15\xa1\x8a\xaa\xa0\xf1\xca\xd0\rj\xc6utt\fb\xbe\x0f\xc0\x87\x00\xe0\xf5\xd7\u07e05f\xbe^\xef\u023a\xef\xbe\abW\xb6\xf7\xc2\vW\u03dc\x1c\x9f\x80\xd9$:\x9c\x17\x8fv\xba\x85\xdb\xefx\x00\u0187\x89>\xd5\xdcp\xf5\xe0j@l\u01cbL\xc0\xaf\x99\xa2\xb1\xd6*\xfb\xf0\xadJ!\xd5\xe54Uu\xda2\xcaA\xb7Z\x9ct \xaa/\xc3\xd9\x10\x18] \u00eb\x1b\x87\xac\xf6\xd6F@\x93\x80\x95\xaf\xee3yc\x10\xacJ\xe8k\u06eb\xb1\v\x11pb@6\t\x98\x86\x82\xde\x00l%3z\xa2\xb3\xdf\n!>^\x02Z\xb9*\x89SN\x01^\x99\x04\u0738\xc9hx\xe5\xea\x1d\x8bc(\xe4\x1c\xb0i-\x949\xc0\x99\xaa\x01c$4\x86\xdf\xfd4\\\xff\x86\x03\xb4\x13\xe06k\x14S7&\xa8\x81\x8b\x90\x0f\xa1\x84n\x18CZ\x90\x1bV\\\u007fb\xd2\xd03\xfb\xa5P5\xac\x15p\xa0\xbf\x9a\xb4A\x12\x13L\x84\xb2b\xfaR\xe9\xb7b\t\xb4\x11 >\xa3\x9b\xbcg\xe49Da\xc2\xe5\v\x8fx\xf5{\xf1\x15\xbb2\x0f\xe7\x19^\x04'''\xf4\xf5\xaf_em\x88^]\xc3,\xeb\xf5\u03ae\xc7\x1e\xfb\u068f\xccf\xb3\x8bG\x87G`2\x15M\xae\x99la{\xe7\x02\x98\fzY\x1d\xd61\x99@c\xc4j\xe4\x19B\xdeg\x1c~6\x14\x98\rC|\x93*\xc9=Um8*\v\xaf\xe8\xf3\xa1\xd1g\x02\xda5 \xe7A\a\x02t\x82V\b\x8e\x80\xa5W\u0699\x0f\x18xY\u0487q\xc9\t\x8ae\xa8\xa9V\x18|\u0280\x8e<\nU\u0230\u04e7U*\xe4\xe04\x03\x0f\xc0\x00\xb2\x05\x90\xf3\x80\a\x8c\xd5\xef\u0457\xedy\x84#\xdc\xc0\x18jU+\x14\nr\xf0'o\t\xbc\xd5@6m\xf2G\xc9\xf8u\x86L\xa8\x18\xb4f\xd8K9\xe6\xc3@'\xa9\xcfMH\x86/\x9b:\x90\x95\xc3^\xed\n\x90\x19C\u0300'V\x8f\x14\x93\xbd\xcdI\bM\fy0\xca\xc5\xf7\x1bV9\xf1\xc1\xdd\x11)\x12/\x02!A#\xccT\xec\u0152](\x83\t\"\x93\xfa\xf8\x88\x1f\xd0=\x1b\x06m\b\xfa\xce\u00c5\xfb2\xfd\xb6$x\xd8H\u212aj\x19\x9a\u16b7NN\xf7\xae\u0386\x18\xf3\xf9\xdc_\xbf~\xc3\x01\xc0\xfe\xfe\xfe\xba\x98\xaf\xd7;\xbb>\xf3\x99\xcfto\xbc\xf9\x86O\xe6LI\xfc\xc1\x98n\xecbs\xfb\x1c\x04\x94p\xc9\u071eS\u8fb8\xe0\xe9\x16\x85<(\xfa\x88C\x10\x82\xe5\x04\xfd\xd2J\xdfM+\x01\xbe\xa9#\xa5<\x1a\x95\xd2\xdeV\xb4H\u040e\x05\xf7\x02\u007f\xd4\x03 L\x04\xf0^\x14r\x8e\xaf!\x16\x04\xa2\x15\xe7\xd9\n/\xb7\x9a\"T>\xd72R\x98\xa5\b!\x93A\a\x1f\xf3\x96\xb8\xf4&g\x02\xb3\x81\xa7\x10\xec,\xba\xb9\xc9V\x18v\xf6\x801\x1e\xde3\\\fS\xe0\\\xf8U7_\b\x8a\x90\xf3,\x05\x019\xe0\xe0\x86\xb8\x99;f\n\x1bB\x19\ueb1b'UB\x19*\x87\x9c\x83\xbc\xeb\xf2\xf7J$U:\x121\x03\xdb\x04\x11\x86\x9c8\xf8N@^\a\u04d0\u0e98X+jUkC\xd2\x14\f\x01S\x03\xbf\xd3\xc0Y5\u01f2\u0308\xe1@\xbe\b\xf3H\xf4H\xa2\xc2D,w\xe1\xe2)Q \xc5\xfb\xc2q2of\xae!,\x1a\x86\xef\x04\x86\x00\x98`\xb3\xdc\xfb\x94\xad\x9a\xad\x90\x87\x16\x00\xf1\u0102\x90\x96\xc5pT\xf8\xd9\u007f\x8b\xaeu1\xff6[\u05ee]\xbb\xec\x9d\xdfr\xce)%,\x0e\xc4\xd8`\xeb\xccyL&\u06c5\xaa\xa6\x18>E\xc9?h\f3Q8\x81\x00K\x8aU\x92-\xfcP\xca\u007fB\x92\x1c\x04W\x02%GQ\xc8:\x81\x81&\x04\u0675\xa0Nt \ua056\t\v\tG\xe4\xb1/]\xd2\x16C\x81#\x16\xd0\x14\xc0d\xe0\x0f.uC\x9e\xde$\xabH#\xc9\xd0\b%\x9c\x99\xc8\xe7\xa86 ][\xefz\xc0\xa9<\x1c\x13\x026\x058Vq\x8b1\x02/\x9c\xaf\x9f\xc4\r\x82s\u0403\x97\xca\x13\x87)@\x16-\xc1l\x1a`\xa7Qs\xaa\xb2\xe8\xca`JP2\x8a\n+\x81X\u0529\xa2\xeaQ\xb1\u007fsm\xbb@\xba)\xd1n\xf8\x1d\xfa\x1e\x0e\xac!\xd7>\xc0\"\xb1\u007f&\x85UR\xfek\xc3\xc0N\x03lZ,\xc2\xe7\x9b \xed\xd7Z+\xd9Q2\xfe\"\x88rP4\xfb\xc0Z\xa5\xa0\fR2M2{C\xc1Z\n\f\x16\xde`\x18\x11\xd0\"\xdc\x1b\xbe\xb8\a\x92\xd9X\x0e\xa2\x06e(\x87\x8a\x98\xb9H\x87d\xc3h\x1b\xc5\u4b35\xebb\xbe^\xef\xecj\xdb\xf6\xfb\u06b65}\u05e15&\r\x19\xd9\x18\xec\xec]\x80m\xa6)\x99\xbc\xc4Q#\x15QF\xea,R\xd2{\xe8\x1a\x83\x8fv\xd5\xecq\x8d\a\x8fR\xd7V\xb6\x8a\xf0\xa0E\xf5_(8\xbc\xc1\xf0g\xacv\xb2\v\x0fk\xd4\u072b\x8b\xec\x12\xa6D\x8e`PEnI\xf4?\xab\x99\x9ed\u01af\x93\x14 \x83T\xddyP\xe6\x83 \xa1S\xa60\xc43\xe5\xcfE\x04\xb6\x16d\x18\xd2;x\xd7\xc3;\xa71t^\x80c\x82a\x817\x02\xe79\f\xf1\xd43\xc0s\xe0f{\x0fr\xb1#\u0542n\r\xa3i\x18\xbc\xc1\xe03\x16\xbc\xdb\xe8\xbc \x9ap\x15\xfcI*v\u04c8E3\xd5\x13\t\x891uq\x00(\x12h\xdeC9g\xf1\xab\x9a\x10d\x97!\x0e\xe0\x99\x03\xbc\x0f8|d\xbaxx\xca\xcc\x1e\xa5MZ\xf0N\v\xb1\xa4\x8c\x17P\x10\xf6Pm\x89<<\xaf\x89@\\\x1f\xd8'\x94n&a\xc9x\u007fiw+y\xd87\x99\x90n6\u0783:=\xec\xa4\xcfd^\xb1\x1b\x8a\xf1v\xe5\xecE@\xc9\x17\x06\x02\xf4\xce\xe9&\xed\xfd\xba\x98\xaf\xd7;\xbb\xdex\u336d\xae[\xe6\x1b?\xdd\xd0\x06\x1b;\xe7\xc0\xa6I7j%V\xa1<8\x1a>\xdc \xc03\xa5\x00g\xb2\x94\n0\x15\xc1\xc9\x15\xd7;\xcd6\x87A\xc0\xa3\x8ft\xe6\x1b\u01c7u\xdb\xc0\xf7\x1e\xf0\x1e\xa6#\xb4\x81M\xd1G\xfc4\f\xf1\xca\xf9\xa1\x14\xf8\x88L\x83|\x1f\u046av\xc0,\t\x0f\xb3:\x05ReEK\x10\x98\xd0\xfe\u01df'\b\xdf\xf5H_\x15\xd40\xf43\f\xea\x1c\xbc\xef![N\xa9}3\r\xb7p\x88~\xe7\x04\x11\x82k\x00!F\xb3\xa0\xe4?\xa3\xc3F\x86\xb5\f;50\xb75\xa0\xbdF;^\x19\x04\x8aV]y\x8e\xf5\xe3\xf0;\xf4\xa21\xda\x10\xc0;\x1f\x92|\xbcF\xa5En7\x97G\x15Z\x9ddo\x1a\x18a\x00K\u0639\x83a\r\x87\x96^\u0099\xc2k\xd7m\x83\xe9\xd7n\x03\x99X\xb0al\x98\xb0\xf9\x15\xc3Wp6\xf2RA\x1aC\x9c\x87\xeb:\xf4\v\xc0K\x9f|\xed\x01\xa3\xd4W\xf6\xf0\xec\x01'up\x93\xa4\xfd\x1c\xd2\x12\xfc\x86\x81\xb8\x1eB:\fe\x9fKu\x05c\x19S\xb8K\x04\x8fv\x11\x90\xa8+\xe8b\xb9\xc4k\xaf\xbd\x06\x00\xb8~\xfd\xfa\xba\x98\xaf\xd7;\xbb\xae\\y\xa1\x9b\xcd\xe6 c\xb2\x98\"\x14\x8b\xe9\xf6m0\x8dM\x8eq\ts-\x1b\xe3T\xa4\x8b\xee\x95\x011*\b\xe1\xe8\xc7\xc2\xf5\\\x8f\xa2\x87t,:e2\x83\fl\f\xa5<\x0e\x0f\a\x91\x94\x9eV\xda\r\xdd\xf9A\x0f\xb6\x04\xdb\x10\xbc\x10\xbc\x93\xdc\xd1sV6\xa6\x8e\xb3!\xd0.@\xad\x9a\u056e\x84^\f\xe4\xf6\f\t\x12\xf8:\x9b\xb3\xe6\x8c\xc8\xf8n\x15?\xd7\x18\x10\x1b\xb0cx\xeb \xe4\xd4\xfeu!\x80c8\xd1\v\xe6\xa1\xd4E/\x00,\xa7\x94$b\x8bfb\xd0N-\xec^\x03>\u05c2[^y\xad\xd5V\x1bX2D\x92\xe4\xfe\x01\x91Nv0\xe2<|\xef@\xceA\u0125\x81\xacZ\xd3\u02c8\xd50EZ7\xb0c\x000x\xbf\x83_zH/AD$ \x16\x9de\x18V\x13\xad\x9d\x06\bE\xdaZe\xa8\xb0QX\u00c7MS\x88\xf3\u07c7\x1d\x9e\xfb^}\xf0\xbd\x878W\xa8\x889X6\x0f:\xf3\xf8\u07c2\xa7\xefZ\u00b2!\x15=\x05\x02\x8d\x06\x92K\x1a\u019b\u05a0\x99n\xa9E\x05\x96\x85\x1f\f\x87a\xb9\xc5l\xb6\xc0\xd3O=\x05\x00\xb8z\xf5\xc5u1_\xaf[\xbf\x8e\x8en`{{\x0f\x00pxx8Y,\x16\xc9\xfa3\x1d\\\xd9`\xb2\xb5\v2\r|\xe7R\xe1\xaelk%&\xf6He1\xeb\rrWn\xb4=MRy\x1a\xcf\xdb\x04rr\xa4\x10*E\"\xc6R\x85\xa4,\x8e1}\x99\x81]\x8d\x9cC\x0fp\xaf\xa2\x94N$\x85\x1e\x10)\xe4c\x88B\xbe\xa7\xe6\x8e\u04b6W\xc1P\x14\xf3T\x91?\xf5\xb9\x80\x13\b/\xc1\x17\xab\x84\x85\ua23a\b\xbbTXsa\x88E\u0702!\x90\xd6\xebP\xee\u0423\xe9\bB\x06\x10\x81\xf3:\xa8sN\u09aa\x18U\x81\x92\x01O-\xb0\u05c0no`&\\c\u0660:\xfc\xa2\x00\xaa\xa2\x9a5\xa3\xe2\x94^c\u0083\x9dQ\xab\xda8\x88L\xd6\n\x18\x19\xfceoq\xec\x1a\b\fx\xbf\xd3a${\x15\xeb\x10\xe0\x9d\xa0\ac\xd94h\xd8b\xc2\fc-L\xdb\xc0X\x930q&5P\xeb%\xe6MPr\x824\xb6\x81\x99\xb4p\xddB\x87\xf2\x92g/Y\xa2 \xd9\xd5R|u\xa3\x91\x10\x9c\b\x16\r\xc1t\x04\xebD! .|\xe6\xc3\t\xaa\xd9\xdc\xc9\x16\x15\x05\x04\xc3`\x881X,\x97\xf2\xecs\xcfy\x00\xf8\xfa\xcb__\x17\xf3\xf5\xba\xf5\xeb\xf9\xe7_\bl7\xf9\xe0\xdf\xf8\x1b?q\xff\xf1\xf1\xf1@_/0\xb6A\xbb\xbd\xabFQ]_\xc3\u0525'Hx\xd0S\a\xc8HF\xfe\x86\x82\x80\x85)\x15\xb5\xe1\xfc\xb3\xf4\xe5\xa6*2\x1d\xab\xdcu\x1a\xa0\xe8\xd1\x1a\x15E\xe5l\t\x14$\xff\xd4{M\xa0q*\xe36\xa1\x80F\x95$\x99(\x80a\xf5\u0096^;P\x89\x015\x8a\x1b\xfb\x01T\xa2\x98\xb5T0\xcb\xe0\xf2\x9d\xba\x04y\xa0F!\xb0\"\xf2\xb8\xe5L\xa0\xd9\x1dQ\xb2\xa1\xd5z\xaa\f\r\u01c07\x04\x17\xd2vx\xdb\x02\xb75\x10\x9b\xb3<\x93\x87\v\rLe\x86\x1cK\xca\xd2~\x19\xd9Y\x89\x19\x863w;n>\x88CXHE\xc9D\x80\xfe\xb9\x05\xc4z\xf8n\tYv\xf0\x8d\x16Vo\x04\xd6\x03=\x04\vg1\xeb\f6\xc8`\xbbi`Mvt\xf4\x14\xe5\xff\x04\x1b\xae\xbb\xf3\x81\x9c(\xba_\xab\u0372\x81\x90\u02ef!\x89\x89\f\xbcs\xf0\xe22\xfe\x0f\xa0\xbc\xb5,\x01mC\x1a\x9d\xe7\xe3\xf0V\xed\x94)\xa9\xac\x18\xcd\xc66\xd86I,\x86\xf4;\x03\x96\xcb\x1e{{{\x97/]\xba\xf4\x9d\x00\xfe\xe0\xde{\xeeY\x17\xf3\xf5\xba\xf5+\xe2|o\xbc\xf1\xdaE\xe7\xdc^\xd7u\xa1\x13.\x86?\x93\t\x9a3\xbb@k!\xb3y\x91?\x19y{\xb9\x13\u00a0\x9e\xa6\x0e\x86D\x85B\xb6\xb6\xb6\xae\n\xb5\fA\x81S\x99\u06ab5\x92h\u0624\xeb\xc7S\x03\xd9\x16`\xe1\xc0>\x04\xfcz\xa5\xfaq\u8b09\x95\x93M\x93 \xb3gh\xaa\x0e\"\x05/|\x8b`l\xe5\xbd\u2fa9\xb8\x95\xa6\x89\x95\x81\xd7\n\xf912,\xb3\u0425\xa0\xbfQ\x12\xc4\x04\xdcgK\xb9\xe5\x98\x03\xe8\x03\x17=\xc0I\xd6k\x98\x05\x87@l\xb3caZ\u029bd\xe1s#R\xb2\xb43\xa3e%K\xf4-\xaetR\xe1\x06Q\x90\x1eMdt@\xcca\xb0\xed\xbd@Z\xb5\x11\xe6^\xe2\x88R\xf1i\x02Z\a\xb8%\xe3\x18\x84\x1e\x0e;\x04lNM\xa2%\xe68<\n\xac\xa1B\xd0\xe3\x01O\x04\t\xc2!xWX\xff\x1a0;xb@\\\xb5\xe9\u01efG\xa4\xf3\x14\u00c0\xb7\f\x0f\xa0w\x02\xe9}\xa2gF\x05\xa9m\xa60M[\xfe\x84z\x12\x15\x0f\xd7\xfb\xe5t\xb2\xd1z/\xef\a\x006\xf6-\xb6\xf1u1_\xaf\xb7a\xc5a\u0375k\u05fa\xf9|\xee\xca\a9\u0791\xa6ia67 \x13\x86\xb7ZX\x84Vs)s6X\x9d\xab\x99\x1a\xee \xe7\xa6\xc1\x103\xc16\x95eG\xe9\xad1,\x16\xe3E>\u05dfh\xea\x14:\xa8-\x03,-\xd8uh\u0200z\xafy\x96\xe1\xb5q\xb4\x9emIa\x00\f\x92|JhB\x04\xc6\x10\xc4S\xf0\xad\x11$\"z\xf5\x1a\x86\x83G\t1zA&?`\x84\xac\xd8\u007fK\x88\xd5\xdb&\xc0yH'\xa9\vN\x9d\xa1Wk\x04\xbfe4\xceN\ua409lD%\x95=\x80\x14\x97\x89\x90-\xd2E\xb0\x1a\x9e:\f\xc5NB&_|-\xca0\x93\x14\xa76\x0f\xc8\xcci\u0232!H\xe7\xe1\xbd\x16cb\r\x880N0\x99{\xcc-0\xef\x19\xfd\xb1\xc3\xc2\x03\xdbSFk\x92\xa7b\x15=\x17\xe7\xaf\x1e\x80\xf3@\x17a\xbeP\xec!z>\x122\xc9z7v\xf8\xd5\xcc \x88\x8d\x98\xf4t\xc5\x1b\f:!,\xe7\xe15\x16n\x8a\xb6\x9d`\xb2\xb9\x8b\xa3k/\x17\xf7g\xc0\u052d\xa5\u00e3c<\xf9\xd43\xc7\x000\x99L\u05dd\xf9z\xbd\x13\x98\xf9\x11\x00\xe0\u018d\x1b\xe8\xbae8FF\xa3\xa1\x10\x1c\x11d\xfa\xde\x00\u0796E\x83\x82;\x1eV\x83$R\a(\xb9xq\x0e\x83(a\x1a\x06\x06f\xe2\xf5\xb7\xa8+I\xc1/\x1e|>\x86\x1bD\xa8M\x86\x01\xbfc\xe1\x9d\xc0\xec\xf7\xabX\xbd\xf7@\x17^\x9f%\x15\xb8T\xa7\x05\xa9g\xac\xb1\x9b\x17\x0e\x02*JA\x13\xa9\xd8\r\xbcu\x89sDY\xe93\xb3\"\xfb/\xc25\x88\xf5\xf8/\v\x01\x0e]\x1d\x8c\x03\xa8\xc8\b\xac\u0664!\xb7BLm\xcd{Z{(\xc5\xe1\u01e10L\x93\x02\xf2\x1a\xfb\x9d\x8e\xbc\x17\xb7W/\x929\xf7\x80\xb2WN\x1c\xd0I*\xe2\xce\xe7\x0e96\xf5\xb2\xf4h\x16j\xbb\xe0\x9c\xe0h\xee\xb0\x14`\xa3!lZ\xed\x9e\xe3\xe5\xe4d\u02dc\xb3F\xbd\x10\xe6\xbdn\xca\rS\xa2\xcc*\x13\x86\x835E\xf9\xeb\x94<\a\x15\x9f\u007f7.$\x19\u016f\x11\x93\x87\xe0a\x9a\t\xa6\xbb\xe7B7\xae?K\x14\xd5\x1acpxt\x8cW^~e\x02\x00\xff\xf5\xaf\xfc\x8aH\x05\xfb\xad\x8b\xf9z\u0742u\xe3\u018d\x00\xb3\xbc\x81\xbe\xef\a\x1e\xe4\x91\u007fl\x82]\x88\x87\x04Iv|\x9e\xcd\b\x9e]i;$\x91\v\x92\x89T\x8d>\x04\x18\xa0d\xa9\xe0\x14\x0f\xa9\x9a\x8e\x81\x9aK!\xa3]z\xb2@\xb7\xcap\x91N\xc0\xfb.\x83\vqo\x12\x01\x16\x02,=\xc4\x0e\x1aT\xa9Y\x119\x9c(gE\n\x17\x8a\u039c\u021c\xb22A\\Y\x11\x94Cd\x91\xb2\u04e3\xcc4Ah=\xbd^w\n|\xca\xc4$\x89\xb5v)\xf0\x8d\xa07\xd9>\x9c\a\x9e\xe5\xb2\n\x85\x87\xce\x14\xd5\u0303\x8b\x80\x90\xe8\xdcX6\xe7\xe9\xc7K\u009d\xdc\xf5KTkF\xab\x85\x99\x83\x9f;\xb8\xa5\x87[xx78\xa8\x84\r\x9f\x1d\xd0\xcc=\\C\xe8'\f\xf1\x82e\xef\xd1y\u00bc\x03\xb6Z\xc6\u0532b\xe4\xd1}\x92\xf2\u0463i4lZzI\x14E\x15\x101`\f\xe0\xbc\xe2\xe1\xc80\x95Gq\xd0\x11\x00\xbd\xc0\x1d\xab\x8b\xa2\x04\xee\"\x89\x86\x85;q\xa0\xa6\xc5\xf6\x99\v 29\x9d(l\\\xd6\x1a\xbe~\xfd\x06\xb6vv\xbeOD\xdeMDO\u007f\xf9+\x8f\xf0\xea\x91m]\xcc\xd7\xebm\\\xb9[L\xa8o\x91n\x13\xdd\x00\x95\xa2\xe6{\x0f\x81WA\x87\xb6Ia8\x88\x8a\xafM%\xf6-\xd0\a\x89\x18Q\u0418fp4,\u0265:h\x00<\x14\xb4\xbe*$X\xc6Fv#\xcb+l!\x9b\x06|\xe4\x82JD*\xdb[\x9a{\xe0\x10\xc0n\xe9\x94\x18\x8a,\xe5\"Z\xee%\xe9\x8c\x10(\x10\xf92J\u0751\x97@6\u0556_\xa5\xf5oe*%\x80\x9cx\xd0\xccg\tyX\xbd\xa8\xb5\xac8\x0f:\xea\x01\x03\xb8M\x13\xca\aeXb\x18Y\x11\v\xb8\x94\x87\x88\xdce\nj\x1dV\x91\aR\xed\xa8\x12:\xd3\xf85bW\x1eA\x1d\xd7\v\u0731\x83\x9bi!G\x9f3Y%\xf8\xbe\xe4\x03\x00\xc1\xf4\x82f\xee\xe1C87y\xc5\u0717\x0e\xe8\xe7\x1e\xf3F\xb0i\x19\x1b\x96\xd4y\xb3\xb8\x8e\xd1q\u0449(\x1f\x1e\x02\x1f\xa5\xf6.\x18|1A\x1cU\xa7\b\xef\x83\xef\xcaR '\x0en\xe1\xd5\x0e\x80\xc2\rCq\x98\xeba\xed\x04[\xb7]\x00\xb3\x85x\x970\xf7\xc0\u28ae\xefq\xed\xda\xf5\xb3\u007f\xfe\xe7_9\a\xe0\xe9?\xfd\xd3?\xfb\x96rN\\\x17\xf3o\x83\xb5\xb5\xb5\x05\x00\xd8\xdd=\x83\xa6\xb1\x15\x94\x91Q\b\a\x17Zg\xf1Y\x99W\x9e\xe3%\f\v1\x92\xb5\u0245\x97\x85\xbeIb\x89I\xe1%=\x90\x0f\u055e +\x8aCY\x1dv\x9e\xd2\xcc{\xc9](H\xbbt\xf4\x12\xb3\x12\x10\xea\x06\x8c\x03\xe8\u062b\xf9\xd56\xe7\xe1\x1b\xe5\xee\xb9T|Fiz\xacR\x14v\xa7\x98Z_\xbd&\x1a\xf7\xa1\xc90\x05\xad\x82D\x9d\x00\xc7\x0e\xb2\x10\x90SJ^\xec(\x97\x02\xf4\xe1\x1d\xea\xf5\xf3=\x11x\xcahL\xceT\xa5\xe2\u0691T\a\xaej\x10-8\xd5Q\xb7\x86\xbe\x90F\x11\t\x1f\xf7\x92\xdf\aT\x9c5?v\xf0G\x0eXx\xf5l/TW\xb9\xb3\x0f\xc6`a\u00f0K\x81\x9f{,6\xb5;\xe7\u008fg\xd6\t:\xe7\xd0y\xc6f\xc3hM\x11\x10R^\xe0b\xa0\x1c\xd9A>X\xf8:\x0f\xf4\xbd\xa0\xef\xbd\xd2\x1d\xbdW\xe8m.\xa0.\x04\x0ez\xa9g\x0f\xa44\"\xdbN\xb0}\xf6\"\xda\xcdm\u030fn\f\u0384D]\xef\xd0\xf7\xee]\x8f|\xf9O\x1e\x04\xf0\xa5\x97_~e]\xcc\xd7\xeb\u05ae\xf3\xe7\xcf\x03\x00.^\xbc\xd0L\xa7\x1b\xa6\n\a\x0e\x0f]\xdf-\xe1l\x0f\xd9d\u040c\x13\u034b|\xf4\xba\x88\xe7\xe7,d)\x8b'\xb3\x0e\xfe\xa4\xc8\n\x95\xa0^\fv\x86`\x89r\xf2\xec\u0597\n\x10\x8d\x90\xd1O\xa9\xdc2\x98\xd9\xc5\xe3\xbf\x10@N\v\xa4\x84\x82.\xbd\x84\x87\x1a\x80\u04ce\u03c8\xc0\x1c(\u03dc6\xa3\xf2\xb2\xe8\x9c\aa\x10R\x85\x86Rm\x8aM\xd9\xe50y\x84\xa0\x8c\xb2\xab\xc5P\x05D\xaf\x1d\xe6Qx[\xc6\xe0\n\x86\x17\xe5];\x0e~[>lT\xc7\x0e\x1d\x01\x1e\x16\xdc0,\x11\x1a\x124&\xe4rV\xae\x88X\x11\x14\xc5\xea\xee\xb3\xcd\x14\xa8\xc4\u05fddc4\t\xb1|\x11s\x0f\x17\u018b`\xe9\x05\xb3\x85G\u007f\xe4`\x97\x02\xeb\xea\xefYN;d@Ae\xa7\xddy\xdf\x10\x1c\xa9\x1f\v\xdb\xfc\xba\x9d\a\x0e\x17\x1eK'\xd8j\x18\x9b\r%\xc36?82\xa9s\x80\xa0\xf3@\u702e\x03\xba\xa5G\xb7\xe8\xe1\xfa\x108\xed\x05f\xee@}T\ud19d\xaa\xa0\u062a\xca\x13\x90\xdeac\xeb,v\xce]\xc6\xec\xe0\x9a\n\x95(:4\x12\x11\x91;8<4_\xf9\u029f\xee\x01\xc0\x9b\u05ee\U0007a62f\xd7-]\x97/\xdf\x05\x00\xb8\xff\xfe\xf7\xbch\x8c\xb9\xd64\xed\x9d\xfd\xa2\xcb\xcf\x05\x11\xdcb\x8e\xc5\xec\x00n\n\xc8\x06CN\xfaB\xf4\xa2\xc5\\\xbcW\xe2o\xe9~H\xc8\x11k\x94'\x9a\x12\n\xba\x17\xc0\x05\u05fb&(\xf6R\\[=\u007f\xac\xbaX*\xf1p\xac\u01b6y\x19\xf4\xbf\xf1k\xb9\x80\x89\xfb\xe8\xa1\x12\xbbv\xfd;\uf05e\xb5\xa80<\x98\x18<\r\xa1\xc8Bu\xb0\x05Q\x96J\xa6\x02?\n\xe9Ws\b*\xe2\u0688\xea\xd7.\xe9\xe8\x0f\xc8\u0703\x0f\x1cp\x02\xf8>\x9ayi\x01\xf1\x84\",B\x92\xa8\xca\xce<\x16\x8d\xc7b\x9b\xd0A\xb0\x00`z\x825:\x18l\r\x05\u0719j%\xfe\x00W\x8f\xa9N\\0c\xbcD\a\u00c8YQ\xc2\xfe\xbd\bz'\x989\xc1\xac\xd7\xeez2w0\xbdO\x1d9\x95\x1e\xe0X\xfd\xfdD\x1c\x9a;\xa0\x9dy,\f\xa9\xf0H\xa8\"\u0590\x00\x8b^\xd09\x8f\xce\x01\x1bF\x1d\x19\xf1\xb2~\x8c\x00\x00 \x00IDAT\xbd\u03ff\xf7\xde\x01\xb3\xcea\xd1y\xb8^\xe05\xd5\x0e\xce\xeb\xc9\u0487\x19\x89]z\xd8pj\x90h#_\xdcx\n\a\xe9\x89\xcb-\xe6\x98l\x9e\xc1\xd9K\x0f\xe2\xb5\xe7\xfe\"5/\xf1\x04\xd6\u0616\xbf\xfe\xf5W\xf0\xe0\xbb\xef{XD\x1a\"Z~+\u0541u8\u0177\xc1z\xdf\xfb\x1e\n\xb38z\xcc;\xf7\xfc\xf6\xf6\xb6\xfa\xaf\x14\x86L\xbe_`v\xed58\xe9\xd0oY\xb8\t\x87pa\xed\xd0<\xbc\xfac@\xbd\xc3\xd3s\x1bR\\$\xfc9r\xc0L\u0228,:\xea!\xfb\rU\x06\xc0\xcaG\xd5\xe7\u0240\x12\x87S\x86~]\xe8r\x9d\xc0\xf7\x02\xd7+\x03$B\xdc\xec\xf5\xe3\xae\a\x163\xe0\xe4\x06p4\x03fN\xd0I\x0e7F\xe2<\x97\x85\x9aV\xe97$\xab\xaf\xbcP\xe6D\xf6\x8b\x17\x81s\x0e]\xef\xd1y\x8f\xbe\xf7\xf0\xc7\x02wBp\x1d\xc1{J\x9f\x1b_'\xc5\xea\x1a\xac\x03\xd8\x01\xdc\t\xda\x13\a\xd3\xe7!d\xe7\x05\xb3Np\xbc\xf48Zz\x9ct\x82E/\x8a/\x17\xb8\xb9H9\x89(\nZP\xcc\xc6k\x9c\xdf\x04\xcey,\x9d\xc7q'\xd8_x\x1cu\x82\xce\t\xcc\xc2\xc3\xf4\xa2F`R\xc8\xe7e\x04\f\v\x03W.\x14\xbev\xe9\xd1\u0303\xaf\x8a[\xa5\xd3pPv\x1eu\x0e7\xe6\x0e\a\v\x87\xe3\xa5\xc7I\xe7q\xb0\xd4?;Z\n\x16N}\u1f68\x8a\xd9Z\x03n4$\xda:\x82\xedC\x01\x17\x02\x87\x1f\x8cD\xe1\x1d\x16$=\x82x\a\xe9{X3\xc5\u079d\xf7c\xb2\xb9\v\xef\\:\xbfH\xd8\xd0Ofs\x1c\x9f\xcc>p\xfd\u06ab\x97\xbf\xd5\xea\xc0\xba\x98\u007f\x1b\xac\xe9t;\xbd\xff\xc0\xbb\x1f\x90\xdd\xdd\x1d\xb8\xbe\x97\x12\xb7p}\x8f\xe37^\x86_.\x81\xb6A\xbfi\xe0Z\n\x1d\"\x82\x90\xc3\xd5>\x18a\xe8T\xce2)\x14p\xa6p\xf4g\no\x99;\x1c\xe1\x199e\x92I\x83\x02\xee\a\x03\xd8!\xf7\xbdt\x00t\v\x8f~\xe9\u0447\xff\xfb\x98\xff(\x9a\u00e9\xff\x97\xf0 \x03\x98\t\xba\x03\xe0\xc6\xc2\xe0ZG8\xea\t\v\x1f%\xf4T\xc0%\xa5 ^*+\xf0\xe8\xab\x18i\x9a\xf1T\x12\xdd\b\x9d\xf3\xe8{\x87\xcei\x81u \xf4\vF7c\xb8\x9eV\x87\x8f\xe1\xd8\x1fO\ni\x18\x1d^\xbbY\n\x9a\x93\x9c\xd1Z\xb2F\x97N\x8b\xfa\xc1B\xdfN:\x85,\xa2\x16)\xbfI*R^j\xa6J,\xee\xcb^p\xb8\xf0\xb81\xf78X8,\\\xa0\xeby\x80;\x0f^\x86k\xeasW\x9eSz\xa4\x1e\x8bH\xa9\xc2\xd7\xe1g3\xf3\xb0s\u5967\xc3P\xf1\u03e3\x1dD\xe7\x04'K\x8f\xa3\xa5\xd3\xcdj\xa9\x1bX6\x0fCrP\x8c7\x1a;\xc0v!{\xd5\xd7\xe0\xbf\xf4\x1e\xe2\xf4M/\x8c$\x9bg\xdf-\xb1{\xee2\xce\xdcy?|\u07e5P\xedxk.\x97=\x98\u0307\u007f\xef3\xff\xfa\x01\x00x\xf4\u047f\xfa\x96\xc1\xcd\xd70\u02f7\u067a\xfb\ueedfi\u0513\x99\x04\xd9\xe0\xd9\xf7=n\xbc\xf8,\xdcb\x06\xbb\xb5\x8b\xaea\xf4\xdb\x04C\x0e4\xcfT1\a\a\x8e\x14<\x92\x14zL\x05K,\x9d\x95\ubf00\x02\xad\xa0\xf4\xac3j\xd6\u02f0\x1b\xc7\x00F\xa9\x1a\xdfb8\xd7;\xc1\xe2\xc4A\x0e: \xf0\x9e9\xc8\u096a\x109L\xc2\a\x8c\xdd\xce\xbf\xef\x97\xd8\u07bb\x80\xf3w\u007f\x00\xaf_\xf9j`\xf4P\xe2\x9e\v\x80W_\u007f\x03\u007f\xf5\xb5\xc7.\x02\xc0\xfb\xdf\xffAY\x17\xf3\xf5z\x87\xba\xf4\xe9\x1f:\xe7~\xa1i\xec\x8ew^}\u02a1\xc7\u0323W_\xc2rv\x8c\t\x1b\x104,\x19[\xd0\xe0\x85\xb9\x1e\x93\x1d{\x80\x03\v!\xa3\x00\x11W\xc9L\x16\u0285\x8e(\x17x)\xcdGiP\a\x06\x05{\u0629\x97\x03\xd0\xe4+\xee\xb5\xe8\x1c\xcd\x1c\xfa\xfd\x1e\x93\x13\x8f\xb6\x0f\x1d#ibO5[\x95\xb0\x01\xf9\u8ded\xf8\xf9\xf4\xa4\aL\x83~\x83\x94E\xb2\x04f\x860eB\ub056\x05\x86\x82*r\xe8\xeb\x8e2\x18\"\xc0\x13\xa1\xa0\xc6b\xe2\xc0\xe8`\xb0\x14\x03\xcc<\u06a5\x86YP\x1c\xbe\rmi\u00b55^\a\u007f\x1eY|K\x02P\a4'N\u00ec\x1b\xca\xf4\x93\xc1\xcb\x12\xd1n\xbds\x02\xe34\xf9\xa7\t'%\x13\x8d\xc8\u0086\xd8-=\xbaN\xf9\xdf.\xea\x97L\x10|E\xcfz/\xb0s\x0f\x13^\xff0R\xaf\u0718\xaa\x01w\xf8\x05s\xfcf\x81'n\x96\x1evF\xe8ZN\xa7\x86\xc1\xa0[.p\xfd\xf9'\xd0\u03cea\x8c\xa9\ak\x02HCXn\x19\xf4\x8d\xde\xf0\xa9\x93\x11\x1d\xf6a\xee\x80\xc3\x1e\xbe\x93@ P\xec\u060b\xfa\\y_\x02/\xf5\xf0-\xf1@\x12\xcb-\xc0\x14\x01\xb68\\\n\xae\xcf=\xf6\xe7^y\xceR\xe6F\xaa\xf5*\xf7yhXU3\xd4\xd9qe\x1c^\xb4\"H\x96\xb1\xbd\xa0\x9dy\xd8P\x1c\xd3\xeb\x93\x1c\xf2 \"Xz\xe0\xc43\x8e\xbcv\xde3o0\x13\x83\x13X\x9c\x88\xc5B\f\xfa\x98\xfaN\x00\xf5\x80\x9d9p\xa0\xe1\xb1S\x88a$ \xaf\n4\xa3\x04I \xb1q\xaa\xd0\v\x00\xa6\xf3\xb0\x01n)\x9fX*\xf1w\u0526\u00e8\x1b\xd5\x02\u007f\x1e\xf9;\xaf\x83\xe2&\f=\xd9\xcb*l5J0\xad7\xd2*z/\x15\xf4\xf0\xf3\x85M\x89\xe7>o*\xde\x01\xbe\x0f\xf7\x1a\x06\xe1\x1b\xf9\x9e\xa1\b\xd5t\x92\xba}v\x8a\x93s\xc4\xca#\x93%\x06G\xa7$\xa2\xb0\x891U7\xa3w\x1d\xce]x\x0f6vnG\xdf-\xf2s\x02\xed\xe2_~\xf95\xbc\xfe\xfa\x9b\xffa|-\x8f>\xfaW\xebb\xbe^\xb7~=\xfc\xf0w>\xb2\xb3\xb3\xdd5\x8dzP\x88wZ<\xbd\xc7\xc1+W\xb0\u007f\xf5\xa9\x9c\xb2\x1e\x8bvx\x13K\xe8\xa7\f\xc7\x01;\x17U.\xf6^\xd09\xa0?\xec\xd1\xdd\xe80_(7\xf9h\xeep8s8\x98\xf58\x98{\x9c,\x04\xb3\xdec\xde\v\x96}\x80%\x9c\xaa4]`\u007f\xf4^\xa1\x94y'8Xx\xbc9s\u061f;\xccc\x11G\x9d\x0fMPf\x04\xfb1,gP.\x05+JL\xf2\xc1\x9b;*\x06\x97\n\xb7p\xef\x87_\xa4*\x86\x19\x13g,`\xb0\x80A/\x9c\xb4\xb2E\x9e\x05\x9a\xb9S\b\xc0\xe5b\x13\x8f.C\xf8\xa3*\x95\x9c\x95\xba\xe4\x03-\xb0\x1c.\x04\xaby;\xf7h\xe6\xaeH\x10\x02\x06\xc9\u007f(\xffKE7N\xa5\x9d/e+\x83\xf2E\u0645v\xe5\n\xf5\x10\x86{\xf2*\u06fe\x18SS\u044dK6k\u031b\x8dRE\xcd\u00a39r\xaa\u0685\x069\x8b\xf39\x1c\xa3\f\x9e.6\xaaf\xe1`\x17>\f\x8cI-\x1bb\x17\x1d\xe9N\xd5\xc9 \x8cU}Q\xd0\xc3&\xedS5\x17l\x9d9\x8f3w\xdc\x03b\x0e\xf3\xa5\xc0.\x12\xc1\xa2\xebppp\xf0\x9f\x1f\x1d\xbcy)\xc0\x97\xebb\xbe^\xb7~}\xfa\xd3\u007f\xf3_\xbd\xfb\xdd\xef\uedb7\xb6 \xe2\xc5\xfb\xc8Y&\xcc\xf7\xaf\xe3\u0367\xfe2t\ub738\xd2U\xe0/\x03\xdex\x1d\x86\x86\xa1gT\b.\x17\x1e\xcb\xeb\x1d\xe6\xd7:\x1c\xcd\x1c\xf6\xe7\x1e\xfb3\x87\x1b3\x87\xfd\x93\x1e\u05ce{\\\x9b9\\\x9f\xe9\xe0\xf2\xc6\xc2c?\f\xe1\x0e\x97\xf5\xdb~\xf8\xb3\xa5\x93\"\x86\xae\x1e\x98\"tb*`\x89\xbe\x1b8\u0144\xe4\x94a\x9dW\x00\x99|\xaeLv\xee\u041c\xf8\"\xfc\xad\xf2\u072f\x8b\xf9\xb7\xd1\xfa\xdc\xe7\xfeM|\xf7\xf0\x81\a\x1ex,\x18\xec\x93\x1e=\x1d@\x8c~~\x8ck\xcf?\x0e\xd7-S\u01e2\x1d\xa0\xd3\xf3\xb6\x0f\x82\v\x118xx\x1e\x1c\xa8\xc3d\u035c8\x98\x13\x95\xd5\xfb\x88\u007fz\x95a\xf7=\xb0\U001024e0Z<(D.\x87\v\x8f\x93\xa5`\xdey5\x99Bf<\x8e\xc0\xb3\t\x1aQ\x88%;\xf5\r\xd9\x18\xc3\x0e\xbb\xa2\u03608\xf2\x17\x1bDs\xa2\xdd4R\x105a5e3\xe3\xd442\xc5$\xafE\xd6tR\r.\xc9I\x8d\x8d\xaf\xbc\xea1P\x04`\xef\xf3\t\u0123\xb0\x8b\x11e\x9a\u031c\xfa\xe9\f.\x97/f\x18\xe3_y\x14\x91\x82\b`\x16N!\x90N\xf2fYz,\xa4\r`0\x9f(\xbd\x04\u02bc\xcd\xc4%\xaf\xbfQ\xb4\xca5'\x0eX\xf4\xa1y\xf0\xa9\xa1\xc8\n\xd6p\xedz\x0f;\xeb\x95YS\x0e\xbf\u3f03\xa0\x05\x9d9\xf1\xc4KK\xa2tm\x12S\x86R\x8c\\\x9c%\x9d\xbb\xf8^L\xb7\xf7\u0f7e\x9eHGt\xce\xe3\xf5\xd7\xdf\u011f\xfd\xf9_\xfcd\xfc:\u007f\xf0\x87\x9f_\x17\xf3\xf5\xba5\xeb\xe3\x1f\xff\xe1\u0521L\xa7\x93\xff}cc\n\xdb4\x19\x13\x06\xe0]\x8f\xa3W_\xc4\xec\xcd\xd7@\xe0\u0288\x88\xc4\xeb0\xc8\xf5\xc1|\xcb\xc3G\xbb\\\x1e\x84\xe0:\xf5\u07d8\u0303\xcf4\xe5#u\nA\xa6\xfa-w\x87\x92\xa9u\xc3r\xb7\x12@\xa4t9v\x12X,\x85\xb0u\xd8\x05\x16\xb62\u547f\xac\xca$\xb9`q\x1f\x86\x8b\x9dO\xf4MB\xa6>&D\xa7t(\x1c\x90\x00\xf8\xc1\x1f\xf8\x18~\xff\xf7?\xb3.\xe6\xebuk\u05f9s\xb7\xff\xf1\xddw_F\xdb4U\xcc\x16\xb1\xc1\xec\xfa\x1b\xd8\u007f\xe9Y\x95H\u01ee(\x98ei\u01e2]\xbab\x8c^9\xce(>c\xaaL\x1c\xf2A\xa0\x05}\xe6\xd1,\xfch\x81\x1a\x0e\xff\x860\x80\xc88\x04\x90:{\xa7\xf0\x822=h\xe0'^\x1f\xab\x85\xea\xae0\x16\xfe\u0215O\xf3\xba\x82sL.\f\x17\x17\xbeN\xfe\x19r\x97\x87\xb5+\xe2\xb9K\x9f\xd9\x1f\x82\x84\xeb\x0f\x85Q\xd5\xd7\xe128{\xac\xf4\xea\x06\xc1\x9d\xcf\xd0G\xb1\x91f\xbeuY\u0425F>\n\xf8E\x06\u05d7\n\xf8J7\x86|Z\xa1*\xf7\x94\xea\xd3C\x89\xa6\xac\b\b\xa4\xee\u02a5t\x12\x0e\xb4J\x0eZO\xe7\x82e\x80\x0e@3\"\x13\xe4\xfa\x9d\xc0\xc4al\u0090d\xe5^-\x19WD\xa5NW*x'\xb2[\x12\x9b\xcaG\u058a\xee\xe0g/\xbe\a;{\x17\xe1\xbd\xcb\x1b\x1a\x11\x8c\xb1x\xf3\xcdk\xf8\xccg>\xfb)\x11\xd9\x01\x80\x8f}\xec\xe3\xebb\xbe^\xb7f=\xf8\xe0C\x00\x80\x9f\xfa\xa9\x9f>\xd8\xdb\xdb\xfbB\u06f6`\u00c1k\xabC\xcf\xe5\xc91n\\}\x1a\u02d3\xa3\x18\xe1[\r\xb1H\x04pN\x99\x06\xe2A\x81s.&c\xc2%\x83\x80{\xc1$\x14\xf4lBU?\xectJSJ\xa7\xb4\x91\x11\xdePJ\xe2\x00.\x19<\xb0\x82\xa2\xed_\xc9o\x96\u02ba5}\xdf\xc2@\x8a\x05hO<\xec\u04af4\xa1c\xf0/8\f\xf3\xe6n\u0415\a\x16\x8b\x8c`\xf9E\x9b\x1f\v\u06eaD\xb6\xa8\x86\xc1k\x9e\x9d\xa8|\xdd\xe7\x93\a\xf9P\xec:\x19\ud307\x8c\x9c\xea4Q|\xbe]ze\x89\xf8b\x17\x93\x9b\x1f \xe8\xb4\x1dz\xe0\x9f^}\xef\xb8\x11\x10\xb41\b\xc3\x15\x9e;U\xbe\x96\xa6\x95\xc1K\xc7v\x92\xbfF0\u02eaY/>\xe1\xec\xbe4v\v\xc5\xdb\xc7\x01k\xf8\xfb\xf8\n\x15\xf2\xe3tO8\xd7a\xb2q\x06\xe7\xef\xf9\x0e\xdd\xfc\xbcK/\x9c\x8d\xc1\xc1\xe11^}\xed\xb5\xef\xfbG\xff\xe8\u007f\xfay\x00\xf8\xc1\x1f\xfc\u063a\x98\xaf\u05ed]Dtt\xd7]w}\xfe\xe2\xc5\v`f0s1\xe8\x13\x1c\xbc\xf4,\xf6_z\x16\xc6\xd8,n\xf1>)\xe7\xbc\xf8<\x14r\x1e\xe4\x94\xc6\xe7M\xb0\xc1\x1d\u0d26WS\xa5f.\xc1r\x14+\x18\xab\xa1\x12\xd7\x1cU\xe1\xd7E \xc8\xf0\xb9\xf7\xa7\x88XV\xc1\xe1\xb2\x1e\x92\x14\x03O\xc9\xe3M\n\x02\"vY\xb0c\x9c`\x12\x06\x99+\xf3\xbf\x016-\b\xdd\xf1R\x8a\x84\xc8\xe0\a\xe3d\xe5\x1fJ\xb1C\b#\xa5<\xd5s\x88\x81\xca*b\xfeN\u007f~^\xe6\x0e\x9dD\xa9\x9a6\xc0C\xa3\x90\aF\xfc\xb1\n\t)\a\xbe\xbdv\xe5\xa7\u007f\x8dr\x97X1\x1b\x1b\xd1l\r\u060ai\x86\x13?\xe2 J\x10\xa7\xb3\x06\xbb\x90L\xf1\x14\x9d\t\u0639\xb2W\xf4z\x06\x8f\x98\xd8]\x87\xc1e\xa4\x12\"D\xcb\xd5\xd9\xdbTZx\xe6{\xae\xb8\xc1\xa2\xea\xd3\xf5\x1d\x8cmq\xe9\x81\x0fcs\xe7|\x8a\xac\x8b\u0670ll\xf7\xd2K/\xe3\v_\xf8\xd2/\x8a\u021d\x00p\xe5\u02b3\xb4.\xe6\xebuK\u05af\xfc\xca\u007fE\x00p\xe9\xd2\u017f\xb8\xef\xbew)\x9c\x12&\xfeD\x00\x1b\x8b\xa3\xd7^\xc4\xfe\x95'\xc0\xd6Vj\xf8H\x0f\x13x\x888\x888\xc0\xb9\x14\xa8\x9b\n:\x90\x94\x82\x1c\xe0\x05\xd3\t&'\x0ev\xa6V\xba\x15d1H\xa5\xf7#X\xb9\f\xba9v\x81\xc5\xe2O\xa3\xcb\xe5b(R\b\x8aV*L\xd1*\xa6D\x8b\x88o\xe7\x0e\xddvZ\xe0J\xd1\f\r\u00c4(C3\xe4jy+W\xcaI\xaa\x8bz\xd9\xd9S\xd1\b\x13%\u07d5\x15nf\x81\xfbG\x0f\x97\xf8\u0112\x00v\xe1t\x18:\xac_\x18H\xff\xa9 \xf6\x84\x8d\xc4v\x82&Z\xc8V\xf0\x04\x9d\x82w\xadZ\x13\x97\x11v\xe9\xe4B\x83kV~\xc5\xe81\xe0\xf3\xa0\xd8,\u00bc\x82\tv\xa9\xe2 .6\xad\xfc&\x89:\x1b\xa3\xb2\xa9\xb0\u01e5p\x8f\xb31\xfa1(\xdd\xf3\\\xec\xf4\xe2k\x1e;\xe0\xe1\\\x87\x9dsw\xe3\xc2\xfd\x0f\u00c7\xe1\u007f<\x1a6\xed\xc4^\xbb\xbe\x8f\x17^\xb8\xfa\xf0o\xfd\xe6?\xfeY\x00\xf8\xd1\x1f\xfd\xeb$\"\xebb\xbe^o\xff\xfa\xb9\x9f\xfb9\x01\x80_\xfa\xa5_|\xf5\xce;\xef|\xacm\xda\xec\xdd\x1dD\x14\x8b\xc3\x1b\xb8\xf1\xc2Sp\xf3\xe3\f\xc1 \xe3\xe6)\xbd\u073b\u0421\xbb\xc0\xb4\x90\xba\xdb\xf5\n\x85\x18'\xb0\xbd\xa0YxL\x0e\x9dJ\xe6\xe3\xb16\u05e4\xf1\x8e\xfa\x94\x8e\x90]\xe0\x97\xdf\xec\xe8_\xbd\x16I^\x1d2\u0491&\xaf\x16\xd4dA*\xbeV\xbb\xd0P\x05\x19qy\x8c\u03efYFW\xc1\xac\xd8DE\x9b\x1b\xd4\xf3\"T5\x16:\x1e\xebn\xe9\xf4\x83\a\x05\xf6\x8dv\xe2\xc1\xaa\xa0W/\x18ve\x98\xf7MN<\xc5&\xd9,|R\u050e\xa4\x88\xdc\xf4ZW\xaf\xad \xa3\xa4\x82=\x8c\x8d\xca^\x0f\xd9K\x05ZX\xa9Sv\x8e]\n\x9a\xc0\xa3\x1fK,\x11`esY\xb9FD\xf5\xe6\x01\xaa\xff,J\xfb\xe3\xe6D:\x87\xe9\xbb\x05\xect\x13\x17\xde\xf5\x1f\xa0\x9dn%\u07bb\x04\xdeU\xd3N\xdd\xd3O?\x83/\u007f\xe5+\u007f[D.>\xfa\xe8c\xfes\x9f\xfb\xb7f]\xcc\xd7\xebm_\x1f\xfa\xd0w)&j'\xcf\x186\xff\xfc\xfc\x9d\xe7\x035\x91**\xd7\xf5\xe7\x1e\xc3\xd1+/\xc04\xadv\xe0\xa5\xf1G\x14S{e\x1c\b<\xc8{eYt\xf1\x18\x1ce\xeb\xc1;\xc5i\x81\xb1\v\x8f\xc9A\x8f&J\xb7\x8b\a\xcf\xd7\xf4o\fO\xc7\xe5\u0411:\r:&\x8f\x82_>\xa80\x05$\x91\xeb\xd6\bH?\x14\xfc\f\xb1\xf3\xa285sI\xf8\xb9\x14\xafKB!\xb4\xa1\x9b,a\x1d\xf6\xa5(iX\x1d\xa9\xda`(%\xe2\x14\xf0\x0f\x8d\xb4\xd3\xe5F\x83<\f.C\xb2\xb9\xd3\xd7s\x1a#h\xac\xb8\x9b\x0e\x85@\xe8\x94O:\xfd\x0fW\x85U\x18\u02cf\x1a\x9c\xc8(\xc7\xe3\xb1\xcfg\x01\b\xd0\xcc=\xda\xc3\xc0s\x97b\xd0.\x999U~C\xa9\xe1\xc4B\xec\x15\xa1\xc2\xc8]\x8f\x12\xfd \"\x8a'T\xa6,\xff\x0f\xafD|\x8f3\xe7\xef\xc5\xd9K\x0f\xc2\xfb\x0e\xd9\x17\x18h\xda\xd6\\\xbb~\x03O<\xf1\xe4w\xfd\x93\u007f\xf2\xbf\xfe4\x00|\xe2\x13?,\xebb\xbe^\xb7d\xfd\xea\xaf\xfe\xb7-\x00\\\xbct\xf1s\x97.]\xd2b\xce\xf9\xcc\xcd\xc6`\xff\xc5gp\xe3\xca\x13`c\xab\x87(S\f3\xd4\"\u0781\x9c\x16\x00vJ\xe9\xe3h\x0eUL\xdd(\u061e\u0699C\xbb\xdf\x05N\xf4\xc0s|\x80qc\x88\x84\x14\xf6\xb0\xb4\xc2C\xce_\x84N\x03\x89cM-\xe3L\xab\xe8\xa2\"^,\xbc\xde\xe4\xa5\x12\xbeo{\x1c\u0516\xa8\x94\xf0\u02b4XH\xe5\xd8WBN\xe3\xfc\xbcS^\xa3d:\xa0\x10\xad\x0e\x15\x8bo\x1e1e\xd3\xf9`C\x90\xa9\x8a6\rC\x05r\x93\x1a\f\xd2Aj\xb3Tj#\xc9i\a#y\v\x10\xfe\x94\xfa\x9e\xb8\xfa%\xf5\x05\x95\x8fx,\xd2\x19W'\x95\xf9\u03dc\xdeO4vB\xc9>\xe8\xc4\x14f@Y\xe1)\xc3\x13\xc9\u0419\x11\x12\xfc\x85\xa2w\x8b\xcfP\x1f\t\xd80\x9c\xeb\xb0y\xe6<\xce\xdd\xf5\xbej`\"\x04\x80\x19M;\x91\xc7\x1f\u007f\x02\x9f\xff\xfc\xe7?%\"[\x00\xfco\xff\xf6\xffA\xebb\xbe^o\xfbz\xf7\xbb\x1fp\x00\xf0\xf7\xfe\xde\u007f\xf3\xdc\xed\xb7\x9f\xfb\xea\xe6\xe6\x14q,\x19\x8d\xb7\xba\x93C\xbc\xf9\xd4_\xa2;\xba\x0e\xd3\xd8|T%$\xc3\"}\x8b\xb8\xb9\xcb\x0eX)am\xd10Ka\x16\xea}\xba\xa7J\xe8>\x9d\x98R\xfa7W \x8a\x14\x9b\\:qb\x10[\x18\xed\f\xbc\x87w^\a\x9f(\xf3R)\xcd\f\xc8Z\x9c9\u007f\x0f\xa6\xdbg\x83\xcd@\xaa\xf80\xb6\xa5\xfd\xfd\x03<\xfb\xecs\x9f\xfe\xb5_\xfb\x1f\x1f\x06\x80\x9f\xf9\x99\x9f\x95u1_\xaf\xb7}\xfd\xc2/\xfc\xa2\xbb\xed\xb6\xdb\xccd\xb2\xf9\xc4m\xb7\xdd\xf6\xff\xdd}\xf9.\xf4}/\u027c?@\x02\xaf=\xf6e\x1c\xbe\xf4,l3\t\xceq>\x1dU\xe3\xfb\xd2;\xf8\xbeW[\\\xef\x8b\xe3o-\x91/\xebP,\x90f.h\x0e\x1dh\u9aeeQd\xbcq\x8d\x0f\xbd\xe9$u\xbb4Zf\x8ax\f\xa1\x9a7\"7\xb9\xbb\xa5\xc6\xc8++\\\xaf\x05\x9b}\x10\x13\x85anb\xb0,\x94}\x81\"H\x19\xa1;&?\x024\xc8\xc8&\x82z H2\b`\xae\x03W\a\xf0svd\xa4\xbe\xe0\xca{\xa8\x0f\xf9|\xd5\xd9+A\xc4\x1c\xa9\xf8s\x1a\x9c\x16\xc5\x10z\xe9\xb1{\xe7\xdd\xd8;\u007f\xafr\xe1#t\x13\u00a4A\x8cg\x9e}\x16\xaf\xbc\xf2\xea/\x8b\xc8\xc6\x1afY\xaf[\xb2\x88\b\xbf\xfe\xeb\xbfF\x00\xf0S?\xf5\x93\u007fy\xf1\u2965xob\"\x9a@\r\x85N^\xff:\xae_y\x02\xd2/a-g\xe7\xba8\f\r\xc5\\\\\x0f\xdfw\u06a5\x8fv\xd6T\b\x8f\x8a\x01\x97\x17\x98\xb9\xba\u5c53\x95;N\x06tD\t\x1d\x99\x06<\f9\x8c\x94\xc3\x1bP\x93\xffd\xb5\x8dEYOO\xeb\u042b\xfa\x19\x1c\v9t\xda\xe4\x94niB\xb0\xb1Y\x043\xad\xd8\xfe\x06j!\xb9\x01\xbd\xaf\x1c\x02\f`\xa5\xea\xba\xd1\xc8\xfb\xe5\xbf\x1b\x1c[\xa4\xd8\x00L\x1f\x95\xa7\x92\xb1\xf3Y\x98e\f\xf6\x85\xb8!\xc488._\xaf\xe4L%\f\x83\xa7Qdq\xa6\x8f\a\x89Ho\xb9Jf\x8aT\xc1\xcf)t[\n3.h\xf0\a\xa1\xf0\x81\b\xefk\x016 6A\xe5i*A\x9c\xe6\xd4r\x1a\xf6S\xe1\u0260\x11\x82yc(\xad\x99=A\x83\xa2\x8d\u00d9\xf3wb\xef\xfc]yK\x8a\xd0\f1\x88\rn\\\xbf\x81\xabW\xaf\xfe\xf0\xff\xfd\u007f\xfd\x9f\xbb\x00\xf0\xc5/\xfe\x11\xad\x8b\xf9z\xbd\xed\xeb\xe3\x1f\xff\x98\x03\x80\x1f\xf9\x91\x1f\xfb\xfc\xe5\xcbw}\xf5\xfc\xf9\xdb\xd1w\u02fe\xa4Uy\xd7\xe3\xfa\xb3\x8f\xa2?\xdeGc\x1b\x18\x04\xaaWY\f\xc5C|_\x99\x11U\x02\xf5\xd8\xed\xc6G\xa5\xe8\xdac\x92\x85\x9diA''\x95\xd7I*(\xa5wy\x18\xf4\xd1P\xc82R@\u0190\x02\x19\x83~G\xf3\u03a4\x1a\x8cR\xb4\x9c\xf5\x99\u007f\x1e\xfd[\x9a\x90\xc0\x13\xa7\xadTl<\xa3\x85\xfc\x1b\x01\x9aO\x83(d\x84:B\xb5\x1b\x19I\x18\x86\x16p\x8bYJ\xa2*\u018d11X:\x81\r\xb2\xfd\xa4\xac\x8c[aAK\xadh\x84+\u01bac\x9b#N\t|\xaeOP+\xe8Q\x18jK\xf5\xb3\x87\u035b\t\x9eB\x91M]=\x03\xc4\xca\xfd\xe6P\xd0\xd9d?\x18\xc4 \xf1\u0708\x94\xe6]\x12/\br\xb7\x1d\x87\xd7>\xd0:M#\x98\x9e\xd9\xc6\u0785{a'\x1bJS,n\"6\x16\xce{\xbc\xf0\xc2\vw\xbd\xf0\xc2\xd5\xef\x02\x80\xef\xfd\xde\xef\x97u1_\xaf\xb7}\xbd\xe7=\x0f\xc9#\x8f\xfc1\x11\xd1\xebw\xdcq\xfb\xffs\xee\xecYx\xef\vb\xb9>\xba7\xae<\x89\u064d7u\x10JE@3\xe7\aL1G\xa5(\xd2\xe0!\x1d\x01Z\x93qU\xc4H\xe1\xb5sl\x8e\xbd\x8a\x8a\x06Tp):6re\xfaN\x81O\xd3\xd8\xd9\xff4\xcd=U\x8a\xc8\xf4\xc5eDj*\x03)}`\xe7D\xb7\xc6f\xe6\xd0\x1e\xf5)\r\x88J\u067f\x94\xd4I\x19\x96\xbd\u0453\xc0J!\xfel\xff\xee\xdf\xfd\x9bu1_\xaf\xb7\u007f}\xe4#\xdf#\x00\xf03\u007f\xeb?\xf9\u02fd\xbd\xbd\xeb\x8d1\x94\xe4\x99\xe1f\x9f\xddx\x1dG\xaf^\x85\x13\x0f\xb0Y\xc1\xbf\xd3\xc3\xe9\x1d\xc4wY}W\xe9\xb0\v\x81J\x10\xc2\xe815\x14\x1e\"\x8dm;V\xbbU\xc8\xd0]\xaf@/\xfa<8,\x83\x12\x12\xaf\xbb\xc4%\xe4\x14\xfa\x9fHE7\x8c\x83\xac\x92Yq\xca>TI\xe9\xb9W\xf6\x8aI\x83\xcf\xfc\x99\x9c\xe4\xfbC\xea\xdc\x18LR\x1f\bV>(m$\xcbPb\xbay\u05df\xbas\n\x19\x9e\u02c0\x9d\x17\x97\xc8\u012e<0\x91\xeaW*\x83\x83K,\xd82\u0632CQ\xa7!\x14\xb4B\x16\\9\xfdH\xc1<\x1a\v\xd2(0\x12\x80\t$\xa1|3\a\xf8#\x8a\u07b8\xf0K\xa6*\xfb4m\xac\x83\x81\x01\x11'\xd4=J\xffS\\!)\xa4c\r\xc1X\x02Y\x82\xa0\u01d9K\x97\xb1s\xf6N\xf5t\x8e\u015c\t\xcc\x16\xc4\x16\xf3\xf9\x1cO>\xf9\xd4GD\xa4\x01\x80\xcf}\xees\xebb\xbe^\xb7n}\xe8\xe1\x0f\xff\xdb\v\x17\xee|~oo\x17}\xdfgO\v\x01\xdcb\x86\xebW\x9e\x84[\xccA\u01aaA\u007f\xc1Z\xa0\xf4Pz8\xd7\u00fb\x1e+\x86\xaaT\f\xa0\xca\xce8P\xfe\xa2\xb8\x86\x9d\xa0=\u0283\xc5\x15\xf1G\x90\xf0\x93_\xc5P\xa4\xea\xe2\x8a?/\xa8\x8bc\xf6-\xabX\xb6\xa4\x0en\x98@A\x85\x95\x00\xb9\x82\xe5\xe2\xf2\xd00\xc1+.G\xd9}ckL55\xb0\x88\x1d\u0242\xab\x93DkH&BA\u9be3Mnd\x10\x85\x84\x9f(\xf6\xa2\xb7\u45a7\xe9\x04\xc6\u0520r\xcaah\xe8\xb78\xfc)e\xa4\x87\x8fT\xd9\xf45\x83M\x04\a\xa8\xab<\x19\u0122\x9aN\f\x12\x06\xf4Qz_@Q\xb2\x12*\x121s\xb5\xb5\xe0\xb09H\xe8V\x98\x04l\td\b\x04\x87\x8d\xdb\xce\xe0\u031d\x97al\x1b\xf2I\xf3\xa9\xc2X\x8b\xc5b\x81'\x9ex\xe2\xd2\x17\xbe\xf0\a\xef\x06\x80\xbf\xff\xf7\xff\xfbu1_\xaf\xb7\u007f=\xf3\u0313\xf1A8\xb9x\xf1\xe2\x1fmnm\xa6@\x80\xe8$\xd7-\x17\xb8\xf6\xdcc\xe8f'*\x87\xa6\u0324\b'\xe2\x80C\u01a3jW\u3728\xbb\xd3\xe8R\u0211\xd5\u0485\xa2\xe7\xb2_\xf7\xe4XM\x9ed\xa5\x98K\xea\x80\xe9\x14%\f\x8d1%\x86\xe1\b7+-C*x]*\xb3\xfa\xb5\x80Q\u022b\xcb`\x12\xfb\xf8\x82\xc5\"\xa7\x15lz\x8b\xc2.\xab\x88\xd1h\\\xdb\x10Y\xa2jf\xaa8x\xac\x87\x14:q\x1fT\xa2\x8a\xa3\x93\u01ea-\x02\x9dVvW\xdfJ\xa0\xa5R8\t\xaa\u079ep\x9a\xccW/:G\u0604\u00b9\xa0l\x00L\xf8\t\x9cT4\xcfT\u04a5(\xe2\x12\xc2\u028bBO#\x9d\u007f\x86Z\x8a\xcf#\x82p\b\xb1f=\x8cRCZ\xe4\x01\x90e\x9c\xbb|?\xa6[g\xe0\\\x9f\x8b9\x11\xd86Xv=^~\xf9\xe5\xc9g>\xf3\xd9O\xc5\xd7\xf8\x87\xdf\x04\xc1\x15\xebb\xfem\xbe\x1ex\xe0\xc1\xf4\xfeG?\xfa\xe1?\x9aN\xa7G\xc6\xc4\xcc\xc30\xc8\xf3\x1eG\xaf\\\xc5\xc9\x1b/\xa9\x10\x83\xb9\xa8)\x02\x1f\x06R\xca=\xef\xe1]\a\x1fb\xb6\xea\xb0\xc7\xfc\x9c\x97\xf1g\xe4<\xa8\xf3\u025f\x1b\"\xe0e\xe8\xd0\x175\xf7\x90\x12\xcd/\x17M\x00xK5\xcc\x18>]\xb8\x14\xd6|\xc4\u0560\x86R\x0e\x9e\xads\v\nf\x18\x8e\xa6H\xa8M\xd9\xc2\x00\x00 \x00IDAT8)\xbcXV\xeclO\u00cf\xdf\u00bf@\xc6\xe1\u007f9\xa5\xa9\x97B\xa8e\x96>\xd1\x15c\x88E3\xd37\x13\x95\x95n\x84\xbb=\x80\x97\x86.\x8b\xa5W\xfa)\xad\xf6MN\x1e#\u007f\x9d\xfcS\f\xc8\x18u\xe2\fp\x8a0\xa7\xcf\xe3\xa1\xe3b8\x19\x96\xfe\xfbz\x8f\xac\xc2\\\x91\xd1R\xe3\xff\xf9\xdeT>>\xc1\x18F\xc3\x046\x04j(\xcfTHp\xf6]\xef\xc6\xd6\xde\xed\x99\tC\xf1k[x\x0f,\x16K\xbc\xf0\xc2\xd5_\x14\xd1v\xe4\a~\xe0c\xebb\xbe^\xb7n\xfd\xec\xcf\xfe\xed/\xdc\u007f\xdf\xfd\xf3\xad\xadM\xb8\xbe\x17}(\x14W\\\x9e\x1c\xe0\xe0\x85'\x01\xef\xc0\x86S\"\x83\x88\x04?\xf3l\xbe\xe5]\x97\xa0\x96\x88G\xe6\u0388*\x0eu6\xb6\xaa\x8b#\xa0I\xf0\xed\xb1\x03\xf7z\x02PEcY@G\xf0\xd813\xaa\xb1z)\x03\u0339\xc4\ah\x1c+\x18\xfa\x81Se\xbaNE\x96\xe5[\xe1*CE\x10\x9d\xf2\xe7\xc5\xffK|\xa8\xe2\xce\xe5\x01\xb0\x9c\xe67&\x85\xd4\xdf\x15)J\xc9#\aI\xf1\xba\xf2\xbdG\xf6\x17\x19\x19gF\xd8'\xceB\xeaKwsc\x97\x15\x9az(\xe4\xc4\f\x84\x82\xee\r%\xd8#\xcd-\x80\"\x14e\xe0\u0452\x9c\xc5hpU\a\x11t\x81\x01C\x05\xc5QBRJct\xf0\u026d\x01Y*\xf2p\x1d\xb6\u039d\xc7\xf6\xd9\xf3`b\xddD\x8a\xae\xde6\xad\x1c\x1e\x1e\xe2\xd1G\x1f\xbd\xf8\xf9\xcf\u007f\xee\xaf}\xb3<\xdf\xebb\xfe\xef\xc1\xfa\xa7\xff\xf4\u007f\x8b7\xe3\v\x17/\xdc\xf9\xc5\xe9\xa4\xd5\xea\x1a\x8f\xad\x04t\xb3c\xbc\xf9\xcc\xd7\xe0\xbb\x05\x989\xfb\x92\xc7F,>\x04\u041b\xdd\xf7\u02d0+\xba\xda1V&V\xa5\xb1\xb6HV]\u01b4\xa2\x85Gs\uc495k\xeavob\xfe$\x83.x\xd4\xc1\xae<\xdd\xcbi8\xb5TM5%\xbea\u0465\xcap\xa3\xa8\xf39+S(\x19:\x0f\u07ac\x1b\x1f\xf9{\x1a\x9e.$'n\x14\x19\x11\xa7\xa62E\x05k\xf8\xa7v\xa16\xb3\x11\xb2\xc8\tH\xa74\xd3R\xf2UJ)S1\xad\xa6\xb7\x8a\x1b\x1a\xf9\xf3\xe1) u\xe2\x041\f\xd70\x94\xde\u007f\xf0\xbd\xef\xfd\xe2d2\u0566&\xa5\xa2\x13|\xdf\xe3\xe0\xe5+\x98_\u007f]\x99\x03\xc9\xf1\x90\xaa\"\x1d\xe5\xfd\xcew5v>\f/(\x9eB*\xe2\xdbb\x06g\xe4g\xb3\x13\xb43\x87\xf6\u0105\xa1\xe7M\x9c\xb8V\xa8\u007fr\xd3#\xbe\xd0\xcd\x0e\xffR8\rR\r\xe5$\xde{\x194\x11_\x17UFP\xdf\x10\xbcpj\xbd\xa3\x9b\xd7\u0081mp\xec\x8c\xc7\x10\x9c$\xc4q\x92=r\"\xa7<\u57be\xb5\xbeE\xc6@\x962TCd\x10\xed<\xdc\xedFH\xe8%\xbd4P\x01\xc50\x84\b\xce0\x96\x1b\x16\x8e\xf5c\x98\x907;2'\xc8E\x9c\x03\xee\x1e\xf9\xe6\x8cA\xe0g\xb5\x1b\xe4\xc6D\u007f\u007f\u0094\xbd]\x02\x8b\xa5\x1a\xf6\x8aR\x16\xcf\xdcu/\u068d\xcd\xc4j\x89\xd1sD\x1c\u063a\x1eW\xaf^\xfd\u8e98\xaf\xd7-[\xef\u007f\u007f>\t>\xf4\xde\xf7\xfe\xebK\x97.\xa1i,\xbc\xb8P\xd4\xf4A\x99\xdfx\x037^x*Q\xc4R\u0716\xe4\x87\"&O\x88\xef\xe1\xfb%\x10x\xe7\t\x8fL\x83\xa6\xa2\xc8\xfb\x12w\x8e\f\x11\x9f\x86\xa2\x14\x859\xc7N\xa9s\x812&\xb4*\nO\x1e\xd6TW{Yq\u05ebq\xf3\x9a\x98!#\x85\x8b\xc6an)7\x10\x1a\xc0\xf7rJm\x96Uo\x93\xb1#\xc3J=\x1c\x16w\x1a$,\x15\xc5\xea4\xdb\xdc\xc0\x8fO\xc3\xda\x12\x16\"T\xac\xf1\x15\xcf\xf2JDu\x9a\x1b\x1a\xa1\xb6>\xa7Qx\xa9d\xe0\xd0\xe0\x8ax\xd6\xee\xdc4\x16\xbce\x80-\x86oY?\x87\x00c\x18&\f\xe2I2\u03fb\xf6\uf29b\x8c:\x03Q\u0237\x8dM\xc8*\xbd_\xcd}\xa2\x10\x89\u00d1\xcd\x1b\xf5\x04\x8d3\xa4\b\xd1\x10\x11v\xee\xb8\x18\xc4C9\x10#\xfeLM;\xa57^\u007f\x13\x8f?\xfe\u0136\x88l\x03\x99l\xb0.\xe6\xeb\xf5\xb6\xae/\u007f\xf9K\x04\x00?\xf6\xd7?\xfdg\xf7\xde{\xf7\xd3M\xd3hDVR\xdd1\xe6\x87\xfb\xb8\xf6\xdcc qJ\x1b\xa3\x82\xf6\a\xa9\xfe\vx\x88\xef\xe0]W\xe0+EWKuzs\xec\xce5\xe5G\x87q\xa5l\x9ez\u581bE\xf0p\x19\xaad\xe8f\x92\x14Z%\x91\x8c\u06a7\x8eu\u01b2\x8aU\x8f\xd6\u027a\xf3\x8b\xf8\xf9P\x12Ie'\xff\x8d,\xba9\x12S\xa6\xf7\xe4\x14zI\x85o\x05\xe2\"*\x04WaP\xeb\xc7\xe0\xa2\xe1\xf5\x93\xe2@D\xd5\ub5caX(\xab\xf6\x03\xdf\u0211$\x16X\xd6n\xb8\x9dXl\xec\xb6\xd8>\xdb\xe2\xccn\x8b\xad-\x8b\xa6a\xb4\x86\u0476\x8c\xa6UL\xdb2\xea\xc0\x0fP\x96\xebG\x8f\x97\xb2s\xe7\x12#\xaf\xef\x17\x1f\u031c\r\v\x98\x00\t,\x96\xd8\x1c$\xff\xf3P\u0427{g\xd1n\x9d\xd1\xe6\"]\x1f=c\x18cp2\x9b\xe1\xf0\xf0\xf0\xae\xbf\xfa\xab\xbf\xf8\x00\x00\xfc\xf1\x1f\u007fi]\xcc\xd7\xeb\xed_\x1f\xfe\xf0G\x03M\x9b\xbaK\x97\xee\xfa\xbd\xe9t\xa2\x8f\xacw\xc1\x82\x9f\xd1\xcd\xe7\u063f\xfa4\x96\xfb\xaf\x83\xad\xc9).T\x14\xe4\xf8p\x06E\xa8s]H5/\xf3\u054ad\x9a\x92\xba\xe8\x8a.\xdd\xe70\t\ntE\xd3\x05VF\x80\n\x84Vs2\xa5\xd0\x12\xae\x18\xb7~\x03\xfc\xe9(u\x8c\xc3\u0541\x04i\xd0c\x16'\x848\x00\x1cD\xbfU\x1c\xc7R\x19:\xdc0d\x9c\xaaBc/\xa0\x1c\xfcRNQ\x1a\xe2\xff2,\xfcaX\xb8\xaa\x16- \xa14\a\xac\x8d\u0525\fz\xc6MR\xb6o\x86\xb9W\x1ba\xcd!\x8f~\xf0d\bm\xcb\xd8\xd80\xd887\xc5\xd6\xde\x14\xbb\x9b\rv\xce4\xd8\u07b6\xd8h\x19\x8d\x01\x8c%\xd8\t\xc3\x1a\x0e\x8c\u0161\xd9\x0eU\xb9\xaf\\\x9aq\x85W\x10\xa3\x12\x95\x88$A\xb6Oh,\x83\x1b\x02O,LksFn\x81\xbd{\xefa\xa6\x1b\xd8>\u007fIgH\xdeW\x87\x18f\x03\xef\x81\xfd\xfd\xfd3\xbf\xf3;\xff\xe2\x12\x00\xfc\xb3\u007f\xf6\xdbx\xea\xa9\xc7\xd7\xc5|\xbdn\xddz\xcf{\xde\xf3G\x0f<\xf0\x80>`\xde\x05\x99\xa6b\xc8'o\xbe\x82\x83\xaf?\acl\xa8\u0252\x1f\xcb\x02\x1fW\xec\\\xe1\x96\xca|\xab:\xfe\x8f\xb4\x99\x1e\x95?y\xea\"]\xc6\xd1c.e,\x9c\xe9\x9fS\u0462\x0f3\xccV \x90\\\xfch%\x03\x13\x99\xdf|\x1a\xb6]R\xe2X\v\x87p\x8ex\x13*,\vF\v\x1c\u0764 \xca*\x82Q\xc09\xaa\xf5\xa1J\x81+\x18\fr\x19\xc5F\xa3\xd7\xc93\xe0\rF\xc83\xc5FC#\xdb\x16\x8d\x1b\x98\xd1\n5h\xc0R\x1a3\xa3/60\x1a\x02YD\xb0\x960i\x18v\x8baw,l\xdb\xc0\xb0\x81\x99\x18\xd8M\x06\x1bE\xc4\r+\xef\x9b-\x83,\xaf\xe0\xe1U\xe6I:\xb5D\x99~hB0 \x06\x91\x84\xd9+\x81\f\x83\xdb\u0415\x97A\xd8\xe1g\xf0\xe2\xc1\xd6b\xe7\xceK*\xa4\xf3!\xa0%\u078fLX.\xbbn:\xdd\u061b\xcdN>\x01\x00?\xf1\x13?\xce\xefy\xcfC\xebb\xbe^o\xff\xfa\x87\xff\xf0\xd7\t\x00\xee\xbd\xf7\xdeG.^\xbc\xf8jc\x9bp\xe3\xea\x83\xc0\xd6\xe0\xe4\xfa\x1b\xd8\u007f\xf1Y\x18\u02e3]nv\xec\b\x959\xf0\xce!\xbe\xa0r\xdf\xe4\x1c.\xb5\xba3\xc2.)\xa9'\f\xeb\xa2\x19\x94\x84\x81\x95\u0400!B\xb4\xc2\x1d\xaf_\xaf\u0704\x0f]\xff\xd5X0\x03\r`\tg\x19\xae\x89\xafC\x8a\r\x81\x060\r\x12\x1bf\x15\xe2\x19\xf1\xfd\xa5\xba\x97EQP\xca\x19\xc4\xf0\u02d4\xbe&\xf1\xfa(;$~\\\x0fM\x85W7\x9b\xb1\xba^l)+\x93\x05\x1a\x83\u042bv\u007f\x15\x98!\xca\xef3k17\x13\x02\xefZ\xa0\t\x12\"c\xd5\x17h\xa3\x05\xb5\x16`\x1dp2\xb4\x93G\xfc\xfd\x13\xaa\xe3I9\xbbH\x94\xc4D\x81)\xb4\xa3\xe1\xda\x10)\x83\x85\x98@\r\ubc35\x8a\r,\f\xf5E@\xc6`\xe7\xf6\xf3`k\x03\xa6N\x15m\xd36\x8d\\\xbf~\x1dO=\xf5\xcc\x1e\x00\xfc\xf2/\xff\x1d\u007fxx}]\xcc\xd7\xeb\xed_?\xfe\xe3\x9f\x16\x00\xf8\u0527\xfe\xa3\x97\u03de\xbd\xed\xf7766re\x10\xbd\x1d\x96\xb3\x13\x1c\xbc|\x05\xdd\xecP]\xe9Rvc=K\f\xed9\xe0{H\x10\x11\x95\xb2\xe7\x8a\xee7r&\u03f0\x01\xe5\x80\xe5\x10t\x11y\xd3\xe4D\v\x91\x89l\x8a\xd3\a\x00\x8f=\xfe\u013a3_\xaf[\xb3\xbe\xf6\xb5\xaf\x12\x00\xdcs\xcf\xe5G\xee\xba\ubbbe,\xb0\"\x0eD\x8c\xfdW_\xc0\xe1+\u03e3i\x9a\xe0c\x11\x1e\x8eA\u01d6\xb2\x15\xc5\xc3E\x9f\x8c\x02\xfa .`\x05\xa2\xd5\xe3\xfc \u0693nR\xefF}\xb4G>Y\x04+_|\xb5\u03d5S\x99}eU\x8f\xe2\x92\u0254\xb1\xb9\xa7C\xba\u026e\x85m\xb9:\xfa\v\x8d\x9f\x16\b7{\xd1R\xc3\xff\x03\xa3/*w4:E\x84\x946\xa7|\r\x1a&lX\xc6dj\xd0L\x18\xb6\xe54|\xf4\xa1\xb8\xa7\xa4 \x1a\xbb\xe8\xe3q|+\xe3\x8f\x11\xf5\xd1\xc0\xb9<'%\x05\xac\xdcX\x02m\x19\xd0\x06\xe3\x14!+hja6\x1b\x98I\x8bf2E\xd3Na\xdb\x16Mka\f\xd73\x0f*7\xf6\xe8\x8cX\x9b~I\xc8\x00U\u02a3r\u02a9\xd5\u007f[Z\xd5P\xe0\x9e\x97,\x18\x81\xc0\xb4-\xectR\x04GSv\xdc\x14\b\x11\xe1\xe5W^Y\xfe\xee\xef\xfe\xee\x12\x00\xbe\xf4\x0e2Z\xd6\xc5\xfc\u07f3\xf5\x81\x0f|\x87\x00\xc0/\xfc\xc2/]\xdd\xdd\xdd\xfd\xc3\xcd\xcd)\xbc\x12\xcaCm ,\x0e\xf7\xb1\xff\xea\x15\xf8\xff\x9f\xbd7\x8f\xb7\xac*\xafE\xc7\xf7\u0379\xd6\xde\xfbtTA!\x14\x05\x04J\x1a\xa1 \x16\x02\u04bdkh\x05\x1b\x82\x1a\x8d\xb9\x11\x8d\x06\tQ\xaf\xbe\xe73\xd7\x17\xafz\x93\x97\u0118\xe4&\xf16&1/O\xa3\x98\\rc\xf3\x8c\x82J\xb0\uf0c8 J+}[\rU\xa7\xdf\u035as~\xf7\x8f9\xe7Zs\xad\xbdNU\xde\xfd\x03\xcab\xcf\xdf\xef\xfc\xaa\xea\xd49\xbb_c~s|\xe3\x1b\xc3\f\xfdh\u007f\xfa\xf1\x16$\xa6G>$\xd7\x06\xaf\xe8\xaa\x11Jc\xd2i\x8c\x01\xb6\xd4*\xd3v\xb8\x93\x8a\x86AK\x15\x9c\x0e5\xa1\xc9SW\x8d2i&a\xb4\x13\x1d5\xb9_\xa5\xbc \xe4\aht\xa6\x15\xba\x8a\u0419Q\xe8L+hE\x15\x17\xbd\x06\xc3R\u056bM\x93\u0644\x8a\x925\x0e\x13\xf1\xb5^\x83\u0268\xf9e\x85\xc6q\x87\x19\u074c\x90+\x82\xee1\xb29\x8d\xbc\xc3\xc8\x14\x95\x94QJ\xbbT\x81\r\xb2\x16\x19^\xc7\xf5V\xdf\xf5&]EcL\x98\xe2\x00\xa4=\x06\xcd(\u007f2h\v\xe0p\xfeT\x81N\xa0BXC\xe9\x0e\xb2\xbc\x87\xac\xd3\x01)\xed\xfd[h\xfc\xb5\xabT3TV\xfa\xc4\xec\x11Ny\x1f\x16\xad\x19\x943\x90q\u057f\x89\xb2D\xa1\xaa\x91\x1a\xab|\xeb\x13\x86T\xd6I\x9e\x8e\x84&h\xa5\xdc\x1a\x8eF|\xff\xfd\xf73\x00\xec\u0639s\x02\xe6\x93\xf5\u052d#\x8e8\\\x13\xd1#\xb3\xb3\xb37\x1cu\xd4Q0\xa3\x91Kydk\n\xcc?z/\x06\v;\xa1X\xfb\x12&U\x12D\x02@\xa8\x94qE\x99b*\xe1\x1a\xaf\x9c\x93d\x99\x9a\xe2\xa4}n?\x1eiym\x81t{\xc4|\"ii\x83\xee\xb5\x15\x8c\x95\xcf5sP]Li\xe8\x0342M\xd0\x04\xe4\x1d\x86\x9e\xd3P\x1d\xdf@s%\x8d\x91p4h\xabZe\x1c\xf2ZmZb\xe5\xdc\xd0\xc0K\x8b\x9fJ\xc2\xd9g\x8a\xd0U\x80V\x04\xd6\x04\x9e\u0460\xf5\x19t\x87\x91k\x86V\xa1R\xe6\u051aaO\xc6_\xe3\xc8\x1d\x1d\"\xd3MZ\xf6\xd0\x12\x90\xa0*\xc92\xf2\u0291i\x05\xear\xcdc\xb1^\xea\x87[\xeb\x06\xc0-\x15\x88\nJu\xc1y\xc7\xef\f@K\xb0E\x9d\xb6\x8a\xcf\u0445MKE3\xad\x9c|`\aPV\xe2>\x1d\xd1\x17&\"\x95\x04\xd79\x81\x90\x82\xeat\xab\t\xe0z\xe6(\x0f\x87#\x1cr\u0221\xcf9\xe6\xd8cO\x04\x80\x13O<\x91&`>YO\xd9z\xc3\x1b\xde@\x00p\xcc1\xc7\u0733n\xdd:\x80\xa0D\x9cP\x19@\xc0\xd8\xf5\xf8\xfdX\x99\u07c6,\xefTC\x87\x89\xee<\x1e\u0465\xf4\x96\xb65\x99\"\xb5\x8d\xaaK+\xea\xd6\x12\u071b\xd3\xf5.\x02\x9b\x932\x84\xbaV\xd1\u05fa\x9aT\x13z\x8f_\xe6k_g5W\x12\x02\xb2,4\xecf\x14\xb8\xabj\xb9\x11\xaa\xa7\xa0\xa6T5\x04\xd3\x12j\xbc7xlS+J\xed\x90\"\xf5\x83K\xa4\v$\xc5s\xffxY\x13::\xd2\x04\xf0^#\xd3\njZA\xf5\x14t\x06t\xb4\x0fapLp\u068f\xd3\xd7\x01y\xcf\xc3U\xe5\xc9E*\x8bc\xec\u1d4d\xbd\x06\xa5\x00\xce\x18\xd4U~\u0693\x9atT\x83\xaa\x12\x01r\xf2\xd59\xa7\x16\x02\x04h\rR:\x8c\xf3S\x12#\xc7`j\x8e\xf4'v2\x01\xb8UG\x81s5v\x1ap\xceS\x85Rg\t}\xea\x96R\xe0\xbc\xeb\x1fZ\f\x9c\x8e\xb1\x89DT\x14\x85\x9d\x9d\x9b\xa5^o\xea(\x00\x98\x9b\x9b\x9b\x80\xf9d=uk\u077a\x03\x1c\x00\x9cw\xde/\xdc\xc1\u0337\xe7y\x0eg\v\x11g|\xe3Gi,\xee|\f\xbb\xb7=\xe8\xa5cTM\xdd\u0544\x89R\xc9\x1a\x05\xce'\x11\x89\tm\xa7\x14\x8c\u0491Lj\x16\xeb5\xee 6\x16IU\xe0\xe4\x1d\x15\xa9\x15\x1c\xc7i\x1a)9\x01\x19s\u05d6\xf6\f\xe5\u06a4\x8f\xe7vuF\xe0\x0e\x81g\x94\x97\u01e5A\u011a\xa0\xa6\x95\a\xa9\xb4\xa1\xb8FSQ\u068e\x0e-\x9e\\5\xb9dT\x0fQ5\x06Z{\x96\xe4\x1b\u00e4\x80NF\xd0\u0468J3h\x86A9\x81\t\xe0\xf085\xc3\xd3/Lp\n\xb0:q*DK?\xa39\xfa\xb4\xc6ND\x8d\u05d6\x92\x97\x93\x13\x9e\x9a\xa7\x14\xa8\xc3\xe1\x90Q\x97s\x96\xbe)\xb1\x9bA\x04\xea2D\xa1\x8cx\xf3AQ\x1cr\xf0\xc2\u0670T\x1f\xb5\xbc\xfe\x8cr\xa8\x88\x99\xa02\xdf\xf8\x14\xaa\xac\x1f\xc4:\xd8d\xb2\x13hX\x00K\xa8\xcc\xf3^5\x80\x84T\xc1\xe4\xc7\xfe\xad1\x18\r}\xf8\xeah4\x9a\xd0,\x93\xf5\u052ds\xce9\xc7\x01\xc0)\xa7\x9cv\xffA\a\x1d\xf4\xc0\xec\xcc\f\x8c1\u039a\"8!\x12\xcch\x88\xed\x0f\u078ea\u007f\x1e*\xcb\u00a7%H\xbe\\\xe5']\x06\x068\a\x17\xc2+\x90D\xb6\x8d\x83\x9c\xd4t\xd4\xf5\u03a4\xd7\x00\xebL!\xef0\xf2\x8e\x1f\u91a2\xbaN\xba\xea?%\xf2f\xaa\xf3\xc92>u\xb9&\xa9\x90L\x161\x03:\xf3\x928\x9a\u0460\x9e*G\xe3\xd3\xdf\xd5S\x8c\u038cB\x96yN\u0595\xd4\u0178;\xc9\xda>-\rZ\x02i;\x93jz\u9997U\u0515g\x9a\xa1\x94\x97\xfa0\x13\xb8\xcb@O\x87\x14\x1f@r\x0f\x8c\xc4\x04M\x9e*\"\xf2rO\xa7\xa9\xee\xf9\xbe'=\xa5\x94n\r{5*\x88'\x18\xad\xbd\x82\x85\xbb\xcaS,\x94\x06\x83H\t\x98\xfe-Hc\x00}u\x9e\u6002Q\x99c\xc5Sa\u0512K\xf2z5\xe8'o\xc9\xe2)\x16Q(\xbb\x9eN\x04\xce\xf9l\xd0\xd42\xb7\xa2p<\xedb\x84\xa0:\xbd$\x90C\xea\xc2\"\x11\xb2\u01a2(F\x02\x00\xa6(&`>YO\xdd:\u3333\u4aab~C\x11\xd1\u02a6M\x9b\xee:l\xd3a0\u0188\xb3\x06\u058c\xe0\x9c\x05k\x8d\xc7\xef\xfd!\x16w=\x06\xdd\xe9\xc2\x11`\x93(\xb3\x94\xe2\xf0 \xee\x12C\xa2\xb5\x9cI\xea\xf6\xb3c\xf0!^>\x96k\xdf\xc0\u02fb\xaa\xa4\x0f\\\x18\x84\x19\x93\xc6Q\u04c0\xbc\xc1?\xb7\xc8\xeeh\rV_\xe0\xc7\xc8YyP\xe4Y\xed'-\x93\xe9\u0258\x80\u011a\x90\xcfhtr\x86\xd6\x04\xd1T\x8d\x9c'\r`\u0683\x9aE\x92>\xa04\x8d\xbbHZ&\xe5+\xc0\x12\xf6\x01\xc4Y^\xa90\xa8C\xa0\x19\xe5\xb9\xe18\x80\xc5\x04\xf4\xfc\xf7\x88\xc3\xfb\xe7\x82\x12I\x13D\xb7\xbc\n\xb2vw\x81\xd0\xf4\xea\x19\u007fK\\\xb2)\xaa\x0eC\xcdy\xae\u0725\x80\x99(^\xa89\xd1+~\x03\xa7\x8c\xc0\x91\xdf&\xa0\xa3\b:\xba+&'\x99\xca\x06(\xbc\a\xa1\x8a\x8e\xbf\xc8\xda\xd36\xfe\xbd\x8c6\xb9\xa86\x11\xa9'\xa1\xc6\x13\xd1\xc8:Xbd\u0769R\xcbN\xa9\xe82\xa6T\x85\xd4#\xff#n\x02\xe6\x93\xf5\u052e#\x8f<\xd2\x01\xc0\xb1\xc7\x1e\xfb/Z\xeb\x95,\x8c\x83\xfa\xe1\x1f\vf\x85\u015d\x8fa\xfb\x83\xb7\xc3:\x03\xce\x14(\v\xfa\xdc\xd8LK\xa4g^\xa2hC\xac\x9c\xad\u05ffM[\xd2\x16 M\x1cR\xbdicO\x81\xa7\xb5\a\x84\x10\xc2.k\x17\x8d\xb5\xbf\x8c+\xa6\xa5\xb5:o\xdeH\xa4\x05\xb4\"\xcf\xefv\xa8.QoT\xa6\xdcc\xa8)\xafl\x81\"X\x15\u031b\x90\xd2Bk\xf9\x9cP\xc3tP\xd6d\x9fR\x18\r4/\x90\x11\xb2\x8e\xaf\xca\x19!\xfalZ\x81z\xaa\x9a\xf0\f\x0f\x96;\f\xee( $F\x95U\xb6\n\x03F\rm\xfd\xf8\xabKk\x9cp$y.u\u0263V\xecO8=\x06\x05\xae\x9c\x92\xa8\xc2\xf4P4.\xa4\xf1o\x06u\xd9[\xd4R\x10\xa5\xc0\xf7?)\x9eLP\xc9\x05k\x9f5\xf6\xef\a8|V\u00c0\x10$-\"\xa8Rf\xc1\xf7c$\xfa\xbd\x130\xb4\x82\u0551\x83\x03\x81\xb3,\xf9]i|\xac\xbc1\x1c1=\xed\xd7\xf4\x04\u031f\xa1\xeb\xcc3\xbd\r\xf3\x9b\xdf\xfc\x96\x1f\xaf_\u007f\xe0\x83\xddn7T-\x0eb\x8d\u709d\xc5\x03\xb7}\r\xfd\xe5\x1d\xc8z=pF\x90\x8e\x82\xcb\bN{\x1f\x10\x1f\xfb\x85r\x04\xdaK\x14M9\xfe\\\xa75\xc6\xf5\xe0m\x93\x98\x1c\x9ax4\xa7\xc0=\x0e2\xc0\xa4:o\xd8\xd9\x12\u045e ~\x8f\xf5qZ\u1ae0\x85\xe6\x1e\x033\x1e\xfc\xaa\r\"5\x8f\rn}\x99o4R\xee\x83\x16\x9c\n\x13\xa2\xdc\u019f7\x06i\xa8v\xa6G\xb3!\u062c<\u02de\x02\x00\xc9\b\xbaC\u0202\xf2\x8e\x18\xa0@e\xa0\x1e\xcf\xe9\xa1J\x11\\\x8fa\b\xb0\xae\xbe)\xfaf\xe8\xb8\u007f\xb8\xb4\x9e[\xc6#D\x9b\x9a\x17\x9f\f\xe77\x1a\xee\x12hN\x039\x97\xbf(\x8d\x91\u007f\xa1\x9a\x8d|\xf5w\x11\xff{\xe1I\x92?\x02\xfa\xd70\xce>p\xdd\n\xd8KE\xeb\xd6\xc9\x16\xe13\x8a\xd8@\x0f\x95x\x00\xef\xf8\x15\xef\xdcY\xa0?tX\xec[\x14\xd6\u007f\x86I\xe9F\x82\x91\xff\U000948cf]t\xd6w\u775bT\xe6\x93\xf5\x14\xaf\xf3\u03ff0\xba(\xfed\xfd\xfau?\u0770a\x03\xac\xb5\xe2]\xf7\x83\"\x85\x15\x9e|\xf8n,l\xbf\xcf\x1b\xf8+\xf6\x13\x99D\xb0\f\xd8\f\xb0\xba2w\x92\xc0=W\x9as\xc1\xda\x01\fI\x85\x9aL\xceHP\x88P\xa0:hFA\xe5\fR\xf1\x18\xbd7\xb6\xb6\x9c)\u017f\u05a7U\x82\xdeXi\x02g\x04L)\xa0\xa3\xead1\u01951\x04?\x19*]*9WI\xc3\x15\x924\xf9\xba\xfa\x1c5\x0f\x1bYc\u04d1f\x0f\x00\xa1\x19\x9c\xb3w\xfe\x8bw\xa1}\xf5K\x19\x97A\x105\x13*\b\\N0\x8a`\u04f4\xa1\x14`\xa9\xfd\xddi\xdb\xf4Z\u01cc\u04aa<#p\x87\x81\x19\r\x9aR\xa8\xfb\xa47NQ2~\x88+\x1fZ9\xe0\x13\xdfW\xff\x99\x92`(\u6e1a\ue31f\x1b\x0f\u8f8fc\xadC!\x82\u00b9Z\xfb\xa44\xe5\x92J\x8e(\"0\xd6ayP`a\xa5\xc0\xa8\xf0\tMD\xde;\xc67\xfc%\t\x88\x0e-Sq\x12\xa8\x97,\\O\x135\xcbd=\xb5+\xfd\u031dx\xe2\t;gg\xe7 \"\xe4-C\xfd\\=+\x85a\u007f\x05\x0f\xff\u4ef0v\b\xd6Y\xa9.\x88\xb2A\x973\xac\xe6Ro]F\xd1%\xdaqjuR\x94\x1aE[ce\xb9\xb27\xa5)\x055\xa3\xa03\xafn\x88\x95W\x1d`\xd0N\u153a\xe0\xbd\x1bps\x1cl\xe9\x84\nW%\xb7/T\x9bq\xa9\xf5\"\x15\x83\xa75(\xe3j\u011f\xd1Ry\x03k\xfd\x8d\xd64\x83\xa0f4\xf2)\x15T#\t\xf0T\xa7\xe6\x86lN*\x15H\v\xc5\xd36d\u009a\xc19{\xf9\\\x87\xf7\x98\x19\x9dn\x16\x04\x01\xf7\x18\u064c\xaa,\xb7\xa3\xbae\xec\xfe\xd6\xf2i,\xdd\xd3\xf7t|\x800Aw\x152\xe5\a\xa9\x88\b\x92\x93\xaf\x80U5);v\x86\x10\u007f\xa5\xbb.\xc3i\xef\xc4S\x029\xd57\u023dGUS\xe3tB5\x1f.\xad\x83zeV\x83:\x9c\xf0\u048d\xd3F\xe3\xce\xd6\x1cD\u04be\xdav\xe2`\xc5\xc1\x88\xf8\u07ae\x02l\x87\xe1\xf2\xe0K\u00fe\xf9\u8303-\x1c\x9c\x15\x18\b\xac\b\xcc\xc8a4t\xb0&j\xca\x05\xd6\n\x8c\x15\f\x06\x0e\x8b+\x06\v+\x06\xab\x03\v\x91@\xb7\u01e0\n88[T\xba$\xaaNP\xd69\xe9t;\u0635{\xd7\x03\xfdA\xff\x16\x00\u063e}\xbb\x9b\x80\xf9d=m\xeb\xdcs\u03fbijjzg\xa7\xd3A)7ta\u0519\xbd-\xee\x8e{o\v\x12=F\x9a,L\xd6\a\u43ba\x04\xa3\xf7\xe0\xf3]K\x9f\x97\x96\x01\xa2\xca\xdd\xce{\x88$\x84j\x87\x90\xcd)\xe8\x8e\x0f\xfeu\x8d\xea\x97\x1a\xb7O\x89- \x89\xec\x85b\t:\xe4\xdc7\u0290S\xf0\xcfn\x199\x97\xf6\x84#\u0584,\xd0Aec\x98\x81\xf1\x12to\xdc\xfe\x9e+c\u02bd\u05ca\x8a\xaf?\u00df\nr\xaei\xb5\xdb6\r\x06!\xeby\x8e?\xea\xf7K\x1fo^\xab\x12o\xb6\x8eS9\u0478\u007f\xbc\x1f\xcca\u042c\x02\xa6\xfdI!\x86HS\xb2\x11Hi\xd4YW\xec\xa4\xf3_\xf1?\x1c\x93?\xf9\xc1\xf7s\xac8\xff\xfeG\x13\xb1\x98\x02d\x1c\xc4\xf8\x11|'\x9e\x901\x01\xe0\v#\x18\x0e-F\x85Aa\x1c\x8c\x15\x14F\xb0\xb2j\xb0\xb4R\xa0?p0\xae\x1a\xed\x0f\x01\xb9\xfe\xb1:\a[\x8cJs8F\x95\xc0%\u21080\u055b\xeao\u077a\xb5\x0f\x00\x87\x1f~\xf8\x843\x9f\xac\xa7o\x1du\xd4\xe6\x1b7m:l\xc7\xdc\xdc\x01\xb0\xd6W\xd5\xe2,\x98\x00\x9de\x18\xae.\xe1\xf1\x9f\xde\x02\x16\v\u036aVF\xb1\x03\xf4\u04075\xdb\xcc\xf3\u65774j\xe0\"\u0524F\xa4V\xa9I\xfcD\xaa\xc47<\xdc\x17Okd3\n\u0228\xd6\xe8\xaa\xe1\f\x8d\xfbp\xcbX5\x99\xd6\xc2\xe1\xd7\x19\xe0\x8c@\n\xbe2\xe7\x16\xf0M\x1c\x1e\x9b@\xcc\xe4\x95-\xd2\xe3\xaa\u008d\x8a\x8a1\u007f,\u00b8\xba\x86Z\xcf\x0f)\xb0\x11\x13\xb2\x0eA\xa9\xa0\x9bf\x02z\xec\xf9}\x1e\xefC\xa4\xb5\xb3\xf8\x97\x14\xbd\x8c\u045b\xd3\xe8L)t\x82>=\x866H\x8b\x87\x0e\xed\xf5TQ\x1f\xb5\xcd4AM\xb1\xaf\xca3\xaeM\xbf\x8fW\xf4\xf5\x9eE\x9bs\xbb\x930\x18\x95y\xf9eMJn\x05\u0537\x90\x91\x85\x14\x0e\x12\xaa\xf1H\xa1\x18\xe5i@\n!\xcc\u00d1\xc3p\xe80\x1a9\x8c\n\x87\xfe\xd0a0r\xb0\x12\xde\u007f\x92@[\x95.\xbb~\xc3q\x16f\xb0Z\xf5\x17\xe2)\t\x028G\x04\xe0\xd0C\x0f\xd5\xcf\u007f\xfeY\x1a\x00\xb6n\xdd:\x01\xf3\xc9z\xea\xd7\xea\xeaR\u025fo\xde|\xf4\xad\xddn\xb7\xf4\x87vA/\xabX\xc1Z\x83\xf9m\x0fb\xb0\xb2\ryG#SA\xcd!\x04v\x04e\x04\xd9\xd0_\xfdN\xc5\xea\u070d\xe5\x97Q\xb3\t\x88(WKR\x85\xd8?\x1e!\n\xd3\xfbA/\xad\b\xd9\\\x06\xdd\xf5\xd5y=\x88\x81\u01a3gbe-\xcd\u071b\x06\xe5C\x04\xce\xd9Osj?%X\xaf\x14\xc7C\x96K\x15\rR\xab^\x82\xe91l\x90\xff\xf9F\xf1\u06aa\x90\xf4d\x10gU\x05kW\xc8\x1c\x1c\x10uTph\x02M\xd79\xe9\xb5n!\x16\x9b\x19y\a\xc8|Z!\xd7\u0790K\x01Aw\x1e\xbcT\x80\x16E\v\xb5l\x9a\t\x81\x15$\x9dY7\xf0\xe4=\xae\x01\xb4\xb4%\x12\u057a\xa6\x91\xb0\xa1\xb1S\x013Aw\xbd<\x95\t\xd0\xca\a\x99\xa0o\x81\xbe\x81+\x9c7\u010a\x95\xbe\x00\x8e\x04\x96\x91\x18i\x01\xd6\t\x06#A\u007f\xe8\xd0\x1f8\x8c\x8c\v\x1e\xe7^\xd6\xc9YH5\xe2\xaa\x1f\xa0\x14C\xac\xc1p1\x04N4\xe4\x87\xceY\xd7\xebu\xe1\x9c\xdc\x0f\xe0^_\x99o\x9ap\xe6\x93\xf5\u052f\xa9\xa9\xd9\xf2\xef[\xb7n\xfd\xfa\xd4TO\xb4\u05be\xba\x15\a'\x16\xcc\f\xa52,=\xf9\x04\xb6=r;\xf4\\\x86,gh\x95\x00\xad\x13pa\xc1C\vK\x0eF\t\f\xd5u\xbbcQo\xa9~;\xb5\xa4\xd5\x04d\x1e\x10kV,\"\xd0S\f\xbd>\x87\xed\xb2\xd7GG:\xa6v\x1f\xd2N\x8d\a\xb4\x8a\xfe&e\x85\xa7\x025\xa0B\xfa\x8c\xa65=KJxJ\x9bg%\xb5OP=\x05\x9aU\xde\xe8JUz\xfc\xb6\a\xd4v\u016fE\xc2pF\xd0S\f\xa5\xa9\xc2S(\xd4\xdauk\xe14\x94\xaf|\xbd\x8b\x93o\x80\xd6+Q\x19\x9bYoU:\x96\x9bT\x00\xa5.{\xfe8\xfa\x83D\x80\xe1\x90A\u065a\xd8\xd3(\xa6\xa3\xe41\xe7\xb0?y\xfa\tS\u028f\xb8'`\xd8\u6552\x9ef\xcaSN\xf2\xbf\xc2~z\x95\xf3\x8af\xa2\xb1I\x9e\xda!\xa1\u04a4'3\xa6Y\x97\xc1\xeb3`\xca\xd3@\x92h\xddkV\xb7\x90*\x90[\u0195;\x12\x93}\x8ad\u01f1\x01t\x9d\xaf\xdc]NXq\x82%\xe30\xd4@\x911LF0\xda\xcbb\x8d\x06\xa0\xb8z\xadu\bmV\xfe\xab\fW\xa1\u051f?$\r\x05\xc7N\xef\xb2K \xa5`\x8b\x11\xe6\x1f\xbc\x1b\xb6\x18\xfa\x1f\f\xca\x18\t\xee\xa0J)\x1c|\xf0\xc1\xc3\xcb.\xbbt\x01\x00\xce>\xfb\u0327\xf5Z\xd6\x138\x9b\xac\xb8\xba\xdd\xfc\u01a3\x8e:\n\x8f>\xfa\x18\x86\xc3a\xe9\x12GD\x10(\x8c\xfa\xab\x98\u007f\xe2\x11\x8c\xfa\xab\xfe\xfb\xcaA\xcd*P\xe1\xe0\xfa6\xc4o\x95\x1a\\X;\x80X\x03 \x03\x93\x06\xb3\x06\x83\xcb\v>\xba\x06z\x05\x01Cu\x14\x9c\x10`\x05\xb0\x9e\x1b\x85b\by\xef\x13JIi\xac\xee|\x02\xcb\xdb\x1e\x868\a\xa5\xf32\x95HB\xf3s\xe3!\u03e2\xf5\xeb\xd7\xfft\xfd\xfa\r_\a\x80\x13OYO\xeb\x1a\x0eW\xd1\xe9La\u02d6\x93\x16n\xbd\xf5G\xcb\xff\xf2/zf8\x18\x02\xf0\u04c2\x95\xf3-ai\xc7\xe3X~r\x1bf7l\x84+\x86\xd0\x19!\x9f\xd3\xe8;\x81\x1b\xc5\x04\x1a\x02\xc8\xf9\v\xac\x18\xa1pE\x88\xfe\xd2 \xe8\xb2\u05258%)\xe4+'\u0470\x8e\x80\x91\x03\x93?:\xc3V\x01\x10D\xf5 `\u0342l\xda\u00ac\x8e`\n\a\xb2\x0e,>$\x83\\\xa4\x05\x18\f\x05\"\r0WG|\xf6\xea\x15\"\x04\x8a\x85\x92\xe0\x04)C\x12j2:T\x91b\u0360\x8bT\x16)B@\xc6\x1ex\x87\xce\xff\xdb\x010\x91\xa2\xf0\x95\xa6OWJ#\x86\xaa\xe3>\xa9\xb0\xc1\xc4\u02b1\xc3\xc0\xb4\xcf\u03ecB\x9fi\x9cFj\x99\xb8tR\x0fe\x02\x00\x0e\xaf\x81\xf4\x18n\xd9\u07ce\x15\x81qRZ\xfd\x8e7=\x93\xb4#&d\xd3\nj]\xe6O\n\xae\x9e\xa3]\xca\x12]\xe0\xb3\x1dPX\x815\x0e\x19\x01\xb9B\xeb\b\u007f\x93\x11s\x02\x14\x85\xc5\xe2b\x81]\xf3#\f\v\a\x8aJ'?\xc5S\xc6\xd3\xc1Q2\x1c\xdc4O\xf0^+U?\xb7\xaa\u04a3\xcbbT\x1f)\xad\x01g\xb0\xed\xf6\x1b1X\xd8\x05V\xc1\x1f>\xbc\x98\xe2,\x9c\xb54w\xc0\x1c6o\xde\xfc#\n;\xd8!\x87\x1c6\xa1Y&\xeb\xe9]\x9d\xce\x14\x00\xe0\xbc\xf3.\xd8\x01\xd0u\x9dN\x0eV\\\x82m\xe4]\x89\x19K\xdb\x1f\xc3\xf2\xce'\xa0t\x06\x12\x81\"\xa0\xdbc\xe8\x19U\x1an\x95Lp9@d\xe1l\x01S\f`\x8aU\x14\xa3U\x183\x805C\x883\xc12\xd7\x02\xec d\x01k \xa6\x803\x05l\xe1\xfft\xa3\x11\xccp\b;\x1c\xc2\x0e\a\xb0\xc3\x01\xa4\x18B\xe5\x06\xbak\xe0\xdc\b\xd6\x19X\xb1!\xe9\xc8\x02A^im\x01kG~,[lI\u00b3\xf6\xc7j\u0242\u0331\u64ce\xb2I\n\x12P\xcd\xc3[\xea\xfcC\xb3\x92\x95\xa4:\xcf\"7\x14\x9c\x1f\x11}\xd1\xdb\u87e4Q\x9c1\xc2\xfe\xe3m\x87g5\x90Q-\x10[Z\x06\x98\x9a \xe6ds\x93+\x93\xb3fFv(\xa8=\r\xe2\x04&4b\xb3\u0408\xf6z?\a8\xaf\xf9v\xf1\xcb\xf8?\xad\x11\xd80\u0623\x9c\x94\xdav\xa4^\xee)\xb1\x1f\xfen\x1d0\x18Y<\xb9{\x88\x1dO\xf61\x18\xda\xd0@\x0e\x8d\xf9\xa8|R\x04V\x9e6\x8b7A\xd2\xd0\rIr4\t\x96\xe7\xcc\xc1\xc6!\x86\x91\x10\xcaD\xa1\x9dw\u0782\xc7n\xfa\x1a\xec\xa8\xef]\x13\x9d\xc0Yo\xeflM\x81<\xd7\xc8\xf3|\xfe\xf4\xd3O\xbda_\xb9\x8e'`>YI\xe1E\xab\x87\x1f~\xf8]\xd3\xd3\xd3 f\xdf\xedOB\x1eH+\xac\xcc\xef\xc4\xf2\xce\xed\xbe\x92\x0e\x95\x17A\xd0\xe9)`JyYXc\xea\xaf\xdc\x10\x9c\x83u\x06\xce\x198[\xc0Y\x03gM\x00\xd8 gd$\xf3\xde!\x8a.\x06_XS\xe6\x8c:k\xe1\x8c\x05\x91 \x9fV\xc8z\xbe\x8a-\x9d\xf4\xa2\xe1W\xb0*ub\xe1\u0107N\x1bW\xc0\xb1\v`\xc0a|\xbf\x81\xadR\x85mV\xb4\n\xd5hri\xce*\xa5\xb1\xcde\xd3NU\u0464\n\xa5\xea\xa2\rZkWe\x96D\xf5M)\xcf\xe9\x97\x1cxJ\xe4\x8f;\x9f\x8c\xa9E\x9a\x8e\x84)\xf5\x92\xfa\x86k\xaf\xba\xa9\xf4\xf3!\xb2-\xe8\xb7]\xf4-d@\xf5\x18\x1cl\x82\xe3\xd4e\xf0g\xf3TMi-+\xc1\x06B\x90\xb1\x0f\x98P\x8d\x87]\xfe3\xa1\x87\x00`4\xb2\xd8=?\xc2\xee\xf9\x01\x8a\xc2\xf8p\x8d\x92\xd3\xf6@L*\x84N$\xc0]?\x85T\xb6\xb9\x84DvJ\x95\x92\x89\x98\xfdO\t@J\xa3?\xff$\x1e\xb9\xe9+Xy\xf2q\xb0\xca\xfc\t\xc1\x85\xfe\x8e\xb30\xa6\xc0\xf4\xf44\x0e;\xec\xb0]\x97]\xf6\x8aoN\xc0|\xb2\xf6\xc9U\x14\u0177\x0e\xdbxX\xe0\x1d\x15\xca(s\x02\x88\x14\xcc`\x80\x95\xf9\x9d0\xa3Q\xc0Z_\x8du\x14\u041bQp\xb9\x97\f6r\x18*\u03d6\b\x80%\xd8\xfa\xafJ\x96X\xaf\n\u02f3vR\xc6E\xa0\xf6Gg\x01\xe7\x84\u03acB7\x8c\xbb;F\xd9\x18\x15\b\x1c\v\xac\n\x80$\x0eV\f\x80\x02\x8a\x02\x9f\x9dq\xbdQW\x17\x0f\x06k\x01jt\x12\xa9\xe5\xe2I\xa3\xd0B\xdaE\x8f*_t\xf6\x80.M\fo\x94\xcd\xd1+>\x86P\xd0\x14\x97\x89GT\x93\x82\xd4E\xd6\u037e/5.\xf0Z*O\xec\xefR\xe0\xcecfh\xfa:\xa3\xca\x1a\x05|\xd5\xee\u008d\xaaYU\xf3)\x8f\xef\x8b\rU\xb9\xb5\xc1'\xc5\xfa\u05eb\x9e(\xd5|\xd5\xc2\xf0\x8f\x8b\x01I\x82\xfe\xd0b\xe7\xee\x02\xf3\v#8k\xc1\\\x8d\u06f3\xf6\xcd\xe1\xb2\xe3*\xf5\xbc\xd9J8%\x89\u02c3\x84\x8a\u07a7/)\xed7\x030\u0574\xee\xc4\n\xfd\xdd\u06f1\xf8\xe8}\x10k\x03\xd0Gu\x90\x83\xb5\x06\xa6(033\x83\xe3\x8e;\xf6>\"z\x12\x00>\xf9\xc9\u007f\x9c\x80\xf9d\xed\x1b\xeb\xee\xbb\xef\x04\x00l9\xe9\xa4\xe5\u00cf8\xbc\xac\u0309\t\x04\xf6U\"\xfcD\xdd\xf2\xae\x1d\x18,-&\x86C\xfeb\xec*`jF\x01yt\xe6\xab\xa6o\xba\nBn\xe1e\xb0v\nP\xb2WP\xeb\xccO\xf5=E !P\x18\x8d'\x178\xf51J\u0217\xb5\xa6\xcb0]\x8eA;\xfe\xfdp\x80\xb5a\u042c\x11\xfc \xe2*Z\x05\rN[\x00q\x95n\xdc9\xc1j\xdfb\xe7\xae\x02\x8b+\x05\x00\a\u05be\xe1\xcd\x01\x80)\x18a\x89s\x15\x98\xa7\x13f\xd13\x87\xabH=\x0e\x95\xb8\xd2\x04\x9d{\xa9\"\x10\xc2:\x90\xc8E\x89`G\x03\x98a?)*$4a\r\x8ab\x88\xa8\xf0\u06bcy\xf3W\xe2\xcf\x1c}\xf4\xd1\x130\x9f\xac}c\x1dw\x9c\x97(\x9eq\u05bfy\xa8?\x18}+\xeftA\xac\xaa\xd4rT\x8d\xa3\x95\x85y\fVV\xc2\xff\a\b\vWc'gt\xa7\x19\xc4\xf0\xa6]e\xe8n\xc2\xf1\x12jy\x90e&X);\b\x00 \x15\x18\x94\x19\x8b\xb1rNS_\xc4\x1f\xbfy\x8a\xa1;\x04\x1d\x8e\xe3.1\xfdB\xd4\xc0\x97G\xec\b\x9e\x1e\xe0\xd3@\aB\xaa\x85oC\xf1*\xe0Y\x1az\xe9f\xba{\xa9\r\x0f\xf7\xe7\x0f\x02T\x02e\x19\x87GU\x15lC\x83\x8f;>v\r-@\xdc\x04ri\x99\x19\xaa\x019\xd5O;)xQ!\xa0U\vg=\xfd\x9d\bw\x12\x1e\xdd\u007f\x99\x0ec\xd0e\xac\x1a\x81)B\x90w\xe0\u015dqej\x0f\xa5\xe1\x13\xc9\xccB\xd4us\xa05\xac\x93\xe05\xee?\x13\xab}\x8b\x9d\v\x05\x96\x87\x16\xc4\x02V\xe2#\xf1\xcaCb\xf2\x9eK#\xfd\x87jm\x87\xca)\x80\t\xa4\x18:S\xc8r\r\x1d\xfcW\x1cE\xe9hu2c\xa51Z^\x84\u9bc2X%/\x9a\x835~~\"\x16'\x87\x1ez\xc8\xee\xf8:\x9fz\xea\xe9O\xfb5(e\x92\xa0\x13\nt\x8ab\nn\x90\u0546\x16\xdd\x12\xe3g\u060a\xef\xa1P\xa2,\x15'Py\x17\x8b\x8f?\x80\xc5G\xef\x87\xeet\xcaW\xcb9\vS\f\x83\x84\xd6?\x15c\f\xb2,\xfb\xf1\x04\xcc'k_^J\xb2\x1e\xf4\xd4\\\xf0Z\xf1\x17%S\f\x8c@p\x94c8i\xda\xc4V\xc0\xc6 \x9fW9\xa3\x00\x11\x8c\xfa^\xe2\xc6\xde\xc9\xc8W\xa4H\x94-\x11rC\x05fC,\x1a\xc7H\x9c\xb8W\u0109\xcbF\x8ee\x82 \x90\fP=B\xc7\x10\xdcH\xbc\xe2F\x82\x1b^\x11\xa7\x0e\t\x02\vk\rP\x10lt\xe3\x8b<)5\xaba\x97T\xb8\xf5\xd9~\u007f\"\xa9\xa8\x89V+\x98N\xb0\xf6-<\xdd\xe38\x86\x02KH&\"HHj\xb2\x9a\xd1\xe9*d\xaa\xf1\x1c\xc7\xfeY\xa5\xdeT\xed\aJz\vi\xd6k\xe5\xd3\x02\x01\x8a\xc2ai\xd5`q\xd5\xfaA\x9c.\xc1A\xa13p`\xeb\xfb\rF\x01\x85\x16\x8c2\xf2\xcd\xd88^\x1fv\xb5\xb8\xb9\t\x04b\x1a\x94\x17*0\xadK#C\x89\x1c6'\x87\xca\x10\x8b\x94o\x14W\x95\xb8\x94\xf7S}\xb4\xd2\xcd\x01e3\x99\x88\xa1\u0201(\x9c|\xe2\xe7\x96c\x8f&\xc8B\x9d\x8f\x92\xab\x1c\xd4}\xf3\x95\x15\u00cd\x06\xd8\xfd\xc0\x9d\x18,\xecB\x16\f\xe7\x9c\bL1\x825E\xf9\xd2+\xa5h\u00c6\r\u0634\u9c3f\u0717.\xdcI\x03t\xb2\x00\x00\x8f\xce\xfb\xa0\x8a!\xe0\n\x95Cwz(5\xbb\x9cp\xc2\"P\x9d\x1eDe(\x8c\r\x9ab\x8c!\x98\xa7?\x04\xdc!\xe8\x1eC+\u007f\xaeO\x8d\x8d\xa8\x9cLta`\xc8+\x14\x9c\xf3\x15\xb5\xb1\x16\xc6\x1aX\xe3\x1bm\xb1\x11\uab03\x18\xaf?/\xbf\x1f\xa5\x8e6<\x98\x1eCu\t\xb9\xf6r;\u07d8\x8b\x9e\x1fA\x12I^\u007fn\x8d\x81\x1d\x8d<'Z\xb3i$\xa4\u0588\xd1\xcc*V\xa0\xf1\xc9:\x91\x96\x89\xc3\xe6\x16\xe9\xf3:\x05\x04\xcb>\x0e-R$\xc2\xc1\xf5\x11\xde,J\xcf0f\xa78\xf8VI\xbd\xa1\x97\x10+^bQM\xf5P\xc9Q\a\xba*\xe9@F\xc1\x87\xb3\x82\xe5\x15\x83\xed\xbbGxr~\x84A\xdfxgB+X\xe9\x10\xe6g\x15\x16f\x18\xcb=\xc6j\a\xe8\xe7\x04\x13\x8f\x1aQ1b\x05b\x91\f\v\xc5\x10\x90\xcay\x90\x12\xba\xa7\xd4}\x97\xaed\x95N\\\xe5\f\x95\xb1\xf7\x92WTy\xe2\xc4Ppjf\xc4&\xee\x9a\xd1KE\a5\x14\xa5\xf9\x11\x1e\xe0]\x98\x9aR\xe1\xe4`k\x01\u05b1\xa0\x10\xe8N\x17\u02cf=\x80\x9dw\xdc\f\x8aY\xb8\x10?\xec6\x1a\u052a\xf2\x03\x0e8\x00'\x9d\xb4\xe5;\xaf~\xf5\xbf\xfd2\x00|\xf4\xa3\x1f\xa1}\xe1\x1a\x9eT\xe6\x93\x05\x00\xd8=\xf4\u0235\x00\x18C\x1aJg\xb59\xf5*\xf4\u01c2\xbb\xb3(\xa8\x8b\xa20\xc8\x1a\xc1\x03\xa9C\xac\x8b\x00\x94\x937\xb4\n\xea\x87\xf2\x8c\v\x01\xbb\xc8!W\xbc\xafq\xc0\xd0z\x10\u0395 S\xec+kix\x17Z4-I\x93O\xb6\x1fUW#\x87\xac\xf0\xaa\x898\xaa\x0f\x17=Fbc\xcd\xc2Y\x02F#@\x00\x95\xe5\xe5 \t\t\xb5\xba\xff\x95`\xbf\xb6J\xb0^F3\xbc\x9e]Y\xb8\"!=\x92\xecN\xc7\x00:\x8c\xee\xb4*#\xdd(\x95\xcd5n[\x12\xa9f\xa4\x87\xbc\x9dkh\x16\xbb\n\x83\xe1\x04##X\\5X^\xb1\x18\x8dl\t\xc2\x12\x1f_\xdc\x178\xfe\x9b*\xf0\x1e\ubf3a\xc6\xf7\xa4\xb2\u0265\x1a\xabS*JJ O\xaa\xf0*\x14\xa3\xf1\xbc\x82&\x8c\x9d\x8f<\bV\xaa\xac\u0108\x00g\v\xcc\x1e|\x18\xd6o\xfc9\xc0\x19T\u04cf\xa8\x94\vc\x9d\xbf0,B\xe2\xa9\x16\xf2a\xd1\xcez\xa7\x0f\x82\x83\x83\xf5^\xe7#\x83bP\xc0\x0e-z$\u0202\u06d2\x18T\u0561\x95\xd2B \xe9\xc0\u008a\x84\x01\x14\t\xb4\xb8\xaf8U\xc7Ws*\x84/\u0107U\x14\x82\xd1\xc0\x86\xa9R\xcf\u04fbh\xa6dm\xe0\x9d]\b\x9c\x96\x92r(\x9b|\x0ep&\x04)X?0\xe3\x8aP\xc9Z\x01Y\a\x8a\xa3\xed\x85\xff?\a\xc1\xd0\tL\x11\x86glh\u0205\xaf\x11\x01\u00d1\xc3\xea\x8a\xc5j\xdfb0\xb0\xe8\x0f\xfc\u07d7W\r\x16\x96\r\x96V\f\x86#\ak|pC\u007f\xe00\xbf\xe0\xc7\xde\x17\x17\v\xec\xda=\u0136\x9d}\xcc/\x8e0\x18\x85\xdb\xe8[X#\xd5LVt\u038a\xbd\x8exR\xb1\xc90VR\xb1\x8f\xd9\xc1DM6\x85\xca[q\u5552\xf9\x04#\xd5ap\xaeJ\xc30j&8\xa5\xf9$TQ/\xacB\xb0v\xbc\xad\xf0E\x89\xe3B\x9c\xfcd\x12d\x1c>'\xe1q\u0692\xc2\x0f\x15:3\x1c\bB\x89q\\\xe2\xb5C\xe4C\x9b\x8b\x95\x05 \x19\xdb/\x86\xab0\u5d27\xff\xe1\r\x1b6\xe0\x94S\xb6\xfe\xc3\x15W\xbc\xf1\x06\x00\xf8\x9b\xbf\xf9k\u0697\xae\xdfIe>Y\xf8\xf1\xbd\xf7\xe1\xa4go\xc6\t[\x9e;\xf5\xd5;\x1f;\xf9\x87\u07f8\x01K\xf3\xbb\u041b\x9e\t@\xee\xa7\xe4\x9c1\x98y\xd6&\xcc\x1c\xbc1|\u0429\x96r\x1f\xf4n\x151\x13)W\xeb`\x04@\x16\xe4w\u05abc\x14\xfb\xc6\x15\xe9\xc0\x8f:\a%\xc0\xb4\x06:\xca\x03\x8e\x8bMX\xc4\x01%*/0W\xfaySP(\x04\xa1DPL0\x93o\n\xc6)?[m>\xce:\xf4\x97-h\xca!\xcb\x18D\xde\x1f\x06\xca\xfbs\b\xf9\xd8;(\x8b(\x87p\x0e\x15\x9d\x13\x1eC\xc3\b\xb7\xa4\xfeK\xccw(\u04da\n#X\xb5\xbeJ\xcc\xc3\tB\xc2\xc4g\xa1\x01\x03\a3\x12\xac\x8c\b\xc5\u040f\x9cKR\x95\x1b'\xc8\x14a\xaa\xab\xa0\xd97\xf7V\xfa\x06\xab}\x13\xaa2\x82\xb1\xe15\xabq\xedR6n)\xf5+\x97\xd4i\x91\u01a8\xa1\xb4/PU\xbc\xd4H\xf2\xa9\xf2[\x91\x84;\x8c\xadTb\x99~+n\b\xd1@\x8b\t\u03b0\xaf\xa9-\xfb\r\xbcv\x18\xf3\x958\x91@IP\xef\xc4SS\xb0\xe8\x15\x00:X\x05\x1b'\xb0\xb1!\x90\x98l\xc5S\x8dw_\xd4\xe8\xce\xccy\x96\xc9\x1aXk1\x1a\xf6\u02e6\xa7\b\x9c\u059aO=\xf5y\x0f\\y\xe5\x15\xff7\x11\x15\xef~\xf7\xbb\xb2+\xaf\xbc\xaa\x98\x80\xf9d\xed\x13\xeb\xd1G\x1f\xc6\xf7\xbf\u007f#Nz\xf6f\x00\xc0*0\xfd\xc5O\xfcw|\xff+_\xf4MIq\xa5`W\x9c\x03\xeb\x1c3\x87\x1e\r5\xb5\x0e\xa6X\xf5\x95.\xb3?\xaa\x82@*\x83\x90*\xe9\x8e\xc28X\xe7+(f@2\a\xd1\x02\t\xc1\x13\xba\xa3||\x99V\x81&A\xa0W\xa2\x02\xa5\xba\xea\xa5\xd4LK\xe2\xc2\xe8\xabp0\u01d3|#\xc5GJn\xdc)@\x8a\xe8#\x13\xaa\xf3U\x83\xfe\x12\x83f3?5\xc8\x02h\x80\x11\x142\xe45\xe9\xe5m\x05`)\u00c4\xb9\n\xa2\xaf5\xfc\xaa\xb6\x00\xacu\x81\x86\x16,\xf7-V\xad\x03\xeb\u0434c\x81c`\xa4\b#\x0eC;V`D`FR#\x92)\xf8\xc7\x14\x00\x86}\vf\x82\xb5\x02\x13\xaai\x8bJy\xc3A@\xed\x15-R\u6596`\x1cOP\"\xed\xa3\xa2\x8d\xac\xcfR\xcd\x14\xab\xe8\x98e\x1a\xfdf\x12\x95J\xbd\xf1\xd9\xcc\fM\xfe+\x00\xb7\x8fi\xe3\xa4Z'\x90\xadxwo\xf8\xe6\xca\x17=>\xe4\xe8\x89n\x1d\xe0\x1cC3\x82\xaa(<\u007f\xf8M\xb3\x90\xa81\x0f\x1e-I\xaf\x85\xc2\xedw\xbb=(\x02\x06K\xf30E\x81b\u0507\rMO\xa5\x94Xk\xe9\xb4\xd3N\u0165\x97\xbe\xf4\x1f\x8f?~\u02dd\x00\xf0\xf6\xb7\xbf\u077c\xef}\xef\xc7\x04\xcc'k\x9fXw\xdf}\x17^\xf6\xb2_\x8a\xbcs\xefw\xff\xe0\x0f\xfe\xe8S\x1f\xbb\x1a;\x9fx\x04\xdd\xee4\x9cu\xa5\xc1\x96\x19\r0u\u0421\x98;j\v\x06#\v\xed\x1c\xf2L\xc3\x19\x83\x1dw\u07c6'\xee\xba\x15B\x8cl\xfa\x00p\xd6\x05\xe7=@\xf5\xa0\xf2.\xa6f\xa6\u041b\x9a\x02e30N\x83\x95F\xa65\xa8\x97Au\xbd\x91\x94\xb0@LQU\xf6\xc2U\x05(\x95\x9a\xa2\xe4Y\xa3a\x1e\x04\xcc\x0eJ\x92\xb0\x8b8`\x14mX\x15 \xdaW\xf2\xb6\xec\x82\xf91\xf6\xc1R\x01\xce\b\xdd\\{\xe3\x1a.\x94\xb2\a>\xfb\xe71w\xe4\xf1\x18\fG`\x00\x86\x18\xa3\x95%\xdc\xf7\xc3\xef\xe1\x81\xef]\x0f;\x1a@uz`\xa5\xc1:\x87\xd29T\x96C\xe5\x1ddy\a\u0719\x02\xeb.\x14w\xa0\x14\xa3;5\x8d\x83\x8f<\x06S\a\x1d\x84\xa9u\ab\xf6Y\x9b\xc0*\x83s~\xf8\xc3k\x83\xebcIH\xc0:\x0e\x15Q\xe0\xb4]\x90\x1aV\xc7\xe8\xf0\xe3\x04\f\x01\x8c\"\xd7\x1e\xa4n\x10A\xd1\x17,,\x10d\x16\xe8u3Tv\xb2\x94\x1a\xf0y^\xb9\xdcT\xa8\x1a)\x97d\x80'}\x88V0\x18X\xac\x0e,V\xfb\x06\xc3\xc2\x05\xef\x9a \xcfVH@U\xca\u01a3$I=\xf5\xb1\xdb\x16\x8a\"\xfdy\xa97.\xd3a\x9dd\x8c\x145\xa3\x17Jm\x1a\xc2Tn\xec_\x06\xb9h\t\xe2T}\x0f\x8d\xe9Ij\xd9\x10R)\"S\xa5\vo\xfen\x93\xdbI\xbd\xc8%U\u0144!3\xcd@\x0e?\xbe/\xce\xc7\rJ\xe8$\xc7\u03c2\t\x83\xc4q\xaa\x94\x90\xbew\u1e72Bwj\x06\x18\xae\xe2'\xd7\xfd\x1d\x1e\xfd\xc9\xf7a\xc5\xc1\x98Q\b\xe6Vp\xceI\xaf\xd7\u034e;\xeeXw\xc9%\x17\xbf\x9b\x88\u6bff\xfe\xf3|\xe1\x85\x17\xbbo|\xe3kx\xc1\v\u039d\x80\xf9d=\xbd+\x1d\xc1\x17\x91\xb9\xff\xf2_>\xf0\xc1\xab\xaf\xfe\xf8ko\xbe\xf9\x87%\x8a8k\xabtwkp\xe0\xe6\x13q\xc4\xff\xf6R\xe8N\xd7\u02f5\x04\xb0C\x03\xeb4\xa66\x1e\x8b\r\xc7<\x01[\f\xfdE`\n\xd8b\b;\x1a\u0099\x11\xccR\x1f\xabf\x04gF\xb0\xa3\x01l1\x808\x03\xd69\ue7daC65\x8dC\x8f?\x15']r9\xd6\x1fz\x04\u020c\x82\xe1V<27\x89\x00jbQ\xa2\u0328\xa0E\x82\xb6:\x82*;It\U00061135\x9e\xb6\x98\x17\x82\x13\x8d\x19E\xd0\xe29[AU\u0757\x8d3\xa9\xc2\x0flc0&V\xd1\xe2\x04\x8b\xcb\x06\xbb\x17F\x18\x1a\a\xe7\u01bd\xbcSO\x97\x1a\xb2\xb9:pS\x92\xe99\xaec\x97\xba\x87n\x82\x92\xb4\x86\x85oi\xbf[\xfe\x117\x14.i#/1\x8c\x19\xc6u\x1bB*\xa5\x9a\x91\xf6\xa2\x1a\xad\x12\x03\x92c\x88D\u4f9aN\xc2$)\x9b\xdf\xe24\x1c\xf2d\xcb'\xc2\xfe}\xd1\u481c\x9f\xd8u\x89\xad\xb2\n\xdd\v#\xfe\xcb5\xf9\u007f\xaa\x14,L\nyo\x1an\xb0\x8c\x9f|\xe1\xefq\xdfw\xbf\xe4\xfb.\xc5\b\x90\xe0a.\"D\xa0\x13N8\x01/x\xc1\v\xfe\xf2%/\xb9\xf4\xf3\x00p\xf1\xc5/v\x1f\xff\xf8\xc7\xf69 \x9f\x80\xf93\x14\xc8/\xbd\xf4\xa5\n\x80\x15\x91\r\xef\u007f\xff\xfb\xae\xf9\xdc\u7bbd\xf0\x96[n\xad\x95\x83Q\x1b\xedL\x81\xe9\x83\x0e\xc5\xe6\v_\x8d\xf5\u01dc\x8cbe9\xd0\b\x04\xe7,Hi\x1cr\xd2\xd9\xd8p\xfc\xa9!\xb1\xd7W\xb4\xce\x14a\xaar\x003XE\xb1\xba\x8cbe\x01\xab\xbb\x1e\xc7\xf2\xf6\a1\xd8\xfd\x04\x9c-\xc0Y\x17*\x9f\x82\xcb7`q\x95\xd1\xe9\x17\xc8U2\xf5\u01c9\xa7GI\xe2F\xf8\x960\xd4S9,R\xe0\xaaG\xc6b8r\xe8\x0f\x9cW\u007f8\xa0\x13=;J\v\x19\x1f\xf8\u03240\xb2\n\xf3K\x0e#kq\x00\x1cz\x04\xe8tz\xb2\u00b32->r\xe5\xde\x0124e\x9d`a\xa9\xc0\xce\xf9\x11\x8cI%\x84\x187xI\xfe#\x86\x05c\xac9\xd9tkL\x01\xbce\x8b\x8b\xc8\xc8\xd5w\xa9\xa1\x1cI\xff,\xe9\x91D\xcf]\x01\xb8\x00\xcd,\xd0D\x96\x12y\xfc\x12\xf4\x03\x80\x97Fb\xb5\xe7\x13D)\xb0V\x10\xad!PX\x19\x12F\xf3\x0e\xbd\x91A\xb7\xe3\xd0\xc9\x14\xb4\x0e\xca\x18\xaa&2]h\x86:\v\x14\xd6z9\x9c\x13\fG\x0eK+\x06\xc6:\x9f'\xd9B%4\xc1\xb9\x1ct\xaaH\xe3\xf2\xb9q\x02\x88\x92\x00\x9c$X\x8b\x14\xc4S~\xba\xd9xL\x8c\xcb\xca\xe9Kj\xfcn\xba\xebPL\xbb\xa7\x8a\x87\xa7j\xac\x1e\xa1\x01Zj\xc8\xc3mH\xc2\x1e\x11\xd5\x19\xa3\x9a+e\x83M\x8a\x8b\u00ddH\xf0\xed\xc9\x19\xd0a\x1a\u05c9\xf2Q\x85\xc4\xc1\x06\x82\xc0`\xaf%\x0f\x12X\xa1\xf43\x18g\x13|\xb9\x9eu{\x18-\xed\xc6\x1d\xd7\x06 \x17\x17r=\x87\xe5\xfb+\x00fgg\xf1\xdc\xe7\xfe\xfc\xb6\xb7\xbd\xed\xadW\xfe\xe9\x9f\xfe\x19\x00\xe0?\xfc\x87\xdf\xdeg\x81|\x02\xe6\u03e0u\xcd5\u007f\x9fR+\a\xbf\xef}\u007f\x10\x80\xfc\xa6\xda%\xc5\xca'\x01\x883\u041d9l\xbe\xf0U8\xfa\xfc_\x02)\r7\x1a\x822\x9f2\xcc\xc6V\xa92\xd6\xc1\x9aA96^\xbb>%\x89\x14\x82\x97\b\xeaN\x17\xb3\x87\x1c\xdd\x18\xfcqp\u01a0\xb0\x84\xa5\x15\u03c1\xf6z\xde\xcat\fD\x02\xc00\x01\xc6x\xe0\x1e\x15\x1eH\x87A\xc3\x1dKiV\b\x8a\b\xcf\xdfZ\xf2&_D\xec7%\xad\x81\\A\xb1\x0e\t\b\x04\xe3\bK\xcb\x05VV\t\x99fd\xc1\x0f[\xc5\xd0\xdf \xf4\xb1\xce\u06fd\x8e\x02\x95\x02\x04\x90\x0f\xd5z\x15\xa9\xd6R\x9d\x02\x15\xe8\xb4\xf0\r\xcdP\x89FQ\x9c\x84f\xa3jDRjnE\xf5)\x9a`f\x85\x10\x9b\u059cl\xad)rP\x81x\xadzO\xe4\x83\u008d\xff\x8f\x15\xb74@\xbf\xad!\xba\xb71\x9b\x90p\xa5D\xa0)\x80\x94\x00V\xa8|n\x12U;>\x85\xd9\x039G\u03df\xf0\xb9\f=\x14'\x9e\x03\xcf;9\x06\xbb\x9e\xc0\x1d\xd7}\x1c\x0f~\xefKeM_\fW}\x97\x84|\x91\xd2\xe9tp\xdey\xe7\xe25\xafy\xcd;\x8e<\xf2\xa8[\x01\xe0w~\xe7\xbd\xf4\u05b7\xfe\xef\xb2/_\xe3\x130\u007f\x06\xac[n\xb9\x19\xd7^{m\t'\u007f\xfc\xc7\u007f\xf4;_\xfc\xe2\xf5\x17\xdc|\xf3\xcd5 \xf71q\n\xceZ\xa8n\x0f\xc7\\\xfcj\x1c\u007f\xe9\x1b@*\x87\x19\xae\x86\x80g\xf1A\x12\x91\xdaH\x06y\xe0\xc4\xfb\x83K\x92\xba#i\x9b,\xd2\x16\xa6\xfcW\x1c\xc0\x11x\x89\x1a\x93\xaf\xa0\x17\xfb\x0eC\v\xf4:\x82,\xf3#\xf9)7\xed\xac\xa00\x0e\xfd\x81E\u007f\xe8\x82D/\x02\x0e'r\xba`\x9b\u01de\x04\x96\x8c\xe1Dy)\x89\xd6\x10\xc5A\x1aWy~H\xa2\xcb\x1e\x8e\x1c\x86C_\x067)\x13)'$i\\\x14\xd2L\x91\x93:s\xd1`\x90\xbd,\x12\xa8\x95\xb2\x8d\x1c\x8e\x9a\u0084\x12:%275uH\xa3\ua9b1\f\xb9\x06E\x938coU\xd1\xd4\x00\x00 \x00IDAT\xa5\x96\xb9\x14'\xad8\xa1`\xa8QqK\xbd\xc0\xde\xdb$\rS\xbb;{\xb5\xefx\u007ft\x8d`\xc9+1\t\xaa2H#\n\ue4e0\xd0\xecDp\\\f'P.Mi\xa0\xb3\fYg\n\x8b\x0f\u0789\xdb?\xf71'\x02\xd1\xcf]u\xd5o\xfc\xee]w\xdd\u0163\xd1(9\xd52\x98\x19\xd6\x14\u0226f\xb0\xf5\x97\u07c2\xe7\xbd\xee\xdf\xc3\xe9\x0eVvn\ai\r\xb1\xa6\xd2A\xd7xP\n\u0578\xb7\"\x8d\xbe\xe1\xa5\xc4\u03c6\xe0]\x17\xc2'B\xb5\x1e\xbd5@R\x1e\xab)N\xc7P\xacJ=\xd8G\x85\x82\xef|Q\xa5E\xce\x00\x9d\xc7n-%\x13\x8a*T\xe7\x1a\xa45\xa0\x14\x88t\u0253\x97\x0f?\x04B\xb7Z\x1f\xc6\xd9\xf0HE\u0101\x95\xb4c\x17\xef3\r\x9b\x93\xf1&\x1e\xa8\x85zH&dk\u07d2jH\xa7tMlJ\xfa\x12\x15\n% \\\x01r\xcd\xf0\xb2\xe2\xcb+\xcd_Y\xd1S\xfaC\t\x8dRo\xa26\x00\xbaI\xfb\xb4\x1f6\xea\x89MkT\xe1\u9a40\xe1\a\xc6r\xf6T\xcb\xc8*82\u07bf'd\x8d\x86\xb8W\x18\x01\n\xe7S\x83@\xc1\xfe\x98*k`!B\xd6\xed\x82l\x81\a\xbeu\x1d\xee\xba\xe1\x1f\xb1\xf0\xf0O\xa1t\x0e\x10\xf9\xc1 3\x02AP\x14\x85LMO\xd1\xc5\x17\xbf\x10o|\xe3\x15\xef\xbf\u4497\xfc\a\x00\xb8\xf5\u059b\xf5s\x9f\xfb<\xf3\xb3r\xadO\xc0|?_\x11\xc8\x01\xe0\x83\x1f\xfc\xafo\xbe\xf1\xc6\x1b\x8f\u0736m[\xedx\u034aa\n\x83\xee\xf4\x1cN\xbf\xfcmx\xdek\xdf\t\u05dd\xc2\xca\xe2\"T\xa7\x9b\\t\xae2\x92J\bQ\x0f\x8c\x14\x9aR\f\xd2\x1a\u0119\xbf<\x03\x90;k \xc6@|\x84{Y\x95\xc7x\xb8\xb1+>\x98g\x11\xd7K\xdd\nP\x13\xb8\xf3\x1dN_\x89+\rRY\xa0U\x94\x0f\x9d\xe6\xa4\u04a6\u0291\xd6S%\xd4Z5\x8a\xf8\tG)\xfd_\xfc\xe9\xc3k\xc5)\x89\xabk\x80T\x1aRD\ud217\x0e\u05d0\xb4P!@5\x0f\x934\x16+\x86\x84\xc6h\x97&\xa5CM\xfe=\x8d\x91\xe3\xea1D.\x1c\xc9@O\xeb\xd0\xd1^\x165\x03\xa3k\xdc~rPI\x8b\x80\x12\xed=\x90k\x06r\xae\xf8z\xa5\x18\xb0\n \xeb\xa78\x01(\x12\x14\x16\x18\x05-y\x15:\xc5a(\u0281\x88\x91O\xf50X\u0609\xfb\xbe\xfci\xdc\xf7\x8d\xcfa\xb0\xb8\v*\xcb\x01\x10\x8c\x19z;\nq(\x8aBz\xdd.\xbd\xf0\xa2\x8bp\xe5\x95W\xfe\xe1%\x97\xbc\xf8\u075e\x9a\xfc\xc1\xcf\x14\x90O\xc0\xfc\x19\xb4D\xe4\xc8_\xfe\xe5W\xbd\xe2\xe1\x87\x1fFEM\xfa)8\xb1\x16Y\xa7\x8b3.\u007f\x1b\u03ba\xf2=pY\a\v\x8bK`\xad\xa1:]\x00\x80eU\x19O\xa5\xf3\x87AM\xe0\x91@\x81\x02\x9dA\xac|\xe5\x1a~\x9e\xadop\x8a5\xc1\xf9\xceU!\xbd\xa0\xe4v\x83\xe1S\n\xe0\xc9\xc6C\xb5\xe0\xe5\x00\x82\xac\x00f(\xed\x81\\\x02\x1fZ\xa3\x02D\xea`\x1a\x13s\x9a\x00\x19\x833b\xa3/\xda\xc1J\x04?)O\x02\xe0\u069eR\x8b\xe1\xack\xb2\u06c1\x1c\xa8\xf3\xdbq\u04e1\x96\xffo%\xa2\x1b\x8d\u0438\v\xd5F\xec\x13\n\x05i\xa5\x9fV\xe1\xa8O\xdf\xd3\xf8Sjm\\\x8a\x8c?4\xda\x03aN\xb5\x83Ju\xa6\xd1\xe4e\xa3\xa9\xab\xa2\x04? &\x86\x8d\xea*r(,P\u0113Yz\xe2\x01\x00\xe7@\xa4\xa0\xf2\x0e\x96\x1e\xbb\x1fw|\xeecx\xf8\xc6/\xc1\x16#\xb0\u03bd\xe3\xa45\xb0\xa3!\b\x0e\xc6Z\xbbn\xdd:u\xfe\xf9\xe7\xe2\xcdo~\xf3\u007f\xbc\xe0\x82\x8b~\x1f\x00>\xfc\xe1\xff\x87\xb6n=\xd5\xfc\xac]\xe3\x130\u07cf\xd7O~r\x1b\xb6l9\x19\x00\xf0\xf1\x8f\u007f\uc94f>\xfa\xe81\xbbv\xed\xae\xae+\xf2\xb2\fq\x82\x93.|9\xcex\xfd;\xa0z\x1d\xac\xce/\x87\xa9z\x02\xe9\xcc\xdb\xd0f\xc6s\xec\xc1\xb1NP)\t(P#>E\xa0\xb2\xc0\xa52b\xcc\x03.g\f\xe8,T\xe5.\x96\xc6U\xa3TB|@\xb4aM\xa5\xe5TQ0\x15~q\x05\x86\xf0\xee}~s\t\u0380$e\x80p\x1a6\r4|\xc8\xd3L\xd14\xe6>z\u03d0\x94\xdar\x92\xca\u0696\xc6\xd0+\x81?\xaeZ\xbe\xf5*=\x89\x9a\xab=\xb7\xc8l$\xf6\xba2N\xba\x97\xda\xf6Fu^r\xe1L\x15\xa5B\x95\u007fw)gL\xbcV\x9ae\xb34\xec\n\xdah\x95t\x83l&\xf7\xd5\x1fI\xf3w\tQh\x1a7\x81\xb4\x1a\x8f\xcb\x06\x0f{\x0e`\x0e\u0170\x81n1\x8e`\x85\u0293\x0f#\x89\x00\x14\a\xad3\xa8N\x0f;\xee\xfc\x01\xee\xf8\xa7\x0f\xe3\xb1\x1f}\xcfG\xc7\xe9\f\x80O`\xb2f\b\x88\x85)\n\u0670\xe1 u\xdai\xa7\xed~\xfd\xeb_\xff\x9f.\xb8\xe0\xa2\xf7\x03\xc0\xaf\xfd\xdaki\xe3\xc6\xc3\xe4g\xf1z\x9f\x80\xf9~\xbc\xb6l9\x19\"BD$\xb7\xdd\xf6\xe33\a\x83!Dd\b\xa0\x13/0g-\x0e:\xfc(<\xffW\u078c\xe9\x03\xd7aq\xf7\nD$\xf0\x92\xc1\xc7C)\x90RP\xd1\x1e\x15i2=UG\xf8hO\x1a*\xeb\x18\xd2SzgST\x97\x04g\xc2\x04\x14\xa9\xbc0\xd3[n\f\xcd4\xea\xbc4\u0772TT8)\x15\x18\xe2Z@\xb1\x95\x17\xa8\xa8\x8d\x84d\xaem$^)!-\xdcx\x12\xa9W\xbb\x91\xe4n\xa4Q\xa9\u05ea\xda \x17\x045~!\xcd\x1aM9!\x97\xe3,G\u0273\n%tJC\u007f!\x82:\x1e\xc8\x18\xef\\\u06948\xa9\xe7\x12Q\v\u04a4\\uc*\xbe\xf93\xe5\x8f&\xf4\xcd8\xcd\xef\r\x00\xd2\xe0\x8a\xa6\x99\x155\xeaWj\xdb\\J\x95K]iRe`V\u07c8\x13\xb2\xad1O{\x00\xdbT&)mO{|@u\xaf\x8bQ\x97\xccsz\xa7\xe5f\xe2\xc1Z%_\x12(\x13\xc5\xde\xf91>O'\x02#\x04\x03\x05C\x0e\xa2t\xb0V\xf0fl\xf1\xa4E\x8a\x91\xe7=\xd8a\x1f\xf7}\xf5\xb3\xb8\xe3\u068fa\xf7\xc3?\x85\xd2\x1d\u007f\xaa\n[\x89\xb5\x8583 \u034c\x13O>\t\xe7\x9cs\xceg\xde\xf3\x9ew\xfd\x9f\x87\x1ez\xf8\xfd\x00\xf0\xaew\xfd6\x9d}\xf6Yr\u9957\xfd\xcc^\xef\x130\u07cf\xd7\xfd\xf7\xdfO\x00\xa4(\x86'\x0e\x87\u00e3\x17\x17\x17\xc1\xccdm\xf4iv\xc8r\x8d\u00f7\x9c\x8a|z\x16\v\xfd\x81?\xc6\x06\xdbP'M\x1e\xb5\x91\x05\xb9V\xc1\xab\x02\xa8\xc7\b\x1d\x97\xfc\xbcC9\x86/\xa5\xa7t%\xed\xa3\xa6\xa1\x9f\xa4\xbc\xb0\x946\"13\xa2\x04\xb4\xf8\bc\xd2\x10\u0575t\x94\xec\x0e\u049c%O\xe2\u07e9^V\xd6\xce H(\x8b\xb5\baj\x96\xe4q\x8a\xb2\xac\xdd\u00c8y\xed%L\x9e{\x94(rL\u04a31\xfb\x15\xa0\x95%\xa9\xfb\xbd4\x8a\u548f\x96\xd6B\x1a\x82q\x9a\xa5\xc9\xe2\xd4\xda\xce\r\x11P\xaa\x9e\xe1&M\x13$\x8b\xb1\x1a\xd7T\x9d\xb9\x84\xaasX\xf4\xcd1a,_H`\x89!*\x03\x87f5\xfb@(\x88#\xa8L#\u02fbXz\xe2A\xdc\xfd\x85kp\xff7\xfe\t\x83\xa5y\xa8\xac[\xebS8;\x92b\u0627^7\xc7\x19g\x9c\x81\xcb.\xbb\xec#o}\xeb\u06ee\xf8\xe0\a\xff\x02\x17]t\xa1\xfa\xe7\u007f\xbe\xc1\x12\x91\xfc\xac_\xef\x130\u07cf\u05ed\xb7\xde\n\x00\xf8\xeew\xbf3\u06b6\xed\t\x93$\x8c\xfb\x0f\xb9\x00y\xa7\x87\xf5\a\x1f\x8a,Wp\xcb\x16\xb6\xf4\x84\x1e\xbf\xc0\xc7*\xb8\xe4\xf8.i\u015ap\xc4\x12\xc0\x9dR\x1e=\x863KmN\xbd<-\xd4F\xbe\xa9Fs\x8f\xc9\xff\"\xf7\x1a\xdd\fE\xa4\x1a3O\xe5\x13\x89\x96\xbc\xae\x90\xa9N\r\t\x05_\xca\xdc\u028a|\u0301\xb0\xd1\xe0ly\x81\xa8\x85\x18\x1a\x93\"6\x90\xb9m\xf0\xa6\xed\xd0@\x18\xf7\xe8*\xc1vM\xe2\x1a5#.iT\xeac-\x80\x96;\u07db\u0405\x92\xcfN\t2\x04d\u0283\xb9&oM\x1b\u007fVQ\xf5Yt$p\xe2-~c\x18\x92\x84\xe9Md\xfe\xf5c&(\ue049Q\xf4W\xf0\xc8M_\u015d\xd7^\x8dm\xb7\xdf\bg\r\x98\xb3*l\x1a\x04g\x8d\f\a\xabt\xf0\x86\x83p\xca)[\x17.\xbb\xec\x17\xdf\xfe\xa67\xbd\xe5o\x01\xe0O\xfe\u43f2w\xbe\xf3\xb7\v\"\xda/\xae\xf7\t\x98\xef\xc7\ub847\x1e\x02\x00\xdc~\xfb\x1d\xb4\xb8\xb8T\xe5D\xa6\xd8\xe9\x04\x9c\xe5\xc1\a\xc4WK.a4\xdcZ\xc7p\xaa\x83\xebZ\xd7\xc3x\x85G5>\xb5f\xce\x1a\x80\xbef\xe9\x9aR\xda\x01\xa0]\xf2\u007fI<\xa9\xaf\xf6\x1458\xe0D_\xbd'\xc1s\x8b\x11UIaP;\xbe\xd5\x14\x1fi\x1a\x8fT\xd5p\n\xacT/\xe21\xa6\xf2\xdc\xd3\xc6\u0664J\xd2j\xba\xe1\u007f\x024\x95#\xed\xef\u025e\xda\a\xa9\x8c\xb3mci\xda\xd8R\vM\xa3\u0607HDJ\xc5\x03\xbd #\xf2\xa1\x12a\xe0G U\xe0r\x8d\u0593\xe4\xc4%Py\a:?\x00\xa6\xbf\x84\x9dw\u078c{\xbe\xf4I<\xf0\x8d\xcfbe\xc7c`\x95y\u014a\xf3\u039d\x9e\xa6rR\x8c\x86t\xc4\xe1\x9bp\xce9g\xcf_y\xe5\x1b_~\xdey\x17|\r\x00~\xef\xf7~\x976o\xde\\\xecO\xd7\xfb\x04\xcc\xf7\xe3\xd5\xef\x0f\x00\x00\xcb\xcb+0\u01b46\x02\xfb\xab\xcb\u8bec\x04\x06\x84a}\xf9\\S-H;\x05\\\a\xa5\xe4\xfbM\u0395\u05a8\xea\xeb\xf5jThP\"[\xab\x98XnX\x8dx'\x01\x81\xb3\u0271\xdf5C\u0712Z85\x9cj\xf3\v\xa7\x96J;\xf9y\xda\x03\r\x9d\xe2\x0e\xed\x85\xf2Hi\x8a6\x00LM\xb6\xa8\xc1\xd9K\xe3\xf5\x96\xc6\f}\xbbU@\x02\xcc2\x0e\xf6m?\x9b\x9a;\x8eY\xd36\xfe\xa4\x96\u075b \xa1\n\xf7i@\xf1\xb8@\x94\xf8\xd3\v` q\x0e\xcd[\n\xa3jZ\xa7Q\x81\x00!\x9f\x9e\x83\xd8\x02\xbb\xef\xbd\r\xf7~\xed3\xb8\xe7\x8b\xd7`\xe1\xe1{\x82\x0f\x0e{7c[\xf8\x01\xb8\x80\xff\xa6\x18\xd2a\x87m\xc4%\x97\\\xfc\xf0o\xfe\xe6Uo8\xe5\x94S\xbf\x06\x00g\x9f}6\x1dq\xc4\x11\xf2\xcaW\xfe2&`>Y?\x13kzz\x1a\x00\xb0n\xdd\x01\xd0ZS\x1b\x98[\x01\x1e\xbb\xfb6<\xfb\xdc_\x84\xca2\xc0\x8cJ\xa0qu\xf4+\x8bT'-<\xed\x1eh\x81\xf1\n\x93BVg2Q\x1a\xf9\xe1d#`\xd4\xef75dt\xf0\xde\x1c\xa4\xe3\b~x\xbc\x8d*\xb8\x1cj\xa2\x06O,\xb4f\xb5\xdd\x046\xa0\xddKdOTC:H\xda\xe4\xe2\xa9\xed\xa4\u04e0^\xa2\x94\x9dZ\xee\xdf5*zY\u3157f%\x1e\x01\xbf\xa5\xe1K\r\u03bby;{z\xee\x94\xd0m\x8a\xbc\u02e1\xa2\x94/\xf7wl\xc5W\xe2&\x98_9T\x8a\x14'\xa8\xbd\xd7\x11\u01f9\xd3\x05\xeb\f\xbb\xef\xbf\x13\x0f~\xe3\x9f\xf0\xd3/}\x02;\xef\xb9\r\xce\x14\t3\xe7\x1b\xf7\xc4\u02a3\xb83B\x04\u06b2\xe5D\x9c~\xfa\xe9\x9f\xfd\u0407>\xf8V\xa2\xfc!\x00x\xc5+^N\xaf}\xed\xe5\xf2\xf2\x97\xff\xd2~w\xbdO\xc0|?^g\x9du&>\xf0\x01\xe0E/\xba\xa4\xf3\x0f\xff\xf0?r\x9f\xe03~Y\xfe\xf0\xf3\xff\x88\xe7\\\xfcj\xac?~\v\x86\xa3\x11\x8ci\ua269\x9e\u053e\x06pK\xa3Z\x17\xa9Q\xcc\xe9\xa19\x0e\x1d6\xc2\x1a*q\x9f\xa2\xa4\"\x0e\xa0j\xa5Q\x95\xa2r\x1etX\xeb\u030f\xb1\xc6\xdfZ\x15\xf6\xbfF\f\xb2'*\xa9\xf5\xb4\xd22h\x93\x16\xff\xae\x85\xedi\xbb\u03f1\xf9$Z\x9b\xc7\x1es\x14h>\xb6\xa4\x1a\x8eT\x9a\uc067\xdf\x13\x8d\x1e\xe9\x16\u037e\x12\xd7\fd\u025b\xee\xc4\x0f\xf9\xd8p\x92\xaa;$W\x03K.\x8c\xe9#PcJi\xa8\xbc\x8b\xfe\xeem\xb8\xef\xeb\x9f\xc5=_\xbc\x06\xdbn\xfb\x1e\u0330\xdf\xf2\xfa\x87\xe9_\x888k\xe9\xc0\x03\xd7\xd3\xc9'\x9f\x8c\xf3\xcf?\xef\xaf\xdf\xfd\xee\xf7\xbe\x93\x88\x16\x01\xe0\x8f\xff\xf8\xfdt\xee\xb9\xe7\xca\x19g\x9c\xb5_^\xef4\x81\xbc\xfdw\xddz\xeb\x0f\xe9\xb9\xcf=EDD\xbf\xf0\x85\x17}\xfe\xc6\x1b\xbf\u007f\xd1\xc2\xc2B\x01 k\xfe\xec9\xaf\xfb?\xf0\xa2w}\x00\xab\x05\xb0k~\x11&\t@p\xad\xf9\xedT\x06\u8d8dl73}\u04df+\x81<\x06\u0460R\u03a4\xe0\xe5\x12\x00\x8c`\xdeVIK\x8b\xeap\f@\xf1\xaf\xb4_\xc5\xda \xb9\xa7\n\xbc\xf5\xff\xa5\xae\xf2\xc0\x1a\x8f3\xd5~G\xa0N)\x13Yc\xd3L)\x1d\xfaW<^iy({\xba\x8dh\xa6\x16\u04d5\xe2\xfb\xc0I\u04d9#\x80\aKZ\x1d\xee\xa0pQ^X\xf5`\u01ac\u0723\xc6'\xdc9\xb3\x02k\r\xcer\x10\x80\xc7~\xf0u\xfc\xe4\xd3\u007f\x8d\a\xbf\xfd\x05\f\x97\xe6[@\xb5\xbcv\x84\x92\v\xcf\u060f\xe0w\x15\xa1\u02c4\x9c\xa3\xb4P0r\xc0\xc8\tFNj@.\xd2\xdc\xc0\xc2ILk\xe4\xbd\x19\xe8\xde\x14\x88\b\x8b\x0f\u078d\x9b>\xfc>|\xed}W\xe1\xee/^\xe3\x81|,\xfeNy\x97O\u71cb\x0e\x1e\x9dLmj\xf6\xd6\x03L\xf5\n\xdc\x04N\xdco\x9cT\xdbW\x89\xc2\xe8=|'Ck\r\u055d\x02 \x18,\xec\u0093w\u0742\a\xbe\xfd\x05\x89\xc7\u007f\xf4]\xac>\xf9\xc4\x1a\xaf?\x05\x1fr\xb2\xb6\x18\xb9u\xeb\xd7g\xc7<\xfb\xd9\u063c\xf9\u87dey\xe6\xf3\xff\xdb\xdb\xdf\xfe[\u007fCD%\xa1\xfew\u007fw5]~\xf9\xeb\xe4\x99t}O\xc0|?_\x9f\xfc\xe4?\"J\xb0\xbe\xfa\xd5/\x9fu\xd5Uo\xfa\xd4\xddw\u07fdqO\xbf\xb3\xf5\x97\u07ccs\xff\xaf\xff\x86a\xbf\x0f\xe3\xbc\xe6\xc0%~\xdee\xf5\x89\xb4\x8a[;\x977\xf5\aA\x00s\xae\x02\xdek\r\xb8\xe8\u0451zm\xd5\xf4\xdb4\x0e\xf0.i\u6943N\xa9\x94\xb2)\xb3k\x1bY\x97\x96*|\xefT\xc5\u068a\x17\x91q*\xa6mx\x96\x1a\xb4Jk\xc61\xa1\xe6E\xd2\xd4\xfbKc6\xaa\x91i\f\x91\x8a\u058a?\xdf\u059c\xe6@\xa3\xa8D\xaa\x19u\xe21\xc4\u00c6\xc1\x1e\x13\xbc\xe6\u0460Q$\xd26Toz\x131\xf2\xde\f\xc4\x19,\x1b'\x9cp\xc2\xe3\x17\\p\xde'\xae\xbc\xf27\xff\x84\x88\x1eM\u007f\xe7\xc6\x1b\xbf\x87\xe7?\xff\xccg\u0735>\x01\xf3g\xc0\xfa\xad\xdfz\ab(\xed\u55ff\xe6=\xd7_\xff\u03ff\xbfc\u01ce1\xfca\xe5#\xe3\x9e\xf5\x9c\xad\xb8\xf4?}\n\a\x1c\xbd\x19+\xbb\x97|\xb2O\xe9\xa1RM\xbb\xa4\x81p\xcdj=\x8eo\xa3\x99l\x8fj\x80\xa4\xe4\xe0\x13\x80\xb1\rpX\x8b\n\xdf\xe3\x9c\u0358\u007f\xeb\xdaMPZk\x8eH\xc6\xf9c\xd9\x03\xc5Q\xbb\xfd\xda\xff'\u05b9\te\xd5\u49db\xf7W5\x1b\x83\xdb\xe0\x1a\x9b\x95\xb4\x9cL\u0186_\xd1p/\xa0\xea=\xe2F\u056e\x89\x02\x95\xe2}T\xac\xab\xde,\x17\x14)#G\xb0.\xd17%Fk\xe9f\xcb\xf1\x15P\ny\xb7\v3\x1aa\xe7Oo\xc3#?\xf8:\x1e\xf8\xe6ux\xe2\xf6\x9bP\xac.\xb5\x03Sp\xe3,CK 8\xe4Y\a\xe3\xb8\xe3\x8e\xdbu\xce9g\xff\x8f\xdf\xff\xfd\xf7\xfd\x15\x11\u0756\xfe\u03bd\xf7\u0783g?\xfb\xd8g\xecu>\x01\xf3g\xc0\xfa\xc8G\xfe_\xfc\xfa\xaf\xbf1\x80\x89\x1cp\uee7f\xf0\xc9o~\xf3\x9b\x17:\xd7\xeeq\xca\xcc8\xe1\u016f\xc1\x19W\xbe\x17sG\x1e\x8b\xe1\xb0@Q\x14\x10g\xe1b-^*Y\xa8\x01\xec\xd5m\xa9\x84\x03\x88\xba\xe3X\u5e44#\x8f|y\xe4mC&\xd1X\xc5\f\xaa\uedd5{nC\xf9\xa6\xcdk\v\xa72\xc6}\xaf\xc5\xe7\xa0e\x02\xb26\xfe)\xf5\r\xa3\xb4}\xa5\xca\u05e6e\a\x8aI;M@\x8f\x9e.\xdeU\xb0\xb1\xb1H;\xdf.\xc9k]\xbe\xee\u912bT NR\u077f\"Ow\xe9\xa0\x15\x8f\x16\u0205\x93\x92B\x89\u0787\"\xd28uH\xa9\x18W\xd1\x06\x81\t\xac2\xe8N\x0ek,\x1e\xbf\xed{\xb8\xef\x9b\xd7\xe1\xc1\xef\u0740\x9d\xf7\xfc\b\xb6\x18\xb5\xa2Q\x19p\x12\xde\xebLkt{\x1d\x9cx\xc2\t\u063a\xf5\xb9?\xb8\xe0\xfc\xf3\xdf\xf1\xcaW\xbd\xfa\xeb\xe9\xaf\xfd\xdd\xdf]\x8d\xcb/\u007f\xdd3\xfe:\x9f\x80\xf93d\xfd\xf8\u01f7\u2913\x9e\v\x00\xf8\xda\u05fe\xb2\xf5\xfd\xef\u007f\xff\u05ef\xbf\xfe\x86\xb9Vr84\x167m=\a[^q%\x8e8\xfbE\xe8\x1e\xf8,\x18\xe3P\f\ap\u0468\xab\x85w\x8d\x00V\xafM\xa5\xf4\xb3\x8eG\xf8\xf8;&\xe1\xc7K\x87\xbb\xa4t\x96\x96t\x84\xb1\xea\xbcm\x80\xa6\r\xe9Z\x88\xf65\xbdRP\xc9\xef\x9a\x00\xdb\x1c\xe0\u065b>[jS\xad\xd5\xf3\xad\x03yx\xf6m\x8a\x97\xb0\xf9U:q\n\x95\xaf\xff\xa6kP[Q:\x18+\xed\u0606\xb4e\xe5N5\xc0\x8f\xf7i\xa4\xd2RF\x8f\x1eA4.KN\x19\xa8d\x89\x11\xc0\xe3\xaeKD\xe0,\x83\xce;p\xd6b\xdb\x1d?\xc4\xdd_\xfe\x14\xee\xff\xe6ux\xf2\xbe\xdb\xd1\xf4\a\x8a\x0f\xa0\x04p?\xf5C\x9dN\x8e\x99\xe9\x19l\u06b4\t\xcf{\xde)\v'\x9ex\u009f\xfc\xd6o\xbd\xf3CD\xb4\v\x00>\xfe\xf1\x8f\xf1k_\xfbknreO\xc0\xfc\x19\xb9n\xba\xe9\xfbt\xdai\xa7\v\x00|\xe2\x13\xff\xf0\x92\xff\xfc\x9f\xff\xeb5\xdf\xfe\xf6wf\xdb>\x16\x14F\xfa\xa7\xd6o\xc0\xc6\u7783\x13^\xf6F\x1cv\xea\xb9PS3\xb0\xc6\xc1\fVk\x8d\xae\x8a\xb2\x90\x06\x8f^\x81I\x12(_\x1bXI\xc1\xbcf\xb0DU\xd5O\r\xad\xf2ZMKip\xed\xcd\x1fn\xca'E\x9a\xbe1\x82*\xbb\xa1\x82cn\xb1*H=l\u02a1\x9e\xf0}\xa6\xf1\xfec\x94]J\xa8d\u02f0\x86\xe4a\xa6\x1b\x9dC}X\b\t\xe0\u01e0\xb44\x06/Fw\xc6\u7903\xc3c\xf4\b72\xde\xe5\xb0R\xdf\\R\x8a\xab&-M^\u0426\xb5B\xa9Ya\x8dNo\n\"\x82'\xef\xbb\x1dw|\xe1\xbf\xe3\xbeo~\x1e\xbb\x1f\xb8\x13f4h1\x81!\x1f$\xce\f\x11'\xe2\x84\xe6\xe6f1;;\x83C\x0e9\x14g\x9f}\xe6\u03a3\x8f>\xfa/^x\xf1%\u007f{\u0496\x93\x1e\x04\x80W\xbe\xf2\x15\xea\x13\x9f\xf8\x94\xdd_\u0331&`>Y\xff\xcb\xeb\xaf\xfe\xea/\xf8Moz\x8b\x03\x80\xab\xaf\xfe\u0605\x1f\xf9\xc8G\xae\xf9\xcew\xbe\xbba4\x1a\x19\xa5\x94\xb2\u05b5\xea3f\x0f9\x1c\x87\x9dz.\x8e\xb9\xe8Wp\xe8\xd6s\xa0{3(\x06\xabp\x81\x96i~\xa4\u04a37S\x134+d\xa5\x06\xa7]w\xf1\xab6\x95\xa6\xba\xa5\xc9\x17\xd7\x14\x19M\xab\xdb=\xad\x06h1\x118\xdcge\x0e\x15\x81\x8f\xcaA\xa7X\xc4:Y;u'\x1d\xb2\xa9\x01:\u0579\xf9\x96t\xb9\xbd6C}\x90\x03\x95\x9bb\xc6\x04\x15\xc0\x19\xa5\xc5,\xd5\f\u04cc\xabd\xa4\xae\xda&\x91\xe4\x8d\xd4\r\xba\xa4\x02o$\x9b\x05\xa5\xd2$q0\u0387C\xe4\xdd\x0e\x96\x1f\u007f\bw\xdf\xf0I\xfc\xf8\u068fc\xe7Oo\x83\xb4T\xe2Q\x99\xa2\x98\xc59g\x8c)p\xd0A\af\x1b6\x1c\x8c\x83\x0f>x\xfb\x19g<\xff\xd6\xd3N;\xf5\u00ff\xf2+\xbfz\x1d\x11-\xc7\u07fb\xfa\xea\x8f\xd2\xeb^\xf7z\x99\\\xc5\x130\x9f\xac\xb0>\xf4\xa1\xbf\xe4\xdf\xfc\xcd7;\x00\xf8\xf4\xa7?y\xc1\xd5W_\xfd\x0f\xdf\xfa\u05b77\xec\xdc\xf9$\x98\u0649\b\xa7>.13\x93\x94\xc6\xf4\xc1\x1b\xb1\xf9\u0717\xe1\x84\u02ee\xc0\xfag\x9f\xfc?\u06fb\xd2\xe0:\xaa3{\uef7d\xbcE\xfb\xd3\xf2$\u02ca6\x8c\x1d/x\x19\xc6\xc66v\x8c\x1c\x98\x94\xcb\xd4\f\x1e\x02\xe4G25E\xe18\x19\xa8\u0250T`H\x82a\x96\x84Jf\x8a\u0270XP@\xa8\n!\xc9\x04\xc8x\x02\x89\a\x13\x1b\xe3\x15\x19[\xc6c\xcb\xd6bY\x8b%\xdbOz\u04b3\x96\xb7t\xf7\xbd\xf3\xa3\xbb_w?=9T*\x10\x92\xf4\xf7G\xb6\xf4\xd4oQ\xdfs\xbf{\xbe\xf3\x9d\x0f\x86a@OM[G\xe5\x1c\x8b\u05dc\xbc\xd3[\xfa\x83\x8bs\xc7\fj\x06\xee6}\v\xa0DNES\xe4aT\x80Y\\\r?\xc0\x02p\x80\xdb\x04t\x99\xda\xca\x0e\x93;\xd6sN\x10N\x929s\xd7\x103\xb2~GuCs\x00\xde\xfe\xbf\xbd9\xe4\xb6\xf0\xbb\xaf\u0248\xa3\xef'\xd9l\xdetx\xb4\u01aaZ\x80k\xda\xc9\xdat\x89\xbb{\x96{\x8a\xc1b\xc6)\x04\x96~\xdcV\xbc\x10\x97g\x8b\xd3[`\x1e\x9f$E\x85\x12\n \x99\xb8\x82\xc1\xf7\xf6\xa1\xfd\xa7O\xa1\xef\u0777\xf2r\xe2\x84R\xd3\b\x8b1\b\xce\rn\x18,\x12)CCC\x03\xaa\xab\xab/,\\\xb8\xf0\xf5\x96\x96\x96\xc7ZZ6\x9es\xff\xde7\xbf\xf9\x10Y\xb6l\x99\xb8\xed\xb6\xbf\xf6\x17\xaf\x0f\xe6~\xe4\u01b7\xbe\xf5M\xf2\xe8\xa3\xff$\x00\xa0\xad\xed\xf0\x86\x1d;\x9e\xf9\xcf\xfd\xfb\x0f,s/\x01\xaf\u0305\xe4\xe4\xa2\xc45\x9d&\x97\x1b\xcf*'0\xcb88\u0324C\x90\x876\u0235\x17\x80\u02e6\xd56\xf9\xa2\xc4\xecj\x14 \x969\x94p\x81\"q\x15\x05\x85\xd7\u070b\xe4Q\x9c\xe4\xd0\x14\x94\x98\xf2=B\xecY\x1e\xf6\xa7 r\xe4\x92\xe6\xc6B@\xac\xe767\x99,\x03\xef\xca\xfeM\x1bY1\xc3\u01c6\xbbOA\xc8\xd5\xec\v\xab\x17\x80xL\xbe$\xd7H;\xee\xca\u0429e\x8aEe\x19JH\x8561\x81\xe1\xe3\xef\xa0\xe3\xcdW\xd0\xf5\xf6N$\xc7F\xf2\x838\xa1`\x8cZ\x9b\tGEy\x05\xe6\u039d\x8b\x9a\x9a\xe8\xb1\r\x1b6\xec\u07f6\ud2ed\x8a\x12<\xed\xfe\xbd\x05\v\xaeEkk+\u05ad\xfb\x94\xbf`}0\xf7\xe3j\xf1\xe0\x83_'\xdf\xfe\xf6cV3\xa5\xa8\u07fe\xfd\xe1\xc7\xf6\xed\xdb\xf7\u064e\x8e3\x88\xc7\u3982\u015d\xa1Sj6n\x00\xe0Z\x06\xc1\xb2J\xd4\u07f8\tsW\u0742\xaa\xeb\u05a00Z\vC3`his\xaa}\x0e\xaa\x12\xe1:\xda\xc3\xd5\xe5\txG\xb3[w\xa6c\x80\ubc3c\xd9\xd6~kX\xb4\x10\xb3\xdf\xd0\xf9\x9a\x98\xf2\xb5\xc5S7\x9dB\\\xad\xed\"\xbf.\xfb>bg\x8ea\xe4\\\a\x92c1\xa4\xa7&\xc0\r}\xc6\xe7I)\u02f6\u061b_\xad\xb1mB\x18\xe9t\x9a\x97\x95\x95\xc9s\xe6\xd4`\xfe\xfc\xf9\xf1\x95+\xff\xfc\xdf\xee\xbf\xffk\xdf%\x84d\xc7\x02}\xe7;\xffJ\x1ex\xe0\x1f}y\xa1\x0f\xe6~|T\xf1\xea\xab?\xc3\xee\u077b\xc9SO\xed\xc8.\xbcw\xde\u0673\xf1\xe5\x97\u007f\xf2\x8d\xe3\xc7O\xac\xef\xec\xec\xc4\xe8\u8a1d\x9cR\x0f\x8d`\x1d\xbd\x05\u7812\x84py\r\xe6,[\x83\xba\x1bnA\xe5\u0095(\xaem\x02Q$\xe8i\u00f4\b\xe0\x1c\x82\xebV\xd6\xeed\xa6\xe6\x14!W\xcb\xd1U-\x02\xf3\xd3(\xf4K\xd5\x00\x00\v\xecIDAT\"\x1e\x83+K\x8d\xe1\xc9\xfc\x89\xfd\xe2g\aL\x9b\xe20r&M\xb8\x9b\x99f{\x1dW\x1b\xd6\xecH\xfeL\x12;+[\xb4~n\xb8\xb2\xf3|\x1c8r\b!\x02\xaf2\x881\x06EU!)\x12\x88\x00\u04898&c\x171q\xb1\x0f\xa3\xbd\x1d\x88u\x9d\xc4\u04296\\\x19\ua0de\x9a\xc2\f{\a\xf7\xe9\x8b8~\xf2\x0emC@\b\x11\x9a\x96\xe1\xa1P\x98\u035bw\r\xea\xea\xea\x06\x97-[\xba\xf3\xcb_\xfe\u04bfG\"\x95=\xeekuvv`\u07bc\x05\xfe\xe2\xf2\xc1\u070f\xdfG\xb4\xb6>\x8d\xad[\xb7\xb9\x8e\xf9B~\xe9\xa5\x1f\u07bdk\u05ee;\xfb\xfb\a\u059dF\xb2lR.yd\x83e\xd6\xf8\xca*\x80:\x1b\x94p\x9aw(1\x1b\xf8)\x01\xb3(-JMb\x852\n\x89\x02Z:\x83\x89K\x03&h\xf7\x9e\xc1X\xdfY\x8c\xf5wc|\xa0\v\x13\x17\a\xbd\xe3\xe0(3yn\xeb\x14E\x89W\xc6#\xf2\fN\x15B\x80R\x02YV \xcb\x12\x1a\x1b\x1b\xd1\xdc\xdc<\x19\x8dV\xb5\xdeu\u05dd?Y\xb5jM\x9b\xfb\xf1\xdf\xff\xfe\xe3\xb8\uffbf\xf7\x17\x90\x0f\xe6~|\x9c\xe2\x95W\xfe\v[\xb6\u070e#G\x0ea\u03de\xbd\xec\x81\a\x1e\xb4\x95/U/\xbf\xfc\u04a7\xdb\xdbO\xdc\xdd\xd6vt\xfd\xa9S\xa7\x90H$\x90N\xa7=L\xc5L\n\xc603hj\x82<\xa1\x14L\x0e@\t\x17A\n\x85!\a\v\xa0\x84\x8b\xa0\x16\x95!\x14\xa9B\xb8j.\xc2\x15s\x10(.\x85\x1a.B\xb0\xb8\x14\xc1\x92\n\xa8\x85%\x90\x14\x15\xce \x04\x0eC7\xcci\xedB\x98\x13L\x05\xcf\x0e\f\xa6\xd4\xd2e\u00dc\x96\x03 ;\xcb\xd46\xb0\u02b5\x9b\xe5B@\xe3f\xe1\xd5\x00\xcd\u038c\x13v\xeaL\b\xe0\x18E\xb9\xc6\u06f9\xac\xa9,>\u01b1\x036\v\xae\xb6\xbe\x9c\x11\xc7!\xd11,s\rL&f\x87'\x17\x02\f\xe6&\x96\x99\x9e\u0115\xe1~\x8c\xf5w\"~\xfe,F{;\x90\x18\xee\xc3\xc4\xf0\x00&b\x17\xc0u\x87\xf3\xa6L\u029aY\x99\xb2A\xe21\xf52\x9d\x10E\xdeF,\xc30\x04!\x84\x84B!\x14\x15\x15\xa2\xb1\xb1\x11\x8b\x17/>\xdd\xd4\xd4\xf8\x8b\xa5K\x97\xbd|\xd3M-\xed\x00\xb0~\xfd\x8dt\u06f6m\xb8\xf3\xce\xcf\xf9\xea\x14\x1f\xcc\xfd\xf8C\x897\xde\xf8\x05}\xe3\x8d_\xb2'\x9ex\xd2V\xbe\x84\u007f\xf0\x83\x176\x1f=\xfa\u07b7\x8e\x1e=\xba``\xa0\x1f\xb1X\f\x9a\xa6\xe7-\t\xba\xb3C\x13\xe0I6\xd3\x16\x82Cp\xd7\fw\xca \xa9A\u0221\x02H\x81\x10\xa4@\x10J\xa8\x00\x81\xc2R\x84\"QD\x1a\xe6#\u04bc\b\xa5\x9f\xb8\x16\xe1\xb2JH\x8a\nI\x92 I\xd41\xc4\x12\x00\xb8\x01\xce-B\xc5eW\xeb1\x8d\xb2\xa8\ffm2 \x04\x19\x01d,x\xd2\f\xb3\u02d2[\x1bD\x96\n\xe2\xe6\tA\b\x93'2\xbf\xaf\xc3\xd0\xd20\xd2Ip]\x03\xd7M\x1baSJHA\xc0A\xb9n\x82\xb3\xaeA\x18:\fC\x03\x84\x80\x1a.\x82\x1c\f\x9b\x12A-\x8d\xf4D\x02S\xf1\u02d8\x8c\rc\xf2R?\x12\xc3\x03\x98\x8a_F*1\x8aTb\x14\xc9\u0118\xc7\a\x85P\x06\xcaXv\x93\xb3\v\x964\x0f\x80C\x88\x19\x12Ka\x06!\x04(**FYY\x19\xae\xb9\xa6\x19MM\x8d?^\xb0`\xc1\xd3\u06f6}\xb9\x8b\x102l?]k\xeb\xd3l\xeb\xd6m\xba\xbf2|0\xf7\xe3\x0f4\xac\x81\xd1n\xe5\vmm\xdd\xf1\xb9\u00c7\x0f\xdf\u007f\xf2\xe4\xff-\x1d\x19\x19\xc1\xf0\xf002\x99\x8cA\b\x04\xa5L2\v\x9d9\x1c\xac\xc5E\x10\xf7\x84g\xe7\xa2\x10\xdc\u021b5RJ!\a\xc3P\vK\x10,-G\u025cFT^\xb3\b%\xd1Z\x14\x94U \\Z\t\xb5\xa8\x14r(\fI\t\x80I2d\x89\x81P\xe6iN2\v\x8f\xe6f\xc2u\x03\x84\xeb\xa0\xe0\xa000\x9d\xd611\x95\xc4\u0115+\x98\x1a\x1f\xc5\xd4D\x02\xa9\xa9\t\xe8\xa9$2\xa9\x142\x13cHO\x8cCKN\xc2H\xa7`d\xd204\xf3\xab\x9eJ\x82k\xa6m\xb00\f\ap\xadZ\x02\xb1\xc0\x94s\xdd,\x06\x1b\xe6\xfb\xb4\x1b\xb3\f-\x03\xaee\xa0k\x19\xf3\u07fav\xf5\x05\x9d\x95\x8bRPP\xc7\xc7\x1c\x8e\u01ce;\x03'\xc43(\x9b\xeb\xban\b\xc1%UUI$\x12AYY\x19\xae\xbdv~b\xf9\xf2\xa5\xaf/_\xbe\xec_n\xbe\xf93\x1e>\xfc\xb5\xd7^!\xd5\xd5Q\xb1j\xd5\x1a\u007f1\xf8`\xee\xc7\x1fC\xec\xdc\xf9sr\xeb\xad\u007f)r8\u04ed\x1d\x1d\x1d[\xbb\xba\xba\xe7\x0f\r\r\x05c\xb1\x18\xe2\xf11!\x047\b\xa1T\bn+(H.\x1d\xe3\xf6Gw\xeeT\xe2\x92\xf59\xed\xa3B\x18.\x87?\x02I\r\x80\xc92\x98\xacB\t\x86\xa0\x14\x14\xa1\xb8\xbc\x1a\x85\x955\b\x16\x95@\r\x86!)*\x18\xa5Y!$#\x020t\x18\x99\f2\xa9i\xd3\xe27\x93\x82\xd0\u04d8\xba2\x8exl\x04\x93\x93W\x90\x9e\x9e\x86\xaee\xc0\r\xdd\x04^+\x03\xe7\u0724v\x84\xf8\xe8Tw6\x10\x13W\xb3\x8eS\xb4\x9c\xc9w\xbb5\xdd\xc4\xf1+\x067\x83J\x12#\x95\x95\x95(++CAA\xc1x]]]\xfb\xfa\xf5\xeb\xf7\xdes\xcf\u059f\x12B:\xdc\xd7{\xf0\xc1\xaf\x93{\xef\xbdW\xd4\xd4\xd4\xfa7\xbf\x0f\xe6~\xfc\xb1\xc5\xd3O?\x85S\xa7N\x91'\x9ex\u049d\xa9\xb3C\x87\x0e\u073as\xe7\xceM\xdd\xdd=\xab\x93\xc9\xe4\x82X,\x86\x81\x81ALOOA\xd7uLO'!\xc4\a2\xac\xbd\u028dLr\xe7\xd2\xffN\x16E\xde\xd1l\x1f\xe5\x02\xf5H\x02]_\xad\xb6y\u4302\xcb97y\u078d\xfd\x18\xce\x058\xe7\x90$\t\xaa\xaa\xa2\xa8\xa8\b\xd1h\x14\x91H\xd9XII\xc9\u19a6\xa6C\x1b7\xb6\x1c\xfd\u0527n\xdaE\b\xf1\xf0\xdfo\xbe\xf9+|\xfa\xd3\u007f\xe1\xdf\xec>\x98\xfb\xf1\xa7\x10\xb3\xa9\x18\x84\xe0\u05fe\xf8\xe2\x8b\x1b\xdb\xdb\xdb\xe7\uaeb6\xe2\u0295\x89\xf2s\xe7\xceM\x85\xc3\xe1\u56a6\x05{{\xcf#\x91H \x93I\xc308\f\xc3@&\x93\xf9\xe3\\x\xb9Y2!\x1e\xd31\xea\xea\xc1w\x17D\xed,;\xdf\x06f\u007f\x9fR{\xec\x9a\xd5\xf9i\xa9V\x18cP\xd5\x00**\xcaQ[[\v\u01a4\xe9`0\xd0Y]]=\xac\xaa\u02ae\xdbn\xdbrv\u035a\xb5\xbf\xca\u05d5\xb9k\xd7/q\xcb-\x9f\xf1on\x1f\xcc\xfd\xf8S\x8c\x8b\x17\x87\x10\x8d\xd6`p\xb0\x8f\xd4\xd6~B\xe4\x1c\xfb\xab\x00\x94\xec\u077b7\xd9\xdb\xdb3\xaf\xaf\xaf\xaf\xee\u0295\xc9\x06Bp\xfd\xc8H\x8c\xc6b#)JiEQQ\u046a\u02d7/c``\x10\x13\x13\x13\u0434\f4M\x83\xae\x1b0\f\x03\x9a\xa6\x9b<\xb7\xdbf\xe0Cj\x11\xbf\x9a\x89\x96\x99\a\x93\x19\xf3D\xb3\t\xf2l\xb9\xbdG\xcbm6\xfa0f\xd3%\xc4j\xa42m\x87\u0740\x9d}FB!\u02e6R\xc56\xb7b\x8cZ\xe0mf\u07a5\xa5%\xa8\xad\xadE0\x18\ucaac\xac\xec\f\x04\x82GC\xa1`\xe7\xbcy\u05cc\xb6\xb4l8\x1f\x8d\xd6^$\x84$\xec\xabvv\x9e!\xf3\xe6\xcd\x17\x00\xb0c\xc7S\u063cy3\xe6\u0319\xeb\xdf\xd0>\x98\xfb\xf1\xa7\x1c==\x9dhj\x9a\a!\x04v\xee\xfc9\x89\xc5b\xec\xc9'\x9f\x16\u01cf\x1f7\xf2\x03\xa6\xa8\xb0\xeeK\xbd\xa3\xe3T\xb8\xaf\xaf\u007fN[[[@Q\xe4\u0159Lf\xe5\u0673g\xb5\xe9\xe9diII\xf1\xba\x8b\x17/\x97\x0e\f\f`||\x1c\xba\xae!\x93\u0450L\x9a\xfe/6\xd8Sk B~\x80\xcf\xef\xed2\xc3\xfb\u071e=*\x04r\x8b\xb7\xb2,\x83Rj6\xf5\xe4\\U\x96e(\xb2\x9c\x05W\x0f\xc7M\x88w,\x9b\x95=\xeb\xba\x0e\u039d\xe9M\xf6\xefp\xceA)\x81$IP\x14\x15\xb2,\x811\x06J\x19dYBqq\xb1\x88F\xa3\xa4\xa4\xa48\x1d\x8f\xc7\x0f\x8c\x8d\x8d\x9fkhh\b44\u05031\xe98\xe7\xbcm\xf5\xea\x1b\x86W\xaf^;F\b\x19\xcd}\xcf\xf7\xddw\xaf\xb4b\xc5r\xb1l\xd92\xbed\xc9R\xf1\xfa\xeb\xff\x83M\x9b6\xfb7\xb0\x0f\xe6~\xf8q\xb5\fW\xe0\u0529\xf7iOO/y\xfb\xed}(,\f\xd3D\xe2\n}\xfc\xf1\xffH\xff\x86\xdf\v\x02\x10\xa9\u0514|\xe4\xc8\xe1\u04b6\xb6cJEE\xf9\xc6\u04e7;\x16\x8d\x8c\u0116\x8d\x8c\x8c.\x1e\x1a\x1a\n'\x12\xe3\xd40\xcc\x06\x97t:\x8d\xa9\xa9)LM%a\xaa\r\t4M\x87\xa6i\xf9\x93k\x80\u0232\fIbfc\x90p\x18sU\r\xa0\xa8\xa8\x10\x81@\x00\x92$\x81s\x81d2\t\x00P\x14\x05\xc1`\x00\x92$\x9bEXY\x02!$I\b\x9d,..DAA\x01\x14EE \xa0BUU(\x8a\n\xc6X\xf6\x89UU\xa5\xc1`\x80^\xb80\xb4\xef\xfc\xf9\xf3\xa7\xc2\xe10K\xa7\u04d9\xea\xea\xea\xe6`0T\xdc\xdf\xdfwZQ\x14c\xee\u0739\xa4\xbe\xbe\x1e\xc5\xc5E\b\x85B2\x80\xc1c\xc7\xda\xf7LNN&\u05acY%777\x19\r\r\r\xf1H\xa4j\n\xf6\xdc\rB\x92\xb9\xeb~\xfb\xf6\x87\x95T*i\xd4\xd7\u05cbU\xabV\x8a\xa5KW\xf8\xdap\x1f\xcc\xfd\xf0\xe3\u00cb\xae\xae3\u063d\xfb\xd7\u0636\xedK\xbf\xf1\xb1\xd3\xd3\x13U\x87\x0e\x1d^\xb7\u007f\xff\x81\x8at:\xb5H\b\\\xdf\xdd\u074dX,\x16\xe6\\\xd4%\x12\t#\x95JrEQKB\xa1\x90\xb5A8\x14\rc\fB\b$\x12\t=\x9dNO\xaa\xaaJM\xe0UH(\x14\x82,+\xa3\x15\x15\x91X}}=\"\x91\x88$\x84\xb8\xd4\xd9\xd9\xf9v:\x9d\x89777K\xcd\xcdM(..\x86$1Z\\\\\"\x15\x16\x16\xbe;22z|\xf5\xea\x1b\fYV\xd9\aY\x8b\x84\x90\xe9<\x9b\x98G\xfe\xf9\xdb\xc4\x0f\u007f\xf8\"\u05ad[\x87\xba\xba\x06\xff\xa6\xf2\xc1\xdc\x0f?>>\xd1\xde\xfe\x1e\x1e}\xf4\x9f\xf1\uaaef}\x90\x93@\xf9\x89\x13\xc7n>r\xa4-}\xe6\xcc\x19\xbd\xb2\xb2\xe2\x9a\xf2\xf2\xc8\n\xceE\x88s\xce3\x99\x8c\xb0\xb2c\x99\x10\x92\xec\xed=\xff\xf6\x85\v\x17\x06\xeb\xea\xeaX]]\x1d\xa9\xae\x8e\xb2\x86\x86\x06\xb2h\u0452vB\xc8\u064f\xe3\xe71<<\x88\xeaj_&\xe8\x87\x1f~\xfc\x81\xc7\xd0\xd0\xc0\xc7\xf2u\xdd\u007f\xff\xdfbp\xb0\xdf\xff\x03\xf9\xf1\xa1\xc7\xff\x03 \x99\rH\xa6\x0e6\x92\x00\x00\x00\x00IEND\xaeB`\x82") - -// dashboardDockerfile is the Dockerfile required to build an dashboard container -// to aggregate various private network services under one easily accessible page. -var dashboardDockerfile = ` -FROM mhart/alpine-node:latest - -WORKDIR /usr/app - -RUN \ - npm install connect serve-static && \ - \ - echo 'var connect = require("connect");' > server.js && \ - echo 'var serveStatic = require("serve-static");' >> server.js && \ - echo 'connect().use(serveStatic("/dashboard")).listen(80, function(){' >> server.js && \ - echo ' console.log("Server running on 80...");' >> server.js && \ - echo '});' >> server.js - -ADD {{.Network}}.json /dashboard/{{.Network}}.json -ADD {{.Network}}-cpp.json /dashboard/{{.Network}}-cpp.json -ADD {{.Network}}-harmony.json /dashboard/{{.Network}}-harmony.json -ADD {{.Network}}-parity.json /dashboard/{{.Network}}-parity.json -ADD {{.Network}}-python.json /dashboard/{{.Network}}-python.json -ADD index.html /dashboard/index.html -ADD puppeth.png /dashboard/puppeth.png - -EXPOSE 80 - -CMD ["node", "./server.js"] -` - -// dashboardComposefile is the docker-compose.yml file required to deploy and -// maintain an service aggregating dashboard. -var dashboardComposefile = ` -version: '2' -services: - dashboard: - build: . - image: {{.Network}}/dashboard{{if not .VHost}} - ports: - - "{{.Port}}:80"{{end}} - environment: - - ETHSTATS_PAGE={{.EthstatsPage}} - - EXPLORER_PAGE={{.ExplorerPage}} - - WALLET_PAGE={{.WalletPage}} - - FAUCET_PAGE={{.FaucetPage}}{{if .VHost}} - - VIRTUAL_HOST={{.VHost}}{{end}} - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" - restart: always -` - -// deployDashboard deploys a new dashboard container to a remote machine via SSH, -// docker and docker-compose. If an instance with the specified network name -// already exists there, it will be overwritten! -func deployDashboard(client *sshClient, network string, conf *config, config *dashboardInfos, nocache bool) ([]byte, error) { - // Generate the content to upload to the server - workdir := fmt.Sprintf("%d", rand.Int63()) - files := make(map[string][]byte) - - dockerfile := new(bytes.Buffer) - template.Must(template.New("").Parse(dashboardDockerfile)).Execute(dockerfile, map[string]interface{}{ - "Network": network, - }) - files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() - - composefile := new(bytes.Buffer) - template.Must(template.New("").Parse(dashboardComposefile)).Execute(composefile, map[string]interface{}{ - "Network": network, - "Port": config.port, - "VHost": config.host, - "EthstatsPage": config.ethstats, - "ExplorerPage": config.explorer, - "FaucetPage": config.faucet, - }) - files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() - - statsLogin := fmt.Sprintf("yournode:%s", conf.ethstats) - if !config.trusted { - statsLogin = "" - } - indexfile := new(bytes.Buffer) - bootCpp := make([]string, len(conf.bootnodes)) - for i, boot := range conf.bootnodes { - bootCpp[i] = "required:" + strings.TrimPrefix(boot, "enode://") - } - bootHarmony := make([]string, len(conf.bootnodes)) - for i, boot := range conf.bootnodes { - bootHarmony[i] = fmt.Sprintf("-Dpeer.active.%d.url=%s", i, boot) - } - bootPython := make([]string, len(conf.bootnodes)) - for i, boot := range conf.bootnodes { - bootPython[i] = "'" + boot + "'" - } - template.Must(template.New("").Parse(dashboardContent)).Execute(indexfile, map[string]interface{}{ - "Network": network, - "NetworkID": conf.Genesis.Config.ChainID, - "NetworkTitle": strings.Title(network), - "EthstatsPage": config.ethstats, - "ExplorerPage": config.explorer, - "FaucetPage": config.faucet, - "GethGenesis": network + ".json", - "Bootnodes": conf.bootnodes, - "BootnodesFlat": strings.Join(conf.bootnodes, ","), - "Ethstats": statsLogin, - "Ethash": conf.Genesis.Config.Ethash != nil, - "CppGenesis": network + "-cpp.json", - "CppBootnodes": strings.Join(bootCpp, " "), - "HarmonyGenesis": network + "-harmony.json", - "HarmonyBootnodes": strings.Join(bootHarmony, " "), - "ParityGenesis": network + "-parity.json", - "PythonGenesis": network + "-python.json", - "PythonBootnodes": strings.Join(bootPython, ","), - "Homestead": conf.Genesis.Config.HomesteadBlock, - "Tangerine": conf.Genesis.Config.EIP150Block, - "Spurious": conf.Genesis.Config.EIP155Block, - "Byzantium": conf.Genesis.Config.ByzantiumBlock, - "Constantinople": conf.Genesis.Config.ConstantinopleBlock, - "ConstantinopleFix": conf.Genesis.Config.PetersburgBlock, - }) - files[filepath.Join(workdir, "index.html")] = indexfile.Bytes() - - // Marshal the genesis spec files for go-ethereum and all the other clients - genesis, _ := conf.Genesis.MarshalJSON() - files[filepath.Join(workdir, network+".json")] = genesis - files[filepath.Join(workdir, "puppeth.png")] = dashboardMascot - - // Upload the deployment files to the remote server (and clean up afterwards) - if out, err := client.Upload(files); err != nil { - return out, err - } - defer client.Run("rm -rf " + workdir) - - // Build and deploy the dashboard service - if nocache { - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network)) - } - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network)) -} - -// dashboardInfos is returned from a dashboard status check to allow reporting -// various configuration parameters. -type dashboardInfos struct { - host string - port int - trusted bool - - ethstats string - explorer string - faucet string -} - -// Report converts the typed struct into a plain string->string map, containing -// most - but not all - fields for reporting to the user. -func (info *dashboardInfos) Report() map[string]string { - return map[string]string{ - "Website address": info.host, - "Website listener port": strconv.Itoa(info.port), - "Ethstats service": info.ethstats, - "Explorer service": info.explorer, - "Faucet service": info.faucet, - } -} - -// checkDashboard does a health-check against a dashboard container to verify if -// it's running, and if yes, gathering a collection of useful infos about it. -func checkDashboard(client *sshClient, network string) (*dashboardInfos, error) { - // Inspect a possible ethstats container on the host - infos, err := inspectContainer(client, fmt.Sprintf("%s_dashboard_1", network)) - if err != nil { - return nil, err - } - if !infos.running { - return nil, ErrServiceOffline - } - // Resolve the port from the host, or the reverse proxy - port := infos.portmap["80/tcp"] - if port == 0 { - if proxy, _ := checkNginx(client, network); proxy != nil { - port = proxy.port - } - } - if port == 0 { - return nil, ErrNotExposed - } - // Resolve the host from the reverse-proxy and configure the connection string - host := infos.envvars["VIRTUAL_HOST"] - if host == "" { - host = client.server - } - // Run a sanity check to see if the port is reachable - if err = checkPort(host, port); err != nil { - log.Warn("Dashboard service seems unreachable", "server", host, "port", port, "err", err) - } - // Container available, assemble and return the useful infos - return &dashboardInfos{ - host: host, - port: port, - ethstats: infos.envvars["ETHSTATS_PAGE"], - explorer: infos.envvars["EXPLORER_PAGE"], - faucet: infos.envvars["FAUCET_PAGE"], - }, nil -} diff --git a/cmd/puppeth/module_explorer.go b/cmd/puppeth/module_explorer.go deleted file mode 100644 index 3812f9fdb963..000000000000 --- a/cmd/puppeth/module_explorer.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "fmt" - "html/template" - "math/rand" - "path/filepath" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/log" -) - -// explorerDockerfile is the Dockerfile required to run a block explorer. -var explorerDockerfile = ` -FROM puppeth/blockscout:latest - -ADD genesis.json /genesis.json -RUN \ - echo 'geth --cache 512 init /genesis.json' > explorer.sh && \ - echo $'geth --networkid {{.NetworkID}} --syncmode "full" --gcmode "archive" --port {{.EthPort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --http --http.api "net,web3,eth,debug,txpool" --http.corsdomain "*" --http.vhosts "*" --ws --ws.origins "*" --exitwhensynced' >> explorer.sh && \ - echo $'exec geth --networkid {{.NetworkID}} --syncmode "full" --gcmode "archive" --port {{.EthPort}} --bootnodes {{.Bootnodes}} --ethstats \'{{.Ethstats}}\' --cache=512 --http --http.api "net,web3,eth,debug,txpool" --http.corsdomain "*" --http.vhosts "*" --ws --ws.origins "*" &' >> explorer.sh && \ - echo '/usr/local/bin/docker-entrypoint.sh postgres &' >> explorer.sh && \ - echo 'sleep 5' >> explorer.sh && \ - echo 'mix do ecto.drop --force, ecto.create, ecto.migrate' >> explorer.sh && \ - echo 'mix phx.server' >> explorer.sh - -ENTRYPOINT ["/bin/sh", "explorer.sh"] -` - -// explorerComposefile is the docker-compose.yml file required to deploy and -// maintain a block explorer. -var explorerComposefile = ` -version: '2' -services: - explorer: - build: . - image: {{.Network}}/explorer - container_name: {{.Network}}_explorer_1 - ports: - - "{{.EthPort}}:{{.EthPort}}" - - "{{.EthPort}}:{{.EthPort}}/udp"{{if not .VHost}} - - "{{.WebPort}}:4000"{{end}} - environment: - - ETH_PORT={{.EthPort}} - - ETH_NAME={{.EthName}} - - BLOCK_TRANSFORMER={{.Transformer}}{{if .VHost}} - - VIRTUAL_HOST={{.VHost}} - - VIRTUAL_PORT=4000{{end}} - volumes: - - {{.Datadir}}:/opt/app/.ethereum - - {{.DBDir}}:/var/lib/postgresql/data - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" - restart: always -` - -// deployExplorer deploys a new block explorer container to a remote machine via -// SSH, docker and docker-compose. If an instance with the specified network name -// already exists there, it will be overwritten! -func deployExplorer(client *sshClient, network string, bootnodes []string, config *explorerInfos, nocache bool, isClique bool) ([]byte, error) { - // Generate the content to upload to the server - workdir := fmt.Sprintf("%d", rand.Int63()) - files := make(map[string][]byte) - - dockerfile := new(bytes.Buffer) - template.Must(template.New("").Parse(explorerDockerfile)).Execute(dockerfile, map[string]interface{}{ - "NetworkID": config.node.network, - "Bootnodes": strings.Join(bootnodes, ","), - "Ethstats": config.node.ethstats, - "EthPort": config.node.port, - }) - files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() - - transformer := "base" - if isClique { - transformer = "clique" - } - composefile := new(bytes.Buffer) - template.Must(template.New("").Parse(explorerComposefile)).Execute(composefile, map[string]interface{}{ - "Network": network, - "VHost": config.host, - "Ethstats": config.node.ethstats, - "Datadir": config.node.datadir, - "DBDir": config.dbdir, - "EthPort": config.node.port, - "EthName": getEthName(config.node.ethstats), - "WebPort": config.port, - "Transformer": transformer, - }) - files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() - files[filepath.Join(workdir, "genesis.json")] = config.node.genesis - - // Upload the deployment files to the remote server (and clean up afterwards) - if out, err := client.Upload(files); err != nil { - return out, err - } - defer client.Run("rm -rf " + workdir) - - // Build and deploy the boot or seal node service - if nocache { - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network)) - } - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network)) -} - -// explorerInfos is returned from a block explorer status check to allow reporting -// various configuration parameters. -type explorerInfos struct { - node *nodeInfos - dbdir string - host string - port int -} - -// Report converts the typed struct into a plain string->string map, containing -// most - but not all - fields for reporting to the user. -func (info *explorerInfos) Report() map[string]string { - report := map[string]string{ - "Website address ": info.host, - "Website listener port ": strconv.Itoa(info.port), - "Ethereum listener port ": strconv.Itoa(info.node.port), - "Ethstats username": info.node.ethstats, - } - return report -} - -// checkExplorer does a health-check against a block explorer server to verify -// whether it's running, and if yes, whether it's responsive. -func checkExplorer(client *sshClient, network string) (*explorerInfos, error) { - // Inspect a possible explorer container on the host - infos, err := inspectContainer(client, fmt.Sprintf("%s_explorer_1", network)) - if err != nil { - return nil, err - } - if !infos.running { - return nil, ErrServiceOffline - } - // Resolve the port from the host, or the reverse proxy - port := infos.portmap["4000/tcp"] - if port == 0 { - if proxy, _ := checkNginx(client, network); proxy != nil { - port = proxy.port - } - } - if port == 0 { - return nil, ErrNotExposed - } - // Resolve the host from the reverse-proxy and the config values - host := infos.envvars["VIRTUAL_HOST"] - if host == "" { - host = client.server - } - // Run a sanity check to see if the devp2p is reachable - p2pPort := infos.portmap[infos.envvars["ETH_PORT"]+"/tcp"] - if err = checkPort(host, p2pPort); err != nil { - log.Warn("Explorer node seems unreachable", "server", host, "port", p2pPort, "err", err) - } - if err = checkPort(host, port); err != nil { - log.Warn("Explorer service seems unreachable", "server", host, "port", port, "err", err) - } - // Assemble and return the useful infos - stats := &explorerInfos{ - node: &nodeInfos{ - datadir: infos.volumes["/opt/app/.ethereum"], - port: infos.portmap[infos.envvars["ETH_PORT"]+"/tcp"], - ethstats: infos.envvars["ETH_NAME"], - }, - dbdir: infos.volumes["/var/lib/postgresql/data"], - host: host, - port: port, - } - return stats, nil -} diff --git a/cmd/puppeth/module_faucet.go b/cmd/puppeth/module_faucet.go deleted file mode 100644 index a4f6e65694df..000000000000 --- a/cmd/puppeth/module_faucet.go +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "html/template" - "math/rand" - "path/filepath" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" -) - -// faucetDockerfile is the Dockerfile required to build a faucet container to -// grant crypto tokens based on GitHub authentications. -var faucetDockerfile = ` -FROM ethereum/client-go:alltools-latest - -ADD genesis.json /genesis.json -ADD account.json /account.json -ADD account.pass /account.pass - -EXPOSE 8080 30303 30303/udp - -ENTRYPOINT [ \ - "faucet", "--genesis", "/genesis.json", "--network", "{{.NetworkID}}", "--bootnodes", "{{.Bootnodes}}", "--ethstats", "{{.Ethstats}}", "--ethport", "{{.EthPort}}", \ - "--faucet.name", "{{.FaucetName}}", "--faucet.amount", "{{.FaucetAmount}}", "--faucet.minutes", "{{.FaucetMinutes}}", "--faucet.tiers", "{{.FaucetTiers}}", \ - "--account.json", "/account.json", "--account.pass", "/account.pass" \ - {{if .CaptchaToken}}, "--captcha.token", "{{.CaptchaToken}}", "--captcha.secret", "{{.CaptchaSecret}}"{{end}}{{if .NoAuth}}, "--noauth"{{end}} \ - {{if .TwitterToken}}, "--twitter.token.v1", "{{.TwitterToken}}"{{end}} \ -]` - -// faucetComposefile is the docker-compose.yml file required to deploy and maintain -// a crypto faucet. -var faucetComposefile = ` -version: '2' -services: - faucet: - build: . - image: {{.Network}}/faucet - container_name: {{.Network}}_faucet_1 - ports: - - "{{.EthPort}}:{{.EthPort}}" - - "{{.EthPort}}:{{.EthPort}}/udp"{{if not .VHost}} - - "{{.ApiPort}}:8080"{{end}} - volumes: - - {{.Datadir}}:/root/.faucet - environment: - - ETH_PORT={{.EthPort}} - - ETH_NAME={{.EthName}} - - FAUCET_AMOUNT={{.FaucetAmount}} - - FAUCET_MINUTES={{.FaucetMinutes}} - - FAUCET_TIERS={{.FaucetTiers}} - - CAPTCHA_TOKEN={{.CaptchaToken}} - - CAPTCHA_SECRET={{.CaptchaSecret}} - - TWITTER_TOKEN={{.TwitterToken}} - - NO_AUTH={{.NoAuth}}{{if .VHost}} - - VIRTUAL_HOST={{.VHost}} - - VIRTUAL_PORT=8080{{end}} - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" - restart: always -` - -// deployFaucet deploys a new faucet container to a remote machine via SSH, -// docker and docker-compose. If an instance with the specified network name -// already exists there, it will be overwritten! -func deployFaucet(client *sshClient, network string, bootnodes []string, config *faucetInfos, nocache bool) ([]byte, error) { - // Generate the content to upload to the server - workdir := fmt.Sprintf("%d", rand.Int63()) - files := make(map[string][]byte) - - dockerfile := new(bytes.Buffer) - template.Must(template.New("").Parse(faucetDockerfile)).Execute(dockerfile, map[string]interface{}{ - "NetworkID": config.node.network, - "Bootnodes": strings.Join(bootnodes, ","), - "Ethstats": config.node.ethstats, - "EthPort": config.node.port, - "CaptchaToken": config.captchaToken, - "CaptchaSecret": config.captchaSecret, - "FaucetName": strings.Title(network), - "FaucetAmount": config.amount, - "FaucetMinutes": config.minutes, - "FaucetTiers": config.tiers, - "NoAuth": config.noauth, - "TwitterToken": config.twitterToken, - }) - files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() - - composefile := new(bytes.Buffer) - template.Must(template.New("").Parse(faucetComposefile)).Execute(composefile, map[string]interface{}{ - "Network": network, - "Datadir": config.node.datadir, - "VHost": config.host, - "ApiPort": config.port, - "EthPort": config.node.port, - "EthName": getEthName(config.node.ethstats), - "CaptchaToken": config.captchaToken, - "CaptchaSecret": config.captchaSecret, - "FaucetAmount": config.amount, - "FaucetMinutes": config.minutes, - "FaucetTiers": config.tiers, - "NoAuth": config.noauth, - "TwitterToken": config.twitterToken, - }) - files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() - - files[filepath.Join(workdir, "genesis.json")] = config.node.genesis - files[filepath.Join(workdir, "account.json")] = []byte(config.node.keyJSON) - files[filepath.Join(workdir, "account.pass")] = []byte(config.node.keyPass) - - // Upload the deployment files to the remote server (and clean up afterwards) - if out, err := client.Upload(files); err != nil { - return out, err - } - defer client.Run("rm -rf " + workdir) - - // Build and deploy the faucet service - if nocache { - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network)) - } - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network)) -} - -// faucetInfos is returned from a faucet status check to allow reporting various -// configuration parameters. -type faucetInfos struct { - node *nodeInfos - host string - port int - amount int - minutes int - tiers int - noauth bool - captchaToken string - captchaSecret string - twitterToken string -} - -// Report converts the typed struct into a plain string->string map, containing -// most - but not all - fields for reporting to the user. -func (info *faucetInfos) Report() map[string]string { - report := map[string]string{ - "Website address": info.host, - "Website listener port": strconv.Itoa(info.port), - "Ethereum listener port": strconv.Itoa(info.node.port), - "Funding amount (base tier)": fmt.Sprintf("%d Ethers", info.amount), - "Funding cooldown (base tier)": fmt.Sprintf("%d mins", info.minutes), - "Funding tiers": strconv.Itoa(info.tiers), - "Captha protection": fmt.Sprintf("%v", info.captchaToken != ""), - "Using Twitter API": fmt.Sprintf("%v", info.twitterToken != ""), - "Ethstats username": info.node.ethstats, - } - if info.noauth { - report["Debug mode (no auth)"] = "enabled" - } - if info.node.keyJSON != "" { - var key struct { - Address string `json:"address"` - } - if err := json.Unmarshal([]byte(info.node.keyJSON), &key); err == nil { - report["Funding account"] = common.HexToAddress(key.Address).Hex() - } else { - log.Error("Failed to retrieve signer address", "err", err) - } - } - return report -} - -// checkFaucet does a health-check against a faucet server to verify whether -// it's running, and if yes, gathering a collection of useful infos about it. -func checkFaucet(client *sshClient, network string) (*faucetInfos, error) { - // Inspect a possible faucet container on the host - infos, err := inspectContainer(client, fmt.Sprintf("%s_faucet_1", network)) - if err != nil { - return nil, err - } - if !infos.running { - return nil, ErrServiceOffline - } - // Resolve the port from the host, or the reverse proxy - port := infos.portmap["8080/tcp"] - if port == 0 { - if proxy, _ := checkNginx(client, network); proxy != nil { - port = proxy.port - } - } - if port == 0 { - return nil, ErrNotExposed - } - // Resolve the host from the reverse-proxy and the config values - host := infos.envvars["VIRTUAL_HOST"] - if host == "" { - host = client.server - } - amount, _ := strconv.Atoi(infos.envvars["FAUCET_AMOUNT"]) - minutes, _ := strconv.Atoi(infos.envvars["FAUCET_MINUTES"]) - tiers, _ := strconv.Atoi(infos.envvars["FAUCET_TIERS"]) - - // Retrieve the funding account information - var out []byte - keyJSON, keyPass := "", "" - if out, err = client.Run(fmt.Sprintf("docker exec %s_faucet_1 cat /account.json", network)); err == nil { - keyJSON = string(bytes.TrimSpace(out)) - } - if out, err = client.Run(fmt.Sprintf("docker exec %s_faucet_1 cat /account.pass", network)); err == nil { - keyPass = string(bytes.TrimSpace(out)) - } - // Run a sanity check to see if the port is reachable - if err = checkPort(host, port); err != nil { - log.Warn("Faucet service seems unreachable", "server", host, "port", port, "err", err) - } - // Container available, assemble and return the useful infos - return &faucetInfos{ - node: &nodeInfos{ - datadir: infos.volumes["/root/.faucet"], - port: infos.portmap[infos.envvars["ETH_PORT"]+"/tcp"], - ethstats: infos.envvars["ETH_NAME"], - keyJSON: keyJSON, - keyPass: keyPass, - }, - host: host, - port: port, - amount: amount, - minutes: minutes, - tiers: tiers, - captchaToken: infos.envvars["CAPTCHA_TOKEN"], - captchaSecret: infos.envvars["CAPTCHA_SECRET"], - noauth: infos.envvars["NO_AUTH"] == "true", - twitterToken: infos.envvars["TWITTER_TOKEN"], - }, nil -} diff --git a/cmd/puppeth/module_node.go b/cmd/puppeth/module_node.go deleted file mode 100644 index b8aa30db39a8..000000000000 --- a/cmd/puppeth/module_node.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "math/rand" - "path/filepath" - "strconv" - "strings" - "text/template" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" -) - -// nodeDockerfile is the Dockerfile required to run an Ethereum node. -var nodeDockerfile = ` -FROM ethereum/client-go:latest - -ADD genesis.json /genesis.json -{{if .Unlock}} - ADD signer.json /signer.json - ADD signer.pass /signer.pass -{{end}} -RUN \ - echo 'geth --cache 512 init /genesis.json' > geth.sh && \{{if .Unlock}} - echo 'mkdir -p /root/.ethereum/keystore/ && cp /signer.json /root/.ethereum/keystore/' >> geth.sh && \{{end}} - echo $'exec geth --networkid {{.NetworkID}} --cache 512 --port {{.Port}} --nat extip:{{.IP}} --maxpeers {{.Peers}} {{.LightFlag}} --ethstats \'{{.Ethstats}}\' {{if .Bootnodes}}--bootnodes {{.Bootnodes}}{{end}} {{if .Etherbase}}--miner.etherbase {{.Etherbase}} --mine --miner.threads 1{{end}} {{if .Unlock}}--unlock 0 --password /signer.pass --mine{{end}} --miner.gastarget {{.GasTarget}} --miner.gaslimit {{.GasLimit}} --miner.gasprice {{.GasPrice}}' >> geth.sh - -ENTRYPOINT ["/bin/sh", "geth.sh"] -` - -// nodeComposefile is the docker-compose.yml file required to deploy and maintain -// an Ethereum node (bootnode or miner for now). -var nodeComposefile = ` -version: '2' -services: - {{.Type}}: - build: . - image: {{.Network}}/{{.Type}} - container_name: {{.Network}}_{{.Type}}_1 - ports: - - "{{.Port}}:{{.Port}}" - - "{{.Port}}:{{.Port}}/udp" - volumes: - - {{.Datadir}}:/root/.ethereum{{if .Ethashdir}} - - {{.Ethashdir}}:/root/.ethash{{end}} - environment: - - PORT={{.Port}}/tcp - - TOTAL_PEERS={{.TotalPeers}} - - LIGHT_PEERS={{.LightPeers}} - - STATS_NAME={{.Ethstats}} - - MINER_NAME={{.Etherbase}} - - GAS_TARGET={{.GasTarget}} - - GAS_LIMIT={{.GasLimit}} - - GAS_PRICE={{.GasPrice}} - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" - restart: always -` - -// deployNode deploys a new Ethereum node container to a remote machine via SSH, -// docker and docker-compose. If an instance with the specified network name -// already exists there, it will be overwritten! -func deployNode(client *sshClient, network string, bootnodes []string, config *nodeInfos, nocache bool) ([]byte, error) { - kind := "sealnode" - if config.keyJSON == "" && config.etherbase == "" { - kind = "bootnode" - bootnodes = make([]string, 0) - } - // Generate the content to upload to the server - workdir := fmt.Sprintf("%d", rand.Int63()) - files := make(map[string][]byte) - - lightFlag := "" - if config.peersLight > 0 { - lightFlag = fmt.Sprintf("--light.maxpeers=%d --light.serve=50", config.peersLight) - } - dockerfile := new(bytes.Buffer) - template.Must(template.New("").Parse(nodeDockerfile)).Execute(dockerfile, map[string]interface{}{ - "NetworkID": config.network, - "Port": config.port, - "IP": client.address, - "Peers": config.peersTotal, - "LightFlag": lightFlag, - "Bootnodes": strings.Join(bootnodes, ","), - "Ethstats": config.ethstats, - "Etherbase": config.etherbase, - "GasTarget": uint64(1000000 * config.gasTarget), - "GasLimit": uint64(1000000 * config.gasLimit), - "GasPrice": uint64(1000000000 * config.gasPrice), - "Unlock": config.keyJSON != "", - }) - files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes() - - composefile := new(bytes.Buffer) - template.Must(template.New("").Parse(nodeComposefile)).Execute(composefile, map[string]interface{}{ - "Type": kind, - "Datadir": config.datadir, - "Ethashdir": config.ethashdir, - "Network": network, - "Port": config.port, - "TotalPeers": config.peersTotal, - "Light": config.peersLight > 0, - "LightPeers": config.peersLight, - "Ethstats": getEthName(config.ethstats), - "Etherbase": config.etherbase, - "GasTarget": config.gasTarget, - "GasLimit": config.gasLimit, - "GasPrice": config.gasPrice, - }) - files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes() - - files[filepath.Join(workdir, "genesis.json")] = config.genesis - if config.keyJSON != "" { - files[filepath.Join(workdir, "signer.json")] = []byte(config.keyJSON) - files[filepath.Join(workdir, "signer.pass")] = []byte(config.keyPass) - } - // Upload the deployment files to the remote server (and clean up afterwards) - if out, err := client.Upload(files); err != nil { - return out, err - } - defer client.Run("rm -rf " + workdir) - - // Build and deploy the boot or seal node service - if nocache { - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network)) - } - return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network)) -} - -// nodeInfos is returned from a boot or seal node status check to allow reporting -// various configuration parameters. -type nodeInfos struct { - genesis []byte - network int64 - datadir string - ethashdir string - ethstats string - port int - enode string - peersTotal int - peersLight int - etherbase string - keyJSON string - keyPass string - gasTarget float64 - gasLimit float64 - gasPrice float64 -} - -// Report converts the typed struct into a plain string->string map, containing -// most - but not all - fields for reporting to the user. -func (info *nodeInfos) Report() map[string]string { - report := map[string]string{ - "Data directory": info.datadir, - "Listener port": strconv.Itoa(info.port), - "Peer count (all total)": strconv.Itoa(info.peersTotal), - "Peer count (light nodes)": strconv.Itoa(info.peersLight), - "Ethstats username": info.ethstats, - } - if info.gasTarget > 0 { - // Miner or signer node - report["Gas price (minimum accepted)"] = fmt.Sprintf("%0.3f GWei", info.gasPrice) - report["Gas floor (baseline target)"] = fmt.Sprintf("%0.3f MGas", info.gasTarget) - report["Gas ceil (target maximum)"] = fmt.Sprintf("%0.3f MGas", info.gasLimit) - - if info.etherbase != "" { - // Ethash proof-of-work miner - report["Ethash directory"] = info.ethashdir - report["Miner account"] = info.etherbase - } - if info.keyJSON != "" { - // Clique proof-of-authority signer - var key struct { - Address string `json:"address"` - } - if err := json.Unmarshal([]byte(info.keyJSON), &key); err == nil { - report["Signer account"] = common.HexToAddress(key.Address).Hex() - } else { - log.Error("Failed to retrieve signer address", "err", err) - } - } - } - return report -} - -// checkNode does a health-check against a boot or seal node server to verify -// whether it's running, and if yes, whether it's responsive. -func checkNode(client *sshClient, network string, boot bool) (*nodeInfos, error) { - kind := "bootnode" - if !boot { - kind = "sealnode" - } - // Inspect a possible bootnode container on the host - infos, err := inspectContainer(client, fmt.Sprintf("%s_%s_1", network, kind)) - if err != nil { - return nil, err - } - if !infos.running { - return nil, ErrServiceOffline - } - // Resolve a few types from the environmental variables - totalPeers, _ := strconv.Atoi(infos.envvars["TOTAL_PEERS"]) - lightPeers, _ := strconv.Atoi(infos.envvars["LIGHT_PEERS"]) - gasTarget, _ := strconv.ParseFloat(infos.envvars["GAS_TARGET"], 64) - gasLimit, _ := strconv.ParseFloat(infos.envvars["GAS_LIMIT"], 64) - gasPrice, _ := strconv.ParseFloat(infos.envvars["GAS_PRICE"], 64) - - // Container available, retrieve its node ID and its genesis json - var out []byte - if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 geth --exec admin.nodeInfo.enode --cache=16 attach", network, kind)); err != nil { - return nil, ErrServiceUnreachable - } - enode := bytes.Trim(bytes.TrimSpace(out), "\"") - - if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 cat /genesis.json", network, kind)); err != nil { - return nil, ErrServiceUnreachable - } - genesis := bytes.TrimSpace(out) - - keyJSON, keyPass := "", "" - if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 cat /signer.json", network, kind)); err == nil { - keyJSON = string(bytes.TrimSpace(out)) - } - if out, err = client.Run(fmt.Sprintf("docker exec %s_%s_1 cat /signer.pass", network, kind)); err == nil { - keyPass = string(bytes.TrimSpace(out)) - } - // Run a sanity check to see if the devp2p is reachable - port := infos.portmap[infos.envvars["PORT"]] - if err = checkPort(client.server, port); err != nil { - log.Warn(fmt.Sprintf("%s devp2p port seems unreachable", strings.Title(kind)), "server", client.server, "port", port, "err", err) - } - // Assemble and return the useful infos - stats := &nodeInfos{ - genesis: genesis, - datadir: infos.volumes["/root/.ethereum"], - ethashdir: infos.volumes["/root/.ethash"], - port: port, - peersTotal: totalPeers, - peersLight: lightPeers, - ethstats: infos.envvars["STATS_NAME"], - etherbase: infos.envvars["MINER_NAME"], - keyJSON: keyJSON, - keyPass: keyPass, - gasTarget: gasTarget, - gasLimit: gasLimit, - gasPrice: gasPrice, - } - stats.enode = string(enode) - - return stats, nil -} diff --git a/cmd/puppeth/puppeth.go b/cmd/puppeth/puppeth.go deleted file mode 100644 index 415542b60cc9..000000000000 --- a/cmd/puppeth/puppeth.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// puppeth is a command to assemble and maintain private networks. -package main - -import ( - "math/rand" - "os" - "strings" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/urfave/cli/v2" -) - -// main is just a boring entry point to set up the CLI app. -func main() { - app := cli.NewApp() - app.Name = "puppeth" - app.Usage = "assemble and maintain private Ethereum networks" - app.Flags = []cli.Flag{ - &cli.StringFlag{ - Name: "network", - Usage: "name of the network to administer (no spaces or hyphens, please)", - }, - &cli.IntFlag{ - Name: "loglevel", - Value: 3, - Usage: "log level to emit to the screen", - }, - } - app.Before = func(c *cli.Context) error { - // Set up the logger to print everything and the random generator - log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true)))) - rand.Seed(time.Now().UnixNano()) - - return nil - } - app.Action = runWizard - app.Run(os.Args) -} - -// runWizard start the wizard and relinquish control to it. -func runWizard(c *cli.Context) error { - network := c.String("network") - if strings.Contains(network, " ") || strings.Contains(network, "-") || strings.ToLower(network) != network { - log.Crit("No spaces, hyphens or capital letters allowed in network name") - } - makeWizard(c.String("network")).run() - return nil -} diff --git a/cmd/puppeth/ssh.go b/cmd/puppeth/ssh.go deleted file mode 100644 index a20b3bfda209..000000000000 --- a/cmd/puppeth/ssh.go +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "net" - "os" - "os/user" - "path/filepath" - "strings" - - "github.com/ethereum/go-ethereum/log" - "golang.org/x/crypto/ssh" - "golang.org/x/crypto/ssh/agent" - "golang.org/x/term" -) - -// sshClient is a small wrapper around Go's SSH client with a few utility methods -// implemented on top. -type sshClient struct { - server string // Server name or IP without port number - address string // IP address of the remote server - pubkey []byte // RSA public key to authenticate the server - client *ssh.Client - logger log.Logger -} - -const EnvSSHAuthSock = "SSH_AUTH_SOCK" - -// dial establishes an SSH connection to a remote node using the current user and -// the user's configured private RSA key. If that fails, password authentication -// is fallen back to. server can be a string like user:identity@server:port. -func dial(server string, pubkey []byte) (*sshClient, error) { - // Figure out username, identity, hostname and port - hostname := "" - hostport := server - username := "" - identity := "id_rsa" // default - - if strings.Contains(server, "@") { - prefix := server[:strings.Index(server, "@")] - if strings.Contains(prefix, ":") { - username = prefix[:strings.Index(prefix, ":")] - identity = prefix[strings.Index(prefix, ":")+1:] - } else { - username = prefix - } - hostport = server[strings.Index(server, "@")+1:] - } - if strings.Contains(hostport, ":") { - hostname = hostport[:strings.Index(hostport, ":")] - } else { - hostname = hostport - hostport += ":22" - } - logger := log.New("server", server) - logger.Debug("Attempting to establish SSH connection") - - user, err := user.Current() - if err != nil { - return nil, err - } - if username == "" { - username = user.Username - } - - // Configure the supported authentication methods (ssh agent, private key and password) - var ( - auths []ssh.AuthMethod - conn net.Conn - ) - if conn, err = net.Dial("unix", os.Getenv(EnvSSHAuthSock)); err != nil { - log.Warn("Unable to dial SSH agent, falling back to private keys", "err", err) - } else { - client := agent.NewClient(conn) - auths = append(auths, ssh.PublicKeysCallback(client.Signers)) - } - if err != nil { - path := filepath.Join(user.HomeDir, ".ssh", identity) - if buf, err := os.ReadFile(path); err != nil { - log.Warn("No SSH key, falling back to passwords", "path", path, "err", err) - } else { - key, err := ssh.ParsePrivateKey(buf) - if err != nil { - fmt.Printf("What's the decryption password for %s? (won't be echoed)\n>", path) - blob, err := term.ReadPassword(int(os.Stdin.Fd())) - fmt.Println() - if err != nil { - log.Warn("Couldn't read password", "err", err) - } - key, err := ssh.ParsePrivateKeyWithPassphrase(buf, blob) - if err != nil { - log.Warn("Failed to decrypt SSH key, falling back to passwords", "path", path, "err", err) - } else { - auths = append(auths, ssh.PublicKeys(key)) - } - } else { - auths = append(auths, ssh.PublicKeys(key)) - } - } - auths = append(auths, ssh.PasswordCallback(func() (string, error) { - fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", username, server) - blob, err := term.ReadPassword(int(os.Stdin.Fd())) - - fmt.Println() - return string(blob), err - })) - } - // Resolve the IP address of the remote server - addr, err := net.LookupHost(hostname) - if err != nil { - return nil, err - } - if len(addr) == 0 { - return nil, errors.New("no IPs associated with domain") - } - // Try to dial in to the remote server - logger.Trace("Dialing remote SSH server", "user", username) - keycheck := func(hostname string, remote net.Addr, key ssh.PublicKey) error { - // If no public key is known for SSH, ask the user to confirm - if pubkey == nil { - fmt.Println() - fmt.Printf("The authenticity of host '%s (%s)' can't be established.\n", hostname, remote) - fmt.Printf("SSH key fingerprint is %s [MD5]\n", ssh.FingerprintLegacyMD5(key)) - fmt.Printf("Are you sure you want to continue connecting (yes/no)? ") - - for { - text, err := bufio.NewReader(os.Stdin).ReadString('\n') - switch { - case err != nil: - return err - case strings.TrimSpace(text) == "yes": - pubkey = key.Marshal() - return nil - case strings.TrimSpace(text) == "no": - return errors.New("users says no") - default: - fmt.Println("Please answer 'yes' or 'no'") - continue - } - } - } - // If a public key exists for this SSH server, check that it matches - if bytes.Equal(pubkey, key.Marshal()) { - return nil - } - // We have a mismatch, forbid connecting - return errors.New("ssh key mismatch, re-add the machine to update") - } - client, err := ssh.Dial("tcp", hostport, &ssh.ClientConfig{User: username, Auth: auths, HostKeyCallback: keycheck}) - if err != nil { - return nil, err - } - // Connection established, return our utility wrapper - c := &sshClient{ - server: hostname, - address: addr[0], - pubkey: pubkey, - client: client, - logger: logger, - } - if err := c.init(); err != nil { - client.Close() - return nil, err - } - return c, nil -} - -// init runs some initialization commands on the remote server to ensure it's -// capable of acting as puppeth target. -func (client *sshClient) init() error { - client.logger.Debug("Verifying if docker is available") - if out, err := client.Run("docker version"); err != nil { - if len(out) == 0 { - return err - } - return fmt.Errorf("docker configured incorrectly: %s", out) - } - client.logger.Debug("Verifying if docker-compose is available") - if out, err := client.Run("docker-compose version"); err != nil { - if len(out) == 0 { - return err - } - return fmt.Errorf("docker-compose configured incorrectly: %s", out) - } - return nil -} - -// Close terminates the connection to an SSH server. -func (client *sshClient) Close() error { - return client.client.Close() -} - -// Run executes a command on the remote server and returns the combined output -// along with any error status. -func (client *sshClient) Run(cmd string) ([]byte, error) { - // Establish a single command session - session, err := client.client.NewSession() - if err != nil { - return nil, err - } - defer session.Close() - - // Execute the command and return any output - client.logger.Trace("Running command on remote server", "cmd", cmd) - return session.CombinedOutput(cmd) -} - -// Stream executes a command on the remote server and streams all outputs into -// the local stdout and stderr streams. -func (client *sshClient) Stream(cmd string) error { - // Establish a single command session - session, err := client.client.NewSession() - if err != nil { - return err - } - defer session.Close() - - session.Stdout = os.Stdout - session.Stderr = os.Stderr - - // Execute the command and return any output - client.logger.Trace("Streaming command on remote server", "cmd", cmd) - return session.Run(cmd) -} - -// Upload copies the set of files to a remote server via SCP, creating any non- -// existing folders in the mean time. -func (client *sshClient) Upload(files map[string][]byte) ([]byte, error) { - // Establish a single command session - session, err := client.client.NewSession() - if err != nil { - return nil, err - } - defer session.Close() - - // Create a goroutine that streams the SCP content - go func() { - out, _ := session.StdinPipe() - defer out.Close() - - for file, content := range files { - client.logger.Trace("Uploading file to server", "file", file, "bytes", len(content)) - - fmt.Fprintln(out, "D0755", 0, filepath.Dir(file)) // Ensure the folder exists - fmt.Fprintln(out, "C0644", len(content), filepath.Base(file)) // Create the actual file - out.Write(content) // Stream the data content - fmt.Fprint(out, "\x00") // Transfer end with \x00 - fmt.Fprintln(out, "E") // Leave directory (simpler) - } - }() - return session.CombinedOutput("/usr/bin/scp -v -tr ./") -} diff --git a/cmd/puppeth/wizard.go b/cmd/puppeth/wizard.go deleted file mode 100644 index 6e5ca41d68fa..000000000000 --- a/cmd/puppeth/wizard.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "encoding/json" - "fmt" - "math/big" - "net" - "net/url" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/console/prompt" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/log" - "github.com/peterh/liner" - "golang.org/x/term" -) - -// config contains all the configurations needed by puppeth that should be saved -// between sessions. -type config struct { - path string // File containing the configuration values - bootnodes []string // Bootnodes to always connect to by all nodes - ethstats string // Ethstats settings to cache for node deploys - - Genesis *core.Genesis `json:"genesis,omitempty"` // Genesis block to cache for node deploys - Servers map[string][]byte `json:"servers,omitempty"` -} - -// servers retrieves an alphabetically sorted list of servers. -func (c config) servers() []string { - servers := make([]string, 0, len(c.Servers)) - for server := range c.Servers { - servers = append(servers, server) - } - sort.Strings(servers) - - return servers -} - -// flush dumps the contents of config to disk. -func (c config) flush() { - os.MkdirAll(filepath.Dir(c.path), 0755) - - out, _ := json.MarshalIndent(c, "", " ") - if err := os.WriteFile(c.path, out, 0644); err != nil { - log.Warn("Failed to save puppeth configs", "file", c.path, "err", err) - } -} - -type wizard struct { - network string // Network name to manage - conf config // Configurations from previous runs - - servers map[string]*sshClient // SSH connections to servers to administer - services map[string][]string // Ethereum services known to be running on servers - - lock sync.Mutex // Lock to protect configs during concurrent service discovery -} - -// prompts the user for input with the given prompt string. Returns when a value is entered. -// Causes the wizard to exit if ctrl-d is pressed -func promptInput(p string) string { - for { - text, err := prompt.Stdin.PromptInput(p) - if err != nil { - if err != liner.ErrPromptAborted { - log.Crit("Failed to read user input", "err", err) - } - } else { - return text - } - } -} - -// read reads a single line from stdin, trimming if from spaces. -func (w *wizard) read() string { - text := promptInput("> ") - return strings.TrimSpace(text) -} - -// readString reads a single line from stdin, trimming if from spaces, enforcing -// non-emptyness. -func (w *wizard) readString() string { - for { - text := promptInput("> ") - if text = strings.TrimSpace(text); text != "" { - return text - } - } -} - -// readDefaultString reads a single line from stdin, trimming if from spaces. If -// an empty line is entered, the default value is returned. -func (w *wizard) readDefaultString(def string) string { - text := promptInput("> ") - if text = strings.TrimSpace(text); text != "" { - return text - } - return def -} - -// readDefaultYesNo reads a single line from stdin, trimming if from spaces and -// interpreting it as a 'yes' or a 'no'. If an empty line is entered, the default -// value is returned. -func (w *wizard) readDefaultYesNo(def bool) bool { - for { - text := promptInput("> ") - if text = strings.ToLower(strings.TrimSpace(text)); text == "" { - return def - } - if text == "y" || text == "yes" { - return true - } - if text == "n" || text == "no" { - return false - } - log.Error("Invalid input, expected 'y', 'yes', 'n', 'no' or empty") - } -} - -// readURL reads a single line from stdin, trimming if from spaces and trying to -// interpret it as a URL (http, https or file). -func (w *wizard) readURL() *url.URL { - for { - text := promptInput("> ") - uri, err := url.Parse(strings.TrimSpace(text)) - if err != nil { - log.Error("Invalid input, expected URL", "err", err) - continue - } - return uri - } -} - -// readInt reads a single line from stdin, trimming if from spaces, enforcing it -// to parse into an integer. -func (w *wizard) readInt() int { - for { - text := promptInput("> ") - if text = strings.TrimSpace(text); text == "" { - continue - } - val, err := strconv.Atoi(strings.TrimSpace(text)) - if err != nil { - log.Error("Invalid input, expected integer", "err", err) - continue - } - return val - } -} - -// readDefaultInt reads a single line from stdin, trimming if from spaces, enforcing -// it to parse into an integer. If an empty line is entered, the default value is -// returned. -func (w *wizard) readDefaultInt(def int) int { - for { - text := promptInput("> ") - if text = strings.TrimSpace(text); text == "" { - return def - } - val, err := strconv.Atoi(strings.TrimSpace(text)) - if err != nil { - log.Error("Invalid input, expected integer", "err", err) - continue - } - return val - } -} - -// readDefaultBigInt reads a single line from stdin, trimming if from spaces, -// enforcing it to parse into a big integer. If an empty line is entered, the -// default value is returned. -func (w *wizard) readDefaultBigInt(def *big.Int) *big.Int { - for { - text := promptInput("> ") - if text = strings.TrimSpace(text); text == "" { - return def - } - val, ok := new(big.Int).SetString(text, 0) - if !ok { - log.Error("Invalid input, expected big integer") - continue - } - return val - } -} - -// readDefaultFloat reads a single line from stdin, trimming if from spaces, enforcing -// it to parse into a float. If an empty line is entered, the default value is returned. -func (w *wizard) readDefaultFloat(def float64) float64 { - for { - text := promptInput("> ") - if text = strings.TrimSpace(text); text == "" { - return def - } - val, err := strconv.ParseFloat(strings.TrimSpace(text), 64) - if err != nil { - log.Error("Invalid input, expected float", "err", err) - continue - } - return val - } -} - -// readPassword reads a single line from stdin, trimming it from the trailing new -// line and returns it. The input will not be echoed. -func (w *wizard) readPassword() string { - fmt.Printf("> ") - text, err := term.ReadPassword(int(os.Stdin.Fd())) - if err != nil { - log.Crit("Failed to read password", "err", err) - } - fmt.Println() - return string(text) -} - -// readAddress reads a single line from stdin, trimming if from spaces and converts -// it to an Ethereum address. -func (w *wizard) readAddress() *common.Address { - for { - text := promptInput("> 0x") - if text = strings.TrimSpace(text); text == "" { - return nil - } - // Make sure it looks ok and return it if so - if len(text) != 40 { - log.Error("Invalid address length, please retry") - continue - } - bigaddr, _ := new(big.Int).SetString(text, 16) - address := common.BigToAddress(bigaddr) - return &address - } -} - -// readDefaultAddress reads a single line from stdin, trimming if from spaces and -// converts it to an Ethereum address. If an empty line is entered, the default -// value is returned. -func (w *wizard) readDefaultAddress(def common.Address) common.Address { - for { - // Read the address from the user - text := promptInput("> 0x") - if text = strings.TrimSpace(text); text == "" { - return def - } - // Make sure it looks ok and return it if so - if len(text) != 40 { - log.Error("Invalid address length, please retry") - continue - } - bigaddr, _ := new(big.Int).SetString(text, 16) - return common.BigToAddress(bigaddr) - } -} - -// readJSON reads a raw JSON message and returns it. -func (w *wizard) readJSON() string { - var blob json.RawMessage - - for { - text := promptInput("> ") - reader := strings.NewReader(text) - if err := json.NewDecoder(reader).Decode(&blob); err != nil { - log.Error("Invalid JSON, please try again", "err", err) - continue - } - return string(blob) - } -} - -// readIPAddress reads a single line from stdin, trimming if from spaces and -// returning it if it's convertible to an IP address. The reason for keeping -// the user input format instead of returning a Go net.IP is to match with -// weird formats used by ethstats, which compares IPs textually, not by value. -func (w *wizard) readIPAddress() string { - for { - // Read the IP address from the user - fmt.Printf("> ") - text := promptInput("> ") - if text = strings.TrimSpace(text); text == "" { - return "" - } - // Make sure it looks ok and return it if so - if ip := net.ParseIP(text); ip == nil { - log.Error("Invalid IP address, please retry") - continue - } - return text - } -} diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go deleted file mode 100644 index ac17bc7b271c..000000000000 --- a/cmd/puppeth/wizard_genesis.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "math/big" - "math/rand" - "net/http" - "os" - "path/filepath" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" -) - -// makeGenesis creates a new genesis struct based on some user input. -func (w *wizard) makeGenesis() { - // Construct a default genesis block - genesis := &core.Genesis{ - Timestamp: uint64(time.Now().Unix()), - GasLimit: 4700000, - Difficulty: big.NewInt(524288), - Alloc: make(core.GenesisAlloc), - Config: ¶ms.ChainConfig{ - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - }, - } - // Figure out which consensus engine to choose - fmt.Println() - fmt.Println("Which consensus engine to use? (default = clique)") - fmt.Println(" 1. Ethash - proof-of-work") - fmt.Println(" 2. Clique - proof-of-authority") - - choice := w.read() - switch { - case choice == "1": - // In case of ethash, we're pretty much done - genesis.Config.Ethash = new(params.EthashConfig) - genesis.ExtraData = make([]byte, 32) - - case choice == "" || choice == "2": - // In the case of clique, configure the consensus parameters - genesis.Difficulty = big.NewInt(1) - genesis.Config.Clique = ¶ms.CliqueConfig{ - Period: 15, - Epoch: 30000, - } - fmt.Println() - fmt.Println("How many seconds should blocks take? (default = 15)") - genesis.Config.Clique.Period = uint64(w.readDefaultInt(15)) - - // We also need the initial list of signers - fmt.Println() - fmt.Println("Which accounts are allowed to seal? (mandatory at least one)") - - var signers []common.Address - for { - if address := w.readAddress(); address != nil { - signers = append(signers, *address) - continue - } - if len(signers) > 0 { - break - } - } - // Sort the signers and embed into the extra-data section - for i := 0; i < len(signers); i++ { - for j := i + 1; j < len(signers); j++ { - if bytes.Compare(signers[i][:], signers[j][:]) > 0 { - signers[i], signers[j] = signers[j], signers[i] - } - } - } - genesis.ExtraData = make([]byte, 32+len(signers)*common.AddressLength+65) - for i, signer := range signers { - copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:]) - } - - default: - log.Crit("Invalid consensus engine choice", "choice", choice) - } - // Consensus all set, just ask for initial funds and go - fmt.Println() - fmt.Println("Which accounts should be pre-funded? (advisable at least one)") - for { - // Read the address of the account to fund - if address := w.readAddress(); address != nil { - genesis.Alloc[*address] = core.GenesisAccount{ - Balance: new(big.Int).Lsh(big.NewInt(1), 256-7), // 2^256 / 128 (allow many pre-funds without balance overflows) - } - continue - } - break - } - fmt.Println() - fmt.Println("Should the precompile-addresses (0x1 .. 0xff) be pre-funded with 1 wei? (advisable yes)") - if w.readDefaultYesNo(true) { - // Add a batch of precompile balances to avoid them getting deleted - for i := int64(0); i < 256; i++ { - genesis.Alloc[common.BigToAddress(big.NewInt(i))] = core.GenesisAccount{Balance: big.NewInt(1)} - } - } - // Query the user for some custom extras - fmt.Println() - fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)") - genesis.Config.ChainID = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536)))) - - // All done, store the genesis and flush to disk - log.Info("Configured new genesis block") - - w.conf.Genesis = genesis - w.conf.flush() -} - -// importGenesis imports a Geth genesis spec into puppeth. -func (w *wizard) importGenesis() { - // Request the genesis JSON spec URL from the user - fmt.Println() - fmt.Println("Where's the genesis file? (local file or http/https url)") - url := w.readURL() - - // Convert the various allowed URLs to a reader stream - var reader io.Reader - - switch url.Scheme { - case "http", "https": - // Remote web URL, retrieve it via an HTTP client - res, err := http.Get(url.String()) - if err != nil { - log.Error("Failed to retrieve remote genesis", "err", err) - return - } - defer res.Body.Close() - reader = res.Body - - case "": - // Schemaless URL, interpret as a local file - file, err := os.Open(url.String()) - if err != nil { - log.Error("Failed to open local genesis", "err", err) - return - } - defer file.Close() - reader = file - - default: - log.Error("Unsupported genesis URL scheme", "scheme", url.Scheme) - return - } - // Parse the genesis file and inject it successful - var genesis core.Genesis - if err := json.NewDecoder(reader).Decode(&genesis); err != nil { - log.Error("Invalid genesis spec", "err", err) - return - } - log.Info("Imported genesis block") - - w.conf.Genesis = &genesis - w.conf.flush() -} - -// manageGenesis permits the modification of chain configuration parameters in -// a genesis config and the export of the entire genesis spec. -func (w *wizard) manageGenesis() { - // Figure out whether to modify or export the genesis - fmt.Println() - fmt.Println(" 1. Modify existing configurations") - fmt.Println(" 2. Export genesis configurations") - fmt.Println(" 3. Remove genesis configuration") - - choice := w.read() - switch choice { - case "1": - // Fork rule updating requested, iterate over each fork - fmt.Println() - fmt.Printf("Which block should Homestead come into effect? (default = %v)\n", w.conf.Genesis.Config.HomesteadBlock) - w.conf.Genesis.Config.HomesteadBlock = w.readDefaultBigInt(w.conf.Genesis.Config.HomesteadBlock) - - fmt.Println() - fmt.Printf("Which block should EIP150 (Tangerine Whistle) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP150Block) - w.conf.Genesis.Config.EIP150Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP150Block) - - fmt.Println() - fmt.Printf("Which block should EIP155 (Spurious Dragon) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP155Block) - w.conf.Genesis.Config.EIP155Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP155Block) - - fmt.Println() - fmt.Printf("Which block should EIP158/161 (also Spurious Dragon) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP158Block) - w.conf.Genesis.Config.EIP158Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP158Block) - - fmt.Println() - fmt.Printf("Which block should Byzantium come into effect? (default = %v)\n", w.conf.Genesis.Config.ByzantiumBlock) - w.conf.Genesis.Config.ByzantiumBlock = w.readDefaultBigInt(w.conf.Genesis.Config.ByzantiumBlock) - - fmt.Println() - fmt.Printf("Which block should Constantinople come into effect? (default = %v)\n", w.conf.Genesis.Config.ConstantinopleBlock) - w.conf.Genesis.Config.ConstantinopleBlock = w.readDefaultBigInt(w.conf.Genesis.Config.ConstantinopleBlock) - if w.conf.Genesis.Config.PetersburgBlock == nil { - w.conf.Genesis.Config.PetersburgBlock = w.conf.Genesis.Config.ConstantinopleBlock - } - fmt.Println() - fmt.Printf("Which block should Petersburg come into effect? (default = %v)\n", w.conf.Genesis.Config.PetersburgBlock) - w.conf.Genesis.Config.PetersburgBlock = w.readDefaultBigInt(w.conf.Genesis.Config.PetersburgBlock) - - fmt.Println() - fmt.Printf("Which block should Istanbul come into effect? (default = %v)\n", w.conf.Genesis.Config.IstanbulBlock) - w.conf.Genesis.Config.IstanbulBlock = w.readDefaultBigInt(w.conf.Genesis.Config.IstanbulBlock) - - fmt.Println() - fmt.Printf("Which block should Berlin come into effect? (default = %v)\n", w.conf.Genesis.Config.BerlinBlock) - w.conf.Genesis.Config.BerlinBlock = w.readDefaultBigInt(w.conf.Genesis.Config.BerlinBlock) - - fmt.Println() - fmt.Printf("Which block should London come into effect? (default = %v)\n", w.conf.Genesis.Config.LondonBlock) - w.conf.Genesis.Config.LondonBlock = w.readDefaultBigInt(w.conf.Genesis.Config.LondonBlock) - - out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", " ") - fmt.Printf("Chain configuration updated:\n\n%s\n", out) - - w.conf.flush() - - case "2": - // Save whatever genesis configuration we currently have - fmt.Println() - fmt.Printf("Which folder to save the genesis spec into? (default = current)\n") - fmt.Printf(" Will create %s.json\n", w.network) - - folder := w.readDefaultString(".") - if err := os.MkdirAll(folder, 0755); err != nil { - log.Error("Failed to create spec folder", "folder", folder, "err", err) - return - } - out, _ := json.MarshalIndent(w.conf.Genesis, "", " ") - - // Export the native genesis spec used by puppeth and Geth - gethJson := filepath.Join(folder, fmt.Sprintf("%s.json", w.network)) - if err := os.WriteFile(gethJson, out, 0644); err != nil { - log.Error("Failed to save genesis file", "err", err) - return - } - log.Info("Saved native genesis chain spec", "path", gethJson) - - case "3": - // Make sure we don't have any services running - if len(w.conf.servers()) > 0 { - log.Error("Genesis reset requires all services and servers torn down") - return - } - log.Info("Genesis block destroyed") - - w.conf.Genesis = nil - w.conf.flush() - default: - log.Error("That's not something I can do") - return - } -} diff --git a/consensus/misc/forks.go b/consensus/misc/forks.go deleted file mode 100644 index a6f3303ea6fa..000000000000 --- a/consensus/misc/forks.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 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 misc - -import ( - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" -) - -// VerifyForkHashes verifies that blocks conforming to network hard-forks do have -// the correct hashes, to avoid clients going off on different chains. This is an -// optional feature. -func VerifyForkHashes(config *params.ChainConfig, header *types.Header, uncle bool) error { - // We don't care about uncles - if uncle { - return nil - } - // If the homestead reprice hash is set, validate it - if config.EIP150Block != nil && config.EIP150Block.Cmp(header.Number) == 0 { - if config.EIP150Hash != (common.Hash{}) && config.EIP150Hash != header.Hash() { - return fmt.Errorf("homestead gas reprice fork: have %#x, want %#x", header.Hash(), config.EIP150Hash) - } - } - // All ok, return - return nil -} diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 6e9856d680f6..21a9c6676bd5 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -62,12 +62,6 @@ func (bc *BlockChain) CurrentSafeBlock() *types.Header { return bc.currentSafeBlock.Load() } -// CurrentSafeBlock retrieves the current safe block of the canonical -// chain. The block is retrieved from the blockchain's internal cache. -func (bc *BlockChain) CurrentSafeBlock() *types.Block { - return bc.currentSafeBlock.Load().(*types.Block) -} - // HasHeader checks if a block header is present in the database or not, caching // it if present. func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool { diff --git a/core/state/database.go b/core/state/database.go index 262898dbea98..82f620b46083 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -99,9 +99,6 @@ type Trie interface { // DeleteAccount abstracts an account deletion from the trie. DeleteAccount(address common.Address) error - // TryDeleteAccount abstracts an account deletion from the trie. - TryDeleteAccount(key []byte) error - // Hash returns the root hash of the trie. It does not write to the database and // can be used even if the trie doesn't have one. Hash() common.Hash diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 4eb5a48bb593..68c2f574b873 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -228,7 +228,7 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, trieId *trie.ID, prefix [ // The snap state is exhausted, pass the entire key/val set for verification root := trieId.Root if origin == nil && !diskMore { - stackTr := trie.NewStackTrieWithOwner(nil, owner) + stackTr := trie.NewStackTrie(nil) for i, key := range keys { stackTr.Update(key, vals[i]) } diff --git a/core/state/statedb.go b/core/state/statedb.go index bf48055ef675..b89f4bfd8c32 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1024,13 +1024,6 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { } accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size() } - // Merge the dirty nodes of account trie into global set - if set != nil { - if err := nodes.Merge(set); err != nil { - return common.Hash{}, err - } - accountTrieNodes = set.Len() - } if metrics.EnabledExpensive { s.AccountCommits += time.Since(start) diff --git a/eth/api_backend.go b/eth/api_backend.go index 064674d7a80e..ac160b0736a1 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -143,9 +143,6 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe header := b.eth.blockchain.CurrentSafeBlock() return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil } - if number == rpc.SafeBlockNumber { - return b.eth.blockchain.CurrentSafeBlock(), nil - } return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil } diff --git a/eth/backend.go b/eth/backend.go index af26eb719587..6368c0e03c56 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -22,7 +22,6 @@ import ( "fmt" "math/big" "runtime" - "strings" "sync" "sync/atomic" diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index f7d155a18151..1fe98424723b 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -20,7 +20,6 @@ package catalyst import ( "errors" "fmt" - "math/big" "sync" "time" @@ -473,10 +472,6 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData) (engine.Payloa if res := api.checkInvalidAncestor(block.Hash(), block.Hash()); res != nil { return *res, nil } - // If this block was rejected previously, keep rejecting it - if res := api.checkInvalidAncestor(block.Hash(), block.Hash()); res != nil { - return *res, nil - } // If the parent is missing, we - in theory - could trigger a sync, but that // would also entail a reorg. That is problematic if multiple sibling blocks // are being fed to us, and even more so, if some semi-distant uncle shortens @@ -640,106 +635,6 @@ func (api *ConsensusAPI) checkInvalidAncestor(check common.Hash, head common.Has } } -// delayPayloadImport stashes the given block away for import at a later time, -// either via a forkchoice update or a sync extension. This method is meant to -// be called by the newpayload command when the block seems to be ok, but some -// prerequisite prevents it from being processed (e.g. no parent, or snap sync). -func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (beacon.PayloadStatusV1, error) { - // Sanity check that this block's parent is not on a previously invalidated - // chain. If it is, mark the block as invalid too. - if res := api.checkInvalidAncestor(block.ParentHash(), block.Hash()); res != nil { - return *res, nil - } - // Stash the block away for a potential forced forkchoice update to it - // at a later time. - api.remoteBlocks.put(block.Hash(), block.Header()) - - // Although we don't want to trigger a sync, if there is one already in - // progress, try to extend if with the current payload request to relieve - // some strain from the forkchoice update. - if err := api.eth.Downloader().BeaconExtend(api.eth.SyncMode(), block.Header()); err == nil { - log.Debug("Payload accepted for sync extension", "number", block.NumberU64(), "hash", block.Hash()) - return beacon.PayloadStatusV1{Status: beacon.SYNCING}, nil - } - // Either no beacon sync was started yet, or it rejected the delivered - // payload as non-integratable on top of the existing sync. We'll just - // have to rely on the beacon client to forcefully update the head with - // a forkchoice update request. - if api.eth.SyncMode() == downloader.FullSync { - // In full sync mode, failure to import a well-formed block can only mean - // that the parent state is missing and the syncer rejected extending the - // current cycle with the new payload. - log.Warn("Ignoring payload with missing parent", "number", block.NumberU64(), "hash", block.Hash(), "parent", block.ParentHash()) - } else { - // In non-full sync mode (i.e. snap sync) all payloads are rejected until - // snap sync terminates as snap sync relies on direct database injections - // and cannot afford concurrent out-if-band modifications via imports. - log.Warn("Ignoring payload while snap syncing", "number", block.NumberU64(), "hash", block.Hash()) - } - return beacon.PayloadStatusV1{Status: beacon.SYNCING}, nil -} - -// setInvalidAncestor is a callback for the downloader to notify us if a bad block -// is encountered during the async sync. -func (api *ConsensusAPI) setInvalidAncestor(invalid *types.Header, origin *types.Header) { - api.invalidLock.Lock() - defer api.invalidLock.Unlock() - - api.invalidTipsets[origin.Hash()] = invalid - api.invalidBlocksHits[invalid.Hash()]++ -} - -// checkInvalidAncestor checks whether the specified chain end links to a known -// bad ancestor. If yes, it constructs the payload failure response to return. -func (api *ConsensusAPI) checkInvalidAncestor(check common.Hash, head common.Hash) *beacon.PayloadStatusV1 { - api.invalidLock.Lock() - defer api.invalidLock.Unlock() - - // If the hash to check is unknown, return valid - invalid, ok := api.invalidTipsets[check] - if !ok { - return nil - } - // If the bad hash was hit too many times, evict it and try to reprocess in - // the hopes that we have a data race that we can exit out of. - badHash := invalid.Hash() - - api.invalidBlocksHits[badHash]++ - if api.invalidBlocksHits[badHash] >= invalidBlockHitEviction { - log.Warn("Too many bad block import attempt, trying", "number", invalid.Number, "hash", badHash) - delete(api.invalidBlocksHits, badHash) - - for descendant, badHeader := range api.invalidTipsets { - if badHeader.Hash() == badHash { - delete(api.invalidTipsets, descendant) - } - } - return nil - } - // Not too many failures yet, mark the head of the invalid chain as invalid - if check != head { - log.Warn("Marked new chain head as invalid", "hash", head, "badnumber", invalid.Number, "badhash", badHash) - for len(api.invalidTipsets) >= invalidTipsetsCap { - for key := range api.invalidTipsets { - delete(api.invalidTipsets, key) - break - } - } - api.invalidTipsets[head] = invalid - } - // If the last valid hash is the terminal pow block, return 0x0 for latest valid hash - lastValid := &invalid.ParentHash - if header := api.eth.BlockChain().GetHeader(invalid.ParentHash, invalid.Number.Uint64()-1); header != nil && header.Difficulty.Sign() != 0 { - lastValid = &common.Hash{} - } - failure := "links to previously rejected block" - return &beacon.PayloadStatusV1{ - Status: beacon.INVALID, - LatestValidHash: lastValid, - ValidationError: &failure, - } -} - // invalid returns a response "INVALID" with the latest valid hash supplied by latest or to the current head // if no latestValid block was provided. func (api *ConsensusAPI) invalid(err error, latestValid *types.Header) engine.PayloadStatusV1 { @@ -879,127 +774,3 @@ func getBody(block *types.Block) *engine.ExecutionPayloadBodyV1 { Withdrawals: withdrawals, } } - -// heartbeat loops indefinitely, and checks if there have been beacon client updates -// received in the last while. If not - or if they but strange ones - it warns the -// user that something might be off with their consensus node. -// -// TODO(karalabe): Spin this goroutine down somehow -func (api *ConsensusAPI) heartbeat() { - // Sleep a bit on startup since there's obviously no beacon client yet - // attached, so no need to print scary warnings to the user. - time.Sleep(beaconUpdateStartupTimeout) - - var ( - offlineLogged time.Time - ) - for { - // Sleep a bit and retrieve the last known consensus updates - time.Sleep(5 * time.Second) - - // If the network is not yet merged/merging, don't bother scaring the user - ttd := api.eth.BlockChain().Config().TerminalTotalDifficulty - if ttd == nil { - continue - } - api.lastTransitionLock.Lock() - lastTransitionUpdate := api.lastTransitionUpdate - api.lastTransitionLock.Unlock() - - api.lastForkchoiceLock.Lock() - lastForkchoiceUpdate := api.lastForkchoiceUpdate - api.lastForkchoiceLock.Unlock() - - api.lastNewPayloadLock.Lock() - lastNewPayloadUpdate := api.lastNewPayloadUpdate - api.lastNewPayloadLock.Unlock() - - // If there have been no updates for the past while, warn the user - // that the beacon client is probably offline - if api.eth.BlockChain().Config().TerminalTotalDifficultyPassed || api.eth.Merger().TDDReached() { - if time.Since(lastForkchoiceUpdate) > beaconUpdateConsensusTimeout && time.Since(lastNewPayloadUpdate) > beaconUpdateConsensusTimeout { - if time.Since(lastTransitionUpdate) > beaconUpdateExchangeTimeout { - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - if lastTransitionUpdate.IsZero() { - log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!") - } else { - log.Warn("Previously seen beacon client is offline. Please ensure it is operational to follow the chain!") - } - offlineLogged = time.Now() - } - continue - } - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() { - log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") - } else { - log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!") - } - offlineLogged = time.Now() - } - continue - } else { - offlineLogged = time.Time{} - } - } else { - if time.Since(lastTransitionUpdate) > beaconUpdateExchangeTimeout { - if time.Since(offlineLogged) > beaconUpdateWarnFrequency { - // Retrieve the last few blocks and make a rough estimate as - // to when the merge transition should happen - var ( - chain = api.eth.BlockChain() - head = chain.CurrentBlock() - htd = chain.GetTd(head.Hash(), head.NumberU64()) - eta time.Duration - ) - if head.NumberU64() > 0 && htd.Cmp(ttd) < 0 { - // Accumulate the last 64 difficulties to estimate the growth - var diff float64 - - block := head - for i := 0; i < 64; i++ { - diff += float64(block.Difficulty().Uint64()) - if parent := chain.GetBlock(block.ParentHash(), block.NumberU64()-1); parent == nil { - break - } else { - block = parent - } - } - // Estimate an ETA based on the block times and the difficulty growth - growth := diff / float64(head.Time()-block.Time()+1) // +1 to avoid div by zero - if growth > 0 { - if left := new(big.Int).Sub(ttd, htd); left.IsUint64() { - eta = time.Duration(float64(left.Uint64())/growth) * time.Second - } else { - eta = time.Duration(new(big.Int).Div(left, big.NewInt(int64(growth))).Uint64()) * time.Second - } - } - } - var message string - if htd.Cmp(ttd) > 0 { - if lastTransitionUpdate.IsZero() { - message = "Merge already reached, but no beacon client seen. Please launch one to follow the chain!" - } else { - message = "Merge already reached, but previously seen beacon client is offline. Please ensure it is operational to follow the chain!" - } - } else { - if lastTransitionUpdate.IsZero() { - message = "Merge is configured, but no beacon client seen. Please ensure you have one available before the transition arrives!" - } else { - message = "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transition arrives!" - } - } - if eta == 0 { - log.Warn(message) - } else { - log.Warn(message, "eta", common.PrettyAge(time.Now().Add(-eta))) // weird hack, but duration formatted doesn't handle days - } - offlineLogged = time.Now() - } - continue - } else { - offlineLogged = time.Time{} - } - } - } -} diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 2f34bc2c2879..b7255a242e9f 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -289,8 +289,5 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.OverrideShanghai != nil { c.OverrideShanghai = dec.OverrideShanghai } - if dec.OverrideTerminalTotalDifficultyPassed != nil { - c.OverrideTerminalTotalDifficultyPassed = dec.OverrideTerminalTotalDifficultyPassed - } return nil } diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 7af94996bfbd..03f39691ab3a 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -104,7 +104,7 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { if header == nil { return nil, errors.New("unknown block") } - return f.blockLogs(ctx, header, false) + return f.blockLogs(ctx, header) } // Short-cut if all we care about is pending logs if f.begin == rpc.PendingBlockNumber.Int64() { @@ -223,7 +223,7 @@ func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, err if header == nil || err != nil { return logs, err } - found, err := f.blockLogs(ctx, header, true) + found, err := f.blockLogs(ctx, header) if err != nil { return logs, err } @@ -248,7 +248,7 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e if header == nil || err != nil { return logs, err } - found, err := f.blockLogs(ctx, header, false) + found, err := f.blockLogs(ctx, header) if err != nil { return logs, err } @@ -313,19 +313,6 @@ func (f *Filter) pendingLogs() ([]*types.Log, error) { return nil, nil } -// pendingLogs returns the logs matching the filter criteria within the pending block. -func (f *Filter) pendingLogs() ([]*types.Log, error) { - block, receipts := f.sys.backend.PendingBlockAndReceipts() - if bloomFilter(block.Bloom(), f.addresses, f.topics) { - var unfiltered []*types.Log - for _, r := range receipts { - unfiltered = append(unfiltered, r.Logs...) - } - return filterLogs(unfiltered, nil, nil, f.addresses, f.topics), nil - } - return nil, nil -} - func includes(addresses []common.Address, a common.Address) bool { for _, addr := range addresses { if addr == a { diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index ddb2e277f93c..9fc20f335b1a 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -37,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - lru "github.com/hashicorp/golang-lru" ) // Config represents the configuration of the filter system. diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 6c03f00ffacd..55781ac54b74 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index af513a1dfaca..4ac03e512fb7 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -111,10 +111,6 @@ type callTracerConfig struct { WithLog bool `json:"withLog"` // If true, call tracer will collect event logs } -type callTracerConfig struct { - OnlyTopCall bool `json:"onlyTopCall"` // If true, call tracer won't collect any subcalls -} - // newCallTracer returns a native go tracer which tracks // call frames of a tx, and implements vm.EVMLogger. func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { diff --git a/eth/tracers/native/revertreason.go b/eth/tracers/native/revertreason.go deleted file mode 100644 index d09b86100901..000000000000 --- a/eth/tracers/native/revertreason.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2022 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 native - -import ( - "bytes" - "encoding/json" - "math/big" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers" -) - -func init() { - register("revertReasonTracer", newRevertReasonTracer) -} - -var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4] - -// revertReasonTracer is a go implementation of the Tracer interface which -// track the error message or revert reason return by the contract. -type revertReasonTracer struct { - env *vm.EVM - revertReason string // The revert reason return from the tx, if tx success, empty string return - interrupt uint32 // Atomic flag to signal execution interruption - reason error // Textual reason for the interruption -} - -// newRevertReasonTracer returns a new revert reason tracer. -func newRevertReasonTracer(_ *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { - return &revertReasonTracer{}, nil -} - -// CaptureStart implements the EVMLogger interface to initialize the tracing operation. -func (t *revertReasonTracer) CaptureStart(env *vm.EVM, _ common.Address, _ common.Address, _ bool, _ []byte, _ uint64, _ *big.Int) { - t.env = env -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (t *revertReasonTracer) CaptureEnd(output []byte, _ uint64, _ time.Duration, err error) { - if err != nil { - if err == vm.ErrExecutionReverted && len(output) > 4 && bytes.Equal(output[:4], revertSelector) { - errMsg, _ := abi.UnpackRevert(output) - t.revertReason = err.Error() + ": " + errMsg - } else { - t.revertReason = err.Error() - } - } -} - -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *revertReasonTracer) CaptureState(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ []byte, _ int, _ error) { -} - -// CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *revertReasonTracer) CaptureFault(_ uint64, _ vm.OpCode, _, _ uint64, _ *vm.ScopeContext, _ int, _ error) { -} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *revertReasonTracer) CaptureEnter(_ vm.OpCode, _ common.Address, _ common.Address, _ []byte, _ uint64, _ *big.Int) { - // Skip if tracing was interrupted - if atomic.LoadUint32(&t.interrupt) > 0 { - t.env.Cancel() - return - } -} - -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (t *revertReasonTracer) CaptureExit(_ []byte, _ uint64, _ error) {} - -func (t *revertReasonTracer) CaptureTxStart(_ uint64) {} - -func (t *revertReasonTracer) CaptureTxEnd(_ uint64) {} - -// GetResult returns an error message json object. -func (t *revertReasonTracer) GetResult() (json.RawMessage, error) { - res, err := json.Marshal(t.revertReason) - if err != nil { - return nil, err - } - return res, t.reason -} - -// Stop terminates execution of the tracer at the first opportune moment. -func (t *revertReasonTracer) Stop(err error) { - t.reason = err - atomic.StoreUint32(&t.interrupt, 1) -} diff --git a/eth/tracers/native/tracer.go b/eth/tracers/native/tracer.go deleted file mode 100644 index 9587caf19fd1..000000000000 --- a/eth/tracers/native/tracer.go +++ /dev/null @@ -1,83 +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 . - -/* -Package native is a collection of tracers written in go. - -In order to add a native tracer and have it compiled into the binary, a new -file needs to be added to this folder, containing an implementation of the -`eth.tracers.Tracer` interface. - -Aside from implementing the tracer, it also needs to register itself, using the -`register` method -- and this needs to be done in the package initialization. - -Example: - -```golang -func init() { - register("noopTracerNative", newNoopTracer) -} -``` -*/ -package native - -import ( - "encoding/json" - "errors" - - "github.com/ethereum/go-ethereum/eth/tracers" -) - -// init registers itself this packages as a lookup for tracers. -func init() { - tracers.RegisterLookup(false, lookup) -} - -// ctorFn is the constructor signature of a native tracer. -type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error) - -/* -ctors is a map of package-local tracer constructors. - -We cannot be certain about the order of init-functions within a package, -The go spec (https://golang.org/ref/spec#Package_initialization) says - -> To ensure reproducible initialization behavior, build systems -> are encouraged to present multiple files belonging to the same -> package in lexical file name order to a compiler. - -Hence, we cannot make the map in init, but must make it upon first use. -*/ -var ctors map[string]ctorFn - -// register is used by native tracers to register their presence. -func register(name string, ctor ctorFn) { - if ctors == nil { - ctors = make(map[string]ctorFn) - } - ctors[name] = ctor -} - -// lookup returns a tracer, if one can be matched to the given name. -func lookup(name string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { - if ctors == nil { - ctors = make(map[string]ctorFn) - } - if ctor, ok := ctors[name]; ok { - return ctor(ctx, cfg) - } - return nil, errors.New("no tracer found") -} diff --git a/go.sum b/go.sum index 5c1f170be5d2..1022db1e43a9 100644 --- a/go.sum +++ b/go.sum @@ -342,18 +342,12 @@ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -415,8 +409,6 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= -github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= @@ -554,8 +546,6 @@ golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 3ffe81a5e00c..0249c8664d3c 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -27,10 +27,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" diff --git a/mobile/accounts.go b/mobile/accounts.go deleted file mode 100644 index d9eab93a741d..000000000000 --- a/mobile/accounts.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the accounts package to support client side key -// management on mobile platforms. - -package geth - -import ( - "errors" - "time" - - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -const ( - // StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB - // memory and taking approximately 1s CPU time on a modern processor. - StandardScryptN = int(keystore.StandardScryptN) - - // StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB - // memory and taking approximately 1s CPU time on a modern processor. - StandardScryptP = int(keystore.StandardScryptP) - - // LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB - // memory and taking approximately 100ms CPU time on a modern processor. - LightScryptN = int(keystore.LightScryptN) - - // LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB - // memory and taking approximately 100ms CPU time on a modern processor. - LightScryptP = int(keystore.LightScryptP) -) - -// Account represents a stored key. -type Account struct{ account accounts.Account } - -// Accounts represents a slice of accounts. -type Accounts struct{ accounts []accounts.Account } - -// Size returns the number of accounts in the slice. -func (a *Accounts) Size() int { - return len(a.accounts) -} - -// Get returns the account at the given index from the slice. -func (a *Accounts) Get(index int) (account *Account, _ error) { - if index < 0 || index >= len(a.accounts) { - return nil, errors.New("index out of bounds") - } - return &Account{a.accounts[index]}, nil -} - -// Set sets the account at the given index in the slice. -func (a *Accounts) Set(index int, account *Account) error { - if index < 0 || index >= len(a.accounts) { - return errors.New("index out of bounds") - } - a.accounts[index] = account.account - return nil -} - -// GetAddress retrieves the address associated with the account. -func (a *Account) GetAddress() *Address { - return &Address{a.account.Address} -} - -// GetURL retrieves the canonical URL of the account. -func (a *Account) GetURL() string { - return a.account.URL.String() -} - -// KeyStore manages a key storage directory on disk. -type KeyStore struct{ keystore *keystore.KeyStore } - -// NewKeyStore creates a keystore for the given directory. -func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore { - return &KeyStore{keystore: keystore.NewKeyStore(keydir, scryptN, scryptP)} -} - -// HasAddress reports whether a key with the given address is present. -func (ks *KeyStore) HasAddress(address *Address) bool { - return ks.keystore.HasAddress(address.address) -} - -// GetAccounts returns all key files present in the directory. -func (ks *KeyStore) GetAccounts() *Accounts { - return &Accounts{ks.keystore.Accounts()} -} - -// DeleteAccount deletes the key matched by account if the passphrase is correct. -// If a contains no filename, the address must match a unique key. -func (ks *KeyStore) DeleteAccount(account *Account, passphrase string) error { - return ks.keystore.Delete(account.account, passphrase) -} - -// SignHash calculates a ECDSA signature for the given hash. The produced signature -// is in the [R || S || V] format where V is 0 or 1. -func (ks *KeyStore) SignHash(address *Address, hash []byte) (signature []byte, _ error) { - return ks.keystore.SignHash(accounts.Account{Address: address.address}, common.CopyBytes(hash)) -} - -// SignTx signs the given transaction with the requested account. -func (ks *KeyStore) SignTx(account *Account, tx *Transaction, chainID *BigInt) (*Transaction, error) { - if chainID == nil { // Null passed from mobile app - chainID = new(BigInt) - } - signed, err := ks.keystore.SignTx(account.account, tx.tx, chainID.bigint) - if err != nil { - return nil, err - } - return &Transaction{signed}, nil -} - -// SignHashPassphrase signs hash if the private key matching the given address can -// be decrypted with the given passphrase. The produced signature is in the -// [R || S || V] format where V is 0 or 1. -func (ks *KeyStore) SignHashPassphrase(account *Account, passphrase string, hash []byte) (signature []byte, _ error) { - return ks.keystore.SignHashWithPassphrase(account.account, passphrase, common.CopyBytes(hash)) -} - -// SignTxPassphrase signs the transaction if the private key matching the -// given address can be decrypted with the given passphrase. -func (ks *KeyStore) SignTxPassphrase(account *Account, passphrase string, tx *Transaction, chainID *BigInt) (*Transaction, error) { - if chainID == nil { // Null passed from mobile app - chainID = new(BigInt) - } - signed, err := ks.keystore.SignTxWithPassphrase(account.account, passphrase, tx.tx, chainID.bigint) - if err != nil { - return nil, err - } - return &Transaction{signed}, nil -} - -// Unlock unlocks the given account indefinitely. -func (ks *KeyStore) Unlock(account *Account, passphrase string) error { - return ks.keystore.TimedUnlock(account.account, passphrase, 0) -} - -// Lock removes the private key with the given address from memory. -func (ks *KeyStore) Lock(address *Address) error { - return ks.keystore.Lock(address.address) -} - -// TimedUnlock unlocks the given account with the passphrase. The account stays -// unlocked for the duration of timeout (nanoseconds). A timeout of 0 unlocks the -// account until the program exits. The account must match a unique key file. -// -// If the account address is already unlocked for a duration, TimedUnlock extends or -// shortens the active unlock timeout. If the address was previously unlocked -// indefinitely the timeout is not altered. -func (ks *KeyStore) TimedUnlock(account *Account, passphrase string, timeout int64) error { - return ks.keystore.TimedUnlock(account.account, passphrase, time.Duration(timeout)) -} - -// NewAccount generates a new key and stores it into the key directory, -// encrypting it with the passphrase. -func (ks *KeyStore) NewAccount(passphrase string) (*Account, error) { - account, err := ks.keystore.NewAccount(passphrase) - if err != nil { - return nil, err - } - return &Account{account}, nil -} - -// UpdateAccount changes the passphrase of an existing account. -func (ks *KeyStore) UpdateAccount(account *Account, passphrase, newPassphrase string) error { - return ks.keystore.Update(account.account, passphrase, newPassphrase) -} - -// ExportKey exports as a JSON key, encrypted with newPassphrase. -func (ks *KeyStore) ExportKey(account *Account, passphrase, newPassphrase string) (key []byte, _ error) { - return ks.keystore.Export(account.account, passphrase, newPassphrase) -} - -// ImportKey stores the given encrypted JSON key into the key directory. -func (ks *KeyStore) ImportKey(keyJSON []byte, passphrase, newPassphrase string) (account *Account, _ error) { - acc, err := ks.keystore.Import(common.CopyBytes(keyJSON), passphrase, newPassphrase) - if err != nil { - return nil, err - } - return &Account{acc}, nil -} - -// ImportECDSAKey stores the given encrypted JSON key into the key directory. -func (ks *KeyStore) ImportECDSAKey(key []byte, passphrase string) (account *Account, _ error) { - privkey, err := crypto.ToECDSA(common.CopyBytes(key)) - if err != nil { - return nil, err - } - acc, err := ks.keystore.ImportECDSA(privkey, passphrase) - if err != nil { - return nil, err - } - return &Account{acc}, nil -} - -// ImportPreSaleKey decrypts the given Ethereum presale wallet and stores -// a key file in the key directory. The key file is encrypted with the same passphrase. -func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (account *Account, _ error) { - acc, err := ks.keystore.ImportPreSaleKey(common.CopyBytes(keyJSON), passphrase) - if err != nil { - return nil, err - } - return &Account{acc}, nil -} diff --git a/mobile/ethclient.go b/mobile/ethclient.go deleted file mode 100644 index 00bcb3a2b9bc..000000000000 --- a/mobile/ethclient.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2016 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 . - -// Contains a wrapper for the Ethereum client. - -package geth - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" -) - -// EthereumClient provides access to the Ethereum APIs. -type EthereumClient struct { - client *ethclient.Client -} - -// NewEthereumClient connects a client to the given URL. -func NewEthereumClient(rawurl string) (client *EthereumClient, _ error) { - rawClient, err := ethclient.Dial(rawurl) - return &EthereumClient{rawClient}, err -} - -// GetBlockByHash returns the given full block. -func (ec *EthereumClient) GetBlockByHash(ctx *Context, hash *Hash) (block *Block, _ error) { - rawBlock, err := ec.client.BlockByHash(ctx.context, hash.hash) - return &Block{rawBlock}, err -} - -// GetBlockByNumber returns a block from the current canonical chain. If number is <0, the -// latest known block is returned. -func (ec *EthereumClient) GetBlockByNumber(ctx *Context, number int64) (block *Block, _ error) { - if number < 0 { - rawBlock, err := ec.client.BlockByNumber(ctx.context, nil) - return &Block{rawBlock}, err - } - rawBlock, err := ec.client.BlockByNumber(ctx.context, big.NewInt(number)) - return &Block{rawBlock}, err -} - -// GetHeaderByHash returns the block header with the given hash. -func (ec *EthereumClient) GetHeaderByHash(ctx *Context, hash *Hash) (header *Header, _ error) { - rawHeader, err := ec.client.HeaderByHash(ctx.context, hash.hash) - return &Header{rawHeader}, err -} - -// GetHeaderByNumber returns a block header from the current canonical chain. If number is <0, -// the latest known header is returned. -func (ec *EthereumClient) GetHeaderByNumber(ctx *Context, number int64) (header *Header, _ error) { - if number < 0 { - rawHeader, err := ec.client.HeaderByNumber(ctx.context, nil) - return &Header{rawHeader}, err - } - rawHeader, err := ec.client.HeaderByNumber(ctx.context, big.NewInt(number)) - return &Header{rawHeader}, err -} - -// GetTransactionByHash returns the transaction with the given hash. -func (ec *EthereumClient) GetTransactionByHash(ctx *Context, hash *Hash) (tx *Transaction, _ error) { - // TODO(karalabe): handle isPending - rawTx, _, err := ec.client.TransactionByHash(ctx.context, hash.hash) - return &Transaction{rawTx}, err -} - -// GetTransactionSender returns the sender address of a transaction. The transaction must -// be included in blockchain at the given block and index. -func (ec *EthereumClient) GetTransactionSender(ctx *Context, tx *Transaction, blockhash *Hash, index int) (sender *Address, _ error) { - addr, err := ec.client.TransactionSender(ctx.context, tx.tx, blockhash.hash, uint(index)) - return &Address{addr}, err -} - -// GetTransactionCount returns the total number of transactions in the given block. -func (ec *EthereumClient) GetTransactionCount(ctx *Context, hash *Hash) (count int, _ error) { - rawCount, err := ec.client.TransactionCount(ctx.context, hash.hash) - return int(rawCount), err -} - -// GetTransactionInBlock returns a single transaction at index in the given block. -func (ec *EthereumClient) GetTransactionInBlock(ctx *Context, hash *Hash, index int) (tx *Transaction, _ error) { - rawTx, err := ec.client.TransactionInBlock(ctx.context, hash.hash, uint(index)) - return &Transaction{rawTx}, err -} - -// GetTransactionReceipt returns the receipt of a transaction by transaction hash. -// Note that the receipt is not available for pending transactions. -func (ec *EthereumClient) GetTransactionReceipt(ctx *Context, hash *Hash) (receipt *Receipt, _ error) { - rawReceipt, err := ec.client.TransactionReceipt(ctx.context, hash.hash) - return &Receipt{rawReceipt}, err -} - -// SyncProgress retrieves the current progress of the sync algorithm. If there's -// no sync currently running, it returns nil. -func (ec *EthereumClient) SyncProgress(ctx *Context) (progress *SyncProgress, _ error) { - rawProgress, err := ec.client.SyncProgress(ctx.context) - if rawProgress == nil { - return nil, err - } - return &SyncProgress{*rawProgress}, err -} - -// NewHeadHandler is a client-side subscription callback to invoke on events and -// subscription failure. -type NewHeadHandler interface { - OnNewHead(header *Header) - OnError(failure string) -} - -// SubscribeNewHead subscribes to notifications about the current blockchain head -// on the given channel. -func (ec *EthereumClient) SubscribeNewHead(ctx *Context, handler NewHeadHandler, buffer int) (sub *Subscription, _ error) { - // Subscribe to the event internally - ch := make(chan *types.Header, buffer) - rawSub, err := ec.client.SubscribeNewHead(ctx.context, ch) - if err != nil { - return nil, err - } - // Start up a dispatcher to feed into the callback - go func() { - for { - select { - case header := <-ch: - handler.OnNewHead(&Header{header}) - - case err := <-rawSub.Err(): - if err != nil { - handler.OnError(err.Error()) - } - return - } - } - }() - return &Subscription{rawSub}, nil -} - -// State Access - -// GetBalanceAt returns the wei balance of the given account. -// The block number can be <0, in which case the balance is taken from the latest known block. -func (ec *EthereumClient) GetBalanceAt(ctx *Context, account *Address, number int64) (balance *BigInt, _ error) { - if number < 0 { - rawBalance, err := ec.client.BalanceAt(ctx.context, account.address, nil) - return &BigInt{rawBalance}, err - } - rawBalance, err := ec.client.BalanceAt(ctx.context, account.address, big.NewInt(number)) - return &BigInt{rawBalance}, err -} - -// GetStorageAt returns the value of key in the contract storage of the given account. -// The block number can be <0, in which case the value is taken from the latest known block. -func (ec *EthereumClient) GetStorageAt(ctx *Context, account *Address, key *Hash, number int64) (storage []byte, _ error) { - if number < 0 { - return ec.client.StorageAt(ctx.context, account.address, key.hash, nil) - } - return ec.client.StorageAt(ctx.context, account.address, key.hash, big.NewInt(number)) -} - -// GetCodeAt returns the contract code of the given account. -// The block number can be <0, in which case the code is taken from the latest known block. -func (ec *EthereumClient) GetCodeAt(ctx *Context, account *Address, number int64) (code []byte, _ error) { - if number < 0 { - return ec.client.CodeAt(ctx.context, account.address, nil) - } - return ec.client.CodeAt(ctx.context, account.address, big.NewInt(number)) -} - -// GetNonceAt returns the account nonce of the given account. -// The block number can be <0, in which case the nonce is taken from the latest known block. -func (ec *EthereumClient) GetNonceAt(ctx *Context, account *Address, number int64) (nonce int64, _ error) { - if number < 0 { - rawNonce, err := ec.client.NonceAt(ctx.context, account.address, nil) - return int64(rawNonce), err - } - rawNonce, err := ec.client.NonceAt(ctx.context, account.address, big.NewInt(number)) - return int64(rawNonce), err -} - -// Filters - -// FilterLogs executes a filter query. -func (ec *EthereumClient) FilterLogs(ctx *Context, query *FilterQuery) (logs *Logs, _ error) { - rawLogs, err := ec.client.FilterLogs(ctx.context, query.query) - if err != nil { - return nil, err - } - // Temp hack due to vm.Logs being []*vm.Log - res := make([]*types.Log, len(rawLogs)) - for i := range rawLogs { - res[i] = &rawLogs[i] - } - return &Logs{res}, nil -} - -// FilterLogsHandler is a client-side subscription callback to invoke on events and -// subscription failure. -type FilterLogsHandler interface { - OnFilterLogs(log *Log) - OnError(failure string) -} - -// SubscribeFilterLogs subscribes to the results of a streaming filter query. -func (ec *EthereumClient) SubscribeFilterLogs(ctx *Context, query *FilterQuery, handler FilterLogsHandler, buffer int) (sub *Subscription, _ error) { - // Subscribe to the event internally - ch := make(chan types.Log, buffer) - rawSub, err := ec.client.SubscribeFilterLogs(ctx.context, query.query, ch) - if err != nil { - return nil, err - } - // Start up a dispatcher to feed into the callback - go func() { - for { - select { - case log := <-ch: - handler.OnFilterLogs(&Log{&log}) - - case err := <-rawSub.Err(): - if err != nil { - handler.OnError(err.Error()) - } - return - } - } - }() - return &Subscription{rawSub}, nil -} - -// Pending State - -// GetPendingBalanceAt returns the wei balance of the given account in the pending state. -func (ec *EthereumClient) GetPendingBalanceAt(ctx *Context, account *Address) (balance *BigInt, _ error) { - rawBalance, err := ec.client.PendingBalanceAt(ctx.context, account.address) - return &BigInt{rawBalance}, err -} - -// GetPendingStorageAt returns the value of key in the contract storage of the given account in the pending state. -func (ec *EthereumClient) GetPendingStorageAt(ctx *Context, account *Address, key *Hash) (storage []byte, _ error) { - return ec.client.PendingStorageAt(ctx.context, account.address, key.hash) -} - -// GetPendingCodeAt returns the contract code of the given account in the pending state. -func (ec *EthereumClient) GetPendingCodeAt(ctx *Context, account *Address) (code []byte, _ error) { - return ec.client.PendingCodeAt(ctx.context, account.address) -} - -// GetPendingNonceAt returns the account nonce of the given account in the pending state. -// This is the nonce that should be used for the next transaction. -func (ec *EthereumClient) GetPendingNonceAt(ctx *Context, account *Address) (nonce int64, _ error) { - rawNonce, err := ec.client.PendingNonceAt(ctx.context, account.address) - return int64(rawNonce), err -} - -// GetPendingTransactionCount returns the total number of transactions in the pending state. -func (ec *EthereumClient) GetPendingTransactionCount(ctx *Context) (count int, _ error) { - rawCount, err := ec.client.PendingTransactionCount(ctx.context) - return int(rawCount), err -} - -// Contract Calling - -// CallContract executes a message call transaction, which is directly executed in the VM -// of the node, but never mined into the blockchain. -// -// blockNumber selects the block height at which the call runs. It can be <0, in which -// case the code is taken from the latest known block. Note that state from very old -// blocks might not be available. -func (ec *EthereumClient) CallContract(ctx *Context, msg *CallMsg, number int64) (output []byte, _ error) { - if number < 0 { - return ec.client.CallContract(ctx.context, msg.msg, nil) - } - return ec.client.CallContract(ctx.context, msg.msg, big.NewInt(number)) -} - -// PendingCallContract executes a message call transaction using the EVM. -// The state seen by the contract call is the pending state. -func (ec *EthereumClient) PendingCallContract(ctx *Context, msg *CallMsg) (output []byte, _ error) { - return ec.client.PendingCallContract(ctx.context, msg.msg) -} - -// SuggestGasPrice retrieves the currently suggested gas price to allow a timely -// execution of a transaction. -func (ec *EthereumClient) SuggestGasPrice(ctx *Context) (price *BigInt, _ error) { - rawPrice, err := ec.client.SuggestGasPrice(ctx.context) - return &BigInt{rawPrice}, err -} - -// EstimateGas tries to estimate the gas needed to execute a specific transaction based on -// the current pending state of the backend blockchain. There is no guarantee that this is -// the true gas limit requirement as other transactions may be added or removed by miners, -// but it should provide a basis for setting a reasonable default. -func (ec *EthereumClient) EstimateGas(ctx *Context, msg *CallMsg) (gas int64, _ error) { - rawGas, err := ec.client.EstimateGas(ctx.context, msg.msg) - return int64(rawGas), err -} - -// SendTransaction injects a signed transaction into the pending pool for execution. -// -// If the transaction was a contract creation use the TransactionReceipt method to get the -// contract address after the transaction has been mined. -func (ec *EthereumClient) SendTransaction(ctx *Context, tx *Transaction) error { - return ec.client.SendTransaction(ctx.context, tx.tx) -} diff --git a/mobile/types.go b/mobile/types.go deleted file mode 100644 index f3f92e4d4ac3..000000000000 --- a/mobile/types.go +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright 2016 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 . - -// Contains all the wrappers from the core/types package. - -package geth - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rlp" -) - -type jsonEncoder interface { - EncodeJSON() (string, error) -} - -// encodeOrError tries to encode the object into json. -// If the encoding fails the resulting error is returned. -func encodeOrError(encoder jsonEncoder) string { - enc, err := encoder.EncodeJSON() - if err != nil { - return err.Error() - } - return enc -} - -// A Nonce is a 64-bit hash which proves (combined with the mix-hash) that -// a sufficient amount of computation has been carried out on a block. -type Nonce struct { - nonce types.BlockNonce -} - -// GetBytes retrieves the byte representation of the block nonce. -func (n *Nonce) GetBytes() []byte { - return n.nonce[:] -} - -// GetHex retrieves the hex string representation of the block nonce. -func (n *Nonce) GetHex() string { - return fmt.Sprintf("%#x", n.nonce[:]) -} - -// String returns a printable representation of the nonce. -func (n *Nonce) String() string { - return n.GetHex() -} - -// Bloom represents a 256 bit bloom filter. -type Bloom struct { - bloom types.Bloom -} - -// GetBytes retrieves the byte representation of the bloom filter. -func (b *Bloom) GetBytes() []byte { - return b.bloom[:] -} - -// GetHex retrieves the hex string representation of the bloom filter. -func (b *Bloom) GetHex() string { - return fmt.Sprintf("%#x", b.bloom[:]) -} - -// String returns a printable representation of the bloom filter. -func (b *Bloom) String() string { - return b.GetHex() -} - -// Header represents a block header in the Ethereum blockchain. -type Header struct { - header *types.Header -} - -// NewHeaderFromRLP parses a header from an RLP data dump. -func NewHeaderFromRLP(data []byte) (*Header, error) { - h := &Header{ - header: new(types.Header), - } - if err := rlp.DecodeBytes(common.CopyBytes(data), h.header); err != nil { - return nil, err - } - return h, nil -} - -// EncodeRLP encodes a header into an RLP data dump. -func (h *Header) EncodeRLP() ([]byte, error) { - return rlp.EncodeToBytes(h.header) -} - -// NewHeaderFromJSON parses a header from a JSON data dump. -func NewHeaderFromJSON(data string) (*Header, error) { - h := &Header{ - header: new(types.Header), - } - if err := json.Unmarshal([]byte(data), h.header); err != nil { - return nil, err - } - return h, nil -} - -// EncodeJSON encodes a header into a JSON data dump. -func (h *Header) EncodeJSON() (string, error) { - data, err := json.Marshal(h.header) - return string(data), err -} - -// String returns a printable representation of the header. -func (h *Header) String() string { - return encodeOrError(h) -} - -func (h *Header) GetParentHash() *Hash { return &Hash{h.header.ParentHash} } -func (h *Header) GetUncleHash() *Hash { return &Hash{h.header.UncleHash} } -func (h *Header) GetCoinbase() *Address { return &Address{h.header.Coinbase} } -func (h *Header) GetRoot() *Hash { return &Hash{h.header.Root} } -func (h *Header) GetTxHash() *Hash { return &Hash{h.header.TxHash} } -func (h *Header) GetReceiptHash() *Hash { return &Hash{h.header.ReceiptHash} } -func (h *Header) GetBloom() *Bloom { return &Bloom{h.header.Bloom} } -func (h *Header) GetDifficulty() *BigInt { return &BigInt{h.header.Difficulty} } -func (h *Header) GetNumber() int64 { return h.header.Number.Int64() } -func (h *Header) GetGasLimit() int64 { return int64(h.header.GasLimit) } -func (h *Header) GetGasUsed() int64 { return int64(h.header.GasUsed) } -func (h *Header) GetTime() int64 { return int64(h.header.Time) } -func (h *Header) GetExtra() []byte { return h.header.Extra } -func (h *Header) GetMixDigest() *Hash { return &Hash{h.header.MixDigest} } -func (h *Header) GetNonce() *Nonce { return &Nonce{h.header.Nonce} } -func (h *Header) GetHash() *Hash { return &Hash{h.header.Hash()} } - -// Headers represents a slice of headers. -type Headers struct{ headers []*types.Header } - -// Size returns the number of headers in the slice. -func (h *Headers) Size() int { - return len(h.headers) -} - -// Get returns the header at the given index from the slice. -func (h *Headers) Get(index int) (header *Header, _ error) { - if index < 0 || index >= len(h.headers) { - return nil, errors.New("index out of bounds") - } - return &Header{h.headers[index]}, nil -} - -// Block represents an entire block in the Ethereum blockchain. -type Block struct { - block *types.Block -} - -// NewBlockFromRLP parses a block from an RLP data dump. -func NewBlockFromRLP(data []byte) (*Block, error) { - b := &Block{ - block: new(types.Block), - } - if err := rlp.DecodeBytes(common.CopyBytes(data), b.block); err != nil { - return nil, err - } - return b, nil -} - -// EncodeRLP encodes a block into an RLP data dump. -func (b *Block) EncodeRLP() ([]byte, error) { - return rlp.EncodeToBytes(b.block) -} - -// NewBlockFromJSON parses a block from a JSON data dump. -func NewBlockFromJSON(data string) (*Block, error) { - b := &Block{ - block: new(types.Block), - } - if err := json.Unmarshal([]byte(data), b.block); err != nil { - return nil, err - } - return b, nil -} - -// EncodeJSON encodes a block into a JSON data dump. -func (b *Block) EncodeJSON() (string, error) { - data, err := json.Marshal(b.block) - return string(data), err -} - -// String returns a printable representation of the block. -func (b *Block) String() string { - return encodeOrError(b) -} - -func (b *Block) GetParentHash() *Hash { return &Hash{b.block.ParentHash()} } -func (b *Block) GetUncleHash() *Hash { return &Hash{b.block.UncleHash()} } -func (b *Block) GetCoinbase() *Address { return &Address{b.block.Coinbase()} } -func (b *Block) GetRoot() *Hash { return &Hash{b.block.Root()} } -func (b *Block) GetTxHash() *Hash { return &Hash{b.block.TxHash()} } -func (b *Block) GetReceiptHash() *Hash { return &Hash{b.block.ReceiptHash()} } -func (b *Block) GetBloom() *Bloom { return &Bloom{b.block.Bloom()} } -func (b *Block) GetDifficulty() *BigInt { return &BigInt{b.block.Difficulty()} } -func (b *Block) GetNumber() int64 { return b.block.Number().Int64() } -func (b *Block) GetGasLimit() int64 { return int64(b.block.GasLimit()) } -func (b *Block) GetGasUsed() int64 { return int64(b.block.GasUsed()) } -func (b *Block) GetTime() int64 { return int64(b.block.Time()) } -func (b *Block) GetExtra() []byte { return b.block.Extra() } -func (b *Block) GetMixDigest() *Hash { return &Hash{b.block.MixDigest()} } -func (b *Block) GetNonce() int64 { return int64(b.block.Nonce()) } -func (b *Block) GetHash() *Hash { return &Hash{b.block.Hash()} } -func (b *Block) GetHeader() *Header { return &Header{b.block.Header()} } -func (b *Block) GetUncles() *Headers { return &Headers{b.block.Uncles()} } -func (b *Block) GetTransactions() *Transactions { return &Transactions{b.block.Transactions()} } -func (b *Block) GetTransaction(hash *Hash) *Transaction { - return &Transaction{b.block.Transaction(hash.hash)} -} - -// Transaction represents a single Ethereum transaction. -type Transaction struct { - tx *types.Transaction -} - -// NewContractCreation creates a new transaction for deploying a new contract with -// the given properties. -func NewContractCreation(nonce int64, amount *BigInt, gasLimit int64, gasPrice *BigInt, data []byte) *Transaction { - return &Transaction{types.NewContractCreation(uint64(nonce), amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))} -} - -// NewTransaction creates a new transaction with the given properties. Contracts -// can be created by transacting with a nil recipient. -func NewTransaction(nonce int64, to *Address, amount *BigInt, gasLimit int64, gasPrice *BigInt, data []byte) *Transaction { - if to == nil { - return &Transaction{types.NewContractCreation(uint64(nonce), amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))} - } - return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))} -} - -// NewTransactionFromRLP parses a transaction from an RLP data dump. -func NewTransactionFromRLP(data []byte) (*Transaction, error) { - tx := &Transaction{ - tx: new(types.Transaction), - } - if err := rlp.DecodeBytes(common.CopyBytes(data), tx.tx); err != nil { - return nil, err - } - return tx, nil -} - -// EncodeRLP encodes a transaction into an RLP data dump. -func (tx *Transaction) EncodeRLP() ([]byte, error) { - return rlp.EncodeToBytes(tx.tx) -} - -// NewTransactionFromJSON parses a transaction from a JSON data dump. -func NewTransactionFromJSON(data string) (*Transaction, error) { - tx := &Transaction{ - tx: new(types.Transaction), - } - if err := json.Unmarshal([]byte(data), tx.tx); err != nil { - return nil, err - } - return tx, nil -} - -// EncodeJSON encodes a transaction into a JSON data dump. -func (tx *Transaction) EncodeJSON() (string, error) { - data, err := json.Marshal(tx.tx) - return string(data), err -} - -// String returns a printable representation of the transaction. -func (tx *Transaction) String() string { - return encodeOrError(tx) -} - -func (tx *Transaction) GetData() []byte { return tx.tx.Data() } -func (tx *Transaction) GetGas() int64 { return int64(tx.tx.Gas()) } -func (tx *Transaction) GetGasPrice() *BigInt { return &BigInt{tx.tx.GasPrice()} } -func (tx *Transaction) GetValue() *BigInt { return &BigInt{tx.tx.Value()} } -func (tx *Transaction) GetNonce() int64 { return int64(tx.tx.Nonce()) } - -func (tx *Transaction) GetHash() *Hash { return &Hash{tx.tx.Hash()} } -func (tx *Transaction) GetCost() *BigInt { return &BigInt{tx.tx.Cost()} } - -func (tx *Transaction) GetTo() *Address { - if to := tx.tx.To(); to != nil { - return &Address{*to} - } - return nil -} - -func (tx *Transaction) WithSignature(sig []byte, chainID *BigInt) (signedTx *Transaction, _ error) { - var signer types.Signer = types.HomesteadSigner{} - if chainID != nil { - signer = types.NewEIP155Signer(chainID.bigint) - } - rawTx, err := tx.tx.WithSignature(signer, common.CopyBytes(sig)) - return &Transaction{rawTx}, err -} - -// Transactions represents a slice of transactions. -type Transactions struct{ txs types.Transactions } - -// Size returns the number of transactions in the slice. -func (txs *Transactions) Size() int { - return len(txs.txs) -} - -// Get returns the transaction at the given index from the slice. -func (txs *Transactions) Get(index int) (tx *Transaction, _ error) { - if index < 0 || index >= len(txs.txs) { - return nil, errors.New("index out of bounds") - } - return &Transaction{txs.txs[index]}, nil -} - -// Receipt represents the results of a transaction. -type Receipt struct { - receipt *types.Receipt -} - -// NewReceiptFromRLP parses a transaction receipt from an RLP data dump. -func NewReceiptFromRLP(data []byte) (*Receipt, error) { - r := &Receipt{ - receipt: new(types.Receipt), - } - if err := rlp.DecodeBytes(common.CopyBytes(data), r.receipt); err != nil { - return nil, err - } - return r, nil -} - -// EncodeRLP encodes a transaction receipt into an RLP data dump. -func (r *Receipt) EncodeRLP() ([]byte, error) { - return rlp.EncodeToBytes(r.receipt) -} - -// NewReceiptFromJSON parses a transaction receipt from a JSON data dump. -func NewReceiptFromJSON(data string) (*Receipt, error) { - r := &Receipt{ - receipt: new(types.Receipt), - } - if err := json.Unmarshal([]byte(data), r.receipt); err != nil { - return nil, err - } - return r, nil -} - -// EncodeJSON encodes a transaction receipt into a JSON data dump. -func (r *Receipt) EncodeJSON() (string, error) { - data, err := json.Marshal(r.receipt) - return string(data), err -} - -// String returns a printable representation of the receipt. -func (r *Receipt) String() string { - return encodeOrError(r) -} - -func (r *Receipt) GetStatus() int { return int(r.receipt.Status) } -func (r *Receipt) GetPostState() []byte { return r.receipt.PostState } -func (r *Receipt) GetCumulativeGasUsed() int64 { return int64(r.receipt.CumulativeGasUsed) } -func (r *Receipt) GetBloom() *Bloom { return &Bloom{r.receipt.Bloom} } -func (r *Receipt) GetLogs() *Logs { return &Logs{r.receipt.Logs} } -func (r *Receipt) GetTxHash() *Hash { return &Hash{r.receipt.TxHash} } -func (r *Receipt) GetContractAddress() *Address { return &Address{r.receipt.ContractAddress} } -func (r *Receipt) GetGasUsed() int64 { return int64(r.receipt.GasUsed) } diff --git a/params/config.go b/params/config.go index 24c2dfa0656f..82d00bc8f515 100644 --- a/params/config.go +++ b/params/config.go @@ -624,11 +624,6 @@ func (c *ChainConfig) IsGrayGlacier(num *big.Int) bool { return isBlockForked(c.GrayGlacierBlock, num) } -// IsGrayGlacier returns whether num is either equal to the Gray Glacier (EIP-5133) fork block or greater. -func (c *ChainConfig) IsGrayGlacier(num *big.Int) bool { - return isForked(c.GrayGlacierBlock, num) -} - // IsTerminalPoWBlock returns whether the given block is the last block of PoW stage. func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool { if c.TerminalTotalDifficulty == nil { diff --git a/trie/proof.go b/trie/proof.go index 85b764012703..65df7577b9b6 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -22,7 +22,6 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) diff --git a/trie/stacktrie.go b/trie/stacktrie.go index 9a6d8cf2d720..030d2a596c88 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -83,16 +83,6 @@ func NewStackTrieWithOwner(writeFn NodeWriteFunc, owner common.Hash) *StackTrie } } -// NewStackTrieWithOwner allocates and initializes an empty trie, but with -// the additional owner field. -func NewStackTrieWithOwner(db ethdb.KeyValueWriter, owner common.Hash) *StackTrie { - return &StackTrie{ - owner: owner, - nodeType: emptyNode, - db: db, - } -} - // NewFromBinary initialises a serialized stacktrie with the given db. func NewFromBinary(data []byte, writeFn NodeWriteFunc) (*StackTrie, error) { var st StackTrie diff --git a/trie/tracer.go b/trie/tracer.go index 7a397b652b58..e70b6c73c25b 100644 --- a/trie/tracer.go +++ b/trie/tracer.go @@ -50,9 +50,7 @@ func newTracer() *tracer { deletes: make(map[string]struct{}), accessList: make(map[string][]byte), } - t.origin[string(key)] = val } -*/ // onRead tracks the newly loaded trie node and caches the rlp-encoded // blob internally. Don't change the value outside of function since @@ -117,9 +115,6 @@ func (t *tracer) copy() *tracer { for path, blob := range t.accessList { accessList[path] = common.CopyBytes(blob) } - for key, val := range t.origin { - origin[key] = val - } return &tracer{ inserts: inserts, deletes: deletes, diff --git a/trie/util_test.go b/trie/util_test.go deleted file mode 100644 index 252dc09e0804..000000000000 --- a/trie/util_test.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package trie - -import ( - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" -) - -// Tests if the trie diffs are tracked correctly. -func TestTrieTracer(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase()) - trie := NewEmpty(db) - trie.tracer = newTracer() - - // Insert a batch of entries, all the nodes should be marked as inserted - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) - } - trie.Hash() - - seen := make(map[string]struct{}) - it := trie.NodeIterator(nil) - for it.Next(true) { - if it.Leaf() { - continue - } - seen[string(it.Path())] = struct{}{} - } - inserted := trie.tracer.insertList() - if len(inserted) != len(seen) { - t.Fatalf("Unexpected inserted node tracked want %d got %d", len(seen), len(inserted)) - } - for _, k := range inserted { - _, ok := seen[string(k)] - if !ok { - t.Fatalf("Unexpected inserted node") - } - } - deleted := trie.tracer.deleteList() - if len(deleted) != 0 { - t.Fatalf("Unexpected deleted node tracked %d", len(deleted)) - } - - // Commit the changes and re-create with new root - root, nodes, _ := trie.Commit(false) - db.Update(NewWithNodeSet(nodes)) - trie, _ = New(common.Hash{}, root, db) - trie.tracer = newTracer() - - // Delete all the elements, check deletion set - for _, val := range vals { - trie.Delete([]byte(val.k)) - } - trie.Hash() - - inserted = trie.tracer.insertList() - if len(inserted) != 0 { - t.Fatalf("Unexpected inserted node tracked %d", len(inserted)) - } - deleted = trie.tracer.deleteList() - if len(deleted) != len(seen) { - t.Fatalf("Unexpected deleted node tracked want %d got %d", len(seen), len(deleted)) - } - for _, k := range deleted { - _, ok := seen[string(k)] - if !ok { - t.Fatalf("Unexpected inserted node") - } - } -} - -func TestTrieTracerNoop(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) - trie.tracer = newTracer() - - // Insert a batch of entries, all the nodes should be marked as inserted - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - trie.Update([]byte(val.k), []byte(val.v)) - } - for _, val := range vals { - trie.Delete([]byte(val.k)) - } - if len(trie.tracer.insertList()) != 0 { - t.Fatalf("Unexpected inserted node tracked %d", len(trie.tracer.insertList())) - } - if len(trie.tracer.deleteList()) != 0 { - t.Fatalf("Unexpected deleted node tracked %d", len(trie.tracer.deleteList())) - } -} From 7fe95645c01259c784f031dcfedcb34419051e27 Mon Sep 17 00:00:00 2001 From: susannapaxos <86749396+susannapaxos@users.noreply.github.com> Date: Thu, 9 Sep 2021 09:32:13 -0700 Subject: [PATCH 715/715] add market gas price to simulate duplicate nonce behavior (#7) --- accounts/abi/bind/backends/simulated.go | 9 +- accounts/abi/bind/backends/simulated_test.go | 201 +++++++++++++++++++ 2 files changed, 207 insertions(+), 3 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 5c9edd381ced..f0a495e43979 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -64,6 +64,7 @@ type SimulatedBackend struct { blockchain *core.BlockChain // Ethereum blockchain to handle the consensus mu sync.Mutex + stuckTransactions types.Transactions // holds onto all txes that don't go into the pending block due to low gas pendingBlock *types.Block // Currently pending block that will be imported on request pendingState *state.StateDB // Currently pending state that will be the active on request pendingReceipts types.Receipts // Currently receipts for the pending block @@ -129,7 +130,7 @@ func (b *SimulatedBackend) Commit() common.Hash { blocks, _ := core.GenerateChain(b.config, parentBlock, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { - for _, tx := range b.pendingBlock.Transactions() { + for _, tx := range append(b.pendingBlock.Transactions(), b.stuckTransactions...) { if b.marketGasPrice == nil || b.marketGasPrice.Cmp(tx.GasPrice()) <= 0 { block.AddTxWithChain(b.blockchain, tx) } else { @@ -145,8 +146,8 @@ func (b *SimulatedBackend) Commit() common.Hash { // Using the last inserted block here makes it possible to build on a side // chain after a fork. - b.rollback(b.pendingBlock) - + b.stuckTransactions = remainingTx + b.rollback(blocks[0]) return blockHash } @@ -741,6 +742,8 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa b.pendingBlock = blocks[0] b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil) b.pendingReceipts = receipts[0] + b.stuckTransactions = remainingTxes + return nil } diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go index 698bfc576573..8090dc1af647 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/accounts/abi/bind/backends/simulated_test.go @@ -27,6 +27,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -1397,3 +1400,201 @@ func TestAdjustTimeAfterFork(t *testing.T) { t.Errorf("failed to build block on fork") } } + +// TestLowGasTxNotBeingMined checks that the lower gas fee tx with same nonce does not get mined +// Steps: +// 1. Send a tx lower than the set market gas price +// 2. Commit to chain, check nonce stays the same +// 3. Send a tx meets the market gas price with same nonce. +// 4. Commit to chain +// 5. Check tx2 is not in pending state and nonce has increased +func TestLowGasTxNotBeingMined(t *testing.T) { + testAddr := crypto.PubkeyToAddress(testKey.PublicKey) + var gas uint64 = 21000 + + sim := simTestBackend(testAddr) + defer sim.Close() + + var testCases = []struct { + name string + txType byte + }{ + { + name: "LegacyTx", + txType: types.LegacyTxType, + }, + { + name: "dynamicTx", + txType: types.DynamicFeeTxType, + }, + } + for i, test := range testCases { + t.Run(test.name, func(t *testing.T) { + bgCtx := context.Background() + // Create tx and send + head, _ := sim.HeaderByNumber(context.Background(), nil) + tip, err := sim.SuggestGasTipCap(bgCtx) + require.NoError(t, err) + gasPrice := new(big.Int).Add(head.BaseFee, tip) + sim.SetMarketGasPrice(int64(gasPrice.Uint64())) + + lowFeeGas := new(big.Int).Sub(gasPrice, tip) + txValue := big.NewInt(1) + + var lowGasFeeTx *types.Transaction + + if test.txType == types.LegacyTxType { + lowGasFeeTx = types.NewTx(&types.LegacyTx{ + Nonce: uint64(i), + To: &testAddr, + Value: txValue, + GasPrice: lowFeeGas, + Gas: gas, + }) + } else if test.txType == types.DynamicFeeTxType { + lowGasFeeTx = types.NewTx(&types.DynamicFeeTx{ + Nonce: uint64(i), + Gas: gas, + To: &testAddr, + Value: txValue, + GasTipCap: lowFeeGas, + GasFeeCap: lowFeeGas, + }) + } else { + t.Fatal("unexpected txType received") + } + + signedTx, err := types.SignTx(lowGasFeeTx, types.LatestSigner(sim.config), testKey) + require.NoError(t, err) + + // send tx to simulated backend + err = sim.SendTransaction(bgCtx, signedTx) + require.NoError(t, err) + sim.Commit() + + // expect nonce be the same because low gas fee tx will not be mined + nonce, err := sim.PendingNonceAt(bgCtx, testAddr) + require.NoError(t, err) + assert.Equal(t, uint64(i), nonce) + + // send tx with higher gas fee + sufficientGasFeeTx := types.NewTx(&types.LegacyTx{ + Nonce: uint64(i), + To: &testAddr, + Value: txValue, + GasPrice: gasPrice, + Gas: gas, + }) + + signedSufficientTx, err := types.SignTx(sufficientGasFeeTx, types.HomesteadSigner{}, testKey) + require.NoError(t, err) + + err = sim.SendTransaction(bgCtx, signedSufficientTx) + require.NoError(t, err) + sim.Commit() + + // the higher gas transaction should have been mined + _, isPending, err := sim.TransactionByHash(bgCtx, signedSufficientTx.Hash()) + require.NoError(t, err) + assert.False(t, isPending) + + // expect nonce has increased + nonce, err = sim.PendingNonceAt(bgCtx, testAddr) + require.NoError(t, err) + assert.Equal(t, uint64(i)+1, nonce) + }) + } +} + +// TestLowGasTxGetMinedOnceGasFeeDropped checks that lower gas fee txes still stay in mem pool +// and get mined once gas fee requirement has been met +// Steps: +// 1. Send a tx lower than the set market gas price +// 2. Commit to chain, tx does not get mined +// 3. Gas fee drops, commit again +// 4. Check tx get mined +func TestLowGasTxGetMinedOnceGasFeeDropped(t *testing.T) { + var testCases = []struct { + name string + txType byte + }{ + { + name: "LegacyTx", + txType: types.LegacyTxType, + }, + { + name: "dynamicTx", + txType: types.DynamicFeeTxType, + }, + } + testAddr := crypto.PubkeyToAddress(testKey.PublicKey) + var gas uint64 = 21000 + + sim := simTestBackend(testAddr) + defer sim.Close() + + for i, test := range testCases { + t.Run(test.name, func(t *testing.T) { + bgCtx := context.Background() + // Create tx and send + head, _ := sim.HeaderByNumber(context.Background(), nil) + tip, err := sim.SuggestGasTipCap(bgCtx) + require.NoError(t, err) + normalGasPrice := new(big.Int).Add(head.BaseFee, tip) + highGasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(5)) + + sim.SetMarketGasPrice(int64(highGasPrice.Uint64())) + + var normalGasFeeTx *types.Transaction + txValue := big.NewInt(1) + + if test.txType == types.LegacyTxType { + normalGasFeeTx = types.NewTx(&types.LegacyTx{ + Nonce: uint64(i), + To: &testAddr, + Value: txValue, + GasPrice: normalGasPrice, + Gas: gas, + }) + } else if test.txType == types.DynamicFeeTxType { + normalGasFeeTx = types.NewTx(&types.DynamicFeeTx{ + Nonce: uint64(i), + Gas: gas, + To: &testAddr, + Value: txValue, + GasTipCap: normalGasPrice, + GasFeeCap: normalGasPrice, + }) + } else { + t.Fatal("unexpected txType received") + } + + signedTx, err := types.SignTx(normalGasFeeTx, types.LatestSigner(sim.config), testKey) + require.NoError(t, err) + + // send tx to simulated backend + err = sim.SendTransaction(bgCtx, signedTx) + require.NoError(t, err) + sim.Commit() + + // check that the nonce stays the same because nothing has been mined + pendingNonce, err := sim.PendingNonceAt(bgCtx, testAddr) + require.NoError(t, err) + assert.Equal(t, uint64(i), pendingNonce) + + // gas fee has dropped + sim.SetMarketGasPrice(int64(normalGasPrice.Uint64())) + sim.Commit() + + // nonce has increased + pendingNonce, err = sim.PendingNonceAt(bgCtx, testAddr) + require.NoError(t, err) + assert.Equal(t, uint64(i)+1, pendingNonce) + + // the transaction should have been mined + _, isPending, err := sim.TransactionByHash(bgCtx, signedTx.Hash()) + require.NoError(t, err) + assert.False(t, isPending) + }) + } +}